Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Tuning & environment knobs

ferroplan's defaults are chosen so that a plain ff -o domain -f problem is the measured-best path — you should rarely need any of these. When you do, every knob is an environment variable, read at solve time. Reads are panic-free on wasm32; the boolean features additionally have in-process overrides in ferroplan::features (set_overrides, set_escalate_override, set_espc_override) for WASM/embedded callers, where std::env::set_var panics.

Almost every knob is a restore hatch: it exists to reproduce an earlier behavior or to run an experiment, and the default is the recommended setting. All results are deterministic and thread-count independent.

Budgets — the wall and the memory

A budget is declared, never imposed: ferroplan does not kill itself. It reads what the caller (or the caller's runner) will enforce and arranges to be finished first. Per call, in code, the same two ideas are Options::wall_ms and Options::should_continue.

variabledefaulteffect
FF_TIME_LIMITunsetthe process's REAL wall budget in seconds — see Classical search for the ladder gate it arms. Since 0.28 it also bounds everything done to a plan ALREADY in hand.
FF_REPORT_RESERVE_SECS3 % of the wall (0.5–3 s) + a size termhow far short of the wall optional work on a found plan stops — the quality chases, the preference scorer, the PDDL3 optimizer over its seed — so the plan is reported before a runner that kills AT the wall fires (0.28).
FF_MEM_BUDGET_GBunsetthe retained-memory budget in GiB (fractional ok) the caller will enforce. It sizes the modelled node caps, and since 0.28 it is also MEASURED: the engine reads its own resident size (/proc/self/status; task_info on macOS).
FF_NO_MEM_WALLwall ondisable the 0.28 measured memory wall. With it, bounded work — a chase over a banked plan, the grounding that would price or score a plan already found, a rung's bet — stops at 75 % of FF_MEM_BUDGET_GB and returns what was banked; a trip is sticky for that scope. A first search, with nothing to fall back on, is never cut by it.
FF_MEM_TRIP_FRAC0.75move that line — for measuring it (0.85 was measured: nothing solves or scores better, and one board instance peaks at 5.97 GB of 6).
FF_EHC_WALL_FRAC0.25the fraction of the remaining wall EHC may spend before handing down the ladder. FF_NO_EHC_WALLCAP=1 removes the slice.
FF_NO_RUNG_WALLCAPcheckpoints onturn OFF the clock checkpoints inside the bounded rungs, best-first batches and grounding (the 0.21 shapes — a run can then overrun its wall; kept as the permanent RED record).
FF_WALL_DEBUG / FF_GROUND_PHASESoffnarrate every wall and memory decision / every grounding phase with its elapsed time on stderr. Probe eyes; never affect the search.

Temporal

vardefaulteffect
FF_TDEMANDnumeric-onlyforce the Full demand tier (also seed demand from predicate-goal thresholds) first, for conjunctive/structural builds.
FF_NO_TDEMAND—master switch to the pristine pre-v0.2 path: no demand guidance, no relevance pruning, no escalation.
FF_NOREL—disable goal-relevance pruning alone (keep demand guidance).
FF_NO_ESCALATEladder ondisable the on-failure escalation ladder (retry Full tier, then decomposer). Only affects would-be failures.
FF_TDECOMPoffroute the temporal path through the partition-and-resolve decomposer first (the decompose API always does, regardless).
FF_TCONCoffrun the concurrent scheduling phase — repack a plan onto actor objects to minimize makespan.
FF_TDEMAND_W3weight of the temporal demand seed.
FF_NO_TSYMMsymmetry ondisable the 0.13 pending-interval symmetry reduction (canonical agenda order + redundant identical-interval elimination). The restore hatch for its one named corpus casualty (parking-2011 #16).
FF_TEMPORAL_NODE_CAPbyte modeloverride the deterministic temporal stored-node cap directly (0 disables; default derives from the memory target and static task dims).
FF_TEMPORAL_ABS_KEYrelativerestore ABSOLUTE agenda times in the visited key on TIL-free tasks (the pre-0.10 behavior; relative keying dedups retimed permutations).
FF_TLAMAoffexperimental: the temporal LAMA rung (fact-landmark-dominant key). Measured negative — snap-task landmarks are RUNNING-token chains with no branching signal.
FF_LAX_HELPFULoffexperimental: re-arm empty temporal helpful sets with a lax fallback instead of a full scan. Measured zero new solves.
FF_TAGENDA_W0experimental: complete-pass agenda-size ordering term (de-prioritize interval hoarding). Measured negative on parc-printer-t.
FF_NO_FIXPOINT_GROUNDfixpoint (Session)make the Session's temporal entry use stratified grounding instead of reached-restricted fixpoint grounding (the ~117× transient-memory win on sparse-reachable worlds). Corpus/CLI paths always use stratified — their tie-breaks pin the scoreboard baselines.
FF_NO_ORBITorbits ondisable object-symmetry orbit detection (0.14): goal-respecting member permutations canonicalize the temporal visited key, collapsing states that differ only by relabeling interchangeable objects/goal pairs (machine-shop's wall; rescues turn-and-open under the sound invariant semantics).
FF_ORBIT_DEBUGoffnarrate orbit detection (candidate groups, bail reasons) and per-solve eval counts on stderr — the probe eyes, never affects the search.
FF_ORBIT_GENoffexperimental: generation-side stabilizer skipping (0.15): with orbits detected, an op whose state-fixing member swap maps it to an already-generated sibling is never generated (TMS: 2.4× real evals at equal budget; duplicates 81% → 53% — but zero new solves, since TMS's wall is the start-credit plateau, not throughput). The 0.15 sweep referee flipped it opt-in: the per-expansion stabilizer scan cost match-cellar 9 solved instances. The canonical-key pre-dedup stays default-on.
FF_TLIFOoffexperimental: LIFO tie-breaking at equal temporal keys. Measured WORSE on the TMS plateau (best_h 150 vs 110) — dives a high-h corridor.
FF_TB_FREE_Goffexperimental: don't charge g for time-advance successors. Measured WORSE on TMS (best_h 196) — rides time forward, wasting windows.
FF_TAGENDA_W_PRUNE0experimental: the agenda-size term on the PRUNED pass (start-credit counter-account). Measured worse on TMS (best_h 173) though it does push the search deep enough for window blocking to engage.
FF_NO_TCOMPRESSrung ondisable the 0.28 compression rung (plan a concurrency-free temporal task as a classical one, left-shift it onto the clock, validate against the original). Restores the 0.27 route.
FF_TCOMPRESS_WALL_FRAC / FF_TCOMPRESS_CHASE_FRAC0.25 / 0.25the share of the remaining wall the compression rung may bet, and the share the decision-epoch makespan chase gets after it banks. Unwalled, the bet is capped at 2,000 evaluations per classical rung instead.
FF_NO_TSUCCgenerator onrestore the full operator scan in temporal expansion. 0.28 wired the anchored successor generator (0.27's classical lever) into the temporal rung; it is byte-identical by construction and, measured, removes a 0.01–7.7 % term — the relaxed planning graph is the other 92–99 %. Kept for exactly that kind of measurement.
FF_TEVAL_BUDGETunlimitedcap CLI temporal search evaluations — the deterministic measuring stick for A/B probes (eval budgets, never wall clock).

Classical search (experiments & restore hatches)

vardefaulteffect
FF_NOVELTYautothe width-1 BFWS-style novelty rung (0.17) — a third bounded classical rung after EHC and LAMA fail, open list ordered by state novelty then h. 0.19: DEFAULT-ON when FF_TIME_LIMIT is declared and >40% of the budget remains (the 0.18 gated referee measured +4/−0, reversing 0.17's ungated +7/−51 tax); FF_NO_NOVELTY=1 opts out, FF_NOVELTY=1 forces it without a budget. No budget declared ⇒ rung off, byte-identical ladder. FF_NOVELTY_ONLY=1 probes the rung alone.
FF_TIME_LIMITunsetthe process's REAL wall budget in seconds (0.18 budget-aware ladder). The clock arms at solve entry (grounding counts as spent budget); a bounded rung (LAMA, novelty) is entered only while more than 40% of the budget remains, so late-ladder rungs stop starving the complete fallback near the budget edge — the mechanism behind the novelty referee's −51. Unset = all-rungs behavior, byte-identical to 0.17. benchmarks/ipc67.py passes its per-instance --timeout automatically. Informational, never kills the process. FF_WALL_DEBUG=1 narrates the gate's verdict on stderr (the probe eyes, never affects the search).
FF_NO_NEED_DIRSdirection-awarerestore the 0.27 relaxed-graph fixpoint test, which counted ANY numeric bound movement as progress — a consumable's un-read lower bound drifting down sent every dead-end evaluation to the 2,000-layer cap. Heuristic values are identical either way; only the cost of proving a dead end changes (~78× evaluations per second on rovers-metric-time shapes).
FF_HTRACEoffprint the classical best-first best_h trace (evaluation count and seconds at each improvement) on stderr.
FF_NO_DNF_STATICresolvedisable static resolution inside precondition DNF expansion (restore the 2^k imply blowup the 0.10 fix removed — openstacks-ADL 6/30 → 30/30).
FF_NO_TRAJ_ENDend-actionrestore the exponential goal-DNF construction for hard trajectory monitors (pre-0.8).
FF_CLMoffexperimental: classical landmark-count guidance term. Measured negative (transport unchanged, floor-tile worse).
FF_LEN_ANYTIMEoffexperimental: keep draining the open list after the first plan, returning the shortest found. Measured −9 coverage at 60 s; opt-in only.
FF_LEN_SWEEP_EVALSoffexperimental: iterated-weight anytime re-sweeps for unit-cost plan length (~1.8% shorter at ~28× evals).

PDDL3 preference optimizer

The default path is the exact-closure metric optimizer; these restore its predecessor pieces or tune its budget.

vardefaulteffect
FF_PREF_EVAL_BUDGET2000000deterministic per-solve eval budget — the real quality dial. Higher = more optimization time on hard instances.
FF_PREF_NO_ESCALATEescalatedisable the budget-escalating retry (abandon a probe on its first capped iteration).
FF_PREF_GREEDYanytimerestore first-improvement sweeps: return at the first plan under the bound and restart, instead of tightening the bound in place and draining the sweep.
FF_PREF_NO_RESTARTSladder ondisable the diversified restart ladder (rotated open-list weight profiles on a capped no-improvement sweep) — the lever behind the storage p06/p07 and pathways p05 wins.
FF_PREF_NO_SEEDseed ondisable 0.28's incumbent zero — the hard-goal plan handed to the optimizer as a floor, and returned (with a note) when nothing cheaper was found. Restores 0.27, where such a run reported solved: false.
FF_PREF_SEED_BOUNDfloor onlyalso OPEN the branch-and-bound with the seed's metric as its first bound (off by default: the seed is a floor, not a bound, so the optimizer's own search is byte-identical to 0.27's).
FF_PREF_SEED_WALL_FRAC / FF_PREF_SEED_EHC_FRAC1.0 / 0.6the share of the remaining wall the hard-goal search may use, and EHC's share of THAT.
FF_PREF_SEEDoffexperimental: forgo-aware second seed — price each preference's completion with a cost-aware relaxed plan and pre-forgo those priced over their weight. Measured neutral on rovers (the EHC seed already lands there).
FF_PREF_SEED3offexperimental: partitioned closure seed — compose a per-preference-component incumbent (mutex-conflict-pruned, sibling-protected stages) before the tightening loop. Composes genuinely (tpp p05: 99 vs the 105 init-tail) but measured neutral on finals: the anytime+ladder loop reaches the same metric from either bound.
FF_PREF_NO_SELECTselect ondisable the 0.6 selection layer (exact preference-subset selection solved combinatorially, then planned as a hard-goal target; docs/forensics-tpp.md). Selection is what ties SGPlan5 on tpp p06 and widened the rovers totals lead; its bounded seed runs outside the tightening budget.
FF_PREF_NO_STATICsimplifydisable static preference simplification at compile (keep statically-satisfied instances).
FF_PREF_NO_BARRIERbarrier onexclude init-satisfied preferences from the guidance (the 0.4–0.5.0 behavior). Keeping them (the 0.5.1 default) protects high-weight trap preferences — the storage 8/8 sweep — see docs/forensics-tpp.md. FF_PREF_BARRIER is accepted, now redundant.
FF_PREF_COMPILEDclosureroute through the legacy compiled-goal B&B instead of the exact-closure optimizer.
FF_PREF_NUMLEGACYclosurefolded numeric metrics only (rovers-shaped): restore the pre-0.5 routing to the legacy B&B. The closure path now dominates it (rovers flipped to a domain lead).
FF_PREF_COST_WEIGHTdomain-dependentcost-aware open-list weight (SearchCfg::w_c). Experimental — a measured dead end on rovers; default 0 there.
FF_RES_WEIGHT / FF_RES_THRESHtuned / 0satisfaction-guidance resource penalty weight / threshold.
FF_DEADLINE_WEIGHT0extra penalty on deadline-pair triggers in satisfaction guidance.
FF_RES_DEBUG—print resource/preference simplification diagnostics.

ESPC penalty loop (default-on where it bites)

The extended-saddle-point penalty loop for resource-coupled preference domains (openstacks-shaped). On by default since 0.5, with a deterministic evaluated-state budget; it engages only when the compiled task carries once-only conditional-achievement deadline pairs — on every other task it is a verified no-op.

vardefaulteffect
FF_NO_ESPCespc onopt out — restore the closure-optimizer-only default path.
FF_ESPC_EVAL_BUDGET6000000deterministic eval pool for the loop (λ iterations + polish) — the primary budget contract, thread-count independent.
FF_ESPC_TIME_MSunsetoptional additional wall-clock cap for interactive use. Applies only when set; setting it trades determinism for latency.
FF_ESPC_MONOpartitionedreproduce the earlier monolithic (pre-0.4.0) loop.
FF_ESPC—accepted for compatibility (pre-0.5 opt-in); redundant now.

Advanced ESPC schedule tuning (rarely needed): FF_ESPC_OUTER (outer iterations), FF_ESPC_RATE (initial penalty rate, 20), FF_ESPC_K (consecutive-violation rate bump, 2), FF_ESPC_LAMBDA0 (initial λ, 0), FF_ESPC_STALL (stall limit before termination, 4).

PDDL3 trajectory constraints

vardefaulteffect
FF_CONSTRAINTS_REJECTenforcerestore the 0.4.1–0.6 blanket rejection of every (:constraints ...) block, instead of compiling the untimed operators into enforced monitor automata (0.7) — hard constraints as goal conjuncts, soft (preference ...) constraints priced through the PDDL3 metric machinery. The hatch restores rejection, not ignoring — no setting makes ferroplan silently drop a constraint.

Reproducing a specific benchmark

The IPC-5 scoreboard records the exact env for each domain — e.g. openstacks's domain lead is FF_ESPC=1 FF_ESPC_TIME_MS=90000.