UNPKG

stsys

Version:

String rewriting system (semi-Thue system)

213 lines (200 loc) 4.57 kB
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(); };