Esempio n. 1
0
    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)
Esempio n. 3
0
 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)
Esempio n. 4
0
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)
Esempio n. 5
0
    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()
Esempio n. 6
0
    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)
Esempio n. 7
0
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]))
Esempio n. 8
0
    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()
Esempio n. 9
0
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)
Esempio n. 10
0
    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")
Esempio n. 11
0
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
Esempio n. 12
0
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()
Esempio n. 13
0
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", "")
Esempio n. 14
0
 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)
Esempio n. 15
0
# 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")
Esempio n. 16
0
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
Esempio n. 17
0
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()