Cloud Simulation

Cloud Simulation

Cloud Execution via QoroService

QoroService connects Divi to Qoro’s cloud simulation platform, where jobs are routed to high-performance Maestro simulator backends — including MPS, state vector, and stabilizer simulators.

This is ideal for:

  • Large circuits that are too slow for local simulation
  • Running on high-performance cloud simulators
  • Parallelizing workloads across cloud instances
  • Scaling variational algorithms to larger problem sizes

Getting Started

1. Create an Account & Get Your API Token

Visit dash.qoroquantum.net to create an account and manage your API tokens. From the dashboard you can:

  • Generate your API token — head to the Token page to activate your token
  • Purchase simulation credits — browse available credit packages on the Credits page
  • Monitor your jobs — track submitted jobs, credit usage, and execution history

2. Install Divi

pip install qoro-divi

3. Configure Your Token

Store your API token in a .env file at the root of your project:

# .env
QORO_API_KEY="your-api-token"

⚠️ Important: Make sure .env is listed in your .gitignore so you don’t accidentally commit your API key to version control.

Then use it in your code:

from divi.backends import QoroService, JobConfig

# Option 1: Pass the token directly
q_service = QoroService(auth_token="your-api-token", config=JobConfig(shots=5000, qpu_system="qoro_maestro"))

# Option 2: Reads from QORO_API_KEY environment variable automatically
q_service = QoroService(config=JobConfig(shots=5000, qpu_system="qoro_maestro"))

4. Use It as a Backend

Any Divi quantum program accepts QoroService as a backend — just swap it in:

# Local simulation
from divi.backends import ParallelSimulator
backend = ParallelSimulator()

# Cloud simulation — same interface, more power
from divi.backends import QoroService, JobConfig
backend = QoroService(config=JobConfig(shots=5000, qpu_system="qoro_maestro"))

Examples

Cloud VQE

Run a Variational Quantum Eigensolver for molecular ground-state energy estimation:

import pennylane as qml
from divi.qprog import VQE, HartreeFockAnsatz
from divi.qprog.optimizers import ScipyOptimizer, ScipyMethod
from divi.backends import QoroService, JobConfig

q_service = QoroService(config=JobConfig(shots=5000, qpu_system="qoro_maestro"))

# Define a hydrogen molecule
molecule = qml.qchem.Molecule(
    symbols=["H", "H"],
    coordinates=[[0.0, 0.0, 0.0], [0.0, 0.0, 0.735]],
)

vqe = VQE(
    molecule=molecule,
    ansatz=HartreeFockAnsatz(),
    optimizer=ScipyOptimizer(ScipyMethod.COBYLA),
    max_iterations=10,
    backend=q_service,
)

vqe.run()
print(f"Energy: {vqe.best_loss:.4f}")

Cloud QAOA

Solve combinatorial optimization problems like MaxCut using QAOA:

from divi.qprog import QAOA, GraphProblem
from divi.qprog.optimizers import MonteCarloOptimizer
from divi.backends import QoroService, JobConfig
import networkx as nx

q_service = QoroService(config=JobConfig(shots=10000, qpu_system="qoro_maestro"))

G = nx.random_regular_graph(3, 20, seed=42)

qaoa = QAOA(
    problem=G,
    graph_problem=GraphProblem.MAXCUT,
    n_layers=2,
    optimizer=MonteCarloOptimizer(),
    max_iterations=10,
    backend=q_service,
)

qaoa.run()
print(f"Solution: {qaoa.solution}")

Cloud VQE Sweep

Sweep across molecular bond lengths to map out a potential energy surface:

import pennylane as qml
from divi.qprog import VQEHyperparameterSweep, MoleculeTransformer, HartreeFockAnsatz
from divi.qprog.optimizers import ScipyOptimizer, ScipyMethod
from divi.backends import QoroService, JobConfig

q_service = QoroService(config=JobConfig(shots=5000, qpu_system="qoro_maestro"))

# Define a base hydrogen molecule
base_molecule = qml.qchem.Molecule(
    symbols=["H", "H"],
    coordinates=[[0.0, 0.0, 0.0], [0.0, 0.0, 0.735]],
)

# Create a transformer that scales the bond length
transformer = MoleculeTransformer(
    base_molecule=base_molecule,
    bond_modifiers=[0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.5, 1.8, 2.0],
)

sweep = VQEHyperparameterSweep(
    ansatze=[HartreeFockAnsatz()],
    molecule_transformer=transformer,
    optimizer=ScipyOptimizer(ScipyMethod.COBYLA),
    max_iterations=20,
    backend=q_service,
)

sweep.create_programs()
sweep.run(blocking=True)

(best_ansatz, best_modifier), best_energy = sweep.aggregate_results()
print(f"Best energy: {best_energy:.4f} Ha (ansatz={best_ansatz}, modifier={best_modifier})")

Cloud Custom VQA

Run a custom variational quantum algorithm with your own parameterized circuit:

import pennylane as qml
from divi.qprog import CustomVQA
from divi.qprog.optimizers import ScipyOptimizer, ScipyMethod
from divi.backends import QoroService, JobConfig

q_service = QoroService(config=JobConfig(shots=5000, qpu_system="qoro_maestro"))

# Define a parameterized quantum circuit as a QuantumScript
H = qml.Hamiltonian([1.0, 0.5], [qml.PauliZ(0), qml.PauliX(0) @ qml.PauliX(1)])

with qml.queuing.AnnotatedQueue() as q:
    qml.RY(0.1, wires=0)
    qml.RY(0.2, wires=1)
    qml.CNOT(wires=[0, 1])
    qml.expval(H)

qscript = qml.tape.QuantumScript.from_queue(q, trainable_params=[0, 1])

custom = CustomVQA(
    qscript=qscript,
    optimizer=ScipyOptimizer(ScipyMethod.L_BFGS_B),
    max_iterations=50,
    backend=q_service,
)

custom.run()
print(f"Best energy: {custom.best_loss:.4f}")

Features

Expectation Value Support

When using QoroService with the qoro_maestro system, expectation values of your cost Hamiltonian are computed directly on the cloud backend. Instead of sampling bitstrings locally and reconstructing expectation values, Divi sends the Hamiltonian as Pauli operator strings to the cloud, where they are evaluated efficiently. This avoids the overhead of observable grouping and state tomography.

This is enabled automatically for all variational algorithms (VQE, QAOA, CustomVQA, etc.) when the backend supports it. You can also use it directly via submit_circuits by providing your QASM circuit and observables as semicolon-separated Pauli strings:

from divi.backends import QoroService, JobConfig

q_service = QoroService(config=JobConfig(shots=5000, qpu_system="qoro_maestro"))

# A simple 2-qubit QASM circuit
qasm_circuit = """
OPENQASM 2.0;
include "qelib1.inc";
qreg q[2];
ry(0.5) q[0];
ry(1.2) q[1];
cx q[0], q[1];
"""

# Submit with Pauli observables — each term is a string of I, X, Y, Z
# e.g. "ZI" measures Z on qubit 0, I on qubit 1
result = q_service.submit_circuits(
    circuits={"my_circuit": qasm_circuit},
    ham_ops="ZI;IX;XX",  # Semicolon-separated Pauli operator strings
)

# Poll until the job completes
q_service.poll_job_status(result, loop_until_complete=True)

# Retrieve the expectation values
result = q_service.get_job_results(result)
print(result.results)

If you need to force sampling-based measurement instead, set force_sampling=True in your JobConfig:

q_service = QoroService(config=JobConfig(shots=5000, qpu_system="qoro_maestro", force_sampling=True))

Checkpointing

Save and resume long-running cloud jobs. If a cloud execution is interrupted, checkpointing lets you pick up exactly where you left off:

from divi.qprog.checkpointing import CheckpointConfig

qaoa = QAOA(
    problem=G,
    graph_problem=GraphProblem.MAXCUT,
    n_layers=2,
    optimizer=ScipyOptimizer(ScipyMethod.COBYLA),
    max_iterations=100,
    backend=q_service,
)

qaoa.run(checkpoint_config=CheckpointConfig(checkpoint_dir="./checkpoints"))