def test_topological_nodes(self): """The topological_nodes() method""" self.dag.apply_operation_back(CnotGate(), [self.qubit0, self.qubit1], []) self.dag.apply_operation_back(HGate(), [self.qubit0], []) self.dag.apply_operation_back(CnotGate(), [self.qubit2, self.qubit1], []) self.dag.apply_operation_back(CnotGate(), [self.qubit0, self.qubit2], []) self.dag.apply_operation_back(HGate(), [self.qubit2], []) named_nodes = self.dag.topological_nodes() expected = [('qr[0]', []), ('qr[1]', []), ('cx', [(QuantumRegister(3, 'qr'), 0), (QuantumRegister(3, 'qr'), 1)]), ('h', [(QuantumRegister(3, 'qr'), 0)]), ('qr[2]', []), ('cx', [(QuantumRegister(3, 'qr'), 2), (QuantumRegister(3, 'qr'), 1)]), ('cx', [(QuantumRegister(3, 'qr'), 0), (QuantumRegister(3, 'qr'), 2)]), ('h', [(QuantumRegister(3, 'qr'), 2)]), ('qr[0]', []), ('qr[1]', []), ('qr[2]', []), ('cr[0]', []), ('cr[0]', []), ('cr[1]', []), ('cr[1]', [])] self.assertEqual(expected, [(i.name, i.qargs) for i in named_nodes])
def _define_decompositions(self): decomposition = DAGCircuit() q = QuantumRegister(5, "q") decomposition.add_qreg(q) decomposition.add_basis_element("u1", 1, 0, 1) decomposition.add_basis_element("cx", 2, 0, 0) decomposition.add_basis_element("ccx", 3, 0, 0) decomposition.add_basis_element("c3x", 4, 0, 0) decomposition.add_basis_element("c4x", 5, 0, 0) rule = [ C4NotGate(q[0], q[1], q[2], q[3], q[4]), C3NotGate(q[0], q[1], q[2], q[3]), ToffoliGate(q[0], q[1], q[2]), CnotGate(q[0], q[1]), U1Gate(-self.param[0] / 16, q[1]), U1Gate(-self.param[0] / 8, q[2]), U1Gate(-self.param[0] / 4, q[3]), U1Gate(-self.param[0] / 2, q[4]), CnotGate(q[0], q[1]), ToffoliGate(q[0], q[1], q[2]), C3NotGate(q[0], q[1], q[2], q[3]), C4NotGate(q[0], q[1], q[2], q[3], q[4]), U1Gate(self.param[0] / 16, q[0]), U1Gate(self.param[0] / 16, q[1]), U1Gate(self.param[0] / 8, q[2]), U1Gate(self.param[0] / 4, q[3]), U1Gate(self.param[0] / 2, q[4]) ] for inst in rule: decomposition.apply_operation_back(inst) self._decompositions = [decomposition]
def test_dag_collect_runs(self): """Test the collect_runs method with 3 different gates.""" self.dag.apply_operation_back(U1Gate(3.14), [self.qubit0]) self.dag.apply_operation_back(U1Gate(3.14), [self.qubit0]) self.dag.apply_operation_back(U1Gate(3.14), [self.qubit0]) self.dag.apply_operation_back(CnotGate(), [self.qubit2, self.qubit1]) self.dag.apply_operation_back(CnotGate(), [self.qubit1, self.qubit2]) self.dag.apply_operation_back(HGate(), [self.qubit2]) collected_runs = self.dag.collect_runs(['u1', 'cx', 'h']) self.assertEqual(len(collected_runs), 3) for run in collected_runs: if run[0].name == 'cx': self.assertEqual(len(run), 2) self.assertEqual(['cx'] * 2, [x.name for x in run]) self.assertEqual( [[self.qubit2, self.qubit1], [self.qubit1, self.qubit2]], [x.qargs for x in run]) elif run[0].name == 'h': self.assertEqual(len(run), 1) self.assertEqual(['h'], [x.name for x in run]) self.assertEqual([[self.qubit2]], [x.qargs for x in run]) elif run[0].name == 'u1': self.assertEqual(len(run), 3) self.assertEqual(['u1'] * 3, [x.name for x in run]) self.assertEqual([[self.qubit0], [self.qubit0], [self.qubit0]], [x.qargs for x in run]) else: self.fail('Unknown run encountered')
def _define_decompositions(self): """ gate cu3(theta,phi,lambda) c, t { 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; } """ decomposition = DAGCircuit() q = QuantumRegister(2, "q") decomposition.add_qreg(q) decomposition.add_basis_element("u1", 1, 0, 1) decomposition.add_basis_element("u3", 1, 0, 3) decomposition.add_basis_element("cx", 2, 0, 0) rule = [ U1Gate((self.param[2] - self.param[1]) / 2, q[1]), CnotGate(q[0], q[1]), U3Gate(-self.param[0] / 2, 0, -(self.param[1] + self.param[2]) / 2, q[1]), CnotGate(q[0], q[1]), U3Gate(self.param[0] / 2, self.param[1], 0, q[1]) ] for inst in rule: decomposition.apply_operation_back(inst) self._decompositions = [decomposition]
def _define_decompositions(self): """ gate ch a,b { h b; sdg b; cx a,b; h b; t b; cx a,b; t b; h b; s b; x b; s a;} """ decomposition = DAGCircuit() q = QuantumRegister(2, "q") decomposition.add_qreg(q) rule = [ HGate(q[1]), SdgGate(q[1]), CnotGate(q[0], q[1]), HGate(q[1]), TGate(q[1]), CnotGate(q[0], q[1]), TGate(q[1]), HGate(q[1]), SGate(q[1]), XGate(q[1]), SGate(q[0]) ] for inst in rule: decomposition.apply_operation_back(inst) self._decompositions = [decomposition]
def test_remove_op_node_longer(self): """ Test remove_op_node method in a "longer" dag""" self.dag.apply_operation_back(CnotGate(), [self.qubit0, self.qubit1]) self.dag.apply_operation_back(HGate(), [self.qubit0]) self.dag.apply_operation_back(CnotGate(), [self.qubit2, self.qubit1]) self.dag.apply_operation_back(CnotGate(), [self.qubit0, self.qubit2]) self.dag.apply_operation_back(HGate(), [self.qubit2]) named_nodes = [node for node in self.dag.nodes_in_topological_order()] self.dag.remove_op_node(named_nodes[2]) expected = [('qr[0]', []), ('h', [self.qubit0]), ('qr[1]', []), ('qr[2]', []), ('cx', [self.qubit2, self.qubit1]), ('cx', [self.qubit0, self.qubit2]), ('h', [self.qubit2]), ('qr[0]', []), ('qr[1]', []), ('qr[2]', []), ('cr[0]', []), ('cr[0]', []), ('cr[1]', []), ('cr[1]', [])] self.assertEqual(expected, [(i.name, i.qargs) for i in self.dag.nodes_in_topological_order()])
def _define(self): """ gate ch a,b { h b; sdg b; cx a,b; h b; t b; cx a,b; t b; h b; s b; x b; s a;} """ definition = [] q = QuantumRegister(2, "q") rule = [(HGate(), [q[1]], []), (SdgGate(), [q[1]], []), (CnotGate(), [q[0], q[1]], []), (HGate(), [q[1]], []), (TGate(), [q[1]], []), (CnotGate(), [q[0], q[1]], []), (TGate(), [q[1]], []), (HGate(), [q[1]], []), (SGate(), [q[1]], []), (XGate(), [q[1]], []), (SGate(), [q[0]], [])] for inst in rule: definition.append(inst) self.definition = definition
def _multiplex(self, target_gate, list_of_angles): """ Return a recursive implementation of a multiplexor circuit, where each instruction itself has a decomposition based on smaller multiplexors. The LSB is the multiplexor "data" and the other bits are multiplexor "select". Args: target_gate (Gate): Ry or Rz gate to apply to target qubit, multiplexed over all other "select" qubits list_of_angles (list[float]): list of rotation angles to apply Ry and Rz Returns: DAGCircuit: the circuit implementing the multiplexor's action """ list_len = len(list_of_angles) local_num_qubits = int(math.log2(list_len)) + 1 q = QuantumRegister(local_num_qubits) circuit = QuantumCircuit(q) circuit.name = "multiplex" + local_num_qubits.__str__() lsb = q[0] msb = q[local_num_qubits - 1] # case of no multiplexing: base case for recursion if local_num_qubits == 1: circuit.append(target_gate(list_of_angles[0]), [q[0]]) return circuit # calc angle weights, assuming recursion (that is the lower-level # requested angles have been correctly implemented by recursion angle_weight = scipy.kron([[0.5, 0.5], [0.5, -0.5]], np.identity(2 ** (local_num_qubits - 2))) # calc the combo angles list_of_angles = angle_weight.dot(np.array(list_of_angles)).tolist() # recursive step on half the angles fulfilling the above assumption multiplex_1 = self._multiplex(target_gate, list_of_angles[0:(list_len // 2)]) circuit.append(multiplex_1.to_instruction(), q[0:-1]) # attach CNOT as follows, thereby flipping the LSB qubit circuit.append(CnotGate(), [msb, lsb]) # implement extra efficiency from the paper of cancelling adjacent # CNOTs (by leaving out last CNOT and reversing (NOT inverting) the # second lower-level multiplex) multiplex_2 = self._multiplex(target_gate, list_of_angles[(list_len // 2):]) if list_len > 1: circuit.append(multiplex_2.to_instruction().mirror(), q[0:-1]) else: circuit.append(multiplex_2.to_instruction(), q[0:-1]) # attach a final CNOT circuit.append(CnotGate(), [msb, lsb]) return circuit
def _multiplex(self, bottom_gate, bottom_qubit_index, list_of_angles): """ Internal recursive method to create gates to perform rotations on the imaginary qubits: works by rotating LSB (and hence ALL imaginary qubits) by combo angle and then flipping sign (by flipping the bit, hence moving the complex amplitudes) of half the imaginary qubits (CNOT) followed by another combo angle on LSB, therefore executing conditional (on MSB) rotations, thereby disentangling LSB. """ list_len = len(list_of_angles) target_qubit = self.nth_qubit_from_least_sig_qubit(bottom_qubit_index) # Case of no multiplexing = base case for recursion if list_len == 1: return bottom_gate(list_of_angles[0], target_qubit) local_num_qubits = int(math.log2(list_len)) + 1 control_qubit = self.nth_qubit_from_least_sig_qubit( local_num_qubits - 1 + bottom_qubit_index) # calc angle weights, assuming recursion (that is the lower-level # requested angles have been correctly implemented by recursion angle_weight = scipy.kron([[0.5, 0.5], [0.5, -0.5]], numpy.identity(2 ** (local_num_qubits - 2))) # calc the combo angles list_of_angles = (angle_weight * numpy.matrix( list_of_angles).transpose()).reshape(-1).tolist()[0] combine_composite_gates = CompositeGate( "multiplex" + local_num_qubits.__str__(), [], self.arg) # recursive step on half the angles fulfilling the above assumption combine_composite_gates._attach( self._multiplex(bottom_gate, bottom_qubit_index, list_of_angles[0:(list_len // 2)])) # combine_composite_gates.cx(control_qubit,target_qubit) -> does not # work as expected because checks circuit # so attach CNOT as follows, thereby flipping the LSB qubit combine_composite_gates._attach(CnotGate(control_qubit, target_qubit)) # implement extra efficiency from the paper of cancelling adjacent # CNOTs (by leaving out last CNOT and reversing (NOT inverting) the # second lower-level multiplex) sub_gate = self._multiplex( bottom_gate, bottom_qubit_index, list_of_angles[(list_len // 2):]) if isinstance(sub_gate, CompositeGate): combine_composite_gates._attach(sub_gate.reverse()) else: combine_composite_gates._attach(sub_gate) # outer multiplex keeps final CNOT, because no adjacent CNOT to cancel # with if self.num_qubits == local_num_qubits + bottom_qubit_index: combine_composite_gates._attach(CnotGate(control_qubit, target_qubit)) return combine_composite_gates
def test_nodes_in_topological_order(self): """ The node_nums_in_topological_order() method""" self.dag.apply_operation_back(CnotGate(self.qubit0, self.qubit1)) self.dag.apply_operation_back(HGate(self.qubit0)) self.dag.apply_operation_back(CnotGate(self.qubit2, self.qubit1)) self.dag.apply_operation_back(CnotGate(self.qubit0, self.qubit2)) self.dag.apply_operation_back(HGate(self.qubit2)) named_nodes = self.dag.node_nums_in_topological_order() self.assertEqual([9, 10, 7, 8, 5, 3, 1, 11, 13, 4, 12, 14, 15, 6, 2], [i for i in named_nodes])
def _define(self): """ gate swap a,b { cx a,b; cx b,a; cx a,b; } """ definition = [] q = QuantumRegister(2, "q") rule = [(CnotGate(), [q[0], q[1]], []), (CnotGate(), [q[1], q[0]], []), (CnotGate(), [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; } """ definition = [] q = QuantumRegister(2, "q") rule = [(CnotGate(), [q[0], q[1]], []), (U1Gate(self.params[0]), [q[1]], []), (CnotGate(), [q[0], q[1]], [])] for inst in rule: definition.append(inst) self.definition = definition
def test_remove_op_node_longer(self): """Test remove_op_node method in a "longer" dag""" self.dag.apply_operation_back(CnotGate(), [self.qubit0, self.qubit1]) self.dag.apply_operation_back(HGate(), [self.qubit0]) self.dag.apply_operation_back(CnotGate(), [self.qubit2, self.qubit1]) self.dag.apply_operation_back(CnotGate(), [self.qubit0, self.qubit2]) self.dag.apply_operation_back(HGate(), [self.qubit2]) op_nodes = list(self.dag.topological_op_nodes()) self.dag.remove_op_node(op_nodes[0]) expected = [('h', [self.qubit0]), ('cx', [self.qubit2, self.qubit1]), ('cx', [self.qubit0, self.qubit2]), ('h', [self.qubit2])] self.assertEqual(expected, [(i.name, i.qargs) for i in self.dag.topological_op_nodes()])
def _process_cnot(self, node): """Process a CNOT gate node.""" id0 = self._process_bit_id(node.children[0]) id1 = self._process_bit_id(node.children[1]) if not (len(id0) == len(id1) or len(id0) == 1 or len(id1) == 1): raise QiskitError("internal error: qreg size mismatch", "line=%s" % node.line, "file=%s" % node.file) maxidx = max([len(id0), len(id1)]) for idx in range(maxidx): if len(id0) > 1 and len(id1) > 1: self.dag.apply_operation_back(CnotGate(), [id0[idx], id1[idx]], [], self.condition) elif len(id0) > 1: self.dag.apply_operation_back(CnotGate(), [id0[idx], id1[0]], [], self.condition) else: self.dag.apply_operation_back(CnotGate(), [id0[0], id1[idx]], [], self.condition)
def _define_decompositions(self): """ gate swap a,b { cx a,b; cx b,a; cx a,b; } """ decomposition = DAGCircuit() q = QuantumRegister(2, "q") decomposition.add_qreg(q) rule = [ CnotGate(q[0], q[1]), CnotGate(q[1], q[0]), CnotGate(q[0], q[1]) ] for inst in rule: decomposition.apply_operation_back(inst) self._decompositions = [decomposition]
def test_topological_op_nodes(self): """The topological_op_nodes() method""" self.dag.apply_operation_back(CnotGate(), [self.qubit0, self.qubit1], []) self.dag.apply_operation_back(HGate(), [self.qubit0], []) self.dag.apply_operation_back(CnotGate(), [self.qubit2, self.qubit1], []) self.dag.apply_operation_back(CnotGate(), [self.qubit0, self.qubit2], []) self.dag.apply_operation_back(HGate(), [self.qubit2], []) named_nodes = self.dag.topological_op_nodes() expected = [('cx', [self.qubit0, self.qubit1]), ('h', [self.qubit0]), ('cx', [self.qubit2, self.qubit1]), ('cx', [self.qubit0, self.qubit2]), ('h', [self.qubit2])] self.assertEqual(expected, [(i.name, i.qargs) for i in named_nodes])
def test_instructions_equal(self): """Test equality of two instructions.""" hop1 = Instruction('h', 1, 0, []) hop2 = Instruction('s', 1, 0, []) hop3 = Instruction('h', 1, 0, []) self.assertFalse(hop1 == hop2) self.assertTrue(hop1 == hop3) uop1 = Instruction('u', 1, 0, [0.4, 0.5, 0.5]) uop2 = Instruction('u', 1, 0, [0.4, 0.6, 0.5]) uop3 = Instruction('v', 1, 0, [0.4, 0.5, 0.5]) uop4 = Instruction('u', 1, 0, [0.4, 0.5, 0.5]) self.assertFalse(uop1 == uop2) self.assertTrue(uop1 == uop4) self.assertFalse(uop1 == uop3) self.assertTrue(HGate() == HGate()) self.assertFalse(HGate() == CnotGate()) self.assertFalse(hop1 == HGate()) eop1 = Instruction('kraus', 1, 0, [np.array([[1, 0], [0, 1]])]) eop2 = Instruction('kraus', 1, 0, [np.array([[0, 1], [1, 0]])]) eop3 = Instruction('kraus', 1, 0, [np.array([[1, 0], [0, 1]])]) eop4 = Instruction('kraus', 1, 0, [np.eye(4)]) self.assertTrue(eop1 == eop3) self.assertFalse(eop1 == eop2) self.assertFalse(eop1 == eop4)
def _define(self): """ self.u3(theta / 2, 0, 0, q_target) self.cx(q_control, q_target) self.u3(-theta / 2, 0, 0, q_target) self.cx(q_control, q_target) """ definition = [] q = QuantumRegister(2, "q") rule = [(U3Gate(self.params[0] / 2, 0, 0), [q[1]], []), (CnotGate(), [q[0], q[1]], []), (U3Gate(-self.params[0] / 2, 0, 0), [q[1]], []), (CnotGate(), [q[0], q[1]], [])] for inst in rule: definition.append(inst) self.definition = definition
def test_layers_basic(self): """The layers() method returns a list of layers, each of them with a list of nodes.""" qreg = QuantumRegister(2, 'qr') creg = ClassicalRegister(2, 'cr') qubit0 = qreg[0] qubit1 = qreg[1] clbit0 = creg[0] clbit1 = creg[1] condition = (creg, 3) dag = DAGCircuit() dag.add_qreg(qreg) dag.add_creg(creg) dag.apply_operation_back(HGate(), [qubit0], []) dag.apply_operation_back(CnotGate(), [qubit0, qubit1], [], condition=None) dag.apply_operation_back(Measure(), [qubit1, clbit1], [], condition=None) dag.apply_operation_back(XGate(), [qubit1], [], condition=condition) dag.apply_operation_back(Measure(), [qubit0, clbit0], [], condition=None) dag.apply_operation_back(Measure(), [qubit1, clbit1], [], condition=None) layers = list(dag.layers()) self.assertEqual(5, len(layers)) name_layers = [[ node.op.name for node in layer["graph"].nodes() if node.type == "op" ] for layer in layers] self.assertEqual( [['h'], ['cx'], ['measure'], ['x'], ['measure', 'measure']], name_layers)
def test_substituting_node_preserves_name_args_condition(self, inplace): """Verify name, args and condition are preserved by a substitution.""" dag = DAGCircuit() qr = QuantumRegister(2) cr = ClassicalRegister(1) dag.add_qreg(qr) dag.add_creg(cr) dag.apply_operation_back(HGate(), [qr[1]]) node_to_be_replaced = dag.apply_operation_back(CnotGate(), [qr[1], qr[0]], condition=(cr, 1)) node_to_be_replaced.name = 'test_name' dag.apply_operation_back(HGate(), [qr[1]]) replacement_node = dag.substitute_node(node_to_be_replaced, CzGate(), inplace=inplace) raise_if_dagcircuit_invalid(dag) self.assertEqual(replacement_node.name, 'test_name') self.assertEqual(replacement_node.qargs, [qr[1], qr[0]]) self.assertEqual(replacement_node.cargs, []) self.assertEqual(replacement_node.condition, (cr, 1)) self.assertEqual(replacement_node is node_to_be_replaced, inplace)
def test_layers_basic(self): """ The layers() method returns a list of layers, each of them with a list of nodes.""" qreg = QuantumRegister(2, 'qr') creg = ClassicalRegister(2, 'cr') qubit0 = qreg[0] qubit1 = qreg[1] clbit0 = creg[0] clbit1 = creg[1] condition = (creg, 3) dag = DAGCircuit() dag.add_basis_element('h', 1, 0, 0) dag.add_basis_element('cx', 2, 0, 0) dag.add_basis_element('x', 1, 0, 0) dag.add_basis_element('measure', 1, 1, 0) dag.add_qreg(qreg) dag.add_creg(creg) dag.apply_operation_back(HGate(qubit0)) dag.apply_operation_back(CnotGate(qubit0, qubit1), condition=None) dag.apply_operation_back(Measure(qubit1, clbit1), condition=None) dag.apply_operation_back(XGate(qubit1), condition=condition) dag.apply_operation_back(Measure(qubit0, clbit0), condition=None) dag.apply_operation_back(Measure(qubit1, clbit1), condition=None) layers = list(dag.layers()) self.assertEqual(5, len(layers)) name_layers = [[ node[1]["op"].name for node in layer["graph"].multi_graph.nodes(data=True) if node[1]["type"] == "op" ] for layer in layers] self.assertEqual( [['h'], ['cx'], ['measure'], ['x'], ['measure', 'measure']], name_layers)
def _define(self): """ gate cswap a,b,c { cx c,b; ccx a,b,c; cx c,b; } """ definition = [] q = QuantumRegister(3, "q") rule = [(CnotGate(), [q[2], q[1]], []), (ToffoliGate(), [q[0], q[1], q[2]], []), (CnotGate(), [q[2], 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; } """ definition = [] q = QuantumRegister(2, "q") rule = [(U1Gate(self.params[0] / 2), [q[1]], []), (CnotGate(), [q[0], q[1]], []), (U1Gate(-self.params[0] / 2), [q[1]], []), (CnotGate(), [q[0], q[1]], [])] for inst in rule: definition.append(inst) self.definition = definition
def setUp(self): self.dag = DAGCircuit() qreg = QuantumRegister(3, 'qr') creg = ClassicalRegister(2, 'cr') self.dag.add_qreg(qreg) self.dag.add_creg(creg) self.dag.add_basis_element(name='h', number_qubits=1, number_classical=0, number_parameters=0) self.dag.add_basis_element('cx', 2, 0, 0) self.dag.add_basis_element('x', 1, 0, 0) self.dag.add_basis_element('measure', 1, 1, 0) self.dag.add_basis_element('reset', 1, 0, 0) self.qubit0 = qreg[0] self.qubit1 = qreg[1] self.qubit2 = qreg[2] self.clbit0 = creg[0] self.clbit1 = creg[1] self.condition = (creg, 3) self.dag.apply_operation_back(HGate(self.qubit0)) self.dag.apply_operation_back(CnotGate(self.qubit0, self.qubit1)) self.dag.apply_operation_back(XGate(self.qubit1))
def _define_decompositions(self): decomposition = DAGCircuit() q = QuantumRegister(6, "q") decomposition.add_qreg(q) decomposition.add_basis_element("u1", 1, 0, 1) decomposition.add_basis_element("h", 1, 0, 0) decomposition.add_basis_element("x", 1, 0, 0) decomposition.add_basis_element("cx", 2, 0, 0) decomposition.add_basis_element("ccx", 3, 0, 0) decomposition.add_basis_element("c3x", 4, 0, 0) decomposition.add_basis_element("c4x", 5, 0, 0) decomposition.add_basis_element("t", 1, 0, 0) decomposition.add_basis_element("tdg", 1, 0, 0) rule = [ HGate(q[5]), C4NotGate(q[0], q[1], q[2], q[3], q[5]), TdgGate(q[5]), CnotGate(q[4], q[5]), TGate(q[5]), C4NotGate(q[0], q[1], q[2], q[3], q[5]), TdgGate(q[5]), CnotGate(q[4], q[5]), TGate(q[5]), HGate(q[5]), C4NotGate(q[0], q[1], q[2], q[3], q[4]), C3NotGate(q[0], q[1], q[2], q[3]), ToffoliGate(q[0], q[1], q[2]), CnotGate(q[0], q[1]), XGate(q[0]), U1Gate(-math.pi / 32, q[1]), U1Gate(-math.pi / 16, q[2]), U1Gate(-math.pi / 8, q[3]), U1Gate(-math.pi / 4, q[4]), XGate(q[0]), CnotGate(q[0], q[1]), ToffoliGate(q[0], q[1], q[2]), C3NotGate(q[0], q[1], q[2], q[3]), C4NotGate(q[0], q[1], q[2], q[3], q[4]), U1Gate(math.pi / 32, q[0]), U1Gate(math.pi / 32, q[1]), U1Gate(math.pi / 16, q[2]), U1Gate(math.pi / 8, q[3]), U1Gate(math.pi / 4, q[4]) ] for inst in rule: decomposition.apply_operation_back(inst) self._decompositions = [decomposition]
def _define_decompositions(self): """ gate rzz(theta) a, b { cx a, b; u1(theta) b; cx a, b; } """ decomposition = DAGCircuit() q = QuantumRegister(2, "q") decomposition.add_qreg(q) decomposition.add_basis_element("u1", 1, 0, 1) decomposition.add_basis_element("cx", 2, 0, 0) rule = [ CnotGate(q[0], q[1]), U1Gate(self.param[0], q[0]), CnotGate(q[0], q[1]) ] for inst in rule: decomposition.apply_operation_back(inst) self._decompositions = [decomposition]
def _define(self): """Calculate a subcircuit that implements this unitary.""" definition = [] q = QuantumRegister(2, "q") theta = self.params[0] rule = [ (U3Gate(np.pi / 2, theta, 0), [q[0]], []), (HGate(), [q[1]], []), (CnotGate(), [q[0], q[1]], []), (U1Gate(-theta), [q[1]], []), (CnotGate(), [q[0], q[1]], []), (HGate(), [q[1]], []), (U2Gate(-np.pi, np.pi - theta), [q[0]], []), ] 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; # now it is swapped: b,c cx pi(c),pi(b); } """ definition = [] q = QuantumRegister(3, "q") rule = [(CnotGate(), [q[2], q[1]], []), (Ourense_ToffoliGate(), [q[0], q[1], q[2]], []), (CnotGate(), [q[1], q[2]], [])] for inst in rule: definition.append(inst) self.definition = definition
def direction_mapper(circuit_graph, coupling_graph): """Change the direction of CNOT gates to conform to CouplingGraph. circuit_graph = input DAGCircuit coupling_graph = corresponding CouplingGraph Adds "h" to the circuit basis. Returns a DAGCircuit object containing a circuit equivalent to circuit_graph but with CNOT gate directions matching the edges of coupling_graph. Raises an exception if the circuit_graph does not conform to the coupling_graph. """ if "cx" not in circuit_graph.basis: return circuit_graph if circuit_graph.basis["cx"] != (2, 0, 0): raise MapperError("cx gate has unexpected signature %s" % circuit_graph.basis["cx"]) qr_fcx = QuantumRegister(2, "fcx") flipped_cx_circuit = DAGCircuit() flipped_cx_circuit.add_qreg(qr_fcx) flipped_cx_circuit.add_basis_element("CX", 2) flipped_cx_circuit.add_basis_element("U", 1, 0, 3) flipped_cx_circuit.add_basis_element("cx", 2) flipped_cx_circuit.add_basis_element("u2", 1, 0, 2) flipped_cx_circuit.add_basis_element("h", 1) flipped_cx_circuit.add_gate_data("cx", cx_data) flipped_cx_circuit.add_gate_data("u2", u2_data) flipped_cx_circuit.add_gate_data("h", h_data) flipped_cx_circuit.apply_operation_back(HGate(qr_fcx[0])) flipped_cx_circuit.apply_operation_back(HGate(qr_fcx[1])) flipped_cx_circuit.apply_operation_back(CnotGate(qr_fcx[1], qr_fcx[0])) flipped_cx_circuit.apply_operation_back(HGate(qr_fcx[0])) flipped_cx_circuit.apply_operation_back(HGate(qr_fcx[1])) q_tmp = QuantumRegister(coupling_graph.size(), 'q') cg_edges = [((q_tmp, i), (q_tmp, j)) for i, j in coupling_graph.get_edges()] for cx_node in circuit_graph.get_named_nodes("cx"): nd = circuit_graph.multi_graph.node[cx_node] cxedge = tuple(nd["qargs"]) if cxedge in cg_edges: logger.debug("cx %s[%d], %s[%d] -- OK", cxedge[0][0], cxedge[0][1], cxedge[1][0], cxedge[1][1]) continue elif (cxedge[1], cxedge[0]) in cg_edges: circuit_graph.substitute_circuit_one(cx_node, flipped_cx_circuit, wires=[qr_fcx[0], qr_fcx[1]]) logger.debug("cx %s[%d], %s[%d] -FLIP", cxedge[0][0], cxedge[0][1], cxedge[1][0], cxedge[1][1]) else: raise MapperError("circuit incompatible with CouplingGraph: " "cx on %s" % pprint.pformat(cxedge)) return circuit_graph
def test_get_named_nodes(self): """The get_named_nodes(AName) method returns all the nodes with name AName""" self.dag.apply_operation_back(CnotGate(self.qubit0, self.qubit1)) self.dag.apply_operation_back(HGate(self.qubit0)) self.dag.apply_operation_back(CnotGate(self.qubit2, self.qubit1)) self.dag.apply_operation_back(CnotGate(self.qubit0, self.qubit2)) self.dag.apply_operation_back(HGate(self.qubit2)) # The ordering is not assured, so we only compare the output (unordered) sets. # We use tuples because lists aren't hashable. named_nodes = self.dag.get_named_nodes('cx') node_qargs = {tuple(self.dag.multi_graph.node[node_id]["op"].qargs) for node_id in named_nodes} expected_qargs = { (self.qubit0, self.qubit1), (self.qubit2, self.qubit1), (self.qubit0, self.qubit2)} self.assertEqual(expected_qargs, node_qargs)