From eab3033de78c816837cf4d1a0659befc7d83ea4f Mon Sep 17 00:00:00 2001
From: Hendrik Buschmeier <hbuschme@uni-bielefeld.de>
Date: Sat, 5 Apr 2014 00:26:15 +0200
Subject: [PATCH] Refactoring: Merged factor elimination, particlefiltering in
 one file, respectively.

---
 primo/decision/UtilityTable.py                |  65 ---
 primo/decision/__init__.py                    |   3 -
 primo/decision/make_decision/__init__.py      |   2 -
 primo/reasoning/factor.py                     | 421 ++++++++++++++++++
 .../EasiestFactorElimination.py               | 105 -----
 primo/reasoning/factorelemination/Factor.py   |  36 --
 .../reasoning/factorelemination/FactorTree.py | 141 ------
 .../factorelemination/FactorTreeFactory.py    | 166 -------
 primo/reasoning/factorelemination/__init__.py |   4 -
 primo/reasoning/particlebased/__init__.py     |   2 -
 ...ParticleFilterDBN.py => particlefilter.py} |   8 +-
 11 files changed, 426 insertions(+), 527 deletions(-)
 delete mode 100644 primo/decision/UtilityTable.py
 delete mode 100644 primo/decision/__init__.py
 delete mode 100644 primo/decision/make_decision/__init__.py
 create mode 100644 primo/reasoning/factor.py
 delete mode 100644 primo/reasoning/factorelemination/EasiestFactorElimination.py
 delete mode 100644 primo/reasoning/factorelemination/Factor.py
 delete mode 100644 primo/reasoning/factorelemination/FactorTree.py
 delete mode 100644 primo/reasoning/factorelemination/FactorTreeFactory.py
 delete mode 100644 primo/reasoning/factorelemination/__init__.py
 delete mode 100644 primo/reasoning/particlebased/__init__.py
 rename primo/reasoning/{particlebased/ParticleFilterDBN.py => particlefilter.py} (98%)

diff --git a/primo/decision/UtilityTable.py b/primo/decision/UtilityTable.py
deleted file mode 100644
index 26dcfb3..0000000
--- a/primo/decision/UtilityTable.py
+++ /dev/null
@@ -1,65 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import numpy
-import operator
-
-class UtilityTable(object):
-    '''
-    self.variables -- list of the parent nodes
-    self.table -- utility table which contains the utility
-    '''
-    
-    def __init__(self):
-        super(UtilityTable, self).__init__()
-        self.table = numpy.array(0)
-        self.variables = []
-    
-    def add_variable(self, variable):
-        self.variables.append(variable)
-
-        ax = self.table.ndim
-        self.table=numpy.expand_dims(self.table,ax)
-        self.table=numpy.repeat(self.table,len(variable.value_range),axis = ax)
-
-    def get_ut_index(self, node_value_pairs):
-        nodes, values = zip(*node_value_pairs)
-        index = []
-        for node in self.variables:
-            index_in_values_list = nodes.index(node)
-            value = values[index_in_values_list]
-            index.append(node.value_range.index(value))
-        return tuple(index)    
-        
-    def set_utility_table(self, table, nodes):
-        if not set(nodes) == set(self.variables):
-            raise Exception("The list which should define the ordering of the variables does not match"
-                " the variables that this cpt depends on (plus the node itself)")
-        if not self.table.ndim == table.ndim:
-            raise Exception("The provided probability table does not have the right number of dimensions")
-        for d,node in enumerate(nodes):
-            if len(node.value_range) != table.shape[d]:
-                raise Exception("The size of the provided probability table does not match the number of possible values of the node "+node.name+" in dimension "+str(d))
-
-        self.table = table
-        self.variables = nodes
-      
-    def set_utility(self, value, node_value_pairs):
-        index = self.get_ut_index(node_value_pairs)
-        self.table[index]=value
-    
-    def get_utility_table(self):
-        return self.table
-        
-    def get_variables(self):
-        return self.variables
-    
-    def get_utility(self, node_value_pairs):
-        index = self.get_ut_index(node_value_pairs)
-        return self.table[index]
-
-    def __str__(self):
-        return str(self.table)        
-            
-        
-    
-    
\ No newline at end of file
diff --git a/primo/decision/__init__.py b/primo/decision/__init__.py
deleted file mode 100644
index d454ced..0000000
--- a/primo/decision/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from UtilityNode import UtilityNode
-from DecisionNode import DecisionNode
-from UtilityTable import UtilityTable
\ No newline at end of file
diff --git a/primo/decision/make_decision/__init__.py b/primo/decision/make_decision/__init__.py
deleted file mode 100644
index 82eee2b..0000000
--- a/primo/decision/make_decision/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-from MakeDecision import MakeDecision
-
diff --git a/primo/reasoning/factor.py b/primo/reasoning/factor.py
new file mode 100644
index 0000000..18cc9a9
--- /dev/null
+++ b/primo/reasoning/factor.py
@@ -0,0 +1,421 @@
+import networkx as nx
+
+import primo.densities
+
+class Factor(object):
+
+    def __init__(self,node):
+        self.node = node
+        self.calCPD = node.get_cpd().copy()
+        self.cluster = set()
+        self.isEvidence = False
+
+    def __str__(self):
+        return self.node.name
+
+    def set_evidence(self,evd):
+        self.calCPD = self.node.get_cpd().copy()
+        self.calCPD = self.calCPD.set_evidence(evd)
+        self.isEvidene = True
+
+    def clear_evidence(self):
+        self.calCPD = self.node.get_cpd().copy()
+        self.isEvidence = False
+
+    def set_cluster(self,cluster):
+        self.cluster = cluster
+
+    def get_variables(self):
+        return self.node.get_cpd().variables
+
+    def get_calculation_CDP(self):
+        return self.calCPD;
+
+    def get_node(self):
+        return self.node
+
+    def contains_node(self,node):
+        return self.node == node
+
+class FactorTree(object):
+    '''The factor tree contains for each node of the BayesNet a factor. It
+    is a directed graph with one root node. To speed up the reasoning it uses
+    a message based approach which stores calculated intermediate results at
+    edges. Thus, the first query is expensive and all following are easy calculated.
+    The speed of the first message calculation depends on how the tree was build.
+    Literature: Modeling and Reasoning with Bayesian Networks - Adnan Darwiche
+    Chapter 7    
+    '''
+    
+    
+    def __init__(self,graph,rootNode):
+        self.graph = graph
+        self.rootNode = rootNode
+        
+    def calculate_PoE(self):
+        '''Calculates the probability of evidence with the set evidence'''
+        if not self.graph.graph['messagesValid']:
+            self.calculate_messages()
+            
+        cpd = self.calculate_marginal_forOne(self.rootNode)
+        
+        for v in cpd.get_variables()[:]:
+            cpd = cpd.marginalization(v)
+            
+        return cpd
+        
+    def calculate_marginal(self,variables):
+        ''' If evidence is set, then this methods calculates the posterior marginal.
+        With an empty evidence this is automatically the prior marginal.'''
+        if not self.graph.graph['messagesValid']:
+            self.calculate_messages()
+            
+            
+        resPT = primo.densities.ProbabilityTable.get_neutral_multiplication_PT()
+        
+            
+        for f in self.graph.nodes():
+            if f.get_node() in variables:
+                resPT = resPT.multiplication(self.calculate_marginal_forOne(f))
+                
+        resPT = resPT.normalize_as_jpt()
+                
+        return resPT
+                
+    def calculate_marginal_forOne(self,factor):
+        curCPD = factor.get_calculation_CDP().copy()
+        
+        for p in self.graph.predecessors(factor):
+            tmpCPD = self.graph[p][factor]['msgRightWay']
+            curCPD = curCPD.multiplication(tmpCPD)
+                      
+        for p in self.graph.neighbors(factor):
+            tmpCPD = self.graph[factor][p]['msgAgainstWay']
+            curCPD = curCPD.multiplication(tmpCPD)
+            
+        for v in curCPD.get_variables()[:]:
+            if v != factor.get_node():
+                curCPD = curCPD.marginalization(v)
+                
+        return curCPD
+        
+        
+    def draw(self):
+        '''Draws the FactorTree'''
+        import matplotlib.pyplot as plt
+        nx.draw_circular(self.graph)
+        plt.show()
+        
+    def calculate_messages(self):
+        ''' Calculates the messages and stores the intermediate results.'''
+        self.pull_phase(self.rootNode,self.graph)
+        self.push_phase(self.rootNode,self.graph,primo.densities.ProbabilityTable.get_neutral_multiplication_PT())
+        self.graph.graph['messagesValid'] = True
+        
+        
+    def set_evidences(self,evidences):
+        self.graph.graph['messagesValid'] = False
+        
+        evNodes = zip(*evidences)
+       
+        for factor in self.graph.nodes():
+            if factor.get_node() in evNodes[0]:
+                idx = evNodes[0].index(factor.get_node())
+                factor.set_evidence(evidences[idx])
+        
+    
+        
+        
+    def pull_phase(self,factor,graph):
+        
+        calCPD = factor.get_calculation_CDP()
+        #calculate the messages of the children
+        for child in graph.neighbors(factor):
+            tmpInput = self.pull_phase(child,graph)
+            
+            
+            #project each factor on the specific separator
+            separator = graph[factor][child]['separator']
+            for var in tmpInput.variables[:]:
+                if var not in separator:
+                    tmpInput = tmpInput.marginalization(var)
+                
+            
+            #save message on edge: it's the opposite of the direction of the edge
+            graph[factor][child]['msgAgainstWay'] = tmpInput 
+            #calculate the new message
+            calCPD = calCPD.multiplication(tmpInput)
+              
+        return calCPD
+        
+    def push_phase(self,factor,graph,inCPD):
+       
+        for child in graph.neighbors(factor):
+            tmpCPD = inCPD.multiplication(factor.get_calculation_CDP())
+            for child2 in graph.neighbors(factor):
+                if (child != child2):
+                    tmpCPD = tmpCPD.multiplication(graph[factor][child2]['msgAgainstWay'])
+            
+            separator = graph[factor][child]['separator']
+            #project on outgoing edge separator
+            for var in tmpCPD.variables:
+                if var not in separator:
+                    tmpCPD = tmpCPD.marginalization(var)
+            
+            #add setOut to outgoing vars from child
+            #Message with the direction of the edge
+            graph[factor][child]['msgRightWay'] = tmpCPD
+                
+           
+            self.push_phase(child,graph,tmpCPD)
+
+
+class FactorTreeFactory(object):
+    '''The FactorTreeFactory creates the FactorTree out of a BayesNet.'''
+    
+    def create_random_factortree(self,bayesNet):
+        ''' Creates a randomly structured FactorTree. This method is useful for testing
+        if reasoning works for arbitrary trees.'''
+        allNodes = bayesNet.get_all_nodes()
+        
+        if len(allNodes) == 0:
+            raise Exception("createRandomFactorTree: No nodes in given BayesNet")
+        
+        tn = allNodes.pop()
+        rootFactor = Factor(tn)
+
+        graph = nx.DiGraph(messagesValid=False)
+        graph.add_node(rootFactor)        
+        
+        usedNodes = [rootFactor]
+        
+        for n in allNodes[:]:
+            parentNode = choice(usedNodes[:])
+            newFactor = Factor(n)
+            graph.add_edge(parentNode,newFactor, inVars=set(),outVars=set())
+            usedNodes.append(newFactor)
+            
+        self.calculate_seperators_pull(rootFactor,graph)
+        self.calculate_seperators_push(rootFactor,graph,set())
+        self.intersect_seperators(graph)
+        
+        self.calculate_clusters(rootFactor,graph,set())
+            
+            
+        return FactorTree(graph,rootFactor)
+        
+    def create_greedy_factortree(self,bayesNet):
+        '''This method creates a factor the after the following algorithm:
+            
+            1. Sort factors after containing variables (descending).
+            2. For each node in the sorted list insert at it's best position.
+            
+            The best position is the node with the most joint variables.''' 
+        
+        allNodes = bayesNet.get_all_nodes()
+        
+        if len(allNodes) == 0:
+            raise Exception("createRandomFactorTree: No nodes in given BayesNet")
+            
+        sortNodeList = []
+        
+        for n in allNodes:
+            sortNodeList.append((len(n.get_cpd().get_variables()),n))
+          
+        #sort node list
+        sortNodeList = sorted(sortNodeList,key=itemgetter(0),reverse=True)
+        
+        sortNodeList =  zip(*sortNodeList)
+        sortNodeList = list(sortNodeList[1])
+        
+        #root node with the most variables
+        rootFactor = Factor(sortNodeList.pop(0))
+        
+        #create new graph for factor tree
+        graph = nx.DiGraph(messagesValid=False)
+        graph.add_node(rootFactor) 
+        
+        #All nodes are added
+        for nd in sortNodeList[:]:
+            (ct,insFactor) = self.find_best_node_for_insertion(graph,rootFactor,set(nd.get_cpd().get_variables()))
+            nFactor = Factor(nd)
+            graph.add_edge(insFactor,nFactor, inVars=set(),outVars=set())
+            
+        #For the later calculation the seperators are needed
+        self.calculate_seperators_pull(rootFactor,graph)
+        self.calculate_seperators_push(rootFactor,graph,set())
+        self.intersect_seperators(graph)
+        
+        #the cluster are not necessarily needed but indicate how good the calculation of messages performs
+        self.calculate_clusters(rootFactor,graph,set())
+            
+            
+        return FactorTree(graph,rootFactor)
+        
+        
+    def find_best_node_for_insertion(self,graph,factor,nodeSet):
+        '''finds the node in the graph with the most common variables to the given node'''
+        
+        curJointCount = len(set(factor.get_variables()) & nodeSet)
+        curInsertFactor = factor
+        
+        for nbs in graph.neighbors(factor):
+            (count,retFactor) = self.find_best_node_for_insertion(graph,nbs,nodeSet)
+            if count >= curJointCount:
+                curJointCount = count
+                curInsertFactor = retFactor
+                
+        return (curJointCount,curInsertFactor)
+            
+        
+    def calculate_seperators_pull(self,factor,graph):
+        
+        s = set()  
+        pullSet = set(factor.get_variables())
+        
+        #find all variables in outgoing edges for factor
+        for child in graph.neighbors(factor):
+            s = self.calculate_seperators_pull(child,graph)
+            graph[factor][child]['inVars'] =  s
+                    
+            pullSet =  s | pullSet
+               
+        return pullSet
+        
+    def calculate_seperators_push(self,factor,graph,setOut):
+
+        #add local vars to set
+        setOut = set(factor.get_variables()) | setOut
+        
+
+        for child in graph.neighbors(factor):
+            tmpSet = copy.copy(setOut)
+            for child2 in graph.neighbors(factor):
+                if (child != child2):
+                    tmpSet = tmpSet | graph[factor][child2]['inVars']
+            
+            #add setOut to outgoing variables from the child
+            tmp = graph[factor][child]['outVars']
+            graph[factor][child]['outVars'] = tmp | tmpSet
+                
+           
+            self.calculate_seperators_push(child,graph,tmpSet)
+            
+
+    def intersect_seperators(self,graph):
+        
+        for n,nbrs in graph.adjacency_iter():
+            for nbr,eattr in nbrs.items():
+                eattr['separator'] = eattr['inVars'] & eattr['outVars']
+                
+    def calculate_clusters(self,factor,graph,parent_seperator):
+        
+        localCluster = parent_seperator | set(factor.get_variables())
+        
+        for n in graph.neighbors(factor):
+            tmpSeparator = graph[factor][n]['separator']
+            localCluster = localCluster | tmpSeparator
+            self.calculate_clusters(n,graph,tmpSeparator)
+            
+        factor.set_cluster(localCluster)
+
+
+class EasiestFactorElimination(object):
+    '''This is the easiest way for factor elimination.It's has the worst runtime because:
+    1. Needed evidences are set (optional).
+    2. All nodes are multiplied.
+    3. The redundant variables are summed out
+    
+    Literature: Modeling and Reasoning with Bayesian Networks - Adnan Darwiche
+    Chapter 6-7    
+    '''
+    
+    
+    
+    def __init__(self,bayesNet):
+        self.bn= bayesNet
+
+        
+    def calculate_PriorMarginal(self,variables):  
+        '''Calculates the prior marignal for the given variables. The resulting
+        CPD is returned.'''
+        nodes = self.bn.get_all_nodes()
+        
+        finCpd = nodes.pop().get_cpd()
+        
+        for n in nodes:
+            finCpd = finCpd.multiplication(n.get_cpd())
+            
+        for v in finCpd.get_variables():
+            if v not in variables:
+                finCpd = finCpd.marginalization(v)
+        
+        return finCpd
+        
+    def calculate_PosteriorMarginal(self,variables,evidence):
+        '''Calculates the posterior marginal for given variables and evidence.
+        It returns the resulting cpd.'''
+        nodes = self.bn.get_all_nodes()
+        
+        #List of evidences
+        ev_list = zip(*evidence)     
+        # Special Case: First Node
+        node1 = nodes.pop()
+        if node1 in ev_list[0]:
+            ind = ev_list[0].index(node1)
+            finCpd = node1.get_cpd().set_evidence(evidence[ind])
+            
+        else:
+            finCpd = node1.get_cpd()
+            
+            
+        # For all other nodes
+        for n in nodes:
+            if n in ev_list[0]:
+                #Set evidence and multiply
+                ind = ev_list[0].index(n)
+                nCPD = n.get_cpd().set_evidence(evidence[ind])
+                finCpd = finCpd.multiplication(nCPD)            
+            else:
+                #only multiply
+                finCpd = finCpd.multiplication(n.get_cpd())
+
+                
+        for v in finCpd.get_variables():
+            if v not in variables:
+                finCpd = finCpd.marginalization(v)
+                
+        finCpd = finCpd.normalize_as_jpt()
+        
+            
+        return finCpd
+        
+    def calculate_PoE(self,evidence):
+        ''' Calculates the probabilty of evidence for the given evidence and returns the result.'''
+        
+        nodes = self.bn.get_all_nodes()
+        
+        unzipped_list = zip(*evidence)
+              
+        node1 = nodes.pop()
+        if node1 in unzipped_list[0]:
+            ind = unzipped_list[0].index(node1)
+            finCpd = node1.get_cpd().set_evidence(evidence[ind])
+            
+        else:
+            finCpd = node1.get_cpd()
+                  
+        for n in nodes:
+            if n in unzipped_list[0]:
+                ind = unzipped_list[0].index(n)
+                nCPD = n.get_cpd().set_evidence(evidence[ind])
+                finCpd = finCpd.multiplication(nCPD)
+            else:
+                finCpd = finCpd.multiplication(n.get_cpd())
+          
+        for v in finCpd.get_variables():
+            finCpd = finCpd.marginalization(v)
+            
+        return finCpd
+
+    
diff --git a/primo/reasoning/factorelemination/EasiestFactorElimination.py b/primo/reasoning/factorelemination/EasiestFactorElimination.py
deleted file mode 100644
index 74b9f14..0000000
--- a/primo/reasoning/factorelemination/EasiestFactorElimination.py
+++ /dev/null
@@ -1,105 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-from  primo.core import BayesNet
-from  primo.reasoning import DiscreteNode
-import numpy
-
-class EasiestFactorElimination(object):
-    '''This is the easiest way for factor elimination.It's has the worst runtime because:
-    1. Needed evidences are set (optional).
-    2. All nodes are multiplied.
-    3. The redundant variables are summed out
-    
-    Literature: Modeling and Reasoning with Bayesian Networks - Adnan Darwiche
-    Chapter 6-7    
-    '''
-    
-    
-    
-    def __init__(self,bayesNet):
-        self.bn= bayesNet
-
-        
-    def calculate_PriorMarginal(self,variables):  
-        '''Calculates the prior marignal for the given variables. The resulting
-        CPD is returned.'''
-        nodes = self.bn.get_all_nodes()
-        
-        finCpd = nodes.pop().get_cpd()
-        
-        for n in nodes:
-            finCpd = finCpd.multiplication(n.get_cpd())
-            
-        for v in finCpd.get_variables():
-            if v not in variables:
-                finCpd = finCpd.marginalization(v)
-        
-        return finCpd
-        
-    def calculate_PosteriorMarginal(self,variables,evidence):
-        '''Calculates the posterior marginal for given variables and evidence.
-        It returns the resulting cpd.'''
-        nodes = self.bn.get_all_nodes()
-        
-        #List of evidences
-        ev_list = zip(*evidence)     
-        # Special Case: First Node
-        node1 = nodes.pop()
-        if node1 in ev_list[0]:
-            ind = ev_list[0].index(node1)
-            finCpd = node1.get_cpd().set_evidence(evidence[ind])
-            
-        else:
-            finCpd = node1.get_cpd()
-            
-            
-        # For all other nodes
-        for n in nodes:
-            if n in ev_list[0]:
-                #Set evidence and multiply
-                ind = ev_list[0].index(n)
-                nCPD = n.get_cpd().set_evidence(evidence[ind])
-                finCpd = finCpd.multiplication(nCPD)            
-            else:
-                #only multiply
-                finCpd = finCpd.multiplication(n.get_cpd())
-
-                
-        for v in finCpd.get_variables():
-            if v not in variables:
-                finCpd = finCpd.marginalization(v)
-                
-        finCpd = finCpd.normalize_as_jpt()
-        
-            
-        return finCpd
-        
-        
-        
-    def calculate_PoE(self,evidence):
-        ''' Calculates the probabilty of evidence for the given evidence and returns the result.'''
-        
-        nodes = self.bn.get_all_nodes()
-        
-        unzipped_list = zip(*evidence)
-              
-        node1 = nodes.pop()
-        if node1 in unzipped_list[0]:
-            ind = unzipped_list[0].index(node1)
-            finCpd = node1.get_cpd().set_evidence(evidence[ind])
-            
-        else:
-            finCpd = node1.get_cpd()
-                  
-        for n in nodes:
-            if n in unzipped_list[0]:
-                ind = unzipped_list[0].index(n)
-                nCPD = n.get_cpd().set_evidence(evidence[ind])
-                finCpd = finCpd.multiplication(nCPD)
-            else:
-                finCpd = finCpd.multiplication(n.get_cpd())
-          
-        for v in finCpd.get_variables():
-            finCpd = finCpd.marginalization(v)
-            
-        return finCpd
diff --git a/primo/reasoning/factorelemination/Factor.py b/primo/reasoning/factorelemination/Factor.py
deleted file mode 100644
index 2f7c6ad..0000000
--- a/primo/reasoning/factorelemination/Factor.py
+++ /dev/null
@@ -1,36 +0,0 @@
-class Factor(object):
-
-    def __init__(self,node):
-        self.node = node
-        self.calCPD = node.get_cpd().copy()
-        self.cluster = set()
-        self.isEvidence = False
-
-    def __str__(self):
-        return self.node.name
-
-    def set_evidence(self,evd):
-        self.calCPD = self.node.get_cpd().copy()
-        self.calCPD = self.calCPD.set_evidence(evd)
-        self.isEvidene = True
-
-    def clear_evidence(self):
-        self.calCPD = self.node.get_cpd().copy()
-        self.isEvidence = False
-
-    def set_cluster(self,cluster):
-        self.cluster = cluster
-
-    def get_variables(self):
-        return self.node.get_cpd().variables
-
-    def get_calculation_CDP(self):
-        return self.calCPD;
-
-    def get_node(self):
-        return self.node
-
-    def contains_node(self,node):
-        return self.node == node
-
-
diff --git a/primo/reasoning/factorelemination/FactorTree.py b/primo/reasoning/factorelemination/FactorTree.py
deleted file mode 100644
index 892da14..0000000
--- a/primo/reasoning/factorelemination/FactorTree.py
+++ /dev/null
@@ -1,141 +0,0 @@
-
-import networkx as nx
-import primo.reasoning.density.ProbabilityTable as ProbabilityTable
-
-
-class FactorTree(object):
-    '''The factor tree contains for each node of the BayesNet a factor. It
-    is a directed graph with one root node. To speed up the reasoning it uses
-    a message based approach which stores calculated intermediate results at
-    edges. Thus, the first query is expensive and all following are easy calculated.
-    The speed of the first message calculation depends on how the tree was build.
-    Literature: Modeling and Reasoning with Bayesian Networks - Adnan Darwiche
-    Chapter 7    
-    '''
-    
-    
-    def __init__(self,graph,rootNode):
-        self.graph = graph
-        self.rootNode = rootNode
-        
-    def calculate_PoE(self):
-        '''Calculates the probability of evidence with the set evidence'''
-        if not self.graph.graph['messagesValid']:
-            self.calculate_messages()
-            
-        cpd = self.calculate_marginal_forOne(self.rootNode)
-        
-        for v in cpd.get_variables()[:]:
-            cpd = cpd.marginalization(v)
-            
-        return cpd
-        
-    def calculate_marginal(self,variables):
-        ''' If evidence is set, then this methods calculates the posterior marginal.
-        With an empty evidence this is automatically the prior marginal.'''
-        if not self.graph.graph['messagesValid']:
-            self.calculate_messages()
-            
-            
-        resPT = ProbabilityTable.get_neutral_multiplication_PT()
-        
-            
-        for f in self.graph.nodes():
-            if f.get_node() in variables:
-                resPT = resPT.multiplication(self.calculate_marginal_forOne(f))
-                
-        resPT = resPT.normalize_as_jpt()
-                
-        return resPT
-                
-    def calculate_marginal_forOne(self,factor):
-        curCPD = factor.get_calculation_CDP().copy()
-        
-        for p in self.graph.predecessors(factor):
-            tmpCPD = self.graph[p][factor]['msgRightWay']
-            curCPD = curCPD.multiplication(tmpCPD)
-                      
-        for p in self.graph.neighbors(factor):
-            tmpCPD = self.graph[factor][p]['msgAgainstWay']
-            curCPD = curCPD.multiplication(tmpCPD)
-            
-        for v in curCPD.get_variables()[:]:
-            if v != factor.get_node():
-                curCPD = curCPD.marginalization(v)
-                
-        return curCPD
-        
-        
-    def draw(self):
-        '''Draws the FactorTree'''
-        import matplotlib.pyplot as plt
-        nx.draw_circular(self.graph)
-        plt.show()
-        
-    def calculate_messages(self):
-        ''' Calculates the messages and stores the intermediate results.'''
-        self.pull_phase(self.rootNode,self.graph)
-        self.push_phase(self.rootNode,self.graph,ProbabilityTable.get_neutral_multiplication_PT())
-        self.graph.graph['messagesValid'] = True
-        
-        
-    def set_evidences(self,evidences):
-        self.graph.graph['messagesValid'] = False
-        
-        evNodes = zip(*evidences)
-       
-        for factor in self.graph.nodes():
-            if factor.get_node() in evNodes[0]:
-                idx = evNodes[0].index(factor.get_node())
-                factor.set_evidence(evidences[idx])
-        
-    
-        
-        
-    def pull_phase(self,factor,graph):
-        
-        calCPD = factor.get_calculation_CDP()
-        #calculate the messages of the children
-        for child in graph.neighbors(factor):
-            tmpInput = self.pull_phase(child,graph)
-            
-            
-            #project each factor on the specific separator
-            separator = graph[factor][child]['separator']
-            for var in tmpInput.variables[:]:
-                if var not in separator:
-                    tmpInput = tmpInput.marginalization(var)
-                
-            
-            #save message on edge: it's the opposite of the direction of the edge
-            graph[factor][child]['msgAgainstWay'] = tmpInput 
-            #calculate the new message
-            calCPD = calCPD.multiplication(tmpInput)
-              
-        return calCPD
-        
-    def push_phase(self,factor,graph,inCPD):
-       
-        for child in graph.neighbors(factor):
-            tmpCPD = inCPD.multiplication(factor.get_calculation_CDP())
-            for child2 in graph.neighbors(factor):
-                if (child != child2):
-                    tmpCPD = tmpCPD.multiplication(graph[factor][child2]['msgAgainstWay'])
-            
-            separator = graph[factor][child]['separator']
-            #project on outgoing edge separator
-            for var in tmpCPD.variables:
-                if var not in separator:
-                    tmpCPD = tmpCPD.marginalization(var)
-            
-            #add setOut to outgoing vars from child
-            #Message with the direction of the edge
-            graph[factor][child]['msgRightWay'] = tmpCPD
-                
-           
-            self.push_phase(child,graph,tmpCPD)
-            
-    
-    
-    
-    
diff --git a/primo/reasoning/factorelemination/FactorTreeFactory.py b/primo/reasoning/factorelemination/FactorTreeFactory.py
deleted file mode 100644
index 2302c4b..0000000
--- a/primo/reasoning/factorelemination/FactorTreeFactory.py
+++ /dev/null
@@ -1,166 +0,0 @@
-
-import networkx as nx
-import copy
-from primo.reasoning.factorelemination import Factor
-from primo.reasoning.factorelemination import FactorTree
-from random import choice
-from operator import itemgetter
-
-class FactorTreeFactory(object):
-    '''The FactorTreeFactory creates the FactorTree out of a BayesNet.'''
-    
-    def create_random_factortree(self,bayesNet):
-        ''' Creates a randomly structured FactorTree. This method is useful for testing
-        if reasoning works for arbitrary trees.'''
-        allNodes = bayesNet.get_all_nodes()
-        
-        if len(allNodes) == 0:
-            raise Exception("createRandomFactorTree: No nodes in given BayesNet")
-        
-        tn = allNodes.pop()
-        rootFactor = Factor(tn)
-
-        graph = nx.DiGraph(messagesValid=False)
-        graph.add_node(rootFactor)        
-        
-        usedNodes = [rootFactor]
-        
-        for n in allNodes[:]:
-            parentNode = choice(usedNodes[:])
-            newFactor = Factor(n)
-            graph.add_edge(parentNode,newFactor, inVars=set(),outVars=set())
-            usedNodes.append(newFactor)
-            
-        self.calculate_seperators_pull(rootFactor,graph)
-        self.calculate_seperators_push(rootFactor,graph,set())
-        self.intersect_seperators(graph)
-        
-        self.calculate_clusters(rootFactor,graph,set())
-            
-            
-        return FactorTree(graph,rootFactor)
-        
-    def create_greedy_factortree(self,bayesNet):
-        '''This method creates a factor the after the following algorithm:
-            
-            1. Sort factors after containing variables (descending).
-            2. For each node in the sorted list insert at it's best position.
-            
-            The best position is the node with the most joint variables.''' 
-        
-        allNodes = bayesNet.get_all_nodes()
-        
-        if len(allNodes) == 0:
-            raise Exception("createRandomFactorTree: No nodes in given BayesNet")
-            
-        sortNodeList = []
-        
-        for n in allNodes:
-            sortNodeList.append((len(n.get_cpd().get_variables()),n))
-          
-        #sort node list
-        sortNodeList = sorted(sortNodeList,key=itemgetter(0),reverse=True)
-        
-        sortNodeList =  zip(*sortNodeList)
-        sortNodeList = list(sortNodeList[1])
-        
-        #root node with the most variables
-        rootFactor = Factor(sortNodeList.pop(0))
-        
-        #create new graph for factor tree
-        graph = nx.DiGraph(messagesValid=False)
-        graph.add_node(rootFactor) 
-        
-        #All nodes are added
-        for nd in sortNodeList[:]:
-            (ct,insFactor) = self.find_best_node_for_insertion(graph,rootFactor,set(nd.get_cpd().get_variables()))
-            nFactor = Factor(nd)
-            graph.add_edge(insFactor,nFactor, inVars=set(),outVars=set())
-            
-        #For the later calculation the seperators are needed
-        self.calculate_seperators_pull(rootFactor,graph)
-        self.calculate_seperators_push(rootFactor,graph,set())
-        self.intersect_seperators(graph)
-        
-        #the cluster are not necessarily needed but indicate how good the calculation of messages performs
-        self.calculate_clusters(rootFactor,graph,set())
-            
-            
-        return FactorTree(graph,rootFactor)
-        
-        
-    def find_best_node_for_insertion(self,graph,factor,nodeSet):
-        '''finds the node in the graph with the most common variables to the given node'''
-        
-        curJointCount = len(set(factor.get_variables()) & nodeSet)
-        curInsertFactor = factor
-        
-        for nbs in graph.neighbors(factor):
-            (count,retFactor) = self.find_best_node_for_insertion(graph,nbs,nodeSet)
-            if count >= curJointCount:
-                curJointCount = count
-                curInsertFactor = retFactor
-                
-        return (curJointCount,curInsertFactor)
-            
-        
-    def calculate_seperators_pull(self,factor,graph):
-        
-        s = set()  
-        pullSet = set(factor.get_variables())
-        
-        #find all variables in outgoing edges for factor
-        for child in graph.neighbors(factor):
-            s = self.calculate_seperators_pull(child,graph)
-            graph[factor][child]['inVars'] =  s
-                    
-            pullSet =  s | pullSet
-               
-        return pullSet
-        
-    def calculate_seperators_push(self,factor,graph,setOut):
-
-        #add local vars to set
-        setOut = set(factor.get_variables()) | setOut
-        
-
-        for child in graph.neighbors(factor):
-            tmpSet = copy.copy(setOut)
-            for child2 in graph.neighbors(factor):
-                if (child != child2):
-                    tmpSet = tmpSet | graph[factor][child2]['inVars']
-            
-            #add setOut to outgoing variables from the child
-            tmp = graph[factor][child]['outVars']
-            graph[factor][child]['outVars'] = tmp | tmpSet
-                
-           
-            self.calculate_seperators_push(child,graph,tmpSet)
-            
-
-    def intersect_seperators(self,graph):
-        
-        for n,nbrs in graph.adjacency_iter():
-            for nbr,eattr in nbrs.items():
-                eattr['separator'] = eattr['inVars'] & eattr['outVars']
-                
-    def calculate_clusters(self,factor,graph,parent_seperator):
-        
-        localCluster = parent_seperator | set(factor.get_variables())
-        
-        for n in graph.neighbors(factor):
-            tmpSeparator = graph[factor][n]['separator']
-            localCluster = localCluster | tmpSeparator
-            self.calculate_clusters(n,graph,tmpSeparator)
-            
-        factor.set_cluster(localCluster)
-
-            
-            
-                        
-        
-        
-            
-        
-        
-    
diff --git a/primo/reasoning/factorelemination/__init__.py b/primo/reasoning/factorelemination/__init__.py
deleted file mode 100644
index f0b37c0..0000000
--- a/primo/reasoning/factorelemination/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-from EasiestFactorElimination import EasiestFactorElimination
-from Factor import Factor
-from FactorTree import FactorTree
-from FactorTreeFactory import FactorTreeFactory
\ No newline at end of file
diff --git a/primo/reasoning/particlebased/__init__.py b/primo/reasoning/particlebased/__init__.py
deleted file mode 100644
index 866e708..0000000
--- a/primo/reasoning/particlebased/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-# -*- coding: utf-8 -*-
-import ParticleFilterDBN
\ No newline at end of file
diff --git a/primo/reasoning/particlebased/ParticleFilterDBN.py b/primo/reasoning/particlefilter.py
similarity index 98%
rename from primo/reasoning/particlebased/ParticleFilterDBN.py
rename to primo/reasoning/particlefilter.py
index 52fd87b..e34e6b7 100644
--- a/primo/reasoning/particlebased/ParticleFilterDBN.py
+++ b/primo/reasoning/particlefilter.py
@@ -1,10 +1,12 @@
 # -*- coding: utf-8 -*-
-from primo.core import BayesNet
-from primo.core import DynamicBayesNet
-import random
+
 import copy
+import random
 import time
 
+from primo.networks import BayesNet
+from primo.networks import DynamicBayesNet
+
 class Particle(object):
     ''' 
     This is the basic particle class used by the DBN particle filter.
-- 
GitLab