⚛️ js-quantum
April 9, 2026 · View on GitHub
⚛️ js-quantum
A complete, Quantum Computing SDK for TypeScript
Real state-vector simulator · OpenQASM 3.1 transpiler · IBM Quantum & qBraid backends Built from scratch on Web Standards — zero native dependencies.
🎮 Try the interactive simulator in your browser →
Tip
New to quantum computing? Jump straight to the
High-Level API — you pass plain
JavaScript arrays, numbers and functions, pick an English verb (find,
minimize, simulate, …), and get the decoded answer back. No
quantum-computing vocabulary required.
Note
Looking for fine control? The Low-Level API gives you a full OpenQASM 3.1–compatible circuit builder with 80+ gates across 14 tiers, classical control flow, parameter binding, and a custom state-vector simulator.
📚 Table of Contents
| Section | Description |
|---|---|
| 🚀 Installation | Get started in one line |
| ⚡ Quick Start | Your first Bell state |
| 🧱 Core Concepts | Qubits, gates, measurement |
| 🛠️ Building Circuits — Didactic Tour | From superposition to Shor-style building blocks |
| 🔀 Classical Control Flow & Expansion API | if, for, while, switch, assignments |
| 🔬 Simulation & Inspection | State vectors, probabilities, Bloch |
| ☁️ Backends | Simulator · IBM · qBraid · OpenQASM |
| 📖 API Reference | Every public symbol with a short explanation |
| ✨ High-Level API — Didactic Tour | Plain-JS inputs, English verbs, decoded answers |
| 🏗️ Architecture | Internal layering |
| 📜 License | MIT |
🚀 Installation
|
From JSR (recommended)
|
Local development
|
Important
js-quantum is a pure-TypeScript Deno module using only Web Standards. It
runs on Deno, in modern browsers, and is publishable on JSR. No numpy, no
BLAS, no native bindings.
⚡ Quick Start: Your First Bell State
A Bell state is the simplest two-qubit entangled state — think of it as two quantum coins that always land on the same face.
import { QuantumCircuit, SimulatorBackend } from "jsr:@hviana/js-quantum";
// 1️⃣ Build the circuit
const qc = new QuantumCircuit();
qc.h(0) // put qubit 0 into superposition
.cx(0, 1); // entangle qubit 1 with qubit 0
// 2️⃣ Add a classical register to store measurement outcomes
qc.addClassicalRegister("c", 2);
qc.measure(0, { registerName: "c", bitIndex: 0 });
qc.measure(1, { registerName: "c", bitIndex: 1 });
// 3️⃣ Simulate with 1024 shots
const sim = new SimulatorBackend();
const result = sim.execute(sim.transpileAndPackage(qc, 1024));
console.log(result);
// → { "00": ~50, "11": ~50 }
// Never "01" or "10" — the qubits are perfectly correlated. ✨
Tip
Reading results. Every backend returns a plain object mapping bitstrings
→ percentages (summing to 100). The bitstring reads most-significant bit
on the left, so "10" means "classical bit 1 is set, classical bit 0 is
clear".
🧱 Core Concepts
| Concept | In one sentence | In js-quantum |
|---|---|---|
| 🔹 Qubit | The quantum version of a bit — can be 0, 1, or a superposition of both. |
Addressed by an integer index: 0, 1, 2, … |
| 🔸 Gate | A reversible operation that rotates qubits. | qc.h(0), qc.cx(0, 1), qc.rx(θ, 0), … |
| 🧪 Measurement | Collapses a qubit to 0 or 1 and writes it to a classical bit. |
qc.measure(qubit, { registerName, bitIndex }) |
| 💾 Classical register | A named array of classical bits that measurements are written into. | qc.addClassicalRegister("c", n) |
| 🎲 Shots | How many times the circuit is run end-to-end when sampling. | Second argument to transpileAndPackage(qc, shots) |
| 📐 Parameter | A symbolic angle you bind to a number later. | AngleExpr.symbol("θ") → qc.run({ θ: Math.PI/3 }) |
Note
Qubit ordering. For an m-qubit gate, the first qubit argument
corresponds to the most-significant local matrix bit. When comparing
printed bitstrings against Qiskit, remember that Qiskit prints qubit n − 1
on the left — so a state that reads |10⟩ in js-quantum may print as
|01⟩ there. The amplitudes, probabilities, and distributions are
identical; only the string rendering differs.
🛠️ Building Circuits — The Didactic Tour
Each example below is complete and runnable. They progress from "the smallest possible quantum effect" to richer compositions using the Expansion API.
🟢 1 · Single qubit in superposition — the Hello World of quantum
import { QuantumCircuit, SimulatorBackend } from "jsr:@hviana/js-quantum";
const qc = new QuantumCircuit();
qc.h(0); // 50/50 superposition
qc.addClassicalRegister("c", 1);
qc.measure(0, { registerName: "c", bitIndex: 0 });
const sim = new SimulatorBackend();
console.log(sim.execute(sim.transpileAndPackage(qc, 1024)));
// → { "0": ~50, "1": ~50 }
h (Hadamard) is the gate that creates equal superpositions of |0⟩ and
|1⟩.
🟢 2 · GHZ state — three-qubit entanglement
const qc = new QuantumCircuit();
qc.h(0).cx(0, 1).cx(0, 2); // |000⟩ + |111⟩ (unnormalized)
qc.addClassicalRegister("c", 3);
qc.measure(0, { registerName: "c", bitIndex: 0 });
qc.measure(1, { registerName: "c", bitIndex: 1 });
qc.measure(2, { registerName: "c", bitIndex: 2 });
console.log(new SimulatorBackend().execute(sim.transpileAndPackage(qc, 1024)));
// → { "000": ~50, "111": ~50 }
🟡 3 · Parameterized circuit with symbolic binding
import {
AngleExpr,
QuantumCircuit,
SimulatorBackend,
} from "jsr:@hviana/js-quantum";
const theta = AngleExpr.symbol("theta");
const qc = new QuantumCircuit();
qc.rx(theta, 0); // rotation around the X axis
qc.addClassicalRegister("c", 1);
qc.measure(0, { registerName: "c", bitIndex: 0 });
// Bind the symbol to a concrete angle at run time
const bound = qc.run({ theta: Math.PI / 3 });
console.log(new SimulatorBackend().execute(
new SimulatorBackend().transpileAndPackage(bound, 1024),
));
💡 Use
AngleExprwhen you want to build the circuit once and sweep parameters — ideal for variational algorithms.
🟡 4 · Circuit composition, inverses, and reuse
// Build a reusable Bell-preparation block
const bell = new QuantumCircuit();
bell.h(0).cx(0, 1);
const unBell = bell.inverse(); // uncomputation
const qc = new QuantumCircuit();
qc.compose(bell); // prepare
// … do something with the entangled pair …
qc.compose(unBell); // undo (uncompute)
🟠 5 · Gate modifiers: inv · pow · ctrl · negctrl
const qc = new QuantumCircuit();
qc.ctrl(1, "x", [0, 1]); // 1-controlled X (== CX)
qc.inv("s", [0]); // S†
qc.pow(3, "x", [0]); // X³ = X
qc.negctrl(1, "h", [2, 3]); // H on qubit 3, triggered when qubit 2 = 0
🔴 6 · Custom gate definition
const body = new QuantumCircuit();
body.applyGate({ name: "h", qubits: [0] });
body.applyGate({ name: "z", qubits: [0] });
body.applyGate({ name: "h", qubits: [0] });
const qc = new QuantumCircuit();
qc.defineGate("hzh", /* params */ [], /* qubit args */ ["q"], body);
// "hzh" is now callable by name like any built-in gate.
🔴 7 · QFT and a modular adder
// Quantum Fourier Transform on three qubits
const qft = new QuantumCircuit();
qft.qft([0, 1, 2]);
// Modular adder: set a=1, b=2, then add in place
const add = new QuantumCircuit();
add.x(0); // a[0] = 1
add.x(3); // b[1] = 1
add.modularAdder([0, 1], [2, 3]); // b ← (a + b) mod 4
🔀 Classical Control Flow — The Expansion API
This is the single most powerful — and at first glance, most intimidating — part
of js-quantum. It lets a running circuit branch, loop, and update classical
variables based on mid-circuit measurements, exactly like OpenQASM 3.1.
Methods like ifTest, forLoop, whileLoop, and switch do not take
plain JavaScript conditions. They take tagged-union IR nodes — small plain
objects with a kind field that describes an OpenQASM-level classical
expression.
Tip
You have two equivalent options for building these nodes:
- Write the object literal by hand — explicit, verbose, copy-paste friendly.
- Use the
Exprfactory from"jsr:@hviana/js-quantum"— short, typed, recommended for anything non-trivial.
Both produce identical output.
🧩 The four expression literals you will see most
// Integer literal Identifier (variable reference)
{ kind: "int-literal", value: 0 } { kind: "identifier", name: "c" }
// Boolean literal Binary operator
{ kind: "bool-literal", value: true } { kind: "binary", op: "==",
left: { kind: "identifier", name: "c" },
right: { kind: "int-literal", value: 1 } }
// Range (used by `for`) Bitstring literal
{ kind: "range",
start: { kind: "int-literal", value: 0 },
end: { kind: "int-literal", value: 3 } } { kind: "bitstring-literal", value: "1010" }
The same tree written using Expr:
import { Expr } from "jsr:@hviana/js-quantum";
Expr.int(0); // int literal
Expr.ref("c"); // identifier
Expr.bool(true); // bool literal
Expr.binary("==", Expr.ref("c"), Expr.int(1)); // c == 1
Expr.range(Expr.int(0), undefined, Expr.int(3)); // 0..3
Expr.bitstring("1010"); // "1010"
Example 1 — 🔁 ifTest: quantum error correction via feedback
Perform a correction gate on a target qubit only if a measurement of the
control qubit returned 1.
import { Expr, QuantumCircuit, SimulatorBackend } from "jsr:@hviana/js-quantum";
const qc = new QuantumCircuit();
qc.addClassicalRegister("c", 1);
// Prepare + measure qubit 0 into classical bit c[0]
qc.h(0);
qc.measure(0, { registerName: "c", bitIndex: 0 });
// The conditional body lives in its own sub-circuit
const correction = new QuantumCircuit();
correction.x(1); // flip qubit 1
// if (c == 1) { x(1); }
qc.ifTest(
Expr.binary("==", Expr.ref("c"), Expr.int(1)),
correction,
);
The exact same thing, written without the Expr helper — functionally
identical:
qc.ifTest(
{
kind: "binary",
op: "==",
left: { kind: "identifier", name: "c" },
right: { kind: "int-literal", value: 1 },
},
correction,
);
Example 2 — 🔁 ifTest with else branch
const ifTrue = new QuantumCircuit();
ifTrue.x(1);
const ifFalse = new QuantumCircuit();
ifFalse.z(1);
qc.ifTest(
Expr.binary("!=", Expr.ref("c"), Expr.int(0)), // c != 0
ifTrue,
ifFalse,
);
Example 3 — 🔁 Comparing a register against a bitstring
qc.ifTest(
Expr.binary("==", Expr.ref("c"), Expr.bitstring("101")),
correction,
);
Example 4 — 🔄 forLoop: repeated Trotter layers
Apply the same entangling layer three times — useful for Trotterized Hamiltonian evolution, QAOA layers, and variational ansätze.
const layer = new QuantumCircuit();
layer.h(0);
layer.cx(0, 1);
layer.rz(0.3, 1);
const qc = new QuantumCircuit();
qc.forLoop(
"i", // loop variable name
Expr.range(Expr.int(0), undefined, Expr.int(3)), // for i in 0..3
layer, // body
);
Raw equivalent:
qc.forLoop("i", {
kind: "range",
start: { kind: "int-literal", value: 0 },
end: { kind: "int-literal", value: 3 },
}, layer);
Example 5 — 🔄 forLoop over an explicit set of indices
qc.forLoop(
"j",
Expr.set([Expr.int(0), Expr.int(2), Expr.int(4)]), // for j in {0, 2, 4}
layer,
);
Example 6 — ♾️ whileLoop: repeat until success
A classic "repeat-until-success" pattern used in magic state distillation: keep
running a Heralded procedure while a classical flag ok is still 0.
const qc = new QuantumCircuit();
qc.addClassicalRegister("ok", 1);
const attempt = new QuantumCircuit();
attempt.h(0);
attempt.measure(0, { registerName: "ok", bitIndex: 0 });
// while (ok == 0) { attempt(); }
qc.whileLoop(
Expr.binary("==", Expr.ref("ok"), Expr.int(0)),
attempt,
);
Example 7 — 🎛️ switch: dispatch on a syndrome
A three-qubit code measures a 2-bit syndrome and applies a different correction for each possible value.
const corr00 = new QuantumCircuit(); /* no correction */
const corr01 = new QuantumCircuit();
corr01.x(0);
const corr10 = new QuantumCircuit();
corr10.x(1);
const corr11 = new QuantumCircuit();
corr11.x(2);
qc.switch(
Expr.ref("syndrome"), // subject
[
{ values: [Expr.int(0)], body: corr00 }, // case 0
{ values: [Expr.int(1)], body: corr01 }, // case 1
{ values: [Expr.int(2)], body: corr10 }, // case 2
{ values: [Expr.int(3)], body: corr11 }, // case 3
],
);
Note that each values entry is an array — a single case can cover multiple
values, exactly like OpenQASM 3.1.
Example 8 — 🔢 Classical assignment and arithmetic
Declare a classical integer, initialize it, and mutate it inside a loop.
import { Expr, QuantumCircuit } from "jsr:@hviana/js-quantum";
const qc = new QuantumCircuit();
// int counter = 0;
qc.declareClassicalVar("counter", { kind: "int", width: 32 }, Expr.int(0));
const body = new QuantumCircuit();
// counter += 1;
body.classicalAssignOp(Expr.ref("counter"), "+=", Expr.int(1));
qc.forLoop("i", Expr.range(Expr.int(0), undefined, Expr.int(10)), body);
Example 9 — 🧮 Nested: for inside if
A classical-conditional warm-up followed by a repeated entangling layer:
const innerLoop = new QuantumCircuit();
innerLoop.forLoop(
"k",
Expr.range(Expr.int(0), undefined, Expr.int(5)),
layer,
);
qc.ifTest(
Expr.binary(">", Expr.ref("counter"), Expr.int(0)), // counter > 0
innerLoop,
);
Example 10 — 🧠 Complex boolean expressions
// (c == 1) && (counter < 5)
const cond = Expr.binary(
"&&",
Expr.binary("==", Expr.ref("c"), Expr.int(1)),
Expr.binary("<", Expr.ref("counter"), Expr.int(5)),
);
qc.ifTest(cond, correction);
Tip
Mental model. Anywhere you'd write a classical expression in OpenQASM 3.1
— whether it's a condition, a loop bound, a switch subject, an assignment
target, or a function argument — you're building a tree of these small
{ kind: "..." } nodes. The leaves are literals (int-literal,
float-literal, bool-literal, bitstring-literal, identifier) and the
interior nodes are operators (unary, binary, range, call, cast, …).
The Expr factory just makes the trees shorter to write.
🔬 Simulation & Inspection
Exact state vector (unitary-only circuits)
import { QuantumCircuit, SimulatorBackend } from "jsr:@hviana/js-quantum";
const qc = new QuantumCircuit();
qc.h(0).cx(0, 1);
const state = new SimulatorBackend().getStateVector(qc);
// state[0] = 1/√2, state[3] = 1/√2 → the Bell state (|00⟩ + |11⟩)/√2
Sampling the measurement distribution
const sim = new SimulatorBackend();
const hist = sim.execute(sim.transpileAndPackage(qc, 4096));
// → { "00": ~50, "11": ~50 } bitstrings → percentages
Bloch sphere visualization
import { blochOfCircuit } from "jsr:@hviana/js-quantum";
const qc = new QuantumCircuit();
qc.h(0);
console.log(blochOfCircuit(qc, 0));
// → { x: 1, y: 0, z: 0, theta: π/2, phi: 0, r: 1 }
☁️ Backends — Simulator, IBM, qBraid, OpenQASM
Every backend implements the same tiny interface:
transpileAndPackage(circuit, shots?) → execute(...) → ExecutionResult (a
Record<string, number> of bitstring → percentage).
🖥️ SimulatorBackend — local, noiseless, fast
const sim = new SimulatorBackend({ defaultShots: 2048 });
const result = sim.execute(sim.transpileAndPackage(qc));
Uses subspace iteration — never materializes the full 2ⁿ × 2ⁿ matrix.
🛰️ IBMBackend — IBM Quantum hardware via Sampler V2
import { IBMBackend } from "jsr:@hviana/js-quantum";
const ibm = new IBMBackend({
name: "ibm_brisbane",
numQubits: 127,
basisGates: ["id", "rz", "sx", "x", "ecr"],
couplingMap: null, // or the device's coupling map
serviceCrn: Deno.env.get("IBM_SERVICE_CRN")!,
apiVersion: "2025-01-01",
apiKey: Deno.env.get("IBM_API_KEY")!, // or { bearerToken }
});
const packaged = ibm.transpileAndPackage(qc, 4096);
const result = await ibm.execute(packaged);
🌐 QBraidBackend — qBraid cloud via v2 API
import { QBraidBackend } from "jsr:@hviana/js-quantum";
const qbraid = new QBraidBackend({
name: "qbraid_sim",
numQubits: 5,
basisGates: ["h", "cx", "rz", "sx"],
couplingMap: null,
deviceQrn: Deno.env.get("QBRAID_DEVICE_QRN")!,
apiKey: Deno.env.get("QBRAID_API_KEY")!,
apiEndpoint: "https://api.qbraid.com/v2",
corsProxy: undefined,
});
const result = await qbraid.execute(qbraid.transpileAndPackage(qc));
📄 OpenQASMTranspiler — round-trip to/from OpenQASM 3.1
import { OpenQASMTranspiler } from "jsr:@hviana/js-quantum";
const T = new OpenQASMTranspiler();
const qasmText = T.serialize(qc); // → string
const reparsed = T.deserialize(qasmText); // → QuantumCircuit
🧮 Hardware-aware transpilation pipeline
import { transpile } from "jsr:@hviana/js-quantum";
const compiled = transpile(qc, {
numQubits: 5,
basisGates: ["ecr", "id", "rz", "sx", "x"],
couplingMap: [[0, 1], [1, 2], [2, 3], [3, 4]],
});
Includes KAK and ZYZ decomposition, gate-modifier expansion, composite unrolling, SABRE layout & routing, basis translation, and peephole optimization.
📖 API Reference
All methods on QuantumCircuit return this for chaining.
🏗️ QuantumCircuit — the central builder
new QuantumCircuit(globalPhase?: number | AngleExpr)
Program metadata
| Method | Purpose |
|---|---|
setProgramVersion(major, minor?) | Set the emitted OpenQASM version header. |
omitProgramVersion() | Suppress the version header entirely. |
include(path) | Emit an include "path"; directive. |
setCalibrationGrammar(name) | Emit defcalgrammar "name"; (e.g. "openpulse"). |
Classical registers
| Method | Purpose |
|---|---|
addClassicalRegister(name, size) | Declare a named bit[size] register for measurement results. |
getClassicalRegister(name) | Look up a declared register by name. |
🎛️ Tier 0 — single-qubit primitives (hardcoded matrices)
| Gate | Method | Meaning |
|---|---|---|
I | qc.id(q) | Identity |
H | qc.h(q) | Hadamard — creates equal superposition |
X Y Z | qc.x/y/z(q) | Pauli bit-flip / bit+phase / phase flip |
S/S† | qc.s/sdg(q) | π/2 phase rotations |
T/T† | qc.t/tdg(q) | π/4 phase rotations |
SX/SX† | qc.sx/sxdg(q) | Square root of X |
P(λ) | qc.p(λ, q) | Arbitrary phase |
R(θ,φ) | qc.r(θ, φ, q) | Rotation in the X–Y plane |
RX/RY/RZ(θ) | qc.rx/ry/rz(θ, q) | Axis rotations |
U(θ,φ,λ) | qc.u(θ, φ, λ, q) | Universal single-qubit |
RV(vx,vy,vz) | qc.rv(vx, vy, vz, q) | Rotation-vector form |
GPhase(θ) | qc.globalPhaseGate(θ) | Zero-qubit global phase |
🎛️ Tier 1 — the seed two-qubit gate
| Gate | Method |
|---|---|
CX | qc.cx(control, target) — the only hardcoded multi-qubit matrix |
🎛️ Tiers 2–14 — compositionally derived from Tier 0 + CX
Tier 2 · Controlled single-qubit gates
qc.cz(c, t) qc.cy(c, t) qc.ch(c, t)
qc.cp(λ, c, t) qc.crx(θ, c, t) qc.cry(θ, c, t) qc.crz(θ, c, t)
qc.cs(c, t) qc.csdg(c, t) qc.csx(c, t)
qc.cu(θ, φ, λ, γ, c, t)
qc.dcx(q0, q1)
Tier 3 · Two-qubit interactions
qc.swap(q0, q1) qc.iswap(q0, q1) qc.ecr(q0, q1)
qc.rxx(θ, q0, q1) qc.ryy(θ, q0, q1) qc.rzz(θ, q0, q1) qc.rzx(θ, q0, q1)
qc.xxPlusYY(θ, β, q0, q1) qc.xxMinusYY(θ, β, q0, q1)
Tier 4 · Three-qubit gates
qc.ccx(c1, c2, t); // Toffoli
qc.ccz(c1, c2, t);
qc.cswap(c, t1, t2); // Fredkin
qc.rccx(c1, c2, t); // relative-phase Toffoli
Tier 5 · Multi-controlled, phase-safe
qc.c3x(...) qc.c3sx(...) qc.c4x(...) qc.rc3x(...)
qc.mcx(controls, target) // MCX via H · MCPhase(π) · H
qc.mcp(λ, controls, target) // multi-controlled phase
Tier 6 · N-qubit composites
qc.ms(θ, qubits); // Mølmer–Sørensen
qc.pauli(pauliString, qubits); // e.g. "XYZI"
qc.diagonal(phases, qubits);
qc.permutation(sigma, qubits);
qc.mcmt(gate, controls, targets); // multi-control multi-target
qc.pauliProductRotation(θ, paulis, qubits);
Tier 7 · Uniformly controlled + unitary synthesis
qc.ucrx(angles, controls, target) qc.ucry(angles, controls, target) qc.ucrz(angles, controls, target)
qc.ucPauliRot(angles, axis, controls, target)
qc.uc(unitaries, controls, target) // Möttönen 4-layer UCGate
qc.unitary(matrix, qubits) // arbitrary 2ⁿ×2ⁿ unitary
qc.linearFunction(matrix, qubits) // GF(2) linear map
qc.isometry(matrix, qubits)
Tier 8 · Hamiltonian simulation
qc.pauliEvolution(terms, time, qubits); // Trotterized e^{-iHt}
qc.hamiltonianGate(matrix, time, qubits); // exact via Jacobi eigendecomposition
Tier 9 · Quantum Fourier Transform
qc.qft(qubits); // exact QFT (or its inverse via inv)
Tier 10 · Reversible classical logic
qc.andGate(inputs, output) qc.orGate(inputs, output)
qc.bitwiseXor(a, b) qc.innerProduct(a, b, output)
Tier 11 · Arithmetic
qc.halfAdder(a, b, sum, carry);
qc.fullAdder(a, b, cIn, sum, cOut);
qc.modularAdder(a, b);
qc.multiplier(a, b, product);
Tier 12 · Function loading (amplitude encoding of f(x))
qc.linearPauliRotations(slope, offset, stateQubits, target, axis?)
qc.polynomialPauliRotations(coeffs, stateQubits, target, axis?)
qc.piecewiseLinearPauliRotations(breakpoints, slopes, offsets, stateQubits, target, axis?)
qc.piecewisePolynomialPauliRotations(breakpoints, coeffsList, stateQubits, target, axis?)
qc.piecewiseChebyshev(fSamples, breakpoints, stateQubits, target, axis?)
qc.linearAmplitudeFunction(slope, offset, domain, image, stateQubits, target)
qc.exactReciprocal(scalingFactor, stateQubits, target)
Tier 13 · Oracles, comparators, aggregation
qc.integerComparator(value, stateQubits, result, work, geq?)
qc.quadraticForm(A, b, c, stateQubits, resultQubits)
qc.weightedSum(weights, stateQubits, sumQubits)
qc.phaseOracle(esop, qubits) // phase-flip oracle
qc.bitFlipOracle(esop, qubits, output)
Tier 14 · State preparation
qc.graphState(adjacencyMatrix, qubits);
Non-unitary operations
| Method | Purpose |
|---|---|
qc.measure(qubit, clbit?) | Measure one qubit into a classical bit. |
qc.measureRegister(qubits, clbitRefs) | Measure many qubits at once. |
qc.reset(qubit) | Reset a qubit to ` |
qc.barrier(...qubits) | Compiler barrier — forbids reordering across it. |
qc.delay(duration, qubits?) | Idle for a duration (scheduling). |
qc.timed(operation, duration) | Bound a sub-operation's duration. |
Gate modifiers & low-level application
| Method | Purpose |
|---|---|
qc.inv(name, qubits, params?) | Apply a gate's inverse by name. |
qc.pow(k, name, qubits, params?) | Apply a gate raised to integer or symbolic power k. |
qc.ctrl(n, name, qubits, params?) | Add n positive controls on the front. |
qc.negctrl(n, name, qubits, params?) | Add n negative (zero-valued) controls. |
qc.applyGate({ name, qubits, parameters?, modifiers?, localPhase?, surfaceName? }) | Low-level escape hatch. |
Definitions & declarations
| Method | Purpose |
|---|---|
qc.defineGate(name, params, qubits, body) | Define a user-level gate. |
qc.defineSubroutine(name, params, returnType, body) | Define a classical/quantum subroutine. |
qc.declareExtern(name, params, returnType) | Declare an externally-provided callable. |
qc.declareClassicalVar(name, type, init?) | Declare a classical variable. |
qc.declareConst(name, type, value) | Compile-time constant. |
qc.declareInput(name, type, default?) | Runtime input parameter. |
qc.declareOutput(name, type, init?) | Runtime output variable. |
qc.alias(name, target) | let name = target; alias. |
qc.declareLegacyQReg(name, size) / declareLegacyCReg(name, size) | OpenQASM 2 compatibility. |
Classical statements & control flow
| Method | Purpose |
|---|---|
qc.classicalAssign(target, value) | target = value; |
qc.classicalAssignOp(target, op, value) | Compound assignment (+=, -=, *=, <<=, …) |
qc.exprStatement(expr) | Bare expression statement. |
qc.returnValue(v) / qc.returnVoid() | Subroutine returns. |
qc.ifTest(condition, trueBody, falseBody?) | Classical conditional — see Expansion API. |
qc.forLoop(loopVar, iterable, body) | for loopVar in iterable { body } |
qc.whileLoop(condition, body) | while (condition) { body } |
qc.switch(subject, cases, defaultBody?) | switch (subject) { case … } |
qc.breakLoop() / qc.continueLoop() / qc.end() | Loop / program control. |
qc.box(body, duration?) | Timed box[d] { … } scope. |
Composition & inspection
| Method | Purpose |
|---|---|
qc.compose(other, qubitMap?) | Append another circuit (optionally remapping qubits). |
qc.toGate(label?) / qc.toInstruction(label?) | Convert a sub-circuit into a reusable opaque gate/instruction. |
qc.clone() | Deep copy. |
qc.inverse() | Dagger (reverse + inv each gate). |
qc.run(bindings) | Return a copy with all AngleExpr symbols bound to concrete values. |
qc.complexity() | Gate-count summary (depth, width, per-tier counts). |
qc.toMatrix() | Build the full unitary (warning: O(2^{2n}) memory). |
qc.append(instruction) | Append a raw Instruction IR node. |
📐 AngleExpr — symbolic angles & parameters
Exact-rational-normalized symbolic angle system. Use it for parameterized circuits, VQE ansätze, and any sweep.
AngleExpr.int(n) // integer literal
AngleExpr.float(x) // floating-point literal
AngleExpr.rational(num, den) // exact p/q
AngleExpr.symbol("theta") // unresolved symbol — bind later via qc.run({ theta: … })
AngleExpr.PI AngleExpr.TAU AngleExpr.EULER // built-in constants
a.plus(b) a.minus(b) a.times(b) a.dividedBy(b) a.negated()
a.bind({ x: 0.5 }) a.isResolved() a.evaluate()
// Exact proof helpers (for compiler passes)
provablyZero(e) provablyTwoPiMultiple(e) provablyInteger(e)
asExactInteger(e) provablyEqual(a, b) wrapPhase(angle, eps?)
🔌 Backend — the uniform execution interface
interface Backend {
name: string;
numQubits: number;
basisGates: readonly string[];
couplingMap: ReadonlyArray<readonly [number, number]> | null;
transpileAndPackage(circuit, shots?): Executable;
execute(executable, shots?): ExecutionResult | Promise<ExecutionResult>;
}
type ExecutionResult = Record<string, number>; // bitstring → percentage (sums to 100)
Every backend — including any you write yourself — just has to implement this shape.
🖥️ SimulatorBackend
Noiseless local state-vector simulator. Never builds the full 2ⁿ × 2ⁿ matrix.
new SimulatorBackend({ numQubits?: number, defaultShots?: number })
sim.transpileAndPackage(circuit, shots?) // compile for local execution
sim.execute(executable, shots?) // sample bitstrings
sim.getStateVector(circuit) // exact amplitudes (unitary-only)
☁️ IBMBackend
Submits circuits to IBM Quantum via the Sampler V2 REST API.
new IBMBackend({
name, numQubits, basisGates, couplingMap,
serviceCrn, apiVersion,
bearerToken | apiKey, // either one
apiEndpoint?, corsProxy?,
})
☁️ QBraidBackend
Submits circuits to qBraid via the v2 API.
new QBraidBackend({
name,
numQubits,
basisGates,
couplingMap,
deviceQrn,
apiKey,
apiEndpoint,
corsProxy,
});
📄 OpenQASMTranspiler
Round-trip serialization of QuantumCircuit ↔ OpenQASM 3.1 source text.
const T = new OpenQASMTranspiler();
T.serialize(circuit); // QuantumCircuit → string
T.deserialize(text); // string → QuantumCircuit
🧮 Compilation pipeline (individual passes)
import {
decomposeKAK, // 2-qubit KAK decomposition
decomposeToRzSx, // lower to {Rz, Sx, X} basis
decomposeZYZ, // 1-qubit ZYZ decomposition
expandGateModifiers, // flatten inv/pow/ctrl/negctrl
layoutSABRE, // virtual → physical layout
optimize, // peephole + commutation
routeSABRE, // insert SWAPs for coupling
translateToBasis, // rewrite into target basis
transpile, // end-to-end driver
unrollComposites, // inline defined gates
} from "jsr:@hviana/js-quantum";
🌐 Bloch sphere
import { blochFromStateVector, blochOfCircuit } from "jsr:@hviana/js-quantum";
const { x, y, z, theta, phi, r } = blochOfCircuit(circuit, qubitIndex);
Reduces the full state to a single-qubit density matrix and returns its Bloch-sphere coordinates — perfect for visualization.
🧰 Expr · Op · Dur · State — expansion API factories
Tiny helper modules that build Expansion-API IR nodes with short, typed function calls instead of object literals. See Classical Control Flow for the full tour.
Expr.int(0) Expr.ref("c") Expr.binary("==", Expr.ref("c"), Expr.int(1))
Expr.range(Expr.int(0), undefined, Expr.int(3))
Op.virtual(0) Op.indexed(Op.identifier("q"), [Expr.int(2)])
Dur.literal(100, "ns")
State.bitstring("0101")
✨ High-Level API — The Didactic Tour
The High-Level API (hlapi) wraps js-quantum in a single chainable
pipeline built around one entry point — quantum() — that returns a
QuantumTask. You supply classical data (numbers, arrays, matrices,
callables, graphs) through .data() or one of its shorthands (.search_in(),
.matrix(), .vector(), .cost_function(), .graph(), .function(),
.training_data(), .system()), optionally pick a strategy via .solve(), and
call .run() to receive a ResultHandle. The .answer() method returns the
classical result you actually care about: the found item, the solution
vector, the optimal assignment, the list of prime factors. No qubits, gates,
oracles, Hamiltonians, or bitstrings ever appear in the user-facing code.
Advanced users can reach full control through optional parameters on the same
calls (explicit step sequences for .solve(), backend overrides on .run(),
direct quantum-native input via .input(), .oracle(), .hamiltonian(), ...).
.circuit() extracts the host-library QuantumCircuit for use with external
tools.
import { quantum } from "jsr:@hviana/js-quantum";
💡 Reading the examples. Every example below is framed around a practical use case — a problem where the underlying quantum algorithm has genuine structural value (verify-easy / search-hard, NP-hard cost landscapes, real physical Hamiltonians, real engineering linear systems). Instance sizes are kept small for simulator tractability, but the shape of each problem is one a real practitioner would recognise. A short Under the hood note after each snippet names the algorithms and flags where the simulator falls back to a classical computation.
🔐 A. Breaking an RSA-style semiprime
🎯 Use case: recover the two prime factors of a semiprime modulus — the textbook Shor target and the reason quantum computing matters for cryptography.
| Classical in | Classical out |
|---|---|
target: 15 (the modulus) | [3, 5] (the factors) |
const result = await quantum("factoring")
.data("target", 15)
.run();
console.log(result.answer()); // → [3, 5]
🔬 Under the hood. Shor's algorithm: quantum order-finding via QFT + continued-fraction post-processing. On the default simulator the bridge falls back to classical trial division; the exponential speedup is realised only on real hardware with a modular-exponentiation oracle.
🧾 B. Reconciling a subset of invoices
🎯 Use case: given a list of invoice amounts and a target total, find a subset that reconciles exactly. Subset-sum is NP-hard: verifying a candidate is O(n) but searching is exponential — the canonical regime for amplitude amplification.
| Classical in | Classical out |
|---|---|
invoices: [7, 13, 11, 8, 3, 14, 5], target: 42 | a reconciling subset, e.g. [13, 11, 8, 3, 7] |
const invoices = [7, 13, 11, 8, 3, 14, 5];
const target = 42;
// Search space: every subset encoded as a bitmask ($2^{7}$ = 128 candidates).
const candidates = Array.from({ length: 1 << invoices.length }, (_, m) => m);
const reconciles = (mask: unknown) => {
let sum = 0;
for (let i = 0; i < invoices.length; i++) {
if (((mask as number) >> i) & 1) sum += invoices[i];
}
return sum === target;
};
const result = await quantum("search")
.search_in(candidates, reconciles)
.run();
const mask = result.answer() as number;
const subset = invoices.filter((_, i) => (mask >> i) & 1);
console.log(subset); // → e.g. [13, 11, 8, 3, 7]
🔬 Under the hood. Grover's algorithm / amplitude amplification. The bridge builds a phase oracle from the predicate and runs the optimal number of Grover iterations. On a classical simulator the predicate is evaluated across the candidate space to mark the oracle — the √N speedup is structural and is realised only on real hardware, where the predicate becomes a reversible oracle circuit.
🕸️ C. Locating a fault on a mesh network
🎯 Use case: a 3×3 mesh of routers has started dropping packets on exactly one device. Probing every router sequentially is O(N); a quantum walk on the topology locates the faulty node in O(√N) by exploiting the graph structure rather than any per-node label.
// Build a 3×3 mesh adjacency (9 routers, cardinal neighbours).
const n = 3;
const nodes = Array.from({ length: n * n }, (_, i) => i);
const adjacency: number[][] = nodes.map(() => nodes.map(() => 0));
for (let r = 0; r < n; r++) {
for (let c = 0; c < n; c++) {
const i = r * n + c;
if (r + 1 < n) {
adjacency[i][(r + 1) * n + c] = adjacency[(r + 1) * n + c][i] = 1;
}
if (c + 1 < n) {
adjacency[i][r * n + (c + 1)] = adjacency[r * n + (c + 1)][i] = 1;
}
}
}
// One router has a degraded health counter (SNMP-style probe).
const isFaulty = (node: unknown) => (node as number) === 5;
const result = await quantum("search")
.graph(adjacency)
.search_in(nodes, isFaulty)
.run();
console.log("faulty router:", result.answer()); // → 5
🔬 Under the hood. Szegedy / continuous-time quantum walk for spatial search. The walk operator is marked by the predicate and mixes along the graph structure; on real hardware the √N advantage is structural.
⚛️ D. Simulating a transverse-field Ising chain
🎯 Use case: evolve a small magnetic spin chain under a transverse-field Ising Hamiltonian and read back the measurement distribution — a standard benchmark Hamiltonian from condensed-matter physics.
// 2-qubit transverse-field Ising Hamiltonian.
const H = [
[1, 1, 1, 0],
[1, -1, 0, 1],
[1, 0, -1, 1],
[0, 1, 1, 1],
];
const result = await quantum("simulation")
.system(H)
.run();
console.log(result.answer()); // → distribution over basis states
🔬 Under the hood. Trotter-Suzuki product formulas, LCU, and interaction-picture simulation. Exponential speedups over classical simulation are expected for physically-motivated Hamiltonians with many spins; this 2-qubit instance is just for the API shape.
⚡ E. Loop currents in a DC resistor mesh
🎯 Use case: a three-mesh DC circuit driven by a 10 V source. Kirchhoff's voltage law around each independent loop yields a 3×3 linear system whose solution is the loop currents
I₁, I₂, I₃. The same shape scales to thousands of meshes in power-grid analysis — the target regime for HHL-class solvers on sparse, well-conditioned systems.
// (R1 + R2) I1 − R2 I2 = V
// − R2 I1 + (R2 + R3 + R4) I2 − R4 I3 = 0
// − R4 I2 + (R4 + R5) I3 = 0
// R1=2, R2=4, R3=6, R4=3, R5=5 Ω; V=10 V
const A = [
[6, -4, 0],
[-4, 13, -3],
[0, -3, 8],
];
const b = [10, 0, 0];
const result = await quantum("linear_system")
.matrix(A)
.vector(b)
.run();
console.log(result.answer()); // → loop currents [I1, I2, I3]
🔬 Under the hood. HHL / QSVT-based linear algebra. On the default simulator the bridge falls back to Gaussian elimination; the exponential advantage applies to sparse, well-conditioned, block-encoded systems on real hardware.
🧩 F. Combinatorial optimisation — Max-Cut
🎯 Use case: partition the nodes of a graph into two groups so that the number of edges crossing the partition is maximised. Max-Cut is NP-hard and appears in load balancing, VLSI layout, and statistical physics.
const edges: [number, number][] = [
[0, 1],
[1, 2],
[2, 3],
[3, 4],
[4, 0],
[0, 2],
];
const cost = (bits: number[]) => {
let cut = 0;
for (const [i, j] of edges) if (bits[i] !== bits[j]) cut++;
return -cut; // minimisation ↔ maximum cut
};
const result = await quantum("optimization")
.cost_function(cost, { metadata: { numBits: 5 } })
.run();
console.log(result.answer()); // → { assignment: [...], cost: -5 }
🔬 Under the hood. QAOA, VQE, and adiabatic optimisation. The cost function is encoded as a problem Hamiltonian; variational angles are optimised in a classical loop.
🎲 G. Sampling from a classically hard distribution
🎯 Use case: draw bitstring samples from a distribution that is
#P-hard to simulate classically — the benchmark used for quantum supremacy / advantage claims and a candidate source of certified randomness.
const result = await quantum("sampling")
.data("custom", null, { metadata: { n: 4 } })
.run();
console.log(result.answer()); // → ["0000", "0101", ...]
🔬 Under the hood. IQP sampling on the gate-model simulator produces a uniform distribution over the specified number of qubits.
🌸 H. Classification with a quantum kernel
🎯 Use case: classify iris flowers by two numeric features (petal length and width) using a quantum kernel. Quantum kernels embed data into a high-dimensional Hilbert space that can be provably hard to evaluate classically.
const training = [
{ features: [1.4, 0.2], label: "setosa" },
{ features: [1.3, 0.2], label: "setosa" },
{ features: [4.7, 1.4], label: "versicolor" },
{ features: [4.5, 1.5], label: "versicolor" },
];
const result = await quantum("classification")
.training_data(training)
.data("custom", [4.6, 1.4])
.run();
console.log(result.answer()); // → ["versicolor"]
🔬 Under the hood. Quantum kernel estimation / variational quantum classifier. The simulator computes the kernel matrix classically; the potential speedup is in the feature-map evaluation on real hardware.
🛡️ I. Error correction on encoded data
🎯 Use case: recover a logical bit from an encoded representation — the basic building block of fault-tolerant quantum computing (and, by analogy, of classical ECC on storage media).
const encoded = [1, 1, 0, 1, 1]; // intended logical 1 with a single flip
const result = await quantum("error_correction")
.data("system", encoded)
.run();
console.log(result.answer()); // → corrected logical bit
🔬 Under the hood. Surface-code encoding, stabiliser measurements, and MWPM-style syndrome decoding. Full stabiliser simulation is out of scope for the default backend; the bridge currently returns a fallback.
📡 J. Heisenberg-limited phase estimation
🎯 Use case: estimate a weak unknown phase (e.g., from an NV-centre magnetometer or an interferometer) with Heisenberg-limited precision — a quadratic improvement over the standard quantum limit, used in atomic clocks, gravimetry, and magnetic sensing.
const unknownPhase = 0.3183; // ≈ 1/π — pretend it is unknown
const signal = (_x: number) => unknownPhase;
const result = await quantum("phase_estimation")
.function(signal)
.run();
console.log(result.answer()); // → { phase: 0.3183, confidence: 0.95 }
🔬 Under the hood. Quantum phase estimation, GHZ-state sensing, and Heisenberg-limited estimation. The 1/N scaling in the number of probes beats the 1/√N shot-noise limit on real hardware.
🎛️ Advanced control — all knobs exposed
Everything above uses defaults. When you do need control, the API accepts options at three levels: problem construction, solve, and run. The examples below exercise every configurable knob.
1. Problem form, resource limits, algorithm family, and shots
import { quantum } from "jsr:@hviana/js-quantum";
const invoices = [7, 13, 11, 8, 3, 14, 5];
const target = 42;
const candidates = Array.from({ length: 1 << invoices.length }, (_, m) => m);
const reconciles = (mask: unknown): boolean => {
let sum = 0;
for (let i = 0; i < invoices.length; i++) {
if (((mask as number) >> i) & 1) sum += invoices[i];
}
return sum === target;
};
const result = await quantum(
// Object form — explicitly set problem_class and task
// (instead of the shorthand string "search").
{ problem_class: "amplitude_amplification", task: "search" },
// Resource limits — .run() throws if the circuit exceeds these caps.
{ resources: { maxDepth: 500, maxGates: 2000 } },
)
.search_in(candidates, reconciles)
// Explicit algorithm family (default is inferred from the task).
.solve("amplitude_amplification")
// shots: number of measurement repetitions (default 1024).
.run({ shots: 4096 });
console.log(result.answer()); // → reconciling mask
console.log(result.confidence()); // → [0, 1]
console.log(result.inspect("resources")); // → { gates, depth, tCount, qubits }
2. Task-specific metadata
Some tasks read metadata fields from .data() / .system() /
.cost_function():
import { quantum } from "jsr:@hviana/js-quantum";
// Hamiltonian simulation: metadata.time and metadata.steps control
// the evolution time and Trotter decomposition steps.
const H = [
[1, 1, 1, 0],
[1, -1, 0, 1],
[1, 0, -1, 1],
[0, 1, 1, 1],
];
const result = await quantum("simulation")
.system(H, { metadata: { time: 2.0, steps: 4 } })
.run();
console.log(result.answer()); // → distribution of basis states
Other metadata consumed by the bridge:
| Task | Method | Metadata field | Default | Effect |
|---|---|---|---|---|
simulation | .system(H, opts) | time | 1.0 | Evolution time for exp(−iHt) |
simulation | .system(H, opts) | steps | 1 | Trotter decomposition steps |
optimize | .cost_function() | numBits / n | 6 | Number of qubits for QAOA |
period_finding | .function() | maxN | 128 | Upper bound on the search range |
3. Pipeline step overrides
Override specific steps in a preset pipeline without rewriting the whole thing:
import { quantum } from "jsr:@hviana/js-quantum";
const edges: [number, number][] = [[0, 1], [1, 2], [2, 3], [3, 0], [0, 2]];
const cost = (bits: number[]): number => {
let cut = 0;
for (const [i, j] of edges) if (bits[i] !== bits[j]) cut++;
return -cut;
};
const result = await quantum("optimization")
.cost_function(cost, { metadata: { numBits: 4 } })
// Use the "variational" preset, but override the measure step
// to repeat 3 times.
.solve("variational", {
override: [{ action: "measure", repeat: 3, params: {} }],
})
.run({ shots: 2048 });
console.log(result.answer()); // → { assignment: [...], cost: -4 }
4. Fully custom pipeline
Replace the preset entirely with your own step sequence:
import { quantum } from "jsr:@hviana/js-quantum";
const result = await quantum({
problem_class: "hidden_subgroup",
task: "search",
})
.search_in([0, 1, 2, 3, 4, 5, 6, 7], (x: unknown) => x === 5)
.solve([
{ action: "prepare", input: "initial_state", repeat: 1, params: {} },
{ action: "apply", input: "oracle", repeat: 2, params: {} },
{ action: "apply", input: "diffuser", repeat: 2, params: {} },
{ action: "measure", repeat: 1, params: {} },
])
.run({ shots: 1024 });
console.log(result.answer()); // → 5
5. Real hardware backend
import { IBMBackend, quantum } from "jsr:@hviana/js-quantum";
const ibm = new IBMBackend({
apiConfig: { bearerToken: "TOKEN", serviceCrn: "CRN" },
backendName: "ibm_kyoto",
});
// Any example from above runs on real hardware — just pass the backend.
const result = await quantum("search", { backend: ibm })
.search_in([0, 1, 2, 3], (x: unknown) => x === 3)
.run({ shots: 4096 });
// Or pass the backend at .run() time: .run({ shots: 4096, backend: ibm })
Summary of all configurable knobs
| Knob | Method / Option | Example value | Effect |
|---|---|---|---|
| Problem (object form) | quantum({ problem_class, task }) | { task: "search" } | Explicit class + task instead of a string |
| Resource limits | quantum(..., { resources }) | { maxDepth: 500 } | Rejects circuit if depth or gate count exceed cap |
| Algorithm family | .solve(family) | "variational" | Selects the pipeline preset |
| Custom pipeline | .solve([steps]) | [{ action: "apply" }] | User-defined step sequence |
| Pipeline step overrides | .solve(family, { override }) | [{ action: "measure" }] | Replaces matching steps in the preset |
| Task-specific metadata | .data(role, value, { metadata }) | { time: 2.0, steps: 4 } | Consumed by the bridge for specific tasks |
| Shots | .run({ shots }) | 4096 | Measurement repetitions (default 1024) |
| Backend | .run({ backend }) or quantum(..., { backend }) | IBMBackend instance | Simulator (default) or real hardware |
🔁 Swap
IBMBackendfor aQBraidBackendinstance (or any customBackend) to run the exact same pipeline on a different device — no other code change is required.
⚠️ Experimental API
The High-Level API (
hlapi) is experimental. Its interfaces, entity schemas, enum values, and behavioral contracts are subject to breaking changes in any release. Do not depend on it in production workflows. Feedback and contributions are welcome.
🏗️ Architecture
┌─────────────────┐ ┌─────────────┐ ┌─────────────────┐ ┌──────────────────┐
│ QuantumCircuit │───▶│ Transpiler │───▶│ Backend │───▶│ExecutionResult │
└─────────────────┘ └─────────────┘ └─────────────────┘ └──────────────────┘
│ │
OpenQASM 3.1 serializer SimulatorBackend
+ parser + passes IBMBackend
QBraidBackend
The SDK is organized as a strict layered build:
- 🧮 Foundation —
complex.ts,matrix.ts,parameter.ts,types.ts - 🎛️ Gates —
gates.ts— all 80+ gates across 14 tiers, compositionally derived from the 19 Tier 0 single-qubit primitives plus the single Tier 1CX. - 🧩 Expansion API —
expansion.ts— pure factory module for classical expressions, quantum operands, durations, and state specs. - 🏗️
QuantumCircuit—circuit.ts— the central builder + thematerializeGatedispatcher that bridges the IR to concrete gate matrices. - ☁️ Backends —
backend.ts,simulator.ts,ibm_backend.ts,qbraid_backend.ts - 🧮 Transpiler —
transpiler.ts— OpenQASM 3.1 serializer + recursive-descent parser + compilation passes. - 🌐 Bloch sphere —
bloch.ts— reduced density matrix → Bloch vector. - 📦 Public API —
mod.ts— the single entry point.
✅ Specification highlights
- Phase-safe multi-controlled X via mutual recursion
MCX(N) = H(t) → MCPhase(π, N) → H(t)(no X-root ladder). - Möttönen 4-layer
UCGatesynthesis with exact ZYZ decomposition. - Complex Jacobi eigendecomposition for
HamiltonianGate. - Phase Convention 1 minimum exact-expression conformance profile in
parameter.tswithwrapPhasebranch-cut snap. - Subspace iteration in the simulator — never constructs the full
2ⁿ × 2ⁿmatrix. - 974 tests passing (excluding the live cloud-execution tests gated behind environment variables).
🧪 Running Tests
deno test --allow-env
The IBM and qBraid live execution tests are skipped by default. Enable them via environment variables:
# IBM
export IBM_BEARER_TOKEN=... # OR IBM_API_KEY=...
export IBM_SERVICE_CRN=...
export IBM_BACKEND_NAME=ibm_kyoto
deno test --allow-env --allow-net
# qBraid
export QBRAID_API_KEY=...
export QBRAID_DEVICE_QRN=...
deno test --allow-env --allow-net
📜 License
MIT © Henrique Emanoel Viana
Built with
agents.md-for-quantum-simulation.