Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Events triggered by actions #17

Open
neighthan opened this issue Jun 22, 2022 · 6 comments
Open

Events triggered by actions #17

neighthan opened this issue Jun 22, 2022 · 6 comments

Comments

@neighthan
Copy link

In your paper, it says "effects become instantaneously available to events, without the epsilon separation." I assumed this was true for the effects of actions as well as events; is that correct? If so, SMTPlan doesn't seem to model this correctly. E.g. if I run SMTPlan with -c 3 then I get variables like (x)0_0, (x)0_1, and (x)0_2. The effects of actions are all on the (x)0_2 variables, and the preconditions of the actions are required on the (x)0_1 variables. So no matter how large I set c, I can't get events which occur simultaneously (in the same happening) but after actions. Unless I've missed something?

Is there any way to work around this? I could change the separation constraints between happenings to just be di >= 0 instead of di >= 1 / 10. This seems like it could fix things for events that are simultaneous with but after actions (by having the next happening occur immediately, with di == 0), though I haven't tried it, but it would remove the epsilon separation that there's supposed to be for actions ("the values of such instantaneous effects [of actions] can be exploited to support other actions only after a small amount of time"). I haven't read (Fox & Long, 2003); are there caveats to removing this separation? Is it just there for practical reasons (e.g. easier to write planning algorithms) or something more critical?

@neighthan
Copy link
Author

After a little more thought, I don't think allowing the happenings to have zero durations would solve this problem either (the preconditions of the event would already be satisfied, so there wouldn't be a zero-crossing to force the next happening to occur at the same time as the previous one). I think the easiest solution then would be to have actions occur at the start of happenings instead of at the end. This has its own issues (some valid plans won't be possible anymore because the action might depend on events happening first), but it is safer (invalid plans where events fail to occur after actions won't be possible, at least with a large enough bound on the event cascade). At the cost of longer planning times, I suppose you could also have events both before and after actions within a happening; that would also introduce another hyperparameter, since you'd need to bound the pre- and post-action event cascades.

@m312z
Copy link
Contributor

m312z commented Jun 23, 2022

Hello Nathan,

It's been a while since I've looked at the code, but I thought that actions checked for preconditions in the first "layer" of the happening (x)0_0, and applied their effects in the second (x)0_1, and then events chain from there. This is what the paper suggests (H9-10), but the implementation could be wrong there.

I don't think this would cause plans to not be possible for the reason you suggest: if an action requires an event to happen before the action is applied, they would be in separate happenings, with epsilon between them. I found the best place to get a description of the semantics of plan execution was in the VAL papers, where the steps for checking the validity of a happening are described in detail.

One reason for epsilon separation is practical - you cannot observe event "e" has occurred and simultaneously execute action "a". There will always be some time taken to perform the turnaround of observation/action. For example, if the plan [a1,a2] can only be successfuly executed with an epsilon separation of 0.01, but it takes the dispatching code 0.1 seconds to see that the first action has been completed and send the next, then it is not possible to execute unless you could see 0.09 into the future. Setting epsilon to zero would require some amount of precognition.

Best regards,
Michael

@DerekLong101
Copy link

DerekLong101 commented Jun 23, 2022 via email

@neighthan
Copy link
Author

Thanks for your responses, Michael and Derek.

To the point of why an epsilon separation is required at all, you explained that well and I see the reasoning behind it for a real system (with sensing and processing delays).

I don't think this would cause plans to not be possible for the reason you suggest: if an action requires an event to happen before the action is applied, they would be in separate happenings, with epsilon between them.

  • I was thinking that there may be a case where a plan only works if the action could be taken at the instant the event occurs, but I agree this doesn't really have practical value since you can't ever be that precise, and you could adjust epsilon to however precise you think you could be.

However, I still think there's an issue in the codebase for the preconditions / effects of actions.

It's been a while since I've looked at the code, but I thought that actions checked for preconditions in the first "layer" of the happening (x)0_0, and applied their effects in the second (x)0_1, and then events chain from there. This is what the paper suggests (H9-10), but the implementation could be wrong there.

  • This is what I thought as well, which is why I was surprised. My original example is a bit more complicated than would be worth looking at, but here's a simpler one:

domain.pddl

(define (domain test)

(:requirements :strips :numeric-fluents :negative-preconditions)

(:predicates
  (stopped)
)

(:action go
  :parameters ()
  :precondition (stopped)
  :effect (and
    (not (stopped))
  )
)

)

problem.pddl

(define (problem test1) (:domain test)

(:init
  (stopped)
)

(:goal (and
  (not (stopped))
))

)

If I pass these to SMTPlan with 2 happenings and a bound of 3 for the "event cascade" (not sure if that's the right terminology), I get back the following constraints (I parsed the raw smtlib output of SMTPlan with z3 so it's more legible):

t0 == 0,
d0 >= 1/10,
t1 == t0 + d0,
t1 > t0,
d1 >= 1/10,
(stopped)0_0,
(go)0_dur == 0,
(go)1_dur == 0,
Implies((go)0_sta, Not((stopped)0_3)),
Implies((go)0_sta, (stopped)0_2),
Implies((go)1_sta, Not((stopped)1_3)),
Implies((go)1_sta, (stopped)1_2),
Implies((stopped)0_1, Or((stopped)0_0)),
Implies(Not((stopped)0_1), Or(Not((stopped)0_0))),
Implies((stopped)0_2, Or((stopped)0_1)),
Implies(Not((stopped)0_2), Or(Not((stopped)0_1))),
Implies((stopped)0_3, Or((stopped)0_2)),
Implies(Not((stopped)0_3), Or(Not((stopped)0_2), (go)0_sta)),
Implies((stopped)1_1, Or((stopped)1_0)),
Implies(Not((stopped)1_1), Or(Not((stopped)1_0))),
Implies((stopped)1_2, Or((stopped)1_1)),
Implies(Not((stopped)1_2), Or(Not((stopped)1_1))),
Implies((stopped)1_3, Or((stopped)1_2)),
Implies(Not((stopped)1_3), Or(Not((stopped)1_2), (go)1_sta)),
Implies((stopped)1_0, Or((stopped)0_3)),
Implies(Not((stopped)1_0), Or(Not((stopped)0_3))),
Not((stopped)1_3)

You'll notice constraints like Implies((go)0_sta, Not((stopped)0_3)) and Implies((go)0_sta, (stopped)0_2), so the effects of the action seem to be on the last "layer" of the happening and the preconditions on the penultimate layer. Am I doing anything wrong here / is there any easy way to fix this? In my environment, this is allowing the agent to pass through obstacles sometimes because the collision event which should occur after a move action can't trigger in the same happening, and by the next happening the agent has moved past the obstacle's boundary (there's probably a way I can rewrite the environment to work around this, but it seemed to be a discrepancy between the code and the paper too).

@m312z
Copy link
Contributor

m312z commented Jul 22, 2022

As a quick check, if you increase the bounds on the length of the even chain, is it still the final two "layers"? Just in case it is somehow hard-coded (wrongly) to be 2/3. I think this is a fairly easy fix if you can modify the source code. I'll take a look now.

@m312z
Copy link
Contributor

m312z commented Jul 22, 2022

Hello again,

The offending constraints are in this switch statement here:

case ENC_ACTION_CONDITION:

For at start, end, and overall cases you will see "opt->cascade_bound-2" used to specify the event layer in which the condition should be true.

From here:

case ENC_SIMPLE_ACTION_EFFECT:

You can see a similar thing with action effects, using "opt->cascade_bound-1".

If you can't change these, then an alternative would be to modify the output directly (e.g. with a regex) which should be possible since the constraints all have the same form.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants