Find a ground state with OpenQARP
examples/openqarp_vqe.py
The problem
Section titled “The problem”Run a variational algorithm written against OpenQARP, with the platform as its engine.
QubitraEngine is a qarp.engines.Engine, so OpenQARP’s own VQE drives it without
knowing the backend is remote — and the property worth watching is batching: an analytic
parameter-shift gradient evaluates two shifted circuits per parameter, and the engine
sends every stencil point of the step as one job.
The chemistry is H2 at its equilibrium bond length, in the two-qubit form its symmetries reduce to. Its ground state is known, so a correct run has somewhere to land.
Needs the extra: pip install 'qubitra-sdk[openqarp]'.
The walkthrough
Section titled “The walkthrough”The Hamiltonian
Section titled “The Hamiltonian”from qarp.operators import QubitOperator
H2 = ( QubitOperator("", -1.0523732) + QubitOperator("Z0", 0.39793742) + QubitOperator("Z1", -0.39793742) + QubitOperator("Z0 Z1", -0.01128010) + QubitOperator("X0 X1", 0.18093119))NUCLEAR_REPULSION = 0.7199689Five Pauli terms, the electronic part of the energy. The nuclei contribute a constant that no circuit computes, added back at the end for the total energy.
The ansatz
Section titled “The ansatz”def ansatz() -> SimpleBlock: """|01> then a single Givens rotation — the one parameter H2's ground state needs.""" block = SimpleBlock(2, name="ucc") block.x(0) block.rx(0, np.pi / 2) block.h(1) block.cx(0, 1) block.rz(1, sympy.Symbol("theta")) block.cx(0, 1) block.rx(0, -np.pi / 2) block.h(1) block.build() return blockAn OpenQARP block like any other. sympy.Symbol("theta") is the free parameter; it
becomes an input float[64] theta; declaration in the circuit the platform receives, and
each evaluation travels as a parameter row beside it.
The engine
Section titled “The engine” # Credentials resolve from QUBITRA_API_KEY / QUBITRA_API_URL, same as QubitraClient. engine = QubitraEngine(backend_id)The whole integration. Swapping QarpEngine() for QubitraEngine(backend_id) is the
only line that differs from running locally.
The optimisation
Section titled “The optimisation” vqe = VQE( operator=H2, ket=ansatz(), initial_parameters=np.array([0.0]), gradient="parameter-shift", engine=engine, ) vqe.build()
energy, parameters = vqe.run()build() compiles the primitive and negotiates the circuit format with the backend;
nothing is submitted yet. run() then drives the optimiser: each iteration is one
estimator PUB for the energy, then one job carrying both shifted points of the gradient.
The cost model that implies: two platform round trips per iteration, each a few seconds of submit-poll-fetch, whatever the circuit costs. That is workable for prototyping against real backends, and the reason the stencil must hold together as one job.
Running it
Section titled “Running it”QUBITRA_API_KEY=qpk_... python examples/openqarp_vqe.pyOutput, trimmed:
backend: sim-statevector-26qtheta: +0.223528electronic energy: -1.857275 Ha (exact: -1.857275)total energy: -1.137306 Ha (exact: -1.137306)The total energy is H2’s ground state to six decimals. The example exits non-zero if the optimiser lands anywhere else: the ansatz spans the ground state and the backend’s estimator is exact, so a wrong number is a broken path rather than a hard problem.
Where to go next
Section titled “Where to go next”- OpenQARP — the full adapter: which primitive targets run, what is refused, and how sweeps and gradients batch.
- Circuit formats — how a parameter row binds to an
inputdeclaration. - Sessions — correlating a whole optimisation run.