Repository: pgmpy/pgmpy

Issue:
`factor_product` returns same object as input for single argument
### Subject of the issue
`pgmpy.factors.base.factor_product` returns the same object as input. No copy is made

### Your environment
* pgmpy version - 0.1.18
* Python version - 3.8.10
* Operating System - WSL 2 on Windows 10 Enterprise

### Steps to reproduce
In the case where `factor_product` gets a single argument it returns the same object as the input
```
>>> from pgmpy.factors.discrete import DiscreteFactor
>>> import numpy as np
>>> phi = DiscreteFactor(['x1', 'x2'], [2,2], np.ones(4))
>>> from pgmpy.factors.base import factor_product
>>> phi
<DiscreteFactor representing phi(x1:2, x2:2) at 0x7f7e46d44370>
>>> factor_product(*[phi])
<DiscreteFactor representing phi(x1:2, x2:2) at 0x7f7e46d44370>
```

This created a problem in `DBNInference._get_factor` where the returned factor is modified (https://github.com/pgmpy/pgmpy/blob/dev/pgmpy/inference/dbn_inference.py#L203) leading to the factors in `belief_prop.junction_tree` being modified when they probably shouldn't be

### Expected behaviour
`factor_product` should probably return a copied input in the single argument case.

### Actual behaviour
`factor_product` returns the same object as the input


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

```diff
@@            Coverage Diff             @@
##              dev    #1566      +/-   ##
==========================================
- Coverage   94.77%   93.89%   -0.88%     
==========================================
  Files         143      143              
  Lines       16581    16530      -51     
==========================================
- Hits        15714    15521     -193     
- Misses        867     1009     +142     
```


| [Impacted Files](https://codecov.io/gh/pgmpy/pgmpy/pull/1566?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy) | Coverage Δ | |
|---|---|---|
| [pgmpy/factors/base.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1566/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy#diff-cGdtcHkvZmFjdG9ycy9iYXNlLnB5) | `91.17% <100.00%> (+0.26%)` | :arrow_up: |
| [...py/tests/test\_factors/test\_discrete/test\_Factor.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1566/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy#diff-cGdtcHkvdGVzdHMvdGVzdF9mYWN0b3JzL3Rlc3RfZGlzY3JldGUvdGVzdF9GYWN0b3IucHk=) | `99.70% <100.00%> (+<0.01%)` | :arrow_up: |
| [pgmpy/sampling/NUTS.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1566/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy#diff-cGdtcHkvc2FtcGxpbmcvTlVUUy5weQ==) | `19.74% <0.00%> (-78.35%)` | :arrow_down: |
| [...py/tests/test\_sampling/test\_continuous\_sampling.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1566/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy#diff-cGdtcHkvdGVzdHMvdGVzdF9zYW1wbGluZy90ZXN0X2NvbnRpbnVvdXNfc2FtcGxpbmcucHk=) | `83.33% <0.00%> (-16.67%)` | :arrow_down: |
| [.../test\_models/test\_LinearGaussianBayesianNetwork.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1566/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\_Gaussian\_CPD.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1566/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy#diff-cGdtcHkvdGVzdHMvdGVzdF9mYWN0b3JzL3Rlc3RfY29udGludW91cy90ZXN0X0xpbmVhcl9HYXVzc2lhbl9DUEQucHk=) | `46.66% <0.00%> (-1.73%)` | :arrow_down: |
| [pgmpy/factors/continuous/discretize.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1566/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/1566/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: |
| [...gmpy/factors/distributions/GaussianDistribution.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1566/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/1566/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: |
| ... and [19 more](https://codecov.io/gh/pgmpy/pgmpy/pull/1566/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy) | |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy)


Patch:
diff --git a/pgmpy/factors/base.py b/pgmpy/factors/base.py
index bd55c64e..0ad6ddd4 100644
--- a/pgmpy/factors/base.py
+++ b/pgmpy/factors/base.py
@@ -70,7 +70,10 @@ def factor_product(*args):
             "All the args are expected to be instances of the same factor class."
         )
 
-    return reduce(lambda phi1, phi2: phi1 * phi2, args)
+    if len(args) == 1:
+        return args[0].copy()
+    else:
+        return reduce(lambda phi1, phi2: phi1 * phi2, args)
 
 
 def factor_sum_product(output_vars, factors):


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 9be8b7dc..5d49480c 100644
--- a/pgmpy/tests/test_factors/test_discrete/test_Factor.py
+++ b/pgmpy/tests/test_factors/test_discrete/test_Factor.py
@@ -553,6 +553,11 @@ class TestFactorMethods(unittest.TestCase):
         self.assertEqual(prod, expected_factor)
         self.assertEqual(set(prod.variables), set(expected_factor.variables))
 
+        # Test for Issue 1565
+        prod = factor_product(phi)
+        self.assertEqual(phi, prod)
+        self.assertNotEqual(id(phi), id(prod))
+
     def test_product(self):
         phi = DiscreteFactor(["x1", "x2"], [2, 2], range(4))
         phi1 = DiscreteFactor(["x3", "x4"], [2, 2], range(4))