Skip to content

Commit ab8a0dd

Browse files
committed
Add template for creating quantum local applications using the new SDK
1 parent c89b723 commit ab8a0dd

7 files changed

Lines changed: 167 additions & 0 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/usr/bin/env bash
2+
3+
./terminate.sh
4+
./run.sh
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from asyncio import StreamReader, StreamWriter
2+
from pathlib import Path
3+
4+
from simulaqron.general.host_config import SocketsConfig
5+
from simulaqron.sdk.protocol import SimulaQronClassicalClient
6+
from simulaqron.settings import network_config, simulaqron_settings
7+
from simulaqron.settings.network_config import NodeConfigType
8+
9+
# This is recipe to use NetQASM with simulaqron backend.
10+
from netqasm.runtime.settings import set_simulator
11+
set_simulator("simulaqron")
12+
13+
# Importing NetQASM connection, Qubit and EPR socket must be *after*
14+
# setting the simulator for NetQASM
15+
from netqasm.sdk.external import NetQASMConnection # noqa: E402
16+
from netqasm.sdk import Qubit, EPRSocket # noqa: E402
17+
18+
19+
# This function contains the code of the classical client
20+
def quantum_program(this_node_name: str) -> int:
21+
# To start executing quantum operations, we need to create a NetQASM connection
22+
with NetQASMConnection(this_node_name, epr_sockets=[epr_socket]) as alice:
23+
# Create a qubit
24+
q = Qubit(alice)
25+
26+
# Perform some local quantum operations
27+
q.H()
28+
q.X()
29+
m1 = q.measure()
30+
# Any value that comes from NetQASM *need* to be retrieved ("casted" to int)
31+
# *after* the connection is closed (or after flushing the connection, untested)
32+
m1_val = int(m1)
33+
return m1_val
34+
35+
36+
if __name__ == "__main__":
37+
# Load the simulaqron settings file
38+
simulaqron_config_file = Path("simulaqron_settings.json")
39+
simulaqron_settings.read_from_file(simulaqron_config_file)
40+
41+
# Load the file network configuration file
42+
# We still need this file to correctly interact with the SimulaQron backend (QNodeOS and Virtual Node)
43+
network_config_file = Path("simulaqron_network.json")
44+
network_config.read_from_file(network_config_file)
45+
46+
# Some data for this node:
47+
network_name = "default" # A network with this name *must* exist in "simulaqron_network.json"
48+
node_name = "YourName" # A node with this name *must* exist in "simulaqron_network.json"
49+
50+
# Get the socket configuration for the sockets used for the application layer
51+
sockets_config = SocketsConfig(network_config, network_name, NodeConfigType.APP)
52+
53+
# Name of one node to classically connect to
54+
server_name = "Bob"
55+
56+
result = quantum_program()
57+
print(result)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/usr/bin/env bash
2+
3+
# Flag used to determine whether to start simulaqron backend or not
4+
# This is useful when using this script to run the application in different machines.
5+
START_SIMULAQRON=true
6+
7+
# Process the arguments, if any
8+
while [[ $# -gt 0 ]]; do
9+
case $1 in
10+
-n|--no-start-simulaqron)
11+
START_SIMULAQRON=false
12+
shift
13+
;;
14+
esac
15+
done
16+
17+
if [ "$START_SIMULAQRON" = true ]; then
18+
# Check if SimulaQron is already running
19+
if [ ! -f ~/.simulaqron_pids/simulaqron_network_default.pid ]; then
20+
# TODO - Modify the list of nodes to start on this machine
21+
# TODO - Change the filename of the network configuration if you changed that
22+
# TODO - Change the filename of the simulaqron configuration if you changed that
23+
# If not, start simulaqron backend for both nodes
24+
simulaqron start --nodes=Alice --network-config-file simulaqron_network.json --simulaqron-config-file simulaqron_settings.json
25+
fi
26+
fi
27+
28+
python3 nodeTest.py
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
[
2+
{
3+
"name": "default",
4+
"nodes": [
5+
{
6+
"Alice": {
7+
"app_socket": ["localhost", 8821],
8+
"qnodeos_socket": ["localhost", 8822],
9+
"vnode_socket": ["localhost", 8823]
10+
}
11+
},
12+
{
13+
"Bob": {
14+
"app_socket": ["localhost", 8831],
15+
"qnodeos_socket": ["localhost", 8832],
16+
"vnode_socket": ["localhost", 8833]
17+
}
18+
},
19+
{
20+
"Charlie": {
21+
"app_socket": ["localhost", 8841],
22+
"qnodeos_socket": ["localhost", 8842],
23+
"vnode_socket": ["localhost", 8843]
24+
}
25+
},
26+
{
27+
"David": {
28+
"app_socket": ["localhost", 8871],
29+
"qnodeos_socket": ["localhost", 8872],
30+
"vnode_socket": ["localhost", 8873]
31+
}
32+
}
33+
],
34+
"topology": null
35+
}
36+
]
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"max_qubits": 20,
3+
"max_registers": 1000,
4+
"conn_retry_time": 0.5,
5+
"conn_max_retries": 10,
6+
"recv_timeout": 100,
7+
"recv_retry_time": 0.1,
8+
"recv_max_retries": 10,
9+
"log_level": 30,
10+
"sim_backend": "projectq",
11+
"noisy_qubits": false,
12+
"max_app_waiting_time": -1.0,
13+
"t1": 1.0
14+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/usr/bin/env sh
2+
TEST_PIDS=$(ps aux | grep python | grep -E "Test" | awk {'print $2'})
3+
if [ "$TEST_PIDS" != "" ]
4+
then
5+
kill -9 $TEST_PIDS
6+
fi
7+
8+
# Check if SimulaQron is running
9+
if [ -f ~/.simulaqron_pids/simulaqron_network_default.pid ]; then
10+
if ! simulaqron stop
11+
then
12+
# Kill the process, only if simulaqron could not be stopped gracefully
13+
cat $HOME/.simulaqron_pids/simulaqron_network_default.pid | xargs kill -9
14+
fi
15+
fi
16+

simulaqron/sdk/protocol.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,18 @@ async def connected_handler(reader: StreamReader, writer: StreamWriter):
6262

6363
class SimulaQronClassicalServer:
6464
def __init__(self, sockets_config: SocketsConfig, name: str):
65+
"""
66+
Classical server used to server classical clients to remote nodes. The given socket configs
67+
object contains the specification of the available nodes on the network that this server can
68+
interact with. Please note that this configuration *does not limit* the clients that can
69+
connect to this server.
70+
71+
:param sockets_config: The sockets configuration for the whole network.
72+
:type sockets_config: SocketsConfig
73+
:param name: The name of the server to connect to. The name *must* exist in the
74+
configuration file given when constructing this server.
75+
:type name: str
76+
"""
6577
self._node_name = name
6678
self._sockets_data = sockets_config.hostDict[self._node_name]
6779
self._connection_handler: Optional[Callable[[StreamReader, StreamWriter], Awaitable[None]]] = None

0 commit comments

Comments
 (0)