示例#1
0
def _noise_model_program_header(noise_model, name_translator):
    """
    Generate the header for a pyquil Program that uses ``noise_model`` to overload noisy gates.

    :param NoiseModel noise_model: The assumed noise model.
    :return: A quil Program with the noise pragmas.
    :rtype: pyquil.quil.Program
    """
    from pyquil.quil import Program
    p = Program()
    for k in noise_model.gates:
        name = name_translator(k.gate)
        p.define_noisy_gate(name, k.targets, k.kraus_ops)
    for q, ap in noise_model.assignment_probs.items():
        p.define_noisy_readout(q, p00=ap[0, 0], p11=ap[1, 1])
    return p
示例#2
0
def test_pragma_with_placeholders():
    q = QubitPlaceholder()
    q2 = QubitPlaceholder()
    p = Program()
    p.inst(Pragma('FENCE', [q, q2]))
    address_map = {q: 0, q2: 1}
    addressed_pragma = address_qubits(p, address_map)[0]
    parse_equals('PRAGMA FENCE 0 1\n', addressed_pragma)

    pq = Program(X(q))
    pq.define_noisy_readout(q, .8, .9)

    pq.inst(X(q2))
    pq.define_noisy_readout(q2, .9, .8)

    ret = address_qubits(pq, address_map).out()
    assert ret == """X 0
示例#3
0
def _modified_noise_model_program_header(noise_model: NoiseModel) -> "Program":
    """
    Generate the header for a pyquil Program that uses ``noise_model`` to overload noisy gates.
    The program header consists of 3 sections:

        - The ``DEFGATE`` statements that define the meaning of the newly introduced "noisy" gate
          names.
        - The ``PRAGMA ADD-KRAUS`` statements to overload these noisy gates on specific qubit
          targets with their noisy implementation.
        - THe ``PRAGMA READOUT-POVM`` statements that define the noisy readout per qubit.

    :param noise_model: The assumed noise model.
    :return: A quil Program with the noise pragmas.
    """
    from pyquil.quil import Program

    p = Program()
    defgates: Set[str] = set()
    for k in noise_model.gates:

        # obtain ideal gate matrix and new, noisy name by looking it up in the NOISY_GATES dict
        try:
            ideal_gate, new_name = get_modified_noisy_gate(
                k.gate, tuple(k.params))

            # if ideal version of gate has not yet been DEFGATE'd, do this
            if new_name not in defgates:
                p.defgate(new_name, ideal_gate)
                defgates.add(new_name)
        except NoisyGateUndefined:
            print(
                "WARNING: Could not find ideal gate definition for gate {}".
                format(k.gate),
                file=sys.stderr,
            )
            new_name = k.gate

        # define noisy version of gate on specific targets
        p.define_noisy_gate(new_name, k.targets, k.kraus_ops)

    # define noisy readouts
    for q, ap in noise_model.assignment_probs.items():
        p.define_noisy_readout(q, p00=ap[0, 0], p11=ap[1, 1])
    return p
示例#4
0
def test_pragma_with_placeholders():
    q = QubitPlaceholder()
    q2 = QubitPlaceholder()
    p = Program()
    p.inst(Pragma("FENCE", [q, q2]))
    address_map = {q: 0, q2: 1}
    addressed_pragma = address_qubits(p, address_map)[0]
    parse_equals("PRAGMA FENCE 0 1\n", addressed_pragma)

    pq = Program(X(q))
    pq.define_noisy_readout(q, 0.8, 0.9)

    pq.inst(X(q2))
    pq.define_noisy_readout(q2, 0.9, 0.8)

    ret = address_qubits(pq, address_map).out()
    assert (ret == """X 0
PRAGMA READOUT-POVM 0 "(0.8 0.09999999999999998 0.19999999999999996 0.9)"
X 1
PRAGMA READOUT-POVM 1 "(0.9 0.19999999999999996 0.09999999999999998 0.8)"
""")
示例#5
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
示例#6
0
def test_define_noisy_readout():
    pq = Program(X(0))
    pq.define_noisy_readout(0, 0.8, 0.9)

    pq.inst(X(1))
    pq.define_noisy_readout(1, 0.9, 0.8)

    ret = pq.out()
    assert (ret == """X 0
PRAGMA READOUT-POVM 0 "(0.8 0.09999999999999998 0.19999999999999996 0.9)"
X 1
PRAGMA READOUT-POVM 1 "(0.9 0.19999999999999996 0.09999999999999998 0.8)"
""")
    # test error due to bad normalization
    with pytest.raises(ValueError):
        pq.define_noisy_readout(0, 1.1, 0.5)
    # test error due to bad normalization
    with pytest.raises(ValueError):
        pq.define_noisy_readout(0, 0.5, 1.5)
    # test error due to negative probability
    with pytest.raises(ValueError):
        pq.define_noisy_readout(0, -0.1, 0.5)
    # test error due to negative probability
    with pytest.raises(ValueError):
        pq.define_noisy_readout(0, 0.5, -1.0)
    # test error due to bad qubit_index value
    with pytest.raises(ValueError):
        pq.define_noisy_readout(-1, 0.5, 0.5)
    # test error due to bad qubit_index type
    with pytest.raises(TypeError):
        pq.define_noisy_readout(1.0, 0.5, 0.5)
示例#7
0
    def expval(self, observable):
        wires = observable.wires
        # 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.name in [
                    "PauliX", "PauliY", "PauliZ", "Identity", "Hadamard"
            ]:
                prep_prog = Program()
                for instr in self.program.instructions:
                    if isinstance(instr, Gate):
                        # split gate and wires -- assumes 1q and 2q gates
                        tup_gate_wires = instr.out().split(' ')
                        gate = tup_gate_wires[0]
                        str_instr = str(gate)
                        # map wires to qubits
                        for w in tup_gate_wires[1:]:
                            str_instr += f' {int(w)}'
                        prep_prog += Program(str_instr)

                if self.readout_error is not None:
                    prep_prog.define_noisy_readout(qubit,
                                                   p00=self.readout_error[0],
                                                   p11=self.readout_error[1])

                # All observables are rotated and can be measured in the PauliZ basis
                tomo_expt = Experiment(settings=d_expt_settings["PauliZ"],
                                       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.name == '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

        return super().expval(observable)
示例#8
0
    def expval(self, observable):
        wires = observable.wires

        # `measure_observables` called only when parametric compilation is turned off
        if not self.parametric_compilation:

            # Single-qubit observable
            if len(wires) == 1:

                # Ensure sensible observable
                assert observable.name in [
                    "PauliX", "PauliY", "PauliZ", "Identity", "Hadamard"
                ], "Unknown observable"

                # Create appropriate PauliZ operator
                wire = wires[0]
                qubit = self.wiring[wire]
                pauli_obs = sZ(qubit)

            # Multi-qubit observable
            elif len(wires) > 1 and isinstance(
                    observable, Tensor) and not self.parametric_compilation:

                # All observables are rotated to be measured in the Z-basis, so we just need to
                # check which wires exist in the observable, map them to physical qubits, and measure
                # the product of PauliZ operators on those qubits
                pauli_obs = sI()
                for wire in observable.wires:
                    qubit = wire
                    pauli_obs *= sZ(self.wiring[qubit])

            # Program preparing the state in which to measure observable
            prep_prog = Program()
            for instr in self.program.instructions:
                if isinstance(instr, Gate):
                    # split gate and wires -- assumes 1q and 2q gates
                    tup_gate_wires = instr.out().split(" ")
                    gate = tup_gate_wires[0]
                    str_instr = str(gate)
                    # map wires to qubits
                    for w in tup_gate_wires[1:]:
                        str_instr += f" {int(w)}"
                    prep_prog += Program(str_instr)

            if self.readout_error is not None:
                for wire in observable.wires:
                    qubit = wire
                    prep_prog.define_noisy_readout(self.wiring[qubit],
                                                   p00=self.readout_error[0],
                                                   p11=self.readout_error[1])

            # Measure out multi-qubit observable
            tomo_expt = Experiment(
                settings=[ExperimentSetting(TensorProductState(), pauli_obs)],
                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 the estimated expectation value
            return np.sum(
                [expt_result.expectation for expt_result in meas_obs])

        # Calculation of expectation value without using `measure_observables`
        return super().expval(observable)