/** * Flattened, data-oriented execution IR for first-order logic formulas. * * The hot-path representation stores formulas in parallel typed arrays * indexed by formulaId. No deep nesting exists at runtime; child * relationships are expressed through numeric offsets into the same * flat tables. * * Invariant: every formula referenced by a child pointer is stored in * the same LogicIr instance. The root formula always has id 0. */ import type { ImhotepId, SourceOrigin } from './types.js' // --------------------------------------------------------------------------- // Formula Kinds (must fit in Uint8) // --------------------------------------------------------------------------- export const FORMULA_KIND_FORALL = 1 export const FORMULA_KIND_EXISTS = 2 export const FORMULA_KIND_AND = 3 export const FORMULA_KIND_OR = 4 export const FORMULA_KIND_NOT = 5 export const FORMULA_KIND_IMPLIES = 6 export const FORMULA_KIND_PREDICATE = 7 export type FormulaKind = | typeof FORMULA_KIND_FORALL | typeof FORMULA_KIND_EXISTS | typeof FORMULA_KIND_AND | typeof FORMULA_KIND_OR | typeof FORMULA_KIND_NOT | typeof FORMULA_KIND_IMPLIES | typeof FORMULA_KIND_PREDICATE // --------------------------------------------------------------------------- // Logic IR Tables // --------------------------------------------------------------------------- export interface LogicIr { /** Total number of formulas in this IR. */ formulaCount: number // Formula classification (all Uint8Array) formulaKind: Uint8Array // Child pointers (Uint32Array, 0xFFFFFFFF means "none") formulaLeft: Uint32Array formulaRight: Uint32Array // Binding region (for quantifiers) // Each quantifier formula references a slice [bindingStart, bindingStart + bindingCount) // in the flat binding table below. bindingStart: Uint32Array bindingCount: Uint8Array // Predicate call region (for atomic formulas) // Each predicate formula references a slice [argStart, argStart + argCount) predicateId: Uint32Array argStart: Uint32Array argCount: Uint8Array // Origin and proof tracking (Uint32Array) originIndex: Uint32Array } // --------------------------------------------------------------------------- // Flat Binding Table // --------------------------------------------------------------------------- export interface BindingTable { /** Number of bindings. */ count: number // Variable names (string table index) variableNameId: Uint32Array // Domain descriptor index domainId: Uint32Array } // --------------------------------------------------------------------------- // Flat Argument Table (for predicate calls) // --------------------------------------------------------------------------- export interface ArgTable { /** Number of argument terms. */ count: number // Term kind: 1 = variable, 2 = accessor, 3 = literal number termKind: Uint8Array // For variables: binding table index // For accessors: variable binding index // For literals: 0xFFFFFFFF (value stored in literalValue) termRef: Uint32Array // For accessors: string table index of property name // For literals: the literal numeric value (reinterpreted as Uint32) termAux: Uint32Array } // --------------------------------------------------------------------------- // Predicate Registry Index // --------------------------------------------------------------------------- export interface PredicateIndexEntry { predicateId: number name: string arity: number domainSignature: number[] requiredFacts: string[] } export interface PredicateIndex { entries: PredicateIndexEntry[] byName: Map } // --------------------------------------------------------------------------- // String Table (shared across IR tables) // --------------------------------------------------------------------------- export interface IrStringTable { values: string[] byValue: Map } // --------------------------------------------------------------------------- // Evaluation Request // --------------------------------------------------------------------------- export interface LogicEvaluationRequest { logicIr: LogicIr bindings: BindingTable args: ArgTable predicates: PredicateIndex strings: IrStringTable rootFormulaId: number } // --------------------------------------------------------------------------- // Builder // --------------------------------------------------------------------------- export interface LogicIrBuilder { addFormula(descriptor: LogicFormulaDescriptor): number addBinding(descriptor: LogicBindingDescriptor): number addArg(descriptor: LogicArgDescriptor): number build(): LogicIr } export interface LogicFormulaDescriptor { kind: FormulaKind left?: number right?: number bindingStart?: number bindingCount?: number predicateId?: number argStart?: number argCount?: number originIndex?: number } export interface LogicBindingDescriptor { variableNameId: number domainId: number } export interface LogicArgDescriptor { termKind: number termRef: number termAux: number } // --------------------------------------------------------------------------- // Helper: Create empty Logic IR // --------------------------------------------------------------------------- export function createEmptyLogicIr(): LogicIr { return { formulaCount: 0, formulaKind: new Uint8Array(0), formulaLeft: new Uint32Array(0), formulaRight: new Uint32Array(0), bindingStart: new Uint32Array(0), bindingCount: new Uint8Array(0), predicateId: new Uint32Array(0), argStart: new Uint32Array(0), argCount: new Uint8Array(0), originIndex: new Uint32Array(0), } } export function createEmptyBindingTable(): BindingTable { return { count: 0, variableNameId: new Uint32Array(0), domainId: new Uint32Array(0), } } export function createEmptyArgTable(): ArgTable { return { count: 0, termKind: new Uint8Array(0), termRef: new Uint32Array(0), termAux: new Uint32Array(0), } } export function createEmptyStringTable(): IrStringTable { return { values: [], byValue: new Map(), } } // --------------------------------------------------------------------------- // Helper: Intern a string into the string table // --------------------------------------------------------------------------- export function internString(table: IrStringTable, value: string): number { const existing = table.byValue.get(value) if (existing !== undefined) { return existing } const id = table.values.length table.values.push(value) table.byValue.set(value, id) return id }