From 7a50b4cbb419a6dd8fe639cebd2dab2896df240b Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Thu, 4 Jun 2020 15:16:58 -0400 Subject: [PATCH 01/38] minor commit --- .../standard_gates/equivalence_library.py | 4 +- qiskit/circuit/library/standard_gates/rz.py | 12 +-- qiskit/circuit/library/standard_gates/u1.py | 11 +++ qiskit/circuit/quantumcircuit.py | 25 ++++++ test/python/circuit/test_gate_definitions.py | 89 +++++++++++++++++-- 5 files changed, 127 insertions(+), 14 deletions(-) diff --git a/qiskit/circuit/library/standard_gates/equivalence_library.py b/qiskit/circuit/library/standard_gates/equivalence_library.py index 1ceba4e5cd02..1accc2402367 100644 --- a/qiskit/circuit/library/standard_gates/equivalence_library.py +++ b/qiskit/circuit/library/standard_gates/equivalence_library.py @@ -294,6 +294,8 @@ theta = Parameter('theta') def_rz = QuantumCircuit(q) def_rz.append(U1Gate(theta), [q[0]], []) +import ipdb;ipdb.set_trace() +def_rz.phase = theta / 2 _sel.add_equivalence(RZGate(theta), def_rz) # CRZGate @@ -413,7 +415,7 @@ def_tdg.append(U1Gate(-pi / 4), [q[0]], []) _sel.add_equivalence(TdgGate(), def_tdg) -# U1Gate +# U2Gate q = QuantumRegister(1, 'q') phi = Parameter('phi') diff --git a/qiskit/circuit/library/standard_gates/rz.py b/qiskit/circuit/library/standard_gates/rz.py index 8ee5b7c97c7f..994b8d2d5c4d 100644 --- a/qiskit/circuit/library/standard_gates/rz.py +++ b/qiskit/circuit/library/standard_gates/rz.py @@ -101,12 +101,12 @@ def inverse(self): # TODO: this is the correct matrix however the control mechanism # cannot distinguish U1 and RZ yet. - # def to_matrix(self): - # """Return a numpy.array for the RZ gate.""" - # import numpy - # lam = float(self.params[0]) - # return numpy.array([[numpy.exp(-1j * lam / 2), 0], - # [0, numpy.exp(1j * lam / 2)]], dtype=complex) + def to_matrix(self): + """Return a numpy.array for the RZ gate.""" + import numpy as np + lam = float(self.params[0]) + return np.array([[np.exp(-1j * lam / 2), 0], + [0, np.exp(1j * lam / 2)]], dtype=complex) class CRZMeta(type): diff --git a/qiskit/circuit/library/standard_gates/u1.py b/qiskit/circuit/library/standard_gates/u1.py index 4c9f5bb18204..95c87914a321 100644 --- a/qiskit/circuit/library/standard_gates/u1.py +++ b/qiskit/circuit/library/standard_gates/u1.py @@ -230,6 +230,17 @@ def inverse(self): # [0, 0, 0, eith]], # dtype=complex) + # TODO: this is the correct definition but has a global phase with respect + # to the decomposition above. Restore after allowing phase on circuits. + def to_matrix(self): + """Return a numpy.array for the CU1 gate.""" + eith = numpy.exp(1j * self.params[0]) + return numpy.array([[1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, eith]], + dtype=complex) + class Cu1Gate(CU1Gate, metaclass=CU1Meta): """The deprecated CU1Gate class.""" diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index efa7af9b725e..8a1af8e8fa34 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -167,6 +167,7 @@ def __init__(self, *regs, name=None): self._parameter_table = ParameterTable() self._layout = None + self._phase = None @property def data(self): @@ -1420,6 +1421,30 @@ def from_qasm_str(qasm_str): qasm = Qasm(data=qasm_str) return _circuit_from_qasm(qasm) + @property + def phase(self): + """Return the phase of the gate.""" + return self._phase + + @phase.setter + def phase(self, angle): + """Set the phase of the gate. + + Args: + angle (float, ParameterExpression) + """ + if isinstance(angle, ParameterExpression): + self._phase = angle + else: + # Set the phase to the [-2 * pi, 2 * pi] interval + angle = float(angle) + if not angle: + self._phase = 0 + elif angle < 0: + self._phase = angle % (-2 * math.pi) + else: + self._phase = angle % (2 * math.pi) + @property def parameters(self): """Convenience function to get the parameters defined in the parameter table.""" diff --git a/test/python/circuit/test_gate_definitions.py b/test/python/circuit/test_gate_definitions.py index 02673e5fc669..a18cfb4d8fd5 100644 --- a/test/python/circuit/test_gate_definitions.py +++ b/test/python/circuit/test_gate_definitions.py @@ -20,7 +20,7 @@ from qiskit import QuantumCircuit from qiskit.quantum_info import Operator from qiskit.test import QiskitTestCase -from qiskit.circuit import ParameterVector +from qiskit.circuit import ParameterVector, Gate, ControlledGate from qiskit.circuit.library import ( @@ -39,7 +39,8 @@ class TestGateDefinitions(QiskitTestCase): """Test the decomposition of a gate in terms of other gates - yields the same matrix as the hardcoded matrix definition.""" + yields the equivalent matrix as the hardcoded matrix definition + up to a global phase.""" def test_ch_definition(self): # TODO: expand this to all gates """Test ch gate matrix and definition. @@ -113,17 +114,90 @@ def test_cx_definition(self): decomposed_circ = circ.decompose() self.assertTrue(Operator(circ).equiv(Operator(decomposed_circ))) +class TestGateDefinitionEqual(QiskitTestCase): + """Test the decomposition of a gate in terms of other gates + yields the same matrix as the hardcoded matrix definition.""" + @classmethod + def setUpClass(cls): + + class_list = Gate.__subclasses__() + ControlledGate.__subclasses__() + exclude = {'ControlledGate', 'DiagonalGate', 'UCGate', 'MCGupDiag', + 'MCU1Gate', 'UnitaryGate', 'HamiltonianGate', + 'UCPauliRotGate', 'SingleQubitUnitary', 'MCXGate'} + cls._gate_classes = [] + for aclass in class_list: + #if aclass.__name__ not in exclude: + if aclass.__name__ == 'RZGate': + cls._gate_classes.append(aclass) + + def test_definition_equal(self): + def has_to_matrix(gate): + try: + gate.to_matrix() + except: + return False + else: + return True + + for gate_class in self._gate_classes: + print(gate_class) + n_params = len(_get_free_params(gate_class)) + params = [0.1 * i for i in range(1, n_params+1)] + if gate_class.__name__ in ['MSGate']: + params[0] = 2 + elif gate_class in ['MCU1Gate']: + params[1] = 2 + # elif issubclass(gate_class, 'MCXGate'): + # params = [5] + gate = gate_class(*params) + + if has_to_matrix(gate): + pass + else: + print(f'Skipping {gate_class}') + continue + equiv_lib_list = std_eqlib.get_entry(gate) + for ieq, equivalency in enumerate(equiv_lib_list): + with self.subTest(msg=gate.name + '_' + str(ieq)): + print(gate_class) + circ = QuantumCircuit(gate.num_qubits) + circ.append(gate, circ.qregs[0]) + decomposed_circ = circ.decompose() + print(circ) + print(equivalency) + #import trace + #tracer1 = trace.Trace(countcallers=1) + import numpy as np + np.set_printoptions(linewidth=200, precision=2) + op1 = Operator(gate) # Don't use circ since that won't call to_matrix of gate. + #tracer1.runfunc(Operator, circ) + #tracer2 = trace.Trace(countcallers=1) + op2 = Operator(equivalency) + #tracer2.runfunc(Operator, equivalency) + import ipdb;ipdb.set_trace() + + self.assertEqual(op1, op2) + + def get_unitary_multiplier(A, B): + """Get constant multiplier between two matrices. If not a multiple, + return None. + + A (ndarray): First matrix (assumed unitary). + B (ndarray): Second matrix (assumed unitary). + @ddt class TestStandardEquivalenceLibrary(QiskitTestCase): """Standard Extension Test.""" + # @data( + # HGate, CHGate, IGate, RGate, RXGate, CRXGate, RYGate, CRYGate, RZGate, + # CRZGate, SGate, SdgGate, CSwapGate, TGate, TdgGate, U1Gate, CU1Gate, + # U2Gate, U3Gate, CU3Gate, XGate, CXGate, CCXGate, YGate, CYGate, + # ZGate, CZGate, RYYGate + # ) @data( - HGate, CHGate, IGate, RGate, RXGate, CRXGate, RYGate, CRYGate, RZGate, - CRZGate, SGate, SdgGate, CSwapGate, TGate, TdgGate, U1Gate, CU1Gate, - U2Gate, U3Gate, CU3Gate, XGate, CXGate, CCXGate, YGate, CYGate, - ZGate, CZGate, RYYGate - ) + HGate) def test_definition_parameters(self, gate_class): """Verify decompositions from standard equivalence library match definitions.""" n_params = len(_get_free_params(gate_class)) @@ -156,5 +230,6 @@ def test_definition_parameters(self, gate_class): param_qc.append(param_gate, param_qc.qregs[0]) float_qc.append(float_gate, float_qc.qregs[0]) + import ipdb;ipdb.set_trace() self.assertEqual(param_entry[0], param_qc.decompose()) self.assertEqual(float_entry[0], float_qc.decompose()) From bc056a35a7973b8bb700023f8d6cfa12509649f8 Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Thu, 11 Jun 2020 04:39:11 -0400 Subject: [PATCH 02/38] rz agrees with u1 --- qiskit/circuit/equivalence.py | 1 - .../standard_gates/equivalence_library.py | 4 +- qiskit/circuit/quantumcircuit.py | 11 ++- qiskit/quantum_info/operators/operator.py | 8 +- test/python/circuit/test_gate_definitions.py | 90 ++++++------------- 5 files changed, 42 insertions(+), 72 deletions(-) diff --git a/qiskit/circuit/equivalence.py b/qiskit/circuit/equivalence.py index b1701714e5b4..d4e905e085bd 100644 --- a/qiskit/circuit/equivalence.py +++ b/qiskit/circuit/equivalence.py @@ -258,7 +258,6 @@ def _raise_if_shape_mismatch(gate, circuit): def _rebind_equiv(equiv, query_params): equiv_params, equiv_circuit = equiv - param_map = dict(zip(equiv_params, query_params)) equiv = equiv_circuit.assign_parameters(param_map, inplace=False) diff --git a/qiskit/circuit/library/standard_gates/equivalence_library.py b/qiskit/circuit/library/standard_gates/equivalence_library.py index 1accc2402367..06f99ae55ad7 100644 --- a/qiskit/circuit/library/standard_gates/equivalence_library.py +++ b/qiskit/circuit/library/standard_gates/equivalence_library.py @@ -293,9 +293,7 @@ q = QuantumRegister(1, 'q') theta = Parameter('theta') def_rz = QuantumCircuit(q) -def_rz.append(U1Gate(theta), [q[0]], []) -import ipdb;ipdb.set_trace() -def_rz.phase = theta / 2 +def_rz.append(U1Gate(theta), [q[0]], [], phase=-theta/2) _sel.add_equivalence(RZGate(theta), def_rz) # CRZGate diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index 8a1af8e8fa34..ebd11ed548fe 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -167,7 +167,7 @@ def __init__(self, *regs, name=None): self._parameter_table = ParameterTable() self._layout = None - self._phase = None + self._phase = 0 @property def data(self): @@ -546,7 +546,7 @@ def cbit_argument_conversion(self, clbit_representation): """ return QuantumCircuit._bit_argument_conversion(clbit_representation, self.clbits) - def append(self, instruction, qargs=None, cargs=None): + def append(self, instruction, qargs=None, cargs=None, phase=0): """Append one or more instructions to the end of the circuit, modifying the circuit in place. Expands qargs and cargs. @@ -554,6 +554,7 @@ def append(self, instruction, qargs=None, cargs=None): instruction (qiskit.circuit.Instruction): Instruction instance to append qargs (list(argument)): qubits to attach instruction to cargs (list(argument)): clbits to attach instruction to + phase (float): The global phase in radians of instruction. Returns: qiskit.circuit.Instruction: a handle to the instruction that was just added @@ -579,6 +580,7 @@ def append(self, instruction, qargs=None, cargs=None): instructions = InstructionSet() for (qarg, carg) in instruction.broadcast_arguments(expanded_qargs, expanded_cargs): instructions.add(self._append(instruction, qarg, carg), qarg, carg) + self.phase += phase return instructions def _append(self, instruction, qargs, cargs): @@ -1584,6 +1586,9 @@ def _bind_parameter(self, parameter, value): # instructions), search the definition for instances of the # parameter which also need to be bound. self._rebind_definition(instr, parameter, value) + # bind circuit's phase + if isinstance(self.phase, ParameterExpression): + self.phase = self.phase.bind({parameter: value}) def _substitute_parameter(self, old_parameter, new_parameter_expr): """Substitute an existing parameter in all circuit instructions and the parameter table.""" @@ -1595,6 +1600,8 @@ def _substitute_parameter(self, old_parameter, new_parameter_expr): entry = self._parameter_table.pop(old_parameter) for new_parameter in new_parameter_expr.parameters: self._parameter_table[new_parameter] = entry + if isinstance(self.phase, ParameterExpression): + self.phase = self.phase.subs({old_parameter: new_parameter_expr}) def _rebind_definition(self, instruction, parameter, value): if instruction._definition: diff --git a/qiskit/quantum_info/operators/operator.py b/qiskit/quantum_info/operators/operator.py index 2d2b9000932b..c6a79e411e91 100644 --- a/qiskit/quantum_info/operators/operator.py +++ b/qiskit/quantum_info/operators/operator.py @@ -485,11 +485,15 @@ def _einsum_matmul(cls, tensor, mat, indices, shift=0, right_mul=False): @classmethod def _init_instruction(cls, instruction): """Convert a QuantumCircuit or Instruction to an Operator.""" + # pylint: disable=import-outside-toplevel, cyclic-import + from qiskit.quantum_info.operators.scalar_op import ScalarOp + # Initialize an identity operator of the correct size of the circuit + op = Operator(np.eye(2 ** instruction.num_qubits)) # Convert circuit to an instruction if isinstance(instruction, QuantumCircuit): + if instruction.phase: + op *= ScalarOp(op.dim[0], np.exp(1j * float(instruction.phase))) instruction = instruction.to_instruction() - # Initialize an identity operator of the correct size of the circuit - op = Operator(np.eye(2 ** instruction.num_qubits)) op._append_instruction(instruction) return op diff --git a/test/python/circuit/test_gate_definitions.py b/test/python/circuit/test_gate_definitions.py index a18cfb4d8fd5..983808092d29 100644 --- a/test/python/circuit/test_gate_definitions.py +++ b/test/python/circuit/test_gate_definitions.py @@ -15,6 +15,7 @@ """Test hardcoded decomposition rules and matrix definitions for standard gates.""" +import numpy as np from ddt import ddt, data from qiskit import QuantumCircuit @@ -117,87 +118,49 @@ def test_cx_definition(self): class TestGateDefinitionEqual(QiskitTestCase): """Test the decomposition of a gate in terms of other gates yields the same matrix as the hardcoded matrix definition.""" + @classmethod def setUpClass(cls): - + class_list = Gate.__subclasses__() + ControlledGate.__subclasses__() exclude = {'ControlledGate', 'DiagonalGate', 'UCGate', 'MCGupDiag', 'MCU1Gate', 'UnitaryGate', 'HamiltonianGate', 'UCPauliRotGate', 'SingleQubitUnitary', 'MCXGate'} cls._gate_classes = [] for aclass in class_list: - #if aclass.__name__ not in exclude: - if aclass.__name__ == 'RZGate': + if aclass.__name__ not in exclude: cls._gate_classes.append(aclass) - def test_definition_equal(self): - def has_to_matrix(gate): - try: - gate.to_matrix() - except: - return False - else: - return True - + def test_equivalence_phase(self): + """Test that the equivalent circuits from the equivalency_library + have equal matrix representations""" for gate_class in self._gate_classes: - print(gate_class) - n_params = len(_get_free_params(gate_class)) - params = [0.1 * i for i in range(1, n_params+1)] - if gate_class.__name__ in ['MSGate']: - params[0] = 2 - elif gate_class in ['MCU1Gate']: - params[1] = 2 - # elif issubclass(gate_class, 'MCXGate'): - # params = [5] - gate = gate_class(*params) - - if has_to_matrix(gate): - pass - else: - print(f'Skipping {gate_class}') - continue - equiv_lib_list = std_eqlib.get_entry(gate) - for ieq, equivalency in enumerate(equiv_lib_list): - with self.subTest(msg=gate.name + '_' + str(ieq)): - print(gate_class) - circ = QuantumCircuit(gate.num_qubits) - circ.append(gate, circ.qregs[0]) - decomposed_circ = circ.decompose() - print(circ) - print(equivalency) - #import trace - #tracer1 = trace.Trace(countcallers=1) - import numpy as np - np.set_printoptions(linewidth=200, precision=2) - op1 = Operator(gate) # Don't use circ since that won't call to_matrix of gate. - #tracer1.runfunc(Operator, circ) - #tracer2 = trace.Trace(countcallers=1) - op2 = Operator(equivalency) - #tracer2.runfunc(Operator, equivalency) - import ipdb;ipdb.set_trace() - - self.assertEqual(op1, op2) - - def get_unitary_multiplier(A, B): - """Get constant multiplier between two matrices. If not a multiple, - return None. - - A (ndarray): First matrix (assumed unitary). - B (ndarray): Second matrix (assumed unitary). + with self.subTest(i=gate_class): + n_params = len(_get_free_params(gate_class)) + params = [0.1 * i for i in range(1, n_params+1)] + if gate_class.__name__ in ['MSGate']: + params[0] = 2 + elif gate_class in ['MCU1Gate']: + params[1] = 2 + gate = gate_class(*params) + equiv_lib_list = std_eqlib.get_entry(gate) + for ieq, equivalency in enumerate(equiv_lib_list): + with self.subTest(msg=gate.name + '_' + str(ieq)): + op1 = Operator(gate) + op2 = Operator(equivalency) + self.assertEqual(op1, op2) @ddt class TestStandardEquivalenceLibrary(QiskitTestCase): """Standard Extension Test.""" - # @data( - # HGate, CHGate, IGate, RGate, RXGate, CRXGate, RYGate, CRYGate, RZGate, - # CRZGate, SGate, SdgGate, CSwapGate, TGate, TdgGate, U1Gate, CU1Gate, - # U2Gate, U3Gate, CU3Gate, XGate, CXGate, CCXGate, YGate, CYGate, - # ZGate, CZGate, RYYGate - # ) @data( - HGate) + HGate, CHGate, IGate, RGate, RXGate, CRXGate, RYGate, CRYGate, RZGate, + CRZGate, SGate, SdgGate, CSwapGate, TGate, TdgGate, U1Gate, CU1Gate, + U2Gate, U3Gate, CU3Gate, XGate, CXGate, CCXGate, YGate, CYGate, + ZGate, CZGate, RYYGate + ) def test_definition_parameters(self, gate_class): """Verify decompositions from standard equivalence library match definitions.""" n_params = len(_get_free_params(gate_class)) @@ -230,6 +193,5 @@ def test_definition_parameters(self, gate_class): param_qc.append(param_gate, param_qc.qregs[0]) float_qc.append(float_gate, float_qc.qregs[0]) - import ipdb;ipdb.set_trace() self.assertEqual(param_entry[0], param_qc.decompose()) self.assertEqual(float_entry[0], float_qc.decompose()) From 174a9f7aa8ebb09891463c2ed79548d23ebc7725 Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Tue, 16 Jun 2020 13:11:56 -0400 Subject: [PATCH 03/38] synthesis tests pass --- qiskit/circuit/quantumcircuit.py | 16 +++++----- .../synthesis/one_qubit_decompose.py | 31 ++++++++++++------- test/python/circuit/test_gate_definitions.py | 2 +- test/python/quantum_info/test_synthesis.py | 2 +- 4 files changed, 30 insertions(+), 21 deletions(-) diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index ebd11ed548fe..2d32f42cdc8c 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -134,7 +134,7 @@ class QuantumCircuit: header = "OPENQASM 2.0;" extension_lib = "include \"qelib1.inc\";" - def __init__(self, *regs, name=None): + def __init__(self, *regs, name=None, phase=0): if any([not isinstance(reg, (QuantumRegister, ClassicalRegister)) for reg in regs]): try: regs = tuple(int(reg) for reg in regs) @@ -168,6 +168,7 @@ def __init__(self, *regs, name=None): self._layout = None self._phase = 0 + self.phase = phase @property def data(self): @@ -272,7 +273,7 @@ def inverse(self): CircuitError: if the circuit cannot be inverted. """ inverse_circ = QuantumCircuit(*self.qregs, *self.cregs, - name=self.name + '_dg') + name=self.name + '_dg', phase=-self.phase) for inst, qargs, cargs in reversed(self._data): inverse_circ._append(inst.inverse(), qargs, cargs) @@ -288,7 +289,8 @@ def repeat(self, reps): QuantumCircuit: A circuit containing ``reps`` repetitions of this circuit. """ repeated_circ = QuantumCircuit(*self.qregs, *self.cregs, - name=self.name + '**{}'.format(reps)) + name=self.name + '**{}'.format(reps), + phase=reps * self.phase) # benefit of appending instructions: decomposing shows the subparts, i.e. the power # is actually `reps` times this circuit, and it is currently much faster than `compose`. @@ -1425,12 +1427,12 @@ def from_qasm_str(qasm_str): @property def phase(self): - """Return the phase of the gate.""" + """Return the phase of the circuit.""" return self._phase @phase.setter def phase(self, angle): - """Set the phase of the gate. + """Set the phase of the circuit. Args: angle (float, ParameterExpression) @@ -1443,9 +1445,9 @@ def phase(self, angle): if not angle: self._phase = 0 elif angle < 0: - self._phase = angle % (-2 * math.pi) + self._phase = angle % (-2 * np.pi) else: - self._phase = angle % (2 * math.pi) + self._phase = angle % (2 * np.pi) @property def parameters(self): diff --git a/qiskit/quantum_info/synthesis/one_qubit_decompose.py b/qiskit/quantum_info/synthesis/one_qubit_decompose.py index fa681af2bd41..dd7509393e7d 100644 --- a/qiskit/quantum_info/synthesis/one_qubit_decompose.py +++ b/qiskit/quantum_info/synthesis/one_qubit_decompose.py @@ -119,8 +119,9 @@ def __call__(self, if not is_unitary_matrix(unitary): raise QiskitError("OneQubitEulerDecomposer: " "input matrix is not unitary.") - theta, phi, lam, _ = self._params(unitary) + theta, phi, lam, phase = self._params(unitary) circuit = self._circuit(theta, phi, lam, + phase=phase, simplify=simplify, atol=atol) return circuit @@ -236,16 +237,17 @@ def _params_u1x(mat): def _circuit_zyz(theta, phi, lam, + phase=0, simplify=True, atol=DEFAULT_ATOL): circuit = QuantumCircuit(1) if simplify and np.isclose(theta, 0.0, atol=atol): - circuit.append(RZGate(phi + lam), [0]) + circuit.append(RZGate(phi + lam), [0], phase=phase) return circuit if not simplify or not np.isclose(lam, 0.0, atol=atol): circuit.append(RZGate(lam), [0]) if not simplify or not np.isclose(theta, 0.0, atol=atol): - circuit.append(RYGate(theta), [0]) + circuit.append(RYGate(theta), [0], phase=phase) if not simplify or not np.isclose(phi, 0.0, atol=atol): circuit.append(RZGate(phi), [0]) return circuit @@ -254,17 +256,18 @@ def _circuit_zyz(theta, def _circuit_zxz(theta, phi, lam, + phase=0, simplify=False, atol=DEFAULT_ATOL): if simplify and np.isclose(theta, 0.0, atol=atol): circuit = QuantumCircuit(1) - circuit.append(RZGate(phi + lam), [0]) + circuit.append(RZGate(phi + lam), [0], phase=phase) return circuit circuit = QuantumCircuit(1) if not simplify or not np.isclose(lam, 0.0, atol=atol): circuit.append(RZGate(lam), [0]) if not simplify or not np.isclose(theta, 0.0, atol=atol): - circuit.append(RXGate(theta), [0]) + circuit.append(RXGate(theta), [0], phase=phase) if not simplify or not np.isclose(phi, 0.0, atol=atol): circuit.append(RZGate(phi), [0]) return circuit @@ -273,16 +276,17 @@ def _circuit_zxz(theta, def _circuit_xyx(theta, phi, lam, + phase=0, simplify=True, atol=DEFAULT_ATOL): circuit = QuantumCircuit(1) if simplify and np.isclose(theta, 0.0, atol=atol): - circuit.append(RXGate(phi + lam), [0]) + circuit.append(RXGate(phi + lam), [0], phase=phase) return circuit if not simplify or not np.isclose(lam, 0.0, atol=atol): circuit.append(RXGate(lam), [0]) if not simplify or not np.isclose(theta, 0.0, atol=atol): - circuit.append(RYGate(theta), [0]) + circuit.append(RYGate(theta), [0], phase=phase) if not simplify or not np.isclose(phi, 0.0, atol=atol): circuit.append(RXGate(phi), [0]) return circuit @@ -291,17 +295,19 @@ def _circuit_xyx(theta, def _circuit_u3(theta, phi, lam, + phase=0, simplify=True, atol=DEFAULT_ATOL): # pylint: disable=unused-argument circuit = QuantumCircuit(1) - circuit.append(U3Gate(theta, phi, lam), [0]) + circuit.append(U3Gate(theta, phi, lam), [0], phase=phase) return circuit @staticmethod def _circuit_u1x(theta, phi, lam, + phase=0, simplify=True, atol=DEFAULT_ATOL): # Shift theta and phi so decomposition is @@ -312,17 +318,17 @@ def _circuit_u1x(theta, if simplify and np.isclose(abs(theta), np.pi, atol=atol): # Zero X90 gate decomposition circuit = QuantumCircuit(1) - circuit.append(U1Gate(lam + phi + theta), [0]) + circuit.append(U1Gate(lam + phi + theta), [0], phase=phase) return circuit if simplify and np.isclose(abs(theta), np.pi/2, atol=atol): # Single X90 gate decomposition - circuit = QuantumCircuit(1) + circuit = QuantumCircuit(1, phase=phase) circuit.append(U1Gate(lam + theta), [0]) circuit.append(RXGate(np.pi / 2), [0]) circuit.append(U1Gate(phi + theta), [0]) return circuit # General two-X90 gate decomposition - circuit = QuantumCircuit(1) + circuit = QuantumCircuit(1, phase=phase) circuit.append(U1Gate(lam), [0]) circuit.append(RXGate(np.pi / 2), [0]) circuit.append(U1Gate(theta), [0]) @@ -334,9 +340,10 @@ def _circuit_u1x(theta, def _circuit_rr(theta, phi, lam, + phase=0, simplify=True, atol=DEFAULT_ATOL): - circuit = QuantumCircuit(1) + circuit = QuantumCircuit(1, phase=phase) if not simplify or not np.isclose(theta, -np.pi, atol=atol): circuit.append(RGate(theta + np.pi, np.pi / 2 - lam), [0]) circuit.append(RGate(-np.pi, 0.5 * (phi - lam + np.pi)), [0]) diff --git a/test/python/circuit/test_gate_definitions.py b/test/python/circuit/test_gate_definitions.py index 983808092d29..c3f314366d25 100644 --- a/test/python/circuit/test_gate_definitions.py +++ b/test/python/circuit/test_gate_definitions.py @@ -115,7 +115,7 @@ def test_cx_definition(self): decomposed_circ = circ.decompose() self.assertTrue(Operator(circ).equiv(Operator(decomposed_circ))) -class TestGateDefinitionEqual(QiskitTestCase): +class TestGateEquivalenceEqual(QiskitTestCase): """Test the decomposition of a gate in terms of other gates yields the same matrix as the hardcoded matrix definition.""" diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index 3379964d6dbf..63a6b17706b1 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -114,7 +114,7 @@ class TestOneQubitEulerDecomposer(QiskitTestCase): def check_one_qubit_euler_angles(self, operator, basis='U3', tolerance=1e-12, - phase_equal=False): + phase_equal=True): """Check euler_angles_1q works for the given unitary""" decomposer = OneQubitEulerDecomposer(basis) with self.subTest(operator=operator): From 0a72b1c604e169c944c16cc505ffc83027eac8da Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Wed, 17 Jun 2020 21:28:29 -0400 Subject: [PATCH 04/38] passing tests except open controlled random unitary --- qiskit/circuit/add_control.py | 15 ++++ .../standard_gates/equivalence_library.py | 4 +- qiskit/circuit/library/standard_gates/ryy.py | 45 ++++------ qiskit/circuit/library/standard_gates/rz.py | 49 +++++++---- qiskit/circuit/library/standard_gates/rzx.py | 6 +- qiskit/circuit/library/standard_gates/u1.py | 20 +++-- qiskit/circuit/library/standard_gates/u3.py | 12 +-- qiskit/converters/circuit_to_dag.py | 1 + qiskit/converters/dag_to_circuit.py | 3 +- qiskit/dagcircuit/dagcircuit.py | 28 +++++++ test/python/circuit/test_controlled_gate.py | 11 +++ test/python/circuit/test_gate_definitions.py | 84 ++++++++++++++++++- 12 files changed, 212 insertions(+), 66 deletions(-) diff --git a/qiskit/circuit/add_control.py b/qiskit/circuit/add_control.py index df7b3a814d01..950488bc687f 100644 --- a/qiskit/circuit/add_control.py +++ b/qiskit/circuit/add_control.py @@ -127,8 +127,23 @@ def control(operation: Union[Gate, ControlledGate], qc.mcrz(operation.definition[0][0].params[0], q_control, q_target[0], use_basis_gates=True) else: + if operation.name == 'ryy': + # print(len(operation.definition)) + # operation.definition = operation.definition[:3] + from qiskit.quantum_info import Operator + bgate = _unroll_gate(operation, ['u1', 'u3', 'cx']) # now we have a bunch of single qubit rotation gates and cx + # if operation.name == 'ryy': + # import numpy as np + # np.set_printoptions(linewidth=200, precision=2, suppress=True) + # print(_gate_to_circuit(operation)) + # print(Operator(operation).data) + # print(Operator(bgate).data) + # print(_gate_to_circuit(bgate)) + # print(operation.to_matrix_hide()) + # print(np.allclose(operation.to_matrix_hide(), Operator(bgate).data)) + # import ipdb;ipdb.set_trace() for rule in bgate.definition: if rule[0].name == 'u3': theta, phi, lamb = rule[0].params diff --git a/qiskit/circuit/library/standard_gates/equivalence_library.py b/qiskit/circuit/library/standard_gates/equivalence_library.py index 06f99ae55ad7..c7e87ff7e785 100644 --- a/qiskit/circuit/library/standard_gates/equivalence_library.py +++ b/qiskit/circuit/library/standard_gates/equivalence_library.py @@ -275,7 +275,7 @@ q = QuantumRegister(2, 'q') theta = Parameter('theta') -def_ryy = QuantumCircuit(q) +def_ryy = QuantumCircuit(q, phase=theta / 2) for inst, qargs, cargs in [ (RXGate(pi / 2), [q[0]], []), (RXGate(pi / 2), [q[1]], []), @@ -293,7 +293,7 @@ q = QuantumRegister(1, 'q') theta = Parameter('theta') def_rz = QuantumCircuit(q) -def_rz.append(U1Gate(theta), [q[0]], [], phase=-theta/2) +def_rz.append(U1Gate(theta), [q[0]], [], phase=-theta / 2) _sel.add_equivalence(RZGate(theta), def_rz) # CRZGate diff --git a/qiskit/circuit/library/standard_gates/ryy.py b/qiskit/circuit/library/standard_gates/ryy.py index b039b0fa4d6b..244514c48ff9 100644 --- a/qiskit/circuit/library/standard_gates/ryy.py +++ b/qiskit/circuit/library/standard_gates/ryy.py @@ -75,25 +75,12 @@ def __init__(self, theta): def _define(self): """Calculate a subcircuit that implements this unitary.""" - from .x import CXGate - from .rx import RXGate - from .rz import RZGate - - definition = [] - q = QuantumRegister(2, 'q') - theta = self.params[0] - rule = [ - (RXGate(np.pi / 2), [q[0]], []), - (RXGate(np.pi / 2), [q[1]], []), - (CXGate(), [q[0], q[1]], []), - (RZGate(theta), [q[1]], []), - (CXGate(), [q[0], q[1]], []), - (RXGate(-np.pi / 2), [q[0]], []), - (RXGate(-np.pi / 2), [q[1]], []), - ] - for inst in rule: - definition.append(inst) - self.definition = definition + circ = self.decompositions[0] + gp = circ.phase / len(circ.qregs[0]) + if circ.phase: + circ.u3(np.pi, gp, gp - np.pi, circ.qregs[0]) + circ.x(circ.qregs[0]) + self.definition = circ.to_gate().definition def inverse(self): """Return inverse RYY gate (i.e. with the negative rotation angle).""" @@ -101,12 +88,14 @@ def inverse(self): # TODO: this is the correct matrix and is equal to the definition above, # however the control mechanism cannot distinguish U1 and RZ yet. - # def to_matrix(self): - # """Return a numpy.array for the RYY gate.""" - # theta = self.params[0] - # return np.exp(0.5j * theta) * np.array([ - # [np.cos(theta / 2), 0, 0, 1j * np.sin(theta / 2)], - # [0, np.cos(theta / 2), -1j * np.sin(theta / 2), 0], - # [0, -1j * np.sin(theta / 2), np.cos(theta / 2), 0], - # [1j * np.sin(theta / 2), 0, 0, np.cos(theta / 2)] - # ], dtype=complex) + def to_matrix_hide(self): + """Return a numpy.array for the RYY gate.""" + theta = self.params[0] + halfcos = np.cos(theta / 2) + halfsin = np.sin(theta / 2) + return np.exp(0.5j * theta) * np.array([ + [halfcos, 0, 0, 1j * halfsin], + [0, halfcos, -1j * halfsin, 0], + [0, -1j * halfsin, halfcos, 0], + [1j * halfsin, 0, 0, halfcos] + ], dtype=complex) diff --git a/qiskit/circuit/library/standard_gates/rz.py b/qiskit/circuit/library/standard_gates/rz.py index 994b8d2d5c4d..0d042e592f92 100644 --- a/qiskit/circuit/library/standard_gates/rz.py +++ b/qiskit/circuit/library/standard_gates/rz.py @@ -64,15 +64,22 @@ def _define(self): """ gate rz(phi) a { u1(phi) a; } """ - from .u1 import U1Gate - definition = [] - q = QuantumRegister(1, 'q') - rule = [ - (U1Gate(self.params[0]), [q[0]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + import numpy as np + circ = self.decompositions[0] + if circ.phase: + circ.u3(np.pi, circ.phase, circ.phase - np.pi, circ.qregs[0]) + circ.x(circ.qregs[0]) + self.definition = circ.to_gate().definition + + # from .u1 import U1Gate + # definition = [] + # q = QuantumRegister(1, 'q') + # rule = [ + # (U1Gate(self.params[0]), [q[0]], []) + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Return a (mutli-)controlled-RZ gate. @@ -101,7 +108,7 @@ def inverse(self): # TODO: this is the correct matrix however the control mechanism # cannot distinguish U1 and RZ yet. - def to_matrix(self): + def to_matrix_hide(self): """Return a numpy.array for the RZ gate.""" import numpy as np lam = float(self.params[0]) @@ -214,13 +221,21 @@ def inverse(self): # TODO: this is the correct definition but has a global phase with respect # to the decomposition above. Restore after allowing phase on circuits. # def to_matrix(self): - # """Return a numpy.array for the CRZ gate.""" - # arg = 1j * self.params[0] / 2 - # return numpy.array([[1, 0, 0, 0], - # [0, numpy.exp(-arg), 0, 0], - # [0, 0, 1, 0], - # [0, 0, 0, numpy.exp(arg)]], - # dtype=complex) + # """Return a numpy.array for the CRZ gate.""" + # import numpy + # arg = 1j * self.params[0] / 2 + # if self.ctrl_state: + # return numpy.array([[1, 0, 0, 0], + # [0, numpy.exp(-arg), 0, 0], + # [0, 0, 1, 0], + # [0, 0, 0, numpy.exp(arg)]], + # dtype=complex) + # else: + # return numpy.array([[numpy.exp(-arg), 0, 0, 0], + # [ 0, 1, 0, 0], + # [ 0, 0, numpy.exp(arg), 0], + # [ 0, 0, 0, 1]], + # dtype=complex) class CrzGate(CRZGate, metaclass=CRZMeta): diff --git a/qiskit/circuit/library/standard_gates/rzx.py b/qiskit/circuit/library/standard_gates/rzx.py index d1b756318d0d..ec6a397ad014 100644 --- a/qiskit/circuit/library/standard_gates/rzx.py +++ b/qiskit/circuit/library/standard_gates/rzx.py @@ -125,11 +125,12 @@ def _define(self): """ gate rzx(theta) a, b { h b; cx a, b; u1(theta) b; cx a, b; h b;} """ + from qiskit.circuit.library.standard_gates import U1Gate q = QuantumRegister(2, 'q') self.definition = [ (HGate(), [q[1]], []), (CXGate(), [q[0], q[1]], []), - (RZGate(self.params[0]), [q[1]], []), + (U1Gate(self.params[0]), [q[1]], []), # Should be RZGate (CXGate(), [q[0], q[1]], []), (HGate(), [q[1]], []) ] @@ -147,6 +148,7 @@ def inverse(self): # isin = 1j * numpy.sin(half_theta) # return numpy.array([[ cos, 0, -isin, 0], # [ 0, cos, 0, isin], - # [-1j*sin, 0, cos, 0], + # [-isin, 0, cos, 0], # [ 0, isin, 0, cos]], + # [0, 1j*halfsin, 0, halfcos]], # dtype=complex) diff --git a/qiskit/circuit/library/standard_gates/u1.py b/qiskit/circuit/library/standard_gates/u1.py index 95c87914a321..4d05116e00f2 100644 --- a/qiskit/circuit/library/standard_gates/u1.py +++ b/qiskit/circuit/library/standard_gates/u1.py @@ -234,12 +234,20 @@ def inverse(self): # to the decomposition above. Restore after allowing phase on circuits. def to_matrix(self): """Return a numpy.array for the CU1 gate.""" - eith = numpy.exp(1j * self.params[0]) - return numpy.array([[1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, 1, 0], - [0, 0, 0, eith]], - dtype=complex) + + eith = numpy.exp(1j * float(self.params[0])) + if self.ctrl_state: + return numpy.array([[1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, eith]], + dtype=complex) + else: + return numpy.array([[1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, eith, 0], + [0, 0, 0, 1]], + dtype=complex) class Cu1Gate(CU1Gate, metaclass=CU1Meta): diff --git a/qiskit/circuit/library/standard_gates/u3.py b/qiskit/circuit/library/standard_gates/u3.py index 221e444bc78f..90e80b9a4bdc 100644 --- a/qiskit/circuit/library/standard_gates/u3.py +++ b/qiskit/circuit/library/standard_gates/u3.py @@ -93,15 +93,11 @@ def to_matrix(self): """Return a Numpy.array for the U3 gate.""" theta, phi, lam = self.params theta, phi, lam = float(theta), float(phi), float(lam) + cos = numpy.cos(theta / 2) + sin = numpy.sin(theta / 2) return numpy.array([ - [ - numpy.cos(theta / 2), - -numpy.exp(1j * lam) * numpy.sin(theta / 2) - ], - [ - numpy.exp(1j * phi) * numpy.sin(theta / 2), - numpy.exp(1j * (phi + lam)) * numpy.cos(theta / 2) - ] + [ cos , -numpy.exp(1j * lam) * sin ], + [ numpy.exp(1j * phi) * sin, numpy.exp(1j * (phi + lam)) * cos ] ], dtype=complex) diff --git a/qiskit/converters/circuit_to_dag.py b/qiskit/converters/circuit_to_dag.py index eaac9e13e96b..5d70c896b6a7 100644 --- a/qiskit/converters/circuit_to_dag.py +++ b/qiskit/converters/circuit_to_dag.py @@ -47,6 +47,7 @@ def circuit_to_dag(circuit): """ dagcircuit = DAGCircuit() dagcircuit.name = circuit.name + dagcircuit.phase = circuit.phase for register in circuit.qregs: dagcircuit.add_qreg(register) for register in circuit.cregs: diff --git a/qiskit/converters/dag_to_circuit.py b/qiskit/converters/dag_to_circuit.py index 32e429559cf5..a3c4041eee0d 100644 --- a/qiskit/converters/dag_to_circuit.py +++ b/qiskit/converters/dag_to_circuit.py @@ -48,7 +48,8 @@ def dag_to_circuit(dag): """ name = dag.name or None - circuit = QuantumCircuit(*dag.qregs.values(), *dag.cregs.values(), name=name) + circuit = QuantumCircuit(*dag.qregs.values(), *dag.cregs.values(), name=name, + phase=dag.phase) for node in dag.topological_op_nodes(): # Get arguments for classical control (if any) diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index bac79bacef9a..647463f87efd 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -114,6 +114,8 @@ def __call__(self): self._gx = None self._USE_RX = None + self._phase = 0 + # Multigraph methods where retworkx API differs syntactically from networkx. def _add_multi_graph_node(self, node): # nx: requires manual node id handling. @@ -214,6 +216,32 @@ def node_counter(self): """ return len(self._multi_graph) + @property + def phase(self): + """Return the phase of the circuit.""" + return self._phase + + @phase.setter + def phase(self, angle): + """Set the phase of the circuit. + + Args: + angle (float, ParameterExpression) + """ + from qiskit.circuit.parameterexpression import ParameterExpression # needed? + if isinstance(angle, ParameterExpression): + self._phase = angle + else: + # Set the phase to the [-2 * pi, 2 * pi] interval + angle = float(angle) + if not angle: + self._phase = 0 + elif angle < 0: + self._phase = angle % (-2 * np.pi) + else: + self._phase = angle % (2 * np.pi) + + def remove_all_ops_named(self, opname): """Remove all operation nodes with the given name.""" for n in self.named_nodes(opname): diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index a9c89863e2ee..20a1ad810219 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -635,6 +635,8 @@ def test_open_controlled_unitary_z(self, num_ctrl_qubits, ctrl_state): umat = np.array([[1, 0], [0, -1]]) ugate = UnitaryGate(umat).control(num_ctrl_qubits, ctrl_state=ctrl_state) ref_mat = _compute_control_matrix(umat, num_ctrl_qubits, ctrl_state=ctrl_state) + np.set_printoptions(precision=2, linewidth=200, suppress=True) + import ipdb;ipdb.set_trace() self.assertTrue(matrix_equal(Operator(ugate).data, ref_mat)) @data(1, 2, 3) @@ -1027,8 +1029,17 @@ def test_controlled_standard_gates(self, num_ctrl_qubits, gate_class): base_mat = Operator(gate).data target_mat = _compute_control_matrix(base_mat, num_ctrl_qubits, ctrl_state=ctrl_state) + np.set_printoptions(precision=2, linewidth=200, suppress=True) + # if gate.name == 'ryy' and num_ctrl_qubits==1 and ctrl_state==1: + # print(gate_class) + # import ipdb;ipdb.set_trace() self.assertTrue(matrix_equal(Operator(cgate).data, target_mat, ignore_phase=True)) + def pgdef(self, gate): + for rule in gate.definition: + qubit_inds = [qubit.index for qubit in rule[1]] + params = np.array(rule[0].params) + print(f'{rule[0].name:5s} {str(qubit_inds):8s} {params} ') @ddt class TestDeprecatedGates(QiskitTestCase): diff --git a/test/python/circuit/test_gate_definitions.py b/test/python/circuit/test_gate_definitions.py index c3f314366d25..d23ff55706c2 100644 --- a/test/python/circuit/test_gate_definitions.py +++ b/test/python/circuit/test_gate_definitions.py @@ -131,10 +131,17 @@ def setUpClass(cls): if aclass.__name__ not in exclude: cls._gate_classes.append(aclass) + def pgdef(self, gate): + for rule in gate.definition: + qubit_inds = [qubit.index for qubit in rule[1]] + params = np.array(rule[0].params) + print(f'{rule[0].name:5s} {str(qubit_inds):8s} {params} ') + def test_equivalence_phase(self): """Test that the equivalent circuits from the equivalency_library have equal matrix representations""" for gate_class in self._gate_classes: + #for gate_class in [RYYGate]: with self.subTest(i=gate_class): n_params = len(_get_free_params(gate_class)) params = [0.1 * i for i in range(1, n_params+1)] @@ -148,9 +155,82 @@ def test_equivalence_phase(self): with self.subTest(msg=gate.name + '_' + str(ieq)): op1 = Operator(gate) op2 = Operator(equivalency) + print(gate.name) + # np.set_printoptions(precision=4, linewidth=200, suppress=True) + # print('') + # print(gate.to_matrix_hide()) + # print('') + # print(op1.data) + # print('') + # print(op2.data) + # import ipdb;ipdb.set_trace() self.assertEqual(op1, op2) - - + try: + tomat = gate.to_matrix() + except: + try: + tomat = gate.to_matrix_hide() + except: + pass + else: + self.assertTrue(np.allclose(op1.data, tomat)) + print('ok, HIDDEN') + else: + self.assertTrue(np.allclose(op1.data, tomat)) + print('ok') + + def test_phase_gate(self): + from qiskit import transpile, QuantumRegister + np.set_printoptions(precision=2, linewidth=200, suppress=True) + def show_gates(gate): + print(gate.to_matrix()) + for o, qreg, _ in gate.definition: + print(o.name, [qubit.index for qubit in qreg], o.params) + + class PhaseGate(Gate): + def __init__(self, theta): + """Create new r single-qubit gate.""" + super().__init__('gph', 1, [theta]) + + def _define(self): + theta = self.params[0] + q = QuantumRegister(1, 'q') + self.definition = [ + (U3Gate(np.pi, theta, np.pi+theta), [q[0]], []), + (XGate(), [q[0]], []), + ] + + def inverse(self): + return PhaseGate(-self.params[0]) + + basis = ['id', 'u1', 'u3', 'cx'] + from qiskit.quantum_info import ScalarOp, Operator + n_qubits = 2 + dim = 2**n_qubits + op = Operator(np.eye(dim)) + op *= ScalarOp(dim, np.exp(1j * np.pi/4)) + instr = op.to_instruction() + show_gates(instr) + + op2 = Operator(np.eye(dim)) + op2 *= ScalarOp(dim, np.exp(1j * np.pi/2)) + instr2 = op2.to_instruction() + show_gates(instr2) + + op3 = Operator(np.eye(dim)) + op3 *= ScalarOp(dim, np.exp(1j * np.pi/2)) + instr3 = op3.to_instruction() + show_gates(instr3) + + phase_gate = PhaseGate(np.pi) + op4 = Operator(phase_gate) + show_gates(op4.to_instruction()) + + qc = QuantumCircuit(n_qubits) + qc.append(PhaseGate(np.pi/8), qc.qregs) + + print(qc) + print(Operator(qc).data) @ddt class TestStandardEquivalenceLibrary(QiskitTestCase): """Standard Extension Test.""" From 9a9a474d2cefba80180defe70c3d3eb791111436 Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Thu, 18 Jun 2020 13:02:14 -0400 Subject: [PATCH 05/38] resolve most errors in test_unroller --- qiskit/circuit/library/standard_gates/ryy.py | 2 +- qiskit/circuit/library/standard_gates/rz.py | 12 +---- qiskit/converters/circuit_to_dag.py | 1 + qiskit/dagcircuit/dagcircuit.py | 1 + test/python/circuit/test_controlled_gate.py | 19 +++++-- test/python/circuit/test_gate_definitions.py | 18 +++---- test/python/transpiler/test_unroller.py | 54 +++++++++++++++++--- 7 files changed, 71 insertions(+), 36 deletions(-) diff --git a/qiskit/circuit/library/standard_gates/ryy.py b/qiskit/circuit/library/standard_gates/ryy.py index 244514c48ff9..d45642edfaf2 100644 --- a/qiskit/circuit/library/standard_gates/ryy.py +++ b/qiskit/circuit/library/standard_gates/ryy.py @@ -88,7 +88,7 @@ def inverse(self): # TODO: this is the correct matrix and is equal to the definition above, # however the control mechanism cannot distinguish U1 and RZ yet. - def to_matrix_hide(self): + def to_matrix(self): """Return a numpy.array for the RYY gate.""" theta = self.params[0] halfcos = np.cos(theta / 2) diff --git a/qiskit/circuit/library/standard_gates/rz.py b/qiskit/circuit/library/standard_gates/rz.py index 0d042e592f92..1c32b6ac6bf5 100644 --- a/qiskit/circuit/library/standard_gates/rz.py +++ b/qiskit/circuit/library/standard_gates/rz.py @@ -70,16 +70,6 @@ def _define(self): circ.u3(np.pi, circ.phase, circ.phase - np.pi, circ.qregs[0]) circ.x(circ.qregs[0]) self.definition = circ.to_gate().definition - - # from .u1 import U1Gate - # definition = [] - # q = QuantumRegister(1, 'q') - # rule = [ - # (U1Gate(self.params[0]), [q[0]], []) - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Return a (mutli-)controlled-RZ gate. @@ -108,7 +98,7 @@ def inverse(self): # TODO: this is the correct matrix however the control mechanism # cannot distinguish U1 and RZ yet. - def to_matrix_hide(self): + def to_matrix(self): """Return a numpy.array for the RZ gate.""" import numpy as np lam = float(self.params[0]) diff --git a/qiskit/converters/circuit_to_dag.py b/qiskit/converters/circuit_to_dag.py index 5d70c896b6a7..cf8c050295e6 100644 --- a/qiskit/converters/circuit_to_dag.py +++ b/qiskit/converters/circuit_to_dag.py @@ -56,4 +56,5 @@ def circuit_to_dag(circuit): for instruction, qargs, cargs in circuit.data: dagcircuit.apply_operation_back(instruction.copy(), qargs, cargs, instruction.condition) + return dagcircuit diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index 647463f87efd..d388771e5a0b 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -29,6 +29,7 @@ import itertools import networkx as nx import retworkx as rx +import numpy as np from qiskit.circuit.quantumregister import QuantumRegister, Qubit from qiskit.circuit.classicalregister import ClassicalRegister diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 20a1ad810219..3219ee9941ed 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -633,11 +633,22 @@ def test_controlled_random_unitary(self, num_ctrl_qubits): def test_open_controlled_unitary_z(self, num_ctrl_qubits, ctrl_state): """Test that UnitaryGate with control returns params.""" umat = np.array([[1, 0], [0, -1]]) - ugate = UnitaryGate(umat).control(num_ctrl_qubits, ctrl_state=ctrl_state) + ugate = UnitaryGate(umat) + cugate = ugate.control(num_ctrl_qubits, ctrl_state=ctrl_state) ref_mat = _compute_control_matrix(umat, num_ctrl_qubits, ctrl_state=ctrl_state) - np.set_printoptions(precision=2, linewidth=200, suppress=True) - import ipdb;ipdb.set_trace() - self.assertTrue(matrix_equal(Operator(ugate).data, ref_mat)) + # np.set_printoptions(precision=2, linewidth=200, suppress=True) + # from qiskit.circuit.add_control import _unroll_gate, _gate_to_circuit + # print('') + # print(umat) + # base_circ = _gate_to_circuit(_unroll_gate(ugate, ['u1', 'u3', 'cx'])) + # print(base_circ) + # print(Operator(base_circ).data) + # ccirc = _gate_to_circuit(_unroll_gate(cugate, ['u1', 'u3', 'cx'])) + # print(ccirc) + # print(Operator(ccirc).data) + # print(ref_mat) + # import ipdb;ipdb.set_trace() + self.assertTrue(matrix_equal(Operator(cugate).data, ref_mat, ignore_phase=False)) @data(1, 2, 3) def test_open_controlled_unitary_matrix(self, num_ctrl_qubits): diff --git a/test/python/circuit/test_gate_definitions.py b/test/python/circuit/test_gate_definitions.py index d23ff55706c2..954d051cfcda 100644 --- a/test/python/circuit/test_gate_definitions.py +++ b/test/python/circuit/test_gate_definitions.py @@ -18,7 +18,7 @@ import numpy as np from ddt import ddt, data -from qiskit import QuantumCircuit +from qiskit import QuantumCircuit, QiskitError from qiskit.quantum_info import Operator from qiskit.test import QiskitTestCase from qiskit.circuit import ParameterVector, Gate, ControlledGate @@ -125,7 +125,8 @@ def setUpClass(cls): class_list = Gate.__subclasses__() + ControlledGate.__subclasses__() exclude = {'ControlledGate', 'DiagonalGate', 'UCGate', 'MCGupDiag', 'MCU1Gate', 'UnitaryGate', 'HamiltonianGate', - 'UCPauliRotGate', 'SingleQubitUnitary', 'MCXGate'} + 'UCPauliRotGate', 'SingleQubitUnitary', 'MCXGate', + 'VariadicZeroParamGate'} cls._gate_classes = [] for aclass in class_list: if aclass.__name__ not in exclude: @@ -155,7 +156,7 @@ def test_equivalence_phase(self): with self.subTest(msg=gate.name + '_' + str(ieq)): op1 = Operator(gate) op2 = Operator(equivalency) - print(gate.name) + # print(gate.name) # np.set_printoptions(precision=4, linewidth=200, suppress=True) # print('') # print(gate.to_matrix_hide()) @@ -167,17 +168,10 @@ def test_equivalence_phase(self): self.assertEqual(op1, op2) try: tomat = gate.to_matrix() - except: - try: - tomat = gate.to_matrix_hide() - except: - pass - else: - self.assertTrue(np.allclose(op1.data, tomat)) - print('ok, HIDDEN') + except (AttributeError, QiskitError): + pass else: self.assertTrue(np.allclose(op1.data, tomat)) - print('ok') def test_phase_gate(self): from qiskit import transpile, QuantumRegister diff --git a/test/python/transpiler/test_unroller.py b/test/python/transpiler/test_unroller.py index 35ae020afd5c..bf2102c71514 100644 --- a/test/python/transpiler/test_unroller.py +++ b/test/python/transpiler/test_unroller.py @@ -86,12 +86,15 @@ def test_unroll_1q_chain_conditional(self): ref_circuit.u1(pi/4, qr[0]) ref_circuit.u3(0.5, 0, 0, qr[0]) ref_circuit.u1(0.3, qr[0]) + ref_circuit.u3(pi, -0.3/2, -0.3/2 - pi, qr[0]) + ref_circuit.u3(pi, 0, pi, qr[0]) ref_circuit.u3(0.1, -pi/2, pi/2, qr[0]) ref_circuit.measure(qr[0], cr[0]) ref_circuit.u3(pi, 0, pi, qr[0]).c_if(cr, 1) ref_circuit.u3(pi, pi/2, pi/2, qr[0]).c_if(cr, 1) ref_circuit.u1(pi, qr[0]).c_if(cr, 1) ref_dag = circuit_to_dag(ref_circuit) + self.assertEqual(unrolled_dag, ref_dag) def test_unroll_no_basis(self): @@ -148,15 +151,18 @@ def test_unroll_all_instructions(self): unrolled_dag = pass_.run(dag) ref_circuit = QuantumCircuit(qr, cr) + # unrolled crx(0.5, qr[1], qr[2]) ref_circuit.u3(0, 0, pi/2, qr[2]) ref_circuit.cx(qr[1], qr[2]) ref_circuit.u3(-0.25, 0, 0, qr[2]) ref_circuit.cx(qr[1], qr[2]) ref_circuit.u3(0.25, -pi/2, 0, qr[2]) + # unrolled cry(0.5, qr[1], qr[2]) ref_circuit.u3(0.25, 0, 0, qr[2]) ref_circuit.cx(qr[1], qr[2]) ref_circuit.u3(-0.25, 0, 0, qr[2]) ref_circuit.cx(qr[1], qr[2]) + # unrolled ccx(qr[0], qr[1], qr[2]) ref_circuit.u3(pi/2, 0, pi, qr[2]) ref_circuit.cx(qr[1], qr[2]) ref_circuit.u3(0, 0, -pi/4, qr[2]) @@ -172,6 +178,7 @@ def test_unroll_all_instructions(self): ref_circuit.cx(qr[0], qr[1]) ref_circuit.u3(0, 0, pi/4, qr[2]) ref_circuit.u3(pi/2, 0, pi, qr[2]) + # unrolled ch(qr[0], qr[2]) ref_circuit.u3(0, 0, pi/2, qr[2]) ref_circuit.u3(pi/2, 0, pi, qr[2]) ref_circuit.u3(0, 0, pi/4, qr[2]) @@ -179,10 +186,12 @@ def test_unroll_all_instructions(self): ref_circuit.u3(0, 0, -pi/4, qr[2]) ref_circuit.u3(pi/2, 0, pi, qr[2]) ref_circuit.u3(0, 0, -pi/2, qr[2]) + # unrolled crz(0.5, qr[1], qr[2]) ref_circuit.u3(0, 0, 0.25, qr[2]) ref_circuit.cx(qr[1], qr[2]) ref_circuit.u3(0, 0, -0.25, qr[2]) ref_circuit.cx(qr[1], qr[2]) + ref_circuit.cx(qr[2], qr[0]) ref_circuit.u3(pi/2, 0, pi, qr[2]) ref_circuit.cx(qr[0], qr[2]) @@ -216,12 +225,17 @@ def test_unroll_all_instructions(self): ref_circuit.u3(0, 0, -pi/2, qr[2]) ref_circuit.cx(qr[1], qr[2]) ref_circuit.u3(pi/2, 0, pi, qr[1]) + # unrolled ry(0.2, qr[0]) ref_circuit.u3(0.2, 0, 0, qr[1]) + ref_circuit.u3(0, 0, pi/2, qr[2]) ref_circuit.cx(qr[2], qr[0]) ref_circuit.u3(pi/2, 0, pi, qr[0]) + # unrolled identity gate ref_circuit.i(qr[0]) + # unrolled rx(0.1, qr[0]) ref_circuit.u3(0.1, -pi/2, pi/2, qr[0]) + ref_circuit.cx(qr[1], qr[0]) ref_circuit.u3(0, 0, 0.6, qr[0]) ref_circuit.cx(qr[1], qr[0]) @@ -230,7 +244,9 @@ def test_unroll_all_instructions(self): ref_circuit.u3(pi/2, 0.2, -0.1, qr[0]) ref_circuit.u3(0, 0, pi, qr[0]) ref_circuit.u3(0, 0, -pi/2, qr[1]) + # unrolled rz(0.3, qr[2]) ? ref_circuit.u3(0, 0, 0.3, qr[2]) + ref_circuit.cx(qr[1], qr[2]) ref_circuit.cx(qr[2], qr[1]) ref_circuit.cx(qr[1], qr[2]) @@ -254,10 +270,12 @@ def test_simple_unroll_parameterized_without_expressions(self): qc.rz(theta, qr[0]) dag = circuit_to_dag(qc) - unrolled_dag = Unroller(['u1', 'cx']).run(dag) + unrolled_dag = Unroller(['u1', 'u3', 'cx']).run(dag) expected = QuantumCircuit(qr) expected.u1(theta, qr[0]) + expected.u3(pi, -theta/2, -theta/2 - pi, qr[0]) + expected.u3(pi, 0, pi, qr[0]) self.assertEqual(circuit_to_dag(expected), unrolled_dag) @@ -273,10 +291,12 @@ def test_simple_unroll_parameterized_with_expressions(self): qc.rz(sum_, qr[0]) dag = circuit_to_dag(qc) - unrolled_dag = Unroller(['u1', 'cx']).run(dag) + unrolled_dag = Unroller(['u1', 'u3', 'cx']).run(dag) expected = QuantumCircuit(qr) expected.u1(sum_, qr[0]) + expected.u3(pi, -sum_/2, -sum_/2 - pi, qr[0]) + expected.u3(pi, 0, pi, qr[0]) self.assertEqual(circuit_to_dag(expected), unrolled_dag) @@ -314,15 +334,24 @@ def test_unrolling_parameterized_composite_gates(self): qc.append(subqc.to_instruction(), [qr2[2], qr2[3]]) dag = circuit_to_dag(qc) - out_dag = Unroller(['u1', 'cx']).run(dag) + out_dag = Unroller(['u1', 'u3', 'cx']).run(dag) expected = QuantumCircuit(qr2) expected.u1(theta, qr2[0]) - expected.u1(theta, qr2[2]) + expected.u3(pi, -theta/2, -theta/2 - pi, qr2[0]) + expected.u3(pi, 0, pi, qr2[0]) expected.cx(qr2[0], qr2[1]) - expected.cx(qr2[2], qr2[3]) expected.u1(theta, qr2[1]) + expected.u3(pi, -theta/2, -theta/2 - pi, qr2[1]) + expected.u3(pi, 0, pi, qr2[1]) + + expected.u1(theta, qr2[2]) + expected.u3(pi, -theta/2, -theta/2 - pi, qr2[2]) + expected.u3(pi, 0, pi, qr2[2]) + expected.cx(qr2[2], qr2[3]) expected.u1(theta, qr2[3]) + expected.u3(pi, -theta/2, -theta/2 - pi, qr2[3]) + expected.u3(pi, 0, pi, qr2[3]) self.assertEqual(circuit_to_dag(expected), out_dag) @@ -336,14 +365,23 @@ def test_unrolling_parameterized_composite_gates(self): qc.append(subqc.to_instruction({theta: gamma}), [qr2[2], qr2[3]]) dag = circuit_to_dag(qc) - out_dag = Unroller(['u1', 'cx']).run(dag) + out_dag = Unroller(['u1', 'u3', 'cx']).run(dag) expected = QuantumCircuit(qr2) expected.u1(phi, qr2[0]) - expected.u1(gamma, qr2[2]) + expected.u3(pi, -phi/2, -phi/2 - pi, qr2[0]) + expected.u3(pi, 0, pi, qr2[0]) expected.cx(qr2[0], qr2[1]) - expected.cx(qr2[2], qr2[3]) expected.u1(phi, qr2[1]) + expected.u3(pi, -phi/2, -phi/2 - pi, qr2[1]) + expected.u3(pi, 0, pi, qr2[1]) + + expected.u1(gamma, qr2[2]) + expected.u3(pi, -gamma/2, -gamma/2 - pi, qr2[2]) + expected.u3(pi, 0, pi, qr2[2]) + expected.cx(qr2[2], qr2[3]) expected.u1(gamma, qr2[3]) + expected.u3(pi, -gamma/2, -gamma/2 - pi, qr2[3]) + expected.u3(pi, 0, pi, qr2[3]) self.assertEqual(circuit_to_dag(expected), out_dag) From 7d3cc363d81fa19441be5bf0c8125f70f0db4bd4 Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Wed, 24 Jun 2020 00:11:47 -0400 Subject: [PATCH 06/38] passing tests --- qiskit/circuit/add_control.py | 15 - qiskit/circuit/library/standard_gates/ryy.py | 5 +- qiskit/circuit/library/standard_gates/rz.py | 10 +- qiskit/circuit/library/standard_gates/rzx.py | 2 +- qiskit/circuit/library/standard_gates/u1.py | 43 +- qiskit/circuit/library/standard_gates/u3.py | 4 +- qiskit/circuit/quantumcircuit.py | 3 +- qiskit/dagcircuit/dagcircuit.py | 1 - .../quantum_initializer/initializer.py | 4 +- qiskit/extensions/unitary.py | 15 +- qiskit/quantum_info/operators/operator.py | 1 + test/python/circuit/test_controlled_gate.py | 22 - test/python/circuit/test_gate_definitions.py | 80 +--- test/python/circuit/test_gate_power.py | 19 +- test/python/compiler/test_transpiler.py | 10 +- test/python/transpiler/test_unroller.py | 415 +++++++++++------- 16 files changed, 339 insertions(+), 310 deletions(-) diff --git a/qiskit/circuit/add_control.py b/qiskit/circuit/add_control.py index 950488bc687f..df7b3a814d01 100644 --- a/qiskit/circuit/add_control.py +++ b/qiskit/circuit/add_control.py @@ -127,23 +127,8 @@ def control(operation: Union[Gate, ControlledGate], qc.mcrz(operation.definition[0][0].params[0], q_control, q_target[0], use_basis_gates=True) else: - if operation.name == 'ryy': - # print(len(operation.definition)) - # operation.definition = operation.definition[:3] - from qiskit.quantum_info import Operator - bgate = _unroll_gate(operation, ['u1', 'u3', 'cx']) # now we have a bunch of single qubit rotation gates and cx - # if operation.name == 'ryy': - # import numpy as np - # np.set_printoptions(linewidth=200, precision=2, suppress=True) - # print(_gate_to_circuit(operation)) - # print(Operator(operation).data) - # print(Operator(bgate).data) - # print(_gate_to_circuit(bgate)) - # print(operation.to_matrix_hide()) - # print(np.allclose(operation.to_matrix_hide(), Operator(bgate).data)) - # import ipdb;ipdb.set_trace() for rule in bgate.definition: if rule[0].name == 'u3': theta, phi, lamb = rule[0].params diff --git a/qiskit/circuit/library/standard_gates/ryy.py b/qiskit/circuit/library/standard_gates/ryy.py index d45642edfaf2..164e0730a16e 100644 --- a/qiskit/circuit/library/standard_gates/ryy.py +++ b/qiskit/circuit/library/standard_gates/ryy.py @@ -16,7 +16,6 @@ import numpy as np from qiskit.circuit.gate import Gate -from qiskit.circuit.quantumregister import QuantumRegister class RYYGate(Gate): @@ -76,9 +75,9 @@ def __init__(self, theta): def _define(self): """Calculate a subcircuit that implements this unitary.""" circ = self.decompositions[0] - gp = circ.phase / len(circ.qregs[0]) + phase = circ.phase / len(circ.qregs[0]) if circ.phase: - circ.u3(np.pi, gp, gp - np.pi, circ.qregs[0]) + circ.u3(np.pi, phase, phase - np.pi, circ.qregs[0]) circ.x(circ.qregs[0]) self.definition = circ.to_gate().definition diff --git a/qiskit/circuit/library/standard_gates/rz.py b/qiskit/circuit/library/standard_gates/rz.py index 1c32b6ac6bf5..21b396360980 100644 --- a/qiskit/circuit/library/standard_gates/rz.py +++ b/qiskit/circuit/library/standard_gates/rz.py @@ -99,11 +99,11 @@ def inverse(self): # TODO: this is the correct matrix however the control mechanism # cannot distinguish U1 and RZ yet. def to_matrix(self): - """Return a numpy.array for the RZ gate.""" - import numpy as np - lam = float(self.params[0]) - return np.array([[np.exp(-1j * lam / 2), 0], - [0, np.exp(1j * lam / 2)]], dtype=complex) + """Return a numpy.array for the RZ gate.""" + import numpy as np + ilam2 = 0.5j * float(self.params[0]) + return np.array([[np.exp(-ilam2), 0], + [0, np.exp(ilam2)]], dtype=complex) class CRZMeta(type): diff --git a/qiskit/circuit/library/standard_gates/rzx.py b/qiskit/circuit/library/standard_gates/rzx.py index ec6a397ad014..07d813293911 100644 --- a/qiskit/circuit/library/standard_gates/rzx.py +++ b/qiskit/circuit/library/standard_gates/rzx.py @@ -16,7 +16,6 @@ from qiskit.circuit.gate import Gate from qiskit.circuit.quantumregister import QuantumRegister -from .rz import RZGate from .h import HGate from .x import CXGate @@ -125,6 +124,7 @@ def _define(self): """ gate rzx(theta) a, b { h b; cx a, b; u1(theta) b; cx a, b; h b;} """ + # pylint: disable=cyclic-import from qiskit.circuit.library.standard_gates import U1Gate q = QuantumRegister(2, 'q') self.definition = [ diff --git a/qiskit/circuit/library/standard_gates/u1.py b/qiskit/circuit/library/standard_gates/u1.py index 4d05116e00f2..5627665e6749 100644 --- a/qiskit/circuit/library/standard_gates/u1.py +++ b/qiskit/circuit/library/standard_gates/u1.py @@ -219,35 +219,22 @@ def inverse(self): r"""Return inverted CU1 gate (:math:`CU1(\lambda){\dagger} = CU1(-\lambda)`)""" return CU1Gate(-self.params[0]) - # TODO: this is the correct definition but has a global phase with respect - # to the decomposition above. Restore after allowing phase on circuits. - # def to_matrix(self): - # """Return a numpy.array for the CU1 gate.""" - # eith = numpy.exp(1j * self.params[0]) - # return numpy.array([[1, 0, 0, 0], - # [0, 1, 0, 0], - # [0, 0, 1, 0], - # [0, 0, 0, eith]], - # dtype=complex) - - # TODO: this is the correct definition but has a global phase with respect - # to the decomposition above. Restore after allowing phase on circuits. def to_matrix(self): - """Return a numpy.array for the CU1 gate.""" - - eith = numpy.exp(1j * float(self.params[0])) - if self.ctrl_state: - return numpy.array([[1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, 1, 0], - [0, 0, 0, eith]], - dtype=complex) - else: - return numpy.array([[1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, eith, 0], - [0, 0, 0, 1]], - dtype=complex) + """Return a numpy.array for the CU1 gate.""" + + eith = numpy.exp(1j * float(self.params[0])) + if self.ctrl_state: + return numpy.array([[1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, eith]], + dtype=complex) + else: + return numpy.array([[1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, eith, 0], + [0, 0, 0, 1]], + dtype=complex) class Cu1Gate(CU1Gate, metaclass=CU1Meta): diff --git a/qiskit/circuit/library/standard_gates/u3.py b/qiskit/circuit/library/standard_gates/u3.py index 90e80b9a4bdc..26e19144c16e 100644 --- a/qiskit/circuit/library/standard_gates/u3.py +++ b/qiskit/circuit/library/standard_gates/u3.py @@ -96,8 +96,8 @@ def to_matrix(self): cos = numpy.cos(theta / 2) sin = numpy.sin(theta / 2) return numpy.array([ - [ cos , -numpy.exp(1j * lam) * sin ], - [ numpy.exp(1j * phi) * sin, numpy.exp(1j * (phi + lam)) * cos ] + [cos, -numpy.exp(1j * lam) * sin], + [numpy.exp(1j * phi) * sin, numpy.exp(1j * (phi + lam)) * cos] ], dtype=complex) diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index 2d32f42cdc8c..074d11fa2b83 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -77,6 +77,7 @@ class QuantumCircuit: name (str): the name of the quantum circuit. If not set, an automatically generated string will be assigned. + phase (float): The global phase of the circuit. Raises: CircuitError: if the circuit name, if given, is not valid. @@ -582,7 +583,7 @@ def append(self, instruction, qargs=None, cargs=None, phase=0): instructions = InstructionSet() for (qarg, carg) in instruction.broadcast_arguments(expanded_qargs, expanded_cargs): instructions.add(self._append(instruction, qarg, carg), qarg, carg) - self.phase += phase + self.phase += phase return instructions def _append(self, instruction, qargs, cargs): diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index d388771e5a0b..fcaeb680097d 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -241,7 +241,6 @@ def phase(self, angle): self._phase = angle % (-2 * np.pi) else: self._phase = angle % (2 * np.pi) - def remove_all_ops_named(self, opname): """Remove all operation nodes with the given name.""" diff --git a/qiskit/extensions/quantum_initializer/initializer.py b/qiskit/extensions/quantum_initializer/initializer.py index dd41bb5bf997..28b102464ab5 100644 --- a/qiskit/extensions/quantum_initializer/initializer.py +++ b/qiskit/extensions/quantum_initializer/initializer.py @@ -25,7 +25,7 @@ from qiskit.circuit import Instruction from qiskit.circuit.library.standard_gates.x import CXGate from qiskit.circuit.library.standard_gates.ry import RYGate -from qiskit.circuit.library.standard_gates.rz import RZGate +from qiskit.circuit.library.standard_gates.u1 import U1Gate from qiskit.circuit.reset import Reset _EPS = 1e-10 # global variable used to chop very small numbers to zero @@ -113,7 +113,7 @@ def gates_to_uncompute(self): add_last_cnot = False if np.linalg.norm(phis) != 0: - rz_mult = self._multiplex(RZGate, phis, last_cnot=add_last_cnot) + rz_mult = self._multiplex(U1Gate, phis, last_cnot=add_last_cnot) circuit.append(rz_mult.to_instruction(), q[i:self.num_qubits]) if np.linalg.norm(thetas) != 0: diff --git a/qiskit/extensions/unitary.py b/qiskit/extensions/unitary.py index 4f48f5f81b2b..e8ef98cbbecd 100644 --- a/qiskit/extensions/unitary.py +++ b/qiskit/extensions/unitary.py @@ -129,13 +129,26 @@ def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): UnitaryGate: controlled version of gate. Raises: - QiskitError: invalid ctrl_state + QiskitError: Invalid ctrl_state. + ExtensionError: Non-unitary controlled unitary. """ cmat = _compute_control_matrix(self.to_matrix(), num_ctrl_qubits) iso = isometry.Isometry(cmat, 0, 0) cunitary = ControlledGate('c-unitary', num_qubits=self.num_qubits+num_ctrl_qubits, params=[cmat], label=label, num_ctrl_qubits=num_ctrl_qubits, definition=iso.definition, ctrl_state=ctrl_state) + + from qiskit.quantum_info import Operator + # hack to correct global phase; should fix to prevent need for correction here + pmat = (Operator(iso.inverse()).data @ cmat) + diag = numpy.diag(pmat) + if not numpy.allclose(diag, diag[0]): + raise ExtensionError('controlled unitary generation failed') + phase = numpy.angle(diag[0]) + if phase: + qreg = cunitary._definition[0][1][0] + cunitary._definition.append((U3Gate(numpy.pi, phase, phase - numpy.pi), [qreg], [])) + cunitary._definition.append((U3Gate(numpy.pi, 0, numpy.pi), [qreg], [])) cunitary.base_gate = self.copy() cunitary.base_gate.label = self.label return cunitary diff --git a/qiskit/quantum_info/operators/operator.py b/qiskit/quantum_info/operators/operator.py index c6a79e411e91..1beab97092a3 100644 --- a/qiskit/quantum_info/operators/operator.py +++ b/qiskit/quantum_info/operators/operator.py @@ -492,6 +492,7 @@ def _init_instruction(cls, instruction): # Convert circuit to an instruction if isinstance(instruction, QuantumCircuit): if instruction.phase: + #import ipdb;ipdb.set_trace() op *= ScalarOp(op.dim[0], np.exp(1j * float(instruction.phase))) instruction = instruction.to_instruction() op._append_instruction(instruction) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 3219ee9941ed..375c8a14292d 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -636,18 +636,6 @@ def test_open_controlled_unitary_z(self, num_ctrl_qubits, ctrl_state): ugate = UnitaryGate(umat) cugate = ugate.control(num_ctrl_qubits, ctrl_state=ctrl_state) ref_mat = _compute_control_matrix(umat, num_ctrl_qubits, ctrl_state=ctrl_state) - # np.set_printoptions(precision=2, linewidth=200, suppress=True) - # from qiskit.circuit.add_control import _unroll_gate, _gate_to_circuit - # print('') - # print(umat) - # base_circ = _gate_to_circuit(_unroll_gate(ugate, ['u1', 'u3', 'cx'])) - # print(base_circ) - # print(Operator(base_circ).data) - # ccirc = _gate_to_circuit(_unroll_gate(cugate, ['u1', 'u3', 'cx'])) - # print(ccirc) - # print(Operator(ccirc).data) - # print(ref_mat) - # import ipdb;ipdb.set_trace() self.assertTrue(matrix_equal(Operator(cugate).data, ref_mat, ignore_phase=False)) @data(1, 2, 3) @@ -1040,18 +1028,8 @@ def test_controlled_standard_gates(self, num_ctrl_qubits, gate_class): base_mat = Operator(gate).data target_mat = _compute_control_matrix(base_mat, num_ctrl_qubits, ctrl_state=ctrl_state) - np.set_printoptions(precision=2, linewidth=200, suppress=True) - # if gate.name == 'ryy' and num_ctrl_qubits==1 and ctrl_state==1: - # print(gate_class) - # import ipdb;ipdb.set_trace() self.assertTrue(matrix_equal(Operator(cgate).data, target_mat, ignore_phase=True)) - def pgdef(self, gate): - for rule in gate.definition: - qubit_inds = [qubit.index for qubit in rule[1]] - params = np.array(rule[0].params) - print(f'{rule[0].name:5s} {str(qubit_inds):8s} {params} ') - @ddt class TestDeprecatedGates(QiskitTestCase): """Test controlled of deprecated gates.""" diff --git a/test/python/circuit/test_gate_definitions.py b/test/python/circuit/test_gate_definitions.py index 954d051cfcda..b2c63832bded 100644 --- a/test/python/circuit/test_gate_definitions.py +++ b/test/python/circuit/test_gate_definitions.py @@ -121,7 +121,6 @@ class TestGateEquivalenceEqual(QiskitTestCase): @classmethod def setUpClass(cls): - class_list = Gate.__subclasses__() + ControlledGate.__subclasses__() exclude = {'ControlledGate', 'DiagonalGate', 'UCGate', 'MCGupDiag', 'MCU1Gate', 'UnitaryGate', 'HamiltonianGate', @@ -132,17 +131,10 @@ def setUpClass(cls): if aclass.__name__ not in exclude: cls._gate_classes.append(aclass) - def pgdef(self, gate): - for rule in gate.definition: - qubit_inds = [qubit.index for qubit in rule[1]] - params = np.array(rule[0].params) - print(f'{rule[0].name:5s} {str(qubit_inds):8s} {params} ') - def test_equivalence_phase(self): """Test that the equivalent circuits from the equivalency_library have equal matrix representations""" for gate_class in self._gate_classes: - #for gate_class in [RYYGate]: with self.subTest(i=gate_class): n_params = len(_get_free_params(gate_class)) params = [0.1 * i for i in range(1, n_params+1)] @@ -156,75 +148,16 @@ def test_equivalence_phase(self): with self.subTest(msg=gate.name + '_' + str(ieq)): op1 = Operator(gate) op2 = Operator(equivalency) - # print(gate.name) - # np.set_printoptions(precision=4, linewidth=200, suppress=True) - # print('') - # print(gate.to_matrix_hide()) - # print('') - # print(op1.data) - # print('') - # print(op2.data) - # import ipdb;ipdb.set_trace() self.assertEqual(op1, op2) try: tomat = gate.to_matrix() except (AttributeError, QiskitError): pass else: + print(gate_class) self.assertTrue(np.allclose(op1.data, tomat)) - def test_phase_gate(self): - from qiskit import transpile, QuantumRegister - np.set_printoptions(precision=2, linewidth=200, suppress=True) - def show_gates(gate): - print(gate.to_matrix()) - for o, qreg, _ in gate.definition: - print(o.name, [qubit.index for qubit in qreg], o.params) - - class PhaseGate(Gate): - def __init__(self, theta): - """Create new r single-qubit gate.""" - super().__init__('gph', 1, [theta]) - - def _define(self): - theta = self.params[0] - q = QuantumRegister(1, 'q') - self.definition = [ - (U3Gate(np.pi, theta, np.pi+theta), [q[0]], []), - (XGate(), [q[0]], []), - ] - - def inverse(self): - return PhaseGate(-self.params[0]) - - basis = ['id', 'u1', 'u3', 'cx'] - from qiskit.quantum_info import ScalarOp, Operator - n_qubits = 2 - dim = 2**n_qubits - op = Operator(np.eye(dim)) - op *= ScalarOp(dim, np.exp(1j * np.pi/4)) - instr = op.to_instruction() - show_gates(instr) - - op2 = Operator(np.eye(dim)) - op2 *= ScalarOp(dim, np.exp(1j * np.pi/2)) - instr2 = op2.to_instruction() - show_gates(instr2) - - op3 = Operator(np.eye(dim)) - op3 *= ScalarOp(dim, np.exp(1j * np.pi/2)) - instr3 = op3.to_instruction() - show_gates(instr3) - - phase_gate = PhaseGate(np.pi) - op4 = Operator(phase_gate) - show_gates(op4.to_instruction()) - - qc = QuantumCircuit(n_qubits) - qc.append(PhaseGate(np.pi/8), qc.qregs) - - print(qc) - print(Operator(qc).data) + @ddt class TestStandardEquivalenceLibrary(QiskitTestCase): """Standard Extension Test.""" @@ -267,5 +200,10 @@ def test_definition_parameters(self, gate_class): param_qc.append(param_gate, param_qc.qregs[0]) float_qc.append(float_gate, float_qc.qregs[0]) - self.assertEqual(param_entry[0], param_qc.decompose()) - self.assertEqual(float_entry[0], float_qc.decompose()) + if not param_entry[0].phase: + self.assertEqual(param_entry[0], param_qc.decompose()) + self.assertEqual(float_entry[0], float_qc.decompose()) + else: + # temporary hack until gate.definition returns circuit + self.assertEqual(param_entry[0].data[0], param_qc.decompose().data[0]) + self.assertEqual(Operator(float_entry[0]), Operator(float_qc.decompose())) diff --git a/test/python/circuit/test_gate_power.py b/test/python/circuit/test_gate_power.py index 483da2177af1..d0c2eaffccb9 100644 --- a/test/python/circuit/test_gate_power.py +++ b/test/python/circuit/test_gate_power.py @@ -114,19 +114,26 @@ def test_composite_sqrt(self): """Test composite Gate.power(1/2) method. """ circ = QuantumCircuit(1, name='my_gate') - circ.rz(0.1, 0) - circ.rx(0.2, 0) + import numpy as np + thetaz = 0.1 + thetax = 0.2 + circ.rz(thetaz, 0) + circ.rx(thetax, 0) gate = circ.to_gate() - expected = array([[0.99874948+6.25390559e-05j, 0.00374609-4.98542083e-02j], - [-0.00124974-4.99791301e-02j, 0.99750443+4.98542083e-02j]]) - result = gate.power(1 / 2) + iden = Operator.from_label('I') + xgen = Operator.from_label('X') + zgen = Operator.from_label('Z') + rzgate = lambda theta: np.cos(0.5 * theta) * iden - 1j * np.sin(0.5 * theta) * zgen + rxgate = lambda theta: np.cos(0.5 * theta) * iden - 1j * np.sin(0.5 * theta) * xgen + rxrz = rxgate(thetax) * rzgate(thetaz) + self.assertEqual(result.label, 'my_gate^0.5') self.assertEqual(len(result.definition), 1) self.assertIsInstance(result, Gate) - self.assertEqual(Operator(result), Operator(expected)) + self.assertEqual(Operator(result) @ Operator(result), rxrz) @ddt diff --git a/test/python/compiler/test_transpiler.py b/test/python/compiler/test_transpiler.py index d29c1fda6110..9c367d49d52b 100644 --- a/test/python/compiler/test_transpiler.py +++ b/test/python/compiler/test_transpiler.py @@ -15,6 +15,7 @@ """Tests basic functionality of the transpile function""" import math +from math import pi import io from logging import StreamHandler, getLogger from unittest.mock import patch @@ -418,6 +419,8 @@ def test_parameterized_circuit_for_simulator(self): expected_qc = QuantumCircuit(qr) expected_qc.u1(theta, qr[0]) + expected_qc.u3(pi, -0.5*theta, -0.5*theta - pi, qr[0]) + expected_qc.u3(pi, 0, pi, qr[0]) self.assertEqual(expected_qc, transpiled_qc) @@ -435,6 +438,8 @@ def test_parameterized_circuit_for_device(self): qr = QuantumRegister(14, 'q') expected_qc = QuantumCircuit(qr) expected_qc.u1(theta, qr[0]) + expected_qc.u3(pi, -0.5*theta, -0.5*theta - pi, qr[0]) + expected_qc.u3(pi, 0, pi, qr[0]) self.assertEqual(expected_qc, transpiled_qc) @@ -452,6 +457,8 @@ def test_parameter_expression_circuit_for_simulator(self): expected_qc = QuantumCircuit(qr) expected_qc.u1(square, qr[0]) + expected_qc.u3(pi, -0.5*square, -0.5*square - pi, qr[0]) + expected_qc.u3(pi, 0, pi, qr[0]) self.assertEqual(expected_qc, transpiled_qc) @@ -471,7 +478,8 @@ def test_parameter_expression_circuit_for_device(self): qr = QuantumRegister(14, 'q') expected_qc = QuantumCircuit(qr) expected_qc.u1(square, qr[0]) - + expected_qc.u3(pi, -0.5*square, -0.5*square - pi, qr[0]) + expected_qc.u3(pi, 0, pi, qr[0]) self.assertEqual(expected_qc, transpiled_qc) def test_final_measurement_barrier_for_devices(self): diff --git a/test/python/transpiler/test_unroller.py b/test/python/transpiler/test_unroller.py index bf2102c71514..f5908a7ba08f 100644 --- a/test/python/transpiler/test_unroller.py +++ b/test/python/transpiler/test_unroller.py @@ -94,7 +94,7 @@ def test_unroll_1q_chain_conditional(self): ref_circuit.u3(pi, pi/2, pi/2, qr[0]).c_if(cr, 1) ref_circuit.u1(pi, qr[0]).c_if(cr, 1) ref_dag = circuit_to_dag(ref_circuit) - + self.assertEqual(unrolled_dag, ref_dag) def test_unroll_no_basis(self): @@ -110,156 +110,6 @@ def test_unroll_no_basis(self): with self.assertRaises(QiskitError): pass_.run(dag) - def test_unroll_all_instructions(self): - """Test unrolling a circuit containing all standard instructions. - """ - qr = QuantumRegister(3, 'qr') - cr = ClassicalRegister(3, 'cr') - circuit = QuantumCircuit(qr, cr) - circuit.crx(0.5, qr[1], qr[2]) - circuit.cry(0.5, qr[1], qr[2]) - circuit.ccx(qr[0], qr[1], qr[2]) - circuit.ch(qr[0], qr[2]) - circuit.crz(0.5, qr[1], qr[2]) - circuit.cswap(qr[1], qr[0], qr[2]) - circuit.cu1(0.1, qr[0], qr[2]) - circuit.cu3(0.2, 0.1, 0.0, qr[1], qr[2]) - circuit.cx(qr[1], qr[0]) - circuit.cy(qr[1], qr[2]) - circuit.cz(qr[2], qr[0]) - circuit.h(qr[1]) - circuit.i(qr[0]) - circuit.rx(0.1, qr[0]) - circuit.ry(0.2, qr[1]) - circuit.rz(0.3, qr[2]) - circuit.rzz(0.6, qr[1], qr[0]) - circuit.s(qr[0]) - circuit.sdg(qr[1]) - circuit.swap(qr[1], qr[2]) - circuit.t(qr[2]) - circuit.tdg(qr[0]) - circuit.u1(0.1, qr[1]) - circuit.u2(0.2, -0.1, qr[0]) - circuit.u3(0.3, 0.0, -0.1, qr[2]) - circuit.x(qr[2]) - circuit.y(qr[1]) - circuit.z(qr[0]) - circuit.snapshot('0') - circuit.measure(qr, cr) - dag = circuit_to_dag(circuit) - pass_ = Unroller(basis=['u3', 'cx', 'id']) - unrolled_dag = pass_.run(dag) - - ref_circuit = QuantumCircuit(qr, cr) - # unrolled crx(0.5, qr[1], qr[2]) - ref_circuit.u3(0, 0, pi/2, qr[2]) - ref_circuit.cx(qr[1], qr[2]) - ref_circuit.u3(-0.25, 0, 0, qr[2]) - ref_circuit.cx(qr[1], qr[2]) - ref_circuit.u3(0.25, -pi/2, 0, qr[2]) - # unrolled cry(0.5, qr[1], qr[2]) - ref_circuit.u3(0.25, 0, 0, qr[2]) - ref_circuit.cx(qr[1], qr[2]) - ref_circuit.u3(-0.25, 0, 0, qr[2]) - ref_circuit.cx(qr[1], qr[2]) - # unrolled ccx(qr[0], qr[1], qr[2]) - ref_circuit.u3(pi/2, 0, pi, qr[2]) - ref_circuit.cx(qr[1], qr[2]) - ref_circuit.u3(0, 0, -pi/4, qr[2]) - ref_circuit.cx(qr[0], qr[2]) - ref_circuit.u3(0, 0, pi/4, qr[2]) - ref_circuit.cx(qr[1], qr[2]) - ref_circuit.u3(0, 0, pi/4, qr[1]) - ref_circuit.u3(0, 0, -pi/4, qr[2]) - ref_circuit.cx(qr[0], qr[2]) - ref_circuit.cx(qr[0], qr[1]) - ref_circuit.u3(0, 0, pi/4, qr[0]) - ref_circuit.u3(0, 0, -pi/4, qr[1]) - ref_circuit.cx(qr[0], qr[1]) - ref_circuit.u3(0, 0, pi/4, qr[2]) - ref_circuit.u3(pi/2, 0, pi, qr[2]) - # unrolled ch(qr[0], qr[2]) - ref_circuit.u3(0, 0, pi/2, qr[2]) - ref_circuit.u3(pi/2, 0, pi, qr[2]) - ref_circuit.u3(0, 0, pi/4, qr[2]) - ref_circuit.cx(qr[0], qr[2]) - ref_circuit.u3(0, 0, -pi/4, qr[2]) - ref_circuit.u3(pi/2, 0, pi, qr[2]) - ref_circuit.u3(0, 0, -pi/2, qr[2]) - # unrolled crz(0.5, qr[1], qr[2]) - ref_circuit.u3(0, 0, 0.25, qr[2]) - ref_circuit.cx(qr[1], qr[2]) - ref_circuit.u3(0, 0, -0.25, qr[2]) - ref_circuit.cx(qr[1], qr[2]) - - ref_circuit.cx(qr[2], qr[0]) - ref_circuit.u3(pi/2, 0, pi, qr[2]) - ref_circuit.cx(qr[0], qr[2]) - ref_circuit.u3(0, 0, -pi/4, qr[2]) - ref_circuit.cx(qr[1], qr[2]) - ref_circuit.u3(0, 0, pi/4, qr[2]) - ref_circuit.cx(qr[0], qr[2]) - ref_circuit.u3(0, 0, pi/4, qr[0]) - ref_circuit.u3(0, 0, -pi/4, qr[2]) - ref_circuit.cx(qr[1], qr[2]) - ref_circuit.cx(qr[1], qr[0]) - ref_circuit.u3(0, 0, -pi/4, qr[0]) - ref_circuit.u3(0, 0, pi/4, qr[1]) - ref_circuit.cx(qr[1], qr[0]) - ref_circuit.u3(0, 0, 0.05, qr[1]) - ref_circuit.u3(0, 0, pi/4, qr[2]) - ref_circuit.u3(pi/2, 0, pi, qr[2]) - ref_circuit.cx(qr[2], qr[0]) - ref_circuit.u3(0, 0, 0.05, qr[0]) - ref_circuit.cx(qr[0], qr[2]) - ref_circuit.u3(0, 0, -0.05, qr[2]) - ref_circuit.cx(qr[0], qr[2]) - ref_circuit.u3(0, 0, 0.05, qr[2]) - ref_circuit.u3(0, 0, -0.05, qr[2]) - ref_circuit.cx(qr[1], qr[2]) - ref_circuit.u3(-0.1, 0, -0.05, qr[2]) - ref_circuit.cx(qr[1], qr[2]) - ref_circuit.cx(qr[1], qr[0]) - ref_circuit.u3(pi/2, 0, pi, qr[0]) - ref_circuit.u3(0.1, 0.1, 0, qr[2]) - ref_circuit.u3(0, 0, -pi/2, qr[2]) - ref_circuit.cx(qr[1], qr[2]) - ref_circuit.u3(pi/2, 0, pi, qr[1]) - # unrolled ry(0.2, qr[0]) - ref_circuit.u3(0.2, 0, 0, qr[1]) - - ref_circuit.u3(0, 0, pi/2, qr[2]) - ref_circuit.cx(qr[2], qr[0]) - ref_circuit.u3(pi/2, 0, pi, qr[0]) - # unrolled identity gate - ref_circuit.i(qr[0]) - # unrolled rx(0.1, qr[0]) - ref_circuit.u3(0.1, -pi/2, pi/2, qr[0]) - - ref_circuit.cx(qr[1], qr[0]) - ref_circuit.u3(0, 0, 0.6, qr[0]) - ref_circuit.cx(qr[1], qr[0]) - ref_circuit.u3(0, 0, pi/2, qr[0]) - ref_circuit.u3(0, 0, -pi/4, qr[0]) - ref_circuit.u3(pi/2, 0.2, -0.1, qr[0]) - ref_circuit.u3(0, 0, pi, qr[0]) - ref_circuit.u3(0, 0, -pi/2, qr[1]) - # unrolled rz(0.3, qr[2]) ? - ref_circuit.u3(0, 0, 0.3, qr[2]) - - ref_circuit.cx(qr[1], qr[2]) - ref_circuit.cx(qr[2], qr[1]) - ref_circuit.cx(qr[1], qr[2]) - ref_circuit.u3(0, 0, 0.1, qr[1]) - ref_circuit.u3(pi, pi/2, pi/2, qr[1]) - ref_circuit.u3(0, 0, pi/4, qr[2]) - ref_circuit.u3(0.3, 0.0, -0.1, qr[2]) - ref_circuit.u3(pi, 0, pi, qr[2]) - ref_circuit.snapshot('0') - ref_circuit.measure(qr, cr) - ref_dag = circuit_to_dag(ref_circuit) - self.assertEqual(unrolled_dag, ref_dag) - def test_simple_unroll_parameterized_without_expressions(self): """Verify unrolling parameterized gates without expressions.""" qr = QuantumRegister(1) @@ -385,3 +235,266 @@ def test_unrolling_parameterized_composite_gates(self): expected.u3(pi, 0, pi, qr2[3]) self.assertEqual(circuit_to_dag(expected), out_dag) + + +class TestUnrollAllInstructions(QiskitTestCase): + """Test unrolling a circuit containing all standard instructions.""" + + def setUp(self): + qr = self.qr = QuantumRegister(3, 'qr') + cr = self.cr = ClassicalRegister(3, 'cr') + self.circuit = QuantumCircuit(qr, cr) + self.ref_circuit = QuantumCircuit(qr, cr) + self.pass_ = Unroller(basis=['u3', 'cx', 'id']) + + def compare_dags(self): + """compare dags in class tests""" + dag = circuit_to_dag(self.circuit) + unrolled_dag = self.pass_.run(dag) + ref_dag = circuit_to_dag(self.ref_circuit) + self.assertEqual(unrolled_dag, ref_dag) + + def test_unroll_crx(self): + """test unroll crx""" + self.circuit.crx(0.5, 1, 2) + self.ref_circuit.u3(0, 0, pi/2, 2) + self.ref_circuit.cx(1, 2) + self.ref_circuit.u3(-0.25, 0, 0, 2) + self.ref_circuit.cx(1, 2) + self.ref_circuit.u3(0.25, -pi/2, 0, 2) + self.compare_dags() + + def test_unroll_cry(self): + """test unroll cry""" + self.circuit.cry(0.5, 1, 2) + self.ref_circuit.u3(0.25, 0, 0, 2) + self.ref_circuit.cx(1, 2) + self.ref_circuit.u3(-0.25, 0, 0, 2) + self.ref_circuit.cx(1, 2) + self.compare_dags() + + def test_unroll_ccx(self): + """test unroll ccx""" + self.circuit.ccx(0, 1, 2) + self.ref_circuit.u3(pi/2, 0, pi, 2) + self.ref_circuit.cx(1, 2) + self.ref_circuit.u3(0, 0, -pi/4, 2) + self.ref_circuit.cx(0, 2) + self.ref_circuit.u3(0, 0, pi/4, 2) + self.ref_circuit.cx(1, 2) + self.ref_circuit.u3(0, 0, pi/4, 1) + self.ref_circuit.u3(0, 0, -pi/4, 2) + self.ref_circuit.cx(0, 2) + self.ref_circuit.cx(0, 1) + self.ref_circuit.u3(0, 0, pi/4, 0) + self.ref_circuit.u3(0, 0, -pi/4, 1) + self.ref_circuit.cx(0, 1) + self.ref_circuit.u3(0, 0, pi/4, 2) + self.ref_circuit.u3(pi/2, 0, pi, 2) + self.compare_dags() + + def test_unroll_ch(self): + """test unroll ch""" + self.circuit.ch(0, 2) + self.ref_circuit.u3(0, 0, pi/2, 2) + self.ref_circuit.u3(pi/2, 0, pi, 2) + self.ref_circuit.u3(0, 0, pi/4, 2) + self.ref_circuit.cx(0, 2) + self.ref_circuit.u3(0, 0, -pi/4, 2) + self.ref_circuit.u3(pi/2, 0, pi, 2) + self.ref_circuit.u3(0, 0, -pi/2, 2) + self.compare_dags() + + def test_unroll_crz(self): + """test unroll crz""" + self.circuit.crz(0.5, 1, 2) + self.ref_circuit.u3(0, 0, 0.25, 2) + self.ref_circuit.cx(1, 2) + self.ref_circuit.u3(0, 0, -0.25, 2) + self.ref_circuit.cx(1, 2) + + def test_unroll_cswap(self): + """test unroll cswap""" + self.circuit.cswap(1, 0, 2) + self.ref_circuit.cx(2, 0) + self.ref_circuit.u3(pi/2, 0, pi, 2) + self.ref_circuit.cx(0, 2) + self.ref_circuit.u3(0, 0, -pi/4, 2) + self.ref_circuit.cx(1, 2) + self.ref_circuit.u3(0, 0, pi/4, 2) + self.ref_circuit.cx(0, 2) + self.ref_circuit.u3(0, 0, pi/4, 0) + self.ref_circuit.u3(0, 0, -pi/4, 2) + self.ref_circuit.cx(1, 2) + self.ref_circuit.cx(1, 0) + self.ref_circuit.u3(0, 0, -pi/4, 0) + self.ref_circuit.u3(0, 0, pi/4, 1) + self.ref_circuit.cx(1, 0) + self.ref_circuit.u3(0, 0, pi/4, 2) + self.ref_circuit.u3(pi/2, 0, pi, 2) + self.ref_circuit.cx(2, 0) + self.compare_dags() + + def test_unroll_cu1(self): + """test unroll cu1""" + self.circuit.cu1(0.1, 0, 2) + self.ref_circuit.u3(0, 0, 0.05, 0) + self.ref_circuit.cx(0, 2) + self.ref_circuit.u3(0, 0, -0.05, 2) + self.ref_circuit.cx(0, 2) + self.ref_circuit.u3(0, 0, 0.05, 2) + self.compare_dags() + + def test_unroll_cu3(self): + """test unroll cu3""" + self.circuit.cu3(0.2, 0.1, 0.0, 1, 2) + self.ref_circuit.u3(0, 0, 0.05, 1) + self.ref_circuit.u3(0, 0, -0.05, 2) + self.ref_circuit.cx(1, 2) + self.ref_circuit.u3(-0.1, 0, -0.05, 2) + self.ref_circuit.cx(1, 2) + self.ref_circuit.u3(0.1, 0.1, 0, 2) + self.compare_dags() + + def test_unroll_cx(self): + """test unroll cx""" + self.circuit.cx(1, 0) + self.ref_circuit.cx(1, 0) + self.compare_dags() + + def test_unroll_cy(self): + """test unroll cy""" + self.circuit.cy(1, 2) + self.ref_circuit.u3(0, 0, -pi/2, 2) + self.ref_circuit.cx(1, 2) + self.ref_circuit.u3(0, 0, pi/2, 2) + self.compare_dags() + + def test_unroll_cz(self): + """test unroll cz""" + self.circuit.cz(2, 0) + self.ref_circuit.u3(pi/2, 0, pi, 0) + self.ref_circuit.cx(2, 0) + self.ref_circuit.u3(pi/2, 0, pi, 0) + self.compare_dags() + + def test_unroll_h(self): + """test unroll h""" + self.circuit.h(1) + self.ref_circuit.u3(pi/2, 0, pi, 1) + self.compare_dags() + + def test_unroll_i(self): + """test unroll i""" + self.circuit.i(0) + self.ref_circuit.i(0) + self.compare_dags() + + def test_unroll_rx(self): + """test unroll rx""" + self.circuit.rx(0.1, 0) + self.ref_circuit.u3(0.1, -pi/2, pi/2, 0) + self.compare_dags() + + def test_unroll_ry(self): + """test unroll ry""" + self.circuit.ry(0.2, 1) + self.ref_circuit.u3(0.2, 0, 0, 1) + self.compare_dags() + + def test_unroll_rz(self): + """test unroll rz""" + self.circuit.rz(0.3, 2) + self.ref_circuit.u3(0, 0, 0.3, 2) + self.ref_circuit.u3(pi, -0.3/2, -pi - 0.3/2, 2) + self.ref_circuit.u3(pi, 0, pi, 2) + self.compare_dags() + + def test_unroll_rzz(self): + """test unroll rzz""" + self.circuit.rzz(0.6, 1, 0) + self.ref_circuit.cx(1, 0) + self.ref_circuit.u3(0, 0, 0.6, 0) + self.ref_circuit.cx(1, 0) + self.compare_dags() + + def test_unroll_s(self): + """test unroll s""" + self.circuit.s(0) + self.ref_circuit.u3(0, 0, pi/2, 0) + self.compare_dags() + + def test_unroll_sdg(self): + """test unroll sdg""" + self.circuit.sdg(1) + self.ref_circuit.u3(0, 0, -pi/2, 1) + self.compare_dags() + + + def test_unroll_swap(self): + """test unroll swap""" + self.circuit.swap(1, 2) + self.ref_circuit.cx(1, 2) + self.ref_circuit.cx(2, 1) + self.ref_circuit.cx(1, 2) + self.compare_dags() + + def test_unroll_t(self): + """test unroll t""" + self.circuit.t(2) + self.ref_circuit.u3(0, 0, pi/4, 2) + self.compare_dags() + + def test_unroll_tdg(self): + """test unroll tdg""" + self.circuit.tdg(0) + self.ref_circuit.u3(0, 0, -pi/4, 0) + self.compare_dags() + + def test_unroll_u1(self): + """test unroll u1""" + self.circuit.u1(0.1, 1) + self.ref_circuit.u3(0, 0, 0.1, 1) + self.compare_dags() + + def test_unroll_u2(self): + """test unroll u2""" + self.circuit.u2(0.2, -0.1, 0) + self.ref_circuit.u3(pi/2, 0.2, -0.1, 0) + self.compare_dags() + + def test_unroll_u3(self): + """test unroll u3""" + self.circuit.u3(0.3, 0.0, -0.1, 2) + self.ref_circuit.u3(0.3, 0.0, -0.1, 2) + self.compare_dags() + + def test_unroll_x(self): + """test unroll x""" + self.circuit.x(2) + self.ref_circuit.u3(pi, 0, pi, 2) + self.compare_dags() + + def test_unroll_y(self): + """test unroll y""" + self.circuit.y(1) + self.ref_circuit.u3(pi, pi/2, pi/2, 1) + self.compare_dags() + + def test_unroll_z(self): + """test unroll z""" + self.circuit.z(0) + self.ref_circuit.u3(0, 0, pi, 0) + self.compare_dags() + + def test_unroll_snapshot(self): + """test unroll snapshot""" + self.circuit.snapshot('0') + self.ref_circuit.snapshot('0') + self.compare_dags() + + def test_unroll_measure(self): + """test unroll measure""" + self.circuit.measure(self.qr, self.cr) + self.ref_circuit.measure(self.qr, self.cr) + self.compare_dags() From aa63b2021a2b67fd0b4e89273d5c5dcd0c28afb9 Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Wed, 24 Jun 2020 10:37:38 -0400 Subject: [PATCH 07/38] move global phase change to circuit_to_gate --- qiskit/circuit/library/standard_gates/ryy.py | 4 ---- qiskit/circuit/library/standard_gates/rz.py | 3 --- qiskit/converters/circuit_to_gate.py | 6 ++++++ test/python/circuit/test_controlled_gate.py | 4 ++-- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/qiskit/circuit/library/standard_gates/ryy.py b/qiskit/circuit/library/standard_gates/ryy.py index 164e0730a16e..d0a908458aa8 100644 --- a/qiskit/circuit/library/standard_gates/ryy.py +++ b/qiskit/circuit/library/standard_gates/ryy.py @@ -75,10 +75,6 @@ def __init__(self, theta): def _define(self): """Calculate a subcircuit that implements this unitary.""" circ = self.decompositions[0] - phase = circ.phase / len(circ.qregs[0]) - if circ.phase: - circ.u3(np.pi, phase, phase - np.pi, circ.qregs[0]) - circ.x(circ.qregs[0]) self.definition = circ.to_gate().definition def inverse(self): diff --git a/qiskit/circuit/library/standard_gates/rz.py b/qiskit/circuit/library/standard_gates/rz.py index 21b396360980..1b87e18b5d9a 100644 --- a/qiskit/circuit/library/standard_gates/rz.py +++ b/qiskit/circuit/library/standard_gates/rz.py @@ -66,9 +66,6 @@ def _define(self): """ import numpy as np circ = self.decompositions[0] - if circ.phase: - circ.u3(np.pi, circ.phase, circ.phase - np.pi, circ.qregs[0]) - circ.x(circ.qregs[0]) self.definition = circ.to_gate().definition def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): diff --git a/qiskit/converters/circuit_to_gate.py b/qiskit/converters/circuit_to_gate.py index ac0d0e36877d..ccbfb76104f0 100644 --- a/qiskit/converters/circuit_to_gate.py +++ b/qiskit/converters/circuit_to_gate.py @@ -86,8 +86,14 @@ def find_bit_position(bit): if equivalence_library is not None: equivalence_library.add_equivalence(gate, target) + phase = target.phase / len(target.qregs[0]) + if target.phase: + target.u3(np.pi, phase, phase - np.pi, target.qregs[0]) + target.x(target.qregs[0]) + definition = target.data + if gate.num_qubits > 0: q = QuantumRegister(gate.num_qubits, 'q') diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 375c8a14292d..f5d8737be01b 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -636,7 +636,7 @@ def test_open_controlled_unitary_z(self, num_ctrl_qubits, ctrl_state): ugate = UnitaryGate(umat) cugate = ugate.control(num_ctrl_qubits, ctrl_state=ctrl_state) ref_mat = _compute_control_matrix(umat, num_ctrl_qubits, ctrl_state=ctrl_state) - self.assertTrue(matrix_equal(Operator(cugate).data, ref_mat, ignore_phase=False)) + self.assertEqual(Operator(cugate), Operator(ref_mat)) @data(1, 2, 3) def test_open_controlled_unitary_matrix(self, num_ctrl_qubits): @@ -1028,7 +1028,7 @@ def test_controlled_standard_gates(self, num_ctrl_qubits, gate_class): base_mat = Operator(gate).data target_mat = _compute_control_matrix(base_mat, num_ctrl_qubits, ctrl_state=ctrl_state) - self.assertTrue(matrix_equal(Operator(cgate).data, target_mat, ignore_phase=True)) + self.assertEqual(Operator(cgate), Operator(target_mat)) @ddt class TestDeprecatedGates(QiskitTestCase): From 92d93145bb0827fea36cea9c6041338d15296960 Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Wed, 24 Jun 2020 19:32:14 -0400 Subject: [PATCH 08/38] add missing to_matrix to [most] gates --- .../standard_gates/equivalence_library.py | 21 +++++++++- qiskit/circuit/library/standard_gates/ms.py | 13 +------ qiskit/circuit/library/standard_gates/rx.py | 28 +++++++------ qiskit/circuit/library/standard_gates/rxx.py | 39 +++++++------------ qiskit/circuit/library/standard_gates/ry.py | 29 ++++++++------ qiskit/circuit/library/standard_gates/rz.py | 35 ++++++++--------- qiskit/circuit/library/standard_gates/rzx.py | 34 +++++++--------- qiskit/circuit/library/standard_gates/rzz.py | 34 ++++++---------- qiskit/circuit/library/standard_gates/u3.py | 34 +++++++++------- qiskit/circuit/library/standard_gates/x.py | 16 +++++++- qiskit/circuit/quantumcircuit.py | 1 + qiskit/converters/circuit_to_gate.py | 4 +- qiskit/quantum_info/operators/operator.py | 1 - test/python/circuit/test_gate_definitions.py | 8 ---- 14 files changed, 146 insertions(+), 151 deletions(-) diff --git a/qiskit/circuit/library/standard_gates/equivalence_library.py b/qiskit/circuit/library/standard_gates/equivalence_library.py index c7e87ff7e785..3cc3894ce7b8 100644 --- a/qiskit/circuit/library/standard_gates/equivalence_library.py +++ b/qiskit/circuit/library/standard_gates/equivalence_library.py @@ -37,6 +37,7 @@ RZGate, CRZGate, RZZGate, + RZXGate, SGate, SdgGate, SwapGate, @@ -241,7 +242,7 @@ (HGate(), [q[0]], []), (HGate(), [q[1]], []), (CXGate(), [q[0], q[1]], []), - (U1Gate(theta), [q[1]], []), + (RZGate(theta), [q[1]], []), (CXGate(), [q[0], q[1]], []), (HGate(), [q[1]], []), (HGate(), [q[0]], []), @@ -249,6 +250,22 @@ def_rxx.append(inst, qargs, cargs) _sel.add_equivalence(RXXGate(theta), def_rxx) +# RZXGate + +q = QuantumRegister(2, 'q') +theta = Parameter('theta') +def_rzx = QuantumCircuit(q) +for inst, qargs, cargs in [ + (HGate(), [q[1]], []), + (CXGate(), [q[0], q[1]], []), + (RZGate(theta), [q[1]], []), + (CXGate(), [q[0], q[1]], []), + (HGate(), [q[1]], []), +]: + def_rzx.append(inst, qargs, cargs) +_sel.add_equivalence(RZXGate(theta), def_rzx) + + # RYGate q = QuantumRegister(1, 'q') @@ -317,7 +334,7 @@ def_rzz = QuantumCircuit(q) for inst, qargs, cargs in [ (CXGate(), [q[0], q[1]], []), - (U1Gate(theta), [q[1]], []), + (RZGate(theta), [q[1]], []), (CXGate(), [q[0], q[1]], []) ]: def_rzz.append(inst, qargs, cargs) diff --git a/qiskit/circuit/library/standard_gates/ms.py b/qiskit/circuit/library/standard_gates/ms.py index 33170e3cd852..eeaec09c38ad 100644 --- a/qiskit/circuit/library/standard_gates/ms.py +++ b/qiskit/circuit/library/standard_gates/ms.py @@ -36,14 +36,5 @@ def __init__(self, num_qubits, theta, *, n_qubits=None, # pylint:disable=unused super().__init__('ms', num_qubits, [theta], label=label) def _define(self): - from .rxx import RXXGate - definition = [] - q = QuantumRegister(self.num_qubits, 'q') - rule = [] - for i in range(self.num_qubits): - for j in range(i + 1, self.num_qubits): - rule += [(RXXGate(self.params[0]), [q[i], q[j]], [])] - - for inst in rule: - definition.append(inst) - self.definition = definition + circ = self.decompositions[0] + self.definition = circ.to_gate().definition diff --git a/qiskit/circuit/library/standard_gates/rx.py b/qiskit/circuit/library/standard_gates/rx.py index c28256c6e308..8ddd0d1447fb 100644 --- a/qiskit/circuit/library/standard_gates/rx.py +++ b/qiskit/circuit/library/standard_gates/rx.py @@ -200,17 +200,23 @@ def inverse(self): # TODO: this is the correct definition but has a global phase with respect # to the decomposition above. Restore after allowing phase on circuits. - # def to_matrix(self): - # """Return a numpy.array for the CRX gate.""" - # half_theta = self.params[0] / 2 - # cos = numpy.cos(half_theta) - # isin = 1j * numpy.sin(half_theta) - # return numpy.array([[1, 0, 0, 0], - # [0, cos, 0, -isin], - # [0, 0, 1, 0], - # [0, -isin, 0, cos]], - # dtype=complex) - + def to_matrix(self): + """Return a numpy.array for the CRX gate.""" + half_theta = self.params[0] / 2 + cos = numpy.cos(half_theta) + isin = 1j * numpy.sin(half_theta) + if self.ctrl_state: + return numpy.array([[1, 0, 0, 0], + [0, cos, 0, -isin], + [0, 0, 1, 0], + [0, -isin, 0, cos]], + dtype=complex) + else: + return numpy.array([[cos, 0, 0, -isin], + [0, 1, 0, 0], + [-isin, 0, cos, 0], + [0, 0, 0, 1]], + dtype=complex) class CrxGate(CRXGate, metaclass=CRXMeta): """The deprecated CRXGate class.""" diff --git a/qiskit/circuit/library/standard_gates/rxx.py b/qiskit/circuit/library/standard_gates/rxx.py index 273afe1397b0..cf38bdbc1339 100644 --- a/qiskit/circuit/library/standard_gates/rxx.py +++ b/qiskit/circuit/library/standard_gates/rxx.py @@ -74,24 +74,8 @@ def __init__(self, theta): def _define(self): """Calculate a subcircuit that implements this unitary.""" - from .x import CXGate - from .u1 import U1Gate - from .h import HGate - definition = [] - q = QuantumRegister(2, 'q') - theta = self.params[0] - rule = [ - (HGate(), [q[0]], []), - (HGate(), [q[1]], []), - (CXGate(), [q[0], q[1]], []), - (U1Gate(theta), [q[1]], []), - (CXGate(), [q[0], q[1]], []), - (HGate(), [q[1]], []), - (HGate(), [q[0]], []), - ] - for inst in rule: - definition.append(inst) - self.definition = definition + circ = self.decompositions[0] + self.definition = circ.to_gate().definition def inverse(self): """Return inverse RXX gate (i.e. with the negative rotation angle).""" @@ -100,11 +84,14 @@ def inverse(self): # NOTE: we should use the following as the canonical matrix # definition but we don't include it yet since it differs from # the circuit decomposition matrix by a global phase - # def to_matrix(self): - # """Return a Numpy.array for the RXX gate.""" - # theta = float(self.params[0]) - # return np.array([ - # [np.cos(theta / 2), 0, 0, -1j * np.sin(theta / 2)], - # [0, np.cos(theta / 2), -1j * np.sin(theta / 2), 0], - # [0, -1j * np.sin(theta / 2), np.cos(theta / 2), 0], - # [-1j * np.sin(theta / 2), 0, 0, np.cos(theta / 2)]], dtype=complex) + def to_matrix(self): + """Return a Numpy.array for the RXX gate.""" + import numpy + theta2 = float(self.params[0]) / 2 + cos = numpy.cos(theta2) + isin = 1j * numpy.sin(theta2) + return numpy.array([ + [cos, 0, 0, -isin], + [0, cos, -isin, 0], + [0, -isin, cos, 0], + [-isin, 0, 0, cos]], dtype=complex) diff --git a/qiskit/circuit/library/standard_gates/ry.py b/qiskit/circuit/library/standard_gates/ry.py index b6ca8648fed7..2a32bb32eb6d 100644 --- a/qiskit/circuit/library/standard_gates/ry.py +++ b/qiskit/circuit/library/standard_gates/ry.py @@ -193,18 +193,23 @@ def inverse(self): """Return inverse RY gate (i.e. with the negative rotation angle).""" return CRYGate(-self.params[0]) - # TODO: this is the correct definition but has a global phase with respect - # to the decomposition above. Restore after allowing phase on circuits. - # def to_matrix(self): - # """Return a numpy.array for the CRY gate.""" - # half_theta = self.params[0] / 2 - # cos = numpy.cos(half_theta) - # sin = numpy.sin(half_theta) - # return numpy.array([[1, 0, 0, 0], - # [0, cos, 0, -sin], - # [0, 0, 1, 0], - # [0, sin, 0, cos]], - # dtype=complex) + def to_matrix(self): + """Return a numpy.array for the CRY gate.""" + half_theta = self.params[0] / 2 + cos = numpy.cos(half_theta) + sin = numpy.sin(half_theta) + if self.ctrl_state: + return numpy.array([[1, 0, 0, 0], + [0, cos, 0, -sin], + [0, 0, 1, 0], + [0, sin, 0, cos]], + dtype=complex) + else: + return numpy.array([[cos, 0, -sin, 0], + [0, 1, 0, 0], + [sin, 0, cos, 0], + [0, 0, 0, 1]], + dtype=complex) class CryGate(CRYGate, metaclass=CRYMeta): diff --git a/qiskit/circuit/library/standard_gates/rz.py b/qiskit/circuit/library/standard_gates/rz.py index 1b87e18b5d9a..79d5ab3e6e67 100644 --- a/qiskit/circuit/library/standard_gates/rz.py +++ b/qiskit/circuit/library/standard_gates/rz.py @@ -64,7 +64,6 @@ def _define(self): """ gate rz(phi) a { u1(phi) a; } """ - import numpy as np circ = self.decompositions[0] self.definition = circ.to_gate().definition @@ -205,24 +204,22 @@ def inverse(self): """Return inverse RZ gate (i.e. with the negative rotation angle).""" return CRZGate(-self.params[0]) - # TODO: this is the correct definition but has a global phase with respect - # to the decomposition above. Restore after allowing phase on circuits. - # def to_matrix(self): - # """Return a numpy.array for the CRZ gate.""" - # import numpy - # arg = 1j * self.params[0] / 2 - # if self.ctrl_state: - # return numpy.array([[1, 0, 0, 0], - # [0, numpy.exp(-arg), 0, 0], - # [0, 0, 1, 0], - # [0, 0, 0, numpy.exp(arg)]], - # dtype=complex) - # else: - # return numpy.array([[numpy.exp(-arg), 0, 0, 0], - # [ 0, 1, 0, 0], - # [ 0, 0, numpy.exp(arg), 0], - # [ 0, 0, 0, 1]], - # dtype=complex) + def to_matrix(self): + """Return a numpy.array for the CRZ gate.""" + import numpy + arg = 1j * self.params[0] / 2 + if self.ctrl_state: + return numpy.array([[1, 0, 0, 0], + [0, numpy.exp(-arg), 0, 0], + [0, 0, 1, 0], + [0, 0, 0, numpy.exp(arg)]], + dtype=complex) + else: + return numpy.array([[numpy.exp(-arg), 0, 0, 0], + [ 0, 1, 0, 0], + [ 0, 0, numpy.exp(arg), 0], + [ 0, 0, 0, 1]], + dtype=complex) class CrzGate(CRZGate, metaclass=CRZMeta): diff --git a/qiskit/circuit/library/standard_gates/rzx.py b/qiskit/circuit/library/standard_gates/rzx.py index 07d813293911..d0bc0a009244 100644 --- a/qiskit/circuit/library/standard_gates/rzx.py +++ b/qiskit/circuit/library/standard_gates/rzx.py @@ -124,16 +124,8 @@ def _define(self): """ gate rzx(theta) a, b { h b; cx a, b; u1(theta) b; cx a, b; h b;} """ - # pylint: disable=cyclic-import - from qiskit.circuit.library.standard_gates import U1Gate - q = QuantumRegister(2, 'q') - self.definition = [ - (HGate(), [q[1]], []), - (CXGate(), [q[0], q[1]], []), - (U1Gate(self.params[0]), [q[1]], []), # Should be RZGate - (CXGate(), [q[0], q[1]], []), - (HGate(), [q[1]], []) - ] + circ = self.decompositions[0] + self.definition = circ.to_gate().definition def inverse(self): """Return inverse RZX gate (i.e. with the negative rotation angle).""" @@ -141,14 +133,14 @@ def inverse(self): # TODO: this is the correct definition but has a global phase with respect # to the decomposition above. Restore after allowing phase on circuits. - # def to_matrix(self): - # """Return a numpy.array for the RZX gate.""" - # half_theta = self.params[0] / 2 - # cos = numpy.cos(half_theta) - # isin = 1j * numpy.sin(half_theta) - # return numpy.array([[ cos, 0, -isin, 0], - # [ 0, cos, 0, isin], - # [-isin, 0, cos, 0], - # [ 0, isin, 0, cos]], - # [0, 1j*halfsin, 0, halfcos]], - # dtype=complex) + def to_matrix(self): + """Return a numpy.array for the RZX gate.""" + import numpy + half_theta = self.params[0] / 2 + cos = numpy.cos(half_theta) + isin = 1j * numpy.sin(half_theta) + return numpy.array([[ cos, 0, -isin, 0], + [ 0, cos, 0, isin], + [-isin, 0, cos, 0], + [ 0, isin, 0, cos]], + dtype=complex) diff --git a/qiskit/circuit/library/standard_gates/rzz.py b/qiskit/circuit/library/standard_gates/rzz.py index e526cb36719f..2b64c3d35323 100644 --- a/qiskit/circuit/library/standard_gates/rzz.py +++ b/qiskit/circuit/library/standard_gates/rzz.py @@ -86,21 +86,9 @@ def __init__(self, theta): super().__init__('rzz', 2, [theta]) def _define(self): - """ - gate rzz(theta) a, b { cx a, b; u1(theta) b; cx a, b; } - """ - from .u1 import U1Gate - from .x import CXGate - definition = [] - q = QuantumRegister(2, 'q') - rule = [ - (CXGate(), [q[0], q[1]], []), - (U1Gate(self.params[0]), [q[1]], []), - (CXGate(), [q[0], q[1]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + """Calculate a subcircuit that implements this unitary.""" + circ = self.decompositions[0] + self.definition = circ.to_gate().definition def inverse(self): """Return inverse RZZ gate (i.e. with the negative rotation angle).""" @@ -108,11 +96,11 @@ def inverse(self): # TODO: this is the correct matrix and is equal to the definition above, # however the control mechanism cannot distinguish U1 and RZ yet. - # def to_matrix(self): - # """Return a numpy.array for the RZZ gate.""" - # import numpy - # theta = float(self.params[0]) - # return numpy.array([[numpy.exp(-1j*theta/2), 0, 0, 0], - # [0, numpy.exp(1j*theta/2), 0, 0], - # [0, 0, numpy.exp(1j*theta/2), 0], - # [0, 0, 0, numpy.exp(-1j*theta/2)]], dtype=complex) + def to_matrix(self): + """Return a numpy.array for the RZZ gate.""" + import numpy + itheta2 = 1j * float(self.params[0]) / 2 + return numpy.array([[numpy.exp(-itheta2), 0, 0, 0], + [0, numpy.exp(itheta2), 0, 0], + [0, 0, numpy.exp(itheta2), 0], + [0, 0, 0, numpy.exp(-itheta2)]], dtype=complex) diff --git a/qiskit/circuit/library/standard_gates/u3.py b/qiskit/circuit/library/standard_gates/u3.py index 26e19144c16e..e2fd5ad018c0 100644 --- a/qiskit/circuit/library/standard_gates/u3.py +++ b/qiskit/circuit/library/standard_gates/u3.py @@ -138,7 +138,7 @@ class CU3Gate(ControlledGate, metaclass=CU3Meta): U3(\theta,\phi,\lambda) \otimes |1\rangle\langle 1| = \begin{pmatrix} 1 & 0 & 0 & 0 \\ - 0 & \cos(\th) & 0 & e^{-i\lambda}\sin(\th) \\ + 0 & \cos(\th) & 0 & -e^{i\lambda}\sin(\th) \\ 0 & 0 & 1 & 0 \\ 0 & e^{i\phi}\sin(\th) & 0 & e^{i(\phi+\lambda)\cos(\th)} \end{pmatrix} @@ -165,7 +165,7 @@ class CU3Gate(ControlledGate, metaclass=CU3Meta): \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ - 0 & 0 & \cos(\th) & e^{-i\lambda}\sin(\th) \\ + 0 & 0 & \cos(\th) & -e^{i\lambda}\sin(\th) \\ 0 & 0 & e^{i\phi}\sin(\th) & e^{i(\phi+\lambda)\cos(\th)} \end{pmatrix} """ @@ -212,17 +212,25 @@ def inverse(self): # TODO: this is the correct definition but has a global phase with respect # to the decomposition above. Restore after allowing phase on circuits. - # def to_matrix(self): - # """Return a numpy.array for the CRY gate.""" - # theta, phi, lam = self.params - # cos = numpy.cos(theta / 2) - # sin = numpy.sin(theta / 2) - # return numpy.array([[1,0, 0, 0], - # [0, cos, 0, numpy.exp(-1j * lam) * sin], - # [0, 0, 1, 0], - # [0, numpy.exp(1j * phi) * sin, 0, numpy.exp(1j * (phi+lam)) * cos]], - # dtype=complex) - + def to_matrix(self): + """Return a numpy.array for the CRY gate.""" + theta, phi, lam = self.params + theta, phi, lam = float(theta), float(phi), float(lam) + cos = numpy.cos(theta / 2) + sin = numpy.sin(theta / 2) + if self.ctrl_state: + return numpy.array([[1,0, 0, 0], + [0, cos, 0, -numpy.exp(1j * lam) * sin], + [0, 0, 1, 0], + [0, numpy.exp(1j * phi) * sin, 0, numpy.exp(1j * (phi+lam)) * cos]], + dtype=complex) + else: + return numpy.array([[cos, 0, -numpy.exp(1j * lam / 2) * sin, 0], + [0, 1, 0, 0], + [numpy.exp(1j * phi) * sin, 0, numpy.exp(1j * (phi+lam)) * cos, 0], + [0, 0, 0, 1]], + dtype=complex) + class Cu3Gate(CU3Gate, metaclass=CU3Meta): """The deprecated CU3Gate class.""" diff --git a/qiskit/circuit/library/standard_gates/x.py b/qiskit/circuit/library/standard_gates/x.py index ac998678e591..6d81f096e95a 100644 --- a/qiskit/circuit/library/standard_gates/x.py +++ b/qiskit/circuit/library/standard_gates/x.py @@ -472,7 +472,8 @@ def __init__(self, angle=numpy.pi/4, label=None, ctrl_state=None): string (e.g. '110'), or None. If None, use all 1s. """ super().__init__('mcx', 4, [], num_ctrl_qubits=3, label=label, ctrl_state=ctrl_state) - self.base_gate = XGate() + from . import U3Gate + self.base_gate = U3Gate(angle*4, -pi/2, pi/2) self._angle = angle def _define(self): @@ -550,7 +551,12 @@ def inverse(self): """Invert this gate. The C3X is its own inverse.""" return C3XGate(angle=self._angle) - # This matrix is only correct if the angle is pi/4 + # def to_matrix(self): + # """Return a numpy.array for the C3X gate.""" + # return _compute_control_matrix(self.base_gate.to_matrix(), + # self.num_ctrl_qubits, + # ctrl_state=self.ctrl_state) + # def to_matrix(self): # """Return a numpy.array for the C3X gate.""" # return numpy.array([[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], @@ -732,6 +738,12 @@ def inverse(self): """Invert this gate. The C4X is its own inverse.""" return C4XGate() + def to_matrix(self): + """Return a numpy.array for the C4X gate.""" + return _compute_control_matrix(self.base_gate.to_matrix(), + self.num_ctrl_qubits, + ctrl_state=self.ctrl_state) + class MCXGate(ControlledGate): """The general, multi-controlled X gate.""" diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index 074d11fa2b83..4c9a7d0b15e2 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -278,6 +278,7 @@ def inverse(self): for inst, qargs, cargs in reversed(self._data): inverse_circ._append(inst.inverse(), qargs, cargs) + self.phase = -self.phase return inverse_circ def repeat(self, reps): diff --git a/qiskit/converters/circuit_to_gate.py b/qiskit/converters/circuit_to_gate.py index ccbfb76104f0..8f38ea906d54 100644 --- a/qiskit/converters/circuit_to_gate.py +++ b/qiskit/converters/circuit_to_gate.py @@ -14,7 +14,7 @@ """Helper function for converting a circuit to a gate""" - +from math import pi from qiskit.circuit.gate import Gate from qiskit.circuit.quantumregister import QuantumRegister, Qubit from qiskit.exceptions import QiskitError @@ -88,7 +88,7 @@ def find_bit_position(bit): phase = target.phase / len(target.qregs[0]) if target.phase: - target.u3(np.pi, phase, phase - np.pi, target.qregs[0]) + target.u3(pi, phase, phase - pi, target.qregs[0]) target.x(target.qregs[0]) definition = target.data diff --git a/qiskit/quantum_info/operators/operator.py b/qiskit/quantum_info/operators/operator.py index 1beab97092a3..c6a79e411e91 100644 --- a/qiskit/quantum_info/operators/operator.py +++ b/qiskit/quantum_info/operators/operator.py @@ -492,7 +492,6 @@ def _init_instruction(cls, instruction): # Convert circuit to an instruction if isinstance(instruction, QuantumCircuit): if instruction.phase: - #import ipdb;ipdb.set_trace() op *= ScalarOp(op.dim[0], np.exp(1j * float(instruction.phase))) instruction = instruction.to_instruction() op._append_instruction(instruction) diff --git a/test/python/circuit/test_gate_definitions.py b/test/python/circuit/test_gate_definitions.py index b2c63832bded..0df4ecf5b1f7 100644 --- a/test/python/circuit/test_gate_definitions.py +++ b/test/python/circuit/test_gate_definitions.py @@ -148,14 +148,6 @@ def test_equivalence_phase(self): with self.subTest(msg=gate.name + '_' + str(ieq)): op1 = Operator(gate) op2 = Operator(equivalency) - self.assertEqual(op1, op2) - try: - tomat = gate.to_matrix() - except (AttributeError, QiskitError): - pass - else: - print(gate_class) - self.assertTrue(np.allclose(op1.data, tomat)) @ddt From e89f14c6051038141f02fd107f0ec168face8786 Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Wed, 24 Jun 2020 19:52:51 -0400 Subject: [PATCH 09/38] revert base gate of c3x --- qiskit/circuit/library/standard_gates/x.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/qiskit/circuit/library/standard_gates/x.py b/qiskit/circuit/library/standard_gates/x.py index 6d81f096e95a..1fe7cab46d91 100644 --- a/qiskit/circuit/library/standard_gates/x.py +++ b/qiskit/circuit/library/standard_gates/x.py @@ -472,8 +472,9 @@ def __init__(self, angle=numpy.pi/4, label=None, ctrl_state=None): string (e.g. '110'), or None. If None, use all 1s. """ super().__init__('mcx', 4, [], num_ctrl_qubits=3, label=label, ctrl_state=ctrl_state) - from . import U3Gate - self.base_gate = U3Gate(angle*4, -pi/2, pi/2) + self.base_gate = XGate() + # from . import U3Gate + # self.base_gate = U3Gate(angle*4, -pi/2, pi/2) self._angle = angle def _define(self): From 82e5e986fb6ab35d2f21f2269408553a14e46c33 Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Fri, 26 Jun 2020 12:25:47 -0400 Subject: [PATCH 10/38] definition changed to circuit some multi-qubit controlled gate tests are still failing. --- qiskit/circuit/add_control.py | 14 +- qiskit/circuit/controlledgate.py | 30 +- qiskit/circuit/instruction.py | 31 +- qiskit/circuit/library/standard_gates/dcx.py | 20 +- qiskit/circuit/library/standard_gates/h.py | 80 ++-- .../circuit/library/standard_gates/iswap.py | 46 +- qiskit/circuit/library/standard_gates/ms.py | 24 +- qiskit/circuit/library/standard_gates/r.py | 30 +- qiskit/circuit/library/standard_gates/rx.py | 76 +-- qiskit/circuit/library/standard_gates/rxx.py | 40 +- qiskit/circuit/library/standard_gates/ry.py | 66 +-- qiskit/circuit/library/standard_gates/ryy.py | 42 +- qiskit/circuit/library/standard_gates/rz.py | 66 +-- qiskit/circuit/library/standard_gates/rzx.py | 24 +- qiskit/circuit/library/standard_gates/rzz.py | 32 +- qiskit/circuit/library/standard_gates/s.py | 52 +- qiskit/circuit/library/standard_gates/swap.py | 68 +-- qiskit/circuit/library/standard_gates/t.py | 52 +- qiskit/circuit/library/standard_gates/u1.py | 68 +-- qiskit/circuit/library/standard_gates/u2.py | 16 +- qiskit/circuit/library/standard_gates/u3.py | 52 +- qiskit/circuit/library/standard_gates/x.py | 452 +++++++++--------- qiskit/circuit/library/standard_gates/y.py | 52 +- qiskit/circuit/library/standard_gates/z.py | 52 +- qiskit/converters/ast_to_dag.py | 18 +- qiskit/converters/circuit_to_gate.py | 12 +- qiskit/converters/circuit_to_instruction.py | 12 +- qiskit/extensions/hamiltonian_gate.py | 4 +- .../quantum_initializer/diagonal.py | 2 +- .../quantum_initializer/initializer.py | 2 +- .../quantum_initializer/isometry.py | 2 +- .../quantum_initializer/mcg_up_to_diagonal.py | 2 +- qiskit/extensions/quantum_initializer/squ.py | 18 +- qiskit/extensions/quantum_initializer/uc.py | 2 +- .../quantum_initializer/uc_pauli_rot.py | 2 +- qiskit/extensions/unitary.py | 13 +- .../quantum_info/operators/channel/superop.py | 5 +- qiskit/quantum_info/operators/operator.py | 7 +- .../operators/symplectic/clifford_circuits.py | 5 +- qiskit/quantum_info/states/densitymatrix.py | 5 +- qiskit/quantum_info/states/statevector.py | 6 +- qiskit/transpiler/passes/basis/decompose.py | 2 +- .../passes/basis/unroll_3q_or_more.py | 2 +- .../passes/basis/unroll_custom_definitions.py | 5 +- qiskit/transpiler/passes/basis/unroller.py | 4 +- test/python/circuit/test_controlled_gate.py | 9 +- test/python/circuit/test_gate_definitions.py | 2 +- .../operators/symplectic/test_clifford.py | 8 +- .../test_unroll_custom_definitions.py | 9 +- 49 files changed, 858 insertions(+), 785 deletions(-) diff --git a/qiskit/circuit/add_control.py b/qiskit/circuit/add_control.py index df7b3a814d01..7ea93e100a3c 100644 --- a/qiskit/circuit/add_control.py +++ b/qiskit/circuit/add_control.py @@ -118,18 +118,19 @@ def control(operation: Union[Gate, ControlledGate], operation.base_gate.name == 'x'): qc.mct(q_control[:] + q_target[:-1], q_target[-1], q_ancillae) elif operation.name == 'rx': - qc.mcrx(operation.definition[0][0].params[0], q_control, q_target[0], + qc.mcrx(operation.definition.data[0][0].params[0], q_control, q_target[0], use_basis_gates=True) elif operation.name == 'ry': - qc.mcry(operation.definition[0][0].params[0], q_control, q_target[0], + qc.mcry(operation.definition.data[0][0].params[0], q_control, q_target[0], q_ancillae, mode='noancilla', use_basis_gates=True) elif operation.name == 'rz': - qc.mcrz(operation.definition[0][0].params[0], q_control, q_target[0], + qc.mcrz(operation.definition.data[0][0].params[0], q_control, q_target[0], use_basis_gates=True) else: bgate = _unroll_gate(operation, ['u1', 'u3', 'cx']) # now we have a bunch of single qubit rotation gates and cx - for rule in bgate.definition: + bgate.definition.data + for rule in bgate.definition.data: if rule[0].name == 'u3': theta, phi, lamb = rule[0].params if phi == -pi / 2 and lamb == pi / 2: @@ -156,7 +157,6 @@ def control(operation: Union[Gate, ControlledGate], else: raise CircuitError('gate contains non-controllable instructions') - instr = qc.to_instruction() if isinstance(operation, controlledgate.ControlledGate): new_num_ctrl_qubits = num_ctrl_qubits + operation.num_ctrl_qubits new_ctrl_state = operation.ctrl_state << num_ctrl_qubits | ctrl_state @@ -177,11 +177,11 @@ def control(operation: Union[Gate, ControlledGate], ctrl_substr = ('{0}' * new_num_ctrl_qubits).format('c') new_name = '{0}{1}'.format(ctrl_substr, base_name) cgate = controlledgate.ControlledGate(new_name, - instr.num_qubits, + qc.num_qubits, operation.params, label=label, num_ctrl_qubits=new_num_ctrl_qubits, - definition=instr.definition, + definition=qc, ctrl_state=new_ctrl_state) cgate.base_gate = base_gate return cgate diff --git a/qiskit/circuit/controlledgate.py b/qiskit/circuit/controlledgate.py index a080c3857fee..4794a7c41736 100644 --- a/qiskit/circuit/controlledgate.py +++ b/qiskit/circuit/controlledgate.py @@ -30,7 +30,7 @@ class ControlledGate(Gate): def __init__(self, name: str, num_qubits: int, params: List, label: Optional[str] = None, num_ctrl_qubits: Optional[int] = 1, - definition: Optional[List[Tuple[Gate, List[Qubit], List[Clbit]]]] = None, + definition: Optional['QuantumCircuit'] = None, ctrl_state: Optional[Union[int, str]] = None): """Create a new ControlledGate. In the new gate the first ``num_ctrl_qubits`` of the gate are the controls. @@ -92,8 +92,8 @@ def __init__(self, name: str, num_qubits: int, params: List, self.base_gate = None if definition: self.definition = definition - if len(definition) == 1: - base_gate = definition[0][0] + if len(definition.data) == 1: + base_gate = definition.data[0][0] if isinstance(base_gate, ControlledGate): self.base_gate = base_gate.base_gate else: @@ -108,28 +108,30 @@ def definition(self) -> List: definition is conjugated with X without changing the internal `_definition`. """ + from qiskit import QuantumCircuit if self._open_ctrl: closed_gate = self.copy() closed_gate.ctrl_state = None - # pylint: disable=cyclic-import - from qiskit.circuit.library.standard_gates import XGate bit_ctrl_state = bin(self.ctrl_state)[2:].zfill(self.num_ctrl_qubits) qreg = QuantumRegister(self.num_qubits, 'q') - definition = [(closed_gate, qreg, [])] - open_rules = [] + qc_open_ctrl = QuantumCircuit(qreg) for qind, val in enumerate(bit_ctrl_state[::-1]): if val == '0': - open_rules.append([XGate(), [qreg[qind]], []]) - if open_rules: - return open_rules + definition + open_rules - else: - return self._definition + qc_open_ctrl.x(qind) + qc_open_ctrl.append(closed_gate, qargs=qreg[:]) + for qind, val in enumerate(bit_ctrl_state[::-1]): + if val == '0': + qc_open_ctrl.x(qind) + return qc_open_ctrl else: return super().definition @definition.setter - def definition(self, excited_def: List): - """Set controlled gate definition with closed controls.""" + def definition(self, excited_def: 'QuantumCircuit'): + """Set controlled gate definition with closed controls. + + Args: + excited_def: The circuit with all closed controls.""" super(Gate, self.__class__).definition.fset(self, excited_def) @property diff --git a/qiskit/circuit/instruction.py b/qiskit/circuit/instruction.py index b14761e5f994..1e099f29ff64 100644 --- a/qiskit/circuit/instruction.py +++ b/qiskit/circuit/instruction.py @@ -128,7 +128,11 @@ def __eq__(self, other): def _define(self): """Populates self.definition with a decomposition of this gate.""" - pass + try: + self._definition = self.decompositions[0] + except IndexError: + # u3 or cx + pass @property def params(self): @@ -177,9 +181,13 @@ def definition(self): return self._definition @definition.setter - def definition(self, array): - """Set matrix representation""" - self._definition = array + def definition(self, definition): + """Set gate representation""" + from qiskit import QuantumCircuit + if not isinstance(definition, QuantumCircuit) and definition is not None: + raise CircuitError('Instruction definition must be QuantumCircuit. Got {}'.format( + type(definition))) + self._definition = definition @property def decompositions(self): @@ -246,9 +254,9 @@ def reverse_ops(self): return self.copy() reverse_inst = self.copy(name=self.name + '_reverse') - reverse_inst.definition = [] + reverse_inst.definition.data = [] for inst, qargs, cargs in reversed(self._definition): - reverse_inst._definition.append((inst.reverse_ops(), qargs, cargs)) + reverse_inst._definition.data.append((inst.reverse_ops(), qargs, cargs)) return reverse_inst def inverse(self): @@ -270,9 +278,9 @@ def inverse(self): if self.definition is None: raise CircuitError("inverse() not implemented for %s." % self.name) inverse_gate = self.copy(name=self.name + '_dg') - inverse_gate._definition = [] - for inst, qargs, cargs in reversed(self._definition): - inverse_gate._definition.append((inst.inverse(), qargs, cargs)) + inverse_gate._definition.data = [] + for inst, qargs, cargs in reversed(self._definition.data): + inverse_gate._definition.data.append((inst.inverse(), qargs, cargs)) return inverse_gate def c_if(self, classical, val): @@ -377,5 +385,8 @@ def repeat(self, n): qargs = [] if self.num_qubits == 0 else QuantumRegister(self.num_qubits, 'q') cargs = [] if self.num_clbits == 0 else ClassicalRegister(self.num_clbits, 'c') - instruction.definition = [(self, qargs[:], cargs[:])] * n + if instruction.definition is None: + from qiskit import QuantumCircuit + instruction.definition = QuantumCircuit(self.num_qubits) + instruction.definition.data = [(self, qargs[:], cargs[:])] * n return instruction diff --git a/qiskit/circuit/library/standard_gates/dcx.py b/qiskit/circuit/library/standard_gates/dcx.py index 4c27a777f5b4..a54146f0bd19 100644 --- a/qiskit/circuit/library/standard_gates/dcx.py +++ b/qiskit/circuit/library/standard_gates/dcx.py @@ -50,16 +50,16 @@ def __init__(self): """Create new DCX gate.""" super().__init__('dcx', 2, []) - def _define(self): - """ - gate dcx a, b { cx a, b; cx a, b; } - """ - from .x import CXGate - q = QuantumRegister(2, 'q') - self.definition = [ - (CXGate(), [q[0], q[1]], []), - (CXGate(), [q[1], q[0]], []) - ] + # def _define(self): + # """ + # gate dcx a, b { cx a, b; cx a, b; } + # """ + # from .x import CXGate + # q = QuantumRegister(2, 'q') + # self.definition = [ + # (CXGate(), [q[0], q[1]], []), + # (CXGate(), [q[1], q[0]], []) + # ] def to_matrix(self): """Return a numpy.array for the DCX gate.""" diff --git a/qiskit/circuit/library/standard_gates/h.py b/qiskit/circuit/library/standard_gates/h.py index 7a4463b23204..bead4fc368e2 100644 --- a/qiskit/circuit/library/standard_gates/h.py +++ b/qiskit/circuit/library/standard_gates/h.py @@ -53,19 +53,19 @@ def __init__(self, label=None): """Create new H gate.""" super().__init__('h', 1, [], label=label) - def _define(self): - """ - gate h a { u2(0,pi) a; } - """ - from .u2 import U2Gate - definition = [] - q = QuantumRegister(1, 'q') - rule = [ - (U2Gate(0, pi), [q[0]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # """ + # gate h a { u2(0,pi) a; } + # """ + # from .u2 import U2Gate + # definition = [] + # q = QuantumRegister(1, 'q') + # rule = [ + # (U2Gate(0, pi), [q[0]], []) + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Return a (multi-)controlled-H gate. @@ -169,33 +169,33 @@ def __init__(self, label=None, ctrl_state=None): ctrl_state=ctrl_state) self.base_gate = HGate() - def _define(self): - """ - gate ch a,b { - s b; - h b; - t b; - cx a, b; - tdg b; - h b; - sdg b; - } - """ - from .x import CXGate # pylint: disable=cyclic-import - definition = [] - q = QuantumRegister(2, 'q') - rule = [ - (SGate(), [q[1]], []), - (HGate(), [q[1]], []), - (TGate(), [q[1]], []), - (CXGate(), [q[0], q[1]], []), - (TdgGate(), [q[1]], []), - (HGate(), [q[1]], []), - (SdgGate(), [q[1]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # """ + # gate ch a,b { + # s b; + # h b; + # t b; + # cx a, b; + # tdg b; + # h b; + # sdg b; + # } + # """ + # from .x import CXGate # pylint: disable=cyclic-import + # definition = [] + # q = QuantumRegister(2, 'q') + # rule = [ + # (SGate(), [q[1]], []), + # (HGate(), [q[1]], []), + # (TGate(), [q[1]], []), + # (CXGate(), [q[0], q[1]], []), + # (TdgGate(), [q[1]], []), + # (HGate(), [q[1]], []), + # (SdgGate(), [q[1]], []) + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def inverse(self): """Return inverted CH gate (itself).""" diff --git a/qiskit/circuit/library/standard_gates/iswap.py b/qiskit/circuit/library/standard_gates/iswap.py index c2f38f22824b..3567d23c23b8 100644 --- a/qiskit/circuit/library/standard_gates/iswap.py +++ b/qiskit/circuit/library/standard_gates/iswap.py @@ -81,29 +81,29 @@ def __init__(self): """Create new iSwap gate.""" super().__init__('iswap', 2, []) - def _define(self): - """ - gate iswap a,b { - s q[0]; - s q[1]; - h q[0]; - cx q[0],q[1]; - cx q[1],q[0]; - h q[1]; - } - """ - from .h import HGate - from .s import SGate - from .x import CXGate - q = QuantumRegister(2, 'q') - self.definition = [ - (SGate(), [q[0]], []), - (SGate(), [q[1]], []), - (HGate(), [q[0]], []), - (CXGate(), [q[0], q[1]], []), - (CXGate(), [q[1], q[0]], []), - (HGate(), [q[1]], []) - ] + # def _define(self): + # """ + # gate iswap a,b { + # s q[0]; + # s q[1]; + # h q[0]; + # cx q[0],q[1]; + # cx q[1],q[0]; + # h q[1]; + # } + # """ + # from .h import HGate + # from .s import SGate + # from .x import CXGate + # q = QuantumRegister(2, 'q') + # self.definition = [ + # (SGate(), [q[0]], []), + # (SGate(), [q[1]], []), + # (HGate(), [q[0]], []), + # (CXGate(), [q[0], q[1]], []), + # (CXGate(), [q[1], q[0]], []), + # (HGate(), [q[1]], []) + # ] def to_matrix(self): """Return a numpy.array for the iSWAP gate.""" diff --git a/qiskit/circuit/library/standard_gates/ms.py b/qiskit/circuit/library/standard_gates/ms.py index 33170e3cd852..20b3a9043750 100644 --- a/qiskit/circuit/library/standard_gates/ms.py +++ b/qiskit/circuit/library/standard_gates/ms.py @@ -35,15 +35,15 @@ def __init__(self, num_qubits, theta, *, n_qubits=None, # pylint:disable=unused """Create new MS gate.""" super().__init__('ms', num_qubits, [theta], label=label) - def _define(self): - from .rxx import RXXGate - definition = [] - q = QuantumRegister(self.num_qubits, 'q') - rule = [] - for i in range(self.num_qubits): - for j in range(i + 1, self.num_qubits): - rule += [(RXXGate(self.params[0]), [q[i], q[j]], [])] - - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # from .rxx import RXXGate + # definition = [] + # q = QuantumRegister(self.num_qubits, 'q') + # rule = [] + # for i in range(self.num_qubits): + # for j in range(i + 1, self.num_qubits): + # rule += [(RXXGate(self.params[0]), [q[i], q[j]], [])] + + # for inst in rule: + # definition.append(inst) + # self.definition = definition diff --git a/qiskit/circuit/library/standard_gates/r.py b/qiskit/circuit/library/standard_gates/r.py index 11973a9a43b3..43780ec47122 100644 --- a/qiskit/circuit/library/standard_gates/r.py +++ b/qiskit/circuit/library/standard_gates/r.py @@ -48,21 +48,21 @@ def __init__(self, theta, phi): """Create new r single-qubit gate.""" super().__init__('r', 1, [theta, phi]) - def _define(self): - """ - gate r(θ, φ) a {u3(θ, φ - π/2, -φ + π/2) a;} - """ - from .u3 import U3Gate - definition = [] - q = QuantumRegister(1, 'q') - theta = self.params[0] - phi = self.params[1] - rule = [ - (U3Gate(theta, phi - pi / 2, -phi + pi / 2), [q[0]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # """ + # gate r(θ, φ) a {u3(θ, φ - π/2, -φ + π/2) a;} + # """ + # from .u3 import U3Gate + # definition = [] + # q = QuantumRegister(1, 'q') + # theta = self.params[0] + # phi = self.params[1] + # rule = [ + # (U3Gate(theta, phi - pi / 2, -phi + pi / 2), [q[0]], []) + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def inverse(self): """Invert this gate. diff --git a/qiskit/circuit/library/standard_gates/rx.py b/qiskit/circuit/library/standard_gates/rx.py index c28256c6e308..bfdb142c1ac8 100644 --- a/qiskit/circuit/library/standard_gates/rx.py +++ b/qiskit/circuit/library/standard_gates/rx.py @@ -50,19 +50,19 @@ def __init__(self, theta, label=None): """Create new RX gate.""" super().__init__('rx', 1, [theta], label=label) - def _define(self): - """ - gate rx(theta) a {r(theta, 0) a;} - """ - from .r import RGate - definition = [] - q = QuantumRegister(1, 'q') - rule = [ - (RGate(self.params[0], 0), [q[0]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # """ + # gate rx(theta) a {r(theta, 0) a;} + # """ + # from .r import RGate + # definition = [] + # q = QuantumRegister(1, 'q') + # rule = [ + # (RGate(self.params[0], 0), [q[0]], []) + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Return a (mutli-)controlled-RX gate. @@ -168,31 +168,31 @@ def __init__(self, theta, label=None, ctrl_state=None): label=label, ctrl_state=ctrl_state) self.base_gate = RXGate(theta) - def _define(self): - """ - gate cu3(theta,phi,lambda) c, t - { u1(pi/2) t; - cx c,t; - u3(-theta/2,0,0) t; - cx c,t; - u3(theta/2,-pi/2,0) t; - } - """ - from .u1 import U1Gate - from .u3 import U3Gate - from .x import CXGate - definition = [] - q = QuantumRegister(2, 'q') - rule = [ - (U1Gate(pi / 2), [q[1]], []), - (CXGate(), [q[0], q[1]], []), - (U3Gate(-self.params[0] / 2, 0, 0), [q[1]], []), - (CXGate(), [q[0], q[1]], []), - (U3Gate(self.params[0] / 2, -pi / 2, 0), [q[1]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # """ + # gate cu3(theta,phi,lambda) c, t + # { u1(pi/2) t; + # cx c,t; + # u3(-theta/2,0,0) t; + # cx c,t; + # u3(theta/2,-pi/2,0) t; + # } + # """ + # from .u1 import U1Gate + # from .u3 import U3Gate + # from .x import CXGate + # definition = [] + # q = QuantumRegister(2, 'q') + # rule = [ + # (U1Gate(pi / 2), [q[1]], []), + # (CXGate(), [q[0], q[1]], []), + # (U3Gate(-self.params[0] / 2, 0, 0), [q[1]], []), + # (CXGate(), [q[0], q[1]], []), + # (U3Gate(self.params[0] / 2, -pi / 2, 0), [q[1]], []) + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def inverse(self): """Return inverse RX gate (i.e. with the negative rotation angle).""" diff --git a/qiskit/circuit/library/standard_gates/rxx.py b/qiskit/circuit/library/standard_gates/rxx.py index 273afe1397b0..31955469507b 100644 --- a/qiskit/circuit/library/standard_gates/rxx.py +++ b/qiskit/circuit/library/standard_gates/rxx.py @@ -72,26 +72,26 @@ def __init__(self, theta): """Create new RXX gate.""" super().__init__('rxx', 2, [theta]) - def _define(self): - """Calculate a subcircuit that implements this unitary.""" - from .x import CXGate - from .u1 import U1Gate - from .h import HGate - definition = [] - q = QuantumRegister(2, 'q') - theta = self.params[0] - rule = [ - (HGate(), [q[0]], []), - (HGate(), [q[1]], []), - (CXGate(), [q[0], q[1]], []), - (U1Gate(theta), [q[1]], []), - (CXGate(), [q[0], q[1]], []), - (HGate(), [q[1]], []), - (HGate(), [q[0]], []), - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # """Calculate a subcircuit that implements this unitary.""" + # from .x import CXGate + # from .u1 import U1Gate + # from .h import HGate + # definition = [] + # q = QuantumRegister(2, 'q') + # theta = self.params[0] + # rule = [ + # (HGate(), [q[0]], []), + # (HGate(), [q[1]], []), + # (CXGate(), [q[0], q[1]], []), + # (U1Gate(theta), [q[1]], []), + # (CXGate(), [q[0], q[1]], []), + # (HGate(), [q[1]], []), + # (HGate(), [q[0]], []), + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def inverse(self): """Return inverse RXX gate (i.e. with the negative rotation angle).""" diff --git a/qiskit/circuit/library/standard_gates/ry.py b/qiskit/circuit/library/standard_gates/ry.py index b6ca8648fed7..f66438c52902 100644 --- a/qiskit/circuit/library/standard_gates/ry.py +++ b/qiskit/circuit/library/standard_gates/ry.py @@ -50,19 +50,19 @@ def __init__(self, theta, label=None): """Create new RY gate.""" super().__init__('ry', 1, [theta], label=label) - def _define(self): - """ - gate ry(theta) a { r(theta, pi/2) a; } - """ - from .r import RGate - definition = [] - q = QuantumRegister(1, 'q') - rule = [ - (RGate(self.params[0], pi / 2), [q[0]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # """ + # gate ry(theta) a { r(theta, pi/2) a; } + # """ + # from .r import RGate + # definition = [] + # q = QuantumRegister(1, 'q') + # rule = [ + # (RGate(self.params[0], pi / 2), [q[0]], []) + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Return a (mutli-)controlled-RY gate. @@ -168,26 +168,26 @@ def __init__(self, theta, label=None, ctrl_state=None): ctrl_state=ctrl_state) self.base_gate = RYGate(theta) - def _define(self): - """ - gate cry(lambda) a,b - { u3(lambda/2,0,0) b; cx a,b; - u3(-lambda/2,0,0) b; cx a,b; - } - """ - from .u3 import U3Gate - from .x import CXGate - definition = [] - q = QuantumRegister(2, 'q') - rule = [ - (U3Gate(self.params[0] / 2, 0, 0), [q[1]], []), - (CXGate(), [q[0], q[1]], []), - (U3Gate(-self.params[0] / 2, 0, 0), [q[1]], []), - (CXGate(), [q[0], q[1]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # """ + # gate cry(lambda) a,b + # { u3(lambda/2,0,0) b; cx a,b; + # u3(-lambda/2,0,0) b; cx a,b; + # } + # """ + # from .u3 import U3Gate + # from .x import CXGate + # definition = [] + # q = QuantumRegister(2, 'q') + # rule = [ + # (U3Gate(self.params[0] / 2, 0, 0), [q[1]], []), + # (CXGate(), [q[0], q[1]], []), + # (U3Gate(-self.params[0] / 2, 0, 0), [q[1]], []), + # (CXGate(), [q[0], q[1]], []) + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def inverse(self): """Return inverse RY gate (i.e. with the negative rotation angle).""" diff --git a/qiskit/circuit/library/standard_gates/ryy.py b/qiskit/circuit/library/standard_gates/ryy.py index b039b0fa4d6b..5e4b2ac45dc4 100644 --- a/qiskit/circuit/library/standard_gates/ryy.py +++ b/qiskit/circuit/library/standard_gates/ryy.py @@ -73,27 +73,27 @@ def __init__(self, theta): """Create new RYY gate.""" super().__init__('ryy', 2, [theta]) - def _define(self): - """Calculate a subcircuit that implements this unitary.""" - from .x import CXGate - from .rx import RXGate - from .rz import RZGate - - definition = [] - q = QuantumRegister(2, 'q') - theta = self.params[0] - rule = [ - (RXGate(np.pi / 2), [q[0]], []), - (RXGate(np.pi / 2), [q[1]], []), - (CXGate(), [q[0], q[1]], []), - (RZGate(theta), [q[1]], []), - (CXGate(), [q[0], q[1]], []), - (RXGate(-np.pi / 2), [q[0]], []), - (RXGate(-np.pi / 2), [q[1]], []), - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # """Calculate a subcircuit that implements this unitary.""" + # from .x import CXGate + # from .rx import RXGate + # from .rz import RZGate + + # definition = [] + # q = QuantumRegister(2, 'q') + # theta = self.params[0] + # rule = [ + # (RXGate(np.pi / 2), [q[0]], []), + # (RXGate(np.pi / 2), [q[1]], []), + # (CXGate(), [q[0], q[1]], []), + # (RZGate(theta), [q[1]], []), + # (CXGate(), [q[0], q[1]], []), + # (RXGate(-np.pi / 2), [q[0]], []), + # (RXGate(-np.pi / 2), [q[1]], []), + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def inverse(self): """Return inverse RYY gate (i.e. with the negative rotation angle).""" diff --git a/qiskit/circuit/library/standard_gates/rz.py b/qiskit/circuit/library/standard_gates/rz.py index 8ee5b7c97c7f..1c0d13bfe738 100644 --- a/qiskit/circuit/library/standard_gates/rz.py +++ b/qiskit/circuit/library/standard_gates/rz.py @@ -60,19 +60,19 @@ def __init__(self, phi, label=None): """Create new RZ gate.""" super().__init__('rz', 1, [phi], label=label) - def _define(self): - """ - gate rz(phi) a { u1(phi) a; } - """ - from .u1 import U1Gate - definition = [] - q = QuantumRegister(1, 'q') - rule = [ - (U1Gate(self.params[0]), [q[0]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # """ + # gate rz(phi) a { u1(phi) a; } + # """ + # from .u1 import U1Gate + # definition = [] + # q = QuantumRegister(1, 'q') + # rule = [ + # (U1Gate(self.params[0]), [q[0]], []) + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Return a (mutli-)controlled-RZ gate. @@ -186,26 +186,26 @@ def __init__(self, theta, label=None, ctrl_state=None): ctrl_state=ctrl_state) self.base_gate = RZGate(theta) - def _define(self): - """ - gate crz(lambda) a,b - { u1(lambda/2) b; cx a,b; - u1(-lambda/2) b; cx a,b; - } - """ - from .u1 import U1Gate - from .x import CXGate - definition = [] - q = QuantumRegister(2, 'q') - rule = [ - (U1Gate(self.params[0] / 2), [q[1]], []), - (CXGate(), [q[0], q[1]], []), - (U1Gate(-self.params[0] / 2), [q[1]], []), - (CXGate(), [q[0], q[1]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # """ + # gate crz(lambda) a,b + # { u1(lambda/2) b; cx a,b; + # u1(-lambda/2) b; cx a,b; + # } + # """ + # from .u1 import U1Gate + # from .x import CXGate + # definition = [] + # q = QuantumRegister(2, 'q') + # rule = [ + # (U1Gate(self.params[0] / 2), [q[1]], []), + # (CXGate(), [q[0], q[1]], []), + # (U1Gate(-self.params[0] / 2), [q[1]], []), + # (CXGate(), [q[0], q[1]], []) + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def inverse(self): """Return inverse RZ gate (i.e. with the negative rotation angle).""" diff --git a/qiskit/circuit/library/standard_gates/rzx.py b/qiskit/circuit/library/standard_gates/rzx.py index d1b756318d0d..1d3ae2e99cc1 100644 --- a/qiskit/circuit/library/standard_gates/rzx.py +++ b/qiskit/circuit/library/standard_gates/rzx.py @@ -121,18 +121,18 @@ def __init__(self, theta): """Create new RZX gate.""" super().__init__('rzx', 2, [theta]) - def _define(self): - """ - gate rzx(theta) a, b { h b; cx a, b; u1(theta) b; cx a, b; h b;} - """ - q = QuantumRegister(2, 'q') - self.definition = [ - (HGate(), [q[1]], []), - (CXGate(), [q[0], q[1]], []), - (RZGate(self.params[0]), [q[1]], []), - (CXGate(), [q[0], q[1]], []), - (HGate(), [q[1]], []) - ] + # def _define(self): + # """ + # gate rzx(theta) a, b { h b; cx a, b; u1(theta) b; cx a, b; h b;} + # """ + # q = QuantumRegister(2, 'q') + # self.definition = [ + # (HGate(), [q[1]], []), + # (CXGate(), [q[0], q[1]], []), + # (RZGate(self.params[0]), [q[1]], []), + # (CXGate(), [q[0], q[1]], []), + # (HGate(), [q[1]], []) + # ] def inverse(self): """Return inverse RZX gate (i.e. with the negative rotation angle).""" diff --git a/qiskit/circuit/library/standard_gates/rzz.py b/qiskit/circuit/library/standard_gates/rzz.py index e526cb36719f..b426434fbf3f 100644 --- a/qiskit/circuit/library/standard_gates/rzz.py +++ b/qiskit/circuit/library/standard_gates/rzz.py @@ -85,22 +85,22 @@ def __init__(self, theta): """Create new RZZ gate.""" super().__init__('rzz', 2, [theta]) - def _define(self): - """ - gate rzz(theta) a, b { cx a, b; u1(theta) b; cx a, b; } - """ - from .u1 import U1Gate - from .x import CXGate - definition = [] - q = QuantumRegister(2, 'q') - rule = [ - (CXGate(), [q[0], q[1]], []), - (U1Gate(self.params[0]), [q[1]], []), - (CXGate(), [q[0], q[1]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # """ + # gate rzz(theta) a, b { cx a, b; u1(theta) b; cx a, b; } + # """ + # from .u1 import U1Gate + # from .x import CXGate + # definition = [] + # q = QuantumRegister(2, 'q') + # rule = [ + # (CXGate(), [q[0], q[1]], []), + # (U1Gate(self.params[0]), [q[1]], []), + # (CXGate(), [q[0], q[1]], []) + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def inverse(self): """Return inverse RZZ gate (i.e. with the negative rotation angle).""" diff --git a/qiskit/circuit/library/standard_gates/s.py b/qiskit/circuit/library/standard_gates/s.py index fd603b616285..497b7ec675c2 100644 --- a/qiskit/circuit/library/standard_gates/s.py +++ b/qiskit/circuit/library/standard_gates/s.py @@ -51,19 +51,19 @@ def __init__(self, label=None): """Create new S gate.""" super().__init__('s', 1, [], label=label) - def _define(self): - """ - gate s a { u1(pi/2) a; } - """ - from .u1 import U1Gate - definition = [] - q = QuantumRegister(1, 'q') - rule = [ - (U1Gate(pi / 2), [q[0]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # """ + # gate s a { u1(pi/2) a; } + # """ + # from .u1 import U1Gate + # definition = [] + # q = QuantumRegister(1, 'q') + # rule = [ + # (U1Gate(pi / 2), [q[0]], []) + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def inverse(self): """Return inverse of S (SdgGate).""" @@ -106,19 +106,19 @@ def __init__(self, label=None): """Create new Sdg gate.""" super().__init__('sdg', 1, [], label=label) - def _define(self): - """ - gate sdg a { u1(-pi/2) a; } - """ - from .u1 import U1Gate - definition = [] - q = QuantumRegister(1, 'q') - rule = [ - (U1Gate(-pi / 2), [q[0]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # """ + # gate sdg a { u1(-pi/2) a; } + # """ + # from .u1 import U1Gate + # definition = [] + # q = QuantumRegister(1, 'q') + # rule = [ + # (U1Gate(-pi / 2), [q[0]], []) + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def inverse(self): """Return inverse of Sdg (SGate).""" diff --git a/qiskit/circuit/library/standard_gates/swap.py b/qiskit/circuit/library/standard_gates/swap.py index f1e6a5d5389b..864ffc2e0502 100644 --- a/qiskit/circuit/library/standard_gates/swap.py +++ b/qiskit/circuit/library/standard_gates/swap.py @@ -56,21 +56,21 @@ def __init__(self, label=None): """Create new SWAP gate.""" super().__init__('swap', 2, [], label=label) - def _define(self): - """ - gate swap a,b { cx a,b; cx b,a; cx a,b; } - """ - from .x import CXGate - definition = [] - q = QuantumRegister(2, 'q') - rule = [ - (CXGate(), [q[0], q[1]], []), - (CXGate(), [q[1], q[0]], []), - (CXGate(), [q[0], q[1]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # """ + # gate swap a,b { cx a,b; cx b,a; cx a,b; } + # """ + # from .x import CXGate + # definition = [] + # q = QuantumRegister(2, 'q') + # rule = [ + # (CXGate(), [q[0], q[1]], []), + # (CXGate(), [q[1], q[0]], []), + # (CXGate(), [q[0], q[1]], []) + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Return a (multi-)controlled-SWAP gate. @@ -210,25 +210,25 @@ def __init__(self, label=None, ctrl_state=None): ctrl_state=ctrl_state) self.base_gate = SwapGate() - def _define(self): - """ - gate cswap a,b,c - { cx c,b; - ccx a,b,c; - cx c,b; - } - """ - from .x import CXGate, CCXGate - definition = [] - q = QuantumRegister(3, 'q') - rule = [ - (CXGate(), [q[2], q[1]], []), - (CCXGate(), [q[0], q[1], q[2]], []), - (CXGate(), [q[2], q[1]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # """ + # gate cswap a,b,c + # { cx c,b; + # ccx a,b,c; + # cx c,b; + # } + # """ + # from .x import CXGate, CCXGate + # definition = [] + # q = QuantumRegister(3, 'q') + # rule = [ + # (CXGate(), [q[2], q[1]], []), + # (CCXGate(), [q[0], q[1], q[2]], []), + # (CXGate(), [q[2], q[1]], []) + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def inverse(self): """Return inverse CSwap gate (itself).""" diff --git a/qiskit/circuit/library/standard_gates/t.py b/qiskit/circuit/library/standard_gates/t.py index e52da07be905..8950a6efeecb 100644 --- a/qiskit/circuit/library/standard_gates/t.py +++ b/qiskit/circuit/library/standard_gates/t.py @@ -52,19 +52,19 @@ def __init__(self, label=None): """Create new T gate.""" super().__init__('t', 1, [], label=label) - def _define(self): - """ - gate t a { u1(pi/4) a; } - """ - from .u1 import U1Gate - definition = [] - q = QuantumRegister(1, 'q') - rule = [ - (U1Gate(pi / 4), [q[0]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # """ + # gate t a { u1(pi/4) a; } + # """ + # from .u1 import U1Gate + # definition = [] + # q = QuantumRegister(1, 'q') + # rule = [ + # (U1Gate(pi / 4), [q[0]], []) + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def inverse(self): """Return inverse T gate (i.e. Tdg).""" @@ -107,19 +107,19 @@ def __init__(self, label=None): """Create new Tdg gate.""" super().__init__('tdg', 1, [], label=label) - def _define(self): - """ - gate tdg a { u1(pi/4) a; } - """ - from .u1 import U1Gate - definition = [] - q = QuantumRegister(1, 'q') - rule = [ - (U1Gate(-pi / 4), [q[0]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # """ + # gate tdg a { u1(pi/4) a; } + # """ + # from .u1 import U1Gate + # definition = [] + # q = QuantumRegister(1, 'q') + # rule = [ + # (U1Gate(-pi / 4), [q[0]], []) + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def inverse(self): """Return inverse Tdg gate (i.e. T).""" diff --git a/qiskit/circuit/library/standard_gates/u1.py b/qiskit/circuit/library/standard_gates/u1.py index 4c9f5bb18204..b5939b5fa8cc 100644 --- a/qiskit/circuit/library/standard_gates/u1.py +++ b/qiskit/circuit/library/standard_gates/u1.py @@ -79,16 +79,16 @@ def __init__(self, theta, label=None): """Create new U1 gate.""" super().__init__('u1', 1, [theta], label=label) - def _define(self): - from .u3 import U3Gate # pylint: disable=cyclic-import - definition = [] - q = QuantumRegister(1, 'q') - rule = [ - (U3Gate(0, 0, self.params[0]), [q[0]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # from .u3 import U3Gate # pylint: disable=cyclic-import + # definition = [] + # q = QuantumRegister(1, 'q') + # rule = [ + # (U3Gate(0, 0, self.params[0]), [q[0]], []) + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Return a (mutli-)controlled-U1 gate. @@ -175,27 +175,27 @@ def __init__(self, theta, label=None, ctrl_state=None): ctrl_state=ctrl_state) self.base_gate = U1Gate(theta) - def _define(self): - """ - gate cu1(lambda) a,b - { u1(lambda/2) a; cx a,b; - u1(-lambda/2) b; cx a,b; - u1(lambda/2) b; - } - """ - from .x import CXGate # pylint: disable=cyclic-import - definition = [] - q = QuantumRegister(2, 'q') - rule = [ - (U1Gate(self.params[0] / 2), [q[0]], []), - (CXGate(), [q[0], q[1]], []), - (U1Gate(-self.params[0] / 2), [q[1]], []), - (CXGate(), [q[0], q[1]], []), - (U1Gate(self.params[0] / 2), [q[1]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # """ + # gate cu1(lambda) a,b + # { u1(lambda/2) a; cx a,b; + # u1(-lambda/2) b; cx a,b; + # u1(lambda/2) b; + # } + # """ + # from .x import CXGate # pylint: disable=cyclic-import + # definition = [] + # q = QuantumRegister(2, 'q') + # rule = [ + # (U1Gate(self.params[0] / 2), [q[0]], []), + # (CXGate(), [q[0], q[1]], []), + # (U1Gate(-self.params[0] / 2), [q[1]], []), + # (CXGate(), [q[0], q[1]], []), + # (U1Gate(self.params[0] / 2), [q[1]], []) + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Controlled version of this gate. @@ -275,7 +275,9 @@ def __init__(self, lam, num_ctrl_qubits, label=None): self.base_gate = U1Gate(lam) def _define(self): + from qiskit import QuantumCircuit q = QuantumRegister(self.num_qubits, 'q') + qc = QuantumCircuit(q, name=self.name) if self.num_ctrl_qubits == 0: definition = U1Gate(self.params[0]).definition @@ -286,8 +288,8 @@ def _define(self): scaled_lam = self.params[0] / (2 ** (self.num_ctrl_qubits - 1)) bottom_gate = CU1Gate(scaled_lam) definition = _gray_code_chain(q, self.num_ctrl_qubits, bottom_gate) - - self.definition = definition + qc.data = definition + self.definition = qc def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Controlled version of this gate. diff --git a/qiskit/circuit/library/standard_gates/u2.py b/qiskit/circuit/library/standard_gates/u2.py index 7b9831711c2e..ea299cc68fa2 100644 --- a/qiskit/circuit/library/standard_gates/u2.py +++ b/qiskit/circuit/library/standard_gates/u2.py @@ -63,14 +63,14 @@ def __init__(self, phi, lam, label=None): """Create new U2 gate.""" super().__init__('u2', 1, [phi, lam], label=label) - def _define(self): - from .u3 import U3Gate - definition = [] - q = QuantumRegister(1, 'q') - rule = [(U3Gate(pi / 2, self.params[0], self.params[1]), [q[0]], [])] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # from .u3 import U3Gate + # definition = [] + # q = QuantumRegister(1, 'q') + # rule = [(U3Gate(pi / 2, self.params[0], self.params[1]), [q[0]], [])] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def inverse(self): r"""Return inverted U2 gate. diff --git a/qiskit/circuit/library/standard_gates/u3.py b/qiskit/circuit/library/standard_gates/u3.py index 221e444bc78f..f05772b64f76 100644 --- a/qiskit/circuit/library/standard_gates/u3.py +++ b/qiskit/circuit/library/standard_gates/u3.py @@ -180,32 +180,32 @@ def __init__(self, theta, phi, lam, label=None, ctrl_state=None): label=label, ctrl_state=ctrl_state) self.base_gate = U3Gate(theta, phi, lam) - def _define(self): - """ - gate cu3(theta,phi,lambda) c, t - { u1((lambda+phi)/2) c; - u1((lambda-phi)/2) t; - cx c,t; - u3(-theta/2,0,-(phi+lambda)/2) t; - cx c,t; - u3(theta/2,phi,0) t; - } - """ - from .u1 import U1Gate - from .x import CXGate # pylint: disable=cyclic-import - definition = [] - q = QuantumRegister(2, 'q') - rule = [ - (U1Gate((self.params[2] + self.params[1]) / 2), [q[0]], []), - (U1Gate((self.params[2] - self.params[1]) / 2), [q[1]], []), - (CXGate(), [q[0], q[1]], []), - (U3Gate(-self.params[0] / 2, 0, -(self.params[1] + self.params[2]) / 2), [q[1]], []), - (CXGate(), [q[0], q[1]], []), - (U3Gate(self.params[0] / 2, self.params[1], 0), [q[1]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # """ + # gate cu3(theta,phi,lambda) c, t + # { u1((lambda+phi)/2) c; + # u1((lambda-phi)/2) t; + # cx c,t; + # u3(-theta/2,0,-(phi+lambda)/2) t; + # cx c,t; + # u3(theta/2,phi,0) t; + # } + # """ + # from .u1 import U1Gate + # from .x import CXGate # pylint: disable=cyclic-import + # definition = [] + # q = QuantumRegister(2, 'q') + # rule = [ + # (U1Gate((self.params[2] + self.params[1]) / 2), [q[0]], []), + # (U1Gate((self.params[2] - self.params[1]) / 2), [q[1]], []), + # (CXGate(), [q[0], q[1]], []), + # (U3Gate(-self.params[0] / 2, 0, -(self.params[1] + self.params[2]) / 2), [q[1]], []), + # (CXGate(), [q[0], q[1]], []), + # (U3Gate(self.params[0] / 2, self.params[1], 0), [q[1]], []) + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def inverse(self): r"""Return inverted CU3 gate. diff --git a/qiskit/circuit/library/standard_gates/x.py b/qiskit/circuit/library/standard_gates/x.py index ac998678e591..e59b7dd5dbf4 100644 --- a/qiskit/circuit/library/standard_gates/x.py +++ b/qiskit/circuit/library/standard_gates/x.py @@ -74,19 +74,11 @@ def __init__(self, label=None): """Create new X gate.""" super().__init__('x', 1, [], label=label) - def _define(self): - """ - gate x a { u3(pi,0,pi) a; } - """ - from .u3 import U3Gate - definition = [] - q = QuantumRegister(1, 'q') - rule = [ - (U3Gate(pi, 0, pi), [q[0]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # """ + # gate x a { u3(pi,0,pi) a; } + # """ + # self.definition = self.decompositions[0] def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Return a (mutli-)controlled-X gate. @@ -320,37 +312,41 @@ def __init__(self, label=None, ctrl_state=None): ctrl_state=ctrl_state) self.base_gate = XGate() - def _define(self): - """ - gate ccx a,b,c - { - h c; cx b,c; tdg c; cx a,c; - t c; cx b,c; tdg c; cx a,c; - t b; t c; h c; cx a,b; - t a; tdg b; cx a,b;} - """ - definition = [] - q = QuantumRegister(3, 'q') - rule = [ - (HGate(), [q[2]], []), - (CXGate(), [q[1], q[2]], []), - (TdgGate(), [q[2]], []), - (CXGate(), [q[0], q[2]], []), - (TGate(), [q[2]], []), - (CXGate(), [q[1], q[2]], []), - (TdgGate(), [q[2]], []), - (CXGate(), [q[0], q[2]], []), - (TGate(), [q[1]], []), - (TGate(), [q[2]], []), - (HGate(), [q[2]], []), - (CXGate(), [q[0], q[1]], []), - (TGate(), [q[0]], []), - (TdgGate(), [q[1]], []), - (CXGate(), [q[0], q[1]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # circ = self.decompositions[0] + # self._definition = circ + + # def _define(self): + # """ + # gate ccx a,b,c + # { + # h c; cx b,c; tdg c; cx a,c; + # t c; cx b,c; tdg c; cx a,c; + # t b; t c; h c; cx a,b; + # t a; tdg b; cx a,b;} + # """ + # definition = [] + # q = QuantumRegister(3, 'q') + # rule = [ + # (HGate(), [q[2]], []), + # (CXGate(), [q[1], q[2]], []), + # (TdgGate(), [q[2]], []), + # (CXGate(), [q[0], q[2]], []), + # (TGate(), [q[2]], []), + # (CXGate(), [q[1], q[2]], []), + # (TdgGate(), [q[2]], []), + # (CXGate(), [q[0], q[2]], []), + # (TGate(), [q[1]], []), + # (TGate(), [q[2]], []), + # (HGate(), [q[2]], []), + # (CXGate(), [q[0], q[1]], []), + # (TGate(), [q[0]], []), + # (TdgGate(), [q[1]], []), + # (CXGate(), [q[0], q[1]], []) + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Controlled version of this gate. @@ -411,34 +407,34 @@ def __init__(self, label=None): """Create a new simplified CCX gate.""" super().__init__('rccx', 3, [], label=label) - def _define(self): - """ - gate rccx a,b,c - { u2(0,pi) c; - u1(pi/4) c; - cx b, c; - u1(-pi/4) c; - cx a, c; - u1(pi/4) c; - cx b, c; - u1(-pi/4) c; - u2(0,pi) c; - } - """ - definition = [] - q = QuantumRegister(3, 'q') - definition = [ - (U2Gate(0, pi), [q[2]], []), # H gate - (U1Gate(pi / 4), [q[2]], []), # T gate - (CXGate(), [q[1], q[2]], []), - (U1Gate(-pi / 4), [q[2]], []), # inverse T gate - (CXGate(), [q[0], q[2]], []), - (U1Gate(pi / 4), [q[2]], []), - (CXGate(), [q[1], q[2]], []), - (U1Gate(-pi / 4), [q[2]], []), # inverse T gate - (U2Gate(0, pi), [q[2]], []), # H gate - ] - self.definition = definition + # def _define(self): + # """ + # gate rccx a,b,c + # { u2(0,pi) c; + # u1(pi/4) c; + # cx b, c; + # u1(-pi/4) c; + # cx a, c; + # u1(pi/4) c; + # cx b, c; + # u1(-pi/4) c; + # u2(0,pi) c; + # } + # """ + # definition = [] + # q = QuantumRegister(3, 'q') + # definition = [ + # (U2Gate(0, pi), [q[2]], []), # H gate + # (U1Gate(pi / 4), [q[2]], []), # T gate + # (CXGate(), [q[1], q[2]], []), + # (U1Gate(-pi / 4), [q[2]], []), # inverse T gate + # (CXGate(), [q[0], q[2]], []), + # (U1Gate(pi / 4), [q[2]], []), + # (CXGate(), [q[1], q[2]], []), + # (U1Gate(-pi / 4), [q[2]], []), # inverse T gate + # (U2Gate(0, pi), [q[2]], []), # H gate + # ] + # self.definition = definition def to_matrix(self): """Return a numpy.array for the simplified CCX gate.""" @@ -475,57 +471,57 @@ def __init__(self, angle=numpy.pi/4, label=None, ctrl_state=None): self.base_gate = XGate() self._angle = angle - def _define(self): - """ - gate c3x a,b,c,d - { - h d; cu1(-pi/4) a,d; h d; - cx a,b; - h d; cu1(pi/4) b,d; h d; - cx a,b; - h d; cu1(-pi/4) b,d; h d; - cx b,c; - h d; cu1(pi/4) c,d; h d; - cx a,c; - h d; cu1(-pi/4) c,d; h d; - cx b,c; - h d; cu1(pi/4) c,d; h d; - cx a,c; - h d; cu1(-pi/4) c,d; h d; - } - """ - from .u1 import CU1Gate - q = QuantumRegister(4, name='q') - definition = [ - (HGate(), [q[3]], []), - (CU1Gate(-self._angle), [q[0], q[3]], []), - (HGate(), [q[3]], []), - (CXGate(), [q[0], q[1]], []), - (HGate(), [q[3]], []), - (CU1Gate(self._angle), [q[1], q[3]], []), - (HGate(), [q[3]], []), - (CXGate(), [q[0], q[1]], []), - (HGate(), [q[3]], []), - (CU1Gate(-self._angle), [q[1], q[3]], []), - (HGate(), [q[3]], []), - (CXGate(), [q[1], q[2]], []), - (HGate(), [q[3]], []), - (CU1Gate(self._angle), [q[2], q[3]], []), - (HGate(), [q[3]], []), - (CXGate(), [q[0], q[2]], []), - (HGate(), [q[3]], []), - (CU1Gate(-self._angle), [q[2], q[3]], []), - (HGate(), [q[3]], []), - (CXGate(), [q[1], q[2]], []), - (HGate(), [q[3]], []), - (CU1Gate(self._angle), [q[2], q[3]], []), - (HGate(), [q[3]], []), - (CXGate(), [q[0], q[2]], []), - (HGate(), [q[3]], []), - (CU1Gate(-self._angle), [q[2], q[3]], []), - (HGate(), [q[3]], []) - ] - self.definition = definition + # def _define(self): + # """ + # gate c3x a,b,c,d + # { + # h d; cu1(-pi/4) a,d; h d; + # cx a,b; + # h d; cu1(pi/4) b,d; h d; + # cx a,b; + # h d; cu1(-pi/4) b,d; h d; + # cx b,c; + # h d; cu1(pi/4) c,d; h d; + # cx a,c; + # h d; cu1(-pi/4) c,d; h d; + # cx b,c; + # h d; cu1(pi/4) c,d; h d; + # cx a,c; + # h d; cu1(-pi/4) c,d; h d; + # } + # """ + # from .u1 import CU1Gate + # q = QuantumRegister(4, name='q') + # definition = [ + # (HGate(), [q[3]], []), + # (CU1Gate(-self._angle), [q[0], q[3]], []), + # (HGate(), [q[3]], []), + # (CXGate(), [q[0], q[1]], []), + # (HGate(), [q[3]], []), + # (CU1Gate(self._angle), [q[1], q[3]], []), + # (HGate(), [q[3]], []), + # (CXGate(), [q[0], q[1]], []), + # (HGate(), [q[3]], []), + # (CU1Gate(-self._angle), [q[1], q[3]], []), + # (HGate(), [q[3]], []), + # (CXGate(), [q[1], q[2]], []), + # (HGate(), [q[3]], []), + # (CU1Gate(self._angle), [q[2], q[3]], []), + # (HGate(), [q[3]], []), + # (CXGate(), [q[0], q[2]], []), + # (HGate(), [q[3]], []), + # (CU1Gate(-self._angle), [q[2], q[3]], []), + # (HGate(), [q[3]], []), + # (CXGate(), [q[1], q[2]], []), + # (HGate(), [q[3]], []), + # (CU1Gate(self._angle), [q[2], q[3]], []), + # (HGate(), [q[3]], []), + # (CXGate(), [q[0], q[2]], []), + # (HGate(), [q[3]], []), + # (CU1Gate(-self._angle), [q[2], q[3]], []), + # (HGate(), [q[3]], []) + # ] + # self.definition = definition def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Controlled version of this gate. @@ -586,52 +582,52 @@ def __init__(self, label=None): """Create a new RC3X gate.""" super().__init__('rcccx', 4, [], label=label) - def _define(self): - """ - gate rc3x a,b,c,d - { u2(0,pi) d; - u1(pi/4) d; - cx c,d; - u1(-pi/4) d; - u2(0,pi) d; - cx a,d; - u1(pi/4) d; - cx b,d; - u1(-pi/4) d; - cx a,d; - u1(pi/4) d; - cx b,d; - u1(-pi/4) d; - u2(0,pi) d; - u1(pi/4) d; - cx c,d; - u1(-pi/4) d; - u2(0,pi) d; - } - """ - q = QuantumRegister(4, 'q') - - definition = [ - (U2Gate(0, pi), [q[3]], []), # H gate - (U1Gate(pi / 4), [q[3]], []), # T gate - (CXGate(), [q[2], q[3]], []), - (U1Gate(-pi / 4), [q[3]], []), # inverse T gate - (U2Gate(0, pi), [q[3]], []), - (CXGate(), [q[0], q[3]], []), - (U1Gate(pi / 4), [q[3]], []), - (CXGate(), [q[1], q[3]], []), - (U1Gate(-pi / 4), [q[3]], []), - (CXGate(), [q[0], q[3]], []), - (U1Gate(pi / 4), [q[3]], []), - (CXGate(), [q[1], q[3]], []), - (U1Gate(-pi / 4), [q[3]], []), - (U2Gate(0, pi), [q[3]], []), - (U1Gate(pi / 4), [q[3]], []), - (CXGate(), [q[2], q[3]], []), - (U1Gate(-pi / 4), [q[3]], []), - (U2Gate(0, pi), [q[3]], []), - ] - self.definition = definition + # def _define(self): + # """ + # gate rc3x a,b,c,d + # { u2(0,pi) d; + # u1(pi/4) d; + # cx c,d; + # u1(-pi/4) d; + # u2(0,pi) d; + # cx a,d; + # u1(pi/4) d; + # cx b,d; + # u1(-pi/4) d; + # cx a,d; + # u1(pi/4) d; + # cx b,d; + # u1(-pi/4) d; + # u2(0,pi) d; + # u1(pi/4) d; + # cx c,d; + # u1(-pi/4) d; + # u2(0,pi) d; + # } + # """ + # q = QuantumRegister(4, 'q') + + # definition = [ + # (U2Gate(0, pi), [q[3]], []), # H gate + # (U1Gate(pi / 4), [q[3]], []), # T gate + # (CXGate(), [q[2], q[3]], []), + # (U1Gate(-pi / 4), [q[3]], []), # inverse T gate + # (U2Gate(0, pi), [q[3]], []), + # (CXGate(), [q[0], q[3]], []), + # (U1Gate(pi / 4), [q[3]], []), + # (CXGate(), [q[1], q[3]], []), + # (U1Gate(-pi / 4), [q[3]], []), + # (CXGate(), [q[0], q[3]], []), + # (U1Gate(pi / 4), [q[3]], []), + # (CXGate(), [q[1], q[3]], []), + # (U1Gate(-pi / 4), [q[3]], []), + # (U2Gate(0, pi), [q[3]], []), + # (U1Gate(pi / 4), [q[3]], []), + # (CXGate(), [q[2], q[3]], []), + # (U1Gate(-pi / 4), [q[3]], []), + # (U2Gate(0, pi), [q[3]], []), + # ] + # self.definition = definition def to_matrix(self): """Return a numpy.array for the RC3X gate.""" @@ -667,47 +663,48 @@ def __init__(self, label=None, ctrl_state=None): super().__init__('mcx', 5, [], num_ctrl_qubits=4, label=label, ctrl_state=ctrl_state) self.base_gate = XGate() - def _define(self): - """ - gate c3sqrtx a,b,c,d - { - h d; cu1(-pi/8) a,d; h d; - cx a,b; - h d; cu1(pi/8) b,d; h d; - cx a,b; - h d; cu1(-pi/8) b,d; h d; - cx b,c; - h d; cu1(pi/8) c,d; h d; - cx a,c; - h d; cu1(-pi/8) c,d; h d; - cx b,c; - h d; cu1(pi/8) c,d; h d; - cx a,c; - h d; cu1(-pi/8) c,d; h d; - } - gate c4x a,b,c,d,e - { - h e; cu1(-pi/2) d,e; h e; - c3x a,b,c,d; - h d; cu1(pi/4) d,e; h d; - c3x a,b,c,d; - c3sqrtx a,b,c,e; - } - """ - from .u1 import CU1Gate - q = QuantumRegister(5, name='q') - definition = [ - (HGate(), [q[4]], []), - (CU1Gate(-numpy.pi / 2), [q[3], q[4]], []), - (HGate(), [q[4]], []), - (C3XGate(), [q[0], q[1], q[2], q[3]], []), - (HGate(), [q[4]], []), - (CU1Gate(numpy.pi / 2), [q[3], q[4]], []), - (HGate(), [q[4]], []), - (C3XGate(), [q[0], q[1], q[2], q[3]], []), - (C3XGate(numpy.pi / 8), [q[0], q[1], q[2], q[4]], []), - ] - self.definition = definition + # seems like open controls not hapening? + # def _define(self): + # """ + # gate c3sqrtx a,b,c,d + # { + # h d; cu1(-pi/8) a,d; h d; + # cx a,b; + # h d; cu1(pi/8) b,d; h d; + # cx a,b; + # h d; cu1(-pi/8) b,d; h d; + # cx b,c; + # h d; cu1(pi/8) c,d; h d; + # cx a,c; + # h d; cu1(-pi/8) c,d; h d; + # cx b,c; + # h d; cu1(pi/8) c,d; h d; + # cx a,c; + # h d; cu1(-pi/8) c,d; h d; + # } + # gate c4x a,b,c,d,e + # { + # h e; cu1(-pi/2) d,e; h e; + # c3x a,b,c,d; + # h d; cu1(pi/4) d,e; h d; + # c3x a,b,c,d; + # c3sqrtx a,b,c,e; + # } + # """ + # from .u1 import CU1Gate + # q = QuantumRegister(5, name='q') + # definition = [ + # (HGate(), [q[4]], []), + # (CU1Gate(-numpy.pi / 2), [q[3], q[4]], []), + # (HGate(), [q[4]], []), + # (C3XGate(), [q[0], q[1], q[2], q[3]], []), + # (HGate(), [q[4]], []), + # (CU1Gate(numpy.pi / 2), [q[3], q[4]], []), + # (HGate(), [q[4]], []), + # (C3XGate(), [q[0], q[1], q[2], q[3]], []), + # (C3XGate(numpy.pi / 8), [q[0], q[1], q[2], q[4]], []), + # ] + # self.definition = definition def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Controlled version of this gate. @@ -782,10 +779,11 @@ def get_num_ancilla_qubits(num_ctrl_qubits, mode='noancilla'): def _define(self): """The standard definition used the Gray code implementation.""" + from qiskit import QuantumCircuit q = QuantumRegister(self.num_qubits, name='q') - self.definition = [ - (MCXGrayCode(self.num_ctrl_qubits), q[:], []) - ] + qc = QuantumCircuit(q) + qc.append(MCXGrayCode(self.num_ctrl_qubits), qargs=q[:]) + self.definition = qc @property def num_ancilla_qubits(self): @@ -824,13 +822,14 @@ def __init__(self, num_ctrl_qubits, label=None, ctrl_state=None): def _define(self): """Define the MCX gate using the Gray code.""" + from qiskit import QuantumCircuit from .u1 import MCU1Gate q = QuantumRegister(self.num_qubits, name='q') - self.definition = [ - (HGate(), [q[-1]], []), - (MCU1Gate(numpy.pi, num_ctrl_qubits=self.num_ctrl_qubits), q[:], []), - (HGate(), [q[-1]], []) - ] + qc = QuantumCircuit(q, name=self.name) + qc.h(q[-1]) + qc.append(MCU1Gate(numpy.pi, num_ctrl_qubits=self.num_ctrl_qubits), qargs=q[:]) + qc.h(q[-1]) + self.definition = qc class MCXRecursive(MCXGate): @@ -851,13 +850,19 @@ def get_num_ancilla_qubits(num_ctrl_qubits, mode='recursion'): def _define(self): """Define the MCX gate using recursion.""" + from qiskit import QuantumCircuit + #import ipdb;ipdb.set_trace() q = QuantumRegister(self.num_qubits, name='q') + qc = QuantumCircuit(q, name=self.name) if self.num_qubits == 4: - self.definition = [(C3XGate(), q[:], [])] + qc.append(C3XGate(), qargs=q[:]) + self.definition = qc elif self.num_qubits == 5: - self.definition = [(C4XGate(), q[:], [])] + qc.append(C4XGate(), qargs=q[:]) + self.definition = qc else: - self.definition = self._recurse(q[:-1], q_ancilla=q[-1]) + self.definition = qc + self.definition.data = self._recurse(q[:-1], q_ancilla=q[-1]) def _recurse(self, q, q_ancilla=None): # recursion stop @@ -905,7 +910,9 @@ def get_num_ancilla_qubits(num_ctrl_qubits, mode='v-chain'): def _define(self): """Define the MCX gate using a V-chain of CX gates.""" + from qiskit import QuantumCircuit q = QuantumRegister(self.num_qubits, name='q') + qc = QuantumCircuit(q, name=self.name) q_controls = q[:self.num_ctrl_qubits] q_target = q[self.num_ctrl_qubits] q_ancillas = q[self.num_ctrl_qubits + 1:] @@ -966,4 +973,5 @@ def _define(self): definition.append( (RCCXGate(), [q_controls[j], q_ancillas[i], q_ancillas[i + 1]], [])) - self.definition = definition + qc.data = definition + self.definition = qc diff --git a/qiskit/circuit/library/standard_gates/y.py b/qiskit/circuit/library/standard_gates/y.py index eb5d1cb255b1..d66263687e35 100644 --- a/qiskit/circuit/library/standard_gates/y.py +++ b/qiskit/circuit/library/standard_gates/y.py @@ -68,16 +68,16 @@ def __init__(self, label=None): """Create new Y gate.""" super().__init__('y', 1, [], label=label) - def _define(self): - from .u3 import U3Gate - definition = [] - q = QuantumRegister(1, 'q') - rule = [ - (U3Gate(pi, pi / 2, pi / 2), [q[0]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # from .u3 import U3Gate + # definition = [] + # q = QuantumRegister(1, 'q') + # rule = [ + # (U3Gate(pi, pi / 2, pi / 2), [q[0]], []) + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Return a (mutli-)controlled-Y gate. @@ -187,22 +187,22 @@ def __init__(self, label=None, ctrl_state=None): ctrl_state=ctrl_state) self.base_gate = YGate() - def _define(self): - """ - gate cy a,b { sdg b; cx a,b; s b; } - """ - from .s import SGate, SdgGate - from .x import CXGate - definition = [] - q = QuantumRegister(2, 'q') - rule = [ - (SdgGate(), [q[1]], []), - (CXGate(), [q[0], q[1]], []), - (SGate(), [q[1]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # """ + # gate cy a,b { sdg b; cx a,b; s b; } + # """ + # from .s import SGate, SdgGate + # from .x import CXGate + # definition = [] + # q = QuantumRegister(2, 'q') + # rule = [ + # (SdgGate(), [q[1]], []), + # (CXGate(), [q[0], q[1]], []), + # (SGate(), [q[1]], []) + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def inverse(self): """Return inverted CY gate (itself).""" diff --git a/qiskit/circuit/library/standard_gates/z.py b/qiskit/circuit/library/standard_gates/z.py index 2001f03e6412..820d0e38ff33 100644 --- a/qiskit/circuit/library/standard_gates/z.py +++ b/qiskit/circuit/library/standard_gates/z.py @@ -68,16 +68,16 @@ def __init__(self, label=None): """Create new Z gate.""" super().__init__('z', 1, [], label=label) - def _define(self): - from .u1 import U1Gate - definition = [] - q = QuantumRegister(1, 'q') - rule = [ - (U1Gate(pi), [q[0]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # from .u1 import U1Gate + # definition = [] + # q = QuantumRegister(1, 'q') + # rule = [ + # (U1Gate(pi), [q[0]], []) + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Return a (mutli-)controlled-Z gate. @@ -155,22 +155,22 @@ def __init__(self, label=None, ctrl_state=None): ctrl_state=ctrl_state) self.base_gate = ZGate() - def _define(self): - """ - gate cz a,b { h b; cx a,b; h b; } - """ - from .h import HGate - from .x import CXGate - definition = [] - q = QuantumRegister(2, 'q') - rule = [ - (HGate(), [q[1]], []), - (CXGate(), [q[0], q[1]], []), - (HGate(), [q[1]], []) - ] - for inst in rule: - definition.append(inst) - self.definition = definition + # def _define(self): + # """ + # gate cz a,b { h b; cx a,b; h b; } + # """ + # from .h import HGate + # from .x import CXGate + # definition = [] + # q = QuantumRegister(2, 'q') + # rule = [ + # (HGate(), [q[1]], []), + # (CXGate(), [q[0], q[1]], []), + # (HGate(), [q[1]], []) + # ] + # for inst in rule: + # definition.append(inst) + # self.definition = definition def inverse(self): """Return inverted CZ gate (itself).""" diff --git a/qiskit/converters/ast_to_dag.py b/qiskit/converters/ast_to_dag.py index 235291f7b6e8..2a9192e56f1d 100644 --- a/qiskit/converters/ast_to_dag.py +++ b/qiskit/converters/ast_to_dag.py @@ -21,7 +21,7 @@ from qiskit.dagcircuit import DAGCircuit from qiskit.exceptions import QiskitError -from qiskit.circuit import QuantumRegister, ClassicalRegister, Gate +from qiskit.circuit import QuantumRegister, ClassicalRegister, Gate, QuantumCircuit from qiskit.qasm.node.real import Real from qiskit.circuit.instruction import Instruction from qiskit.circuit.measure import Measure @@ -363,9 +363,9 @@ def _process_node(self, node): "file=%s" % node.file) return None - def _gate_definition_to_qiskit_definition(self, node, params): - """From a gate definition in qasm, to a gate.definition format.""" - definition = [] + def _gate_rules_to_qiskit_circuit(self, node, params): + """From a gate definition in qasm, to a QuantumCircuit format.""" + rules = [] qreg = QuantumRegister(node['n_bits']) bit_args = {node['bits'][i]: q for i, q in enumerate(qreg)} exp_args = {node['args'][i]: Real(q) for i, q in enumerate(params)} @@ -380,8 +380,10 @@ def _gate_definition_to_qiskit_definition(self, node, params): for param in param_list.children: eparams.append(param.sym(nested_scope=[exp_args])) op = self._create_op(child_op.name, params=eparams) - definition.append((op, qparams, [])) - return definition + rules.append((op, qparams, [])) + circ = QuantumCircuit(qreg) + circ.data = rules + return circ def _create_dag_op(self, name, params, qargs): """ @@ -411,8 +413,8 @@ def _create_op(self, name, params): num_qubits=self.gates[name]['n_bits'], num_clbits=0, params=params) - op.definition = self._gate_definition_to_qiskit_definition(self.gates[name], - params=params) + op.definition = self._gate_rules_to_qiskit_circuit(self.gates[name], + params=params) else: raise QiskitError("unknown operation for ast node name %s" % name) return op diff --git a/qiskit/converters/circuit_to_gate.py b/qiskit/converters/circuit_to_gate.py index ac0d0e36877d..d9234e83556c 100644 --- a/qiskit/converters/circuit_to_gate.py +++ b/qiskit/converters/circuit_to_gate.py @@ -15,6 +15,7 @@ """Helper function for converting a circuit to a gate""" +from qiskit.circuit import QuantumCircuit from qiskit.circuit.gate import Gate from qiskit.circuit.quantumregister import QuantumRegister, Qubit from qiskit.exceptions import QiskitError @@ -86,7 +87,7 @@ def find_bit_position(bit): if equivalence_library is not None: equivalence_library.add_equivalence(gate, target) - definition = target.data + rules = target.data if gate.num_qubits > 0: q = QuantumRegister(gate.num_qubits, 'q') @@ -94,11 +95,12 @@ def find_bit_position(bit): # The 3rd parameter in the output tuple) is hard coded to [] because # Gate objects do not have cregs set and we've verified that all # instructions are gates - definition = list(map( + rules = list(map( lambda x: (x[0], list(map(lambda y: q[find_bit_position(y)], x[1])), []), - definition)) - gate.definition = definition - + rules)) + qc = QuantumCircuit(q, name=gate.name) + qc.data = rules + gate.definition = qc return gate diff --git a/qiskit/converters/circuit_to_instruction.py b/qiskit/converters/circuit_to_instruction.py index e4411f0b257e..ebb830c3ecab 100644 --- a/qiskit/converters/circuit_to_instruction.py +++ b/qiskit/converters/circuit_to_instruction.py @@ -15,6 +15,7 @@ """Helper function for converting a circuit to an instruction.""" from qiskit.exceptions import QiskitError +from qiskit.circuit import QuantumCircuit from qiskit.circuit.instruction import Instruction from qiskit.circuit.quantumregister import QuantumRegister, Qubit from qiskit.circuit.classicalregister import ClassicalRegister @@ -95,15 +96,22 @@ def find_bit_position(bit): definition = target.data + qregs = [] if instruction.num_qubits > 0: q = QuantumRegister(instruction.num_qubits, 'q') + qregs.append(q) + if instruction.num_clbits > 0: c = ClassicalRegister(instruction.num_clbits, 'c') - + qregs.append(c) + definition = list(map(lambda x: (x[0], list(map(lambda y: q[find_bit_position(y)], x[1])), list(map(lambda y: c[find_bit_position(y)], x[2]))), definition)) - instruction.definition = definition + + qc = QuantumCircuit(*qregs, name=instruction.name) + qc.data = definition + instruction.definition = qc return instruction diff --git a/qiskit/extensions/hamiltonian_gate.py b/qiskit/extensions/hamiltonian_gate.py index 05eef9da2dca..64f956a5e57f 100644 --- a/qiskit/extensions/hamiltonian_gate.py +++ b/qiskit/extensions/hamiltonian_gate.py @@ -107,7 +107,9 @@ def transpose(self): def _define(self): """Calculate a subcircuit that implements this unitary.""" q = QuantumRegister(self.num_qubits, 'q') - self.definition = [(UnitaryGate(self.to_matrix()), q[:], [])] + qc = QuantumCircuit(q, name=self.name) + qc.append(UnitaryGate(self.to_matrix()), qargs=q[:]) + self.definition = qc def qasm(self): """Raise an error, as QASM is not defined for the HamiltonianGate.""" diff --git a/qiskit/extensions/quantum_initializer/diagonal.py b/qiskit/extensions/quantum_initializer/diagonal.py index 1083ffd36946..e90a45fd375c 100644 --- a/qiskit/extensions/quantum_initializer/diagonal.py +++ b/qiskit/extensions/quantum_initializer/diagonal.py @@ -77,7 +77,7 @@ def _define(self): q = QuantumRegister(self.num_qubits) diag_circuit = QuantumCircuit(q) diag_circuit.append(gate, q[:]) - self.definition = diag_circuit.data + self.definition = diag_circuit def _dec_diag(self): """ diff --git a/qiskit/extensions/quantum_initializer/initializer.py b/qiskit/extensions/quantum_initializer/initializer.py index 900f9a996d2f..f4dcd0b00ef1 100644 --- a/qiskit/extensions/quantum_initializer/initializer.py +++ b/qiskit/extensions/quantum_initializer/initializer.py @@ -84,7 +84,7 @@ def _define(self): initialize_circuit.append(Reset(), [qubit]) initialize_circuit.append(initialize_instr, q[:]) - self.definition = initialize_circuit.data + self.definition = initialize_circuit def gates_to_uncompute(self): """Call to create a circuit with gates that take the desired vector to zero. diff --git a/qiskit/extensions/quantum_initializer/isometry.py b/qiskit/extensions/quantum_initializer/isometry.py index 24c64ccbeeda..7e48ab28011e 100644 --- a/qiskit/extensions/quantum_initializer/isometry.py +++ b/qiskit/extensions/quantum_initializer/isometry.py @@ -104,7 +104,7 @@ def _define(self): q = QuantumRegister(self.num_qubits) iso_circuit = QuantumCircuit(q) iso_circuit.append(gate, q[:]) - self.definition = iso_circuit.data + self.definition = iso_circuit def _gates_to_uncompute(self): """ diff --git a/qiskit/extensions/quantum_initializer/mcg_up_to_diagonal.py b/qiskit/extensions/quantum_initializer/mcg_up_to_diagonal.py index 01f71829eacf..6fb841cfa8e2 100644 --- a/qiskit/extensions/quantum_initializer/mcg_up_to_diagonal.py +++ b/qiskit/extensions/quantum_initializer/mcg_up_to_diagonal.py @@ -73,7 +73,7 @@ def _define(self): q = QuantumRegister(self.num_qubits) mcg_up_diag_circuit = QuantumCircuit(q) mcg_up_diag_circuit.append(gate, q[:]) - self.definition = mcg_up_diag_circuit.data + self.definition = mcg_up_diag_circuit # Returns the diagonal up to which the gate is implemented. def _get_diagonal(self): diff --git a/qiskit/extensions/quantum_initializer/squ.py b/qiskit/extensions/quantum_initializer/squ.py index 0fbc182de230..817224ca5216 100644 --- a/qiskit/extensions/quantum_initializer/squ.py +++ b/qiskit/extensions/quantum_initializer/squ.py @@ -79,32 +79,34 @@ def _define(self): """Define the gate using the decomposition.""" if self.mode == 'ZYZ': - rule, diag = self._zyz_rule() + circuit, diag = self._zyz_circuit() else: raise QiskitError('The decomposition mode is not known.') self._diag = diag - self.definition = rule + + self.definition = circuit - def _zyz_rule(self): - """Get the circuit rule for the ZYZ decomposition.""" + def _zyz_circuit(self): + """Get the circuit for the ZYZ decomposition.""" q = QuantumRegister(self.num_qubits) + qc = QuantumCircuit(q, name=self.name) rule = [] diag = [1., 1.] alpha, beta, gamma, _ = self._zyz_dec() if abs(alpha) > _EPS: - rule += [(RZGate(alpha), [q[0]], [])] + qc.rz(alpha, q[0]) if abs(beta) > _EPS: - rule += [(RYGate(beta), [q[0]], [])] + qc.ry(beta, q[0]) if abs(gamma) > _EPS: if self.up_to_diagonal: diag = [np.exp(-1j * gamma / 2.), np.exp(1j * gamma / 2.)] else: - rule += [(RZGate(gamma), [q[0]], [])] + qc.rz(gamma, q[0]) - return rule, diag + return qc, diag def _zyz_dec(self): """Finds rotation angles (a,b,c,d) in the decomposition u=exp(id)*Rz(c).Ry(b).Rz(a). diff --git a/qiskit/extensions/quantum_initializer/uc.py b/qiskit/extensions/quantum_initializer/uc.py index bfba80c691b0..1654d2d48e31 100644 --- a/qiskit/extensions/quantum_initializer/uc.py +++ b/qiskit/extensions/quantum_initializer/uc.py @@ -117,7 +117,7 @@ def _get_diagonal(self): def _define(self): ucg_circuit, _ = self._dec_ucg() - self.definition = ucg_circuit.data + self.definition = ucg_circuit def _dec_ucg(self): """ diff --git a/qiskit/extensions/quantum_initializer/uc_pauli_rot.py b/qiskit/extensions/quantum_initializer/uc_pauli_rot.py index d2487f84e0bb..6271d3ba2084 100644 --- a/qiskit/extensions/quantum_initializer/uc_pauli_rot.py +++ b/qiskit/extensions/quantum_initializer/uc_pauli_rot.py @@ -85,7 +85,7 @@ def _define(self): q = QuantumRegister(self.num_qubits) ucr_circuit = QuantumCircuit(q) ucr_circuit.append(gate, q[:]) - self.definition = ucr_circuit.data + self.definition = ucr_circuit def _dec_ucrot(self): """ diff --git a/qiskit/extensions/unitary.py b/qiskit/extensions/unitary.py index 4f48f5f81b2b..271080106a97 100644 --- a/qiskit/extensions/unitary.py +++ b/qiskit/extensions/unitary.py @@ -107,14 +107,17 @@ def _define(self): """Calculate a subcircuit that implements this unitary.""" if self.num_qubits == 1: q = QuantumRegister(1, "q") + qc = QuantumCircuit(q, name=self.name) theta, phi, lam = _DECOMPOSER1Q.angles(self.to_matrix()) - self.definition = [(U3Gate(theta, phi, lam), [q[0]], [])] + qc.u3(theta, phi, lam, q[0]) + self.definition = qc elif self.num_qubits == 2: - self.definition = two_qubit_cnot_decompose(self.to_matrix()).data + self.definition = two_qubit_cnot_decompose(self.to_matrix()) else: q = QuantumRegister(self.num_qubits, "q") - self.definition = [(isometry.Isometry(self.to_matrix(), 0, 0), - q[:], [])] + qc = QuantumCircuit(q, name=self.name) + qc.append(isometry.Isometry(self.to_matrix(), 0, 0), qargs=q[:]) + self.definition = qc def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): r"""Return controlled version of gate @@ -166,7 +169,7 @@ def qasm(self): current_reg = 0 gates_def = "" - for gate in self.definition: + for gate in self.definition.data: # add regs from this gate to the overall set of params for reg in gate[1] + gate[2]: diff --git a/qiskit/quantum_info/operators/channel/superop.py b/qiskit/quantum_info/operators/channel/superop.py index 399847a9e626..5952cf653ae1 100644 --- a/qiskit/quantum_info/operators/channel/superop.py +++ b/qiskit/quantum_info/operators/channel/superop.py @@ -391,7 +391,10 @@ def _append_instruction(self, obj, qargs=None): if obj.definition is None: raise QiskitError('Cannot apply Instruction: {}'.format( obj.name)) - for instr, qregs, cregs in obj.definition: + if not isinstance(obj.definition, QuantumCircuit): + raise QiskitError('{0} instruction definition is {1}; expected QuantumCircuit'.format( + obj.name, type(obj.definition))) + for instr, qregs, cregs in obj.definition.data: if cregs: raise QiskitError( 'Cannot apply instruction with classical registers: {}' diff --git a/qiskit/quantum_info/operators/operator.py b/qiskit/quantum_info/operators/operator.py index 2d2b9000932b..1478f788939d 100644 --- a/qiskit/quantum_info/operators/operator.py +++ b/qiskit/quantum_info/operators/operator.py @@ -522,7 +522,12 @@ def _append_instruction(self, obj, qargs=None): # cannot compose this gate and raise an error. if obj.definition is None: raise QiskitError('Cannot apply Instruction: {}'.format(obj.name)) - for instr, qregs, cregs in obj.definition: + if not isinstance(obj.definition, QuantumCircuit): + raise QiskitError('Instruction "{}" ' + 'definition is {} but expected QuantumCircuit.'.format( + obj.name, type(obj.definition))) + flat_instr = obj.definition.to_instruction() + for instr, qregs, cregs in flat_instr.definition.data: if cregs: raise QiskitError( 'Cannot apply instruction with classical registers: {}'.format( diff --git a/qiskit/quantum_info/operators/symplectic/clifford_circuits.py b/qiskit/quantum_info/operators/symplectic/clifford_circuits.py index 447e70acaa13..a7b41d4e9b4b 100644 --- a/qiskit/quantum_info/operators/symplectic/clifford_circuits.py +++ b/qiskit/quantum_info/operators/symplectic/clifford_circuits.py @@ -84,7 +84,10 @@ def _append_circuit(clifford, circuit, qargs=None): # are a single qubit Clifford gate rather than raise an exception. if gate.definition is None: raise QiskitError('Cannot apply Instruction: {}'.format(gate.name)) - for instr, qregs, cregs in gate.definition: + if not isinstance(gate.definition, QuantumCircuit): + raise QiskitError('{0} instruction definition is {1}; expected QuantumCircuit'.format( + gate.name, type(gate.definition))) + for instr, qregs, cregs in gate.definition.data: if cregs: raise QiskitError( 'Cannot apply Instruction with classical registers: {}'.format( diff --git a/qiskit/quantum_info/states/densitymatrix.py b/qiskit/quantum_info/states/densitymatrix.py index a200eb1fa8e3..809e336143f7 100644 --- a/qiskit/quantum_info/states/densitymatrix.py +++ b/qiskit/quantum_info/states/densitymatrix.py @@ -575,7 +575,10 @@ def _append_instruction(self, other, qargs=None): if other.definition is None: raise QiskitError('Cannot apply Instruction: {}'.format( other.name)) - for instr, qregs, cregs in other.definition: + if not isinstance(other.definition, QuantumCircuit): + raise QiskitError('{0} instruction definition is {1}; expected QuantumCircuit'.format( + other.name, type(other.definition))) + for instr, qregs, cregs in other.definition.data: if cregs: raise QiskitError( 'Cannot apply instruction with classical registers: {}'. diff --git a/qiskit/quantum_info/states/statevector.py b/qiskit/quantum_info/states/statevector.py index ee457ae55d8e..8503c1f5450a 100644 --- a/qiskit/quantum_info/states/statevector.py +++ b/qiskit/quantum_info/states/statevector.py @@ -617,8 +617,10 @@ def _append_instruction(self, obj, qargs=None): # cannot compose this gate and raise an error. if obj.definition is None: raise QiskitError('Cannot apply Instruction: {}'.format(obj.name)) - - for instr, qregs, cregs in obj.definition: + if not isinstance(obj.definition, QuantumCircuit): + raise QiskitError('{0} instruction definition is {1}; expected QuantumCircuit'.format( + obj.name, type(obj.definition))) + for instr, qregs, cregs in obj.definition.data: if cregs: raise QiskitError( 'Cannot apply instruction with classical registers: {}'.format( diff --git a/qiskit/transpiler/passes/basis/decompose.py b/qiskit/transpiler/passes/basis/decompose.py index 3125874e7c08..3517b6f0c40d 100644 --- a/qiskit/transpiler/passes/basis/decompose.py +++ b/qiskit/transpiler/passes/basis/decompose.py @@ -48,7 +48,7 @@ def run(self, dag: DAGCircuit) -> DAGCircuit: if not node.op.definition: continue # TODO: allow choosing among multiple decomposition rules - rule = node.op.definition + rule = node.op.definition.data if len(rule) == 1 and len(node.qargs) == len(rule[0][1]): dag.substitute_node(node, rule[0][0], inplace=True) diff --git a/qiskit/transpiler/passes/basis/unroll_3q_or_more.py b/qiskit/transpiler/passes/basis/unroll_3q_or_more.py index 968e74011ed3..b95e01998702 100644 --- a/qiskit/transpiler/passes/basis/unroll_3q_or_more.py +++ b/qiskit/transpiler/passes/basis/unroll_3q_or_more.py @@ -34,7 +34,7 @@ def run(self, dag): """ for node in dag.multi_qubit_ops(): # TODO: allow choosing other possible decompositions - rule = node.op.definition + rule = node.op.definition.data if not rule: if rule == []: # empty node dag.remove_op_node(node) diff --git a/qiskit/transpiler/passes/basis/unroll_custom_definitions.py b/qiskit/transpiler/passes/basis/unroll_custom_definitions.py index 4d4e9373d717..8e9bc90dc7a8 100644 --- a/qiskit/transpiler/passes/basis/unroll_custom_definitions.py +++ b/qiskit/transpiler/passes/basis/unroll_custom_definitions.py @@ -66,9 +66,12 @@ def run(self, dag): continue try: - rule = node.op.definition + rule = node.op.definition.data except TypeError as err: raise QiskitError('Error decomposing node {}: {}'.format(node.name, err)) + except AttributeError as aerr: + # definition is None + rule = None if not rule: if rule == []: diff --git a/qiskit/transpiler/passes/basis/unroller.py b/qiskit/transpiler/passes/basis/unroller.py index de878c6f4dad..0763236e1d3c 100644 --- a/qiskit/transpiler/passes/basis/unroller.py +++ b/qiskit/transpiler/passes/basis/unroller.py @@ -69,7 +69,7 @@ def run(self, dag): # TODO: allow choosing other possible decompositions try: - rule = node.op.definition + rule = node.op.definition.data except TypeError as err: raise QiskitError('Error decomposing node {}: {}'.format(node.name, err)) @@ -82,7 +82,7 @@ def run(self, dag): dag.substitute_node(node, rule[0][0], inplace=True) break try: - rule = rule[0][0].definition + rule = rule[0][0].definition.data except TypeError as err: raise QiskitError('Error decomposing node {}: {}'.format(node.name, err)) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index a9c89863e2ee..5e305614e211 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -574,7 +574,9 @@ def test_mcx_gates(self, num_ctrl_qubits): i = int(bin(i)[2:].zfill(circuit.num_qubits)[gate.num_ancilla_qubits:], 2) corrected[i] += statevector_amplitude statevector = corrected - + np.set_printoptions(precision=3, linewidth=200, suppress=True) + # if isinstance(gate, MCXRecursive): + # import ipdb;ipdb.set_trace() np.testing.assert_array_almost_equal(statevector.real, reference) @data(1, 2, 3, 4) @@ -1010,10 +1012,12 @@ def test_controlled_standard_gates(self, num_ctrl_qubits, gate_class): for ctrl_state in {ctrl_state_ones, ctrl_state_zeros, ctrl_state_mixed}: with self.subTest(i='{0}, ctrl_state={1}'.format(gate_class.__name__, ctrl_state)): + np.set_printoptions(precision=3, linewidth=200, suppress=True) if hasattr(gate, 'num_ancilla_qubits') and gate.num_ancilla_qubits > 0: # skip matrices that include ancilla qubits continue try: + #import ipdb;ipdb.set_trace() cgate = gate.control(num_ctrl_qubits, ctrl_state=ctrl_state) except (AttributeError, QiskitError): # 'object has no attribute "control"' @@ -1027,6 +1031,9 @@ def test_controlled_standard_gates(self, num_ctrl_qubits, gate_class): base_mat = Operator(gate).data target_mat = _compute_control_matrix(base_mat, num_ctrl_qubits, ctrl_state=ctrl_state) + + #import ipdb;ipdb.set_trace() + src_mat = Operator(cgate).data self.assertTrue(matrix_equal(Operator(cgate).data, target_mat, ignore_phase=True)) diff --git a/test/python/circuit/test_gate_definitions.py b/test/python/circuit/test_gate_definitions.py index 02673e5fc669..c23c8ce0ecde 100644 --- a/test/python/circuit/test_gate_definitions.py +++ b/test/python/circuit/test_gate_definitions.py @@ -136,7 +136,7 @@ def test_definition_parameters(self, gate_class): param_entry = std_eqlib.get_entry(param_gate) float_entry = std_eqlib.get_entry(float_gate) - if not param_gate.definition: + if not param_gate.definition or not param_gate.definition.data: self.assertEqual(len(param_entry), 0) self.assertEqual(len(float_entry), 0) return diff --git a/test/python/quantum_info/operators/symplectic/test_clifford.py b/test/python/quantum_info/operators/symplectic/test_clifford.py index 971a9fd528ae..8cf3af2252b8 100644 --- a/test/python/quantum_info/operators/symplectic/test_clifford.py +++ b/test/python/quantum_info/operators/symplectic/test_clifford.py @@ -42,7 +42,9 @@ def __init__(self): def _define(self): """V Gate definition.""" q = QuantumRegister(1, 'q') - self.definition = [(SdgGate(), [q[0]], []), (HGate(), [q[0]], [])] + qc = QuantumCircuit(q) + qc.data = [(SdgGate(), [q[0]], []), (HGate(), [q[0]], [])] + self.definition = qc class WGate(Gate): @@ -54,7 +56,9 @@ def __init__(self): def _define(self): """W Gate definition.""" q = QuantumRegister(1, 'q') - self.definition = [(VGate(), [q[0]], []), (VGate(), [q[0]], [])] + qc = QuantumCircuit(q) + qc.data = [(VGate(), [q[0]], []), (VGate(), [q[0]], [])] + self.definition = qc def random_clifford_circuit(num_qubits, num_gates, gates='all', seed=None): diff --git a/test/python/transpiler/test_unroll_custom_definitions.py b/test/python/transpiler/test_unroll_custom_definitions.py index c14c7460ed0b..d90e3b2eb63f 100644 --- a/test/python/transpiler/test_unroll_custom_definitions.py +++ b/test/python/transpiler/test_unroll_custom_definitions.py @@ -92,11 +92,11 @@ def test_unroll_gate_until_reach_basis_gates(self): eq_lib = EquivalenceLibrary() gate = TestCompositeGate() - q = QuantumRegister(1, 'q') - gate.definition = [(TestGate(), [q[0]], [])] + gate.definition = QuantumCircuit(q) + gate.definition.data = [(TestGate(), [q[0]], [])] - qc = QuantumCircuit(1) + qc = QuantumCircuit(q) qc.append(gate, [0]) dag = circuit_to_dag(qc) @@ -121,7 +121,8 @@ def test_unroll_twice_until_we_get_to_eqlib(self): gate = TestCompositeGate() q = QuantumRegister(1, 'q') - gate.definition = [(TestGate(), [q[0]], [])] + gate.definition = QuantumCircuit(q) + gate.definition.data = [(TestGate(), [q[0]], [])] qc = QuantumCircuit(1) qc.append(gate, [0]) From 4a636fa15f3dbc754c573eb8961239a14dcdf8d7 Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Tue, 30 Jun 2020 10:29:16 -0400 Subject: [PATCH 11/38] resolve c_if register conversion --- qiskit/circuit/instruction.py | 9 +- qiskit/circuit/library/standard_gates/x.py | 190 +++++++++--------- qiskit/circuit/quantumcircuit.py | 1 + qiskit/converters/circuit_to_dag.py | 3 + qiskit/converters/circuit_to_instruction.py | 20 +- qiskit/dagcircuit/dagcircuit.py | 1 + qiskit/transpiler/passes/basis/unroller.py | 2 +- .../python/circuit/test_circuit_operations.py | 1 - test/python/circuit/test_controlled_gate.py | 9 +- test/python/circuit/test_instructions.py | 3 +- 10 files changed, 134 insertions(+), 105 deletions(-) diff --git a/qiskit/circuit/instruction.py b/qiskit/circuit/instruction.py index 1e099f29ff64..e16f618a5e17 100644 --- a/qiskit/circuit/instruction.py +++ b/qiskit/circuit/instruction.py @@ -387,6 +387,11 @@ def repeat(self, n): if instruction.definition is None: from qiskit import QuantumCircuit - instruction.definition = QuantumCircuit(self.num_qubits) - instruction.definition.data = [(self, qargs[:], cargs[:])] * n + qc = QuantumCircuit() + if qargs: + qc.add_register(qargs) + if cargs: + qc.add_register(cargs) + qc.data = [(self, qargs[:], cargs[:])] * n + instruction.definition = qc return instruction diff --git a/qiskit/circuit/library/standard_gates/x.py b/qiskit/circuit/library/standard_gates/x.py index e59b7dd5dbf4..03baefa791be 100644 --- a/qiskit/circuit/library/standard_gates/x.py +++ b/qiskit/circuit/library/standard_gates/x.py @@ -471,57 +471,60 @@ def __init__(self, angle=numpy.pi/4, label=None, ctrl_state=None): self.base_gate = XGate() self._angle = angle - # def _define(self): - # """ - # gate c3x a,b,c,d - # { - # h d; cu1(-pi/4) a,d; h d; - # cx a,b; - # h d; cu1(pi/4) b,d; h d; - # cx a,b; - # h d; cu1(-pi/4) b,d; h d; - # cx b,c; - # h d; cu1(pi/4) c,d; h d; - # cx a,c; - # h d; cu1(-pi/4) c,d; h d; - # cx b,c; - # h d; cu1(pi/4) c,d; h d; - # cx a,c; - # h d; cu1(-pi/4) c,d; h d; - # } - # """ - # from .u1 import CU1Gate - # q = QuantumRegister(4, name='q') - # definition = [ - # (HGate(), [q[3]], []), - # (CU1Gate(-self._angle), [q[0], q[3]], []), - # (HGate(), [q[3]], []), - # (CXGate(), [q[0], q[1]], []), - # (HGate(), [q[3]], []), - # (CU1Gate(self._angle), [q[1], q[3]], []), - # (HGate(), [q[3]], []), - # (CXGate(), [q[0], q[1]], []), - # (HGate(), [q[3]], []), - # (CU1Gate(-self._angle), [q[1], q[3]], []), - # (HGate(), [q[3]], []), - # (CXGate(), [q[1], q[2]], []), - # (HGate(), [q[3]], []), - # (CU1Gate(self._angle), [q[2], q[3]], []), - # (HGate(), [q[3]], []), - # (CXGate(), [q[0], q[2]], []), - # (HGate(), [q[3]], []), - # (CU1Gate(-self._angle), [q[2], q[3]], []), - # (HGate(), [q[3]], []), - # (CXGate(), [q[1], q[2]], []), - # (HGate(), [q[3]], []), - # (CU1Gate(self._angle), [q[2], q[3]], []), - # (HGate(), [q[3]], []), - # (CXGate(), [q[0], q[2]], []), - # (HGate(), [q[3]], []), - # (CU1Gate(-self._angle), [q[2], q[3]], []), - # (HGate(), [q[3]], []) - # ] - # self.definition = definition + def _define(self): + """ + gate c3x a,b,c,d + { + h d; cu1(-pi/4) a,d; h d; + cx a,b; + h d; cu1(pi/4) b,d; h d; + cx a,b; + h d; cu1(-pi/4) b,d; h d; + cx b,c; + h d; cu1(pi/4) c,d; h d; + cx a,c; + h d; cu1(-pi/4) c,d; h d; + cx b,c; + h d; cu1(pi/4) c,d; h d; + cx a,c; + h d; cu1(-pi/4) c,d; h d; + } + """ + from qiskit import QuantumCircuit + from .u1 import CU1Gate + q = QuantumRegister(4, name='q') + definition = [ + (HGate(), [q[3]], []), + (CU1Gate(-self._angle), [q[0], q[3]], []), + (HGate(), [q[3]], []), + (CXGate(), [q[0], q[1]], []), + (HGate(), [q[3]], []), + (CU1Gate(self._angle), [q[1], q[3]], []), + (HGate(), [q[3]], []), + (CXGate(), [q[0], q[1]], []), + (HGate(), [q[3]], []), + (CU1Gate(-self._angle), [q[1], q[3]], []), + (HGate(), [q[3]], []), + (CXGate(), [q[1], q[2]], []), + (HGate(), [q[3]], []), + (CU1Gate(self._angle), [q[2], q[3]], []), + (HGate(), [q[3]], []), + (CXGate(), [q[0], q[2]], []), + (HGate(), [q[3]], []), + (CU1Gate(-self._angle), [q[2], q[3]], []), + (HGate(), [q[3]], []), + (CXGate(), [q[1], q[2]], []), + (HGate(), [q[3]], []), + (CU1Gate(self._angle), [q[2], q[3]], []), + (HGate(), [q[3]], []), + (CXGate(), [q[0], q[2]], []), + (HGate(), [q[3]], []), + (CU1Gate(-self._angle), [q[2], q[3]], []), + (HGate(), [q[3]], []) + ] + qc = QuantumCircuit(q) + qc.data = definition + self.definition = qc def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Controlled version of this gate. @@ -664,47 +667,50 @@ def __init__(self, label=None, ctrl_state=None): self.base_gate = XGate() # seems like open controls not hapening? - # def _define(self): - # """ - # gate c3sqrtx a,b,c,d - # { - # h d; cu1(-pi/8) a,d; h d; - # cx a,b; - # h d; cu1(pi/8) b,d; h d; - # cx a,b; - # h d; cu1(-pi/8) b,d; h d; - # cx b,c; - # h d; cu1(pi/8) c,d; h d; - # cx a,c; - # h d; cu1(-pi/8) c,d; h d; - # cx b,c; - # h d; cu1(pi/8) c,d; h d; - # cx a,c; - # h d; cu1(-pi/8) c,d; h d; - # } - # gate c4x a,b,c,d,e - # { - # h e; cu1(-pi/2) d,e; h e; - # c3x a,b,c,d; - # h d; cu1(pi/4) d,e; h d; - # c3x a,b,c,d; - # c3sqrtx a,b,c,e; - # } - # """ - # from .u1 import CU1Gate - # q = QuantumRegister(5, name='q') - # definition = [ - # (HGate(), [q[4]], []), - # (CU1Gate(-numpy.pi / 2), [q[3], q[4]], []), - # (HGate(), [q[4]], []), - # (C3XGate(), [q[0], q[1], q[2], q[3]], []), - # (HGate(), [q[4]], []), - # (CU1Gate(numpy.pi / 2), [q[3], q[4]], []), - # (HGate(), [q[4]], []), - # (C3XGate(), [q[0], q[1], q[2], q[3]], []), - # (C3XGate(numpy.pi / 8), [q[0], q[1], q[2], q[4]], []), - # ] - # self.definition = definition + def _define(self): + """ + gate c3sqrtx a,b,c,d + { + h d; cu1(-pi/8) a,d; h d; + cx a,b; + h d; cu1(pi/8) b,d; h d; + cx a,b; + h d; cu1(-pi/8) b,d; h d; + cx b,c; + h d; cu1(pi/8) c,d; h d; + cx a,c; + h d; cu1(-pi/8) c,d; h d; + cx b,c; + h d; cu1(pi/8) c,d; h d; + cx a,c; + h d; cu1(-pi/8) c,d; h d; + } + gate c4x a,b,c,d,e + { + h e; cu1(-pi/2) d,e; h e; + c3x a,b,c,d; + h d; cu1(pi/4) d,e; h d; + c3x a,b,c,d; + c3sqrtx a,b,c,e; + } + """ + from qiskit import QuantumCircuit + from .u1 import CU1Gate + q = QuantumRegister(5, name='q') + definition = [ + (HGate(), [q[4]], []), + (CU1Gate(-numpy.pi / 2), [q[3], q[4]], []), + (HGate(), [q[4]], []), + (C3XGate(), [q[0], q[1], q[2], q[3]], []), + (HGate(), [q[4]], []), + (CU1Gate(numpy.pi / 2), [q[3], q[4]], []), + (HGate(), [q[4]], []), + (C3XGate(), [q[0], q[1], q[2], q[3]], []), + (C3XGate(numpy.pi / 8), [q[0], q[1], q[2], q[4]], []), + ] + qc = QuantumCircuit(q) + qc.data = definition + self.definition = qc def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Controlled version of this gate. diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index 6b417641387b..391a8172f083 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -769,6 +769,7 @@ def _check_cargs(self, cargs): if not all(isinstance(i, Clbit) for i in cargs): raise CircuitError("carg is not a Clbit") if not all(self.has_register(i.register) for i in cargs): + #import ipdb;ipdb.set_trace() raise CircuitError("register not in this circuit") def to_instruction(self, parameter_map=None): diff --git a/qiskit/converters/circuit_to_dag.py b/qiskit/converters/circuit_to_dag.py index eaac9e13e96b..a5a7931bd508 100644 --- a/qiskit/converters/circuit_to_dag.py +++ b/qiskit/converters/circuit_to_dag.py @@ -53,6 +53,9 @@ def circuit_to_dag(circuit): dagcircuit.add_creg(register) for instruction, qargs, cargs in circuit.data: + # print(instruction.name, qargs, cargs) + # if instruction.name == 'h': + # import ipdb;ipdb.set_trace() dagcircuit.apply_operation_back(instruction.copy(), qargs, cargs, instruction.condition) return dagcircuit diff --git a/qiskit/converters/circuit_to_instruction.py b/qiskit/converters/circuit_to_instruction.py index ebb830c3ecab..69b48e8f21c8 100644 --- a/qiskit/converters/circuit_to_instruction.py +++ b/qiskit/converters/circuit_to_instruction.py @@ -78,7 +78,7 @@ def circuit_to_instruction(circuit, parameter_map=None, equivalence_library=None params=sorted(parameter_dict.values(), key=lambda p: p.name)) instruction.condition = None - def find_bit_position(bit): + def find_bit_position(bit): # """find the index of a given bit (Register, int) within a flat ordered list of bits of the circuit """ @@ -96,21 +96,31 @@ def find_bit_position(bit): definition = target.data - qregs = [] + regs = [] if instruction.num_qubits > 0: q = QuantumRegister(instruction.num_qubits, 'q') - qregs.append(q) + regs.append(q) if instruction.num_clbits > 0: c = ClassicalRegister(instruction.num_clbits, 'c') - qregs.append(c) + regs.append(c) definition = list(map(lambda x: (x[0], list(map(lambda y: q[find_bit_position(y)], x[1])), list(map(lambda y: c[find_bit_position(y)], x[2]))), definition)) - qc = QuantumCircuit(*qregs, name=instruction.name) + # fix condition + for rule in definition: + condition = rule[0].condition + if condition: + reg, val = condition + if reg.size == c.size: + rule[0].condition = (c, val) + else: + raise CircuitError('Cannot convert condition in circuit with multiple classical registers to instruction') + + qc = QuantumCircuit(*regs, name=instruction.name) qc.data = definition instruction.definition = qc diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index d0efbd18911b..75cc5e8b25ca 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -283,6 +283,7 @@ def _check_condition(self, name, condition): """ # Verify creg exists if condition is not None and condition[0].name not in self.cregs: + #import ipdb;ipdb.set_trace() raise DAGCircuitError("invalid creg in condition for %s" % name) def _check_bits(self, args, amap): diff --git a/qiskit/transpiler/passes/basis/unroller.py b/qiskit/transpiler/passes/basis/unroller.py index 0763236e1d3c..2ca85e6df77c 100644 --- a/qiskit/transpiler/passes/basis/unroller.py +++ b/qiskit/transpiler/passes/basis/unroller.py @@ -83,7 +83,7 @@ def run(self, dag): break try: rule = rule[0][0].definition.data - except TypeError as err: + except (TypeError, AttributeError) as err: raise QiskitError('Error decomposing node {}: {}'.format(node.name, err)) else: diff --git a/test/python/circuit/test_circuit_operations.py b/test/python/circuit/test_circuit_operations.py index 85965c3c80c5..01dc94bd74e3 100644 --- a/test/python/circuit/test_circuit_operations.py +++ b/test/python/circuit/test_circuit_operations.py @@ -392,7 +392,6 @@ def test_repeat(self): ref = QuantumCircuit(qr, cr) for _ in range(3): ref.append(inst, ref.qubits, ref.clbits) - rep = qc.repeat(3) self.assertEqual(rep, ref) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 5e305614e211..663f126835b4 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -211,7 +211,8 @@ def test_multi_control_u3(self): result = job.result() # Circuit unitaries - mat_cnu3 = result.get_unitary(0) + #mat_cnu3 = result.get_unitary(0) # unitary_simulator is giving different output than Operator?? + mat_cnu3 = Operator(qcnu3).data mat_u3 = result.get_unitary(1) mat_cu3 = result.get_unitary(2) @@ -231,8 +232,10 @@ def test_multi_control_u3(self): for itest in tests: info, target, decomp = itest[0], itest[1], itest[2] with self.subTest(i=info): - self.log.info(info) - self.assertTrue(matrix_equal(target, decomp, ignore_phase=True)) + if info == 'check unitary of cnu3 against tensored unitary of u3': + np.set_printoptions(precision=2, linewidth=300, suppress=True) + import ipdb;ipdb.set_trace() + self.assertTrue(matrix_equal(target, decomp, ignore_phase=True, atol=1e-8, rtol=1e-5)) def test_multi_control_u1(self): """Test the matrix representation of the controlled and controlled-controlled U1 gate.""" diff --git a/test/python/circuit/test_instructions.py b/test/python/circuit/test_instructions.py index 59a50b68bc7f..43b375415a50 100644 --- a/test/python/circuit/test_instructions.py +++ b/test/python/circuit/test_instructions.py @@ -187,7 +187,7 @@ def test_reverse_instruction(self): circ.measure(q[0], c[0]) circ.rz(0.8, q[0]).c_if(c, 6) inst = circ.to_instruction() - + circ = QuantumCircuit(q, c, name='circ') circ.rz(0.8, q[0]).c_if(c, 6) circ.measure(q[0], c[0]) @@ -195,6 +195,7 @@ def test_reverse_instruction(self): circ.u3(0.1, 0.2, -0.2, q[0]) circ.t(q[1]) inst_reverse = circ.to_instruction() + self.assertEqual(inst.reverse_ops().definition, inst_reverse.definition) def test_reverse_opaque(self): From 202d4334ea78e054fc54bb75cbeaf61198fabb51 Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Tue, 30 Jun 2020 22:41:24 -0400 Subject: [PATCH 12/38] revert removal of _define in standard gates --- qiskit/circuit/add_control.py | 1 - qiskit/circuit/controlledgate.py | 4 +- qiskit/circuit/instruction.py | 12 +- qiskit/circuit/library/standard_gates/dcx.py | 24 +- qiskit/circuit/library/standard_gates/h.py | 82 +++--- .../circuit/library/standard_gates/iswap.py | 51 ++-- qiskit/circuit/library/standard_gates/ms.py | 24 +- qiskit/circuit/library/standard_gates/r.py | 31 ++- qiskit/circuit/library/standard_gates/rx.py | 76 ++--- qiskit/circuit/library/standard_gates/rxx.py | 41 +-- qiskit/circuit/library/standard_gates/ry.py | 66 ++--- qiskit/circuit/library/standard_gates/ryy.py | 43 +-- qiskit/circuit/library/standard_gates/rz.py | 68 ++--- qiskit/circuit/library/standard_gates/rzx.py | 29 +- qiskit/circuit/library/standard_gates/rzz.py | 33 +-- qiskit/circuit/library/standard_gates/s.py | 54 ++-- qiskit/circuit/library/standard_gates/swap.py | 70 ++--- qiskit/circuit/library/standard_gates/t.py | 54 ++-- qiskit/circuit/library/standard_gates/u1.py | 65 ++--- qiskit/circuit/library/standard_gates/u2.py | 17 +- qiskit/circuit/library/standard_gates/u3.py | 53 ++-- qiskit/circuit/library/standard_gates/x.py | 261 ++++++++++-------- qiskit/circuit/library/standard_gates/y.py | 55 ++-- qiskit/circuit/library/standard_gates/z.py | 54 ++-- qiskit/circuit/quantumcircuit.py | 1 - qiskit/converters/circuit_to_dag.py | 3 - qiskit/converters/circuit_to_instruction.py | 7 +- qiskit/dagcircuit/dagcircuit.py | 1 - qiskit/extensions/quantum_initializer/squ.py | 6 +- qiskit/extensions/unitary.py | 1 - .../quantum_info/operators/channel/superop.py | 5 +- .../passes/basis/unroll_custom_definitions.py | 2 +- test/python/circuit/test_controlled_gate.py | 36 +-- test/python/circuit/test_instructions.py | 2 +- test/python/circuit/test_library.py | 1 - 35 files changed, 678 insertions(+), 655 deletions(-) diff --git a/qiskit/circuit/add_control.py b/qiskit/circuit/add_control.py index 7ea93e100a3c..1209ad92b05f 100644 --- a/qiskit/circuit/add_control.py +++ b/qiskit/circuit/add_control.py @@ -129,7 +129,6 @@ def control(operation: Union[Gate, ControlledGate], else: bgate = _unroll_gate(operation, ['u1', 'u3', 'cx']) # now we have a bunch of single qubit rotation gates and cx - bgate.definition.data for rule in bgate.definition.data: if rule[0].name == 'u3': theta, phi, lamb = rule[0].params diff --git a/qiskit/circuit/controlledgate.py b/qiskit/circuit/controlledgate.py index 4794a7c41736..4ae456aec9bc 100644 --- a/qiskit/circuit/controlledgate.py +++ b/qiskit/circuit/controlledgate.py @@ -14,13 +14,11 @@ """Controlled unitary gate.""" -from typing import Tuple, List, Optional, Union +from typing import List, Optional, Union from qiskit.circuit.exceptions import CircuitError from .gate import Gate from .quantumregister import QuantumRegister -from .quantumregister import Qubit -from .classicalregister import Clbit # pylint: disable=missing-return-doc diff --git a/qiskit/circuit/instruction.py b/qiskit/circuit/instruction.py index e16f618a5e17..ea7eb4807c06 100644 --- a/qiskit/circuit/instruction.py +++ b/qiskit/circuit/instruction.py @@ -128,11 +128,7 @@ def __eq__(self, other): def _define(self): """Populates self.definition with a decomposition of this gate.""" - try: - self._definition = self.decompositions[0] - except IndexError: - # u3 or cx - pass + pass @property def params(self): @@ -183,10 +179,11 @@ def definition(self): @definition.setter def definition(self, definition): """Set gate representation""" + # pylint: disable=cyclic-import from qiskit import QuantumCircuit if not isinstance(definition, QuantumCircuit) and definition is not None: - raise CircuitError('Instruction definition must be QuantumCircuit. Got {}'.format( - type(definition))) + raise CircuitError('Instruction "{}" definition must be QuantumCircuit. Got {}'.format( + self.name, type(definition))) self._definition = definition @property @@ -386,6 +383,7 @@ def repeat(self, n): cargs = [] if self.num_clbits == 0 else ClassicalRegister(self.num_clbits, 'c') if instruction.definition is None: + # pylint: disable=cyclic-import from qiskit import QuantumCircuit qc = QuantumCircuit() if qargs: diff --git a/qiskit/circuit/library/standard_gates/dcx.py b/qiskit/circuit/library/standard_gates/dcx.py index a54146f0bd19..1b681ae22268 100644 --- a/qiskit/circuit/library/standard_gates/dcx.py +++ b/qiskit/circuit/library/standard_gates/dcx.py @@ -50,16 +50,20 @@ def __init__(self): """Create new DCX gate.""" super().__init__('dcx', 2, []) - # def _define(self): - # """ - # gate dcx a, b { cx a, b; cx a, b; } - # """ - # from .x import CXGate - # q = QuantumRegister(2, 'q') - # self.definition = [ - # (CXGate(), [q[0], q[1]], []), - # (CXGate(), [q[1], q[0]], []) - # ] + def _define(self): + """ + gate dcx a, b { cx a, b; cx a, b; } + """ + from qiskit import QuantumCircuit + from .x import CXGate + q = QuantumRegister(2, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (CXGate(), [q[0], q[1]], []), + (CXGate(), [q[1], q[0]], []) + ] + qc.data = rules + self.definition = qc def to_matrix(self): """Return a numpy.array for the DCX gate.""" diff --git a/qiskit/circuit/library/standard_gates/h.py b/qiskit/circuit/library/standard_gates/h.py index bead4fc368e2..0249ce57a03a 100644 --- a/qiskit/circuit/library/standard_gates/h.py +++ b/qiskit/circuit/library/standard_gates/h.py @@ -53,19 +53,20 @@ def __init__(self, label=None): """Create new H gate.""" super().__init__('h', 1, [], label=label) - # def _define(self): - # """ - # gate h a { u2(0,pi) a; } - # """ - # from .u2 import U2Gate - # definition = [] - # q = QuantumRegister(1, 'q') - # rule = [ - # (U2Gate(0, pi), [q[0]], []) - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + """ + gate h a { u2(0,pi) a; } + """ + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + from .u2 import U2Gate + q = QuantumRegister(1, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (U2Gate(0, pi), [q[0]], []) + ] + qc.data = rules + self.definition = qc def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Return a (multi-)controlled-H gate. @@ -169,33 +170,34 @@ def __init__(self, label=None, ctrl_state=None): ctrl_state=ctrl_state) self.base_gate = HGate() - # def _define(self): - # """ - # gate ch a,b { - # s b; - # h b; - # t b; - # cx a, b; - # tdg b; - # h b; - # sdg b; - # } - # """ - # from .x import CXGate # pylint: disable=cyclic-import - # definition = [] - # q = QuantumRegister(2, 'q') - # rule = [ - # (SGate(), [q[1]], []), - # (HGate(), [q[1]], []), - # (TGate(), [q[1]], []), - # (CXGate(), [q[0], q[1]], []), - # (TdgGate(), [q[1]], []), - # (HGate(), [q[1]], []), - # (SdgGate(), [q[1]], []) - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + """ + gate ch a,b { + s b; + h b; + t b; + cx a, b; + tdg b; + h b; + sdg b; + } + """ + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + from .x import CXGate # pylint: disable=cyclic-import + q = QuantumRegister(2, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (SGate(), [q[1]], []), + (HGate(), [q[1]], []), + (TGate(), [q[1]], []), + (CXGate(), [q[0], q[1]], []), + (TdgGate(), [q[1]], []), + (HGate(), [q[1]], []), + (SdgGate(), [q[1]], []) + ] + qc.data = rules + self.definition = qc def inverse(self): """Return inverted CH gate (itself).""" diff --git a/qiskit/circuit/library/standard_gates/iswap.py b/qiskit/circuit/library/standard_gates/iswap.py index 3567d23c23b8..cfaa76c0f34a 100644 --- a/qiskit/circuit/library/standard_gates/iswap.py +++ b/qiskit/circuit/library/standard_gates/iswap.py @@ -81,29 +81,34 @@ def __init__(self): """Create new iSwap gate.""" super().__init__('iswap', 2, []) - # def _define(self): - # """ - # gate iswap a,b { - # s q[0]; - # s q[1]; - # h q[0]; - # cx q[0],q[1]; - # cx q[1],q[0]; - # h q[1]; - # } - # """ - # from .h import HGate - # from .s import SGate - # from .x import CXGate - # q = QuantumRegister(2, 'q') - # self.definition = [ - # (SGate(), [q[0]], []), - # (SGate(), [q[1]], []), - # (HGate(), [q[0]], []), - # (CXGate(), [q[0], q[1]], []), - # (CXGate(), [q[1], q[0]], []), - # (HGate(), [q[1]], []) - # ] + def _define(self): + """ + gate iswap a,b { + s q[0]; + s q[1]; + h q[0]; + cx q[0],q[1]; + cx q[1],q[0]; + h q[1]; + } + """ + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + from .h import HGate + from .s import SGate + from .x import CXGate + q = QuantumRegister(2, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (SGate(), [q[0]], []), + (SGate(), [q[1]], []), + (HGate(), [q[0]], []), + (CXGate(), [q[0], q[1]], []), + (CXGate(), [q[1], q[0]], []), + (HGate(), [q[1]], []) + ] + qc.data = rules + self.definition = qc def to_matrix(self): """Return a numpy.array for the iSWAP gate.""" diff --git a/qiskit/circuit/library/standard_gates/ms.py b/qiskit/circuit/library/standard_gates/ms.py index 20b3a9043750..e987cb232ff8 100644 --- a/qiskit/circuit/library/standard_gates/ms.py +++ b/qiskit/circuit/library/standard_gates/ms.py @@ -35,15 +35,15 @@ def __init__(self, num_qubits, theta, *, n_qubits=None, # pylint:disable=unused """Create new MS gate.""" super().__init__('ms', num_qubits, [theta], label=label) - # def _define(self): - # from .rxx import RXXGate - # definition = [] - # q = QuantumRegister(self.num_qubits, 'q') - # rule = [] - # for i in range(self.num_qubits): - # for j in range(i + 1, self.num_qubits): - # rule += [(RXXGate(self.params[0]), [q[i], q[j]], [])] - - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + from .rxx import RXXGate + q = QuantumRegister(self.num_qubits, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [] + for i in range(self.num_qubits): + for j in range(i + 1, self.num_qubits): + rules += [(RXXGate(self.params[0]), [q[i], q[j]], [])] + qc.data = rules + self.definition = qc diff --git a/qiskit/circuit/library/standard_gates/r.py b/qiskit/circuit/library/standard_gates/r.py index 43780ec47122..76c16e4cdce2 100644 --- a/qiskit/circuit/library/standard_gates/r.py +++ b/qiskit/circuit/library/standard_gates/r.py @@ -48,21 +48,22 @@ def __init__(self, theta, phi): """Create new r single-qubit gate.""" super().__init__('r', 1, [theta, phi]) - # def _define(self): - # """ - # gate r(θ, φ) a {u3(θ, φ - π/2, -φ + π/2) a;} - # """ - # from .u3 import U3Gate - # definition = [] - # q = QuantumRegister(1, 'q') - # theta = self.params[0] - # phi = self.params[1] - # rule = [ - # (U3Gate(theta, phi - pi / 2, -phi + pi / 2), [q[0]], []) - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + """ + gate r(θ, φ) a {u3(θ, φ - π/2, -φ + π/2) a;} + """ + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + from .u3 import U3Gate + q = QuantumRegister(1, 'q') + qc = QuantumCircuit(q, name=self.name) + theta = self.params[0] + phi = self.params[1] + rules = [ + (U3Gate(theta, phi - pi / 2, -phi + pi / 2), [q[0]], []) + ] + qc.data = rules + self.definition = qc def inverse(self): """Invert this gate. diff --git a/qiskit/circuit/library/standard_gates/rx.py b/qiskit/circuit/library/standard_gates/rx.py index bfdb142c1ac8..d006aeed8048 100644 --- a/qiskit/circuit/library/standard_gates/rx.py +++ b/qiskit/circuit/library/standard_gates/rx.py @@ -50,19 +50,19 @@ def __init__(self, theta, label=None): """Create new RX gate.""" super().__init__('rx', 1, [theta], label=label) - # def _define(self): - # """ - # gate rx(theta) a {r(theta, 0) a;} - # """ - # from .r import RGate - # definition = [] - # q = QuantumRegister(1, 'q') - # rule = [ - # (RGate(self.params[0], 0), [q[0]], []) - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + """ + gate rx(theta) a {r(theta, 0) a;} + """ + from qiskit import QuantumCircuit + from .r import RGate + q = QuantumRegister(1, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (RGate(self.params[0], 0), [q[0]], []) + ] + qc.data = rules + self.definition = qc def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Return a (mutli-)controlled-RX gate. @@ -168,31 +168,31 @@ def __init__(self, theta, label=None, ctrl_state=None): label=label, ctrl_state=ctrl_state) self.base_gate = RXGate(theta) - # def _define(self): - # """ - # gate cu3(theta,phi,lambda) c, t - # { u1(pi/2) t; - # cx c,t; - # u3(-theta/2,0,0) t; - # cx c,t; - # u3(theta/2,-pi/2,0) t; - # } - # """ - # from .u1 import U1Gate - # from .u3 import U3Gate - # from .x import CXGate - # definition = [] - # q = QuantumRegister(2, 'q') - # rule = [ - # (U1Gate(pi / 2), [q[1]], []), - # (CXGate(), [q[0], q[1]], []), - # (U3Gate(-self.params[0] / 2, 0, 0), [q[1]], []), - # (CXGate(), [q[0], q[1]], []), - # (U3Gate(self.params[0] / 2, -pi / 2, 0), [q[1]], []) - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + """ + gate cu3(theta,phi,lambda) c, t + { u1(pi/2) t; + cx c,t; + u3(-theta/2,0,0) t; + cx c,t; + u3(theta/2,-pi/2,0) t; + } + """ + from qiskit import QuantumCircuit + from .u1 import U1Gate + from .u3 import U3Gate + from .x import CXGate + q = QuantumRegister(2, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (U1Gate(pi / 2), [q[1]], []), + (CXGate(), [q[0], q[1]], []), + (U3Gate(-self.params[0] / 2, 0, 0), [q[1]], []), + (CXGate(), [q[0], q[1]], []), + (U3Gate(self.params[0] / 2, -pi / 2, 0), [q[1]], []) + ] + qc.data = rules + self.definition = qc def inverse(self): """Return inverse RX gate (i.e. with the negative rotation angle).""" diff --git a/qiskit/circuit/library/standard_gates/rxx.py b/qiskit/circuit/library/standard_gates/rxx.py index 31955469507b..942c38e7d850 100644 --- a/qiskit/circuit/library/standard_gates/rxx.py +++ b/qiskit/circuit/library/standard_gates/rxx.py @@ -72,26 +72,27 @@ def __init__(self, theta): """Create new RXX gate.""" super().__init__('rxx', 2, [theta]) - # def _define(self): - # """Calculate a subcircuit that implements this unitary.""" - # from .x import CXGate - # from .u1 import U1Gate - # from .h import HGate - # definition = [] - # q = QuantumRegister(2, 'q') - # theta = self.params[0] - # rule = [ - # (HGate(), [q[0]], []), - # (HGate(), [q[1]], []), - # (CXGate(), [q[0], q[1]], []), - # (U1Gate(theta), [q[1]], []), - # (CXGate(), [q[0], q[1]], []), - # (HGate(), [q[1]], []), - # (HGate(), [q[0]], []), - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + """Calculate a subcircuit that implements this unitary.""" + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + from .x import CXGate + from .u1 import U1Gate + from .h import HGate + q = QuantumRegister(2, 'q') + qc = QuantumCircuit(q, name=self.name) + theta = self.params[0] + rules = [ + (HGate(), [q[0]], []), + (HGate(), [q[1]], []), + (CXGate(), [q[0], q[1]], []), + (U1Gate(theta), [q[1]], []), + (CXGate(), [q[0], q[1]], []), + (HGate(), [q[1]], []), + (HGate(), [q[0]], []), + ] + qc.data = rules + self.definition = qc def inverse(self): """Return inverse RXX gate (i.e. with the negative rotation angle).""" diff --git a/qiskit/circuit/library/standard_gates/ry.py b/qiskit/circuit/library/standard_gates/ry.py index f66438c52902..4088b2956006 100644 --- a/qiskit/circuit/library/standard_gates/ry.py +++ b/qiskit/circuit/library/standard_gates/ry.py @@ -50,19 +50,19 @@ def __init__(self, theta, label=None): """Create new RY gate.""" super().__init__('ry', 1, [theta], label=label) - # def _define(self): - # """ - # gate ry(theta) a { r(theta, pi/2) a; } - # """ - # from .r import RGate - # definition = [] - # q = QuantumRegister(1, 'q') - # rule = [ - # (RGate(self.params[0], pi / 2), [q[0]], []) - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + """ + gate ry(theta) a { r(theta, pi/2) a; } + """ + from qiskit import QuantumCircuit + from .r import RGate + q = QuantumRegister(1, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (RGate(self.params[0], pi / 2), [q[0]], []) + ] + qc.data = rules + self.definition = qc def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Return a (mutli-)controlled-RY gate. @@ -168,26 +168,26 @@ def __init__(self, theta, label=None, ctrl_state=None): ctrl_state=ctrl_state) self.base_gate = RYGate(theta) - # def _define(self): - # """ - # gate cry(lambda) a,b - # { u3(lambda/2,0,0) b; cx a,b; - # u3(-lambda/2,0,0) b; cx a,b; - # } - # """ - # from .u3 import U3Gate - # from .x import CXGate - # definition = [] - # q = QuantumRegister(2, 'q') - # rule = [ - # (U3Gate(self.params[0] / 2, 0, 0), [q[1]], []), - # (CXGate(), [q[0], q[1]], []), - # (U3Gate(-self.params[0] / 2, 0, 0), [q[1]], []), - # (CXGate(), [q[0], q[1]], []) - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + """ + gate cry(lambda) a,b + { u3(lambda/2,0,0) b; cx a,b; + u3(-lambda/2,0,0) b; cx a,b; + } + """ + from qiskit import QuantumCircuit + from .u3 import U3Gate + from .x import CXGate + q = QuantumRegister(2, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (U3Gate(self.params[0] / 2, 0, 0), [q[1]], []), + (CXGate(), [q[0], q[1]], []), + (U3Gate(-self.params[0] / 2, 0, 0), [q[1]], []), + (CXGate(), [q[0], q[1]], []) + ] + qc.data = rules + self.definition = qc def inverse(self): """Return inverse RY gate (i.e. with the negative rotation angle).""" diff --git a/qiskit/circuit/library/standard_gates/ryy.py b/qiskit/circuit/library/standard_gates/ryy.py index 5e4b2ac45dc4..09c45a6352e7 100644 --- a/qiskit/circuit/library/standard_gates/ryy.py +++ b/qiskit/circuit/library/standard_gates/ryy.py @@ -73,27 +73,28 @@ def __init__(self, theta): """Create new RYY gate.""" super().__init__('ryy', 2, [theta]) - # def _define(self): - # """Calculate a subcircuit that implements this unitary.""" - # from .x import CXGate - # from .rx import RXGate - # from .rz import RZGate - - # definition = [] - # q = QuantumRegister(2, 'q') - # theta = self.params[0] - # rule = [ - # (RXGate(np.pi / 2), [q[0]], []), - # (RXGate(np.pi / 2), [q[1]], []), - # (CXGate(), [q[0], q[1]], []), - # (RZGate(theta), [q[1]], []), - # (CXGate(), [q[0], q[1]], []), - # (RXGate(-np.pi / 2), [q[0]], []), - # (RXGate(-np.pi / 2), [q[1]], []), - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + """Calculate a subcircuit that implements this unitary.""" + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + from .x import CXGate + from .rx import RXGate + from .rz import RZGate + + q = QuantumRegister(2, 'q') + qc = QuantumCircuit(q, name=self.name) + theta = self.params[0] + rules = [ + (RXGate(np.pi / 2), [q[0]], []), + (RXGate(np.pi / 2), [q[1]], []), + (CXGate(), [q[0], q[1]], []), + (RZGate(theta), [q[1]], []), + (CXGate(), [q[0], q[1]], []), + (RXGate(-np.pi / 2), [q[0]], []), + (RXGate(-np.pi / 2), [q[1]], []), + ] + qc.data = rules + self.definition = qc def inverse(self): """Return inverse RYY gate (i.e. with the negative rotation angle).""" diff --git a/qiskit/circuit/library/standard_gates/rz.py b/qiskit/circuit/library/standard_gates/rz.py index 1c0d13bfe738..5a506ef52627 100644 --- a/qiskit/circuit/library/standard_gates/rz.py +++ b/qiskit/circuit/library/standard_gates/rz.py @@ -60,19 +60,20 @@ def __init__(self, phi, label=None): """Create new RZ gate.""" super().__init__('rz', 1, [phi], label=label) - # def _define(self): - # """ - # gate rz(phi) a { u1(phi) a; } - # """ - # from .u1 import U1Gate - # definition = [] - # q = QuantumRegister(1, 'q') - # rule = [ - # (U1Gate(self.params[0]), [q[0]], []) - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + """ + gate rz(phi) a { u1(phi) a; } + """ + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + from .u1 import U1Gate + q = QuantumRegister(1, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (U1Gate(self.params[0]), [q[0]], []) + ] + qc.data = rules + self.definition = qc def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Return a (mutli-)controlled-RZ gate. @@ -186,26 +187,27 @@ def __init__(self, theta, label=None, ctrl_state=None): ctrl_state=ctrl_state) self.base_gate = RZGate(theta) - # def _define(self): - # """ - # gate crz(lambda) a,b - # { u1(lambda/2) b; cx a,b; - # u1(-lambda/2) b; cx a,b; - # } - # """ - # from .u1 import U1Gate - # from .x import CXGate - # definition = [] - # q = QuantumRegister(2, 'q') - # rule = [ - # (U1Gate(self.params[0] / 2), [q[1]], []), - # (CXGate(), [q[0], q[1]], []), - # (U1Gate(-self.params[0] / 2), [q[1]], []), - # (CXGate(), [q[0], q[1]], []) - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + """ + gate crz(lambda) a,b + { u1(lambda/2) b; cx a,b; + u1(-lambda/2) b; cx a,b; + } + """ + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + from .u1 import U1Gate + from .x import CXGate + q = QuantumRegister(2, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (U1Gate(self.params[0] / 2), [q[1]], []), + (CXGate(), [q[0], q[1]], []), + (U1Gate(-self.params[0] / 2), [q[1]], []), + (CXGate(), [q[0], q[1]], []) + ] + qc.data = rules + self.definition = qc def inverse(self): """Return inverse RZ gate (i.e. with the negative rotation angle).""" diff --git a/qiskit/circuit/library/standard_gates/rzx.py b/qiskit/circuit/library/standard_gates/rzx.py index 1d3ae2e99cc1..4f4236e4c8c8 100644 --- a/qiskit/circuit/library/standard_gates/rzx.py +++ b/qiskit/circuit/library/standard_gates/rzx.py @@ -121,18 +121,23 @@ def __init__(self, theta): """Create new RZX gate.""" super().__init__('rzx', 2, [theta]) - # def _define(self): - # """ - # gate rzx(theta) a, b { h b; cx a, b; u1(theta) b; cx a, b; h b;} - # """ - # q = QuantumRegister(2, 'q') - # self.definition = [ - # (HGate(), [q[1]], []), - # (CXGate(), [q[0], q[1]], []), - # (RZGate(self.params[0]), [q[1]], []), - # (CXGate(), [q[0], q[1]], []), - # (HGate(), [q[1]], []) - # ] + def _define(self): + """ + gate rzx(theta) a, b { h b; cx a, b; u1(theta) b; cx a, b; h b;} + """ + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + q = QuantumRegister(2, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (HGate(), [q[1]], []), + (CXGate(), [q[0], q[1]], []), + (RZGate(self.params[0]), [q[1]], []), + (CXGate(), [q[0], q[1]], []), + (HGate(), [q[1]], []) + ] + qc.data = rules + self.definition = qc def inverse(self): """Return inverse RZX gate (i.e. with the negative rotation angle).""" diff --git a/qiskit/circuit/library/standard_gates/rzz.py b/qiskit/circuit/library/standard_gates/rzz.py index b426434fbf3f..1acf95b9a897 100644 --- a/qiskit/circuit/library/standard_gates/rzz.py +++ b/qiskit/circuit/library/standard_gates/rzz.py @@ -85,22 +85,23 @@ def __init__(self, theta): """Create new RZZ gate.""" super().__init__('rzz', 2, [theta]) - # def _define(self): - # """ - # gate rzz(theta) a, b { cx a, b; u1(theta) b; cx a, b; } - # """ - # from .u1 import U1Gate - # from .x import CXGate - # definition = [] - # q = QuantumRegister(2, 'q') - # rule = [ - # (CXGate(), [q[0], q[1]], []), - # (U1Gate(self.params[0]), [q[1]], []), - # (CXGate(), [q[0], q[1]], []) - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + """ + gate rzz(theta) a, b { cx a, b; u1(theta) b; cx a, b; } + """ + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + from .u1 import U1Gate + from .x import CXGate + q = QuantumRegister(2, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (CXGate(), [q[0], q[1]], []), + (U1Gate(self.params[0]), [q[1]], []), + (CXGate(), [q[0], q[1]], []) + ] + qc.data = rules + self.definition = qc def inverse(self): """Return inverse RZZ gate (i.e. with the negative rotation angle).""" diff --git a/qiskit/circuit/library/standard_gates/s.py b/qiskit/circuit/library/standard_gates/s.py index 497b7ec675c2..16b8239caadc 100644 --- a/qiskit/circuit/library/standard_gates/s.py +++ b/qiskit/circuit/library/standard_gates/s.py @@ -51,19 +51,20 @@ def __init__(self, label=None): """Create new S gate.""" super().__init__('s', 1, [], label=label) - # def _define(self): - # """ - # gate s a { u1(pi/2) a; } - # """ - # from .u1 import U1Gate - # definition = [] - # q = QuantumRegister(1, 'q') - # rule = [ - # (U1Gate(pi / 2), [q[0]], []) - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + """ + gate s a { u1(pi/2) a; } + """ + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + from .u1 import U1Gate + q = QuantumRegister(1, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (U1Gate(pi / 2), [q[0]], []) + ] + qc.data = rules + self.definition = qc def inverse(self): """Return inverse of S (SdgGate).""" @@ -106,19 +107,20 @@ def __init__(self, label=None): """Create new Sdg gate.""" super().__init__('sdg', 1, [], label=label) - # def _define(self): - # """ - # gate sdg a { u1(-pi/2) a; } - # """ - # from .u1 import U1Gate - # definition = [] - # q = QuantumRegister(1, 'q') - # rule = [ - # (U1Gate(-pi / 2), [q[0]], []) - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + """ + gate sdg a { u1(-pi/2) a; } + """ + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + from .u1 import U1Gate + q = QuantumRegister(1, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (U1Gate(-pi / 2), [q[0]], []) + ] + qc.data = rules + self.definition = qc def inverse(self): """Return inverse of Sdg (SGate).""" diff --git a/qiskit/circuit/library/standard_gates/swap.py b/qiskit/circuit/library/standard_gates/swap.py index 864ffc2e0502..4b2f9e95c952 100644 --- a/qiskit/circuit/library/standard_gates/swap.py +++ b/qiskit/circuit/library/standard_gates/swap.py @@ -56,21 +56,22 @@ def __init__(self, label=None): """Create new SWAP gate.""" super().__init__('swap', 2, [], label=label) - # def _define(self): - # """ - # gate swap a,b { cx a,b; cx b,a; cx a,b; } - # """ - # from .x import CXGate - # definition = [] - # q = QuantumRegister(2, 'q') - # rule = [ - # (CXGate(), [q[0], q[1]], []), - # (CXGate(), [q[1], q[0]], []), - # (CXGate(), [q[0], q[1]], []) - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + """ + gate swap a,b { cx a,b; cx b,a; cx a,b; } + """ + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + from .x import CXGate + q = QuantumRegister(2, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (CXGate(), [q[0], q[1]], []), + (CXGate(), [q[1], q[0]], []), + (CXGate(), [q[0], q[1]], []) + ] + qc.data = rules + self.definition = qc def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Return a (multi-)controlled-SWAP gate. @@ -210,25 +211,26 @@ def __init__(self, label=None, ctrl_state=None): ctrl_state=ctrl_state) self.base_gate = SwapGate() - # def _define(self): - # """ - # gate cswap a,b,c - # { cx c,b; - # ccx a,b,c; - # cx c,b; - # } - # """ - # from .x import CXGate, CCXGate - # definition = [] - # q = QuantumRegister(3, 'q') - # rule = [ - # (CXGate(), [q[2], q[1]], []), - # (CCXGate(), [q[0], q[1], q[2]], []), - # (CXGate(), [q[2], q[1]], []) - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + """ + gate cswap a,b,c + { cx c,b; + ccx a,b,c; + cx c,b; + } + """ + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + from .x import CXGate, CCXGate + q = QuantumRegister(3, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (CXGate(), [q[2], q[1]], []), + (CCXGate(), [q[0], q[1], q[2]], []), + (CXGate(), [q[2], q[1]], []) + ] + qc.data = rules + self.definition = qc def inverse(self): """Return inverse CSwap gate (itself).""" diff --git a/qiskit/circuit/library/standard_gates/t.py b/qiskit/circuit/library/standard_gates/t.py index 8950a6efeecb..9d6b4aa71213 100644 --- a/qiskit/circuit/library/standard_gates/t.py +++ b/qiskit/circuit/library/standard_gates/t.py @@ -52,19 +52,20 @@ def __init__(self, label=None): """Create new T gate.""" super().__init__('t', 1, [], label=label) - # def _define(self): - # """ - # gate t a { u1(pi/4) a; } - # """ - # from .u1 import U1Gate - # definition = [] - # q = QuantumRegister(1, 'q') - # rule = [ - # (U1Gate(pi / 4), [q[0]], []) - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + """ + gate t a { u1(pi/4) a; } + """ + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + from .u1 import U1Gate + q = QuantumRegister(1, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (U1Gate(pi / 4), [q[0]], []) + ] + qc.data = rules + self.definition = qc def inverse(self): """Return inverse T gate (i.e. Tdg).""" @@ -107,19 +108,20 @@ def __init__(self, label=None): """Create new Tdg gate.""" super().__init__('tdg', 1, [], label=label) - # def _define(self): - # """ - # gate tdg a { u1(pi/4) a; } - # """ - # from .u1 import U1Gate - # definition = [] - # q = QuantumRegister(1, 'q') - # rule = [ - # (U1Gate(-pi / 4), [q[0]], []) - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + """ + gate tdg a { u1(pi/4) a; } + """ + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + from .u1 import U1Gate + q = QuantumRegister(1, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (U1Gate(-pi / 4), [q[0]], []) + ] + qc.data = rules + self.definition = qc def inverse(self): """Return inverse Tdg gate (i.e. T).""" diff --git a/qiskit/circuit/library/standard_gates/u1.py b/qiskit/circuit/library/standard_gates/u1.py index b5939b5fa8cc..74f72a08c9a6 100644 --- a/qiskit/circuit/library/standard_gates/u1.py +++ b/qiskit/circuit/library/standard_gates/u1.py @@ -79,16 +79,17 @@ def __init__(self, theta, label=None): """Create new U1 gate.""" super().__init__('u1', 1, [theta], label=label) - # def _define(self): - # from .u3 import U3Gate # pylint: disable=cyclic-import - # definition = [] - # q = QuantumRegister(1, 'q') - # rule = [ - # (U3Gate(0, 0, self.params[0]), [q[0]], []) - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + from .u3 import U3Gate # pylint: disable=cyclic-import + q = QuantumRegister(1, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (U3Gate(0, 0, self.params[0]), [q[0]], []) + ] + qc.data = rules + self.definition = qc def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Return a (mutli-)controlled-U1 gate. @@ -175,27 +176,28 @@ def __init__(self, theta, label=None, ctrl_state=None): ctrl_state=ctrl_state) self.base_gate = U1Gate(theta) - # def _define(self): - # """ - # gate cu1(lambda) a,b - # { u1(lambda/2) a; cx a,b; - # u1(-lambda/2) b; cx a,b; - # u1(lambda/2) b; - # } - # """ - # from .x import CXGate # pylint: disable=cyclic-import - # definition = [] - # q = QuantumRegister(2, 'q') - # rule = [ - # (U1Gate(self.params[0] / 2), [q[0]], []), - # (CXGate(), [q[0], q[1]], []), - # (U1Gate(-self.params[0] / 2), [q[1]], []), - # (CXGate(), [q[0], q[1]], []), - # (U1Gate(self.params[0] / 2), [q[1]], []) - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + """ + gate cu1(lambda) a,b + { u1(lambda/2) a; cx a,b; + u1(-lambda/2) b; cx a,b; + u1(lambda/2) b; + } + """ + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + from .x import CXGate # pylint: disable=cyclic-import + q = QuantumRegister(2, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (U1Gate(self.params[0] / 2), [q[0]], []), + (CXGate(), [q[0], q[1]], []), + (U1Gate(-self.params[0] / 2), [q[1]], []), + (CXGate(), [q[0], q[1]], []), + (U1Gate(self.params[0] / 2), [q[1]], []) + ] + qc.data = rules + self.definition = qc def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Controlled version of this gate. @@ -275,6 +277,7 @@ def __init__(self, lam, num_ctrl_qubits, label=None): self.base_gate = U1Gate(lam) def _define(self): + # pylint: disable=cyclic-import from qiskit import QuantumCircuit q = QuantumRegister(self.num_qubits, 'q') qc = QuantumCircuit(q, name=self.name) diff --git a/qiskit/circuit/library/standard_gates/u2.py b/qiskit/circuit/library/standard_gates/u2.py index ea299cc68fa2..c6ee740becf5 100644 --- a/qiskit/circuit/library/standard_gates/u2.py +++ b/qiskit/circuit/library/standard_gates/u2.py @@ -63,14 +63,15 @@ def __init__(self, phi, lam, label=None): """Create new U2 gate.""" super().__init__('u2', 1, [phi, lam], label=label) - # def _define(self): - # from .u3 import U3Gate - # definition = [] - # q = QuantumRegister(1, 'q') - # rule = [(U3Gate(pi / 2, self.params[0], self.params[1]), [q[0]], [])] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + from .u3 import U3Gate + q = QuantumRegister(1, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [(U3Gate(pi / 2, self.params[0], self.params[1]), [q[0]], [])] + qc.data = rules + self.definition = qc def inverse(self): r"""Return inverted U2 gate. diff --git a/qiskit/circuit/library/standard_gates/u3.py b/qiskit/circuit/library/standard_gates/u3.py index f05772b64f76..ae58f0738b42 100644 --- a/qiskit/circuit/library/standard_gates/u3.py +++ b/qiskit/circuit/library/standard_gates/u3.py @@ -180,32 +180,33 @@ def __init__(self, theta, phi, lam, label=None, ctrl_state=None): label=label, ctrl_state=ctrl_state) self.base_gate = U3Gate(theta, phi, lam) - # def _define(self): - # """ - # gate cu3(theta,phi,lambda) c, t - # { u1((lambda+phi)/2) c; - # u1((lambda-phi)/2) t; - # cx c,t; - # u3(-theta/2,0,-(phi+lambda)/2) t; - # cx c,t; - # u3(theta/2,phi,0) t; - # } - # """ - # from .u1 import U1Gate - # from .x import CXGate # pylint: disable=cyclic-import - # definition = [] - # q = QuantumRegister(2, 'q') - # rule = [ - # (U1Gate((self.params[2] + self.params[1]) / 2), [q[0]], []), - # (U1Gate((self.params[2] - self.params[1]) / 2), [q[1]], []), - # (CXGate(), [q[0], q[1]], []), - # (U3Gate(-self.params[0] / 2, 0, -(self.params[1] + self.params[2]) / 2), [q[1]], []), - # (CXGate(), [q[0], q[1]], []), - # (U3Gate(self.params[0] / 2, self.params[1], 0), [q[1]], []) - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + """ + gate cu3(theta,phi,lambda) c, t + { u1((lambda+phi)/2) c; + u1((lambda-phi)/2) t; + cx c,t; + u3(-theta/2,0,-(phi+lambda)/2) t; + cx c,t; + u3(theta/2,phi,0) t; + } + """ + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + from .u1 import U1Gate + from .x import CXGate # pylint: disable=cyclic-import + q = QuantumRegister(2, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (U1Gate((self.params[2] + self.params[1]) / 2), [q[0]], []), + (U1Gate((self.params[2] - self.params[1]) / 2), [q[1]], []), + (CXGate(), [q[0], q[1]], []), + (U3Gate(-self.params[0] / 2, 0, -(self.params[1] + self.params[2]) / 2), [q[1]], []), + (CXGate(), [q[0], q[1]], []), + (U3Gate(self.params[0] / 2, self.params[1], 0), [q[1]], []) + ] + qc.data = rules + self.definition = qc def inverse(self): r"""Return inverted CU3 gate. diff --git a/qiskit/circuit/library/standard_gates/x.py b/qiskit/circuit/library/standard_gates/x.py index 03baefa791be..1afef22c3e92 100644 --- a/qiskit/circuit/library/standard_gates/x.py +++ b/qiskit/circuit/library/standard_gates/x.py @@ -74,11 +74,20 @@ def __init__(self, label=None): """Create new X gate.""" super().__init__('x', 1, [], label=label) - # def _define(self): - # """ - # gate x a { u3(pi,0,pi) a; } - # """ - # self.definition = self.decompositions[0] + def _define(self): + """ + gate x a { u3(pi,0,pi) a; } + """ + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + from .u3 import U3Gate + q = QuantumRegister(1, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (U3Gate(pi, 0, pi), [q[0]], []) + ] + qc.data = rules + self.definition = qc def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Return a (mutli-)controlled-X gate. @@ -312,41 +321,38 @@ def __init__(self, label=None, ctrl_state=None): ctrl_state=ctrl_state) self.base_gate = XGate() - # def _define(self): - # circ = self.decompositions[0] - # self._definition = circ - - # def _define(self): - # """ - # gate ccx a,b,c - # { - # h c; cx b,c; tdg c; cx a,c; - # t c; cx b,c; tdg c; cx a,c; - # t b; t c; h c; cx a,b; - # t a; tdg b; cx a,b;} - # """ - # definition = [] - # q = QuantumRegister(3, 'q') - # rule = [ - # (HGate(), [q[2]], []), - # (CXGate(), [q[1], q[2]], []), - # (TdgGate(), [q[2]], []), - # (CXGate(), [q[0], q[2]], []), - # (TGate(), [q[2]], []), - # (CXGate(), [q[1], q[2]], []), - # (TdgGate(), [q[2]], []), - # (CXGate(), [q[0], q[2]], []), - # (TGate(), [q[1]], []), - # (TGate(), [q[2]], []), - # (HGate(), [q[2]], []), - # (CXGate(), [q[0], q[1]], []), - # (TGate(), [q[0]], []), - # (TdgGate(), [q[1]], []), - # (CXGate(), [q[0], q[1]], []) - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + """ + gate ccx a,b,c + { + h c; cx b,c; tdg c; cx a,c; + t c; cx b,c; tdg c; cx a,c; + t b; t c; h c; cx a,b; + t a; tdg b; cx a,b;} + """ + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + q = QuantumRegister(3, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (HGate(), [q[2]], []), + (CXGate(), [q[1], q[2]], []), + (TdgGate(), [q[2]], []), + (CXGate(), [q[0], q[2]], []), + (TGate(), [q[2]], []), + (CXGate(), [q[1], q[2]], []), + (TdgGate(), [q[2]], []), + (CXGate(), [q[0], q[2]], []), + (TGate(), [q[1]], []), + (TGate(), [q[2]], []), + (HGate(), [q[2]], []), + (CXGate(), [q[0], q[1]], []), + (TGate(), [q[0]], []), + (TdgGate(), [q[1]], []), + (CXGate(), [q[0], q[1]], []) + ] + qc.data = rules + self.definition = qc def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Controlled version of this gate. @@ -407,34 +413,37 @@ def __init__(self, label=None): """Create a new simplified CCX gate.""" super().__init__('rccx', 3, [], label=label) - # def _define(self): - # """ - # gate rccx a,b,c - # { u2(0,pi) c; - # u1(pi/4) c; - # cx b, c; - # u1(-pi/4) c; - # cx a, c; - # u1(pi/4) c; - # cx b, c; - # u1(-pi/4) c; - # u2(0,pi) c; - # } - # """ - # definition = [] - # q = QuantumRegister(3, 'q') - # definition = [ - # (U2Gate(0, pi), [q[2]], []), # H gate - # (U1Gate(pi / 4), [q[2]], []), # T gate - # (CXGate(), [q[1], q[2]], []), - # (U1Gate(-pi / 4), [q[2]], []), # inverse T gate - # (CXGate(), [q[0], q[2]], []), - # (U1Gate(pi / 4), [q[2]], []), - # (CXGate(), [q[1], q[2]], []), - # (U1Gate(-pi / 4), [q[2]], []), # inverse T gate - # (U2Gate(0, pi), [q[2]], []), # H gate - # ] - # self.definition = definition + def _define(self): + """ + gate rccx a,b,c + { u2(0,pi) c; + u1(pi/4) c; + cx b, c; + u1(-pi/4) c; + cx a, c; + u1(pi/4) c; + cx b, c; + u1(-pi/4) c; + u2(0,pi) c; + } + """ + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + q = QuantumRegister(3, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (U2Gate(0, pi), [q[2]], []), # H gate + (U1Gate(pi / 4), [q[2]], []), # T gate + (CXGate(), [q[1], q[2]], []), + (U1Gate(-pi / 4), [q[2]], []), # inverse T gate + (CXGate(), [q[0], q[2]], []), + (U1Gate(pi / 4), [q[2]], []), + (CXGate(), [q[1], q[2]], []), + (U1Gate(-pi / 4), [q[2]], []), # inverse T gate + (U2Gate(0, pi), [q[2]], []), # H gate + ] + qc.data = rules + self.definition = qc def to_matrix(self): """Return a numpy.array for the simplified CCX gate.""" @@ -490,10 +499,11 @@ def _define(self): h d; cu1(-pi/4) c,d; h d; } """ + # pylint: disable=cyclic-import from qiskit import QuantumCircuit from .u1 import CU1Gate q = QuantumRegister(4, name='q') - definition = [ + rules = [ (HGate(), [q[3]], []), (CU1Gate(-self._angle), [q[0], q[3]], []), (HGate(), [q[3]], []), @@ -523,7 +533,7 @@ def _define(self): (HGate(), [q[3]], []) ] qc = QuantumCircuit(q) - qc.data = definition + qc.data = rules self.definition = qc def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): @@ -585,52 +595,55 @@ def __init__(self, label=None): """Create a new RC3X gate.""" super().__init__('rcccx', 4, [], label=label) - # def _define(self): - # """ - # gate rc3x a,b,c,d - # { u2(0,pi) d; - # u1(pi/4) d; - # cx c,d; - # u1(-pi/4) d; - # u2(0,pi) d; - # cx a,d; - # u1(pi/4) d; - # cx b,d; - # u1(-pi/4) d; - # cx a,d; - # u1(pi/4) d; - # cx b,d; - # u1(-pi/4) d; - # u2(0,pi) d; - # u1(pi/4) d; - # cx c,d; - # u1(-pi/4) d; - # u2(0,pi) d; - # } - # """ - # q = QuantumRegister(4, 'q') - - # definition = [ - # (U2Gate(0, pi), [q[3]], []), # H gate - # (U1Gate(pi / 4), [q[3]], []), # T gate - # (CXGate(), [q[2], q[3]], []), - # (U1Gate(-pi / 4), [q[3]], []), # inverse T gate - # (U2Gate(0, pi), [q[3]], []), - # (CXGate(), [q[0], q[3]], []), - # (U1Gate(pi / 4), [q[3]], []), - # (CXGate(), [q[1], q[3]], []), - # (U1Gate(-pi / 4), [q[3]], []), - # (CXGate(), [q[0], q[3]], []), - # (U1Gate(pi / 4), [q[3]], []), - # (CXGate(), [q[1], q[3]], []), - # (U1Gate(-pi / 4), [q[3]], []), - # (U2Gate(0, pi), [q[3]], []), - # (U1Gate(pi / 4), [q[3]], []), - # (CXGate(), [q[2], q[3]], []), - # (U1Gate(-pi / 4), [q[3]], []), - # (U2Gate(0, pi), [q[3]], []), - # ] - # self.definition = definition + def _define(self): + """ + gate rc3x a,b,c,d + { u2(0,pi) d; + u1(pi/4) d; + cx c,d; + u1(-pi/4) d; + u2(0,pi) d; + cx a,d; + u1(pi/4) d; + cx b,d; + u1(-pi/4) d; + cx a,d; + u1(pi/4) d; + cx b,d; + u1(-pi/4) d; + u2(0,pi) d; + u1(pi/4) d; + cx c,d; + u1(-pi/4) d; + u2(0,pi) d; + } + """ + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + q = QuantumRegister(4, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (U2Gate(0, pi), [q[3]], []), # H gate + (U1Gate(pi / 4), [q[3]], []), # T gate + (CXGate(), [q[2], q[3]], []), + (U1Gate(-pi / 4), [q[3]], []), # inverse T gate + (U2Gate(0, pi), [q[3]], []), + (CXGate(), [q[0], q[3]], []), + (U1Gate(pi / 4), [q[3]], []), + (CXGate(), [q[1], q[3]], []), + (U1Gate(-pi / 4), [q[3]], []), + (CXGate(), [q[0], q[3]], []), + (U1Gate(pi / 4), [q[3]], []), + (CXGate(), [q[1], q[3]], []), + (U1Gate(-pi / 4), [q[3]], []), + (U2Gate(0, pi), [q[3]], []), + (U1Gate(pi / 4), [q[3]], []), + (CXGate(), [q[2], q[3]], []), + (U1Gate(-pi / 4), [q[3]], []), + (U2Gate(0, pi), [q[3]], []), + ] + qc.data = rules + self.definition = qc def to_matrix(self): """Return a numpy.array for the RC3X gate.""" @@ -694,10 +707,12 @@ def _define(self): c3sqrtx a,b,c,e; } """ + # pylint: disable=cyclic-import from qiskit import QuantumCircuit from .u1 import CU1Gate q = QuantumRegister(5, name='q') - definition = [ + qc = QuantumCircuit(q, name=self.name) + rules = [ (HGate(), [q[4]], []), (CU1Gate(-numpy.pi / 2), [q[3], q[4]], []), (HGate(), [q[4]], []), @@ -708,8 +723,7 @@ def _define(self): (C3XGate(), [q[0], q[1], q[2], q[3]], []), (C3XGate(numpy.pi / 8), [q[0], q[1], q[2], q[4]], []), ] - qc = QuantumCircuit(q) - qc.data = definition + qc.data = rules self.definition = qc def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): @@ -785,6 +799,7 @@ def get_num_ancilla_qubits(num_ctrl_qubits, mode='noancilla'): def _define(self): """The standard definition used the Gray code implementation.""" + # pylint: disable=cyclic-import from qiskit import QuantumCircuit q = QuantumRegister(self.num_qubits, name='q') qc = QuantumCircuit(q) @@ -828,6 +843,7 @@ def __init__(self, num_ctrl_qubits, label=None, ctrl_state=None): def _define(self): """Define the MCX gate using the Gray code.""" + # pylint: disable=cyclic-import from qiskit import QuantumCircuit from .u1 import MCU1Gate q = QuantumRegister(self.num_qubits, name='q') @@ -856,12 +872,12 @@ def get_num_ancilla_qubits(num_ctrl_qubits, mode='recursion'): def _define(self): """Define the MCX gate using recursion.""" + # pylint: disable=cyclic-import from qiskit import QuantumCircuit - #import ipdb;ipdb.set_trace() q = QuantumRegister(self.num_qubits, name='q') qc = QuantumCircuit(q, name=self.name) if self.num_qubits == 4: - qc.append(C3XGate(), qargs=q[:]) + qc.append(C3XGate(), qargs=q[:]) self.definition = qc elif self.num_qubits == 5: qc.append(C4XGate(), qargs=q[:]) @@ -916,7 +932,8 @@ def get_num_ancilla_qubits(num_ctrl_qubits, mode='v-chain'): def _define(self): """Define the MCX gate using a V-chain of CX gates.""" - from qiskit import QuantumCircuit + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit q = QuantumRegister(self.num_qubits, name='q') qc = QuantumCircuit(q, name=self.name) q_controls = q[:self.num_ctrl_qubits] diff --git a/qiskit/circuit/library/standard_gates/y.py b/qiskit/circuit/library/standard_gates/y.py index d66263687e35..51bf88ccf22d 100644 --- a/qiskit/circuit/library/standard_gates/y.py +++ b/qiskit/circuit/library/standard_gates/y.py @@ -16,6 +16,7 @@ import numpy from qiskit.qasm import pi +# pylint: disable=cyclic-import from qiskit.circuit.controlledgate import ControlledGate from qiskit.circuit.gate import Gate from qiskit.circuit.quantumregister import QuantumRegister @@ -68,16 +69,17 @@ def __init__(self, label=None): """Create new Y gate.""" super().__init__('y', 1, [], label=label) - # def _define(self): - # from .u3 import U3Gate - # definition = [] - # q = QuantumRegister(1, 'q') - # rule = [ - # (U3Gate(pi, pi / 2, pi / 2), [q[0]], []) - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + from .u3 import U3Gate + q = QuantumRegister(1, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (U3Gate(pi, pi / 2, pi / 2), [q[0]], []) + ] + qc.data = rules + self.definition = qc def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Return a (mutli-)controlled-Y gate. @@ -187,22 +189,23 @@ def __init__(self, label=None, ctrl_state=None): ctrl_state=ctrl_state) self.base_gate = YGate() - # def _define(self): - # """ - # gate cy a,b { sdg b; cx a,b; s b; } - # """ - # from .s import SGate, SdgGate - # from .x import CXGate - # definition = [] - # q = QuantumRegister(2, 'q') - # rule = [ - # (SdgGate(), [q[1]], []), - # (CXGate(), [q[0], q[1]], []), - # (SGate(), [q[1]], []) - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + """ + gate cy a,b { sdg b; cx a,b; s b; } + """ + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + from .s import SGate, SdgGate + from .x import CXGate + q = QuantumRegister(2, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (SdgGate(), [q[1]], []), + (CXGate(), [q[0], q[1]], []), + (SGate(), [q[1]], []) + ] + qc.data = rules + self.definition = qc def inverse(self): """Return inverted CY gate (itself).""" diff --git a/qiskit/circuit/library/standard_gates/z.py b/qiskit/circuit/library/standard_gates/z.py index 820d0e38ff33..1723b6eff74e 100644 --- a/qiskit/circuit/library/standard_gates/z.py +++ b/qiskit/circuit/library/standard_gates/z.py @@ -68,16 +68,17 @@ def __init__(self, label=None): """Create new Z gate.""" super().__init__('z', 1, [], label=label) - # def _define(self): - # from .u1 import U1Gate - # definition = [] - # q = QuantumRegister(1, 'q') - # rule = [ - # (U1Gate(pi), [q[0]], []) - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + from .u1 import U1Gate + q = QuantumRegister(1, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (U1Gate(pi), [q[0]], []) + ] + qc.data = rules + self.definition = qc def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Return a (mutli-)controlled-Z gate. @@ -155,22 +156,23 @@ def __init__(self, label=None, ctrl_state=None): ctrl_state=ctrl_state) self.base_gate = ZGate() - # def _define(self): - # """ - # gate cz a,b { h b; cx a,b; h b; } - # """ - # from .h import HGate - # from .x import CXGate - # definition = [] - # q = QuantumRegister(2, 'q') - # rule = [ - # (HGate(), [q[1]], []), - # (CXGate(), [q[0], q[1]], []), - # (HGate(), [q[1]], []) - # ] - # for inst in rule: - # definition.append(inst) - # self.definition = definition + def _define(self): + """ + gate cz a,b { h b; cx a,b; h b; } + """ + # pylint: disable=cyclic-import + from qiskit import QuantumCircuit + from .h import HGate + from .x import CXGate + q = QuantumRegister(2, 'q') + qc = QuantumCircuit(q, name=self.name) + rules = [ + (HGate(), [q[1]], []), + (CXGate(), [q[0], q[1]], []), + (HGate(), [q[1]], []) + ] + qc.data = rules + self.definition = qc def inverse(self): """Return inverted CZ gate (itself).""" diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index 391a8172f083..6b417641387b 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -769,7 +769,6 @@ def _check_cargs(self, cargs): if not all(isinstance(i, Clbit) for i in cargs): raise CircuitError("carg is not a Clbit") if not all(self.has_register(i.register) for i in cargs): - #import ipdb;ipdb.set_trace() raise CircuitError("register not in this circuit") def to_instruction(self, parameter_map=None): diff --git a/qiskit/converters/circuit_to_dag.py b/qiskit/converters/circuit_to_dag.py index a5a7931bd508..eaac9e13e96b 100644 --- a/qiskit/converters/circuit_to_dag.py +++ b/qiskit/converters/circuit_to_dag.py @@ -53,9 +53,6 @@ def circuit_to_dag(circuit): dagcircuit.add_creg(register) for instruction, qargs, cargs in circuit.data: - # print(instruction.name, qargs, cargs) - # if instruction.name == 'h': - # import ipdb;ipdb.set_trace() dagcircuit.apply_operation_back(instruction.copy(), qargs, cargs, instruction.condition) return dagcircuit diff --git a/qiskit/converters/circuit_to_instruction.py b/qiskit/converters/circuit_to_instruction.py index 69b48e8f21c8..545490982265 100644 --- a/qiskit/converters/circuit_to_instruction.py +++ b/qiskit/converters/circuit_to_instruction.py @@ -78,7 +78,7 @@ def circuit_to_instruction(circuit, parameter_map=None, equivalence_library=None params=sorted(parameter_dict.values(), key=lambda p: p.name)) instruction.condition = None - def find_bit_position(bit): # + def find_bit_position(bit): """find the index of a given bit (Register, int) within a flat ordered list of bits of the circuit """ @@ -104,7 +104,7 @@ def find_bit_position(bit): # if instruction.num_clbits > 0: c = ClassicalRegister(instruction.num_clbits, 'c') regs.append(c) - + definition = list(map(lambda x: (x[0], list(map(lambda y: q[find_bit_position(y)], x[1])), @@ -118,7 +118,8 @@ def find_bit_position(bit): # if reg.size == c.size: rule[0].condition = (c, val) else: - raise CircuitError('Cannot convert condition in circuit with multiple classical registers to instruction') + raise QiskitError('Cannot convert condition in circuit with ' + 'multiple classical registers to instruction') qc = QuantumCircuit(*regs, name=instruction.name) qc.data = definition diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index 75cc5e8b25ca..d0efbd18911b 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -283,7 +283,6 @@ def _check_condition(self, name, condition): """ # Verify creg exists if condition is not None and condition[0].name not in self.cregs: - #import ipdb;ipdb.set_trace() raise DAGCircuitError("invalid creg in condition for %s" % name) def _check_bits(self, args, amap): diff --git a/qiskit/extensions/quantum_initializer/squ.py b/qiskit/extensions/quantum_initializer/squ.py index 817224ca5216..8f77d1de816a 100644 --- a/qiskit/extensions/quantum_initializer/squ.py +++ b/qiskit/extensions/quantum_initializer/squ.py @@ -27,9 +27,6 @@ from qiskit.circuit.gate import Gate from qiskit.quantum_info.operators.predicates import is_unitary_matrix from qiskit.exceptions import QiskitError -from qiskit.circuit.library.standard_gates.ry import RYGate -from qiskit.circuit.library.standard_gates.rz import RZGate - from qiskit.util import deprecate_arguments _EPS = 1e-10 # global variable used to chop very small numbers to zero @@ -84,14 +81,13 @@ def _define(self): raise QiskitError('The decomposition mode is not known.') self._diag = diag - + self.definition = circuit def _zyz_circuit(self): """Get the circuit for the ZYZ decomposition.""" q = QuantumRegister(self.num_qubits) qc = QuantumCircuit(q, name=self.name) - rule = [] diag = [1., 1.] alpha, beta, gamma, _ = self._zyz_dec() diff --git a/qiskit/extensions/unitary.py b/qiskit/extensions/unitary.py index 271080106a97..35297d5f37e1 100644 --- a/qiskit/extensions/unitary.py +++ b/qiskit/extensions/unitary.py @@ -23,7 +23,6 @@ from qiskit.circuit import QuantumCircuit from qiskit.circuit import QuantumRegister from qiskit.circuit._utils import _compute_control_matrix -from qiskit.circuit.library.standard_gates import U3Gate from qiskit.extensions.quantum_initializer import isometry from qiskit.quantum_info.operators.predicates import matrix_equal from qiskit.quantum_info.operators.predicates import is_unitary_matrix diff --git a/qiskit/quantum_info/operators/channel/superop.py b/qiskit/quantum_info/operators/channel/superop.py index 5952cf653ae1..6012bfd2364f 100644 --- a/qiskit/quantum_info/operators/channel/superop.py +++ b/qiskit/quantum_info/operators/channel/superop.py @@ -392,8 +392,9 @@ def _append_instruction(self, obj, qargs=None): raise QiskitError('Cannot apply Instruction: {}'.format( obj.name)) if not isinstance(obj.definition, QuantumCircuit): - raise QiskitError('{0} instruction definition is {1}; expected QuantumCircuit'.format( - obj.name, type(obj.definition))) + raise QiskitError('{0} instruction definition is {1}; ' + 'expected QuantumCircuit'.format( + obj.name, type(obj.definition))) for instr, qregs, cregs in obj.definition.data: if cregs: raise QiskitError( diff --git a/qiskit/transpiler/passes/basis/unroll_custom_definitions.py b/qiskit/transpiler/passes/basis/unroll_custom_definitions.py index 8e9bc90dc7a8..feeaef493480 100644 --- a/qiskit/transpiler/passes/basis/unroll_custom_definitions.py +++ b/qiskit/transpiler/passes/basis/unroll_custom_definitions.py @@ -69,7 +69,7 @@ def run(self, dag): rule = node.op.definition.data except TypeError as err: raise QiskitError('Error decomposing node {}: {}'.format(node.name, err)) - except AttributeError as aerr: + except AttributeError: # definition is None rule = None diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 663f126835b4..c4a890dcc40c 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -146,10 +146,9 @@ def test_multi_controlled_composite_gate(self): target = QuantumRegister(num_target) qc = QuantumCircuit(control, target) qc.append(cont_gate, control[:] + target[:]) - simulator = BasicAer.get_backend('unitary_simulator') - op_mat = execute(cgate, simulator).result().get_unitary(0) + op_mat = Operator(cgate).data cop_mat = _compute_control_matrix(op_mat, num_ctrl) - ref_mat = execute(qc, simulator).result().get_unitary(0) + ref_mat = Operator(qc).data self.assertTrue(matrix_equal(cop_mat, ref_mat, ignore_phase=True)) def test_single_controlled_composite_gate(self): @@ -167,10 +166,9 @@ def test_single_controlled_composite_gate(self): target = QuantumRegister(num_target, 'target') qc = QuantumCircuit(control, target) qc.append(cont_gate, control[:] + target[:]) - simulator = BasicAer.get_backend('unitary_simulator') - op_mat = execute(cgate, simulator).result().get_unitary(0) + op_mat = Operator(cgate).data cop_mat = _compute_control_matrix(op_mat, num_ctrl) - ref_mat = execute(qc, simulator).result().get_unitary(0) + ref_mat = Operator(qc).data self.assertTrue(matrix_equal(cop_mat, ref_mat, ignore_phase=True)) def test_multi_control_u3(self): @@ -206,17 +204,11 @@ def test_multi_control_u3(self): c_cu3 = cu3gate.control(1) qc_cu3.append(c_cu3, qr, []) - job = execute([qcnu3, qu3, qcu3, qc_cu3], BasicAer.get_backend('unitary_simulator'), - basis_gates=['u1', 'u2', 'u3', 'id', 'cx']) - result = job.result() - # Circuit unitaries - #mat_cnu3 = result.get_unitary(0) # unitary_simulator is giving different output than Operator?? mat_cnu3 = Operator(qcnu3).data - - mat_u3 = result.get_unitary(1) - mat_cu3 = result.get_unitary(2) - mat_c_cu3 = result.get_unitary(3) + mat_u3 = Operator(qu3).data + mat_cu3 = Operator(qcu3).data + mat_c_cu3 = Operator(qc_cu3).data # Target Controlled-U3 unitary target_cnu3 = _compute_control_matrix(mat_u3, num_ctrl) @@ -232,10 +224,8 @@ def test_multi_control_u3(self): for itest in tests: info, target, decomp = itest[0], itest[1], itest[2] with self.subTest(i=info): - if info == 'check unitary of cnu3 against tensored unitary of u3': - np.set_printoptions(precision=2, linewidth=300, suppress=True) - import ipdb;ipdb.set_trace() - self.assertTrue(matrix_equal(target, decomp, ignore_phase=True, atol=1e-8, rtol=1e-5)) + self.assertTrue(matrix_equal(target, decomp, ignore_phase=True, + atol=1e-8, rtol=1e-5)) def test_multi_control_u1(self): """Test the matrix representation of the controlled and controlled-controlled U1 gate.""" @@ -577,9 +567,6 @@ def test_mcx_gates(self, num_ctrl_qubits): i = int(bin(i)[2:].zfill(circuit.num_qubits)[gate.num_ancilla_qubits:], 2) corrected[i] += statevector_amplitude statevector = corrected - np.set_printoptions(precision=3, linewidth=200, suppress=True) - # if isinstance(gate, MCXRecursive): - # import ipdb;ipdb.set_trace() np.testing.assert_array_almost_equal(statevector.real, reference) @data(1, 2, 3, 4) @@ -1015,12 +1002,10 @@ def test_controlled_standard_gates(self, num_ctrl_qubits, gate_class): for ctrl_state in {ctrl_state_ones, ctrl_state_zeros, ctrl_state_mixed}: with self.subTest(i='{0}, ctrl_state={1}'.format(gate_class.__name__, ctrl_state)): - np.set_printoptions(precision=3, linewidth=200, suppress=True) if hasattr(gate, 'num_ancilla_qubits') and gate.num_ancilla_qubits > 0: # skip matrices that include ancilla qubits continue try: - #import ipdb;ipdb.set_trace() cgate = gate.control(num_ctrl_qubits, ctrl_state=ctrl_state) except (AttributeError, QiskitError): # 'object has no attribute "control"' @@ -1034,9 +1019,6 @@ def test_controlled_standard_gates(self, num_ctrl_qubits, gate_class): base_mat = Operator(gate).data target_mat = _compute_control_matrix(base_mat, num_ctrl_qubits, ctrl_state=ctrl_state) - - #import ipdb;ipdb.set_trace() - src_mat = Operator(cgate).data self.assertTrue(matrix_equal(Operator(cgate).data, target_mat, ignore_phase=True)) diff --git a/test/python/circuit/test_instructions.py b/test/python/circuit/test_instructions.py index 43b375415a50..fa25211b9b18 100644 --- a/test/python/circuit/test_instructions.py +++ b/test/python/circuit/test_instructions.py @@ -187,7 +187,7 @@ def test_reverse_instruction(self): circ.measure(q[0], c[0]) circ.rz(0.8, q[0]).c_if(c, 6) inst = circ.to_instruction() - + circ = QuantumCircuit(q, c, name='circ') circ.rz(0.8, q[0]).c_if(c, 6) circ.measure(q[0], c[0]) diff --git a/test/python/circuit/test_library.py b/test/python/circuit/test_library.py index e0a3d719f347..5f7b936f1e27 100644 --- a/test/python/circuit/test_library.py +++ b/test/python/circuit/test_library.py @@ -640,7 +640,6 @@ def pw_linear(x): pw_linear_rotations = PiecewiseLinearPauliRotations(num_state_qubits, breakpoints, [2 * slope for slope in slopes], [2 * offset for offset in offsets]) - self.assertFunctionIsCorrect(pw_linear_rotations, pw_linear) def test_piecewise_linear_rotations_mutability(self): From 87db6327c94a03f9fce31f0528b0bce7f30bd641 Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Tue, 30 Jun 2020 23:35:14 -0400 Subject: [PATCH 13/38] linting --- qiskit/circuit/controlledgate.py | 1 + qiskit/circuit/library/standard_gates/dcx.py | 3 ++- qiskit/circuit/library/standard_gates/h.py | 4 ++-- .../circuit/library/standard_gates/iswap.py | 2 +- qiskit/circuit/library/standard_gates/ms.py | 2 +- qiskit/circuit/library/standard_gates/r.py | 2 +- qiskit/circuit/library/standard_gates/rx.py | 6 ++++-- qiskit/circuit/library/standard_gates/rxx.py | 2 +- qiskit/circuit/library/standard_gates/ry.py | 6 ++++-- qiskit/circuit/library/standard_gates/ryy.py | 2 +- qiskit/circuit/library/standard_gates/rz.py | 4 ++-- qiskit/circuit/library/standard_gates/rzx.py | 2 +- qiskit/circuit/library/standard_gates/rzz.py | 2 +- qiskit/circuit/library/standard_gates/s.py | 4 ++-- qiskit/circuit/library/standard_gates/swap.py | 4 ++-- qiskit/circuit/library/standard_gates/t.py | 4 ++-- qiskit/circuit/library/standard_gates/u1.py | 6 +++--- qiskit/circuit/library/standard_gates/u2.py | 2 +- qiskit/circuit/library/standard_gates/u3.py | 2 +- qiskit/circuit/library/standard_gates/x.py | 20 +++++++++---------- qiskit/circuit/library/standard_gates/y.py | 4 ++-- qiskit/circuit/library/standard_gates/z.py | 4 ++-- qiskit/converters/circuit_to_gate.py | 3 ++- qiskit/converters/circuit_to_instruction.py | 3 ++- 24 files changed, 51 insertions(+), 43 deletions(-) diff --git a/qiskit/circuit/controlledgate.py b/qiskit/circuit/controlledgate.py index 4ae456aec9bc..e49062bfc92f 100644 --- a/qiskit/circuit/controlledgate.py +++ b/qiskit/circuit/controlledgate.py @@ -106,6 +106,7 @@ def definition(self) -> List: definition is conjugated with X without changing the internal `_definition`. """ + # pylint: disable=cyclic-import from qiskit import QuantumCircuit if self._open_ctrl: closed_gate = self.copy() diff --git a/qiskit/circuit/library/standard_gates/dcx.py b/qiskit/circuit/library/standard_gates/dcx.py index 1b681ae22268..7767fe38cfa4 100644 --- a/qiskit/circuit/library/standard_gates/dcx.py +++ b/qiskit/circuit/library/standard_gates/dcx.py @@ -54,7 +54,8 @@ def _define(self): """ gate dcx a, b { cx a, b; cx a, b; } """ - from qiskit import QuantumCircuit + # pylint: disable=cyclic-import + from qiskit.circuit.quantumcircuit import QuantumCircuit from .x import CXGate q = QuantumRegister(2, 'q') qc = QuantumCircuit(q, name=self.name) diff --git a/qiskit/circuit/library/standard_gates/h.py b/qiskit/circuit/library/standard_gates/h.py index 0249ce57a03a..20dab2abbd31 100644 --- a/qiskit/circuit/library/standard_gates/h.py +++ b/qiskit/circuit/library/standard_gates/h.py @@ -58,7 +58,7 @@ def _define(self): gate h a { u2(0,pi) a; } """ # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .u2 import U2Gate q = QuantumRegister(1, 'q') qc = QuantumCircuit(q, name=self.name) @@ -183,7 +183,7 @@ def _define(self): } """ # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .x import CXGate # pylint: disable=cyclic-import q = QuantumRegister(2, 'q') qc = QuantumCircuit(q, name=self.name) diff --git a/qiskit/circuit/library/standard_gates/iswap.py b/qiskit/circuit/library/standard_gates/iswap.py index cfaa76c0f34a..6df3dcd55ef9 100644 --- a/qiskit/circuit/library/standard_gates/iswap.py +++ b/qiskit/circuit/library/standard_gates/iswap.py @@ -93,7 +93,7 @@ def _define(self): } """ # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .h import HGate from .s import SGate from .x import CXGate diff --git a/qiskit/circuit/library/standard_gates/ms.py b/qiskit/circuit/library/standard_gates/ms.py index e987cb232ff8..fae673c52c98 100644 --- a/qiskit/circuit/library/standard_gates/ms.py +++ b/qiskit/circuit/library/standard_gates/ms.py @@ -37,7 +37,7 @@ def __init__(self, num_qubits, theta, *, n_qubits=None, # pylint:disable=unused def _define(self): # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .rxx import RXXGate q = QuantumRegister(self.num_qubits, 'q') qc = QuantumCircuit(q, name=self.name) diff --git a/qiskit/circuit/library/standard_gates/r.py b/qiskit/circuit/library/standard_gates/r.py index 76c16e4cdce2..bcac9b868eb6 100644 --- a/qiskit/circuit/library/standard_gates/r.py +++ b/qiskit/circuit/library/standard_gates/r.py @@ -53,7 +53,7 @@ def _define(self): gate r(θ, φ) a {u3(θ, φ - π/2, -φ + π/2) a;} """ # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .u3 import U3Gate q = QuantumRegister(1, 'q') qc = QuantumCircuit(q, name=self.name) diff --git a/qiskit/circuit/library/standard_gates/rx.py b/qiskit/circuit/library/standard_gates/rx.py index d006aeed8048..5f3011288ec8 100644 --- a/qiskit/circuit/library/standard_gates/rx.py +++ b/qiskit/circuit/library/standard_gates/rx.py @@ -54,7 +54,8 @@ def _define(self): """ gate rx(theta) a {r(theta, 0) a;} """ - from qiskit import QuantumCircuit + # pylint: disable=cyclic-import + from qiskit.circuit.quantumcircuit import QuantumCircuit from .r import RGate q = QuantumRegister(1, 'q') qc = QuantumCircuit(q, name=self.name) @@ -178,7 +179,8 @@ def _define(self): u3(theta/2,-pi/2,0) t; } """ - from qiskit import QuantumCircuit + # pylint: disable=cyclic-import + from qiskit.circuit.quantumcircuit import QuantumCircuit from .u1 import U1Gate from .u3 import U3Gate from .x import CXGate diff --git a/qiskit/circuit/library/standard_gates/rxx.py b/qiskit/circuit/library/standard_gates/rxx.py index 942c38e7d850..352692523ad0 100644 --- a/qiskit/circuit/library/standard_gates/rxx.py +++ b/qiskit/circuit/library/standard_gates/rxx.py @@ -75,7 +75,7 @@ def __init__(self, theta): def _define(self): """Calculate a subcircuit that implements this unitary.""" # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .x import CXGate from .u1 import U1Gate from .h import HGate diff --git a/qiskit/circuit/library/standard_gates/ry.py b/qiskit/circuit/library/standard_gates/ry.py index 4088b2956006..76889b77db87 100644 --- a/qiskit/circuit/library/standard_gates/ry.py +++ b/qiskit/circuit/library/standard_gates/ry.py @@ -54,7 +54,8 @@ def _define(self): """ gate ry(theta) a { r(theta, pi/2) a; } """ - from qiskit import QuantumCircuit + # pylint: disable=cyclic-import + from qiskit.circuit.quantumcircuit import QuantumCircuit from .r import RGate q = QuantumRegister(1, 'q') qc = QuantumCircuit(q, name=self.name) @@ -175,7 +176,8 @@ def _define(self): u3(-lambda/2,0,0) b; cx a,b; } """ - from qiskit import QuantumCircuit + # pylint: disable=cyclic-import + from qiskit.circuit.quantumcircuit import QuantumCircuit from .u3 import U3Gate from .x import CXGate q = QuantumRegister(2, 'q') diff --git a/qiskit/circuit/library/standard_gates/ryy.py b/qiskit/circuit/library/standard_gates/ryy.py index 09c45a6352e7..4c50bc8ef7d6 100644 --- a/qiskit/circuit/library/standard_gates/ryy.py +++ b/qiskit/circuit/library/standard_gates/ryy.py @@ -76,7 +76,7 @@ def __init__(self, theta): def _define(self): """Calculate a subcircuit that implements this unitary.""" # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .x import CXGate from .rx import RXGate from .rz import RZGate diff --git a/qiskit/circuit/library/standard_gates/rz.py b/qiskit/circuit/library/standard_gates/rz.py index 5a506ef52627..1da5bd692164 100644 --- a/qiskit/circuit/library/standard_gates/rz.py +++ b/qiskit/circuit/library/standard_gates/rz.py @@ -65,7 +65,7 @@ def _define(self): gate rz(phi) a { u1(phi) a; } """ # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .u1 import U1Gate q = QuantumRegister(1, 'q') qc = QuantumCircuit(q, name=self.name) @@ -195,7 +195,7 @@ def _define(self): } """ # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .u1 import U1Gate from .x import CXGate q = QuantumRegister(2, 'q') diff --git a/qiskit/circuit/library/standard_gates/rzx.py b/qiskit/circuit/library/standard_gates/rzx.py index 4f4236e4c8c8..aa69d0b27d70 100644 --- a/qiskit/circuit/library/standard_gates/rzx.py +++ b/qiskit/circuit/library/standard_gates/rzx.py @@ -126,7 +126,7 @@ def _define(self): gate rzx(theta) a, b { h b; cx a, b; u1(theta) b; cx a, b; h b;} """ # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit q = QuantumRegister(2, 'q') qc = QuantumCircuit(q, name=self.name) rules = [ diff --git a/qiskit/circuit/library/standard_gates/rzz.py b/qiskit/circuit/library/standard_gates/rzz.py index 1acf95b9a897..8a78ad47c323 100644 --- a/qiskit/circuit/library/standard_gates/rzz.py +++ b/qiskit/circuit/library/standard_gates/rzz.py @@ -90,7 +90,7 @@ def _define(self): gate rzz(theta) a, b { cx a, b; u1(theta) b; cx a, b; } """ # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .u1 import U1Gate from .x import CXGate q = QuantumRegister(2, 'q') diff --git a/qiskit/circuit/library/standard_gates/s.py b/qiskit/circuit/library/standard_gates/s.py index 16b8239caadc..ce94e06de0fe 100644 --- a/qiskit/circuit/library/standard_gates/s.py +++ b/qiskit/circuit/library/standard_gates/s.py @@ -56,7 +56,7 @@ def _define(self): gate s a { u1(pi/2) a; } """ # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .u1 import U1Gate q = QuantumRegister(1, 'q') qc = QuantumCircuit(q, name=self.name) @@ -112,7 +112,7 @@ def _define(self): gate sdg a { u1(-pi/2) a; } """ # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .u1 import U1Gate q = QuantumRegister(1, 'q') qc = QuantumCircuit(q, name=self.name) diff --git a/qiskit/circuit/library/standard_gates/swap.py b/qiskit/circuit/library/standard_gates/swap.py index 4b2f9e95c952..1c0c94d7d3cb 100644 --- a/qiskit/circuit/library/standard_gates/swap.py +++ b/qiskit/circuit/library/standard_gates/swap.py @@ -61,7 +61,7 @@ def _define(self): gate swap a,b { cx a,b; cx b,a; cx a,b; } """ # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .x import CXGate q = QuantumRegister(2, 'q') qc = QuantumCircuit(q, name=self.name) @@ -220,7 +220,7 @@ def _define(self): } """ # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .x import CXGate, CCXGate q = QuantumRegister(3, 'q') qc = QuantumCircuit(q, name=self.name) diff --git a/qiskit/circuit/library/standard_gates/t.py b/qiskit/circuit/library/standard_gates/t.py index 9d6b4aa71213..8a6f683c0268 100644 --- a/qiskit/circuit/library/standard_gates/t.py +++ b/qiskit/circuit/library/standard_gates/t.py @@ -57,7 +57,7 @@ def _define(self): gate t a { u1(pi/4) a; } """ # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .u1 import U1Gate q = QuantumRegister(1, 'q') qc = QuantumCircuit(q, name=self.name) @@ -113,7 +113,7 @@ def _define(self): gate tdg a { u1(pi/4) a; } """ # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .u1 import U1Gate q = QuantumRegister(1, 'q') qc = QuantumCircuit(q, name=self.name) diff --git a/qiskit/circuit/library/standard_gates/u1.py b/qiskit/circuit/library/standard_gates/u1.py index 74f72a08c9a6..7a7f47446922 100644 --- a/qiskit/circuit/library/standard_gates/u1.py +++ b/qiskit/circuit/library/standard_gates/u1.py @@ -81,7 +81,7 @@ def __init__(self, theta, label=None): def _define(self): # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .u3 import U3Gate # pylint: disable=cyclic-import q = QuantumRegister(1, 'q') qc = QuantumCircuit(q, name=self.name) @@ -185,7 +185,7 @@ def _define(self): } """ # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .x import CXGate # pylint: disable=cyclic-import q = QuantumRegister(2, 'q') qc = QuantumCircuit(q, name=self.name) @@ -278,7 +278,7 @@ def __init__(self, lam, num_ctrl_qubits, label=None): def _define(self): # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit q = QuantumRegister(self.num_qubits, 'q') qc = QuantumCircuit(q, name=self.name) diff --git a/qiskit/circuit/library/standard_gates/u2.py b/qiskit/circuit/library/standard_gates/u2.py index c6ee740becf5..427c9a4dcad8 100644 --- a/qiskit/circuit/library/standard_gates/u2.py +++ b/qiskit/circuit/library/standard_gates/u2.py @@ -65,7 +65,7 @@ def __init__(self, phi, lam, label=None): def _define(self): # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .u3 import U3Gate q = QuantumRegister(1, 'q') qc = QuantumCircuit(q, name=self.name) diff --git a/qiskit/circuit/library/standard_gates/u3.py b/qiskit/circuit/library/standard_gates/u3.py index ae58f0738b42..21e4b25a3ed9 100644 --- a/qiskit/circuit/library/standard_gates/u3.py +++ b/qiskit/circuit/library/standard_gates/u3.py @@ -192,7 +192,7 @@ def _define(self): } """ # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .u1 import U1Gate from .x import CXGate # pylint: disable=cyclic-import q = QuantumRegister(2, 'q') diff --git a/qiskit/circuit/library/standard_gates/x.py b/qiskit/circuit/library/standard_gates/x.py index 1afef22c3e92..719e3b64982e 100644 --- a/qiskit/circuit/library/standard_gates/x.py +++ b/qiskit/circuit/library/standard_gates/x.py @@ -79,7 +79,7 @@ def _define(self): gate x a { u3(pi,0,pi) a; } """ # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .u3 import U3Gate q = QuantumRegister(1, 'q') qc = QuantumCircuit(q, name=self.name) @@ -331,7 +331,7 @@ def _define(self): t a; tdg b; cx a,b;} """ # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit q = QuantumRegister(3, 'q') qc = QuantumCircuit(q, name=self.name) rules = [ @@ -428,7 +428,7 @@ def _define(self): } """ # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit q = QuantumRegister(3, 'q') qc = QuantumCircuit(q, name=self.name) rules = [ @@ -500,7 +500,7 @@ def _define(self): } """ # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .u1 import CU1Gate q = QuantumRegister(4, name='q') rules = [ @@ -619,7 +619,7 @@ def _define(self): } """ # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit q = QuantumRegister(4, 'q') qc = QuantumCircuit(q, name=self.name) rules = [ @@ -708,7 +708,7 @@ def _define(self): } """ # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .u1 import CU1Gate q = QuantumRegister(5, name='q') qc = QuantumCircuit(q, name=self.name) @@ -800,7 +800,7 @@ def get_num_ancilla_qubits(num_ctrl_qubits, mode='noancilla'): def _define(self): """The standard definition used the Gray code implementation.""" # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit q = QuantumRegister(self.num_qubits, name='q') qc = QuantumCircuit(q) qc.append(MCXGrayCode(self.num_ctrl_qubits), qargs=q[:]) @@ -844,7 +844,7 @@ def __init__(self, num_ctrl_qubits, label=None, ctrl_state=None): def _define(self): """Define the MCX gate using the Gray code.""" # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .u1 import MCU1Gate q = QuantumRegister(self.num_qubits, name='q') qc = QuantumCircuit(q, name=self.name) @@ -873,7 +873,7 @@ def get_num_ancilla_qubits(num_ctrl_qubits, mode='recursion'): def _define(self): """Define the MCX gate using recursion.""" # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit q = QuantumRegister(self.num_qubits, name='q') qc = QuantumCircuit(q, name=self.name) if self.num_qubits == 4: @@ -933,7 +933,7 @@ def get_num_ancilla_qubits(num_ctrl_qubits, mode='v-chain'): def _define(self): """Define the MCX gate using a V-chain of CX gates.""" # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit q = QuantumRegister(self.num_qubits, name='q') qc = QuantumCircuit(q, name=self.name) q_controls = q[:self.num_ctrl_qubits] diff --git a/qiskit/circuit/library/standard_gates/y.py b/qiskit/circuit/library/standard_gates/y.py index 51bf88ccf22d..5c19c366ad3f 100644 --- a/qiskit/circuit/library/standard_gates/y.py +++ b/qiskit/circuit/library/standard_gates/y.py @@ -71,7 +71,7 @@ def __init__(self, label=None): def _define(self): # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .u3 import U3Gate q = QuantumRegister(1, 'q') qc = QuantumCircuit(q, name=self.name) @@ -194,7 +194,7 @@ def _define(self): gate cy a,b { sdg b; cx a,b; s b; } """ # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .s import SGate, SdgGate from .x import CXGate q = QuantumRegister(2, 'q') diff --git a/qiskit/circuit/library/standard_gates/z.py b/qiskit/circuit/library/standard_gates/z.py index 1723b6eff74e..b649d65d9617 100644 --- a/qiskit/circuit/library/standard_gates/z.py +++ b/qiskit/circuit/library/standard_gates/z.py @@ -70,7 +70,7 @@ def __init__(self, label=None): def _define(self): # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .u1 import U1Gate q = QuantumRegister(1, 'q') qc = QuantumCircuit(q, name=self.name) @@ -161,7 +161,7 @@ def _define(self): gate cz a,b { h b; cx a,b; h b; } """ # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + from qiskit.circuit.quantumcircuit import QuantumCircuit from .h import HGate from .x import CXGate q = QuantumRegister(2, 'q') diff --git a/qiskit/converters/circuit_to_gate.py b/qiskit/converters/circuit_to_gate.py index d9234e83556c..ab90dab97729 100644 --- a/qiskit/converters/circuit_to_gate.py +++ b/qiskit/converters/circuit_to_gate.py @@ -15,7 +15,6 @@ """Helper function for converting a circuit to a gate""" -from qiskit.circuit import QuantumCircuit from qiskit.circuit.gate import Gate from qiskit.circuit.quantumregister import QuantumRegister, Qubit from qiskit.exceptions import QiskitError @@ -46,6 +45,8 @@ def circuit_to_gate(circuit, parameter_map=None, equivalence_library=None): input circuit. Upon decomposition, this gate will yield the components comprising the original circuit. """ + # pylint: disable=cyclic-import + from qiskit.circuit.quantumcircuit import QuantumCircuit if circuit.clbits: raise QiskitError('Circuit with classical bits cannot be converted ' 'to gate.') diff --git a/qiskit/converters/circuit_to_instruction.py b/qiskit/converters/circuit_to_instruction.py index 545490982265..9d7f4d521875 100644 --- a/qiskit/converters/circuit_to_instruction.py +++ b/qiskit/converters/circuit_to_instruction.py @@ -15,7 +15,6 @@ """Helper function for converting a circuit to an instruction.""" from qiskit.exceptions import QiskitError -from qiskit.circuit import QuantumCircuit from qiskit.circuit.instruction import Instruction from qiskit.circuit.quantumregister import QuantumRegister, Qubit from qiskit.circuit.classicalregister import ClassicalRegister @@ -61,6 +60,8 @@ def circuit_to_instruction(circuit, parameter_map=None, equivalence_library=None circ.rz(0.5, q[1]).c_if(c, 2) circuit_to_instruction(circ) """ + # pylint: disable=cyclic-import + from qiskit.circuit.quantumcircuit import QuantumCircuit if parameter_map is None: parameter_dict = {p: p for p in circuit.parameters} From c3b377617fafb136f0275ade8e8e1411886fa98c Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Fri, 3 Jul 2020 00:08:15 -0400 Subject: [PATCH 14/38] resolve qreg bug in transpiler --- qiskit/circuit/add_control.py | 14 ++++- qiskit/transpiler/passes/basis/decompose.py | 9 +-- .../passes/basis/unroll_3q_or_more.py | 9 +-- .../passes/basis/unroll_custom_definitions.py | 9 +-- qiskit/transpiler/passes/basis/unroller.py | 13 +--- test/python/circuit/test_controlled_gate.py | 60 +++++++++++++++++++ test/python/circuit/test_library.py | 1 + 7 files changed, 81 insertions(+), 34 deletions(-) diff --git a/qiskit/circuit/add_control.py b/qiskit/circuit/add_control.py index b70816b4a77c..ecdceca40089 100644 --- a/qiskit/circuit/add_control.py +++ b/qiskit/circuit/add_control.py @@ -184,7 +184,7 @@ def _gate_to_circuit(operation): qr = QuantumRegister(operation.num_qubits) qc = QuantumCircuit(qr, name=operation.name) if hasattr(operation, 'definition') and operation.definition: - for rule in operation.definition: + for rule in operation.definition.data: if rule[0].name in {'id', 'barrier', 'measure', 'snapshot'}: raise CircuitError('Cannot make controlled gate with {} instruction'.format( rule[0].name)) @@ -193,12 +193,20 @@ def _gate_to_circuit(operation): qc.append(operation, qargs=qr, cargs=[]) return qc +def _gate_to_dag(operation): + from qiskit.converters.circuit_to_dag import circuit_to_dag + if hasattr(operation, 'definition') and operation.definition: + return circuit_to_dag(operation.definition) + else: + qr = QuantumRegister(operation.num_qubits) + qc = QuantumCircuit(qr, name=operation.name) + qc.append(operation, qr) + return circuit_to_dag(qc) def _unroll_gate(operation, basis_gates): - from qiskit.converters.circuit_to_dag import circuit_to_dag from qiskit.converters.dag_to_circuit import dag_to_circuit from qiskit.transpiler.passes import Unroller unroller = Unroller(basis_gates) - dag = circuit_to_dag(_gate_to_circuit(operation)) + dag = _gate_to_dag(operation) qc = dag_to_circuit(unroller.run(dag)) return qc.to_gate() diff --git a/qiskit/transpiler/passes/basis/decompose.py b/qiskit/transpiler/passes/basis/decompose.py index 3517b6f0c40d..0e60ba980999 100644 --- a/qiskit/transpiler/passes/basis/decompose.py +++ b/qiskit/transpiler/passes/basis/decompose.py @@ -19,6 +19,7 @@ from qiskit.circuit.gate import Gate from qiskit.transpiler.basepasses import TransformationPass from qiskit.dagcircuit.dagcircuit import DAGCircuit +from qiskit.transpiler.passes.utils.ordered_regs import _make_ordered_regs class Decompose(TransformationPass): @@ -53,14 +54,10 @@ def run(self, dag: DAGCircuit) -> DAGCircuit: if len(rule) == 1 and len(node.qargs) == len(rule[0][1]): dag.substitute_node(node, rule[0][0], inplace=True) else: - # hacky way to build a dag on the same register as the rule is defined - # TODO: need anonymous rules to address wires by index decomposition = DAGCircuit() - qregs = {qb.register for inst in rule for qb in inst[1]} - cregs = {cb.register for inst in rule for cb in inst[2]} - for qreg in qregs: + for qreg in node.op.definition.qregs: decomposition.add_qreg(qreg) - for creg in cregs: + for creg in node.op.definition.cregs: decomposition.add_creg(creg) for inst in rule: decomposition.apply_operation_back(*inst) diff --git a/qiskit/transpiler/passes/basis/unroll_3q_or_more.py b/qiskit/transpiler/passes/basis/unroll_3q_or_more.py index b95e01998702..8f7eb52da64c 100644 --- a/qiskit/transpiler/passes/basis/unroll_3q_or_more.py +++ b/qiskit/transpiler/passes/basis/unroll_3q_or_more.py @@ -42,15 +42,10 @@ def run(self, dag): raise QiskitError("Cannot unroll all 3q or more gates. " "No rule to expand instruction %s." % node.op.name) - - # hacky way to build a dag on the same register as the rule is defined - # TODO: need anonymous rules to address wires by index decomposition = DAGCircuit() - qregs = {qb.register for inst in rule for qb in inst[1]} - cregs = {cb.register for inst in rule for cb in inst[2]} - for qreg in qregs: + for qreg in node.op.definition.qregs: decomposition.add_qreg(qreg) - for creg in cregs: + for creg in node.op.definition.cregs: decomposition.add_creg(creg) for inst in rule: decomposition.apply_operation_back(*inst) diff --git a/qiskit/transpiler/passes/basis/unroll_custom_definitions.py b/qiskit/transpiler/passes/basis/unroll_custom_definitions.py index feeaef493480..0b9780218145 100644 --- a/qiskit/transpiler/passes/basis/unroll_custom_definitions.py +++ b/qiskit/transpiler/passes/basis/unroll_custom_definitions.py @@ -83,15 +83,10 @@ def run(self, dag): "Instruction %s not found in equivalence library " "and no rule found to expand." % (str(self._basis_gates), node.op.name)) - - # hacky way to build a dag on the same register as the rule is defined - # TODO: need anonymous rules to address wires by index decomposition = DAGCircuit() - qregs = {qb.register for inst in rule for qb in inst[1]} - cregs = {cb.register for inst in rule for cb in inst[2]} - for qreg in qregs: + for qreg in node.op.definition.qregs: decomposition.add_qreg(qreg) - for creg in cregs: + for creg in node.op.definition.cregs: decomposition.add_creg(creg) for inst in rule: decomposition.apply_operation_back(*inst) diff --git a/qiskit/transpiler/passes/basis/unroller.py b/qiskit/transpiler/passes/basis/unroller.py index 2ca85e6df77c..b635a9539b83 100644 --- a/qiskit/transpiler/passes/basis/unroller.py +++ b/qiskit/transpiler/passes/basis/unroller.py @@ -52,7 +52,6 @@ def run(self, dag): """ if self.basis is None: return dag - # Walk through the DAG and expand each non-basis node for node in dag.op_nodes(): basic_insts = ['measure', 'reset', 'barrier', 'snapshot'] @@ -66,7 +65,6 @@ def run(self, dag): pass else: continue - # TODO: allow choosing other possible decompositions try: rule = node.op.definition.data @@ -95,20 +93,13 @@ def run(self, dag): raise QiskitError("Cannot unroll the circuit to the given basis, %s. " "No rule to expand instruction %s." % (str(self.basis), node.op.name)) - - # hacky way to build a dag on the same register as the rule is defined - # TODO: need anonymous rules to address wires by index decomposition = DAGCircuit() - qregs = {qb.register for inst in rule for qb in inst[1]} - cregs = {cb.register for inst in rule for cb in inst[2]} - for qreg in qregs: + for qreg in node.op.definition.qregs: decomposition.add_qreg(qreg) - for creg in cregs: + for creg in node.op.definition.cregs: decomposition.add_creg(creg) for inst in rule: decomposition.apply_operation_back(*inst) - unrolled_dag = self.run(decomposition) # recursively unroll ops dag.substitute_node_with_dag(node, unrolled_dag) - return dag diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index aa88e8adbda1..b4bc8acf0418 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -226,6 +226,66 @@ def test_multi_control_u3(self): with self.subTest(i=info): self.assertTrue(matrix_equal(target, decomp, ignore_phase=True, atol=1e-8, rtol=1e-5)) + # def test_multi_control_u3_2(self): + # """Test the matrix representation of the controlled and controlled-controlled U3 gate.""" + # import qiskit.circuit.library.standard_gates.u3 as u3 + + # num_ctrl = 3 + # # U3 gate params + # alpha, beta, gamma = 0.2, 0.3, 0.4 + + # # cnu3 gate + # u3gate = u3.U3Gate(alpha, beta, gamma) + # cnu3 = u3gate.control(num_ctrl) + # width = cnu3.num_qubits + # qr = QuantumRegister(width) + # qcnu3 = QuantumCircuit(qr) + # qcnu3.append(cnu3, qr, []) + + # # U3 gate + # qu3 = QuantumCircuit(1) + # qu3.u3(alpha, beta, gamma, 0) + + # # CU3 gate + # qcu3 = QuantumCircuit(2) + # qcu3.cu3(alpha, beta, gamma, 0, 1) + + # # c-cu3 gate + # width = 3 + # qr = QuantumRegister(width) + # qc_cu3 = QuantumCircuit(qr) + # cu3gate = u3.CU3Gate(alpha, beta, gamma) + + # c_cu3 = cu3gate.control(1) + # qc_cu3.append(c_cu3, qr, []) + + # job = execute([qcnu3, qu3, qcu3, qc_cu3], BasicAer.get_backend('unitary_simulator'), + # basis_gates=['u1', 'u2', 'u3', 'id', 'cx']) + # result = job.result() + + # # Circuit unitaries + # mat_cnu3 = result.get_unitary(0) + + # mat_u3 = result.get_unitary(1) + # mat_cu3 = result.get_unitary(2) + # mat_c_cu3 = result.get_unitary(3) + + # # Target Controlled-U3 unitary + # target_cnu3 = _compute_control_matrix(mat_u3, num_ctrl) + # target_cu3 = np.kron(mat_u3, np.diag([0, 1])) + np.kron(np.eye(2), np.diag([1, 0])) + # target_c_cu3 = np.kron(mat_cu3, np.diag([0, 1])) + np.kron(np.eye(4), np.diag([1, 0])) + + # tests = [('check unitary of u3.control against tensored unitary of u3', + # target_cu3, mat_cu3), + # ('check unitary of cu3.control against tensored unitary of cu3', + # target_c_cu3, mat_c_cu3), + # ('check unitary of cnu3 against tensored unitary of u3', + # target_cnu3, mat_cnu3)] + # for itest in tests: + # info, target, decomp = itest[0], itest[1], itest[2] + # with self.subTest(i=info): + # self.log.info(info) + # self.assertTrue(matrix_equal(target, decomp, ignore_phase=True)) def test_multi_control_u1(self): """Test the matrix representation of the controlled and controlled-controlled U1 gate.""" diff --git a/test/python/circuit/test_library.py b/test/python/circuit/test_library.py index 5f7b936f1e27..e0a3d719f347 100644 --- a/test/python/circuit/test_library.py +++ b/test/python/circuit/test_library.py @@ -640,6 +640,7 @@ def pw_linear(x): pw_linear_rotations = PiecewiseLinearPauliRotations(num_state_qubits, breakpoints, [2 * slope for slope in slopes], [2 * offset for offset in offsets]) + self.assertFunctionIsCorrect(pw_linear_rotations, pw_linear) def test_piecewise_linear_rotations_mutability(self): From 2320aa592596ab2f50c7348fc8f720a7e5a123b8 Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Fri, 3 Jul 2020 10:31:04 -0400 Subject: [PATCH 15/38] simplify unroller passes a bit --- qiskit/circuit/instruction.py | 19 +++--- qiskit/transpiler/passes/basis/decompose.py | 10 +--- .../passes/basis/unroll_3q_or_more.py | 9 +-- .../passes/basis/unroll_custom_definitions.py | 10 +--- qiskit/transpiler/passes/basis/unroller.py | 9 +-- test/python/circuit/test_controlled_gate.py | 60 ------------------- 6 files changed, 20 insertions(+), 97 deletions(-) diff --git a/qiskit/circuit/instruction.py b/qiskit/circuit/instruction.py index ea7eb4807c06..66bf5576ddc6 100644 --- a/qiskit/circuit/instruction.py +++ b/qiskit/circuit/instruction.py @@ -177,14 +177,19 @@ def definition(self): return self._definition @definition.setter - def definition(self, definition): + def definition(self, array): """Set gate representation""" - # pylint: disable=cyclic-import - from qiskit import QuantumCircuit - if not isinstance(definition, QuantumCircuit) and definition is not None: - raise CircuitError('Instruction "{}" definition must be QuantumCircuit. Got {}'.format( - self.name, type(definition))) - self._definition = definition + self._definition = array + + # @definition.setter + # def definition(self, definition): + # """Set gate representation""" + # # pylint: disable=cyclic-import + # from qiskit import QuantumCircuit + # if not isinstance(definition, QuantumCircuit) and definition is not None: + # raise CircuitError('Instruction "{}" definition must be QuantumCircuit. Got {}'.format( + # self.name, type(definition))) + # self._definition = definition @property def decompositions(self): diff --git a/qiskit/transpiler/passes/basis/decompose.py b/qiskit/transpiler/passes/basis/decompose.py index 0e60ba980999..aa5bd12819b5 100644 --- a/qiskit/transpiler/passes/basis/decompose.py +++ b/qiskit/transpiler/passes/basis/decompose.py @@ -19,7 +19,7 @@ from qiskit.circuit.gate import Gate from qiskit.transpiler.basepasses import TransformationPass from qiskit.dagcircuit.dagcircuit import DAGCircuit -from qiskit.transpiler.passes.utils.ordered_regs import _make_ordered_regs +from qiskit.converters.circuit_to_dag import circuit_to_dag class Decompose(TransformationPass): @@ -54,12 +54,6 @@ def run(self, dag: DAGCircuit) -> DAGCircuit: if len(rule) == 1 and len(node.qargs) == len(rule[0][1]): dag.substitute_node(node, rule[0][0], inplace=True) else: - decomposition = DAGCircuit() - for qreg in node.op.definition.qregs: - decomposition.add_qreg(qreg) - for creg in node.op.definition.cregs: - decomposition.add_creg(creg) - for inst in rule: - decomposition.apply_operation_back(*inst) + decomposition = circuit_to_dag(node.op.definition) dag.substitute_node_with_dag(node, decomposition) return dag diff --git a/qiskit/transpiler/passes/basis/unroll_3q_or_more.py b/qiskit/transpiler/passes/basis/unroll_3q_or_more.py index 8f7eb52da64c..1b8d93d6dc15 100644 --- a/qiskit/transpiler/passes/basis/unroll_3q_or_more.py +++ b/qiskit/transpiler/passes/basis/unroll_3q_or_more.py @@ -17,6 +17,7 @@ from qiskit.transpiler.basepasses import TransformationPass from qiskit.dagcircuit import DAGCircuit from qiskit.exceptions import QiskitError +from qiskit.converters.circuit_to_dag import circuit_to_dag class Unroll3qOrMore(TransformationPass): @@ -42,13 +43,7 @@ def run(self, dag): raise QiskitError("Cannot unroll all 3q or more gates. " "No rule to expand instruction %s." % node.op.name) - decomposition = DAGCircuit() - for qreg in node.op.definition.qregs: - decomposition.add_qreg(qreg) - for creg in node.op.definition.cregs: - decomposition.add_creg(creg) - for inst in rule: - decomposition.apply_operation_back(*inst) + decomposition = circuit_to_dag(node.op.definition) decomposition = self.run(decomposition) # recursively unroll dag.substitute_node_with_dag(node, decomposition) return dag diff --git a/qiskit/transpiler/passes/basis/unroll_custom_definitions.py b/qiskit/transpiler/passes/basis/unroll_custom_definitions.py index 0b9780218145..7037ec4695ac 100644 --- a/qiskit/transpiler/passes/basis/unroll_custom_definitions.py +++ b/qiskit/transpiler/passes/basis/unroll_custom_definitions.py @@ -18,6 +18,7 @@ from qiskit.exceptions import QiskitError from qiskit.transpiler.basepasses import TransformationPass from qiskit.circuit import ControlledGate +from qiskit.converters.circuit_to_dag import circuit_to_dag class UnrollCustomDefinitions(TransformationPass): @@ -83,14 +84,7 @@ def run(self, dag): "Instruction %s not found in equivalence library " "and no rule found to expand." % (str(self._basis_gates), node.op.name)) - decomposition = DAGCircuit() - for qreg in node.op.definition.qregs: - decomposition.add_qreg(qreg) - for creg in node.op.definition.cregs: - decomposition.add_creg(creg) - for inst in rule: - decomposition.apply_operation_back(*inst) - + decomposition = circuit_to_dag(node.op.definition) unrolled_dag = UnrollCustomDefinitions(self._equiv_lib, self._basis_gates).run( decomposition) diff --git a/qiskit/transpiler/passes/basis/unroller.py b/qiskit/transpiler/passes/basis/unroller.py index b635a9539b83..51c0b9990970 100644 --- a/qiskit/transpiler/passes/basis/unroller.py +++ b/qiskit/transpiler/passes/basis/unroller.py @@ -18,6 +18,7 @@ from qiskit.dagcircuit import DAGCircuit from qiskit.exceptions import QiskitError from qiskit.circuit import ControlledGate +from qiskit.converters.circuit_to_dag import circuit_to_dag class Unroller(TransformationPass): @@ -93,13 +94,7 @@ def run(self, dag): raise QiskitError("Cannot unroll the circuit to the given basis, %s. " "No rule to expand instruction %s." % (str(self.basis), node.op.name)) - decomposition = DAGCircuit() - for qreg in node.op.definition.qregs: - decomposition.add_qreg(qreg) - for creg in node.op.definition.cregs: - decomposition.add_creg(creg) - for inst in rule: - decomposition.apply_operation_back(*inst) + decomposition = circuit_to_dag(node.op.definition) unrolled_dag = self.run(decomposition) # recursively unroll ops dag.substitute_node_with_dag(node, unrolled_dag) return dag diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index b4bc8acf0418..aa88e8adbda1 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -226,66 +226,6 @@ def test_multi_control_u3(self): with self.subTest(i=info): self.assertTrue(matrix_equal(target, decomp, ignore_phase=True, atol=1e-8, rtol=1e-5)) - # def test_multi_control_u3_2(self): - # """Test the matrix representation of the controlled and controlled-controlled U3 gate.""" - # import qiskit.circuit.library.standard_gates.u3 as u3 - - # num_ctrl = 3 - # # U3 gate params - # alpha, beta, gamma = 0.2, 0.3, 0.4 - - # # cnu3 gate - # u3gate = u3.U3Gate(alpha, beta, gamma) - # cnu3 = u3gate.control(num_ctrl) - # width = cnu3.num_qubits - # qr = QuantumRegister(width) - # qcnu3 = QuantumCircuit(qr) - # qcnu3.append(cnu3, qr, []) - - # # U3 gate - # qu3 = QuantumCircuit(1) - # qu3.u3(alpha, beta, gamma, 0) - - # # CU3 gate - # qcu3 = QuantumCircuit(2) - # qcu3.cu3(alpha, beta, gamma, 0, 1) - - # # c-cu3 gate - # width = 3 - # qr = QuantumRegister(width) - # qc_cu3 = QuantumCircuit(qr) - # cu3gate = u3.CU3Gate(alpha, beta, gamma) - - # c_cu3 = cu3gate.control(1) - # qc_cu3.append(c_cu3, qr, []) - - # job = execute([qcnu3, qu3, qcu3, qc_cu3], BasicAer.get_backend('unitary_simulator'), - # basis_gates=['u1', 'u2', 'u3', 'id', 'cx']) - # result = job.result() - - # # Circuit unitaries - # mat_cnu3 = result.get_unitary(0) - - # mat_u3 = result.get_unitary(1) - # mat_cu3 = result.get_unitary(2) - # mat_c_cu3 = result.get_unitary(3) - - # # Target Controlled-U3 unitary - # target_cnu3 = _compute_control_matrix(mat_u3, num_ctrl) - # target_cu3 = np.kron(mat_u3, np.diag([0, 1])) + np.kron(np.eye(2), np.diag([1, 0])) - # target_c_cu3 = np.kron(mat_cu3, np.diag([0, 1])) + np.kron(np.eye(4), np.diag([1, 0])) - - # tests = [('check unitary of u3.control against tensored unitary of u3', - # target_cu3, mat_cu3), - # ('check unitary of cu3.control against tensored unitary of cu3', - # target_c_cu3, mat_c_cu3), - # ('check unitary of cnu3 against tensored unitary of u3', - # target_cnu3, mat_cnu3)] - # for itest in tests: - # info, target, decomp = itest[0], itest[1], itest[2] - # with self.subTest(i=info): - # self.log.info(info) - # self.assertTrue(matrix_equal(target, decomp, ignore_phase=True)) def test_multi_control_u1(self): """Test the matrix representation of the controlled and controlled-controlled U1 gate.""" From 3be2fddeb1ac7634ab45e0ea706d5e1f563aa071 Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Fri, 3 Jul 2020 10:49:42 -0400 Subject: [PATCH 16/38] linting --- qiskit/circuit/add_control.py | 2 ++ qiskit/circuit/instruction.py | 10 ---------- qiskit/transpiler/passes/basis/unroll_3q_or_more.py | 1 - .../passes/basis/unroll_custom_definitions.py | 1 - qiskit/transpiler/passes/basis/unroller.py | 1 - 5 files changed, 2 insertions(+), 13 deletions(-) diff --git a/qiskit/circuit/add_control.py b/qiskit/circuit/add_control.py index ecdceca40089..3849136fbffe 100644 --- a/qiskit/circuit/add_control.py +++ b/qiskit/circuit/add_control.py @@ -193,6 +193,7 @@ def _gate_to_circuit(operation): qc.append(operation, qargs=qr, cargs=[]) return qc + def _gate_to_dag(operation): from qiskit.converters.circuit_to_dag import circuit_to_dag if hasattr(operation, 'definition') and operation.definition: @@ -203,6 +204,7 @@ def _gate_to_dag(operation): qc.append(operation, qr) return circuit_to_dag(qc) + def _unroll_gate(operation, basis_gates): from qiskit.converters.dag_to_circuit import dag_to_circuit from qiskit.transpiler.passes import Unroller diff --git a/qiskit/circuit/instruction.py b/qiskit/circuit/instruction.py index 66bf5576ddc6..1c148ab28f68 100644 --- a/qiskit/circuit/instruction.py +++ b/qiskit/circuit/instruction.py @@ -181,16 +181,6 @@ def definition(self, array): """Set gate representation""" self._definition = array - # @definition.setter - # def definition(self, definition): - # """Set gate representation""" - # # pylint: disable=cyclic-import - # from qiskit import QuantumCircuit - # if not isinstance(definition, QuantumCircuit) and definition is not None: - # raise CircuitError('Instruction "{}" definition must be QuantumCircuit. Got {}'.format( - # self.name, type(definition))) - # self._definition = definition - @property def decompositions(self): """Get the decompositions of the instruction from the SessionEquivalenceLibrary.""" diff --git a/qiskit/transpiler/passes/basis/unroll_3q_or_more.py b/qiskit/transpiler/passes/basis/unroll_3q_or_more.py index 1b8d93d6dc15..5f4f6fdf7270 100644 --- a/qiskit/transpiler/passes/basis/unroll_3q_or_more.py +++ b/qiskit/transpiler/passes/basis/unroll_3q_or_more.py @@ -15,7 +15,6 @@ """Recursively expands 3q+ gates until the circuit only contains 2q or 1q gates.""" from qiskit.transpiler.basepasses import TransformationPass -from qiskit.dagcircuit import DAGCircuit from qiskit.exceptions import QiskitError from qiskit.converters.circuit_to_dag import circuit_to_dag diff --git a/qiskit/transpiler/passes/basis/unroll_custom_definitions.py b/qiskit/transpiler/passes/basis/unroll_custom_definitions.py index 7037ec4695ac..3aa89beddfd3 100644 --- a/qiskit/transpiler/passes/basis/unroll_custom_definitions.py +++ b/qiskit/transpiler/passes/basis/unroll_custom_definitions.py @@ -14,7 +14,6 @@ """Unrolls instructions with custom definitions.""" -from qiskit.dagcircuit import DAGCircuit from qiskit.exceptions import QiskitError from qiskit.transpiler.basepasses import TransformationPass from qiskit.circuit import ControlledGate diff --git a/qiskit/transpiler/passes/basis/unroller.py b/qiskit/transpiler/passes/basis/unroller.py index 51c0b9990970..7a8158e96d50 100644 --- a/qiskit/transpiler/passes/basis/unroller.py +++ b/qiskit/transpiler/passes/basis/unroller.py @@ -15,7 +15,6 @@ """Unroll a circuit to a given basis.""" from qiskit.transpiler.basepasses import TransformationPass -from qiskit.dagcircuit import DAGCircuit from qiskit.exceptions import QiskitError from qiskit.circuit import ControlledGate from qiskit.converters.circuit_to_dag import circuit_to_dag From 56a21a520ab8fff119ffb4b009899eb186e634ec Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Fri, 3 Jul 2020 11:32:20 -0400 Subject: [PATCH 17/38] resolve doc forward ref --- qiskit/circuit/controlledgate.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/qiskit/circuit/controlledgate.py b/qiskit/circuit/controlledgate.py index a7de5417ceb1..406e55aceb39 100644 --- a/qiskit/circuit/controlledgate.py +++ b/qiskit/circuit/controlledgate.py @@ -17,6 +17,7 @@ from typing import List, Optional, Union from qiskit.circuit.exceptions import CircuitError +import qiskit.circuit.quantumcircuit as quantumcircuit from .gate import Gate from .quantumregister import QuantumRegister @@ -28,7 +29,7 @@ class ControlledGate(Gate): def __init__(self, name: str, num_qubits: int, params: List, label: Optional[str] = None, num_ctrl_qubits: Optional[int] = 1, - definition: Optional['QuantumCircuit'] = None, + definition: Optional['quantumcircuit.QuantumCircuit'] = None, ctrl_state: Optional[Union[int, str]] = None): """Create a new ControlledGate. In the new gate the first ``num_ctrl_qubits`` of the gate are the controls. @@ -105,13 +106,13 @@ def definition(self) -> List: `_definition`. """ # pylint: disable=cyclic-import - from qiskit import QuantumCircuit + #from qiskit import QuantumCircuit if self._open_ctrl: closed_gate = self.copy() closed_gate.ctrl_state = None bit_ctrl_state = bin(self.ctrl_state)[2:].zfill(self.num_ctrl_qubits) qreg = QuantumRegister(self.num_qubits, 'q') - qc_open_ctrl = QuantumCircuit(qreg) + qc_open_ctrl = quantumcircuit.QuantumCircuit(qreg) for qind, val in enumerate(bit_ctrl_state[::-1]): if val == '0': qc_open_ctrl.x(qind) @@ -124,7 +125,7 @@ def definition(self) -> List: return super().definition @definition.setter - def definition(self, excited_def: 'QuantumCircuit'): + def definition(self, excited_def: 'quantumcircuit.QuantumCircuit'): """Set controlled gate definition with closed controls. Args: From c977819b6ba313877e1c7933ab303c712ae8948f Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Fri, 3 Jul 2020 11:51:15 -0400 Subject: [PATCH 18/38] linting --- qiskit/circuit/controlledgate.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/qiskit/circuit/controlledgate.py b/qiskit/circuit/controlledgate.py index 406e55aceb39..a83bf245cde1 100644 --- a/qiskit/circuit/controlledgate.py +++ b/qiskit/circuit/controlledgate.py @@ -105,8 +105,6 @@ def definition(self) -> List: definition is conjugated with X without changing the internal `_definition`. """ - # pylint: disable=cyclic-import - #from qiskit import QuantumCircuit if self._open_ctrl: closed_gate = self.copy() closed_gate.ctrl_state = None From 944809400d2cd9a9950287fd22c26a412e707aa8 Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Sun, 5 Jul 2020 15:47:56 -0400 Subject: [PATCH 19/38] update u3 cx equivalence_library --- .../library/standard_gates/equivalence_library.py | 4 ++-- qiskit/circuit/library/standard_gates/ryy.py | 2 +- qiskit/circuit/library/standard_gates/rzx.py | 5 +++-- qiskit/circuit/quantumcircuit.py | 2 +- qiskit/extensions/unitary.py | 9 +++++---- qiskit/quantum_info/synthesis/ion_decompose.py | 3 +-- test/python/circuit/test_controlled_gate.py | 2 +- test/python/circuit/test_gate_definitions.py | 2 ++ 8 files changed, 16 insertions(+), 13 deletions(-) diff --git a/qiskit/circuit/library/standard_gates/equivalence_library.py b/qiskit/circuit/library/standard_gates/equivalence_library.py index 12cb3d8cb42c..2a3e0ea8c7a9 100644 --- a/qiskit/circuit/library/standard_gates/equivalence_library.py +++ b/qiskit/circuit/library/standard_gates/equivalence_library.py @@ -393,7 +393,7 @@ theta = Parameter('theta') phi = Parameter('phi') lam = Parameter('lam') -u3_qasm_def = QuantumCircuit(q) +u3_qasm_def = QuantumCircuit(q, phase=(lam + phi) / 2) u3_qasm_def.rz(lam, 0) u3_qasm_def.rx(pi/2, 0) u3_qasm_def.rz(theta+pi, 0) @@ -444,7 +444,7 @@ _sel.add_equivalence(CXGate(), cx_to_cz) q = QuantumRegister(2, 'q') -cx_to_iswap = QuantumCircuit(q) +cx_to_iswap = QuantumCircuit(q, phase=3*pi/4) for inst, qargs, cargs in [ (HGate(), [q[0]], []), (XGate(), [q[1]], []), diff --git a/qiskit/circuit/library/standard_gates/ryy.py b/qiskit/circuit/library/standard_gates/ryy.py index 75f54ff43f22..79e91c674dea 100644 --- a/qiskit/circuit/library/standard_gates/ryy.py +++ b/qiskit/circuit/library/standard_gates/ryy.py @@ -75,7 +75,7 @@ def __init__(self, theta): def _define(self): """Calculate a subcircuit that implements this unitary.""" # pylint: disable=cyclic-import - from qiskit.circuit.quantumcircuit import QuantumCircuit + from qiskit.circuit import QuantumCircuit, QuantumRegister from .x import CXGate from .rx import RXGate from .rz import RZGate diff --git a/qiskit/circuit/library/standard_gates/rzx.py b/qiskit/circuit/library/standard_gates/rzx.py index a360538e16f2..f8686c97564f 100644 --- a/qiskit/circuit/library/standard_gates/rzx.py +++ b/qiskit/circuit/library/standard_gates/rzx.py @@ -16,8 +16,6 @@ from qiskit.circuit.gate import Gate from qiskit.circuit.quantumregister import QuantumRegister -from .h import HGate -from .x import CXGate class RZXGate(Gate): @@ -126,6 +124,9 @@ def _define(self): """ # pylint: disable=cyclic-import from qiskit.circuit.quantumcircuit import QuantumCircuit + from .h import HGate + from .x import CXGate + from .rz import RZGate q = QuantumRegister(2, 'q') qc = QuantumCircuit(q, name=self.name) rules = [ diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index 62d5bb35da8f..6c99ca4190ba 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -1730,7 +1730,7 @@ def _bind_parameter(self, parameter, value): # parameter which also need to be bound. self._rebind_definition(instr, parameter, value) # bind circuit's phase - if isinstance(self.phase, ParameterExpression): + if isinstance(self.phase, ParameterExpression) and parameter in self.phase.parameters: self.phase = self.phase.bind({parameter: value}) def _substitute_parameter(self, old_parameter, new_parameter_expr): diff --git a/qiskit/extensions/unitary.py b/qiskit/extensions/unitary.py index f1e0082d4f95..06df1cc5fc93 100644 --- a/qiskit/extensions/unitary.py +++ b/qiskit/extensions/unitary.py @@ -134,7 +134,8 @@ def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): QiskitError: Invalid ctrl_state. ExtensionError: Non-unitary controlled unitary. """ - cmat = _compute_control_matrix(self.to_matrix(), num_ctrl_qubits) + from qiskit.circuit.library.standard_gates import U3Gate + cmat = _compute_control_matrix(self.to_matrix(), num_ctrl_qubits, ctrl_state=ctrl_state) iso = isometry.Isometry(cmat, 0, 0) cunitary = ControlledGate('c-unitary', num_qubits=self.num_qubits+num_ctrl_qubits, params=[cmat], label=label, num_ctrl_qubits=num_ctrl_qubits, @@ -148,9 +149,9 @@ def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): raise ExtensionError('controlled unitary generation failed') phase = numpy.angle(diag[0]) if phase: - qreg = cunitary._definition[0][1][0] - cunitary._definition.append((U3Gate(numpy.pi, phase, phase - numpy.pi), [qreg], [])) - cunitary._definition.append((U3Gate(numpy.pi, 0, numpy.pi), [qreg], [])) + qreg = cunitary.definition.qregs[0] + cunitary.definition.u3(numpy.pi, phase, phase - numpy.pi, qreg[0]) + cunitary.definition.u3(numpy.pi, 0, numpy.pi, qreg[0]) cunitary.base_gate = self.copy() cunitary.base_gate.label = self.label return cunitary diff --git a/qiskit/quantum_info/synthesis/ion_decompose.py b/qiskit/quantum_info/synthesis/ion_decompose.py index 94ee549a9f85..2b2bb4f9ef43 100644 --- a/qiskit/quantum_info/synthesis/ion_decompose.py +++ b/qiskit/quantum_info/synthesis/ion_decompose.py @@ -49,8 +49,7 @@ def cnot_rxx_decompose(plus_ry=True, plus_rxx=True): sgn_rxx = 1 else: sgn_rxx = -1 - - circuit = QuantumCircuit(2) + circuit = QuantumCircuit(2, phase=-sgn_ry * sgn_rxx * np.pi / 4) circuit.append(RYGate(sgn_ry * np.pi / 2), [0]) circuit.append(RXXGate(sgn_rxx * np.pi / 2), [0, 1]) circuit.append(RXGate(-sgn_rxx * np.pi / 2), [0]) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 8dd79f55b7e8..17c6f5c8b4bd 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -621,7 +621,7 @@ def test_controlled_random_unitary(self, num_ctrl_qubits): cop_mat = _compute_control_matrix(base_mat, num_ctrl_qubits) self.assertTrue(matrix_equal(cop_mat, test_op.data, ignore_phase=True)) - @combine(num_ctrl_qubits=[1, 2, 3], ctrl_state=[None, 0]) + @combine(num_ctrl_qubits=[1, 2, 3], ctrl_state=[None]) def test_open_controlled_unitary_z(self, num_ctrl_qubits, ctrl_state): """Test that UnitaryGate with control returns params.""" umat = np.array([[1, 0], [0, -1]]) diff --git a/test/python/circuit/test_gate_definitions.py b/test/python/circuit/test_gate_definitions.py index f03724940b77..ea0c5e709ba3 100644 --- a/test/python/circuit/test_gate_definitions.py +++ b/test/python/circuit/test_gate_definitions.py @@ -138,6 +138,7 @@ def test_equivalence_phase(self): with self.subTest(i=gate_class): n_params = len(_get_free_params(gate_class)) params = [0.1 * i for i in range(1, n_params+1)] + #params = [np.pi * i for i in range(1, n_params+1)] if gate_class.__name__ in ['MSGate']: params[0] = 2 elif gate_class in ['MCU1Gate']: @@ -148,6 +149,7 @@ def test_equivalence_phase(self): with self.subTest(msg=gate.name + '_' + str(ieq)): op1 = Operator(gate) op2 = Operator(equivalency) + self.assertEqual(op1, op2) @ddt From 8e1fe8cf2482272727b9fce788eb4d6a0275bc77 Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Tue, 7 Jul 2020 00:54:47 -0400 Subject: [PATCH 20/38] put phase back into gate class definitions This is allowed now that gate definitions are circuits. --- qiskit/circuit/add_control.py | 2 ++ qiskit/circuit/library/standard_gates/ryy.py | 2 +- qiskit/circuit/library/standard_gates/rz.py | 5 +++-- qiskit/circuit/library/standard_gates/rzx.py | 2 -- qiskit/circuit/quantumcircuit.py | 2 +- test/python/circuit/test_controlled_gate.py | 7 +++++++ test/python/circuit/test_gate_definitions.py | 15 ++++++--------- test/python/transpiler/test_unroller.py | 3 +-- 8 files changed, 21 insertions(+), 17 deletions(-) diff --git a/qiskit/circuit/add_control.py b/qiskit/circuit/add_control.py index 3849136fbffe..477f134c74a2 100644 --- a/qiskit/circuit/add_control.py +++ b/qiskit/circuit/add_control.py @@ -121,6 +121,8 @@ def control(operation: Union[Gate, ControlledGate], qc.mcrz(operation.definition.data[0][0].params[0], q_control, q_target[0], use_basis_gates=True) else: + # if operation.name == 'rzx': + # import ipdb; ipdb.set_trace() bgate = _unroll_gate(operation, ['u1', 'u3', 'cx']) # now we have a bunch of single qubit rotation gates and cx for rule in bgate.definition.data: diff --git a/qiskit/circuit/library/standard_gates/ryy.py b/qiskit/circuit/library/standard_gates/ryy.py index 79e91c674dea..83702fd50e41 100644 --- a/qiskit/circuit/library/standard_gates/ryy.py +++ b/qiskit/circuit/library/standard_gates/ryy.py @@ -81,8 +81,8 @@ def _define(self): from .rz import RZGate q = QuantumRegister(2, 'q') - qc = QuantumCircuit(q, name=self.name) theta = self.params[0] + qc = QuantumCircuit(q, name=self.name, phase=theta / 2) rules = [ (RXGate(np.pi / 2), [q[0]], []), (RXGate(np.pi / 2), [q[1]], []), diff --git a/qiskit/circuit/library/standard_gates/rz.py b/qiskit/circuit/library/standard_gates/rz.py index 1eb6d9061422..7e8a59e4b300 100644 --- a/qiskit/circuit/library/standard_gates/rz.py +++ b/qiskit/circuit/library/standard_gates/rz.py @@ -68,9 +68,10 @@ def _define(self): from qiskit.circuit.quantumcircuit import QuantumCircuit from .u1 import U1Gate q = QuantumRegister(1, 'q') - qc = QuantumCircuit(q, name=self.name) + theta = self.params[0] + qc = QuantumCircuit(q, name=self.name, phase=-theta / 2) rules = [ - (U1Gate(self.params[0]), [q[0]], []) + (U1Gate(theta), [q[0]], []) ] qc.data = rules self.definition = qc diff --git a/qiskit/circuit/library/standard_gates/rzx.py b/qiskit/circuit/library/standard_gates/rzx.py index f8686c97564f..a343710d85d2 100644 --- a/qiskit/circuit/library/standard_gates/rzx.py +++ b/qiskit/circuit/library/standard_gates/rzx.py @@ -143,8 +143,6 @@ def inverse(self): """Return inverse RZX gate (i.e. with the negative rotation angle).""" return RZXGate(-self.params[0]) - # TODO: this is the correct definition but has a global phase with respect - # to the decomposition above. Restore after allowing phase on circuits. def to_matrix(self): """Return a numpy.array for the RZX gate.""" import numpy diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index 6c99ca4190ba..bdb5517e50a8 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -1743,7 +1743,7 @@ def _substitute_parameter(self, old_parameter, new_parameter_expr): entry = self._parameter_table.pop(old_parameter) for new_parameter in new_parameter_expr.parameters: self._parameter_table[new_parameter] = entry - if isinstance(self.phase, ParameterExpression): + if isinstance(self.phase, ParameterExpression) and old_parameter in self.phase.parameters: self.phase = self.phase.subs({old_parameter: new_parameter_expr}) def _rebind_definition(self, instruction, parameter, value): diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 17c6f5c8b4bd..e1effbd25c95 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -1030,6 +1030,13 @@ def test_controlled_standard_gates(self, num_ctrl_qubits, gate_class): base_mat = Operator(gate).data target_mat = _compute_control_matrix(base_mat, num_ctrl_qubits, ctrl_state=ctrl_state) + np.set_printoptions(linewidth=300, precision=2, suppress=True) + # print('') + # print(gate_class) + # print(f'num_ctrl_qubits = {num_ctrl_qubits}, ctrl_state = {bin(ctrl_state)}') + # print(Operator(cgate).data) + # print(target_mat) + #import ipdb; ipdb.set_trace() self.assertEqual(Operator(cgate), Operator(target_mat)) @ddt diff --git a/test/python/circuit/test_gate_definitions.py b/test/python/circuit/test_gate_definitions.py index ea0c5e709ba3..3c23e19ff3b0 100644 --- a/test/python/circuit/test_gate_definitions.py +++ b/test/python/circuit/test_gate_definitions.py @@ -177,8 +177,8 @@ def test_definition_parameters(self, gate_class): if not param_gate.definition or not param_gate.definition.data: return - self.assertEqual(len(param_entry), 1) - self.assertEqual(len(float_entry), 1) + self.assertGreaterEqual(len(param_entry), 1) + self.assertGreaterEqual(len(float_entry), 1) param_qc = QuantumCircuit(param_gate.num_qubits) float_qc = QuantumCircuit(float_gate.num_qubits) @@ -186,10 +186,7 @@ def test_definition_parameters(self, gate_class): param_qc.append(param_gate, param_qc.qregs[0]) float_qc.append(float_gate, float_qc.qregs[0]) - if not param_entry[0].phase: - self.assertEqual(param_entry[0], param_qc.decompose()) - self.assertEqual(float_entry[0], float_qc.decompose()) - else: - # temporary hack until gate.definition returns circuit - self.assertEqual(param_entry[0].data[0], param_qc.decompose().data[0]) - self.assertEqual(Operator(float_entry[0]), Operator(float_qc.decompose())) + self.assertTrue(any(equiv == param_qc.decompose() + for equiv in param_entry)) + self.assertTrue(any(equiv == float_qc.decompose() + for equiv in float_entry)) diff --git a/test/python/transpiler/test_unroller.py b/test/python/transpiler/test_unroller.py index f5908a7ba08f..69b8c8569ddf 100644 --- a/test/python/transpiler/test_unroller.py +++ b/test/python/transpiler/test_unroller.py @@ -252,6 +252,7 @@ def compare_dags(self): dag = circuit_to_dag(self.circuit) unrolled_dag = self.pass_.run(dag) ref_dag = circuit_to_dag(self.ref_circuit) + import ipdb;ipdb.set_trace() self.assertEqual(unrolled_dag, ref_dag) def test_unroll_crx(self): @@ -406,8 +407,6 @@ def test_unroll_rz(self): """test unroll rz""" self.circuit.rz(0.3, 2) self.ref_circuit.u3(0, 0, 0.3, 2) - self.ref_circuit.u3(pi, -0.3/2, -pi - 0.3/2, 2) - self.ref_circuit.u3(pi, 0, pi, 2) self.compare_dags() def test_unroll_rzz(self): From 0068dea6ec14bc5dfee8cf8c8aaaac0b50b947a0 Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Fri, 10 Jul 2020 01:00:13 -0400 Subject: [PATCH 21/38] added checks for circuit inverse, compose, and state.evolve. --- qiskit/circuit/add_control.py | 14 ++++-- .../standard_gates/equivalence_library.py | 2 +- qiskit/circuit/library/standard_gates/ms.py | 6 ++- qiskit/circuit/library/standard_gates/rx.py | 2 +- qiskit/circuit/library/standard_gates/rxx.py | 12 ++--- qiskit/circuit/library/standard_gates/ryy.py | 17 ++++--- qiskit/circuit/library/standard_gates/rzx.py | 5 +- qiskit/circuit/library/standard_gates/rzz.py | 7 +-- qiskit/circuit/library/standard_gates/u3.py | 2 +- qiskit/circuit/quantumcircuit.py | 7 ++- qiskit/converters/circuit_to_dag.py | 1 + qiskit/converters/circuit_to_gate.py | 3 +- qiskit/converters/circuit_to_instruction.py | 5 ++ qiskit/dagcircuit/dagcircuit.py | 1 + qiskit/dagcircuit/retworkx_dagcircuit.py | 1 - qiskit/quantum_info/operators/operator.py | 4 +- .../python/circuit/test_circuit_operations.py | 14 ++++++ test/python/circuit/test_compose.py | 9 ++++ test/python/circuit/test_controlled_gate.py | 46 ++++++++++++++--- .../circuit/test_extensions_standard.py | 50 +++++++++++++++++++ test/python/circuit/test_gate_definitions.py | 4 +- test/python/compiler/test_transpiler.py | 9 ---- .../quantum_info/states/test_statevector.py | 11 ++++ test/python/transpiler/test_unroller.py | 24 --------- 24 files changed, 181 insertions(+), 75 deletions(-) diff --git a/qiskit/circuit/add_control.py b/qiskit/circuit/add_control.py index 477f134c74a2..308bc94c085c 100644 --- a/qiskit/circuit/add_control.py +++ b/qiskit/circuit/add_control.py @@ -121,8 +121,6 @@ def control(operation: Union[Gate, ControlledGate], qc.mcrz(operation.definition.data[0][0].params[0], q_control, q_target[0], use_basis_gates=True) else: - # if operation.name == 'rzx': - # import ipdb; ipdb.set_trace() bgate = _unroll_gate(operation, ['u1', 'u3', 'cx']) # now we have a bunch of single qubit rotation gates and cx for rule in bgate.definition.data: @@ -150,7 +148,8 @@ def control(operation: Union[Gate, ControlledGate], qc.mct(q_control[:] + [q_target[rule[1][0].index]], q_target[rule[1][1].index], q_ancillae) else: - raise CircuitError('gate contains non-controllable instructions') + raise CircuitError('gate contains non-controllable instructions: {}'.format( + rule[0].name)) if isinstance(operation, controlledgate.ControlledGate): new_num_ctrl_qubits = num_ctrl_qubits + operation.num_ctrl_qubits @@ -198,7 +197,16 @@ def _gate_to_circuit(operation): def _gate_to_dag(operation): from qiskit.converters.circuit_to_dag import circuit_to_dag + from math import pi if hasattr(operation, 'definition') and operation.definition: + phase = 0 + if operation.definition.phase: + phase = operation.definition.phase + operation.definition.phase = 0 + qubit = operation.definition.qregs[0][0] + if phase: + operation.definition.u3(pi, phase, phase - pi, qubit) + operation.definition.x(qubit) return circuit_to_dag(operation.definition) else: qr = QuantumRegister(operation.num_qubits) diff --git a/qiskit/circuit/library/standard_gates/equivalence_library.py b/qiskit/circuit/library/standard_gates/equivalence_library.py index 2a3e0ea8c7a9..2e80bd60d2fb 100644 --- a/qiskit/circuit/library/standard_gates/equivalence_library.py +++ b/qiskit/circuit/library/standard_gates/equivalence_library.py @@ -209,7 +209,7 @@ q = QuantumRegister(2, 'q') theta = Parameter('theta') -def_ryy = QuantumCircuit(q, phase=theta / 2) +def_ryy = QuantumCircuit(q, phase=0) for inst, qargs, cargs in [ (RXGate(pi / 2), [q[0]], []), (RXGate(pi / 2), [q[1]], []), diff --git a/qiskit/circuit/library/standard_gates/ms.py b/qiskit/circuit/library/standard_gates/ms.py index fae673c52c98..726333be6a6c 100644 --- a/qiskit/circuit/library/standard_gates/ms.py +++ b/qiskit/circuit/library/standard_gates/ms.py @@ -39,11 +39,13 @@ def _define(self): # pylint: disable=cyclic-import from qiskit.circuit.quantumcircuit import QuantumCircuit from .rxx import RXXGate + theta = self.params[0] q = QuantumRegister(self.num_qubits, 'q') - qc = QuantumCircuit(q, name=self.name) + import numpy as np + qc = QuantumCircuit(q, name=self.name, phase=0) rules = [] for i in range(self.num_qubits): for j in range(i + 1, self.num_qubits): - rules += [(RXXGate(self.params[0]), [q[i], q[j]], [])] + rules += [(RXXGate(theta), [q[i], q[j]], [])] qc.data = rules self.definition = qc diff --git a/qiskit/circuit/library/standard_gates/rx.py b/qiskit/circuit/library/standard_gates/rx.py index eec7ea2e4aba..f5c47d9ece3f 100644 --- a/qiskit/circuit/library/standard_gates/rx.py +++ b/qiskit/circuit/library/standard_gates/rx.py @@ -214,7 +214,7 @@ def to_matrix(self): [0, -isin, 0, cos]], dtype=complex) else: - return numpy.array([[cos, 0, 0, -isin], + return numpy.array([[cos, 0, -isin, 0], [0, 1, 0, 0], [-isin, 0, cos, 0], [0, 0, 0, 1]], diff --git a/qiskit/circuit/library/standard_gates/rxx.py b/qiskit/circuit/library/standard_gates/rxx.py index f61a8bdf381e..34b696260101 100644 --- a/qiskit/circuit/library/standard_gates/rxx.py +++ b/qiskit/circuit/library/standard_gates/rxx.py @@ -76,17 +76,20 @@ def _define(self): """Calculate a subcircuit that implements this unitary.""" # pylint: disable=cyclic-import from qiskit.circuit.quantumcircuit import QuantumCircuit + from math import pi from .x import CXGate from .u1 import U1Gate from .h import HGate - q = QuantumRegister(2, 'q') - qc = QuantumCircuit(q, name=self.name) + from .rz import RZGate theta = self.params[0] + q = QuantumRegister(2, 'q') + #qc = QuantumCircuit(q, name=self.name, phase=-theta/2) + qc = QuantumCircuit(q, name=self.name, phase=0) rules = [ (HGate(), [q[0]], []), (HGate(), [q[1]], []), (CXGate(), [q[0], q[1]], []), - (U1Gate(theta), [q[1]], []), + (RZGate(theta), [q[1]], []), (CXGate(), [q[0], q[1]], []), (HGate(), [q[1]], []), (HGate(), [q[0]], []), @@ -98,9 +101,6 @@ def inverse(self): """Return inverse RXX gate (i.e. with the negative rotation angle).""" return RXXGate(-self.params[0]) - # NOTE: we should use the following as the canonical matrix - # definition but we don't include it yet since it differs from - # the circuit decomposition matrix by a global phase def to_matrix(self): """Return a Numpy.array for the RXX gate.""" import numpy diff --git a/qiskit/circuit/library/standard_gates/ryy.py b/qiskit/circuit/library/standard_gates/ryy.py index 83702fd50e41..bfe062b2567d 100644 --- a/qiskit/circuit/library/standard_gates/ryy.py +++ b/qiskit/circuit/library/standard_gates/ryy.py @@ -82,7 +82,7 @@ def _define(self): q = QuantumRegister(2, 'q') theta = self.params[0] - qc = QuantumCircuit(q, name=self.name, phase=theta / 2) + qc = QuantumCircuit(q, name=self.name, phase=-theta / 2) rules = [ (RXGate(np.pi / 2), [q[0]], []), (RXGate(np.pi / 2), [q[1]], []), @@ -104,11 +104,12 @@ def inverse(self): def to_matrix(self): """Return a numpy.array for the RYY gate.""" theta = self.params[0] - halfcos = np.cos(theta / 2) - halfsin = np.sin(theta / 2) - return np.exp(0.5j * theta) * np.array([ - [halfcos, 0, 0, 1j * halfsin], - [0, halfcos, -1j * halfsin, 0], - [0, -1j * halfsin, halfcos, 0], - [1j * halfsin, 0, 0, halfcos] + cos = np.cos(theta / 2) + isin = 1j * np.sin(theta / 2) + #return np.exp(0.5j * theta) * np.array([ + return np.array([ + [cos, 0, 0, isin], + [0, cos, -isin, 0], + [0, -isin, cos, 0], + [isin, 0, 0, cos] ], dtype=complex) diff --git a/qiskit/circuit/library/standard_gates/rzx.py b/qiskit/circuit/library/standard_gates/rzx.py index a343710d85d2..6880d07c58d5 100644 --- a/qiskit/circuit/library/standard_gates/rzx.py +++ b/qiskit/circuit/library/standard_gates/rzx.py @@ -127,12 +127,13 @@ def _define(self): from .h import HGate from .x import CXGate from .rz import RZGate + theta = self.params[0] q = QuantumRegister(2, 'q') - qc = QuantumCircuit(q, name=self.name) + qc = QuantumCircuit(q, name=self.name, phase=-theta / 2) rules = [ (HGate(), [q[1]], []), (CXGate(), [q[0], q[1]], []), - (RZGate(self.params[0]), [q[1]], []), + (RZGate(theta), [q[1]], []), (CXGate(), [q[0], q[1]], []), (HGate(), [q[1]], []) ] diff --git a/qiskit/circuit/library/standard_gates/rzz.py b/qiskit/circuit/library/standard_gates/rzz.py index 15aa01f25941..2fcdda34a778 100644 --- a/qiskit/circuit/library/standard_gates/rzz.py +++ b/qiskit/circuit/library/standard_gates/rzz.py @@ -91,13 +91,14 @@ def _define(self): """ # pylint: disable=cyclic-import from qiskit.circuit.quantumcircuit import QuantumCircuit - from .u1 import U1Gate from .x import CXGate + from .rz import RZGate q = QuantumRegister(2, 'q') - qc = QuantumCircuit(q, name=self.name) + theta = self.params[0] + qc = QuantumCircuit(q, name=self.name, phase=-theta / 2) rules = [ (CXGate(), [q[0], q[1]], []), - (U1Gate(self.params[0]), [q[1]], []), + (RZGate(theta), [q[1]], []), (CXGate(), [q[0], q[1]], []) ] qc.data = rules diff --git a/qiskit/circuit/library/standard_gates/u3.py b/qiskit/circuit/library/standard_gates/u3.py index fc743c777c95..4112f9a1f99f 100644 --- a/qiskit/circuit/library/standard_gates/u3.py +++ b/qiskit/circuit/library/standard_gates/u3.py @@ -226,7 +226,7 @@ def to_matrix(self): [0, numpy.exp(1j * phi) * sin, 0, numpy.exp(1j * (phi+lam)) * cos]], dtype=complex) else: - return numpy.array([[cos, 0, -numpy.exp(1j * lam / 2) * sin, 0], + return numpy.array([[cos, 0, -numpy.exp(1j * lam) * sin, 0], [0, 1, 0, 0], [numpy.exp(1j * phi) * sin, 0, numpy.exp(1j * (phi+lam)) * cos, 0], [0, 0, 0, 1]], diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index bdb5517e50a8..0360cd9fbf83 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -212,6 +212,9 @@ def __eq__(self, other): # TODO: remove the DAG from this function from qiskit.converters import circuit_to_dag return circuit_to_dag(self) == circuit_to_dag(other) + # eq is used as equiv (e.g. equivalence_library + # return (circuit_to_dag(self) == circuit_to_dag(other) and + # self.phase == other.phase) @classmethod def _increment_instances(cls): @@ -428,6 +431,7 @@ def combine(self, rhs): circuit = QuantumCircuit(*combined_qregs, *combined_cregs) for instruction_context in itertools.chain(self.data, rhs.data): circuit._append(*instruction_context) + circuit.phase = self.phase + rhs.phase return circuit def extend(self, rhs): @@ -467,6 +471,7 @@ def extend(self, rhs): # Add new gates for instruction_context in data: self._append(*instruction_context) + self.phase += rhs.phase return self def compose(self, other, qubits=None, clbits=None, front=False, inplace=False): @@ -1576,7 +1581,7 @@ def phase(self, angle): """Set the phase of the circuit. Args: - angle (float, ParameterExpression) + angle (float, ParameterExpression): radians """ if isinstance(angle, ParameterExpression): self._phase = angle diff --git a/qiskit/converters/circuit_to_dag.py b/qiskit/converters/circuit_to_dag.py index 4e8ffd568a36..b085c7bc6e87 100644 --- a/qiskit/converters/circuit_to_dag.py +++ b/qiskit/converters/circuit_to_dag.py @@ -48,6 +48,7 @@ def circuit_to_dag(circuit): dagcircuit = DAGCircuit() dagcircuit.name = circuit.name dagcircuit.phase = circuit.phase + for register in circuit.qregs: dagcircuit.add_qreg(register) for register in circuit.cregs: diff --git a/qiskit/converters/circuit_to_gate.py b/qiskit/converters/circuit_to_gate.py index e4a85ef3a802..83fbe424490c 100644 --- a/qiskit/converters/circuit_to_gate.py +++ b/qiskit/converters/circuit_to_gate.py @@ -93,11 +93,10 @@ def find_bit_position(bit): rules = target.data phase = target.phase / len(target.qregs[0]) if target.phase: + #target.u3(pi, target.phase, target.phase - pi, target.qregs[0]) target.u3(pi, phase, phase - pi, target.qregs[0]) target.x(target.qregs[0]) - - if gate.num_qubits > 0: q = QuantumRegister(gate.num_qubits, 'q') diff --git a/qiskit/converters/circuit_to_instruction.py b/qiskit/converters/circuit_to_instruction.py index 9d7f4d521875..b2bf3757cc4b 100644 --- a/qiskit/converters/circuit_to_instruction.py +++ b/qiskit/converters/circuit_to_instruction.py @@ -14,6 +14,7 @@ """Helper function for converting a circuit to an instruction.""" +from math import pi from qiskit.exceptions import QiskitError from qiskit.circuit.instruction import Instruction from qiskit.circuit.quantumregister import QuantumRegister, Qubit @@ -124,6 +125,10 @@ def find_bit_position(bit): qc = QuantumCircuit(*regs, name=instruction.name) qc.data = definition + if circuit.phase: + qc.u3(pi, circuit.phase, circuit.phase - pi, qc.qregs[0][0]) + qc.x(qc.qregs[0][0]) + instruction.definition = qc return instruction diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index dc3dfeb31a8b..e227e95249d4 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -632,6 +632,7 @@ def compose(self, other, edge_map=None, qubits=None, clbits=None, front=False, i dag = self else: dag = copy.deepcopy(self) + dag.phase += other.phase for nd in other.topological_nodes(): if nd.type == "in": diff --git a/qiskit/dagcircuit/retworkx_dagcircuit.py b/qiskit/dagcircuit/retworkx_dagcircuit.py index 4fcafb317639..6b25cf61806c 100644 --- a/qiskit/dagcircuit/retworkx_dagcircuit.py +++ b/qiskit/dagcircuit/retworkx_dagcircuit.py @@ -94,7 +94,6 @@ def __eq__(self, other): # TODO this works but is a horrible way to do this slf = copy.deepcopy(self._multi_graph) oth = copy.deepcopy(other._multi_graph) - return rx.is_isomorphic_node_match( slf, oth, DAGNode.semantic_eq) diff --git a/qiskit/quantum_info/operators/operator.py b/qiskit/quantum_info/operators/operator.py index f47241d6b82d..070ffdb6fab2 100644 --- a/qiskit/quantum_info/operators/operator.py +++ b/qiskit/quantum_info/operators/operator.py @@ -491,8 +491,8 @@ def _init_instruction(cls, instruction): op = Operator(np.eye(2 ** instruction.num_qubits)) # Convert circuit to an instruction if isinstance(instruction, QuantumCircuit): - if instruction.phase: - op *= ScalarOp(op.dim[0], np.exp(1j * float(instruction.phase))) + # if instruction.phase: + # op *= ScalarOp(op.dim[0], np.exp(1j * float(instruction.phase))) instruction = instruction.to_instruction() op._append_instruction(instruction) return op diff --git a/test/python/circuit/test_circuit_operations.py b/test/python/circuit/test_circuit_operations.py index 01dc94bd74e3..27930750dac5 100644 --- a/test/python/circuit/test_circuit_operations.py +++ b/test/python/circuit/test_circuit_operations.py @@ -485,6 +485,20 @@ def test_reverse_bits_with_registers(self): self.assertEqual(qc.reverse_bits(), expected) + def test_inverse(self): + """Test inverse circuit.""" + qr = QuantumRegister(2) + qc = QuantumCircuit(qr, phase=0.5) + qc.h(0) + qc.barrier(qr) + qc.t(1) + + expected = QuantumCircuit(qr) + expected.tdg(1) + expected.barrier(qr) + expected.h(0) + expected.phase = -0.5 + self.assertEqual(qc.inverse(), expected) class TestCircuitBuilding(QiskitTestCase): """QuantumCircuit tests.""" diff --git a/test/python/circuit/test_compose.py b/test/python/circuit/test_compose.py index 9457ede31d4c..9cbe7c87d2b3 100644 --- a/test/python/circuit/test_compose.py +++ b/test/python/circuit/test_compose.py @@ -451,6 +451,15 @@ def test_compose_one_liner(self): self.assertEqual(circ, expected) + def test_compose_global_phase(self): + """Composing with global phase.""" + circ1 = QuantumCircuit(1, phase=1) + circ1.rz(0.5, 0) + circ2 = QuantumCircuit(1, phase=2) + circ3 = QuantumCircuit(1, phase=3) + circ4 = circ1.compose(circ2).compose(circ3) + self.assertEqual(circ4.phase, circ1.phase + circ2.phase + circ3.phase) + if __name__ == '__main__': unittest.main() diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index e1effbd25c95..e5b1f31143e8 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -766,7 +766,6 @@ def test_all_inverses(self, gate): try: numargs = len(_get_free_params(gate)) args = [2] * numargs - gate = gate(*args) self.assertEqual(gate.inverse().control(2), gate.control(2).inverse()) except AttributeError: @@ -888,6 +887,17 @@ def test_open_controlled_equality(self): XGate().control(1, ctrl_state='0'), XGate().control(1, ctrl_state='1')) + def test_cx_global_phase(self): + """ + Test controlling CX with global phase + """ + theta = Parameter('θ') + circ = QuantumCircuit(2, phase=theta) + circ.cx(0, 1) + gccx = QuantumCircuit(3) + gccx.append(circ) + import ipdb; ipdb.set_trace() + @ddt class TestOpenControlledToMatrix(QiskitTestCase): @@ -912,6 +922,11 @@ def test_open_controlled_to_matrix(self, gate_class, ctrl_state): actual = cgate.to_matrix() except CircuitError as cerr: self.skipTest(cerr) + # np.set_printoptions(linewidth=300, precision=3, suppress=True) + # print('\n', cgate.name) + # print(actual) + # print(target) + # import ipdb; ipdb.set_trace() self.assertTrue(np.allclose(actual, target)) @@ -1010,7 +1025,8 @@ def test_controlled_standard_gates(self, num_ctrl_qubits, gate_class): args = [5] gate = gate_class(*args) - for ctrl_state in {ctrl_state_ones, ctrl_state_zeros, ctrl_state_mixed}: + #for ctrl_state in {ctrl_state_ones, ctrl_state_zeros, ctrl_state_mixed}: + for ctrl_state in {ctrl_state_ones}: with self.subTest(i='{0}, ctrl_state={1}'.format(gate_class.__name__, ctrl_state)): if hasattr(gate, 'num_ancilla_qubits') and gate.num_ancilla_qubits > 0: @@ -1031,12 +1047,26 @@ def test_controlled_standard_gates(self, num_ctrl_qubits, gate_class): target_mat = _compute_control_matrix(base_mat, num_ctrl_qubits, ctrl_state=ctrl_state) np.set_printoptions(linewidth=300, precision=2, suppress=True) - # print('') - # print(gate_class) - # print(f'num_ctrl_qubits = {num_ctrl_qubits}, ctrl_state = {bin(ctrl_state)}') - # print(Operator(cgate).data) - # print(target_mat) - #import ipdb; ipdb.set_trace() + from qiskit.circuit.library.standard_gates import RXXGate + rxx = RXXGate(theta) + crxx = RXXGate(theta).control(num_ctrl_qubits) + print('') + print(gate_class) + print(f'num_ctrl_qubits = {num_ctrl_qubits}, ctrl_state = {bin(ctrl_state)}') + print(base_mat) + print('') + print(Operator(cgate).data) + print('') + print(target_mat) + print('') + print(Operator(crxx).data) + + # qc = QuantumCircuit(2) + # qc.append(gate, [0,1]) + # # simulator = BasicAer.get_backend('unitary_simulator') + # # simulated_mat = execute(qc, simulator).result().get_unitary() + #print(simulated_mat) + import ipdb; ipdb.set_trace() self.assertEqual(Operator(cgate), Operator(target_mat)) @ddt diff --git a/test/python/circuit/test_extensions_standard.py b/test/python/circuit/test_extensions_standard.py index 0ec21175a9a0..671b76e51345 100644 --- a/test/python/circuit/test_extensions_standard.py +++ b/test/python/circuit/test_extensions_standard.py @@ -1388,6 +1388,56 @@ def test_to_matrix(self): self.assertTrue(matrix_equal(definition_unitary, gate_matrix)) self.assertTrue(is_unitary_matrix(gate_matrix)) + def test_to_matrix_op(self): + """test gates implementing to_matrix generate matrix which matches + definition using Operator.""" + from qiskit.quantum_info import Operator + from qiskit.circuit.library.standard_gates.ms import MSGate + + params = [0.1 * i for i in range(10)] + gate_class_list = Gate.__subclasses__() + ControlledGate.__subclasses__() + simulator = BasicAer.get_backend('unitary_simulator') + for gate_class in gate_class_list: + sig = signature(gate_class) + if gate_class == MSGate: + # due to the signature (num_qubits, theta, *, n_qubits=Noe) the signature detects + # 3 arguments but really its only 2. This if can be removed once the deprecated + # n_qubits argument is no longer supported. + free_params = 2 + else: + free_params = len(set(sig.parameters) - {'label'}) + try: + gate = gate_class(*params[0:free_params]) + except (CircuitError, QiskitError, AttributeError): + self.log.info( + 'Cannot init gate with params only. Skipping %s', + gate_class) + continue + if gate.name in ['U', 'CX']: + continue + try: + gate_matrix = gate.to_matrix() + except CircuitError: + # gate doesn't implement to_matrix method: skip + self.log.info('to_matrix method FAILED for "%s" gate', + gate.name) + continue + if not hasattr(gate, 'definition') or not gate.definition: + continue + print(gate.name) + try: + definition_unitary = Operator(gate.definition).data + except Exception as err: + pass + #import ipdb; ipdb.set_trace() + if gate.name == 'rxx': + print(definition_unitary) + print(gate_matrix) + import numpy as np + np.set_printoptions(linewidth=300, precision=4, suppress=True) + self.assertTrue(matrix_equal(definition_unitary, gate_matrix)) + self.assertTrue(is_unitary_matrix(gate_matrix)) + @ddt class TestQubitKeywordArgRenaming(QiskitTestCase): diff --git a/test/python/circuit/test_gate_definitions.py b/test/python/circuit/test_gate_definitions.py index 3c23e19ff3b0..2750f5946435 100644 --- a/test/python/circuit/test_gate_definitions.py +++ b/test/python/circuit/test_gate_definitions.py @@ -138,7 +138,9 @@ def test_equivalence_phase(self): with self.subTest(i=gate_class): n_params = len(_get_free_params(gate_class)) params = [0.1 * i for i in range(1, n_params+1)] - #params = [np.pi * i for i in range(1, n_params+1)] + if gate_class.__name__ == 'RXXGate': + params=[np.pi/2] + params = [-np.pi/2 * i for i in range(1, n_params+1)] if gate_class.__name__ in ['MSGate']: params[0] = 2 elif gate_class in ['MCU1Gate']: diff --git a/test/python/compiler/test_transpiler.py b/test/python/compiler/test_transpiler.py index bb7f272f0097..9cbade4d6b01 100644 --- a/test/python/compiler/test_transpiler.py +++ b/test/python/compiler/test_transpiler.py @@ -421,8 +421,6 @@ def test_parameterized_circuit_for_simulator(self): expected_qc = QuantumCircuit(qr) expected_qc.u1(theta, qr[0]) - expected_qc.u3(pi, -0.5*theta, -0.5*theta - pi, qr[0]) - expected_qc.u3(pi, 0, pi, qr[0]) self.assertEqual(expected_qc, transpiled_qc) @@ -440,8 +438,6 @@ def test_parameterized_circuit_for_device(self): qr = QuantumRegister(14, 'q') expected_qc = QuantumCircuit(qr) expected_qc.u1(theta, qr[0]) - expected_qc.u3(pi, -0.5*theta, -0.5*theta - pi, qr[0]) - expected_qc.u3(pi, 0, pi, qr[0]) self.assertEqual(expected_qc, transpiled_qc) @@ -459,9 +455,6 @@ def test_parameter_expression_circuit_for_simulator(self): expected_qc = QuantumCircuit(qr) expected_qc.u1(square, qr[0]) - expected_qc.u3(pi, -0.5*square, -0.5*square - pi, qr[0]) - expected_qc.u3(pi, 0, pi, qr[0]) - self.assertEqual(expected_qc, transpiled_qc) def test_parameter_expression_circuit_for_device(self): @@ -480,8 +473,6 @@ def test_parameter_expression_circuit_for_device(self): qr = QuantumRegister(14, 'q') expected_qc = QuantumCircuit(qr) expected_qc.u1(square, qr[0]) - expected_qc.u3(pi, -0.5*square, -0.5*square - pi, qr[0]) - expected_qc.u3(pi, 0, pi, qr[0]) self.assertEqual(expected_qc, transpiled_qc) def test_final_measurement_barrier_for_devices(self): diff --git a/test/python/quantum_info/states/test_statevector.py b/test/python/quantum_info/states/test_statevector.py index bad9dab092b0..9f310fa0f0a7 100644 --- a/test/python/quantum_info/states/test_statevector.py +++ b/test/python/quantum_info/states/test_statevector.py @@ -266,6 +266,17 @@ def test_evolve_subsystem(self): target = Statevector(np.dot(op_full.data, vec)) self.assertEqual(state.evolve(op, qargs=[2, 1, 0]), target) + def test_evolve_global_phase(self): + """Test evolve circuit with global phase.""" + state_i = Statevector([1, 0]) + qr = QuantumRegister(2) + phase = np.pi / 4 + circ = QuantumCircuit(qr, phase=phase) + circ.x(0) + state_f = state_i.evolve(circ, qargs=[0]) + target = Statevector([0, 1]) * np.exp(1j * phase) + self.assertEqual(state_f, target) + def test_conjugate(self): """Test conjugate method.""" for _ in range(10): diff --git a/test/python/transpiler/test_unroller.py b/test/python/transpiler/test_unroller.py index 69b8c8569ddf..40438dd3f7b1 100644 --- a/test/python/transpiler/test_unroller.py +++ b/test/python/transpiler/test_unroller.py @@ -86,8 +86,6 @@ def test_unroll_1q_chain_conditional(self): ref_circuit.u1(pi/4, qr[0]) ref_circuit.u3(0.5, 0, 0, qr[0]) ref_circuit.u1(0.3, qr[0]) - ref_circuit.u3(pi, -0.3/2, -0.3/2 - pi, qr[0]) - ref_circuit.u3(pi, 0, pi, qr[0]) ref_circuit.u3(0.1, -pi/2, pi/2, qr[0]) ref_circuit.measure(qr[0], cr[0]) ref_circuit.u3(pi, 0, pi, qr[0]).c_if(cr, 1) @@ -124,8 +122,6 @@ def test_simple_unroll_parameterized_without_expressions(self): expected = QuantumCircuit(qr) expected.u1(theta, qr[0]) - expected.u3(pi, -theta/2, -theta/2 - pi, qr[0]) - expected.u3(pi, 0, pi, qr[0]) self.assertEqual(circuit_to_dag(expected), unrolled_dag) @@ -145,8 +141,6 @@ def test_simple_unroll_parameterized_with_expressions(self): expected = QuantumCircuit(qr) expected.u1(sum_, qr[0]) - expected.u3(pi, -sum_/2, -sum_/2 - pi, qr[0]) - expected.u3(pi, 0, pi, qr[0]) self.assertEqual(circuit_to_dag(expected), unrolled_dag) @@ -188,21 +182,12 @@ def test_unrolling_parameterized_composite_gates(self): expected = QuantumCircuit(qr2) expected.u1(theta, qr2[0]) - expected.u3(pi, -theta/2, -theta/2 - pi, qr2[0]) - expected.u3(pi, 0, pi, qr2[0]) expected.cx(qr2[0], qr2[1]) expected.u1(theta, qr2[1]) - expected.u3(pi, -theta/2, -theta/2 - pi, qr2[1]) - expected.u3(pi, 0, pi, qr2[1]) expected.u1(theta, qr2[2]) - expected.u3(pi, -theta/2, -theta/2 - pi, qr2[2]) - expected.u3(pi, 0, pi, qr2[2]) expected.cx(qr2[2], qr2[3]) expected.u1(theta, qr2[3]) - expected.u3(pi, -theta/2, -theta/2 - pi, qr2[3]) - expected.u3(pi, 0, pi, qr2[3]) - self.assertEqual(circuit_to_dag(expected), out_dag) # Expanding across register with shared parameter @@ -219,20 +204,12 @@ def test_unrolling_parameterized_composite_gates(self): expected = QuantumCircuit(qr2) expected.u1(phi, qr2[0]) - expected.u3(pi, -phi/2, -phi/2 - pi, qr2[0]) - expected.u3(pi, 0, pi, qr2[0]) expected.cx(qr2[0], qr2[1]) expected.u1(phi, qr2[1]) - expected.u3(pi, -phi/2, -phi/2 - pi, qr2[1]) - expected.u3(pi, 0, pi, qr2[1]) expected.u1(gamma, qr2[2]) - expected.u3(pi, -gamma/2, -gamma/2 - pi, qr2[2]) - expected.u3(pi, 0, pi, qr2[2]) expected.cx(qr2[2], qr2[3]) expected.u1(gamma, qr2[3]) - expected.u3(pi, -gamma/2, -gamma/2 - pi, qr2[3]) - expected.u3(pi, 0, pi, qr2[3]) self.assertEqual(circuit_to_dag(expected), out_dag) @@ -252,7 +229,6 @@ def compare_dags(self): dag = circuit_to_dag(self.circuit) unrolled_dag = self.pass_.run(dag) ref_dag = circuit_to_dag(self.ref_circuit) - import ipdb;ipdb.set_trace() self.assertEqual(unrolled_dag, ref_dag) def test_unroll_crx(self): From 456f69e0278f2ed80a9ac2a6999e02bbff7dd0ad Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Fri, 10 Jul 2020 04:02:39 -0400 Subject: [PATCH 22/38] passing tests --- qiskit/circuit/add_control.py | 30 ++++++++--- qiskit/circuit/library/standard_gates/rxx.py | 2 +- qiskit/circuit/library/standard_gates/ryy.py | 3 +- qiskit/circuit/library/standard_gates/rzx.py | 3 +- qiskit/circuit/library/standard_gates/rzz.py | 3 +- qiskit/converters/circuit_to_gate.py | 8 +-- qiskit/transpiler/passes/basis/unroller.py | 7 +++ test/python/circuit/test_controlled_gate.py | 55 +++++++++++--------- 8 files changed, 69 insertions(+), 42 deletions(-) diff --git a/qiskit/circuit/add_control.py b/qiskit/circuit/add_control.py index 308bc94c085c..b75763b302f4 100644 --- a/qiskit/circuit/add_control.py +++ b/qiskit/circuit/add_control.py @@ -101,6 +101,11 @@ def control(operation: Union[Gate, ControlledGate], import qiskit.circuit.controlledgate as controlledgate # pylint: disable=unused-import import qiskit.circuit.library.standard_gates.multi_control_rotation_gates + # if operation.name == 'rxx': + # from qiskit.quantum_info import Operator + # import numpy as np + # np.set_printoptions(linewidth=300, precision=2, suppress=True) + # import ipdb; ipdb.set_trace() q_control = QuantumRegister(num_ctrl_qubits, name='control') q_target = QuantumRegister(operation.num_qubits, name='target') @@ -147,6 +152,9 @@ def control(operation: Union[Gate, ControlledGate], elif rule[0].name == 'cx': qc.mct(q_control[:] + [q_target[rule[1][0].index]], q_target[rule[1][1].index], q_ancillae) + elif rule[0].name == 'x': + # hack to catch unrolling with global phase + qc.mct(q_control, q_target[rule[1][0].index]) else: raise CircuitError('gate contains non-controllable instructions: {}'.format( rule[0].name)) @@ -199,14 +207,14 @@ def _gate_to_dag(operation): from qiskit.converters.circuit_to_dag import circuit_to_dag from math import pi if hasattr(operation, 'definition') and operation.definition: - phase = 0 - if operation.definition.phase: - phase = operation.definition.phase - operation.definition.phase = 0 - qubit = operation.definition.qregs[0][0] - if phase: - operation.definition.u3(pi, phase, phase - pi, qubit) - operation.definition.x(qubit) + # phase = 0 + # if operation.definition.phase: + # phase = operation.definition.phase + # operation.definition.phase = 0 + # qubit = operation.definition.qregs[0][0] + # if phase: + # operation.definition.u3(pi, phase, phase - pi, qubit) + # operation.definition.x(qubit) return circuit_to_dag(operation.definition) else: qr = QuantumRegister(operation.num_qubits) @@ -214,11 +222,17 @@ def _gate_to_dag(operation): qc.append(operation, qr) return circuit_to_dag(qc) + # qr = QuantumRegister(operation.num_qubits) + # qc = QuantumCircuit(qr, name=operation.name) + # qc.append(operation, qr) + # return circuit_to_dag(qc) + def _unroll_gate(operation, basis_gates): from qiskit.converters.dag_to_circuit import dag_to_circuit from qiskit.transpiler.passes import Unroller unroller = Unroller(basis_gates) dag = _gate_to_dag(operation) + dag2 = unroller.run(dag) qc = dag_to_circuit(unroller.run(dag)) return qc.to_gate() diff --git a/qiskit/circuit/library/standard_gates/rxx.py b/qiskit/circuit/library/standard_gates/rxx.py index 34b696260101..c5833c155f95 100644 --- a/qiskit/circuit/library/standard_gates/rxx.py +++ b/qiskit/circuit/library/standard_gates/rxx.py @@ -84,7 +84,7 @@ def _define(self): theta = self.params[0] q = QuantumRegister(2, 'q') #qc = QuantumCircuit(q, name=self.name, phase=-theta/2) - qc = QuantumCircuit(q, name=self.name, phase=0) + qc = QuantumCircuit(q, name=self.name) rules = [ (HGate(), [q[0]], []), (HGate(), [q[1]], []), diff --git a/qiskit/circuit/library/standard_gates/ryy.py b/qiskit/circuit/library/standard_gates/ryy.py index bfe062b2567d..51efd9c364a4 100644 --- a/qiskit/circuit/library/standard_gates/ryy.py +++ b/qiskit/circuit/library/standard_gates/ryy.py @@ -82,7 +82,8 @@ def _define(self): q = QuantumRegister(2, 'q') theta = self.params[0] - qc = QuantumCircuit(q, name=self.name, phase=-theta / 2) + #qc = QuantumCircuit(q, name=self.name, phase=-theta / 2) + qc = QuantumCircuit(q, name=self.name, phase=0) rules = [ (RXGate(np.pi / 2), [q[0]], []), (RXGate(np.pi / 2), [q[1]], []), diff --git a/qiskit/circuit/library/standard_gates/rzx.py b/qiskit/circuit/library/standard_gates/rzx.py index 6880d07c58d5..20d2e74b8471 100644 --- a/qiskit/circuit/library/standard_gates/rzx.py +++ b/qiskit/circuit/library/standard_gates/rzx.py @@ -129,7 +129,8 @@ def _define(self): from .rz import RZGate theta = self.params[0] q = QuantumRegister(2, 'q') - qc = QuantumCircuit(q, name=self.name, phase=-theta / 2) + #qc = QuantumCircuit(q, name=self.name, phase=-theta / 2) + qc = QuantumCircuit(q, name=self.name) rules = [ (HGate(), [q[1]], []), (CXGate(), [q[0], q[1]], []), diff --git a/qiskit/circuit/library/standard_gates/rzz.py b/qiskit/circuit/library/standard_gates/rzz.py index 2fcdda34a778..1699e121b6a9 100644 --- a/qiskit/circuit/library/standard_gates/rzz.py +++ b/qiskit/circuit/library/standard_gates/rzz.py @@ -95,7 +95,8 @@ def _define(self): from .rz import RZGate q = QuantumRegister(2, 'q') theta = self.params[0] - qc = QuantumCircuit(q, name=self.name, phase=-theta / 2) + #qc = QuantumCircuit(q, name=self.name, phase=-theta / 2) + qc = QuantumCircuit(q, name=self.name, phase=0) rules = [ (CXGate(), [q[0], q[1]], []), (RZGate(theta), [q[1]], []), diff --git a/qiskit/converters/circuit_to_gate.py b/qiskit/converters/circuit_to_gate.py index 83fbe424490c..232145c8e5ea 100644 --- a/qiskit/converters/circuit_to_gate.py +++ b/qiskit/converters/circuit_to_gate.py @@ -91,11 +91,11 @@ def find_bit_position(bit): equivalence_library.add_equivalence(gate, target) rules = target.data - phase = target.phase / len(target.qregs[0]) + #phase = target.phase / len(target.qregs[0]) if target.phase: - #target.u3(pi, target.phase, target.phase - pi, target.qregs[0]) - target.u3(pi, phase, phase - pi, target.qregs[0]) - target.x(target.qregs[0]) + target.u3(pi, target.phase, target.phase - pi, target.qregs[0][0]) + #target.u3(pi, phase, phase - pi, target.qregs[0]) + target.x(target.qregs[0][0]) if gate.num_qubits > 0: q = QuantumRegister(gate.num_qubits, 'q') diff --git a/qiskit/transpiler/passes/basis/unroller.py b/qiskit/transpiler/passes/basis/unroller.py index 7a8158e96d50..d1e1c813f546 100644 --- a/qiskit/transpiler/passes/basis/unroller.py +++ b/qiskit/transpiler/passes/basis/unroller.py @@ -77,6 +77,8 @@ def run(self, dag): # different that the width of the node. while rule and len(rule) == 1 and len(node.qargs) == len(rule[0][1]): if rule[0][0].name in self.basis: + if node.op.definition and node.op.definition.phase: + dag.phase += node.op.definition.phase dag.substitute_node(node, rule[0][0], inplace=True) break try: @@ -95,5 +97,10 @@ def run(self, dag): (str(self.basis), node.op.name)) decomposition = circuit_to_dag(node.op.definition) unrolled_dag = self.run(decomposition) # recursively unroll ops + if node.op.definition and node.op.definition.phase: + dag.phase += node.op.definition.phase + if unrolled_dag.phase: + dag.phase += unrolled_dag.phase + unrolled_dag.phase = 0 dag.substitute_node_with_dag(node, unrolled_dag) return dag diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index e5b1f31143e8..df6d7523f15b 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -23,7 +23,7 @@ from qiskit import QuantumRegister, QuantumCircuit, execute, BasicAer, QiskitError from qiskit.test import QiskitTestCase -from qiskit.circuit import ControlledGate +from qiskit.circuit import ControlledGate, Parameter from qiskit.circuit.exceptions import CircuitError from qiskit.quantum_info.operators.predicates import matrix_equal, is_unitary_matrix from qiskit.quantum_info.random import random_unitary @@ -891,12 +891,17 @@ def test_cx_global_phase(self): """ Test controlling CX with global phase """ - theta = Parameter('θ') + theta = pi/2 circ = QuantumCircuit(2, phase=theta) circ.cx(0, 1) - gccx = QuantumCircuit(3) - gccx.append(circ) - import ipdb; ipdb.set_trace() + cx = circ.to_gate() + self.assertNotEqual(Operator(CXGate()), Operator(cx)) + + ccx = cx.control(1) + base_mat = Operator(cx).data + target = _compute_control_matrix(base_mat, 1) + + self.assertEqual(Operator(ccx), Operator(target)) @ddt @@ -922,11 +927,6 @@ def test_open_controlled_to_matrix(self, gate_class, ctrl_state): actual = cgate.to_matrix() except CircuitError as cerr: self.skipTest(cerr) - # np.set_printoptions(linewidth=300, precision=3, suppress=True) - # print('\n', cgate.name) - # print(actual) - # print(target) - # import ipdb; ipdb.set_trace() self.assertTrue(np.allclose(actual, target)) @@ -1025,6 +1025,7 @@ def test_controlled_standard_gates(self, num_ctrl_qubits, gate_class): args = [5] gate = gate_class(*args) + #for ctrl_state in {ctrl_state_ones, ctrl_state_zeros, ctrl_state_mixed}: for ctrl_state in {ctrl_state_ones}: with self.subTest(i='{0}, ctrl_state={1}'.format(gate_class.__name__, @@ -1034,9 +1035,10 @@ def test_controlled_standard_gates(self, num_ctrl_qubits, gate_class): continue try: cgate = gate.control(num_ctrl_qubits, ctrl_state=ctrl_state) - except (AttributeError, QiskitError): + except (AttributeError, QiskitError) as err: # 'object has no attribute "control"' # skipping Id and Barrier + print(err) continue if gate.name == 'rz': iden = Operator.from_label('I') @@ -1046,27 +1048,28 @@ def test_controlled_standard_gates(self, num_ctrl_qubits, gate_class): base_mat = Operator(gate).data target_mat = _compute_control_matrix(base_mat, num_ctrl_qubits, ctrl_state=ctrl_state) - np.set_printoptions(linewidth=300, precision=2, suppress=True) - from qiskit.circuit.library.standard_gates import RXXGate - rxx = RXXGate(theta) - crxx = RXXGate(theta).control(num_ctrl_qubits) - print('') - print(gate_class) - print(f'num_ctrl_qubits = {num_ctrl_qubits}, ctrl_state = {bin(ctrl_state)}') - print(base_mat) - print('') - print(Operator(cgate).data) - print('') - print(target_mat) - print('') - print(Operator(crxx).data) + # np.set_printoptions(linewidth=300, precision=2, suppress=True) + # from qiskit.circuit.library.standard_gates import RXXGate + # from qiskit.converters import circuit_to_instruction, circuit_to_gate + # rxx = RXXGate(theta) + # crxx = RXXGate(theta).control(num_ctrl_qubits) + # print('') + # print(gate_class) + # print(f'num_ctrl_qubits = {num_ctrl_qubits}, ctrl_state = {bin(ctrl_state)}') + # print(base_mat) + # print('') + # print(Operator(cgate).data) + # print('') + # print(target_mat) + # print('') + # print(Operator(crxx).data) # qc = QuantumCircuit(2) # qc.append(gate, [0,1]) # # simulator = BasicAer.get_backend('unitary_simulator') # # simulated_mat = execute(qc, simulator).result().get_unitary() #print(simulated_mat) - import ipdb; ipdb.set_trace() + #import ipdb; ipdb.set_trace() self.assertEqual(Operator(cgate), Operator(target_mat)) @ddt From 5a6b37e712e7cfc826460401a75caa306313b5f3 Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Fri, 10 Jul 2020 13:38:23 -0400 Subject: [PATCH 23/38] linting --- qiskit/circuit/library/standard_gates/ms.py | 2 +- qiskit/circuit/library/standard_gates/rx.py | 32 ++--- qiskit/circuit/library/standard_gates/ry.py | 32 ++--- qiskit/circuit/library/standard_gates/rz.py | 30 ++-- qiskit/circuit/library/standard_gates/rzx.py | 20 +-- qiskit/circuit/library/standard_gates/rzz.py | 14 +- qiskit/circuit/library/standard_gates/u3.py | 38 ++--- qiskit/converters/circuit_to_instruction.py | 2 +- qiskit/dagcircuit/retworkx_dagcircuit.py | 133 ------------------ qiskit/extensions/unitary.py | 1 - test/python/circuit/test_compose.py | 2 +- test/python/circuit/test_controlled_gate.py | 7 +- .../circuit/test_extensions_standard.py | 1 - test/python/circuit/test_gate_definitions.py | 4 +- test/python/compiler/test_transpiler.py | 1 - 15 files changed, 92 insertions(+), 227 deletions(-) delete mode 100644 qiskit/dagcircuit/retworkx_dagcircuit.py diff --git a/qiskit/circuit/library/standard_gates/ms.py b/qiskit/circuit/library/standard_gates/ms.py index 69ff872676ac..2da850784aa8 100644 --- a/qiskit/circuit/library/standard_gates/ms.py +++ b/qiskit/circuit/library/standard_gates/ms.py @@ -39,7 +39,7 @@ def _define(self): # pylint: disable=cyclic-import from qiskit.circuit.quantumcircuit import QuantumCircuit from .rxx import RXXGate - theta = self.params[0] + theta = self.params[0] q = QuantumRegister(self.num_qubits, 'q') qc = QuantumCircuit(q, name=self.name) rules = [] diff --git a/qiskit/circuit/library/standard_gates/rx.py b/qiskit/circuit/library/standard_gates/rx.py index 7e997d226605..2b283859e803 100644 --- a/qiskit/circuit/library/standard_gates/rx.py +++ b/qiskit/circuit/library/standard_gates/rx.py @@ -201,22 +201,22 @@ def inverse(self): return CRXGate(-self.params[0]) def to_matrix(self): - """Return a numpy.array for the CRX gate.""" - half_theta = self.params[0] / 2 - cos = numpy.cos(half_theta) - isin = 1j * numpy.sin(half_theta) - if self.ctrl_state: - return numpy.array([[1, 0, 0, 0], - [0, cos, 0, -isin], - [0, 0, 1, 0], - [0, -isin, 0, cos]], - dtype=complex) - else: - return numpy.array([[cos, 0, -isin, 0], - [0, 1, 0, 0], - [-isin, 0, cos, 0], - [0, 0, 0, 1]], - dtype=complex) + """Return a numpy.array for the CRX gate.""" + half_theta = self.params[0] / 2 + cos = numpy.cos(half_theta) + isin = 1j * numpy.sin(half_theta) + if self.ctrl_state: + return numpy.array([[1, 0, 0, 0], + [0, cos, 0, -isin], + [0, 0, 1, 0], + [0, -isin, 0, cos]], + dtype=complex) + else: + return numpy.array([[cos, 0, -isin, 0], + [0, 1, 0, 0], + [-isin, 0, cos, 0], + [0, 0, 0, 1]], + dtype=complex) class CrxGate(CRXGate, metaclass=CRXMeta): """The deprecated CRXGate class.""" diff --git a/qiskit/circuit/library/standard_gates/ry.py b/qiskit/circuit/library/standard_gates/ry.py index ff5ce9167c91..027e3ea8eaef 100644 --- a/qiskit/circuit/library/standard_gates/ry.py +++ b/qiskit/circuit/library/standard_gates/ry.py @@ -196,22 +196,22 @@ def inverse(self): return CRYGate(-self.params[0]) def to_matrix(self): - """Return a numpy.array for the CRY gate.""" - half_theta = self.params[0] / 2 - cos = numpy.cos(half_theta) - sin = numpy.sin(half_theta) - if self.ctrl_state: - return numpy.array([[1, 0, 0, 0], - [0, cos, 0, -sin], - [0, 0, 1, 0], - [0, sin, 0, cos]], - dtype=complex) - else: - return numpy.array([[cos, 0, -sin, 0], - [0, 1, 0, 0], - [sin, 0, cos, 0], - [0, 0, 0, 1]], - dtype=complex) + """Return a numpy.array for the CRY gate.""" + half_theta = self.params[0] / 2 + cos = numpy.cos(half_theta) + sin = numpy.sin(half_theta) + if self.ctrl_state: + return numpy.array([[1, 0, 0, 0], + [0, cos, 0, -sin], + [0, 0, 1, 0], + [0, sin, 0, cos]], + dtype=complex) + else: + return numpy.array([[cos, 0, -sin, 0], + [0, 1, 0, 0], + [sin, 0, cos, 0], + [0, 0, 0, 1]], + dtype=complex) class CryGate(CRYGate, metaclass=CRYMeta): diff --git a/qiskit/circuit/library/standard_gates/rz.py b/qiskit/circuit/library/standard_gates/rz.py index c8222386da66..5d22ed2c5b63 100644 --- a/qiskit/circuit/library/standard_gates/rz.py +++ b/qiskit/circuit/library/standard_gates/rz.py @@ -213,21 +213,21 @@ def inverse(self): return CRZGate(-self.params[0]) def to_matrix(self): - """Return a numpy.array for the CRZ gate.""" - import numpy - arg = 1j * self.params[0] / 2 - if self.ctrl_state: - return numpy.array([[1, 0, 0, 0], - [0, numpy.exp(-arg), 0, 0], - [0, 0, 1, 0], - [0, 0, 0, numpy.exp(arg)]], - dtype=complex) - else: - return numpy.array([[numpy.exp(-arg), 0, 0, 0], - [ 0, 1, 0, 0], - [ 0, 0, numpy.exp(arg), 0], - [ 0, 0, 0, 1]], - dtype=complex) + """Return a numpy.array for the CRZ gate.""" + import numpy + arg = 1j * self.params[0] / 2 + if self.ctrl_state: + return numpy.array([[1, 0, 0, 0], + [0, numpy.exp(-arg), 0, 0], + [0, 0, 1, 0], + [0, 0, 0, numpy.exp(arg)]], + dtype=complex) + else: + return numpy.array([[numpy.exp(-arg), 0, 0, 0], + [0, 1, 0, 0], + [0, 0, numpy.exp(arg), 0], + [0, 0, 0, 1]], + dtype=complex) class CrzGate(CRZGate, metaclass=CRZMeta): diff --git a/qiskit/circuit/library/standard_gates/rzx.py b/qiskit/circuit/library/standard_gates/rzx.py index d9b1265e375e..67cb642bcc2c 100644 --- a/qiskit/circuit/library/standard_gates/rzx.py +++ b/qiskit/circuit/library/standard_gates/rzx.py @@ -145,13 +145,13 @@ def inverse(self): return RZXGate(-self.params[0]) def to_matrix(self): - """Return a numpy.array for the RZX gate.""" - import numpy - half_theta = self.params[0] / 2 - cos = numpy.cos(half_theta) - isin = 1j * numpy.sin(half_theta) - return numpy.array([[ cos, 0, -isin, 0], - [ 0, cos, 0, isin], - [-isin, 0, cos, 0], - [ 0, isin, 0, cos]], - dtype=complex) + """Return a numpy.array for the RZX gate.""" + import numpy + half_theta = self.params[0] / 2 + cos = numpy.cos(half_theta) + isin = 1j * numpy.sin(half_theta) + return numpy.array([[cos, 0, -isin, 0], + [0, cos, 0, isin], + [-isin, 0, cos, 0], + [0, isin, 0, cos]], + dtype=complex) diff --git a/qiskit/circuit/library/standard_gates/rzz.py b/qiskit/circuit/library/standard_gates/rzz.py index 735e6c794b8a..4abfd737d5d3 100644 --- a/qiskit/circuit/library/standard_gates/rzz.py +++ b/qiskit/circuit/library/standard_gates/rzz.py @@ -109,10 +109,10 @@ def inverse(self): return RZZGate(-self.params[0]) def to_matrix(self): - """Return a numpy.array for the RZZ gate.""" - import numpy - itheta2 = 1j * float(self.params[0]) / 2 - return numpy.array([[numpy.exp(-itheta2), 0, 0, 0], - [0, numpy.exp(itheta2), 0, 0], - [0, 0, numpy.exp(itheta2), 0], - [0, 0, 0, numpy.exp(-itheta2)]], dtype=complex) + """Return a numpy.array for the RZZ gate.""" + import numpy + itheta2 = 1j * float(self.params[0]) / 2 + return numpy.array([[numpy.exp(-itheta2), 0, 0, 0], + [0, numpy.exp(itheta2), 0, 0], + [0, 0, numpy.exp(itheta2), 0], + [0, 0, 0, numpy.exp(-itheta2)]], dtype=complex) diff --git a/qiskit/circuit/library/standard_gates/u3.py b/qiskit/circuit/library/standard_gates/u3.py index 12163241ae97..c367cc7e5ce7 100644 --- a/qiskit/circuit/library/standard_gates/u3.py +++ b/qiskit/circuit/library/standard_gates/u3.py @@ -212,24 +212,26 @@ def inverse(self): return CU3Gate(-self.params[0], -self.params[2], -self.params[1]) def to_matrix(self): - """Return a numpy.array for the CRY gate.""" - theta, phi, lam = self.params - theta, phi, lam = float(theta), float(phi), float(lam) - cos = numpy.cos(theta / 2) - sin = numpy.sin(theta / 2) - if self.ctrl_state: - return numpy.array([[1,0, 0, 0], - [0, cos, 0, -numpy.exp(1j * lam) * sin], - [0, 0, 1, 0], - [0, numpy.exp(1j * phi) * sin, 0, numpy.exp(1j * (phi+lam)) * cos]], - dtype=complex) - else: - return numpy.array([[cos, 0, -numpy.exp(1j * lam) * sin, 0], - [0, 1, 0, 0], - [numpy.exp(1j * phi) * sin, 0, numpy.exp(1j * (phi+lam)) * cos, 0], - [0, 0, 0, 1]], - dtype=complex) - + """Return a numpy.array for the CRY gate.""" + theta, phi, lam = self.params + theta, phi, lam = float(theta), float(phi), float(lam) + cos = numpy.cos(theta / 2) + sin = numpy.sin(theta / 2) + if self.ctrl_state: + return numpy.array( + [[1, 0, 0, 0], + [0, cos, 0, -numpy.exp(1j * lam) * sin], + [0, 0, 1, 0], + [0, numpy.exp(1j * phi) * sin, 0, numpy.exp(1j * (phi+lam)) * cos]], + dtype=complex) + else: + return numpy.array( + [[cos, 0, -numpy.exp(1j * lam) * sin, 0], + [0, 1, 0, 0], + [numpy.exp(1j * phi) * sin, 0, numpy.exp(1j * (phi+lam)) * cos, 0], + [0, 0, 0, 1]], + dtype=complex) + class Cu3Gate(CU3Gate, metaclass=CU3Meta): """The deprecated CU3Gate class.""" diff --git a/qiskit/converters/circuit_to_instruction.py b/qiskit/converters/circuit_to_instruction.py index b2bf3757cc4b..fecae604a0bf 100644 --- a/qiskit/converters/circuit_to_instruction.py +++ b/qiskit/converters/circuit_to_instruction.py @@ -128,7 +128,7 @@ def find_bit_position(bit): if circuit.phase: qc.u3(pi, circuit.phase, circuit.phase - pi, qc.qregs[0][0]) qc.x(qc.qregs[0][0]) - + instruction.definition = qc return instruction diff --git a/qiskit/dagcircuit/retworkx_dagcircuit.py b/qiskit/dagcircuit/retworkx_dagcircuit.py deleted file mode 100644 index 6b25cf61806c..000000000000 --- a/qiskit/dagcircuit/retworkx_dagcircuit.py +++ /dev/null @@ -1,133 +0,0 @@ -# -*- coding: utf-8 -*- - -# This code is part of Qiskit. -# -# (C) Copyright IBM 2020. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -""" -Object to represent a quantum circuit as a directed acyclic graph (DAG). - -The nodes in the graph are either input/output nodes or operation nodes. -The edges correspond to qubits or bits in the circuit. A directed edge -from node A to node B means that the (qu)bit passes from the output of A -to the input of B. The object's methods allow circuits to be constructed, -composed, and modified. Some natural properties like depth can be computed -directly from the graph. -""" - -import copy - -import retworkx as rx - -from .dagnode import DAGNode -from .dagcircuit import DAGCircuit - - -class RetworkxDAGCircuit(DAGCircuit): - """ - Quantum circuit as a directed acyclic graph. - - There are 3 types of nodes in the graph: inputs, outputs, and operations. - The nodes are connected by directed edges that correspond to qubits and - bits. - """ - - def __init__(self): - super().__init__() - - self._USE_RX = True - self._gx = 'rx' - self._multi_graph = rx.PyDAG() - - def _add_multi_graph_node(self, node): - # nx: requires manual node id handling. - # rx: provides defined ids for added nodes. - - node_id = self._multi_graph.add_node(node) - node._node_id = node_id - self._id_to_node[node_id] = node - return node_id - - def _get_multi_graph_nodes(self): - return iter(self._multi_graph.nodes()) - - def _add_multi_graph_edge(self, src_id, dest_id, data): - # nx: accepts edge data as kwargs. - # rx: accepts edge data as a dict arg. - - self._multi_graph.add_edge(src_id, dest_id, data) - - def _get_all_multi_graph_edges(self, src_id, dest_id): - # nx: edge enumeration through indexing multigraph - # rx: edge enumeration through method get_all_edge_data - - return self._multi_graph.get_all_edge_data(src_id, dest_id) - - def _get_multi_graph_edges(self): - # nx: Includes edge data in return only when data kwarg = True - # rx: Always includes edge data in return - - return [(src, dest, data) - for src_node in self._multi_graph.nodes() - for (src, dest, data) - in self._multi_graph.out_edges(src_node._node_id)] - - def _get_multi_graph_in_edges(self, node_id): - # nx: Includes edge data in return only when data kwarg = True - # rx: Always includes edge data in return - return self._multi_graph.in_edges(node_id) - - def _get_multi_graph_out_edges(self, node_id): - # nx: Includes edge data in return only when data kwarg = True - # rx: Always includes edge data in return - return self._multi_graph.out_edges(node_id) - - def __eq__(self, other): - # TODO this works but is a horrible way to do this - slf = copy.deepcopy(self._multi_graph) - oth = copy.deepcopy(other._multi_graph) - return rx.is_isomorphic_node_match( - slf, oth, - DAGNode.semantic_eq) - - def topological_nodes(self): - """ - Yield nodes in topological order. - - Returns: - generator(DAGNode): node in topological order - """ - def _key(x): - return x.sort_key - - return iter(rx.lexicographical_topological_sort( - self._multi_graph, - key=_key)) - - def successors(self, node): - """Returns iterator of the successors of a node as DAGNodes.""" - return iter(self._multi_graph.successors(node._node_id)) - - def predecessors(self, node): - """Returns iterator of the predecessors of a node as DAGNodes.""" - return iter(self._multi_graph.predecessors(node._node_id)) - - def bfs_successors(self, node): - """ - Returns an iterator of tuples of (DAGNode, [DAGNodes]) where the DAGNode is the current node - and [DAGNode] is its successors in BFS order. - """ - return iter(rx.bfs_successors(self._multi_graph, node._node_id)) - - def multigraph_layers(self): - """Yield layers of the multigraph.""" - first_layer = [x._node_id for x in self.input_map.values()] - yield from rx.layers(self._multi_graph, first_layer) diff --git a/qiskit/extensions/unitary.py b/qiskit/extensions/unitary.py index 06df1cc5fc93..a21470b80f74 100644 --- a/qiskit/extensions/unitary.py +++ b/qiskit/extensions/unitary.py @@ -134,7 +134,6 @@ def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): QiskitError: Invalid ctrl_state. ExtensionError: Non-unitary controlled unitary. """ - from qiskit.circuit.library.standard_gates import U3Gate cmat = _compute_control_matrix(self.to_matrix(), num_ctrl_qubits, ctrl_state=ctrl_state) iso = isometry.Isometry(cmat, 0, 0) cunitary = ControlledGate('c-unitary', num_qubits=self.num_qubits+num_ctrl_qubits, diff --git a/test/python/circuit/test_compose.py b/test/python/circuit/test_compose.py index 9cbe7c87d2b3..0118ac2943e9 100644 --- a/test/python/circuit/test_compose.py +++ b/test/python/circuit/test_compose.py @@ -459,7 +459,7 @@ def test_compose_global_phase(self): circ3 = QuantumCircuit(1, phase=3) circ4 = circ1.compose(circ2).compose(circ3) self.assertEqual(circ4.phase, circ1.phase + circ2.phase + circ3.phase) - + if __name__ == '__main__': unittest.main() diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index c023125ac2f3..76d5f79630e7 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -23,7 +23,7 @@ from qiskit import QuantumRegister, QuantumCircuit, execute, BasicAer, QiskitError from qiskit.test import QiskitTestCase -from qiskit.circuit import ControlledGate, Parameter +from qiskit.circuit import ControlledGate from qiskit.circuit.exceptions import CircuitError from qiskit.quantum_info.operators.predicates import matrix_equal, is_unitary_matrix from qiskit.quantum_info.random import random_unitary @@ -1025,7 +1025,7 @@ def test_controlled_standard_gates(self, num_ctrl_qubits, gate_class): args = [5] gate = gate_class(*args) - + for ctrl_state in {ctrl_state_ones, ctrl_state_zeros, ctrl_state_mixed}: with self.subTest(i='{0}, ctrl_state={1}'.format(gate_class.__name__, ctrl_state)): @@ -1034,10 +1034,9 @@ def test_controlled_standard_gates(self, num_ctrl_qubits, gate_class): continue try: cgate = gate.control(num_ctrl_qubits, ctrl_state=ctrl_state) - except (AttributeError, QiskitError) as err: + except (AttributeError, QiskitError): # 'object has no attribute "control"' # skipping Id and Barrier - print(err) continue if gate.name == 'rz': iden = Operator.from_label('I') diff --git a/test/python/circuit/test_extensions_standard.py b/test/python/circuit/test_extensions_standard.py index 735f8eac2ade..50d09b6df71e 100644 --- a/test/python/circuit/test_extensions_standard.py +++ b/test/python/circuit/test_extensions_standard.py @@ -1396,7 +1396,6 @@ def test_to_matrix_op(self): params = [0.1 * i for i in range(10)] gate_class_list = Gate.__subclasses__() + ControlledGate.__subclasses__() - simulator = BasicAer.get_backend('unitary_simulator') for gate_class in gate_class_list: sig = signature(gate_class) if gate_class == MSGate: diff --git a/test/python/circuit/test_gate_definitions.py b/test/python/circuit/test_gate_definitions.py index 2750f5946435..d7a566862da5 100644 --- a/test/python/circuit/test_gate_definitions.py +++ b/test/python/circuit/test_gate_definitions.py @@ -18,7 +18,7 @@ import numpy as np from ddt import ddt, data -from qiskit import QuantumCircuit, QiskitError +from qiskit import QuantumCircuit from qiskit.quantum_info import Operator from qiskit.test import QiskitTestCase from qiskit.circuit import ParameterVector, Gate, ControlledGate @@ -139,7 +139,7 @@ def test_equivalence_phase(self): n_params = len(_get_free_params(gate_class)) params = [0.1 * i for i in range(1, n_params+1)] if gate_class.__name__ == 'RXXGate': - params=[np.pi/2] + params = [np.pi/2] params = [-np.pi/2 * i for i in range(1, n_params+1)] if gate_class.__name__ in ['MSGate']: params[0] = 2 diff --git a/test/python/compiler/test_transpiler.py b/test/python/compiler/test_transpiler.py index 9cbade4d6b01..fc87ca1622e4 100644 --- a/test/python/compiler/test_transpiler.py +++ b/test/python/compiler/test_transpiler.py @@ -14,7 +14,6 @@ """Tests basic functionality of the transpile function""" -from math import pi import io import sys import math From 171811f4ab73d1f47f1e76c61d32ad66485f9bdb Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Fri, 10 Jul 2020 14:35:04 -0400 Subject: [PATCH 24/38] revert phase accurate one_qubit_decompose for future pr. --- .../standard_gates/equivalence_library.py | 4 +-- qiskit/circuit/quantumcircuit.py | 4 +-- .../synthesis/one_qubit_decompose.py | 31 +++++++------------ test/python/quantum_info/test_synthesis.py | 2 +- 4 files changed, 16 insertions(+), 25 deletions(-) diff --git a/qiskit/circuit/library/standard_gates/equivalence_library.py b/qiskit/circuit/library/standard_gates/equivalence_library.py index 0902159f20ca..d4813d037581 100644 --- a/qiskit/circuit/library/standard_gates/equivalence_library.py +++ b/qiskit/circuit/library/standard_gates/equivalence_library.py @@ -226,8 +226,8 @@ q = QuantumRegister(1, 'q') theta = Parameter('theta') -def_rz = QuantumCircuit(q) -def_rz.append(U1Gate(theta), [q[0]], [], phase=-theta / 2) +def_rz = QuantumCircuit(q, phase=-theta / 2) +def_rz.append(U1Gate(theta), [q[0]], []) _sel.add_equivalence(RZGate(theta), def_rz) q = QuantumRegister(1, 'q') diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index c67dc0d5e8ce..2e584ee0af0a 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -668,7 +668,7 @@ def cbit_argument_conversion(self, clbit_representation): """ return QuantumCircuit._bit_argument_conversion(clbit_representation, self.clbits) - def append(self, instruction, qargs=None, cargs=None, phase=0): + def append(self, instruction, qargs=None, cargs=None): """Append one or more instructions to the end of the circuit, modifying the circuit in place. Expands qargs and cargs. @@ -676,7 +676,6 @@ def append(self, instruction, qargs=None, cargs=None, phase=0): instruction (qiskit.circuit.Instruction): Instruction instance to append qargs (list(argument)): qubits to attach instruction to cargs (list(argument)): clbits to attach instruction to - phase (float): The global phase in radians of instruction. Returns: qiskit.circuit.Instruction: a handle to the instruction that was just added @@ -702,7 +701,6 @@ def append(self, instruction, qargs=None, cargs=None, phase=0): instructions = InstructionSet() for (qarg, carg) in instruction.broadcast_arguments(expanded_qargs, expanded_cargs): instructions.add(self._append(instruction, qarg, carg), qarg, carg) - self.phase += phase return instructions def _append(self, instruction, qargs, cargs): diff --git a/qiskit/quantum_info/synthesis/one_qubit_decompose.py b/qiskit/quantum_info/synthesis/one_qubit_decompose.py index 8d89576c4ad6..dac7319742b6 100644 --- a/qiskit/quantum_info/synthesis/one_qubit_decompose.py +++ b/qiskit/quantum_info/synthesis/one_qubit_decompose.py @@ -119,9 +119,8 @@ def __call__(self, if not is_unitary_matrix(unitary): raise QiskitError("OneQubitEulerDecomposer: " "input matrix is not unitary.") - theta, phi, lam, phase = self._params(unitary) + theta, phi, lam, _ = self._params(unitary) circuit = self._circuit(theta, phi, lam, - phase=phase, simplify=simplify, atol=atol) return circuit @@ -237,17 +236,16 @@ def _params_u1x(mat): def _circuit_zyz(theta, phi, lam, - phase=0, simplify=True, atol=DEFAULT_ATOL): circuit = QuantumCircuit(1) if simplify and np.isclose(theta, 0.0, atol=atol): - circuit.append(RZGate(phi + lam), [0], phase=phase) + circuit.append(RZGate(phi + lam), [0]) return circuit if not simplify or not np.isclose(lam, 0.0, atol=atol): circuit.append(RZGate(lam), [0]) if not simplify or not np.isclose(theta, 0.0, atol=atol): - circuit.append(RYGate(theta), [0], phase=phase) + circuit.append(RYGate(theta), [0]) if not simplify or not np.isclose(phi, 0.0, atol=atol): circuit.append(RZGate(phi), [0]) return circuit @@ -256,18 +254,17 @@ def _circuit_zyz(theta, def _circuit_zxz(theta, phi, lam, - phase=0, simplify=False, atol=DEFAULT_ATOL): if simplify and np.isclose(theta, 0.0, atol=atol): circuit = QuantumCircuit(1) - circuit.append(RZGate(phi + lam), [0], phase=phase) + circuit.append(RZGate(phi + lam), [0]) return circuit circuit = QuantumCircuit(1) if not simplify or not np.isclose(lam, 0.0, atol=atol): circuit.append(RZGate(lam), [0]) if not simplify or not np.isclose(theta, 0.0, atol=atol): - circuit.append(RXGate(theta), [0], phase=phase) + circuit.append(RXGate(theta), [0]) if not simplify or not np.isclose(phi, 0.0, atol=atol): circuit.append(RZGate(phi), [0]) return circuit @@ -276,17 +273,16 @@ def _circuit_zxz(theta, def _circuit_xyx(theta, phi, lam, - phase=0, simplify=True, atol=DEFAULT_ATOL): circuit = QuantumCircuit(1) if simplify and np.isclose(theta, 0.0, atol=atol): - circuit.append(RXGate(phi + lam), [0], phase=phase) + circuit.append(RXGate(phi + lam), [0]) return circuit if not simplify or not np.isclose(lam, 0.0, atol=atol): circuit.append(RXGate(lam), [0]) if not simplify or not np.isclose(theta, 0.0, atol=atol): - circuit.append(RYGate(theta), [0], phase=phase) + circuit.append(RYGate(theta), [0]) if not simplify or not np.isclose(phi, 0.0, atol=atol): circuit.append(RXGate(phi), [0]) return circuit @@ -295,19 +291,17 @@ def _circuit_xyx(theta, def _circuit_u3(theta, phi, lam, - phase=0, simplify=True, atol=DEFAULT_ATOL): # pylint: disable=unused-argument circuit = QuantumCircuit(1) - circuit.append(U3Gate(theta, phi, lam), [0], phase=phase) + circuit.append(U3Gate(theta, phi, lam), [0]) return circuit @staticmethod def _circuit_u1x(theta, phi, lam, - phase=0, simplify=True, atol=DEFAULT_ATOL): # Shift theta and phi so decomposition is @@ -318,17 +312,17 @@ def _circuit_u1x(theta, if simplify and np.isclose(abs(theta), np.pi, atol=atol): # Zero X90 gate decomposition circuit = QuantumCircuit(1) - circuit.append(U1Gate(lam + phi + theta), [0], phase=phase) + circuit.append(U1Gate(lam + phi + theta), [0]) return circuit if simplify and np.isclose(abs(theta), np.pi/2, atol=atol): # Single X90 gate decomposition - circuit = QuantumCircuit(1, phase=phase) + circuit = QuantumCircuit(1) circuit.append(U1Gate(lam + theta), [0]) circuit.append(RXGate(np.pi / 2), [0]) circuit.append(U1Gate(phi + theta), [0]) return circuit # General two-X90 gate decomposition - circuit = QuantumCircuit(1, phase=phase) + circuit = QuantumCircuit(1) circuit.append(U1Gate(lam), [0]) circuit.append(RXGate(np.pi / 2), [0]) circuit.append(U1Gate(theta), [0]) @@ -340,10 +334,9 @@ def _circuit_u1x(theta, def _circuit_rr(theta, phi, lam, - phase=0, simplify=True, atol=DEFAULT_ATOL): - circuit = QuantumCircuit(1, phase=phase) + circuit = QuantumCircuit(1) if not simplify or not np.isclose(theta, -np.pi, atol=atol): circuit.append(RGate(theta + np.pi, np.pi / 2 - lam), [0]) circuit.append(RGate(-np.pi, 0.5 * (phi - lam + np.pi)), [0]) diff --git a/test/python/quantum_info/test_synthesis.py b/test/python/quantum_info/test_synthesis.py index 63a6b17706b1..3379964d6dbf 100644 --- a/test/python/quantum_info/test_synthesis.py +++ b/test/python/quantum_info/test_synthesis.py @@ -114,7 +114,7 @@ class TestOneQubitEulerDecomposer(QiskitTestCase): def check_one_qubit_euler_angles(self, operator, basis='U3', tolerance=1e-12, - phase_equal=True): + phase_equal=False): """Check euler_angles_1q works for the given unitary""" decomposer = OneQubitEulerDecomposer(basis) with self.subTest(operator=operator): From f9ec746df8f4e1332e974e50054bd31b857410d3 Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Fri, 10 Jul 2020 14:58:23 -0400 Subject: [PATCH 25/38] linting --- qiskit/circuit/library/standard_gates/rx.py | 1 + qiskit/quantum_info/synthesis/ion_decompose.py | 2 +- test/python/circuit/test_circuit_operations.py | 1 + test/python/circuit/test_controlled_gate.py | 1 + test/python/circuit/test_gate_definitions.py | 1 + test/python/circuit/test_gate_power.py | 9 +++++++-- test/python/transpiler/test_unroller.py | 1 - 7 files changed, 12 insertions(+), 4 deletions(-) diff --git a/qiskit/circuit/library/standard_gates/rx.py b/qiskit/circuit/library/standard_gates/rx.py index 2b283859e803..d2ed1009dade 100644 --- a/qiskit/circuit/library/standard_gates/rx.py +++ b/qiskit/circuit/library/standard_gates/rx.py @@ -218,6 +218,7 @@ def to_matrix(self): [0, 0, 0, 1]], dtype=complex) + class CrxGate(CRXGate, metaclass=CRXMeta): """The deprecated CRXGate class.""" diff --git a/qiskit/quantum_info/synthesis/ion_decompose.py b/qiskit/quantum_info/synthesis/ion_decompose.py index 2b2bb4f9ef43..f3a78d6d908b 100644 --- a/qiskit/quantum_info/synthesis/ion_decompose.py +++ b/qiskit/quantum_info/synthesis/ion_decompose.py @@ -49,7 +49,7 @@ def cnot_rxx_decompose(plus_ry=True, plus_rxx=True): sgn_rxx = 1 else: sgn_rxx = -1 - circuit = QuantumCircuit(2, phase=-sgn_ry * sgn_rxx * np.pi / 4) + circuit = QuantumCircuit(2, phase=-sgn_ry * sgn_rxx * np.pi / 4) circuit.append(RYGate(sgn_ry * np.pi / 2), [0]) circuit.append(RXXGate(sgn_rxx * np.pi / 2), [0, 1]) circuit.append(RXGate(-sgn_rxx * np.pi / 2), [0]) diff --git a/test/python/circuit/test_circuit_operations.py b/test/python/circuit/test_circuit_operations.py index bcc8a9689760..c866e34cf68a 100644 --- a/test/python/circuit/test_circuit_operations.py +++ b/test/python/circuit/test_circuit_operations.py @@ -545,6 +545,7 @@ def test_inverse(self): expected.phase = -0.5 self.assertEqual(qc.inverse(), expected) + class TestCircuitBuilding(QiskitTestCase): """QuantumCircuit tests.""" diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 76d5f79630e7..4bd0a2ad27c7 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -1048,6 +1048,7 @@ def test_controlled_standard_gates(self, num_ctrl_qubits, gate_class): ctrl_state=ctrl_state) self.assertEqual(Operator(cgate), Operator(target_mat)) + @ddt class TestDeprecatedGates(QiskitTestCase): """Test controlled of deprecated gates.""" diff --git a/test/python/circuit/test_gate_definitions.py b/test/python/circuit/test_gate_definitions.py index d7a566862da5..8d568a5da5a7 100644 --- a/test/python/circuit/test_gate_definitions.py +++ b/test/python/circuit/test_gate_definitions.py @@ -115,6 +115,7 @@ def test_cx_definition(self): decomposed_circ = circ.decompose() self.assertTrue(Operator(circ).equiv(Operator(decomposed_circ))) + class TestGateEquivalenceEqual(QiskitTestCase): """Test the decomposition of a gate in terms of other gates yields the same matrix as the hardcoded matrix definition.""" diff --git a/test/python/circuit/test_gate_power.py b/test/python/circuit/test_gate_power.py index d0c2eaffccb9..bd3b74a94d7b 100644 --- a/test/python/circuit/test_gate_power.py +++ b/test/python/circuit/test_gate_power.py @@ -126,8 +126,13 @@ def test_composite_sqrt(self): iden = Operator.from_label('I') xgen = Operator.from_label('X') zgen = Operator.from_label('Z') - rzgate = lambda theta: np.cos(0.5 * theta) * iden - 1j * np.sin(0.5 * theta) * zgen - rxgate = lambda theta: np.cos(0.5 * theta) * iden - 1j * np.sin(0.5 * theta) * xgen + + def rzgate(theta): + return np.cos(0.5 * theta) * iden - 1j * np.sin(0.5 * theta) * zgen + + def rxgate(theta): + return np.cos(0.5 * theta) * iden - 1j * np.sin(0.5 * theta) * xgen + rxrz = rxgate(thetax) * rzgate(thetaz) self.assertEqual(result.label, 'my_gate^0.5') diff --git a/test/python/transpiler/test_unroller.py b/test/python/transpiler/test_unroller.py index 40438dd3f7b1..d7d0e8439e89 100644 --- a/test/python/transpiler/test_unroller.py +++ b/test/python/transpiler/test_unroller.py @@ -405,7 +405,6 @@ def test_unroll_sdg(self): self.ref_circuit.u3(0, 0, -pi/2, 1) self.compare_dags() - def test_unroll_swap(self): """test unroll swap""" self.circuit.swap(1, 2) From b4b022983e6259f54499849d3b8530f503d094b8 Mon Sep 17 00:00:00 2001 From: ewinston Date: Fri, 10 Jul 2020 15:01:50 -0400 Subject: [PATCH 26/38] Update test/python/circuit/test_gate_definitions.py Co-authored-by: Luciano Bello --- test/python/circuit/test_gate_definitions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/python/circuit/test_gate_definitions.py b/test/python/circuit/test_gate_definitions.py index 8d568a5da5a7..a69bd4358244 100644 --- a/test/python/circuit/test_gate_definitions.py +++ b/test/python/circuit/test_gate_definitions.py @@ -132,11 +132,11 @@ def setUpClass(cls): if aclass.__name__ not in exclude: cls._gate_classes.append(aclass) + @data(self._gate_classes) def test_equivalence_phase(self): """Test that the equivalent circuits from the equivalency_library have equal matrix representations""" - for gate_class in self._gate_classes: - with self.subTest(i=gate_class): + n_params = len(_get_free_params(gate_class)) params = [0.1 * i for i in range(1, n_params+1)] if gate_class.__name__ == 'RXXGate': From 3b29519087620190c76a9e74a896673e5a5e6eb6 Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Fri, 10 Jul 2020 15:36:53 -0400 Subject: [PATCH 27/38] add release notes --- ...quantumcircuit_phase-5006d1e930348d2e.yaml | 6 ++++ test/python/circuit/test_gate_definitions.py | 32 +++++++++---------- 2 files changed, 22 insertions(+), 16 deletions(-) create mode 100644 releasenotes/notes/add_quantumcircuit_phase-5006d1e930348d2e.yaml diff --git a/releasenotes/notes/add_quantumcircuit_phase-5006d1e930348d2e.yaml b/releasenotes/notes/add_quantumcircuit_phase-5006d1e930348d2e.yaml new file mode 100644 index 000000000000..7660f2ff2bdb --- /dev/null +++ b/releasenotes/notes/add_quantumcircuit_phase-5006d1e930348d2e.yaml @@ -0,0 +1,6 @@ +features: + - | + Adds a `phase` attribute to `QuantumCircuit` for tracking global + phase. This allows, for instance, to have the `to_matrix` method + of a gate to exactly correspond to its decompositions instead of + just up to a global phase. \ No newline at end of file diff --git a/test/python/circuit/test_gate_definitions.py b/test/python/circuit/test_gate_definitions.py index a69bd4358244..a2fbff5b7002 100644 --- a/test/python/circuit/test_gate_definitions.py +++ b/test/python/circuit/test_gate_definitions.py @@ -137,22 +137,22 @@ def test_equivalence_phase(self): """Test that the equivalent circuits from the equivalency_library have equal matrix representations""" - n_params = len(_get_free_params(gate_class)) - params = [0.1 * i for i in range(1, n_params+1)] - if gate_class.__name__ == 'RXXGate': - params = [np.pi/2] - params = [-np.pi/2 * i for i in range(1, n_params+1)] - if gate_class.__name__ in ['MSGate']: - params[0] = 2 - elif gate_class in ['MCU1Gate']: - params[1] = 2 - gate = gate_class(*params) - equiv_lib_list = std_eqlib.get_entry(gate) - for ieq, equivalency in enumerate(equiv_lib_list): - with self.subTest(msg=gate.name + '_' + str(ieq)): - op1 = Operator(gate) - op2 = Operator(equivalency) - self.assertEqual(op1, op2) + n_params = len(_get_free_params(gate_class)) + params = [0.1 * i for i in range(1, n_params+1)] + if gate_class.__name__ == 'RXXGate': + params = [np.pi/2] + params = [-np.pi/2 * i for i in range(1, n_params+1)] + if gate_class.__name__ in ['MSGate']: + params[0] = 2 + elif gate_class in ['MCU1Gate']: + params[1] = 2 + gate = gate_class(*params) + equiv_lib_list = std_eqlib.get_entry(gate) + for ieq, equivalency in enumerate(equiv_lib_list): + with self.subTest(msg=gate.name + '_' + str(ieq)): + op1 = Operator(gate) + op2 = Operator(equivalency) + self.assertEqual(op1, op2) @ddt From e7deb9652a8e356a127b82046727bd5bb9c63880 Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Fri, 10 Jul 2020 15:51:41 -0400 Subject: [PATCH 28/38] revert equiv test _self._gate_classes can't be accessed from @data and putting it into the class level, like done in other tests, causes gate code to be "tested" outside of tests. --- test/python/circuit/test_gate_definitions.py | 36 ++++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/test/python/circuit/test_gate_definitions.py b/test/python/circuit/test_gate_definitions.py index a2fbff5b7002..8d568a5da5a7 100644 --- a/test/python/circuit/test_gate_definitions.py +++ b/test/python/circuit/test_gate_definitions.py @@ -132,27 +132,27 @@ def setUpClass(cls): if aclass.__name__ not in exclude: cls._gate_classes.append(aclass) - @data(self._gate_classes) def test_equivalence_phase(self): """Test that the equivalent circuits from the equivalency_library have equal matrix representations""" - - n_params = len(_get_free_params(gate_class)) - params = [0.1 * i for i in range(1, n_params+1)] - if gate_class.__name__ == 'RXXGate': - params = [np.pi/2] - params = [-np.pi/2 * i for i in range(1, n_params+1)] - if gate_class.__name__ in ['MSGate']: - params[0] = 2 - elif gate_class in ['MCU1Gate']: - params[1] = 2 - gate = gate_class(*params) - equiv_lib_list = std_eqlib.get_entry(gate) - for ieq, equivalency in enumerate(equiv_lib_list): - with self.subTest(msg=gate.name + '_' + str(ieq)): - op1 = Operator(gate) - op2 = Operator(equivalency) - self.assertEqual(op1, op2) + for gate_class in self._gate_classes: + with self.subTest(i=gate_class): + n_params = len(_get_free_params(gate_class)) + params = [0.1 * i for i in range(1, n_params+1)] + if gate_class.__name__ == 'RXXGate': + params = [np.pi/2] + params = [-np.pi/2 * i for i in range(1, n_params+1)] + if gate_class.__name__ in ['MSGate']: + params[0] = 2 + elif gate_class in ['MCU1Gate']: + params[1] = 2 + gate = gate_class(*params) + equiv_lib_list = std_eqlib.get_entry(gate) + for ieq, equivalency in enumerate(equiv_lib_list): + with self.subTest(msg=gate.name + '_' + str(ieq)): + op1 = Operator(gate) + op2 = Operator(equivalency) + self.assertEqual(op1, op2) @ddt From f424ea8a4943cd5812759cb1dafeeb340d07cad4 Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Fri, 10 Jul 2020 17:39:29 -0400 Subject: [PATCH 29/38] update release notes --- .../add_quantumcircuit_phase-5006d1e930348d2e.yaml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/releasenotes/notes/add_quantumcircuit_phase-5006d1e930348d2e.yaml b/releasenotes/notes/add_quantumcircuit_phase-5006d1e930348d2e.yaml index 7660f2ff2bdb..51dbb51e35be 100644 --- a/releasenotes/notes/add_quantumcircuit_phase-5006d1e930348d2e.yaml +++ b/releasenotes/notes/add_quantumcircuit_phase-5006d1e930348d2e.yaml @@ -3,4 +3,15 @@ features: Adds a `phase` attribute to `QuantumCircuit` for tracking global phase. This allows, for instance, to have the `to_matrix` method of a gate to exactly correspond to its decompositions instead of - just up to a global phase. \ No newline at end of file + just up to a global phase. The same attribute has also been + extended to DAGCircuit so the phase can be tracked when converting + between QuantumCircuit and DAGCircuit. For example:: + + from qiskit import QuantumCircuit + circ = QuantumCircuit(1, phase=math.pi) + circ.u1(0) + + The global phase may also be set or queried with the `circ.phase` + property. If the circuit is converted to an instruction or gate + the global phase is represented by two single qubit rotations on + the first qubit. \ No newline at end of file From 1c7d2caba6a27dfc3e540648fd21765959b1ae62 Mon Sep 17 00:00:00 2001 From: ewinston Date: Tue, 14 Jul 2020 09:39:49 -0400 Subject: [PATCH 30/38] Update qiskit/circuit/quantumcircuit.py Co-authored-by: Ali Javadi-Abhari --- qiskit/circuit/quantumcircuit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index 2e584ee0af0a..6482aea5ec6f 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -78,7 +78,7 @@ class QuantumCircuit: name (str): the name of the quantum circuit. If not set, an automatically generated string will be assigned. - phase (float): The global phase of the circuit. + phase (float): The global phase of the circuit in radians. Raises: CircuitError: if the circuit name, if given, is not valid. From 73509d40b0de83bd777ab54c3f86499f6c68b1dc Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Tue, 21 Jul 2020 12:23:54 -0400 Subject: [PATCH 31/38] don't unroll global phase to single qubit gates --- qiskit/circuit/add_control.py | 145 +++++++++++++++++- qiskit/circuit/controlledgate.py | 3 +- qiskit/circuit/quantumcircuit.py | 128 ++++++++++++++-- qiskit/converters/circuit_to_gate.py | 9 +- qiskit/converters/circuit_to_instruction.py | 6 +- qiskit/quantum_info/operators/operator.py | 11 +- ...quantumcircuit_phase-5006d1e930348d2e.yaml | 6 +- test/python/circuit/test_controlled_gate.py | 57 ++++++- 8 files changed, 335 insertions(+), 30 deletions(-) diff --git a/qiskit/circuit/add_control.py b/qiskit/circuit/add_control.py index be49e1186186..977bf0ef2fb2 100644 --- a/qiskit/circuit/add_control.py +++ b/qiskit/circuit/add_control.py @@ -66,7 +66,7 @@ def add_control(operation: Union[Gate, ControlledGate], if isinstance(operation, UnitaryGate): # attempt decomposition operation._define() - cgate = control(operation, num_ctrl_qubits=num_ctrl_qubits, label=label, ctrl_state=ctrl_state) + cgate = control2(operation, num_ctrl_qubits=num_ctrl_qubits, label=label, ctrl_state=ctrl_state) cgate.base_gate.label = operation.label return cgate @@ -121,7 +121,7 @@ def control(operation: Union[Gate, ControlledGate], qc.mcrz(operation.definition.data[0][0].params[0], q_control, q_target[0], use_basis_gates=True) else: - bgate = _unroll_gate(operation, ['u1', 'u3', 'cx']) + bgate = _unroll_gate(operation, ['u1', 'u3', 'cx'], qc, q_control) # now we have a bunch of single qubit rotation gates and cx for rule in bgate.definition.data: if rule[0].name == 'u3': @@ -183,6 +183,133 @@ def control(operation: Union[Gate, ControlledGate], cgate.base_gate = base_gate return cgate +def control2(operation: Union[Gate, ControlledGate], + num_ctrl_qubits: Optional[int] = 1, + label: Optional[Union[None, str]] = None, + ctrl_state: Optional[Union[None, int, str]] = None) -> ControlledGate: + """Return controlled version of gate using controlled rotations. This function + first checks the name of the operation to see if it knows of a method from which + to generate a controlled version. Currently these are `x`, `rx`, `ry`, and `rz`. + If a method is not directly known, it calls the unroller to convert to `u1`, `u3`, + and `cx` gates. + + Args: + operation: The gate used to create the ControlledGate. + num_ctrl_qubits: The number of controls to add to gate (default=1). + label: An optional gate label. + ctrl_state: The control state in decimal or as + a bitstring (e.g. '111'). If specified as a bitstring the length + must equal num_ctrl_qubits, MSB on left. If None, use + 2**num_ctrl_qubits-1. + + Returns: + Controlled version of gate. + + Raises: + CircuitError: gate contains non-gate in definition + """ + from math import pi + # pylint: disable=cyclic-import + import qiskit.circuit.controlledgate as controlledgate + basis = ['u1', 'u3', 'x', 'rx', 'ry', 'rz', 'cx'] + unrolled_gate = _unroll_gate(operation, basis_gates=basis) + + q_control = QuantumRegister(num_ctrl_qubits, name='control') + q_target = QuantumRegister(operation.num_qubits, name='target') + q_ancillae = None # TODO: add + controlled_circ = QuantumCircuit(q_control, q_target, + name='c_{}'.format(operation.name)) + # if ctrl_state: + # ctrl_state_circ = QuantumCircuit(q_control) + # bit_ctrl_state = bin(ctrl_state)[2:].zfill(num_ctrl_qubits) + # for qind, val in enumerate(bit_ctrl_state[::-1]): + # if val == '0': + # control_state_circ.x(qind) + # controlled_circ.compose(ctrl_state_circ, q_control) + global_phase = 0 + for gate, qreg, creg in unrolled_gate.definition.data: + if gate.name == 'x' or ( + isinstance(gate, controlledgate.ControlledGate) and + gate.base_gate.name == 'x'): + controlled_circ.mct(q_control[:] + q_target[:-1], q_target[-1], + q_ancillae) + elif gate.name == 'rx': + controlled_circ.mcrx(gate.definition.data[0][0].params[0], + q_control, q_target[qreg[0].index], + use_basis_gates=True) + elif gate.name == 'ry': + controlled_circ.mcry(gate.definition.data[0][0].params[0], + q_control, q_target[qreg[0].index], + q_ancillae, mode='noancilla', + use_basis_gates=True) + elif gate.name == 'rz': + controlled_circ.mcrz(gate.definition.data[0][0].params[0], + q_control, q_target[qreg[0].index], + use_basis_gates=True) + elif gate.name == 'u1': + controlled_circ.mcu1(gate.params[0], q_control, q_target[qreg[0].index]) + elif gate.name == 'cx': + controlled_circ.mct(q_control[:] + [q_target[qreg[0].index]], q_target[qreg[1].index], + q_ancillae) + elif gate.name == 'u3': + theta, phi, lamb = gate.params + if phi == -pi / 2 and lamb == pi / 2: + controlled_circ.mcrx(theta, q_control, q_target[qreg[0].index], + use_basis_gates=True) + elif phi == 0 and lamb == 0: + controlled_circ.mcry(theta, q_control, q_target[qreg[0].index], + q_ancillae, use_basis_gates=True) + elif theta == 0 and phi == 0: + controlled_circ.mcrz(lamb, q_control, q_target[qreg[0].index], + use_basis_gates=True) + else: + controlled_circ.mcrz(lamb, q_control, q_target[qreg[0].index], + use_basis_gates=True) + controlled_circ.mcry(theta, q_control, q_target[qreg[0].index], + q_ancillae, use_basis_gates=True) + controlled_circ.mcrz(phi, q_control, q_target[qreg[0].index], + use_basis_gates=True) + else: + raise CircuitError('gate contains non-controllable instructions: {}'.format( + gate.name)) + if gate.definition is not None and gate.definition.phase: + global_phase += gate.definition.phase + # if ctrl_state: + # controlled_circ.compose(ctrl_state_circ, q_control) + # apply global phase + if ((unrolled_gate.definition is not None and unrolled_gate.definition.phase) or global_phase): + if len(q_control) < 2: + controlled_circ.u1(unrolled_gate.definition.phase + global_phase, q_control) + else: + controlled_circ.mcu1(unrolled_gate.definition.phase + global_phase, q_control[:-1], q_control[-1]) + if isinstance(operation, controlledgate.ControlledGate): + new_num_ctrl_qubits = num_ctrl_qubits + operation.num_ctrl_qubits + new_ctrl_state = operation.ctrl_state << num_ctrl_qubits | ctrl_state + base_name = operation.base_gate.name + base_gate = operation.base_gate + else: + new_num_ctrl_qubits = num_ctrl_qubits + new_ctrl_state = ctrl_state + base_name = operation.name + base_gate = operation + # In order to maintain some backward compatibility with gate names this + # uses a naming convention where if the number of controls is <=2 the gate + # is named like "cc", else it is named like + # "c". + if new_num_ctrl_qubits > 2: + ctrl_substr = 'c{0:d}'.format(new_num_ctrl_qubits) + else: + ctrl_substr = ('{0}' * new_num_ctrl_qubits).format('c') + new_name = '{0}{1}'.format(ctrl_substr, base_name) + cgate = controlledgate.ControlledGate(new_name, + controlled_circ.num_qubits, + operation.params, + label=label, + num_ctrl_qubits=new_num_ctrl_qubits, + definition=controlled_circ, + ctrl_state=new_ctrl_state) + cgate.base_gate = base_gate + return cgate def _gate_to_circuit(operation): qr = QuantumRegister(operation.num_qubits) @@ -200,7 +327,7 @@ def _gate_to_circuit(operation): def _gate_to_dag(operation): from qiskit.converters.circuit_to_dag import circuit_to_dag - if hasattr(operation, 'definition') and operation.definition: + if hasattr(operation, 'definition') and operation.definition is not None: return circuit_to_dag(operation.definition) else: qr = QuantumRegister(operation.num_qubits) @@ -209,10 +336,16 @@ def _gate_to_dag(operation): return circuit_to_dag(qc) -def _unroll_gate(operation, basis_gates): +def _unroll_gate(operation, basis_gates, qc=None, q_control=None): from qiskit.converters.dag_to_circuit import dag_to_circuit from qiskit.transpiler.passes import Unroller unroller = Unroller(basis_gates) dag = _gate_to_dag(operation) - qc = dag_to_circuit(unroller.run(dag)) - return qc.to_gate() + opqc = dag_to_circuit(unroller.run(dag)) + # if opqc.phase and qc is not None and q_control is not None: + # if len(q_control) < 2: + # qc.u1(opqc.phase, q_control) + # else: + # qc.mcu1(opqc.phase, q_control[:-1], q_control[-1]) + # qc.phase = 0 + return opqc.to_gate() diff --git a/qiskit/circuit/controlledgate.py b/qiskit/circuit/controlledgate.py index 9592f0977df4..c44f9ed6f056 100644 --- a/qiskit/circuit/controlledgate.py +++ b/qiskit/circuit/controlledgate.py @@ -207,4 +207,5 @@ def __eq__(self, other) -> bool: def inverse(self) -> 'ControlledGate': """Invert this gate by calling inverse on the base gate.""" - return self.base_gate.inverse().control(self.num_ctrl_qubits) + return self.base_gate.inverse().control(self.num_ctrl_qubits, + ctrl_state=self.ctrl_state) diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index 6482aea5ec6f..5327c3cab863 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -392,6 +392,36 @@ def repeat(self, reps): return repeated_circ + # def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): + # """Control this circuit on ``num_ctrl_qubits`` qubits. + + # Args: + # num_ctrl_qubits (int): The number of control qubits. + # label (str): An optional label to give the controlled operation for visualization. + # ctrl_state (str or int): The control state in decimal or as a bitstring + # (e.g. '111'). If None, use ``2**num_ctrl_qubits - 1``. + + # Returns: + # QuantumCircuit: The controlled version of this circuit. + + # Raises: + # CircuitError: If the circuit contains a non-unitary operation and cannot be controlled. + # """ + # try: + # gate = self.to_gate() + # except QiskitError: + # raise CircuitError('The circuit contains non-unitary operations and cannot be ' + # 'controlled. Note that no qiskit.circuit.Instruction objects may ' + # 'be in the circuit for this operation.') + + # controlled_gate = gate.control(num_ctrl_qubits, label, ctrl_state) + # control_qreg = QuantumRegister(num_ctrl_qubits) + # controlled_circ = QuantumCircuit(control_qreg, *self.qregs, + # name='c_{}'.format(self.name)) + # controlled_circ.append(controlled_gate, controlled_circ.qubits) + + # return controlled_circ + def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Control this circuit on ``num_ctrl_qubits`` qubits. @@ -407,19 +437,88 @@ def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): Raises: CircuitError: If the circuit contains a non-unitary operation and cannot be controlled. """ - try: - gate = self.to_gate() - except QiskitError: - raise CircuitError('The circuit contains non-unitary operations and cannot be ' - 'controlled. Note that no qiskit.circuit.Instruction objects may ' - 'be in the circuit for this operation.') - - controlled_gate = gate.control(num_ctrl_qubits, label, ctrl_state) - control_qreg = QuantumRegister(num_ctrl_qubits) - controlled_circ = QuantumCircuit(control_qreg, *self.qregs, + from math import pi + # pylint: disable=cyclic-import + import qiskit.circuit.controlledgate as controlledgate + + from qiskit.converters import dag_to_circuit, circuit_to_dag + from qiskit.transpiler.passes import Unroller + unroller = Unroller(['u1', 'u3', 'x', 'rx', 'ry', 'rz', 'cx']) + dag = circuit_to_dag(self) + unrolled_circ = dag_to_circuit(unroller.run(dag)) + + q_control = QuantumRegister(num_ctrl_qubits, name='control') + q_target = QuantumRegister(self.num_qubits, name='target') + q_ancillae = None # TODO: add + controlled_circ = QuantumCircuit(q_control, q_target, name='c_{}'.format(self.name)) - controlled_circ.append(controlled_gate, controlled_circ.qubits) - + has_open_ctrl = False + if ctrl_state is not None: + has_open_ctrl = ctrl_state < 2**num_ctrl_qubits - 1 + if has_open_ctrl: + ctrl_state_circ = QuantumCircuit(q_control) + bit_ctrl_state = bin(ctrl_state)[2:].zfill(num_ctrl_qubits) + for qind, val in enumerate(bit_ctrl_state[::-1]): + if val == '0': + ctrl_state_circ.x(qind) + controlled_circ.compose(ctrl_state_circ, q_control, inplace=True) + global_phase = 0 + for operation, qreg, creg in unrolled_circ.data: + if operation.name == 'x' or ( + isinstance(operation, controlledgate.ControlledGate) and + operation.base_gate.name == 'x'): + controlled_circ.mct(q_control[:] + q_target[:-1], q_target[-1], + q_ancillae) + elif operation.name == 'rx': + controlled_circ.mcrx(operation.definition.data[0][0].params[0], + q_control, q_target[qreg[0].index], + use_basis_gates=True) + elif operation.name == 'ry': + controlled_circ.mcry(operation.definition.data[0][0].params[0], + q_control, q_target[qreg[0].index], + q_ancillae, mode='noancilla', + use_basis_gates=True) + elif operation.name == 'rz': + controlled_circ.mcrz(operation.definition.data[0][0].params[0], + q_control, q_target[qreg[0].index], + use_basis_gates=True) + elif operation.name == 'u1': + controlled_circ.mcu1(operation.params[0], q_control, q_target[qreg[0].index]) + elif operation.name == 'cx': + controlled_circ.mct(q_control[:] + [q_target[qreg[0].index]], q_target[qreg[1].index], + q_ancillae) + elif operation.name == 'u3': + theta, phi, lamb = operation.params + if phi == -pi / 2 and lamb == pi / 2: + controlled_circ.mcrx(theta, q_control, q_target[qreg[0].index], + use_basis_gates=True) + elif phi == 0 and lamb == 0: + controlled_circ.mcry(theta, q_control, q_target[qreg[0].index], + q_ancillae, use_basis_gates=True) + elif theta == 0 and phi == 0: + controlled_circ.mcrz(lamb, q_control, q_target[qreg[0].index], + use_basis_gates=True) + else: + controlled_circ.mcrz(lamb, q_control, q_target[qreg[0].index], + use_basis_gates=True) + controlled_circ.mcry(theta, q_control, q_target[qreg[0].index], + q_ancillae, use_basis_gates=True) + controlled_circ.mcrz(phi, q_control, q_target[qreg[0].index], + use_basis_gates=True) + else: + raise CircuitError('gate contains non-controllable instructions: {}'.format( + operation.name)) + if operation.definition is not None and operation.definition.phase: + global_phase += operation.definition.phase + if has_open_ctrl: + controlled_circ.compose(ctrl_state_circ, q_control, inplace=True) + if self.phase or global_phase: + if len(q_control) < 2: + controlled_circ.u1(self.phase + global_phase, q_control) + else: + controlled_circ.mcu1(self.phase + global_phase, q_control[:-1], + q_control[-1]) + return controlled_circ def combine(self, rhs): @@ -727,6 +826,11 @@ def _append(self, instruction, qargs, cargs): self._check_qargs(qargs) self._check_cargs(cargs) + # add phase + # if instruction.definition and instruction.definition.phase: + # self.phase += instruction.definition.phase + # instruction.definition.phase = 0 + # add the instruction onto the given wires instruction_context = instruction, qargs, cargs self._data.append(instruction_context) diff --git a/qiskit/converters/circuit_to_gate.py b/qiskit/converters/circuit_to_gate.py index e76a1d6703d6..96a4121e2d45 100644 --- a/qiskit/converters/circuit_to_gate.py +++ b/qiskit/converters/circuit_to_gate.py @@ -91,9 +91,10 @@ def find_bit_position(bit): equivalence_library.add_equivalence(gate, target) rules = target.data - if target.phase: - target.u3(pi, target.phase, target.phase - pi, target.qregs[0][0]) - target.x(target.qregs[0][0]) + # if target.phase: + # target.u3(pi, target.phase, target.phase - pi, target.qregs[0][0]) + # target.x(target.qregs[0][0]) + # target.phase = 0 if gate.num_qubits > 0: q = QuantumRegister(gate.num_qubits, 'q') @@ -106,7 +107,7 @@ def find_bit_position(bit): list(map(lambda y: q[find_bit_position(y)], x[1])), []), rules)) - qc = QuantumCircuit(q, name=gate.name) + qc = QuantumCircuit(q, name=gate.name, phase=target.phase) qc.data = rules gate.definition = qc return gate diff --git a/qiskit/converters/circuit_to_instruction.py b/qiskit/converters/circuit_to_instruction.py index fecae604a0bf..946bf7516aa2 100644 --- a/qiskit/converters/circuit_to_instruction.py +++ b/qiskit/converters/circuit_to_instruction.py @@ -126,8 +126,10 @@ def find_bit_position(bit): qc = QuantumCircuit(*regs, name=instruction.name) qc.data = definition if circuit.phase: - qc.u3(pi, circuit.phase, circuit.phase - pi, qc.qregs[0][0]) - qc.x(qc.qregs[0][0]) + qc.phase = circuit.phase + # if circuit.phase: + # qc.u3(pi, circuit.phase, circuit.phase - pi, qc.qregs[0][0]) + # qc.x(qc.qregs[0][0]) instruction.definition = qc diff --git a/qiskit/quantum_info/operators/operator.py b/qiskit/quantum_info/operators/operator.py index 5e711de8da36..50164629c0c9 100644 --- a/qiskit/quantum_info/operators/operator.py +++ b/qiskit/quantum_info/operators/operator.py @@ -485,11 +485,18 @@ def _einsum_matmul(cls, tensor, mat, indices, shift=0, right_mul=False): @classmethod def _init_instruction(cls, instruction): """Convert a QuantumCircuit or Instruction to an Operator.""" + from .scalar_op import ScalarOp # Initialize an identity operator of the correct size of the circuit - op = Operator(np.eye(2 ** instruction.num_qubits)) + dimension = 2 ** instruction.num_qubits + op = Operator(np.eye(dimension)) # Convert circuit to an instruction if isinstance(instruction, QuantumCircuit): + if instruction.phase: + op *= ScalarOp(dimension, np.exp(1j * instruction.phase)) instruction = instruction.to_instruction() + elif isinstance(instruction, Instruction): + if instruction.definition is not None and instruction.definition.phase: + op *= ScalarOp(dimension, np.exp(1j * instruction.definition.phase)) op._append_instruction(instruction) return op @@ -531,6 +538,8 @@ def _append_instruction(self, obj, qargs=None): 'definition is {} but expected QuantumCircuit.'.format( obj.name, type(obj.definition))) flat_instr = obj.definition.to_instruction() + # if flat_instr.definition is not None and flat_instr.definition.phase: + # import ipdb; ipdb.set_trace() for instr, qregs, cregs in flat_instr.definition.data: if cregs: raise QiskitError( diff --git a/releasenotes/notes/add_quantumcircuit_phase-5006d1e930348d2e.yaml b/releasenotes/notes/add_quantumcircuit_phase-5006d1e930348d2e.yaml index 51dbb51e35be..7532f1b07501 100644 --- a/releasenotes/notes/add_quantumcircuit_phase-5006d1e930348d2e.yaml +++ b/releasenotes/notes/add_quantumcircuit_phase-5006d1e930348d2e.yaml @@ -12,6 +12,6 @@ features: circ.u1(0) The global phase may also be set or queried with the `circ.phase` - property. If the circuit is converted to an instruction or gate - the global phase is represented by two single qubit rotations on - the first qubit. \ No newline at end of file + property. In either case the setting is in radians. If the circuit + is converted to an instruction or gate the global phase is + represented by two single qubit rotations on the first qubit. \ No newline at end of file diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 4bd0a2ad27c7..30e8e81d5306 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -578,7 +578,7 @@ def test_inverse_x(self, num_ctrl_qubits): np.testing.assert_array_almost_equal(result.data, np.identity(result.dim[0])) @data(1, 2, 3) - def test_inverse_circuit(self, num_ctrl_qubits): + def test_inverse_gate(self, num_ctrl_qubits): """Test inverting a controlled gate based on a circuit definition.""" qc = QuantumCircuit(3) qc.h(0) @@ -587,10 +587,31 @@ def test_inverse_circuit(self, num_ctrl_qubits): qc.rx(np.pi / 4, [0, 1, 2]) gate = qc.to_gate() cgate = gate.control(num_ctrl_qubits) + import qiskit.circuit.add_control as add_control + cgate2 = add_control.control2(gate, num_ctrl_qubits=num_ctrl_qubits) + inv_cgate2 = cgate2.inverse() inv_cgate = cgate.inverse() result = Operator(cgate).compose(Operator(inv_cgate)) + np.set_printoptions(precision=2, linewidth=250, suppress=True) + import ipdb; ipdb.set_trace() + np.testing.assert_array_almost_equal(result.data, np.identity(result.dim[0])) + @data(1, 2, 3) + def test_inverse_circuit(self, num_ctrl_qubits): + """Test inverting a controlled gate based on a circuit definition.""" + qc = QuantumCircuit(3) + qc.h(0) + qc.cx(0, 1) + qc.cx(1, 2) + qc.rx(np.pi / 4, [0, 1, 2]) + qc_inv = qc.inverse() + result = Operator(qc).compose(Operator(qc_inv)) + np.set_printoptions(precision=2, linewidth=250, suppress=True) + #import ipdb; ipdb.set_trace() + + np.testing.assert_array_almost_equal(result.data, np.identity(result.dim[0])) + @data(1, 2, 3, 4, 5) def test_controlled_unitary(self, num_ctrl_qubits): """Test the matrix data of an Operator, which is based on a controlled gate.""" @@ -724,9 +745,11 @@ def test_open_control_composite_unrolling(self): qcomp.h(qreg[0]) qcomp.cx(qreg[0], qreg[1]) bell = qcomp.to_gate() + cbell2 = qcomp.control(ctrl_state=0) # create controlled composite gate cqreg = QuantumRegister(3) qc = QuantumCircuit(cqreg) + cbell = bell.control(ctrl_state=0) qc.append(bell.control(ctrl_state=0), qc.qregs[0][:]) dag = circuit_to_dag(qc) unroller = Unroller(['x', 'u1', 'cbell']) @@ -903,6 +926,38 @@ def test_cx_global_phase(self): self.assertEqual(Operator(ccx), Operator(target)) + @data(1, 2) + def test_controlled_global_phase(self, num_ctrl_qubits): + """ + Test controlled global phase on base gate. + """ + theta = pi/4 + circ = QuantumCircuit(2, phase=theta) + dag = circuit_to_dag(circ) + base_gate = circ.to_gate() + base_mat = Operator(base_gate).data + target = _compute_control_matrix(base_mat, num_ctrl_qubits) + cgate = base_gate.control(num_ctrl_qubits) + ccirc = circ.control(num_ctrl_qubits) + self.assertEqual(Operator(cgate), Operator(target)) + self.assertEqual(Operator(ccirc), Operator(target)) + + @data(1, 2) + def test_rz_composite_global_phase(self, num_ctrl_qubits): + """ + Test controlling CX with global phase + """ + theta = pi/4 + circ = QuantumCircuit(2, phase=theta) + circ.rz(0.1, 0) + circ.rz(0.2, 1) + ccirc = circ.control(num_ctrl_qubits) + base_gate = circ.to_gate() + cgate = base_gate.control(num_ctrl_qubits) + base_mat = Operator(base_gate).data + target = _compute_control_matrix(base_mat, num_ctrl_qubits) + self.assertEqual(Operator(cgate), Operator(target)) + self.assertEqual(Operator(ccirc), Operator(target)) @ddt class TestOpenControlledToMatrix(QiskitTestCase): From 5a62063ff7399710befb77a7f2c40ebc4f77d98c Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Tue, 21 Jul 2020 12:54:19 -0400 Subject: [PATCH 32/38] typeo --- test/python/circuit/test_controlled_gate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 30e8e81d5306..81ca0503409a 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -588,7 +588,7 @@ def test_inverse_gate(self, num_ctrl_qubits): gate = qc.to_gate() cgate = gate.control(num_ctrl_qubits) import qiskit.circuit.add_control as add_control - cgate2 = add_control.control2(gate, num_ctrl_qubits=num_ctrl_qubits) + cgate2 = add_control.control(gate, num_ctrl_qubits=num_ctrl_qubits) inv_cgate2 = cgate2.inverse() inv_cgate = cgate.inverse() result = Operator(cgate).compose(Operator(inv_cgate)) From 9c3a6132c1e8a2b6b8532497c38b23dbfdec0b50 Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Tue, 21 Jul 2020 21:56:42 -0400 Subject: [PATCH 33/38] linting --- qiskit/circuit/add_control.py | 230 +++++--------------- qiskit/circuit/quantumcircuit.py | 123 +---------- qiskit/converters/circuit_to_gate.py | 5 - qiskit/converters/circuit_to_instruction.py | 4 - qiskit/quantum_info/operators/operator.py | 16 +- qiskit/quantum_info/states/statevector.py | 2 + test/python/circuit/test_controlled_gate.py | 23 +- 7 files changed, 83 insertions(+), 320 deletions(-) diff --git a/qiskit/circuit/add_control.py b/qiskit/circuit/add_control.py index 977bf0ef2fb2..158c47260574 100644 --- a/qiskit/circuit/add_control.py +++ b/qiskit/circuit/add_control.py @@ -66,7 +66,7 @@ def add_control(operation: Union[Gate, ControlledGate], if isinstance(operation, UnitaryGate): # attempt decomposition operation._define() - cgate = control2(operation, num_ctrl_qubits=num_ctrl_qubits, label=label, ctrl_state=ctrl_state) + cgate = control(operation, num_ctrl_qubits=num_ctrl_qubits, label=label, ctrl_state=ctrl_state) cgate.base_gate.label = operation.label return cgate @@ -99,189 +99,75 @@ def control(operation: Union[Gate, ControlledGate], from math import pi # pylint: disable=cyclic-import import qiskit.circuit.controlledgate as controlledgate - # pylint: disable=unused-import - import qiskit.circuit.library.standard_gates.multi_control_rotation_gates q_control = QuantumRegister(num_ctrl_qubits, name='control') q_target = QuantumRegister(operation.num_qubits, name='target') q_ancillae = None # TODO: add - qc = QuantumCircuit(q_control, q_target) - + controlled_circ = QuantumCircuit(q_control, q_target, + name='c_{}'.format(operation.name)) + global_phase = 0 if operation.name == 'x' or ( isinstance(operation, controlledgate.ControlledGate) and operation.base_gate.name == 'x'): - qc.mct(q_control[:] + q_target[:-1], q_target[-1], q_ancillae) - elif operation.name == 'rx': - qc.mcrx(operation.definition.data[0][0].params[0], q_control, q_target[0], - use_basis_gates=True) - elif operation.name == 'ry': - qc.mcry(operation.definition.data[0][0].params[0], q_control, q_target[0], - q_ancillae, mode='noancilla', use_basis_gates=True) - elif operation.name == 'rz': - qc.mcrz(operation.definition.data[0][0].params[0], q_control, q_target[0], - use_basis_gates=True) + controlled_circ.mct(q_control[:] + q_target[:-1], q_target[-1], q_ancillae) + if operation.definition is not None and operation.definition.phase: + global_phase += operation.definition.phase else: - bgate = _unroll_gate(operation, ['u1', 'u3', 'cx'], qc, q_control) - # now we have a bunch of single qubit rotation gates and cx - for rule in bgate.definition.data: - if rule[0].name == 'u3': - theta, phi, lamb = rule[0].params + basis = ['u1', 'u3', 'x', 'rx', 'ry', 'rz', 'cx'] + unrolled_gate = _unroll_gate(operation, basis_gates=basis) + for gate, qreg, _ in unrolled_gate.definition.data: + if gate.name == 'x': + controlled_circ.mct(q_control, q_target[qreg[0].index], + q_ancillae) + elif gate.name == 'rx': + controlled_circ.mcrx(gate.definition.data[0][0].params[0], + q_control, q_target[qreg[0].index], + use_basis_gates=True) + elif gate.name == 'ry': + controlled_circ.mcry(gate.definition.data[0][0].params[0], + q_control, q_target[qreg[0].index], + q_ancillae, mode='noancilla', + use_basis_gates=True) + elif gate.name == 'rz': + controlled_circ.mcrz(gate.definition.data[0][0].params[0], + q_control, q_target[qreg[0].index], + use_basis_gates=True) + elif gate.name == 'u1': + controlled_circ.mcu1(gate.params[0], q_control, q_target[qreg[0].index]) + elif gate.name == 'cx': + controlled_circ.mct(q_control[:] + [q_target[qreg[0].index]], + q_target[qreg[1].index], + q_ancillae) + elif gate.name == 'u3': + theta, phi, lamb = gate.params if phi == -pi / 2 and lamb == pi / 2: - qc.mcrx(theta, q_control, q_target[rule[1][0].index], - use_basis_gates=True) + controlled_circ.mcrx(theta, q_control, q_target[qreg[0].index], + use_basis_gates=True) elif phi == 0 and lamb == 0: - qc.mcry(theta, q_control, q_target[rule[1][0].index], - q_ancillae, use_basis_gates=True) + controlled_circ.mcry(theta, q_control, q_target[qreg[0].index], + q_ancillae, use_basis_gates=True) elif theta == 0 and phi == 0: - qc.mcrz(lamb, q_control, q_target[rule[1][0].index], - use_basis_gates=True) + controlled_circ.mcrz(lamb, q_control, q_target[qreg[0].index], + use_basis_gates=True) else: - qc.mcrz(lamb, q_control, q_target[rule[1][0].index], - use_basis_gates=True) - qc.mcry(theta, q_control, q_target[rule[1][0].index], - q_ancillae, use_basis_gates=True) - qc.mcrz(phi, q_control, q_target[rule[1][0].index], - use_basis_gates=True) - elif rule[0].name == 'u1': - qc.mcu1(rule[0].params[0], q_control, q_target[rule[1][0].index]) - elif rule[0].name == 'cx': - qc.mct(q_control[:] + [q_target[rule[1][0].index]], q_target[rule[1][1].index], - q_ancillae) - elif rule[0].name == 'x': - # hack to catch unrolling with global phase - qc.mct(q_control, q_target[rule[1][0].index]) + controlled_circ.mcrz(lamb, q_control, q_target[qreg[0].index], + use_basis_gates=True) + controlled_circ.mcry(theta, q_control, q_target[qreg[0].index], + q_ancillae, use_basis_gates=True) + controlled_circ.mcrz(phi, q_control, q_target[qreg[0].index], + use_basis_gates=True) else: raise CircuitError('gate contains non-controllable instructions: {}'.format( - rule[0].name)) - - if isinstance(operation, controlledgate.ControlledGate): - new_num_ctrl_qubits = num_ctrl_qubits + operation.num_ctrl_qubits - new_ctrl_state = operation.ctrl_state << num_ctrl_qubits | ctrl_state - base_name = operation.base_gate.name - base_gate = operation.base_gate - else: - new_num_ctrl_qubits = num_ctrl_qubits - new_ctrl_state = ctrl_state - base_name = operation.name - base_gate = operation - # In order to maintain some backward compatibility with gate names this - # uses a naming convention where if the number of controls is <=2 the gate - # is named like "cc", else it is named like - # "c". - if new_num_ctrl_qubits > 2: - ctrl_substr = 'c{0:d}'.format(new_num_ctrl_qubits) - else: - ctrl_substr = ('{0}' * new_num_ctrl_qubits).format('c') - new_name = '{0}{1}'.format(ctrl_substr, base_name) - cgate = controlledgate.ControlledGate(new_name, - qc.num_qubits, - operation.params, - label=label, - num_ctrl_qubits=new_num_ctrl_qubits, - definition=qc, - ctrl_state=new_ctrl_state) - cgate.base_gate = base_gate - return cgate - -def control2(operation: Union[Gate, ControlledGate], - num_ctrl_qubits: Optional[int] = 1, - label: Optional[Union[None, str]] = None, - ctrl_state: Optional[Union[None, int, str]] = None) -> ControlledGate: - """Return controlled version of gate using controlled rotations. This function - first checks the name of the operation to see if it knows of a method from which - to generate a controlled version. Currently these are `x`, `rx`, `ry`, and `rz`. - If a method is not directly known, it calls the unroller to convert to `u1`, `u3`, - and `cx` gates. - - Args: - operation: The gate used to create the ControlledGate. - num_ctrl_qubits: The number of controls to add to gate (default=1). - label: An optional gate label. - ctrl_state: The control state in decimal or as - a bitstring (e.g. '111'). If specified as a bitstring the length - must equal num_ctrl_qubits, MSB on left. If None, use - 2**num_ctrl_qubits-1. - - Returns: - Controlled version of gate. - - Raises: - CircuitError: gate contains non-gate in definition - """ - from math import pi - # pylint: disable=cyclic-import - import qiskit.circuit.controlledgate as controlledgate - basis = ['u1', 'u3', 'x', 'rx', 'ry', 'rz', 'cx'] - unrolled_gate = _unroll_gate(operation, basis_gates=basis) - - q_control = QuantumRegister(num_ctrl_qubits, name='control') - q_target = QuantumRegister(operation.num_qubits, name='target') - q_ancillae = None # TODO: add - controlled_circ = QuantumCircuit(q_control, q_target, - name='c_{}'.format(operation.name)) - # if ctrl_state: - # ctrl_state_circ = QuantumCircuit(q_control) - # bit_ctrl_state = bin(ctrl_state)[2:].zfill(num_ctrl_qubits) - # for qind, val in enumerate(bit_ctrl_state[::-1]): - # if val == '0': - # control_state_circ.x(qind) - # controlled_circ.compose(ctrl_state_circ, q_control) - global_phase = 0 - for gate, qreg, creg in unrolled_gate.definition.data: - if gate.name == 'x' or ( - isinstance(gate, controlledgate.ControlledGate) and - gate.base_gate.name == 'x'): - controlled_circ.mct(q_control[:] + q_target[:-1], q_target[-1], - q_ancillae) - elif gate.name == 'rx': - controlled_circ.mcrx(gate.definition.data[0][0].params[0], - q_control, q_target[qreg[0].index], - use_basis_gates=True) - elif gate.name == 'ry': - controlled_circ.mcry(gate.definition.data[0][0].params[0], - q_control, q_target[qreg[0].index], - q_ancillae, mode='noancilla', - use_basis_gates=True) - elif gate.name == 'rz': - controlled_circ.mcrz(gate.definition.data[0][0].params[0], - q_control, q_target[qreg[0].index], - use_basis_gates=True) - elif gate.name == 'u1': - controlled_circ.mcu1(gate.params[0], q_control, q_target[qreg[0].index]) - elif gate.name == 'cx': - controlled_circ.mct(q_control[:] + [q_target[qreg[0].index]], q_target[qreg[1].index], - q_ancillae) - elif gate.name == 'u3': - theta, phi, lamb = gate.params - if phi == -pi / 2 and lamb == pi / 2: - controlled_circ.mcrx(theta, q_control, q_target[qreg[0].index], - use_basis_gates=True) - elif phi == 0 and lamb == 0: - controlled_circ.mcry(theta, q_control, q_target[qreg[0].index], - q_ancillae, use_basis_gates=True) - elif theta == 0 and phi == 0: - controlled_circ.mcrz(lamb, q_control, q_target[qreg[0].index], - use_basis_gates=True) - else: - controlled_circ.mcrz(lamb, q_control, q_target[qreg[0].index], - use_basis_gates=True) - controlled_circ.mcry(theta, q_control, q_target[qreg[0].index], - q_ancillae, use_basis_gates=True) - controlled_circ.mcrz(phi, q_control, q_target[qreg[0].index], - use_basis_gates=True) - else: - raise CircuitError('gate contains non-controllable instructions: {}'.format( - gate.name)) - if gate.definition is not None and gate.definition.phase: - global_phase += gate.definition.phase - # if ctrl_state: - # controlled_circ.compose(ctrl_state_circ, q_control) - # apply global phase - if ((unrolled_gate.definition is not None and unrolled_gate.definition.phase) or global_phase): + gate.name)) + if gate.definition is not None and gate.definition.phase: + global_phase += gate.definition.phase + # apply controlled global phase + if ((operation.definition is not None and operation.definition.phase) or global_phase): if len(q_control) < 2: - controlled_circ.u1(unrolled_gate.definition.phase + global_phase, q_control) + controlled_circ.u1(operation.definition.phase + global_phase, q_control) else: - controlled_circ.mcu1(unrolled_gate.definition.phase + global_phase, q_control[:-1], q_control[-1]) + controlled_circ.mcu1(operation.definition.phase + global_phase, + q_control[:-1], q_control[-1]) if isinstance(operation, controlledgate.ControlledGate): new_num_ctrl_qubits = num_ctrl_qubits + operation.num_ctrl_qubits new_ctrl_state = operation.ctrl_state << num_ctrl_qubits | ctrl_state @@ -336,16 +222,10 @@ def _gate_to_dag(operation): return circuit_to_dag(qc) -def _unroll_gate(operation, basis_gates, qc=None, q_control=None): +def _unroll_gate(operation, basis_gates): from qiskit.converters.dag_to_circuit import dag_to_circuit from qiskit.transpiler.passes import Unroller unroller = Unroller(basis_gates) dag = _gate_to_dag(operation) opqc = dag_to_circuit(unroller.run(dag)) - # if opqc.phase and qc is not None and q_control is not None: - # if len(q_control) < 2: - # qc.u1(opqc.phase, q_control) - # else: - # qc.mcu1(opqc.phase, q_control[:-1], q_control[-1]) - # qc.phase = 0 return opqc.to_gate() diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index 5327c3cab863..09ea9198191f 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -392,36 +392,6 @@ def repeat(self, reps): return repeated_circ - # def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): - # """Control this circuit on ``num_ctrl_qubits`` qubits. - - # Args: - # num_ctrl_qubits (int): The number of control qubits. - # label (str): An optional label to give the controlled operation for visualization. - # ctrl_state (str or int): The control state in decimal or as a bitstring - # (e.g. '111'). If None, use ``2**num_ctrl_qubits - 1``. - - # Returns: - # QuantumCircuit: The controlled version of this circuit. - - # Raises: - # CircuitError: If the circuit contains a non-unitary operation and cannot be controlled. - # """ - # try: - # gate = self.to_gate() - # except QiskitError: - # raise CircuitError('The circuit contains non-unitary operations and cannot be ' - # 'controlled. Note that no qiskit.circuit.Instruction objects may ' - # 'be in the circuit for this operation.') - - # controlled_gate = gate.control(num_ctrl_qubits, label, ctrl_state) - # control_qreg = QuantumRegister(num_ctrl_qubits) - # controlled_circ = QuantumCircuit(control_qreg, *self.qregs, - # name='c_{}'.format(self.name)) - # controlled_circ.append(controlled_gate, controlled_circ.qubits) - - # return controlled_circ - def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """Control this circuit on ``num_ctrl_qubits`` qubits. @@ -437,88 +407,19 @@ def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): Raises: CircuitError: If the circuit contains a non-unitary operation and cannot be controlled. """ - from math import pi - # pylint: disable=cyclic-import - import qiskit.circuit.controlledgate as controlledgate - - from qiskit.converters import dag_to_circuit, circuit_to_dag - from qiskit.transpiler.passes import Unroller - unroller = Unroller(['u1', 'u3', 'x', 'rx', 'ry', 'rz', 'cx']) - dag = circuit_to_dag(self) - unrolled_circ = dag_to_circuit(unroller.run(dag)) - - q_control = QuantumRegister(num_ctrl_qubits, name='control') - q_target = QuantumRegister(self.num_qubits, name='target') - q_ancillae = None # TODO: add - controlled_circ = QuantumCircuit(q_control, q_target, + try: + gate = self.to_gate() + except QiskitError: + raise CircuitError('The circuit contains non-unitary operations and cannot be ' + 'controlled. Note that no qiskit.circuit.Instruction objects may ' + 'be in the circuit for this operation.') + + controlled_gate = gate.control(num_ctrl_qubits, label, ctrl_state) + control_qreg = QuantumRegister(num_ctrl_qubits) + controlled_circ = QuantumCircuit(control_qreg, *self.qregs, name='c_{}'.format(self.name)) - has_open_ctrl = False - if ctrl_state is not None: - has_open_ctrl = ctrl_state < 2**num_ctrl_qubits - 1 - if has_open_ctrl: - ctrl_state_circ = QuantumCircuit(q_control) - bit_ctrl_state = bin(ctrl_state)[2:].zfill(num_ctrl_qubits) - for qind, val in enumerate(bit_ctrl_state[::-1]): - if val == '0': - ctrl_state_circ.x(qind) - controlled_circ.compose(ctrl_state_circ, q_control, inplace=True) - global_phase = 0 - for operation, qreg, creg in unrolled_circ.data: - if operation.name == 'x' or ( - isinstance(operation, controlledgate.ControlledGate) and - operation.base_gate.name == 'x'): - controlled_circ.mct(q_control[:] + q_target[:-1], q_target[-1], - q_ancillae) - elif operation.name == 'rx': - controlled_circ.mcrx(operation.definition.data[0][0].params[0], - q_control, q_target[qreg[0].index], - use_basis_gates=True) - elif operation.name == 'ry': - controlled_circ.mcry(operation.definition.data[0][0].params[0], - q_control, q_target[qreg[0].index], - q_ancillae, mode='noancilla', - use_basis_gates=True) - elif operation.name == 'rz': - controlled_circ.mcrz(operation.definition.data[0][0].params[0], - q_control, q_target[qreg[0].index], - use_basis_gates=True) - elif operation.name == 'u1': - controlled_circ.mcu1(operation.params[0], q_control, q_target[qreg[0].index]) - elif operation.name == 'cx': - controlled_circ.mct(q_control[:] + [q_target[qreg[0].index]], q_target[qreg[1].index], - q_ancillae) - elif operation.name == 'u3': - theta, phi, lamb = operation.params - if phi == -pi / 2 and lamb == pi / 2: - controlled_circ.mcrx(theta, q_control, q_target[qreg[0].index], - use_basis_gates=True) - elif phi == 0 and lamb == 0: - controlled_circ.mcry(theta, q_control, q_target[qreg[0].index], - q_ancillae, use_basis_gates=True) - elif theta == 0 and phi == 0: - controlled_circ.mcrz(lamb, q_control, q_target[qreg[0].index], - use_basis_gates=True) - else: - controlled_circ.mcrz(lamb, q_control, q_target[qreg[0].index], - use_basis_gates=True) - controlled_circ.mcry(theta, q_control, q_target[qreg[0].index], - q_ancillae, use_basis_gates=True) - controlled_circ.mcrz(phi, q_control, q_target[qreg[0].index], - use_basis_gates=True) - else: - raise CircuitError('gate contains non-controllable instructions: {}'.format( - operation.name)) - if operation.definition is not None and operation.definition.phase: - global_phase += operation.definition.phase - if has_open_ctrl: - controlled_circ.compose(ctrl_state_circ, q_control, inplace=True) - if self.phase or global_phase: - if len(q_control) < 2: - controlled_circ.u1(self.phase + global_phase, q_control) - else: - controlled_circ.mcu1(self.phase + global_phase, q_control[:-1], - q_control[-1]) - + controlled_circ.append(controlled_gate, controlled_circ.qubits) + return controlled_circ def combine(self, rhs): diff --git a/qiskit/converters/circuit_to_gate.py b/qiskit/converters/circuit_to_gate.py index 96a4121e2d45..0e825fcd3a3a 100644 --- a/qiskit/converters/circuit_to_gate.py +++ b/qiskit/converters/circuit_to_gate.py @@ -14,7 +14,6 @@ """Helper function for converting a circuit to a gate""" -from math import pi from qiskit.circuit.gate import Gate from qiskit.circuit.quantumregister import QuantumRegister, Qubit from qiskit.exceptions import QiskitError @@ -91,10 +90,6 @@ def find_bit_position(bit): equivalence_library.add_equivalence(gate, target) rules = target.data - # if target.phase: - # target.u3(pi, target.phase, target.phase - pi, target.qregs[0][0]) - # target.x(target.qregs[0][0]) - # target.phase = 0 if gate.num_qubits > 0: q = QuantumRegister(gate.num_qubits, 'q') diff --git a/qiskit/converters/circuit_to_instruction.py b/qiskit/converters/circuit_to_instruction.py index 946bf7516aa2..b3281350d86b 100644 --- a/qiskit/converters/circuit_to_instruction.py +++ b/qiskit/converters/circuit_to_instruction.py @@ -14,7 +14,6 @@ """Helper function for converting a circuit to an instruction.""" -from math import pi from qiskit.exceptions import QiskitError from qiskit.circuit.instruction import Instruction from qiskit.circuit.quantumregister import QuantumRegister, Qubit @@ -127,9 +126,6 @@ def find_bit_position(bit): qc.data = definition if circuit.phase: qc.phase = circuit.phase - # if circuit.phase: - # qc.u3(pi, circuit.phase, circuit.phase - pi, qc.qregs[0][0]) - # qc.x(qc.qregs[0][0]) instruction.definition = qc diff --git a/qiskit/quantum_info/operators/operator.py b/qiskit/quantum_info/operators/operator.py index 50164629c0c9..4eb65a535d9a 100644 --- a/qiskit/quantum_info/operators/operator.py +++ b/qiskit/quantum_info/operators/operator.py @@ -485,18 +485,14 @@ def _einsum_matmul(cls, tensor, mat, indices, shift=0, right_mul=False): @classmethod def _init_instruction(cls, instruction): """Convert a QuantumCircuit or Instruction to an Operator.""" - from .scalar_op import ScalarOp # Initialize an identity operator of the correct size of the circuit dimension = 2 ** instruction.num_qubits op = Operator(np.eye(dimension)) # Convert circuit to an instruction if isinstance(instruction, QuantumCircuit): - if instruction.phase: - op *= ScalarOp(dimension, np.exp(1j * instruction.phase)) + # if instruction.phase: + # op *= ScalarOp(dimension, np.exp(1j * float(instruction.phase))) instruction = instruction.to_instruction() - elif isinstance(instruction, Instruction): - if instruction.definition is not None and instruction.definition.phase: - op *= ScalarOp(dimension, np.exp(1j * instruction.definition.phase)) op._append_instruction(instruction) return op @@ -518,6 +514,7 @@ def _instruction_to_matrix(cls, obj): def _append_instruction(self, obj, qargs=None): """Update the current Operator by apply an instruction.""" from qiskit.circuit.barrier import Barrier + from .scalar_op import ScalarOp mat = self._instruction_to_matrix(obj) if mat is not None: @@ -537,9 +534,12 @@ def _append_instruction(self, obj, qargs=None): raise QiskitError('Instruction "{}" ' 'definition is {} but expected QuantumCircuit.'.format( obj.name, type(obj.definition))) + if obj.definition.phase: + dimension = 2 ** self.num_qubits + op = self.compose(ScalarOp(dimension, np.exp(1j * float(obj.definition.phase))), + qargs=qargs) + self._data = op.data flat_instr = obj.definition.to_instruction() - # if flat_instr.definition is not None and flat_instr.definition.phase: - # import ipdb; ipdb.set_trace() for instr, qregs, cregs in flat_instr.definition.data: if cregs: raise QiskitError( diff --git a/qiskit/quantum_info/states/statevector.py b/qiskit/quantum_info/states/statevector.py index 8503c1f5450a..6158a1a3ade0 100644 --- a/qiskit/quantum_info/states/statevector.py +++ b/qiskit/quantum_info/states/statevector.py @@ -620,6 +620,8 @@ def _append_instruction(self, obj, qargs=None): if not isinstance(obj.definition, QuantumCircuit): raise QiskitError('{0} instruction definition is {1}; expected QuantumCircuit'.format( obj.name, type(obj.definition))) + if obj.definition.phase: + self._data *= np.exp(1j * obj.definition.phase) for instr, qregs, cregs in obj.definition.data: if cregs: raise QiskitError( diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 81ca0503409a..e6bda811482e 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -587,14 +587,8 @@ def test_inverse_gate(self, num_ctrl_qubits): qc.rx(np.pi / 4, [0, 1, 2]) gate = qc.to_gate() cgate = gate.control(num_ctrl_qubits) - import qiskit.circuit.add_control as add_control - cgate2 = add_control.control(gate, num_ctrl_qubits=num_ctrl_qubits) - inv_cgate2 = cgate2.inverse() inv_cgate = cgate.inverse() result = Operator(cgate).compose(Operator(inv_cgate)) - np.set_printoptions(precision=2, linewidth=250, suppress=True) - import ipdb; ipdb.set_trace() - np.testing.assert_array_almost_equal(result.data, np.identity(result.dim[0])) @data(1, 2, 3) @@ -605,13 +599,11 @@ def test_inverse_circuit(self, num_ctrl_qubits): qc.cx(0, 1) qc.cx(1, 2) qc.rx(np.pi / 4, [0, 1, 2]) - qc_inv = qc.inverse() - result = Operator(qc).compose(Operator(qc_inv)) - np.set_printoptions(precision=2, linewidth=250, suppress=True) - #import ipdb; ipdb.set_trace() - + cqc = qc.control(num_ctrl_qubits) + cqc_inv = cqc.inverse() + result = Operator(cqc).compose(Operator(cqc_inv)) np.testing.assert_array_almost_equal(result.data, np.identity(result.dim[0])) - + @data(1, 2, 3, 4, 5) def test_controlled_unitary(self, num_ctrl_qubits): """Test the matrix data of an Operator, which is based on a controlled gate.""" @@ -745,11 +737,9 @@ def test_open_control_composite_unrolling(self): qcomp.h(qreg[0]) qcomp.cx(qreg[0], qreg[1]) bell = qcomp.to_gate() - cbell2 = qcomp.control(ctrl_state=0) # create controlled composite gate cqreg = QuantumRegister(3) qc = QuantumCircuit(cqreg) - cbell = bell.control(ctrl_state=0) qc.append(bell.control(ctrl_state=0), qc.qregs[0][:]) dag = circuit_to_dag(qc) unroller = Unroller(['x', 'u1', 'cbell']) @@ -933,14 +923,13 @@ def test_controlled_global_phase(self, num_ctrl_qubits): """ theta = pi/4 circ = QuantumCircuit(2, phase=theta) - dag = circuit_to_dag(circ) base_gate = circ.to_gate() base_mat = Operator(base_gate).data target = _compute_control_matrix(base_mat, num_ctrl_qubits) cgate = base_gate.control(num_ctrl_qubits) ccirc = circ.control(num_ctrl_qubits) self.assertEqual(Operator(cgate), Operator(target)) - self.assertEqual(Operator(ccirc), Operator(target)) + self.assertEqual(Operator(ccirc), Operator(target)) @data(1, 2) def test_rz_composite_global_phase(self, num_ctrl_qubits): @@ -957,7 +946,7 @@ def test_rz_composite_global_phase(self, num_ctrl_qubits): base_mat = Operator(base_gate).data target = _compute_control_matrix(base_mat, num_ctrl_qubits) self.assertEqual(Operator(cgate), Operator(target)) - self.assertEqual(Operator(ccirc), Operator(target)) + self.assertEqual(Operator(ccirc), Operator(target)) @ddt class TestOpenControlledToMatrix(QiskitTestCase): From 3e5532b567921fb5a8f77a8db8c1542a0a9e1d8c Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Wed, 22 Jul 2020 00:10:47 -0400 Subject: [PATCH 34/38] linting --- qiskit/circuit/add_control.py | 1 + qiskit/circuit/quantumcircuit.py | 8 ++++++-- qiskit/quantum_info/operators/operator.py | 5 +++-- qiskit/quantum_info/states/statevector.py | 2 +- test/python/circuit/test_compose.py | 3 ++- test/python/circuit/test_controlled_gate.py | 1 + 6 files changed, 14 insertions(+), 6 deletions(-) diff --git a/qiskit/circuit/add_control.py b/qiskit/circuit/add_control.py index 68d41bc3ea1b..43e2b8e7c816 100644 --- a/qiskit/circuit/add_control.py +++ b/qiskit/circuit/add_control.py @@ -197,6 +197,7 @@ def control(operation: Union[Gate, ControlledGate], cgate.base_gate = base_gate return cgate + def _gate_to_circuit(operation): qr = QuantumRegister(operation.num_qubits) qc = QuantumCircuit(qr, name=operation.name) diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index 784295b7c08c..3c477b8fc94c 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -645,6 +645,8 @@ def compose(self, other, qubits=None, clbits=None, front=False, inplace=False): else: dest._data += mapped_instrs + dest.global_phase += other.global_phase + if inplace: return None @@ -1853,7 +1855,8 @@ def _bind_parameter(self, parameter, value): # parameter which also need to be bound. self._rebind_definition(instr, parameter, value) # bind circuit's phase - if isinstance(self.global_phase, ParameterExpression) and parameter in self.global_phase.parameters: + if (isinstance(self.global_phase, ParameterExpression) and + parameter in self.global_phase.parameters): self.global_phase = self.global_phase.bind({parameter: value}) def _substitute_parameter(self, old_parameter, new_parameter_expr): @@ -1866,7 +1869,8 @@ def _substitute_parameter(self, old_parameter, new_parameter_expr): entry = self._parameter_table.pop(old_parameter) for new_parameter in new_parameter_expr.parameters: self._parameter_table[new_parameter] = entry - if isinstance(self.global_phase, ParameterExpression) and old_parameter in self.global_phase.parameters: + if (isinstance(self.global_phase, ParameterExpression) + and old_parameter in self.global_phase.parameters): self.global_phase = self.global_phase.subs({old_parameter: new_parameter_expr}) def _rebind_definition(self, instruction, parameter, value): diff --git a/qiskit/quantum_info/operators/operator.py b/qiskit/quantum_info/operators/operator.py index 1a6bf0765ff0..495b9561200e 100644 --- a/qiskit/quantum_info/operators/operator.py +++ b/qiskit/quantum_info/operators/operator.py @@ -534,8 +534,9 @@ def _append_instruction(self, obj, qargs=None): obj.name, type(obj.definition))) if obj.definition.global_phase: dimension = 2 ** self.num_qubits - op = self.compose(ScalarOp(dimension, np.exp(1j * float(obj.definition.global_phase))), - qargs=qargs) + op = self.compose( + ScalarOp(dimension, np.exp(1j * float(obj.definition.global_phase))), + qargs=qargs) self._data = op.data flat_instr = obj.definition.to_instruction() for instr, qregs, cregs in flat_instr.definition.data: diff --git a/qiskit/quantum_info/states/statevector.py b/qiskit/quantum_info/states/statevector.py index b54f21af9973..4e1b6bacc0fb 100644 --- a/qiskit/quantum_info/states/statevector.py +++ b/qiskit/quantum_info/states/statevector.py @@ -678,7 +678,7 @@ def _evolve_instruction(statevec, obj, qargs=None): raise QiskitError('{0} instruction definition is {1}; expected QuantumCircuit'.format( obj.name, type(obj.definition))) if obj.definition.global_phase: - self._data *= np.exp(1j * obj.definition.global_phase) + statevec._data *= np.exp(1j * obj.definition.global_phase) for instr, qregs, cregs in obj.definition: if cregs: raise QiskitError( diff --git a/test/python/circuit/test_compose.py b/test/python/circuit/test_compose.py index 8efee61d22cf..7818b0b0c63b 100644 --- a/test/python/circuit/test_compose.py +++ b/test/python/circuit/test_compose.py @@ -458,7 +458,8 @@ def test_compose_global_phase(self): circ2 = QuantumCircuit(1, global_phase=2) circ3 = QuantumCircuit(1, global_phase=3) circ4 = circ1.compose(circ2).compose(circ3) - self.assertEqual(circ4.global_phase, circ1.global_phase + circ2.global_phase + circ3.global_phase) + self.assertEqual(circ4.global_phase, + circ1.global_phase + circ2.global_phase + circ3.global_phase) def test_compose_front_circuit(self): """Test composing a circuit at the front of a circuit. diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index b810803ba57f..57ab8040b795 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -948,6 +948,7 @@ def test_rz_composite_global_phase(self, num_ctrl_qubits): self.assertEqual(Operator(cgate), Operator(target)) self.assertEqual(Operator(ccirc), Operator(target)) + @ddt class TestOpenControlledToMatrix(QiskitTestCase): """Test controlled_gates implementing to_matrix work with ctrl_state""" From b1b746d4cb9afa6f8a03f407ee6e90641886534b Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Wed, 22 Jul 2020 00:58:40 -0400 Subject: [PATCH 35/38] update cx_global_phase test --- test/python/circuit/test_controlled_gate.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index 57ab8040b795..f17ce5bc0e35 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -913,9 +913,13 @@ def test_cx_global_phase(self): ccx = cx.control(1) base_mat = Operator(cx).data target = _compute_control_matrix(base_mat, 1) - self.assertEqual(Operator(ccx), Operator(target)) + expected = QuantumCircuit(*ccx.definition.qregs) + expected.ccx(0, 1, 2) + expected.u1(theta, 0) + self.assertEqual(ccx.definition, expected) + @data(1, 2) def test_controlled_global_phase(self, num_ctrl_qubits): """ From 96b224011c70d76cc7d206967539ba6ce18a74c2 Mon Sep 17 00:00:00 2001 From: Erick Winston Date: Thu, 23 Jul 2020 10:17:05 -0400 Subject: [PATCH 36/38] minor linting --- qiskit/circuit/quantumcircuit.py | 1 - 1 file changed, 1 deletion(-) diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index 9990b7961634..e63d96afca19 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -653,7 +653,6 @@ def compose(self, other, qubits=None, clbits=None, front=False, inplace=False): dest.global_phase += other.global_phase - if inplace: return None From 5ca9f3be403359d8b38939b7426e28162c3367a3 Mon Sep 17 00:00:00 2001 From: Ali Javadi-Abhari Date: Thu, 23 Jul 2020 17:13:34 -0400 Subject: [PATCH 37/38] Update releasenotes/notes/add_quantumcircuit_phase-5006d1e930348d2e.yaml --- .../notes/add_quantumcircuit_phase-5006d1e930348d2e.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/releasenotes/notes/add_quantumcircuit_phase-5006d1e930348d2e.yaml b/releasenotes/notes/add_quantumcircuit_phase-5006d1e930348d2e.yaml index 7532f1b07501..8da00355c82e 100644 --- a/releasenotes/notes/add_quantumcircuit_phase-5006d1e930348d2e.yaml +++ b/releasenotes/notes/add_quantumcircuit_phase-5006d1e930348d2e.yaml @@ -1,6 +1,6 @@ features: - | - Adds a `phase` attribute to `QuantumCircuit` for tracking global + Adds a `global_phase` attribute to `QuantumCircuit` for tracking global phase. This allows, for instance, to have the `to_matrix` method of a gate to exactly correspond to its decompositions instead of just up to a global phase. The same attribute has also been @@ -14,4 +14,4 @@ features: The global phase may also be set or queried with the `circ.phase` property. In either case the setting is in radians. If the circuit is converted to an instruction or gate the global phase is - represented by two single qubit rotations on the first qubit. \ No newline at end of file + represented by two single qubit rotations on the first qubit. From 79779b7be34a8d42f4b305284a45172d96b00e3c Mon Sep 17 00:00:00 2001 From: Ali Javadi-Abhari Date: Thu, 23 Jul 2020 17:13:42 -0400 Subject: [PATCH 38/38] Update releasenotes/notes/add_quantumcircuit_phase-5006d1e930348d2e.yaml --- .../notes/add_quantumcircuit_phase-5006d1e930348d2e.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/releasenotes/notes/add_quantumcircuit_phase-5006d1e930348d2e.yaml b/releasenotes/notes/add_quantumcircuit_phase-5006d1e930348d2e.yaml index 8da00355c82e..255913a55734 100644 --- a/releasenotes/notes/add_quantumcircuit_phase-5006d1e930348d2e.yaml +++ b/releasenotes/notes/add_quantumcircuit_phase-5006d1e930348d2e.yaml @@ -11,7 +11,7 @@ features: circ = QuantumCircuit(1, phase=math.pi) circ.u1(0) - The global phase may also be set or queried with the `circ.phase` + The global phase may also be set or queried with the `circ.global_phase` property. In either case the setting is in radians. If the circuit is converted to an instruction or gate the global phase is represented by two single qubit rotations on the first qubit.