def test_basis_change(simulator):
    for angle in list(uniform(0, 2 * pi, 5)):
        EX = simulate(ExpectationValue(U=gates.Rx(target=0, angle=angle), H=PX(0)), backend=simulator)
        EY = simulate(ExpectationValue(U=gates.Rx(target=0, angle=angle), H=PY(0)), backend=simulator)
        EZ = simulate(ExpectationValue(U=gates.Rx(target=0, angle=angle), H=PZ(0)), backend=simulator)

        EXX = simulate(ExpectationValue(U=gates.Rx(target=0, angle=angle) + change_basis(target=0, axis=0),
                                   H=PZ(0)), backend=simulator)
        EYY = simulate(ExpectationValue(U=gates.Rx(target=0, angle=angle) + change_basis(target=0, axis=1),
                                   H=PZ(0)), backend=simulator)
        EZZ = simulate(ExpectationValue(U=gates.Rx(target=0, angle=angle) + change_basis(target=0, axis=2),
                                   H=PZ(0)), backend=simulator)

        assert (isclose(EX, EXX, atol=1.e-4))
        assert (isclose(EY, EYY, atol=1.e-4))
        assert (isclose(EZ, EZZ, atol=1.e-4))

    for i, gate in enumerate([gates.Rx, gates.Ry, gates.Rz]):
        angle = uniform(0, 2 * pi)
        U1 = gate(target=0, angle=angle)
        U2 = change_basis(target=0, axis=i) + gates.Rz(target=0, angle=angle) + change_basis(target=0, axis=i,
                                                                                             daggered=True)
        wfn1 = simulate(U1, backend=simulator)
        wfn2 = simulate(U2, backend=simulator)
        assert (isclose(numpy.abs(wfn1.inner(wfn2)) ** 2, 1.0, atol=1.e-4))

        if simulator == "qiskit":
            return # initial state not yet supported
        wfn1 = simulate(U1, initial_state=1, backend=simulator)
        wfn2 = simulate(U2, initial_state=1, backend=simulator)
        assert (isclose(numpy.abs(wfn1.inner(wfn2)) ** 2, 1.0, atol=1.e-4))
Example #2
0
    def sample_paulistring(self, samples: int, paulistring, variables, *args,
                           **kwargs) -> numbers.Real:
        """
        Sample an individual pauli word (pauli string) and return the average result thereof.
        Parameters
        ----------
        samples: int:
            how many samples to evaluate.
        paulistring:
            the paulistring to be sampled.
        args
        kwargs

        Returns
        -------
        float:
            the average result of sampling the chosen paulistring
        """

        not_in_u = [
            q for q in paulistring.qubits if q not in self.abstract_qubits
        ]
        reduced_ps = paulistring.trace_out_qubits(qubits=not_in_u)
        if reduced_ps.coeff == 0.0:
            return 0.0
        if len(reduced_ps._data.keys()) == 0:
            return reduced_ps.coeff

        # make basis change and translate to backend
        basis_change = QCircuit()
        qubits = []
        for idx, p in reduced_ps.items():
            qubits.append(idx)
            basis_change += change_basis(target=idx, axis=p)

        # add basis change to the circuit
        # deepcopy is necessary to avoid changing the circuits
        # can be circumvented by optimizing the measurements
        # on construction: tq.ExpectationValue(H=H, U=U, optimize_measurements=True)
        circuit = self.create_circuit(circuit=copy.deepcopy(self.circuit),
                                      abstract_circuit=basis_change)
        # run simulators
        counts = self.sample(samples=samples,
                             circuit=circuit,
                             read_out_qubits=qubits,
                             variables=variables,
                             *args,
                             **kwargs)
        # compute energy
        E = 0.0
        n_samples = 0
        for key, count in counts.items():
            parity = key.array.count(1)
            sign = (-1)**parity
            E += sign * count
            n_samples += count
        assert n_samples == samples
        E = E / samples * paulistring.coeff
        return E
Example #3
0
    def sample_paulistring(self, samples: int, paulistring, *args,
                           **kwargs) -> numbers.Real:
        # make basis change and translate to backend
        basis_change = QCircuit()
        not_in_u = [
        ]  # all indices of the paulistring which are not part of the circuit i.e. will always have the same outcome
        qubits = []
        for idx, p in paulistring.items():
            if idx not in self.abstract_qubit_map:
                not_in_u.append(idx)
            else:
                qubits.append(idx)
                basis_change += change_basis(target=idx, axis=p)

        # check the constant parts as <0|pauli|0>, can only be 0 or 1
        # so we can do a fast return of one of them is not Z
        for i in not_in_u:
            pauli = paulistring[i]
            if pauli.upper() != "Z":
                return 0.0

        # make measurement instruction
        measure = QCircuit()
        if len(qubits) == 0:
            # no measurement instructions for a constant term as paulistring
            return paulistring.coeff
        else:
            measure += Measurement(target=qubits)
            #measure += Measurement(name=str(paulistring), target=qubits)
            circuit = self.circuit + self.create_circuit(basis_change +
                                                         measure)
            # run simulators
            counts = self.do_sample(samples=samples,
                                    circuit=circuit,
                                    *args,
                                    **kwargs)
            # compute energy
            E = 0.0
            n_samples = 0
            for key, count in counts.items():
                parity = key.array.count(1)
                sign = (-1)**parity
                E += sign * count
                n_samples += count
            E = E / samples * paulistring.coeff
            return E
Example #4
0
    def sample_paulistring(self, samples: int, paulistring, variables, *args,
                           **kwargs):
        """
        Has to be rewritten because of the pro-scription in qibo against calling already executed circuits.

        Parameters
        ----------
        samples: int:
            how many samples to take.
        paulistring: QubitHamiltonian:
            the paulistring to sample.
        variables: dict:
            the variables to instantiate upon sampling.
        args
        kwargs

        Returns
        -------

        """
        not_in_u = [
            q for q in paulistring.qubits if q not in self.abstract_qubits
        ]
        reduced_ps = paulistring.trace_out_qubits(qubits=not_in_u)
        if reduced_ps.coeff == 0.0:
            return 0.0
        if len(reduced_ps._data.keys()) == 0:
            return reduced_ps.coeff

        # make basis change and translate to backend
        basis_change = QCircuit()
        qubits = []
        for idx, p in reduced_ps.items():
            qubits.append(idx)
            basis_change += change_basis(target=idx, axis=p)

        highest_qubit = max(paulistring.qubits)
        new = self.rebuild_for_sample(abstract_circuit=basis_change,
                                      variables=variables,
                                      highest_qubit=highest_qubit)

        # run simulators
        counts = new.sample(samples=samples,
                            circuit=new.circuit,
                            read_out_qubits=qubits,
                            variables=variables,
                            *args,
                            **kwargs)
        # compute energy
        E = 0.0
        n_samples = 0
        #print('printing the counts')
        #print(counts)
        for key, count in counts.items():
            parity = key.array.count(1)
            sign = (-1)**parity
            E += sign * count
            n_samples += count
        assert n_samples == samples
        E = E / samples * paulistring.coeff
        return E