def test_expectation_value() -> None:
    c = Circuit(2)
    c.H(0)
    c.CX(0, 1)
    op = QubitPauliOperator({
        QubitPauliString({
            Qubit(0): Pauli.Z,
            Qubit(1): Pauli.Z
        }):
        1.0,
        QubitPauliString({
            Qubit(0): Pauli.X,
            Qubit(1): Pauli.X
        }):
        0.3,
        QubitPauliString({
            Qubit(0): Pauli.Z,
            Qubit(1): Pauli.Y
        }):
        0.8j,
        QubitPauliString({Qubit(0): Pauli.Y}):
        -0.4j,
    })
    b = MyBackend()
    b.compile_circuit(c)
    assert get_operator_expectation_value(c, op, b) == pytest.approx(1.3)
def test_sampler_expectation_value() -> None:
    c = Circuit(2)
    c.H(0)
    c.CX(0, 1)
    op = QubitPauliOperator({
        QubitPauliString({
            Qubit(0): Pauli.Z,
            Qubit(1): Pauli.Z
        }):
        1.0,
        QubitPauliString({
            Qubit(0): Pauli.X,
            Qubit(1): Pauli.X
        }):
        0.3,
        QubitPauliString({
            Qubit(0): Pauli.Z,
            Qubit(1): Pauli.Y
        }):
        0.8j,
        QubitPauliString({Qubit(0): Pauli.Y}):
        -0.4j,
    })
    b = MySampler()
    b.compile_circuit(c)
    expectation = get_operator_expectation_value(c,
                                                 op,
                                                 b,
                                                 n_shots=2000,
                                                 seed=0)
    assert (np.real(expectation), np.imag(expectation)) == pytest.approx(
        (1.3, 0.0), abs=0.1)
def test_aer_placed_expectation() -> None:
    # bug TKET-695
    n_qbs = 3
    c = Circuit(n_qbs, n_qbs)
    c.X(0)
    c.CX(0, 2)
    c.CX(1, 2)
    c.H(1)
    # c.measure_all()
    b = AerBackend()
    operator = QubitPauliOperator({
        QubitPauliString(Qubit(0), Pauli.Z): 1.0,
        QubitPauliString(Qubit(1), Pauli.X): 0.5,
    })
    assert b.get_operator_expectation_value(c, operator) == (-0.5 + 0j)
    with open(os.path.join(sys.path[0], "ibmqx2_properties.pickle"),
              "rb") as f:
        properties = pickle.load(f)

    noise_model = NoiseModel.from_backend(properties)

    noise_b = AerBackend(noise_model)

    with pytest.raises(RuntimeError) as errorinfo:
        noise_b.get_operator_expectation_value(c, operator)
        assert "not supported with noise model" in str(errorinfo.value)

    c.rename_units({Qubit(1): Qubit("node", 1)})
    with pytest.raises(ValueError) as errorinfoCirc:
        b.get_operator_expectation_value(c, operator)
        assert "default register Qubits" in str(errorinfoCirc.value)
def test_operator() -> None:
    for b in [AerBackend(), AerStateBackend()]:
        c = circuit_gen()
        zz = QubitPauliOperator(
            {QubitPauliString([Qubit(0), Qubit(1)], [Pauli.Z, Pauli.Z]): 1.0})
        assert cmath.isclose(get_operator_expectation_value(c, zz, b), 1.0)
        c.X(0)
        assert cmath.isclose(get_operator_expectation_value(c, zz, b), -1.0)
def test_operator() -> None:
    c = circuit_gen()
    b = ProjectQBackend()
    zz = QubitPauliOperator(
        {QubitPauliString([Qubit(0), Qubit(1)], [Pauli.Z, Pauli.Z]): 1.0})
    assert np.isclose(get_operator_expectation_value(c, zz, b), complex(1.0))
    c.X(0)
    assert np.isclose(get_operator_expectation_value(c, zz, b), complex(-1.0))
Exemple #6
0
def ucc(params):
    singles_params = {qps: params[0] * coeff for qps, coeff in singles.items()}
    doubles_params = {qps: params[1] * coeff for qps, coeff in doubles.items()}
    excitation_op = QubitPauliOperator({**singles_params, **doubles_params})
    reference_circ = Circuit(4).X(1).X(3)
    ansatz = gen_term_sequence_circuit(excitation_op, reference_circ)
    GuidedPauliSimp().apply(ansatz)
    FullPeepholeOptimise().apply(ansatz)
    return ansatz
Exemple #7
0
def test_expectation() -> None:
    b = BraketBackend(local=True)
    assert b.supports_expectation
    c = Circuit(2, 2)
    c.Rz(0.5, 0)
    zi = QubitPauliString(Qubit(0), Pauli.Z)
    iz = QubitPauliString(Qubit(1), Pauli.Z)
    op = QubitPauliOperator({zi: 0.3, iz: -0.1})
    assert get_pauli_expectation_value(c, zi, b) == 1
    assert get_operator_expectation_value(c, op, b) == pytest.approx(0.2)
    c.X(0)
    assert get_pauli_expectation_value(c, zi, b) == -1
    assert get_operator_expectation_value(c, op, b) == pytest.approx(-0.4)
Exemple #8
0
def test_variance() -> None:
    b = BraketBackend(local=True)
    assert b.supports_variance
    # - Prepare a state (1/sqrt(2), 1/sqrt(2)).
    # - Measure w.r.t. the operator Z which has evcs (1,0) (evl=+1) and (0,1) (evl=-1).
    # - Get +1 with prob. 1/2 and -1 with prob. 1/2.
    c = Circuit(1).H(0)
    z = QubitPauliString(Qubit(0), Pauli.Z)
    assert b.get_pauli_expectation_value(c, z) == pytest.approx(0)
    assert b.get_pauli_variance(c, z) == pytest.approx(1)
    op = QubitPauliOperator({z: 3})
    assert b.get_operator_expectation_value(c, op) == pytest.approx(0)
    assert b.get_operator_variance(c, op) == pytest.approx(9)
Exemple #9
0
def test_moments_with_shots() -> None:
    b = BraketBackend(local=True)
    c = Circuit(1).H(0)
    z = QubitPauliString(Qubit(0), Pauli.Z)
    e = b.get_pauli_expectation_value(c, z, n_shots=10)
    assert abs(e) <= 1
    v = b.get_pauli_variance(c, z, n_shots=10)
    assert v <= 1
    op = QubitPauliOperator({z: 3})
    e = b.get_operator_expectation_value(c, op, n_shots=10)
    assert abs(e) <= 3
    v = b.get_operator_variance(c, op, n_shots=10)
    assert v <= 9
 def get_operator_expectation_value(
     self,
     state_circuit: Circuit,
     operator: QubitPauliOperator,
     n_shots: int = 0,
     valid_check: bool = True,
     **kwargs: KwargTypes,
 ) -> complex:
     if valid_check:
         self._check_all_circuits([state_circuit], nomeasure_warn=False)
     observable = create_observable_from_openfermion_text(
         str(operator.to_OpenFermion()))
     expectation_value = self._expectation_value(state_circuit, observable)
     del observable
     return expectation_value.real
def test_device() -> None:
    c = circuit_gen(False)
    b = IBMQBackend("ibmq_santiago", hub="ibm-q", group="open", project="main")
    assert b._max_per_job == 75
    operator = QubitPauliOperator({
        QubitPauliString(Qubit(0), Pauli.Z): 1.0,
        QubitPauliString(Qubit(0), Pauli.X): 0.5,
    })
    val = get_operator_expectation_value(c, operator, b, 8000)
    print(val)
    c1 = circuit_gen(True)
    c2 = circuit_gen(True)
    b.compile_circuit(c1)
    b.compile_circuit(c2)

    print(b.get_shots(c1, n_shots=10))
    print(b.get_shots(c2, n_shots=10))
Exemple #12
0
def expectation_value(state_circuit, operator, backend, n_shots):
    if backend.supports_expectation:
        compiled_circuit = state_circuit.copy()
        backend.compile_circuit(compiled_circuit)
        return backend.get_operator_expectation_value(
            compiled_circuit, QubitPauliOperator.from_OpenFermion(operator))
    elif backend.supports_shots:
        syn_res_index = state_circuit.bit_readout[syn_res]
        pauli_circuits, coeffs, energy = gen_pauli_measurement_circuits(
            state_circuit, compiler_pass(backend), operator)
        handles = backend.process_circuits(pauli_circuits, n_shots=n_shots)
        for handle, coeff in zip(handles, coeffs):
            res = backend.get_result(handle)
            filtered = filter_shots(res, syn_res)
            energy += coeff * expectation_from_shots(filtered)
            backend.pop_result(handle)
        return energy
    else:
        raise NotImplementedError(
            "Implementation for state and counts to be written")
def test_statevector_expectation() -> None:
    hamiltonian = QubitOperator()
    hamiltonian.terms = {
        (): 0.08406444459465776,
        ((0, "Z"), ): 0.17218393261915543,
        ((1, "Z"), ): 0.17218393261915546,
        ((0, "Z"), (1, "Z")): 0.16892753870087912,
        ((0, "Y"), (1, "X"), (2, "Y")): 0.04523279994605785,
        ((0, "X"), (1, "X"), (2, "X")): (0.04523279994605785),
        ((0, "Y"), (1, "Y"), (2, "X")): -0.04523279994605785,
        ((0, "X"), (1, "Y"), (2, "Y")): (0.04523279994605785),
        ((2, "Z"), ): -0.45150698444804915,
        ((0, "Z"), (2, "Z")): 0.2870580651815905,
        ((1, "Z"), (2, "Z")): 0.2870580651815905,
    }
    target = eigenspectrum(hamiltonian)[0]
    circ = h2_3q_circ(PARAM)
    for b in backends:
        b.compile_circuit(circ)
        energy = b.get_operator_expectation_value(
            circ, QubitPauliOperator.from_OpenFermion(hamiltonian))
        assert np.isclose(energy, target)
c = Circuit(3)
c.H(0).CX(0, 1)
c.Rz(0.3, 0)
c.Rz(-0.3, 1)
c.Ry(0.8, 2)

# Define the measurement operator:

xxi = QubitPauliString({Qubit(0): Pauli.X, Qubit(1): Pauli.X})
zzz = QubitPauliString({
    Qubit(0): Pauli.Z,
    Qubit(1): Pauli.Z,
    Qubit(2): Pauli.Z
})
op = QubitPauliOperator({xxi: -1.8, zzz: 0.7j})

# Run on the backend:

backend = AerBackend()
backend.compile_circuit(c)
exp = backend.get_operator_expectation_value(c, op)
print(exp)

# ## `pytket.extensions.qiskit.AerBackend`

# `AerBackend` wraps up the `qasm_simulator` from the Qiskit Aer package. It supports an extremely flexible set of circuits and uses many effective simulation methods making it a great all-purpose sampling simulator.
#
# Unique features:
# - supports mid-circuit measurement and OpenQASM-style conditional gates;
# - encompasses a variety of underlying simulation methods and automatically selects the best one for each circuit (including statevector, density matrix, (extended) stabilizer and matrix product state);
Exemple #15
0
def ucc(params):
    ansatz = Circuit(4)
    ansatz.X(1).X(3)
    add_excitation(ansatz, singles_a, params[0])
    add_excitation(ansatz, singles_b, params[1])
    add_excitation(ansatz, doubles, params[2])
    DecomposeBoxes().apply(ansatz)
    return ansatz


# The objective function can also be simplified using a utility method for constructing the measurement circuits and processing for expectation value calculations.

from pytket.utils.operators import QubitPauliOperator
from pytket.utils import get_operator_expectation_value

hamiltonian_op = QubitPauliOperator.from_OpenFermion(hamiltonian)

# Simplified objective function using utilities:


def objective(params):
    circ = ucc(params)
    return (get_operator_expectation_value(
        circ, hamiltonian_op, backend, n_shots=4000) +
            nuclear_repulsion_energy)


arg_values = [-3.79002933e-05, 2.42964799e-05, 4.63447157e-01]

energy = objective(arg_values)
print(energy)
Exemple #16
0
               0.12062523483390425 * QubitOperator("Z0 Z2") +
               0.16592785033770352 * QubitOperator("Z0 Z3") +
               0.17141282644776884 * QubitOperator("Z1") +
               0.16592785033770352 * QubitOperator("Z1 Z2") +
               0.12062523483390425 * QubitOperator("Z1 Z3") +
               -0.22343153690813597 * QubitOperator("Z2") +
               0.17441287612261608 * QubitOperator("Z2 Z3") +
               -0.22343153690813597 * QubitOperator("Z3"))

# We can simulate this exactly using a statevector simulator like ProjectQ. This has a built-in method for fast calculations of expectation values that works well for small examples like this.

from pytket.extensions.projectq import ProjectQBackend

backend = ProjectQBackend()
ideal_energy = backend.get_operator_expectation_value(
    ansatz, QubitPauliOperator.from_OpenFermion(hamiltonian))
print(ideal_energy)

# Ideally the state generated by this ansatz will only span the computational basis states with exactly two of the four qubits in state $\lvert 1 \rangle$. This is because these basis states correspond to two electrons being present in the molecule.
#
# This ansatz is a hardware-efficient model that is designed to explore a large portion of the Hilbert space with relatively few entangling gates. Unfortunately, with this much freedom, it will regularly generate states that have no physical interpretation such as states spanning multiple basis states corresponding to different numbers of electrons in the system (which we assume is fixed and conserved).
#
# We can mitigate this by using a syndrome qubit that calculates the parity of the other qubits. Post-selecting this syndrome with $\langle 0 \rvert$ will project the remaining state onto the subspace of basis states with even parity, increasing the likelihood the observed state will be a physically admissible state.
#
# Even if the ansatz parameters are tuned to give a physical state, real devices have noise and imperfect gates, so in practice we may also measure bad states with a small probability. If this syndrome qubit is measured as 1, it means an error has definitely occurred, so we should discard the shot.

syn = Qubit("synq", 0)
syn_res = Bit("synres", 0)
ansatz.add_qubit(syn)
ansatz.add_bit(syn_res)
for qb in qubits:
Exemple #17
0
def _obs_from_qpo(operator: QubitPauliOperator, n_qubits: int) -> Observable:
    H = operator.to_sparse_matrix(n_qubits).toarray()
    return Observable.Hermitian(H)