Repository: pgmpy/pgmpy

Issue:
Variable naming inconsistency?
### Subject of the issue
In line 54, 55 of pgmpy/pgmpy/models/LinearGaussianBayesianNetwork.py, cpd.variables has been checked for, whereas, line 66 of  pgmpy/pgmpy/factors/continuous/LinearGaussianCPD.py has self.variable specified and not variables. Hence, I think that this error is being raised. Highly obliged if you look into it.


### Your environment
* pgmpy version : 0.1.6
* Python version : 3.4
* Operating System : Ubuntu 14.04

### Steps to reproduce
from pgmpy.models import *
model = LinearGaussianBayesianNetwork([('hist_dist', 'dist_relevance'),('curr_dist', 'dist_relevance'),('monthly_exp','offer_interest'),('cat_merchant_affinity','offer_interest'),
					  ('offer_interest','offer_hit_effect'),('dist_relevance','offer_hit_effect')])

model.add_nodes_from(['hist_dist', 'curr_dist', 'dist_relevance','monthly_exp','cat_merchant_affinity','offer_interest','offer_hit_effect'])


from pgmpy.factors.continuous import LinearGaussianCPD

hist_dist_cpd = LinearGaussianCPD('hist_dist', [200], 20)
curr_dist_cpd = LinearGaussianCPD('curr_dist', [400], 50)
dist_rel_cpd  = LinearGaussianCPD('dist_relevance', [0, 0.5, 0.5], 0.1, ['hist_dist', 'curr_dist'])

monthly_exp_cpd = LinearGaussianCPD('monthly_exp', [45000], 5000)
cat_merchant_cpd = LinearGaussianCPD('cat_merchant_affinity', [0.6], 0.2)
offer_interest_cpd = LinearGaussianCPD('offer_interest', [0, 0.7, 0.3], 0.1, ['monthly_exp', 'cat_merchant_affinity'])

offer_hit_effect_cpd = LinearGaussianCPD('offer_hit_effect', [0.1, 0.3, 0.6], 0.2, ['dist_relevance', 'offer_interest'])
model.add_cpds(hist_dist_cpd, curr_dist_cpd, dist_rel_cpd, monthly_exp_cpd, cat_merchant_cpd, offer_interest_cpd, offer_hit_effect_cpd)

### Expected behaviour
No error

### Actual behaviour
File "linearGaussian.py", line 25, in <module>
    model.add_cpds(hist_dist_cpd, curr_dist_cpd, dist_rel_cpd, monthly_exp_cpd, cat_merchant_cpd, offer_interest_cpd, offer_hit_effect_cpd)
  File "/usr/local/lib/python3.4/dist-packages/pgmpy-0.1.6-py3.4.egg/pgmpy/models/LinearGaussianBayesianNetwork.py", line 54, in add_cpds
    if set(cpd.variables) - set(cpd.variables).intersection(
AttributeError: 'LinearGaussianCPD' object has no attribute 'variables'


Discussion:
theUltraMarine19: This is a PR which is a replica of #962 

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e186fddc..f229f139 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,10 +13,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 5. Adds a global `SHOW_PROGRESS` variable.
 6. Adds Chow-Liu structure learning algorithm.
 7. Add `pgmpy.utils.get_example_model` to fetch models from bnlearn's repository.
+8. Adds `get_value` and `set_value` method to `DiscreteFactor` to get/set a single value.
+9. Adds `get_acestral_graph` to `DAG`.
 
 ### Changed
 1. Refactors ConstraintBasedEstimators into PC with a lot of general improvements.
 2. Improved (faster, new arguments) indepenedence tests with changes in argument.
+3. Refactors `sample_discrete` method. Sampling algorithms much faster.
+4. Refactors `HillClimbSearch` to be faster.
+5. Sampling methods now return dataframe of type categorical.
 
 ### Fixed
 
diff --git a/meta.yaml b/meta.yaml
index 5e1aa370..44013243 100644
--- a/meta.yaml
+++ b/meta.yaml
@@ -1,5 +1,5 @@
 {% set name = "pgmpy" %}
-{% set version = "0.1.11" %}
+{% set version = "0.1.12" %}
 
 package:
   name: "{{ name|lower }}"
diff --git a/pgmpy/__init__.py b/pgmpy/__init__.py
index c7370b32..84fa1538 100644
--- a/pgmpy/__init__.py
+++ b/pgmpy/__init__.py
@@ -1,4 +1,4 @@
 from .global_vars import HAS_PANDAS, device, no_progress
 
 __all__ = ["HAS_PANDAS", "device"]
-__version__ = "0.1.11dev"
+__version__ = "0.1.12"
diff --git a/pgmpy/base/DAG.py b/pgmpy/base/DAG.py
index f12951dc..40b70e2e 100644
--- a/pgmpy/base/DAG.py
+++ b/pgmpy/base/DAG.py
@@ -740,7 +740,7 @@ class DAG(nx.DiGraph):
     def get_ancestral_graph(self, nodes):
         """
         Returns the ancestral graph of the given `nodes`. The ancestral graph only
-        contains the nodes which are ancestors of atleast one of the variables in 
+        contains the nodes which are ancestors of atleast one of the variables in
         node.
 
         Parameters
diff --git a/pgmpy/estimators/BayesianEstimator.py b/pgmpy/estimators/BayesianEstimator.py
index 81569dfd..62317e3f 100644
--- a/pgmpy/estimators/BayesianEstimator.py
+++ b/pgmpy/estimators/BayesianEstimator.py
@@ -107,7 +107,7 @@ class BayesianEstimator(ParameterEstimator):
                 'pseudo_counts' = dirichlet hyperparameters; a single number or 2-D array
                  of shape (node_card, product of parents_card) with a "virtual" count for
                  each variable state in the CPD. The virtual counts are added to the
-                 actual state counts found in the data. (if a list is provided, a 
+                 actual state counts found in the data. (if a list is provided, a
                  lexicographic ordering of states is assumed)
             - If 'prior_type' is 'BDeu', then an 'equivalent_sample_size'
                  must be specified instead of 'pseudo_counts'. This is equivalent to
diff --git a/pgmpy/estimators/PC.py b/pgmpy/estimators/PC.py
index 0335f334..f44b6c2f 100644
--- a/pgmpy/estimators/PC.py
+++ b/pgmpy/estimators/PC.py
@@ -237,7 +237,7 @@ class PC(StructureEstimator):
 
         Examples
         --------
-        >>> from pgmpy.estimators import PC 
+        >>> from pgmpy.estimators import PC
         >>> from pgmpy.models import DAG
         >>> from pgmpy.independencies import Independencies
         >>> # build skeleton from list of independencies:
diff --git a/pgmpy/factors/continuous/LinearGaussianCPD.py b/pgmpy/factors/continuous/LinearGaussianCPD.py
index 6db05852..aa45b670 100644
--- a/pgmpy/factors/continuous/LinearGaussianCPD.py
+++ b/pgmpy/factors/continuous/LinearGaussianCPD.py
@@ -79,9 +79,9 @@ class LinearGaussianCPD(BaseFactor):
         self.evidence = evidence
         self.sigma_yx = None
 
-        variables = [variable] + evidence
+        self.variables = [variable] + evidence
         super(LinearGaussianCPD, self).__init__(
-            variables, pdf="gaussian", mean=self.mean, covariance=self.variance
+            self.variables, pdf="gaussian", mean=self.mean, covariance=self.variance
         )
 
     def sum_of_product(self, xi, xj):
diff --git a/pgmpy/factors/discrete/JointProbabilityDistribution.py b/pgmpy/factors/discrete/JointProbabilityDistribution.py
index 113a9d41..a1d32b2f 100644
--- a/pgmpy/factors/discrete/JointProbabilityDistribution.py
+++ b/pgmpy/factors/discrete/JointProbabilityDistribution.py
@@ -69,7 +69,7 @@ class JointProbabilityDistribution(DiscreteFactor):
         x1_1  x2_0  x3_1         0.1250
         x1_1  x2_1  x3_0         0.1250
         x1_1  x2_1  x3_1         0.1250
-       """
+        """
         if np.isclose(np.sum(values), 1):
             super(JointProbabilityDistribution, self).__init__(
                 variables, cardinality, values
diff --git a/pgmpy/models/MarkovModel.py b/pgmpy/models/MarkovModel.py
index a82dd7ca..58a07910 100644
--- a/pgmpy/models/MarkovModel.py
+++ b/pgmpy/models/MarkovModel.py
@@ -145,7 +145,7 @@ class MarkovModel(UndirectedGraph):
         Parameters
         ----------
         node: any hashable python object (optional)
-            The node whose factor we want. If node is not specified
+           The node whose factor we want. If node is not specified
 
         Examples
         --------
@@ -153,13 +153,13 @@ class MarkovModel(UndirectedGraph):
         >>> from pgmpy.factors.discrete import DiscreteFactor
         >>> student = MarkovModel([('Alice', 'Bob'), ('Bob', 'Charles')])
         >>> factor1 = DiscreteFactor(['Alice', 'Bob'], cardinality=[2, 2],
-        ...                 values=np.random.rand(4))
+        ...                          values=np.random.rand(4))
         >>> factor2 = DiscreteFactor(['Bob', 'Charles'], cardinality=[2, 3],
-        ...					values=np.ones(6))
+        ...                          values=np.ones(6))
         >>> student.add_factors(factor1,factor2)
         >>> student.get_factors()
         [<DiscreteFactor representing phi(Alice:2, Bob:2) at 0x7f8a0e9bf630>,
-         <DiscreteFactor representing phi(Bob:2, Charles:3) at 0x7f8a0e9bf5f8>]
+        <DiscreteFactor representing phi(Bob:2, Charles:3) at 0x7f8a0e9bf5f8>]
         >>> student.get_factors('Alice')
         [<DiscreteFactor representing phi(Alice:2, Bob:2) at 0x7f8a0e9bf630>]
         """
diff --git a/pgmpy/models/NaiveBayes.py b/pgmpy/models/NaiveBayes.py
index 4a7d2fe6..40ef77a0 100644
--- a/pgmpy/models/NaiveBayes.py
+++ b/pgmpy/models/NaiveBayes.py
@@ -74,7 +74,7 @@ class NaiveBayes(BayesianModel):
         Adds edges to the model.
 
         Each tuple of the form (u, v) in ebunch adds a new edge in the model.
-        Since there can only be one dependent variable in a Naive Bayes model, `u` should 
+        Since there can only be one dependent variable in a Naive Bayes model, `u` should
         be the same for each tuple in `ebunch`.
 
         Parameters
diff --git a/pgmpy/readwrite/BIF.py b/pgmpy/readwrite/BIF.py
index 42f623ab..b868980f 100644
--- a/pgmpy/readwrite/BIF.py
+++ b/pgmpy/readwrite/BIF.py
@@ -97,7 +97,7 @@ class BIFReader(object):
 
     def get_variable_grammar(self):
         """
-         A method that returns variable grammar
+        A method that returns variable grammar
         """
         # Defining a expression for valid word
         word_expr = Word(alphanums + "_" + "-")
diff --git a/pgmpy/readwrite/XMLBeliefNetwork.py b/pgmpy/readwrite/XMLBeliefNetwork.py
index c0c75254..5c568bde 100644
--- a/pgmpy/readwrite/XMLBeliefNetwork.py
+++ b/pgmpy/readwrite/XMLBeliefNetwork.py
@@ -149,7 +149,7 @@ class XBNReader(object):
         Returns a dictionary of name and its distribution. Distribution is a ndarray.
 
         The ndarray is stored in the standard way such that the rightmost variable
-        changes most often. Consider a CPD of variable 'd' which has parents 'b' and 
+        changes most often. Consider a CPD of variable 'd' which has parents 'b' and
         'c' (distribution['CONDSET'] = ['b', 'c'])
 
                   |  d_0     d_1
diff --git a/pgmpy/sampling/base.py b/pgmpy/sampling/base.py
index d5e26024..edb1003e 100644
--- a/pgmpy/sampling/base.py
+++ b/pgmpy/sampling/base.py
@@ -437,7 +437,7 @@ class ModifiedEuler(BaseSimulateHamiltonianDynamics):
 
 def _return_samples(return_type, samples, state_names_map=None):
     """
-        A utility function to return samples according to type
+    A utility function to return samples according to type
     """
     if return_type.lower() == "dataframe":
         if HAS_PANDAS:
diff --git a/pgmpy/utils/utils.py b/pgmpy/utils/utils.py
index 262e9582..949056b7 100644
--- a/pgmpy/utils/utils.py
+++ b/pgmpy/utils/utils.py
@@ -4,7 +4,7 @@ from urllib.request import urlretrieve
 
 def get_example_model(model):
     """
-    Fetches the specified model from bnlearn repository and returns a 
+    Fetches the specified model from bnlearn repository and returns a
     pgmpy.model instance.
 
     Parameter


Test patch:
diff --git a/pgmpy/tests/test_models/test_LinearGaussianBayesianNetwork.py b/pgmpy/tests/test_models/test_LinearGaussianBayesianNetwork.py
index de711894..d282a46a 100644
--- a/pgmpy/tests/test_models/test_LinearGaussianBayesianNetwork.py
+++ b/pgmpy/tests/test_models/test_LinearGaussianBayesianNetwork.py
@@ -9,13 +9,23 @@ from pgmpy.models import LinearGaussianBayesianNetwork
 
 
 class TestLGBNMethods(unittest.TestCase):
-    @unittest.skip("TODO")
     def setUp(self):
         self.model = LinearGaussianBayesianNetwork([("x1", "x2"), ("x2", "x3")])
         self.cpd1 = LinearGaussianCPD("x1", [1], 4)
         self.cpd2 = LinearGaussianCPD("x2", [-5, 0.5], 4, ["x1"])
         self.cpd3 = LinearGaussianCPD("x3", [4, -1], 3, ["x2"])
 
+    def test_cpds_simple(self):
+        self.assertEqual("x1", self.cpd1.variable)
+        self.assertEqual(4, self.cpd1.variance)
+        self.assertEqual([1], self.cpd1.mean)
+
+        self.model.add_cpds(self.cpd1)
+        cpd = self.model.get_cpds("x1")
+        self.assertEqual(cpd.variable, self.cpd1.variable)
+        self.assertEqual(cpd.variance, self.cpd1.variance)
+        self.assertEqual(cpd.mean, self.cpd1.mean)
+
     @unittest.skip("TODO")
     def test_add_cpds(self):
         self.model.add_cpds(self.cpd1)
diff --git a/pgmpy/tests/test_readwrite/test_XMLBIF.py b/pgmpy/tests/test_readwrite/test_XMLBIF.py
index a6e88c85..51ebb2db 100644
--- a/pgmpy/tests/test_readwrite/test_XMLBIF.py
+++ b/pgmpy/tests/test_readwrite/test_XMLBIF.py
@@ -366,7 +366,10 @@ class TestXMLBIFWriterMethodsString(unittest.TestCase):
         model = reader.get_model(state_name_type=int)
         self.assert_models_equivelent(self.model_stateless, model)
         self.assertDictEqual(
-            {"D": [0, 1],}, model.get_cpds("D").state_names,
+            {
+                "D": [0, 1],
+            },
+            model.get_cpds("D").state_names,
         )
         os.remove("grade_problem_output.xbif")