Files
Imhotep/packages/imhotep-core/src/logic-ir.ts
T

233 lines
6.5 KiB
TypeScript
Raw Normal View History

/**
* 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, number>
}
// ---------------------------------------------------------------------------
// String Table (shared across IR tables)
// ---------------------------------------------------------------------------
export interface IrStringTable {
values: string[]
byValue: Map<string, number>
}
// ---------------------------------------------------------------------------
// 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
}