Skip to content

Commit

Permalink
Add additional basis gates rz, sx, x to basicaer. (Qiskit#6022)
Browse files Browse the repository at this point in the history
* Add additional basis gates rz, sx, x to basicaer.

This commit adds the Rz SX and X gates to basic aer simulators basis
gate set. This is necessary for running simulations of the fake backends
which are using the new basis set for the ibmq gates.

This was extracted from Qiskit#5577 which is blocked on other work.

* Fix lint and tests

* Add missing error from docstring

Co-authored-by: Thomas Alexander <[email protected]>
  • Loading branch information
mtreinish and taalexander authored Mar 15, 2021
1 parent f3e2b7a commit edd76c7
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 49 deletions.
64 changes: 35 additions & 29 deletions qiskit/providers/basicaer/basicaertools.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,50 +15,56 @@
"""

from string import ascii_uppercase, ascii_lowercase
from typing import List, Optional

import numpy as np

import qiskit.circuit.library.standard_gates as gates
from qiskit.exceptions import QiskitError

# Single qubit gates supported by ``single_gate_params``.
SINGLE_QUBIT_GATES = ('U', 'u1', 'u2', 'u3', 'rz', 'sx', 'x')

def single_gate_params(gate, params=None):
"""Apply a single qubit gate to the qubit.

def single_gate_matrix(gate: str, params: Optional[List[float]] = None):
"""Get the matrix for a single qubit.
Args:
gate(str): the single qubit gate name
params(list): the operation parameters op['params']
gate: the single qubit gate name
params: the operation parameters op['params']
Returns:
tuple: a tuple of U gate parameters (theta, phi, lam)
array: A numpy array representing the matrix
Raises:
QiskitError: if the gate name is not valid
QiskitError: If a gate outside the supported set is passed in for the
``Gate`` argument.
"""
if gate in ('U', 'u3'):
return params[0], params[1], params[2]
if params is None:
params = []

if gate == 'U':
gc = gates.UGate
elif gate == 'u3':
gc = gates.U3Gate
elif gate == 'u2':
return np.pi / 2, params[0], params[1]
gc = gates.U2Gate
elif gate == 'u1':
return 0, 0, params[0]
gc = gates.U1Gate
elif gate == 'rz':
gc = gates.RZGate
elif gate == 'id':
return 0, 0, 0
raise QiskitError('Gate is not among the valid types: %s' % gate)

gc = gates.IGate
elif gate == 'sx':
gc = gates.SXGate
elif gate == 'x':
gc = gates.XGate
else:
raise QiskitError('Gate is not a valid basis gate for this simulator: %s' % gate)

def single_gate_matrix(gate, params=None):
"""Get the matrix for a single qubit.
Args:
gate(str): the single qubit gate name
params(list): the operation parameters op['params']
Returns:
array: A numpy array representing the matrix
"""
return gc(*params).to_matrix()

# Converting sym to floats improves the performance of the simulator 10x.
# This a is a probable a FIXME since it might show bugs in the simulator.
(theta, phi, lam) = map(float, single_gate_params(gate, params))

return np.array([[np.cos(theta / 2),
-np.exp(1j * lam) * np.sin(theta / 2)],
[np.exp(1j * phi) * np.sin(theta / 2),
np.exp(1j * phi + 1j * lam) * np.cos(theta / 2)]])
# Cache CX matrix as no parameters.
_CX_MATRIX = gates.CXGate().to_matrix()


def cx_gate_matrix():
Expand Down
26 changes: 21 additions & 5 deletions qiskit/providers/basicaer/qasm_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
from qiskit.providers.basicaer.basicaerjob import BasicAerJob
from .exceptions import BasicAerError
from .basicaertools import single_gate_matrix
from .basicaertools import SINGLE_QUBIT_GATES
from .basicaertools import cx_gate_matrix
from .basicaertools import einsum_vecmul_index

Expand All @@ -56,7 +57,7 @@ class QasmSimulatorPy(BaseBackend):

DEFAULT_CONFIGURATION = {
'backend_name': 'qasm_simulator',
'backend_version': '2.0.0',
'backend_version': '2.1.0',
'n_qubits': min(24, MAX_QUBITS_MEMORY),
'url': 'https://github.com/Qiskit/qiskit-terra',
'simulator': True,
Expand All @@ -67,7 +68,7 @@ class QasmSimulatorPy(BaseBackend):
'max_shots': 65536,
'coupling_map': None,
'description': 'A python simulator for qasm experiments',
'basis_gates': ['u1', 'u2', 'u3', 'cx', 'id', 'unitary'],
'basis_gates': ['u1', 'u2', 'u3', 'rz', 'sx', 'x', 'cx', 'id', 'unitary'],
'gates': [
{
'name': 'u1',
Expand All @@ -84,14 +85,29 @@ class QasmSimulatorPy(BaseBackend):
'parameters': ['theta', 'phi', 'lambda'],
'qasm_def': 'gate u3(theta,phi,lambda) q { U(theta,phi,lambda) q; }'
},
{
'name': 'rz',
'parameters': ['phi'],
'qasm_def': 'gate rz(phi) q { U(0,0,phi) q; }'
},
{
'name': 'sx',
'parameters': [],
'qasm_def': 'gate sx(phi) q { U(pi/2,7*pi/2,pi/2) q; }'
},
{
'name': 'x',
'parameters': [],
'qasm_def': 'gate x q { U(pi,7*pi/2,pi/2) q; }'
},
{
'name': 'cx',
'parameters': ['c', 't'],
'parameters': [],
'qasm_def': 'gate cx c,t { CX c,t; }'
},
{
'name': 'id',
'parameters': ['a'],
'parameters': [],
'qasm_def': 'gate id a { U(0,0,0) a; }'
},
{
Expand Down Expand Up @@ -512,7 +528,7 @@ def run_experiment(self, experiment):
qubits = operation.qubits
gate = operation.params[0]
self._add_unitary(gate, qubits)
elif operation.name in ('U', 'u1', 'u2', 'u3'):
elif operation.name in SINGLE_QUBIT_GATES:
params = getattr(operation, 'params', None)
qubit = operation.qubits[0]
gate = single_gate_matrix(operation.name, params)
Expand Down
23 changes: 19 additions & 4 deletions qiskit/providers/basicaer/statevector_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class StatevectorSimulatorPy(QasmSimulatorPy):

DEFAULT_CONFIGURATION = {
'backend_name': 'statevector_simulator',
'backend_version': '1.0.0',
'backend_version': '1.1.0',
'n_qubits': min(24, MAX_QUBITS_MEMORY),
'url': 'https://github.com/Qiskit/qiskit-terra',
'simulator': True,
Expand All @@ -51,7 +51,7 @@ class StatevectorSimulatorPy(QasmSimulatorPy):
'max_shots': 65536,
'coupling_map': None,
'description': 'A Python statevector simulator for qobj files',
'basis_gates': ['u1', 'u2', 'u3', 'cx', 'id', 'unitary'],
'basis_gates': ['u1', 'u2', 'u3', 'rz', 'sx', 'x', 'cx', 'id', 'unitary'],
'gates': [
{
'name': 'u1',
Expand All @@ -68,14 +68,29 @@ class StatevectorSimulatorPy(QasmSimulatorPy):
'parameters': ['theta', 'phi', 'lambda'],
'qasm_def': 'gate u3(theta,phi,lambda) q { U(theta,phi,lambda) q; }'
},
{
'name': 'rz',
'parameters': ['phi'],
'qasm_def': 'gate rz(phi) q { U(0,0,phi) q; }'
},
{
'name': 'sx',
'parameters': [],
'qasm_def': 'gate sx(phi) q { U(pi/2,7*pi/2,pi/2) q; }'
},
{
'name': 'x',
'parameters': [],
'qasm_def': 'gate x q { U(pi,7*pi/2,pi/2) q; }'
},
{
'name': 'cx',
'parameters': ['c', 't'],
'parameters': [],
'qasm_def': 'gate cx c,t { CX c,t; }'
},
{
'name': 'id',
'parameters': ['a'],
'parameters': [],
'qasm_def': 'gate id a { U(0,0,0) a; }'
},
{
Expand Down
26 changes: 21 additions & 5 deletions qiskit/providers/basicaer/unitary_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
from qiskit.result import Result
from .exceptions import BasicAerError
from .basicaertools import single_gate_matrix
from .basicaertools import SINGLE_QUBIT_GATES
from .basicaertools import cx_gate_matrix
from .basicaertools import einsum_matmul_index

Expand All @@ -55,7 +56,7 @@ class UnitarySimulatorPy(BaseBackend):

DEFAULT_CONFIGURATION = {
'backend_name': 'unitary_simulator',
'backend_version': '1.0.0',
'backend_version': '1.1.0',
'n_qubits': min(24, MAX_QUBITS_MEMORY),
'url': 'https://github.com/Qiskit/qiskit-terra',
'simulator': True,
Expand All @@ -66,7 +67,7 @@ class UnitarySimulatorPy(BaseBackend):
'max_shots': 65536,
'coupling_map': None,
'description': 'A python simulator for unitary matrix corresponding to a circuit',
'basis_gates': ['u1', 'u2', 'u3', 'cx', 'id', 'unitary'],
'basis_gates': ['u1', 'u2', 'u3', 'rz', 'sx', 'x', 'cx', 'id', 'unitary'],
'gates': [
{
'name': 'u1',
Expand All @@ -83,14 +84,29 @@ class UnitarySimulatorPy(BaseBackend):
'parameters': ['theta', 'phi', 'lambda'],
'qasm_def': 'gate u3(theta,phi,lambda) q { U(theta,phi,lambda) q; }'
},
{
'name': 'rz',
'parameters': ['phi'],
'qasm_def': 'gate rz(phi) q { U(0,0,phi) q; }'
},
{
'name': 'sx',
'parameters': [],
'qasm_def': 'gate sx(phi) q { U(pi/2,7*pi/2,pi/2) q; }'
},
{
'name': 'x',
'parameters': [],
'qasm_def': 'gate x q { U(pi,7*pi/2,pi/2) q; }'
},
{
'name': 'cx',
'parameters': ['c', 't'],
'parameters': [],
'qasm_def': 'gate cx c,t { CX c,t; }'
},
{
'name': 'id',
'parameters': ['a'],
'parameters': [],
'qasm_def': 'gate id a { U(0,0,0) a; }'
},
{
Expand Down Expand Up @@ -317,7 +333,7 @@ def run_experiment(self, experiment):
gate = operation.params[0]
self._add_unitary(gate, qubits)
# Check if single gate
elif operation.name in ('U', 'u1', 'u2', 'u3'):
elif operation.name in SINGLE_QUBIT_GATES:
params = getattr(operation, 'params', None)
qubit = operation.qubits[0]
gate = single_gate_matrix(operation.name, params)
Expand Down
11 changes: 5 additions & 6 deletions test/python/compiler/test_transpiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
from qiskit.circuit import Parameter, Gate, Qubit, Clbit
from qiskit.compiler import transpile
from qiskit.converters import circuit_to_dag
from qiskit.circuit.library import CXGate, U3Gate, U2Gate, U1Gate, RXGate, RYGate
from qiskit.circuit.library import CXGate, U3Gate, U2Gate, U1Gate, RXGate, RYGate, RZGate
from qiskit.test import QiskitTestCase, Path
from qiskit.test.mock import FakeMelbourne, FakeRueschlikon, FakeAlmaden
from qiskit.transpiler import Layout, CouplingMap
Expand Down Expand Up @@ -450,9 +450,8 @@ def test_parameterized_circuit_for_simulator(self):

transpiled_qc = transpile(qc, backend=BasicAer.get_backend('qasm_simulator'))

expected_qc = QuantumCircuit(qr, global_phase=-1 * theta / 2.0)
expected_qc.append(U1Gate(theta), [qr[0]])

expected_qc = QuantumCircuit(qr)
expected_qc.append(RZGate(theta), [qr[0]])
self.assertEqual(expected_qc, transpiled_qc)

def test_parameterized_circuit_for_device(self):
Expand Down Expand Up @@ -484,8 +483,8 @@ def test_parameter_expression_circuit_for_simulator(self):

transpiled_qc = transpile(qc, backend=BasicAer.get_backend('qasm_simulator'))

expected_qc = QuantumCircuit(qr, global_phase=-1 * square / 2.0)
expected_qc.append(U1Gate(square), [qr[0]])
expected_qc = QuantumCircuit(qr)
expected_qc.append(RZGate(square), [qr[0]])
self.assertEqual(expected_qc, transpiled_qc)

def test_parameter_expression_circuit_for_device(self):
Expand Down

0 comments on commit edd76c7

Please sign in to comment.