Repository: pgmpy/pgmpy
Pull request #870 (2017-04-13 04:30:10)

Move factor product and divide to base factor
@ankurankan 

Since ContinuousFactor is ready, can I move factor product and divide to base factor?


Patch:
diff --git a/pgmpy/factors/__init__.py b/pgmpy/factors/__init__.py
index 4b70b856..a058654d 100644
--- a/pgmpy/factors/__init__.py
+++ b/pgmpy/factors/__init__.py
@@ -1,6 +1,9 @@
 from .FactorSet import FactorSet, factorset_product, factorset_divide
+from .base import factor_product, factor_divide
 
 __all__ = ['FactorSet',
            'factorset_divide',
            'factorset_product',
+           'factor_product',
+           'factor_divide'
            ]
\ No newline at end of file
diff --git a/pgmpy/factors/base.py b/pgmpy/factors/base.py
index 0eca5a52..9efd734d 100644
--- a/pgmpy/factors/base.py
+++ b/pgmpy/factors/base.py
@@ -1,6 +1,104 @@
+from abc import abstractmethod
+
+from pgmpy.extern.six.moves import reduce
+
+
 class BaseFactor(object):
     """
     Base class for Factors. Any Factor implementation should inherit this class.
     """
     def __init__(self, *args, **kwargs):
         pass
+
+    @abstractmethod
+    def is_valid_cpd(self):
+        pass
+
+def factor_product(*args):
+    """
+    Returns factor product over `args`.
+
+    Parameters
+    ----------
+    args: `BaseFactor` instances.
+        factors to be multiplied
+
+    Returns
+    -------
+    BaseFactor: `BaseFactor` representing factor product over all the `BaseFactor` instances in args.
+
+    Examples
+    --------
+    >>> from pgmpy.factors.discrete import DiscreteFactor
+    >>> from pgmpy.factors import factor_product
+    >>> phi1 = DiscreteFactor(['x1', 'x2', 'x3'], [2, 3, 2], range(12))
+    >>> phi2 = DiscreteFactor(['x3', 'x4', 'x1'], [2, 2, 2], range(8))
+    >>> phi = factor_product(phi1, phi2)
+    >>> phi.variables
+    ['x1', 'x2', 'x3', 'x4']
+    >>> phi.cardinality
+    array([2, 3, 2, 2])
+    >>> phi.values
+    array([[[[ 0,  0],
+             [ 4,  6]],
+
+            [[ 0,  4],
+             [12, 18]],
+
+            [[ 0,  8],
+             [20, 30]]],
+
+
+           [[[ 6, 18],
+             [35, 49]],
+
+            [[ 8, 24],
+             [45, 63]],
+
+            [[10, 30],
+             [55, 77]]]])
+    """
+    if not all(isinstance(phi, BaseFactor) for phi in args):
+        raise TypeError("Arguments must be factors")
+    return reduce(lambda phi1, phi2: phi1 * phi2, args)
+
+
+def factor_divide(phi1, phi2):
+    """
+    Returns `DiscreteFactor` representing `phi1 / phi2`.
+
+    Parameters
+    ----------
+    phi1: Factor
+        The Dividend.
+
+    phi2: Factor
+        The Divisor.
+
+    Returns
+    -------
+    DiscreteFactor: `DiscreteFactor` representing factor division `phi1 / phi2`.
+
+    Examples
+    --------
+    >>> from pgmpy.factors.discrete import DiscreteFactor
+    >>> from pgmpy.factors import factor_product
+    >>> phi1 = DiscreteFactor(['x1', 'x2', 'x3'], [2, 3, 2], range(12))
+    >>> phi2 = DiscreteFactor(['x3', 'x1'], [2, 2], range(1, 5))
+    >>> phi = factor_divide(phi1, phi2)
+    >>> phi.variables
+    ['x1', 'x2', 'x3']
+    >>> phi.cardinality
+    array([2, 3, 2])
+    >>> phi.values
+    array([[[ 0.        ,  0.33333333],
+            [ 2.        ,  1.        ],
+            [ 4.        ,  1.66666667]],
+
+           [[ 3.        ,  1.75      ],
+            [ 4.        ,  2.25      ],
+            [ 5.        ,  2.75      ]]])
+    """
+    if not isinstance(phi1, BaseFactor) or not isinstance(phi2, BaseFactor):
+        raise TypeError("phi1 and phi2 should be factors instances")
+    return phi1.divide(phi2, inplace=False)
diff --git a/pgmpy/factors/continuous/ContinuousFactor.py b/pgmpy/factors/continuous/ContinuousFactor.py
index fc407f6a..41c9e6dc 100644
--- a/pgmpy/factors/continuous/ContinuousFactor.py
+++ b/pgmpy/factors/continuous/ContinuousFactor.py
@@ -35,7 +35,7 @@ class ContinuousFactor(BaseFactor):
         >>> dirichlet_factor = ContinuousFactor(['x', 'y'], drichlet_pdf)
         >>> dirichlet_factor.scope()
         ['x', 'y']
-        >>> dirichlet_factor.assignemnt(5,6)
+        >>> dirichlet_factor.assignment(5,6)
         226800.0
         """
         if not isinstance(variables, (list, tuple, np.ndarray)):
@@ -217,7 +217,7 @@ class ContinuousFactor(BaseFactor):
 
     def marginalize(self, variables, inplace=True):
         """
-        Maximizes the factor with respect to the given variables.
+        Marginalize the factor with respect to the given variables.
 
         Parameters
         ----------
@@ -342,7 +342,7 @@ class ContinuousFactor(BaseFactor):
         -------
         ContinuousFactor or None:
                         if inplace=True (default) returns None
-                        if inplace=False returns a new `DiscreteFactor` instance.
+                        if inplace=False returns a new `ContinuousFactor` instance.
 
         Example
         -------
diff --git a/pgmpy/factors/discrete/DiscreteFactor.py b/pgmpy/factors/discrete/DiscreteFactor.py
index 0879813b..d621f899 100644
--- a/pgmpy/factors/discrete/DiscreteFactor.py
+++ b/pgmpy/factors/discrete/DiscreteFactor.py
@@ -11,7 +11,6 @@ from pgmpy.extern import six
 from pgmpy.extern.six.moves import map, range, reduce, zip
 from pgmpy.utils import StateNameInit, StateNameDecorator
 
-
 State = namedtuple('State', ['var', 'state'])
 
 
@@ -815,90 +814,3 @@ class DiscreteFactor(BaseFactor):
             phi.values = phi.values.swapaxes(axis, exchange_index)
         return hash(str(sorted_var_hashes) + str(phi.values) + str(phi.cardinality))
 
-
-def factor_product(*args):
-    """
-    Returns factor product over `args`.
-
-    Parameters
-    ----------
-    args: `DiscreteFactor` instances.
-        factors to be multiplied
-
-    Returns
-    -------
-    DiscreteFactor: `DiscreteFactor` representing factor product over all the `DiscreteFactor` instances in args.
-
-    Examples
-    --------
-    >>> from pgmpy.factors.discrete import DiscreteFactor, factor_product
-    >>> phi1 = DiscreteFactor(['x1', 'x2', 'x3'], [2, 3, 2], range(12))
-    >>> phi2 = DiscreteFactor(['x3', 'x4', 'x1'], [2, 2, 2], range(8))
-    >>> phi = factor_product(phi1, phi2)
-    >>> phi.variables
-    ['x1', 'x2', 'x3', 'x4']
-    >>> phi.cardinality
-    array([2, 3, 2, 2])
-    >>> phi.values
-    array([[[[ 0,  0],
-             [ 4,  6]],
-
-            [[ 0,  4],
-             [12, 18]],
-
-            [[ 0,  8],
-             [20, 30]]],
-
-
-           [[[ 6, 18],
-             [35, 49]],
-
-            [[ 8, 24],
-             [45, 63]],
-
-            [[10, 30],
-             [55, 77]]]])
-    """
-    if not all(isinstance(phi, DiscreteFactor) for phi in args):
-        raise TypeError("Arguments must be factors")
-    return reduce(lambda phi1, phi2: phi1 * phi2, args)
-
-
-def factor_divide(phi1, phi2):
-    """
-    Returns `DiscreteFactor` representing `phi1 / phi2`.
-
-    Parameters
-    ----------
-    phi1: Factor
-        The Dividend.
-
-    phi2: Factor
-        The Divisor.
-
-    Returns
-    -------
-    DiscreteFactor: `DiscreteFactor` representing factor division `phi1 / phi2`.
-
-    Examples
-    --------
-    >>> from pgmpy.factors.discrete import DiscreteFactor, factor_divide
-    >>> phi1 = DiscreteFactor(['x1', 'x2', 'x3'], [2, 3, 2], range(12))
-    >>> phi2 = DiscreteFactor(['x3', 'x1'], [2, 2], range(1, 5))
-    >>> phi = factor_divide(phi1, phi2)
-    >>> phi.variables
-    ['x1', 'x2', 'x3']
-    >>> phi.cardinality
-    array([2, 3, 2])
-    >>> phi.values
-    array([[[ 0.        ,  0.33333333],
-            [ 2.        ,  1.        ],
-            [ 4.        ,  1.66666667]],
-
-           [[ 3.        ,  1.75      ],
-            [ 4.        ,  2.25      ],
-            [ 5.        ,  2.75      ]]])
-    """
-    if not isinstance(phi1, DiscreteFactor) or not isinstance(phi2, DiscreteFactor):
-        raise TypeError("phi1 and phi2 should be factors instances")
-    return phi1.divide(phi2, inplace=False)
diff --git a/pgmpy/factors/discrete/__init__.py b/pgmpy/factors/discrete/__init__.py
index 3f2e4ecc..82f0f1fc 100644
--- a/pgmpy/factors/discrete/__init__.py
+++ b/pgmpy/factors/discrete/__init__.py
@@ -1,10 +1,8 @@
-from .DiscreteFactor import State, DiscreteFactor, factor_product, factor_divide
+from .DiscreteFactor import State, DiscreteFactor
 from .CPD import TabularCPD
 from .JointProbabilityDistribution import JointProbabilityDistribution
 
 __all__ = ['TabularCPD',
            'DiscreteFactor',
-           'factor_divide',
-           'factor_product',
            'State'
            ]
diff --git a/pgmpy/factors/distributions/CustomDistribution.py b/pgmpy/factors/distributions/CustomDistribution.py
index 6ffbecae..df0d88e5 100644
--- a/pgmpy/factors/distributions/CustomDistribution.py
+++ b/pgmpy/factors/distributions/CustomDistribution.py
@@ -460,7 +460,7 @@ class CustomDistribution(BaseDistribution):
 
         Parameters
         ----------
-        other: ContinuousCustomDistributionFactor
+        other: CustomDistribution
             The CustomDistribution to be multiplied.
 
         Returns
diff --git a/pgmpy/inference/ExactInference.py b/pgmpy/inference/ExactInference.py
index 6e9aa73b..ee353dbd 100644
--- a/pgmpy/inference/ExactInference.py
+++ b/pgmpy/inference/ExactInference.py
@@ -7,7 +7,7 @@ import numpy as np
 from pgmpy.extern.six.moves import filter, range
 
 from pgmpy.extern.six import string_types
-from pgmpy.factors.discrete import factor_product
+from pgmpy.factors import factor_product
 from pgmpy.inference import Inference
 from pgmpy.models import JunctionTree
 from pgmpy.utils import StateNameDecorator
diff --git a/pgmpy/inference/dbn_inference.py b/pgmpy/inference/dbn_inference.py
index 27c502a6..ed8d5158 100644
--- a/pgmpy/inference/dbn_inference.py
+++ b/pgmpy/inference/dbn_inference.py
@@ -2,7 +2,7 @@ from collections import defaultdict
 from itertools import tee, chain, combinations
 
 from pgmpy.factors.discrete import DiscreteFactor
-from pgmpy.factors.discrete import factor_product
+from pgmpy.factors import factor_product
 from pgmpy.inference import Inference, BeliefPropagation
 
 
diff --git a/pgmpy/models/ClusterGraph.py b/pgmpy/models/ClusterGraph.py
index c63c4c58..96276e4a 100644
--- a/pgmpy/models/ClusterGraph.py
+++ b/pgmpy/models/ClusterGraph.py
@@ -5,7 +5,7 @@ from collections import defaultdict
 import numpy as np
 
 from pgmpy.base import UndirectedGraph
-from pgmpy.factors.discrete import factor_product
+from pgmpy.factors import factor_product
 from pgmpy.extern.six.moves import filter, range, zip
 
 
diff --git a/pgmpy/models/FactorGraph.py b/pgmpy/models/FactorGraph.py
index ab9f088c..e3f8394d 100644
--- a/pgmpy/models/FactorGraph.py
+++ b/pgmpy/models/FactorGraph.py
@@ -9,7 +9,7 @@ from networkx.algorithms import bipartite
 from pgmpy.models.MarkovModel import MarkovModel
 from pgmpy.base import UndirectedGraph
 from pgmpy.factors.discrete import DiscreteFactor
-from pgmpy.factors.discrete import factor_product
+from pgmpy.factors import factor_product
 from pgmpy.extern.six.moves import filter, range, zip
 
 
diff --git a/pgmpy/models/MarkovModel.py b/pgmpy/models/MarkovModel.py
index 77fbad33..48a5a0b6 100644
--- a/pgmpy/models/MarkovModel.py
+++ b/pgmpy/models/MarkovModel.py
@@ -6,7 +6,8 @@ import networkx as nx
 import numpy as np
 
 from pgmpy.base import UndirectedGraph
-from pgmpy.factors.discrete import factor_product, DiscreteFactor
+from pgmpy.factors.discrete import DiscreteFactor
+from pgmpy.factors import factor_product
 from pgmpy.independencies import Independencies
 from pgmpy.extern.six.moves import map, range, zip
 
diff --git a/pgmpy/sampling/Sampling.py b/pgmpy/sampling/Sampling.py
index 1a31e566..5bf45c1a 100644
--- a/pgmpy/sampling/Sampling.py
+++ b/pgmpy/sampling/Sampling.py
@@ -4,7 +4,7 @@ import itertools
 import networkx as nx
 import numpy as np
 
-from pgmpy.factors.discrete import factor_product
+from pgmpy.factors import factor_product
 from pgmpy.inference import Inference
 from pgmpy.models import BayesianModel, MarkovChain, MarkovModel
 from pgmpy.utils.mathext import sample_discrete


Test patch:
diff --git a/pgmpy/tests/test_factors/test_discrete/test_Factor.py b/pgmpy/tests/test_factors/test_discrete/test_Factor.py
index deda235b..e5944767 100644
--- a/pgmpy/tests/test_factors/test_discrete/test_Factor.py
+++ b/pgmpy/tests/test_factors/test_discrete/test_Factor.py
@@ -8,8 +8,8 @@ from pgmpy.extern.six.moves import range
 
 from pgmpy.factors.discrete import DiscreteFactor
 from pgmpy.factors.discrete import JointProbabilityDistribution as JPD
-from pgmpy.factors.discrete import factor_divide
-from pgmpy.factors.discrete import factor_product
+from pgmpy.factors import factor_divide
+from pgmpy.factors import factor_product
 from pgmpy.factors.discrete.CPD import TabularCPD
 from pgmpy.independencies import Independencies
 from pgmpy.models import BayesianModel
diff --git a/pgmpy/tests/test_models/test_MarkovModel.py b/pgmpy/tests/test_models/test_MarkovModel.py
index bff0c551..5ddc6409 100644
--- a/pgmpy/tests/test_models/test_MarkovModel.py
+++ b/pgmpy/tests/test_models/test_MarkovModel.py
@@ -3,7 +3,8 @@ import unittest
 import networkx as nx
 import numpy as np
 
-from pgmpy.factors.discrete import DiscreteFactor, factor_product
+from pgmpy.factors.discrete import DiscreteFactor
+from pgmpy.factors import factor_product
 from pgmpy.independencies import Independencies
 from pgmpy.extern import six
 from pgmpy.extern.six.moves import range