Skip to content
 
 

Latest commit

 

History

261 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GTPyhop

Python Version License PyPI

Doctests

GTPyhop is an HTN planning system based on Pyhop, but generalized to plan for both goals and tasks. You describe a world as actions that change state and methods that break tasks into smaller ones; GTPyhop searches for a sequence of actions that accomplishes what you asked for.

Dana Nau is the original author of GTPyhop.

This pip branch is forked from Dana Nau's main branch and refactored for PyPI distribution, thread-safe sessions, benchmarking-friendly example layout, and documentation.


Install

pip install gtpyhop

That gives you the planner and every bundled example. Since 2.0.0, GTPyhop is published as four distributions that all install into the same gtpyhop import namespace:

Install You get Use when
gtpyhop planner and all bundled examples learning, teaching, exploring
gtpyhop-core the planner alone production, CI, embedded
gtpyhop-examples the examples (pulls in core) you installed core first
gtpyhop-diagnostics optional failure attribution you want to know why a plan failed

From a checkout — note there is no root pyproject.toml since 2.0.0, so install the source packages rather than the repository root:

git clone -b pip https://github.com/PCfVW/GTPyhop.git
cd GTPyhop
pip install packages/gtpyhop-core packages/gtpyhop-examples

Add -e to both if you intend to modify GTPyhop or contribute an example; the two source trees only merge into one importable package once installed.

Check it works

python -m gtpyhop.examples.simple_htn --session
python -m gtpyhop.examples.regression_tests

Your first plan

A truck fetches a parcel and delivers it. This runs as written:

import gtpyhop

domain = gtpyhop.Domain('delivery')

# An action checks its preconditions, applies its effects, and returns the
# state. Falling off the end means "not applicable here".
def drive(state, truck, dest):
    if state.fuel[truck] > 0 and state.at[truck] != dest:
        state.at[truck] = dest
        state.fuel[truck] -= 1
        return state

def load(state, parcel, truck):
    if state.at[parcel] == state.at[truck]:
        state.at[parcel] = truck
        return state

def unload(state, parcel, truck):
    if state.at[parcel] == truck:
        state.at[parcel] = state.at[truck]
        return state

gtpyhop.declare_actions(drive, load, unload)

# A method decomposes a task into subtasks and actions.
def m_deliver(state, parcel, truck, dest):
    return [('drive', truck, state.at[parcel]),
            ('load', parcel, truck),
            ('drive', truck, dest),
            ('unload', parcel, truck)]

gtpyhop.declare_task_methods('deliver', m_deliver)

state = gtpyhop.State('s0')
state.at = {'truck1': 'depot', 'parcel1': 'warehouse'}
state.fuel = {'truck1': 2}

with gtpyhop.PlannerSession(domain=domain, verbose=0) as session:
    result = session.find_plan(state, [('deliver', 'parcel1', 'truck1', 'shop')])

for step in result.plan:
    print(step)
('drive', 'truck1', 'warehouse')
('load', 'parcel1', 'truck1')
('drive', 'truck1', 'shop')
('unload', 'parcel1', 'truck1')

PlannerSession is the recommended entry point: it isolates the domain, verbosity and strategy so concurrent planning is safe. The older global API (gtpyhop.find_plan, …) still works unchanged.

When a plan fails

find_plan returning nothing tells you only that no plan exists. GTPyhop can say considerably more. Save the domain above as delivery.py, start the truck with an empty tank, and ask why:

from gtpyhop.diagnostics import explain_dead_end   # pip install gtpyhop-diagnostics

state.fuel = {'truck1': 0}                         # nothing else changes

with gtpyhop.PlannerSession(domain=domain, verbose=0) as session:
    result = session.find_plan(state, [('deliver', 'parcel1', 'truck1', 'shop')],
                               trace=True, trace_state=True)

print(explain_dead_end(result.trace, "delivery.py").summary())
drive('truck1', 'warehouse') was blocked by: state.fuel[truck] > 0

Not just which action failed — which precondition of it, and it correctly ignores the guard that did hold. Walked through step by step in the diagnostics tutorial.

Where to go next

Start here

  • FAQ — which package to install, which strategy to pick, what an action must return
  • Goals tutorial — asking for a state instead of a task, four ways
  • Diagnostics tutorial — from "it failed" to "this precondition blocked it"
  • All Examples — the full catalogue, with pedagogical notes
  • Running Examples — how to invoke and benchmark them

Going further

Writing your own

Project structure

GTPyhop/
├── docs/                        guides, style guides, changelog
├── tools/                       repository utilities (link, domain, doctest and persistence checks)
└── packages/                    one folder per published distribution
    ├── gtpyhop-core/            the planner
    ├── gtpyhop-examples/        the bundled example domains
    ├── gtpyhop-diagnostics/     optional failure attribution
    └── gtpyhop/                 meta-package: core + examples, no source

Each package keeps its own src/gtpyhop/ tree; they merge into a single importable gtpyhop package once installed, so import gtpyhop, import gtpyhop.examples and import gtpyhop.diagnostics all work side by side.

Credits and licence

GTPyhop was created by Dana Nau. This branch is maintained by Eric Jacopin. Released under the Clear BSD License — see LICENSE.txt.

About

This pip branch is a refactoring of Dana Nau's GTPyhop to pip install gtpyhop; iterative seek_plan added (greedy and fully bactracking), thread-safe sessions, (psutil) memory monitoring and tracking, unified new examples (ipc-2020, bio_automation mcp orchestration, memory tracking, poetry, and cybersecurity)

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages