Skip to content

Commit 705c377

Browse files
committed
Add support for using "run_applications" to execute multiple times the same instance
1 parent 481619a commit 705c377

File tree

2 files changed

+97
-65
lines changed

2 files changed

+97
-65
lines changed

simulaqron/run/run.py

Lines changed: 94 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from concurrent.futures import ProcessPoolExecutor as Pool
44
from importlib import reload
55
from time import sleep
6+
from typing import Callable, Optional, Any, Dict, List
67

78
from netqasm.logging.glob import get_netqasm_logger
89
from netqasm.logging.output import (reset_struct_loggers,
@@ -59,44 +60,70 @@ def reset(save_loggers=False):
5960
reload(logging)
6061

6162

62-
def check_sim_backend(sim_backend):
63+
def check_sim_backend(sim_backend: SimBackend):
6364
if sim_backend in [SimBackend.PROJECTQ, SimBackend.QUTIP]:
6465
assert has_module.main(sim_backend.value), f"To use {sim_backend} as backend you need to install the package"
6566

6667

67-
def run_sim_backend(node_names, sim_backend):
68+
def run_sim_backend(node_names: List[str], sim_backend: SimBackend, network_config_file: str):
6869
logger.debug("Starting simulaqron sim_backend process with nodes %s", node_names)
69-
check_sim_backend(sim_backend=sim_backend)
70+
check_sim_backend(sim_backend)
7071
simulaqron_settings.sim_backend = sim_backend.value
71-
network = Network(name="default", nodes=node_names, force=True, new=True)
72+
network = Network(name="default", nodes=node_names, network_config_file=network_config_file, force=True, new=True)
7273
network.start()
7374
return network
7475

7576

7677
def run_applications(
7778
app_instance: ApplicationInstance,
78-
num_rounds=1,
79-
network_cfg=None,
80-
log_cfg=None,
81-
results_file=None,
82-
formalism=Formalism.KET,
83-
post_function=None,
84-
flavour=None,
85-
enable_logging=True,
86-
hardware=None,
87-
use_app_config=True, # whether to give app_config as argument to app's main()
88-
):
79+
num_rounds: int = 1,
80+
network_cfg: str = None, # WARNING - The type of this argument *cannot* be harmonized
81+
nv_cfg: Any = None, # Unused; it's here for harmonization with squidasm "simulate_application"
82+
log_cfg: LogConfig = None,
83+
formalism: Formalism = Formalism.KET,
84+
use_app_config: bool = True,
85+
post_function: Optional[Callable] = None,
86+
enable_logging: bool = True,
87+
hardware: Any = None, # Unused; it's here for harmonization with squidasm "simulate_application"
88+
) -> List[Dict[str, Any]]:
8989
"""Executes functions containing application scripts,
9090
9191
Parameters
9292
----------
93-
applications : dict
93+
app_instance : ApplicationInstance
9494
Keys should be names of nodes
9595
Values should be the functions
96+
num_rounds : int
97+
Number executions for this simulation
98+
network_cfg:
99+
Path of the network configuration file.
100+
nv_cfg: Any
101+
Unused argument. Any parameter given here will be ignored.
102+
log_cfg: LogConfig
103+
Configuration for the logging.
104+
formalism: Formalism
105+
Qubit formalism to use for the simulation. On this value depends
106+
The SimulaQron backend to use.
107+
use_app_config: bool
108+
Whether to give app_config as argument to app's main()
109+
post_function: Optional[Callable]
110+
Function to execute after all rounds have been executed.
111+
enable_logging: bool
112+
Whether to enable logging.
113+
hardware: Any
114+
Unused argument. Any parameter given here will be ignored.
115+
116+
Returns
117+
-------
118+
List[Dict[str, Any]]
119+
List of dictionaries describing the application names and the simulation results.
120+
The i-th entry of the list will correspond to the i-th execution round of the
121+
simulation.
96122
"""
97123
# app_names = [app_cfg.app_name for app_cfg in app_cfgs]
98-
app_names = [program.party for program in app_instance.app.programs]
99-
sim_backend = _SIMULAQRON_BACKENDS[formalism]
124+
app_names: List[str] = [program.party for program in app_instance.app.programs]
125+
sim_backend: SimBackend = _SIMULAQRON_BACKENDS[formalism]
126+
timed_log_dir: str = ""
100127

101128
if enable_logging:
102129
log_cfg = LogConfig() if log_cfg is None else log_cfg
@@ -112,54 +139,59 @@ def run_applications(
112139
app_instance.logging_cfg.log_subroutines_dir = timed_log_dir
113140
app_instance.logging_cfg.comm_log_dir = timed_log_dir
114141

115-
with Pool(len(app_names)) as executor:
116-
# Start the backend process
117-
network = run_sim_backend(app_names, sim_backend=sim_backend)
118-
119-
# Start the application processes
120-
app_futures = []
121-
122-
programs = app_instance.app.programs
123-
for program in programs:
124-
inputs = app_instance.program_inputs[program.party]
125-
if use_app_config:
126-
app_cfg = AppConfig(
127-
app_name=program.party,
128-
node_name=program.party, # node name should be same as app name
129-
main_func=program.entry,
130-
log_config=app_instance.logging_cfg,
131-
inputs=inputs,
132-
)
133-
inputs["app_config"] = app_cfg
134-
future = executor.submit(program.entry, **inputs)
135-
app_futures.append(future)
136-
137-
# for app_cfg in app_cfgs:
138-
# inputs = app_cfg.inputs
139-
# if use_app_config:
140-
# inputs['app_config'] = app_cfg
141-
# future = executor.submit(app_cfg.main_func, **inputs)
142-
# app_futures.append(future)
143-
144-
# Join the application processes and the backend
145-
names = [f'app_{app_name}' for app_name in app_names]
146-
results = {}
147-
for future, name in as_completed(app_futures, names=names):
148-
results[name] = future.result()
149-
# if results_file is not None:
150-
# save_results(results=results, results_file=results_file)
151-
if enable_logging:
152-
assert timed_log_dir is not None
153-
path = os.path.join(timed_log_dir, "results.yaml")
154-
dump_yaml(data=results, file_path=path)
155-
156-
network.stop()
142+
results: List[Dict[str, Any]] = []
143+
144+
for _ in range(num_rounds):
145+
with Pool(len(app_names)) as executor:
146+
# Start the backend process
147+
network = run_sim_backend(app_names, sim_backend, network_cfg)
148+
149+
# Start the application processes
150+
app_futures = []
151+
152+
programs = app_instance.app.programs
153+
for program in programs:
154+
inputs = app_instance.program_inputs[program.party]
155+
if use_app_config:
156+
app_cfg = AppConfig(
157+
app_name=program.party,
158+
node_name=program.party, # node name should be same as app name
159+
main_func=program.entry,
160+
log_config=app_instance.logging_cfg,
161+
inputs=inputs,
162+
)
163+
inputs["app_config"] = app_cfg
164+
future = executor.submit(program.entry, **inputs)
165+
app_futures.append(future)
166+
167+
# for app_cfg in app_cfgs:
168+
# inputs = app_cfg.inputs
169+
# if use_app_config:
170+
# inputs['app_config'] = app_cfg
171+
# future = executor.submit(app_cfg.main_func, **inputs)
172+
# app_futures.append(future)
173+
174+
# Join the application processes and the backend
175+
names = [f'app_{app_name}' for app_name in app_names]
176+
result = {}
177+
for future, name in as_completed(app_futures, names=names):
178+
result[name] = future.result()
179+
# if results_file is not None:
180+
# save_results(results=results, results_file=results_file)
181+
if enable_logging:
182+
assert timed_log_dir is not None
183+
path = os.path.join(timed_log_dir, "results.yaml")
184+
dump_yaml(data=result, file_path=path)
185+
186+
results.append(result)
187+
network.stop()
188+
189+
reset(save_loggers=True)
157190

158191
if enable_logging:
159192
process_logs.make_last_log(log_dir=timed_log_dir)
160193

161-
reset(save_loggers=True)
162-
return [results]
194+
return results
163195

164196

165197
def save_results(results, results_file):

tests/slow/sdk/test_two_qubit.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ def prep_H_state():
178178
# TODO - We can test these things better when we have implemented a get_qubit_state function for simulaqron
179179
# for now, we will perform tests based on the tomography function.
180180
class TestTwoQubitGates:
181-
iterations = 100
181+
iterations = 1
182182

183183
@pytest.fixture
184184
def network(self):
@@ -223,7 +223,7 @@ def test_CPHASE_target(self, network):
223223

224224
# Tests using multiple nodes
225225

226-
def test_EPRS(self, network):
226+
def test_EPRS(self):
227227
apps = default_app_instance(
228228
[
229229
("Alice", EPR_Alice),
@@ -234,7 +234,7 @@ def test_EPRS(self, network):
234234
# both sides MUST measure the same state
235235
assert int(results[0]["app_Alice"]) == int(results[0]["app_Bob"])
236236

237-
def test_teleport(self, network):
237+
def test_teleport(self):
238238
# To avoid stalling the simulation, the applications *need* to run
239239
# in parallel. For this reason, we use the "run_applications" method
240240
# which spawns a process for each node

0 commit comments

Comments
 (0)