示例#1
0
    def draw_line_between(self, origin_id: str, destination_id: str):
        """
        This method connects automatically the two rects given with an edge.

        Parameters
        ----------
        origin_id : str
            The origin node for the edge
        destination_id : str
            The destination node for the edge

        """

        origin_item = None
        destination_item = None

        # Find the rects corresponding to the given ids
        for rect, block in self.scene.blocks.items():
            if block.block_id == origin_id:
                origin_item = rect
            if block.block_id == destination_id:
                destination_item = rect

            if origin_item is not None and destination_item is not None:
                if "Pr" in origin_id:
                    self.scene.auto_add_line(origin_item, destination_item)
                    return
                try:
                    # Update the node input
                    NodeOps.update_node_input(
                        self.renderer.NN.nodes[destination_id],
                        self.renderer.NN.nodes[origin_id].out_dim)

                    # Update sequential nodes, if any
                    if len(self.renderer.NN.edges[destination_id]) > 1:
                        self.renderer.update_network_from(
                            destination_id, origin_id)

                    # The new line is drawn
                    line = self.scene.auto_add_line(origin_item,
                                                    destination_item)
                    out_dim = self.renderer.NN.nodes[
                        self.scene.blocks[origin_item].block_id].out_dim
                    line.update_dims(out_dim)

                    self.scene.blocks[origin_item].out_dim = out_dim
                    self.scene.blocks[destination_item].in_dim = out_dim
                    self.scene.blocks[
                        destination_item].out_dim = self.renderer.NN.nodes[
                            self.scene.blocks[destination_item].
                            block_id].out_dim
                    return

                except Exception as e:
                    self.renderer.delete_edge_from(origin_id)
                    dialog = MessageDialog(
                        str(e) + "\nPlease check dimensions.",
                        MessageType.ERROR)
                    dialog.exec()
                    return
示例#2
0
    def open_property(self):
        """
        This method opens a SMT file containing the description
        of the network properties. The file is checked to be
        consistent with the network and then parsed in order
        to build the property objects.

        Returns
        -------

        """
        # Check project
        if not self.network.nodes:
            err = MessageDialog("No network loaded!", MessageType.ERROR)
            err.exec()
            return

        # Select file
        property_file_name = QFileDialog.getOpenFileName(
            None, "Open property file", "", PROPERTY_FORMATS)

        if property_file_name != ("", ""):
            self.input_handler = InputHandler()

            QApplication.setOverrideCursor(Qt.WaitCursor)
            self.properties = self.input_handler.read_properties(
                property_file_name[0])
            QApplication.restoreOverrideCursor()
            self.opened_property.emit()
示例#3
0
    def read_properties(self, path: str) -> dict:
        """
        This method reads the SMT property file and
        creates a property for each node.

        Parameters
        ----------
        path : str
            The SMT-LIB file path.

        Returns
        -------
        dict
            The dictionary of properties

        """

        parser = SmtLibParser()
        try:
            script = parser.get_script_fname(path)
        except PysmtException:
            dialog = MessageDialog("Failed to parse SMT property.",
                                   MessageType.ERROR)
            dialog.exec()
            return dict()

        declarations = script.filter_by_command_name(
            ['declare-fun', 'declare-const'])
        assertions = script.filter_by_command_name('assert')
        var_set = []
        var_list = []
        properties = dict()

        for d in declarations:
            var_list.append(str(d.args[0]).replace('\'', ''))
            varname = str(d.args[0]).split('_')[0].replace(
                '\'', '')  # Variable format is <v_name>_<idx>
            if varname not in var_set:
                var_set.append(varname)

        counter = 0

        for a in assertions:
            line = str(a.args[0]).replace('\'', '')
            for v in var_set:
                if f" {v}" in line or f"({v}" in line:  # Either '(v ...' or '... v)'
                    if v not in properties.keys():
                        properties[v] = PropertyBlock(f"{counter}Pr",
                                                      "Generic SMT")
                        properties[v].smt_string = ''
                        properties[v].variables = list(
                            filter(lambda x: v in x, var_list))
                        counter += 1
                    conv = ExpressionTreeConverter()
                    wrap = conv.build_from_infix(line).as_prefix()
                    properties[v].smt_string += f"(assert {wrap})\n"
                    break

        return properties
示例#4
0
 def verify_network(self):
     if not self.renderer.NN.nodes:
         dialog = MessageDialog("No network to verify.", MessageType.ERROR)
         dialog.exec()
     elif not self.project.properties:
         dialog = MessageDialog("No property to verify.", MessageType.ERROR)
         dialog.exec()
     else:
         window = VerificationWindow(self.renderer.NN,
                                     self.project.properties)
         window.exec()
示例#5
0
    def verify_network(self):
        """
        This class is a Window for the training of the network.
        It features a file picker for choosing the dataset and
        a grid of parameters for tuning the procedure.

        """

        if self.strategy is None:
            err_dialog = MessageDialog("No verification methodology selected.",
                                       MessageType.ERROR)
            err_dialog.exec()
            return

        # Save properties
        path = 'never2/' + self.__repr__().split(' ')[-1].replace('>',
                                                                  '') + '.smt2'
        utility.write_smt_property(path, self.properties, 'Real')

        input_name = list(self.properties.keys())[0]
        output_name = list(self.properties.keys())[-1]

        # Add logger text box
        log_textbox = LoggerTextBox(self)
        logger = logging.getLogger("pynever.strategies.verification")
        logger.addHandler(log_textbox)
        logger.setLevel(logging.INFO)
        self.layout.addWidget(log_textbox.widget)

        logger.info("***** NeVer 2 - VERIFICATION *****")

        # Load NeVerProperty from file
        parser = reading.SmtPropertyParser(verification.SMTLIBProperty(path),
                                           input_name, output_name)
        to_verify = parser.parse_property()

        # Property read, delete file
        os.remove(path)

        # Launch verification
        self.strategy.verify(self.nn, to_verify)
        self.verify_btn.setEnabled(False)
        self.cancel_btn.setText("Close")
示例#6
0
    def save(self, _as: bool = True):
        """
        This method converts and saves the network in a file.
        It prompts the user before starting.

        Parameters
        ----------
        _as : bool
            This attribute distinguishes between "save" and "save as".
            If _as is True the network will be saved in a new file, while
            if _as is False the network will overwrite the current one.

        """

        # If the user picked "save as" option or there isn't a current file,
        # a dialog is opened to chose where to save the net
        if _as or self.file_name == ("", ""):
            self.file_name = QFileDialog.getSaveFileName(
                None, 'Save File', "", NETWORK_FORMATS_SAVE)

        if self.file_name != ("", ""):
            self.output_handler = OutputHandler()
            self.network.identifier = self.file_name[0].split('/')[-1].split(
                ".")[0]

            # A  "wait cursor" appears locking the interface
            QApplication.setOverrideCursor(Qt.WaitCursor)
            self.output_handler.save(self.network, self.file_name)
            if self.properties:
                self.output_handler.save_properties(self.properties,
                                                    self.file_name)
            QApplication.restoreOverrideCursor()

            # At the end of the loading, the main thread looks for eventual
            # Exception in the output_handler
            if self.output_handler.exception is not None:
                error_dialog = MessageDialog(
                    "Error in network saving: \n" +
                    str(self.output_handler.exception), MessageType.ERROR)
                error_dialog.exec()
示例#7
0
 def train_network(self):
     if not self.renderer.NN.nodes:
         dialog = MessageDialog("No network to train.", MessageType.ERROR)
         dialog.exec()
     else:
         window = TrainingWindow(self.renderer.NN)
         window.exec()
         if window.is_nn_trained:
             dialog = FuncDialog(
                 "Training completed. Weights and biases updated.\nSave network?",
                 self.project.save(False))
             dialog.exec()
示例#8
0
    def open(self):
        """
        This method opens a file for reading a network in one of the supported
        formats. The network is then converted by a thread, while a
        loading dialog is displayed.

        """

        # Open network
        self.file_name = QFileDialog.getOpenFileName(None, "Open network", "",
                                                     NETWORK_FORMATS_OPENING)

        # If a file has been selected:
        if self.file_name != ("", ""):
            self.input_handler = InputHandler()

            # A "wait cursor" appears
            QApplication.setOverrideCursor(Qt.WaitCursor)
            self.network = self.input_handler.read_network(self.file_name[0])
            if isinstance(self.network, pynn.SequentialNetwork) and \
                    self.network.input_id == '':
                self.network.input_id = 'X'
            QApplication.restoreOverrideCursor()

            # At the end of the loading, the main thread looks for potential
            # exceptions in the input_handler
            if self.input_handler.conversion_exception is not None:
                # If there is some error in converting, it is returned
                # an error message
                error_dialog = MessageDialog(
                    "Error in network reading: \n" +
                    str(self.input_handler.conversion_exception),
                    MessageType.ERROR)
                error_dialog.exec()
            else:
                self.opened_net.emit()
示例#9
0
    def parameters_action_validation(self) -> Optional[NodeBlock]:
        """
        This method performs a check on the object on which the parameters
        action is called, in order to prevent unwanted operations.

        Returns
        ----------
        NodeBlock
            The graphic wrapper of the NetworkNode selected, if present.

        """

        if self.canvas.scene.selectedItems():
            if type(self.canvas.scene.selectedItems()[0]) is QGraphicsRectItem:
                # Return block graphic object
                return self.canvas.scene.blocks[self.canvas.scene.selectedItems()[0]]
            elif type(self.canvas.scene.selectedItems()[0]) is GraphicLine:
                msg_dialog = MessageDialog("No parameters available for connections.", MessageType.ERROR)
                msg_dialog.exec()
        else:
            err_dialog = MessageDialog("No block selected.", MessageType.MESSAGE)
            err_dialog.exec()
示例#10
0
    def delete_selected(self):
        """
        This method deletes the selected block or edge.

        """

        if self.scene.mode != DrawingMode.IDLE:
            dialog = MessageDialog(
                "Cannot delete items in draw or insert mode.",
                MessageType.MESSAGE)
            dialog.exec()
        else:
            # Get selected item to delete
            item = self.scene.delete_selected()
            if item is not None:
                if type(item) == QGraphicsRectItem:
                    if self.scene.blocks[
                            item].block_id in self.project.properties.keys():
                        self.project.properties.pop(
                            self.scene.blocks[item].block_id)
                    if self.scene.blocks[
                            item].block_id in self.renderer.NN.nodes.keys():
                        # Get the first node
                        first_node = self.renderer.NN.get_first_node()

                        # If the node is in the network, delete it
                        new_tuple = self.renderer.delete_node(
                            self.scene.blocks[item].block_id)

                        # If there was a connection, preserve it
                        if new_tuple is not None:
                            self.draw_line_between(new_tuple[0], new_tuple[1])

                            # New first node
                            new_first_node = self.renderer.NN.get_first_node()
                            # If the first node is changed
                            if first_node is not new_first_node:
                                self.renderer.disconnected_network[new_first_node.identifier] \
                                    .is_head = True

                    # Delete block if not in connected network
                    if self.scene.blocks[
                            item].block_id in self.renderer.disconnected_network:
                        self.renderer.disconnected_network.pop(
                            self.scene.blocks[item].block_id)

                    # Remove item
                    self.scene.removeItem(item)
                    self.scene.blocks.pop(item)

                elif type(item) == GraphicLine:
                    # Deleting an edge makes the network non sequential
                    block_before = self.scene.blocks[item.origin]
                    block_after = self.scene.blocks[item.destination]

                    if isinstance(block_before, PropertyBlock):
                        if block_after.block_id in self.project.properties.keys(
                        ):
                            del self.project.properties[block_after.block_id]
                        self.scene.removeItem(block_before.rect)
                        self.scene.blocks.pop(block_before.rect)
                    else:
                        block_after.is_head = True

                    self.renderer.delete_edge_from(block_before.block_id)
                    item.remove_self()

            # Delete other selected items
            if self.scene.selectedItems():
                self.delete_selected()
示例#11
0
    def edit_node(self, block: NodeBlock):
        """
        This method propagates the changes stored in the block.edits
        attribute.

        Parameters
        ----------
        block : NodeBlock
            The block to update.

        """

        edits = block.edits
        if edits is not None and block.block_id in self.renderer.disconnected_network.keys(
        ):
            edit_node_id = edits[0]
            edit_data = edits[1]
            new_in_dim = None
            if "in_dim" in edit_data.keys():
                new_in_dim = edit_data["in_dim"]

            # If in_dim changes in FC, update in_features
            if block.node.name == 'Fully Connected' and new_in_dim is not None:
                edit_data["in_features"] = new_in_dim[-1]

            # If out_features changes in FC, update out_dim
            if block.node.name == 'Fully Connected' and 'out_features' in edit_data.keys(
            ):
                edit_data["out_dim"] = block.out_dim[:-1] + (
                    edit_data["out_features"], )

            for block_par, info in block.node.param.items():
                if "shape" in info:
                    str_shape = tuple(map(str, info["shape"].split(', ')))
                    new_shape = tuple()  # Confront
                    for dim in str_shape:
                        new_dim = block.block_data[dim]
                        if dim in edit_data:
                            new_dim = edit_data[dim]
                        if isinstance(new_dim, tuple):
                            new_shape += new_dim
                        else:
                            new_shape += (new_dim, )

                    # Add new Tensor value to edit_data
                    edit_data[block_par] = Tensor(
                        shape=new_shape,
                        buffer=np.random.normal(size=new_shape))

            try:  # Check if the network has changed
                self.renderer.edit_node(edit_node_id, edit_data)
            except Exception as e:
                dialog = MessageDialog(
                    str(e) + "\nImpossible to propagate changes.",
                    MessageType.ERROR)
                dialog.exec()

            # Update the graphic block
            self.renderer.disconnected_network[edit_node_id].update_labels()

            # Update dimensions in edges & nodes
            for line in self.scene.edges:
                if isinstance(self.scene.blocks[line.origin], NodeBlock):
                    origin_id = self.scene.blocks[line.origin].block_id
                    new_dim = self.renderer.NN.nodes[origin_id].out_dim
                    line.update_dims(new_dim)
                    self.scene.blocks[line.origin].out_dim = new_dim
                    self.scene.blocks[line.destination].in_dim = new_dim

            # Empty changes buffer
            block.edits = None
示例#12
0
    def draw_line_between_selected(self):
        """
        This method draws a line if an item was selected in draw_line mode.
        If the connection is legal, the network is updated, otherwise the edge
        is deleted.

        """

        # The method draw_line returns a tuple of the two blocks connected
        conn_nodes = self.scene.add_line()
        if conn_nodes is not None:
            origin = self.scene.blocks[conn_nodes[0]]
            destination = self.scene.blocks[conn_nodes[1]]

            if isinstance(origin, NodeBlock) and isinstance(
                    destination, PropertyBlock):
                conn_nodes[2].remove_self()
                dialog = MessageDialog("Illegal property connection.",
                                       MessageType.ERROR)
                dialog.exec()
                return

            if isinstance(origin, PropertyBlock) and isinstance(
                    destination, NodeBlock):
                origin.variables = utility.create_variables_from(
                    destination.block_id, destination.out_dim)
                origin.pre_condition = False
                origin.condition_label.setText("POST")

                # Properties dict is {node_id: property}
                if origin in self.project.properties.values():
                    # Find key of origin
                    key = list(self.project.properties.keys())[list(
                        self.project.properties.values()).index(origin)]
                    del self.project.properties[key]

                self.project.properties[destination.block_id] = origin
                return

            try:
                # Add the new node to the network
                legal = self.renderer.add_edge(origin.block_id,
                                               destination.block_id)
                if legal:
                    if self.renderer.NN.get_first_node(
                    ).identifier == origin.block_id:
                        origin.is_head = True

                    # Draw dimensions
                    in_dim = self.renderer.NN.nodes[
                        destination.block_id].in_dim

                    if isinstance(self.renderer.NN.nodes[destination.block_id],
                                  nodes.FullyConnectedNode):
                        out_dim = self.renderer.NN.nodes[
                            destination.block_id].out_features
                    else:
                        out_dim = self.renderer.NN.nodes[
                            destination.block_id].out_dim

                    self.scene.blocks[conn_nodes[0]].out_dim = in_dim
                    self.scene.blocks[conn_nodes[1]].out_dim = out_dim
                    destination.in_dim = in_dim
                    destination.is_head = False

                    drawn_edge = conn_nodes[2]
                    drawn_edge.update_dims(in_dim)

                else:
                    # If the edge is illegal for a legal network, it is removed
                    conn_nodes[2].remove_self()
                    dialog = MessageDialog("Sequential network: illegal edge.",
                                           MessageType.ERROR)
                    dialog.exec()
            except Exception as e:
                # If an error occurs, the edge is removed
                conn_nodes[2].remove_self()
                dialog = MessageDialog(str(e), MessageType.ERROR)
                dialog.exec()
示例#13
0
    def insert_node(self):
        """
        This method inserts a block inside the network. The selected
        edge is split in two edges.

        """

        result = self.scene.add_node()
        if result is not None:
            # Nodes
            prev_node = self.scene.blocks[result[0]]
            middle_node = self.scene.blocks[result[1]]

            # Edges
            old_line = result[2]
            l1 = result[3]
            l2 = result[4]

            try:
                # The logical network is modified
                legal = self.renderer.insert_node(prev_node.block_id,
                                                  middle_node.block_id)
            except Exception as e:
                # In case of error, the new edges are deleted
                l1.remove_self()
                l2.remove_self()
                # a Message is displayed
                dialog = MessageDialog(str(e), MessageType.ERROR)
                dialog.exec()
                return

            try:
                if not legal:
                    # If the modification is not possible, the new edges are
                    # removed
                    l1.remove_self()
                    l2.remove_self()
                    dialog = MessageDialog(
                        "Sequential network : illegal operation.",
                        MessageType.ERROR)
                    dialog.exec()
                else:
                    # Otherwise the old edge is removed
                    old_line.remove_self()

                    # inputs and dimensions labels are updated
                    out_dim_1 = self.renderer.NN.nodes[
                        prev_node.block_id].out_dim
                    out_dim_2 = self.renderer.NN.nodes[
                        middle_node.block_id].out_dim

                    # Dimension labels are updated
                    l1.update_dims(out_dim_1)
                    l2.update_dims(out_dim_2)
                    self.scene.blocks[result[0]].out_dim = out_dim_1

                    # Scene blocks are updated
                    self.scene.blocks[l2.origin].in_dim = out_dim_1
                    self.scene.blocks[l2.destination].in_dim = out_dim_2

                    self.scene.blocks[l2.origin].is_head = False
            except Exception as e:
                next_node = self.scene.blocks[l2.destination]
                if prev_node.out_dim is not middle_node.in_dim:
                    l1.set_valid(False)
                if middle_node.out_dim is not next_node.in_dim:
                    l2.set_valid(False)

                dialog = MessageDialog(
                    str(e) + "\nPlease check dimensions.", MessageType.ERROR)
                dialog.exec()
示例#14
0
    def train_network(self):
        """
        This method reads the inout from the window widgets and
        launches the training procedure on the selected dataset.


        """

        err_dialog = None
        if self.dataset_path == "":
            err_dialog = MessageDialog("No dataset selected.",
                                       MessageType.ERROR)
        elif self.widgets["Optimizer"].currentIndex() == -1:
            err_dialog = MessageDialog("No optimizer selected.",
                                       MessageType.ERROR)
        elif self.widgets["Scheduler"].currentIndex() == -1:
            err_dialog = MessageDialog("No scheduler selected.",
                                       MessageType.ERROR)
        elif self.widgets["Loss Function"].currentIndex() == -1:
            err_dialog = MessageDialog("No loss function selected.",
                                       MessageType.ERROR)
        elif self.widgets["Precision Metric"].currentIndex() == -1:
            err_dialog = MessageDialog("No metrics selected.",
                                       MessageType.ERROR)
        elif "value" not in self.params["Epochs"].keys():
            err_dialog = MessageDialog("No epochs selected.",
                                       MessageType.ERROR)
        elif "value" not in self.params["Validation percentage"].keys():
            err_dialog = MessageDialog("No validation percentage selected.",
                                       MessageType.ERROR)
        elif "value" not in self.params["Training batch size"].keys():
            err_dialog = MessageDialog("No training batch size selected.",
                                       MessageType.ERROR)
        elif "value" not in self.params["Validation batch size"].keys():
            err_dialog = MessageDialog("No validation batch size selected.",
                                       MessageType.ERROR)
        if err_dialog is not None:
            err_dialog.exec()
            return

        # Load dataset
        data = self.load_dataset()

        # Add logger text box
        log_textbox = LoggerTextBox(self)
        logger = logging.getLogger("pynever.strategies.training")
        logger.addHandler(log_textbox)
        logger.setLevel(logging.INFO)
        self.layout.addWidget(log_textbox.widget)

        logger.info("***** NeVer 2 - TRAINING *****")

        # Create optimizer dictionary of parameters
        opt_params = dict()
        for k, v in self.gui_params["Optimizer:Adam"].items():
            opt_params[v["name"]] = v["value"]

        # Create scheduler dictionary of parameters
        sched_params = dict()
        for k, v in self.gui_params["Scheduler:ReduceLROnPlateau"].items():
            sched_params[v["name"]] = v["value"]

        # Init loss function
        if self.loss_f == "Loss Function:Cross Entropy":
            loss = torch.nn.CrossEntropyLoss()
            if self.gui_params["Loss Function:Cross Entropy"]["Weight"][
                    "value"] != '':
                loss.weight = self.gui_params["Loss Function:Cross Entropy"][
                    "Weight"]["value"]
            loss.ignore_index = self.gui_params["Loss Function:Cross Entropy"][
                "Ignore index"]["value"]
            loss.reduction = self.gui_params["Loss Function:Cross Entropy"][
                "Reduction"]["value"]
        else:
            loss = fun.mse_loss
            loss.reduction = self.gui_params["Loss Function:MSE Loss"][
                "Reduction"]["value"]

        # Init metrics
        if self.metric == "Precision Metric:Inaccuracy":
            metrics = PytorchMetrics.inaccuracy
        else:
            metrics = fun.mse_loss
            metrics.reduction = self.gui_params["Precision Metric:MSE Loss"][
                "Reduction"]["value"]

        # Checkpoint loading
        checkpoints_path = self.params["Checkpoints root"].get(
            "value", '') + self.nn.identifier + '.pth.tar'
        if not os.path.isfile(checkpoints_path):
            checkpoints_path = None

        start_epoch = 0
        if checkpoints_path is not None:
            checkpoint = torch.load(checkpoints_path)
            start_epoch = checkpoint["epoch"]
            if self.params["Epochs"]["value"] <= start_epoch:
                start_epoch = -1
                logger.info(
                    "Checkpoint already reached, no further training necessary"
                )

        if start_epoch > -1:
            # Init train strategy
            train_strategy = PytorchTraining(
                opt.Adam,
                opt_params,
                loss,
                self.params["Epochs"]["value"],
                self.params["Validation percentage"]["value"],
                self.params["Training batch size"]["value"],
                self.params["Validation batch size"]["value"],
                opt.lr_scheduler.ReduceLROnPlateau,
                sched_params,
                metrics,
                cuda=self.params["Cuda"]["value"],
                train_patience=self.params["Train patience"].get(
                    "value", None),
                checkpoints_root=self.params["Checkpoints root"].get(
                    "value", ''),
                verbose_rate=self.params["Verbosity level"].get("value", None))
            try:
                self.nn = train_strategy.train(self.nn, data)
                self.is_nn_trained = True

                # Delete checkpoint if the network isn't saved
                if self.nn.identifier == '':
                    os.remove('.pth.tar')
            except Exception as e:
                self.nn = None
                dialog = MessageDialog("Training error:\n" + str(e),
                                       MessageType.ERROR)
                dialog.exec()
                self.close()

        self.train_btn.setEnabled(False)
        self.cancel_btn.setText("Close")
示例#15
0
    def save(self, _as: bool = True):
        """
        This method saves the current network if the format is correct

        Parameters
        ----------
        _as : bool, optional
            This attribute distinguishes between "save" and "save as".
            If _as is True the network will be saved in a new file, while
            if _as is False the network will overwrite the current one.
            (Default: True)

        """

        if len(self.canvas.renderer.NN.nodes) == 0 or \
                len(self.canvas.renderer.NN.edges) == 0:
            # Limit case: one disconnected node -> new network with one node
            if len(self.canvas.renderer.disconnected_network) == 1:
                for node in self.canvas.renderer.disconnected_network:
                    try:
                        self.canvas.renderer.add_node_to_nn(node)
                        self.canvas.project.save(_as)
                        self.setWindowTitle(self.SYSNAME + " - " + self.canvas.project.network.identifier)
                    except Exception as e:
                        error_dialog = MessageDialog(str(e), MessageType.ERROR)
                        error_dialog.exec()

            # More than one disconnected nodes cannot be saved
            elif len(self.canvas.renderer.disconnected_network) > 1:
                not_sequential_dialog = MessageDialog("The network is not sequential, and "
                                                      "cannot be saved.",
                                                      MessageType.ERROR)
                not_sequential_dialog.exec()
            else:
                # Network is empty
                message = MessageDialog("The network is empty!", MessageType.MESSAGE)
                message.exec()

        elif self.canvas.renderer.is_nn_sequential():
            # If there are logical nodes, the network is sequential
            every_node_connected = True
            # every node has to be in the nodes dictionary
            for node in self.canvas.renderer.disconnected_network:
                if node not in self.canvas.project.network.nodes:
                    every_node_connected = False
                    break

            if every_node_connected:
                self.canvas.project.save(_as)
                if self.canvas.project.network is not None:
                    self.setWindowTitle(self.SYSNAME + " - " + self.canvas.project.network.identifier)
            else:
                # If there are disconnected nodes, a message is displayed to the
                # user to choose if saving only the connected network
                confirm_dialog = ConfirmDialog("Save network",
                                               "All the nodes outside the "
                                               "sequential network will lost.\n"
                                               "Do you wish to continue?")
                confirm_dialog.exec()
                if confirm_dialog.confirm:
                    self.canvas.project.save(_as)
                    if self.canvas.project.network is not None:
                        self.setWindowTitle(self.SYSNAME + " - " + self.canvas.project.network.identifier)
        else:
            # If the network is not sequential, it cannot be saved.
            not_sequential_dialog = MessageDialog("The network is not sequential and "
                                                  "cannot be saved.",
                                                  MessageType.ERROR)
            not_sequential_dialog.exec()
示例#16
0
 def temp_window():
     dialog = MessageDialog("Work in progress...", MessageType.MESSAGE)
     dialog.exec()