VQE for a spin model using qse Operators

VQE for a spin model using qse Operators#

This notebook builds a spin model using the qse Operator / Operators classes, converts it to a Qiskit SparsePauliOp via to_qiskit() method, and runs VQE to find the ground state energy.

import numpy as np
import qse
from qse.operator.operator import Operator
from qse.operator.operators import Operators

1. Build the spin model.#

We build a 1D transverse-field Ising model (TFIM) on \(N=10\) qubits:

\[H = -J \sum_{i=0}^{N-2} Z_i Z_{i+1} - h \sum_{i=0}^{N-1} X_i\]
N = 10
J = 1.0
h = 0.5
spacing = 1.0

qbits = qse.lattices.chain(spacing, N)

# ZZ interaction terms between neighbouring qubits
hamiltonian = qbits.compute_interaction_hamiltonian(
    distance_func=lambda d: -J * np.isclose(d, spacing),
    interaction="Z",
)

# Transverse field X terms on each qubit
for i in range(N):
    hamiltonian += qse.Operator("X", i, N, coef=-h)

2. Convert to Qiskit SparsePauliOp#

Once we have the Hamiltonian \(H\), we can use the to_qiskit() method to transform it to a Qiskit Sparse Pauli Operator.

pauli_op = hamiltonian.to_qiskit()
print(pauli_op)
SparsePauliOp(['ZZIIIIIIII', 'IZZIIIIIII', 'IIZZIIIIII', 'IIIZZIIIII', 'IIIIZZIIII', 'IIIIIZZIII', 'IIIIIIZZII', 'IIIIIIIZZI', 'IIIIIIIIZZ', 'XIIIIIIIII', 'IXIIIIIIII', 'IIXIIIIIII', 'IIIXIIIIII', 'IIIIXIIIII', 'IIIIIXIIII', 'IIIIIIXIII', 'IIIIIIIXII', 'IIIIIIIIXI', 'IIIIIIIIIX'],
              coeffs=[-1. +0.j, -1. +0.j, -1. +0.j, -1. +0.j, -1. +0.j, -1. +0.j, -1. +0.j,
 -1. +0.j, -1. +0.j, -0.5+0.j, -0.5+0.j, -0.5+0.j, -0.5+0.j, -0.5+0.j,
 -0.5+0.j, -0.5+0.j, -0.5+0.j, -0.5+0.j, -0.5+0.j])

3. Set up and run VQE.#

We set up and run the VQE in qiskit.

from qiskit.primitives import StatevectorEstimator
from qiskit.circuit.library import efficient_su2

import numpy as np
from scipy.optimize import minimize
ansatz = efficient_su2(num_qubits=N, reps=2, entanglement="linear")
estimator = StatevectorEstimator()
energies_list = []


def cost_function(params):
    result = estimator.run([(ansatz, pauli_op, params)]).result()
    energy = result[0].data.evs
    energies_list.append(float(energy))
    return float(energy)


# Random initial parameters
rng = np.random.default_rng(42)
x0 = rng.uniform(-np.pi, np.pi, ansatz.num_parameters)

result = minimize(
    cost_function, x0, method="COBYLA", options={"maxiter": 2000, "rhobeg": 0.5}
)
ground_state = np.linalg.eigh(pauli_op.to_matrix())[0][0]
print(f"VQE ground state energy : {result.fun:.6f}")
print(f"Exact ground state energy: {ground_state}")
VQE ground state energy : -9.746544
Exact ground state energy: -9.765503957927187