Source code for network.groundBN

"""
The Ground Bayes Network (GBN) in ProbReM is the smallest subset of data that is required to answer a specific query. While the PRM uses a first-order representation of the world, the inference process needs a propositional represenation of the data. The :mod:`network.groundBN` module implements an efficient data structure for that purpose.

"""
from analytics.performance import time_analysis
from network.vertices import GBNvertex,ReferenceVertex,computeRefID



[docs]class GBNGraph(dict): ''' A `GBNGraph` is a dictionary that contains a set of vertices of type :class:`GBNvertex`. The `GBNGraph` instance itself is a dictionary which is used to store vertices {key=vertex_id : value= :class:`GBNvertex`}. There are also various different dictionaries of all `GBNvertex` objects that allow fast retrieval of sets of GBN vertices. ''' def __init__(self): ''' init ''' self.allByAttribute = {} """ A dicitonary that groups all `GBNvertex` instances according to their attribute class, e.g. {key=:class:`Attribute` : value=[ list of :class:`!GBNvertex` ]} """ self.samplingVertices = {} """ A dicitonary that groups all sampling `GBNvertex` instances (event & latent vertices), e.g. {key=vertex_id : value= :class:`!GBNvertex`} """ self.eventVertices = {} """ A dicitonary that groups all event `GBNvertex` instances according to their attribute class, e.g. {key=vertex_id : value= :class:`!GBNvertex`} """ self.samplingVerticesByAttribute = {} """ A dicitonary that groups all sampling `GBNvertex` instances (event & latent vertices) according to their attribute class, e.g. {key=:class:`Attribute` : value=[ list of :class:`!GBNvertex` ]} """
[docs] def addEvidenceVertex(self,ID,attr,obj,value): """ Instantiates a new evidence :class:`!GBNvertex` and updates the corresponding GBN data structures. :arg ID: Unique ID :arg attr: :class:`Attribute` :arg obj: Primary Key of attribute object :arg value: Value of vertex """ self[ID] = GBNvertex(ID=ID,attr=attr,obj=obj,fixed=True,value=value) if attr in self.allByAttribute: self.allByAttribute[attr].append(self[ID]) else: self.allByAttribute[attr] = [] self.allByAttribute[attr].append(self[ID]) return ID
[docs] def addSamplingVertex(self,ID,attr,obj): """ Instantiates a new sampling :class:`!GBNvertex` and updates the corresponding GBN data structures. :arg ID: Unique ID :arg attr: :class:`Attribute` :arg obj: Primary Key of attribute object """ self[ID] = GBNvertex(ID=ID,attr=attr,obj=obj,fixed=False) self.samplingVertices[ID] = self[ID] if attr in self.samplingVerticesByAttribute: self.samplingVerticesByAttribute[attr].append(self[ID]) else: self.samplingVerticesByAttribute[attr] = [] self.samplingVerticesByAttribute[attr].append(self[ID]) if attr in self.allByAttribute: self.allByAttribute[attr].append(self[ID]) else: self.allByAttribute[attr] = [] self.allByAttribute[attr].append(self[ID]) return ID
[docs] def addVertex(self,ID,attr,obj, **args): ''' General method to add a vertex to the graph. ''' """ General method to add a vertex to the graph. Note that the node is only instantiated (and added) if `ID` is not in the graph already. If not, instantiates a new :class:`!GBNvertex` and updates the corresponding GBN data structures. :arg ID: Unique ID :arg attr: :class:`Attribute` :arg obj: Primary Key of attribute object :arg **args: Dictionary of other parameters """ if ID not in self: self[ID] = GBNvertex(ID=ID,attr=attr,obj=obj,**args) #print 'Added %s(E=%s) to GBN'%(ID,self[ID].fixed) #also add references to the helper data structures if not self[ID].fixed: self.samplingVertices[ID] = self[ID] if attr in self.samplingVerticesByAttribute: self.samplingVerticesByAttribute[attr].append(self[ID]) else: self.samplingVerticesByAttribute[attr] = [] self.samplingVerticesByAttribute[attr].append(self[ID]) if attr in self.allByAttribute: self.allByAttribute[attr].append(self[ID]) else: self.allByAttribute[attr] = [] self.allByAttribute[attr].append(self[ID]) return ID return False ''' else: ?Gather statistics about how many nodes were added reduntantly '''
[docs] def addReferenceVertex(self,gbnV,dependency): '''Adds a :class:`.ReferenceVertex` to the ground Bayesian network. For now, the reference attribute (all exist attributes) are assumed to be sampling nodes (i.e. not in the evidence nor in the event variables) ''' ID = computeRefID(gbnV) if ID not in self: self[ID] = ReferenceVertex(ID=ID, gbnV=gbnV,dep=dependency) attr = self[ID].attr #also add references to the helper data structures if not self[ID].fixed: self.samplingVertices[ID] = self[ID] if attr in self.samplingVerticesByAttribute: self.samplingVerticesByAttribute[attr].append(self[ID]) else: self.samplingVerticesByAttribute[attr] = [] self.samplingVerticesByAttribute[attr].append(self[ID]) if attr in self.allByAttribute: self.allByAttribute[attr].append(self[ID]) else: self.allByAttribute[attr] = [] self.allByAttribute[attr].append(self[ID]) # initialize reference # add initial edges return ID #nothing added return False
def __missing__(self,key): ''' Called if we try to access a vertex that isn't in the graph. ''' return None
[docs] def logLikelihood(self): ''' Returns the loglikelihood of the `GBNGraph` ''' loglik = 0 for gbnV in self.values(): loglik += gbnV.logLikelihood() return loglik
def __repr__(self): ''' String representation of the statistics of the current Graph ''' rep = '-- Ground Bayesian Network --\n' def prettyStat(gbndict): '''Returns a string representation of the `gbndict` dictionary ''' s = '' for attr,gbnvs in gbndict.items(): s += '%s (%s),'%(attr.fullname,len(gbnvs)) return s[:-1] rep += 'All : %s vertices\n\t%s\n'%(len(self),prettyStat(self.allByAttribute)) rep += 'Sampling : %s vertices\n\t%s\n'%(len(self.samplingVertices),prettyStat(self.samplingVerticesByAttribute)) return rep[:-1] #don't return last '\n'
[docs]class GBNqueue(dict): ''' A queue that keeps track of vertices that need to be processed when constructing the Ground Bayesian network. This class is also a dictionary as the information is stored in groups that correspond to sets of vertices that share the same local distribution (= the same attribute). { key=:class:`Attribute` : value=[ list of :class:`!GBNvertex` ] } ''' def __init__(self): ''' Init ''' def isEmpty(self): if len(self)==0: return True else: return False
[docs] def pop(self): ''' Return a set of GBNvertex instances of the same attribute :math:`A \in A(X)`. This allows us to retrieve the required data in one call to the data interface. We choose an attribute, remove the key from the dictionary and return the associated list. :returns: List of :class:`!GBNvertex` ''' return self.popitem()
[docs] def push(self, gbnVertex): ''' If another :class:`!GBNvertex` is pushed onto the stack, it is added to the list associated with the `gbnVertex.attr` :arg gbnVertex: :class:`GBNvertex` ''' #print 'Adding %s to Queue'%(gbnVertex.ID) self[gbnVertex.attr].append(gbnVertex)
def __missing__(self,key): ''' In case the key - an attribute instance - is not in the dictionary we add it with an empty list of vertices. ''' self[key] = [] return self[key]