def test_qc_joint_calibration(forest): # noise model with 95% symmetrized readout fidelity per qubit noise_model = asymmetric_ro_model([0, 1], 0.945, 0.955) qc = get_qc("2q-qvm") qc.qam.noise_model = noise_model # |01> state program p = Program() p += RESET() p += X(0) p.wrap_in_numshots_loop(10000) # ZZ experiment sz = ExperimentSetting( in_state=sZ(0) * sZ(1), out_operator=sZ(0) * sZ(1), additional_expectations=[[0], [1]] ) e = Experiment(settings=[sz], program=p) results = qc.experiment(e) # ZZ expectation value for state |01> with 95% RO fid on both qubits is about -0.81 assert np.isclose(results[0].expectation, -0.81, atol=0.01) assert results[0].total_counts == 40000 # Z0 expectation value for state |01> with 95% RO fid on both qubits is about -0.9 assert np.isclose(results[0].additional_results[0].expectation, -0.9, atol=0.01) assert results[0].additional_results[1].total_counts == 40000 # Z1 expectation value for state |01> with 95% RO fid on both qubits is about 0.9 assert np.isclose(results[0].additional_results[1].expectation, 0.9, atol=0.01) assert results[0].additional_results[1].total_counts == 40000
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_qc_joint_expectation(forest): device = NxDevice(nx.complete_graph(2)) qc = QuantumComputer( name="testy!", qam=QVM(connection=forest), device=device, compiler=DummyCompiler() ) # |01> state program p = Program() p += RESET() p += X(0) p.wrap_in_numshots_loop(10) # ZZ experiment sz = ExperimentSetting( in_state=sZ(0) * sZ(1), out_operator=sZ(0) * sZ(1), additional_expectations=[[0], [1]] ) e = Experiment(settings=[sz], program=p) results = qc.experiment(e) # ZZ expectation value for state |01> is -1 assert np.isclose(results[0].expectation, -1) assert np.isclose(results[0].std_err, 0) assert results[0].total_counts == 40 # Z0 expectation value for state |01> is -1 assert np.isclose(results[0].additional_results[0].expectation, -1) assert results[0].additional_results[1].total_counts == 40 # Z1 expectation value for state |01> is 1 assert np.isclose(results[0].additional_results[1].expectation, 1) assert results[0].additional_results[1].total_counts == 40
def test_qc_joint_expectation(client_configuration: QCSClientConfiguration, dummy_compiler: DummyCompiler): qc = QuantumComputer(name="testy!", qam=QVM(client_configuration=client_configuration), compiler=dummy_compiler) # |01> state program p = Program() p += RESET() p += X(0) p.wrap_in_numshots_loop(10) # ZZ experiment sz = ExperimentSetting( in_state=_pauli_to_product_state(sZ(0) * sZ(1)), out_operator=sZ(0) * sZ(1), additional_expectations=[[0], [1]] ) e = Experiment(settings=[sz], program=p) results = qc.experiment(e) # ZZ expectation value for state |01> is -1 assert np.isclose(results[0].expectation, -1) assert np.isclose(results[0].std_err, 0) assert results[0].total_counts == 40 # Z0 expectation value for state |01> is -1 assert np.isclose(results[0].additional_results[0].expectation, -1) assert results[0].additional_results[1].total_counts == 40 # Z1 expectation value for state |01> is 1 assert np.isclose(results[0].additional_results[1].expectation, 1) assert results[0].additional_results[1].total_counts == 40
def test_qc_expectation(client_configuration: QCSClientConfiguration, dummy_compiler: DummyCompiler): qc = QuantumComputer(name="testy!", qam=QVM(client_configuration=client_configuration), compiler=dummy_compiler) # bell state program p = Program() p += RESET() p += H(0) p += CNOT(0, 1) p.wrap_in_numshots_loop(10) # XX, YY, ZZ experiment sx = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0) * sZ(1)), out_operator=sX(0) * sX(1)) sy = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0) * sZ(1)), out_operator=sY(0) * sY(1)) sz = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0) * sZ(1)), out_operator=sZ(0) * sZ(1)) e = Experiment(settings=[sx, sy, sz], program=p) results = qc.experiment(e) # XX expectation value for bell state |00> + |11> is 1 assert np.isclose(results[0].expectation, 1) assert np.isclose(results[0].std_err, 0) assert results[0].total_counts == 40 # YY expectation value for bell state |00> + |11> is -1 assert np.isclose(results[1].expectation, -1) assert np.isclose(results[1].std_err, 0) assert results[1].total_counts == 40 # ZZ expectation value for bell state |00> + |11> is 1 assert np.isclose(results[2].expectation, 1) assert np.isclose(results[2].std_err, 0) assert results[2].total_counts == 40
def test_build_symmetrization_memory_maps(): p = Program() s = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0) * sZ(1)), out_operator=sZ(0) * sZ(1)) e = Experiment(settings=[s], program=p) memory_maps = [ { "symmetrization": [0.0, 0.0] }, { "symmetrization": [0.0, np.pi] }, { "symmetrization": [np.pi, 0.0] }, { "symmetrization": [np.pi, np.pi] }, ] assert e.build_symmetrization_memory_maps([0, 1]) == memory_maps
def test_tomo_experiment(): expts = [ ExperimentSetting(TensorProductState(), sX(0) * sY(1)), ExperimentSetting(plusZ(0), sZ(0)), ] suite = Experiment(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_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_for_negative_probabilities(): # trivial program to do state tomography on prog = Program(I(0)) # make an Experiment expt_settings = [ ExperimentSetting(zeros_state([0]), pt) for pt in [sI(0), sX(0), sY(0), sZ(0)] ] experiment_1q = Experiment(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 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 test_qc_expectation_larger_lattice(forest): device = NxDevice(nx.complete_graph(4)) qc = QuantumComputer(name="testy!", qam=QVM(connection=forest), device=device, compiler=DummyCompiler()) q0 = 2 q1 = 3 # bell state program p = Program() p += RESET() p += H(q0) p += CNOT(q0, q1) p.wrap_in_numshots_loop(10) # XX, YY, ZZ experiment sx = ExperimentSetting(in_state=sZ(q0) * sZ(q1), out_operator=sX(q0) * sX(q1)) sy = ExperimentSetting(in_state=sZ(q0) * sZ(q1), out_operator=sY(q0) * sY(q1)) sz = ExperimentSetting(in_state=sZ(q0) * sZ(q1), out_operator=sZ(q0) * sZ(q1)) e = Experiment(settings=[sx, sy, sz], program=p) results = qc.experiment(e) # XX expectation value for bell state |00> + |11> is 1 assert np.isclose(results[0].expectation, 1) assert np.isclose(results[0].std_err, 0) assert results[0].total_counts == 40 # YY expectation value for bell state |00> + |11> is -1 assert np.isclose(results[1].expectation, -1) assert np.isclose(results[1].std_err, 0) assert results[1].total_counts == 40 # ZZ expectation value for bell state |00> + |11> is 1 assert np.isclose(results[2].expectation, 1) assert np.isclose(results[2].std_err, 0) assert results[2].total_counts == 40
def test_qc_calibration_1q(forest): # noise model with 95% symmetrized readout fidelity per qubit noise_model = asymmetric_ro_model([0], 0.945, 0.955) qc = get_qc("1q-qvm") qc.qam.noise_model = noise_model # bell state program (doesn't matter) p = Program() p += RESET() p += H(0) p += CNOT(0, 1) p.wrap_in_numshots_loop(10000) # Z experiment sz = ExperimentSetting(in_state=sZ(0), out_operator=sZ(0)) e = Experiment(settings=[sz], program=p) results = qc.calibrate(e) # Z expectation value should just be 1 - 2 * readout_error np.isclose(results[0].expectation, 0.9, atol=0.01) assert results[0].total_counts == 20000
def test_qc_calibration_2q(client_configuration: QCSClientConfiguration): # noise model with 95% symmetrized readout fidelity per qubit noise_model = asymmetric_ro_model([0, 1], 0.945, 0.955) qc = get_qc("2q-qvm", client_configuration=client_configuration) qc.qam.noise_model = noise_model # bell state program (doesn't matter) p = Program() p += RESET() p += H(0) p += CNOT(0, 1) p.wrap_in_numshots_loop(10000) # ZZ experiment sz = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0) * sZ(1)), out_operator=sZ(0) * sZ(1)) e = Experiment(settings=[sz], program=p) results = qc.calibrate(e) # ZZ expectation should just be (1 - 2 * readout_error_q0) * (1 - 2 * readout_error_q1) np.isclose(results[0].expectation, 0.81, atol=0.01) assert results[0].total_counts == 40000
def compile_tomo_expts(self, pauli_list=None): """ This method compiles the tomography experiment circuits and prepares them for simulation. Every time the circuits are adjusted, re-compiling the tomography experiments is required to affect the outcome. """ # use Forest's sorting algo from the Tomography suite # to group Pauli measurements together settings = [] if pauli_list is None: pauli_list = self.pauli_list for term in pauli_list: # skip an identity operator, if len(term.operations_as_set()) > 0: # initial state and term pair. settings.append(ExperimentSetting( TensorProductState(), term)) # group_experiments cannot be directly run # because there may be experiment with multiple settings. # so here we just use group_experiments to sort out the settings, # then reset the experiments with additional measurements. experiments = Experiment(settings, Program()) suite = group_experiments(experiments) # we just need the grouped settings. grouped_pauil_terms = [] for setting in suite: group = [] for i, term in enumerate(setting): pauil_term = term.out_operator.copy() # Coefficients to be multiplied. pauil_term.coefficient = complex(1.) if i == 0: group.append(pauil_term) elif len(pauil_term) > len(group[0]): group.insert(0, pauil_term) else: group.append(pauil_term) # make sure the longest pauil_term contains all the small # pauil_terms. Otherwise, we prepare a bigger one. bigger_pauli = group[0] if len(group) > 1: for term in group[1:]: for iq, op in term.operations_as_set(): if op != group[0][iq]: assert(group[0][iq] == "I"), \ (f"{term} and {group[0]}" " not compatible!") if bigger_pauli is group[0]: bigger_pauli == group[0].copy() bigger_pauli *= PauliTerm(op, iq) if bigger_pauli is not group[0]: print(f"new pauli_term generated: {bigger_pauli}") group.insert(0, bigger_pauli) grouped_pauil_terms.append(group) # group settings with additional_expectations. grouped_settings = [] for pauil_terms in grouped_pauil_terms: additional = None if len(pauil_terms) > 1: additional = [] for term in pauil_terms[1:]: additional.append(term.get_qubits()) grouped_settings.append( ExperimentSetting(TensorProductState(), pauil_terms[0], additional_expectations=additional)) # get the uccsd program prog = Program() prog += RESET() prog += self.ref_state + self.ansatz prog.wrap_in_numshots_loop(shots=self.shotN) self.experiment_list = Experiment(grouped_settings, prog) print('Number of tomography experiments: ', len(self.experiment_list)) # calibration expreimental results. self.calibrations = self.qc.calibrate(self.experiment_list)
def test_tomo_experiment_empty(): suite = Experiment([], program=Program(X(0))) assert len(suite) == 0 assert str(suite.program) == "X 0\n"
def test_generate_experiment_program(): # simplest example p = Program() s = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0)), out_operator=sZ(0)) e = Experiment(settings=[s], program=p, symmetrization=0) exp = e.generate_experiment_program() test_exp = Program() ro = test_exp.declare("ro", "BIT") test_exp += MEASURE(0, ro[0]) assert exp.out() == test_exp.out() assert exp.num_shots == 1 # 2Q exhaustive symmetrization p = Program() s = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0) * sZ(1)), out_operator=sZ(0) * sZ(1)) e = Experiment(settings=[s], program=p) exp = e.generate_experiment_program() test_exp = Program() test_exp += parameterized_readout_symmetrization([0, 1]) ro = test_exp.declare("ro", "BIT", 2) test_exp += MEASURE(0, ro[0]) test_exp += MEASURE(1, ro[1]) assert exp.out() == test_exp.out() assert exp.num_shots == 1 # add shots p = Program() p.wrap_in_numshots_loop(1000) s = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0)), out_operator=sZ(0)) e = Experiment(settings=[s], program=p, symmetrization=0) exp = e.generate_experiment_program() test_exp = Program() ro = test_exp.declare("ro", "BIT") test_exp += MEASURE(0, ro[0]) assert exp.out() == test_exp.out() assert exp.num_shots == 1000 # active reset p = Program() p += RESET() s = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0)), out_operator=sZ(0)) e = Experiment(settings=[s], program=p, symmetrization=0) exp = e.generate_experiment_program() test_exp = Program() test_exp += RESET() ro = test_exp.declare("ro", "BIT") test_exp += MEASURE(0, ro[0]) assert exp.out() == test_exp.out() assert exp.num_shots == 1 # state preparation and measurement p = Program() s = ExperimentSetting(in_state=_pauli_to_product_state(sY(0)), out_operator=sX(0)) e = Experiment(settings=[s], program=p, symmetrization=0) exp = e.generate_experiment_program() test_exp = Program() test_exp += parameterized_single_qubit_state_preparation([0]) test_exp += parameterized_single_qubit_measurement_basis([0]) ro = test_exp.declare("ro", "BIT") test_exp += MEASURE(0, ro[0]) assert exp.out() == test_exp.out() assert exp.num_shots == 1 # multi-qubit state preparation and measurement p = Program() s = ExperimentSetting(in_state=_pauli_to_product_state(sZ(0) * sY(1)), out_operator=sZ(0) * sX(1)) e = Experiment(settings=[s], program=p, symmetrization=0) exp = e.generate_experiment_program() test_exp = Program() test_exp += parameterized_single_qubit_state_preparation([0, 1]) test_exp += parameterized_single_qubit_measurement_basis([0, 1]) ro = test_exp.declare("ro", "BIT", 2) test_exp += MEASURE(0, ro[0]) test_exp += MEASURE(1, ro[1]) assert exp.out() == test_exp.out() assert exp.num_shots == 1