def test_slice(self): """Verify circuit.data can be sliced.""" qr = QuantumRegister(2) qc = QuantumCircuit(qr) qc.h(0) qc.cx(0, 1) qc.h(1) qc.cx(1, 0) qc.h(1) qc.cx(0, 1) qc.h(0) h_slice = qc.data[::2] cx_slice = qc.data[1:-1:2] self.assertEqual(h_slice, [ (HGate(), [qr[0]], []), (HGate(), [qr[1]], []), (HGate(), [qr[1]], []), (HGate(), [qr[0]], []), ]) self.assertEqual(cx_slice, [ (CnotGate(), [qr[0], qr[1]], []), (CnotGate(), [qr[1], qr[0]], []), (CnotGate(), [qr[0], qr[1]], []), ])
def _define(self): definition = [] # No controls: # q = b # One Control: # q = b, c1 # Two Controls: # q = c1, c2, b q = QuantumRegister(self.total_n, "q") rule = [] angles = [0] * self.n for i in range(self.n): if self.a & (1 << i): for j in range(i, self.n): angles[j] += np.pi / 2**(j - i) # Inverse of U1 gates is just a negative theta if self._inverse: for i in range(len(angles)): angles[i] *= -1 # No controlled bits if self.c1 is None and self.c2 is None: for i in range(len(angles)): rule.append((U1Gate(angles[i]), [q[i]], [])) # One controlled bit if self.c1 and self.c2 is None: for i in range(len(angles)): rule.append((Cu1Gate(angles[i]), [q[self.total_n - 1], q[i]], [])) # Two controlled bits # Uses sqrt of U1 gates which is just half of theta if self.c1 and self.c2: for i in range(len(angles)): rule.append((Cu1Gate(angles[i] / 2.), [q[1], q[i + 2]], [])) # circ.cu1(angles[i]/2., c2, b[i]) rule.append((CnotGate(), [q[0], q[1]], [])) # circ.cx(c1, c2) for i in range(len(angles)): rule.append((Cu1Gate(-angles[i] / 2.), [q[1], q[i + 2]], [])) # circ.cu1(-angles[i]/2., c2, b[i]) rule.append((CnotGate(), [q[0], q[1]], [])) # circ.cx(c1, c2) for i in range(len(angles)): rule.append((Cu1Gate(angles[i] / 2.), [q[0], q[i + 2]], [])) # circ.cu1(angles[i]/2., c1, b[i]) for inst in rule: definition.append(inst) self.definition = definition
def test_instruction_init(self): """Test initialization from a circuit.""" gate = CnotGate() op = Operator(gate).data target = gate.to_matrix() global_phase_equivalent = matrix_equal(op, target, ignore_phase=True) self.assertTrue(global_phase_equivalent) gate = CHGate() op = Operator(gate).data had = HGate().to_matrix() target = np.kron(had, np.diag([0, 1])) + np.kron( np.eye(2), np.diag([1, 0])) global_phase_equivalent = matrix_equal(op, target, ignore_phase=True) self.assertTrue(global_phase_equivalent)
def run(self, dag): """Run the CXDirection pass on `dag`. Flips the cx nodes to match the directed coupling map. Modifies the input dag. Args: dag (DAGCircuit): DAG to map. Returns: DAGCircuit: The rearranged dag for the coupling map Raises: TranspilerError: If the circuit cannot be mapped just by flipping the cx nodes. """ cmap_edges = set(self.coupling_map.get_edges()) if len(dag.qregs) > 1: raise TranspilerError( 'CXDirection expects a single qreg input DAG,' 'but input DAG had qregs: {}.'.format(dag.qregs)) for cnot_node in dag.named_nodes('cx', 'CX'): control = cnot_node.qargs[0] target = cnot_node.qargs[1] physical_q0 = control.index physical_q1 = target.index if self.coupling_map.distance(physical_q0, physical_q1) != 1: raise TranspilerError( 'The circuit requires a connection between physical ' 'qubits %s and %s' % (physical_q0, physical_q1)) if (physical_q0, physical_q1) not in cmap_edges: # A flip needs to be done # Create the replacement dag and associated register. sub_dag = DAGCircuit() sub_qr = QuantumRegister(2) sub_dag.add_qreg(sub_qr) # Add H gates before sub_dag.apply_operation_back(U2Gate(0, pi), [sub_qr[0]], []) sub_dag.apply_operation_back(U2Gate(0, pi), [sub_qr[1]], []) # Flips the cx sub_dag.apply_operation_back(CnotGate(), [sub_qr[1], sub_qr[0]], []) # Add H gates after sub_dag.apply_operation_back(U2Gate(0, pi), [sub_qr[0]], []) sub_dag.apply_operation_back(U2Gate(0, pi), [sub_qr[1]], []) dag.substitute_node_with_dag(cnot_node, sub_dag) return dag
def test_circuit_append(self): """Test appending controlled gate to quantum circuit""" circ = QuantumCircuit(5) inst = CnotGate() circ.append(inst.control(), qargs=[0, 2, 1]) circ.append(inst.control(2), qargs=[0, 3, 1, 2]) circ.append(inst.control().control(), qargs=[0, 3, 1, 2]) # should be same as above self.assertEqual(circ[1][0], circ[2][0]) self.assertEqual(circ.depth(), 3) self.assertEqual(circ[0][0].num_ctrl_qubits, 2) self.assertEqual(circ[1][0].num_ctrl_qubits, 3) self.assertEqual(circ[2][0].num_ctrl_qubits, 3) self.assertEqual(circ[0][0].num_qubits, 3) self.assertEqual(circ[1][0].num_qubits, 4) self.assertEqual(circ[2][0].num_qubits, 4) for instr in circ: gate = instr[0] self.assertTrue(isinstance(gate, ControlledGate))
def comp_cnot_gate_list(qub1, qub2, quant_reg, inverse_cnot=False): ret_params = [] if not inverse_cnot: ret_params.append([CnotGate(), [quant_reg[qub1], quant_reg[qub2]]]) else: ret_params.append([HGate(), [quant_reg[qub1]]]) ret_params.append([HGate(), [quant_reg[qub2]]]) ret_params.append([CnotGate(), [quant_reg[qub1], quant_reg[qub2]]]) ret_params.append([HGate(), [quant_reg[qub1]]]) ret_params.append([HGate(), [quant_reg[qub2]]]) ret = [] for elem in ret_params: ret.append(DAGNode({"op": elem[0], "qargs": elem[1], "type": "op"})) return ret
def test_cnot_rxx_decompose(self): """Verify CNOT decomposition into RXX gate is correct""" cnot = Operator(CnotGate()) decomps = [ cnot_rxx_decompose(), cnot_rxx_decompose(plus_ry=True, plus_rxx=True), cnot_rxx_decompose(plus_ry=True, plus_rxx=False), cnot_rxx_decompose(plus_ry=False, plus_rxx=True), cnot_rxx_decompose(plus_ry=False, plus_rxx=False) ] for decomp in decomps: self.assertTrue(cnot.equiv(decomp))
def test_index_gates(self): """Verify finding the index of a inst/qarg/carg tuple in circuit.data.""" qr = QuantumRegister(2) qc = QuantumCircuit(qr) qc.h(0) qc.cx(0, 1) qc.h(1) qc.h(0) self.assertEqual(qc.data.index((HGate(), [qr[0]], [])), 0) self.assertEqual(qc.data.index((CnotGate(), [qr[0], qr[1]], [])), 1) self.assertEqual(qc.data.index((HGate(), [qr[1]], [])), 2)
def test_getitem_by_insertion_order(self): """Verify one can get circuit.data items in insertion order.""" qr = QuantumRegister(2) qc = QuantumCircuit(qr) qc.h(0) qc.cx(0, 1) qc.h(1) data = qc.data self.assertEqual(data[0], (HGate(), [qr[0]], [])) self.assertEqual(data[1], (CnotGate(), [qr[0], qr[1]], [])) self.assertEqual(data[2], (HGate(), [qr[1]], []))
def test_iter(self): """Verify circuit.data can behave as an iterator.""" qr = QuantumRegister(2) qc = QuantumCircuit(qr) qc.h(0) qc.cx(0, 1) qc.h(1) iter_ = iter(qc.data) self.assertEqual(next(iter_), (HGate(), [qr[0]], [])) self.assertEqual(next(iter_), (CnotGate(), [qr[0], qr[1]], [])) self.assertEqual(next(iter_), (HGate(), [qr[1]], [])) self.assertRaises(StopIteration, next, iter_)
def test_setting_data_is_validated(self): """Verify setting circuit.data is broadcast and validated.""" qr = QuantumRegister(2) qc = QuantumCircuit(qr) qc.data = [(HGate(), [qr[0]], []), (CnotGate(), [0, 1], []), (HGate(), [(qr, 1)], [])] expected_qc = QuantumCircuit(qr) expected_qc.h(0) expected_qc.cx(0, 1) expected_qc.h(1) self.assertEqual(qc, expected_qc) with self.assertRaises(QiskitError): qc.data = [(HGate(), [qr[0], qr[1]], [])] with self.assertRaises(QiskitError): qc.data = [(HGate(), [], [qr[0]])]
def test_extend_is_validated(self): """Verify extending circuit.data is broadcast and validated.""" qr = QuantumRegister(2) qc = QuantumCircuit(qr) qc.data.extend([(HGate(), [qr[0]], []), (CnotGate(), [0, 1], []), (HGate(), [(qr, 1)], [])]) expected_qc = QuantumCircuit(qr) expected_qc.h(0) expected_qc.cx(0, 1) expected_qc.h(1) self.assertEqual(qc, expected_qc) self.assertRaises(QiskitError, qc.data.extend, [(HGate(), [qr[0], qr[1]], [])]) self.assertRaises(QiskitError, qc.data.extend, [(HGate(), [], [qr[0]])])
def test_append_is_validated(self): """Verify appended gates via circuit.data are broadcast and validated.""" qr = QuantumRegister(2) qc = QuantumCircuit(qr) qc.data.append((HGate(), [qr[0]], [])) qc.data.append((CnotGate(), [0, 1], [])) qc.data.append((HGate(), [(qr, 1)], [])) expected_qc = QuantumCircuit(qr) expected_qc.h(0) expected_qc.cx(0, 1) expected_qc.h(1) self.assertEqual(qc, expected_qc) self.assertRaises(QiskitError, qc.data.append, (HGate(), [qr[0], qr[1]], [])) self.assertRaises(QiskitError, qc.data.append, (HGate(), [], [qr[0]]))
def test_insert_is_validated(self): """Verify inserting gates via circuit.data are broadcast and validated.""" qr = QuantumRegister(2) qc = QuantumCircuit(qr) qc.data.insert(0, (HGate(), [qr[0]], [])) qc.data.insert(1, (CnotGate(), [0, 1], [])) qc.data.insert(2, (HGate(), [qr[1]], [])) expected_qc = QuantumCircuit(qr) expected_qc.h(0) expected_qc.cx(0, 1) expected_qc.h(1) self.assertEqual(qc, expected_qc) self.assertRaises(CircuitError, qc.data.insert, 0, (HGate(), [qr[0], qr[1]], [])) self.assertRaises(CircuitError, qc.data.insert, 0, (HGate(), [], [qr[0]]))
def two_qubit_kak(unitary): """Decompose a two-qubit gate over SU(2)+CNOT using the KAK decomposition. Args: unitary (Unitary): a 4x4 unitary operator to decompose. Returns: QuantumCircuit: a circuit implementing the unitary over SU(2)+CNOT Raises: QiskitError: input not a unitary, or error in KAK decomposition. """ unitary_matrix = unitary.representation if unitary_matrix.shape != (4, 4): raise QiskitError("two_qubit_kak: Expected 4x4 matrix") phase = la.det(unitary_matrix)**(-1.0/4.0) # Make it in SU(4), correct phase at the end U = phase * unitary_matrix # B changes to the Bell basis B = (1.0/math.sqrt(2)) * np.array([[1, 1j, 0, 0], [0, 0, 1j, 1], [0, 0, 1j, -1], [1, -1j, 0, 0]], dtype=complex) # We also need B.conj().T below Bdag = B.conj().T # U' = Bdag . U . B Uprime = Bdag.dot(U.dot(B)) # M^2 = trans(U') . U' M2 = Uprime.T.dot(Uprime) # Diagonalize M2 # Must use diagonalization routine which finds a real orthogonal matrix P # when M2 is real. D, P = la.eig(M2) D = np.diag(D) # If det(P) == -1 then in O(4), apply a swap to make P in SO(4) if abs(la.det(P)+1) < 1e-5: swap = np.array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]], dtype=complex) P = P.dot(swap) D = swap.dot(D.dot(swap)) Q = np.sqrt(D) # array from elementwise sqrt # Want to take square root so that Q has determinant 1 if abs(la.det(Q)+1) < 1e-5: Q[0, 0] = -Q[0, 0] # Q^-1*P.T = P' -> QP' = P.T (solve for P' using Ax=b) Pprime = la.solve(Q, P.T) # K' now just U' * P * P' Kprime = Uprime.dot(P.dot(Pprime)) K1 = B.dot(Kprime.dot(P.dot(Bdag))) A = B.dot(Q.dot(Bdag)) K2 = B.dot(P.T.dot(Bdag)) # KAK = K1 * A * K2 KAK = K1.dot(A.dot(K2)) # Verify decomp matches input unitary. if la.norm(KAK - U) > 1e-6: raise QiskitError("two_qubit_kak: KAK decomposition " + "does not return input unitary.") # Compute parameters alpha, beta, gamma so that # A = exp(i * (alpha * XX + beta * YY + gamma * ZZ)) xx = np.array([[0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0], [1, 0, 0, 0]], dtype=complex) yy = np.array([[0, 0, 0, -1], [0, 0, 1, 0], [0, 1, 0, 0], [-1, 0, 0, 0]], dtype=complex) zz = np.array([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]], dtype=complex) A_real_tr = A.real.trace() alpha = math.atan2(A.dot(xx).imag.trace(), A_real_tr) beta = math.atan2(A.dot(yy).imag.trace(), A_real_tr) gamma = math.atan2(A.dot(zz).imag.trace(), A_real_tr) # K1 = kron(U1, U2) and K2 = kron(V1, V2) # Find the matrices U1, U2, V1, V2 # Find a block in K1 where U1_ij * [U2] is not zero L = K1[0:2, 0:2] if la.norm(L) < 1e-9: L = K1[0:2, 2:4] if la.norm(L) < 1e-9: L = K1[2:4, 2:4] # Remove the U1_ij prefactor Q = L.dot(L.conj().T) U2 = L / math.sqrt(Q[0, 0].real) # Now grab U1 given we know U2 R = K1.dot(np.kron(np.identity(2), U2.conj().T)) U1 = np.zeros((2, 2), dtype=complex) U1[0, 0] = R[0, 0] U1[0, 1] = R[0, 2] U1[1, 0] = R[2, 0] U1[1, 1] = R[2, 2] # Repeat K1 routine for K2 L = K2[0:2, 0:2] if la.norm(L) < 1e-9: L = K2[0:2, 2:4] if la.norm(L) < 1e-9: L = K2[2:4, 2:4] Q = np.dot(L, np.transpose(L.conjugate())) V2 = L / np.sqrt(Q[0, 0]) R = np.dot(K2, np.kron(np.identity(2), np.transpose(V2.conjugate()))) V1 = np.zeros_like(U1) V1[0, 0] = R[0, 0] V1[0, 1] = R[0, 2] V1[1, 0] = R[2, 0] V1[1, 1] = R[2, 2] if la.norm(np.kron(U1, U2) - K1) > 1e-4: raise QiskitError("two_qubit_kak: K1 != U1 x U2") if la.norm(np.kron(V1, V2) - K2) > 1e-4: raise QiskitError("two_qubit_kak: K2 != V1 x V2") test = la.expm(1j*(alpha * xx + beta * yy + gamma * zz)) if la.norm(A - test) > 1e-4: raise QiskitError("two_qubit_kak: " + "Matrix A does not match xx,yy,zz decomposition.") # Circuit that implements K1 * A * K2 (up to phase), using # Vatan and Williams Fig. 6 of quant-ph/0308006v3 # Include prefix and suffix single-qubit gates into U2, V1 respectively. V2 = np.array([[np.exp(1j*np.pi/4), 0], [0, np.exp(-1j*np.pi/4)]], dtype=complex).dot(V2) U1 = U1.dot(np.array([[np.exp(-1j*np.pi/4), 0], [0, np.exp(1j*np.pi/4)]], dtype=complex)) # Corrects global phase: exp(ipi/4)*phase' U1 = U1.dot(np.array([[np.exp(1j*np.pi/4), 0], [0, np.exp(1j*np.pi/4)]], dtype=complex)) U1 = phase.conjugate() * U1 # Test g1 = np.kron(V1, V2) g2 = np.array([[1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0]], dtype=complex) theta = 2*gamma - np.pi/2 Ztheta = np.array([[np.exp(1j*theta/2), 0], [0, np.exp(-1j*theta/2)]], dtype=complex) kappa = np.pi/2 - 2*alpha Ykappa = np.array([[math.cos(kappa/2), math.sin(kappa/2)], [-math.sin(kappa/2), math.cos(kappa/2)]], dtype=complex) g3 = np.kron(Ztheta, Ykappa) g4 = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]], dtype=complex) zeta = 2*beta - np.pi/2 Yzeta = np.array([[math.cos(zeta/2), math.sin(zeta/2)], [-math.sin(zeta/2), math.cos(zeta/2)]], dtype=complex) g5 = np.kron(np.identity(2), Yzeta) g6 = g2 g7 = np.kron(U1, U2) V = g2.dot(g1) V = g3.dot(V) V = g4.dot(V) V = g5.dot(V) V = g6.dot(V) V = g7.dot(V) if la.norm(V - U*phase.conjugate()) > 1e-6: raise QiskitError("two_qubit_kak: " + "sequence incorrect, unknown error") v1_param = euler_angles_1q(V1) v2_param = euler_angles_1q(V2) u1_param = euler_angles_1q(U1) u2_param = euler_angles_1q(U2) v1_gate = U3Gate(v1_param[0], v1_param[1], v1_param[2]) v2_gate = U3Gate(v2_param[0], v2_param[1], v2_param[2]) u1_gate = U3Gate(u1_param[0], u1_param[1], u1_param[2]) u2_gate = U3Gate(u2_param[0], u2_param[1], u2_param[2]) q = QuantumRegister(2) return_circuit = QuantumCircuit(q) return_circuit.append(v1_gate, [q[1]]) return_circuit.append(v2_gate, [q[0]]) return_circuit.append(CnotGate(), [q[0], q[1]]) gate = U3Gate(0.0, 0.0, -2.0*gamma + np.pi/2.0) return_circuit.append(gate, [q[1]]) gate = U3Gate(-np.pi/2.0 + 2.0*alpha, 0.0, 0.0) return_circuit.append(gate, [q[0]]) return_circuit.append(CnotGate(), [q[1], q[0]]) gate = U3Gate(-2.0*beta + np.pi/2.0, 0.0, 0.0) return_circuit.append(gate, [q[0]]) return_circuit.append(CnotGate(), [q[0], q[1]]) return_circuit.append(u1_gate, [q[1]]) return_circuit.append(u2_gate, [q[0]]) return return_circuit
def test_controlled_x(self): """Test creation of controlled x gate""" self.assertEqual(XGate().control(), CnotGate())
def test_controlled_cx(self): """Test creation of controlled cx gate""" self.assertEqual(CnotGate().control(), ToffoliGate())
def _define(self): definition = [] # q = c1, c2, b, anc q = QuantumRegister(self.total_n, "q") # No easy way to inverse other than reverse the order of gates and # invert them. if not self._inverse: rule = [ (PhiADDaGate(self.a, self.n, c1=q[0], c2=q[1]), [q[0], q[1]] + [q[i] for i in range(2, self.n + 2)], []), (PhiADDaGate(self.N, self.n, inverse=True), [q[i] for i in range(2, self.n + 2)], []), (QFTGate(self.n, inverse=True), [q[i] for i in range(2, self.n + 2)], []), (CnotGate(), [q[self.total_n - 2], q[self.total_n - 1]], []), (QFTGate(self.n), [q[i] for i in range(2, self.n + 2)], []), (PhiADDaGate(self.N, self.n, c1=q[self.total_n - 1]), [q[i] for i in range(2, self.n + 2)] + [q[self.total_n - 1]], []), (PhiADDaGate(self.a, self.n, c1=q[0], c2=q[1], inverse=True), [q[0], q[1]] + [q[i] for i in range(2, self.n + 2)], []), (QFTGate(self.n, inverse=True), [q[i] for i in range(2, self.n + 2)], []), (XGate(), [q[self.total_n - 2]], []), (CnotGate(), [q[self.total_n - 2], q[self.total_n - 1]], []), (XGate(), [q[self.total_n - 2]], []), (QFTGate(self.n), [q[i] for i in range(2, self.n + 2)], []), (PhiADDaGate(self.a, self.n, c1=q[0], c2=q[1]), [q[0], q[1]] + [q[i] for i in range(2, self.n + 2)], []), ] else: rule = [ (PhiADDaGate(self.a, self.n, c1=q[0], c2=q[1], inverse=True), [q[0], q[1]] + [q[i] for i in range(2, self.n + 2)], []), (QFTGate(self.n, inverse=True), [q[i] for i in range(2, self.n + 2)], []), (XGate(), [q[self.total_n - 2]], []), (CnotGate(), [q[self.total_n - 2], q[self.total_n - 1]], []), (XGate(), [q[self.total_n - 2]], []), (QFTGate(self.n), [q[i] for i in range(2, self.n + 2)], []), (PhiADDaGate(self.a, self.n, c1=q[0], c2=q[1]), [q[0], q[1]] + [q[i] for i in range(2, self.n + 2)], []), (PhiADDaGate(self.N, self.n, c1=q[self.total_n - 1], inverse=True), [q[i] for i in range(2, self.n + 2)] + [q[self.total_n - 1]], []), (QFTGate(self.n, inverse=True), [q[i] for i in range(2, self.n + 2)], []), (CnotGate(), [q[self.total_n - 2], q[self.total_n - 1]], []), (QFTGate(self.n), [q[i] for i in range(2, self.n + 2)], []), (PhiADDaGate(self.N, self.n), [q[i] for i in range(2, self.n + 2)], []), (PhiADDaGate(self.a, self.n, c1=q[0], c2=q[1], inverse=True), [q[0], q[1]] + [q[i] for i in range(2, self.n + 2)], []), ] for inst in rule: definition.append(inst) self.definition = definition