planning-machine 0.2__tar.gz → 0.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- planning_machine-0.3/PKG-INFO +139 -0
- planning_machine-0.3/README.md +126 -0
- planning_machine-0.3/planning_machine/demo/__init__.py +0 -0
- planning_machine-0.3/planning_machine/demo/canberra.yaml +2002 -0
- planning_machine-0.3/planning_machine/demo/config.yaml +5 -0
- planning_machine-0.3/planning_machine/demo/configuration.yaml +5 -0
- planning_machine-0.3/planning_machine/demo/domain.yaml +67 -0
- planning_machine-0.3/planning_machine/demo/map_downloader.py +142 -0
- planning_machine-0.3/planning_machine/demo/solution_visualizer.py +185 -0
- planning_machine-0.3/planning_machine/lib.py +249 -0
- planning_machine-0.3/planning_machine.egg-info/PKG-INFO +139 -0
- {planning_machine-0.2 → planning_machine-0.3}/planning_machine.egg-info/SOURCES.txt +8 -1
- {planning_machine-0.2 → planning_machine-0.3}/setup.py +4 -1
- planning_machine-0.2/PKG-INFO +0 -50
- planning_machine-0.2/README.md +0 -37
- planning_machine-0.2/planning_machine/lib.py +0 -148
- planning_machine-0.2/planning_machine.egg-info/PKG-INFO +0 -50
- {planning_machine-0.2 → planning_machine-0.3}/LICENSE +0 -0
- {planning_machine-0.2 → planning_machine-0.3}/planning_machine/__init__.py +0 -0
- {planning_machine-0.2 → planning_machine-0.3}/planning_machine/mcp_server.py +0 -0
- {planning_machine-0.2 → planning_machine-0.3}/planning_machine/pddl_parser.py +0 -0
- {planning_machine-0.2 → planning_machine-0.3}/planning_machine/report.py +0 -0
- {planning_machine-0.2 → planning_machine-0.3}/planning_machine/yaml_parser.py +0 -0
- {planning_machine-0.2 → planning_machine-0.3}/planning_machine.egg-info/dependency_links.txt +0 -0
- {planning_machine-0.2 → planning_machine-0.3}/planning_machine.egg-info/requires.txt +0 -0
- {planning_machine-0.2 → planning_machine-0.3}/planning_machine.egg-info/top_level.txt +0 -0
- {planning_machine-0.2 → planning_machine-0.3}/setup.cfg +0 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: planning-machine
|
|
3
|
+
Version: 0.3
|
|
4
|
+
Description-Content-Type: text/markdown
|
|
5
|
+
License-File: LICENSE
|
|
6
|
+
Requires-Dist: unified_planning>=1.3.0
|
|
7
|
+
Requires-Dist: PyYAML>=6.0.3
|
|
8
|
+
Requires-Dist: docker>=7.1.0
|
|
9
|
+
Dynamic: description
|
|
10
|
+
Dynamic: description-content-type
|
|
11
|
+
Dynamic: license-file
|
|
12
|
+
Dynamic: requires-dist
|
|
13
|
+
|
|
14
|
+
# Introduction
|
|
15
|
+
PlanningMachine is an automated planning library that parse YAML-based instructions into PDDL, solves them using a planner, and returns a structured plan with step effects. It can be run as a standalone service via Docker Compose or integrated directly into Python projects as a library. The goal of this project is to make the technology in automated planning more accessible to software engineers without exposing them to the internals of how they work.
|
|
16
|
+
|
|
17
|
+
# Setup and Installation
|
|
18
|
+
The Python library can be installed either by building the wheel files from source or via pip. We recommend the latter.
|
|
19
|
+
|
|
20
|
+
## from Source
|
|
21
|
+
1. In the root directory, execute `python setup.py sdist bdist_wheel` to create a `.whl` file in a newly created `dist` folder.
|
|
22
|
+
2. Execute `pip install /dist/filename.whl`, where `filename.whl` is a placeholder name for the created `.whl` file.
|
|
23
|
+
|
|
24
|
+
## from PyPi
|
|
25
|
+
Execute `pip install planning_machine`.
|
|
26
|
+
|
|
27
|
+
# Usage
|
|
28
|
+
PlanningMachine assumes Docker is installed (and running) on your computer.
|
|
29
|
+
|
|
30
|
+
## Config file
|
|
31
|
+
PlanningMachine is driven by a `config.yaml` file that specifies:
|
|
32
|
+
|
|
33
|
+
- `domain` — relative path to a `domain.yaml` file (required)
|
|
34
|
+
- `problem` — relative path to a `problem.yaml` file (required)
|
|
35
|
+
- `planner` — planner name (optional, default `LAPKT`)
|
|
36
|
+
- `mem_limit` — memory limit in GB (optional, default `8`)
|
|
37
|
+
- `cpu_limit` — CPU limit in cores (optional, default `1`)
|
|
38
|
+
|
|
39
|
+
Relative paths are resolved against the directory containing `config.yaml`. Example:
|
|
40
|
+
|
|
41
|
+
```yaml
|
|
42
|
+
domain: domain.yaml
|
|
43
|
+
problem: problem.yaml
|
|
44
|
+
cpu_limit: 1
|
|
45
|
+
mem_limit: 8
|
|
46
|
+
planner: LAPKT
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Grammar overview
|
|
50
|
+
`config.yaml` instructs PlanningMachine to read two YAML files whose structure is defined formally in [`grammar.md`](grammar.md). At a high level:
|
|
51
|
+
|
|
52
|
+
A **domain file** describes the "rules of the world" and contains four top-level keys: `domain` (a name), `types` (a hierarchy mapping each subtype to its supertype), `predicates` (the relations that can hold, optionally with typed arguments), and `actions`. Each action defines its `parameters`, a `precondition` that must hold for it to apply, and the `effect` it produces.
|
|
53
|
+
|
|
54
|
+
A **problem file** describes a specific scenario to solve and contains five top-level keys: `problem` (a name), `domain` (the name of the domain it uses), `objects` (the concrete things in the world, grouped by type), `init` (the predicates true in the starting state), and `goal` (the predicates that must be true in a solution).
|
|
55
|
+
|
|
56
|
+
Preconditions, effects, and goals are written as **formulas**: a single atom such as `at: [veh, loc]`, a negated atom using `not`, or an `and`/`or` junction over a list of atoms. Effects may additionally be **conditional**, using a `when` block with `condition` and `then` lists. All names (types, predicates, actions, parameters, and objects) are identifiers starting with a letter or underscore. The formal syntax rules for the `domain.yaml` and `problem.yaml` files are documented in [`grammar.md`](grammar.md).
|
|
57
|
+
|
|
58
|
+
### Example
|
|
59
|
+
A minimal logistics domain with a single `load` action:
|
|
60
|
+
|
|
61
|
+
```yaml
|
|
62
|
+
domain: logistics
|
|
63
|
+
types:
|
|
64
|
+
# vehicle (subtype) is locatable (type)
|
|
65
|
+
vehicle: locatable
|
|
66
|
+
package: locatable
|
|
67
|
+
loc: location
|
|
68
|
+
predicates:
|
|
69
|
+
predicates:
|
|
70
|
+
# at(obj: locatable, loc: location)
|
|
71
|
+
at:
|
|
72
|
+
- obj: locatable
|
|
73
|
+
- loc: location
|
|
74
|
+
# in(pak: package, veh: vehicle)
|
|
75
|
+
in:
|
|
76
|
+
- pak: package
|
|
77
|
+
- veh: vehicle
|
|
78
|
+
actions:
|
|
79
|
+
# loads a package into a vehicle if and only if they are in the same location.
|
|
80
|
+
load:
|
|
81
|
+
# load(pak: package, veh: vehicle, loc: location)
|
|
82
|
+
parameters:
|
|
83
|
+
- pak: package
|
|
84
|
+
- veh: vehicle
|
|
85
|
+
- loc: location
|
|
86
|
+
# precondition is equivalent to: ```if at(veh, loc) && at(pak, loc)```
|
|
87
|
+
precondition:
|
|
88
|
+
and:
|
|
89
|
+
- at: [veh, loc]
|
|
90
|
+
- at: [pak, loc]
|
|
91
|
+
# effect is equivalent to the "then" part of an "if": in(pak, veh) = True && at(pak, loc) = False
|
|
92
|
+
effect:
|
|
93
|
+
and:
|
|
94
|
+
- in: [pak, veh]
|
|
95
|
+
- not: {at: [pak, loc]}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
A matching problem that asks for the laptop to end up loaded in the car:
|
|
99
|
+
|
|
100
|
+
```yaml
|
|
101
|
+
problem: load_laptop
|
|
102
|
+
domain: logistics
|
|
103
|
+
objects:
|
|
104
|
+
vehicle: [car]
|
|
105
|
+
package: [laptop]
|
|
106
|
+
location: [warehouse]
|
|
107
|
+
init:
|
|
108
|
+
at:
|
|
109
|
+
- [car, warehouse]
|
|
110
|
+
- [laptop, warehouse]
|
|
111
|
+
goal:
|
|
112
|
+
- in: [laptop, car]
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Solving this problem yields a single-step plan: `load(laptop, car, warehouse)`.
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
## Docker Compose
|
|
119
|
+
1. Create a directory named `workdir` in the root folder.
|
|
120
|
+
2. Place `config.yaml`, `domain.yaml`, and `problem.yaml` in `workdir`.
|
|
121
|
+
3. Execute `docker compose up` in the root folder. This parses the files in `workdir` to PDDL, calls the planner to solve them, and extracts the effects of each plan step. The solution is placed in `workdir/plan.yaml`.
|
|
122
|
+
|
|
123
|
+
## Python
|
|
124
|
+
|
|
125
|
+
Import and use the `PlanningMachine` class as follows:
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from planning_machine import PlanningMachine
|
|
129
|
+
|
|
130
|
+
pm = PlanningMachine()
|
|
131
|
+
solution = pm.solve(config_path)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Provide the path to your `config.yaml`, and `.solve()` will return the solution to your planning problem.
|
|
135
|
+
|
|
136
|
+
A demo Jupyter notebook, `demo.ipynb`, is also included. It walks through a real-world logistics problem end-to-end, covering setup, solving, analytics, and visualization.
|
|
137
|
+
|
|
138
|
+
## Contact
|
|
139
|
+
Please contact <a href="mailto:opensource@learningmachines.au">opensource@learningmachines.au</a> for questions, comments, or feedback about the PlanningMachine library.
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Introduction
|
|
2
|
+
PlanningMachine is an automated planning library that parse YAML-based instructions into PDDL, solves them using a planner, and returns a structured plan with step effects. It can be run as a standalone service via Docker Compose or integrated directly into Python projects as a library. The goal of this project is to make the technology in automated planning more accessible to software engineers without exposing them to the internals of how they work.
|
|
3
|
+
|
|
4
|
+
# Setup and Installation
|
|
5
|
+
The Python library can be installed either by building the wheel files from source or via pip. We recommend the latter.
|
|
6
|
+
|
|
7
|
+
## from Source
|
|
8
|
+
1. In the root directory, execute `python setup.py sdist bdist_wheel` to create a `.whl` file in a newly created `dist` folder.
|
|
9
|
+
2. Execute `pip install /dist/filename.whl`, where `filename.whl` is a placeholder name for the created `.whl` file.
|
|
10
|
+
|
|
11
|
+
## from PyPi
|
|
12
|
+
Execute `pip install planning_machine`.
|
|
13
|
+
|
|
14
|
+
# Usage
|
|
15
|
+
PlanningMachine assumes Docker is installed (and running) on your computer.
|
|
16
|
+
|
|
17
|
+
## Config file
|
|
18
|
+
PlanningMachine is driven by a `config.yaml` file that specifies:
|
|
19
|
+
|
|
20
|
+
- `domain` — relative path to a `domain.yaml` file (required)
|
|
21
|
+
- `problem` — relative path to a `problem.yaml` file (required)
|
|
22
|
+
- `planner` — planner name (optional, default `LAPKT`)
|
|
23
|
+
- `mem_limit` — memory limit in GB (optional, default `8`)
|
|
24
|
+
- `cpu_limit` — CPU limit in cores (optional, default `1`)
|
|
25
|
+
|
|
26
|
+
Relative paths are resolved against the directory containing `config.yaml`. Example:
|
|
27
|
+
|
|
28
|
+
```yaml
|
|
29
|
+
domain: domain.yaml
|
|
30
|
+
problem: problem.yaml
|
|
31
|
+
cpu_limit: 1
|
|
32
|
+
mem_limit: 8
|
|
33
|
+
planner: LAPKT
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Grammar overview
|
|
37
|
+
`config.yaml` instructs PlanningMachine to read two YAML files whose structure is defined formally in [`grammar.md`](grammar.md). At a high level:
|
|
38
|
+
|
|
39
|
+
A **domain file** describes the "rules of the world" and contains four top-level keys: `domain` (a name), `types` (a hierarchy mapping each subtype to its supertype), `predicates` (the relations that can hold, optionally with typed arguments), and `actions`. Each action defines its `parameters`, a `precondition` that must hold for it to apply, and the `effect` it produces.
|
|
40
|
+
|
|
41
|
+
A **problem file** describes a specific scenario to solve and contains five top-level keys: `problem` (a name), `domain` (the name of the domain it uses), `objects` (the concrete things in the world, grouped by type), `init` (the predicates true in the starting state), and `goal` (the predicates that must be true in a solution).
|
|
42
|
+
|
|
43
|
+
Preconditions, effects, and goals are written as **formulas**: a single atom such as `at: [veh, loc]`, a negated atom using `not`, or an `and`/`or` junction over a list of atoms. Effects may additionally be **conditional**, using a `when` block with `condition` and `then` lists. All names (types, predicates, actions, parameters, and objects) are identifiers starting with a letter or underscore. The formal syntax rules for the `domain.yaml` and `problem.yaml` files are documented in [`grammar.md`](grammar.md).
|
|
44
|
+
|
|
45
|
+
### Example
|
|
46
|
+
A minimal logistics domain with a single `load` action:
|
|
47
|
+
|
|
48
|
+
```yaml
|
|
49
|
+
domain: logistics
|
|
50
|
+
types:
|
|
51
|
+
# vehicle (subtype) is locatable (type)
|
|
52
|
+
vehicle: locatable
|
|
53
|
+
package: locatable
|
|
54
|
+
loc: location
|
|
55
|
+
predicates:
|
|
56
|
+
predicates:
|
|
57
|
+
# at(obj: locatable, loc: location)
|
|
58
|
+
at:
|
|
59
|
+
- obj: locatable
|
|
60
|
+
- loc: location
|
|
61
|
+
# in(pak: package, veh: vehicle)
|
|
62
|
+
in:
|
|
63
|
+
- pak: package
|
|
64
|
+
- veh: vehicle
|
|
65
|
+
actions:
|
|
66
|
+
# loads a package into a vehicle if and only if they are in the same location.
|
|
67
|
+
load:
|
|
68
|
+
# load(pak: package, veh: vehicle, loc: location)
|
|
69
|
+
parameters:
|
|
70
|
+
- pak: package
|
|
71
|
+
- veh: vehicle
|
|
72
|
+
- loc: location
|
|
73
|
+
# precondition is equivalent to: ```if at(veh, loc) && at(pak, loc)```
|
|
74
|
+
precondition:
|
|
75
|
+
and:
|
|
76
|
+
- at: [veh, loc]
|
|
77
|
+
- at: [pak, loc]
|
|
78
|
+
# effect is equivalent to the "then" part of an "if": in(pak, veh) = True && at(pak, loc) = False
|
|
79
|
+
effect:
|
|
80
|
+
and:
|
|
81
|
+
- in: [pak, veh]
|
|
82
|
+
- not: {at: [pak, loc]}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
A matching problem that asks for the laptop to end up loaded in the car:
|
|
86
|
+
|
|
87
|
+
```yaml
|
|
88
|
+
problem: load_laptop
|
|
89
|
+
domain: logistics
|
|
90
|
+
objects:
|
|
91
|
+
vehicle: [car]
|
|
92
|
+
package: [laptop]
|
|
93
|
+
location: [warehouse]
|
|
94
|
+
init:
|
|
95
|
+
at:
|
|
96
|
+
- [car, warehouse]
|
|
97
|
+
- [laptop, warehouse]
|
|
98
|
+
goal:
|
|
99
|
+
- in: [laptop, car]
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Solving this problem yields a single-step plan: `load(laptop, car, warehouse)`.
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
## Docker Compose
|
|
106
|
+
1. Create a directory named `workdir` in the root folder.
|
|
107
|
+
2. Place `config.yaml`, `domain.yaml`, and `problem.yaml` in `workdir`.
|
|
108
|
+
3. Execute `docker compose up` in the root folder. This parses the files in `workdir` to PDDL, calls the planner to solve them, and extracts the effects of each plan step. The solution is placed in `workdir/plan.yaml`.
|
|
109
|
+
|
|
110
|
+
## Python
|
|
111
|
+
|
|
112
|
+
Import and use the `PlanningMachine` class as follows:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from planning_machine import PlanningMachine
|
|
116
|
+
|
|
117
|
+
pm = PlanningMachine()
|
|
118
|
+
solution = pm.solve(config_path)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Provide the path to your `config.yaml`, and `.solve()` will return the solution to your planning problem.
|
|
122
|
+
|
|
123
|
+
A demo Jupyter notebook, `demo.ipynb`, is also included. It walks through a real-world logistics problem end-to-end, covering setup, solving, analytics, and visualization.
|
|
124
|
+
|
|
125
|
+
## Contact
|
|
126
|
+
Please contact <a href="mailto:opensource@learningmachines.au">opensource@learningmachines.au</a> for questions, comments, or feedback about the PlanningMachine library.
|
|
File without changes
|