def test_exponentiate_3cob(): # testing circuit for 3-terms with change of basis generator = PauliTerm("Z", 0, 1.0) * PauliTerm("Y", 1, 1.0) * PauliTerm( "X", 2, 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
def construct_ansatz(theta, num_qubits, num_layers): ''' Constructs the ansatz based on the example provided in the new project spec. ''' theta = np.reshape(theta, (num_qubits, num_layers)) program = Program() for l in range(num_layers): for q in range(num_qubits): # Assumes qubits are ordered program += RX(theta[q, l], q) program += RZ(theta[q, l], q) if (q + 1) < num_qubits: program += CNOT(q, q+1) return program
def generate_t2_echo_experiments( qubits: Sequence[int], times: Sequence[float], detuning: float = 1e6) -> List[ObservablesExperiment]: """ Return ObservablesExperiments containing programs which constitute a T2 echo experiment to measure the T2 echo coherence decay time. For each delay time in times a single program will be generated in which all qubits are initialized to the minusY state and later simultaneously measured along the Y axis. Unlike in the t2_star experiment above there is a 'echo' applied in the middle of the delay in which the qubit is rotated by pi radians around the Y axis. Similarly to t2_star, if the qubit frequency is perfectly calibrated then the Y expectation will oscillate at the given detuning frequency as the qubit is rotated about the Z axis (with respect to the lab frame, which by hypothesis matches the natural qubit frame). Unlike in a t2_star experiment, even if the qubit frequency is off such that there is some spurious rotation about the Z axis during the DELAY, the effect of an ideal echo is to cancel the effect of this rotation so that the qubit returns to the initial state minusY before the detuning rotation is applied. :param qubits: list of qubits to measure. :param times: the times at which to measure, given in seconds. Each time is rounded to the nearest .1 microseconds. :param detuning: The additional detuning frequency about the z axis. :return: ObservablesExperiments which can be run to acquire an estimate of T2 for each qubit. """ expts = [] for t in times: half_time = round(t / 2, 7) # enforce 100ns boundaries t = round(t, 7) program = Program() settings = [] for q in qubits: half_delay = Pragma('DELAY', [q], str(half_time)) # echo program += [half_delay, RY(pi, q), half_delay] # apply detuning program += RZ(2 * pi * t * detuning, q) settings.append(ExperimentSetting(minusY(q), PauliTerm('Y', q))) expts.append(ObservablesExperiment(settings, program)) return expts
def parameterized_bitstring_prep(qubits: Sequence[int], reg_name: str, append_measure: bool = False, in_x_basis: bool = False) -> Program: """ Produces a parameterized program for the given group of qubits, where each qubit is prepared in the 0 or 1 state depending on the parameterization specified at run-time. See also bitstring_prep which produces a non-parameterized program that prepares and measures a single pre-specified bitstring on the given qubits. Parameterization allows for a single program to measure each bitstring (specified at run-time) and speeds up the collective measurements of all bitstring for a group of qubits. Note that the program produced by bitstring_prep does not execute any gates when preparing 0 on a particular qubit and executes only one gate to prepare 1; meanwhile, this method produces a program which executes three gates for either preparation on each qubit. :param qubits: labels of qubits on which some bitstring will be prepared and, perhaps, measured :param reg_name: the name of the register that will hold the bitstring parameters. :param append_measure: dictates whether to measure the qubits after preparing the bitstring :param in_x_basis: if true, prepare the bitstring in the x basis, where plus <==> zero, minus <==> one. :return: a parameterized program capable of preparing, and optionally measuring, any runtime specified bitstring on the given qubits. See estimate_joint_confusion_in_set in readout.py for example use. """ program = Program() if append_measure: ro = program.declare('ro', memory_type='BIT', memory_size=len(qubits)) bitstr_reg = program.declare(reg_name, memory_type='REAL', memory_size=len(qubits)) for idx, qubit in enumerate(qubits): program += RX(pi / 2, qubit) program += RZ(pi * bitstr_reg[idx], qubit) program += RX(-pi / 2, qubit) # if we are doing logic in X basis, follow each bit preparation with a Hadamard # H |0> = |+> and H |1> = |-> where + and - label the X basis vectors. if in_x_basis: program += H(qubit) if append_measure: program += MEASURE(qubit, ro[idx]) return program
def test_exponentiate(): one_pauli_term = QubitOperator('X0 Y2 Z3') test_program = exponentiate(one_pauli_term) true_program = Program().inst([ H(0), RX(np.pi / 2)(2), CNOT(0, 2), CNOT(2, 3), RZ(2.0)(3), CNOT(2, 3), CNOT(0, 2), H(0), RX(-np.pi / 2)(2) ]) # pyquil has no program compare object # string base comparison might fail assert true_program.out() == test_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_get_qvm_noise_supported_gates_from_compiler_isa(compiler_isa): gates = _get_qvm_noise_supported_gates(compiler_isa) for q in [0, 1, 2]: for g in [ I(q), RX(np.pi / 2, q), RX(-np.pi / 2, q), RX(np.pi, q), RX(-np.pi, q), RZ(THETA, q), ]: assert g in gates assert CZ(0, 1) in gates assert CZ(1, 0) in gates assert ISWAP(1, 2) in gates assert ISWAP(2, 1) in gates assert CPHASE(THETA, 2, 0) in gates assert CPHASE(THETA, 0, 2) in gates
def test_exponentiate_3cob(): # testing circuit for 3-terms with change of basis q = QubitPlaceholder.register(8) generator = PauliTerm("Z", q[0], 1.0) * PauliTerm( "Y", q[1], 1.0) * PauliTerm("X", q[2], 1.0) para_prog = exponential_map(generator) prog = para_prog(1) result_prog = Program().inst([ RX(math.pi / 2.0, q[1]), H(q[2]), CNOT(q[0], q[1]), CNOT(q[1], q[2]), RZ(2.0, q[2]), CNOT(q[1], q[2]), CNOT(q[0], q[1]), RX(-math.pi / 2.0, q[1]), H(q[2]) ]) assert address_qubits(prog) == address_qubits(result_prog)
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'
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)
def test_lifted_gate_modified(): test_unitary = lifted_gate(RZ(np.pi / 4, 0).dagger(), 1) true_unitary = mat.RZ(-np.pi / 4) assert np.allclose(test_unitary, true_unitary) test_unitary = lifted_gate(X(0).dagger().controlled(1), 2) true_unitary = lifted_gate(CNOT(1, 0), 2) other_true = mat.CNOT assert np.allclose(test_unitary, true_unitary) assert np.allclose(other_true, true_unitary) test_unitary = lifted_gate( X(1).dagger().controlled(0).dagger().dagger(), 2) true_unitary = lifted_gate(CNOT(0, 1), 2) assert np.allclose(test_unitary, true_unitary) test_unitary = lifted_gate( X(0).dagger().controlled(1).dagger().dagger().controlled(2), 3) true_unitary = lifted_gate(CCNOT(1, 2, 0), 3) other_true = mat.CCNOT assert np.allclose(test_unitary, true_unitary) assert np.allclose(other_true, true_unitary) test_unitary = lifted_gate( RY(np.pi / 4, 0).dagger().controlled(2).dagger().dagger(), 3) ry_part = lifted_gate(RY(-np.pi / 4, 0), 1) zero = np.eye(2) zero[1, 1] = 0 one = np.eye(2) one[0, 0] = 0 true_unitary = np.kron(zero, np.eye(4)) + np.kron( one, np.kron(np.eye(2), ry_part)) assert np.allclose(test_unitary, true_unitary) test_unitary = lifted_gate(PHASE(0.0, 1).forked(0, [np.pi]), 2) true_unitary = lifted_gate(CZ(0, 1), 2) assert np.allclose(test_unitary, true_unitary) test_unitary = lifted_gate( PHASE(0.0, 2).forked(1, [0.0]).forked(0, [0.0, np.pi]), 3) true_unitary = lifted_gate(CZ(1, 2).controlled(0), 3) assert np.allclose(test_unitary, true_unitary)
def test_exponentiate_3ns(): # testing circuit for 3-terms non-sequential generator = (PauliTerm("Y", 0, 1.0) * PauliTerm("I", 1, 1.0) * PauliTerm("Y", 2, 1.0) * PauliTerm("Y", 3, 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_gates_in_isa(isa_dict): isa = ISA.from_dict(isa_dict) gates = gates_in_isa(isa) for q in [0, 1, 2]: for g in [ I(q), RX(np.pi / 2, q), RX(-np.pi / 2, q), RX(np.pi, q), RX(-np.pi, q), RZ(THETA, q) ]: assert g in gates assert CZ(0, 1) in gates assert CZ(1, 0) in gates assert ISWAP(1, 2) in gates assert ISWAP(2, 1) in gates assert CPHASE(THETA, 2, 0) in gates assert CPHASE(THETA, 0, 2) in gates
def test_exponentiate_3ns(): # testing circuit for 3-terms non-sequential q = QubitPlaceholder.register(8) generator = (PauliTerm("Y", q[0], 1.0) * PauliTerm("I", q[1], 1.0) * PauliTerm("Y", q[2], 1.0) * PauliTerm("Y", q[3], 1.0)) para_prog = exponential_map(generator) prog = para_prog(1) result_prog = Program().inst([ RX(math.pi / 2.0, q[0]), RX(math.pi / 2.0, q[2]), RX(math.pi / 2.0, q[3]), CNOT(q[0], q[2]), CNOT(q[2], q[3]), RZ(2.0, q[3]), CNOT(q[2], q[3]), CNOT(q[0], q[2]), RX(-math.pi / 2.0, q[0]), RX(-math.pi / 2.0, q[2]), RX(-math.pi / 2.0, q[3]) ]) assert address_qubits(prog) == address_qubits(result_prog)
def test_expectations_at_depth(qvm): qvm.qam.random_seed = 5 q = 0 qubits = (q, ) expected_outcomes = [1., 0, -1., 0] for depth in [0, 1, 2, 3, 4]: prep, meas, settings = rpe.all_eigenvector_prep_meas_settings( qubits, I(q)) depth_many_rot = [RZ(pi / 2, q) for _ in range(depth)] program = Program(prep) + sum(depth_many_rot, Program()) + Program(meas) expt = ObservablesExperiment(list(settings), program) results = list(estimate_observables(qvm, expt)) for res in results: meas_dir = res.setting.observable[q] idx = ((depth - 1) if meas_dir == 'Y' else depth) % 4 expected = expected_outcomes[idx] exp = res.expectation assert np.allclose(expected, exp, atol=.05)
def test_parameterized_single_qubit_state_preparation(): p = Program() alpha = p.declare("preparation_alpha", "REAL", 2) beta = p.declare("preparation_beta", "REAL", 2) gamma = p.declare("preparation_gamma", "REAL", 2) p += RZ(alpha[0], 0) p += RX(np.pi / 2, 0) p += RZ(beta[0], 0) p += RX(-np.pi / 2, 0) p += RZ(gamma[0], 0) p += RZ(alpha[1], 1) p += RX(np.pi / 2, 1) p += RZ(beta[1], 1) p += RX(-np.pi / 2, 1) p += RZ(gamma[1], 1) assert parameterized_single_qubit_state_preparation([0, 1]).out() == p.out()
def get_random_circuit(qubits, length, two_qubit_gate_portion=0.3): p = Program() for i in range(int(length / 2)): if (len(qubits) > 1) and (random.random() < two_qubit_gate_portion): random_gate = CZ(*(random.sample(qubits, 2))) else: theta = 2 * np.pi * random.random() qubit = random.choice(qubits) random_gate = random.choice([ RZ(theta, qubit), RX(np.pi / 2, qubit), RX(-np.pi / 2, qubit) ]) p.inst(random_gate) for gate in reversed(Program(p.out()).instructions): p.inst(get_dagger_of_native_gate(gate)) return Program('PRAGMA PRESERVE_BLOCK') + p + Program( 'PRAGMA END_PRESERVE_BLOCK')
def generate_single_t2_echo_experiment(qubits: Union[int, List[int]], time: float, detuning: float, n_shots: int = 1000) -> Program: """ Return a T2 echo program in native Quil for a single time point. :param qubits: Which qubits to measure. :param time: The decay time before measurement. :param detuning: The additional detuning frequency about the z axis. :param n_shots: The number of shots to average over for the data point. :return: A T2 Program. """ program = Program() try: len(qubits) except TypeError: qubits = [qubits] ro = program.declare('ro', 'BIT', len(qubits)) for q in qubits: # prepare plus state |+> program += RX(np.pi / 2, q) # wait half of the delay program += Pragma('DELAY', [q], str(time / 2)) # apply an X gate compiled out of RX(90) program += RX(np.pi / 2, q) program += RX(np.pi / 2, q) # wait the other half of the delay program += Pragma('DELAY', [q], str(time / 2)) program += RZ(2 * np.pi * time * detuning, q) program += RX(np.pi / 2, q) for i in range(len(qubits)): program += MEASURE(qubits[i], ro[i]) program.wrap_in_numshots_loop(n_shots) return program
def three_POVM(theta0, phi0, theta1, theta2, theta3, theta4, alpha_uii, Kraus) -> Program: # for the purpose of POVM we choose the most connected qubit (10 in the case) to be the measured one ancilla = [11, 17] target = 10 program = Program(RESET()) # create initial state if theta0 != 0: program.inst(RY(theta0, target)) if phi0 != 0: program.inst(RZ(phi0, target)) # 1st AP module program.inst(POVM_module_1(theta1, theta2, ancilla, target)) # 2nd AP module (+ U2, T1, T2, T3) program.inst(nCU1('y', alpha_uii, [ancilla[0]], target)) program.inst(POVM_module_2(theta3, theta4, ancilla, target)) # Kraus operators if Kraus == 1: # T2 program.inst(X(ancilla[1])) program.inst(nCU1('y', 2 * np.pi / 3, ancilla, target)) program.inst(X(ancilla[1])) # T3 program.inst(nCU1('y', 7 * np.pi / 3, ancilla, target)) # fix paths encodings: 11->01 program.inst(CNOT(ancilla[1], ancilla[0])) return program
def get_test_program(measure: bool = False) -> Program: PI = float(pi.evalf()) p = Program() p += X(0) p += Y(1) p += Z(2) p += H(3) p += S(0) p += T(1) p += RX(PI / 2, 2) p += RY(PI / 2, 3) p += RZ(PI / 2, 0) p += CZ(0, 1) p += CNOT(2, 3) p += CCNOT(0, 1, 2) p += CPHASE(PI / 4, 2, 1) p += SWAP(0, 3) if measure: ro = p.declare("ro", "BIT", 4) p += MEASURE(0, ro[0]) p += MEASURE(3, ro[1]) p += MEASURE(2, ro[2]) p += MEASURE(1, ro[3]) return p
def test_psiref_bar_p2(): bar = [(0, 1)] p = 2 with patch('grove.pyqaoa.maxcut_qaoa.api', spec=qvm_mod): inst = maxcut_qaoa(bar, steps=p) param_prog = inst.get_parameterized_program() # returns are the rotations correct? prog = param_prog([1.2, 3.4, 2.1, 4.5]) result_prog = Program().inst([ H(0), H(1), X(0), PHASE(1.05)(0), X(0), PHASE(1.05)(0), CNOT(0, 1), RZ(2.1)(1), CNOT(0, 1), H(0), RZ(-2.4)(0), H(0), H(1), RZ(-2.4)(1), H(1), X(0), PHASE(2.25)(0), X(0), PHASE(2.25)(0), CNOT(0, 1), RZ(4.5)(1), CNOT(0, 1), H(0), RZ(-6.8)(0), H(0), H(1), RZ(-6.8)(1), H(1), ]) assert prog == result_prog
def get_decoupling_sequence(self, gate: Gate, dd_pulse_time: float = None) -> "Program": if isinstance(gate, Gate): combined_gate = get_combined_gate( *get_combined_gate_representation(gate.name, 'X', gate.params)) if len(gate.qubits) != 1: p = Program(RZ(pi, gate.qubits[0]), RZ(pi, gate.qubits[1]), RX(pi, gate.qubits[0]), RX(pi, gate.qubits[1]), RZ(pi, gate.qubits[0]), RZ(pi, gate.qubits[1])) else: p = Program(RZ(pi, *gate.qubits), RX(pi, *gate.qubits), RZ(pi, *gate.qubits)) seq = set_gate_time(p, dd_pulse_time) GX = combined_gate(*gate.qubits) GX = gates_with_time(GX.name, GX.params, GX.qubits) GX.dd = False seq += GX return seq
0.0625 + 0.0j, 0.0625 + 0.0j, 0.0625 + 0.0j, 0.0625 + 0.0j, 0.0625 + 0.0j, 0.0625 + 0.0j, 0.0625 + 0.0j, 0.0625 + 0.0j, 0.0625 + 0.0j, ] HADAMARD_WF = [0.70710678 + 0.0j, 0.70710678 + 0.0j] ARBITRARY_STATE_GEN_INSTRUCTIONS = { 1: [ RZ(-1.3778211380875056, 0), PHASE(1.3778211380875056, 0), H(0), RY(-1.5707963267948963, 0), RZ(-1.3778211380875056, 0), ], 2: [ RZ(3.9156492624160952, 0), PHASE(-3.9156492624160952, 0), H(0), RY(-1.334414217642601, 0), RZ(-0.51915346851116273, 0), ], 3: [ RZ(1.1065191340906928, 0), PHASE(-1.1065191340906928, 0),
def test_trotterize(): term_one = PauliTerm("X", 0, 1.0) term_two = PauliTerm("Z", 0, 1.0) with pytest.raises(ValueError): trotterize(term_one, term_two, trotter_order=0) with pytest.raises(ValueError): trotterize(term_one, term_two, trotter_order=5) prog, _ = trotterize(term_one, term_one) result_prog = Program().inst( [H(0), RZ(2.0)(0), H(0), H(0), RZ(2.0)(0), H(0)]) compare_progs(prog, result_prog) # trotter_order 1 steps 1 prog, _ = trotterize(term_one, term_two, trotter_steps=1) result_prog = Program().inst([H(0), RZ(2.0)(0), H(0), RZ(2.0)(0)]) compare_progs(prog, result_prog) # trotter_order 1 steps 2 prog, _ = trotterize(term_one, term_two, trotter_steps=2) result_prog = Program().inst([ H(0), RZ(1.0)(0), H(0), RZ(1.0)(0), H(0), RZ(1.0)(0), H(0), RZ(1.0)(0) ]) compare_progs(prog, result_prog) # trotter_order 2 steps 1 prog, _ = trotterize(term_one, term_two, trotter_order=2) result_prog = Program().inst( [H(0), RZ(1.0)(0), H(0), RZ(2.0)(0), H(0), RZ(1.0)(0), H(0)]) compare_progs(prog, result_prog) # trotter_order 2 steps 2 prog, _ = trotterize(term_one, term_two, trotter_order=2, trotter_steps=2) result_prog = Program().inst([ H(0), RZ(0.5)(0), H(0), RZ(1.0)(0), H(0), RZ(0.5)(0), H(0), H(0), RZ(0.5)(0), H(0), RZ(1.0)(0), H(0), RZ(0.5)(0), H(0) ]) compare_progs(prog, result_prog) # trotter_order 3 steps 1 prog, _ = trotterize(term_one, term_two, trotter_order=3, trotter_steps=1) result_prog = Program().inst([ H(0), RZ(14.0 / 24)(0), H(0), RZ(4.0 / 3.0)(0), H(0), RZ(1.5)(0), H(0), RZ(-4.0 / 3.0)(0), H(0), RZ(-2.0 / 24)(0), H(0), RZ(2.0)(0) ]) compare_progs(prog, result_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 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)) compare_progs(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)) compare_progs(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)]) compare_progs(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)]) compare_progs(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) ]) compare_progs(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) ]) compare_progs(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) ]) compare_progs(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) ]) compare_progs(prog, result_prog)
def single_qubit_unitary(self, angles, qubit): return RX(angles[0], qubit), RZ(angles[1], qubit), RX(angles[2], qubit)
def test_rotations(): p = Program(RX(0.5, 0), RY(0.1, 1), RZ(1.4, 2)) assert p.out() == "RX(0.5) 0\nRY(0.1) 1\nRZ(1.4) 2\n"
def test_rotations(): p = Program(RX(0.5)(0), RY(0.1)(1), RZ(1.4)(2)) assert p.out() == 'RX(0.5) 0\nRY(0.1) 1\nRZ(1.4) 2\n'
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)