The NetQASM interface¶
SimulaQron applications are written using the NetQASM SDK. This page describes the core concepts and programming model. For complete working examples, see Examples.
Installation¶
The NetQASM library is included as a dependency of SimulaQron. For the instructions how to install SimulaQron please check the Getting Started section.
Core concepts¶
NetQASMConnection¶
This objects represent your connection to the local quantum backend (SimulaQron’s virtual quantum node). This is not a connection to another party — it is how your node talks to its local simulated quantum hardware. All qubit operations are queued through this connection.
Create it once, use it throughout your program, and close it at the end:
from netqasm.sdk.external import NetQASMConnection
conn = NetQASMConnection("Alice")
# ... queue quantum operations ...
conn.flush()
conn.close()
If your program uses EPR pairs, pass the EPR sockets at creation time:
from netqasm.sdk import EPRSocket
epr_socket = EPRSocket("Bob")
conn = NetQASMConnection("Alice", epr_sockets=[epr_socket])
Qubit¶
A qubit allocated on the local quantum backend. The qubit gets initialized to the \(|0\rangle\) state. Pass the connection so the backend knows where to allocate it:
from netqasm.sdk import Qubit
q = Qubit(conn)
q.H() # Hadamard
q.X() # Pauli X
q.cnot(other) # CNOT with another qubit
m = q.measure()
Gates are queued — nothing executes until you call flush().
EPRSocket¶
Used to create or receive entangled qubit pairs with a remote node:
from netqasm.sdk import EPRSocket
# On Alice's side:
epr_socket = EPRSocket("Bob")
epr = epr_socket.create_keep()[0]
# On Bob's side:
epr_socket = EPRSocket("Alice")
epr = epr_socket.recv_keep()[0]
flush()¶
The sync point that executes all queued quantum operations and makes measurement results available.
Before flush(), measurement results are just futures/promises. After flush(), you can read them
with int(m):
m = q.measure()
conn.flush() # execute everything queued so far
result = int(m) # NOW this works
You can call flush() multiple times on the same connection. This enables mid-circuit classical logic
— measure, read the result, and decide what to do next:
m1 = q.measure()
conn.flush()
if int(m1) == 1:
other_qubit.X() # conditional correction
conn.flush()
See the mid-circuit logic example in Examples for a full demonstration.
Minimal example¶
A single-node program that creates a qubit, applies a Hadamard gate, and measures:
from netqasm.runtime.settings import set_simulator
set_simulator("simulaqron")
from netqasm.sdk.external import NetQASMConnection
from netqasm.sdk import Qubit
conn = NetQASMConnection("Alice")
q = Qubit(conn)
q.H()
m = q.measure()
conn.flush()
print("Measurement outcome:", int(m))
conn.close()
If you want to run this minimal example, remember to start the SimulaQron backend before executing the code:
simulaqron start.
Two-node EPR example¶
Alice and Bob generate an EPR pair and each measure their qubit to get correlated random numbers.
Alice (creates the EPR pair):
epr_socket = EPRSocket("Bob")
conn = NetQASMConnection("Alice", epr_sockets=[epr_socket])
epr = epr_socket.create_keep()[0]
m = epr.measure()
conn.flush()
print("Alice:", int(m))
conn.close()
Bob (receives the EPR pair):
epr_socket = EPRSocket("Alice")
conn = NetQASMConnection("Bob", epr_sockets=[epr_socket])
epr = epr_socket.recv_keep()[0]
m = epr.measure()
conn.flush()
print("Bob:", int(m))
conn.close()
Both sides will print the same random number (0 or 1), demonstrating quantum correlation. A full working example
of this can be found in the new-sdk/corrRNG example. See the Correlated RNG section for
more details.
Classical communication¶
For exchanging classical messages between nodes (e.g. measurement outcomes for teleportation corrections),
SimulaQron provides SimulaQronClassicalClient and SimulaQronClassicalServer.
Your quantum program function receives (reader, writer) — standard asyncio streams — for sending and
receiving classical messages:
from asyncio import StreamReader, StreamWriter
async def run_alice(reader: StreamReader, writer: StreamWriter):
# Quantum operations
conn = NetQASMConnection("Alice", epr_sockets=[epr_socket])
m = epr_socket.create_keep()[0].measure()
conn.flush()
# Send classical message to Bob
writer.write(str(int(m)).encode("utf-8"))
conn.close()
async def run_bob(reader: StreamReader, writer: StreamWriter):
# Receive classical message from Alice
data = await reader.read(255)
correction = int(data.decode("utf-8"))
# Use correction in quantum operations
conn = NetQASMConnection("Bob", epr_sockets=[epr_socket])
epr = epr_socket.recv_keep()[0]
if correction == 1:
epr.X()
conn.flush()
conn.close()
See the Template page for how to set up the client and server, and the teleportation example for a complete two-node program with classical messaging.
Configuration¶
Each program needs two configuration files in its directory:
simulaqron_network.json— defines the nodes and their socket ports. See Configuring the Network for details.simulaqron_settings.json— configures the simulation backend and other settings. See the Settings section in Getting Started.
The qutip backend is used by default and is recommended unless you need Clifford gates (use
stabilizer in that case).
Further reading¶
Examples — complete working examples from simple to complex
New SDK Overview — detailed SDK concepts and file structure