Bundled Networks & Circuits¶
The library ships a small suite of reference networks and circuits inside the
installed package, so you can run the full workflow before writing a topology
of your own. They are reachable through memq_dqc.assets, which returns
pathlib.Path objects — exactly what Compiler, Partitioner, and
NetworkGraph already accept.
from memq_dqc import Compiler
from memq_dqc.assets import circuit_path, network_path
compiler = Compiler(
circuit_path("qft_n10"),
network_path("10_qubits/n2_pair_nn"),
)
compiler.compile()
Discovering what is available¶
from memq_dqc.assets import list_circuits, list_networks
list_circuits() # ['adder_n28', 'multiply_n13', 'qft_n10', ...]
list_networks() # ['10_qubits/n2_pair_a2a', '10_qubits/n2_pair_nn', ...]
Circuits¶
Ten transpiled OpenQASM programs spanning 4 to 60 qubits, named
<algorithm>_n<qubits>. The .qasm extension is optional in
circuit_path().
| Circuit | Qubits | "sampling" |
"statevector" |
|---|---|---|---|
qft_n4 |
4 | yes | yes |
qft_n5 |
5 | yes | yes |
qft_n10 |
10 | yes | yes |
multiply_n13 |
13 | yes | yes |
qft_n18 |
18 | no | yes |
qft_n20 |
20 | no | yes |
adder_n28 |
28 | yes | too wide |
qft_n29 |
29 | no | too wide |
qft_n40 |
40 | no | too wide |
qft_n60 |
60 | no | too wide |
Every circuit is OpenQASM 3.0 and fully measured: each declares a bit[n] c
register and ends with one explicit c[i] = measure q[i]; per qubit, rather
than a bulk register-to-register measurement. That makes them usable as
verification inputs, not just compilation inputs.
The two columns are the two verification methods, and they fail in opposite
directions — between them they cover every circuit up to qft_n20.
Compiler.verify() uses sampling: it simulates both circuits and compares
output distributions by Hellinger fidelity. That needs the distribution to be
concentrated enough to estimate from a feasible shot count. adder_n28 passes
at 28 qubits because its output is a single computational basis state; a wide
QFT spreads amplitude across all 2ⁿ outcomes, so qft_n18 reaches only 0.26
fidelity even at 200 000 shots, against a 0.9 threshold.
Where sampling starves, use the exact statevector method instead. It is deterministic, needs no shots, and confirms the wide QFTs outright:
from memq_dqc import get_verification_artifacts
from memq_dqc.assets import circuit_path, network_path
from memq_dqc.verify import verify_distributed_circuit
artifacts = get_verification_artifacts(
str(circuit_path("qft_n18")),
str(network_path("20_qubits/n2_pair_nn")),
)
verify_distributed_circuit(
artifacts.original_program,
artifacts.distributed_program,
method="statevector",
) # True
The statevector ceiling counts communication qubits
Statevector verification holds ~2ⁿ amplitudes in memory and refuses to run
past max_qubits (default 28). The n it measures is the width of the
distributed circuit — data qubits plus the communication qubits the
network adds — not the original circuit's qubit count.
So adder_n28 is out of reach despite being exactly 28 qubits: on
30_qubits/n2_pair_nn its distributed form is 34 qubits wide. Choosing a
network with fewer QPUs, and therefore fewer communication qubits, lowers
that width.
Neither limit is a compilation failure. Every bundled circuit partitions and reconstructs; what varies is whether the result can be checked at that width.
More sophisticated verification is coming soon
Sampling and statevector are today's two verification methods, and each has a ceiling — sampling on distribution concentration, statevector on qubit count. A more scalable verification approach that lifts these limits is planned.
Networks¶
Networks are grouped by the circuit size they are built to host, and named
n<QPUs>_<arrangement>_<variant> within each group — so a full name looks like
30_qubits/n4_hub_nn.
The size directory is a capacity, not an exact match: a network sized for
30-qubit circuits hosts any circuit of 30 qubits or fewer. Data qubits per QPU
are ceil(circuit_qubits / n) and identical on every QPU, so rounding up may
leave a few spare data qubits.
Available sizes: 10, 20, 30, 40, and 60 qubits.
Arrangements¶
| Arrangement | Shape | Why it is here |
|---|---|---|
pair |
two QPUs, one edge | minimal distributed case; every non-local gate crosses the same cut |
chain |
open line | linear diameter, hot middle cuts — the stress case for partitioning |
ring |
closed cycle | uniform degree 2 and two routes between any pair, so routing can balance |
hub |
star | one central QPU relays everything; the bottleneck case |
Variants¶
Each arrangement comes in two intra-QPU connectivity variants, so you can isolate the effect of local connectivity while holding the inter-QPU arrangement fixed:
_nn— nearest neighbour: data qubits on a 2D grid with 4-way adjacency, communication qubits attached to one boundary data qubit each._a2a— all-to-all: data qubits fully connected to each other, communication qubits connected to every data qubit. Communication qubits are never connected to one another.
Shared invariants¶
- Every adjacent QPU pair is joined by 2 remote links.
- Each link owns a private pair of communication qubits, so a QPU carries
2 × degreeof them. Chain endpoints therefore have fewer communication qubits than interior QPUs, and a hub has the most. - Coherence time is 100 µs on every qubit; fidelity is 1 on every remote link. No current partitioner or scheduler reads these, but they are carried in the format for coherence- and fidelity-aware algorithms later.
Per-network documentation¶
Every network has a same-named Markdown file describing its arrangement, qubit counts, degrees, and remote links in full:
from memq_dqc.assets import network_doc_path
print(network_doc_path("30_qubits/n4_hub_nn").read_text())
Beyond the bundled set¶
These are a starting point, not a benchmark suite. For your own topologies, see the Network Builder guide — it exports the same JSON format.