Пример #1
0
    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,
                            ))
Пример #2
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)
Пример #3
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):
                        # 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])
                tomo_expt = Experiment(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
Пример #4
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)