Repository: pyro-ppl/pyro

Issue:
FR Warn that model-side sequential enumeration is not implemented
The [TraceEnum_ELBO](https://docs.pyro.ai/en/dev/inference_algos.html#pyro.infer.traceenum_elbo.TraceEnum_ELBO) docs state that guide-side enumeration allows either parallel or sequential enumeration, and model-side allows sequential. However if an unsuspecting user has not read this weak fine print and attempts to sequentially enumerate on the model side, the only warning is
```
UserWarning: Found vars in model but not guide: {'x'}
```
It would be helpful to explicitly warn that model-side sequential enumeration is not implemented.

See e.g. confusion arising on [this forum post](https://forum.pyro.ai/t/inferring-discrete-latent-variable/3172) with @martinjankowiak 


Discussion:

Resolving patch:
diff --git a/pyro/util.py b/pyro/util.py
--- a/pyro/util.py
+++ b/pyro/util.py
@@ -250,6 +250,7 @@ def check_model_guide_match(model_trace, guide_trace, max_plate_nesting=math.inf
         model.
     4. At each sample site that appears in both the model and guide, the model
         and guide agree on sample shape.
+    5. Model-side sequential enumeration is not implemented.
     """
     # Check ordinary sample sites.
     guide_vars = set(
@@ -290,11 +291,15 @@ def check_model_guide_match(model_trace, guide_trace, max_plate_nesting=math.inf
             )
         )
     if not (model_vars <= guide_vars | enum_vars):
-        warnings.warn(
-            "Found vars in model but not guide: {}".format(
-                model_vars - guide_vars - enum_vars
-            )
-        )
+        bad_sites = model_vars - guide_vars - enum_vars
+        for name in bad_sites:
+            if model_trace.nodes[name]["infer"].get("enumerate") == "sequential":
+                raise NotImplementedError(
+                    f"At site {repr(name)}, "
+                    "model-side sequential enumeration is not implemented. "
+                    "Try parallel enumeration or guide-side enumeration."
+                )
+        warnings.warn(f"Found vars in model but not guide: {bad_sites}")
 
     # Check shapes agree.
     for name in model_vars & guide_vars:


Test patch:
diff --git a/tests/infer/test_enum.py b/tests/infer/test_enum.py
--- a/tests/infer/test_enum.py
+++ b/tests/infer/test_enum.py
@@ -107,6 +107,33 @@ def model():
     assert len(traces) == 2 * probs.size(-1)
 
 
+def test_enumerate_sequential_guide():
+    values = []
+
+    def model():
+        x = pyro.sample("x", dist.Bernoulli(0.5))
+        values.append(float(x))
+
+    def guide():
+        pyro.sample("x", dist.Bernoulli(0.5), infer={"enumerate": "sequential"})
+
+    elbo = TraceEnum_ELBO(max_plate_nesting=0)
+    elbo.loss(model, guide)
+    assert len(values) == 2, values
+
+
+def test_enumerate_sequential_model():
+    def model():
+        pyro.sample("x", dist.Bernoulli(0.5), infer={"enumerate": "sequential"})
+
+    def guide():
+        pass
+
+    with pytest.raises(NotImplementedError):
+        elbo = TraceEnum_ELBO(max_plate_nesting=0)
+        elbo.loss(model, guide)
+
+
 # The usual dist.Bernoulli avoids NANs by clamping log prob. This unsafe version
 # allows us to test additional NAN avoidance in _compute_dice_elbo().
 class UnsafeBernoulli(dist.Bernoulli):
diff --git a/tests/infer/test_valid_models.py b/tests/infer/test_valid_models.py
--- a/tests/infer/test_valid_models.py
+++ b/tests/infer/test_valid_models.py
@@ -1575,7 +1575,7 @@ def guide():
         model,
         guide,
         TraceEnum_ELBO(max_plate_nesting=0),
-        match="Found vars in model but not guide",
+        match="At site .*, model-side sequential enumeration is not implemented",
     )