Repository: pgmpy/pgmpy

Issue:
CausalInference: Same Variables in Variables/Evidence Error when not the same?
### Subject of the issue

Hi, I seem to be running into a bug where the CausalInference.query method complains that the variables in the "variables" and evidence arg are the same when they actually aren't. Below is the code: 

### Your environment
* pgmpy version:  0.1.15
* Python version: 3.8
* Operating System:MacOS Catalina

### Steps to reproduce

Here is some simulated data

```
import numpy as np
import pandas as pd
import pgmpy
from pgmpy.models import BayesianModel
from pgmpy.estimators import MaximumLikelihoodEstimator,BayesianEstimator
from pgmpy.inference import VariableElimination,CausalInference


n = 10000

#P(W)

pW = 0.3
W = np.random.binomial(1,pW,n)

#P(X=1|W=0) = 0.3, P(X=1,|W=1) = 0.6
nW1 = np.sum(W==1)
nW0 = np.sum(W==0)

pX_W0 = 0.3
pX_W1 = 0.6
X = np.zeros(n)
X[:] = np.nan

X[W==0] = np.random.binomial(1,pX_W0,nW0)
X[W==1] = np.random.binomial(1,pX_W1,nW1)

#P(Y=1|X=1,W=0) = 0.3, P(Y=1|X=0,W=0) = 0.3, P(Y=1|X=1,W=1) = 0.9, P(Y=1|X=0,W=1) = 0.5

nX1W0 = np.sum((X==1) & (W==0))
nX0W0 = np.sum((X==0) & (W==0))
nX1W1 = np.sum((X==1) & (W==1))
nX0W1 = np.sum((X==0) & (W==1))

pY_X1W0 = 0.3
pY_X0W0 = 0.3
pY_X1W1 = 0.9
pY_X0W1 = 0.5

Y = np.zeros(n)
Y[:] = np.nan 
Y[(X==1) & (W==0)] = np.random.binomial(1,pY_X1W0,nX1W0)
Y[(X==0) & (W==0)] = np.random.binomial(1,pY_X0W0,nX0W0)
Y[(X==1) & (W==1)] = np.random.binomial(1,pY_X1W1,nX1W1)
Y[(X==0) & (W==1)] = np.random.binomial(1,pY_X0W1,nX0W1)

simdata = pd.DataFrame({"Y":Y,"X":X,"W":W})

bn = BayesianModel([("X","Y"),("W","X"),("W","Y")])
bn.fit(simdata)

VE = VariableElimination(bn)
VEres = VE.query(variables=["Y"],evidence={"X":1,"W":1})
VEres.values


ci = CausalInference(bn)
cires = ci.query(variables=["Y"],do={"X":1},evidence={"W":1}) #Error occurs here
cires.values

```


### Expected behaviour

I should be getting around 0.9 for cires[1] but instead I get the error below. The thing is the evidence has W and the variables has Y, so it makes no sense why it is complaining. 

### Actual behaviour

`ValueError: Can't have the same variables in both `variables` and `evidence`. Found in both: {'W'}`


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

[![Impacted file tree graph](https://codecov.io/gh/pgmpy/pgmpy/pull/1461/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/1461?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy)

```diff
@@            Coverage Diff             @@
##              dev    #1461      +/-   ##
==========================================
- Coverage   94.69%   93.08%   -1.61%     
==========================================
  Files         141      141              
  Lines       16325    16343      +18     
==========================================
- Hits        15459    15213     -246     
- Misses        866     1130     +264     
```


| [Impacted Files](https://codecov.io/gh/pgmpy/pgmpy/pull/1461?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy) | Coverage Δ | |
|---|---|---|
| [pgmpy/factors/discrete/DiscreteFactor.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1461/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy#diff-cGdtcHkvZmFjdG9ycy9kaXNjcmV0ZS9EaXNjcmV0ZUZhY3Rvci5weQ==) | `98.99% <100.00%> (+<0.01%)` | :arrow_up: |
| [pgmpy/inference/CausalInference.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1461/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy#diff-cGdtcHkvaW5mZXJlbmNlL0NhdXNhbEluZmVyZW5jZS5weQ==) | `75.84% <100.00%> (+1.28%)` | :arrow_up: |
| [pgmpy/tests/test\_inference/test\_CausalInference.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1461/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy#diff-cGdtcHkvdGVzdHMvdGVzdF9pbmZlcmVuY2UvdGVzdF9DYXVzYWxJbmZlcmVuY2UucHk=) | `100.00% <100.00%> (ø)` | |
| [pgmpy/sampling/NUTS.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1461/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: |
| [pgmpy/readwrite/XMLBeliefNetwork.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1461/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy#diff-cGdtcHkvcmVhZHdyaXRlL1hNTEJlbGllZk5ldHdvcmsucHk=) | `53.62% <0.00%> (-39.14%)` | :arrow_down: |
| [...gmpy/tests/test\_readwrite/test\_XMLBeliefNetwork.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1461/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy#diff-cGdtcHkvdGVzdHMvdGVzdF9yZWFkd3JpdGUvdGVzdF9YTUxCZWxpZWZOZXR3b3JrLnB5) | `75.40% <0.00%> (-18.86%)` | :arrow_down: |
| [...py/tests/test\_sampling/test\_continuous\_sampling.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1461/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy#diff-cGdtcHkvdGVzdHMvdGVzdF9zYW1wbGluZy90ZXN0X2NvbnRpbnVvdXNfc2FtcGxpbmcucHk=) | `83.47% <0.00%> (-16.53%)` | :arrow_down: |
| [pgmpy/readwrite/PomdpX.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1461/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy#diff-cGdtcHkvcmVhZHdyaXRlL1BvbWRwWC5weQ==) | `86.62% <0.00%> (-10.37%)` | :arrow_down: |
| [pgmpy/tests/test\_readwrite/test\_PomdpX.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1461/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy#diff-cGdtcHkvdGVzdHMvdGVzdF9yZWFkd3JpdGUvdGVzdF9Qb21kcFgucHk=) | `83.68% <0.00%> (-9.22%)` | :arrow_down: |
| [pgmpy/estimators/MmhcEstimator.py](https://codecov.io/gh/pgmpy/pgmpy/pull/1461/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy#diff-cGdtcHkvZXN0aW1hdG9ycy9NbWhjRXN0aW1hdG9yLnB5) | `98.11% <0.00%> (-1.89%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pgmpy/pgmpy/pull/1461?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/1461?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pgmpy). Last update [0af6fea...63257e9](https://codecov.io/gh/pgmpy/pgmpy/pull/1461?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).


Patch:
diff --git a/pgmpy/inference/CausalInference.py b/pgmpy/inference/CausalInference.py
index b85f9dce..15dede64 100644
--- a/pgmpy/inference/CausalInference.py
+++ b/pgmpy/inference/CausalInference.py
@@ -6,6 +6,7 @@ import networkx as nx
 from tqdm.auto import tqdm
 
 from pgmpy.models import BayesianNetwork
+from pgmpy.factors.discrete import DiscreteFactor
 from pgmpy.estimators.LinearModel import LinearEstimator
 from pgmpy.global_vars import SHOW_PROGRESS
 from pgmpy.utils.sets import _powerset, _variable_or_iterable_to_set
@@ -590,7 +591,7 @@ class CausalInference(object):
                 f"inference_algo must be one of: 've', 'bp', or an instance of pgmpy.inference.Inference. Got: {inference_algo}"
             )
 
-        # Step 2: Check if adjustment set is provided, otherwise calcualte it.
+        # Step 2: Check if adjustment set is provided, otherwise try calculating it.
         if adjustment_set is None:
             do_vars = [var for var, state in do.items()]
             adjustment_set = set(
@@ -612,13 +613,47 @@ class CausalInference(object):
             evidence = {**evidence, **do}
             return infer.query(variables, evidence, show_progress=False)
 
-        # Step 3: Compute \sum_{z} p(variables | do, z) p(z)
+        # Step 4: For other cases, compute \sum_{z} p(variables | do, z) p(z)
         values = []
-        p_z = infer.query(adjustment_set, evidence=evidence, show_progress=False)
-        adj_states = [
-            self.model.get_cpds(var).state_names[var] for var in adjustment_set
-        ]
 
+        # Step 4.1: Compute p_z and states of z to iterate over.
+        # For computing p_z, if evidence variables also in adjustment set,
+        # manually do reduce else inference will throw error.
+        evidence_adj_inter = {
+            var: state
+            for var, state in evidence.items()
+            if var in adjustment_set.intersection(evidence.keys())
+        }
+        if len(evidence_adj_inter) != 0:
+            p_z = infer.query(adjustment_set, show_progress=False).reduce(
+                [(key, value) for key, value in evidence_adj_inter.items()],
+                inplace=False,
+            )
+            # Since we are doing reduce over some of the variables, they are
+            # going to be removed from the factor but would be required to get
+            # values later. A hackish solution to reintroduce those variables in p_z
+
+            if set(p_z.variables) != adjustment_set:
+                p_z = DiscreteFactor(
+                    p_z.variables + list(evidence_adj_inter.keys()),
+                    list(p_z.cardinality) + [1] * len(evidence_adj_inter),
+                    p_z.values,
+                    state_names={
+                        **p_z.state_names,
+                        **{var: [state] for var, state in evidence_adj_inter.items()},
+                    },
+                )
+        else:
+            p_z = infer.query(adjustment_set, evidence=evidence, show_progress=False)
+
+        adj_states = []
+        for var in adjustment_set:
+            if var in evidence_adj_inter.keys():
+                adj_states.append([evidence_adj_inter[var]])
+            else:
+                adj_states.append(self.model.get_cpds(var).state_names[var])
+
+        # Step 4.2: Iterate over states of adjustment set and compute values.
         if show_progress and SHOW_PROGRESS:
             pbar = tqdm(total=np.prod([len(states) for states in adj_states]))
 


Test patch:
diff --git a/pgmpy/tests/test_inference/test_CausalInference.py b/pgmpy/tests/test_inference/test_CausalInference.py
index c53ccef5..35aa8f1d 100644
--- a/pgmpy/tests/test_inference/test_CausalInference.py
+++ b/pgmpy/tests/test_inference/test_CausalInference.py
@@ -371,6 +371,58 @@ class TestDoQuery(unittest.TestCase):
             query5 = self.example_infer.query(["Y"], adjustment_set=["W", "Z"])
             np_test.assert_array_almost_equal(query5.values, np.array([0.62, 0.38]))
 
+    def test_issue_1459(self):
+        bn = BayesianNetwork([("X", "Y"), ("W", "X"), ("W", "Y")])
+        cpd_w = TabularCPD(variable="W", variable_card=2, values=[[0.7], [0.3]])
+        cpd_x = TabularCPD(
+            variable="X",
+            variable_card=2,
+            values=[[0.7, 0.4], [0.3, 0.6]],
+            evidence=["W"],
+            evidence_card=[2],
+        )
+        cpd_y = TabularCPD(
+            variable="Y",
+            variable_card=2,
+            values=[[0.7, 0.7, 0.5, 0.1], [0.3, 0.3, 0.5, 0.9]],
+            evidence=["W", "X"],
+            evidence_card=[2, 2],
+        )
+
+        bn.add_cpds(cpd_w, cpd_x, cpd_y)
+        causal_infer = CausalInference(bn)
+        query = causal_infer.query(["Y"], do={"X": 1}, evidence={"W": 1})
+        np_test.assert_array_almost_equal(query.values, np.array([0.1, 0.9]))
+
+        # A slight modified version of the above model where only some of the adjustment
+        # set variables are in evidence.
+        bn = BayesianNetwork(
+            [("X", "Y"), ("W1", "X"), ("W1", "Y"), ("W2", "X"), ("W2", "Y")]
+        )
+        cpd_w1 = TabularCPD(variable="W1", variable_card=2, values=[[0.7], [0.3]])
+        cpd_w2 = TabularCPD(variable="W2", variable_card=2, values=[[0.3], [0.7]])
+        cpd_x = TabularCPD(
+            variable="X",
+            variable_card=2,
+            values=[[0.7, 0.4, 0.3, 0.8], [0.3, 0.6, 0.7, 0.2]],
+            evidence=["W1", "W2"],
+            evidence_card=[2, 2],
+        )
+        cpd_y = TabularCPD(
+            variable="Y",
+            variable_card=2,
+            values=[
+                [0.7, 0.7, 0.5, 0.1, 0.9, 0.2, 0.4, 0.6],
+                [0.3, 0.3, 0.5, 0.9, 0.1, 0.8, 0.6, 0.4],
+            ],
+            evidence=["W1", "W2", "X"],
+            evidence_card=[2, 2, 2],
+        )
+        bn.add_cpds(cpd_w1, cpd_w2, cpd_x, cpd_y)
+        causal_infer = CausalInference(bn)
+        query = causal_infer.query(["Y"], do={"X": 1}, evidence={"W1": 1})
+        np_test.assert_array_almost_equal(query.values, np.array([0.48, 0.52]))
+
     def test_query_error(self):
         self.assertRaises(ValueError, self.simp_infer.query, variables="C", do={"T": 1})
         self.assertRaises(