stsys
Version:
String rewriting system (semi-Thue system)
213 lines (200 loc) • 4.57 kB
JavaScript
const strpair = require('./strpair');
class RuleManager
{
constructor()
{
this.indexRoot = {};
this.suffixIndexRoot = {};
this.rules = [];
this.ruleIdsCount = 0;
}
getRulesCount()
{
return this.rules.length;
}
getRules()
{
return this.rules.map(rule => rule.toString());
}
addRule(rule)
{
let i = 0;
let left = rule.left;
let indexNode = this.indexRoot;
while (i < left.length)
{
let c = left.charAt(i++);
if (!indexNode[c])
indexNode[c] = {};
indexNode = indexNode[c];
if (i < left.length)
(indexNode.ovlps || (indexNode.ovlps = [])).push(rule);
}
indexNode.rule = rule;
i = left.length;
while (--i > 0)
{
let j = i;
indexNode = this.suffixIndexRoot;
while (j < left.length)
{
let c = left.charAt(j++);
if (!indexNode[c])
indexNode[c] = {};
indexNode = indexNode[c];
}
(indexNode.ovlps || (indexNode.ovlps = [])).push(rule);
}
rule.id = ++this.ruleIdsCount;
this.rules.push(rule);
}
removeRule(rule)
{
let i = 0;
let left = rule.left;
let len = left.length;
let indexNode = this.indexRoot;
while (i < len)
{
indexNode = indexNode[left.charAt(i++)];
if (!indexNode)
break;
let j = indexNode.ovlps ? indexNode.ovlps.indexOf(rule): -1;
if (j >= 0)
indexNode.ovlps.splice(j, 1);
}
if (indexNode)
indexNode.rule = null;
if ((i = this.rules.indexOf(rule)) >= 0)
this.rules.splice(i, 1);
i = left.length;
while (--i > 0)
{
let j = i;
indexNode = this.suffixIndexRoot;
while (indexNode && j < left.length)
{
indexNode = indexNode[left.charAt(j++)];
}
if (indexNode && indexNode.ovlps && (j = indexNode.ovlps.indexOf(rule)) >= 0)
indexNode.ovlps.splice(j, 1);
}
}
findOverlap(s, i)
{
let indexNode = this.indexRoot;
while (i < s.length)
{
indexNode = indexNode[s.charAt(i++)];
if (!indexNode)
return;
}
if (indexNode.ovlps && indexNode.ovlps.length > 0)
return indexNode.ovlps;
}
resetSuffixIndexNode()
{
this.suffixIndexNode = this.suffixIndexRoot;
}
reduce(s, rule)
{
let i;
let reduced = false;
if (rule)
{
i = s.indexOf(rule.left);
if (i < 0)
return;
s = reduce(s, i, rule);
reduced = true;
}
do
{
i = 0;
while (i < s.length)
{
let r = findMatchingRule.call(this, s, i);
if (r)
{
s = reduce(s, i, r);
reduced = true;
break;
}
else
++i;
}
}
while (i < s.length);
if (reduced)
return s;
}
reduceAll(newRule, prover)
{
let i = 0;
let rule;
while (rule = this.rules[i])
{
if (rule === newRule)
{
++i;
continue;
}
let left1 = rule.left;
if (rule.reduce(this, newRule))
{
if (rule.ordered)
{
if (prover.isLoggable(4))
prover.log('Right side of rule #' + rule.id + ' modified: ' + rule.toString());
}
else if (rule.isTrivial())
{
if (prover.isLoggable(4))
prover.log('Discarding rule #' + rule.id + ' --> (trivial) ' + rule.toString());
rule.left = left1;
this.removeRule(rule);
if (prover.statistics)
prover.statistics.rulesDiscarded++;
continue;
}
else
{
if (prover.isLoggable(4))
prover.log('Demoting rule #' + rule.id + ' --> critical pair ' + rule.toString());
let left2 = rule.left;
rule.left = left1;
this.removeRule(rule);
prover.cpMgr.addCp(strpair.createStrPair(left2, rule.right, rule.parent1, rule.parent2));
if (prover.statistics)
{
prover.statistics.rulesDemoted++;
prover.statistics.cpsAdded++;
}
continue;
}
}
++i;
}
}
}
function reduce(s, i, rule)
{
return s.substring(0, i) + rule.right + s.substring(i + rule.left.length);
}
function findMatchingRule(s, i)
{
let indexNode = this.indexRoot;
do
{
if (indexNode.rule)
return indexNode.rule;
if (i >= s.length)
return;
indexNode = indexNode[s.charAt(i++)];
}
while (indexNode);
}
module.exports.createRuleManager = function()
{
return new RuleManager();
};