Beispiel #1
0
    def sample(self, variables, samples, *args, **kwargs) -> numpy.array:
        # todo: generalize in baseclass. Do Hamiltonian mapping on initialization
        self.update_variables(variables)

        result = []
        for H in self._abstract_hamiltonians:
            E = 0.0
            for ps in H.paulistrings:
                # change basis, measurement is destructive so copy the state
                # to avoid recomputation
                bc = QCircuit()
                zero_string = False
                for idx, p in ps.items():
                    if idx not in self.U.qubit_map:
                        # circuit does not act on the qubit
                        # case1: paulimatrix is 'Z' -> unit factor: ignore that part
                        # case2: zero factor -> continue with next ps
                        if p.upper() != "Z":
                            zero_string = True
                    else:
                        bc += change_basis(target=idx, axis=p)

                if zero_string:
                    continue

                qbc = self.U.create_circuit(abstract_circuit=bc,
                                            variables=None)
                Esamples = []
                for sample in range(samples):
                    state_tmp = qulacs.QuantumState(self.U.n_qubits)
                    self.U.circuit.update_quantum_state(state_tmp)
                    if len(
                            bc.gates
                    ) > 0:  # otherwise there is no basis change (empty qulacs circuit does not work out)
                        qbc.update_quantum_state(state_tmp)
                    ps_measure = 1.0
                    for idx in ps.keys():
                        if idx not in self.U.qubit_map:
                            continue  # means its 1 or Z and <0|Z|0> = 1 anyway
                        else:
                            M = qulacs.gate.Measurement(
                                self.U.qubit_map[idx], self.U.qubit_map[idx])
                            M.update_quantum_state(state_tmp)
                            measured = state_tmp.get_classical_value(
                                self.U.qubit_map[idx])
                            ps_measure *= (-2.0 * measured + 1.0
                                           )  # 0 becomes 1 and 1 becomes -1
                    Esamples.append(ps_measure)
                E += ps.coeff * sum(Esamples) / len(Esamples)

            result.append(E)
        return numpy.asarray(result)
Beispiel #2
0
    def sample(self, variables, samples, *args, **kwargs) -> numpy.array:
        """
        Sample this Expectation Value.
        Parameters
        ----------
        variables:
            variables, to supply to the underlying circuit.
        samples: int:
            the number of samples to take.
        args
        kwargs

        Returns
        -------
        numpy.ndarray:
            the result of sampling as a number.
        """
        self.update_variables(variables)
        state = self.U.initialize_state(self.n_qubits)
        self.U.circuit.update_quantum_state(state)
        result = []
        for H in self._reduced_hamiltonians:  # those are the hamiltonians which where non-used qubits are already traced out
            E = 0.0
            if H.is_all_z() and not self.U.has_noise:
                E = super().sample(samples=samples,
                                   variables=variables,
                                   *args,
                                   **kwargs)
            else:
                for ps in H.paulistrings:
                    # change basis, measurement is destructive so the state will be copied
                    # to avoid recomputation (except when noise was required)
                    bc = QCircuit()
                    for idx, p in ps.items():
                        bc += change_basis(target=idx, axis=p)
                    qbc = self.U.create_circuit(abstract_circuit=bc,
                                                variables=None)
                    Esamples = []
                    for sample in range(samples):
                        if self.U.has_noise and sample > 0:
                            state = self.U.initialize_state(self.n_qubits)
                            self.U.circuit.update_quantum_state(state)
                            state_tmp = state
                        else:
                            state_tmp = state.copy()
                        if len(
                                bc.gates
                        ) > 0:  # otherwise there is no basis change (empty qulacs circuit does not work out)
                            qbc.update_quantum_state(state_tmp)
                        ps_measure = 1.0
                        for idx in ps.keys():
                            assert idx in self.U.abstract_qubits  # assert that the hamiltonian was really reduced
                            M = qulacs.gate.Measurement(
                                self.U.qubit(idx), self.U.qubit(idx))
                            M.update_quantum_state(state_tmp)
                            measured = state_tmp.get_classical_value(
                                self.U.qubit(idx))
                            ps_measure *= (-2.0 * measured + 1.0
                                           )  # 0 becomes 1 and 1 becomes -1
                        Esamples.append(ps_measure)
                    E += ps.coeff * sum(Esamples) / len(Esamples)
            result.append(E)
        return numpy.asarray(result)