Beispiel #1
0
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
Beispiel #2
0
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 generate_monte_carlo_process_dfe_experiment(program: Program, qubits: List[int], benchmarker: BenchmarkConnection,
                                                n_terms: int = 200) -> TomographyExperiment:
    """
    Estimate process fidelity by randomly sampled direct fidelity estimation.

    This leads to constant overhead (w.r.t. number of qubits) fidelity estimation.

    The algorithm is due to:

    [DFE1]  Practical Characterization of Quantum Devices without Tomography
            Silva et al., PRL 107, 210404 (2011)
            https://doi.org/10.1103/PhysRevLett.107.210404

    [DFE2]  Direct Fidelity Estimation from Few Pauli Measurements
            Flammia and Liu, PRL 106, 230501 (2011)
            https://doi.org/10.1103/PhysRevLett.106.230501

    :param program: A program comprised of Clifford group gates that constructs a state
        for which we estimate the fidelity.
    :param qubits: The qubits to perform DFE on. This can be a superset of the qubits
        used in ``program``.
    :param benchmarker: The `BenchmarkConnection` object used to design experiments
    :param n_terms: Number of randomly chosen observables to measure. This number should be 
        a constant less than ``2**len(qubits)``, otherwise ``exhaustive_process_dfe`` is more efficient.
    :return: a DFE experiment object
    :rtype: ``DFEExperiment`
    """
    expr = TomographyExperiment(list(
        _monte_carlo_dfe(program=program, qubits=qubits,
                         in_states=[None, plusX, minusX, plusY, minusY, plusZ, minusZ],
                         n_terms=n_terms, benchmarker=benchmarker)),
        program=program, qubits=qubits)
    return expr
Beispiel #4
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'
Beispiel #5
0
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)
Beispiel #6
0
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))
Beispiel #7
0
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)
Beispiel #8
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
Beispiel #9
0
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
Beispiel #10
0
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)
Beispiel #11
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_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
Beispiel #12
0
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'))
Beispiel #13
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)
Beispiel #14
0
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
Beispiel #15
0
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
Beispiel #16
0
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
Beispiel #17
0
def test_measure_observables_zero_expectation(forest):
    """
    Testing case when expectation value of observable should be close to zero
    """
    qc = get_qc('2q-qvm')
    exptsetting = ExperimentSetting(plusZ(0), sX(0))
    suite = TomographyExperiment([exptsetting],
                                 program=Program(I(0)),
                                 qubits=[0])
    result = list(
        measure_observables(qc,
                            suite,
                            n_shots=10000,
                            readout_symmetrize='exhaustive',
                            calibrate_readout='plus-eig'))[0]
    np.testing.assert_almost_equal(result.expectation, 0.0, decimal=1)
Beispiel #18
0
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 an abstract compiler
    class DummyCompiler(AbstractCompiler):
        def get_version_info(self):
            return {}

        def quil_to_native_quil(self, program: Program):
            return program

        def native_quil_to_executable(self, nq_program: Program):
            return nq_program

    # 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'
Beispiel #19
0
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'
Beispiel #20
0
def test_measure_observables_symmetrize(forest):
    """
    Symmetrization alone should not change the outcome on the QVM
    """
    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,
                                   readout_symmetrize='exhaustive'):
Beispiel #21
0
    def compile_tomo_expts(self):
        """
        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 = []
        for term in self.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:
                experiments.append(ExperimentSetting(TensorProductState(), term))

        suite = TomographyExperiment(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 generate_exhaustive_state_dfe_experiment(program: Program, qubits: list,
                                             benchmarker: BenchmarkConnection) -> TomographyExperiment:
    """
    Estimate state fidelity by exhaustive direct fidelity estimation.

    This leads to a quadratic reduction in overhead w.r.t. state tomography for
    fidelity estimation.

    The algorithm is due to:

    [DFE1]  Practical Characterization of Quantum Devices without Tomography
            Silva et al.,
            PRL 107, 210404 (2011)
            https://doi.org/10.1103/PhysRevLett.107.210404
            https://arxiv.org/abs/1104.3835

    [DFE2]  Direct Fidelity Estimation from Few Pauli Measurements
            Flammia et al.,
            PRL 106, 230501 (2011)
            https://doi.org/10.1103/PhysRevLett.106.230501
            https://arxiv.org/abs/1104.4695

    :param program: A program comprised of Clifford group gates that constructs a state
        for which we estimate the fidelity.
    :param qubits: The qubits to perform DFE on. This can be a superset of the qubits
        used in ``program``.
    :param benchmarker: A ``BecnhmarkConnection`` object to be used in experiment design
    :return: a set of experiments
    :rtype: ``TomographyExperiment`
    """
    expr = TomographyExperiment(list(
        _exhaustive_dfe(program=program,
                        qubits=qubits,
                        in_states=[None, plusZ],
                        benchmarker=benchmarker)),
        program=program, qubits=qubits)
    return expr
Beispiel #23
0
    def expval(self, observable, wires, par):
        # Single-qubit observable
        if len(wires) == 1:
            # identify Experiment Settings for each of the possible single-qubit observables
            wire = wires[0]
            qubit = self.wiring[wire]
            d_expt_settings = {
                "Identity":
                [ExperimentSetting(TensorProductState(), sI(qubit))],
                "PauliX": [ExperimentSetting(TensorProductState(), sX(qubit))],
                "PauliY": [ExperimentSetting(TensorProductState(), sY(qubit))],
                "PauliZ": [ExperimentSetting(TensorProductState(), sZ(qubit))],
                "Hadamard": [
                    ExperimentSetting(TensorProductState(),
                                      float(np.sqrt(1 / 2)) * sX(qubit)),
                    ExperimentSetting(TensorProductState(),
                                      float(np.sqrt(1 / 2)) * sZ(qubit))
                ]
            }
            # expectation values for single-qubit observables
            if observable in [
                    "PauliX", "PauliY", "PauliZ", "Identity", "Hadamard"
            ]:
                prep_prog = Program()
                for instr in self.program.instructions:
                    if isinstance(instr, Gate):
                        # assumes single qubit gates
                        gate, _ = instr.out().split(' ')
                        prep_prog += Program(str(gate) + ' ' + str(qubit))
                if self.readout_error is not None:
                    prep_prog.define_noisy_readout(qubit,
                                                   p00=self.readout_error[0],
                                                   p11=self.readout_error[1])
                tomo_expt = TomographyExperiment(
                    settings=d_expt_settings[observable], program=prep_prog)
                grouped_tomo_expt = group_experiments(tomo_expt)
                meas_obs = list(
                    measure_observables(
                        self.qc,
                        grouped_tomo_expt,
                        active_reset=self.active_reset,
                        symmetrize_readout=self.symmetrize_readout,
                        calibrate_readout=self.calibrate_readout))
                return np.sum(
                    [expt_result.expectation for expt_result in meas_obs])

            elif observable == 'Hermitian':
                # <H> = \sum_i w_i p_i
                Hkey = tuple(par[0].flatten().tolist())
                w = self._eigs[Hkey]['eigval']
                return w[0] * p0 + w[1] * p1

        # Multi-qubit observable
        # ----------------------
        # Currently, we only support qml.expval.Hermitian(A, wires),
        # where A is a 2^N x 2^N matrix acting on N wires.
        #
        # Eventually, we will also support tensor products of Pauli
        # matrices in the PennyLane UI.

        probs = self.probabilities(wires)

        if observable == 'Hermitian':
            Hkey = tuple(par[0].flatten().tolist())
            w = self._eigs[Hkey]['eigval']
            # <A> = \sum_i w_i p_i
            return w @ probs
Beispiel #24
0
def test_experiment_suite_empty():
    suite = TomographyExperiment([], program=Program(X(0)), qubits=[0])
    assert len(suite) == 0
    assert str(suite.program) == 'X 0\n'