def test_define_qft(): def qft3(q0, q1, q2): p = Program() p.inst(H(q2), CPHASE(pi / 2.0)(q1, q2), H(1), CPHASE(pi / 4.0)(q0, q2), CPHASE(pi / 2.0)(q0, q1), H(q0), SWAP(q0, q2)) return p # I(2) is to force 3 qubits in state prep program. state_prep = Program().inst(X(0)) prog = state_prep + qft3(0, 1, 2) output = prog.out() assert output == 'X 0\nH 2\nCPHASE(1.5707963267948966) 1 2\nH 1\nCPHASE(0.7853981633974483) 0 ' \ '2\nCPHASE(1.5707963267948966) 0 1\nH 0\nSWAP 0 2\n'
def test_reset(): p = Program() p.reset(0) p.reset() assert p.out() == "RESET 0\nRESET\n" program = Program() qubit = QubitPlaceholder() # address_qubits() won't work unless there's a gate besides # RESET on a QubitPlaceholder, this is just here to make # addressing work program += X(qubit) program += RESET(qubit) program = address_qubits(program) assert program.out() == "X 0\nRESET 0\n"
def test_control_flows_2(): # create a program that branches based on the value of a classical register x_prog = Program(X(0)) z_prog = Program() branch = Program(H(1)).measure(1, MemoryReference("ro", 1)) \ .if_then(MemoryReference("ro", 1), x_prog, z_prog) \ .measure(0, MemoryReference("ro", 0)) assert branch.out() == ('DECLARE ro BIT[2]\n' 'H 1\n' 'MEASURE 1 ro[1]\n' 'JUMP-WHEN @THEN1 ro[1]\n' 'JUMP @END2\n' 'LABEL @THEN1\n' 'X 0\n' 'LABEL @END2\n' 'MEASURE 0 ro[0]\n')
def test_tomo_experiment(): expts = [ ExperimentSetting(TensorProductState(), sX(0) * sY(1)), ExperimentSetting(plusZ(0), sZ(0)), ] suite = TomographyExperiment(settings=expts, program=Program(X(0), Y(1))) assert len(suite) == 2 for e1, e2 in zip(expts, suite): # experiment suite puts in groups of length 1 assert len(e2) == 1 e2 = e2[0] assert e1 == e2 prog_str = str(suite).splitlines()[3:5] assert prog_str == EXPERIMENT_REPR.splitlines()[4:6]
def test_all_instructions(): pq = Program(H(0), X(1), RX(1.2, 2), CNOT(0, 1), CCNOT(0, 1, 2)) ro = pq.declare("ro") pq.measure(0, ro) pq.defgate("mygate", [[1, 0], [0, 1]]) pq.inst(("mygate", 0)) pq.reset(0) pq += Program(NEG(ro), AND(ro, ro), ADD(ro, 1), EQ(ro, ro, ro)) pq += Program(EXCHANGE(ro, ro), CONVERT(ro, ro)) pq += Program(LOAD(ro, ro, ro), STORE(ro, ro, ro)) G = QuilControlFlowGraph(pq) assert len(G.blocks) == 1 assert set(G.nodes) == set([0]) assert set(G.edges) == set() assert G.is_dag()
def test_merge_with_pauli_noise(): p = Program(X(0)).inst(Z(0)) probs = [0.0, 1.0, 0.0, 0.0] merged = merge_with_pauli_noise(p, probs, [0]) assert (merged.out() == """DEFGATE pauli_noise: 1.0, 0 0, 1.0 PRAGMA ADD-KRAUS pauli_noise 0 "(0.0 0.0 0.0 0.0)" PRAGMA ADD-KRAUS pauli_noise 0 "(0.0 1.0 1.0 0.0)" PRAGMA ADD-KRAUS pauli_noise 0 "(0.0 0.0 0.0 0.0)" PRAGMA ADD-KRAUS pauli_noise 0 "(0.0 0.0 0.0 -0.0)" X 0 pauli_noise 0 Z 0 pauli_noise 0 """)
def test_run_circuitset_and_measure(self, backend): # Given num_circuits = 10 circuit = Circuit(Program(X(0), CNOT(1, 2))) n_samples = 100 # When backend.n_samples = n_samples measurements_set = backend.run_circuitset_and_measure([circuit] * num_circuits) # Then assert len(measurements_set) == num_circuits for measurements in measurements_set: assert len(measurements.bitstrings) == n_samples # Then (since SPAM error could result in unexpected bitstrings, we make sure the most common bitstring is # the one we expect) counts = measurements.get_counts() assert max(counts, key=counts.get) == "100"
def test_to_latex(): """A test to give full coverage of latex_generation and latex_config.""" qubits = range(3) p = Program() p.inst(X(qubits[0]), Y(qubits[0]), CZ(qubits[0], qubits[2]), SWAP(qubits[0], qubits[1]), MEASURE(qubits[0], None), CNOT(qubits[2], qubits[0])) _ = to_latex(p) # Modify settings to access non-standard control paths. settings = get_default_settings() settings['gates']['AllocateQubitGate']['draw_id'] = True settings['gate_shadow'] = None _ = to_latex(p, settings) settings['control']['shadow'] = True _ = to_latex(p, settings)
def test_control_flows_2(): # create a program that branches based on the value of a classical register x_prog = Program(X(0)) z_prog = Program() branch = (Program(Declare("ro", "BIT", 2), H(1)).measure(1, MemoryReference("ro", 1)).if_then( MemoryReference("ro", 1), x_prog, z_prog).measure(0, MemoryReference("ro", 0))) assert branch.out() == ("DECLARE ro BIT[2]\n" "H 1\n" "MEASURE 1 ro[1]\n" "JUMP-WHEN @THEN1 ro[1]\n" "JUMP @END2\n" "LABEL @THEN1\n" "X 0\n" "LABEL @END2\n" "MEASURE 0 ro[0]\n")
def simulate_error(primal: nx.Graph, dual: nx.Graph, p=None, phase_flips=None, bit_flips=None): '''Given a code defined by a primal and dual graph, applies noise under the independent noise model. :param primal: Primal graph of the code :param dual: Dual graph of the code :param p: Probability with which to apply bit and phase flips :param phase_flips, bit_flips: Lists of edges to apply bit/phase flips to, if working in a deterministic setting (in this case, set p=None) :returns: Program for primal and dual graphs representing the applied errors, and lists of edges for each graph where phase and bit flips were applied for debugging ''' if p is None: assert phase_flips is not None assert bit_flips is not None else: # Randomly choose which qubits will have bit/phase flip errors # Working under the independent noise model; since the toric code is a # CSS code, we can analyze bit and phase flip errors seperately assert phase_flips is None assert bit_flips is None phase_flips = set() for edge in primal.edges: if weighted_flip(p): phase_flips.add(edge) bit_flips = set() for edge in dual.edges: if weighted_flip(p): bit_flips.add(edge) primal_pq = Program() dual_pq = Program() # Apply the errors we selected above to the necessary qubits for p_edge in primal.edges: if p_edge in phase_flips: primal_pq += Z(primal.edges[p_edge]['data_qubit']) for d_edge in dual.edges: if d_edge in bit_flips: dual_pq += X(dual.edges[d_edge]['data_qubit']) return primal_pq, phase_flips, dual_pq, bit_flips
def _ops_bool_to_prog(ops_bool: Tuple[bool], qubits: List[int]) -> Program: """ :param ops_bool: tuple of booleans specifying the operation to be carried out on `qubits` :param qubits: list specifying the qubits to be carried operations on :return: Program with the operations specified in `ops_bool` on the qubits specified in `qubits` """ assert len(ops_bool) == len(qubits), "Mismatch of qubits and operations" prog = Program() for i, op_bool in enumerate(ops_bool): if op_bool == 0: continue elif op_bool == 1: prog += Program(X(qubits[i])) else: raise ValueError("ops_bool should only consist of 0s and/or 1s") return prog
def test_readout_correction_works_run_circuitset_and_measure(self): # Given ibmq_api_token = os.getenv("ZAPATA_IBMQ_API_TOKEN") backend = QiskitBackend( device_name="ibmq_qasm_simulator", n_samples=1000, api_token=ibmq_api_token, readout_correction=True, ) circuit = Circuit(Program(X(0), CNOT(1, 2))) # When backend.run_circuitset_and_measure([circuit] * 10) # Then assert backend.readout_correction assert backend.readout_correction_filter is not None
def generate_2q_single_depth_experiment(rotation: Program, depth: int, exp_type: str, measurement_qubit: int, init_one: bool = False, axis: Tuple = None) -> Program: """ A special variant of the 1q method that is specifically designed to calibrate a CPHASE gate. The ideal CPHASE is of the following form CPHASE(\phi) = diag(1,1,1,Exp[-i \phi] The imperfect CPHASE has two local Z rotations and a possible over (or under) rotation on the phase phi. Thus we have CPHASE(\Phi, \Theta_1, \Theta_2) = diag( exp(-a -b), exp(-a + b), exp(a-b), exp(a+b+c) ) a = i \Theta_1 / 2, b = i \Theta_2 / 2, c = i \Phi The following experiments isolate the three angles using the state preparations |0>|+>, |+>|0>, |1>|+>, |+>|1> where the incurred phase is measured on the qubit initialized to the plus state. The four measurements are specified by setting the measurement qubit to either q1 or q2, and setting init_one to True indicating that the non-measurement qubit be prepared in the one state |1>. :param rotation: the program specifying the gate whose angle of rotation we wish to estimate. :param depth: the number of times we apply the rotation in the experiment :param exp_type: X or Y, specifying which operator to measure at the end of the experiment :param measurement_qubit: the qubit to be measured in this variant of the experiment :param axis: the axis of rotation. If none is specified, axis is assumed to be the Z axis. (rotation should be RZ) :param init_one: True iff the non-measurement qubit should be prepared in the 1 state. :param axis: the axis of rotation. If none is specified, axis is assumed to be the Z axis. (rotation should be RZ) :return: An estimate of some aspect of the CPHASE gate which depends on the measurement variant. """ prog = Program() ro_bit = prog.declare("ro", "BIT", 1) qubits = rotation.get_qubits() non_measurement_qubit = list(qubits - {measurement_qubit})[0] prepare_state(prog, measurement_qubit) if init_one: prog.inst(X(non_measurement_qubit)) for _ in range(depth): prog.inst(rotation) if axis: prog.inst(RZ(-axis[1], measurement_qubit)) prog.inst(RY(-axis[0], measurement_qubit)) local_pauli_eig_meas(prog, exp_type, measurement_qubit) prog.measure(measurement_qubit, ro_bit) return prog
def test_is_protoquil(): prog = Program(Declare('ro', 'BIT'), MEASURE(1, MemoryReference("ro", 0)), H(1), RESET()) validate_protoquil(prog) assert prog.is_protoquil() prog = Program(Declare('ro', 'BIT'), H(0), Y(1), CNOT(0, 1)) \ .measure(0, MemoryReference("ro", 0)) \ .if_then(MemoryReference("ro", 0), Program(X(0)), Program()) with pytest.raises(ValueError): validate_protoquil(prog) assert not prog.is_protoquil() prog = Program(Declare('ro', 'BIT'), ClassicalNot(MemoryReference("ro", 0))) with pytest.raises(ValueError): validate_protoquil(prog) assert not prog.is_protoquil()
def test_control_flows(): outer_loop = Program() classical_flag_register = outer_loop.declare('classical_flag_register', 'BIT') outer_loop += MOVE(classical_flag_register, 1) # initialize inner_loop = Program() inner_loop += Program(X(0), H(0)) inner_loop += MEASURE(0, classical_flag_register) # run inner_loop in a loop until classical_flag_register is 0 outer_loop.while_do(classical_flag_register, inner_loop) assert outer_loop.out() == '\n'.join([ "DECLARE classical_flag_register BIT[1]", "MOVE classical_flag_register 1", "LABEL @START1", "JUMP-UNLESS @END2 classical_flag_register", "X 0", "H 0", "MEASURE 0 classical_flag_register", "JUMP @START1", "LABEL @END2", "" ])
def test_qpu_run(forest: ForestConnection): devices = get_devices(async_endpoint=forest.async_endpoint, api_key=forest.api_key, user_id=forest.user_id, as_dict=True) for name, dev in devices.items(): if not dev.is_online: continue # TODO: gh-372. No way to query whether a device is available for running pytest.xfail("Please fix after gh-372") qpu = QPU(connection=forest, device_name=name) bitstrings = qpu.run( quil_program=Program(X(0), MEASURE(0, 0)), classical_addresses=[0], trials=1000, ) assert bitstrings.shape == (1000, 1) assert np.mean(bitstrings) > 0.8
def test_qvm_run_only_pqer(forest: ForestConnection): qvm = QVM(connection=forest, gate_noise=[0.01] * 3, requires_executable=True) p = Program(Declare("ro", "BIT"), X(0), MEASURE(0, MemoryReference("ro"))) p.wrap_in_numshots_loop(1000) with pytest.raises(TypeError) as e: qvm.load(p) qvm.run() qvm.wait() assert e.match(r".*Make sure you have explicitly compiled your program.*") nq = PyQuilExecutableResponse(program=p.out(), attributes={"num_shots": 1000}) qvm.load(nq) qvm.run() qvm.wait() bitstrings = qvm.read_memory(region_name="ro") assert bitstrings.shape == (1000, 1) assert np.mean(bitstrings) > 0.8
def test_out_vs_str(): qs = QubitPlaceholder.register(6) pq = Program( Declare("ro", "BIT", 6), X(qs[0]), CNOT(qs[0], qs[4]), MEASURE(qs[5], MemoryReference("ro", 5)), ) with pytest.raises(RuntimeError) as e: pq.out() assert e.match(r"Qubit q\d+ has not been assigned an index") string_version = str(pq) should_be_re = ( r"DECLARE ro BIT\[6\]\nX \{q\d+\}\nCNOT \{q\d+\} \{q\d+\}\nMEASURE \{q\d+\} ro\[5\]\n" ) assert re.fullmatch(should_be_re, string_version, flags=re.MULTILINE)
def build(self, a): pq = Program() code, x_qubits = to_qubits(1, self.n) pq += code code, b_qubits = to_qubits(0, self.n + 1) pq += code total_iters = 2 * (self.n) ro = pq.declare('ro', 'BIT', total_iters + len(x_qubits)) c = QubitPlaceholder() curr_a = a ''' code, ctrl_qubits = to_qubits(0, total_iters) pq += code for i in range(total_iters): ind = total_iters - 1 - i c = ctrl_qubits[ind] pq += H(c) pq += self.u_a(b_qubits, curr_a, c, x_qubits) curr_a = curr_a ** 2 % self.N for i in range(len(x_qubits)): pq += MEASURE(x_qubits[i], ro[total_iters + i]) ctrl_qubits = ctrl_qubits[::-1] pq += self.inv_qft(ctrl_qubits) #print(wave.wavefunction(address_qubits(pq))) for i in range(total_iters): pq += MEASURE(ctrl_qubits[i], ro[i]) ''' a_vals = [] for i in range(total_iters): a_vals.append(curr_a) curr_a = pow(curr_a, 2, self.N) for ind in range(total_iters - 1, -1, -1): pq += H(c) pq += self.u_a(b_qubits, a_vals[ind], c, x_qubits) pq += self.partial_inv_qft(c, ind, ro, total_iters) pq += MEASURE(c, ro[ind]) then_prog = Program(X(c)) pq.if_then(ro[ind], then_prog) return address_qubits(pq)
def test_multi_qubit_qft(): trial_prog = Program() trial_prog.inst(X(0), X(1), X(2)) trial_prog = trial_prog + inverse_qft([0, 1, 2]) result_prog = Program().inst([X(0), X(1), X(2), SWAP(0, 2), H(0), CPHASE(-1.5707963267948966, 0, 1), CPHASE(-0.7853981633974483, 0, 2), H(1), CPHASE(-1.5707963267948966, 1, 2), H(2)]) assert trial_prog == result_prog
def test_qvm_compile_pickiness(forest): p = Program(Declare("ro", "BIT"), X(0), MEASURE(0, MemoryReference("ro"))) p.wrap_in_numshots_loop(1000) nq = PyQuilExecutableResponse(program=p.out(), attributes={"num_shots": 1000}) # Ok, non-realistic qc = get_qc("9q-qvm") qc.run(p) # Also ok qc.run(nq) # Not ok qc = get_qc("9q-square-qvm") with pytest.raises(TypeError): qc.run(p) # Yot ok qc.run(nq)
def test_qubit_placeholder(): p = Program() p.inst(H(0)) # H 0 q1 = QubitPlaceholder() # q1 = 1 q2 = QubitPlaceholder() # q2 = 3 p.inst(CNOT(q1, q2)) # CNOT 1 3 p.inst(H(2)) q3 = QubitPlaceholder() # q3 = 4 p.inst(X(q3)) # X 4 with pytest.raises(RuntimeError) as e: _ = p.out() assert e.match(r"Qubit q\d+ has not been assigned an index")
def test_qubit_placeholder_2(): p = Program() p.inst(H(0)) # H 0 q1 = QubitPlaceholder() # q1 = 1 q2 = QubitPlaceholder() # q2 = 3 p.inst(CNOT(q1, q2)) # CNOT 1 3 p.inst(H(2)) q3 = QubitPlaceholder() # q3 = 4 p.inst(X(q3)) # X 4 with pytest.raises(ValueError) as e: _ = address_qubits(p, {q1: 1, q2: 3, q3: 4}) assert e.match("Your program mixes instantiated qubits with placeholders")
def test_x_oracle_one_grover(x_oracle): """Testing that Grover's algorithm with an oracle that applies an X gate to the query bit works, with one iteration.""" x_oracle_grover = Program() qubit0 = x_oracle_grover.alloc() qubits = [qubit0] oracle, query_qubit = x_oracle with patch("pyquil.quil.Program.alloc") as mock_alloc: mock_alloc.return_value = qubit0 generated_x_oracle_grover = Grover().oracle_grover(oracle, qubits, 1) # First we put the input into uniform superposition. x_oracle_grover.inst(H(qubit0)) # Now an oracle is applied. x_oracle_grover.inst(X(query_qubit)) # We now apply the diffusion operator. x_oracle_grover.inst(H(qubit0)) x_oracle_grover.inst(Z(qubit0)) x_oracle_grover.inst(H(qubit0)) assert generated_x_oracle_grover == x_oracle_grover
def prep_qubits(qubits: list, n: int): """ Generate a quil program which prepares given qubits in a state representing number n. :param n: the number to write :param qubits: qubit indexes to write the number n :return: circuit to write number n on given qubits. """ p = Program() for qubit in qubits: if n % 2 == 1: p.inst(X(qubit)) else: p.inst(I(qubit)) n = int(n/2) return p
def teleport(start_index, end_index, ancilla_index): """Teleport a qubit from start to end using an ancilla qubit """ p = make_bell_pair(end_index, ancilla_index) # do the teleportation p.inst(CNOT(start_index, ancilla_index)) p.inst(H(start_index)) # measure the results and store them in classical registers [0] and [1] p.measure(start_index, 0) p.measure(ancilla_index, 1) p.if_then(1, X(2)) p.if_then(0, Z(2)) p.measure(end_index, 2) return p
def test_alloc(): p = Program() p.inst(H(0)) # H 0 q1 = p.alloc() # q1 = 1 q2 = p.alloc() # q2 = 3 p.inst(CNOT(q1, q2)) # CNOT 1 3 p.inst(H(2)) q3 = p.alloc() # q3 = 4 p.inst(X(q3)) # X 4 with pytest.raises(RuntimeError) as e: _ = p.out() assert e.match(r'Qubit q\d+ has not been assigned an index')
def test_tomo_experiment_pre_grouped(): expts = [ [ ExperimentSetting(TensorProductState(), sX(0) * sI(1)), ExperimentSetting(TensorProductState(), sI(0) * sX(1)), ], [ ExperimentSetting(TensorProductState(), sZ(0) * sI(1)), ExperimentSetting(TensorProductState(), sI(0) * sZ(1)), ], ] suite = Experiment(settings=expts, program=Program(X(0), Y(1))) assert len(suite) == 2 # number of groups for es1, es2 in zip(expts, suite): for e1, e2 in zip(es1, es2): assert e1 == e2 prog_str = str(suite).splitlines()[3:5] assert prog_str == EXPERIMENT_REPR.splitlines()[4:6]
def run_bv(self, bit): # initialize all attributes self._run_init(bit) qvm = get_qc('9q-square-qvm') # To get a oracle = self._create_oracle(bit) a_circuit = Program() a_ro = a_circuit.declare('ro', 'BIT', len(self.qubits) + 1) bv_circuit = Program() bv_circuit.defgate("oracle", oracle) bv_circuit.inst(X(self.helper), H(self.helper)) bv_circuit.inst([H(i) for i in self.qubits]) bv_circuit.inst( tuple(["oracle"] + sorted(self.qubits + [self.helper], reverse=True))) bv_circuit.inst([H(i) for i in self.qubits]) a_circuit += bv_circuit a_circuit += [ MEASURE(qubit, ro) for qubit, ro in zip(self.qubits, a_ro) ] a_executable = qvm.compile(a_circuit) for i in range(self.n_trials): a_results = qvm.run(a_executable) print("trial {} a:".format(i)) pprint.pprint(a_results[0][::-1]) # To get b use all 0s b_circuit = Program() b_ro = b_circuit.declare('ro', 'BIT', len(self.qubits) + 1) b_circuit += bv_circuit b_circuit += [MEASURE(self.helper, b_ro[self.helper])] b_executable = qvm.compile(b_circuit) for i in range(self.n_trials): b_results = qvm.run(b_executable) print("trial {} b:".format(i)) pprint.pprint(b_results)
def test_dagger(): # these gates are their own inverses p = Program().inst(I(0), X(0), Y(0), Z(0), H(0), CNOT(0,1), CCNOT(0,1,2), SWAP(0,1), CSWAP(0,1,2)) assert p.dagger().out() == 'CSWAP 0 1 2\nSWAP 0 1\n' \ 'CCNOT 0 1 2\nCNOT 0 1\nH 0\n' \ 'Z 0\nY 0\nX 0\nI 0\n' # these gates require negating a parameter p = Program().inst(PHASE(pi, 0), RX(pi, 0), RY(pi, 0), RZ(pi, 0), CPHASE(pi, 0, 1), CPHASE00(pi, 0, 1), CPHASE01(pi, 0, 1), CPHASE10(pi, 0, 1), PSWAP(pi, 0, 1)) assert p.dagger().out() == 'PSWAP(-3.141592653589793) 0 1\n' \ 'CPHASE10(-3.141592653589793) 0 1\n' \ 'CPHASE01(-3.141592653589793) 0 1\n' \ 'CPHASE00(-3.141592653589793) 0 1\n' \ 'CPHASE(-3.141592653589793) 0 1\n' \ 'RZ(-3.141592653589793) 0\n' \ 'RY(-3.141592653589793) 0\n' \ 'RX(-3.141592653589793) 0\n' \ 'PHASE(-3.141592653589793) 0\n' # these gates are special cases p = Program().inst(S(0), T(0), ISWAP(0, 1)) assert p.dagger().out() == 'PSWAP(1.5707963267948966) 0 1\n' \ 'RZ(0.7853981633974483) 0\n' \ 'PHASE(-1.5707963267948966) 0\n' # must invert defined gates G = np.array([[0, 1], [0+1j, 0]]) p = Program().defgate("G", G).inst(("G", 0)) assert p.dagger().out() == 'DEFGATE G-INV:\n' \ ' 0.0+-0.0i, 0.0-1.0i\n' \ ' 1.0+-0.0i, 0.0+-0.0i\n\n' \ 'G-INV 0\n' # can also pass in a list of inverses inv_dict = {"G":"J"} p = Program().defgate("G", G).inst(("G", 0)) assert p.dagger(inv_dict=inv_dict).out() == 'J 0\n'