class TestProgramConverter: """Test that PyQuil Program instances are properly converted.""" @pytest.mark.parametrize( "pyquil_operation,expected_pl_operation", [ (g.I(0), qml.Identity(wires=[0])), (g.H(0), qml.Hadamard(0)), (g.H(0).dagger(), qml.Hadamard(0).inv()), (g.H(0).dagger().dagger(), qml.Hadamard(0).inv().inv()), (g.S(0), qml.S(wires=[0])), (g.S(0).dagger(), qml.S(wires=[0]).inv()), (g.S(0).dagger().dagger(), qml.S(wires=[0]).inv().inv()), (g.T(0), qml.T(wires=[0])), (g.T(0).dagger(), qml.T(wires=[0]).inv()), (g.T(0).dagger().dagger(), qml.T(wires=[0]).inv().inv()), (g.X(0), qml.PauliX(0)), (g.X(0).dagger(), qml.PauliX(0).inv()), (g.X(0).dagger().dagger(), qml.PauliX(0).inv().inv()), (g.X(0).controlled(1), qml.CNOT(wires=[1, 0])), (g.X(0).controlled(1).dagger(), qml.CNOT(wires=[1, 0]).inv()), (g.X(0).controlled(1).dagger().dagger(), qml.CNOT(wires=[1, 0]).inv().inv()), (g.X(0).controlled(1).controlled(2), plf.ops.CCNOT(wires=[2, 1, 0])), (g.X(0).controlled(1).controlled(2).dagger(), plf.ops.CCNOT(wires=[2, 1, 0]).inv()), ( g.X(0).controlled(1).controlled(2).dagger().dagger(), plf.ops.CCNOT(wires=[2, 1, 0]).inv().inv(), ), (g.Y(0), qml.PauliY(0)), (g.Y(0).dagger(), qml.PauliY(0).inv()), (g.Y(0).dagger().dagger(), qml.PauliY(0).inv().inv()), (g.Z(0), qml.PauliZ(0)), (g.Z(0).dagger(), qml.PauliZ(0).inv()), (g.Z(0).dagger().dagger(), qml.PauliZ(0).inv().inv()), (g.Z(0).controlled(1), qml.CZ(wires=[1, 0])), (g.Z(0).controlled(1).dagger(), qml.CZ(wires=[1, 0]).inv()), (g.Z(0).controlled(1).dagger().dagger(), qml.CZ(wires=[1, 0]).inv().inv()), (g.CNOT(0, 1), qml.CNOT(wires=[0, 1])), (g.CNOT(0, 1).dagger(), qml.CNOT(wires=[0, 1]).inv()), (g.CNOT(0, 1).dagger().dagger(), qml.CNOT(wires=[0, 1]).inv().inv()), (g.CNOT(0, 1).controlled(2), plf.ops.CCNOT(wires=[2, 0, 1])), (g.CNOT(0, 1).controlled(2).dagger(), plf.ops.CCNOT(wires=[2, 0, 1]).inv()), ( g.CNOT(0, 1).controlled(2).dagger().dagger(), plf.ops.CCNOT(wires=[2, 0, 1]).inv().inv(), ), (g.SWAP(0, 1), qml.SWAP(wires=[0, 1])), (g.SWAP(0, 1).dagger(), qml.SWAP(wires=[0, 1]).inv()), (g.SWAP(0, 1).dagger().dagger(), qml.SWAP(wires=[0, 1]).inv().inv()), (g.SWAP(0, 1).controlled(2), qml.CSWAP(wires=[2, 0, 1])), (g.SWAP(0, 1).controlled(2).dagger(), qml.CSWAP(wires=[2, 0, 1]).inv()), (g.SWAP(0, 1).controlled(2).dagger().dagger(), qml.CSWAP(wires=[2, 0, 1]).inv().inv()), (g.ISWAP(0, 1), plf.ops.ISWAP(wires=[0, 1])), (g.ISWAP(0, 1).dagger(), plf.ops.ISWAP(wires=[0, 1]).inv()), (g.ISWAP(0, 1).dagger().dagger(), plf.ops.ISWAP(wires=[0, 1]).inv().inv()), (g.PSWAP(0.3, 0, 1), plf.ops.PSWAP(0.3, wires=[0, 1])), (g.PSWAP(0.3, 0, 1).dagger(), plf.ops.PSWAP(0.3, wires=[0, 1 ]).inv()), (g.PSWAP(0.3, 0, 1).dagger().dagger(), plf.ops.PSWAP(0.3, wires=[0, 1]).inv().inv()), (g.CZ(0, 1), qml.CZ(wires=[0, 1])), (g.CZ(0, 1).dagger(), qml.CZ(wires=[0, 1]).inv()), (g.CZ(0, 1).dagger().dagger(), qml.CZ(wires=[0, 1]).inv().inv()), (g.PHASE(0.3, 0), qml.PhaseShift(0.3, wires=[0])), (g.PHASE(0.3, 0).dagger(), qml.PhaseShift(0.3, wires=[0]).inv()), (g.PHASE(0.3, 0).dagger().dagger(), qml.PhaseShift( 0.3, wires=[0]).inv().inv()), (g.PHASE(0.3, 0).controlled(1), plf.ops.CPHASE( 0.3, 3, wires=[1, 0])), (g.PHASE(0.3, 0).controlled(1).dagger(), plf.ops.CPHASE(0.3, 3, wires=[1, 0]).inv()), ( g.PHASE(0.3, 0).controlled(1).dagger().dagger(), plf.ops.CPHASE(0.3, 3, wires=[1, 0]).inv().inv(), ), (g.RX(0.3, 0), qml.RX(0.3, wires=[0])), (g.RX(0.3, 0).dagger(), qml.RX(0.3, wires=[0]).inv()), (g.RX(0.3, 0).dagger().dagger(), qml.RX(0.3, wires=[0]).inv().inv()), (g.RX(0.3, 0).controlled(1), qml.CRX(0.3, wires=[1, 0])), (g.RX(0.3, 0).controlled(1).dagger(), qml.CRX(0.3, wires=[1, 0]).inv()), (g.RX(0.3, 0).controlled(1).dagger().dagger(), qml.CRX(0.3, wires=[1, 0]).inv().inv()), (g.RY(0.3, 0), qml.RY(0.3, wires=[0])), (g.RY(0.3, 0).dagger(), qml.RY(0.3, wires=[0]).inv()), (g.RY(0.3, 0).dagger().dagger(), qml.RY(0.3, wires=[0]).inv().inv()), (g.RY(0.3, 0).controlled(1), qml.CRY(0.3, wires=[1, 0])), (g.RY(0.3, 0).controlled(1).dagger(), qml.CRY(0.3, wires=[1, 0]).inv()), (g.RY(0.3, 0).controlled(1).dagger().dagger(), qml.CRY(0.3, wires=[1, 0]).inv().inv()), (g.RZ(0.3, 0), qml.RZ(0.3, wires=[0])), (g.RZ(0.3, 0).dagger(), qml.RZ(0.3, wires=[0]).inv()), (g.RZ(0.3, 0).dagger().dagger(), qml.RZ(0.3, wires=[0]).inv().inv()), (g.RZ(0.3, 0).controlled(1), qml.CRZ(0.3, wires=[1, 0])), (g.RZ(0.3, 0).controlled(1).dagger(), qml.CRZ(0.3, wires=[1, 0]).inv()), (g.RZ(0.3, 0).controlled(1).dagger().dagger(), qml.CRZ(0.3, wires=[1, 0]).inv().inv()), (g.CPHASE(0.3, 0, 1), plf.ops.CPHASE(0.3, 3, wires=[0, 1])), (g.CPHASE(0.3, 0, 1).dagger(), plf.ops.CPHASE(0.3, 3, wires=[0, 1]).inv()), ( g.CPHASE(0.3, 0, 1).dagger().dagger(), plf.ops.CPHASE(0.3, 3, wires=[0, 1]).inv().inv(), ), (g.CPHASE00(0.3, 0, 1), plf.ops.CPHASE(0.3, 0, wires=[0, 1])), (g.CPHASE00(0.3, 0, 1).dagger(), plf.ops.CPHASE(0.3, 0, wires=[0, 1]).inv()), ( g.CPHASE00(0.3, 0, 1).dagger().dagger(), plf.ops.CPHASE(0.3, 0, wires=[0, 1]).inv().inv(), ), (g.CPHASE01(0.3, 0, 1), plf.ops.CPHASE(0.3, 1, wires=[0, 1])), (g.CPHASE01(0.3, 0, 1).dagger(), plf.ops.CPHASE(0.3, 1, wires=[0, 1]).inv()), ( g.CPHASE01(0.3, 0, 1).dagger().dagger(), plf.ops.CPHASE(0.3, 1, wires=[0, 1]).inv().inv(), ), (g.CPHASE10(0.3, 0, 1), plf.ops.CPHASE(0.3, 2, wires=[0, 1])), (g.CPHASE10(0.3, 0, 1).dagger(), plf.ops.CPHASE(0.3, 2, wires=[0, 1]).inv()), ( g.CPHASE10(0.3, 0, 1).dagger().dagger(), plf.ops.CPHASE(0.3, 2, wires=[0, 1]).inv().inv(), ), (g.CSWAP(0, 1, 2), qml.CSWAP(wires=[0, 1, 2])), (g.CSWAP(0, 1, 2).dagger(), qml.CSWAP(wires=[0, 1, 2]).inv()), (g.CSWAP(0, 1, 2).dagger().dagger(), qml.CSWAP(wires=[0, 1, 2]).inv().inv()), (g.CCNOT(0, 1, 2), plf.ops.CCNOT(wires=[0, 1, 2])), (g.CCNOT(0, 1, 2).dagger(), plf.ops.CCNOT(wires=[0, 1, 2]).inv()), (g.CCNOT(0, 1, 2).dagger().dagger(), plf.ops.CCNOT(wires=[0, 1, 2]).inv().inv()), ], ) def test_convert_operation(self, pyquil_operation, expected_pl_operation): """Test that single pyquil gates are properly converted.""" program = pyquil.Program() program += pyquil_operation with OperationRecorder() as rec: loader = load_program(program) loader(wires=range(len(loader.defined_qubits))) assert rec.queue[0].name == expected_pl_operation.name assert rec.queue[0].wires == expected_pl_operation.wires assert rec.queue[0].params == expected_pl_operation.params def test_convert_simple_program(self): """Test that a simple program is properly converted.""" program = pyquil.Program() program += g.H(0) program += g.RZ(0.34, 1) program += g.CNOT(0, 3) program += g.H(2) program += g.H(7) program += g.X(7) program += g.Y(1) program += g.RZ(0.34, 1) with OperationRecorder() as rec: load_program(program)(wires=range(5)) # The wires should be assigned as # 0 1 2 3 7 # 0 1 2 3 4 expected_queue = [ qml.Hadamard(0), qml.RZ(0.34, wires=[1]), qml.CNOT(wires=[0, 3]), qml.Hadamard(2), qml.Hadamard(4), qml.PauliX(4), qml.PauliY(1), qml.RZ(0.34, wires=[1]), ] for converted, expected in zip(rec.queue, expected_queue): assert converted.name == expected.name assert converted.wires == expected.wires assert converted.params == expected.params def test_convert_simple_program_with_parameters(self): """Test that a simple program with parameters is properly converted.""" program = pyquil.Program() alpha = program.declare("alpha", "REAL") beta = program.declare("beta", "REAL") gamma = program.declare("gamma", "REAL") program += g.H(0) program += g.CNOT(0, 1) program += g.RX(alpha, 1) program += g.RZ(beta, 1) program += g.RX(gamma, 1) program += g.CNOT(0, 1) program += g.H(0) a, b, c = 0.1, 0.2, 0.3 parameter_map = {"alpha": a, "beta": b, "gamma": c} with OperationRecorder() as rec: load_program(program)(wires=range(2), parameter_map=parameter_map) expected_queue = [ qml.Hadamard(0), qml.CNOT(wires=[0, 1]), qml.RX(0.1, wires=[1]), qml.RZ(0.2, wires=[1]), qml.RX(0.3, wires=[1]), qml.CNOT(wires=[0, 1]), qml.Hadamard(0), ] for converted, expected in zip(rec.queue, expected_queue): assert converted.name == expected.name assert converted.wires == expected.wires assert converted.params == expected.params def test_parameter_not_given_error(self): """Test that the correct error is raised if a parameter is not given.""" program = pyquil.Program() alpha = program.declare("alpha", "REAL") beta = program.declare("beta", "REAL") program += g.H(0) program += g.CNOT(0, 1) program += g.RX(alpha, 1) program += g.RZ(beta, 1) a = 0.1 parameter_map = {"alpha": a} with pytest.raises( qml.DeviceError, match= "The PyQuil program defines a variable .* that is not present in the given variable map", ): load_program(program)(wires=range(2), parameter_map=parameter_map) def test_convert_simple_program_with_parameters_mixed_keys(self): """Test that a parametrized program is properly converted when the variable map contains mixed key types.""" program = pyquil.Program() alpha = program.declare("alpha", "REAL") beta = program.declare("beta", "REAL") gamma = program.declare("gamma", "REAL") delta = program.declare("delta", "REAL") program += g.H(0) program += g.CNOT(0, 1) program += g.RX(alpha, 1) program += g.RZ(beta, 1) program += g.RX(gamma, 1) program += g.CNOT(0, 1) program += g.RZ(delta, 0) program += g.H(0) a, b, c, d = 0.1, 0.2, 0.3, 0.4 parameter_map = {"alpha": a, beta: b, gamma: c, "delta": d} with OperationRecorder() as rec: load_program(program)(wires=range(2), parameter_map=parameter_map) expected_queue = [ qml.Hadamard(0), qml.CNOT(wires=[0, 1]), qml.RX(0.1, wires=[1]), qml.RZ(0.2, wires=[1]), qml.RX(0.3, wires=[1]), qml.CNOT(wires=[0, 1]), qml.RZ(0.4, wires=[0]), qml.Hadamard(0), ] for converted, expected in zip(rec.queue, expected_queue): assert converted.name == expected.name assert converted.wires == expected.wires assert converted.params == expected.params def test_convert_simple_program_wire_assignment(self): """Test that the assignment of qubits to wires works as expected.""" program = pyquil.Program() program += g.H(0) program += g.RZ(0.34, 1) program += g.CNOT(0, 3) program += g.H(2) program += g.H(7) program += g.X(7) program += g.Y(1) program += g.RZ(0.34, 1) with OperationRecorder() as rec: load_program(program)(wires=[3, 6, 4, 9, 1]) # The wires should be assigned as # 0 1 2 3 7 # 3 6 4 9 1 expected_queue = [ qml.Hadamard(3), qml.RZ(0.34, wires=[6]), qml.CNOT(wires=[3, 9]), qml.Hadamard(4), qml.Hadamard(1), qml.PauliX(1), qml.PauliY(6), qml.RZ(0.34, wires=[6]), ] for converted, expected in zip(rec.queue, expected_queue): assert converted.name == expected.name assert converted.wires == expected.wires assert converted.params == expected.params @pytest.mark.parametrize("wires", [[0, 1, 2, 3], [4, 5]]) def test_convert_wire_error(self, wires): """Test that the conversion raises an error if the given number of wires doesn't match the number of qubits in the Program.""" program = pyquil.Program() program += g.H(0) program += g.H(1) program += g.H(2) with pytest.raises( qml.DeviceError, match= "The number of given wires does not match the number of qubits in the PyQuil Program", ): load_program(program)(wires=wires) def test_convert_program_with_inverses(self): """Test that a program with inverses is properly converted.""" program = pyquil.Program() program += g.H(0) program += g.RZ(0.34, 1).dagger() program += g.CNOT(0, 3).dagger() program += g.H(2) program += g.H(7).dagger().dagger() program += g.X(7).dagger() program += g.X(7) program += g.Y(1) program += g.RZ(0.34, 1) with OperationRecorder() as rec: load_program(program)(wires=range(5)) expected_queue = [ qml.Hadamard(0), qml.RZ(0.34, wires=[1]).inv(), qml.CNOT(wires=[0, 3]).inv(), qml.Hadamard(2), qml.Hadamard(4), qml.PauliX(4).inv(), qml.PauliX(4), qml.PauliY(1), qml.RZ(0.34, wires=[1]), ] for converted, expected in zip(rec.queue, expected_queue): assert converted.name == expected.name assert converted.wires == expected.wires assert converted.params == expected.params def test_convert_program_with_controlled_operations(self): """Test that a program with controlled operations is properly converted.""" program = pyquil.Program() program += g.RZ(0.34, 1) program += g.RY(0.2, 3).controlled(2) program += g.RX(0.4, 2).controlled(0) program += g.CNOT(1, 4) program += g.CNOT(1, 6).controlled(3) program += g.X(3).controlled(4).controlled(1) with OperationRecorder() as rec: load_program(program)(wires=range(6)) expected_queue = [ qml.RZ(0.34, wires=[1]), qml.CRY(0.2, wires=[2, 3]), qml.CRX(0.4, wires=[0, 2]), qml.CNOT(wires=[1, 4]), plf.ops.CCNOT(wires=[3, 1, 5]), plf.ops.CCNOT(wires=[1, 4, 3]), ] for converted, expected in zip(rec.queue, expected_queue): assert converted.name == expected.name assert converted.wires == expected.wires assert converted.params == expected.params def test_convert_program_with_controlled_operations_not_in_pl_core( self, tol): """Test that a program with controlled operations out of scope of PL core/PLF is properly converted, i.e. the operations are replaced with controlled operations.""" program = pyquil.Program() CS_matrix = np.eye(4, dtype=complex) CS_matrix[3, 3] = 1j CCT_matrix = np.eye(8, dtype=complex) CCT_matrix[7, 7] = np.exp(1j * np.pi / 4) program += g.CNOT(0, 1) program += g.S(0).controlled(1) program += g.S(1).controlled(0) program += g.T(0).controlled(1).controlled(2) program += g.T(1).controlled(0).controlled(2) program += g.T(2).controlled(1).controlled(0) with OperationRecorder() as rec: load_program(program)(wires=range(3)) expected_queue = [ qml.CNOT(wires=[0, 1]), qml.QubitUnitary(CS_matrix, wires=[1, 0]), qml.QubitUnitary(CS_matrix, wires=[0, 1]), qml.QubitUnitary(CCT_matrix, wires=[2, 1, 0]), qml.QubitUnitary(CCT_matrix, wires=[2, 0, 1]), qml.QubitUnitary(CCT_matrix, wires=[0, 1, 2]), ] for converted, expected in zip(rec.queue, expected_queue): assert converted.name == expected.name assert converted.wires == expected.wires assert np.allclose(converted.params, expected.params, atol=tol, rtol=0) def test_convert_program_with_controlled_dagger_operations(self): """Test that a program that combines controlled and daggered operations is properly converted.""" program = pyquil.Program() program += g.CNOT(0, 1).controlled(2) program += g.CNOT(0, 1).dagger().controlled(2) program += g.CNOT(0, 1).controlled(2).dagger() program += g.CNOT(0, 1).dagger().controlled(2).dagger() program += g.RX(0.3, 3).controlled(4) program += g.RX(0.2, 3).controlled(4).dagger() program += g.RX(0.3, 3).dagger().controlled(4) program += g.RX(0.2, 3).dagger().controlled(4).dagger() program += g.X(2).dagger().controlled(4).controlled(1).dagger() program += g.X(0).dagger().controlled(4).controlled(1) program += g.X(0).dagger().controlled(4).dagger().dagger().controlled( 1).dagger() with OperationRecorder() as rec: load_program(program)(wires=range(5)) expected_queue = [ plf.ops.CCNOT(wires=[2, 0, 1]), plf.ops.CCNOT(wires=[2, 0, 1]).inv(), plf.ops.CCNOT(wires=[2, 0, 1]).inv(), plf.ops.CCNOT(wires=[2, 0, 1]), qml.CRX(0.3, wires=[4, 3]), qml.CRX(0.2, wires=[4, 3]).inv(), qml.CRX(0.3, wires=[4, 3]).inv(), qml.CRX(0.2, wires=[4, 3]), plf.ops.CCNOT(wires=[1, 4, 2]), plf.ops.CCNOT(wires=[1, 4, 0]).inv(), plf.ops.CCNOT(wires=[1, 4, 0]), ] for converted, expected in zip(rec.queue, expected_queue): assert converted.name == expected.name assert converted.wires == expected.wires assert converted.params == expected.params def test_convert_program_with_defgates(self): """Test that a program that defines its own gates is properly converted.""" program = pyquil.Program() sqrt_x = np.array([[0.5 + 0.5j, 0.5 - 0.5j], [0.5 - 0.5j, 0.5 + 0.5j]]) sqrt_x_t2 = np.kron(sqrt_x, sqrt_x) sqrt_x_t3 = np.kron(sqrt_x, sqrt_x_t2) sqrt_x_definition = pyquil.quil.DefGate("SQRT-X", sqrt_x) SQRT_X = sqrt_x_definition.get_constructor() sqrt_x_t2_definition = pyquil.quil.DefGate("SQRT-X-T2", sqrt_x_t2) SQRT_X_T2 = sqrt_x_t2_definition.get_constructor() sqrt_x_t3_definition = pyquil.quil.DefGate("SQRT-X-T3", sqrt_x_t3) SQRT_X_T3 = sqrt_x_t3_definition.get_constructor() program += sqrt_x_definition program += sqrt_x_t2_definition program += sqrt_x_t3_definition program += g.CNOT(0, 1) program += SQRT_X(0) program += SQRT_X_T2(1, 2) program += SQRT_X_T3(1, 0, 2) program += g.CNOT(0, 1) program += g.CNOT(1, 2) program += g.CNOT(2, 0) with OperationRecorder() as rec: load_program(program)(wires=range(3)) expected_queue = [ qml.CNOT(wires=[0, 1]), qml.QubitUnitary(sqrt_x, wires=[0]), qml.QubitUnitary(sqrt_x_t2, wires=[1, 2]), qml.QubitUnitary(sqrt_x_t3, wires=[1, 0, 2]), qml.CNOT(wires=[0, 1]), qml.CNOT(wires=[1, 2]), qml.CNOT(wires=[2, 0]), ] for converted, expected in zip(rec.queue, expected_queue): assert converted.name == expected.name assert converted.wires == expected.wires assert converted.params == expected.params def test_convert_program_with_controlled_defgates(self, tol): """Test that a program with controlled defined gates is properly converted.""" program = pyquil.Program() sqrt_x = np.array([[0.5 + 0.5j, 0.5 - 0.5j], [0.5 - 0.5j, 0.5 + 0.5j]]) sqrt_x_t2 = np.kron(sqrt_x, sqrt_x) c_sqrt_x = np.eye(4, dtype=complex) c_sqrt_x[2:, 2:] = sqrt_x c_sqrt_x_t2 = np.eye(8, dtype=complex) c_sqrt_x_t2[4:, 4:] = sqrt_x_t2 sqrt_x_definition = pyquil.quil.DefGate("SQRT-X", sqrt_x) SQRT_X = sqrt_x_definition.get_constructor() sqrt_x_t2_definition = pyquil.quil.DefGate("SQRT-X-T2", sqrt_x_t2) SQRT_X_T2 = sqrt_x_t2_definition.get_constructor() program += sqrt_x_definition program += sqrt_x_t2_definition program += g.CNOT(0, 1) program += SQRT_X(0).controlled(1) program += SQRT_X_T2(1, 2).controlled(0) program += g.X(0).controlled(1) program += g.RX(0.4, 0) with OperationRecorder() as rec: load_program(program)(wires=range(3)) expected_queue = [ qml.CNOT(wires=[0, 1]), qml.QubitUnitary(c_sqrt_x, wires=[1, 0]), qml.QubitUnitary(c_sqrt_x_t2, wires=[0, 1, 2]), qml.CNOT(wires=[1, 0]), qml.RX(0.4, wires=[0]), ] for converted, expected in zip(rec.queue, expected_queue): assert converted.name == expected.name assert converted.wires == expected.wires assert np.allclose(converted.params, expected.params, atol=tol, rtol=0) def test_convert_program_with_defpermutationgates(self): """Test that a program with gates defined via DefPermutationGate is properly converted.""" program = pyquil.Program() expected_matrix = np.eye(4) expected_matrix = expected_matrix[:, [1, 0, 3, 2]] x_plus_x_definition = pyquil.quil.DefPermutationGate( "X+X", [1, 0, 3, 2]) X_plus_X = x_plus_x_definition.get_constructor() program += x_plus_x_definition program += g.CNOT(0, 1) program += X_plus_X(0, 1) program += g.CNOT(0, 1) with OperationRecorder() as rec: load_program(program)(wires=range(2)) expected_queue = [ qml.CNOT(wires=[0, 1]), qml.QubitUnitary(expected_matrix, wires=[0, 1]), qml.CNOT(wires=[0, 1]), ] for converted, expected in zip(rec.queue, expected_queue): assert converted.name == expected.name assert converted.wires == expected.wires assert np.array_equal(converted.params, expected.params) def test_convert_program_with_controlled_defpermutationgates(self): """Test that a program that uses controlled permutation gates is properly converted.""" program = pyquil.Program() expected_matrix = np.eye(4) expected_matrix = expected_matrix[:, [1, 0, 3, 2]] expected_controlled_matrix = np.eye(8) expected_controlled_matrix[4:, 4:] = expected_matrix x_plus_x_definition = pyquil.quil.DefPermutationGate( "X+X", [1, 0, 3, 2]) X_plus_X = x_plus_x_definition.get_constructor() program += x_plus_x_definition program += g.CNOT(0, 1) program += X_plus_X(0, 1).controlled(2) program += X_plus_X(1, 2).controlled(0) program += g.CNOT(0, 1) with OperationRecorder() as rec: load_program(program)(wires=range(3)) expected_queue = [ qml.CNOT(wires=[0, 1]), qml.QubitUnitary(expected_controlled_matrix, wires=[2, 0, 1]), qml.QubitUnitary(expected_controlled_matrix, wires=[0, 1, 2]), qml.CNOT(wires=[0, 1]), ] for converted, expected in zip(rec.queue, expected_queue): assert converted.name == expected.name assert converted.wires == expected.wires assert np.array_equal(converted.params, expected.params) def test_forked_gate_error(self): """Test that an error is raised if conversion of a forked gate is attempted.""" program = pyquil.Program() program += g.CNOT(0, 1) program += g.RX(0.3, 1).forked(2, [0.5]) program += g.CNOT(0, 1) with pytest.raises( qml.DeviceError, match= "Forked gates can not be imported into PennyLane, as this functionality is not supported", ): load_program(program)(wires=range(3))
def I(qubit) -> None: program_context().inst(gates.I(qubit))
def calculate(self): '''Processes the quantum circuit and returns the results''' p = Program() # Gets definitions for quarter & eighth turn gates p = self.define_extra_gates(p) # length of circuit = number of columns col_length = len(self.circuit) num_qubits = 0 # max length of any number of operations per column = number of qubits / rows used for i in self.circuit: if len(i) > num_qubits: num_qubits = len(i) # loops over each gate in circuit and applies the gate for i in range(col_length): # Keeps track of where special components are (i.e. SWAP) special_loc = [] # Obtains any controls in the column i; if present, each gate is made into a controlled gate, else the gate is normal control_qubits, anticontrol_qubits = self.get_controls_in_column(i) # To apply anticontrols, X gate needs to be applied to the corresponding qubit wire and applied again after column is processed for qubit in anticontrol_qubits: p += pqg.X(qubit) for j in range(len(self.circuit[i])): current_gate = str(self.circuit[i][j]).upper() # If the gate is X, Y, Z or H, apply the gate to qubit #j if current_gate in "H": p += pqg.H(j).controlled(control_qubits) elif current_gate in "X": p += pqg.X(j).controlled(control_qubits) elif current_gate in "Y": p += pqg.Y(j).controlled(control_qubits) elif current_gate in "Z": p += pqg.Z(j).controlled(control_qubits) # If the gate is a quarter turn (+/- 90 deg or pi/2) for X, Y or Z, apply the respective gate elif current_gate in ("X^1/2", "X^½"): p += POS_SQRT_X(j).controlled(control_qubits) elif current_gate in ('X^-1/2', 'X^-½'): p += NEG_SQRT_X(j).controlled(control_qubits) elif current_gate in ("Y^1/2", "Y^½"): p += POS_SQRT_Y(j).controlled(control_qubits) elif current_gate in ("Y^-1/2", "Y^-½"): p += NEG_SQRT_Y(j).controlled(control_qubits) elif current_gate in ("Z^1/2", "Z^½", "S"): p += POS_SQRT_Z(j).controlled(control_qubits) elif current_gate in ("Z^-1/2", "Z^-½", "S^-1"): p += NEG_SQRT_Z(j).controlled(control_qubits) # If the gate is an eighth turn (+/- 45 deg or pi/4) for X, Y or Z, apply the respective gate elif current_gate in ("X^1/4", "X^¼"): p += POS_FTRT_X(j).controlled(control_qubits) elif current_gate in ("X^-1/4", "X^-¼"): p += NEG_FTRT_X(j).controlled(control_qubits) elif current_gate in ("Y^1/4", "Y^¼"): p += POS_FTRT_Y(j).controlled(control_qubits) elif current_gate in ("Y^-1/4", "Y^-¼"): p += NEG_FTRT_Y(j).controlled(control_qubits) elif current_gate in ("Z^1/4", "Z^¼", "T"): p += POS_FTRT_Z(j).controlled(control_qubits) elif current_gate in ("Z^-1/4", "Z^-¼", "T^-1"): p += NEG_FTRT_Z(j).controlled(control_qubits) # If the gate is a SWAP gate, check if another one has been found before and perform the SWAP operation # If not, keep track of its location until we find the other SWAP gate elif current_gate in "SWAP": if len(special_loc) == 1: p += pqg.SWAP(special_loc[0], j).controlled(control_qubits) special_loc = [] else: special_loc.append(j) else: p += pqg.I(j) # Reverses the process used to make anticontrols possible for qubit in anticontrol_qubits: p += pqg.X(qubit) self.construct_results_dict(p) return self.results