def _setup_topology(self, topology_file): """ Sets up the topology, if specified. :param topology_file: str The relative path to the json-file defining the topology. It will be assumed that the absolute path to the file is $simulaqron_path/topology_file. If topology is an empty string then a fully connected topology will be used. :return: None """ if topology_file == "": return else: # Get path to SimulaQron folder simulaqron_path = get_simulaqron_path.main() # Get the absolute path to the file abs_path = os.path.join(simulaqron_path, topology_file) try: with open(abs_path, "r") as top_file: try: self.topology = json.load(top_file) except json.JSONDecodeError: raise RuntimeError( "Could not parse the json file: {}".format( abs_path)) except FileNotFoundError: raise FileNotFoundError( "Could not find the file specifying the topology:" " {}".format(abs_path)) except IsADirectoryError: raise FileNotFoundError( "Could not find the file specifying the topology: " "{}".format(abs_path))
def main(): # In this example, we are Bob. myName = "Repeater1" # This file defines the network of virtual quantum nodes simulaqron_path = get_simulaqron_path.main() virtualFile = os.path.join(simulaqron_path, "config/virtualNodes.cfg") # This file defines the nodes acting as servers in the classical communication network classicalFile = "repeater1_classical_net.cfg" # Read configuration files for the virtual quantum, as well as the classical network virtualNet = socketsConfig(virtualFile) classicalNet = socketsConfig(classicalFile) # Check if we should run a local classical server. If so, initialize the code # to handle remote connections on the classical communication network if myName in classicalNet.hostDict: lNode = localNode(classicalNet.hostDict[myName], classicalNet) logging.debug("LOCAL %s: Initialise a classical server..: %s.", myName, lNode) else: lNode = None logging.debug("LOCAL %s: No initialisation of classical server..: %s.", myName, lNode) # Set up the local classical server if applicable, and connect to the virtual # node and other classical servers. Once all connections are set up, this will # execute the function runClientNode setup_local(myName, virtualNet, classicalNet, lNode, runClientNode)
def check_topology(self, topology): simulaqron_path = get_simulaqron_path.main() topology_config_file = os.path.join(simulaqron_path, "config", "topology.json") with open(topology_config_file, 'r') as f: topology_in_file = json.load(f) self.assertEqual(topology_in_file, topology)
def main(): # In this example, we are YOURNAME myName = "Charlie" # This file defines the network of virtual quantum nodes simulaqron_path = get_simulaqron_path.main() virtualFile = os.path.join(simulaqron_path, "config/virtualNodes.cfg") # This file defines the nodes acting as servers in the classical communication network classicalFile = os.path.join(os.path.dirname(__file__), "classicalNet.cfg") # Read configuration files for the virtual quantum, as well as the classical network virtualNet = socketsConfig(virtualFile) classicalNet = socketsConfig(classicalFile) # Check if we should run a local classical server. If so, initialize the code # to handle remote connections on the classical communication network if myName in classicalNet.hostDict: lNode = localNode(classicalNet.hostDict[myName], classicalNet) else: lNode = None # Set up the local classical server if applicable, and connect to the virtual # node and other classical servers. Once all connections are set up, this will # execute the function runClientNode setup_local(myName, virtualNet, classicalNet, lNode, runClientNode)
def tearDownClass(cls): # Set config files back to default for file in ["Nodes.cfg", "topology.json", "settings.ini"]: simulaqron_path = get_simulaqron_path.main() file_path = os.path.join(simulaqron_path, "config", file) os.remove(file_path) construct_node_configs() Settings.default_settings()
def check_nodes_and_topology_in_file(self, network): simulaqron_path = get_simulaqron_path.main() network_config_file = os.path.join(simulaqron_path, "config", "network.json") with open(network_config_file, 'r') as f: network_config = json.load(f) nodes_in_file = list(network_config[network.name]["nodes"].keys()) self.assert_nodes(nodes_in_file, network.nodes) topology_in_file = network_config[network.name]["topology"] self.assert_topology(topology_in_file, network.topology)
def construct_node_configs(nodes=None): """ Constructs the config files for the nodes and their port numbers. Port number used will start from 8801 and end at '8801 + 3*len(nodes)'. :param nodes: list of str or None List of the names of the nodes. If None then the nodes Alice, Bob, Charlie, David and Eve is used. :return: None """ # Default if nodes is None: nodes = ["Alice", "Bob", "Charlie", "David", "Eve"] nrNodes = len(nodes) if nrNodes == 0: return # Get path to SimulaQron folder simulaqron_path = get_simulaqron_path.main() # Get path to configuration files conf_files = [ Settings.CONF_VNODE_FILE, Settings.CONF_CQC_FILE, Settings.CONF_APP_FILE ] # File for just a simple list of the nodes node_file = Settings.CONF_NODES_FILE # What port numbers to start with start_nr = [8801, 8801 + nrNodes, 8801 + 2 * nrNodes] # Start of the configuration files conf_top = [ "# Network configuration file", "#", "# For each host its informal name, as well as its location in the network must", "# be listed.", "#", "# [name], [hostname], [port number]", "#", ] # Write to the configuration files for i in range(len(conf_files)): with open(conf_files[i], "w") as f: for line in conf_top: f.write(line + "\n") for j in range(nrNodes): f.write("{}, localhost, {}\n".format(nodes[j], start_nr[i] + j)) with open(node_file, "w") as f: for j in range(nrNodes): f.write("{}\n".format(nodes[j]))
def __init__(self, name=None, nodes=None, topology=None, cqc_file=None, app_file=None): self._running = False if name is None: self.name = "default" else: self.name = name if cqc_file is None: self._cqc_file = Settings.CONF_CQC_FILE else: self._cqc_file = cqc_file if app_file is None: self._app_file = Settings.CONF_APP_FILE else: self._app_file = app_file simulaqron_path = get_simulaqron_path.main() # Set the nodes if nodes is None: node_config_file = Settings.CONF_NODES_FILE self.nodes = load_node_names(node_config_file) else: self.nodes = nodes construct_node_configs(nodes=nodes) # Set the topology if topology is None: rel_topology_config_file = Settings.CONF_TOPOLOGY_FILE if rel_topology_config_file == '': self.topology = None else: abs_topology_config_file = os.path.join( simulaqron_path, rel_topology_config_file) with open(abs_topology_config_file, 'r') as f: self.topology = json.load(f) else: self.topology = topology construct_topology_config(topology=self.topology, nodes=self.nodes) self.processes = [] self._setup_processes()
def main(name): signal.signal(signal.SIGTERM, sigterm_handler) signal.signal(signal.SIGINT, sigterm_handler) # Get path to SimulaQron folder simulaqron_path = get_simulaqron_path.main() logging.basicConfig( format="%(asctime)s:%(levelname)s:%(message)s", level=Settings.CONF_LOGGING_LEVEL_BACKEND, ) logging.debug("Starting VIRTUAL NODE %s", name) virtualFile = Settings.CONF_VNODE_FILE be = backEnd(name, virtualFile) be.start(maxQubits=Settings.CONF_MAXQUBITS, maxRegisters=Settings.CONF_MAXREGS)
def setUp(self): self.network = None # Set config files simulaqron_path = get_simulaqron_path.main() nodes_config_file = os.path.join(simulaqron_path, "config", "Nodes.cfg") with open(nodes_config_file, 'w') as f: self.nodes = ["Test1", "Test2", "Test3"] f.writelines([node + "\n" for node in self.nodes]) topology_config_file = os.path.join(simulaqron_path, "config", "topology.json") with open(topology_config_file, 'w') as f: self.topology = { "Test1": ["Test2"], "Test2": ["Test3"], "Test3": [] } json.dump(self.topology, f) Settings.CONF_TOPOLOGY_FILE = os.path.join("config", "topology.json")
def init(name, cqcFile=None): """ Initialize a connection to the cqc server with the name given as input. A path to a configure file for the cqc network can be given, if it's not given the config file 'config/cqcNodes.cfg' will be used. Returns a socket object. """ # This file defines the network of CQC servers interfacing to virtual quantum nodes if cqcFile is None: simulaqron_path = get_simulaqron_path.main() cqcFile = os.path.join(simulaqron_path, "config/cqcNodes.cfg") # Read configuration files for the cqc network cqcNet = networkConfig(cqcFile) # Host data if name in cqcNet.hostDict: myHost = cqcNet.hostDict[name] else: logging.error("The name '%s' is not in the cqc network.", name) raise LookupError( "The name '%s' is not in the cqc network.".format(name)) addr = myHost.addr # Connect to cqc server and run protocol cqc = None try: cqc = socket.socket(addr[0], addr[1], addr[2]) except socket.error: logging.error("Could not connect to cqc server: %s", name) try: cqc.connect(addr[4]) except socket.error: cqc.close() logging.error("Could not connect to cqc server: %s", name) return cqc
def main(myName): """Start the indicated backend CQC Server""" signal.signal(signal.SIGTERM, sigterm_handler) signal.signal(signal.SIGINT, sigterm_handler) logging.basicConfig( format="%(asctime)s:%(levelname)s:%(message)s", level=Settings.CONF_LOGGING_LEVEL_BACKEND, ) # Get path to SimulaQron folder simulaqron_path = get_simulaqron_path.main() # This file defines the network of virtual quantum nodes virtualFile = Settings.CONF_VNODE_FILE # This file defines the network of CQC servers interfacing to virtual quantum nodes cqcFile = Settings.CONF_CQC_FILE # Read configuration files for the virtual quantum, as well as the classical network virtualNet = networkConfig(virtualFile) cqcNet = networkConfig(cqcFile) # Check if we are in the host-dictionary if myName in cqcNet.hostDict: myHost = cqcNet.hostDict[myName] cqc_factory = CQCFactory(myHost, myName, cqcNet, SimulaqronCQCHandler) else: logging.error("LOCAL %s: Cannot start classical communication servers.", myName) return # Connect to the local virtual node simulating the "local" qubits connect_to_virtNode(myName, cqc_factory, virtualNet) # Run reactor reactor.run()
def construct_topology_config(topology, nodes, save_fig=True): """ Constructs a json file at config/topology.json, used to define the topology of the network. :param topology: str Should be one of the following: None, 'complete', 'ring', 'random_tree'. :param nodes: list of str List of the names of the nodes. :param save_fig: bool Whether to save a picture of the network :return: None """ if topology: if isinstance(topology, dict): adjacency_dct = {node: topology[node] for node in nodes} elif topology == "complete": adjacency_dct = {} for i, node in enumerate(nodes): adjacency_dct[node] = nodes[:i] + nodes[i + 1:] elif topology == "ring": adjacency_dct = {} nn = len(nodes) for i, node in enumerate(nodes): adjacency_dct[node] = [ nodes[(i - 1) % nn], nodes[(i + 1) % nn] ] elif topology == "path": adjacency_dct = {} nn = len(nodes) for i, node in enumerate(nodes): if i == 0: adjacency_dct[node] = [nodes[i + 1]] elif i == (nn - 1): adjacency_dct[node] = [nodes[i - 1]] else: adjacency_dct[node] = [ nodes[(i - 1) % nn], nodes[(i + 1) % nn] ] elif topology == "random_tree": adjacency_dct = get_random_tree(nodes) elif topology[:16] == "random_connected": try: nr_edges = int(topology[17:]) except ValueError: raise ValueError( "When specifying a random connected graph use the format 'random_connected_{nr_edges}'," "where 'nr_edges' is the number of edges of the graph.") except IndexError: raise ValueError( "When specifying a random connected graph use the format 'random_connected_{nr_edges}'," "where 'nr_edges' is the number of edges of the graph.") adjacency_dct = get_random_connected(nodes, nr_edges) else: raise ValueError("Unknown topology name") # Get path to SimulaQron folder simulaqron_path = get_simulaqron_path.main() if save_fig: network = nx.from_dict_of_lists(adjacency_dct) try: nx.draw(network, with_labels=True) except _tkinter.TclError as err: logging.warning( "Could not draw since there seems to be no screen. Error: {}" .format(err)) else: fig_path = os.path.join(simulaqron_path, "config/topology.png") plt.savefig(fig_path) topology_file = os.path.join(simulaqron_path, "config/topology.json") with open(topology_file, "w") as top_file: json.dump(adjacency_dct, top_file) Settings.set_setting("BACKEND", "topology_file", "config/topology.json") else: Settings.set_setting("BACKEND", "topology_file", "")
def check_nodes(self, nodes): simulaqron_path = get_simulaqron_path.main() nodes_config_file = os.path.join(simulaqron_path, "config", "Nodes.cfg") nodes_in_file = load_node_names(nodes_config_file) self.assertEqual(nodes_in_file, nodes)
# LOSS OF USE, DATA, OR PROFITS OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ######################### # SETTINGS FOR SIMULAQRON ######################### import os import json import logging from enum import Enum from simulaqron.toolbox import get_simulaqron_path simulaqron_path = get_simulaqron_path.main() config_folder = os.path.join(simulaqron_path, "config") class SimBackend(Enum): STABILIZER = "stabilizer" PROJECTQ = "projectq" QUTIP = "qutip" class Config: simulaqron_path = get_simulaqron_path.main() config_folder = os.path.join(simulaqron_path, "config") _internal_settings_file = os.path.join(simulaqron_path, "config", "settings.json")
class Config: simulaqron_path = get_simulaqron_path.main() config_folder = os.path.join(simulaqron_path, "config") _internal_settings_file = os.path.join(simulaqron_path, "config", "settings.json") _user_settings_file = os.path.join(os.path.expanduser("~"), ".simulaqron.json") # Dictionary for settings _config = {} _default_config = { "_read_user": True, "max_qubits": 20, "max_registers": 1000, "conn_retry_time": 0.5, "recv_timeout": 100, # (x 100 ms) "recv_retry_time": 0.1, # (seconds) "log_level": logging.WARNING, "sim_backend": SimBackend.STABILIZER.value, "network_config_file": os.path.join(config_folder, "network.json"), "noisy_qubits": False, "t1": 1.0 } class Decorator: @classmethod def get_setting(cls, method): def updated_func(self): return self._get_setting(method.__name__) return updated_func @classmethod def set_setting(cls, method): def updated_func(self, value): return self._set_setting(method.__name__, value) return updated_func def __init__(self): self.update_settings() def update_settings(self, default=False): # Update with default settings self._config.update(self._default_config) # Update with internal settings (if exists and default is False) if not default: if os.path.exists(self._internal_settings_file): with open(self._internal_settings_file, 'r') as f: internal_config = json.load(f) self._config.update(internal_config) else: self._write() # Update with internal settings (if exists and _read_user is True) if self._read_user: if os.path.exists(self._user_settings_file): with open(self._user_settings_file, 'r') as f: user_config = json.load(f) self._config.update(user_config) def default_settings(self): self.update_settings(default=True) self._write() def _write(self): with open(self._internal_settings_file, 'w') as f: json.dump(self._config, f, indent=4) def _get_setting(self, setting): try: value = self._config[setting] except KeyError: raise KeyError("Cannot find the setting {} in the file {}".format( setting, self._internal_settings_file)) return value def _set_setting(self, setting, value): self._config[setting] = value self._write() # Below are the settings, note that _get_setting and _set_setting are automaticaly # called when a setting is set or get. When a value is set the values is saved to the # settings (json) file using the name of the property as key. @property @Decorator.get_setting def _read_user(self): pass @_read_user.setter @Decorator.set_setting def _read_user(self, _read_user): pass @property @Decorator.get_setting def sim_backend(self): pass @sim_backend.setter @Decorator.set_setting def sim_backend(self, sim_backend): pass @property @Decorator.get_setting def max_qubits(self): pass @max_qubits.setter @Decorator.set_setting def max_qubits(self, max_qubits): pass @property @Decorator.get_setting def max_registers(self): pass @max_registers.setter @Decorator.set_setting def max_registers(self, max_registers): pass @property @Decorator.get_setting def conn_retry_time(self): pass @conn_retry_time.setter @Decorator.set_setting def conn_retry_time(self, conn_retry_time): pass @property @Decorator.get_setting def recv_timeout(self): pass @recv_timeout.setter @Decorator.set_setting def recv_timeout(self, recv_timeout): pass @property @Decorator.get_setting def recv_retry_time(self): pass @recv_retry_time.setter @Decorator.set_setting def recv_retry_time(self, recv_retry_time): pass @property @Decorator.get_setting def log_level(self): pass @log_level.setter @Decorator.set_setting def log_level(self, log_level): pass @property @Decorator.get_setting def network_config_file(self): pass @network_config_file.setter @Decorator.set_setting def network_config_file(self, app_file): pass @property @Decorator.get_setting def noisy_qubits(self): pass @noisy_qubits.setter @Decorator.set_setting def noisy_qubits(self, noisy_qubits): pass @property @Decorator.get_setting def t1(self): pass @t1.setter @Decorator.set_setting def t1(self, t1): pass
class Settings: # Get path to SimulaQron folder simulaqron_path = get_simulaqron_path.main() _settings_file = os.path.join(simulaqron_path, "config/settings.ini") _config = ConfigParser() # default settings for if file is not ready yet CONF_MAXQUBITS = _DefaultSettings.CONF_MAXQUBITS CONF_MAXREGS = _DefaultSettings.CONF_MAXREGS CONF_WAIT_TIME = _DefaultSettings.CONF_WAIT_TIME CONF_RECV_TIMEOUT = _DefaultSettings.CONF_RECV_TIMEOUT CONF_RECV_EPR_TIMEOUT = _DefaultSettings.CONF_RECV_EPR_TIMEOUT CONF_WAIT_TIME_RECV = _DefaultSettings.CONF_WAIT_TIME_RECV CONF_LOGGING_LEVEL_BACKEND = _DefaultSettings.CONF_LOGGING_LEVEL_BACKEND CONF_LOGGING_LEVEL_FRONTEND = _DefaultSettings.CONF_LOGGING_LEVEL_FRONTEND CONF_BACKEND = _DefaultSettings.CONF_BACKEND CONF_TOPOLOGY_FILE = _DefaultSettings.CONF_TOPOLOGY_FILE CONF_APP_FILE = _DefaultSettings.CONF_APP_FILE CONF_CQC_FILE = _DefaultSettings.CONF_CQC_FILE CONF_VNODE_FILE = _DefaultSettings.CONF_VNODE_FILE CONF_NODES_FILE = _DefaultSettings.CONF_NODES_FILE CONF_NOISY_QUBITS = _DefaultSettings.CONF_NOISY_QUBITS CONF_T1 = _DefaultSettings.CONF_T1 log_levels = { "info": logging.INFO, "debug": logging.DEBUG, "warning": logging.WARNING, "error": logging.ERROR, "critical": logging.CRITICAL } @classmethod def init_settings(cls): _config = cls._config _config.read(cls._settings_file) config_changed = False if "BACKEND" not in _config: _config['BACKEND'] = {} backend = _config['BACKEND'] if "MaxQubits_Per_Node" in backend: cls.CONF_MAXQUBITS = int(backend['MaxQubits_Per_Node']) else: _config['BACKEND']['MaxQubits_Per_Node'] = str(cls.CONF_MAXQUBITS) config_changed = True if "MaxRegisters_Per_Node" in backend: cls.CONF_MAXREGS = int(backend['MaxRegisters_Per_Node']) else: _config['BACKEND']['MaxRegisters_Per_Node'] = str(cls.CONF_MAXREGS) config_changed = True if "WaitTime" in backend: cls.CONF_WAIT_TIME = float(backend['WaitTime']) else: backend['WaitTime'] = str(cls.CONF_WAIT_TIME) config_changed = True if "RecvTimeout" in backend: cls.CONF_RECV_TIMEOUT = float(backend['RecvTimeout']) else: backend['RecvTimeout'] = str(cls.CONF_RECV_TIMEOUT) config_changed = True if "RecvEPRTimeout" in backend: cls.CONF_RECV_EPR_TIMEOUT = float(backend['RecvEPRTimeout']) else: backend['RecvEPRTimeout'] = str(cls.CONF_RECV_EPR_TIMEOUT) config_changed = True if "WaitTimeRecv" in backend: cls.CONF_WAIT_TIME_RECV = float(backend['WaitTimeRecv']) else: backend['WaitTimeRecv'] = str(cls.CONF_WAIT_TIME_RECV) config_changed = True if "LogLevel" in backend: _log_level = backend['LogLevel'].lower() if _log_level in cls.log_levels: cls.CONF_LOGGING_LEVEL_BACKEND = cls.log_levels[_log_level] else: backend['LogLevel'] = list(cls.log_levels.keys())[list( cls.log_levels.values()).index( cls.CONF_LOGGING_LEVEL_BACKEND)] else: backend['LogLevel'] = list(cls.log_levels.keys())[list( cls.log_levels.values()).index(cls.CONF_LOGGING_LEVEL_BACKEND)] config_changed = True if "Backend" in backend: cls.CONF_BACKEND = backend["backend"] else: backend["backend"] = cls.CONF_BACKEND config_changed = True if "Topology_File" in backend: cls.CONF_TOPOLOGY_FILE = backend['Topology_File'] else: backend['Topology_File'] = cls.CONF_TOPOLOGY_FILE config_changed = True if "App_File" in backend: cls.CONF_APP_FILE = backend['App_File'] else: backend['App_File'] = cls.CONF_APP_FILE config_changed = True if "Cqc_File" in backend: cls.CONF_CQC_FILE = backend['Cqc_File'] else: backend['Cqc_File'] = cls.CONF_CQC_FILE config_changed = True if "Vnode_File" in backend: cls.CONF_VNODE_FILE = backend['Vnode_File'] else: backend['Vnode_File'] = cls.CONF_VNODE_FILE config_changed = True if "Nodes_File" in backend: cls.CONF_NODES_FILE = backend['Nodes_File'] else: backend['Nodes_File'] = cls.CONF_NODES_FILE config_changed = True if "noisy_qubits" in backend: cls.CONF_NOISY_QUBITS = backend['noisy_qubits'] == 'True' else: backend['noisy_qubits'] = str(cls.CONF_NOISY_QUBITS) config_changed = True if "T1" in backend: cls.CONF_T1 = float(backend['T1']) else: backend['T1'] = str(cls.CONF_T1) config_changed = True if "FRONTEND" not in _config: _config['FRONTEND'] = {} frontend = _config['FRONTEND'] if "LogLevel" in frontend: _log_level = frontend['LogLevel'].lower() if _log_level in cls.log_levels: cls.CONF_LOGGING_LEVEL_FRONTEND = cls.log_levels[_log_level] else: frontend['LogLevel'] = list(cls.log_levels.keys())[list( cls.log_levels.values()).index( cls.CONF_LOGGING_LEVEL_FRONTEND)] else: frontend['LogLevel'] = list(cls.log_levels.keys())[list( cls.log_levels.values()).index( cls.CONF_LOGGING_LEVEL_FRONTEND)] config_changed = True if config_changed: cls.save_settings() @classmethod def save_settings(cls): with open(cls._settings_file, 'w') as file: cls._config.write(file) @classmethod def set_setting(cls, section, key, value): cls._config[section][key] = value cls.save_settings() @classmethod def default_settings(cls): cls.CONF_MAXQUBITS = _DefaultSettings.CONF_MAXQUBITS cls.CONF_MAXREGS = _DefaultSettings.CONF_MAXREGS cls.CONF_WAIT_TIME = _DefaultSettings.CONF_WAIT_TIME cls.CONF_LOGGING_LEVEL_BACKEND = _DefaultSettings.CONF_LOGGING_LEVEL_BACKEND cls.CONF_LOGGING_LEVEL_FRONTEND = _DefaultSettings.CONF_LOGGING_LEVEL_FRONTEND cls.CONF_BACKEND = _DefaultSettings.CONF_BACKEND cls.CONF_TOPOLOGY_FILE = _DefaultSettings.CONF_TOPOLOGY_FILE cls.CONF_NOISY_QUBITS = _DefaultSettings.CONF_NOISY_QUBITS cls.CONF_T1 = _DefaultSettings.CONF_T1 if os.path.exists(cls._settings_file): os.remove(cls._settings_file) cls._config = ConfigParser() cls.init_settings() cls.save_settings()