def update_edge_properties(self, lowerBoundTime, interval):
        """
        Updates the edge properties after computation of a new flowInterval
        :param lowerBoundTime: lowerBoundTime of flowInterval
        :param interval: flowInterval
        """

        for v, w in self.network.edges():
            # Inflow changes
            vTimeLower, vTimeUpper = self.node_label(
                v, interval.lowerBoundTime), self.node_label(
                    v, interval.upperBoundTime)
            inflowChangeBool = Utilities.is_not_eq_tol(
                interval.NTFNodeLabelDict[v],
                0)  # Can we extend the inflow interval?
            inflowVal = interval.NTFEdgeFlowDict[
                (v,
                 w)] / interval.NTFNodeLabelDict[v] if inflowChangeBool else 0
            if inflowChangeBool:
                self.network[v][w]['inflow'][(vTimeLower,
                                              vTimeUpper)] = inflowVal

            if vTimeUpper < float('inf'):
                vLastTime = next(
                    reversed(self.network[v][w]['cumulativeInflow']))
                self.network[v][w]['cumulativeInflow'][
                    vTimeUpper] = self.network[v][w]['cumulativeInflow'][
                        vLastTime] + inflowVal * (vTimeUpper - vTimeLower)

            # Outflow changes
            wTimeLower, wTimeUpper = self.node_label(
                w, interval.lowerBoundTime), self.node_label(
                    w, interval.upperBoundTime)
            outflowChangeBool = Utilities.is_not_eq_tol(
                interval.NTFNodeLabelDict[w],
                0)  # Can we extend the outflow interval?
            outflowVal = interval.NTFEdgeFlowDict[
                (v,
                 w)] / interval.NTFNodeLabelDict[w] if outflowChangeBool else 0
            if outflowChangeBool:
                self.network[v][w]['outflow'][(wTimeLower,
                                               wTimeUpper)] = outflowVal

            if wTimeUpper < float('inf'):
                wLastTime = next(
                    reversed(self.network[v][w]['cumulativeOutflow']))
                self.network[v][w]['cumulativeOutflow'][
                    wTimeUpper] = self.network[v][w]['cumulativeOutflow'][
                        wLastTime] + outflowVal * (wTimeUpper - wTimeLower)

            # Queue size changes
            if vTimeUpper < float('inf'):
                self.update_queue_size(v, w, vTimeLower, vTimeUpper)
            self.animationIntervals[(v, w)].append(
                ((vTimeLower, vTimeUpper), (wTimeLower, wTimeUpper)))

            if vTimeUpper <= wTimeUpper and vTimeUpper != float('inf'):
                # Lies on shortest path
                self.network[v][w]['load'][vTimeUpper] = self.arc_load(
                    v, w, vTimeUpper)
Пример #2
0
 def time_interval_correspondence(self, t):
     """
     :param t: timepoint
     :return: lastTime: lowerBound of flowInterval containing time
     """
     if Utilities.is_eq_tol(t, 0):
         return 0
     for lowerBoundTime in self.lowerBoundsToIntervalDict:
         if Utilities.is_geq_tol(t, lowerBoundTime):
             lastTime = lowerBoundTime
     return lastTime
Пример #3
0
    def __init__(self, network, resettingEdges, lowerBoundTime, inflowRate,
                 minCapacity, counter, outputDirectory, templateFile, scipFile,
                 timeout):
        """
        :param network: Networkx Digraph instance
        :param resettingEdges: list of resetting edges
        :param lowerBoundTime: \theta_k
        :param inflowRate: u_0
        :param minCapacity: minimum capacity of all edges in network
        :param counter: unique ID of FlowInterval - needed for directory creation
        :param outputDirectory: directory to output scip logs
        :param templateFile: path of template which is used by SCIP
        :param scipFile: path to scip binary
        :param timeout: seconds until timeout. Deactivated if equal to 0
        """

        self.network = network
        self.resettingEdges = resettingEdges
        self.lowerBoundTime = lowerBoundTime  # theta_k
        self.upperBoundTime = None  # theta_{k+1} = theta_k + self.alpha
        self.inflowRate = inflowRate
        self.minCapacity = minCapacity  # Needed for zimpl files
        self.id = counter
        self.outputDirectory = outputDirectory
        self.templateFile = templateFile
        self.scipFile = scipFile
        self.timeout = timeout

        self.foundNTF = False
        self.aborted = False
        self.alpha = None
        self.shortestPathNetwork = None  # to be set from NashFlowClass
        self.numberOfSolvedIPs = 0
        self.computationalTime = -1  # Elapsed computation time in seconds
        self.preprocessedNodes = 0
        self.preprocessedEdges = 0
        self.NTFNodeLabelDict = {node: 0 for node in self.network}
        self.NTFEdgeFlowDict = {edge: 0 for edge in self.network.edges()}
        self.binaryVariableNumberList = [
        ]  # List where each element is the size of E'_0 in a NTF call

        # Create FlowInterval Directory
        self.rootPath = os.path.join(
            self.outputDirectory,
            str(self.id) + '-FlowInterval-' + Utilities.get_time())
        Utilities.create_dir(self.rootPath)

        if self.timeout > 0:
            # Start thread controlling whether computation should be aborted
            self.timeoutThread = threading.Thread(target=self.timeout_control)
            self.timeoutThread.start()
Пример #4
0
 def get_outflow(self, v, w, t):
     """
     :param v: tail of edge
     :param w: head of edge
     :param t: time
     :return: f_(v,w)^-(t), i.e. outflow rate of e=(v,w) at time t (picking the newest value)
     """
     if Utilities.is_eq_tol(t, 0):
         return 0
     for wTimeLower, wTimeUpper in self.network[v][w]['outflow']:
         if Utilities.is_between_tol(wTimeLower, t, wTimeUpper):
             # t lies between l_w(theta_k) and l_w(theta_k+1)
             lastOutflow = self.network[v][w]['outflow'][(wTimeLower,
                                                          wTimeUpper)]
     return lastOutflow
Пример #5
0
    def __init__(self, graph, inflowRate, numberOfIntervals, outputDirectory,
                 templateFile, scipFile, cleanUpBool, timeout):
        """
        :param graph: Networkx Digraph instance
        :param inflowRate: u_0
        :param numberOfIntervals: number of intervals that will be computed. -1 if all
        :param outputDirectory: path where output should be saved
        :param templateFile: Selected method, i.e. 0,1,2
        :param scipFile: path to scip binary
        :param cleanUpBool: If true, then cleanup
        :param timeout: seconds until timeout. Deactivated if equal to 0
        """

        self.network = graph.copy()
        self.inflowRate = inflowRate  # For the moment: constant
        self.numberOfIntervals = numberOfIntervals  # No. of intervals to compute
        self.outputDirectory = outputDirectory

        # Template File from /source/templates
        self.templateFile = os.path.join(
            os.getcwd(), 'source', 'templates',
            'algorithm_' + str(templateFile + 1) + '.zpl')
        self.allInOne = (templateFile == 1)
        self.advancedAlgo = (
            templateFile == 2
        )  # If true, then advanced backtracking with preprocessing is performed

        self.scipFile = scipFile
        self.cleanUpBool = cleanUpBool
        self.numberOfSolvedIPs = 0
        self.computationalTime = 0
        self.infinityReached = False  # True if last interval has alpha = +inf
        self.timeout = timeout

        self.minCapacity = Utilities.compute_min_attr_of_network(self.network)
        self.counter = 0
        self.preprocessedNodes = 0
        self.preprocessedEdges = 0

        # Create directory for Nash-Flow
        self.rootPath = os.path.join(self.outputDirectory,
                                     'NashFlow-' + Utilities.get_time())
        Utilities.create_dir(self.rootPath)

        self.flowIntervals = [
        ]  # List containing triplets of form (lowerBound, upperBound, FlowInterval-instance)
        self.lowerBoundsToIntervalDict = OrderedDict()
        self.animationIntervals = {edge: [] for edge in self.network.edges()}
 def get_cumulative_outflow(self, v, w, t):
     """
     :param v: tail of edge
     :param w: head of edge
     :param t: time
     :return: F_(v,w)^-(t)
     """
     if Utilities.is_leq_tol(t, 0):
         return 0
     for timeInterval, outflowVal in reversed(
             self.network[v][w]['outflow'].items()):
         wTimeLower, wTimeUpper = timeInterval
         if Utilities.is_between_tol(wTimeLower, t, wTimeUpper):
             # This is the interval in which t lies
             return self.network[v][w]['cumulativeOutflow'][
                 wTimeLower] + outflowVal * (t - wTimeLower)
    def open_nfc(self, moveGraph=None):
        """
        Opens NashFlowComputation Tool
        :param moveGraph: network that should be moved, None if not specified
        :return:
        """

        if not moveGraph:
            # Just open the application
            cmd = ['python', '../mainControl.py']
        else:
            # Open the application with a certain graph
            # Save the graph
            tmpDir = gettempdir()
            tmpFileName = Utilities.get_time()
            tmpFilePath = os.path.join(tmpDir, tmpFileName)
            self.save_graph(graphPath=tmpFilePath)
            tmpFilePathArgument = tmpFilePath + '.cg'

            cmd = ['python', '../mainControl.py', '-l', tmpFilePathArgument]

        def open_nfc_thread():
            self.proc = subprocess.Popen(cmd)
            self.proc.communicate()

        thread = threading.Thread(target=open_nfc_thread)
        thread.start()
Пример #8
0
    def draw_edges(self, G, pos,
                   edgelist=None,
                   width=1.0,
                   edge_color='k',
                   style='solid',
                   alpha=1.0,
                   edge_cmap=None,
                   edge_vmin=None,
                   edge_vmax=None,
                   ax=None,
                   arrows=True,
                   label=None,
                   **kwds):
        """Workaround to call specific edge drawing function"""

        edges, boxes, tubes, arrows = Utilities.draw_animation_edges(G, pos,
                   edgelist,
                   width,
                   edge_color,
                   style,
                   alpha,
                   edge_cmap,
                   edge_vmin,
                   edge_vmax,
                   ax,
                   arrows,
                   label)

        self.tube_collection = tubes
        return edges, boxes, arrows
    def run_order(self):
        """Execution order"""
        self.rootPath = os.path.join(
            self.outputDirectory,
            str(self.id) + '-NTF-' + Utilities.get_time())
        Utilities.create_dir(self.rootPath)

        copy(self.templateFile, self.rootPath)
        self.templateFile = os.path.join(self.rootPath,
                                         os.path.basename(self.templateFile))
        self.logFile = os.path.join(self.rootPath, 'outputLog.txt')

        self.write_zimpl_files()
        self.start_process()

        self.check_result()
Пример #10
0
    def run(self, nextIntervalOnly=False):
        """
        Compute the flow intervals up to self.numberOfIntervals
        :param nextIntervalOnly: If True, only the next flow interval is computed
        """
        computedUpperBound = 0
        k = 1 if self.numberOfIntervals != -1 else -float('inf')

        if nextIntervalOnly:
            Utilities.create_dir(self.rootPath)
            self.compute_flowInterval()
        else:
            while computedUpperBound < float(
                    'inf') and k <= self.numberOfIntervals:
                self.compute_flowInterval()
                computedUpperBound = self.flowIntervals[-1][1]
                k += 1

        # Clean up
        if self.cleanUpBool:
            rmtree(self.rootPath)
 def is_full(self, v, w, t):
     """
     :param v: tail of edge
     :param w: head of edge
     :param t: time
     :return: True if d_(v,w)(t) ~= storage(v,w)
     """
     try:
         load = self.arc_load(v, w, t)
         return Utilities.is_eq_tol(load, self.network[v][w]['storage'])
     except TypeError:
         return False
Пример #12
0
    def assert_ntf(self):
        """Check if computed NTF really is an NTF"""
        # Works only on shortest path network
        p = lambda e: max(
            [self.NTFNodeLabelDict[e[0]], self.NTFEdgeFlowDict[e] / self.network[e[0]][e[1]]['outCapacity']]) \
            if e not in self.resettingEdges \
            else self.NTFEdgeFlowDict[e] / self.network[e[0]][e[1]]['outCapacity']
        for w in self.shortestPathNetwork:
            if self.shortestPathNetwork.in_edges(w):
                minimalCongestion = min(
                    map(p, self.shortestPathNetwork.in_edges(w)))
                assert (Utilities.is_eq_tol(minimalCongestion,
                                            self.NTFNodeLabelDict[w]))
        for v, w in self.shortestPathNetwork.edges():
            minimalCongestion = min(
                map(p, self.shortestPathNetwork.in_edges(w)))
            assert (Utilities.is_eq_tol(self.NTFEdgeFlowDict[v, w], 0)
                    or Utilities.is_eq_tol(p((v, w)), minimalCongestion))

        # Check if actually an s-t-flow
        for w in self.shortestPathNetwork:
            m = 0
            incomingEdges = self.shortestPathNetwork.in_edges(w)
            outgoingEdges = self.shortestPathNetwork.out_edges(w)
            for e in incomingEdges:
                m += self.NTFEdgeFlowDict[e]
            for e in outgoingEdges:
                m -= self.NTFEdgeFlowDict[e]

            if w == 's':
                assert (Utilities.is_eq_tol(m, (-1) * self.inflowRate))
            elif w == 't':
                assert (Utilities.is_eq_tol(m, self.inflowRate))
            else:
                assert (Utilities.is_eq_tol(m, 0))
    def change_edge_show_status(self, show=True):
        """
        Change whether zero-flow edges are visible or not
        """
        if show:
            self.network = self.originalNetwork.copy()
            # self.network = deepcopy(self.originalNetwork)
        else:
            removedEdges = []
            for edge in self.network.edges():
                if Utilities.is_eq_tol(self.NTFEdgeFlowDict[edge], 0):
                    removedEdges.append(edge)
            self.network.remove_edges_from(removedEdges)
            isolated_nodes = list(nx.isolates(self.network))
            self.network.remove_nodes_from(isolated_nodes)

        self.init_plot()
 def draw_nodes(G,
                pos,
                nodelist=None,
                node_size=300,
                node_color='r',
                node_shape='o',
                alpha=1.0,
                cmap=None,
                vmin=None,
                vmax=None,
                ax=None,
                linewidths=None,
                label=None,
                **kwds):
     """Workaround to specify node drawing function"""
     return Utilities.draw_nodes(G, pos, nodelist, node_size, node_color,
                                 node_shape, alpha, cmap, vmin, vmax, ax,
                                 linewidths, label)
    def add_hline_to_plots(self):
        """Add horizontal lines to intersect vertical line"""
        for hLine in self.hLines:
            hLine.remove()
        self.hLines = []
        self.lineToHLineDict = dict()

        for label in self.hLinesLabels:
            label.remove()
        self.hLinesLabels = []

        for plot in self.plots:
            xVals, yVals, line, label = plot

            # Get the y-value of self.verticalLinePos
            index = Utilities.get_insertion_point_left(xVals, self.verticalLinePos)
            if index == len(xVals) or index == 0:
                continue
            x1, x, x2 = xVals[index - 1], self.verticalLinePos, xVals[index]
            y1, y2 = yVals[index - 1], yVals[index]
            # It holds xVals[index-1] < self.verticalLinePos <= xVals[index]
            fac = float(x - x2) / (x1 - x2)
            y = fac * y1 + (1 - fac) * y2  # this obviously only works if plots are piecewise linear

            axes = self.figure.gca()
            lowerBound, upperBound = axes.get_xlim()
            lineBeginFac = float(x - lowerBound) / (upperBound - lowerBound)
            hLine = axes.axhline(y=y, xmin=lineBeginFac, xmax=1, linewidth=self.verticalLineWidth)
            hLine.set_color(self.verticalLineColor)
            self.hLines.append(hLine)
            hLineText = axes.text(1.02, y, "%.2f" % y, va='center', ha="left", bbox=dict(facecolor="w", alpha=0.5),
                                  transform=axes.get_yaxis_transform())
            hLineText.set_fontsize(8)
            self.hLinesLabels.append(hLineText)

            if not line.get_visible():
                hLine.set_visible(False)
                hLineText.set_visible(False)
            self.lineToHLineDict[line] = (hLine, hLineText)
    def draw_edges(self,
                   G,
                   pos,
                   edgelist=None,
                   width=1.0,
                   edge_color='k',
                   style='solid',
                   alpha=1.0,
                   edge_cmap=None,
                   edge_vmin=None,
                   edge_vmax=None,
                   ax=None,
                   arrows=True,
                   label=None,
                   **kwds):
        """Workaround to specify edge drawing function"""

        arrows = self.showArrows
        return Utilities.draw_edges_with_boxes(G, pos, edgelist, width,
                                               edge_color, style, alpha,
                                               edge_cmap, edge_vmin, edge_vmax,
                                               ax, arrows, label)
    def get_approx_data(self, t):
        """
        Returns approximated queue size and load at time t
        :param t: time
        :return: z_e(t), d_e(t),  where entries can be "N/A"
        """
        D = {'Queue size': "N/A", 'Load': "N/A"}
        for plot in self.plots:
            xVals, yVals, line, label = plot
            if label != 'Load' and label != "Queue size":
                continue

            index = Utilities.get_insertion_point_left(xVals, t)
            if index == len(xVals) or index == 0:
                continue
            else:
                x1, x, x2 = xVals[index - 1], t, xVals[index]
                y1, y2 = yVals[index - 1], yVals[index]
                # It holds: xVals[index-1] < t <= xVals[index]
                fac = float(x - x2) / (x1 - x2)
                y = fac * y1 + (1 - fac) * y2  # this obviously only works if plots are piecewise linear
                D[label] = y

        return D['Queue size'], D['Load']
    def get_edge_labels(self):
        """Returns dict of edge labels"""
        if self.type == 'general':
            attributes = ['outCapacity', 'transitTime'
                          ] if not self.onlyNTF else ['outCapacity']
            multipleBool = (len(attributes) > 1)
        elif self.type == 'spillback':
            attributes = ['inCapacity', 'outCapacity', 'storage', 'transitTime'] if not self.onlyNTF \
                            else ['outCapacity'] # 'inflowBound' has to be added manually below
            multipleBool = True
        attributeList = [
            nx.get_edge_attributes(self.network, attr) for attr in attributes
        ]
        if (self.type == 'spillback' and self.onlyNTF):
            attr = 'inflowBound'
            d = dict()
            for e in self.network.edges():
                (v, w) = e
                d[e] = self.network[v][w]['TFC'][attr]
            attributeList.append(d)

        labelDict = Utilities.join_intersect_dicts(*attributeList)

        # Integer values should be displayed in shortest possible way
        for key, valTuple in labelDict.items():
            if not multipleBool:
                if valTuple != float('inf') and valTuple == int(valTuple):
                    labelDict[key] = int(valTuple)
            else:
                newTuple = []
                for val in valTuple:
                    newTuple.append(
                        int(val) if (
                            val != float('inf') and int(val) == val) else val)
                labelDict[key] = tuple(newTuple)
        return labelDict
    def update_edges(self,
                     added=False,
                     removal=False,
                     moved=False,
                     color=False):
        """
        Redraw edges(s)
        :param added: If True then an edge has been added
        :param removal: If True then an edge has been removed
        :param moved: If True then an edge has been moved
        :param color: If True then the color of an edge has changed
        """
        if removal:
            # Edges have been deleted
            collectionIndex = 0
            toDeleteIndices = []
            for edges, edgeCollection in self.edgeCollections:
                missingEdges = [
                    edge for edge in edges if edge not in self.network.edges()
                ]
                if missingEdges:
                    boxCollection = self.boxCollections[collectionIndex][1]
                    arrowCollection = self.arrowCollections[collectionIndex][1]
                    edgeCollection.remove()
                    boxCollection.remove()
                    arrowCollection.remove()

                    edges = [
                        edge for edge in edges if edge not in missingEdges
                    ]
                    if edges:
                        positions = {
                            v: self.network.nodes[v]['position']
                            for v in self.network.nodes()
                        }
                        newEdgeCollection, newBoxCollection, newArrowCollection = self.draw_edges(
                            self.network,
                            pos=positions,
                            ax=self.axes,
                            arrow=True,
                            edgelist=edges,
                            width=self.edgeWidthSize)
                        self.edgeCollections[collectionIndex] = (
                            edges, newEdgeCollection)
                        self.boxCollections[collectionIndex] = (
                            edges, newBoxCollection)
                        self.arrowCollections[collectionIndex] = (
                            edges, newArrowCollection)

                    else:
                        toDeleteIndices.append(collectionIndex)

                    # Delete edge labels
                    for edge in missingEdges:
                        deletedLabel = self.edgeLabelCollection.pop(edge)
                        deletedLabel.remove()

                collectionIndex += 1

            for index in reversed(toDeleteIndices):
                del self.edgeCollections[index]
                del self.boxCollections[index]
                del self.arrowCollections[index]

        elif added:
            # A node has been added (can we do better than plotting all nodes again)
            if self.focusEdge is not None:
                v, w = self.focusEdge
                edgeCollection, boxCollection, arrowCollection = self.draw_edges(
                    self.network,
                    pos={
                        v: self.network.nodes[v]['position'],
                        w: self.network.nodes[w]['position']
                    },
                    ax=self.axes,
                    arrow=True,
                    edgelist=[self.focusEdge],
                    width=self.edgeWidthSize)

                self.edgeCollections.append(([self.focusEdge], edgeCollection))
                self.boxCollections.append(([self.focusEdge], boxCollection))
                self.arrowCollections.append(
                    ([self.focusEdge], arrowCollection))
                edgeLabelSize = int(round(self.edgeLabelFontSize))
                if not self.onlyNTF:
                    if self.type == 'general':
                        lbl = {
                            self.focusEdge: (self.network[v][w]['outCapacity'],
                                             self.network[v][w]['transitTime'])
                        }
                    elif self.type == 'spillback':
                        lbl = {
                            self.focusEdge: (self.network[v][w]['inCapacity'],
                                             self.network[v][w]['outCapacity'],
                                             self.network[v][w]['transitTime'],
                                             self.network[v][w]['storage'])
                        }
                else:
                    if self.type == 'general':
                        lbl = {
                            self.focusEdge: (self.network[v][w]['outCapacity'])
                        }
                    elif self.type == 'spillback':
                        lbl = {
                            self.focusEdge:
                            (self.network[v][w]['outCapacity'],
                             self.network[v][w]['TFC']['inflowBound'])
                        }
                self.edgeLabelCollection.update(
                    draw_networkx_edge_labels(
                        self.network,
                        pos={
                            v: self.network.nodes[v]['position'],
                            w: self.network.nodes[w]['position']
                        },
                        ax=self.axes,
                        edge_labels=lbl,
                        font_size=edgeLabelSize))

        elif moved:
            collectionIndex = 0
            for edges, edgeCollection in self.edgeCollections:
                pos = nx.get_node_attributes(self.network, 'position')

                p = 0.3
                edge_pos = []
                for edge in edges:
                    src, dst = np.array(pos[edge[0]]), np.array(pos[edge[1]])
                    s = dst - src
                    # src = src + p * s  # Box at beginning
                    # dst = src + (1 - p) * s  # Box at the end
                    dst = src  # No edge at all
                    edge_pos.append((src, dst))

                edge_pos = np.asarray(edge_pos)
                box_pos = np.asarray([(pos[e[0]], pos[e[1]]) for e in edges])
                # Move edges
                edgeCollection.set_segments(edge_pos)

                boxCollection = self.boxCollections[collectionIndex][1]
                # Move boxes
                boxCollection.remove()
                boxCollection = Utilities.get_boxes(edge_pos=box_pos)
                boxCollection.set_zorder(1)  # edges go behind nodes
                # boxCollection.set_label(label)
                self.axes.add_collection(boxCollection)
                self.boxCollections[collectionIndex] = (
                    self.boxCollections[collectionIndex][0], boxCollection)

                arrowCollection = self.arrowCollections[collectionIndex][1]
                # Move boxes
                arrowCollection.remove()
                arrowCollection = Utilities.get_arrows_on_edges(
                    edge_pos=box_pos)
                arrowCollection.set_zorder(2)  # edges go behind nodes
                # boxCollection.set_label(label)
                self.axes.add_collection(arrowCollection)
                self.arrowCollections[collectionIndex] = (
                    self.arrowCollections[collectionIndex][0], arrowCollection)

                collectionIndex += 1

        if color:
            # Update colors
            edgeSize = lambda v, w: self.edgeWidthSize if (
                v, w) != self.focusEdge else self.edgeWidthSize + 1
            boxSize = lambda v, w: 1 if (v, w) != self.focusEdge else 2
            collectionIndex = 0
            for edges, edgeCollection in self.edgeCollections:
                if edges:
                    edgeColorList = [
                        colorConverter.to_rgba(self.edgeColor(v, w), 1)
                        for v, w in edges
                    ]

                    edgeCollection.set_color(edgeColorList)
                    edgeCollection.set_linewidth(
                        [edgeSize(v, w) for v, w in edges])

                    boxCollection = self.boxCollections[collectionIndex][1]
                    boxCollection.set_edgecolor(edgeColorList)
                    boxCollection.set_linewidth(
                        [boxSize(v, w) for v, w in edges])

                    arrowCollection = self.arrowCollections[collectionIndex][1]
                    arrowCollection.set_edgecolor(edgeColorList)
                collectionIndex += 1

        # Update edge label texts and positions
        lbls = self.get_edge_labels()
        for edge, label in self.edgeLabelCollection.items(
        ):  # type(label) = matplotlib.text.Text object
            v, w = edge
            if self.focusNode is not None:
                if v not in self.focusNode and w not in self.focusNode:
                    # No need to update anything
                    continue

            lblTuple = lbls[(v, w)]
            if label.get_text() != lblTuple:
                label.set_text(lblTuple)
            posv = (self.network.nodes[v]['position'][0] * 0.5,
                    self.network.nodes[v]['position'][1] * 0.5)
            posw = (self.network.nodes[w]['position'][0] * 0.5,
                    self.network.nodes[w]['position'][1] * 0.5)
            pos = (posv[0] + posw[0], posv[1] + posw[1])
            label.set_position(pos)

            rotAngle = Utilities.get_edge_label_rotation(
                self.axes, posv, posw, pos)
            label.set_rotation(rotAngle)

        self.draw_idle()
Пример #20
0
    def draw_flow(self, edge, src, dst):
        """
        Draw flow animation
        :param edge: edge = vw to draw
        :param src: position of v
        :param dst: position of w
        """
        if self.edgeColoring[edge]:
            for fk in self.edgeColoring[edge].keys():
                self.edgeColoring[edge][fk].remove()
        self.edgeColoring[edge].clear()
        if self.widthReferenceSize[edge]:
            self.widthReferenceSize[edge].clear()
        if self.visualQueueColoring[edge]:
            self.visualQueueColoring.remove()

        v, w = edge
        time = self.timePoints[self.currentTimeIndex]
        transitTime = self.network[v][w]['transitTime']
        src = np.array(src)
        dst = np.array(dst)
        s = dst - src

        flowOnEdgeList = [self.flowOnEntireEdge[edge][fk][time] for fk in range(len(self.nashFlow.flowIntervals))]
        totalFlowOnEdge = sum(flowOnEdgeList)
        if Utilities.is_eq_tol(totalFlowOnEdge, 0):
            return

        overflowBlocks = []
        for fk in range(len(self.nashFlow.flowIntervals)):
            if Utilities.is_eq_tol(self.flowOnEdgeNotQueue[edge][fk][time], 0):
                # No flow on edgeNotQueue at this time
                continue

            inflowInterval, outflowInterval = self.nashFlow.animationIntervals[edge][fk]
            vTimeLower, vTimeUpper = inflowInterval
            inflow = float(self.network[v][w]['inflow'][(vTimeLower, vTimeUpper)])

            # These position factors are using that the amount on the edgeNotQueue has to be positive at this point
            # This implies that vTimeLower <= time <= vTimeUpper + transitTime

            startFac = float(time - vTimeUpper) / transitTime if time > vTimeUpper else 0
            endFac = float(time - vTimeLower) / transitTime if time <= vTimeLower + transitTime else 1

            start = src + startFac * s
            end = src + endFac * s

            edge_pos = np.asarray([(start, end)])
            edge_color = tuple(colorConverter.to_rgba(self.NTFColors[fk % len(self.NTFColors)],
                                                      alpha=1))

            widthRatioScale = min(1, inflow/self.maxWidthFlowSize[edge])
            self.widthReferenceSize[edge][fk] = max(self.tubeWidthMaximum*widthRatioScale, self.tubeWidthMinimum)
            # Drawing of flow tubes
            edgeCollection = LineCollection(edge_pos,
                                            colors=edge_color,
                                            linewidths=self.tubeWidthFactor*self.widthReferenceSize[edge][fk],
                                            antialiaseds=(1,),
                                            transOffset=self.axes.transData,
                                            alpha=1
                                            )

            edgeCollection.set_zorder(1)
            self.edgeColoring[edge][fk] = edgeCollection
            self.axes.add_collection(edgeCollection)

            # Drawing of overflow blocks
            '''
            if not overflowBlocks:
                if Utilities.is_eq_tol(self.flowOnQueue[edge][fk][time], 0):
                    continue
                else:
                    # Draw first block
                    blockSizeFactor = min(1, self.flowOnEntireEdge[edge][fk][time]/self.maxOverflowStorage[edge])

                    block = Rectangle(start - delta,
                                    width=d,
                                    height=14,
                                    transform=t,
                                    facecolor=self.NTFColors[fk % len(self.NTFColors)],
                                    linewidth=None,
                                    alpha=1)
                    overflowBlocks.append(block)
            else:
                pass
            '''

        if overflowBlocks:
            overflowBlockCollection = PatchCollection(boxes,
                                            match_original=True,
                                            antialiaseds=(1,),
                                            transOffset=self.axes.transData)
            self.visualQueueColoring[edge] = overflowBlockCollection
            self.axes.add_collection(overflowBlockCollection)
    def compute_NTF(self):
        """Computes NTF in current tab"""
        originalNetwork = self.gttr('network')
        network = deepcopy(originalNetwork)
        # Remove inactive edges from network
        inactiveEdges = [
            edge for edge in originalNetwork.edges()
            if not originalNetwork[edge[0]][edge[1]]['TFC']['active']
        ]
        network.remove_edges_from(inactiveEdges)
        # Remove nodes that are now no longer reachable
        L = []
        for (v, d) in network.in_degree():
            if d == 0 and v != 's':
                # Non-reachable node found
                L.append(v)
        network.remove_nodes_from(L)

        # Validate input
        returnCode = self.validate_thinflow_input(network)
        if returnCode != 0:
            # Invalid input has been given
            # Spawn warning
            QtWidgets.QMessageBox.question(QtWidgets.QWidget(),
                                           'Abort: Input error',
                                           self.get_error_message(returnCode),
                                           QtWidgets.QMessageBox.Ok)
            return

        # Drop current NTF plot
        self.re_init_NTF_frame()

        # Get necessary data
        resettingEdges = [
            edge for edge in network.edges()
            if network[edge[0]][edge[1]]['TFC']['resettingEnabled']
        ]
        lowerBoundTime = 0  # No needed for different times as only one flowInterval is being computed
        inflowRate = float(self.inflowLineEdit.text())
        minCapacity = Utilities.compute_min_attr_of_network(network)
        counter = "Standalone"
        rootPath = self.outputDirectory
        self.templateFile = self.templateComboBox.currentIndex()

        if self.currentTF == 'general':
            templateFile = os.path.join(
                os.getcwd(), 'templates',
                'algorithm_' + str(self.templateFile + 1) + '.zpl')
        elif self.currentTF == 'spillback':
            print(
                "Note: For spillback only the basic algorithm [1] is available and hence run now."
            )
            templateFile = os.path.join(os.getcwd(), 'templates',
                                        'algorithm_spillback_1.zpl')
        scipFile = self.scipFile
        timeout = float(self.timeoutLineEdit.text())

        self.save_config()

        if self.currentTF == 'general':
            self.interval_general = FlowInterval(network,
                                                 resettingEdges=resettingEdges,
                                                 lowerBoundTime=lowerBoundTime,
                                                 inflowRate=inflowRate,
                                                 minCapacity=minCapacity,
                                                 counter=counter,
                                                 outputDirectory=rootPath,
                                                 templateFile=templateFile,
                                                 scipFile=scipFile,
                                                 timeout=timeout)
        elif self.currentTF == 'spillback':
            fullEdges = []
            minInflowBound = float('inf')
            for e in network.edges():
                (v, w) = e
                minInflowBound = min(minInflowBound,
                                     network[v][w]['TFC']['inflowBound'])
            self.interval_spillback = FlowInterval_spillback(
                network,
                resettingEdges=resettingEdges,
                fullEdges=fullEdges,
                lowerBoundTime=lowerBoundTime,
                inflowRate=inflowRate,
                minCapacity=minCapacity,
                counter=counter,
                outputDirectory=rootPath,
                templateFile=templateFile,
                scipFile=scipFile,
                timeout=timeout,
                minInflowBound=minInflowBound)

        # Set shortest path network manually to entire graph (is the deepcopy really needed?)
        interval = self.gttr('interval')
        interval.shortestPathNetwork = deepcopy(network)
        if self.currentTF == 'spillback':
            interval.transfer_inflowBound(interval.shortestPathNetwork)

        self.advancedAlgo = (
            self.templateFile == 2
        )  # If true, then advanced backtracking with preprocessing is performed

        if self.currentTF == 'general':
            if self.advancedAlgo:
                interval.get_ntf_advanced()
            else:
                interval.get_ntf()
        elif self.currentTF == 'spillback':
            interval.get_ntf()

        self.sttr(
            'plotNTFCanvas', self.currentTF,
            PlotNTFCanvas(
                interval.shortestPathNetwork,
                self,
                intervalID=None,
                stretchFactor=self.plotNTFCanvasStretchFactor,
                showNoFlowEdges=self.showEdgesWithoutFlowCheckBox.isChecked(),
                onlyNTF=True))

        self.gttr('plotNTFFrameLayout').addWidget(self.gttr('plotNTFCanvas'))
        self.cleanup()
Пример #22
0
    def update_edge_properties(self, lowerBoundTime, interval):
        """
        Updates the edge properties after computation of a new flowInterval
        :param lowerBoundTime: lowerBoundTime of flowInterval
        :param interval: flowInterval
        """
        if lowerBoundTime == 0:
            # init in/outflow
            for v, w in self.network.edges():
                vTimeLower = self.node_label(v, 0)
                wTimeLower = self.node_label(w, 0)

                self.network[v][w]['inflow'] = OrderedDict()
                self.network[v][w]['inflow'][(0, vTimeLower)] = 0

                self.network[v][w]['outflow'] = OrderedDict()
                self.network[v][w]['outflow'][(0, wTimeLower)] = 0

                self.network[v][w]['cumulativeInflow'] = OrderedDict()
                self.network[v][w]['cumulativeInflow'][0] = 0
                self.network[v][w]['cumulativeInflow'][vTimeLower] = 0

                self.network[v][w]['cumulativeOutflow'] = OrderedDict()
                self.network[v][w]['cumulativeOutflow'][0] = 0
                self.network[v][w]['cumulativeOutflow'][wTimeLower] = 0

                self.network[v][w]['queueSize'] = OrderedDict()
                self.network[v][w]['queueSize'][0] = 0
                self.network[v][w]['queueSize'][
                    vTimeLower + self.network[v][w]['transitTime']] = 0

        for v, w in self.network.edges():

            # Inflow changes
            vTimeLower, vTimeUpper = self.node_label(
                v, interval.lowerBoundTime), self.node_label(
                    v, interval.upperBoundTime)
            inflowChangeBool = Utilities.is_not_eq_tol(
                interval.NTFNodeLabelDict[v],
                0)  # Can we extend the inflow interval?
            inflowVal = interval.NTFEdgeFlowDict[
                (v,
                 w)] / interval.NTFNodeLabelDict[v] if inflowChangeBool else 0
            if inflowChangeBool:
                self.network[v][w]['inflow'][(vTimeLower,
                                              vTimeUpper)] = inflowVal

            if vTimeUpper < float('inf'):
                vLastTime = next(
                    reversed(self.network[v][w]['cumulativeInflow']))
                self.network[v][w]['cumulativeInflow'][
                    vTimeUpper] = self.network[v][w]['cumulativeInflow'][
                        vLastTime] + inflowVal * (vTimeUpper - vTimeLower)

            # Outflow changes
            wTimeLower, wTimeUpper = self.node_label(
                w, interval.lowerBoundTime), self.node_label(
                    w, interval.upperBoundTime)
            outflowChangeBool = Utilities.is_not_eq_tol(
                interval.NTFNodeLabelDict[w],
                0)  # Can we extend the outflow interval?
            outflowVal = interval.NTFEdgeFlowDict[
                (v,
                 w)] / interval.NTFNodeLabelDict[w] if outflowChangeBool else 0
            if outflowChangeBool:
                self.network[v][w]['outflow'][(wTimeLower,
                                               wTimeUpper)] = outflowVal

            if wTimeUpper < float('inf'):
                wLastTime = next(
                    reversed(self.network[v][w]['cumulativeOutflow']))
                self.network[v][w]['cumulativeOutflow'][
                    wTimeUpper] = self.network[v][w]['cumulativeOutflow'][
                        wLastTime] + outflowVal * (wTimeUpper - wTimeLower)

            # Queue size changes
            if vTimeUpper < float('inf'):
                lastQueueSizeTime = next(
                    reversed(self.network[v][w]['queueSize']))
                lastQueueSize = self.network[v][w]['queueSize'][
                    lastQueueSizeTime]
                self.network[v][w]['queueSize'][
                    vTimeUpper + self.network[v][w]['transitTime']] = max(
                        0, lastQueueSize +
                        (inflowVal - self.network[v][w]['outCapacity']) *
                        (vTimeUpper - vTimeLower))

            self.animationIntervals[(v, w)].append(
                ((vTimeLower, vTimeUpper), (wTimeLower, wTimeUpper)))
    def update_queue_animation(self, radius=7):
        """Update queue animation to display different edge queue"""
        if not self.focusEdge:
            return
        if self.boxColoring:
            self.boxColoring.remove()
        self.boxColoring = None

        # Work setting
        edge = self.focusEdge
        time = self.timePoints[self.currentTimeIndex]

        totalFlowOnQueue = sum(
            self.flowOnQueue[edge][fk][time]
            for fk in range(len(self.nashFlow.flowIntervals)))

        if Utilities.is_eq_tol(totalFlowOnQueue, 0) or Utilities.is_eq_tol(
                self.maxQueueSize, 0):
            return

        flowRatio = [
            max(0,
                float(self.flowOnQueue[edge][fk][time]) / totalFlowOnQueue)
            for fk in range(len(self.nashFlow.flowIntervals))
        ]
        totalRatio = totalFlowOnQueue / float(self.maxQueueSize)

        delta = np.array([0, radius])
        src = np.array(self.src)
        dst = np.array(self.dst)
        s = dst - src
        angle = np.rad2deg(np.arctan2(s[1], s[0]))
        t = matplotlib.transforms.Affine2D().rotate_deg_around(
            src[0], src[1], angle)
        boxes = []
        lastProportion = 1
        for fk in range(len(self.nashFlow.flowIntervals)):
            if Utilities.is_eq_tol(flowRatio[fk], 0):
                continue

            d = np.sqrt(np.sum(((dst - src) * lastProportion)**2))
            rec = Rectangle(src - delta,
                            width=d,
                            height=radius * 2,
                            transform=t,
                            facecolor=self.NTFColors[fk % len(self.NTFColors)],
                            linewidth=int(lastProportion),
                            alpha=1)
            boxes.append(rec)

            lastProportion -= (totalRatio * flowRatio[fk])
        d = np.sqrt(np.sum(((dst - src) * (1 - totalRatio))**2))
        lastRec = Rectangle(src - delta,
                            width=d,
                            height=radius * 2,
                            transform=t,
                            facecolor='white',
                            linewidth=0,
                            alpha=1)
        boxes.append(lastRec)

        boxCollection = PatchCollection(boxes,
                                        match_original=True,
                                        antialiaseds=(1, ),
                                        transOffset=self.axes.transData)
        self.boxColoring = boxCollection
        self.axes.add_collection(boxCollection)
    def compute_flowInterval(self):
        """Method to compute a single flowInterval"""
        # Get lowerBoundTime
        lowerBoundTime = 0 if not self.flowIntervals else self.flowIntervals[
            -1][1]
        # Compute resettingEdges
        cmp_queue = lambda v, w, t: \
            Utilities.is_greater_tol(self.node_label(w, t),
                                     self.node_label(v, t) + self.network[v][w]['transitTime'])

        resettingEdges = [(v, w) for v, w in self.network.edges() if cmp_queue(v, w, lowerBoundTime)] \
            if lowerBoundTime > 0 else []

        edges_to_choose_from = self.network.edges(
        )  # Fulledges can be non resetting!
        fullEdges = [(v, w) for v, w in edges_to_choose_from
                     if self.is_full(v, w, self.node_label(v, lowerBoundTime))
                     ] if lowerBoundTime > 0 else []

        minInflowBound = None
        interval = FlowInterval_spillback(self.network,
                                          resettingEdges=resettingEdges,
                                          fullEdges=fullEdges,
                                          lowerBoundTime=lowerBoundTime,
                                          inflowRate=self.inflowRate,
                                          minCapacity=self.minOutCapacity,
                                          counter=self.counter,
                                          outputDirectory=self.rootPath,
                                          templateFile=self.templateFile,
                                          scipFile=self.scipFile,
                                          timeout=self.timeout,
                                          minInflowBound=minInflowBound)

        if lowerBoundTime == 0:
            interval.shortestPathNetwork = Utilities.get_shortest_path_network(
                self.network)  # Compute shortest path network
            for v, w in interval.shortestPathNetwork.edges():
                interval.shortestPathNetwork[v][w][
                    'inflowBound'] = self.network[v][w]['inCapacity']
        else:
            interval.shortestPathNetwork = Utilities.get_shortest_path_network(
                self.network,
                labels={
                    v: self.node_label(v, lowerBoundTime)
                    for v in self.network
                })  # Compute shortest path network

            for v, w in interval.shortestPathNetwork.edges():
                vTimeLower = self.node_label(v, lowerBoundTime)
                minimizer = self.get_outflow(
                    v, w, vTimeLower) if (v, w) in fullEdges else float('inf')
                interval.shortestPathNetwork[v][w]['inflowBound'] = min(
                    minimizer, self.network[v][w]['inCapacity'])

        minInflowBound = Utilities.compute_min_attr_of_network(
            interval.shortestPathNetwork, 'inflowBound')
        interval.set_minInflowBound(minInflowBound)

        start = time.time()
        interval.get_ntf()
        '''
        if self.advancedAlgo:
            interval.get_ntf_advanced()
        else:
            interval.get_ntf()
        '''
        end = time.time()
        self.computationalTime += (end - start)
        interval.computationalTime = end - start
        self.preprocessedNodes += interval.preprocessedNodes
        self.preprocessedEdges += interval.preprocessedEdges
        self.lowerBoundsToIntervalDict[lowerBoundTime] = interval

        if lowerBoundTime == 0:
            self.init_edge_properties()

        interval.compute_alpha({
            node: self.node_label(node, lowerBoundTime)
            for node in self.network
        })
        self.flowIntervals.append(
            (interval.lowerBoundTime, interval.upperBoundTime, interval))

        # Update in/out-flow rates
        self.update_edge_properties(lowerBoundTime, interval)

        self.counter += 1
        self.numberOfSolvedIPs += interval.numberOfSolvedIPs

        self.infinityReached = (interval.alpha == float('inf'))
Пример #25
0
    def compute_flowInterval(self):
        """Method to compute a single flowInterval"""
        # Get lowerBoundTime
        lowerBoundTime = 0 if not self.flowIntervals else self.flowIntervals[
            -1][1]

        # Compute resettingEdges
        resettingEdges = [(v, w) for v, w in self.network.edges()
                          if Utilities.is_greater_tol(
                              self.node_label(w, lowerBoundTime),
                              self.node_label(v, lowerBoundTime) +
                              self.network[v][w]['transitTime'], TOL)
                          ] if lowerBoundTime > 0 else []

        interval = FlowInterval(
            self.network,
            resettingEdges=resettingEdges,
            lowerBoundTime=lowerBoundTime,
            inflowRate=self.inflowRate,
            minCapacity=self.minCapacity,
            counter=self.counter,
            outputDirectory=self.rootPath,
            templateFile=self.templateFile,
            scipFile=self.scipFile,
            timeout=self.timeout,
        )

        if lowerBoundTime == 0:
            interval.shortestPathNetwork = Utilities.get_shortest_path_network(
                self.network)  # Compute shortest path network
        else:
            interval.shortestPathNetwork = Utilities.get_shortest_path_network(
                self.network,
                labels={
                    v: self.node_label(v, lowerBoundTime)
                    for v in self.network
                })  # Compute shortest path network

        start = time.time()
        if self.advancedAlgo:
            interval.get_ntf_advanced()
        else:
            interval.get_ntf()

        end = time.time()
        self.computationalTime += (end - start)
        interval.computationalTime = end - start
        self.preprocessedNodes += interval.preprocessedNodes
        self.preprocessedEdges += interval.preprocessedEdges
        self.lowerBoundsToIntervalDict[lowerBoundTime] = interval

        interval.compute_alpha({
            node: self.node_label(node, lowerBoundTime)
            for node in self.network
        })
        self.flowIntervals.append(
            (interval.lowerBoundTime, interval.upperBoundTime, interval))

        # Update in/out-flow rates
        self.update_edge_properties(lowerBoundTime, interval)

        self.counter += 1
        self.numberOfSolvedIPs += interval.numberOfSolvedIPs

        self.infinityReached = (interval.alpha == float('inf'))