j6
Version:
Javascript scientific library (like R, NumPy, Matlab)
128 lines (116 loc) • 2.8 kB
JavaScript
module.exports = function (j6) {
var fs = require('fs');
var log = console.log;
j6.kb = function() {
this.rules = [];
this.facts = {};
this.dict = {};
}
var kbp = kb.prototype;
kbp.load = function(code) {
var lines = code.split(/[\.]+ ?/);
log("%j", lines);
for (var i in lines) {
if (lines[i].trim().length > 0)
this.addRule(lines[i]);
}
return this;
}
kbp.loadFile = function(file) {
var code = fs.readFileSync(process.cwd()+"/"+file, "utf8").replace(/\n/gi, "");
this.load(code);
return this;
}
kbp.isFact=function(term) {
if (term.length == 0)
return true;
return this.facts[term];
}
kbp.check = function(rule) {
for (var i in rule.terms) {
var term = rule.terms[i].trim();
if (this.isFact(term))
continue;
else
return false;
}
return true;
}
kbp.addFact = function(term) {
this.facts[term] = true;
log("addFact(%s)", term);
}
kbp.addRule = function(line) {
var m = line.match(/^([^<=]*)(<=(.*))?$/);
var head = (m[1]==null)?"":m[1].trim();
var terms= (m[3]==null)?"":m[3].trim().split(/&+/);
log("rule:head=%s terms=%j", head, terms);
var rule = { head:head, terms:terms, satisfy:false };
this.rules.push(rule);
this.dict[head] = { headHits: [rule], bodyHits:[] };
}
kbp.forwardChaining = function() {
do {
var anySatisfy = false;
for (var i in this.rules) {
var rule = this.rules[i];
if (!rule.satisfy) {
if (this.check(rule)) {
this.addFact(rule.head);
rule.satisfy = true;
anySatisfy = true;
}
}
}
} while (anySatisfy);
log("facts=%j", Object.keys(this.facts));
return this;
}
kbp.trySatisfy = function(goal) {
log("trySatisfy(%s)", goal);
var word = this.dict[goal];
if (word == null) return false;
var headHits = word.headHits;
for (var i in headHits) {
var rule = headHits[i];
if (rule.satisfy) {
this.addFact(goal);
return true;
} else {
var isSatisfy = true;
for (var ti in rule.terms) {
var term = rule.terms[ti];
var satisfy = this.trySatisfy(term);
if (!satisfy) isSatisfy = false;
}
rule.satisfy = isSatisfy;
if (isSatisfy) {
this.addFact(goal);
return true;
}
}
}
return false;
}
kbp.backwardChaining = function(goal) {
this.trySatisfy(goal);
log("facts=%j", Object.keys(this.facts));
return this;
}
kbp.query = function() {
var r = require('readline').createInterface(process.stdin, process.stdout);
r.setPrompt('?- ');
r.prompt();
var self = this;
r.on('line', function(line) {
var term = line.trim();
if (line === "exit") process.exit();
self.addFact(term);
self.forwardChaining();
r.prompt();
}).on('close', function() {
process.exit(0);
});
return this;
}
}