graphplan

package
v0.2.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 11, 2026 License: MIT Imports: 7 Imported by: 0

README

graphplan

Package graphplan implements the Graphplan planning algorithm (Blum & Furst 1997) for STRIPS and ADL planning domains.

It constructs a planning graph and uses backward-chaining search with memoization to find shortest parallel plans. ADL support includes disjunctive preconditions, conditional effects, universally/existentially quantified formulas, and derived predicates (axioms) computed via fixed-point evaluation.

Key Types

  • Domain -- types, predicates, operator templates, and axioms
  • Problem -- objects, initial state, and goal propositions
  • Operator -- action template with Formula preconditions and effects
  • Axiom -- derived predicate rule (head predicate + Formula body)
  • Formula -- interface for logical formulas (And, Or, Imply, Forall, Exists, When, Atom)
  • Solver -- runs the extend/search loop
  • SolverConfig -- optional settings (e.g. max graph levels)
  • PlanStep -- one time step of parallel actions in the result

Usage

Build a Domain and Problem, create a Solver, call Solve:

domain := &graphplan.Domain{
    Name:       "logistics",
    Types:      []graphplan.Type{{Name: "pkg", Parent: "object"}},
    Predicates: []graphplan.Predicate{{Name: "at", ParamTypes: []string{"pkg", "place"}}},
    Operators:  []graphplan.Operator{ /* ... */ },
}

problem := &graphplan.Problem{
    Name:         "deliver",
    Domain:       domain,
    Objects:      []graphplan.Object{{Name: "p1", Type: "pkg"}},
    InitialState: []graphplan.Proposition{{Predicate: "at", Args: []string{"p1", "src"}}},
    Goals:        []graphplan.Proposition{{Predicate: "at", Args: []string{"p1", "dst"}}},
}

solver, err := graphplan.NewSolver(nil)
if err != nil {
    log.Fatal(err)
}

plan, err := solver.Solve(problem)
if err != nil {
    log.Fatal(err)
}

for _, step := range plan {
    for _, a := range step.Actions {
        if !a.IsNoOp() {
            fmt.Println(a)
        }
    }
}

See examples/rocket/ for a complete working example.

Documentation

Overview

Package graphplan implements the Graphplan algorithm for solving STRIPS and ADL planning problems. It constructs a Planning Graph and uses backward-chaining search with memoization to find shortest parallel plans.

ADL support includes a Formula tree representation with And, Or, Imply, Forall, Exists, and When nodes. Disjunctive preconditions, conditional effects, and universally or existentially quantified formulas are grounded and evaluated during graph expansion. Derived predicates (axioms) are computed via fixed-point evaluation at each proposition layer.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNoValidPlan indicates no valid plan exists for
	// the given problem.
	ErrNoValidPlan = errors.New("no valid plan exists")

	// ErrMaxLevelsExceeded indicates the solver hit the
	// configured level cap without finding a plan.
	ErrMaxLevelsExceeded = errors.New(
		"max levels exceeded",
	)
)
View Source
var ErrNilFormula = errors.New("nil formula")

ErrNilFormula is returned when unmarshaling a JSON null into a Formula.

Functions

func MarshalFormula added in v0.2.2

func MarshalFormula(
	formula Formula,
) ([]byte, error)

MarshalFormula serializes a Formula to JSON using a discriminated-union envelope keyed by "type".

Types

type Action

type Action struct {
	Precondition Formula
	Effect       Formula
	Operator     string
	Args         []string
}

Action is a grounded operator with all parameters bound to concrete objects.

func GroundActions

func GroundActions(
	domain *Domain,
	objects []Object,
) []Action

GroundActions instantiates all operators with all type-compatible object bindings. It handles :equality constraints (neq) by filtering at grounding time.

func (*Action) IsNoOp

func (a *Action) IsNoOp() bool

IsNoOp returns true if this is a frame/no-op action that preserves a single proposition across time steps.

func (*Action) Key

func (a *Action) Key() string

Key returns a unique string key for map lookups.

func (*Action) String

func (a *Action) String() string

String returns the human-readable representation.

type AndFormula added in v0.2.2

type AndFormula struct {
	Children []Formula
}

AndFormula is a conjunction of sub-formulas.

type AtomFormula added in v0.2.2

type AtomFormula struct {
	Predicate string
	Args      []string
	Negated   bool
}

AtomFormula is an atomic predicate application.

func CollectAtoms added in v0.2.2

func CollectAtoms(f Formula) []*AtomFormula

CollectAtoms walks a formula tree depth-first and returns all *AtomFormula leaf nodes.

type Axiom added in v0.2.2

type Axiom struct {
	Body   Formula
	Head   Predicate
	Params []Parameter
}

Axiom defines a derived predicate whose truth is computed from a body formula.

func (Axiom) MarshalJSON added in v0.2.2

func (a Axiom) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler for Axiom.

func (*Axiom) UnmarshalJSON added in v0.2.2

func (a *Axiom) UnmarshalJSON(data []byte) error

UnmarshalJSON implements json.Unmarshaler for Axiom.

type Domain

type Domain struct {
	Name       string
	Types      []Type
	Predicates []Predicate
	Operators  []Operator
	Constants  []Object
	Axioms     []Axiom
}

Domain holds the complete planning domain definition.

type ExistsFormula added in v0.2.2

type ExistsFormula struct {
	Body     Formula
	Variable string
	Type     string
}

ExistsFormula is an existentially quantified formula.

type ForallFormula added in v0.2.2

type ForallFormula struct {
	Body     Formula
	Variable string
	Type     string
}

ForallFormula is a universally quantified formula.

type Formula added in v0.2.2

type Formula interface {
	// contains filtered or unexported methods
}

Formula represents a logical formula in preconditions or effects.

func PropsToFormula added in v0.2.2

func PropsToFormula(props []Proposition) Formula

PropsToFormula converts a flat proposition slice to a formula tree. Returns nil for empty input. A single proposition becomes an *AtomFormula; multiple propositions are wrapped in an *AndFormula.

func UnmarshalFormula added in v0.2.2

func UnmarshalFormula(
	data []byte,
) (Formula, error)

UnmarshalFormula deserializes JSON produced by MarshalFormula back into a Formula value. Returns ErrNilFormula when the input is JSON null.

type Graph

type Graph struct {
	// contains filtered or unexported fields
}

Graph is a directed, leveled planning graph alternating between proposition levels and action levels as described by Blum & Furst (1997).

func NewGraph

func NewGraph(prob *Problem) *Graph

NewGraph creates a planning graph with proposition level 0 containing the initial state. Negative propositions are seeded via the closed-world assumption for predicates used in negative preconditions.

func (*Graph) ActLevelSize

func (g *Graph) ActLevelSize(level int) int

ActLevelSize returns the number of actions at the given level.

func (*Graph) ActionsAreMutex

func (g *Graph) ActionsAreMutex(
	level int,
	actA, actB *Action,
) bool

ActionsAreMutex returns true if two actions are mutually exclusive at the given action level.

func (*Graph) Extend

func (g *Graph) Extend()

Extend adds one action level and one proposition level to the graph.

func (*Graph) GoalsReachable

func (g *Graph) GoalsReachable(
	goals []Proposition,
	level int,
) bool

GoalsReachable returns true if all goals exist at the given proposition level and no pair is mutex.

func (*Graph) HasProp

func (g *Graph) HasProp(
	level int,
	prop Proposition,
) bool

HasProp returns true if proposition prop exists at the given proposition level.

func (*Graph) Leveled

func (g *Graph) Leveled() bool

Leveled returns true if the last two proposition levels are identical (same props and same mutexes).

func (*Graph) NumPropLevels

func (g *Graph) NumPropLevels() int

NumPropLevels returns the number of proposition levels.

func (*Graph) PropLevelSize

func (g *Graph) PropLevelSize(level int) int

PropLevelSize returns the number of propositions at the given level.

func (*Graph) PropsAreMutex

func (g *Graph) PropsAreMutex(
	level int,
	prop, other Proposition,
) bool

PropsAreMutex returns true if two propositions are mutually exclusive at the given proposition level.

func (*Graph) Search

func (g *Graph) Search(
	goals []Proposition,
) ([]PlanStep, bool)

Search attempts to extract a valid plan from the current graph. Returns the plan steps and true if successful, or nil and false if no plan can be extracted. Uses backward-chaining with memoization.

type ImplyFormula added in v0.2.2

type ImplyFormula struct {
	Antecedent Formula
	Consequent Formula
}

ImplyFormula represents (imply A B), equivalent to (or (not A) B).

type Object

type Object struct {
	Name string
	Type string
}

Object is a typed object in the problem.

type Operator

type Operator struct {
	Precondition Formula
	Effect       Formula
	Name         string
	Parameters   []Parameter
}

Operator defines an operator template with typed parameters, a precondition formula, and an effect formula.

func (Operator) MarshalJSON added in v0.2.2

func (o Operator) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler for Operator.

func (*Operator) UnmarshalJSON added in v0.2.2

func (o *Operator) UnmarshalJSON(
	data []byte,
) error

UnmarshalJSON implements json.Unmarshaler for Operator.

type OrFormula added in v0.2.2

type OrFormula struct {
	Children []Formula
}

OrFormula is a disjunction of sub-formulas.

type Parameter

type Parameter struct {
	Name string // e.g. "?r"
	Type string // e.g. "rocket"
}

Parameter is a typed variable in an operator.

type PlanStep

type PlanStep struct {
	Actions []Action
	Time    int
}

PlanStep is one time step in the output plan, containing a set of non-interfering parallel actions.

type Predicate

type Predicate struct {
	Name       string
	ParamTypes []string
}

Predicate defines a predicate template with typed parameter slots.

type Problem

type Problem struct {
	Name         string
	Domain       *Domain
	Objects      []Object
	InitialState []Proposition
	Goals        []Proposition
}

Problem defines a planning problem: a domain, objects, initial state, and goal propositions.

type Proposition

type Proposition struct {
	Predicate string
	Args      []string
	Negated   bool
}

Proposition is a grounded predicate — fully instantiated with concrete objects. When Negated is true, it represents the absence of the fact (closed-world assumption).

func FormulaToProps added in v0.2.2

func FormulaToProps(f Formula) []Proposition

FormulaToProps extracts all atomic propositions from a formula tree by collecting atoms and converting each to a Proposition.

func GroundPredicates added in v0.2.0

func GroundPredicates(
	domain *Domain,
	objects []Object,
	predicateNames map[string]bool,
) []Proposition

GroundPredicates enumerates all type-compatible ground instances of the given predicates. It reuses buildTypeIndex and enumerateBindings to generate all valid argument combinations for each predicate.

func SplitEffects added in v0.2.2

func SplitEffects(
	f Formula,
) (adds, deletes []Proposition)

SplitEffects partitions a formula's atoms into add effects (Negated=false) and delete effects (Negated=true, returned with Negated=false).

func (Proposition) BaseKey added in v0.2.0

func (p Proposition) BaseKey() string

BaseKey returns the key without negation, useful for interference checks between positive and negative propositions.

func (Proposition) Key

func (p Proposition) Key() string

Key returns a unique string key for map lookups. Negated propositions are prefixed with "NOT-".

func (Proposition) Negate added in v0.2.0

func (p Proposition) Negate() Proposition

Negate returns a copy with Negated flipped.

func (Proposition) String

func (p Proposition) String() string

String returns the human-readable representation.

type Solver

type Solver struct {
	SolverConfig
}

Solver runs the Graphplan extend/search loop to find shortest parallel plans for STRIPS problems.

func NewSolver

func NewSolver(
	cfg *SolverConfig,
) (*Solver, error)

NewSolver creates a solver. A nil config uses defaults.

func (*Solver) Solve

func (s *Solver) Solve(
	prob *Problem,
) ([]PlanStep, error)

Solve finds the shortest parallel plan for the given problem. Returns ErrNoValidPlan if no plan exists, or ErrMaxLevelsExceeded if the level cap is hit.

type SolverConfig

type SolverConfig struct {
	// MaxLevels caps graph expansion. Nil means no limit.
	MaxLevels *int `json:"max_levels,omitempty" yaml:"max_levels"`
}

SolverConfig controls solver behavior.

func (*SolverConfig) Validate

func (c *SolverConfig) Validate() error

Validate checks that config values are semantically valid.

type Type

type Type struct {
	Name   string
	Parent string // empty for root type "object"
}

Type represents a PDDL type in the type hierarchy.

type WhenFormula added in v0.2.2

type WhenFormula struct {
	Condition Formula
	Effect    Formula
}

WhenFormula is a conditional effect. Valid only in effect context.

Directories

Path Synopsis
examples
rocket command
Command rocket demonstrates solving the rocket transport problem using the graphplan package.
Command rocket demonstrates solving the rocket transport problem using the graphplan package.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL