def test_adding_gate_under_different_parameters(self): """Verify a gate can be added under different sets of parameters.""" eq_lib = EquivalenceLibrary() theta = Parameter('theta') gate_theta = OneQubitOneParamGate(theta) equiv_theta = QuantumCircuit(1) equiv_theta.p(theta, 0) eq_lib.add_equivalence(gate_theta, equiv_theta) phi = Parameter('phi') gate_phi = OneQubitOneParamGate(phi) equiv_phi = QuantumCircuit(1) equiv_phi.rz(phi, 0) eq_lib.add_equivalence(gate_phi, equiv_phi) lam = Parameter('lam') gate_query = OneQubitOneParamGate(lam) entry = eq_lib.get_entry(gate_query) first_expected = QuantumCircuit(1) first_expected.p(lam, 0) second_expected = QuantumCircuit(1) second_expected.rz(lam, 0) self.assertEqual(len(entry), 2) self.assertEqual(entry[0], first_expected) self.assertEqual(entry[1], second_expected)
def test_multiple_variadic(self): """Verify circuit with multiple instances of variadic gate.""" eq_lib = EquivalenceLibrary() # e.g. MSGate oneq_gate = VariadicZeroParamGate(1) equiv = QuantumCircuit(1) equiv.append(OneQubitZeroParamGate(), [0]) eq_lib.add_equivalence(oneq_gate, equiv) twoq_gate = VariadicZeroParamGate(2) equiv = QuantumCircuit(2) equiv.append(TwoQubitZeroParamGate(), [0, 1]) eq_lib.add_equivalence(twoq_gate, equiv) qc = QuantumCircuit(2) qc.append(VariadicZeroParamGate(1), [0]) qc.append(VariadicZeroParamGate(2), [0, 1]) dag = circuit_to_dag(qc) expected = QuantumCircuit(2) expected.append(OneQubitZeroParamGate(), [0]) expected.append(TwoQubitZeroParamGate(), [0, 1]) expected_dag = circuit_to_dag(expected) pass_ = BasisTranslator(eq_lib, ['1q0p', '2q0p']) actual = pass_.run(dag) self.assertEqual(actual, expected_dag)
def test_adding_gate_and_partially_specified_gate(self): """Verify entries will different numbers of parameters will be returned.""" eq_lib = EquivalenceLibrary() theta = Parameter('theta') phi = Parameter('phi') # e.g. RGate(theta, phi) gate_full = OneQubitTwoParamGate(theta, phi) equiv_full = QuantumCircuit(1) equiv_full.append(U2Gate(theta, phi), [0]) eq_lib.add_equivalence(gate_full, equiv_full) gate_partial = OneQubitTwoParamGate(theta, 0) equiv_partial = QuantumCircuit(1) equiv_partial.rx(theta, 0) eq_lib.add_equivalence(gate_partial, equiv_partial) lam = Parameter('lam') gate_query = OneQubitTwoParamGate(lam, 0) entry = eq_lib.get_entry(gate_query) first_expected = QuantumCircuit(1) first_expected.append(U2Gate(lam, 0), [0]) second_expected = QuantumCircuit(1) second_expected.rx(lam, 0) self.assertEqual(len(entry), 2) self.assertEqual(entry[0], first_expected) self.assertEqual(entry[1], second_expected)
def test_two_single_two_gate_substitutions_with_global_phase(self): """Verify we correctly unroll gates through a single equivalence with global phase.""" eq_lib = EquivalenceLibrary() gate = OneQubitZeroParamGate() equiv = QuantumCircuit(1, global_phase=0.2) equiv.append(OneQubitOneParamGate(pi), [0]) equiv.append(OneQubitOneParamGate(pi), [0]) eq_lib.add_equivalence(gate, equiv) qc = QuantumCircuit(1, global_phase=0.1) qc.append(OneQubitZeroParamGate(), [0]) qc.append(OneQubitZeroParamGate(), [0]) dag = circuit_to_dag(qc) expected = QuantumCircuit(1, global_phase=0.1 + 2 * 0.2) expected.append(OneQubitOneParamGate(pi), [0]) expected.append(OneQubitOneParamGate(pi), [0]) expected.append(OneQubitOneParamGate(pi), [0]) expected.append(OneQubitOneParamGate(pi), [0]) expected_dag = circuit_to_dag(expected) pass_ = BasisTranslator(eq_lib, ['1q1p']) actual = pass_.run(dag) self.assertEqual(actual, expected_dag)
def test_double_substitution_with_global_phase(self): """Verify we correctly unroll gates through multiple equivalences with global phase.""" eq_lib = EquivalenceLibrary() gate = OneQubitZeroParamGate() equiv = QuantumCircuit(1, global_phase=0.2) equiv.append(OneQubitOneParamGate(pi), [0]) eq_lib.add_equivalence(gate, equiv) theta = Parameter('theta') gate = OneQubitOneParamGate(theta) equiv = QuantumCircuit(1, global_phase=0.4) equiv.append(OneQubitTwoParamGate(theta, pi / 2), [0]) eq_lib.add_equivalence(gate, equiv) qc = QuantumCircuit(1, global_phase=0.1) qc.append(OneQubitZeroParamGate(), [0]) dag = circuit_to_dag(qc) expected = QuantumCircuit(1, global_phase=0.1 + 0.2 + 0.4) expected.append(OneQubitTwoParamGate(pi, pi / 2), [0]) expected_dag = circuit_to_dag(expected) pass_ = BasisTranslator(eq_lib, ['1q2p']) actual = pass_.run(dag) self.assertEqual(actual, expected_dag)
def test_unroll_twice_until_we_get_to_eqlib(self): """Verify we unroll gates until we hit basis_gates.""" eq_lib = EquivalenceLibrary() base_gate = TestGate() equiv = QuantumCircuit(1) equiv.h(0) eq_lib.add_equivalence(base_gate, equiv) gate = TestCompositeGate() q = QuantumRegister(1, 'q') gate.definition = QuantumCircuit(q) gate.definition.data = [(TestGate(), [q[0]], [])] qc = QuantumCircuit(1) qc.append(gate, [0]) dag = circuit_to_dag(qc) out = UnrollCustomDefinitions(eq_lib, ['u3', 'cx']).run(dag) expected = QuantumCircuit(1) expected.append(TestGate(), [0]) expected_dag = circuit_to_dag(expected) self.assertEqual(out, expected_dag)
def test_nested_loop(self): """Test a simple if-else with parameters.""" qubits = [Qubit(), Qubit()] clbits = [Clbit(), Clbit()] cr = ClassicalRegister(bits=clbits) index1 = Parameter("index1") alpha = Parameter("alpha") gate = OneQubitOneParamGate(alpha) equiv = QuantumCircuit([qubits[0]]) equiv.append(OneQubitZeroParamGate(name="1q0p_2"), [qubits[0]]) equiv.append(OneQubitOneParamGate(alpha, name="1q1p_2"), [qubits[0]]) eq_lib = EquivalenceLibrary() eq_lib.add_equivalence(gate, equiv) circ = QuantumCircuit(qubits, cr) with circ.for_loop(range(3), loop_parameter=index1) as ind: with circ.while_loop((cr, 0)): circ.append(OneQubitOneParamGate(alpha * ind), [qubits[0]]) dag = circuit_to_dag(circ) dag_translated = BasisTranslator( eq_lib, ["if_else", "for_loop", "while_loop", "1q0p_2", "1q1p_2"]).run(dag) expected = QuantumCircuit(qubits, cr) with expected.for_loop(range(3), loop_parameter=index1) as ind: with expected.while_loop((cr, 0)): expected.append(OneQubitZeroParamGate(name="1q0p_2"), [qubits[0]]) expected.append( OneQubitOneParamGate(alpha * ind, name="1q1p_2"), [qubits[0]]) dag_expected = circuit_to_dag(expected) self.assertEqual(dag_translated, dag_expected)
def test_raise_if_gate_entry_shape_mismatch(self): """Verify we raise if adding a circuit and gate with different shapes.""" # This could be relaxed in the future to e.g. support ancilla management. eq_lib = EquivalenceLibrary() gate = OneQubitZeroParamGate() equiv = QuantumCircuit(2) equiv.h(0) with self.assertRaises(CircuitError): eq_lib.add_equivalence(gate, equiv)
def test_has_entry(self): """Verify we find an entry defined in the library.""" eq_lib = EquivalenceLibrary() gate = OneQubitZeroParamGate() equiv = QuantumCircuit(1) equiv.h(0) eq_lib.add_equivalence(gate, equiv) self.assertTrue(eq_lib.has_entry(gate)) self.assertTrue(eq_lib.has_entry(OneQubitZeroParamGate()))
def test_add_single_entry(self): """Verify an equivalence added to the library can be retrieved.""" eq_lib = EquivalenceLibrary() gate = OneQubitZeroParamGate() equiv = QuantumCircuit(1) equiv.h(0) eq_lib.add_equivalence(gate, equiv) entry = eq_lib.get_entry(gate) self.assertEqual(len(entry), 1) self.assertIsNot(entry[0], equiv) self.assertEqual(entry[0], equiv)
def test_raise_if_gate_equiv_parameter_mismatch(self): """Verify we raise if adding a circuit and gate with different sets of parameters.""" eq_lib = EquivalenceLibrary() theta = Parameter('theta') phi = Parameter('phi') gate = OneQubitOneParamGate(theta) equiv = QuantumCircuit(1) equiv.p(phi, 0) with self.assertRaises(CircuitError): eq_lib.add_equivalence(gate, equiv) with self.assertRaises(CircuitError): eq_lib.set_entry(gate, [equiv])
def test_get_through_empty_library_to_base(self): """Verify we find an entry defined only in the base library.""" base = EquivalenceLibrary() gate = OneQubitZeroParamGate() equiv = QuantumCircuit(1) equiv.h(0) base.add_equivalence(gate, equiv) eq_lib = EquivalenceLibrary(base=base) entry = eq_lib.get_entry(gate) self.assertEqual(len(entry), 1) self.assertIsNot(entry[0], equiv) self.assertEqual(entry[0], equiv)
def test_set_entry(self): """Verify setting an entry overrides any previously added.""" eq_lib = EquivalenceLibrary() gate = OneQubitZeroParamGate() first_equiv = QuantumCircuit(1) first_equiv.h(0) eq_lib.add_equivalence(gate, first_equiv) second_equiv = QuantumCircuit(1) second_equiv.append(U2Gate(0, np.pi), [0]) eq_lib.set_entry(gate, [second_equiv]) entry = eq_lib.get_entry(gate) self.assertEqual(len(entry), 1) self.assertEqual(entry[0], second_equiv)
def test_dont_unroll_a_gate_in_eq_lib(self): """Verify we don't unroll a gate found in equivalence_library.""" eq_lib = EquivalenceLibrary() gate = TestGate() equiv = QuantumCircuit(1) equiv.h(0) eq_lib.add_equivalence(gate, equiv) qc = QuantumCircuit(1) qc.append(gate, [0]) dag = circuit_to_dag(qc) out = UnrollCustomDefinitions(eq_lib, ['u3', 'cx']).run(dag) expected = qc.copy() expected_dag = circuit_to_dag(expected) self.assertEqual(out, expected_dag)
def test_add_double_entry(self): """Verify separately added equivalences can be retrieved.""" eq_lib = EquivalenceLibrary() gate = OneQubitZeroParamGate() first_equiv = QuantumCircuit(1) first_equiv.h(0) eq_lib.add_equivalence(gate, first_equiv) second_equiv = QuantumCircuit(1) second_equiv.append(U2Gate(0, np.pi), [0]) eq_lib.add_equivalence(gate, second_equiv) entry = eq_lib.get_entry(gate) self.assertEqual(len(entry), 2) self.assertEqual(entry[0], first_equiv) self.assertEqual(entry[1], second_equiv)
def test_set_entry(self): """Verify we find only equivalences from top when explicitly set.""" base = EquivalenceLibrary() gate = OneQubitZeroParamGate() first_equiv = QuantumCircuit(1) first_equiv.h(0) base.add_equivalence(gate, first_equiv) eq_lib = EquivalenceLibrary(base=base) second_equiv = QuantumCircuit(1) second_equiv.append(U2Gate(0, np.pi), [0]) eq_lib.set_entry(gate, [second_equiv]) entry = eq_lib.get_entry(gate) self.assertEqual(len(entry), 1) self.assertEqual(entry[0], second_equiv)
def test_add_equivalence(self): """Verify we find all equivalences if a gate is added to top and base.""" base = EquivalenceLibrary() gate = OneQubitZeroParamGate() first_equiv = QuantumCircuit(1) first_equiv.h(0) base.add_equivalence(gate, first_equiv) eq_lib = EquivalenceLibrary(base=base) second_equiv = QuantumCircuit(1) second_equiv.append(U2Gate(0, np.pi), [0]) eq_lib.add_equivalence(gate, second_equiv) entry = eq_lib.get_entry(gate) self.assertEqual(len(entry), 2) self.assertEqual(entry[0], second_equiv) self.assertEqual(entry[1], first_equiv)
def test_if_else(self): """Test a simple if-else with parameters.""" qubits = [Qubit(), Qubit()] clbits = [Clbit(), Clbit()] alpha = Parameter("alpha") beta = Parameter("beta") gate = OneQubitOneParamGate(alpha) equiv = QuantumCircuit([qubits[0]]) equiv.append(OneQubitZeroParamGate(name="1q0p_2"), [qubits[0]]) equiv.append(OneQubitOneParamGate(alpha, name="1q1p_2"), [qubits[0]]) eq_lib = EquivalenceLibrary() eq_lib.add_equivalence(gate, equiv) circ = QuantumCircuit(qubits, clbits) circ.append(OneQubitOneParamGate(beta), [qubits[0]]) circ.measure(qubits[0], clbits[1]) with circ.if_test((clbits[1], 0)) as else_: circ.append(OneQubitOneParamGate(alpha), [qubits[0]]) circ.append(TwoQubitZeroParamGate(), qubits) with else_: circ.append(TwoQubitZeroParamGate(), [qubits[1], qubits[0]]) dag = circuit_to_dag(circ) dag_translated = BasisTranslator( eq_lib, ["if_else", "1q0p_2", "1q1p_2", "2q0p"]).run(dag) expected = QuantumCircuit(qubits, clbits) expected.append(OneQubitZeroParamGate(name="1q0p_2"), [qubits[0]]) expected.append(OneQubitOneParamGate(beta, name="1q1p_2"), [qubits[0]]) expected.measure(qubits[0], clbits[1]) with expected.if_test((clbits[1], 0)) as else_: expected.append(OneQubitZeroParamGate(name="1q0p_2"), [qubits[0]]) expected.append(OneQubitOneParamGate(alpha, name="1q1p_2"), [qubits[0]]) expected.append(TwoQubitZeroParamGate(), qubits) with else_: expected.append(TwoQubitZeroParamGate(), [qubits[1], qubits[0]]) dag_expected = circuit_to_dag(expected) self.assertEqual(dag_translated, dag_expected)
def test_parameter_in_parameter_out(self): """Verify query parameters will be included in returned entry.""" eq_lib = EquivalenceLibrary() theta = Parameter('theta') gate = OneQubitOneParamGate(theta) equiv = QuantumCircuit(1) equiv.p(theta, 0) eq_lib.add_equivalence(gate, equiv) phi = Parameter('phi') gate_phi = OneQubitOneParamGate(phi) entry = eq_lib.get_entry(gate_phi) expected = QuantumCircuit(1) expected.p(phi, 0) self.assertEqual(len(entry), 1) self.assertEqual(entry[0], expected)
def test_partial_parameter_in_parameter_out(self): """Verify numeric query parameters will be included in returned entry.""" eq_lib = EquivalenceLibrary() theta = Parameter('theta') phi = Parameter('phi') gate = OneQubitTwoParamGate(theta, phi) equiv = QuantumCircuit(1) equiv.u(theta, phi, 0, 0) eq_lib.add_equivalence(gate, equiv) lam = Parameter('lam') gate_partial = OneQubitTwoParamGate(lam, 1.59) entry = eq_lib.get_entry(gate_partial) expected = QuantumCircuit(1) expected.u(lam, 1.59, 0, 0) self.assertEqual(len(entry), 1) self.assertEqual(entry[0], expected)
def test_diamond_path(self): """Verify we find a path when there are multiple paths to the target basis.""" eq_lib = EquivalenceLibrary() # Path 1: 1q0p -> 1q1p(pi) -> 1q2p(pi, pi/2) gate = OneQubitZeroParamGate() equiv = QuantumCircuit(1) equiv.append(OneQubitOneParamGate(pi), [0]) eq_lib.add_equivalence(gate, equiv) theta = Parameter('theta') gate = OneQubitOneParamGate(theta) equiv = QuantumCircuit(1) equiv.append(OneQubitTwoParamGate(theta, pi / 2), [0]) eq_lib.add_equivalence(gate, equiv) # Path 2: 1q0p -> 1q1p_prime(pi/2) -> 1q2p(2 * pi/2, pi/2) gate = OneQubitZeroParamGate() equiv = QuantumCircuit(1) equiv.append(OneQubitOneParamPrimeGate(pi / 2), [0]) eq_lib.add_equivalence(gate, equiv) alpha = Parameter('alpha') gate = OneQubitOneParamPrimeGate(alpha) equiv = QuantumCircuit(1) equiv.append(OneQubitTwoParamGate(2 * alpha, pi / 2), [0]) eq_lib.add_equivalence(gate, equiv) qc = QuantumCircuit(1) qc.append(OneQubitZeroParamGate(), [0]) dag = circuit_to_dag(qc) expected = QuantumCircuit(1) expected.append(OneQubitTwoParamGate(pi, pi / 2), [0]) expected_dag = circuit_to_dag(expected) pass_ = BasisTranslator(eq_lib, ['1q2p']) actual = pass_.run(dag) self.assertEqual(actual, expected_dag)
def test_has_entry_in_base(self): """Verify we find an entry defined in the base library.""" base_eq_lib = EquivalenceLibrary() gate = OneQubitZeroParamGate() equiv = QuantumCircuit(1) equiv.h(0) base_eq_lib.add_equivalence(gate, equiv) eq_lib = EquivalenceLibrary(base=base_eq_lib) self.assertTrue(eq_lib.has_entry(gate)) self.assertTrue(eq_lib.has_entry(OneQubitZeroParamGate())) gate = OneQubitZeroParamGate() equiv2 = QuantumCircuit(1) equiv.append(U2Gate(0, np.pi), [0]) eq_lib.add_equivalence(gate, equiv2) self.assertTrue(eq_lib.has_entry(gate)) self.assertTrue(eq_lib.has_entry(OneQubitZeroParamGate()))
phi = Parameter('phi') lamda = Parameter('lamda') u3 = U3Gate(theta, phi, lamda) u2 = U2Gate(theta, phi) u1 = U1Gate(theta) ccx = CCXGate() q = QuantumRegister(1, 'q') equiv_u3 = QuantumCircuit(q) equiv_u3.append(RZGate(phi+(pi/2)), [q[0]], []) equiv_u3.append(HGate(),[q[0]], [] ) equiv_u3.append(RZGate(theta),[q[0]], []) equiv_u3.append(HGate(), [q[0]], []) equiv_u3.append(RZGate(lamda-(pi/2)),[q[0]], 0) eq_lib.add_equivalence(u3, equiv_u3) q = QuantumRegister(1, 'q') equiv_u2 = QuantumCircuit(q) equiv_u2.append(RZGate(theta+(pi/2)), [q[0]], []) equiv_u2.append(HGate(),[q[0]], [] ) equiv_u2.append(RZGate(pi/2),[q[0]], []) equiv_u2.append(HGate(), [q[0]], []) equiv_u2.append(RZGate(phi-(pi/2)),[q[0]], 0) eq_lib.add_equivalence(u2, equiv_u2) q = QuantumRegister(1, 'q') equiv_u1 = QuantumCircuit(q) equiv_u1.append(RZGate(theta), [q[0]], []) eq_lib.add_equivalence(u1, equiv_u1)