UNPKG

stsys

Version:

String rewriting system (semi-Thue system)

298 lines (283 loc) 10 kB
const assert = require('assert'); const createProver = require('../lib/prover').createProver; describe('Prover creation', function(){ it('creation failing (missing axioms)', function(){ try { createProver(); } catch (error) { assert.equal(error.message,'missing axioms'); return; } assert.fail('expected exception not thrown'); }); it('creation failing (no axioms)', function(){ try { createProver([]); } catch (error) { assert.equal(error.message,'no axioms (empty Array)'); return; } assert.fail('expected exception not thrown'); }); it('creation failing (invalid specification)', function(){ try { createProver(42); } catch (error) { assert.equal(error.message,'invalid specification of axioms (neither Array nor string)'); return; } assert.fail('expected exception not thrown'); }); it('creation failing (invalid characters)', function(){ try { createProver('abc = #'); } catch (error) { assert.equal(error.message,'invalid string pair (illegal characters): abc = #'); return; } assert.fail('expected exception not thrown'); }); it('creation failing (missing equality character)', function(){ try { createProver(['a = bc', 'abc']); } catch (error) { assert.equal(error.message,'invalid string pair (missing equality): abc'); return; } assert.fail('expected exception not thrown'); }); it('creation succeeding', function(){ ['ab = ba', ['aba = ba', 'baa = ba', 'aaa = ']].forEach(function(ax){ const prover = createProver(ax); assert.ok(prover); assert.equal(prover.getOrdering(), undefined); assert.equal(prover.getPreorder(), undefined); assert.equal(prover.getState(), null); assert.equal(prover.getRulesCount(), 0); assert.deepEqual(prover.getRules(), []); assert.deepEqual(prover.getGoals(), []); assert.equal(prover.getTotalGoalsCount(), 0); assert.equal(prover.getProvedGoalsCount(), 0); assert.deepEqual(prover.getAxioms(), typeof ax === 'string' ? [ax] : ax); assert.equal(prover.getTotalCpCount(), 0); assert.equal(prover.getStatistics(), null); assert.ok(!prover.getStatisticsAsString()); }); }); }); describe('Prover runs', function(){ it('running to completion', function(){ const prover = createProver(['ab = ba', 'aba = ba']); assert.equal(prover.run({ordering:'lex', preorder:['a', 'b']}), 'completed'); assert.equal(prover.getOrdering(), 'lex'); assert.deepEqual(prover.getPreorder(), ['a', 'b']); assert.equal(prover.getState(), 'completed'); assert.equal(prover.getRulesCount(), 2); assert.deepEqual(prover.getRules(), ['ab -> ba', 'baa -> ba']); assert.equal(prover.getTotalCpCount(), 0); assert.ok(prover.getHrtimeElapsed()); assert.ok(/^\d+ms$/.test(prover.getTimeElapsed())); }); it('stopped, resumed, and rerun', function(){ const prover = createProver(['a = b', 'aab = c', 'aa =']); assert.equal(prover.run({ordering:'lex', preorder:['a', 'c', 'b'], maxRuleGen:2}), 'stopped'); assert.equal(prover.getState(), 'stopped'); assert.equal(prover.getStatistics(), null); assert.equal(prover.getRulesCount(), 2); assert.equal(prover.getTotalCpCount(), 1); assert.ok(prover.getHrtimeElapsed()); assert.ok(/^\d+ms$/.test(prover.getTimeElapsed())); assert.equal(prover.run({statistics:true}), 'completed'); assert.equal(prover.getState(), 'completed'); assert.equal(prover.getStatistics(), null); assert.equal(prover.getRulesCount(), 3); assert.equal(prover.getTotalCpCount(), 0); assert.deepEqual(prover.getRules(), ['a -> b', 'bb -> ', 'c -> b']); assert.equal(prover.run(), 'completed'); assert.equal(prover.getState(), 'completed'); assert.equal(prover.getRulesCount(), 3); assert.equal(prover.getTotalCpCount(), 0); assert.equal(prover.rerun({ ordering:'lex', preorder:['a', 'c', 'b'], maxRuleGen:2, statistics:true}), 'stopped'); assert.equal(prover.getState(), 'stopped'); assert.equal(prover.getRulesCount(), 2); assert.equal(prover.getTotalCpCount(), 1); let stats = prover.getStatistics(); assert.ok(stats); assert.equal(stats.rulesGenerated, 2); assert.equal(typeof (stats = prover.getStatisticsAsString()), 'string'); assert.ok(/Rules generated\s*:\s+2/.test(stats)); assert.equal(prover.rerun({ordering:'lex', preorder:['a', 'c', 'b'], maxRuleGen:1}), 'stopped'); assert.equal(prover.getState(), 'stopped'); assert.equal(prover.getRulesCount(), 1); assert.equal(prover.getTotalCpCount(), 2); assert.equal(prover.getStatistics(), null); assert.ok(!prover.getStatisticsAsString()); }); it('run with changed ordering/preorder', function(){ const prover = createProver(['ab=ba', 'aba=ba'], { ordering: 'lex', preorder: ['b','a'] }); assert.deepEqual(prover.getPreorder(), ['b','a']); assert.equal(prover.run({preorder:['a','b']}), 'completed'); assert.deepEqual(prover.getPreorder(), ['a','b']); assert.equal(prover.getOrdering(), 'lex'); assert.equal(prover.rerun({ordering:'lpo'}), 'completed'); assert.deepEqual(prover.getPreorder(), ['a','b']); assert.equal(prover.getOrdering(), 'lpo'); }); it('timed out', function(){ const prover = createProver('aba = ba'); assert.ok(prover); assert.equal(prover.run({ordering:'lex', preorder:['a', 'b'], timeout:10}), 'stopped'); assert.ok(/^[12]\dms$/.test(prover.getTimeElapsed())); assert.ok(prover.getRulesCount() > 1); assert.ok(prover.getTotalCpCount() > 1); let b = 1; prover.getRules().forEach(function(rule){ const i = rule.indexOf('->'); const left = rule.substring(0, i - 1); const right = rule.substring(i + 3); assert.equal('a' + right, left); assert.ok(new RegExp('^b{' + b++ + '}a$').test(right)); }); }); it('running until all goals are proved', function(){ const prover = createProver('ba = aba'); assert.equal(prover.run({ ordering:'lex', preorder:['a', 'b'], goals:['abbba = bbba', 'abbbbba = bbbbba'] }), 'proved'); assert.equal(prover.getTotalGoalsCount(), 2); assert.equal(prover.getProvedGoalsCount(), 2); const goals = prover.getGoals(); assert.ok(goals instanceof Array); assert.equal(goals.length, 2); goals.forEach(function(g){ assert.equal(typeof g.goal, 'string'); assert.equal(typeof g.proved, 'boolean'); assert.ok(g.proved); assert.equal(typeof g.provedBy, 'string'); }); }); it('resuming to completion after clearing goals', function() { const prover = createProver(['ab=ba', 'aba=ba'], { ordering: 'lex', preorder: ['a','b'] }); assert.equal(prover.run({goals:['aab = ba']}), 'proved'); assert.equal(prover.run(), 'proved'); prover.clearGoals(); assert.equal(prover.run(), 'completed'); }); it('logging', function(){ const log1 = []; const log2 = []; const logger1 = function(s){ log1.push(s); }; const logger2 = function(s){ log2.push(s); }; let prover = createProver(['ab=ba', 'aba=ba'], { logger: logger1, logLevel: 2, ordering: 'lex', preorder: ['a','b'] }); assert.equal(prover.getOrdering(), 'lex'); assert.deepEqual(prover.getPreorder(), ['a','b']); assert.equal(prover.run(), 'completed'); assert.equal(log1.length, 2); assert.equal(log1[0], 'Ordering: Length/lexicographic ordering using preorder a > b'); assert.equal(log1[1], 'Running...'); log1.length = 0; assert.equal(prover.rerun({logLevel: 3}), 'completed'); assert.equal(log1.length, 4); assert.equal(log1[0], 'Ordering: Length/lexicographic ordering using preorder a > b'); assert.equal(log1[1], 'Running...'); assert.equal(log1[2], 'New rule #1: ab -> ba'); assert.equal(log1[3], 'New rule #2: baa -> ba'); log1.length = 0; assert.equal(prover.rerun({logger:logger2}), 'completed'); assert.equal(log1.length, 0); assert.equal(log2.length, 4); prover = createProver(['ab=ba', 'aba=ba'], { ordering: 'lex', preorder: ['a','b'] }); prover.run({logLevel:5}); assert.equal(log1.length, 0); assert.equal(log2.length, 4); prover.rerun({logger:logger1, logLevel:0}); assert.equal(log1.length, 0); prover.rerun({logLevel:3}); assert.deepEqual(log1, log2); log1.length = 0; prover = createProver('abba=bba', { logger: logger1, logLevel: 3, ordering: 'lex', preorder: ['a','b'] }); assert.equal(prover.run({maxRuleGen:5}), 'stopped'); let n = log1.length; assert.ok(n > 5); assert.equal(prover.run({maxRuleGen:5, logLevel:0}), 'stopped'); assert.equal(log1.length, n); assert.equal(prover.run({maxRuleGen:5, logLevel:3}), 'stopped'); assert.ok(log1.length - n > 5); n = log1.length; log2.length = 0; assert.equal(prover.run({maxRuleGen:5, logger:logger2}), 'stopped'); assert.equal(log1.length, n); assert.ok(log2.length > 5); }); it('failing due to missing/incomplete ordering data', function(){ let prover = createProver(['ab=ba', 'aba=ba'], {ordering: 'lpo'}); let exceptionThrown = false; try { prover.run({preorder:['a', 'b']}); } catch (error) { exceptionThrown = true; assert.equal(error.message, 'no ordering specified'); } assert.ok(exceptionThrown); prover = createProver(['ab=ba', 'aba=ba'], {preorder:['a', 'b']}); exceptionThrown = false; try { prover.run({ordering:'syl-r'}); } catch (error) { exceptionThrown = true; assert.equal(error.message, 'invalid preorder: non-empty array of letters expected'); } assert.ok(exceptionThrown); }); });