UNPKG

meta-log-db

Version:

Native database package for Meta-Log (ProLog, DataLog, R5RS)

181 lines 5.68 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FixedPoint = void 0; /** * Fixed-point computation for DataLog */ class FixedPoint { /** * Compute fixed point of a DataLog program */ static compute(program) { let facts = new Set(this.factsToStrings(program.facts)); let previousSize = 0; let iterations = 0; const maxIterations = 1000; while (facts.size !== previousSize && iterations < maxIterations) { previousSize = facts.size; // Apply all rules for (const rule of program.rules) { const newFacts = this.applyRule(rule, Array.from(facts).map(s => this.stringToFact(s))); for (const fact of newFacts) { facts.add(this.factToString(fact)); } } iterations++; } return Array.from(facts).map(s => this.stringToFact(s)); } /** * Apply a rule to generate new facts */ static applyRule(rule, facts) { const newFacts = []; // Match body predicates against facts const bodyMatches = this.matchBody(rule.body, facts); // Generate head facts for each match for (const match of bodyMatches) { const headFact = this.instantiateHead(rule.head, match); if (headFact) { newFacts.push(headFact); } } return newFacts; } /** * Match body predicates against facts */ static matchBody(body, facts) { if (body.length === 0) { return [new Map()]; } const [firstPred, ...restPreds] = body; const firstMatches = this.matchPredicate(firstPred, facts); const allMatches = []; for (const match of firstMatches) { const restMatches = this.matchBody(restPreds, facts); for (const restMatch of restMatches) { const merged = this.mergeMatches(match, restMatch); if (merged) { allMatches.push(merged); } } } return allMatches; } /** * Match a predicate against facts */ static matchPredicate(predicate, facts) { const matches = []; const parsed = this.parsePredicate(predicate); for (const fact of facts) { if (fact.predicate === parsed.predicate) { const match = this.matchArgs(parsed.args, fact.args); if (match) { matches.push(match); } } } return matches; } /** * Match arguments (with variable binding) */ static matchArgs(patternArgs, factArgs) { if (patternArgs.length !== factArgs.length) { return null; } const bindings = new Map(); for (let i = 0; i < patternArgs.length; i++) { const pattern = patternArgs[i]; const fact = factArgs[i]; if (pattern.startsWith('?')) { // Variable const existing = bindings.get(pattern); if (existing !== undefined && existing !== fact) { return null; } bindings.set(pattern, fact); } else if (pattern !== fact.toString()) { // Constant doesn't match return null; } } return bindings; } /** * Instantiate head with bindings */ static instantiateHead(head, bindings) { const parsed = this.parsePredicate(head); const args = []; for (const arg of parsed.args) { if (arg.startsWith('?')) { const value = bindings.get(arg); if (value === undefined) { return null; } args.push(value); } else { args.push(arg); } } return { predicate: parsed.predicate, args }; } /** * Parse predicate string */ static parsePredicate(predStr) { const match = predStr.match(/^(\w+)\((.*)\)$/); if (match) { const predicate = match[1]; const argsStr = match[2]; const args = argsStr ? argsStr.split(',').map(s => s.trim()) : []; return { predicate, args }; } return { predicate: predStr, args: [] }; } /** * Merge two match bindings */ static mergeMatches(match1, match2) { const merged = new Map(match1); for (const [key, value] of match2) { const existing = merged.get(key); if (existing !== undefined && existing !== value) { return null; } merged.set(key, value); } return merged; } /** * Convert fact to string for set operations */ static factToString(fact) { return `${fact.predicate}(${fact.args.join(',')})`; } /** * Convert facts to strings */ static factsToStrings(facts) { return facts.map(f => this.factToString(f)); } /** * Convert string back to fact */ static stringToFact(str) { const match = str.match(/^(\w+)\((.*)\)$/); if (match) { const predicate = match[1]; const args = match[2] ? match[2].split(',').map(s => s.trim()) : []; return { predicate, args }; } return { predicate: str, args: [] }; } } exports.FixedPoint = FixedPoint; //# sourceMappingURL=fixed-point.js.map