Skip to content

Providers

One algorithm, three quantum SDKs

A variational algorithm in Mandacaru is built once, as a product of exponentials of anti-Hermitian generators. Which SDK turns that into a circuit — and runs it — is a single keyword, backend_provider. The same script produces the same state vector on IBM Qiskit, Amazon Braket and Google Cirq, to machine precision, because the circuit decomposition is exact.

The three SDKs

Qiskit

backend_provider="qiskit"

IBM's SDK and the default provider. Every ansatz is compiled to a Qiskit circuit for CNOT-count and depth profiling; asking for execution runs it on Qiskit's state-vector simulator. Qiskit is little-endian, so Mandacaru qubit k is laid on wire n−1−k — the gate counts and the unitary are unaffected.

package
qiskit
executes on
qiskit.quantum_info.Statevector
execution
off — builds circuits for profiling, evaluates the state with the internal NumPy backend unless execute_circuits=True

Amazon Braket

backend_provider="braket"

The provider that reaches real hardware. On the local simulator it returns the exact state vector; through the AWS service it targets the managed SV1/DM1/TN1 simulators or the IonQ, IQM and Rigetti QPUs, where the energy is measured from shots over qubit-wise-commuting Pauli groups instead of read from amplitudes.

package
amazon-braket-sdk
executes on
the local simulator, or the AWS service by device ARN
execution
on — naming Braket is a request to run circuits on it

Cirq

backend_provider="cirq"

Google's SDK. Big-endian like Mandacaru itself, so the circuit reads exactly as the generators are written. Circuits are built from the shared gate stream and simulated with cirq.Simulator; the result matches the other two providers and the internal backend to machine precision.

package
cirq
executes on
cirq.Simulator
execution
on — naming Cirq is a request to run circuits on it

How it is done

Nothing in the algorithm changes between SDKs. The Hamiltonian is built once, and each provider replays it with the circuits compiled and executed by that SDK.

The same ADAPT-VQE on H₂, executed as real circuits on each SDK

from ase import Atoms from mandacaru import Mandacaru h2 = Atoms("H2", positions=[[0, 0, 0], [0, 0, 0.74]], cell=[8.0] * 3) # Build the qubit Hamiltonian once (integrals + Jordan-Wigner) and cache it; # every provider below replays it -- no integrals, no mapping, same problem. h2.calc = Mandacaru(method="adapt-vqe", basis="FAO", pool="qeb", save_hamiltonian="h2.parquet", verbose=False) h2.get_potential_energy() for provider in ("qiskit", "braket", "cirq"): calc = Mandacaru(method="adapt-vqe", pool="qeb", load_hamiltonian="h2.parquet", backend_provider=provider, # which SDK builds the circuits execute_circuits=True, # ... and runs them, too verbose=False) result = calc.run() print(f"{provider:7s} E = {result.optimal_energy:.6f} eV " f"{result.num_operators} operators {result.metrics.cnot_count} CNOTs")
  • backend_provider picks the SDK; execute_circuits=True makes state preparation run a real circuit on that SDK's simulator instead of the internal NumPy state vector. It defaults to True for braket and cirq and False for qiskit.
  • Every generator's terms commute, so exp(θA) factorizes exactly into Pauli rotations — basis change, CNOT ladder, Rz(−2θc), uncompute — and the three SDKs emit the same unitary from one shared gate stream (X, H, S, S†, CNOT, Rz).
  • The Hamiltonian cache keeps the comparison honest: each provider solves the identical operator, so any spread between them is the SDK, not the integrals.
  • Real hardware is the same call with a device and shots — device="ibm_torino", shots=8192 on IBM Quantum, or device="braket-ionq-aria", shots=8192 on Amazon Braket — and the energy is then measured, not read off; see the Hardware page.

What the three SDKs return

The same run on LiH from the project's own examples — every provider recovers the exact ground state of the cached Hamiltonian, grows the same ansatz, and agrees with the internal state vector below 10−5 eV. Braket's local simulator is the slow one; that is the SDK, not the algorithm.

Provider Energy Error vs. FCI Operators CNOTs Time
NumPy (internal) −187.438634 eV 3.65×10⁻⁶ 8 208 0.3 s
Qiskit −187.438636 eV 1.71×10⁻⁶ 8 208 4.1 s
Amazon Braket −187.438635 eV 2.97×10⁻⁶ 8 208 43.9 s
Cirq −187.438636 eV 2.22×10⁻⁶ 8 208 8.9 s

Below the calculator

The providers are ordinary objects. build_provider("cirq") hands an AdaptAnsatz or a Trotterized UCCSD a CircuitProvider; ansatz.state(θ) then executes a circuit, and provider.build(...) returns the SDK's own circuit object for inspection. provider_available("braket") says whether an SDK is importable — naming one never fails at import time.

from mandacaru.backends.providers import build_provider from mandacaru.circuits import AdaptAnsatz from mandacaru.circuits.pools import build_pool pool = build_pool("qeb", 2, (1, 1)) # H2: 2 spatial orbitals, (1, 1) electrons provider = build_provider("cirq") ansatz = AdaptAnsatz(4, pool.occupied_orbitals, "jordan_wigner", provider=provider) for op in pool.operators()[:3]: ansatz.append(op) psi = ansatz.state([0.31, -0.72, 0.45]) # prepared by executing a Cirq circuit circuit = provider.build(4, ansatz.reference_qubits(), ansatz.pauli_generators, [0.31, -0.72, 0.45]) print(circuit) # the cirq.Circuit itself

Keep reading

Seven families of localized orbitals generated from scratch — FAO to def2-QZVPPD — the frozen core, and the C-accelerated integral engine underneath.

ADAPT-VQE, VQE, excited states and periodic systems — every solver sharing one driver, and a dry run before any of them.

Cross-backend validation to 3.5×10⁻⁶ eV, real QPU execution through Amazon Braket, and what still doesn't work.

Try it on your own structure

Install it, or read the manual first.