def test_all_ops_belong_to_tpb(): 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)) ], ] for group in expts: for e1, e2 in itertools.combinations(group, 2): assert _all_qubits_diagonal_in_tpb(e1.in_operator, e2.in_operator) assert _all_qubits_diagonal_in_tpb(e1.out_operator, e2.out_operator) assert _all_qubits_diagonal_in_tpb(sZ(0), sZ(0) * sZ(1)) assert _all_qubits_diagonal_in_tpb(sX(5), sZ(4)) assert not _all_qubits_diagonal_in_tpb(sX(0), sY(0) * sZ(2)) # this last example illustrates that a pair of commuting operators # need not be diagonal in the same tpb assert not _all_qubits_diagonal_in_tpb(sX(1) * sZ(0), sZ(1) * sX(0))
def test_experiment_suite_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_setting_no_in(): out_ops = _generate_random_paulis(n_qubits=4, n_terms=7) for oop in out_ops: expt = ExperimentSetting(zeros_state(oop.get_qubits()), oop) expt2 = ExperimentSetting.from_str(str(expt)) assert expt == expt2 assert expt2.in_operator == functools.reduce(mul, [sZ(q) for q in oop.get_qubits()], sI()) assert expt2.out_operator == oop
def test_expt_settings_diagonal_in_tpb(): expt_setting1 = ExperimentSetting(sZ(1) * sX(0), sY(1) * sZ(0)) expt_setting2 = ExperimentSetting(sY(2) * sZ(1), sZ(2) * sY(1)) assert _expt_settings_diagonal_in_tpb(expt_setting1, expt_setting2) expt_setting3 = ExperimentSetting(sX(2) * sZ(1), sZ(2) * sY(1)) expt_setting4 = ExperimentSetting(sY(2) * sZ(1), sX(2) * sY(1)) assert not _expt_settings_diagonal_in_tpb(expt_setting2, expt_setting3) assert not _expt_settings_diagonal_in_tpb(expt_setting2, expt_setting4)
def test_experiment_no_in(): out_ops = _generate_random_paulis(n_qubits=4, n_terms=7) for oop in out_ops: expt = ExperimentSetting(sI(), oop) expt2 = ExperimentSetting.from_str(str(expt)) assert expt == expt2 assert expt2.in_operator == sI() assert expt2.out_operator == oop
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_max_tpb_overlap_3(): # add another ExperimentSetting to the above expt_setting = ExperimentSetting(PauliTerm.from_compact_str('(1+0j)*Z7Y8Z1Y4Z2Y5Y0X6'), PauliTerm.from_compact_str('(1+0j)*Z4X8Y5X3Y7Y1')) expt_setting2 = ExperimentSetting(sZ(7), sY(1)) p = Program(H(0), H(1), H(2)) qubits = [0, 1, 2] tomo_expt2 = TomographyExperiment([expt_setting, expt_setting2], p, qubits) expected_dict2 = {expt_setting: [expt_setting, expt_setting2]} assert expected_dict2 == _max_tpb_overlap(tomo_expt2)
def test_experiment(): in_ops = _generate_random_paulis(n_qubits=4, n_terms=7) out_ops = _generate_random_paulis(n_qubits=4, n_terms=7) for iop, oop in zip(in_ops, out_ops): expt = ExperimentSetting(iop, oop) assert str(expt) == expt.serializable() expt2 = ExperimentSetting.from_str(str(expt)) assert expt == expt2 assert expt2.in_operator == iop assert expt2.out_operator == oop
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_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_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_measure_observables_many_progs(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)]) ] qc = get_qc('2q-qvm') qc.qam.random_seed = 51 for prog in _random_2q_programs(): suite = TomographyExperiment(expts, program=prog, 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 wfn = WavefunctionSimulator() wfn_exps = {} for expt in expts: wfn_exps[expt] = wfn.expectation(gsuite.program, PauliSum([expt.out_operator])) for res in measure_observables(qc, gsuite, n_shots=1_000): np.testing.assert_allclose(wfn_exps[res.setting], res.expectation, atol=0.1)
def _monte_carlo_dfe(program: Program, qubits: Sequence[int], in_states: list, n_terms: int, benchmarker: BenchmarkConnection) -> ExperimentSetting: """Yield experiments over itertools.product(in_paulis). Used as a helper function for generate_monte_carlo_xxx_dfe_experiment routines. :param program: A program comprised of clifford gates :param qubits: The qubits to perform DFE on. This can be a superset of the qubits used in ``program``. :param in_states: Use these single-qubit Pauli operators in every itertools.product() to generate an exhaustive list of DFE experiments. :param n_terms: Number of preparation and measurement settings to be chosen at random :return: experiment setting iterator :rtype: ``ExperimentSetting`` """ all_st_inds = np.random.randint(len(in_states), size=(n_terms, len(qubits))) for st_inds in all_st_inds: i_st = functools.reduce(mul, (in_states[si](qubits[i]) for i, si in enumerate(st_inds) if in_states[si] is not None), TensorProductState()) # TODO: we should not pick a new one, we should just return a trivial experiment while len(i_st) == 0: # pick a new one second_try_st_inds = np.random.randint(len(in_states), size=len(qubits)) i_st = functools.reduce(mul, (in_states[si](qubits[i]) for i, si in enumerate(second_try_st_inds) if in_states[si] is not None), TensorProductState()) yield ExperimentSetting( in_state=i_st, out_operator=benchmarker.apply_clifford_to_pauli(program, _state_to_pauli(i_st)), )
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 _exhaustive_dfe(program: Program, qubits: Sequence[int], in_states, benchmarker: BenchmarkConnection) -> ExperimentSetting: """Yield experiments over itertools.product(in_paulis). Used as a helper function for generate_exhaustive_xxx_dfe_experiment routines. :param program: A program comprised of clifford gates :param qubits: The qubits to perform DFE on. This can be a superset of the qubits used in ``program``. :param in_states: Use these single-qubit Pauli operators in every itertools.product() to generate an exhaustive list of DFE experiments. :return: experiment setting iterator :rtype: ``ExperimentSetting`` """ n_qubits = len(qubits) for i_states in itertools.product(in_states, repeat=n_qubits): i_st = functools.reduce(mul, (op(q) for op, q in zip(i_states, qubits) if op is not None), TensorProductState()) if len(i_st) == 0: continue yield ExperimentSetting( in_state=i_st, out_operator=benchmarker.apply_clifford_to_pauli(program, _state_to_pauli(i_st)), )
def test_no_complex_coeffs(forest): qc = get_qc('2q-qvm') suite = TomographyExperiment([ExperimentSetting(sI(), 1.j * sY(0))], program=Program(X(0)), qubits=[0]) with pytest.raises(ValueError): res = list(measure_observables(qc, suite))
def test_identity(forest): qc = get_qc('2q-qvm') suite = TomographyExperiment([ExperimentSetting(sI(), 0.123 * sI(0))], program=Program(X(0)), qubits=[0]) result = list(measure_observables(qc, suite))[0] assert result.expectation == 0.123
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_group_experiments_greedy(): ungrouped_tomo_expt = TomographyExperiment( [[ExperimentSetting(PauliTerm.from_compact_str('(1+0j)*Z7Y8Z1Y4Z2Y5Y0X6'), PauliTerm.from_compact_str('(1+0j)*Z4X8Y5X3Y7Y1'))], [ExperimentSetting(sZ(7), sY(1))]], program=Program(H(0), H(1), H(2)), qubits=[0, 1, 2]) grouped_tomo_expt = group_experiments(ungrouped_tomo_expt, method='greedy') expected_grouped_tomo_expt = TomographyExperiment( [[ ExperimentSetting(TensorProductState.from_str('Z0_7 * Y0_8 * Z0_1 * Y0_4 * ' 'Z0_2 * Y0_5 * Y0_0 * X0_6'), PauliTerm.from_compact_str('(1+0j)*Z4X8Y5X3Y7Y1')), ExperimentSetting(plusZ(7), sY(1)) ]], program=Program(H(0), H(1), H(2)), qubits=[0, 1, 2]) assert grouped_tomo_expt == expected_grouped_tomo_expt
def test_max_tpb_overlap_2(): expt_setting = ExperimentSetting(PauliTerm.from_compact_str('(1+0j)*Z7Y8Z1Y4Z2Y5Y0X6'), PauliTerm.from_compact_str('(1+0j)*Z4X8Y5X3Y7Y1')) p = Program(H(0), H(1), H(2)) qubits = [0, 1, 2] tomo_expt = TomographyExperiment([expt_setting], p, qubits) expected_dict = {expt_setting: [expt_setting]} assert expected_dict == _max_tpb_overlap(tomo_expt)
def test_experiment_result(): er = ExperimentResult( setting=ExperimentSetting(plusX(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_experiment_suite(): expts = [ ExperimentSetting(sI(), sX(0) * sY(1)), ExperimentSetting(sZ(0), sZ(0)), ] suite = TomographyExperiment(settings=expts, program=Program(X(0), Y(1)), qubits=[0, 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()[0] assert prog_str == 'X 0; Y 1'
def test_expt_settings_diagonal_in_tpb(): def _expt_settings_diagonal_in_tpb(es1: ExperimentSetting, es2: ExperimentSetting): """ Extends the concept of being diagonal in the same tpb to ExperimentSettings, by determining if the pairs of in_states and out_operators are separately diagonal in the same tpb """ max_weight_in = _max_weight_state([es1.in_state, es2.in_state]) max_weight_out = _max_weight_operator([es1.out_operator, es2.out_operator]) return max_weight_in is not None and max_weight_out is not None expt_setting1 = ExperimentSetting(plusZ(1) * plusX(0), sY(1) * sZ(0)) expt_setting2 = ExperimentSetting(plusY(2) * plusZ(1), sZ(2) * sY(1)) assert _expt_settings_diagonal_in_tpb(expt_setting1, expt_setting2) expt_setting3 = ExperimentSetting(plusX(2) * plusZ(1), sZ(2) * sY(1)) expt_setting4 = ExperimentSetting(plusY(2) * plusZ(1), sX(2) * sY(1)) assert not _expt_settings_diagonal_in_tpb(expt_setting2, expt_setting3) assert not _expt_settings_diagonal_in_tpb(expt_setting2, expt_setting4)
def test_expt_settings_share_ntpb(): expts = [[ ExperimentSetting(zeros_state([0, 1]), sX(0) * sI(1)), ExperimentSetting(zeros_state([0, 1]), sI(0) * sX(1)) ], [ ExperimentSetting(zeros_state([0, 1]), sZ(0) * sI(1)), ExperimentSetting(zeros_state([0, 1]), sI(0) * sZ(1)) ]] for group in expts: for e1, e2 in itertools.combinations(group, 2): assert _max_weight_state([e1.in_state, e2.in_state]) is not None assert _max_weight_operator([e1.out_operator, e2.out_operator]) is not None
def test_group_experiments_greedy(): ungrouped_tomo_expt = TomographyExperiment([[ ExperimentSetting( PauliTerm.from_compact_str('(1+0j)*Z7Y8Z1Y4Z2Y5Y0X6'), PauliTerm.from_compact_str('(1+0j)*Z4X8Y5X3Y7Y1')) ], [ExperimentSetting(sZ(7), sY(1))]], program=Program( H(0), H(1), H(2)), qubits=[0, 1, 2]) grouped_tomo_expt = group_experiments_greedy(ungrouped_tomo_expt) expected_grouped_tomo_expt = TomographyExperiment([[ ExperimentSetting( PauliTerm.from_compact_str('(1+0j)*Z7Y8Z1Y4Z2Y5Y0X6'), PauliTerm.from_compact_str('(1+0j)*Z4X8Y5X3Y7Y1')), ExperimentSetting(sZ(7), sY(1)) ]], program=Program( H(0), H(1), H(2)), qubits=[0, 1, 2]) assert grouped_tomo_expt == expected_grouped_tomo_expt
def test_all_ops_belong_to_tpb(): 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)) ], ] for group in expts: for e1, e2 in itertools.combinations(group, 2): assert _all_qubits_diagonal_in_tpb(e1.in_operator, e2.in_operator) assert _all_qubits_diagonal_in_tpb(e1.out_operator, e2.out_operator)
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. """ self.offset = 0 # use Forest's sorting algo from the Tomography suite # to group Pauli measurements together experiments = [] if pauli_list is None: pauli_list = self.pauli_list for term in pauli_list: # if the Pauli term is an identity operator, # add the term's coefficient directly to the VQE class' offset if len(term.operations_as_set()) == 0: self.offset += term.coefficient.real else: # initial state and term pair. experiments.append(ExperimentSetting( TensorProductState(), term)) suite = Experiment(experiments, program=Program()) gsuite = group_experiments(suite) grouped_list = [] for setting in gsuite: group = [] for term in setting: group.append(term.out_operator) grouped_list.append(group) if self.verbose: print('Number of tomography experiments: ', len(grouped_list)) self.experiment_list = [] for group in grouped_list: self.experiment_list.append( GroupedPauliSetting(group, qc=self.qc, ref_state=self.ref_state, ansatz=self.ansatz, shotN=self.shotN, parametric_way=self.parametric_way, n_qubits=self.n_qubits, method=self.method, verbose=self.verbose, cq=self.custom_qubits, ))
def test_R_operator_fixed_point_2_qubit(): # Check fixed point of operator. See Eq. 5 in Řeháček et al., PRA 75, 042108 (2007). qubits = [0, 1] id_setting = ExperimentSetting(in_state=zeros_state(qubits), out_operator=sI(qubits[0]) * sI(qubits[1])) zz_setting = ExperimentSetting(in_state=zeros_state(qubits), out_operator=sZ(qubits[0]) * sI(qubits[1])) id_result = ExperimentResult(setting=id_setting, expectation=1, total_counts=1) zzplus_result = ExperimentResult(setting=zz_setting, expectation=1, total_counts=1) zz_results = [id_result, zzplus_result] # Z basis test r = _R(P00, zz_results, qubits) actual = r @ P00 @ r np.testing.assert_allclose(actual, P00, atol=1e-12)
def test_measure_observables_no_symm_calibr_raises_error(forest): qc = get_qc('2q-qvm') exptsetting = ExperimentSetting(plusZ(0), sX(0)) suite = TomographyExperiment([exptsetting], program=Program(I(0)), qubits=[0]) with pytest.raises(ValueError): result = list( measure_observables(qc, suite, n_shots=1000, readout_symmetrize=None, calibrate_readout='plus-eig'))
def test_sic_process_tomo(forest): qc = get_qc('2q-qvm') process = Program(X(0)) settings = [] for in_state in [SIC0, SIC1, SIC2, SIC3]: for out_op in [sI, sX, sY, sZ]: settings += [ExperimentSetting( in_state=in_state(q=0), out_operator=out_op(q=0) )] experiment = TomographyExperiment(settings=settings, program=process, qubits=[0]) results = list(measure_observables(qc, experiment)) assert len(results) == 4 * 4