def _one_q_pauli_prep(label: str, index: int, qubit: QubitDesignator) -> Program: """Prepare the index-th eigenstate of the pauli operator given by label.""" if index not in [0, 1]: raise ValueError(f"Bad Pauli index: {index}") if label == "X": if index == 0: return Program(RY(pi / 2, qubit)) else: return Program(RY(-pi / 2, qubit)) elif label == "Y": if index == 0: return Program(RX(-pi / 2, qubit)) else: return Program(RX(pi / 2, qubit)) elif label == "Z": if index == 0: return Program() else: return Program(RX(pi, qubit)) raise ValueError(f"Bad Pauli label: {label}")
def test_qaoa_unitary(): wf_true = [ 0.00167784 + 1.00210180e-05 * 1j, 0.50000000 - 4.99997185e-01 * 1j, 0.50000000 - 4.99997185e-01 * 1j, 0.00167784 + 1.00210180e-05 * 1j, ] prog = Program([ RY(np.pi / 2, 0), RX(np.pi, 0), RY(np.pi / 2, 1), RX(np.pi, 1), CNOT(0, 1), RX(-np.pi / 2, 1), RY(4.71572463191, 1), RX(np.pi / 2, 1), CNOT(0, 1), RX(-2 * 2.74973750579, 0), RX(-2 * 2.74973750579, 1), ]) test_unitary = program_unitary(prog, n_qubits=2) wf_test = np.zeros(4) wf_test[0] = 1.0 wf_test = test_unitary.dot(wf_test) assert np.allclose(wf_test, wf_true)
def test_qaoa_circuit(): wf_true = [ 0.00167784 + 1.00210180e-05 * 1j, 0.50000000 - 4.99997185e-01 * 1j, 0.50000000 - 4.99997185e-01 * 1j, 0.00167784 + 1.00210180e-05 * 1j, ] prog = Program() prog.inst( [ RY(np.pi / 2, 0), RX(np.pi, 0), RY(np.pi / 2, 1), RX(np.pi, 1), CNOT(0, 1), RX(-np.pi / 2, 1), RY(4.71572463191, 1), RX(np.pi / 2, 1), CNOT(0, 1), RX(-2 * 2.74973750579, 0), RX(-2 * 2.74973750579, 1), ] ) qam = PyQVM(n_qubits=2, quantum_simulator_type=ReferenceWavefunctionSimulator) qam.execute(prog) wf = qam.wf_simulator.wf np.testing.assert_allclose(wf_true, wf, atol=1e-8)
def test_PrepareAndMeasureOnQVM_QubitPlaceholders_nondiag_hamiltonian(): q1, q2, q3 = QubitPlaceholder(), QubitPlaceholder(), QubitPlaceholder() ham = PauliTerm("Y", q1) * PauliTerm("Z", q3) ham += PauliTerm("Y", q1) * PauliTerm("Z", q2, -0.3) ham += PauliTerm("Y", q1) * PauliTerm("X", q3, 2.0) params = [3.0, 0.4, 4.5] prepare_ansatz = Program() param_register = prepare_ansatz.declare("params", memory_type="REAL", memory_size=3) prepare_ansatz.inst(RX(param_register[0], q1)) prepare_ansatz.inst(RY(param_register[1], q2)) prepare_ansatz.inst(RY(param_register[2], q3)) def make_memory_map(params): return {"params": params} qubit_mapping = get_default_qubit_mapping(prepare_ansatz) qvm = get_qc("3q-qvm") with local_qvm(): cost_fn = PrepareAndMeasureOnQVM(prepare_ansatz, make_memory_map, qvm=qvm, hamiltonian=ham, scalar_cost_function=False, base_numshots=100, qubit_mapping=qubit_mapping) out = cost_fn(params, nshots=10) assert np.allclose(out, (0.346, 0.07), rtol=1.1)
def get_decoupling_sequence(self, gate: Gate, dd_pulse_time: float = None) -> "Program": if isinstance(gate, Gate): angle = None combined_gate = get_combined_gate( *get_combined_gate_representation(gate.name, 'Y', gate.params)) if len(gate.qubits) != 1: p = Program(RX(pi, gate.qubits[0]), RX(pi, gate.qubits[1]), RY(pi, gate.qubits[0]), RY(pi, gate.qubits[1]), RX(pi, gate.qubits[0]), RX(pi, gate.qubits[1])) else: p = Program(RX(pi, *gate.qubits), RY(pi, *gate.qubits), RX(pi, *gate.qubits)) seq = set_gate_time(p, dd_pulse_time) GY = combined_gate( angle, *gate.qubits) if angle is not None else combined_gate( *gate.qubits) GY = gates_with_time(GY.name, GY.params, GY.qubits) GY.dd = False seq += GY return seq
def rus(inputs, w, b): in_reg = list() for i in inputs: in_reg.append(i) an_reg = list() an_reg.append(QubitPlaceholder()) an_reg.append(QubitPlaceholder()) # Gates and classical memory preparation prep_pq = Program() acl_ro = prep_pq.declare('acl_{}_ro'.format(an_reg[0]), 'BIT', 1) # Rotation gates rot_linear_pq = Program() for i in range(len(w)): rot_linear_pq += CRY(w[i])(in_reg[i], an_reg[0]) rot_linear_pq += RY(b, an_reg[0]) rot_pq = Program() rot_pq += rot_linear_pq rot_pq += CY(an_reg[0], an_reg[1]) rot_pq += RZ(-np.pi / 2, an_reg[0]) rot_pq += rot_linear_pq # Ancilla bit measurement pq = Program() pq += prep_pq pq += rot_pq pq += MEASURE(an_reg[0], acl_ro) # Repeated circuit rep_pq = Program() # rep_pq += RESET(reg[1]) rep_pq += RY(-np.pi / 2, an_reg[1]) rep_pq += rot_pq rep_pq += MEASURE(an_reg[0], acl_ro) pq.while_do(acl_ro, rep_pq) return pq, an_reg[1]
def test_qaoa_density(): wf_true = [ 0.00167784 + 1.00210180e-05 * 1j, 0.50000000 - 4.99997185e-01 * 1j, 0.50000000 - 4.99997185e-01 * 1j, 0.00167784 + 1.00210180e-05 * 1j, ] wf_true = np.reshape(np.array(wf_true), (4, 1)) rho_true = np.dot(wf_true, np.conj(wf_true).T) prog = Program() prog.inst([ RY(np.pi / 2, 0), RX(np.pi, 0), RY(np.pi / 2, 1), RX(np.pi, 1), CNOT(0, 1), RX(-np.pi / 2, 1), RY(4.71572463191, 1), RX(np.pi / 2, 1), CNOT(0, 1), RX(-2 * 2.74973750579, 0), RX(-2 * 2.74973750579, 1), ]) qam = PyQVM(n_qubits=2, quantum_simulator_type=ReferenceDensitySimulator).execute(prog) rho = qam.wf_simulator.density np.testing.assert_allclose(rho_true, rho, atol=1e-8)
def add_xy_meas_coda_to_program(prog, bit_pos_to_xy_str): """ This method adds a "coda" (tail ending) to prog using data in bit_pos_to_xy_str to determine what coda will be. Parameters ---------- prog : Program bit_pos_to_xy_str : dict[int, str] Returns ------- None """ for bit_pos, xy_str in bit_pos_to_xy_str.items(): if xy_str == 'X': # exp(-i*sigy*pi/4)*sigz*exp(i*sigy*pi/4) = sigx prog += RY(-np.pi / 2, bit_pos) elif xy_str == 'Y': # exp(i*sigx*pi/4)*sigz*exp(-i*sigx*pi/4) = sigy prog += RX(np.pi / 2, bit_pos) else: assert False, "Unsupported qbit measurement. '" + \ xy_str + "' Should be either 'X' or 'Y'"
def ansatz(params): p = Program() for i in range(depth): p += CNOT(2, 0) for j in range(n_qubits): p += Program(RY(params[j], j)) return p
def prep_state_program(self, sample): #TODO: Prep a state given classical vector x prog = Program() for i in range(0, self.n): angle = math.pi*sample[i]#/2 prog.inst(RY(angle, i)) return prog
def test_pyquil_program(): """Tests if the Dynamic Decoupling Sequence gives rise to Identity operation in PyQuil """ _duration = 5e-6 _offsets = [0, 1e-6, 2.5e-6, 4e-6, 5e-6] _rabi_rotations = [np.pi / 2, np.pi / 2, np.pi, 0, np.pi / 2] _azimuthal_angles = [0, 0, np.pi / 2, 0, 0] _detuning_rotations = [0, 0, 0, np.pi, 0] sequence = DynamicDecouplingSequence( duration=_duration, offsets=_offsets, rabi_rotations=_rabi_rotations, azimuthal_angles=_azimuthal_angles, detuning_rotations=_detuning_rotations) program = convert_dds_to_pyquil_program(sequence, [0], gate_time=1e-6) assert len(program) == 13 assert program[0] == Pragma("PRESERVE_BLOCK") assert program[-1] == Pragma("END_PRESERVE_BLOCK") assert program[1] == RX(np.pi / 2, 0) assert program[2] == I(0) assert program[3] == RX(np.pi / 2, 0) assert program[4] == I(0) assert program[5] == RY(np.pi, 0) assert program[6] == I(0) assert program[7] == RZ(np.pi, 0) assert program[8] == I(0) assert program[9] == RX(np.pi / 2, 0)
def pauli_meas(idx, op): r""" Generate gate sequence to measure in the eigenbasis of a Pauli operator, assuming we are only able to measure in the Z eigenbasis. The available operations are the following: .. math:: 'X' = \begin{bmatrix} 0 & \frac{-\pi}{2} \\ \frac{-\pi}{2} & 0 \end{bmatrix} 'Y' = \begin{bmatrix} 0 & \frac{-i\pi}{2} \\ \frac{i\pi}{2} & 0 \end{bmatrix} and :math:`'Z' = 'I' = \mathbb{I}`. :param int idx: the qubit index on which the measurement basis rotation is to be performed. :param str op: enumeration ('X', 'Y', 'Z', 'I') representing the axis of the given Pauli matrix :return: a `pyquil` Program representing the Pauli matrix projected onto the Z eigenbasis. :rtype: Program """ if op == 'X': return Program(RY(-np.pi / 2, idx)) elif op == 'Y': return Program(RX(np.pi / 2, idx)) elif op == 'Z': return Program() elif op == 'I': return Program()
def test_qc_expectation_on_qvm(client_configuration: QCSClientConfiguration, dummy_compiler: DummyCompiler): # regression test for https://github.com/rigetti/forest-tutorials/issues/2 qc = QuantumComputer(name="testy!", qam=QVM(client_configuration=client_configuration), compiler=dummy_compiler) p = Program() theta = p.declare("theta", "REAL") p += RESET() p += RY(theta, 0) p.wrap_in_numshots_loop(10000) sx = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0)), out_operator=sX(0)) e = Experiment(settings=[sx], program=p) thetas = [-np.pi / 2, 0.0, np.pi / 2] results = [] # Verify that multiple calls to qc.experiment with the same experiment backed by a QVM that # requires_exectutable does not raise an exception. for theta in thetas: results.append(qc.experiment(e, memory_map={"theta": [theta]})) assert np.isclose(results[0][0].expectation, -1.0, atol=0.01) assert np.isclose(results[0][0].std_err, 0) assert results[0][0].total_counts == 20000 # bounds on atol and std_err here are a little loose to try and avoid test flakiness. assert np.isclose(results[1][0].expectation, 0.0, atol=0.1) assert results[1][0].std_err < 0.01 assert results[1][0].total_counts == 20000 assert np.isclose(results[2][0].expectation, 1.0, atol=0.01) assert np.isclose(results[2][0].std_err, 0) assert results[2][0].total_counts == 20000
def measure_graph_state(graph: nx.Graph, focal_node: int): """Given a graph state, measure a focal node and its neighbors with a particular measurement angle. :param prep_program: Probably the result of :py:func:`create_graph_state`. :param qs: List of qubits used in prep_program or anything that can be indexed by the nodes in the graph ``graph``. :param graph: The graph state graph. This is needed to figure out what the neighbors are :param focal_node: The node in the graph to serve as the focus. The focal node is measured at an angle and all its neighbors are measured in the Z basis :return Program, list of classical offsets into the ``ro`` register. """ program = Program() theta = program.declare('theta', 'REAL') program += RY(theta, focal_node) neighbors = sorted(graph[focal_node]) ro = program.declare('ro', 'BIT', len(neighbors) + 1) program += MEASURE(focal_node, ro[0]) for i, neighbor in enumerate(neighbors): program += MEASURE(neighbor, ro[i + 1]) classical_addresses = list(range(len(neighbors) + 1)) return program, classical_addresses
def get_parameteric_circuit(self, theta=None, verify=False): """ Constructs a parameterized circuit that returns |00> and |11> with equal probability where the optimal parameter theta needs to be determined using Gradient Descent This function is also used to return a circuit for a given value of theta in order to verify the final wavefunction Parameters: ----------- theta : Value of the parameter for which a circuit is returned to verify the final wavefunction verify : If True, returns a circuit for the given value of theta """ parameteric_program = Program() if theta is None: theta = parameteric_program.declare("theta", memory_type="REAL") parameteric_program.inst(RY(theta, 0)) parameteric_program.inst(CNOT(0, 1)) if not verify: ro = parameteric_program.declare("ro", memory_type="BIT", memory_size=2) parameteric_program.inst(MEASURE(0, ro[0])) parameteric_program.inst(MEASURE(1, ro[1])) parameteric_program.wrap_in_numshots_loop(shots=self.shots) return parameteric_program
def generate_single_depth_experiment(rotation: Program, depth: int, exp_type: str, axis: Tuple = None) -> Program: """ Generate an experiment for a single depth where the type specifies a final measurement of either X or Y. The rotation program is repeated depth number of times, and we assume the rotation is about the axis (theta, phi). :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 axis: the axis of rotation. If none is specified, axis is assumed to be the Z axis. (rotation should be RZ) :return: a program specifying the entire experiment of a single iteration of the RPE protocol in [RPE] """ experiment = Program() ro_bit = experiment.declare("ro", "BIT", 1) qubit = list(rotation.get_qubits())[0] prepare_state(experiment, qubit, axis) for _ in range(depth): experiment.inst(rotation) if axis: experiment.inst(RZ(-axis[1], qubit)) experiment.inst(RY(-axis[0], qubit)) local_pauli_eig_meas(experiment, exp_type, qubit) experiment.measure(qubit, ro_bit) return experiment
def prep_state_program(x): #TODO: Prep a state given classical vector x prog = Program() for i in range(0, len(x)): angle = math.pi * x[i] / 2 prog.inst(RY(angle, i)) return prog
def prog(sample): p = pq.Program() n_features = len(sample) for j in range(n_qubits): p.inst(RY(np.arcsin(sample[j % n_features]), j)) p.inst(RZ(np.arccos(sample[j % n_features]**2), j)) return p
def rus_single(input, theta): reg = list() reg.append(input) reg.append(QubitPlaceholder()) reg.append(QubitPlaceholder()) # Gates and classical memory preparation prep_pq = Program() prep_pq += dg_cry prep_pq += dg_cy acl_ro = prep_pq.declare('acl_ro', 'BIT', 1) # Rotation gates rot_pq = Program() rot_pq += CRY(2 * theta)(reg[0], reg[1]) rot_pq += CY(reg[1], reg[2]) rot_pq += RZ(-np.pi / 2, reg[1]) rot_pq += CRY(2 * theta)(reg[0], reg[1]) # Ancilla bit measurement pq = Program() pq += prep_pq pq += rot_pq pq += MEASURE(reg[1], acl_ro) # Repeated circuit rep_pq = Program() # rep_pq += RESET(reg[1]) rep_pq += RY(-np.pi / 2, reg[2]) rep_pq += rot_pq rep_pq += MEASURE(reg[1], acl_ro) pq.while_do(acl_ro, rep_pq) return pq, reg[2]
def ansatz(params): qp = Program() for i in range(depth): qp.inst(CNOT(1,0)) for j in range(n_qubits): qp.inst(RY(params[j], j)) return qp
def prep_state_program(self): #TODO: Prep a state given classical vector x prog = Program() sample = prog.declare('sample', memory_type='REAL', memory_size=self.n) for i in range(0, self.n): angle = math.pi * sample[i] / 2 prog.inst(RY(angle, i)) return prog
def test_noisy_rpe(qvm): qvm.qam.random_seed = 5 angles = pi * np.linspace(2 / 9, 2.0 - 2 / 9, 3) add_error = .15 q = 0 def add_damping_dephasing_noise(prog, T1, T2, gate_time): p = Program() p.defgate("noise", np.eye(2)) p.define_noisy_gate("noise", [q], damping_after_dephasing(T1, T2, gate_time)) for elem in prog: p.inst(elem) if isinstance(elem, Measurement): continue # skip measurement p.inst(("noise", q)) return p def add_noise_to_experiments(expts, t1, t2, p00, p11, q): gate_time = 200 * 10**(-9) for ex in expts: ex.program = add_damping_dephasing_noise( ex.program, t1, t2, gate_time).define_noisy_readout(q, p00, p11) tolerance = .1 # scan over each angle and check that RPE correctly predicts the angle to within .1 radians for angle in angles: RH = Program(RY(-pi / 4, q)).inst(RZ(angle, q)).inst(RY(pi / 4, q)) evecs = rpe.bloch_rotation_to_eigenvectors(pi / 4, q) cob_matrix = rpe.get_change_of_basis_from_eigvecs(evecs) cob = rpe.change_of_basis_matrix_to_quil(qvm, [q], cob_matrix) prep, meas, settings = rpe.all_eigenvector_prep_meas_settings([q], cob) expts = rpe.generate_rpe_experiments(RH, prep, meas, settings, num_depths=7) add_noise_to_experiments(expts, 25 * 10**(-6.), 20 * 10**(-6.), .92, .87, q) results = rpe.acquire_rpe_data(qvm, expts, multiplicative_factor=5., additive_error=add_error) phase_estimate = rpe.robust_phase_estimate(results, [q]) assert np.allclose(phase_estimate, angle, atol=tolerance)
def pauli_basis_measurements(qubit): """ Generates the Programs required to measure the expectation values of the pauli operators. :param qubit: Required argument (so that the caller has a reference). """ pauli_label_meas_progs = [Program(), Program(RY(-np.pi / 2, qubit)), Program(RX(-np.pi / 2, qubit)), Program()] return pauli_label_meas_progs
def local_pauli_eigs_prep(op, qubit): """ Generate all gate sequences to prepare all eigenstates of a (local) Pauli operator, assuming we are starting from the ground state. :param str op: A string representation of the Pauli operator whose eigenstate we'd like to prepare. :param int qubit: The index of the qubit that the preparation is acting on :rtype list: A list of programs """ if op == 'X': gates = [RY(pi / 2, qubit), RY(-pi / 2, qubit)] elif op == 'Y': gates = [RX(-pi / 2, qubit), RX(pi / 2, qubit)] elif op == 'Z': gates = [I(qubit), RX(pi, qubit)] else: raise ValueError('Unknown gate operation') return [Program(gate) for gate in gates]
def random_local_pauli_eig_prep(prog, op, qubit, random_seed=None): """ Generate gate sequence to prepare a random local eigenstate of a Pauli operator, assuming we are starting from the ground state. :param Program prog: The `pyquil.quil.Program` object to which preparation pulses will be appended :param str op: Single character string representing the Pauli operator (one of 'I', 'X', 'Y', 'Z') :param int qubit: index of Qubit the preparation acts on :param int random_seed: A seed to seed the RNG with. :return: A string description of the eigenstate prepared. """ # TODO: # + Return only the sign of the Pauli operator (more compact representation) # + When given the identity, prepare random Pauli eigenstate # + replace calls to random with sampling of random integers if random_seed is not None: seed(random_seed) if op == 'X': if random() > 0.5: gate = RY(pi / 2, qubit) descr = '+X' else: gate = RY(-pi / 2, qubit) descr = '-X' elif op == 'Y': if random() > 0.5: gate = RX(-pi / 2, qubit) descr = '+Y' else: gate = RX(pi / 2, qubit) descr = '-Y' elif op == 'Z': if random() > 0.5: gate = I(qubit) descr = '+Z' else: gate = RX(pi, qubit) descr = '-Z' else: raise ValueError('Unknown gate operation') prog.inst(gate) return descr
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(-pi) 0 1\n' \ 'CPHASE10(-pi) 0 1\n' \ 'CPHASE01(-pi) 0 1\n' \ 'CPHASE00(-pi) 0 1\n' \ 'CPHASE(-pi) 0 1\n' \ 'RZ(-pi) 0\n' \ 'RY(-pi) 0\n' \ 'RX(-pi) 0\n' \ 'PHASE(-pi) 0\n' # these gates are special cases p = Program().inst(S(0), T(0), ISWAP(0, 1)) assert p.dagger().out() == 'PSWAP(pi/2) 0 1\n' \ 'RZ(pi/4) 0\n' \ 'PHASE(-pi/2) 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, -i\n' \ ' 1.0, 0.0\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' # defined parameterized gates cannot auto generate daggered version https://github.com/rigetticomputing/pyquil/issues/304 theta = Parameter('theta') gparam_matrix = np.array([[quil_cos(theta / 2), -1j * quil_sin(theta / 2)], [-1j * quil_sin(theta / 2), quil_cos(theta / 2)]]) g_param_def = DefGate('GPARAM', gparam_matrix, [theta]) p = Program(g_param_def) with pytest.raises(TypeError): p.dagger() # defined parameterized gates should passback parameters https://github.com/rigetticomputing/pyquil/issues/304 GPARAM = g_param_def.get_constructor() p = Program(GPARAM(pi)(1, 2)) assert p.dagger().out() == 'GPARAM-INV(pi) 1 2\n'
def GiveLogicalErrRate(code_name, noise_model_kraus, num_trials_tot, code, init_state_mode): logical_err_rate = 0.0 # print(code.encoding_program) # print(code.decoding_program) for trial_id in range(num_trials_tot): initial_state_prep = Program() inverse_initial_state_prep = Program() for qubit_id in range(code.k): if init_state_mode == 0: bit = np.random.randint(2) if bit == 1: initial_state_prep += X(qubit_id) inverse_initial_state_prep += X(qubit_id) else: z_angle = (2 * np.pi * np.random.rand(1)) y_angle = (1 * np.pi * np.random.rand(1)) initial_state_prep += RZ(z_angle[0], qubit_id) initial_state_prep += RY(y_angle[0], qubit_id) inverse_initial_state_prep += RY(-y_angle[0], qubit_id) inverse_initial_state_prep += RZ(-z_angle[0], qubit_id) # Don't use I gate anywher else in program error_prog = Program() for qubit_id in range(code.n): error_prog += Program(I(qubit_id)) kraus_ops = noise_model_kraus error_defn = Program() for qubit_id in range(code.n): error_defn.define_noisy_gate('I', [qubit_id], kraus_ops) error_prog = error_defn + error_prog num_errors = basic_tests.test_general(code, initial_state_prep, error_prog, 1, inverse_initial_state_prep) logical_err_rate += num_errors logical_err_rate = logical_err_rate / num_trials_tot print(code_name, logical_err_rate) return logical_err_rate
def test_rotation_programs(): """ Testing the generation of post rotations """ test_term = sZ(0) * sX(20) * sI(100) * sY(5) # note: string comparison of programs requires gates to be in the same order true_rotation_program = Program().inst( [RX(np.pi / 2)(5), RY(-np.pi / 2)(20)]) test_rotation_program = get_rotation_program(test_term) assert true_rotation_program.out() == test_rotation_program.out()
def test_noisy_RPE(qvm): qvm.qam.random_seed = 5 angles = pi * np.linspace(2 / 9, 2.0 - 2 / 9, 3) num_depths = 6 # max depth of 2^(num_depths - 1) add_error = .15 def add_damping_dephasing_noise(prog, T1, T2, gate_time): p = Program() p.defgate("noise", np.eye(2)) p.define_noisy_gate("noise", [0], damping_after_dephasing(T1, T2, gate_time)) for elem in prog: p.inst(elem) if isinstance(elem, Measurement): continue # skip measurement p.inst(("noise", 0)) return p def add_noise_to_experiments(df, t1, t2, p00, p11): gate_time = 200 * 10**(-9) df["Experiment"] = Series([ add_damping_dephasing_noise(prog, t1, t2, gate_time).define_noisy_readout( 0, p00, p11) for prog in df["Experiment"].values ]) tolerance = .1 # scan over each angle and check that RPE correctly predicts the angle to within .1 radians for angle in angles: RH = Program(RY(-pi / 4, 0)).inst(RZ(angle, 0)).inst(RY(pi / 4, 0)) experiments = rpe.generate_rpe_experiments(RH, num_depths, axis=(pi / 4, 0)) add_noise_to_experiments(experiments, 25 * 10**(-6.), 20 * 10**(-6.), .92, .87) experiments = rpe.acquire_rpe_data(experiments, qvm, multiplicative_factor=5., additive_error=add_error) xs, ys, x_stds, y_stds = rpe.find_expectation_values(experiments) phase_estimate = rpe.robust_phase_estimate(xs, ys, x_stds, y_stds) assert np.allclose(phase_estimate, angle, atol=tolerance)
def test_noisy_rpe(qvm): qvm.qam.random_seed = 5 angles = pi * np.linspace(2 / 9, 2.0 - 2 / 9, 3) add_error = .15 def add_damping_dephasing_noise(prog, T1, T2, gate_time): p = Program() p.defgate("noise", np.eye(2)) p.define_noisy_gate("noise", [0], damping_after_dephasing(T1, T2, gate_time)) for elem in prog: p.inst(elem) if isinstance(elem, Measurement): continue # skip measurement p.inst(("noise", 0)) return p def add_noise_to_experiments(df, t1, t2, p00, p11): gate_time = 200 * 10**(-9) df["Program"] = Series([ add_damping_dephasing_noise(prog, t1, t2, gate_time).define_noisy_readout( 0, p00, p11) for prog in df["Program"].values ]) tolerance = .1 # scan over each angle and check that RPE correctly predicts the angle to within .1 radians for angle in angles: RH = Program(RY(-pi / 4, 0)).inst(RZ(angle, 0)).inst(RY(pi / 4, 0)) evecs = rpe.bloch_rotation_to_eigenvectors(pi / 4, 0) cob = rpe.get_change_of_basis_from_eigvecs(evecs) expt = rpe.generate_rpe_experiment(RH, cob, num_depths=7) expt = rpe.add_programs_to_rpe_dataframe(qvm, expt) add_noise_to_experiments(expt, 25 * 10**(-6.), 20 * 10**(-6.), .92, .87) expt = rpe.acquire_rpe_data(qvm, expt, multiplicative_factor=5., additive_error=add_error) phase_estimate = rpe.robust_phase_estimate(expt) assert np.allclose(phase_estimate, angle, atol=tolerance)