Skip to main content

Crate ferroplan

Crate ferroplan 

Source
Expand description

§ferroplan

A fast, data-parallel PDDL planner in Rust — a deterministic planning core for the age of AI. The engine is a delete-relaxation FF heuristic over a data-oriented (bitset / structure-of-arrays) task representation, with enforced hill-climbing + best-first fallback and parallel grounding / heuristic evaluation.

PDDL coverage: STRIPS, typing, ADL (conditional/forall effects, equality), numeric fluents, derived axioms, PDDL3 soft-goal preferences/metric, and PDDL2.1 temporal durative actions (constant / parameter-dependent durations, duration inequalities, timed initial literals). Plus an SGPlan-style partition-and-resolve mode.

§The public API (all serde-serializable)

  • solve — plan a domain + problem; returns a Solution (mode auto-detected).
  • decompose — split a temporal goal too big for one-shot search into ordered, individually-solved Contracts, stitched into one validated plan (Decomposition).
  • parse — syntax-check PDDL and summarize its structure (ParseReport) without grounding or solving — fast feedback for an authoring loop.
  • Session — ground once, replan many: hold a mutable world state (set_fact/set_fluent) and re-solve per tick paying only the search (~10x per-tick on small contracts) — the embedding API for games/simulations.
  • plan::validate_plan — independently check a plan under ferroplan’s semantics.

§Quick start

let domain = std::fs::read_to_string("domain.pddl").unwrap();
let problem = std::fs::read_to_string("problem.pddl").unwrap();

// Catch syntax mistakes before solving.
let report = ferroplan::parse(&domain);
assert!(report.ok, "{:?}", report.error);

let solution = ferroplan::solve(&domain, &problem, &ferroplan::Options::default()).unwrap();
if let Some(plan) = solution.plan {
    for step in &plan.steps { println!("{}", step.action); }
}

The lower-level text-rendering entry points (run_planner, run_ff) produce classic Metric-FF / IPC output and back the ff binary.

Re-exports§

pub use api::decompose;
pub use api::parse;
pub use api::solve;
pub use api::Contract;
pub use api::Decomposition;
pub use api::DomainSummary;
pub use api::Metric;
pub use api::Mode;
pub use api::Options;
pub use api::ParseReport;
pub use api::Plan;
pub use api::ProblemSummary;
pub use api::Search;
pub use api::Solution;
pub use api::SolveError;
pub use api::Statistics;
pub use api::Step;
pub use planner::run_ff;
pub use planner::run_planner;
pub use session::Session;
pub use trace::trace;
pub use trace::StateSnapshot;
pub use types::ParseError;

Modules§

api
The smart, serde-serializable public API.
bitset
Fixed-width bit set over u64 words — the fact layer of a state. Word-oriented so applicability/apply are tight bitwise loops and states are compact for hashing/dedup in parallel search.
constraints
PDDL3 trajectory-constraint ENFORCEMENT (0.7, docs/roadmap-0.7.md).
derived
Derived predicates (:derived axioms), compiled away before grounding.
espc
ESPC — Extended Saddle-Point Condition penalty-resolution outer loop.
features
Process-global overrides for the env-gated planner features.
ground
Grounding into the data-oriented PackedTask.
hash
In-tree FxHash — a fast, deterministic hasher (the rustc-hash algorithm), so we drop SipHash for the hot visited-set and the grounding interner without a dependency. Deterministic: no random seed, so results are reproducible and thread-count-independent (bucket layout never affects the search order, which is driven by the heap, not set iteration).
heuristic
FF relaxed-plan heuristic over the packed task, allocation-free on the hot path: all working buffers live in a reusable Scratch that a worker thread creates once and resets per evaluation (cleared, never re-allocated). This removes the per-state allocation churn — and the global-allocator contention it caused across worker threads — which was the main limit on both raw speed and parallel scaling.
invariants
Mutex-group synthesis: Helmert-style monotonicity invariants (multi-predicate).
lexer
Hand-written PDDL tokenizer (mirrors lex-ops_pddl.l / lex-fct_pddl.l).
output
Output formatting. The plan block, the unsolvable/trivial messages, and the exit codes match Metric-FF (and metricff) so this binary is a drop-in: the planner crate’s regex and the differential harness consume it unchanged. The search-configuration / progress lines honestly reflect the parallel engine.
packed
Data-oriented grounded task (Structure-of-Arrays / CSR) and bitset state.
par
Minimal data-parallel primitives over std::thread::scope (no external deps). The thread count comes from FFDP_THREADS (if set) else available cores; threads <= 1 falls back to a plain sequential map, so behaviour is deterministic regardless of parallelism.
parser
Recursive-descent parser for the PDDL subset Metric-FF accepts. Mirrors scan-ops_pddl.y (domain) and scan-fct_pddl.y (problem).
partition
Goal partitioning.
pddl3
PDDL3.0 soft-goal preferences + metric optimization (phase 1).
plan
Built-in plan validator — check a plan against ferroplan’s OWN semantics.
planner
report
Output rendering. Default = classic Metric-FF format (drop-in for the planner crate + the differential validator); -ipc = SGPlan6’s IPC temporal format.
resolve
Partition-and-resolve control loop (the SGPlan core, adapted to numeric STRIPS — see docs/sgplan6-spec.md §5,§9).
resource
Renewable “counter” resource detection for resource-aware search guidance.
search
Data-parallel weighted best-first search.
selection
Exact preference-subset SELECTION for the PDDL3 metric path.
session
Ground once, replan many — the embedding API for callers that re-solve the same world every tick (a game’s villagers, a simulation loop, an agent runtime).
temporal
PDDL2.1 temporal planning — durative actions (EPIC-Temporal).
trace
Plan trace: replay a plan and capture the world state before the first action and after every action — the instrumentation a UI needs to animate a plan. Mirrors crate::verify’s replay loop but snapshots each intermediate state. Classic/numeric/PDDL3 plans (a sequential op list) only; temporal plans (overlapping durative actions) are not replayed this way.
tresolve
Temporal partition-and-resolve decomposer (Phase B) — the SGPlan partition loop (crate::resolve) brought to the durative/numeric path, gated by FF_TDECOMP.
tsched
Concurrent scheduling phase for temporal plans.
types
AST (parser output) and the numeric intermediate representation shared by grounding and the heuristic. The grounded representation is data-oriented and lives in packed.rs.
verify
Independent PDDL3 plan/metric verifier (conformance oracle).
viz
Visualization model: derive an abstract graph from a parsed domain + problem, plus helpers a GUI needs (per-snapshot positions, PDDL generation). This is pure, view-agnostic logic — no GUI/layout types — so any front-end (Bevy, egui, web) can consume it.