-
Notifications
You must be signed in to change notification settings - Fork 4
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
Plan transformations: failure handling by code replacement and task tree (de)serialization that can restore (some) functions. #37
base: master
Are you sure you want to change the base?
Conversation
… tree (de)serialization; modified plan-failure and the fail function to add code-path information about the point of failure.
Interesting PR, i.e. cool that you work on plan transformations! This has some deep changes which might/might not have implications for various other people --hard to judge just from the PR. I guess we just have to give it a try. Also: Great job writing so many comments. |
UPDATE: added a new macro in cram-projection: with-transformative-tryouts. The macro uses the previously defined with-transformative-failure-handling (and macros existing in cpl since before this pull request: with-projection-environment). A code sample of how the macro in its present structure should be used is found in the CRAM tutorial on plan transformation. In brief: (with-transformative-tryouts env clause body) will run body in projection environment env. The results of the projection run are then passed to clause, which should decide whether to transform body and/or rerun it outside projection. Clause should finish with a retry. Once a non-projection run of body happens, with-transformative-tryouts finishes. Variables defined inside the macro: in-projection-environment and projection-signal-data. Effect on task tree: just as with-transformative-failure-handling, only the latest run is kept in the task tree. |
Latch fluents are not related to plan transformations, just included in this PR because I didn't have time to open another. A latch fluent starts with value nil and a fluent to monitor. When the monitored fluent becomes non-NIL, the latch fluent becomes T. However, it needs to be manually set to NIL afterwards (subsequent changes to the monitored fluent will not matter). I'll be using latch fluents as quick tests of whether some robot has been near an area during a plan run. Perhaps it's a cute feature to put in CRAM too. |
Accumulator fluents are a more general type of latch fluent. An example will be a fluent that stores the maximum value reached by some other fluent. In general, an accumulator fluent is one that updates when its monitored fluent updates, and the update function depends on both the old value of the accumulator fluent and the new value of the monitored fluent. |
Moar changes, rather central: "compile time" parameters for cram-functions. More documentation on how they are supposed to work can be found in the cram tutorial on plan transformation on the cram-system website. In brief, compile-time parameters are parameters that are set at code generation. Typically, this is compile time, but they can also be adjusted by plan transformation, which is their reason to exist. Until now, all parameters to a cram-function are "run-time" and do not take their values from the task tree. Since our current plan transformation operates on the task tree, it means function parameters are beyond its scope. Hence, the introduction of compile time parameters. As before, I try to make the changes by inserting either new macros or optional parameters, so that old code shouldn't need to change. So, there's a new macro, def-ptr-cram-function, which is a cram function that receives one "compile-time" parameter (which can be a list) and however many run-time parameters the programmer wishes. "compile-time" parameters can be adjusted by plan transformation because they take their values from the task tree. Note, compile time parameters are always nil for regular cram-functions. EDIT: another, perhaps more familiar way to look at this: ptr-/compile-time parameters are environment variables in a closure wrapped around a [ptr-]cram-function. (Though this version of the implementation doesn't actually use closures). |
…w they treat their lambda lists.
…takes the previously effective ptr-parameter as a default.
…g in the ptr implementation.
…rsion for goal handling that allows more recipes for the same goal pattern, with scores for each recipe to rank and order how they are attempted.
Defined with-transformative-failure-handling, task tree (de)serialization; modified plan-failure and the fail function to add code-path information about the point of failure.
Changes are such that the interface of previously existing functions/classes doesn't break, but see next comments.
Changes appear at replace-task-code and the new slot in the plan-failure class, however both these changes are implemented via optional parameters, so will not affect existing code.
Usage of task trees to store episode data may be affected by with-transformative-failure-handling since the way with-failure-handling constructs the tree after a failure is different: with-failure-handling will have the initial and retried runs of a piece of code in different task tree nodes, whereas with-transformative-failure-handling will only keep the last (hopefully succesful) run of a piece of code in the task tree node. However, since semrec has taken over as the logging mechanism for plan runs, this should be a minor concern. with-transformative-failure-handling does not affect semrec's logging of retries.
De/Serialization of task trees is done via cl-store (rather than the full episode-knowledge-backend). This was for simplicity/focus: we seem to be using semrec for logging experiment data rather than episode-knowledge anyway, and all that might be needed for future runtime use cases of plan transformation is the ability to store/load the task tree.
cl-store is capable to de/serialize function names, and it turns out this is sufficient to allow task trees to rerun code replacements after being loaded from a file (assuming the named function has also been previously loaded). Un-named functions are not de/serializable at this time; in particular, constructs like (lamda (&rest args) &body) will cause an error on restore. This is why, prior to saving, the store-tree function goes through the task tree and removes any function object that looks like a reference to an unnamed function.