def test_memory_commands(): parse_equals( "DECLARE mem OCTET[32] SHARING mem2 OFFSET 16 REAL OFFSET 32 REAL", Declare("mem", "OCTET", 32, shared_region="mem2", offsets=[(16, "REAL"), (32, "REAL")]), ) parse_equals( "STORE mem ro[2] ro[0]", STORE("mem", MemoryReference("ro", 2), MemoryReference("ro", 0))) parse_equals("STORE mem ro[2] 7", STORE("mem", MemoryReference("ro", 2), 7)) parse_equals( "LOAD ro[8] mem mem[4]", LOAD(MemoryReference("ro", 8), "mem", MemoryReference("mem", 4))) parse_equals("CONVERT ro[1] ro[2]", CONVERT(MemoryReference("ro", 1), MemoryReference("ro", 2))) parse_equals("EXCHANGE ro[0] ro[1]", EXCHANGE(MemoryReference("ro", 0), MemoryReference("ro", 1))) parse_equals("MOVE mem[2] 4", MOVE(MemoryReference("mem", 2), 4)) parse_equals("MOVE mem[2] -4", MOVE(MemoryReference("mem", 2), -4)) parse_equals("MOVE mem[2] -4.1", MOVE(MemoryReference("mem", 2), -4.1))
def _prepend_real_declarations( *, program: Program, resolvers: Sequence[cirq.ParamResolverOrSimilarType]) -> Program: """Adds memory declarations for all variables in each of the `resolver`'s param dict. Note, this function assumes that the first parameter resolver will contain all variables subsequently referenced in `resolvers`. Args: program: The program that the quantum computer will execute. resolvers: A sequence of parameters resolvers that provide values for parameter references in the original `cirq.Circuit`. Returns: A program that includes the QUIL memory declarations as described above. """ if len(resolvers) > 0: resolver = resolvers[0] param_dict = _get_param_dict(resolver) for key in param_dict.keys(): declaration = Declare(str(key), "REAL") program._instructions.insert(0, declaration) program._synthesized_instructions = None program.declarations[declaration.name] = declaration logger.debug(f"prepended declaration {declaration}") return program
def test_get_qvm_with_topology_2(client_configuration: QCSClientConfiguration): topo = nx.from_edgelist([(5, 6), (6, 7)]) qc = _get_qvm_with_topology( name="test-qvm", topology=topo, noisy=False, qvm_type="qvm", compiler_timeout=5.0, execution_timeout=5.0, client_configuration=client_configuration, ) results = qc.run( qc.compile( Program( Declare("ro", "BIT", 3), X(5), MEASURE(5, ("ro", 0)), MEASURE(6, ("ro", 1)), MEASURE(7, ("ro", 2)), ).wrap_in_numshots_loop(5) ) ) assert results.shape == (5, 3) assert all(r[0] == 1 for r in results)
def rewrite_arithmetic(prog: Program) -> RewriteArithmeticResponse: """Rewrite compound arithmetic expressions. The basic motivation is that a parametric program may have gates with compound arguments which cannot be evaluated natively on the underlying control hardware. The solution provided here is to translate a program like DECLARE theta REAL DECLARE beta REAL RZ(3 * theta) 0 RZ(beta+theta) 0 into something like DECLARE theta REAL DECLARE beta REAL DECLARE __P REAL[2] RZ(__P[0]) 0 RZ(__P[1]) 0 along with a "recalculation table" mapping new memory references to their corresponding arithmetic expressions, { ParameterAref('__P', 0): "((3.0)*theta[0])", ParameterAref('__P', 1): "(beta[0]+theta[0])" } When executing the parametric program with specific values for `theta` and `beta`, the PyQuil client will patch in values for `__P` by evaluating the expressions in the recalculation table. :param prog: A program. :returns: A RewriteArithmeticResponse, containing the updated program along with its memory descriptors and a recalculation table. """ def spec(inst: Declare) -> ParameterSpec: return ParameterSpec(type=inst.memory_type, length=inst.memory_size) def aref(ref: MemoryReference) -> ParameterAref: return ParameterAref(name=ref.name, index=ref.offset) updated = prog.copy_everything_except_instructions() old_descriptors = { inst.name: spec(inst) for inst in prog if isinstance(inst, Declare) } recalculation_table = {} seen_exprs = {} # generate a unique name. it's nice to do this in a deterministic fashion # rather than globbing in a UUID suffix = len(old_descriptors) while f"__P{suffix}" in old_descriptors: suffix += 1 mref_name = f"__P{suffix}" mref_idx = 0 for inst in prog: if isinstance(inst, Gate): new_params = [] for param in inst.params: if isinstance(param, (Real, MemoryReference)): new_params.append(param) elif isinstance(param, Expression): expr = str(param) if expr in seen_exprs: new_params.append(seen_exprs[expr]) else: new_mref = MemoryReference(mref_name, mref_idx) seen_exprs[expr] = new_mref mref_idx += 1 recalculation_table[aref(new_mref)] = expr new_params.append(new_mref) else: raise ValueError( f"Unknown parameter type {type(param)} in {inst}.") updated.inst(Gate(inst.name, new_params, inst.qubits)) else: updated.inst(inst) if mref_idx > 0: updated._instructions.insert(0, Declare(mref_name, "REAL", mref_idx)) return RewriteArithmeticResponse( quil=updated.out(), original_memory_descriptors=old_descriptors, recalculation_table=recalculation_table, )
def test_classical_regs(): p = Program() p.inst(Declare("ro", "BIT", 2), X(0)).measure(0, MemoryReference("ro", 1)) assert p.out() == ("DECLARE ro BIT[2]\nX 0\nMEASURE 0 ro[1]\n")
validate_noise_probabilities, validate_qubit_list, prepare_register_list, ) 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 Halt, Declare from pyquil.quilatom import MemoryReference from pyquil.simulation.tools import program_unitary EMPTY_PROGRAM = Program() BELL_STATE = Program(H(0), CNOT(0, 1)) BELL_STATE_MEASURE = Program( Declare("ro", "BIT", 2), H(0), CNOT(0, 1), MEASURE(0, MemoryReference("ro", 0)), MEASURE(1, MemoryReference("ro", 1)), ) COMPILED_BELL_STATE = Program([ 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), Halt(),
def test_classical_regs(): p = Program() p.inst(Declare('ro', 'BIT', 2), X(0)).measure(0, MemoryReference("ro", 1)) assert p.out() == ('DECLARE ro BIT[2]\n' 'X 0\n' 'MEASURE 0 ro[1]\n')
def rewrite_arithmetic(prog: Program) -> RewriteArithmeticResponse: """Rewrite compound arithmetic expressions. The basic motivation is that a parametric program may have gates with compound arguments which cannot be evaluated natively on the underlying control hardware. The solution provided here is to translate a program like DECLARE theta REAL DECLARE beta REAL RZ(3 * theta) 0 RZ(beta+theta) 0 into something like DECLARE theta REAL DECLARE beta REAL DECLARE __P REAL[2] RZ(__P[0]) 0 RZ(__P[1]) 0 along with a "recalculation table" mapping new memory references to their corresponding arithmetic expressions, { ParameterAref('__P', 0): "((3.0)*theta[0])", ParameterAref('__P', 1): "(beta[0]+theta[0])" } When executing the parametric program with specific values for `theta` and `beta`, the PyQuil client will patch in values for `__P` by evaluating the expressions in the recalculation table. :param prog: A program. :returns: A RewriteArithmeticResponse, containing the updated program along with its memory descriptors and a recalculation table. """ def spec(inst: Declare) -> ParameterSpec: return ParameterSpec(type=inst.memory_type, length=inst.memory_size) def aref(ref: MemoryReference) -> ParameterAref: return ParameterAref(name=ref.name, index=ref.offset) updated = prog.copy_everything_except_instructions() old_descriptors = { inst.name: spec(inst) for inst in prog if isinstance(inst, Declare) } recalculation_table: Dict[ParameterAref, str] = {} seen_exprs: Dict[str, MemoryReference] = {} # generate a unique name. it's nice to do this in a deterministic fashion # rather than globbing in a UUID suffix = len(old_descriptors) while f"__P{suffix}" in old_descriptors: suffix += 1 mref_name = f"__P{suffix}" mref_idx = 0 def expr_mref(expr: object) -> MemoryReference: """ Get a suitable MemoryReference for a given expression. """ nonlocal mref_idx expr = str(expr) if expr in seen_exprs: return seen_exprs[expr] new_mref = MemoryReference(mref_name, mref_idx) seen_exprs[expr] = new_mref mref_idx += 1 recalculation_table[aref(new_mref)] = expr return new_mref for inst in prog: if isinstance(inst, Gate): new_params: List[Union[Real, MemoryReference]] = [] for param in inst.params: if isinstance(param, Real): new_params.append(param) elif isinstance(param, Expression): # Quil gate angles are in radians, # but downstream processing expects revolutions expr = str(Div(param, 2 * np.pi)) new_params.append(expr_mref(expr)) else: raise ValueError( f"Unknown parameter type {type(param)} in {inst}.") updated.inst(Gate(inst.name, new_params, inst.qubits)) elif isinstance(inst, (SetFrequency, ShiftFrequency)): if isinstance(inst.freq, Real): updated.inst(inst) continue try: fdefn = prog.frames[inst.frame] except KeyError: raise ValueError( f"Unable to rewrite {inst} without DEFFRAME {inst.frame}.") if fdefn.sample_rate is None: raise ValueError( f"Unable to rewrite {inst} on frame with undefined SAMPLE-RATE." ) if fdefn.center_frequency: expr = Sub(inst.freq, fdefn.center_frequency) else: expr = inst.freq expr = Div(expr, fdefn.sample_rate) expr = str(expr) updated.inst(inst.__class__(inst.frame, expr_mref(expr))) elif isinstance(inst, (SetPhase, ShiftPhase)): if isinstance(inst.phase, Real): updated.inst(inst) else: # Quil phases are in radians # but downstream processing expects revolutions expr = str(Div(inst.phase, 2 * np.pi)) updated.inst(inst.__class__(inst.frame, expr_mref(expr))) elif isinstance(inst, SetScale): if isinstance(inst.scale, Real): updated.inst(inst) else: # scale is in [-4,4) # binary patching assumes periodic with period 1 # so we divide by 8... expr = str(Div(inst.scale, 8)) updated.inst(SetScale(inst.frame, expr_mref(expr))) else: updated.inst(inst) if mref_idx > 0: updated._instructions.insert(0, Declare(mref_name, "REAL", mref_idx)) return RewriteArithmeticResponse( quil=updated.out(), original_memory_descriptors=old_descriptors, recalculation_table=recalculation_table, )
def test_get_qubit_placeholders(): qs = QubitPlaceholder.register(8) pq = Program(Declare("ro", "BIT"), X(qs[0]), CNOT(qs[0], qs[4]), MEASURE(qs[5], MemoryReference("ro", 0))) assert pq.get_qubits() == {qs[i] for i in [0, 4, 5]}
def test_len_nested(): p = Program(Declare("ro", "BIT"), H(0)).measure(0, MemoryReference("ro", 0)) q = Program(H(0), CNOT(0, 1)) p.if_then(MemoryReference("ro", 0), q) assert len(p) == 9
# y0ka1 # July 16th, 2021 from pyquil import get_qc, Program from pyquil.gates import * from pyquil.api import local_forest_runtime from pyquil.quilbase import Declare # Defining my quantum program quantumprog = Program( Declare( "ro", "BIT", 2 ), # This declares a classical register named ro with 2 bits to measure qubits with H( 0 ), # places my first bit into a state of super position between states |0> and |1> CNOT(0, 1), # This entangles the two bits into a connected super position X( 1 ), # Because I have entangled these qubits I can apply X to their linear combo MEASURE(0, ("ro", 0)), MEASURE(1, ("ro", 1))).wrap_in_numshots_loop(10) # Defining a second program quantumprog2 = Program(Declare("co", "BIT", 2), H(0), CNOT(0, 1), Z(0), X(0), MEASURE(0, ("co", 0)), MEASURE(1, ("co", 1))).wrap_in_numshots_loop(10) # returning my circuit parameterizations and metrics print( "============================================================================"
def test_unitary_measure(): prog = Program(Declare("ro", "BIT"), H(0), H(1), MEASURE(0, MemoryReference("ro", 0))) with pytest.raises(ValueError): program_unitary(prog, n_qubits=2)
from rpcq.messages import BinaryExecutableRequest, BinaryExecutableResponse from pyquil.api import QVMConnection, QPUCompiler, get_qc, QVMCompiler from pyquil.api._base_connection import (validate_noise_probabilities, validate_qubit_list, prepare_register_list) 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 Halt, Declare from pyquil.quilatom import MemoryReference EMPTY_PROGRAM = Program() BELL_STATE = Program(H(0), CNOT(0, 1)) BELL_STATE_MEASURE = Program(Declare('ro', 'BIT', 2), H(0), CNOT(0, 1), MEASURE(0, MemoryReference('ro', 0)), MEASURE(1, MemoryReference('ro', 1))) COMPILED_BELL_STATE = Program([ 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), Halt() ]) DUMMY_ISA_DICT = {"1Q": {"0": {}, "1": {}}, "2Q": {"0-1": {}}} DUMMY_ISA = ISA.from_dict(DUMMY_ISA_DICT)
def test_get_classical_addresses_from_program(): p = Program(Declare("ro", "BIT", 4), [H(i) for i in range(4)]) assert get_classical_addresses_from_program(p) == {} p += [MEASURE(i, MemoryReference("ro", i)) for i in [0, 3, 1]] assert get_classical_addresses_from_program(p) == {"ro": [0, 1, 3]}
# necessary pyquil modules import pyquil from pyquil import get_qc, Program from pyquil.gates import * from pyquil.api import local_forest_runtime from pyquil.quilbase import Declare # altair for plotting import altair as alt # Defining a circuit to run quantumprog = Program( Declare( "ro", "BIT", 2 ), # This declares a classical register named ro with 4 bits to measure qubits with CNOT(0, 1), H(0), Z(0), H(0), # The outcome should prove HZH=X X(1), MEASURE(0, ("ro", 0)), MEASURE(1, ("ro", 1)), ).wrap_in_numshots_loop(10) # returning my circuit parameterizations and metrics print("=====================================================\n") print("CIRCUIT DEFINITIONS:") print(quantumprog) print("=====================================================\n") # run the program on a QVM
def test_no_implicit_declare(): program = Program(Declare("read_out", "BIT", 5), MEASURE(0, MemoryReference("read_out", 4))) assert program.out() == ( "DECLARE read_out BIT[5]\nMEASURE 0 read_out[4]\n")
get_qc, LocalQVMCompiler, QVMCompiler, LocalBenchmarkConnection) 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 2 3)"', )), 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 2 3)"', )), Pragma("EXPECTED_REWIRING", ('"#(0 1 2 3)"', )), Pragma("CURRENT_REWIRING", ('"#(0 1 2 3)"', )), ]) DUMMY_ISA_DICT = {"1Q": {"0": {}, "1": {}}, "2Q": {"0-1": {}}} DUMMY_ISA = ISA.from_dict(DUMMY_ISA_DICT)
def test_prog_init(): p = Program() p.inst(Declare("ro", "BIT"), X(0)).measure(0, MemoryReference("ro", 0)) assert p.out() == ("DECLARE ro BIT[1]\nX 0\nMEASURE 0 ro[0]\n")
def test_prog_init(): p = Program() p.inst(Declare('ro', 'BIT'), X(0)).measure(0, MemoryReference("ro", 0)) assert p.out() == ('DECLARE ro BIT[1]\n' 'X 0\n' 'MEASURE 0 ro[0]\n')
def test_get_qubits_not_as_indices(): pq = Program(Declare("ro", "BIT"), X(0), CNOT(0, 4), MEASURE(5, MemoryReference("ro", 0))) assert pq.get_qubits(indices=False) == {Qubit(i) for i in [0, 4, 5]}
def test_qvm__default_client(client_configuration: QCSClientConfiguration): qvm = QVM(client_configuration=client_configuration) p = Program(Declare("ro", "BIT"), X(0), MEASURE(0, MemoryReference("ro"))) result = qvm.run(p.wrap_in_numshots_loop(1000)) bitstrings = result.readout_data.get("ro") assert bitstrings.shape == (1000, 1)