Skip to content

Commit

Permalink
Merge pull request #550 from aiplan4eu/doc-polishing
Browse files Browse the repository at this point in the history
doc: various improvements to documentation
  • Loading branch information
mikand committed Dec 22, 2023
2 parents 01c4614 + 8bc0b6b commit da5bc97
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 26 deletions.
42 changes: 37 additions & 5 deletions docs/contributor_guide.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,30 @@
Contributor's Guide
===================

This page is dedicated to the technical information that you may find useful when contributing code or documentation to the UP repository.
For information on the contribution process, please have a look to the `corresponding page <https://github.com/aiplan4eu/unified-planning/blob/master/CONTRIBUTING.md>`_.

Common commands (Justfile)
--------------------------

A list of common commands and recipes are available in a `justfile <https://github.com/aiplan4eu/unified-planning/blob/master/justfile>`_.
You can use it to find out common commands (e.g. running tests, reformatting the code) or use it directly with the `just <https://github.com/casey/just>`_ command line tool.

Whenever you see a command ``just RECIPE_NAME`` in this page, it means the command is available as a just recipe.
You can run it directly with ``just`` or check the ``justfile`` for the actual commands to run.

Checklist
---------

Before sending a pull-request, you should check the following conditions:

- your code is properly formatted with ``black`` (``just format``)
- your code passes the linter check (``just check-mypy``)
- your code passes all existing unit tests
- you have added tests to ensure that your change is and remains valid
- you have updated the documentation to reflect your changes

Whenever possible these are automatically check in CI.

Documentation
-------------
Expand All @@ -13,8 +36,7 @@ It consists of a collection of reStructuredText documents and python notebooks t
Building the documentation
^^^^^^^^^^^^^^^^^^^^^^^^^^


The documentation can be built locally like so::
The documentation can be built locally like so (``just build-doc``)::

cd docs/ # enter the documentation folder
pip install -r requirements.txt # install documentation toolchain
Expand All @@ -30,11 +52,21 @@ The reference API part of the documentation is built automatically by the `docs/
The script contains the list of classes that will appear in the documentation.
If you contribute a new *user-facing* class, the list of classes should be updated to make it appear in the API reference.

Ensuring documentation consistency
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

As much as possible, we strive to make example code testable to ensure that it remains valid when updating the library.
This notably include all code in ``docs/code_snippets`` as well as all notebooks in ``docs/notebooks``.

If your notebook has some code that should *not* be run in CI, the corresponding cell should be tagged with the ``remove_from_CI`` flag.

Protobuf bindings
-----------------

The UP provides protobuf bindings that can be used export the problems modeled with the UP in a protobuf format.
The schema for this format are available in the `unified_planning/grpc/unified_planning.proto <https://github.com/aiplan4eu/unified-planning/blob/master/unified_planning/grpc/unified_planning.proto>`_ file.

Issue Tracking
--------------
When updating them you should ensure that:

Issue tracking is done in GitHub issues: https://github.com/aiplan4eu/unified-planning/issues
- the schema remains backward compatible (no removal, no change in the fields indices)
- you have regenerated the python bindings available in the repository (``just gen-protobuf``)
12 changes: 9 additions & 3 deletions docs/getting_started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,18 @@ In this guide we present the main functionalities offered by the Unified-Plannin


.. toctree::
:maxdepth: 2
:maxdepth: 1
:glob:
:hidden:
:caption: Getting Started

getting_started/whats_planning
getting_started/installation
getting_started/quickstart
notebooks/tutorial/modeling.ipynb

.. raw:: html

<iframe text-align="center" width="560" height="315" src="https://www.youtube.com/embed/DhZpdTRnfyU?si=IJuMvC0SHv1p0los" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>




44 changes: 32 additions & 12 deletions docs/optimality.rst
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
.. _engines:

==========
Optimality
==========
======================
Metrics & Plan Quality
======================

.. contents::
:local:
Expand All @@ -28,19 +28,39 @@ The UP library defines a set of "Quality Metrics" to express the objective funct
Creating quality metrics amounts to instantiate the corresponding object and adding it to one or more `Problem` instances. See the `Optimal Planning Notebook <https://github.com/aiplan4eu/unified-planning/blob/master/docs/notebooks/02-optimal-planning.ipynb>`_ for an example.


Optimal and Satisficing Planning
================================
Optimal, Anytime and Satisficing Planning
=========================================

Some planning engines can guarantee to find the optimal solution for some kinds of quality metrics, others can only apply a best-effort approach to find good-quality solutions without optimality guarantees. The UP allows the user to explicitly define the desired optimality guarantees as parameters of the operative modes.
When dealing with quality metrics, it is useful to keep the following in mind:

If a planning engine is able to generate a solution result it could be either marked as `SOLVED_OPTIMALLY` or `SOLVED_SATISFICING` to indicate whether the produced solution is guaranteed to be optimal or not.
- A **satisficing** planner will return the first plan found, regardless of its quality.
- An **optimal** planner will only return a provably optimal plan.
- An **anytime** planner will return a series of plan of increasing quality until it runs out of time or is no longer able to improve its last solution.

.. code-block::
Notes
-----
# By default, Oneshot planner will return the first available solver (typically a satisficing one)
with OneshotPlanner(problem_kind=problem.kind) as planner:
res = planner.solve(utr_problem)
# An optimal solver can be explicitly required with the optimality_guarantee parameter
with OneshotPlanner(problem_kind=problem.kind,
optimality_guarantee=PlanGenerationResultStatus.SOLVED_OPTIMALLY) as optimal_planner:
res = optimal_planner.solve(utr_problem)
If a planning problem without optimality metrics is required to be solved optimally, an exception is thrown.
# An anytime planner can be requested with the AnytimePlanning operation mode
with AnytimePlanner(problem_kind=problem.kind) as planner:
for res in planner.get_solutions(problem):
print(res)
If a planning problem without optimality metrics is solved by a planning engine capable of guaranteeing some optimality, it is anyway marked as `SOLVED_SATISFICING`.
Proving the optimality of plan can be very time-consuming and orders of magnitude longer than finding it.
Indeed, it requires the planner to prove that all potential alternative plans are of lower quality.
As a rule of thumb, if you are interested in finding high quality solutions but do not care about optimality you should use an anytime planner.
Its runtime can be capped with the ``timeout`` parameter of ``get_solutions()`` or may just break out of the loop when your happy with the returned solution.

Notes
-----

The UP currently supports only 1 metric in each problem, therefore multi-objective optimization is not possible.
- If a planning problem without optimality metrics is required to be solved optimally, an exception is thrown.
- If a planning problem without optimality metrics is solved by a planning engine capable of guaranteeing some optimality, it is anyway marked as `SOLVED_SATISFICING`.
- The UP currently supports only 1 metric in each problem, therefore multi-objective optimization is not possible.
25 changes: 19 additions & 6 deletions docs/problem_representation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -247,15 +247,25 @@ In all the examples below all the shortcuts must be imported, with the command:

Classical and Numeric Planning
------------------------------
The following example shows a simple robotic planning problem modeling a robot moving between locations while consuming battery. The example shows the basic functionalities and objects needed to declare the problem specification. A more detailed presentation of the different objects is available on the `Google Colab <https://colab.research.google.com/github/aiplan4eu/unified-planning/blob/master/docs/notebooks/01-basic-example.ipynb>`_ Python notebook where we document and explain all the different classes and their semantics.

Classical and Numeric planning are the most common problems and the building blocks of most other planning problems.
At their root, they allow the definition of instantaneous that provide:

- preconditions that allow to check whether the action is applicable in a given state, and
- effects that allow the computation of the resulting state after the action is executed.

The classical and numeric planning only differ in that classical planning does not allow to referring to numeric variables in the state.
The following example shows a simple robotic planning problem modeling a robot moving between locations while consuming battery.
The example shows the basic functionalities and objects needed to declare the problem specification.
`[Classical detailed presentation 🔗] <notebooks/01-basic-example.html>`__
`[Numeric detailed presentation 🔗] <notebooks/01-numeric-planning.html>`__

.. literalinclude:: ./code_snippets/robot_battery.py
:lines: 3-38

:caption: Syntax Overview

In the current version, the Unified-Planning library allows the specification of classical, numerical and temporal planning problems. In order to support the latitude expressiveness levels we have operators for arithmetic such as plus minus times and division and specific temporal operators to attach conditions and effects to specific timings within the duration of an action. The library :ref:`documentation <api-reference>` provides examples and describes the use of these functionalities.


Temporal Planning
-----------------

Expand All @@ -266,9 +276,11 @@ This means that it is possible to model actions having:
* conditions or effects expressed at specific instant of the action, in particular at times start+delay or end+delay, where start refers to the starting time of the action, end to the ending time and delay is a real constant (positive or negative).
* durative conditions to be maintained within sub-intervals, delimited by the same time-point used for instantaneous conditions.

`[Detailed presentation 🔗] <notebooks/03-temporal-planning.html>`__

.. literalinclude:: ./code_snippets/temporal_and_scheduling.py
:lines: 3-44

:caption: Syntax Overview

Hierarchical Planning
---------------------
Expand All @@ -290,15 +302,15 @@ The problem comes in several variants, depending on various features. Specifical

.. literalinclude:: ./code_snippets/multi_agent_and_contingent.py
:lines: 3-41

:caption: Syntax Overview

Contingent Planning
-------------------
A contingent planning problem represents an action-based problem in which the exact initial state is not entirely known and some of the actions produce “observations” upon execution. More specifically, some actions can be SensingActions, which indicate which fluents they observe and after the successful execution of such actions, the observed fluents become known to the executor. The inherent non-determinism in the initial state can therefore be “shrinked” by performing suitable SensingActions and a plan is then a strategy that prescribes what to execute based on the past observations.

.. literalinclude:: ./code_snippets/multi_agent_and_contingent.py
:lines: 44-95

:caption: Syntax Overview

Scheduling
----------
Expand Down Expand Up @@ -334,4 +346,5 @@ object between a series of waypoints. `[Detailed presentation 🔗] <notebooks/

.. literalinclude:: ./code_snippets/tamp_problem.py
:lines: 5-116
:caption: Syntax Overview

35 changes: 35 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@


# Format the code base
format:
python3 -m black --exclude=unified_planning/grpc/generated/ .

# Check that the code base is correctly formated
check-format:
python3 -m black --check --exclude=unified_planning/grpc/generated/ .

# Run mypy linter on the code base
check-mypy:
python3 -m mypy unified_planning

# Generate protobuf bindings
gen-protobuf:
pip show grpcio-tools | grep "Version: 1.54.2" # Check installed version for reproducibility
bash scripts/generate_protobuf_bindings.sh

# Test one (or more) engine with report
test-engine +engine_name:
python3 up_test_cases/report.py {{engine_name}}

# Generate the documentation
build-doc target="html":
pip install -r docs/requirements.txt
sphinx-build -M {{target}} docs/ docs/_build -W --keep-going

# Open local documentation in the browser
open-doc browser="firefox":
{{browser}} docs/_build/html/index.html

# Install unified-planning from sources
install:
pip install .

0 comments on commit da5bc97

Please sign in to comment.