iocchi / PetriNetPlans

Petri Net Plans library and applications
31 stars 15 forks source link

pnpgen_linear creates illegal PNPs using execution rules #10

Closed cdondrup closed 8 years ago

cdondrup commented 8 years ago

Playing with pnpgen_linear and the execution rules, I discovered that when a duration is given to the action, the execution rule is only created for the action but not for the concurrent wait. Here is an example of a say action with a duration of 2 seconds that is supposed to restart the plan if a condition is false:

wrong durative action

The execution rule is:

*if* my_condition *during* say *do* restart_plan

As you can, see the rule is correctly applied to the say action but the wait is still executed as usual. This means that X43 will acquire 2 tokens after the second iteration of the plan which leads to it progressing via the join even though the say action was never successful. Of course I could define an execution rule for wait as well but I do not want all my wait actions to be treated the same because the conditions for, e.g. a durative say and durative goto action, might be completely different.

So imho, when the execution rules are applied, it would be necessary to find the wait that is concurrent with the action the rule is for, apply it, and connect the wait to the same transition either interrupting it or using the place after wait.end (X43 in the image).

As far as I understand the current plan generation, this would be difficult because the rules are applied after the actions have been created at least in the linear case. Given that I might have several concurrent durative actions, I potentially have several wait actions that are executed at the same time, e.g. say_foo|5 and goto_bar|10 are concurrent (I don't think this is currently supported by the linear plan generation but does have real-world use-cases). If I add a rule to say, only the wait_5 should be interrrupted and not the wait_10. Identifying this after the actions have been generated could be tricky though. Hence, I would argue that the execution rules would have to be applied during PNP generation and not after. In this case, however, the goto_bar|10 could acquire 2 tokens if the recovery is restart_plan...

All this is quite complicated and lets me think that restart_plan and fail_plan are quite dangerous but necessary recoveries which have to interrupt all actions concurrent with the one they are defined for. Not sure how and if that would be possible though. I am grateful for any thoughts or comments on that matter. Also, maybe I am just using it wrong.

iocchi commented 8 years ago

Hi, yes this is also a missing feature. I think it can be solved in this way: when the wait action is put in parallel to an action, I can store the pair of PNP places <action,wait> in a table. Then, if an interrupt is applied to an action, I can check this table and apply the same interrupt also to the corresponding wait. The only problem that I see is that this behavior cannot be generalized for any case. There are cases in which the interrupt of an action should not affect other actions running in parallel. So at this moment I can implement this mechanism only for wait actions in parallel with other actions. Do you think it will fully solve your problem?

Thanks.

Il 05/08/2016 11:34, Christian Dondrup ha scritto:

Playing with pnpgen_linear and the execution rules, I discovered that when a duration is given to the action, the execution rule is only created for the action but not for the concurrent wait. Here is an example of a |say| action with a duration of 2 seconds that is supposed to restart the plan if a condition is false:

wrong durative action https://cloud.githubusercontent.com/assets/4293484/17431323/71ac7aba-5af1-11e6-8ed3-f4087569d718.png

The execution rule is:

|if my_condition during say do restart_plan |

As you can, see the rule is correctly applied to the say action but the wait is still executed as usual. This means that |X43| will acquire 2 tokens after the second iteration of the plan which leads to it progressing via the join even though the |say| action was never successful. Of course I could define an execution rule for |wait| as well but I do not want all my |wait| actions to be treated the same because the conditions for, e.g. a durative |say| and durative |goto| action, might be completely different.

So imho, when the execution rules are applied, it would be necessary to find the wait that is concurrent with the action the rule is for, apply it, and connect the wait to the same transition either interrupting it or using the place after |wait.end| (|X43| in the image).

As far as I understand the current plan generation, this would be difficult because the rules are applied after the actions have been created at least in the linear case https://github.com/iocchi/PetriNetPlans/blob/master/PNPgen/src/pnpgen_linear.cpp#L31-L37. Given that I might have several concurrent durative actions, I potentially have several wait actions that are executed at the same time, e.g. |say_foo|5| and |goto_bar|10| are concurrent (I don't think this is currently supported by the linear plan generation but does have real-world use-cases). If I add a rule to |say|, only the |wait_5| should be interrrupted and not the |wait_10|. Identifying this after the actions have been generated could be tricky though. Hence, I would argue that the execution rules would have to be applied during PNP generation and not after. In this case, however, the |goto_bar|10| could acquire 2 tokens if the recovery is |restart_plan|...

All this is quite complicated and lets me think that |restart_plan| and |fail_plan| are quite dangerous but necessary recoveries which have to interrupt all actions concurrent with the one they are defined for. Not sure how and if that would be possible though. I am grateful for any thoughts or comments on that matter. Also, maybe I am just using it wrong.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/iocchi/PetriNetPlans/issues/10, or mute the thread https://github.com/notifications/unsubscribe-auth/AC7HF65cNJpvRy1jfhXyaWj_JuYLvKgOks5qcwPAgaJpZM4JdhLK.

cdondrup commented 8 years ago

This would be a great start. Thank you!

I understand that not all concurrent actions can be considered for all conditions and recoveries but for the specific recoveries: restart_plan and fail_plan all actions that are currently executed would have to be interrupted in my opinion. Taking the example of say_foo|5 and goto_bar|10 executed concurrently at the same time the problems are: fail_plan would not be a home state because if the rule *if* condition *during* goto *do* fail_plan is applied the tokens in say_foo|5 are not consumed. If *if* condition *during* goto *do* restart_plan is applied the say_foo|5 action will acquire more than one token when the plan is executed a second time because the token from the first run wasn't consumed.

Hence, for these two recoveries in particular, all actions that are executed concurrently with the action the rule applies to should be interrupted. So for *if* condition *during* goto *do* restart_plan not only the wait_10 but also the say_foo and wait_5 would have to be interrupted or the say_foo.end and wait_5.end transitions would have to be connected to the restart_plan recovery.

iocchi commented 8 years ago

Just pushed a version that should solve the problem. Please test it and let me know if it works well now for the wait actions. You are right about the behavior for restart and fail plan. Listed as a next TODO.

cdondrup commented 8 years ago

Thank you! I will give it a go.

cdondrup commented 8 years ago

This works beautifully now. Given the plan goto_forward|5; say_hello|2 and the execution rules:

*if* failed *during* goto *do* restart_action
*if* robot_dist_far *during* say *do* restart_plan

I get the following PNP

pnp3

Which correctly consumes all tokes and therefore works like a charm.

Thank you very much for the quick help! Much appreciated.

iocchi commented 8 years ago

A new update that now correctly set the correct places to the fork and join places when restart/skip_action are used. Otherwise only the main action (and not wait) is restarted. Please try this new update to remove this further problem.

cdondrup commented 8 years ago

Didn't even notice that one but you are of course right. Works for me:

goto_forward|5; say_hello|2

with

*if* failed *during* goto *do* restart_action
*if* robot_dist_far *during* say *do* restart_action

generates

pnp4

And execution works perfectly.