Skip to content

feat(wam-c): T9 fact-table inline (backtrackable, default in-range, capped) - #3300

Open
s243a wants to merge 1 commit into
mainfrom
claude/c-t9-fact-table
Open

feat(wam-c): T9 fact-table inline (backtrackable, default in-range, capped)#3300
s243a wants to merge 1 commit into
mainfrom
claude/c-t9-fact-table

Conversation

@s243a

@s243a s243a commented Jun 21, 2026

Copy link
Copy Markdown
Owner

What

Brings T9 fact-table inline to the C WAM target (after Rust and F#).

Key difference from the other targets: C already had a static row table + first-arg bucket index + a per-row unify scan — but the scan was deterministic (returned only the first matching row, so edge(a,X) over multiple a facts yielded just one solution). T9 makes the in-window fact lowering backtrackable so every matching row is enumerated, and adds the t9 window / opt-out / oversized policy around it.

Policy (mirrors Rust/F#)

An all-ground-facts predicate (arity ≥ 1) whose row count is in [t9_min_rows, t9_max_rows] (defaults 64..256) lowers to the backtrackable fact-table handler by default. Opt out with fact_table_inline(false); below t9_min_rows keeps the cheap deterministic scanner; above t9_max_rows declines + warns (steer to an external fact source).

Mechanism (mirrors the runtime's disjunction side-stack choice point)

  • Runtime (wam_runtime.h): a WAM_FACT_TABLE_RETRY sentinel; a WamFactTableFrame side-stack (flattened row-table pointer + candidate index array + position + arity + return PC) saved/restored/pruned alongside disj_top in the ChoicePoint; a shared static inline wam_fact_table_scan that, on a match, leaves a choice point for the remaining candidates before binding so backtracking yields the next row. wam_run dispatches WAM_FACT_TABLE_RETRYwam_resume_fact_table. (Made the scan a header static inline so both the generated handlers and the resume function can call it across translation units.)
  • Emitter (wam_c_target.pl): wam_c_fact_table_classify + thresholds + wam_c_maybe_warn_oversized_facts; a fact_table(Rows) plan gated ahead of the deterministic fact_only branch in plan_wam_c_lowered_helper (Options now threaded through the planner); wam_c_fact_table_helper_for_predicate reuses the existing row table + bucket index and emits a handler that derefs the first arg, picks the bucket (or full scan) and drives wam_fact_table_scan. Registered through the same foreign-predicate path as today's facts, so it's reachable as a query and from another predicate with zero dispatch changes.

Tests

  • tests/test_wam_c_fact_table_exec.pl (gcc-gated): builds a project and a C driver that enumerates all solutions per arg mode by forcing backtracking (a collect/2 foreign that records bindings and fails). Verifies (+,-) index lookup → [1,2,4] in source order, (-,+) value-bound scan → [b], (-,-) → all 6, (+,+) membership, and absent-key → 0. ALL 6 PASS (exit-code assertions).
  • tests/test_wam_c_fact_table_emit.pl (fast): planner gating (default→fact_table, opt-out/below-min/above-cap→fact_only), oversized warning, classifier, emitted scan + row table + bucket switch, value literals.
  • Existing C target suite stays green (0 failures — the shared header + planner changes don't regress).

Matrix: adds a c row (the matrix previously had none), T9 = ✓ capped.

🤖 Generated with Claude Code

https://claude.ai/code/session_013gLfigNMgCkxybbp7m6fXw


Generated by Claude Code

…apped)

Brings the Rust/F# T9 fact-table work to the C WAM target. The C target already
emitted a static row table + first-arg bucket index, but its scan was
deterministic (returned only the first matching row). T9 makes the in-window
fact lowering backtrackable so every matching row is enumerated, and adds the
t9 window / opt-out / oversized semantics around it.

Policy (mirrors Rust/F#): an all-ground-facts predicate (arity >= 1) whose row
count is in [t9_min_rows, t9_max_rows] (defaults 64..256) lowers to the
backtrackable fact-table handler by default. Opt out with
fact_table_inline(false); below t9_min_rows keeps the cheap deterministic
scanner; above t9_max_rows declines + warns (steer to an external fact source).

Mechanism (mirrors the runtime's disjunction side-stack CP):
- Runtime (wam_runtime.h): WAM_FACT_TABLE_RETRY sentinel; WamFactTableFrame
  side-stack (flattened row table ptr + candidate indices + pos + arity +
  return_pc) saved/restored/pruned alongside disj_top in the ChoicePoint; a
  shared static-inline wam_fact_table_scan that, on a match, leaves a choice
  point for the remaining candidates before binding, so backtracking yields the
  next row. wam_run dispatches WAM_FACT_TABLE_RETRY to wam_resume_fact_table.
- Emitter (wam_c_target.pl): wam_c_fact_table_classify + thresholds +
  wam_c_maybe_warn_oversized_facts; a fact_table(Rows) plan gated ahead of the
  deterministic fact_only branch in plan_wam_c_lowered_helper (Options now
  threaded through); wam_c_fact_table_helper_for_predicate emits the row table +
  bucket index (reused) and a handler that derefs the first arg, picks the
  bucket (or full scan) and drives wam_fact_table_scan. Registered as a foreign
  predicate, so it is reachable as a query and from another predicate unchanged.

Tests: test_wam_c_fact_table_exec.pl (gcc-gated; query-mode matrix
(+,-)/(-,+)/(-,-)/(+,+)/absent-key enumerated by forcing backtracking ->
ALL 6 PASS) and test_wam_c_fact_table_emit.pl (planner gating, opt-out,
below-min, above-cap+warning, value literals, emitted scan). Existing C target
suite stays green. Matrix: add a `c` row, T9 ✓ capped.

https://claude.ai/code/session_013gLfigNMgCkxybbp7m6fXw
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant