Coder Social home page Coder Social logo

unified-planning's People

Contributors

alee08 avatar alelafar avatar alexander-sung avatar alvalentini avatar arbimo avatar elisatosello avatar fabio-patrizi avatar fracchiariello avatar framba-luca avatar franklinselva avatar hstairs avatar ivanserina avatar jrenoux avatar karpase avatar lbonassi95 avatar mikand avatar miquelramirez avatar onjen avatar roeger avatar sebastianstock avatar serivan avatar shi-raida avatar speckdavid avatar srajangoyal avatar stoppini avatar uwe-koeckemann avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

unified-planning's Issues

Running a planning system in a user-specified configuration

User Story

As a user, I want to select a specific planning system and pass a configuration string to it to run it in a specific configuration.

This targets the expert users that run a planning engine via the UPF but do not want to use some default configuration.

Acceptance Criteria

  • Users can pick a specific planning system.
  • Users can pass a configuration string (or whatever is suitable) to the planning system.
  • The mechanism is documented from the user perspective.
  • The mechanism is documented for the system developers who want to support this for their engine.

Additional Material

No

Attention Points

No

Planning engine credits

User Story

As a Planning Engine developer I want to get credit when mu planning engine is used.

For example, if planner A is selected (manually or automatically) it would be nice to let the user know who created the engine, show relevant publications and possibly some links for "self-promotion".

Acceptance Criteria

  • When a certain engine is used, give credit in the STDOUT/STDERR by default
  • The user can explicitly silence this feature to avoid annoying output when not needed
  • The output is clearly divided from other output of the client application
  • It would be nice to have a credits() feature listing the credits for the planning engines and the UP library

Attention Points

  • This change will require an additional "field" to be compiled by planning engines developers.

Improving on the interface after planning to interpret additional planner output

The Unified Planning Framework should be able to have some feature to get additional information after the planner has done its task. This may be related to both the case where the planner has not been able to find a solution and the case where the planner did find a solution. For the former, additional information explaining the reasons of the failure are desirable, like memory crash, instance proved unsolvable so on and so forth. For the latter, additional information could include statistics of the planner, or the cost of the found solution.
@mikand that perhaps we can have a more structured data type for the result of the planner.

Name of the fresh actions created by the transformers

The transformers create a fresh action with a naming convention where __ is reserved, but this method can be improved for better readability.
Mikand suggestions:

Ok, clear. This should work but maybe we can:

  1. Encapsulate the naming templates so that we can ask for fresh action/fluent names
  2. Follow C convention any symbol starting with __ is reserved, internal underscores do not make a difference
  3. Insert in fluent/action names the name of the transformer (or an abbreviation): e.g. (a() -> __dnf_a_1()) so that it becomes a bit more readable

Reason for the planner as context manager (with)

I was wondering why the planners are designed as context managers (i.e. it is possible to use them in a with statement). Apart from the very simple case:

with OneshotPlanner(name="tamer") as planner:
    plan = planner.solve(problem)

That can be easily written as:

planner = OneshotPlanner(name="tamer")
plan = planner.solve(problem)

I do not see any other examples that can make me understand the use-case. In particular, I don't see how this can extend to other kinds of planners (e.g. anytime planners or planners that survive the single solve call because they need to keep information).

How to check the applicability of an action at a given state and apply it

User Story

As an AI researcher I want to use UP in my research project to:

  1. Check action applicability: given the current state s0, check if a lifted action a can be applied at s0 (their preconditions are met at that state) or not. Another option is to use a method to obtain all the possible instantations of a at s0 (i.e., obtain the grounded actions corresponding to the lifted action a) and, then, use another method to check the applicability of each grounded action at s0.

  2. Apply an action to the state: after checking that a is applicable, obtain the grounded action a_g by manually selecting the object to instantiate each parameter on and, then, obtain the next state s1 that results from applying a_g at s0. Ideally, this process would support PDDL extensions like :exists, :forall and :when.

In case this functionality is not implemented yet and there are no intentions to do so in the next few days, I would really appreciate some guidance for implementing such functions myself.

Acceptance Criteria

  • Action applicability implemented.
  • Action transition implemented.

Explain why no planner can handle the problem

User Story

As a UP user I want to receive information why none of my planners can solve the kind of problem I described, to reformulate the problem or find a suitable planner.

#!/usr/bin/env python3
from unified_planning.model import Fluent, InstantaneousAction, Object, Problem
from unified_planning.shortcuts import Equals, Not, OneshotPlanner, UserType


Location = UserType("Location")
a, b, c = locations = [Object(location, Location) for location in ('a', 'b', 'c')]

robot_at = Fluent("RobotAt", Location)

move = InstantaneousAction("Move", x=Location, y=Location)
x, y = move.parameters()
move.add_precondition(Equals(robot_at, x))
move.add_effect(robot_at, y, Not(Equals(robot_at, b)))

problem = Problem("Simple")
problem.add_fluent(robot_at, default_initial_value=a)
problem.add_action(move)
problem.add_objects(locations)
problem.add_goal(Equals(robot_at, c))

with OneshotPlanner(problem_kind=problem.kind()) as planner:
    plan = planner.solve(problem)
    print(f"{planner.name()} returned: {plan}")

In this small example, I use conditional planning for no reason in the effect of action move. Since none of my planners can handle this, I currently receive a RuntimeError: No active exception to reraise. A concrete error message is desired, ideally one explaining the missing feature of conditional planning in all of my available planners.

Acceptance Criteria

  • At least the error message shall state that no available planner can handle the problem kind.
  • Optionally, if feasible, each planner returns one reason why it cannot handle the problem kind.
  • Optionally, if feasible, each planner returns all reasons why it cannot handle the problem kind.

Attention Points

Coincidentally, this request is related to our discussions yesterday regarding improved results from the planners. I'm not sure if this issue is handled within the improved design, so I'd like to bring it up here. From my understanding our discussions addressed the cases where a planner can handle the problem kind in principle but fails on the concrete problem instance, whereas for the problem in this issue no planner will actually run and give any result.

PDDLReader chokes on Miconic (fulladl)

When reading a (classical) Miconic problem in the full-adl version (attached), the PDDLReader throws a syntax error:

SyntaxError: Not able to handle: ['when', ['and', ['boarded', '?p'], ['destin', '?p', '?f']], ['and', ['not', ['boarded', '?p']], ['served', '?p']]]

Here are the files (please remove suffix txt, I could not attach pddl files):
domain.pddl.txt
f2-4.pddl.txt

To Reproduce

from unified_planning.shortcuts import *
from unified_planning.io import PDDLWriter, PDDLReader
reader = PDDLReader()
problem = reader.parse_problem('domain.pddl', 'miconic-fulladl/f2-4.pddl')

CI/CD push on PyPi

Just like pysmt, we need to open an account on pypi (https://pypi.org/) and extend the CI/CD to push a dev-package for the upf at any commit on master.

This makes it possible to use pip install even dev versions easily!

PDDL Output

User Story

As a planning expert/enthusiast I want to be able to emit a PDDL representation of a planning problem modeled in the upf library to interoperate with an external planner manually.

For example, I want to dump a planning model that is generated from a TSB to include it in a planning competition or to experiment with an off-the-shelf planner that is not interfaced with the UPF

Acceptance Criteria

  • The generated PDDL is acceptable by major planners in the category (for now, numeric and classical planners)
  • If needed, options are provided to enable/disable specific dialects
  • The PDDL can be saved to an actual file, showed on the screen or in file-like object for code-level reuse / network transmission

Additional Material

An interface like

from upf.io import PDDLPrinter
printer = PDDLPrinter(problem) 
printer.write_domain("domain.pddl")
printer.write_problem("instance.pddl")

could be suitable.

Attention Points

  • Using a template library like Jinja could be a good idea
  • Avoid writing a "valley of prints"
  • Avoid excessive string concatenation (i.e., a + " - " + b)

Closed World Assumption

As a PDDL user, I would find it nice to have a way to express the initial state in CWA through UPF. Maybe we could make it optional, but, at least for propositional variables, this should be quite straightforward, and very handy especially for problems with a large number of objects. For instance, when there is the need to model when two positions are (not) connected.

Improving on the interface "while" planning to interpret additional planner output

Establish some mechanism for letting the Unified Planning Framework able to inspect the output of the planner whilst the planner is actually planning. For instance, the planner maybe able to say when it has done preprocessing, or some estimation of the heuristic while planning that gives some notion of progress.
It has been noticed that this is likely to be very planner specific, and @arbimo suggested that at the moment we may as well just give the ability to read the standard output of the planner. Bit low level, but can be useful for some use case.

Adding Intervals to Temporal Planning

User Story

As a Timeline-based Planner Provider I want to access implicit or assign explicit intervals to preconditions, effects, actions, states, and goals to impose temporal (and resource) constraints between these intervals.

Acceptance Criteria

  • Implicit interval handles can be obtained for any precondition, effect and action, as well as any goal or state expression
  • Explicit intervals can be attached to any precondition, effect and action, as well as any goal or state expression
  • Constraints using temporal intervals can be added to problems or actions

Additional Material

  • Suggestion below is based on discussion #45
import upf

Location = upf.UserType('Location')
robot_at = upf.Fluent('robot_at', BoolType(), [Location])
distance = upf.Fluent('distance', RealType(), [Location, Location])

move = upf.DurativeAction('move', l_from=Location, l_to=Location)
l_from = move.parameter('l_from')
l_to = move.parameter('l_to')

i_move_1 = Interval('C1')
# or: i_move_1 = 'C1_
# similar for other intervals used below ...

# Intervals may be attached as optional arguments:
move.set_duration_constraint(IntervalDuration(5, 16))
move.add_start_condition(Not(Equals(l_from, l_to)), delay=3) 
move.add_condition(StartTiming(), Not(Equals(l_from, l_to)), interval=i_move_1)
move.add_condition(EndTiming(3), robot_at(l_from), interval=i_move_2)
move.add_condition(EndTiming(), Not(robot_at(l_to)), interval=i_move_3)
move.add_effect(StartTiming(), robot_at(l_from), False, , interval=i_move_e_1)
move.add_effect(EndTiming(),robot_at(l_to), True, interval=i_move_e_2)
move.add_durative_condition(LeftOpenInterval(StartTiming(), EndTiming()), Not(robot_at(l_to))) 

i_move = Interval()
move.set_interval(i1)

# add a temporal constraint:
move.add_constraint(Duration(i_move, 10, 20)) # flexible duration
move.add_constraint(Meets(i_move_2, i_move_e_2)) # relate condition and effect
move.add_constraint(Overlaps(i_move_2, i_move)) # relate precondition and action

# attach a resource usage to an interval
r1 = ReusableResource(capacity=1)
move.add_constraint(Use(r1, 1, interval=i_move)

# access condition interval based on add_condition order?
i_move_1_alt = move.get_condition_interval(0) 
assertEquals(i_move_1_alt, i_move_1)

l1 = upf.Object('l1', Location)
l2 = upf.Object('l2', Location)
problem = upf.Problem('robot')
problem.add_fluent(robot_at)
problem.add_durative_action(move)
problem.add_object(l1)
problem.add_object(l2)
problem.set_initial_value(robot_at(l1), True, interval=Interval())
problem.set_initial_value(robot_at(l2), False)
problem.add_timed_effect(100, AssignEffect(robot_at(l2), False))
problem.add_goal(robot_at(l2), interval=Interval()) # At the end of the plan robot is in l2
problem.add_timed_goal(500, robot_at(l1)) # At time 500 robot is in l1
problem.add_maintain_goal(LeftOpenInterval(50, 100), robot_at(l1)) # Between (50 and 100] robot stays in l2

Attention Points

  • Intervals must be grounded to unique instances in a ground action (e.g., many instances of a move action in the same plan must use unique intervals)
    • Intervals of preconditions/goals may be substituted by effect/state intervals that provide them, but this is the same as using unique names and a temporal equality constraint between them.
  • Once an interval is grounded/instantiated for a concrete action, it can be used to relate multiple actions in a temporal plan
  • (Maybe this should be a discussion instead. Let me know and I'll move this over.)

Getting a planner with support for multiple operative modes

User Story

As a non-expert planning user I want to identify a planner that can be used in two operative modes: one shot plan generation and plan repair. The way I see operative modes currently implemented (i.e., through calling a factory that gives me a planner implementing only one operative mode) I cannot make this request explicitly.

As discussed, one way to support this is by calling repeatedly the factory, and then do the checking manually. It would be nice thou to have a method implementing such a functionality directly

Acceptance Criteria

  • Be able to get a planner supporting multiple operative modes
  • Be informed whether there is no such a planner

Tests not passing and dependency problem

Describe the bug
Tests use pytest, but that is not provided as a dependency.
In addition to this, at least one test is not passing:

$ bash run_tests.sh 
=========================================================================================== test session starts ===========================================================================================
platform linux -- Python 3.8.10, pytest-4.6.9, py-1.8.1, pluggy-0.13.0
Django settings: toru_django.settings (from environment variable)
rootdir: /home/calisi/AIPlan4EU/upf-experiments/unified-planning
plugins: pylama-7.4.3, mock-1.10.4, cov-2.8.1, django-3.5.1
collected 38 items / 1 errors / 37 selected                                                                                                                                                               

================================================================================================= ERRORS ==================================================================================================
_________________________________________________________________________ ERROR collecting unified_planning/test/test_pddl_io.py __________________________________________________________________________
ImportError while importing test module '/home/calisi/AIPlan4EU/upf-experiments/unified-planning/unified_planning/test/test_pddl_io.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
unified_planning/test/test_pddl_io.py:23: in <module>
    from unified_planning.io.pddl_reader import PDDLReader
unified_planning/io/pddl_reader.py:20: in <module>
    from pyparsing import Optional, one_of, Suppress, nestedExpr, Group, restOfLine # type: ignore
E   ImportError: cannot import name 'one_of' from 'pyparsing' (/usr/lib/python3/dist-packages/pyparsing.py)
========================================================================================= 1 error in 0.47 seconds =========================================================================================

The one_of is misspelled, it should be oneOf, at least for the current version of pyparsing installed on Ubuntu (that is 2.4.6-1). Moreover, trying to correct the syntax, another issue happen:

$ bash run_tests.sh 
=========================================================================================== test session starts ===========================================================================================
platform linux -- Python 3.8.10, pytest-4.6.9, py-1.8.1, pluggy-0.13.0
Django settings: toru_django.settings (from environment variable)
rootdir: /home/calisi/AIPlan4EU/upf-experiments/unified-planning
plugins: pylama-7.4.3, mock-1.10.4, cov-2.8.1, django-3.5.1
collected 38 items / 1 errors / 37 selected                                                                                                                                                               

================================================================================================= ERRORS ==================================================================================================
_________________________________________________________________________ ERROR collecting unified_planning/test/test_pddl_io.py __________________________________________________________________________
ImportError while importing test module '/home/calisi/AIPlan4EU/upf-experiments/unified-planning/unified_planning/test/test_pddl_io.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
unified_planning/test/test_pddl_io.py:23: in <module>
    from unified_planning.io.pddl_reader import PDDLReader
unified_planning/io/pddl_reader.py:21: in <module>
    from pyparsing.results import ParseResults # type: ignore
E   ModuleNotFoundError: No module named 'pyparsing.results'; 'pyparsing' is not a package
========================================================================================= 1 error in 0.24 seconds =========================================================================================

So it could be that there is a problem with the version of pyparsing?

Additional context
I am running Ubuntu 20.04.03.

Conditional effects

User Story

As a TSB Developer I want to express conditional effects to simplify the modeling of conditional behaviors.

A conditional effect is an action effect that takes place only when a condition is met. A normal effect states that x := 5, a conditional effect could be stated as if phi then x := 5 (where phi is a condition expression) in an imperative programming language.

In the UPF, at the moment, we can only add normal effects (with the add_effect() method of the Action class). We need to extend this function to make it possible to write something like:

act = Action(...)
...
act.add_effcet(x, 5) # x:=5, normal effect
act.add_effect(y, 10, condition=Or(a, b)) # if a or b then y := 10

Acceptance Criteria

  • Conditional effects can be stated via code and stored in the Action class
  • Conditional effects can be printed in a suitable human-readable format when a problem or an action is printed
  • The PDDL printer is extended to support conditional effects
  • The problem kind is extended to detect when conditional effects are present

Additional Material

Attention Points

  • We need to decide if we wan to extend the effects representation or if we want to add a new, special structure just for conditional effects within the action. I am in favor of the first option, but we need to think about this.

Floating-point numbers converted to fractions by the pddl writer

Bug description
When using pddl_writer to write a problem in PDDL, floating-point numbers are converted to fractions. For instance, 1.7 becomes 17/10 (see below). In PDDL this syntax is not supported.

To reproduce

import unified_planning
from unified_planning.shortcuts import *
from unified_planning.io.pddl_reader import PDDLReader
from unified_planning.io.pddl_writer import PDDLWriter

reader = PDDLReader()
pddl_problem = reader.parse_problem('./domain.pddl', './instance_2_1000_1229.pddl')
w = PDDLWriter(pddl_problem)
print(w.get_problem())

The goal field in the output problem is:
(:goal (and (and (<= 1 (x farm0)) (<= 1 (x farm1)) (<= 1400 (+ (* 17/10 (x farm1)) (x farm0))))))

PDDL files: pddl_files.zip

Expected behavior
The goal field in the output problem is:
(:goal (and (and (<= 1 (x farm0)) (<= 1 (x farm1)) (<= 1400 (+ (* 1.7 (x farm1)) (x farm0))))))

Environment

  • OS: Ubuntu 20.04.3 LTS
  • Python version: 3.8.12

PDDL parsing

User Story

As a planning expert I want to import existing PDDL benchmarks and models to augment them via code and/or use integrated planning techniques.

The parser should be able to read just a domain or a domain+problem and generate a Problem instance.

Acceptance Criteria

  • IPC classical and numerical planning examples can be successfully parsed
  • A suite of erroneous model is created and added to CI
  • Proper errors are reported to the user

Additional Material

Attention Points

Parallel Solving

User Story

As a TSB developer I want to use multiple planners or more than one configuration of the same planner in parallel to solve a planning problem.

The parallel solving should have the same interface as the normal solving: each call to the solver is a sort of "voting system" that returns the result of the solver that answers first and the other solvers are stopped.

Acceptance Criteria

  • Easy to switch from using a single solver or a parallel solver
  • One can solve a planning problem using two different planners
  • One can solve a planning problem using a planner in two configurations (e.g. 2 random seeds)

Additional Material

Attention Points

  • Fragmentation issues: we shall find a way to avoid having too many classes and constructors (e.g. OneShotSolver, ParallelOneShotSolver, Validator, ParallelValidator).

An exercise in a MSc course on AI

User Story

  1. Short story:
    As a teacher, I want to use UPF to let my students play around with different planners.

  2. Full story:
    I teach an introductory course on AI in a MSc program on computer engineering. In one of the hands-on exercises, students have to build an integrated planning and execution system to control a simulated robot. They are given an off-the-shelf HTN planner and a low-fidelity robot simulator. They need to write the top-level execution loop, which interacts with the planner and with the robot simulator accordingly to the following diagram.

spa-pipeline

The robot has to transport boxes across different rooms to reach a given configuration; additional difficulties include closed doors that need to be opened, and the presence of a gremlin who occasionally displaces the boxes.

I want the students to use the UPF instead of the given planner, so they can experiment with using different planners, possibly addressing more complex tasks.

Acceptance Criteria

  • Using the UPF should not make the exercise more complex for the students

Additional Material

  • Example of top level code that the students are expected to implement. The call to "pyhop" should be replaced by a suitable call to UPF.
def top_level(robot, task, verbose=1):
    """ Top level execution loop: make a robot perform a task, replan on failures """
    state = State()
    while sense_plan_act(robot, state, task, verbose=verbose) is False:
        continue

def sense_plan_act(robot, state, task, onestep=False, verbose=1):
    """ Sense-Plan-Act loop: read the world state, generate a plan, execute it  """
    get_state(state, robot)
    plan = pyhop.pyhop(state, task, verbose)
    if plan:
        result = do_action(plan, robot)
        if result:
            print("Execution completed!")
        else:
            print("Execution failed!")
        return result
    else:
        print("No plan found!")
    return None

Attention Points

  • No other relevant info for now

Inconsistent use of @property

Within the library sometimes we use @property to create non-parametric getters, sometimes not.

For example:

  • In Environment we use @property
  • In model, most of the times we use plain methods (e.g. IntType.lower_bound(), )
  • In Problem we have name which is a @property again
  • Fluents use plain methods (f.name()) while actions have the property (a.name)

I think this is quite confusing for the user and shall be uniformed.

Default configurations based on taxonomy

User Story

As a planning engine developer, I want to be able to specify default configurations to make the engine easily usable.

This story stems from the Fast Downward planning system, which has quite a large configuration space. We would like to pre-define configurations that get automatically selected based on the taxonomy and possibly more fine-grained criteria such the existence of conditional effects, quantifiers, etc.

Acceptance Criteria

  • A planning system can be integrated with a number of default configurations.
  • In the integration of the planning system, one can set which configuration is used for which kind of problem.
  • The mechanism is documented in the wiki.

Additional Material

Attention Points

  • none

Errors when using PythonWriter

Describe the bug
I have found 3 issues when using PythonWriter with the provided PDDL instance:

  1. Some predicates have '-' in the name. The translation to python keeps the '-' in the python variables (see fluent_ready-to-load in the output file). This issue can also occur when '-' is in action names.
  2. There is a missing newline here: problem_initial_defaults[tm.BoolType()] = emgr.FALSE()problem = up.model.Problem("TPP", env, initial_defaults=problem_initial_defaults) (line 27 of output)
  3. See act_drive = up.model.InstantaneousAction("drive", t=type_truck, from=type_place, to=type_place). The 'from' parameter of the action is a python keyword.

To Reproduce

from unified_planning.shortcuts import *
from unified_planning.io.pddl_writer import PDDLWriter
from unified_planning.io.python_writer import PythonWriter
from unified_planning.io.pddl_reader import PDDLReader
reader = PDDLReader()
pddl_problem = reader.parse_problem('domain.pddl', 'p01.pddl')
w = PythonWriter(pddl_problem)
w.write_problem_code_to_file('output')

TPP.zip

Invalid names in the PDDL writer

As it is now, the PDDL writer accepts and writes in PDDL invalid PDDL name identifiers.

The names should be checked and eventually mangled before being dumped in PDDL. (Small reminder: PDDL is case insensitive)

Conditional Effects Compiler

User Story

As an Advanced UPF user I want to compile away conditional effects to use a planner that does not support them.

The compilation of conditional effects yields an exponential number of actions, but in many cases, the growth is acceptable.
For an action with n conditional effects, in general we get 2^n actions without conditional effects. Each resulting action has a subset of the conditional effects as normal effects and the conditions of the enabled effects as normal preconditions.

As interface, something like the following seems reasonable

p = Problem(...)
compiler = ConditionalEffectRemover(p)
p_nocond = compiler.get_rewritten_problem() 
...
plan_nocond = SequencePlan(...) # Suppose this is a valid plan for p_nocond
plan = compiler.rewrite_back_plan(plan_nocond)
# plan is valid for p

Acceptance Criteria

  • Add example problems with conditional effects and compile them to equivalent problems without
  • Use the "rewrite_back_plan" functionality to test the rewriting validity

Additional Material

Attention Points

  • Do not use recursion for the implementation! Use iteration (and a stack) instead.

Sequential Plan Validation

User Story

As a TSB Developer I want to validate a sequential plan without using external tools.

I.e. Given a SequentialPlan in input I would like to decide if the plan is valid for a given problem and to report the reason of failure otherwise (e.g. "ith action failed because precondition phi is not achieved").

Acceptance Criteria

  • A suitable implementation of validator is implemented in pure python
  • The validator is usable as any other validator from the factory.py
  • The interface is capable of giving reason for validation errors

Additional Material

Attention Points

  • If needed, extend the general Validator operation-mode to provide explanations and adapt the tamer implementation

Planner supports() and asserts

I see that the Solver interface has a supports() method to establish if the solver can solve the problem.
I see that tamer (up-tamer) checks for (asserts) this before starting solving the problem, while pyperplan (up-pyperplan) has the correct supports() function, but it is not used. Wouldn't it make sense to always (i.e. from the interface itself) check this, instead of demanding the check to the single implementations?

'expression not well-formed' error when parsing PDDL

Bug description
The upf crashes when parsing some PDDL instances.

To reproduce

import upf
from upf.shortcuts import *
from upf.io.pddl_reader import PDDLReader

reader = PDDLReader()
pddl_problem = reader.parse_problem('domain.pddl', 'p01.pddl')

This snippet of code produces the following error:
UPFTypeError: The expression '(at(t, m) and loaded(g, t, l3) and ready-to-load(g, m, l2) and next(l2, l1) and next(l4, l3))' is not well-formed

PDDL files: pddl_files.zip

Expected behavior

The pddl_problem is instantiated correctly.

Environment

  • OS: Ubuntu 20.04.3 LTS
  • Python version: 3.8.12

Provide a release tag

At Magazino we're currently looking into packaging this repository. It would be great to have a tagged version to start with. Are you planning to do releases at some point?

Python planner fails with non-python object names

Describe the bug
When using the PythonPrinter on a problem that contains names (e.g. action names) that are not valid python names, the produced code is invalid.

To Reproduce
Steps to reproduce the behavior:

  1. Create a problem with an action named invalid-name
  2. Generate the python code using the PythonPrinter
  3. Try to execute the generated python code
  4. See error

Expected behavior
Python variables are "mangled" to form valid python names

AttributeError: '_UserType' object has no attribute 'type'

Describe the bug
When using UP with the newest versions of unified-planning, pyperplan, and tamer, program execution of the UP example as below yields AttributeError: '_UserType' object has no attribute 'type' at line move.add_precondition(at(x)).

To Reproduce

#!/usr/bin/env python3
from unified_planning.model import Fluent, InstantaneousAction, Object, Problem
from unified_planning.shortcuts import BoolType, OneshotPlanner, UserType


Location = UserType("Location")
a, b = Object('a', Location), Object('b', Location)

at = Fluent("At", BoolType(), [Location])

move = InstantaneousAction("Move", x=Location, y=Location)
x, y = move.parameters()
move.add_precondition(at(x))
move.add_effect(at(x), False)
move.add_effect(at(y), True)

problem = Problem("Example")
problem.add_fluent(at, default_initial_value=False)
problem.add_action(move)
problem.add_objects([a, b])
problem.set_initial_value(at(a), True)
problem.add_goal(at(b))

with OneshotPlanner(problem_kind=problem.kind()) as planner:
    plan = planner.solve(problem)
    print(f"{planner.name()} returned: {plan}")

Expected behavior
Previously this and similar examples ran without problem. The last working commits for me are:

  • unified-planning: 3b513d5
  • up-pyperplan: a6aa9f2
  • up-tamer: a1e3108

Desktop:

  • OS: Ubuntu 20.04

Planning taxonomy

An initial version of the taxonomy is reported here. This issue is for discussions and improvements to the taxonomy.

Support for multi-valued state variables, boolean expressions, global constraints, etc.

User Story

As a TSB Developer I want the UPF to support the description that we internally use in our company. In our system, the planner is responsible on deciding what action to start/abort in the current state. The description of the problem is encoded by the developers in a proprietary YAML-based file, called YADDL (pron. ['ja:dl]), this description is then translated into a more planning-friendly description. While the system is running, the current state is computed and the planner outputs the current operations to be performed to reach a specified goal. In our system the state can change unpredictably, i.e. the state can change for reasons external to the actions being performed (exogenous events).

In particular, our problem description has the following features (that I am not sure if they are already implemented in the UPF):

  • our state is described by a set of multi-valued (enum) variables (something like SAS+), both in YADDL and in the planning-friendly translation
  • actions are not instantaneous, we are currently not considering their duration, but only that some action has a start and an end, this is encoded in YADDL by flagging them as non-durative, but they are then split in the planning-friendly translation into a predefined set of instantaneous actions: start, finish, abort and aborted; it is important to notice that while the executor can start or abort a durative action, it can only wait for it to finish or become aborted (that is: it is an expected event, that "eventually" will happen)
  • the effects of the actions are not deterministic, at least they can either succeed or fail, and the effects are different in the two cases, but we also have sometimes non-determinism in the success or the failure of an action; we are already considering to extend this non-determinism to include probabilities (this is true both in the YADDL version and in the planning-friendly translation, in the latter we just have a list of possible variable assignments)
  • we have the notion of global constraints, that is a set of boolean expressions that must always hold if their conditions are met; the planner should never produce a plan that violates these constraints, but it can happen that, because of the exogenous events, the current state violates the constraints (both in YADDL and in the planning-friendly translation)
  • our current goal is described as a set of boolean expressions over the state variables, each expression has an optional condition (that enables it) and a priority (the planner should consider lower priority goals if the higher priority goals are all met) (this is the same both in the YADDL description and in the planning-friendly description)
  • we can specify a cost for the actions: we currently use this only to instruct the planner that it is always preferable to abort an action than to wait for it to finish, if in the current state we are not interested in the outcomes of successfully finishing that action (this is optional for the YADDL description and we are currently not using it, but during the translation into the planning-friendly description, the start, finish, abort and aborted actions are given the suitable cost)

We would like to use the UPF to encode at least the planning-friendly translation, for this reason we need the features summarized in the Acceptance Criteria below.

Acceptance Criteria

The UPF description should:

  • allow to specify multi-valued state variables
  • allow to specify non-deterministic effects (i.e. the effect of an action can be one-of a set of effects), and possibly probabilities
  • allow to specify action costs
  • allow to specify the action (pre-)conditions in terms of boolean expressions over the state variables
  • allow to specify global constraints in the form of boolean expressions over the state variables
  • allow to specify the goals as a set of boolean expressions with a condition and a priority

Additional material

Here is an example of a YADDL file, in its current version.

wait-next-job.yaddl.yaml.txt

Expression Term Substitution

User Story

As a TSB developer I want to substitute a term in an upf expression with another term to evaluate an expression given an assignment and to perform rewritings of the expression.

Acceptance Criteria

  • Given an expression phi with fluents x and y, it must be possible to substitute a constant value for x and a value for y, such that a call to the simplifier on the resulting expression yields a constant
  • Given an expression phi it must be possible to substitute a sub-term x + 3 with a fresh variable y

Additional Material

Attention Points

  • Use a dagwalker
  • Pay attention to the caching mechanism

ANML Interoperability

User Story

As a Planning Expert I want to write ANML problem formulations from the UP library to interoperate with my ANML planner. Moreover, I want to read ANML problems as UP problems.

Acceptance Criteria

  • Given a UP Problem I can print an ANML specification (just like I can do for PDDL 2.1)
  • I can easily print the specification to a single file or to a python string
  • Given a set of ANML files (ANML, unlike PDDL does not have a forced distinction between domain and problem) I want to read the ANML problem specification as a UP Problem.

Attention Points

  • ANML has several features that are currently unsupported by the UP library, we shall report clear "unsupported" errors when these are encountered.
  • Several "dialects" of ANML exist, at least we should target TAMER and FAPE/ARIES dialects for the time being
  • ANML supports class-like types with actions and local fluents. In a first version it's OK to ignore these and focus on "flat" models

Serializable problem description format

User Story

As a technology provider I want to be able to load the problem definition and solver configuration from structured data.

The UPF allows constructing planning problems from both a python API or by parsing a problem definition in a supported input language (currently PDDL). The problem is loaded in memory in the UPF. Currently to call a planner, the UPF can either rely on the planner's python binding or export the problem to PDDL.

PDDL as language for exchanging the description of planning problem is limiting as the UPF allows specifying constructs that do not directly map to PDDL (e.g. ICE in #45). On the other hand, relying on the python API strongly couples the UPF with a particular version of the solver and complicates distribution.

Having a specialized data structure that fully represents the planning problem would enable planners to support the the native features of the UPF while running in a separate process.
As a planner developer, it would allow decoupling the planner's implementation and the UPF development, with the ability to test the planner on problems constructed with the UPF without directly depending on it.

Acceptance Criteria

  • The problem description format is independent from any programming language (e.g. JSON or protobuf)
  • The problem description format can be serialized, either to be written to a file or to be sent over the network to planner running in another process.
  • The problem description format is extensible, with parts of the schema being explicitly linked to particular features (e.g. hierarchies, ...)

Attention Points

  • Backward compatibility of the problem description format is important. Extensions to the schema should be backward compatible and it should be possible to compile away the cutting edge features to a smaller/earlier schema version. This needs to be kept in mind but is not necessary for prototyping phase.

Discusson on resources representation

In WP3 meetings we discussed several options for implementing a model of resources int he UPF that abstracts away from the "manual" encoding into numeric planning. This issue is intended to summarize the discussion so far and to keep track of proposals, ideas and snippets.

Objective

Instead of manually modeling numerical quantities and their dynamics in the action conditions and effects, provide high-level structures to model the resource and its dynamics. This is to simplify and avoid reinventing the wheel for the user, but also to bridge the gap with scheduling and timeline-based planning and allow for future planners with dedicated resources support.

Proposal spirit

We want to allow for resources to be instantiated from a set of templates (e.g. "RealInstantaneousConsumableResource") taht are defined in the UPF and have a semantic explanation attached to them. Resources are added as first-class citizens in the problem, but the UPF will provide support for compiling them away in numeric/hybrid planning. In this way a solver can either handle resources natively or compile them away and use more general techniques.

Proposal Example

This is an example implementation of a RealInstantaneousConsumableResource, that is a real-valued resourced that can be consumed or produced instantaneously.

This code is on the UPF side:

class InstantaneousRealConsumableResource(Resource):
    '''
    This Resource models a real-valued quantity that is consumed (or produced) instantaneously
   
    E.g. A  battery can be modeled as follows.
    Suppose the move(from, to) action consumes distance(from, to) * consumption_rate battery units when applied 
      InstantaneousRealConsumableResource('battery', 
                                          {move: Times(duration(from, to), consumption_rate}, 
                                          100)
    '''
    def __init__(self, name, consuming_actions=None, initial_value=None):
        self.consuming_actions = consuming_actions
        self.name = name
        self.initial_value = initial_value

    def add_consuming_action(self, action, consumption_expression):
        '''
        Add a new action taht consumes or produces this resource.
        `consumption_expression` is an expression modeling how much resource is produced/consumed
        '''
        self.consuming_actions[action] = consumption_expression


def InstantaneousRealConsumableResourceCompiler(problem, resource):
    '''
    This method modifies `problem` to model the dynamics of the `resource`.
    '''
    domain = upf.Fluent(resource.name, RealType())
    problem.add_fluent(domain)

    for a in problem.actions():
        consume = resource.consuming_actions.get(a, None)
        if consume is not None:
            a.add_precondition(GE(domain, consume))
            a.add_decrease_effect(domain, consume)
    problem.set_initial_value(domain, resource.initial_value)

On the user side, a modeling like this can be used as follows:

Location = UserType('Location')
robot_at = upf.Fluent('robot_at', BoolType(), [Location])
distance = upf.Fluent('distance', RealType(), [Location, Location])
move = upf.Action('move', l_from=Location, l_to=Location)
l_from = move.parameter('l_from')
l_to = move.parameter('l_to')
# move.add_precondition(GE(battery, 10)) # This is created automatically
move.add_precondition(Not(Equals(l_from, l_to)))
move.add_precondition(robot_at(l_from))
move.add_precondition(Not(robot_at(l_to)))
move.add_effect(robot_at(l_from), False)
move.add_effect(robot_at(l_to), True)
# move.add_effect(battery.decrease(10)) -> This is done automagically
l1 = upf.Object('l1', Location)
l2 = upf.Object('l2', Location)
problem = upf.Problem('robot')
problem.add_fluent(robot_at)
battery = InstantaneousRealConsumableResource('battery', {move: distance(l_from, l_to)}, initial_value=100)
problem.add_resource(battery)
problem.add_action(move)
problem.add_object(l1)
problem.add_object(l2)
problem.set_initial_value(robot_at(l1), True)
problem.set_initial_value(robot_at(l2), False)
# problem.set_initial_value(battery, 100) # this calls the `get_initial_state_assignment` method
problem.add_goal(robot_at(l2))

To maintain the definition of the resource closer to the Acton consuming it we could do instead:

Location = UserType('Location')
robot_at = upf.Fluent('robot_at', BoolType(), [Location])
distance = upf.Fluent('distance', RealType(), [Location, Location])
battery = InstantaneousRealConsumableResource('battery', initial_value=100)
move = upf.Action('move', l_from=Location, l_to=Location)
l_from = move.parameter('l_from')
l_to = move.parameter('l_to')
battery.add_consuming_action(move, distance(l_from, l_to))
move.add_precondition(Not(Equals(l_from, l_to)))
move.add_precondition(robot_at(l_from))
move.add_precondition(Not(robot_at(l_to)))
move.add_effect(robot_at(l_from), False)
move.add_effect(robot_at(l_to), True)
l1 = upf.Object('l1', Location)
l2 = upf.Object('l2', Location)
problem = upf.Problem('robot')
problem.add_fluent(robot_at)
problem.add_resource(battery)
problem.add_action(move)
problem.add_object(l1)
problem.add_object(l2)
problem.set_initial_value(robot_at(l1), True)
problem.set_initial_value(robot_at(l2), False)
problem.add_goal(robot_at(l2))

Issues / Comments

  • It could be confusing to not associate the resource with the actions that consume or produce it. In the first example, having the resource "far away" from the move action can be confusing
  • Resources should be parametrized, so that we can create for example one battery for each robot in the problem
  • The initial state might be moved to the problem to reuse the same resource over multiple Problems
  • Recording actions that increase/decrease or set the resource could be more flexible, but it risks to be harder to deal with in scheduling/timeline

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.