Quick start

This page takes you from an empty file to a running distributed quantum program.

1. Write the program

A NetQMPI application is a plain Python file that defines a main(env) function. The same file runs on every rank — this is the SPMD model — and each rank tells itself apart by its rank number.

app.py
 1from netqmpi.sdk.environment import Environment
 2
 3
 4def main(env: Environment = None):
 5    comm = env.comm
 6    rank = comm.rank
 7
 8    next_rank = comm.get_next_rank(rank)
 9    previous_rank = comm.get_prev_rank(rank)
10
11    # Only what is inside the block takes part in the distributed program.
12    with comm:
13        circuit = env.create_circuit(num_qubits=1, num_clbits=1)
14
15        if rank == 0:
16            circuit.h(0)                          # prepare |+>
17            comm.qsend(circuit, [0], next_rank)   # and give it away
18        else:
19            comm.qrecv(circuit, [0], previous_rank)
20            circuit.measure(0, 0)
21
22    # The circuits of all ranks are submitted together when the last rank
23    # leaves the block, so only that rank sees results here — and it sees
24    # every rank's counts, keyed by rank.
25    if comm.results:
26        for other, counts in comm.results.items():
27            print(f"rank_{other}: {counts}")

Three things are worth noticing:

main(env) is the entry point

NetQMPI loads your script and calls this function once per rank, injecting an Environment. A script without main() is rejected before anything runs.

Nothing mentions entanglement

qsend() and qrecv() are all you write. The EPR-pair generation, the Bell measurement and the classical corrections that make up the teleportation protocol are filled in by the backend adapter.

The program is backend-agnostic

It imports only from netqmpi.sdk. No backend package appears anywhere, which is what lets the same file run on all four backends.

2. Run it

The launcher is MPI-like: pick the number of nodes with -n and the backend with a flag.

netqmpi -n 2 app.py --aer --shots 1024      # circuit simulation
netqmpi -n 2 app.py --netqasm               # quantum-network simulation
netqmpi -n 2 app.py --cunqa --shots 1024    # HPC vQPU emulation
netqmpi -n 2 app.py --qoala --shots 100     # node execution environment

Start with --aer if you just want to see it work: it is the only backend with no special installation requirements.

3. Read the results

Output is a histogram of measurement outcomes per rank, gathered after all ranks have left the with comm: block:

rank_0: {'0': 1024}
rank_1: {'0': 517, '1': 507}

Rank 1 measures the |+⟩ it received in the computational basis, so it reads 0 and 1 about equally often. Rank 0 reads 0 because handing a qubit over moves it: a quantum state cannot be copied, so once qsend returns, rank 0’s qubit is back in |0⟩.

Only some ranks see comm.results

Circuits are submitted jointly when the last rank leaves its with comm: block, so comm.results is populated on that rank and — depending on the backend — possibly not on the others. The if comm.results: guard above is the idiomatic way to print once. See Reading results.

Shipped examples

The repository ships runnable programs under examples/:

Example

What it shows

1_send_recv.py

Distributed superposition, teleported between two ranks

2_round_robin.py

A qubit passed around a ring of ranks

3_scatter.py

qscatter: the root hands one qubit to each other rank

4_gather.py

qgather: every rank hands its qubit to the root

5_qft_expose.py

A full 3-rank QFT built out of telegates

There is also examples/frequent_errors/, a corpus of programs that are meant to fail — one failure mode each — with a run_all.py that reports what NetQMPI says about every one of them without needing any vQPU. It is documented in Troubleshooting.