KCL-Planning / SMTPlan

PDDL+ planning through compilation to SMT
44 stars 19 forks source link

Ignoring a requirement to serialize operations #22

Open fdouglis opened 1 year ago

fdouglis commented 1 year ago

I posted a comment yesterday on #13 regarding concurrency, but in order not to hijack the issue, and because I've now tried to create a minimal use case, posting a new one here.

I'm trying to create a plan that has durations and a limited number of things it can do in parallel. No matter what I try, SMTPlan either says it should all go in parallel, or it hangs and runs forever, or reports the plan is unsolveable. It's quite possible this is an error on my part in the PDDL, or maybe I'm tweaking some issue in the planner. To its credit, SMTPlan is the one thing I find that even comes close --- most in planutils simply dump core or complain!

The idea is to have a count of things that are OK to operate on, aggregated into pools (in this case I have a single "object-group" but there would be more). There's a check per object group that at all times, including after the start of the action with the start effect decrementing this count, the count should be > 0. So if I have 3 things, I expect it to operate on 2, wait 5 seconds, and operate on the 3rd. Instead the plan does all 3 at once.

Here is the simplified domain.

        (domain showbug)
        (:requirements :durative-actions :fluents :action-costs :negative-preconditions)
        (:functions
         (num-objects-unselected ?og)
         )
        (:predicates
                (object-group ?og)
                (object ?o)
                (object-in-group ?o ?og)
                (object-selected ?o)
        )
        (:durative-action select-object
                :parameters (?o ?og)
                :duration (= ?duration 5)
                :condition  (and
                             (at start (object ?o))
                             (at start (object-group ?og))
                             (at start (object-in-group ?o ?og))
                             (at start (not (object-selected ?o)))
                             (at start (> (num-objects-unselected ?og ) 0))
                             (over all (forall (?og2) (> (num-objects-unselected ?og2 ) 0)))
                           )
                :effect (and (at start (decrease  (num-objects-unselected ?og) 1))
                             (at end (object-selected ?o))
                             (at end (increase  (num-objects-unselected ?og) 1))
                             )
        )
)

And the problem instance:

        (problem showbug)
        (:domain showbug)
        (:objects
                o1 o2 o3 og1
        )
        (:init (object o1) (object o2) (object o3) (object-group og1)
               (object-in-group o1 og1) (object-in-group o2 og1) (object-in-group o3 og1)
               (= (num-objects-unselected og1) 3)
        )
        (:goal (and (object-selected o1) (object-selected o2) (object-selected o3)
               ))
)

The plan selects all three in parallel:

0.0:    (select-object o1 og1) [5.0]
0.0:    (select-object o2 og1) [5.0]
0.0:    (select-object o3 og1) [5.0]

In my original domain, it was like this but with a bunch more moving parts, and I tried creating 3 groups of 4, 4, and 2 objects respectively. I also added a counter for the total number of things selected over time. If I simply output that number (i.e. viewed it in debug mode as it was updated) I could see that the number updated was not reflecting that all were run at once. It was as though each one updating it started with the initial value at time T and changed it by 1, even if others were changing it at the same timestamp.

Any thoughts welcome, whether they are about the planner (which seems to have a bug) or my problem (which could certainly have a bug) would be appreciated!

fdouglis commented 1 year ago

Let me add to this a specific example of why I think this is buggy. If I run with debugging, I get this:

smtplan domain-bug.pddl problem-bug.pddl -d -v 
Grounded:   0.001963 seconds
Algebra:    0.003671 seconds
Encoded 1:  0.042437 seconds
Solved 1:   0.003274 seconds
Encoded 2:  0.000248 seconds
0.0:    (select-object o1 og1) [5.0]
0.0:    (select-object o2 og1) [5.0]
0.0:    (select-object o3 og1) [5.0]
0.0:    |(select-object o1 og1)0_run|   (running)
0.0:    |(select-object o2 og1)0_run|   (running)
0.0:    |(select-object o3 og1)0_run|   (running)
0.0:    |(num-objects-unselected og1)0_0| == 3.0
0.0:    |(num-objects-unselected og1)0_1| == 2.0
5.0:    |(select-object o1 og1)1_end|   (end)
5.0:    |(select-object o2 og1)1_end|   (end)
5.0:    |(select-object o3 og1)1_end|   (end)
5.0:    |(object-selected o1)1_1|
5.0:    |(object-selected o2)1_1|
5.0:    |(object-selected o3)1_1|
5.0:    |(num-objects-unselected og1)1_0| == 2.0
5.0:    |(num-objects-unselected og1)1_1| == 3.0
Goal at [5.0]
Solved 2:   0.007638 seconds
Total time: 0.117884 seconds

Note that num-objects-unselected og1 goes from 3 to 2 at the start, and 5s later goes from 2 to 3. I expect that if it is selecting o1 o2 o3 at once, then it should decrement from 3 to 0. Since there is a requirement that it be above 0, it wouldn't allow all three to be selected simultaneously, exactly as I want.

fdouglis commented 1 year ago

Here is a gist with an updated version of the problem -- same result with all being selected in parallel. But here we can see that it's not that it's merely failing to set a fluent for each action, but also that a clause to say that during the duration of the action, there exists something for which the action is not taking place actually fails too.