Skip to content

Python SDK

This is the Python-SDK for using the Q-Alchemy API which helps quantum computing researchers to put classical data into the quantum computer. This is all also called: the loading problem, encoding problem, or quantum state preparation. Some people also call it a form of QRAM, or quantum random-access memory.

Under the hood, Q-Alchemy runs on PineXQ, the hypermedia (Siren) API platform of data cybernetics. You do not need to know anything about it to use this SDK; if you want to work with the API directly, see the PineXQ documentation.

Terminal window
pip install q-alchemy-sdk-py

For a complete environment setup, API-key configuration, and a first preparation with local verification, follow the getting-started guide.

The examples below use a fixed two-qubit state and read Q_ALCHEMY_API_KEY from your environment. Install the relevant integration before running them:

Terminal window
python -m pip install "q-alchemy-sdk-py[qiskit]"
python -m pip install "q-alchemy-sdk-py[pennylane]"
import os
import numpy as np
from q_alchemy.initialize import q_alchemy_as_qasm
state = np.array([1, 0, 0, 1], dtype=complex) / np.sqrt(2)
qasm, summary = q_alchemy_as_qasm(
state,
max_fidelity_loss=0.0,
api_key=os.environ["Q_ALCHEMY_API_KEY"],
return_summary=True,
)
print(qasm)
print(summary)
import os
import numpy as np
from qiskit.quantum_info import Statevector, state_fidelity
from q_alchemy.qiskit_integration import QAlchemyInitialize, OptParams
state = np.array([1, 0, 0, 1], dtype=complex) / np.sqrt(2)
prep = QAlchemyInitialize(
params=state.tolist(),
opt_params=OptParams(
max_fidelity_loss=0.0,
api_key=os.environ["Q_ALCHEMY_API_KEY"],
),
).definition
print(prep.draw(output="text"))
fidelity = state_fidelity(Statevector.from_instruction(prep), Statevector(state))
print(f"Local simulation fidelity: {fidelity:.6f}")
import os
import numpy as np
import pennylane as qml
from q_alchemy.pennylane_integration import QAlchemyStatePreparation, OptParams
state = np.array([1, 0, 0, 1], dtype=complex) / np.sqrt(2)
dev = qml.device("default.qubit", wires=2)
@qml.qnode(dev)
def circuit():
QAlchemyStatePreparation(
state,
wires=[0, 1],
opt_params=OptParams(
max_fidelity_loss=0.0,
api_key=os.environ["Q_ALCHEMY_API_KEY"],
),
)
return qml.probs(wires=[0, 1])
print(circuit()) # Expected approximately [0.5, 0.0, 0.0, 0.5]

This example explicitly synthesizes a Q-Alchemy preparation and runs it on a local simulator.

PennyLane provides native support for broadcasting, which allows quantum nodes to process batches of inputs efficiently. This is particularly useful in machine learning applications where inputs often come in batches. When broadcasting is used in conjunction with Q-Alchemy, each state in the batch is individually prepared using Q-Alchemy’s circuit synthesis capabilities.

This larger example also needs the example dependencies: python -m pip install "q-alchemy-sdk-py[examples]". Set Q_ALCHEMY_API_KEY as in the getting-started guide.

import os
import numpy as np
import pennylane as qml
import torch
from q_alchemy.pennylane_integration import AmplitudeEmbedding, OptParams
from sklearn.datasets import make_moons
# Sample data
X, _ = make_moons(n_samples=5, noise=0.1)
X = X / np.linalg.norm(X, axis=1, keepdims=True) # Normalize each row for amplitude embedding
# Create PennyLane device
dev = qml.device("qiskit.aer", wires=1)
@qml.qnode(dev, interface="torch")
def circuit(x):
AmplitudeEmbedding(
x,
wires=[0],
opt_params=OptParams(
max_fidelity_loss=0.0,
api_key=os.environ["Q_ALCHEMY_API_KEY"]
)
)
return qml.expval(qml.PauliZ(0))
# Run the circuit on a batch of inputs
X_tensor = torch.tensor(X, dtype=torch.float64)
print(qml.draw(circuit, level="device", max_length=100)(X_tensor))

This example demonstrates how batched data can be processed using broadcasting with AmplitudeEmbedding, and how Q-Alchemy is triggered on simulators like qiskit.aer. When moving to real hardware or gate-based backends that lack StatePrep gate, Q-Alchemy will transparently handle the state preparation.

For the method selection and tuning parameters every entry point accepts, see Options.

Verifying circuits with the sparse simulator

Section titled “Verifying circuits with the sparse simulator”

Q-Alchemy also hosts a sparse state-vector simulator, so you can check that a preparation circuit really produces your target state. The typical loop is prepare → simulate → verify:

import numpy as np
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector, state_fidelity
from q_alchemy import q_alchemy_as_qasm, SparseSimulator
target = np.array([1, 0, 0, 1], dtype=complex) / np.sqrt(2)
qasm = q_alchemy_as_qasm(target, max_fidelity_loss=0.0) # prepare
prep = QuantumCircuit.from_qasm_str(qasm)
sim = SparseSimulator() # reads Q_ALCHEMY_API_KEY from the env
sv = sim.sparse_statevector(prep) # simulate
print("fidelity:", state_fidelity(Statevector(sv.to_dense()), Statevector(target))) # verify

SparseSimulator also offers .counts(...) for measurement sampling and .tomography(...) for an exact analysis of the simulated state (not measurement-based): its density matrix and purity, plus the fidelity against a dense reference for small circuits. The sparse result holds only the non-zero amplitudes (anything below 1e-10 is dropped), so for a sparse state it stays small even where a dense 2**n vector would not fit in memory. A state that populates most of its basis states is as large as the dense one and can exhaust the simulator. max_nnz=N caps it: after every gate only the N largest amplitudes are kept and renormalised, so the result becomes approximate, and nothing in it marks that it was truncated. sv.to_coo() feeds a simulated state straight back into q_alchemy_as_qasm.

The free service includes simulator access with 4 MB RAM. For commercial workloads, platform pay-as-you-go access and full-suite OEM licensing are available. See Pricing and access or discuss platform access.

The same simulator is exposed as a Qiskit BackendV2, so it works with the transpiler, Sampler and the rest of the Qiskit ecosystem:

from qiskit import QuantumCircuit, transpile
from q_alchemy import QAlchemyBackend
backend = QAlchemyBackend()
qc = QuantumCircuit(2, 2)
qc.h(0); qc.cx(0, 1); qc.measure([0, 1], [0, 1])
job = backend.run(transpile(qc, backend), shots=4096)
print(job.result().get_counts()) # {'00': ~2048, '11': ~2048}

backend.run(...) accepts Aer-style options such as shots, seed_simulator, save_statevector and Q-Alchemy’s own save_sparse_statevector. Through the PennyLane–Qiskit plugin it also works as a PennyLane device: qml.device("qiskit.remote", wires=2, backend=QAlchemyBackend(), shots=4096).

The GitHub repository has the full guide and a runnable notebook.

The q-alchemy-sdk-py is free and open source, released under the Apache License, Version 2.0.