meta-log-db
Version:
Native database package for Meta-Log (ProLog, DataLog, R5RS)
181 lines • 5.68 kB
JavaScript
;
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