Rewrite-to-normal-form under a set of NCPO-LNF-oriented equations, restricted to rewrites that produce no variable bindings.
The variable-binding restriction (rigid tableau architecture)
ShotTx maintains a rigid-variable discipline: every branch-level
rule is forbidden from committing to a value for any free variable.
Free variables in branch formulas — γ-instantiation placeholders
(X_γ) and unification variables — must be reconciled globally
across sibling branches by ShotTx.Prover.ContradictionAgent, which
runs a CSP over all recorded clash options and finds a single
substitution satisfying every open branch's rigid-unification
requirement. If any branch-level rule locally committed to X_γ ↦ t,
it could:
- Close a branch using a σ inconsistent with the σ CA eventually chooses (unsoundness), or
- Force CA to solve a strictly harder problem because the local σ pre-emptively constrained the search (loss of completeness).
Neither is acceptable. This module therefore admits only rewrites
whose matcher σ is the empty substitution — i.e. the equation LHS
must be structurally identical (memoized term-id equal) to the
target subterm. No ShotUn.unify call, no σ, no commitment.
Head-position rewriting via primitive η-expansion equations
(λv̄. h(v̄) = rhs) is also binding-free: it structurally matches
the head declaration h and applies rhs to the existing arguments
via TF.fold_apply!. No free-variable substitution occurs.
What this rules out
The classical paramodulation case where equation f(X) = a rewrites
a subterm f(sk_b) via matcher σ = {X ↦ sk_b} is not performed
here — binding X (a γ-variable from the equation's ∀-quantifier)
is a local commitment to X's value on this branch. Users get such
rewrites only after γ produces the necessary instance and the
resulting concrete equation is added to branch.equations, or by
the Leibniz/extensional α-expansion — never as a shortcut by this
module.
Requirements this satisfies
- Soundness. Every rewrite replaces
L[s]withL[t]givens = t ∈ equationsandsstructurally identical to a subterm ofL. Substitutivity of equality; no σ involved. - No variable commitment. By construction — σ = ∅ throughout. The branch's residual free variables are unchanged.
- Termination. Every step is gated by
strict_gt?(s, t, order)(the paper's NCPO). By Theorem 2 of Niederhauser & Middeldorp (2025), a chain of such steps is dominated by a well-founded CPO⁺ chain; no infinite descent. - Determinism per session. Term-id equality and equation-map iteration order are both deterministic.
Requirements this does not satisfy
- Confluence. Not pursued (would require Knuth-Bendix completion, out of scope).
- Refutational completeness for equational reasoning. By design — the Leibniz/extensional α-expansion is the complete fallback. Demodulation is a canonicalization shortcut for the binding-free fragment.
Summary
Types
Equation map keyed by LHS term id, values are sets of possible RHSs.
Functions
Reduces term_id to its normal form under equations and order.
Types
@type equations() :: %{ required(ShotDs.Data.Term.term_id()) => MapSet.t(ShotDs.Data.Term.term_id()) }
Equation map keyed by LHS term id, values are sets of possible RHSs.
Functions
@spec normalize(ShotDs.Data.Term.term_id(), equations(), ShotTo.Parameters.t()) :: ShotDs.Data.Term.term_id()
Reduces term_id to its normal form under equations and order.
Guarantees:
- If no equation matches any subterm with an NCPO-strictly-decreasing
instance, returns
term_idunchanged. - Otherwise returns a term id
t'such thatterm_id →*_{R,order} t'and no further ordered rewrite applies tot'. - Termination is guaranteed by the paper's
(NCPO-LNF, CPO⁺)reduction-order argument (see module docs).
Empty equation map short-circuits to identity — used from the
insert_formula helper in ShotTx.Prover.Branch on the very first
formulas where no equations exist yet.