Skip to main content
Haiqu’s Orchestration Engine Cuts Quantum Cloud Costs for Utility-Scale Quantum Dynamics Simulation by 350× This notebook demonstrates how to use Haiqu to achieve a 350× cost reduction in quantum cloud computing bill. For concreteness, it uses a utility-scale quantum dynamics simulation of the 2D transverse-field Ising model on 127 qubits (Nature Article). By leveraging proprietary algorithms and orchestration, Haiqu reduces the quantum processor runtime from 4 hours to under 1 minute and quantum cloud bill from ~\10,000to 10,000 to ~\\30. Why the tranverse-field ising model? Universal behavior: Many physical systems and optimization problems—including scheduling, routing, and other combinatorial tasks—can be mapped onto Ising-type Hamiltonians. Classically intractable: In the regime where interaction terms compete, quantum dynamics can generate strong entanglement that quickly overwhelms scalable classical simulation methods. How does Haiqu perform? At 127 qubits and a two-qubit gate depth of 15 (710 CNOTs), the evolution circuit exceeds the reach of brute-force classical simulation. Haiqu handles this regime with ease. Haiqu’s runtime engine achieves the same the accuracy as reported by IBM, but at a fraction of the time and cost: 41 seconds (Haiqu) vs. 4 hours (IBM) and $33 (Haiqu) versus $11,520 (IBM) (350× cost reduction). Having a bug or an issue? Submit feedback Initialize the notebook Import the necessary libraries, setup credentials, initialize the Haiqu SDK, load the device, and show the connectivity map.
## Import and Setup
import matplotlib.pyplot as plt
import numpy as np
from qiskit.quantum_info import SparsePauliOp
from haiqu.sdk import haiqu
from utils.utils import make_ising_evolution_circuit, load_json_data, show_device_connectivity

# Load configurations
config = load_json_data("utils/config.json")
device_execution = any(config["device_credentials"].values())

# Initialize Haiqu
haiqu.login(**{k: v for k, v in config["haiqu"].items() if v})
haiqu.init(config["experiment"]["name"])

# Show the device connectivity
device = haiqu.get_device(config["processor"]["name"])
coupling_map = device.coupling_map
show_device_connectivity(coupling_map=coupling_map)

if device_execution:
    print(f"Executing circuits on {device.id}")
else:
    print("Loading existing results from cache")
Define the simulation The transverse-field Ising Hamiltonian H=Hint+HfieldH = H_{\text{int}} + H_{\text{field}} consists of two terms. The interaction term Hint=Ji,jZiZj,H_{\text{int}} = -J \sum_{\langle i,j \rangle} Z_i Z_j , couples neighboring spins with strength JJ, favoring alignment along z^\hat{z}. The field term Hfield=hi=0N1Xi,H_{\text{field}} = h \sum_{i=0}^{N-1} X_i , randomizes alignment along z^\hat{z} by pushing spins towards x^\hat{x} with a transverse field strength hh. Because HintH_{\text{int}} and HfieldH_{\text{field}} do not commute, HH cannot be directly mapped onto quantum processors. To address this, the evolution circuit is approximated as a sequence of m=t/Δtm = t/\Delta t discrete steps with duration Δt\Delta t: U(t)=eiHt=ei(Hint+Hfield)t(eiHfieldΔteiHintΔt)m.\begin{aligned} U(t) &= e^{-iHt} \\ &= e^{-i (H_{\text{int}} + H_{\text{field}}) t} \\ % &\approx e^{-i H_{\text{field}} \Delta t} \, e^{-i H_{\text{int}} \Delta t}. &\approx \left(e^{-i H_{\text{field}} \Delta t}\, e^{-i H_{\text{int}} \Delta t}\right)^m. \end{aligned}
# Define the circuit
config["circuit"] = {
    "num_qubits": 127,
    "shots": 10_000,
    "num_steps": 5,
    "transverse_field_params": [[0.0], [0.1], [0.2], [0.3], [0.5], [0.7], [0.8], [1.0], [1.2], [1.3], [1.4], [1.5], [1.5708]]
}
parameterized_circuit = make_ising_evolution_circuit(
    num_qubits=config["circuit"]["num_qubits"], 
    num_steps=config["circuit"]["num_steps"], 
    backend_coupling_map=coupling_map
)
The average system magnetization M=1Ni=0N1ZiM = \frac{1}{N} \sum_{i=0}^{N-1} Z_i sums over individual spins on qubit ii Z0=ZIZ1=IZIZ2=IIZIZi=IZI.\begin{aligned} Z_0 &= Z \otimes I \otimes \cdots \\ Z_1 &= I \otimes Z \otimes I \otimes \cdots \\ Z_2 &= I \otimes I \otimes Z \otimes I \otimes \cdots \\ Z_i &= I \otimes \cdots \otimes Z \otimes \cdots \otimes I. \end{aligned} for number of qubits NN, identity operator II, and Pauli-Z operator ZZ.
paulis = []
for i in range(config["circuit"]["num_qubits"]):
    pauli_string = ["I"] * config["circuit"]["num_qubits"]
    pauli_string[i] = "Z"
    paulis.append("".join(pauli_string))

coeffs = [1 / config["circuit"]["num_qubits"]] * len(paulis)
list_observables = [SparsePauliOp(paulis, coeffs)]
Define and run scenarios Four scenarios are considered:
  1. Ideal - Simulated noise-free baseline results.
  2. Noisy - Run on quantum processor without error mitigation.
  3. IBM - Run on quantum processor with IBM error mitigation (Sparse Pauli-Lindblad Noise Learning + ZNE + PEA).
  4. Haiqu - Run on quantum processor with Haiqu proprietary error mitigation and orchestration engine.
Results are compared in terms of quality (closeness to ideal) and efficiency (resource utilization).
def run_scenario_ideal(config, circuit, observables):
    """
    Scenario 1: Ideal - Results with no noise.
    """
    results = load_json_data(
        f"{config['experiment']['cached_folder']}/ideal.json"
    )

    return {
        "scenario_name": "Ideal",
        "scenario_description": "Results with no noise",
        "magnetization": results[0][0],
        "runtime_minutes": None,
        "runtime_bill": None,
    }


def run_scenario_noisy(config, circuit, observables):
    """
    Scenario 2: Noisy - Raw results from quantum processor without error mitigation.
    """
    if device_execution:
        results = haiqu.run(
            circuit,
            parameters=config["circuit"]["transverse_field_params"],
            observables=observables,
            shots=config["circuit"]["shots"],
            device_id=config["processor"]["name"],
            options=config["device_credentials"],
        ).result()
    else:
        results = load_json_data(f"{config['experiment']['cached_folder']}/noisy.json")["results"]

    runtime_minutes = 38 / 60  # For cached job.

    return {
        "scenario_name": "Noisy",
        "scenario_description": "Raw results from quantum processor without error mitigation",
        "magnetization": results[0][0],
        "runtime_minutes": runtime_minutes,
        "runtime_bill": runtime_minutes * config["processor"]["usd_per_minute"],
    }


def run_scenario_mitigated_ibm(config, circuit, observables):
    """
    Scenario 3: Error Mitigated IBM - Results using IBM's error mitigation methods.
    """
    # Results and runtime from IBM Nature Article: https://www.nature.com/articles/s41586-023-06096-3
    results = load_json_data(f"{config['experiment']['cached_folder']}/ibm.json")
    runtime_minutes = 4 * 60  # See IBM paper.
    
    return {
        "scenario_name": "IBM",
        "scenario_description": (
            "Results using IBM's error mitigation methods "
            "(Sparse Pauli-Lindblad Noise Learning + ZNE)"
        ),
        "magnetization": results[0][0],
        "runtime_minutes": runtime_minutes,
        "runtime_bill": runtime_minutes * config["processor"]["usd_per_minute"],
    }


def run_scenario_mitigated_haiqu(config, circuit, observables):
    """
    Scenario 4: Error Mitigated Haiqu - Results using Haiqu's error mitigation.
    """
    if device_execution:
        results = haiqu.run(
            circuit,
            parameters=config["circuit"]["transverse_field_params"],
            observables=observables,
            shots=config["circuit"]["shots"],
            device_id=config["processor"]["name"],
            options=config["device_credentials"],
            use_mitigation=True,
        ).result()
    else:
        results = load_json_data(f"{config['experiment']['cached_folder']}/haiqu.json")["results"]

    runtime_minutes = 41 / 60  # For cached job.

    return {
        "scenario_name": "Haiqu",
        "scenario_description": "Results using Haiqu's error mitigation",
        "magnetization": results[0][0],
        "runtime_minutes": runtime_minutes,
        "runtime_bill": runtime_minutes * config["processor"]["usd_per_minute"],
    }
# Run all scenarios and collect results
scenario_ideal = run_scenario_ideal(config, parameterized_circuit, list_observables)
scenario_noisy = run_scenario_noisy(config, parameterized_circuit, list_observables)
scenario_ibm = run_scenario_mitigated_ibm(config, parameterized_circuit, list_observables)
scenario_error_mitigated = run_scenario_mitigated_haiqu(config, parameterized_circuit, list_observables)

# Create summary array with all scenario results
scenarios_summary = [
    scenario_ideal,
    scenario_noisy,
    scenario_ibm,
    scenario_error_mitigated
]

# Display the summary
import pandas as pd
summary_df = pd.DataFrame(scenarios_summary)
summary_df
Learn from results 💡 Good to Know: Average magnetization decrease with increasing transverse field strength hh as spins are pushed towards x^\hat{x} and randomized along the measurement axis z^\hat{z}. The solution obtained with Haiqu matches the one obtained by IBM. Both improve quality versus the noisy benchmark.
markers = ["x", "o", "s", "d"]
linestyles = [":", "--", "--", "-"]

plt.figure()

for i, scenario in enumerate(scenarios_summary):
    try:
        x = np.asarray(config["circuit"]["transverse_field_params"]).ravel()
        y = np.asarray(scenario["magnetization"]).ravel()
        plt.plot(x, y, label=scenario["scenario_name"], marker=markers[i % len(markers)], linestyle=linestyles[i % len(linestyles)] )
    except Exception:
        print(f"Error plotting {scenario['scenario_name']}")

plt.xlabel("Transverse Field Strength $h$")
plt.ylabel("Magnetization")
plt.legend()
plt.tight_layout()
haiqu.log(plt, name="result")
💡 Good to Know: Haiqu’s algorithmic and orchestration engine reduces the time to solution from 4h to 41s and the cost of solution from ~$10,000 to ~$30 compared to IBM’s implementation. This is enabled through the use of proprietary lightweight, high-efficiency error mitigation algorithms and orchestration.
labels = []
costs = []

for scenario in scenarios_summary:
    if scenario["runtime_bill"] is not None:
        labels.append(scenario["scenario_name"])
        costs.append(scenario["runtime_bill"])

plt.figure()
plt.bar(labels, costs)
plt.yscale("log")
plt.ylabel("Quantum Cloud Bill ($)")
plt.tight_layout()
haiqu.log(plt, name="performance")
Get in Touch Documentation portal docs.haiqu.ai Contact Support feedback.haiqu.ai Follow Us on LinkedIn latest news on LinkedIn Visit Our Website Learn more about Haiqu Inc. on haiqu.ai Business Inquiries Contact us at info@haiqu.ai