Repository: pgmpy/pgmpy

Issue:
DBNInference  ValueError: Self loops are not allowed
Hi! 
when I try to construct model with DBN like this:

![20201222145647](https://user-images.githubusercontent.com/76466183/102854491-fce23180-4465-11eb-98af-44c0ee74deec.png)

`from pgmpy.models import DynamicBayesianNetwork as DBN`
`from pgmpy.factors.discrete import TabularCPD`
`from pgmpy.inference import DBNInference`
`dbn = DBN()`
`dbn.add_edges_from([(('a', 0),('b', 0)),(('a', 0),('a', 1)), (('a', 0),('b', 1))])`
`a_0=TabularCPD(('a', 0), 2, [[0.5],[0.5]])`
`b_0=TabularCPD(('b', 0), 2, [[0.3,0.7],[0.7,0.3]],[('a',0)],[2])`
`a_1=TabularCPD(('a', 1), 2, [[0.3,0.7],[0.7,0.3]],[('a',0)],[2])`
`dbn.add_cpds(a_0, b_0, a_1)`
`dbn_inf = DBNInference(dbn)`

But when I execute the code I get this error:

`  File "C:\users\a5767\appdata\local\programs\python\python36\lib\site-packages\pgmpy\models\untitled9.py", line 25, in <module>
    dbn_inf = DBNInference(dbn)
`
  `File "c:\users\a5767\appdata\local\programs\python\python36\lib\site-packages\pgmpy\inference\dbn_inference.py", line 70, in __init__
    start_markov_model.add_edges_from(combinations_slice_0[0])`
`  File "c:\users\a5767\appdata\local\programs\python\python36\lib\site-packages\pgmpy\base\UndirectedGraph.py", line 252, in add_edges_from
    self.add_edge(edge[0], edge[1])`
`  File "c:\users\a5767\appdata\local\programs\python\python36\lib\site-packages\pgmpy\models\MarkovModel.py", line 105, in add_edge
    raise ValueError("Self loops are not allowed")`
`ValueError: Self loops are not allowed`


 Thank you very much for someone who can help me with this error.


Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/pgmpy/pgmpy/pull/1447?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy) Report
> Merging [#1447](https://codecov.io/gh/pgmpy/pgmpy/pull/1447?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy) (8dca1c1) into [dev](https://codecov.io/gh/pgmpy/pgmpy/commit/f4f6fc22fcd8cb2fdb18ab14722d7dbee35fbb6b?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy) (f4f6fc2) will **decrease** coverage by `0.01%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/pgmpy/pgmpy/pull/1447/graphs/tree.svg?width=650&height=150&src=pr&token=UaJMCdHaEF&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy)](https://codecov.io/gh/pgmpy/pgmpy/pull/1447?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy)

```diff
@@            Coverage Diff             @@
##              dev    #1447      +/-   ##
==========================================
- Coverage   94.55%   94.53%   -0.02%     
==========================================
  Files         141      141              
  Lines       15819    15766      -53     
==========================================
- Hits        14958    14905      -53     
  Misses        861      861              
```


| [Impacted Files](https://codecov.io/gh/pgmpy/pgmpy/pull/1447?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy) | Coverage Δ | |
|---|---|---|
| [...y/tests/test\_models/test\_DynamicBayesianNetwork.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1447/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy#diff-cGdtcHkvdGVzdHMvdGVzdF9tb2RlbHMvdGVzdF9EeW5hbWljQmF5ZXNpYW5OZXR3b3JrLnB5) | `100.00% <ø> (ø)` | |
| [pgmpy/models/DynamicBayesianNetwork.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1447/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy#diff-cGdtcHkvbW9kZWxzL0R5bmFtaWNCYXllc2lhbk5ldHdvcmsucHk=) | `93.08% <100.00%> (-0.04%)` | :arrow_down: |
| [.../test\_models/test\_LinearGaussianBayesianNetwork.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1447/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy#diff-cGdtcHkvdGVzdHMvdGVzdF9tb2RlbHMvdGVzdF9MaW5lYXJHYXVzc2lhbkJheWVzaWFuTmV0d29yay5weQ==) | `39.06% <0.00%> (-3.59%)` | :arrow_down: |
| [...actors/test\_continuous/test\_Linear\_Gaussain\_CPD.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1447/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy#diff-cGdtcHkvdGVzdHMvdGVzdF9mYWN0b3JzL3Rlc3RfY29udGludW91cy90ZXN0X0xpbmVhcl9HYXVzc2Fpbl9DUEQucHk=) | `40.00% <0.00%> (-2.86%)` | :arrow_down: |
| [pgmpy/factors/continuous/discretize.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1447/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy#diff-cGdtcHkvZmFjdG9ycy9jb250aW51b3VzL2Rpc2NyZXRpemUucHk=) | `34.21% <0.00%> (-1.69%)` | :arrow_down: |
| [pgmpy/tests/test\_estimators/test\_SEMEstimator.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1447/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy#diff-cGdtcHkvdGVzdHMvdGVzdF9lc3RpbWF0b3JzL3Rlc3RfU0VNRXN0aW1hdG9yLnB5) | `79.66% <0.00%> (-1.59%)` | :arrow_down: |
| [pgmpy/factors/base.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1447/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy#diff-cGdtcHkvZmFjdG9ycy9iYXNlLnB5) | `84.21% <0.00%> (-0.79%)` | :arrow_down: |
| [...gmpy/factors/distributions/GaussianDistribution.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1447/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy#diff-cGdtcHkvZmFjdG9ycy9kaXN0cmlidXRpb25zL0dhdXNzaWFuRGlzdHJpYnV0aW9uLnB5) | `69.00% <0.00%> (-0.61%)` | :arrow_down: |
| [pgmpy/independencies/Independencies.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1447/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy#diff-cGdtcHkvaW5kZXBlbmRlbmNpZXMvSW5kZXBlbmRlbmNpZXMucHk=) | `87.39% <0.00%> (-0.41%)` | :arrow_down: |
| [pgmpy/factors/continuous/ContinuousFactor.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1447/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy#diff-cGdtcHkvZmFjdG9ycy9jb250aW51b3VzL0NvbnRpbnVvdXNGYWN0b3IucHk=) | `86.11% <0.00%> (-0.38%)` | :arrow_down: |
| ... and [14 more](https://codecov.io/gh/pgmpy/pgmpy/pull/1447/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pgmpy/pgmpy/pull/1447?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pgmpy/pgmpy/pull/1447?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy). Last update [f4f6fc2...8dca1c1](https://codecov.io/gh/pgmpy/pgmpy/pull/1447?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy).

ankurankan: @FelipeGiro I think you can add the new tests in the `TestDynamicBayesianNetworkMethods.test_get_interface_nodes` methods. And please also add a short comment saying which issue the test deals with. Something like `#Tests for #1364`

Patch:
diff --git a/pgmpy/models/DynamicBayesianNetwork.py b/pgmpy/models/DynamicBayesianNetwork.py
index 3cacc633..d12e610b 100644
--- a/pgmpy/models/DynamicBayesianNetwork.py
+++ b/pgmpy/models/DynamicBayesianNetwork.py
@@ -373,10 +373,13 @@ class DynamicBayesianNetwork(DAG):
         """
         if not isinstance(time_slice, int) or time_slice < 0:
             raise ValueError(
-                "The timeslice should be a positive value greater than or equal to zero"
+                f"The timeslice should be a positive integer greater than or equal to zero: ({type(time_slice)}, value: {time_slice})"
             )
 
-        return [DynamicNode(edge[0][0], time_slice) for edge in self.get_inter_edges()]
+        return [
+            DynamicNode(edge[time_slice][0], edge[time_slice][1])
+            for edge in self.get_inter_edges()
+        ]
 
     def get_slice_nodes(self, time_slice=0):
         """


Test patch:
diff --git a/pgmpy/tests/test_models/test_DynamicBayesianNetwork.py b/pgmpy/tests/test_models/test_DynamicBayesianNetwork.py
index 8ae22510..c189a875 100644
--- a/pgmpy/tests/test_models/test_DynamicBayesianNetwork.py
+++ b/pgmpy/tests/test_models/test_DynamicBayesianNetwork.py
@@ -144,9 +144,36 @@ class TestDynamicBayesianNetworkMethods(unittest.TestCase):
         self.assertListEqual(
             sorted(self.network.get_interface_nodes()), [("D", 0), ("I", 0)]
         )
+
         self.assertRaises(ValueError, self.network.get_interface_nodes, -1)
         self.assertRaises(ValueError, self.network.get_interface_nodes, "-")
 
+    def test_get_interface_nodes_1node2edges_divergent_edges(self):
+        # divergent interface edges from one node (a0->a1,b1). issue #1364
+        self.network.add_edges_from(
+            [
+                (("A", 0), ("A", 1)),
+                (("A", 0), ("B", 0)),
+                (("A", 0), ("B", 1)),
+                (("A", 1), ("B", 1)),
+            ]
+        )
+        self.assertListEqual(self.network.get_interface_nodes(0), [("A", 0), ("A", 0)])
+        self.assertListEqual(self.network.get_interface_nodes(1), [("A", 1), ("B", 1)])
+
+    def test_get_interface_nodes_convergent_edges(self):
+        # convergent interface edges to one node(a0,b0->b1). issue #1364
+        self.network.add_edges_from(
+            [
+                (("A", 0), ("B", 1)),
+                (("B", 0), ("B", 1)),
+                (("A", 0), ("B", 0)),
+                (("A", 1), ("B", 1)),
+            ]
+        )
+        self.assertListEqual(self.network.get_interface_nodes(0), [("A", 0), ("B", 0)])
+        self.assertListEqual(self.network.get_interface_nodes(1), [("B", 1), ("B", 1)])
+
     def test_get_slice_nodes(self):
         self.network.add_edges_from(
             [