Example #1
0
    def _prepare_graph_for_calc(self, g: Graph, new_edges):
        """
        Initialises marked edges and pre-graph for further calculations.
        Pre-graph is copy of original graph with zero-flow edges.
        :param g:
        :param new_edges:
        :return:
        """
        # 0. Preparing graph
        # 0.1. Marking new edges
        pr_gr = g.__copy__()
        for new_edge in new_edges:
            new_edge.mark = True
            pr_gr.add_edge(new_edge)

        # 0.2. Initialising flows by zero value
        marked_edges = []
        zero_flow = FuzzyNumber(0)
        for i in range(g.num_vertices):
            for j in range(len(pr_gr[i])):
                # TODO UNNECESSARY COPING AND SETTING
                current_edge = pr_gr[i][j].__copy__()
                if current_edge.mark:
                    current_edge.capacity = current_edge.flow
                    marked_edges.append(current_edge)
                current_edge.flow = zero_flow
                pr_gr[i][j] = current_edge
        return marked_edges, pr_gr
Example #2
0
    def __init__(self, *args):
        if len(args) == 0:
            return
        self.graph = [[]]
        self.source = 0
        self.sink = 0
        self.num_vertices = 0
        self.num_edges = 0
        file = args[0]
        with open(file) as f:
            n = int(f.readline())
            self.num_vertices = n
            self.graph = [[] for i in range(n)]

            m = int(f.readline())
            self.num_edges = m
            self.source = int(f.readline())
            self.sink = int(f.readline())
            # TODO fix stupid line reading
            for i in range(m):
                if i == 3:
                    pass
                line = f.readline().split()
                assert len(line) == 2, "1st line must have exactly 2 numbers - vertices ids"
                vertices = to_int(line)
                v_from, v_to = vertices[0], vertices[1]

                line = f.readline().split(',')
                assert len(line) == 3, "2nd line must have exactly 3 numbers - fuzzy number for a flow"
                fl = to_float(line)
                flow = FuzzyNumber(fl[0], fl[1], fl[2])

                line = f.readline().split(',')
                assert len(line) == 3, "3nd line must have exactly 3 numbers - fuzzy number for a capacity"
                cap = to_float(line)
                capacity = FuzzyNumber(cap[0], cap[1], cap[2])

                w = int(f.readline())
                new_edge = Edge(vert_from=v_from,
                                vert_to=v_to,
                                capacity=capacity,
                                flow=flow,
                                weight=w)
                self.graph[v_from].append(new_edge)
Example #3
0
 def _build_residual(self, g: Graph):
     n = g.num_vertices
     # res_graph = [[] for i in range(n)]
     # Copy just for comfortable initialisation. TODO make it right
     res_graph = g.__copy__()
     res_graph.drop_edges()
     for i in range(n):
         for j in range(len(g[i])):
             current_edge = g[i][j].__copy__()
             reverse_edge = current_edge.reverse()
             if current_edge.flow == FuzzyNumber(0):
                 res_graph.add_edge(current_edge)
             if current_edge.flow > FuzzyNumber(0) and \
                     current_edge.flow < current_edge.capacity:
                 res_graph.add_edge(current_edge)
                 res_graph.add_edge(reverse_edge)
             if current_edge.flow == current_edge.capacity:
                 res_graph.add_edge(reverse_edge)
     return res_graph
Example #4
0
    def predict(self) -> Graph:
        """
        Edmonds-Karp's algorithm

        :return:
        """
        s, t = self.prepared_graph.source, self.prepared_graph.sink

        flow = FuzzyNumber(0)

        # First fill up marked edges, then all the rest
        marked_edges_to_fill = set(self.marked_edges)
        while True:
            while len(marked_edges_to_fill) > 0:
                edge = marked_edges_to_fill.pop()

                path = self._find_path(self.residual_graph,
                                       s,
                                       t,
                                       through_edge=edge)

                # If path through the current marked edge does not exist,
                # skip current edge and don't consider it again
                if len(path) == 0:
                    continue

                d_flow = self._augment_path(path)
                flow += d_flow

                # If path is found and marked edge still has capacity,
                # push it back to consider it later
                if edge.flow < edge.capacity:
                    marked_edges_to_fill.add(edge)
                print("found through")
                print("\t", Graph.str_path(path), "added flow:", d_flow)

            path = self._find_path(self.residual_graph, s, t)
            if len(path) == 0:
                break

            d_flow = self._augment_path(path)
            flow += d_flow

            print("found")
            print("\t", Graph.str_path(path), "added flow:", d_flow)
        print("TOTAL FLOW", flow)
        return self.residual_graph
Example #5
0
    def _build_residual(self, g: Graph) -> Graph:
        """
        Creates residual graph. Direct edges are the same objects as in original graph.
        :param g: original graph.
        :return: residual graph
        """
        n = g.num_vertices
        res_graph = g.__copy__()
        for i in range(n):
            for edge in g[i]:
                current_flow = edge.flow
                current_cap = edge.capacity

                edge.capacity = current_cap
                rev = edge.reverse()
                # TODO THIS NEGATION COULD BE TOTALLY WRONG
                rev.flow = FuzzyNumber(0) - current_flow
                rev.capacity = current_cap
                res_graph.add_edge(rev)
        return res_graph
Example #6
0
    def _prepare_graph_for_calc(self, g: Graph, new_edges: List[Edge]):
        """
        Prepares graph for further calculations.
        :param g:
        :param new_edges:
        :return:
        """
        # 0. Preparing graph
        # 0.1. Marking new edges
        pr_gr = g.__copy__()
        for new_edge in new_edges:
            new_edge.mark = True
            pr_gr.add_edge(new_edge)

        # 0.2. Initialising flows by zero value
        marked_edges = []
        for i in range(g.num_vertices):
            for j in range(len(pr_gr[i])):
                current_edge = pr_gr[i][j]
                if current_edge.mark:
                    current_edge.capacity = current_edge.flow
                    marked_edges.append(current_edge)
                current_edge.flow = FuzzyNumber(0)
        return marked_edges, pr_gr
Example #7
0
    def predict(self):
        current_flow = FuzzyNumber(0)
        s, t = self.prepared_graph.source, self.prepared_graph.sink

        counter = 0
        current_graph = self.prepared_graph.__copy__()
        while current_flow < self.fixed_flow:
            counter += 1
            # 1.  Gf
            res_gr = self._build_residual(current_graph)

            best_dist = INF
            best_path = []
            residual_path = []
            for new_edge in self.marked_edges:
                if new_edge.flow == new_edge.capacity:
                    continue

                v_from = new_edge.vert_from
                v_to = new_edge.vert_to
                edge_weight = new_edge.weight

                path_to_edge_dist, path_to_e = Graph.ford_bellman(
                    res_gr, s, v_from)
                path_from_edge_dist, path_from_e = Graph.ford_bellman(
                    res_gr, v_to, t)

                if path_to_edge_dist + edge_weight + path_from_edge_dist < best_dist:
                    best_dist = path_to_edge_dist + edge_weight + path_from_edge_dist

                    # Building path as edges by the visited vertices in G
                    ## Converting path of vertices to path of edges returns refs on edges from current_graph
                    best_path = Graph.convert_path_to_edges(
                        current_graph, path_to_e)
                    best_path.append(new_edge)
                    best_path.extend(
                        Graph.convert_path_to_edges(current_graph,
                                                    path_from_e))

                    # Building path as edges by the visited vertices in G_f
                    residual_path = Graph.convert_path_to_edges(
                        res_gr, path_to_e)
                    residual_path.append(new_edge)
                    residual_path.extend(
                        Graph.convert_path_to_edges(res_gr, path_from_e))
            if best_dist == INF:
                raise RuntimeError(
                    "No path through the marked edge was found BUT graph was not saturated"
                )

            min_flow = FuzzyNumber(0, INF, 0)
            for i, edge in enumerate(best_path):
                # TODO dangerous. logic is hidden.
                if residual_path[i].reversed:
                    min_flow = min(min_flow, edge.flow)
                else:
                    min_flow = min(min_flow, edge.capacity - edge.flow)
            min_flow = min(min_flow, self.fixed_flow - current_flow)

            for edge in best_path:
                edge.flow = edge.flow + min_flow
            current_flow = current_flow + min_flow
        self.prediction = current_graph
        return current_graph