123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777 |
- import math
- from cbd.CBDBlocks import *
- #the old CBD formalism simulator
- #topological sorting needs to be extracted from this
- class CBDsimulator:
- def __init__(self, model, curIteration=0):
- flattened = False
- self.__model = model
- self.__depGraph = None
- self.sortedGraph = None
- for block in model.getBlocks():
- if isinstance(block,CBD) and flattened == False:
- model.flatten()
- flattened = True
- self.__curIteration = curIteration
- #get de sortedlist of components to use for constant folding optimization
- """self.__depGraph = self.__createDepGraph()
- self.sortedGraph = self.__depGraph.getStrongComponents()
- model.foldConstants(self.sortedGraph)
- model.dump()"""
- self.__depGraph = None
- self.sortedGraph = None
- #return the dep graph
- #TODO: make sure this is safe to do
- def getDepGraph(self):
- if self.__depGraph == None:
- self.__depGraph = self.__createDepGraph()
-
- return self.__depGraph
-
-
- # to add: flattening of hierarchical CBDs before simulation starts
-
- def getModel(self):
- return self.__model
-
- def step(self):
- #print("Iteration" + str(self.__curIteration))
-
- if (self.__curIteration < 2):
- self.__depGraph = self.__createDepGraph()
- """print "----------------- Dependency Graph ---------------------"
- print self.__depGraph
- print "--------------------------------------------------------"""""
- self.sortedGraph = self.__depGraph.getStrongComponents()
- #print "-- Sorted collection of Strongly Connected Components --"
- #print self.sortedGraph # a list of lists
- #print "--------------------------------------------------------"
-
- self.__computeBlocks()
- self.__curIteration += 1
- # Constructs the dependency graph of the current state of the CBD
- def __createDepGraph(self):
- #self.__model.dump()
- blocks = self.__model.getBlocks()
- depGraph = DepGraph()
-
- for block in blocks:
- #print "Block before Depgraph", block
- depGraph.addMember(block)
-
- for block in blocks:
-
- if not block.Trigger == None:
- depGraph.setDependency(block,block.Trigger)
- if isinstance(block, DelayBlock):
- if (self.__curIteration == 0):
- if block.IC in blocks:
- depGraph.setDependency(block,block.IC)
- else:
- raise ValueError("No block linked to IC port of: ", block.getBlockName())
- else:
- pass
- else:
- for influencer in block.linksIN:
- if influencer in blocks:
- depGraph.setDependency(block, influencer)
- else:
- raise ValueError("No block linked to port of: ", block.getBlockName())
- if isinstance(block,TestBlock):
- if block.TRUE_in in blocks:
- depGraph.setDependency(block,block.TRUE_in)
- else:
- raise ValueError("No block linked to TRUE port of: ", block.getBlockName())
- if block.FALSE_in in blocks:
- depGraph.setDependency(block,block.FALSE_in)
- else:
- raise ValueError("No block linked to FALSE port of: ", block.getBlockName())
- # TO IMPLEMENT
- # Treat dependencies on memory blocks (Delay, Integrator, Derivative) differently:
- # During the first iteration (time == 0.0), the block only depends on the IC;
- # During later iterations, it depends on the block type.
- #
- # use depGraph.setDependency(block, block_it_depends_on)
- #
-
- return depGraph
-
- def __computeGeneric(self, block):
- operator = getattr(math, block.getBlockOperator())
- output = operator(block.linksIN[0].getSignal()[self.__curIteration])
- block.appendToSignal(output)
- def __computeConstant(self, block):
- # TO IMPLEMENT
- block.appendToSignal(block.getValue())
- def __computeScope(self,block):
- influentBlock = block.linksIN[0]
- block.appendToSignal(influentBlock.getSignal()[self.__curIteration])
- def __computeNegator(self, block):
- if 1:
- #if block.Trigger.getSignal()[self.__curIteration]:
- influentBlock = block.linksIN[0]
- block.appendToSignal(-influentBlock.getSignal()[self.__curIteration])
- else:
- block.appendToSignal(block.getSignal()[self.__curIteration-1])
- def __computeGain(self, block):
- if 1:
- #if block.Trigger.getSignal()[self.__curIteration]:
- influentBlock = block.linksIN[0]
- block.appendToSignal(influentBlock.getSignal()[self.__curIteration]*block.gain)
- else:
- block.appendToSignal(block.getSignal()[self.__curIteration-1])
- def __computeInverter(self, block):
- if 1:
- #if block.Trigger.getSignal()[self.__curIteration]:
- influentBlock = block.linksIN[0]
- if influentBlock.getSignal()[self.__curIteration] == 0:
- raise ValueError("Can't divide by 0: ", block.getBlockName())
- else:
- block.appendToSignal(1/influentBlock.getSignal()[self.__curIteration])
- else:
- block.appendToSignal(block.getSignal()[self.__curIteration-1])
-
- def __computeAdder(self, block):
- if 1:
- #if block.Trigger.getSignal()[self.__curIteration]:
- sum = 0
- for influentBlock in block.linksIN:
- sum += influentBlock.getSignal()[self.__curIteration]
- block.appendToSignal(sum)
- else:
- block.appendToSignal(block.getSignal()[self.__curIteration-1])
- def __computeProduct(self, block):
- if 1:
- #if block.Trigger.getSignal()[self.__curIteration]:
- prod = 1
- for influentBlock in block.linksIN:
- prod *= influentBlock.getSignal()[self.__curIteration]
- block.appendToSignal(prod)
- else:
- block.appendToSignal(block.getSignal()[self.__curIteration-1])
- def __computePower(self, block):
- if 1:
- #if block.Trigger.getSignal()[self.__curIteration]:
- influentBlock = block.linksIN[0]
- block.appendToSignal(influentBlock.getSignal()[self.__curIteration] ** block.power)
- else:
- block.appendToSignal(block.getSignal()[self.__curIteration-1])
- def __computeModulo(self, block):
- if 1:
- #if block.Trigger.getSignal()[self.__curIteration]:
- influentBlock = block.linksIN[0]
- if block.div == 0:
- raise ValueError("Can't divide by 0: ", block.getBlockName())
- else:
- block.appendToSignal(influentBlock.getSignal()[self.__curIteration] % block.div)
- else:
- block.appendToSignal(block.getSignal()[self.__curIteration-1])
- def __computeDelay(self, block):
- if 1:
- #if block.Trigger.getSignal()[self.__curIteration]:
-
- if self.__curIteration == 0:
- block.appendToSignal(block.IC.getSignal()[self.__curIteration])
- else:
- block.appendToSignal(block.linksIN[0].getSignal()[self.__curIteration - 1])
- else:
- block.appendToSignal(block.getSignal()[self.__curIteration-1])
- def __computeDerivative(self, block):
- # Should never be used. Derivative blocks should be replaced
- # by block diagrams using only Delay blocks
- if (self.__curIteration == 0):
- output = block.IC.getSignal()[self.__curIteration]
- else:
- influent_block = block.linksIN[0] # only one input
- influent_signal = influent_block.getSignal()
- output = (influent_signal[self.__curIteration] - \
- influent_signal[self.__curIteration-1]) / \
- block.getTimeIncrement()
- block.appendToSignal(output)
- def __computeIntegrator(self, block):
- # Should never be used. Integrator blocks should be replaced
- # by block diagrams using only Delay blocks
- if (self.__curIteration == 0):
- output = block.IC.getSignal()[self.__curIteration]
- else:
- if block.reset and block.reset.getSignal()[self.__curIteration-1]:
- #print("Resetting")
- #print(block.getBlockName())
- influent_block = block.init_val
- output = influent_block.getSignal()[self.__curIteration - 1]
- else:
- #print("Not resetting")
- influent_block = block.linksIN[0] # only one input
- influent_signal = influent_block.getSignal()
- output = block.getSignal()[self.__curIteration-1] + \
- influent_signal[self.__curIteration-1] * \
- block.getTimeIncrement()
- block.appendToSignal(output)
- def __computeTest(self, block):
- if 1:
- #if block.Trigger.getSignal()[self.__curIteration]:
- influentBlock = block.linksIN[0]
- if block.expr == "=":
- if influentBlock.getSignal()[self.__curIteration] == block.switch_value:
- block.appendToSignal(block.TRUE_in.getSignal()[self.__curIteration])
- else:
- block.appendToSignal(block.FALSE_in.getSignal()[self.__curIteration])
- elif block.expr == ">":
- if influentBlock.getSignal()[self.__curIteration] > block.switch_value:
- block.appendToSignal(block.TRUE_in.getSignal()[self.__curIteration])
- else:
- block.appendToSignal(block.FALSE_in.getSignal()[self.__curIteration])
- elif block.expr == "<":
- if influentBlock.getSignal()[self.__curIteration] < block.switch_value:
- block.appendToSignal(block.TRUE_in.getSignal()[self.__curIteration])
- else:
- block.appendToSignal(block.FALSE_in.getSignal()[self.__curIteration])
- elif block.expr == "<=":
- if influentBlock.getSignal()[self.__curIteration] < block.switch_value or influentBlock.getSignal()[self.__curIteration] == block.switch_value:
- block.appendToSignal(block.TRUE_in.getSignal()[self.__curIteration])
- else:
- block.appendToSignal(block.FALSE_in.getSignal()[self.__curIteration])
- elif block.expr == ">=":
- if influentBlock.getSignal()[self.__curIteration] > block.switch_value or influentBlock.getSignal()[self.__curIteration] == block.switch_value:
- block.appendToSignal(block.TRUE_in.getSignal()[self.__curIteration])
- else:
- block.appendToSignal(block.FALSE_in.getSignal()[self.__curIteration])
- else:
- raise ValueError("Expression "+block.expr+" isn't a legal expression. Allowed expression are: = > < >= <=")
- else:
- block.appendToSignal(block.getSignal()[self.__curIteration-1])
- def __computeSequence(self, block):
- if 1:
- #if block.Trigger.getSignal()[self.__curIteration]:
- block.appendToSignal(block.seq[block.iteration])
- if self.__curIteration != 0:
- block.iteration += 1
- if block.iteration == len(block.seq):
- block.iteration = 0
- else:
- block.appendToSignal(block.getSignal()[self.__curIteration-1])
- def __computeFloor(self, block):
- if 1:
- #if block.Trigger.getSignal()[self.__curIteration]:
- influentBlock = block.linksIN[0]
- block.appendToSignal(math.floor(influentBlock.getSignal()[self.__curIteration]))
- else:
- block.appendToSignal(block.getSignal()[self.__curIteration-1])
- def __computeBlocks(self):
- for component in self.sortedGraph:
- if (not self.__hasCycle(component)):
- block = component[0] # the strongly connected component has a single element
- #print "Block type + name:", block.getBlockType(),":",block.getBlockName()
- if isinstance(block, GenericBlock):
- self.__computeGeneric(block)
- elif isinstance(block, ConstantBlock):
- self.__computeConstant(block)
- elif isinstance(block, ScopeBlock):
- self.__computeScope(block)
- elif isinstance(block, NegatorBlock):
- self.__computeNegator(block)
- elif isinstance(block, InverterBlock):
- self.__computeInverter(block)
- elif isinstance(block, AdderBlock):
- self.__computeAdder(block)
- elif isinstance(block, ProductBlock):
- self.__computeProduct(block)
- elif isinstance(block, GainBlock):
- self.__computeGain(block)
- elif isinstance(block, FloorBlock):
- self.__computeFloor(block)
- elif isinstance(block, PowerBlock):
- self.__computePower(block)
- elif isinstance(block, ModuloBlock):
- self.__computeModulo(block)
- elif isinstance(block, DerivativeBlock):
- self.__computeDerivative(block)
- elif isinstance(block, IntegratorBlock):
- self.__computeIntegrator(block)
- elif isinstance(block, DelayBlock): # note that this needs to come AFTER Derivative and Integrator !
- # as they are sub-classes of DelayBlock
- self.__computeDelay(block)
- elif isinstance(block, TestBlock):
- self.__computeTest(block)
- elif isinstance(block,SequenceRepeater):
- self.__computeSequence(block)
- elif isinstance(block, CBD):
- raise ValueError("Hierachical blocks should have been flattened by now")
- else:
- raise ValueError("Unknown block type")
- else: #TODO what happens when blocks in loop have different rates?
- print("Component" + str(component))
- # Detected a strongly connected component
- assert self.__isLinear(component), "Cannot solve non-linear algebraic loop"
- solverInput = self.__constructLinearInput(component)
- print("########### Input matrix for linear solver -> ###########")
- self.__printLinearInputMatrices(component, solverInput)
- self.__gaussjLinearSolver(solverInput)
- solutionVector = solverInput[1]
- print("########### Solution from linear solver -> ###########")
- for block in component:
- blockIndex = component.index(block)
- block.appendToSignal(solutionVector[blockIndex])
- print(block.getBlockName() + "=", solutionVector[blockIndex] + "\n")
-
- # Determine whether a component is cyclic
- def __hasCycle(self, component):
- assert len(component)>=1, "A component should have at least one element"
- if len(component)>1:
- return True
- else: # a strong component of size one may still have a cycle: a self-loop
- if self.__depGraph.hasDependency(component[0], component[0]):
- return True
- else:
- return False
- # Determines if an algebraic loop describes a linear equation or not
- def __isLinear(self, strongComponent):
- # TO IMPLEMENT
- for block in strongComponent:
- if (isinstance(block, NegatorBlock) or isinstance(block, AdderBlock) or isinstance(block,GainBlock) ):
- pass
- elif isinstance(block, ProductBlock):
- strongInputs = 0
- for influentBlock in block.linksIN:
- if (influentBlock in strongComponent):
- strongInputs += 1
- if (strongInputs >= 2):
- return False
- else:
- return False
- print("Linear algebraic loop detected")
- return True
- # Constructs input for a solver of systems of linear equations
- # Input consists of two matrices:
- # M1: coefficient matrix, where each row represents an equation of the system
- # M2: result matrix, where each element is the result for the corresponding equation in M1
- def __constructLinearInput(self, strongComponent):
- size = len(strongComponent)
- row = []
- M1 = []
- M2 = []
-
- # Initialize matrices with zeros
- i = 0
- while (i < size):
- j = 0
- row = []
- while (j < size):
- row.append(0)
- j += 1
- M1.append(row)
- M2.append(0)
- i += 1
-
- # TO IMPLEMENT
- for index in range(0, len(strongComponent)):
- print("index = ", index)
- block = strongComponent[index]
- print("strongComponent.index = " + str(strongComponent.index(block)))
- blockType = block.getBlockType()
- if isinstance(block, AdderBlock):
- for influentblock in block.linksIN:
- if (not(influentblock in strongComponent)):
- M2[index] = -influentblock.getSignal()[self.__curIteration]
- print("I'm here " + str(influentblock.getSignal()[self.__curIteration]) +
- str(M2))
- else:
- print("influentblock index = " + str(strongComponent.index(influentblock)))
- print("M1 = " + str(M1))
- M1[index][index] = -1
- M1[index][strongComponent.index(influentblock)] = 1
- elif isinstance(block, NegatorBlock):
- influentblock = block.linksIN[0]
- M2[index] = 0
- M1[index][index] = -1
- M1[index][strongComponent.index(influentblock)] = -1
- elif isinstance(block, ProductBlock):
- factor = 1
- infuentindex = 0
- for influentblock in block.linksIN:
- if (not(influentblock in strongComponent)):
- factor = influentblock.getSignal()[self.__curIteration]
- else:
- infuentindex = strongComponent.index(influentblock)
- M2[index] = 0
- M1[index][index] = -1
- M1[index][infuentindex] = factor
- else:
- print("Fault in check linear")
- return [M1, M2]
-
- def __swap(self, a, b):
- t = a
- a = b
- b = t
- return (a, b)
-
- def __ivector(self, n):
- v = []
- for i in range(n):
- v.append(0)
- return v
-
- # Linear equation solution by Gauss-Jordan elimination
- def __gaussjLinearSolver(self, solverInput):
- M1 = solverInput[0]
- M2 = solverInput[1]
- n = len(M1)
- indxc = self.__ivector(n)
- indxr = self.__ivector(n)
- ipiv = self.__ivector(n)
- icol = 0
- irow = 0
- for i in range(n):
- big = 0.0
- for j in range(n):
- if (ipiv[j] != 1):
- for k in range(n):
- if (ipiv[k] == 0):
- if (math.fabs(M1[j][k]) >= big):
- big = math.fabs(M1[j][k])
- irow = j
- icol = k
- elif (ipiv[k] > 1):
- raise ValueError("GAUSSJ: Singular Matrix-1")
- ipiv[icol] += 1
- if (irow != icol):
- for l in range(n):
- (M1[irow][l], M1[icol][l]) = self.__swap(M1[irow][l], M1[icol][l])
- (M2[irow], M2[icol]) = self.__swap(M2[irow], M2[icol])
- indxr[i] = irow
- indxc[i] = icol
- if (M1[icol][icol] == 0.0):
- raise ValueError("GAUSSJ: Singular Matrix-2")
- pivinv = 1.0/M1[icol][icol]
- M1[icol][icol] = 1.0
- for l in range(n):
- M1[icol][l] *= pivinv
- M2[icol] *= pivinv
- for ll in range(n):
- if (ll != icol):
- dum = M1[ll][icol]
- M1[ll][icol] = 0.0
- for l in range(n):
- M1[ll][l] -= M1[icol][l] * dum
- M2[ll] -= M2[icol] * dum
- l = n
- while (l > 0):
- l -= 1
- if (indxr[l] != indxc[l]):
- for k in range(n):
- (M1[k][indxr[l]], M1[k][indxc[l]]) = self.__swap(M1[k][indxr[l]], M1[k][indxc[l]])
-
- # Print out the input matrices
- def __printLinearInputMatrices(self, strongComponent, solverInput):
- print("Indices:")
- i = 0
- for block in strongComponent:
- print(str(i) + ":" + block.getBlockName() + block.getBlockType())
- i += 1
- print("Matrices:")
- M1 = solverInput[0]
- M2 = solverInput[1]
- for row in M1:
- print(row + "=" + M2[M1.index(row)])
- """ This module implements a dependency graph
- @author: Marc Provost
- @organization: McGill University
- @license: GNU General Public License
- @contact: marc.provost@mail.mcgill.ca
- """
- import copy
- class DepNode:
- """ Class implementing a node in the dependency graph.
- """
-
- def __init__(self, object):
- """ DepNode's constructor.
- @param object: Reference to a semantic object identifying the node
- @type object: Object
- """
- self.__object = object
- self.__isMarked = False
- def mark(self):
- self.__isMarked = True
-
- def unMark(self):
- self.__isMarked = False
-
- def isMarked(self):
- return self.__isMarked
- def getMappedObj(self):
- return self.__object
-
- def __repr__(self):
- return "DepNode :: "+str(self.__object)
-
- class DepGraph:
- """ Class implementing dependency graph.
- """
- def __init__(self):
- """ DepGraph's constructor.
- """
- #Dict holding a mapping "Object -> DepNode"
- self.__semanticMapping = {}
-
- #map object->list of objects depending on object
- self.__dependents = {}
- #map object->list of objects that influences object
- self.__influencers = {}
-
- def __repr__(self):
- repr = "Dependents: \n"
- for dep in self.__dependents:
- repr += dep.getBlockName() + ":" + str(self.__dependents[dep]) + "\n"
- repr += "Influencers: \n"
- for infl in self.__influencers:
- repr += infl.getBlockName() + ":" + str(self.__influencers[infl]) + "\n"
- return repr
- def addMember(self, object):
- """ Add an object mapped to this graph.
- @param object: the object to be added
- @type object: Object
- @raise ValueError: If object is already in the graph
- """
- if not self.hasMember(object):
- node = DepNode(object)
- self.__dependents[object] = []
- self.__influencers[object] = []
- self.__semanticMapping[object] = node
- else:
- raise ValueError("Specified object is already member of this graph")
-
- def hasMember(self, object):
- return object in self.__semanticMapping
- def removeMember(self, object):
- """ Remove a object from this graph.
- @param object: the object to be removed
- @type object: Object
- @raise ValueError: If object is not in the graph
- """
- if self.hasMember(object):
- for dependent in self.getDependents(object):
- self.__influencers[dependent].remove(object)
- for influencer in self.getInfluencers(object):
- self.__dependents[influencer].remove(object)
-
- del self.__dependents[object]
- del self.__influencers[object]
- del self.__semanticMapping[object]
- else:
- raise ValueError("Specified object is not member of this graph")
- def setDependency(self, dependent, influencer):
- """ Creates a dependency between two objects.
- @param dependent: The object which depends on the other
- @param influencer: The object which influences the other
- @type dependent: Object
- @type dependent: Object
- @raise ValueError: if dependent or influencer is not member of this graph
- @raise ValueError: if the dependency already exists
- """
- if self.hasMember(dependent) and self.hasMember(influencer):
- if not influencer in self.__influencers[dependent] and\
- not dependent in self.__dependents[influencer]:
- self.__influencers[dependent].append(influencer)
- self.__dependents[influencer].append(dependent)
- else:
- print("DEPENDENT" + str(dependent))
- print("influencer" + str(influencer))
- raise ValueError("Specified dependency already exists")
- else:
- if not self.hasMember(dependent):
- raise ValueError("Specified dependent object is not member of this graph")
- if not self.hasMember(influencer):
- raise ValueError("Specified influencer object is not member of this graph")
-
- def hasDependency(self, dependent, influencer):
- if self.hasMember(dependent) and self.hasMember(influencer):
- return influencer in self.__influencers[dependent] and\
- dependent in self.__dependents[influencer]
- else:
- if not self.hasMember(dependent):
- raise ValueError("Specified dependent object is not member of this graph")
- if not self.hasMember(influencer):
- raise ValueError("Specified influencer object is not member of this graph")
-
- def unsetDependency(self, dependent, influencer):
- """ Removes a dependency between two objects.
- @param dependent: The object which depends on the other
- @param influencer: The object which influences the other
- @type dependent: Object
- @type dependent: Object
- @raise ValueError: if dependent or influencer is not member of this graph
- @raise ValueError: if the dependency does not exists
- """
- if self.hasMember(dependent) and self.hasMember(influencer):
- if influencer in self.__influencers[dependent] and\
- dependent in self.__dependents[influencer]:
- self.__influencers[dependent].remove(influencer)
- self.__dependents[influencer].remove(dependent)
- else:
- raise ValueError("Specified dependency does not exists")
- else:
- if not self.hasMember(dependent):
- raise ValueError("Specified dependent object is not member of this graph")
- if not self.hasMember(influencer):
- raise ValueError("Specified influencer object is not member of this graph")
-
- def getDependents(self, object):
- if self.hasMember(object):
- return copy.copy(self.__dependents[object])
- else:
- raise ValueError("Specified object is not member of this graph")
- def getInfluencers(self, object):
- if self.hasMember(object):
- return copy.copy(self.__influencers[object])
- else:
- raise ValueError("Specified object is not member of this graph")
-
- def getStrongComponents(self):
- return self.__strongComponents()
-
- def __getDepNode(self, object):
- if self.hasMember(object):
- return self.__semanticMapping[object]
- else:
- raise ValueError("Specified object is not a member of this graph")
-
- def __mark(self, object):
- self.__getDepNode(object).mark()
-
- def __unMark(self, object):
- self.__getDepNode(object).unMark()
-
- def __isMarked(self, object):
- return self.__getDepNode(object).isMarked()
-
- def __topoSort(self):
- """ Performs a topological sort on the graph.
- """
- for object in self.__semanticMapping.keys():
- self.__unMark(object)
-
- sortedList = []
-
- for object in self.__semanticMapping.keys():
- if not self.__isMarked(object):
- self.__dfsSort(object, sortedList)
- return sortedList
-
- def __dfsSort(self, object, sortedList):
- """ Performs a depth first search collecting
- the objects in topological order.
- @param object: the currently visited object.
- @param sortedList: partial sorted list of objects
- @type object: Object
- @type sortedList: list Of Object
- """
-
- if not self.__isMarked(object):
- self.__mark(object)
-
- for influencer in self.getInfluencers(object):
- self.__dfsSort(influencer, sortedList)
-
- sortedList.append(object)
- def __strongComponents(self):
- """ Determine the strong components of the graph
- @rtype: list of list of Object
- """
- strongComponents = []
- sortedList = self.__topoSort()
-
- for object in self.__semanticMapping.keys():
- self.__unMark(object)
-
- sortedList.reverse()
-
- for object in sortedList:
- if not self.__isMarked(object):
- component = []
- self.__dfsCollect(object, component)
- strongComponents.append(component)
-
- strongComponents.reverse()
- return strongComponents
- def __dfsCollect(self, object, component):
- """ Collects objects member of a strong component.
- @param object: Node currently visited
- @param component: current component
- @type object: Object
- @type component: List of Object
- """
- if not self.__isMarked(object):
- self.__mark(object)
-
- for dependent in self.getDependents(object):
- self.__dfsCollect(dependent, component)
-
- component.append(object)
|