def test_program_gates(): ig = Program() ig.inst(H(0), X(1)) assert len(ig.actions) == 2 assert ig.out() == "H 0\nX 1\n"
def test_simple_instructions(): p = Program().inst(HALT, WAIT, RESET, NOP) assert p.out() == 'HALT\nWAIT\nRESET\nNOP\n'
def test_measurement_calls(): p = Program() p.inst(MEASURE(0, 1), MEASURE(0, Addr(1))) assert p.out() == 'MEASURE 0 [1]\n' * 2
def test_plus_operator(): p = Program() p += H(0) p += [X(0), Y(0), Z(0)] assert len(p) == 4 assert p.out() == "H 0\nX 0\nY 0\nZ 0\n"
def test_prog_init(): p = Program() p.inst(X(0)).measure(0, 0) assert p.out() == 'X 0\nMEASURE 0 [0]\n'
def test_conjugate_request(server, mock_rb_cxn): response = mock_rb_cxn.apply_clifford_to_pauli(Program("H 0"), PauliTerm("X", 0, 1.0)) assert isinstance(response, PauliTerm) assert str(response) == "(1+0j)*Z0"
def test_len_one(): prog = Program(X(0)) assert len(prog) == 1
def _S(q: int) -> Program: """ An S in terms of RZ(theta) """ return Program(RZ(np.pi / 2, q))
def basic_compile(program: Program) -> Program: """ A rudimentary but predictable compiler. No rewiring or optimization is done by this compilation step. There may be some gates that are not yet supported. Gates defined in the input program are included without change in the output program. :param program: A program to be compiled to native quil with simple replacements. :return: A program with some of the input non-native quil gates replaced with basic native quil gate implementations. """ new_prog = Program() new_prog.num_shots = program.num_shots new_prog.inst(program.defined_gates) for inst in program: if isinstance(inst, Gate): if inst.name == "CCNOT": new_prog += _CCNOT(*inst.qubits) elif inst.name == "CNOT": new_prog += _CNOT(*inst.qubits) # NB: we haven't implemented CPHASE00/01/10 elif inst.name == "CPHASE": angle_param = inst.params[0] new_prog += _CPHASE(angle_param, *inst.qubits) elif inst.name == "CZ": new_prog += CZ(*inst.qubits) # remove dag modifiers elif inst.name == "H": new_prog += _H(inst.qubits[0]) elif inst.name == "I": new_prog += I(inst.qubits[0]) # remove dag modifiers elif inst.name == "ISWAP": new_prog += _ISWAP(*inst.qubits) # remove dag modifiers elif inst.name == "PHASE": angle_param = inst.params[0] new_prog += _PHASE(angle_param, inst.qubits[0]) elif inst.name == "RX": angle_param = inst.params[0] if is_magic_angle(inst.params[0]): # in case dagger new_prog += RX(angle_param, inst.qubits[0]) else: new_prog += _RX(angle_param, inst.qubits[0]) elif inst.name == "RY": angle_param = inst.params[0] new_prog += _RY(angle_param, inst.qubits[0]) elif inst.name == "RZ": # in case dagger angle_param = inst.params[0] new_prog += RZ(angle_param, inst.qubits[0]) elif inst.name == "S": new_prog += _S(inst.qubits[0]) # NB: we haven't implemented CSWAP or PSWAP elif inst.name == "SWAP": new_prog += _SWAP(*inst.qubits) elif inst.name == "T": new_prog += _T(inst.qubits[0]) elif inst.name == "X": new_prog += _X(inst.qubits[0]) elif inst.name == "XY": angle_param = inst.params[0] new_prog += XY(angle_param, *inst.qubits) elif inst.name == "Y": new_prog += _Y(inst.qubits[0]) elif inst.name == "Z": new_prog += _Z(inst.qubits[0]) elif inst.name in [gate.name for gate in new_prog.defined_gates]: new_prog += inst else: raise ValueError(f"Unknown gate instruction {inst}") else: new_prog += inst new_prog.native_quil_metadata = { "final_rewiring": None, "gate_depth": None, "gate_volume": None, "multiqubit_gate_depth": None, "program_duration": None, "program_fidelity": None, "topological_swaps": 0, } return new_prog
def test_exponentiate_prog(): ham = PauliTerm("Z", 0) result_prog = Program(RZ(2.0, 0)) prog = exponentiate(ham) compare_progs(result_prog, prog)
def basic_compile(program: Program): """ A rudimentary but predictable compiler. No rewiring or optimization is done by this compilation step. There may be some gates that are not yet supported. Gates defined in the input program are included without change in the output program. :param program: a program to be compiled to native quil with simple replacements. :return: a program with some of the input non-native quil gates replaced with basic native quil gate implementations. """ new_prog = Program() new_prog.num_shots = program.num_shots new_prog.inst(program.defined_gates) daggered_defgates = [] for inst in program: if isinstance(inst, Gate): # TODO: this is only a stopgap while the noisy QVM does not support modifiers. # dagger this gate if odd number of daggers. Ignore controlled for now. needs_dagger = inst.modifiers.count('DAGGER') % 2 == 1 angle_param = None if len(inst.params) > 0: angle_param = inst.params[0] if needs_dagger: angle_param = -angle_param if 'CONTROLLED' in inst.modifiers: raise ValueError("Controlled gates are not currently supported.") if inst.name == 'CZ': new_prog += CZ(*inst.qubits) # remove dag modifiers elif inst.name == 'XY': new_prog += XY(angle_param, *inst.qubits) elif inst.name == 'I': new_prog += I(inst.qubits[0]) # remove dag modifiers elif inst.name == 'RZ': # in case dagger new_prog += RZ(angle_param, inst.qubits[0]) elif inst.name == 'RX': if is_magic_angle(inst.params[0]): # in case dagger new_prog += RX(angle_param, inst.qubits[0]) else: new_prog += _RX(angle_param, inst.qubits[0]) elif inst.name == 'RY': new_prog += _RY(angle_param, inst.qubits[0]) elif inst.name == 'CNOT': new_prog += _CNOT(*inst.qubits) elif inst.name == 'CCNOT': new_prog += _CCNOT(*inst.qubits) elif inst.name == 'SWAP': new_prog += _SWAP(*inst.qubits) elif inst.name == 'T': new_prog += _T(inst.qubits[0], needs_dagger) elif inst.name == "H": new_prog += _H(inst.qubits[0]) elif inst.name == "X": new_prog += _X(inst.qubits[0]) elif inst.name in [gate.name for gate in new_prog.defined_gates]: if needs_dagger and inst.name not in daggered_defgates: new_prog.defgate(inst.name + 'DAG', inst.matrix.T.conj()) daggered_defgates.append(inst.name) new_prog += inst else: raise ValueError(f"Unknown gate instruction {inst}") else: new_prog += inst new_prog.native_quil_metadata = { 'final_rewiring': None, 'gate_depth': None, 'gate_volume': None, 'multiqubit_gate_depth': None, 'program_duration': None, 'program_fidelity': None, 'topological_swaps': 0, } return new_prog
def test_default_wf_simulator(): qam = PyQVM(n_qubits=2) qam.execute(Program(H(0), H(1))) assert qam.wf_simulator.wf.reshape(-1).shape == (4, )
def test_larger_qaoa_circuit(): square_qaoa_circuit = [ H(0), H(1), H(2), H(3), X(0), PHASE(0.3928244130249029, 0), X(0), PHASE(0.3928244130249029, 0), CNOT(0, 1), RZ(0.78564882604980579, 1), CNOT(0, 1), X(0), PHASE(0.3928244130249029, 0), X(0), PHASE(0.3928244130249029, 0), CNOT(0, 3), RZ(0.78564882604980579, 3), CNOT(0, 3), X(0), PHASE(0.3928244130249029, 0), X(0), PHASE(0.3928244130249029, 0), CNOT(1, 2), RZ(0.78564882604980579, 2), CNOT(1, 2), X(0), PHASE(0.3928244130249029, 0), X(0), PHASE(0.3928244130249029, 0), CNOT(2, 3), RZ(0.78564882604980579, 3), CNOT(2, 3), H(0), RZ(-0.77868204192240842, 0), H(0), H(1), RZ(-0.77868204192240842, 1), H(1), H(2), RZ(-0.77868204192240842, 2), H(2), H(3), RZ(-0.77868204192240842, 3), H(3), ] prog = Program(square_qaoa_circuit) qam = PyQVM(n_qubits=4, quantum_simulator_type=ReferenceWavefunctionSimulator) qam.execute(prog) wf = qam.wf_simulator.wf wf_true = np.array([ 8.43771693e-05 - 0.1233845 * 1j, -1.24927731e-01 + 0.00329533 * 1j, -1.24927731e-01 + 0.00329533 * 1j, -2.50040954e-01 + 0.12661547 * 1j, -1.24927731e-01 + 0.00329533 * 1j, -4.99915497e-01 - 0.12363516 * 1j, -2.50040954e-01 + 0.12661547 * 1j, -1.24927731e-01 + 0.00329533 * 1j, -1.24927731e-01 + 0.00329533 * 1j, -2.50040954e-01 + 0.12661547 * 1j, -4.99915497e-01 - 0.12363516 * 1j, -1.24927731e-01 + 0.00329533 * 1j, -2.50040954e-01 + 0.12661547 * 1j, -1.24927731e-01 + 0.00329533 * 1j, -1.24927731e-01 + 0.00329533 * 1j, 8.43771693e-05 - 0.1233845 * 1j, ]) np.testing.assert_allclose(wf_true, wf)
def test_against_ref_hadamard(): p = Program(H(0)) qam = PyQVM(n_qubits=1, quantum_simulator_type=ReferenceWavefunctionSimulator) qam.execute(p) np.testing.assert_allclose(HADAMARD_WF, qam.wf_simulator.wf)
NativeQuilRequest, NativeQuilResponse, NativeQuilMetadata, ConjugateByCliffordRequest, ConjugateByCliffordResponse, RandomizedBenchmarkingRequest, RandomizedBenchmarkingResponse) from pyquil.api import (QVMConnection, QPUCompiler, BenchmarkConnection, get_qc, QVMCompiler) from pyquil.api._base_connection import validate_noise_probabilities, validate_qubit_list, \ prepare_register_list from pyquil.api._config import PyquilConfig from pyquil.device import ISA, NxDevice from pyquil.gates import CNOT, H, MEASURE, PHASE, Z, RZ, RX, CZ from pyquil.paulis import PauliTerm from pyquil.quil import Program from pyquil.quilbase import Pragma, Declare EMPTY_PROGRAM = Program() BELL_STATE = Program(H(0), CNOT(0, 1)) BELL_STATE_MEASURE = Program(H(0), CNOT(0, 1), MEASURE(0, 0), MEASURE(1, 1)) COMPILED_BELL_STATE = Program([ Declare("ro", "BIT", 2), Pragma("EXPECTED_REWIRING", ('"#(0 1)"',)), RZ(pi / 2, 0), RX(pi / 2, 0), RZ(-pi / 2, 1), RX(pi / 2, 1), CZ(1, 0), RZ(-pi / 2, 0), RX(-pi / 2, 1), RZ(pi / 2, 1), Pragma("CURRENT_REWIRING", ('"#(0 1)"',)), Pragma("EXPECTED_REWIRING", ('"#(0 1)"',)),
"""Random bit generator circuit in PyQuil 2.1.1.""" # imports from pyquil.quil import Program import pyquil.gates as gates from pyquil import api # get a program and classical memory register qprog = Program() creg = qprog.declare(name="ro", memory_size=1) # REQUIRES: api key, qvm running in background ("qvm -S" in a linux terminal # after it is installed. See Rigetti website for download instructions # https://www.rigetti.com/forest) qvm = api.QVMConnection() # add instructions to the program qprog += [gates.H(0), gates.MEASURE(0, creg[0])] print(qprog) print(qvm.run(qprog, trials=1))
def test_sync_expectation(qvm): result = qvm.expectation(BELL_STATE, [Program(Z(0)), Program(Z(1)), Program(Z(0), Z(1))]) exp_expected = [0.0, 0.0, 1.0] np.testing.assert_allclose(exp_expected, result)
from pyquil.quil import Program import pyquil.api as api from pyquil.gates import * qvm = api.QVMConnection() p = Program() p.inst(H(0), CNOT(0, 1), MEASURE(1, [1])) wavefunction = qvm.wavefunction(p) print(wavefunction)
def test_len_zero(): prog = Program() assert len(prog) == 0
def test_exponentiate(): # test rotation of single qubit generator = PauliTerm("Z", 0, 1.0) para_prog = exponential_map(generator) prog = para_prog(1) result_prog = Program().inst(RZ(2.0)(0)) assert prog == result_prog # testing general 2-circuit generator = PauliTerm("Z", 1, 1.0) * PauliTerm("Z", 0, 1.0) para_prog = exponential_map(generator) prog = para_prog(1) result_prog = Program().inst(CNOT(0, 1)).inst(RZ(2.0)(1)).inst(CNOT(0, 1)) assert prog == result_prog # testing change of basis position 0 generator = PauliTerm("Z", 1, 1.0) * PauliTerm("X", 0, 1.0) param_prog = exponential_map(generator) prog = param_prog(1) result_prog = Program().inst([H(0), CNOT(0, 1), RZ(2.0)(1), CNOT(0, 1), H(0)]) assert prog == result_prog # testing change of basis position 1 generator = PauliTerm("X", 1, 1.0) * PauliTerm("Z", 0, 1.0) para_prog = exponential_map(generator) prog = para_prog(1) result_prog = Program().inst([H(1), CNOT(0, 1), RZ(2.0)(1), CNOT(0, 1), H(1)]) assert prog == result_prog # testing change of basis position 0 generator = PauliTerm("Z", 1, 1.0) * PauliTerm("Y", 0, 1.0) para_prog = exponential_map(generator) prog = para_prog(1) result_prog = Program().inst([RX(math.pi / 2.0)(0), CNOT(0, 1), RZ(2.0)(1), CNOT(0, 1), RX(-math.pi / 2)(0)]) assert prog == result_prog # testing change of basis position 1 generator = PauliTerm("Y", 1, 1.0) * PauliTerm("Z", 0, 1.0) para_prog = exponential_map(generator) prog = para_prog(1) result_prog = Program().inst([RX(math.pi / 2.0)(1), CNOT(0, 1), RZ(2.0)(1), CNOT(0, 1), RX(-math.pi / 2.0)(1)]) assert prog == result_prog # testing circuit for 3-terms with change of basis generator = PauliTerm("X", 2, 1.0) * PauliTerm("Y", 1, 1.0) * PauliTerm("Z", 0, 1.0) para_prog = exponential_map(generator) prog = para_prog(1) result_prog = Program().inst([RX(math.pi / 2.0)(1), H(2), CNOT(0, 1), CNOT(1, 2), RZ(2.0)(2), CNOT(1, 2), CNOT(0, 1), RX(-math.pi / 2.0)(1), H(2)]) assert prog == result_prog # testing circuit for 3-terms non-sequential generator = PauliTerm("Y", 3, 1.0) * PauliTerm("Y", 2, 1.0) * PauliTerm("I", 1, 1.0) * PauliTerm("Y", 0, 1.0) para_prog = exponential_map(generator) prog = para_prog(1) result_prog = Program().inst([RX(math.pi / 2.0)(0), RX(math.pi / 2.0)(2), RX(math.pi / 2.0)(3), CNOT(0, 2), CNOT(2, 3), RZ(2.0)(3), CNOT(2, 3), CNOT(0, 2), RX(-math.pi / 2.0)(0), RX(-math.pi / 2.0)(2), RX(-math.pi / 2.0)(3)]) assert prog == result_prog
def test_len_nested(): p = Program(H(0)).measure(0, 0) q = Program(H(0), CNOT(0, 1)) p.if_then(0, q) assert len(p) == 8
def test_exponentiate_commuting_pauli_sum(): pauli_sum = PauliSum([PauliTerm('Z', 0, 0.5), PauliTerm('Z', 1, 0.5)]) prog = Program().inst(RZ(1.)(0)).inst(RZ(1.)(1)) result_prog = exponentiate_commuting_pauli_sum(pauli_sum)(1.) assert prog == result_prog
def test_program_tuple(): p = Program() p.inst(("Y", 0), ("X", 1)) assert len(p) == 2 assert p.out() == "Y 0\nX 1\n"
def test_exponentiate_prog(): ham = PauliTerm("Z", 0) result_prog = Program(RZ(2.0, 0)) prog = exponentiate(ham) assert prog == result_prog
def test_classical_regs(): p = Program() p.inst(X(0)).measure(0, 1) assert p.out() == 'X 0\nMEASURE 0 [1]\n'
from pyquil.quil import Program from pyquil.gates import H from pyquil.paulis import sI, sX, sZ, exponentiate_commuting_pauli_sum from pyquil.api import QVMConnection # Create a 4-node array graph: 0-1-2-3. graph = [(0, 1), (1, 2), (2, 3)] # Nodes [0, 1, 2, 3]. nodes = range(4) # Create the initial state program, a sum over all bitstrings, via Hadamards on all qubits. init_state_prog = Program([H(i) for i in nodes]) # The cost Hamiltonian is sum of the application of 0.5 * (1 - \sigma_z^i * \sigma_z^j) for all # qubit pairs (i, j). h_cost = -0.5 * sum(sI(nodes[0]) - sZ(i) * sZ(j) for i, j in graph) # The driver Hamiltonian is the sum of the application of \sigma_x^i for all qubits i. h_driver = -1. * sum(sX(i) for i in nodes) def qaoa_ansatz(gammas, betas): """ Function that returns a QAOA ansatz program for a list of angles betas and gammas. len(betas) == len(gammas) == P for a QAOA program of order P. :param list(float) gammas: Angles over which to parameterize the cost Hamiltonian. :param list(float) betas: Angles over which to parameterize the driver Hamiltonian. :return: The QAOA ansatz program. :rtype: Program. """ return Program([exponentiate_commuting_pauli_sum(h_cost)(g) + exponentiate_commuting_pauli_sum(h_driver)(b) \
def test_unary_classicals(): p = Program() p.inst(TRUE(0), FALSE(Addr(1)), NOT(2)) assert p.out() == 'TRUE [0]\n' \ 'FALSE [1]\n' \ 'NOT [2]\n'
def test_noise_helpers(): gates = RX(np.pi / 2, 0), RX(-np.pi / 2, 1), I(1), CZ(0, 1) prog = Program(*gates) inferred_gates = _get_program_gates(prog) assert set(inferred_gates) == set(gates)
def test_singles(): p = Program(I(0), X(0), Y(1), Z(1), H(2), T(2), S(1)) assert p.out() == 'I 0\nX 0\nY 1\nZ 1\nH 2\nT 2\nS 1\n'
def test_prog_merge(): prog_0 = Program(X(0)) prog_1 = Program(Y(0)) assert merge_programs([prog_0, prog_1]).out() == (prog_0 + prog_1).out()