Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.haiqu.ai/llms.txt

Use this file to discover all available pages before exploring further.

General

It reflects compression—reducing large quantum circuits into smaller ones, similar to how a haiku compresses meaning into a few lines.
Haiqu SDK is quantum middleware — a software layer that sits between your code and quantum hardware. Instead of wrestling with low-level noise, transpilation quirks, and device-specific constraints, you write standard Qiskit circuits and let Haiqu handle the rest: circuit compression, error mitigation, transpilation, and experiment tracking are all built in.It is designed for:
  • Quantum researchers and engineers who want to push the limits of what runs on real QPUs today
  • Enterprise teams exploring quantum advantage in optimization, simulation, machine learning, and finance
  • Applied scientists who want reproducible, tracked quantum experiments without building their own infrastructure
The SDK connects to IBM Quantum, AWS Braket, and IonQ Cloud, so you can target whichever hardware your use case demands.
Not a deep one. If you can write a Qiskit QuantumCircuit, you can use Haiqu SDK. The hardest parts of running on real quantum hardware — optimizing transpilation, compressing a circuit, and applying error mitigation — are handled automatically by the SDK.If you are starting from scratch, the Quick Start gets you from zero to a running circuit, including error mitigation, with fewer than ten lines of code.
Haiqu SDK works with Qiskit QuantumCircuit objects. All core features — haiqu.run(), haiqu.state_compression(), haiqu.transpile(), and data loading — expect Qiskit circuits as input.
If you are working in PennyLane or Cirq, you will need to convert your circuits to Qiskit format before passing them to the SDK. Qiskit provides interoperability tools for common conversions.
Haiqu SDK is middleware, not a hardware provider. It routes your jobs to hardware you already have credentials for. To run on real QPUs you need:
  • IBM Quantum: an IBM Quantum account and API token
  • AWS Braket: AWS IAM credentials with Braket permissions
  • IonQ Cloud: an IonQ Cloud API key
Simulators (aer_simulator, fake_fez, fake_torino, and other fake_* backends) work out of the box with no external credentials and are the best place to start.

Getting Started & Installation

The quickest path is the cloud JupyterLab environment — everything is pre-installed and pre-configured. No setup required. You just need your API key and you can run your first circuit within minutes.See the Quick Start guide.

Authentication & API Keys

Call haiqu.login() at the start of every session:
from haiqu.sdk import haiqu

# Cloud JupyterLab: API key is pre-configured, no argument needed
haiqu.login()

# Local install: pass your API key explicitly
haiqu.login(api_access_key="YOUR_HAIQU_API_KEY")
After login, initialize an experiment to keep your work organized:
haiqu.init("My Experiment")
The most common causes, in order of frequency:
  1. Trailing whitespace — copy-pasting an API key from an email or PDF often includes an invisible space or newline at the end. Try api_access_key=key.strip().
  2. Wrong token — using the GitHub install token instead of the Haiqu API key (see the installation FAQ above).
  3. Expired or revoked key — keys can be rotated. Check the Dashboard or contact support at feedback.haiqu.ai to request a new key.
Yes. There are two independent credential layers:
LayerWhat it doesWhere it comes from
Haiqu API keyAuthenticates you to the Haiqu platformYour Haiqu welcome email
IBM / AWS / IonQ credentialsAuthorizes QPU job submission to the hardware providerYour IBM Quantum, AWS, or IonQ account
Your Haiqu API key does not grant access to external QPUs. You need provider credentials to run on real hardware. Simulators work without them.
Use the credential-saving helpers once per environment:
# IBM Quantum
haiqu.save_ibm_credentials(
    ibm_quantum_token="YOUR_IBM_TOKEN",
    ibm_quantum_instance="YOUR_INSTANCE_CRN",
)

# AWS Braket
haiqu.save_aws_credentials(
    aws_access_key_id="YOUR_KEY_ID",
    aws_secret_access_key="YOUR_SECRET",
    aws_default_region="us-east-1",
)
After saving, you can omit the options dict from haiqu.run() entirely — the SDK reads the stored credentials automatically.
For IonQ, pass ionq_api_key directly in the options dict on each run — there is no persistent save helper for IonQ credentials at this time.

Running Circuits

When you submit a circuit directly through an IBM or AWS SDK, you get back raw noisy results with no automatic optimizations applied. haiqu.run() wraps execution with:
  • Automatic transpilation to the target device’s gate set and qubit connectivity
  • Optional error mitigation (use_mitigation=True) to reduce the effect of hardware noise
  • Experiment tracking — every circuit and job is saved to your experiment history
  • A unified interface across IBM, AWS, and IonQ — the same call works regardless of hardware provider
For development and rapid iteration, any of the free simulators work without credentials and give you the same interface.
Both work in haiqu.run() — they are two ways to specify the same thing:
# Short form: pass a string directly
job = haiqu.run(circuit, shots=1000, device_id="ibm_boston")

# Long form: initialize a device object first
device = haiqu.get_device("ibm_boston")
job = haiqu.run(circuit, shots=1000, device=device)
Use device_id for quick one-liners. Use device when you want to inspect backend properties or reuse the same device object across multiple runs.
The following backends work out of the box — no IBM, AWS, or IonQ account required:
BackendWhat it simulates
aer_simulatorIdeal noiseless simulation
fake_fezIBM Fez noise model
fake_torinoIBM Torino noise model
other fake_* backendsVarious IBM device noise models
Use simulators for all development and debugging. Switch to a real QPU only when you need hardware-level validation.
job = haiqu.run(circuit, shots=1000, device_id="aer_simulator")
Yes. You do not need to transpile your circuit before calling haiqu.run(). The SDK automatically transpiles to the target device’s native gate set and qubit connectivity.Call haiqu.transpile() explicitly only when you want to inspect the transpiled circuit or compare transpilation strategies:
transpiled = haiqu.transpile(circuit, device, optimization_level=3)
haiqu.compare_metrics(transpiled, another_transpiled)
See the Transpilation guide for details.
Queue behavior depends on where the job is running:
  • Real QPUs (IBM, AWS, IonQ): queue times are controlled by the hardware provider and can range from minutes to hours depending on demand. This is outside Haiqu’s control. Use job.progress() or job.retrieve_status() to monitor without blocking your session.
  • Simulators: jobs should complete in seconds. If a simulator job is stuck, check your credit balance in the Dashboard and contact support at feedback.haiqu.ai if the issue persists.
job.retrieve_status()  # non-blocking status check
job.progress()         # visual progress indicator
All jobs are persisted on the Haiqu platform. Find the job ID in your Dashboard or by listing jobs programmatically, then retrieve it:
# List all jobs in the current experiment
haiqu.list_jobs()

# Retrieve a specific job by ID
job = haiqu.get_job("JOB_ID")
results = job.result()
You can also filter by circuit: haiqu.list_jobs(circuit=circuit_id).

Circuit Compression

state_compression produces a shallower approximate circuit that acts on the all-zero input state in a way that closely mimics your original circuit. It is not lossless — the approximation quality is reported by job.quality after the job completes.The key insight is that on noisy hardware, a shallower approximate circuit often produces better results than the exact deep circuit. Fewer gates means less accumulated noise, which more than compensates for the approximation error. Haiqu’s compression is designed with this trade-off in mind: it actively uses the device’s noise profile to optimize for real-hardware performance, not just ideal-device fidelity.
job = haiqu.state_compression(circuit=circuit)
compressed_circuit = job.result()

print(job.quality)  # approximation quality on an ideal device
Use compression when:
  • Your circuit is deep (many two-qubit gates) and hardware noise is limiting your results
  • You are targeting a real QPU and want to maximize the signal-to-noise ratio
  • You want to run circuits that would otherwise be too deep to produce meaningful results
Skip compression when:
  • Your circuit is already shallow — the approximation overhead is not worth the gain
  • Your circuit uses mid-circuit measurements with classical feedforward logic (compression applies only to the portion before the first MCM)
  • You are prototyping on a noiseless simulator — compression serves no purpose there
If unsure, try compression_level="low" first on shallow circuits. Check job.quality to decide whether the trade-off is acceptable before committing to heavier compression.
Start with the default ("balanced") and adjust based on your circuit depth and job.quality score:
LevelBest for
"low"Already-shallow circuits; very clean hardware; maximum fidelity preservation
"balanced"Default; best performance across most circuits and noise levels
"high"Very deep circuits where "balanced" does not reduce depth enough
The fine_tuning parameter also affects quality vs. speed:
Fine-tuningWhen to use
"disabled"Fastest; good for rapid iteration
"low"Default; best balance of speed and accuracy
"heavy"Best accuracy; use for final production runs
Set noise_profile to match the QPU device you plan to execute on. If they do not match, the compression is tuned for the wrong noise characteristics and you leave performance on the table.
ProfileDevice family
"ibm_eagle_r3"IBM Eagle (e.g. ibm_brisbane)
"ibm_heron_r1"IBM Heron R1
"ibm_heron_r2"IBM Heron R2 — default
"ibm_heron_r3"IBM Heron R3
"iqm_garnet"IQM Garnet (via AWS Braket)
"iqm_emerald"IQM Emerald (via AWS Braket)
job = haiqu.state_compression(
    circuit=circuit,
    noise_profile="ibm_heron_r2",   # matches ibm_torino, ibm_fez, etc.
)
Yes, but with a limitation: compression is applied only to the portion of the circuit before the first mid-circuit measurement. The remainder of the circuit is left unchanged. If the first MCM is early in the circuit, compression will have little effect.
state_compression is asynchronous — it submits a job and returns immediately. You can do other work while it runs and call job.result() when you need the output.At 100 qubits, approximate runtimes are:
Fine-tuningTypical runtime
"disabled"30 seconds
"low" (default)Up to 5 minutes
"heavy"Up to 15 minutes
The runtime depends on the circuits itself and their scale. Use "disabled" or "low" during development and "heavy" for final runs.

Error Mitigation

Haiqu SDK automatically selects the appropriate mitigation strategy based on your workload type — you do not need to choose a technique manually.Simply toggle the flag and Haiqu handles the rest:
job = haiqu.run(
    circuits=circuit,
    device=device,
    shots=1000,
    use_mitigation=True,
)
Not always. The overhead is only worth it in certain conditions:Enable mitigation when:
  • Running on real QPUs where hardware noise is significant
  • Your circuits are moderately deep (more 2Q gates = more noise = more mitigation benefit)
Skip mitigation when:
  • Using simulators (aer_simulator, fake_*) — there is no real noise to mitigate
  • Rapid prototyping and debugging — the overhead increases latency without benefit
  • Your circuit is very shallow and the hardware noise floor is already low
For production QPU runs, combine both features: compress the circuit first to reduce depth, then run with use_mitigation=True. These two features are designed to work together.
Yes — they are complementary and designed to work together. The recommended workflow for production QPU runs is:
  1. Compress the circuit with haiqu.state_compression(), using the noise_profile that matches your target device
  2. Run the compressed circuit with haiqu.run(..., use_mitigation=True)
Compression reduces circuit depth (less accumulated noise), and error mitigation then further cleans up the remaining hardware noise. Used together, they give significantly better results than either technique alone.

Transpilation

No. haiqu.run() transpiles automatically to the target device’s native gate set and qubit connectivity.Call haiqu.transpile() explicitly only when you want to:
  • Inspect the transpiled circuit before execution
  • Compare the effect of different transpilation parameters (optimization level, layout)
Haiqu uses the open-source Rivet Transpiler, developed by Haiqu. Rivet is built on top of Qiskit’s transpilation framework and exposes additional parameters for fine-grained control over layout, routing, and gate decomposition.Full parameter documentation is available in the Rivet docs.
Transpile the same circuit with different parameters, then use haiqu.compare_metrics() to view depth, gate count, and other metrics side by side:
device = haiqu.get_device("fake_torino")

t_opt0 = haiqu.transpile(circuit, device, optimization_level=0)
t_opt3 = haiqu.transpile(circuit, device, optimization_level=3)

haiqu.compare_metrics(t_opt0, t_opt3)
If you are using state_compression— pass the un-transpiled circuit (or one with minimal transpilation). The compression algorithm prefers linear-connectivity input and handles device adaptation internally as part of the compression process.After compression, call haiqu.run() as usual. It will apply the final transpilation to your target device automatically.
# 1. Compress the raw circuit
job = haiqu.state_compression(circuit=circuit, noise_profile="ibm_heron_r3")
compressed = job.result()

# 2. Run — haiqu.run() transpiles the compressed circuit for you
result = haiqu.run(compressed, device_id="ibm_boston", shots=1000)
If you are using state_compression_2d  — also pass the un-transpiled circuit. However, the function will output a transpiled circuit.

Experiment Tracking

No — if you skip it, your circuits and jobs are placed in a default experiment automatically. Nothing breaks.That said, calling haiqu.init() with a descriptive name at the start of your session is strongly recommended. Experiments accumulate quickly, and without meaningful names it becomes difficult to find specific jobs in the Dashboard or via haiqu.list_jobs() later.
haiqu.init("VQE benchmark — ibm_torino — April 2025")
haiqu.log()haiqu.run()
Executes the circuitNoYes
Saves to experiment historyYesYes (automatically)
ReturnsA tracked circuit objectA job object
Use haiqu.log() when you want to register a circuit for tracking, analysis, or future reference without running it yet. In most workflows you can skip haiqu.log() entirely — haiqu.run() saves the circuit automatically.
# Log without executing
tracked = haiqu.log(qc, name="Bell state", description="2-qubit entangled state")

# Run (also logs automatically)
job = haiqu.run(qc, shots=1000, device_id="aer_simulator")
All jobs and circuits are persisted on the Haiqu platform — closing your notebook does not lose anything.
# Find your job in the current experiment
haiqu.list_jobs()

# Or retrieve from a specific experiment
haiqu.list_jobs(experiment_id="EXPERIMENT_ID")

# Load the job and get results
job = haiqu.get_job("JOB_ID")
results = job.result()
You can also browse all experiments and jobs in the Dashboard and copy job IDs from there.
Use Experiment Reports in the Dashboard. Reports support LaTeX-style Markdown for scientific notation and equations. You can attach plots and metric tables as artifacts by drag and drop.To log a Matplotlib plot programmatically so it appears in the report:
import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.bar(results.keys(), results.values())

haiqu.log(fig, name="Result distribution")
Supported table artifacts include circuit core metrics, advanced metrics, and comparison tables generated by haiqu.compare_metrics().

Hardware Integrations

Save your credentials once using the helper, then submit jobs by device name:
haiqu.save_ibm_credentials(
    ibm_quantum_token="YOUR_IBM_TOKEN",
    ibm_quantum_instance="YOUR_INSTANCE_CRN",
)

# After saving, credentials are applied automatically
job = haiqu.run(circuit, shots=1000, device_id="ibm_boston")
Your IBM token and instance CRN are available at quantum.cloud.ibm.com. See the IBM Quantum integration page for a full walkthrough.
Configure AWS credentials using one of three methods:
# Option 1: Haiqu helper (recommended)
haiqu.save_aws_credentials(
    aws_access_key_id="YOUR_KEY_ID",
    aws_secret_access_key="YOUR_SECRET",
    aws_default_region="us-east-1",
)

# Option 2: AWS CLI (credentials stored in ~/.aws/)
# aws configure

# Option 3: Pass inline per run
options = {
    "aws_access_key_id": "YOUR_KEY_ID",
    "aws_secret_access_key": "YOUR_SECRET",
    "aws_default_region": "us-east-1",
}
AWS Braket gives access to multiple hardware providers including IQM, IonQ, and Rigetti. Use the appropriate device_id, for example "aws_ionq_aria_1". See the AWS Braket integration page for details.
We recommend issuing temporary AWS credentials with limited Braket-only permissions rather than long-lived root credentials.
Yes, via the IonQ Cloud integration. Pass your IonQ API key in the options dict:
options = {
    "ionq_api_key": "YOUR_IONQ_API_KEY",
}

# Check available devices first
haiqu.list_devices()

job = haiqu.run(
    circuit,
    shots=1000,
    device_id="ionq_qpu.forte-enterprise-1",
    options=options,
)
Get your IonQ API key at cloud.ionq.com/settings/keys.
Unlike IBM and AWS, there is no persistent save_ionq_credentials() helper — you need to include ionq_api_key in options for each run.
Reach out via feedback.haiqu.ai. Haiqu’s device abstraction is designed to support additional backends, and the team evaluates new integration requests based on demand. Include the provider name and backend identifier in your request.

Credits & Pricing

Credits are measured in SDK execution time (1 second = 1 credit). The early access plan includes 1 hour of execution time.
Credits are topped up to 1 hour once a month for each user.
Your credit usage progress bar is visible on the main Dashboard.
Job submissions will return an error and you will not be charged once your credit balance is exhausted. To continue using Haiqu SDK, contact the Haiqu team via feedback.haiqu.ai.

Troubleshooting

Work through this checklist in order:
  1. Is the right conda environment active?
    conda activate haiqu-env
    python -c "import haiqu"
    
  2. Is the Python version 3.10?
    python --version  # must be 3.10.x
    
  3. Is the Haiqu SDK version updated?
    pip show haiqu-sdk
    
  4. Did the installation complete successfully? Re-run the install command and confirm the final line reads Successfully installed haiqu-sdk-x.y.z.
    pip install 'git+https://GITHUB_TOKEN@github.com/haiqu-ai/haiqu-sdk.git#egg=haiqu-sdk'
    
  5. Is there a conflicting Qiskit version? Run pip show qiskit and compare against the version installed by Haiqu SDK. Mixed-version environments are a frequent source of import errors.
If none of the above resolves the issue, share the full error traceback at feedback.haiqu.ai.
Please check the Haiqu SDK version; if it’s mismatched, upgrade and restart the kernel. If matched, contact us.
Go through this checklist:
  1. Enable error mitigation: is use_mitigation=True set in haiqu.run()?
  2. Check circuit depth: very deep circuits degrade even with mitigation. Try haiqu.state_compression() first and verify the job.quality score.
  3. Match the noise profile: if using compression, confirm noise_profile matches your target device (see the compression FAQ above).
  4. Run a simulator baseline: execute the same circuit on aer_simulator and compare. If the ideal simulator result also looks wrong, the issue is in the circuit logic, not hardware noise.
  5. Check shot count: too few shots lead to high statistical variance. For distributions, try at least 1000 shots; for observables, 2000+ with mitigation.
haiqu.run() is non-blocking — it submits the job and returns a job handle right away. job.result() is blocking — it waits until the job is complete before returning.On real QPUs, jobs can sit in provider queues for minutes to hours. To track the progress of your job:
# Check status without blocking
print(job.retrieve_status())

# Visual progress indicator (is a blocking display)
job.progress()

# Only call result() once the job is done
if job.retrieve_status() == "DONE":
    results = job.result()
Submit bug reports and feature requests at feedback.haiqu.ai.For bugs, include:
  • Haiqu SDK version (pip show haiqu-sdk)
  • Python version (python --version)
  • All relevant IDs (experiment, circuit, job, etc.)
  • A minimal code snippet that reproduces the issue
  • The full error message and traceback
  • SDK Reference — full API documentation for every function and parameter
  • API Reference — REST API documentation
  • Cookbook — end-to-end code examples for real use cases (LR-QAOA, quantum dynamics, and more)
  • Benchmarks — performance data and specifications across hardware platforms
  • Support — direct contact with the Haiqu team