Ejemplo n.º 1
0
class Controller:
    def __init__(self, filename):
        self.__fName = filename
        self.__graph = None
        self.__loadFromFile()

    def __loadFromFile(self):
        # may raise IOError if invalid filename
        f = open(self.__fName, "r")
        n, m = f.readline().strip().split()
        n = int(n)
        m = int(m)
        self.__graph = DiGraph(n)
        for i in range(m):
            x, y, cost = f.readline().strip().split()
            x = int(x)
            y = int(y)
            cost = int(cost)
            self.__graph.addEdge(x, y)
            self.__graph.setCost(x, y, cost)

    def graph(self):
        return self.__graph
Ejemplo n.º 2
0
class Controller:
    def __init__(self, file):
        '''
        Constructor for controller
        Input: f (string) filename to read a DiGraph from
        '''
        f = open(file, "r")
        n, m = f.readline().strip().split()
        n = int(n)
        m = int(m)
        self.__dg = DiGraph(n)
        for i in range(m):
            x, y, cost = f.readline().strip().split()
            x = int(x)
            y = int(y)
            cost = int(cost)
            self.__dg.addEdge(x, y)
            #self.__dg.setCost(x, y, cost) #! do not
        f.close()

    def getGraph(self):
        return self.__dg

    def BFS(self, s):
        '''
        Breadth first search algorithm (BFS)
        Input:  s - start vertex
        Output: visited (set) - the set of accessible vertices from s
                prev (dictionary) - each key has as value the vertex
                    that is previous to the key in the BFS path
                dist (dictionary) - each key represent a vertex and has
                    as value the length of the shortest path from s to it
        '''
        visited = set()  # set
        q = Queue()  # queue
        prev = {}  # dictionary
        dist = {}  # dictionary

        prev[s] = None
        dist[s] = 0

        q.enqueue(s)
        while len(q) > 0:
            x = q.dequeue()  # get the next element from the queue
            for y in self.__dg.iterateOut(x):
                if y not in visited:
                    visited.add(y)
                    q.enqueue(y)
                    prev[y] = x
                    dist[y] = dist[x] + 1

        return visited, prev, dist

    def getPath(self, s, t):
        '''
        Finds a lowest length path between given vertices s and t
            by using a forward breadth-first search algorithm
        Input:  s - source vertex
                t - target vertex
        Output: a lowest length path between s and t (list of vertices)
        '''
        if s >= self.__dg.getV() or t >= self.__dg.getV():
            raise KeyError("Invalid vertices.")

        path = []

        #1. we perform a BFS starting at s (source vertex)
        visited, prev, dist = self.BFS(s)

        #2. we check if t (target vertex) is in visited
        #       i.e. there exists a (lowest length) path from s to t
        if t not in visited:
            return None  # there is no path from s to t

        #3. we compute the path
#         path.append(v)
#         while v != s:           # while the current vertex is not the start vertex
#             for x in self.__dg.iterateIn(v):
#                 if x in dist and dist[x] == dist[v] - 1:
#                     v = x       # we search in the inbounds of v for a vertex whose path length from s
#                     break       # to it is just 1 unit below the path length from s to the current v
#             path.append(v)      # then, v becomes that vertex and we add it to the path list

        v = t  # we start at t
        path.append(t)
        while v != s:
            v = prev[v]
            path.append(v)
        #4. we reverse the order of elements in the list 'path'
        path.reverse()

        #5. we return the result
        return path
Ejemplo n.º 3
0
class Controller:
    def __init__(self):
        self.__g = DiGraph()  # vertex = activity
        self.__d = {}  # vertex : duration
        self.__ES = {}  # vertex : Earliest Start time
        self.__EF = {}  # vertex : Earliest Finish time
        self.__LS = {}  # vertex : Latest Start time
        self.__LF = {}  # vertex : Latest Finish time
        self.__total = 0  # total time of the project

    def initFromFile(self, file):
        f = open(file, "r")
        n = int(f.readline().strip())
        self.__init__()
        self.__g.addVertex("start")
        self.__d["start"] = 0
        self.__g.addVertex("end")
        self.__d["end"] = 0
        for i in range(1, n + 1, 1):
            self.__g.addVertex(i)
            self.__g.addEdge(i, "end")
        L = f.readline().strip().split()
        L = [int(x) for x in L]
        while len(L) > 1:
            self.__d[L[0]] = L[1]
            if len(L) > 2:
                for i in range(2, len(L), 1):
                    self.__g.addEdge(L[i], L[0])
            L = f.readline().strip().split()
            L = [int(x) for x in L]
        f.close()

    def clear(self):
        '''
        Clears all the activities and sets the project timing to zero.
        '''
        self.__init__()

    def getGraph(self):
        return self.__g

    def getDurationOf(self, x):
        if x not in self.__d.keys():
            raise KeyError
        return self.__d[x]

    def getES(self, x):
        if x not in self.__ES.keys():
            raise KeyError
        return self.__ES[x]

    def getLS(self, x):
        if x not in self.__LS.keys():
            raise KeyError
        return self.__LS[x]

    def getProjectTime(self):
        return self.__total

    def addActivity(self, act, duration):
        '''
        Add activity 'act' to the graph
        '''
        self.__g.addVertex(act)
        self.__d[act] = duration

    def setPrerequisites(self, act, prerequisites):
        '''
        Set the prerequisites for an activity
        Input: act - the activity
               prerequisites (list/iterable)
        '''
        for pre in prerequisites:
            self.__g.addEdge(pre, act)

    def toposort(self):
        '''
        Performs a topological sort of the vertices of a directed graph.
        It also checks if the digraph is a DAG.
        Returns: list of graph's vertices in toposort order
                 None, if the graph is NOT a DAG
        '''
        pred = {}
        q = Queue()
        q.put("start")  # put the "dummy" start activity in the queue
        pred[
            "start"] = 0  # just to make sure it is at the beginning of the toposort
        s = []
        #         for x in self.__g.iterate():
        for x in [x for x in self.__g.iterate() if x != "start"]:
            count = 0
            for y in self.__g.iterateIn(x):
                count += 1
            pred[x] = count
            if pred[x] == 0:
                q.put(x)
        while not q.empty():
            x = q.get()
            s.append(x)
            for y in self.__g.iterateOut(x):
                pred[y] -= 1
                if pred[y] == 0:
                    q.put(y)
        if len(s) == len(self.__g.iterate()):
            return s
        return None

    def computeTiming(self):
        '''
        Computes the timing of the project.
        !! Must be called before any attempt of timing request for an activity / whole project.
        !! After call, NO modification in the activities graph should be made
        Returns: nothing
        Raises: Exception in case the graph is not a DAG (and so, no scheduling can be made)
        '''
        acts = self.toposort()
        if acts == None:
            raise Exception("Error. Not a DAG.")

        self.__ES[acts[0]] = 0
        self.__EF[acts[0]] = self.__d[acts[0]]
        for j in range(1, len(acts), 1):
            L = [self.__EF[x] for x in self.__g.iterateIn(acts[j])]
            if len(L) > 0:
                self.__ES[acts[j]] = max(L)
            else:
                self.__ES[acts[j]] = 0
            self.__EF[acts[j]] = self.__ES[acts[j]] + self.__d[acts[j]]

        self.__total = self.__EF[acts[-1]]

        #         self.__LF[acts[len(acts) - 1]] = self.__total
        #         self.__LS[acts[len(acts) - 1]] = self.__total - self.__d[acts[len(acts) - 1]]
        self.__LF[acts[-1]] = self.__total
        self.__LS[acts[-1]] = self.__total - self.__d[acts[-1]]
        for i in range(len(acts) - 2, -1, -1):
            L = [self.__LS[x] for x in self.__g.iterateOut(acts[i])]
            if len(L) > 0:
                self.__LF[acts[i]] = min(L)
            else:
                self.__LF[acts[i]] = self.__total
            self.__LS[acts[i]] = self.__LF[acts[i]] - self.__d[acts[i]]

    def getCriticalActivities(self):
        '''
        Provides a list of critical activities
        '''
        result = []
        for act in self.__g.iterate():
            if self.__ES[act] == self.__LS[
                    act] and act != "start" and act != "end":
                result.append(act)
        return result