def test_pass_cx_cancellation_own_template(self): """ Check the cancellation of CX gates for the apply of a self made template cx-cx. """ qr = QuantumRegister(2, 'qr') circuit_in = QuantumCircuit(qr) circuit_in.h(qr[0]) circuit_in.h(qr[0]) circuit_in.cx(qr[0], qr[1]) circuit_in.cx(qr[0], qr[1]) circuit_in.cx(qr[0], qr[1]) circuit_in.cx(qr[0], qr[1]) circuit_in.cx(qr[1], qr[0]) circuit_in.cx(qr[1], qr[0]) dag_in = circuit_to_dag(circuit_in) qrt = QuantumRegister(2, 'qrc') qct = QuantumCircuit(qrt) qct.cx(0, 1) qct.cx(0, 1) template_list = [qct] pass_ = TemplateOptimization(template_list) dag_opt = pass_.run(dag_in) circuit_expected = QuantumCircuit(qr) circuit_expected.h(qr[0]) circuit_expected.h(qr[0]) dag_expected = circuit_to_dag(circuit_expected) self.assertEqual(dag_opt, dag_expected)
def test_pass_cx_cancellation_template_from_library(self): """ Check the cancellation of CX gates for the apply of the library template cx-cx (2a_2). """ qr = QuantumRegister(2, 'qr') circuit_in = QuantumCircuit(qr) circuit_in.h(qr[0]) circuit_in.h(qr[0]) circuit_in.cx(qr[0], qr[1]) circuit_in.cx(qr[0], qr[1]) circuit_in.cx(qr[0], qr[1]) circuit_in.cx(qr[0], qr[1]) circuit_in.cx(qr[1], qr[0]) circuit_in.cx(qr[1], qr[0]) dag_in = circuit_to_dag(circuit_in) template_list = [template_nct_2a_2()] pass_ = TemplateOptimization(template_list) dag_opt = pass_.run(dag_in) circuit_expected = QuantumCircuit(qr) circuit_expected.h(qr[0]) circuit_expected.h(qr[0]) dag_expected = circuit_to_dag(circuit_expected) self.assertEqual(dag_opt, dag_expected)
def construct_circuit(self, measurement: bool = False) -> QuantumCircuit: """Construct circuit. Args: measurement: Boolean flag to indicate if measurement should be included in the circuit. Returns: Quantum circuit. """ # Get n value used in Shor's algorithm, to know how many qubits are used self._n = math.ceil(math.log(self._N, 2)) self._qft.num_qubits = self._n + 1 self._iqft.num_qubits = self._n + 1 self._qft_dag = circuit_to_dag(self._qft) self._iqft_dag = circuit_to_dag(self._iqft) # quantum register where the sequential QFT is performed self._up_qreg = QuantumRegister(2 * self._n, name='up') # quantum register where the multiplications are made self._down_qreg = QuantumRegister(self._n, name='down') # auxiliary quantum register used in addition and multiplication self._aux_qreg = QuantumRegister(self._n + 2, name='aux') # Create Quantum Circuit circuit = QuantumCircuit(self._up_qreg, self._down_qreg, self._aux_qreg) # Initialize down register to 1 and create maximal superposition in top register circuit.u2(0, np.pi, self._up_qreg) circuit.u3(np.pi, 0, np.pi, self._down_qreg[0]) tdags = [] dag_self = circuit_to_dag(circuit) # Apply the multiplication gates as showed in # the report in order to create the exponentiation for i in range(0, 2 * self._n): tdags += self._controlled_multiple_mod_N_tdags( self._up_qreg[i], self._down_qreg, self._aux_qreg, int(pow(self._a, pow(2, i)))) for tdag in tdags: dag_compose_with_tagged(dag_self, tdag) composed_circuit = dag_to_circuit(dag_self) circuit.__dict__.update(composed_circuit.__dict__) # Apply inverse QFT iqft = QFT(len(self._up_qreg), inverse=True) circuit.compose(iqft, qubits=self._up_qreg) if measurement: up_cqreg = ClassicalRegister(2 * self._n, name='m') circuit.add_register(up_cqreg) circuit.measure(self._up_qreg, up_cqreg) logger.info(summarize_circuits(circuit)) return circuit
def test_rotation_gates(self): """Test controlled rotation gates""" import qiskit.extensions.standard.u1 as u1 import qiskit.extensions.standard.rx as rx import qiskit.extensions.standard.ry as ry import qiskit.extensions.standard.rz as rz num_ctrl = 2 num_target = 1 qreg = QuantumRegister(num_ctrl + num_target) gu1 = u1.U1Gate(pi) grx = rx.RXGate(pi) gry = ry.RYGate(pi) grz = rz.RZGate(pi) ugu1 = ac._unroll_gate(gu1, ['u1', 'u3', 'cx']) ugrx = ac._unroll_gate(grx, ['u1', 'u3', 'cx']) ugry = ac._unroll_gate(gry, ['u1', 'u3', 'cx']) ugrz = ac._unroll_gate(grz, ['u1', 'u3', 'cx']) cgu1 = ugu1.q_if(num_ctrl) cgrx = ugrx.q_if(num_ctrl) cgry = ugry.q_if(num_ctrl) cgrz = ugrz.q_if(num_ctrl) simulator = BasicAer.get_backend('unitary_simulator') for gate, cgate in zip([gu1, grx, gry, grz], [cgu1, cgrx, cgry, cgrz]): with self.subTest(i=gate.name): qc = QuantumCircuit(num_target) qc.append(gate, qc.qregs[0]) op_mat = execute(qc, simulator).result().get_unitary(0) cqc = QuantumCircuit(num_ctrl + num_target) cqc.append(cgate, cqc.qregs[0]) ref_mat = execute(cqc, simulator).result().get_unitary(0) cop_mat = _compute_control_matrix(op_mat, num_ctrl) self.assertTrue( matrix_equal(cop_mat, ref_mat, ignore_phase=True)) dag = circuit_to_dag(cqc) unroller = Unroller(['u3', 'cx']) uqc = dag_to_circuit(unroller.run(dag)) self.log.info('%s gate count: %d', cgate.name, uqc.size()) self.log.info('\n%s', str(uqc)) # these limits could be changed if gate.name == 'ry': self.assertTrue(uqc.size() <= 32) else: self.assertTrue(uqc.size() <= 20) qc = QuantumCircuit(qreg, name='composite') qc.append(grx.q_if(num_ctrl), qreg) qc.append(gry.q_if(num_ctrl), qreg) qc.append(gry, qreg[0:gry.num_qubits]) qc.append(grz.q_if(num_ctrl), qreg) dag = circuit_to_dag(qc) unroller = Unroller(['u3', 'cx']) uqc = dag_to_circuit(unroller.run(dag)) self.log.info('%s gate count: %d', uqc.name, uqc.size()) self.assertTrue(uqc.size() <= 73) # this limit could be changed
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 assertEqualUnroll(self, basis, circuit, expected): """ Compares the dags after unrolling to basis """ circuit_dag = circuit_to_dag(circuit) expected_dag = circuit_to_dag(expected) circuit_result = Unroller(basis).run(circuit_dag) expected_result = Unroller(basis).run(expected_dag) self.assertEqual(circuit_result, expected_result)
def test_pass_template_wrong_type(self): """ If a template is not equivalent to the identity, it raises an error. """ qr = QuantumRegister(2, 'qr') circuit_in = QuantumCircuit(qr) circuit_in.h(qr[0]) circuit_in.h(qr[0]) circuit_in.cx(qr[0], qr[1]) circuit_in.cx(qr[0], qr[1]) circuit_in.cx(qr[0], qr[1]) circuit_in.cx(qr[0], qr[1]) circuit_in.cx(qr[1], qr[0]) circuit_in.cx(qr[1], qr[0]) dag_in = circuit_to_dag(circuit_in) qrt = QuantumRegister(2, 'qrc') qct = QuantumCircuit(qrt) qct.cx(0, 1) qct.x(0) qct.h(1) template_list = [qct] pass_ = TemplateOptimization(template_list) self.assertRaises(TranspilerError, pass_.run, dag_in)
def run(self, dag): """Run the Unroll3qOrMore pass on `dag`. Args: dag(DAGCircuit): input dag Returns: DAGCircuit: output dag with maximum node degrees of 2 Raises: QiskitError: if a 3q+ gate is not decomposable """ for node in dag.multi_qubit_ops(): # TODO: allow choosing other possible decompositions rule = node.op.definition.data if not rule: if rule == []: # empty node dag.remove_op_node(node) continue raise QiskitError( "Cannot unroll all 3q or more gates. " "No rule to expand instruction %s." % node.op.name ) decomposition = circuit_to_dag(node.op.definition) decomposition = self.run(decomposition) # recursively unroll dag.substitute_node_with_dag(node, decomposition) return dag
def test_transpile_2q_circuit(self): qr = QuantumRegister(2) cr = ClassicalRegister(4) circ = QuantumCircuit(qr, cr) circ.x(qr[0]) circ.measure(qr[0], cr[0]) circ.measure(qr[1], cr[1]) circ.barrier() circ.reset(qr[0]) circ.reset(qr[1]) circ.barrier() circ.y(qr[0]) dag = circuit_to_dag(circ) jcirc = CircuitBuilder() reg1 = jcirc.register("baseregister", 2) reg2 = jcirc.map(qr.name, reg1, slice(0, 2, 1)) block = jcirc.block() block.gate("prepare_all") block.gate("Px", reg2[0]) block.gate("measure_all") block = jcirc.block() block.gate("prepare_all") block = jcirc.block() block.gate("Py", reg2[0]) block.gate("measure_all") self.assertEqual( generate_jaqal_program(jcirc.build()), generate_jaqal_program(jaqal_circuit_from_dag_circuit(dag)), )
def run(self, dag): """Run the UnrollCustomDefinitions pass on `dag`. Args: dag (DAGCircuit): input dag Raises: QiskitError: if unable to unroll given the basis due to undefined decomposition rules (such as a bad basis) or excessive recursion. Returns: DAGCircuit: output unrolled dag """ if self._basis_gates is None: return dag basic_insts = {'measure', 'reset', 'barrier', 'snapshot', 'delay'} device_insts = basic_insts | set(self._basis_gates) for node in dag.op_nodes(): if node.op._directive: continue if dag.has_calibration_for(node): continue if node.name in device_insts or self._equiv_lib.has_entry(node.op): if isinstance(node.op, ControlledGate) and node.op._open_ctrl: pass else: continue try: rule = node.op.definition.data except TypeError as err: raise QiskitError( f'Error decomposing node {node.name}: {err}') from err except AttributeError: # definition is None rule = None if not rule: if rule == []: dag.remove_op_node(node) continue # opaque node raise QiskitError( "Cannot unroll the circuit to the given basis, %s. " "Instruction %s not found in equivalence library " "and no rule found to expand." % (str(self._basis_gates), node.op.name)) decomposition = circuit_to_dag(node.op.definition) unrolled_dag = UnrollCustomDefinitions( self._equiv_lib, self._basis_gates).run(decomposition) dag.substitute_node_with_dag(node, unrolled_dag) return dag
def run(self, dag: DAGCircuit) -> DAGCircuit: """Run the Decompose pass on `dag`. Args: dag: input dag. Returns: output dag where ``gate`` was expanded. """ # Walk through the DAG and expand each non-basis node for node in dag.op_nodes(self.gate): # opaque or built-in gates are not decomposable if not node.op.definition: continue if node.op.definition.global_phase: dag.global_phase += node.op.definition.global_phase # TODO: allow choosing among multiple decomposition rules rule = node.op.definition.data if len(rule) == 1 and len(node.qargs) == len(rule[0][1]) == 1: dag.substitute_node(node, rule[0][0], inplace=True) else: decomposition = circuit_to_dag(node.op.definition) dag.substitute_node_with_dag(node, decomposition) return dag
def test_pass_template_too_many_qubits(self): """ If the template has more qubits than the circuit, it raises an error. """ qr = QuantumRegister(2, 'qr') circuit_in = QuantumCircuit(qr) circuit_in.h(qr[0]) circuit_in.h(qr[0]) circuit_in.cx(qr[0], qr[1]) circuit_in.cx(qr[0], qr[1]) circuit_in.cx(qr[0], qr[1]) circuit_in.cx(qr[0], qr[1]) circuit_in.cx(qr[1], qr[0]) circuit_in.cx(qr[1], qr[0]) dag_in = circuit_to_dag(circuit_in) qrt = QuantumRegister(10, 'qrc') qct = QuantumCircuit(qrt) qct.mcx(control_qubits=[0, 1, 2, 3], target_qubit=[8]) qct.mcx(control_qubits=[0, 1, 2, 3], target_qubit=[8]) qct.x(0) qct.x(0) qct.h(1) qct.h(1) qct.x(8) qct.x(8) template_list = [qct] pass_ = TemplateOptimization(template_list) self.assertRaises(TranspilerError, pass_.run, dag_in)
def test_skip_unentangled_qubits(self): """Test skipping the unentangled qubits.""" num_qubits = 6 entanglement_1 = [[0, 1, 3], [1, 3, 5], [0, 1, 5]] skipped_1 = [2, 4] entanglement_2 = [entanglement_1, [[0, 1, 2], [2, 3, 5]]] skipped_2 = [4] for entanglement, skipped in zip([entanglement_1, entanglement_2], [skipped_1, skipped_2]): with self.subTest(entanglement=entanglement, skipped=skipped): nlocal = NLocal( num_qubits, rotation_blocks=XGate(), entanglement_blocks=CCXGate(), entanglement=entanglement, reps=3, skip_unentangled_qubits=True, ) skipped_set = set(nlocal.qubits[i] for i in skipped) dag = circuit_to_dag(nlocal) idle = set(dag.idle_wires()) self.assertEqual(skipped_set, idle)
def run(self, dag: DAGCircuit) -> DAGCircuit: """Run the Decompose pass on `dag`. Args: dag: input dag. Returns: output dag where ``gate`` was expanded. """ # Walk through the DAG and expand each non-basis node for node in dag.op_nodes(): if self._should_decompose(node): if getattr(node.op, "definition", None) is None: continue # TODO: allow choosing among multiple decomposition rules rule = node.op.definition.data if len(rule) == 1 and len(node.qargs) == len( rule[0].qubits) == 1: if node.op.definition.global_phase: dag.global_phase += node.op.definition.global_phase dag.substitute_node(node, rule[0].operation, inplace=True) else: decomposition = circuit_to_dag(node.op.definition) dag.substitute_node_with_dag(node, decomposition) return dag
def test_single_controlled_rotation_gates(self, gate, cgate): """Test the controlled rotation gates controlled on one qubit.""" if gate.name == 'rz': iden = Operator.from_label('I') zgen = Operator.from_label('Z') op_mat = (np.cos(0.5 * self.theta) * iden - 1j * np.sin(0.5 * self.theta) * zgen).data else: op_mat = Operator(gate).data ref_mat = Operator(cgate).data cop_mat = _compute_control_matrix(op_mat, self.num_ctrl) self.assertTrue(matrix_equal(cop_mat, ref_mat, ignore_phase=True)) cqc = QuantumCircuit(self.num_ctrl + self.num_target) cqc.append(cgate, cqc.qregs[0]) dag = circuit_to_dag(cqc) unroller = Unroller(['u3', 'cx']) uqc = dag_to_circuit(unroller.run(dag)) self.log.info('%s gate count: %d', cgate.name, uqc.size()) self.log.info('\n%s', str(uqc)) # these limits could be changed if gate.name == 'ry': self.assertTrue(uqc.size() <= 32) elif gate.name == 'rz': self.assertTrue(uqc.size() <= 40) else: self.assertTrue(uqc.size() <= 20)
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)) qc = dag_to_circuit(unroller.run(dag)) return qc.to_gate()
def test_open_control_cxx_unrolling(self): """test unrolling of open control gates when gate is in basis""" qreg = QuantumRegister(3) qc = QuantumCircuit(qreg) ccx = CCXGate(ctrl_state=0) qc.append(ccx, [0, 1, 2]) dag = circuit_to_dag(qc) unroller = Unroller(['x', 'ccx']) unrolled_dag = unroller.run(dag) ref_circuit = QuantumCircuit(qreg) ref_circuit.x(qreg[0]) ref_circuit.x(qreg[1]) ref_circuit.ccx(qreg[0], qreg[1], qreg[2]) ref_circuit.x(qreg[0]) ref_circuit.x(qreg[1]) ref_dag = circuit_to_dag(ref_circuit) self.assertEqual(unrolled_dag, ref_dag)
def test_circuit_multi(self): """Test circuit multi regs declared at start. """ qreg0 = QuantumRegister(2, 'q0') creg0 = ClassicalRegister(2, 'c0') qreg1 = QuantumRegister(2, 'q1') creg1 = ClassicalRegister(2, 'c1') circ = QuantumCircuit(qreg0, qreg1, creg0, creg1) circ.x(qreg0[1]) circ.x(qreg1[0]) meas = QuantumCircuit(qreg0, qreg1, creg0, creg1) meas.measure(qreg0, creg0) meas.measure(qreg1, creg1) qc = circ + meas circ2 = QuantumCircuit() circ2.add_register(qreg0) circ2.add_register(qreg1) circ2.add_register(creg0) circ2.add_register(creg1) circ2.x(qreg0[1]) circ2.x(qreg1[0]) meas2 = QuantumCircuit() meas2.add_register(qreg0) meas2.add_register(qreg1) meas2.add_register(creg0) meas2.add_register(creg1) meas2.measure(qreg0, creg0) meas2.measure(qreg1, creg1) qc2 = circ2 + meas2 dag_qc = circuit_to_dag(qc) dag_qc2 = circuit_to_dag(qc2) dag_circ2 = circuit_to_dag(circ2) dag_circ = circuit_to_dag(circ) self.assertEqual(dag_qc, dag_qc2) self.assertEqual(dag_circ, dag_circ2)
def test_open_control_cy_unrolling(self): """test unrolling of open control gates when gate is in basis""" qc = QuantumCircuit(2) qc.cy(0, 1, ctrl_state=0) dag = circuit_to_dag(qc) unroller = Unroller(['u3', 'cy']) uqc = dag_to_circuit(unroller.run(dag)) ref_circuit = QuantumCircuit(2) ref_circuit.u3(np.pi, 0, np.pi, 0) ref_circuit.cy(0, 1) ref_circuit.u3(np.pi, 0, np.pi, 0) self.assertEqual(uqc, ref_circuit)
def test_open_control_composite_unrolling(self): """test unrolling of open control gates when gate is in basis""" # create composite gate qreg = QuantumRegister(2) qcomp = QuantumCircuit(qreg, name='bell') qcomp.h(qreg[0]) qcomp.cx(qreg[0], qreg[1]) bell = qcomp.to_gate() # create controlled composite gate cqreg = QuantumRegister(3) qc = QuantumCircuit(cqreg) qc.append(bell.control(ctrl_state=0), qc.qregs[0][:]) dag = circuit_to_dag(qc) unroller = Unroller(['x', 'u1', 'cbell']) unrolled_dag = unroller.run(dag) # create reference circuit ref_circuit = QuantumCircuit(cqreg) ref_circuit.x(cqreg[0]) ref_circuit.append(bell.control(), [cqreg[0], cqreg[1], cqreg[2]]) ref_circuit.x(cqreg[0]) ref_dag = circuit_to_dag(ref_circuit) self.assertEqual(unrolled_dag, ref_dag)
def test_metadata(self): """Test circuit metadata is preservered through conversion.""" meta_dict = dict(experiment_id="1234", execution_number=4) qr = QuantumRegister(2) circuit_in = QuantumCircuit(qr, metadata=meta_dict) circuit_in.h(qr[0]) circuit_in.cx(qr[0], qr[1]) circuit_in.measure_all() dag = circuit_to_dag(circuit_in) self.assertEqual(dag.metadata, meta_dict) dag_dependency = dag_to_dagdependency(dag) self.assertEqual(dag_dependency.metadata, meta_dict) dag_out = dagdependency_to_dag(dag_dependency) self.assertEqual(dag_out.metadata, meta_dict)
def test_composite(self): """Test composite gate count.""" qreg = QuantumRegister(self.num_ctrl + self.num_target) qc = QuantumCircuit(qreg, name='composite') qc.append(self.grx.control(self.num_ctrl), qreg) qc.append(self.gry.control(self.num_ctrl), qreg) qc.append(self.gry, qreg[0:self.gry.num_qubits]) qc.append(self.grz.control(self.num_ctrl), qreg) dag = circuit_to_dag(qc) unroller = Unroller(['u3', 'cx']) uqc = dag_to_circuit(unroller.run(dag)) self.log.info('%s gate count: %d', uqc.name, uqc.size()) self.assertTrue(uqc.size() <= 93) # this limit could be changed
def run(self, dag: DAGCircuit) -> DAGCircuit: """Run the Decompose pass on `dag`. Args: dag: input DAG. Returns: Output DAG where ``U`` gates have been decomposed. """ # Walk through the DAG and expand each node if required for node in dag.op_nodes(): if isinstance(node.op, (PhaseGate, U1Gate, U2Gate, U3Gate, UGate)): subdag = circuit_to_dag(self.ugate_replacement_circuit( node.op)) dag.substitute_node_with_dag(node, subdag) return dag
def test_circuit_and_dag_dependency(self): """Check convert to dag dependency and back""" qr = QuantumRegister(3) cr = ClassicalRegister(3) circuit_in = QuantumCircuit(qr, cr) circuit_in.h(qr[0]) circuit_in.h(qr[1]) circuit_in.measure(qr[0], cr[0]) circuit_in.measure(qr[1], cr[1]) circuit_in.x(qr[0]).c_if(cr, 0x3) circuit_in.measure(qr[0], cr[0]) circuit_in.measure(qr[1], cr[1]) circuit_in.measure(qr[2], cr[2]) dag_in = circuit_to_dag(circuit_in) dag_dependency = dag_to_dagdependency(dag_in) dag_out = dagdependency_to_dag(dag_dependency) self.assertEqual(dag_out, dag_in)
def __init__(self, mode: str = 'ry'): """ Args: """ super().__init__() self._subdags: List = [] self.initial_layout = None self.gate = qiskit.circuit.library.CXGate self.decomposition = QuantumCircuit(2) if mode == 'ry': self.decomposition.ry(-np.pi / 2, 1) self.decomposition.cz(0, 1) self.decomposition.ry(np.pi / 2, 1) else: self.decomposition.h(1) self.decomposition.cz(0, 1) self.decomposition.h(1) self._dag = circuit_to_dag(self.decomposition)
def run(self, dag): """Run the Unroll3qOrMore pass on `dag`. Args: dag(DAGCircuit): input dag Returns: DAGCircuit: output dag with maximum node degrees of 2 Raises: QiskitError: if a 3q+ gate is not decomposable """ for node in dag.multi_qubit_ops(): if dag.has_calibration_for(node): continue if self.target is not None: # Treat target instructions as global since this pass can be run # prior to layout and routing we don't have phsyical qubits from # the circuit yet if node.name in self.target: continue elif self.basis_gates is not None and node.name in self.basis_gates: continue # TODO: allow choosing other possible decompositions rule = node.op.definition.data if not rule: if rule == []: # empty node dag.remove_op_node(node) continue raise QiskitError( "Cannot unroll all 3q or more gates. " "No rule to expand instruction %s." % node.op.name ) decomposition = circuit_to_dag(node.op.definition) decomposition = self.run(decomposition) # recursively unroll dag.substitute_node_with_dag(node, decomposition) return dag
def test_rotation_gates(self): """Test controlled rotation gates""" import qiskit.extensions.standard.u1 as u1 import qiskit.extensions.standard.rx as rx import qiskit.extensions.standard.ry as ry import qiskit.extensions.standard.rz as rz num_ctrl = 2 num_target = 1 qreg = QuantumRegister(num_ctrl + num_target) theta = pi / 2 gu1 = u1.U1Gate(theta) grx = rx.RXGate(theta) gry = ry.RYGate(theta) grz = rz.RZGate(theta) ugu1 = ac._unroll_gate(gu1, ['u1', 'u3', 'cx']) ugrx = ac._unroll_gate(grx, ['u1', 'u3', 'cx']) ugry = ac._unroll_gate(gry, ['u1', 'u3', 'cx']) ugrz = ac._unroll_gate(grz, ['u1', 'u3', 'cx']) ugrz.params = grz.params cgu1 = ugu1.control(num_ctrl) cgrx = ugrx.control(num_ctrl) cgry = ugry.control(num_ctrl) cgrz = ugrz.control(num_ctrl) for gate, cgate in zip([gu1, grx, gry, grz], [cgu1, cgrx, cgry, cgrz]): with self.subTest(i=gate.name): if gate.name == 'rz': iden = Operator.from_label('I') zgen = Operator.from_label('Z') op_mat = (np.cos(0.5 * theta) * iden - 1j * np.sin(0.5 * theta) * zgen).data else: op_mat = Operator(gate).data ref_mat = Operator(cgate).data cop_mat = _compute_control_matrix(op_mat, num_ctrl) self.assertTrue( matrix_equal(cop_mat, ref_mat, ignore_phase=True)) cqc = QuantumCircuit(num_ctrl + num_target) cqc.append(cgate, cqc.qregs[0]) dag = circuit_to_dag(cqc) unroller = Unroller(['u3', 'cx']) uqc = dag_to_circuit(unroller.run(dag)) self.log.info('%s gate count: %d', cgate.name, uqc.size()) self.log.info('\n%s', str(uqc)) # these limits could be changed if gate.name == 'ry': self.assertTrue(uqc.size() <= 32) elif gate.name == 'rz': self.assertTrue(uqc.size() <= 40) else: self.assertTrue(uqc.size() <= 20) qc = QuantumCircuit(qreg, name='composite') qc.append(grx.control(num_ctrl), qreg) qc.append(gry.control(num_ctrl), qreg) qc.append(gry, qreg[0:gry.num_qubits]) qc.append(grz.control(num_ctrl), qreg) dag = circuit_to_dag(qc) unroller = Unroller(['u3', 'cx']) uqc = dag_to_circuit(unroller.run(dag)) print(uqc.size()) self.log.info('%s gate count: %d', uqc.name, uqc.size()) self.assertTrue(uqc.size() <= 93) # this limit could be changed
def run(self, dag): """Run the Unroller pass on `dag`. Args: dag (DAGCircuit): input dag Raises: QiskitError: if unable to unroll given the basis due to undefined decomposition rules (such as a bad basis) or excessive recursion. Returns: DAGCircuit: output unrolled 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', 'delay'] if node.name in basic_insts: # TODO: this is legacy behavior.Basis_insts should be removed that these # instructions should be part of the device-reported basis. Currently, no # backend reports "measure", for example. continue if node.name in self.basis: # If already a base, ignore. if isinstance(node.op, ControlledGate) and node.op._open_ctrl: pass else: continue # TODO: allow choosing other possible decompositions try: rule = node.op.definition.data except TypeError as err: raise QiskitError('Error decomposing node {}: {}'.format( node.name, err)) # Isometry gates definitions can have widths smaller than that of the # original gate, in which case substitute_node will raise. Fall back # to substitute_node_with_dag if an the width of the definition is # different that the width of the node. while rule and len(rule) == 1 and len(node.qargs) == len( rule[0][1]) == 1: if rule[0][0].name in self.basis: if node.op.definition and node.op.definition.global_phase: dag.global_phase += node.op.definition.global_phase dag.substitute_node(node, rule[0][0], inplace=True) break try: rule = rule[0][0].definition.data except (TypeError, AttributeError) as err: raise QiskitError('Error decomposing node {}: {}'.format( node.name, err)) else: if not rule: if rule == []: # empty node dag.remove_op_node(node) continue # opaque node raise QiskitError( "Cannot unroll the circuit to the given basis, %s. " "No rule to expand instruction %s." % (str(self.basis), node.op.name)) decomposition = circuit_to_dag(node.op.definition) unrolled_dag = self.run( decomposition) # recursively unroll ops if unrolled_dag.global_phase: dag.global_phase += unrolled_dag.global_phase unrolled_dag.global_phase = 0 dag.substitute_node_with_dag(node, unrolled_dag) return dag
def circuit_to_tdag(circuit, qubits=None): return TaggedDAG(circuit_to_dag(circuit), qubits=qubits)
def layer_parser(circ, two_qubit_gate='cx', coupling_map=None): """ Tranforms general circuits into a nice form for a qotp. Args: circ (QuantumCircuit): A generic quantum circuit two_qubit_gate (str): a flag as to which 2 qubit gate to compile with, can be cx or cz coupling_map (list): some particular device topology as list of list (e.g. [[0,1],[1,2],[2,0]]) Returns: dict: A dictionary of the parsed layers with the following keys: ``singlequbit_layers`` (lsit): a list of circuits describing the single qubit gates ``cz_layers`` (list): a list of circuits describing the cz layers ``meas_layer`` (QuantumCircuit): a circuit describing the final measurement Raises: QiskitError: If a circuit element is not implemented in qotp """ # transpile to single qubits and cx # TODO: replace cx with cz when that is available circ_internal = transpile(circ, optimization_level=2, basis_gates=['u1', 'u2', 'u3', 'cx'], coupling_map=coupling_map) # quantum and classial registers qregs = circ_internal.qregs[0] cregs = circ_internal.cregs[0] # conatiners for the eventual output passed to the accred code singlequbitlayers = [ QuantumCircuit(qregs, cregs), QuantumCircuit(qregs, cregs) ] twoqubitlayers = [QuantumCircuit(qregs, cregs)] measlayer = QuantumCircuit(qregs, cregs) # some flags for simplicity current2qs = [] # loop through circuit (best to use the dag object) dag_internal = circuit_to_dag(circ_internal) for dag_layer in dag_internal.layers(): circuit_layer = dag_to_circuit(dag_layer['graph']) for circelem, qsub, csub in circuit_layer: n = circelem.name if n == "barrier": # if a barrier separates any two qubit gates # start a new layer if current2qs != []: singlequbitlayers.append(QuantumCircuit(qregs, cregs)) twoqubitlayers.append(QuantumCircuit(qregs, cregs)) current2qs = [] singlequbitlayers[-2].append(circelem, qsub, csub) elif n in ('u1', 'u2', 'u3'): # single qubit gate q = qsub[0] if q in current2qs: singlequbitlayers[-1].append(circelem, qsub, csub) else: singlequbitlayers[-2].append(circelem, qsub, csub) elif n == "cx": # cx indices q_0 = qsub[0] q_1 = qsub[1] # check if new cnot satisfies overlap criteria if q_0 in current2qs or q_1 in current2qs: singlequbitlayers.append(QuantumCircuit(qregs, cregs)) twoqubitlayers.append(QuantumCircuit(qregs, cregs)) current2qs = [] if two_qubit_gate == 'cx': # append cx twoqubitlayers[-1].cx(q_0, q_1) elif two_qubit_gate == 'cz': # append and correct to cz with h gates twoqubitlayers[-1].cz(q_0, q_1) singlequbitlayers[-1].h(qsub[1]) singlequbitlayers[-2].h(qsub[1]) else: raise QiskitError( "Two qubit gate {0}".format(two_qubit_gate) + " is not implemented in qotp") # add to current current2qs.append(q_0) current2qs.append(q_1) elif n == "measure": measlayer.append(circelem, qsub, csub) else: raise QiskitError("Circuit element {0}".format(n) + " is not implemented in qotp") if current2qs == []: del singlequbitlayers[-1] del twoqubitlayers[-1] for ind, circlayer in enumerate(singlequbitlayers): singlequbitlayers[ind] = transpile(circlayer, basis_gates=['u1', 'u2', 'u3']) parsedlayers = { 'singlequbitlayers': singlequbitlayers, 'twoqubitlayers': twoqubitlayers, 'measlayer': measlayer, 'twoqubitgate': two_qubit_gate, 'qregs': qregs, 'cregs': cregs } return parsedlayers