def test_identity_removal(): test_term = 0.25 * sX(1) * sZ(2) * sX(3) + 0.25j * sX(1) * sZ(2) * sY(3) test_term += -0.25j * sY(1) * sZ(2) * sX(3) + 0.25 * sY(1) * sZ(2) * sY(3) identity_term = 200 * sI(5) new_psum, identity_term_result = remove_identity(identity_term + test_term) assert test_term == new_psum assert identity_term_result == identity_term
def test_group_experiments(grouping_method): expts = [ # cf above, I removed the inner nesting. Still grouped visually ExperimentSetting(sI(), sX(0) * sI(1)), ExperimentSetting(sI(), sI(0) * sX(1)), ExperimentSetting(sI(), sZ(0) * sI(1)), ExperimentSetting(sI(), sI(0) * sZ(1)), ] suite = TomographyExperiment(expts, Program(), qubits=[0, 1]) grouped_suite = group_experiments(suite, method=grouping_method) assert len(suite) == 4 assert len(grouped_suite) == 2
def test_stabilizer_projection_ZZ(): """ test if we project out the correct state """ stabilizer_state = project_stabilized_state([sZ(0) * sZ(1), sX(0) * sX(1)]) true_state = np.zeros((4, 1)) true_state[0, 0] = true_state[3, 0] = 1 true_state /= np.sqrt(2) assert np.allclose(true_state, stabilizer_state.todense())
def test_ps_adds_pt_2(): term = ID() b = term + 1.0 assert str(b) == "(2+0j)*I" assert str(b + 1.0) == "(3+0j)*I" assert str(1.0 + b) == "(3+0j)*I" b = sX(0) + 1.0 assert str(b) == "(1+0j)*X0 + (1+0j)*I" b = 1.0 + sX(0) assert str(b) == "(1+0j)*I + (1+0j)*X0"
def test_ps_sub(): term = 3 * ID() b = term - 1.0 assert str(b) == "(2+0j)*I" assert str(b - 1.0) == "(1+0j)*I" assert str(1.0 - b) == "(-1+0j)*I" b = 1.0 - sX(0) assert str(b) == "(1+0j)*I + (-1+0j)*X0" b = sX(0) - 1.0 assert str(b) == "(1+0j)*X0 + (-1+0j)*I"
def test_sum_equality(): pauli_sum = sY(0) - sX(0) assert pauli_sum != 2 * pauli_sum assert pauli_sum != pauli_sum + sZ(0) assert pauli_sum + sZ(0) != pauli_sum assert pauli_sum != sY(1) - sX(1) assert pauli_sum == -1.0 * sX(0) + sY(0) assert pauli_sum == pauli_sum * 1.0 with pytest.raises(TypeError): assert pauli_sum != 0
def test_sum_equality(): q0, q1 = QubitPlaceholder.register(2) pauli_sum = sY(q0) - sX(q0) assert pauli_sum != 2 * pauli_sum assert pauli_sum != pauli_sum + sZ(q0) assert pauli_sum + sZ(q0) != pauli_sum assert pauli_sum != sY(q1) - sX(q1) assert pauli_sum == -1.0 * sX(q0) + sY(q0) assert pauli_sum == pauli_sum * 1.0 with pytest.raises(TypeError): assert pauli_sum != 0
def test_expectation(client_configuration: QCSClientConfiguration): wfnsim = WavefunctionSimulator(client_configuration=client_configuration) bell = Program(H(0), CNOT(0, 1)) expects = wfnsim.expectation(bell, [sZ(0) * sZ(1), sZ(0), sZ(1), sX(0) * sX(1)]) assert expects.size == 4 np.testing.assert_allclose(expects, [1, 0, 0, 1]) pauli_sum = PauliSum([sZ(0) * sZ(1)]) expects = wfnsim.expectation(bell, pauli_sum) assert expects.size == 1 np.testing.assert_allclose(expects, [1])
def test_ps_sub(): q0 = QubitPlaceholder() term = 3 * ID() b = term - 1.0 assert str(b) == "(2+0j)*I" assert str(b - 1.0) == "(1+0j)*I" assert str(1.0 - b) == "(-1+0j)*I" b = 1.0 - sX(q0) assert re.match(r"\(1\+0j\)\*I \+ \(-1\+0j\)\*Xq\d+", str(b)) b = sX(q0) - 1.0 assert re.match(r"\(1\+0j\)\*Xq\d+ \+ \(-1\+0j\)\*I", str(b))
def test_commuting_terms_indexed(): """ Test performance of commuting_sets_by_index """ pauli_term_1 = PauliSum([sX(0) * sZ(1)]) pauli_term_2 = PauliSum([sX(1) * sZ(2)]) pauli_term_3 = PauliSum([sX(0) * sY(3)]) commuting_set_tuples = commuting_sets_by_indices( [pauli_term_1, pauli_term_2, pauli_term_3], check_trivial_commutation) correct_tuples = [[(0, 0)], [(1, 0), (2, 0)]] assert commuting_set_tuples == correct_tuples
def test_append(): expts = [ [ExperimentSetting(sI(), sX(0) * sI(1)), ExperimentSetting(sI(), sI(0) * sX(1))], [ExperimentSetting(sI(), sZ(0) * sI(1)), ExperimentSetting(sI(), sI(0) * sZ(1))], ] suite = TomographyExperiment( settings=expts, program=Program(X(0), Y(1)), qubits=[0, 1] ) suite.append(ExperimentSetting(sI(), sY(0) * sX(1))) assert (len(str(suite))) > 0
def test_simulation_cnot(): """ Test if the simulation of CNOT is accurate :return: """ prog = Program().inst([H(0), CNOT(0, 1)]) qvmstab = QVM_Stabilizer(num_qubits=2) qvmstab._apply_hadamard(prog.instructions[0]) qvmstab._apply_cnot(prog.instructions[1]) # assert that ZZ XX stabilizes a bell state true_stabilizers = [sX(0) * sX(1), sZ(0) * sZ(1)] test_paulis = binary_stabilizer_to_pauli_stabilizer(qvmstab.tableau[2:, :]) for idx, term in enumerate(test_paulis): assert term == true_stabilizers[idx] # test that CNOT does nothing to |00> state prog = Program().inst([CNOT(0, 1)]) qvmstab = QVM_Stabilizer(num_qubits=2) qvmstab._apply_cnot(prog.instructions[0]) true_tableau = np.array([ [1, 1, 0, 0, 0], # X1 -> X1 X2 [0, 1, 0, 0, 0], # X2 -> X2 [0, 0, 1, 0, 0], # Z1 -> Z1 [0, 0, 1, 1, 0] ]) # Z2 -> Z1 Z2 # note that Z1, Z1 Z2 still stabilizees |00> assert np.allclose(true_tableau, qvmstab.tableau) # test that CNOT produces 11 state after X prog = Program().inst([H(0), S(0), S(0), H(0), CNOT(0, 1)]) qvmstab = QVM_Stabilizer(num_qubits=2) qvmstab._apply_hadamard(prog.instructions[0]) qvmstab._apply_phase(prog.instructions[1]) qvmstab._apply_phase(prog.instructions[2]) qvmstab._apply_hadamard(prog.instructions[3]) qvmstab._apply_cnot(prog.instructions[4]) true_tableau = np.array([[1, 1, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 1, 0, 1], [0, 0, 1, 1, 0]]) # note that -Z1, Z1 Z2 still stabilizees |11> assert np.allclose(true_tableau, qvmstab.tableau) test_paulis = binary_stabilizer_to_pauli_stabilizer( qvmstab.stabilizer_tableau()) state = project_stabilized_state(test_paulis, qvmstab.num_qubits, classical_state=[1, 1]) state_2 = project_stabilized_state(test_paulis, qvmstab.num_qubits) assert np.allclose(np.array(state.todense()), np.array(state_2.todense()))
def test_max_tpb_overlap_1(): tomo_expt_settings = [ExperimentSetting(sZ(1) * sX(0), sY(2) * sY(1)), ExperimentSetting(sX(2) * sZ(1), sY(2) * sZ(0))] tomo_expt_program = Program(H(0), H(1), H(2)) tomo_expt_qubits = [0, 1, 2] tomo_expt = TomographyExperiment(tomo_expt_settings, tomo_expt_program, tomo_expt_qubits) expected_dict = { ExperimentSetting(plusX(0) * plusZ(1) * plusX(2), sZ(0) * sY(1) * sY(2)): [ ExperimentSetting(plusZ(1) * plusX(0), sY(2) * sY(1)), ExperimentSetting(plusX(2) * plusZ(1), sY(2) * sZ(0)) ] } assert expected_dict == _max_tpb_overlap(tomo_expt)
def test_merge_disjoint_experiments(): sett1 = ExperimentSetting(TensorProductState(), sX(0) * sY(1)) sett2 = ExperimentSetting(plusZ(1), sY(1)) sett3 = ExperimentSetting(plusZ(0), sX(0)) sett4 = ExperimentSetting(minusX(1), sY(1)) sett5 = ExperimentSetting(TensorProductState(), sZ(2)) expt1 = Experiment(settings=[sett1, sett2], program=Program(X(1))) expt2 = Experiment(settings=[sett3, sett4], program=Program(Z(0))) expt3 = Experiment(settings=[sett5], program=Program()) merged_expt = merge_disjoint_experiments([expt1, expt2, expt3]) assert len(merged_expt) == 2
def test_diagonal_basis_commutes(): x_term = sX(0) * sX(1) z1_term = sZ(1) z0_term = sZ(0) z0z1_term = sZ(0) * sZ(1) assert not diagonal_basis_commutes(x_term, z1_term) assert not diagonal_basis_commutes(z0z1_term, x_term) assert diagonal_basis_commutes(z1_term, z0_term) assert diagonal_basis_commutes(z0z1_term, z0_term) assert diagonal_basis_commutes(z0z1_term, z1_term) assert diagonal_basis_commutes(z0z1_term, sI(1)) assert diagonal_basis_commutes(z0z1_term, sI(2)) assert diagonal_basis_commutes(z0z1_term, sX(5) * sY(7))
def test_experiment_deser(tmpdir): expts = [ [ExperimentSetting(sI(), sX(0) * sI(1)), ExperimentSetting(sI(), sI(0) * sX(1))], [ExperimentSetting(sI(), sZ(0) * sI(1)), ExperimentSetting(sI(), sI(0) * sZ(1))], ] suite = TomographyExperiment( settings=expts, program=Program(X(0), Y(1)), qubits=[0, 1] ) to_json(f'{tmpdir}/suite.json', suite) suite2 = read_json(f'{tmpdir}/suite.json') assert suite == suite2
def test_rowsum_phase_accumulator(): """ Test the accuracy of the phase accumulator. This subroutine keeps track of the power that $i$ is raised to when multiplying two PauliTerms together. PauliTerms are now composed of multi single-qubit Pauli's. The formula is phase_accumulator(h, i) = 2 * rh + 2 * ri + \sum_{j}^{n}g(x_{ij}, z_{ij}, x_{hj}, z_{hj} The returned value is presented mod 4. notice that since r_h indicates +1 or -1 this corresponds to i^{0} or i^{2}. Given r_{h/i} takes on {0, 1} then we need to multiply by 2 get the correct power of $i$ for the Pauli Term to account for multiplication. In order to test we will generate random elements of P_{n} and then multiply them together keeping track of the $i$ power. We will then compare this to the phase_accumulator subroutine. We have to load in the stabilizer into an empty qvmstab object because the subroutine needs a tableau as a reference """ num_qubits = 2 pauli_terms = [sX(0) * sX(1), sZ(0) * sZ(1)] stab_mat = pauli_stabilizer_to_binary_stabilizer(pauli_terms) qvmstab = QVM_Stabilizer(num_qubits=num_qubits) qvmstab.tableau[num_qubits:, :] = stab_mat exp_on_i = qvmstab._rowsum_phase_accumulator(2, 3) assert exp_on_i == 2 num_qubits = 2 pauli_terms = [sZ(0) * sI(1), sZ(0) * sZ(1)] stab_mat = pauli_stabilizer_to_binary_stabilizer(pauli_terms) qvmstab = QVM_Stabilizer(num_qubits=num_qubits) qvmstab.tableau[num_qubits:, :] = stab_mat exp_on_i = qvmstab._rowsum_phase_accumulator(2, 3) assert exp_on_i == 0 # now try generating random valid elements from 2-qubit group for _ in range(100): num_qubits = 6 pauli_terms = [] for _ in range(num_qubits): pauli_terms.append( reduce(lambda x, y: x * y, [ pauli_subgroup[x](idx) for idx, x in enumerate( np.random.randint(1, 4, num_qubits)) ])) stab_mat = pauli_stabilizer_to_binary_stabilizer(pauli_terms) qvmstab = QVM_Stabilizer(num_qubits=num_qubits) qvmstab.tableau[num_qubits:, :] = stab_mat p_on_i = qvmstab._rowsum_phase_accumulator(num_qubits, num_qubits + 1) coeff_test = pauli_terms[1] * pauli_terms[0] assert np.isclose(coeff_test.coefficient, (1j)**p_on_i)
def test_expectation(forest: ForestConnection): # The forest fixture (argument) to this test is to ensure this is # skipped when a forest web api key is unavailable. You could also # pass it to the constructor of WavefunctionSimulator() but it is not # necessary. wfnsim = WavefunctionSimulator() bell = Program(H(0), CNOT(0, 1)) expects = wfnsim.expectation(bell, [sZ(0) * sZ(1), sZ(0), sZ(1), sX(0) * sX(1)]) assert expects.size == 4 np.testing.assert_allclose(expects, [1, 0, 0, 1]) pauli_sum = PauliSum([sZ(0) * sZ(1)]) expects = wfnsim.expectation(bell, pauli_sum) assert expects.size == 1 np.testing.assert_allclose(expects, [1])
def test_check_commutation_trivial_grouping(): """ Check grouping of trivial terms """ commuting_set_one = sX(0) * sZ(1) + sY(2) commuting_set_two = PauliSum([sX(1)]) hamiltonian = commuting_set_one + commuting_set_two commuting_sets = commuting_sets_trivial(hamiltonian) for comm_set in commuting_sets: if len(comm_set) == 2: true_set = set(map(lambda x: x.id(), commuting_set_one.terms)) assert set(map(lambda x: x.id(), comm_set)) == true_set elif len(comm_set) == 1: true_set = set(map(lambda x: x.id(), commuting_set_two.terms)) assert set(map(lambda x: x.id(), comm_set)) == true_set
def test_group_experiments(grouping_method): expts = [ # cf above, I removed the inner nesting. Still grouped visually 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(expts, Program()) grouped_suite = group_settings(suite, method=grouping_method) assert len(suite) == 4 assert len(grouped_suite) == 2
def test_experiment_deser(tmpdir): 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))) to_json(f"{tmpdir}/suite.json", suite) suite2 = read_json(f"{tmpdir}/suite.json") assert suite == suite2
def test_experiment_result(): er = ExperimentResult( setting=ExperimentSetting(sX(0), sZ(0)), expectation=0.9, stddev=0.05, ) assert str(er) == '(1+0j)*X0→(1+0j)*Z0: 0.9 +- 0.05'
def test_measure_observables(forest): expts = [ ExperimentSetting(sI(), o1 * o2) for o1, o2 in itertools.product([sI(0), sX(0), sY(0), sZ(0)], [sI(1), sX(1), sY(1), sZ(1)]) ] suite = TomographyExperiment(expts, program=Program(X(0), CNOT(0, 1)), qubits=[0, 1]) assert len(suite) == 4 * 4 gsuite = group_experiments(suite) assert len(gsuite) == 3 * 3 # can get all the terms with I for free in this case qc = get_qc('2q-qvm') for res in measure_observables(qc, gsuite, n_shots=10_000): if res.setting.out_operator in [sI(), sZ(0), sZ(1), sZ(0) * sZ(1)]: assert np.abs(res.expectation) > 0.9 else: assert np.abs(res.expectation) < 0.1
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 test_for_negative_probabilities(): # trivial program to do state tomography on prog = Program(I(0)) # make TomographyExperiment expt_settings = [ExperimentSetting(zeros_state([0]), pt) for pt in [sI(0), sX(0), sY(0), sZ(0)]] experiment_1q = TomographyExperiment(settings=expt_settings, program=prog) # make a quantum computer object device = NxDevice(nx.complete_graph(1)) qc_density = QuantumComputer( name="testy!", qam=PyQVM(n_qubits=1, quantum_simulator_type=ReferenceDensitySimulator), device=device, compiler=DummyCompiler(), ) # initialize with a pure state initial_density = np.array([[1.0, 0.0], [0.0, 0.0]]) qc_density.qam.wf_simulator.density = initial_density try: list(measure_observables(qc=qc_density, tomo_experiment=experiment_1q, n_shots=3000)) except ValueError as e: # the error is from np.random.choice by way of self.rs.choice in ReferenceDensitySimulator assert str(e) != "probabilities are not non-negative" # initialize with a mixed state initial_density = np.array([[0.9, 0.0], [0.0, 0.1]]) qc_density.qam.wf_simulator.density = initial_density try: list(measure_observables(qc=qc_density, tomo_experiment=experiment_1q, n_shots=3000)) except ValueError as e: assert str(e) != "probabilities are not non-negative"
def benchmarker(): try: bm = get_benchmarker(timeout=2) bm.apply_clifford_to_pauli(Program(I(0)), sX(0)) return bm except (RequestException, TimeoutError) as e: return pytest.skip("This test requires a running local benchmarker endpoint (ie quilc): {}" .format(e))
def test_stats_from_measurements(): d_results = {0: np.array([0] * 10), 1: np.array([1] * 10)} setting = ExperimentSetting(TensorProductState(), sZ(0) * sX(1)) n_shots = 1000 obs_mean, obs_var = _stats_from_measurements(d_results, setting, n_shots) assert obs_mean == -1.0 assert obs_var == 0.0
def test_tomo_experiment_pre_grouped(): expts = [ [ExperimentSetting(sI(), sX(0) * sI(1)), ExperimentSetting(sI(), sI(0) * sX(1))], [ExperimentSetting(sI(), sZ(0) * sI(1)), ExperimentSetting(sI(), sI(0) * sZ(1))], ] suite = TomographyExperiment( settings=expts, program=Program(X(0), Y(1)), qubits=[0, 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()[0] assert prog_str == 'X 0; Y 1'
def test_experiment_result_compat(): er = ExperimentResult( setting=ExperimentSetting(sX(0), sZ(0)), expectation=0.9, stddev=0.05, total_counts=100, ) assert str(er) == 'X0_0→(1+0j)*Z0: 0.9 +- 0.05'
def test_is_identity(): pt1 = -1.5j * sI(2) pt2 = 1.5 * sX(1) * sZ(2) assert is_identity(pt1) assert is_identity(pt2 + (-1 * pt2) + sI(0)) assert not is_identity(0 * pt1) assert not is_identity(pt2 + (-1 * pt2))
from pyquil.paulis import ID, sX, sY, sZ from pyquil import * from pyquil.gates import H import pyquil.paulis as pl # Pauli term takes an operator "X", "Y", "Z", or "I"; a qubit to act on, and # an optional coefficient. a = 1 * ID() b = -0.75 * sX(0) * sY(1) * sZ(3) c = (5-2j) * sZ(1) * sX(2) # Construct a sum of Pauli terms. sigma = a + b + c print("sigma = {}".format(sigma)) p = Program() p.inst(pl.exponentiate_commuting_pauli_sum(sigma)) print(p)