Repository: aiplan4eu/unified-planning

Issue:
Error when parsing numeric problems with universally quantified effects
**Describe the bug**
Parsing a PDDL domain that includes universally quantified numeric effects raises an ```UPUnboundedVariablesError```.

**To Reproduce**
Use the following PDDL domain and problem files:
```
(define (domain test)
    (:types counter)
    (:functions
        (value ?c - counter)
    )

    (:action increment
        :parameters ()
        :effect (and 
                (forall (?c - counter)
                    (when 
                        (< (value ?c) 10)
                        (and (increase (value ?c) 1))
                    )))))

(define (problem instance)
  (:domain test)
  (:objects
    c0 c1 - counter
  )
  (:init
	(= (value c0) 0)
	(= (value c1) 0)
  )
  (:goal (and 
    (>= (value c0) 2)
    (>= (value c1) 2)
  )))

```
And parse with the following code:
```
from unified_planning.io.pddl_reader import PDDLReader
reader = PDDLReader()
problem = reader.parse_problem("domain.pddl", "problem.pddl")
```
**Behavior**
I get the error:
```
unified_planning.exceptions.UPUnboundedVariablesError: Some variables in the effect are unbounded: {counter c}
```

Hints from issue comments:
@alvalentini: Hi @LBonassi95! Can you check if #673 fixes your problem?@LBonassi95: Yes, the issue has been resolved. Thanks!

Solution patch:
diff --git a/unified_planning/io/pddl_reader.py b/unified_planning/io/pddl_reader.py
index 9959b25c..1dfffdaf 100644
--- a/unified_planning/io/pddl_reader.py
+++ b/unified_planning/io/pddl_reader.py
@@ -692,6 +692,10 @@ class PDDLReader:
                                 complete_str,
                             ),
                         )
+                        if forall_variables:
+                            raise UPUnsupportedProblemTypeError(
+                                "Continuous change with forall effects is not supported"
+                            )
                         if isinstance(act, up.model.Process):
                             act.add_increase_continuous_effect(*con_eff)
                         elif isinstance(act, up.model.DurativeAction):
@@ -722,6 +726,10 @@ class PDDLReader:
                             ),
                         )
 
+                        if forall_variables:
+                            raise UPUnsupportedProblemTypeError(
+                                "Continuous change with forall effects is not supported"
+                            )
                         if isinstance(act, up.model.Process):
                             act.add_increase_continuous_effect(*con_eff)
                         elif isinstance(act, up.model.DurativeAction):
@@ -768,7 +776,7 @@ class PDDLReader:
                         ),
                         cond,
                     )
-                    act.add_increase_effect(*eff if timing is None else (timing, *eff))  # type: ignore
+                    act.add_increase_effect(*eff if timing is None else (timing, *eff), forall=tuple(forall_variables.values()))  # type: ignore
             elif op == "decrease":
                 if "#t" in exp:
                     if not (
@@ -803,6 +811,10 @@ class PDDLReader:
                             ),
                         )
 
+                        if forall_variables:
+                            raise UPUnsupportedProblemTypeError(
+                                "Continuous change with forall effects is not supported"
+                            )
                         if isinstance(act, up.model.Process):
                             act.add_decrease_continuous_effect(*con_eff)
                         elif isinstance(act, up.model.DurativeAction):
@@ -833,6 +845,10 @@ class PDDLReader:
                             ),
                         )
 
+                        if forall_variables:
+                            raise UPUnsupportedProblemTypeError(
+                                "Continuous change with forall effects is not supported"
+                            )
                         if isinstance(act, up.model.Process):
                             act.add_decrease_continuous_effect(*con_eff)
                         elif isinstance(act, up.model.DurativeAction):
@@ -851,6 +867,10 @@ class PDDLReader:
                             1,
                         )
 
+                        if forall_variables:
+                            raise UPUnsupportedProblemTypeError(
+                                "Continuous change with forall effects is not supported"
+                            )
                         if isinstance(act, up.model.Process):
                             act.add_increase_continuous_effect(*con_eff_without)
                         elif isinstance(act, up.model.DurativeAction):
@@ -879,7 +899,7 @@ class PDDLReader:
                         ),
                         cond,
                     )
-                    act.add_decrease_effect(*eff if timing is None else (timing, *eff))  # type: ignore
+                    act.add_decrease_effect(*eff if timing is None else (timing, *eff), forall=tuple(forall_variables.values()))  # type: ignore
             elif op == "forall":
                 assert isinstance(exp, CustomParseResults)
                 if forall_variables:
diff --git a/unified_planning/model/action.py b/unified_planning/model/action.py
index 06dcd268..5a0e31c0 100644
--- a/unified_planning/model/action.py
+++ b/unified_planning/model/action.py
@@ -460,6 +460,9 @@ class DurativeAction(Action, TimedCondsEffs):
         assert (
             self._environment == continuous_effect.environment
         ), "effect does not have the same environment of the action"
+        assert (
+            not continuous_effect.is_forall()
+        ), "Continuous effects with forall variables are not supported yet"
         self._continuous_effects.setdefault(interval, []).append(continuous_effect)
 
 


Test patch:
diff --git a/unified_planning/test/test_pddl_io.py b/unified_planning/test/test_pddl_io.py
index 00538bf5..2cadf564 100644
--- a/unified_planning/test/test_pddl_io.py
+++ b/unified_planning/test/test_pddl_io.py
@@ -25,7 +25,10 @@ from unified_planning.test import (
 )
 from unified_planning.io import PDDLWriter, PDDLReader
 from unified_planning.test.examples import get_example_problems
-from unified_planning.exceptions import UPProblemDefinitionError
+from unified_planning.exceptions import (
+    UPProblemDefinitionError,
+    UPUnsupportedProblemTypeError,
+)
 from unified_planning.model.metrics import MinimizeSequentialPlanLength
 from unified_planning.plans import SequentialPlan
 from unified_planning.model.problem_kind import simple_numeric_kind
@@ -1017,6 +1020,51 @@ class TestPddlIO(unittest_TestCase):
         #    pddl_domain,
         # )
 
+    def test_continuous_forall(self):
+        process_domain = """
+(define
+    (domain continuous_forall)
+    (:types car)
+
+    (:functions
+        (distance_traveled ?car - car)
+    )
+
+    (:process all_cars_travel
+        :parameters ()
+        :effect (forall (?c - car)
+        (increase (distance_traveled(?c)) (* #t (1.0))))
+    )
+)
+"""
+        durative_act_domain = """
+(define
+    (domain continuous_forall)
+    (:types car)
+
+    (:functions
+        (distance_traveled ?car - car)
+    )
+
+    (:durative-action all_cars_travel
+        :parameters ()
+        :duration (and (>= ?duration 4) (<= ?duration 4))
+        :effect (
+            forall (?c - car)
+            (increase (distance_traveled(?c)) (* #t (1.0)))
+        )
+    )
+)
+"""
+        for domain in [process_domain, durative_act_domain]:
+            reader = PDDLReader()
+            with self.assertRaises(UPUnsupportedProblemTypeError) as e:
+                reader.parse_problem_string(domain)
+            self.assertEqual(
+                str(e.exception),
+                "Continuous change with forall effects is not supported",
+            )
+
 
 def _have_same_user_types_considering_renamings(
     original_problem: unified_planning.model.Problem,