finitedomain
Version:
A fast feature rich finite domain solver
1,071 lines (913 loc) • 138 kB
JavaScript
import expect from '../fixtures/mocha_proxy.fixt';
import {
fixt_arrdom_nums,
fixt_arrdom_range,
fixt_arrdom_ranges,
stripAnonVarsFromArrays,
} from '../fixtures/domain.fixt';
import {
SUB,
SUP,
} from '../../src/helpers';
import {
domain__debug,
} from '../../src/domain';
import Solver from '../../src/solver';
let INPUT_MAP = {
bool: {
F: [0, 0],
B: [0, 1],
T: [1, 1],
},
booly: {
F: [0, 0],
B: [0, 0, 5, 5],
T: [5, 5],
},
};
let OUTPUT_MAP = {
bool: {
F: 0,
T: 1,
},
booly: {
F: 0,
T: 5,
},
};
describe('src/constraint.spec', function() {
describe('solver integration', function() {
it('should work without constraints (FIX THIS ONE FIRST)', function() {
// if this test fails the problem is _probably_ unrelated to constraints... :)
let solver = new Solver();
solver.decl('A', 100);
solver.decl('B', 100);
let solution = solver.solve();
expect(solution).to.eql([{A: 100, B: 100}]);
});
describe('eq', function() {
it('should work with a simple solved vars', function() {
let solver = new Solver();
solver.decl('A', 100);
solver.decl('B', 100);
solver.eq('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([{A: 100, B: 100}]);
});
it('should work with a simple solved and unsolved vars', function() {
let solver = new Solver();
solver.decl('A', 100);
solver.decl('B', fixt_arrdom_range(100, 101));
solver.eq('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([{A: 100, B: 100}]);
});
it('should work with a simple unsolved vars that do not reject', function() {
let solver = new Solver();
solver.decl('A', fixt_arrdom_range(100, 101));
solver.decl('B', fixt_arrdom_range(100, 101));
solver.eq('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([{A: 100, B: 100}, {A: 101, B: 101}]);
});
it('should work with a simple unsolved vars that reduce but do not reject', function() {
let solver = new Solver();
solver.decl('A', fixt_arrdom_range(100, 101));
solver.decl('B', fixt_arrdom_range(100, 102));
solver.eq('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([{A: 100, B: 100}, {A: 101, B: 101}]);
});
it('should work with a simple unsolved vars that reject', function() {
let solver = new Solver();
solver.decl('A', fixt_arrdom_range(100, 101));
solver.decl('B', fixt_arrdom_range(200, 201));
solver.eq('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([]);
});
describe('pre-computable', function() {
function preEq(desc, A, B, out) {
it(desc, function() {
let solver = new Solver();
solver.decl('A', A);
solver.decl('B', B);
solver.eq('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql(out);
expect(solver.config.allConstraints.length, 'constraint count').to.eql(0);
});
}
preEq('should not create a constraint if A is solved as number', 101, fixt_arrdom_range(100, 102), [{A: 101, B: 101}]);
preEq('should not create a constraint if A is solved as array', fixt_arrdom_range(101, 101), fixt_arrdom_range(100, 102), [{A: 101, B: 101}]);
preEq('should not create a constraint if B is solved as number', fixt_arrdom_range(100, 102), 101, [{A: 101, B: 101}]);
preEq('should not create a constraint if B is solved as array', fixt_arrdom_range(100, 102), fixt_arrdom_range(101, 101), [{A: 101, B: 101}]);
preEq('should not create a constraint if A and B solved as number and reject', 100, 99, []);
preEq('should not create a constraint if A and B solved as number and pass', 101, 101, [{A: 101, B: 101}]);
preEq('should not create a constraint if A and B solved as array and reject', fixt_arrdom_range(100, 100), fixt_arrdom_range(99, 99), []);
preEq('should not create a constraint if A and B solved as array and pass', fixt_arrdom_range(101, 101), fixt_arrdom_range(101, 101), [{A: 101, B: 101}]);
});
describe('brute force bool table', function() {
function test(A, B, out) {
it('test: A=[' + A + '] B=[' + B + '] out=' + JSON.stringify(out).replace(/"/g, ''), function() {
let solver = new Solver();
solver.decl('A', A);
solver.decl('B', B);
solver.eq('A', 'B');
solver.solve({max: 5}); // only 4 possible outcomes; 00 01 10 11 or none
expect(solver.solutions).to.eql(out);
});
}
test([0, 0], [0, 0], [{A: 0, B: 0}]);
test([0, 1], [0, 0], [{A: 0, B: 0}]); // doe dit voor alle propagators. en zoek uit waarom deze niet werkt.
test([1, 1], [0, 0], []);
test([0, 0], [0, 1], [{A: 0, B: 0}]);
test([0, 1], [0, 1], [{A: 0, B: 0}, {A: 1, B: 1}]);
test([1, 1], [0, 1], [{A: 1, B: 1}]);
test([0, 0], [1, 1], []);
test([0, 1], [1, 1], [{A: 1, B: 1}]);
test([1, 1], [1, 1], [{A: 1, B: 1}]);
});
});
describe('neq', function() {
it('should work with a simple solved vars', function() {
let solver = new Solver();
solver.decl('A', 100);
solver.decl('B', 100);
solver.neq('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([]);
});
it('should work with a simple solved and unsolved vars', function() {
let solver = new Solver();
solver.decl('A', 100);
solver.decl('B', fixt_arrdom_range(100, 101));
solver.neq('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([{A: 100, B: 101}]);
});
it('should work with a simple unsolved vars', function() {
let solver = new Solver();
solver.decl('A', fixt_arrdom_range(100, 101));
solver.decl('B', fixt_arrdom_range(100, 101));
solver.neq('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([{A: 100, B: 101}, {A: 101, B: 100}]);
});
describe('pre-computable', function() {
function preNeq(desc, A, B, out) {
it(desc, function() {
let solver = new Solver();
solver.decl('A', A);
solver.decl('B', B);
solver.neq('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql(out);
expect(solver.config.allConstraints.length, 'constraint count').to.eql(0);
});
}
preNeq('should not create a constraint if A is solved as number', 101, fixt_arrdom_range(100, 102), [{A: 101, B: 100}, {A: 101, B: 102}]);
preNeq('should not create a constraint if A is solved as array', fixt_arrdom_range(101, 101), fixt_arrdom_range(100, 102), [{A: 101, B: 100}, {A: 101, B: 102}]);
preNeq('should not create a constraint if B is solved as number', fixt_arrdom_range(100, 102), 101, [{A: 100, B: 101}, {A: 102, B: 101}]);
preNeq('should not create a constraint if B is solved as array', fixt_arrdom_range(100, 102), fixt_arrdom_range(101, 101), [{A: 100, B: 101}, {A: 102, B: 101}]);
preNeq('should not create a constraint if A and B solved as number and reject', 101, 101, []);
preNeq('should not create a constraint if A and B solved as number and pass', 100, 99, [{A: 100, B: 99}]);
preNeq('should not create a constraint if A and B solved as array and reject', fixt_arrdom_range(101, 101), fixt_arrdom_range(101, 101), []);
preNeq('should not create a constraint if A and B solved as array and pass', fixt_arrdom_range(100, 100), fixt_arrdom_range(99, 99), [{A: 100, B: 99}]);
});
describe('brute force bool table', function() {
function test(A, B, out) {
it('test: A=[' + A + '] B=[' + B + '] out=' + JSON.stringify(out).replace(/"/g, ''), function() {
let solver = new Solver();
solver.decl('A', A);
solver.decl('B', B);
solver.neq('A', 'B');
solver.solve({max: 5}); // only 4 possible outcomes; 00 01 10 11 or none
expect(solver.solutions).to.eql(out);
});
}
test([0, 0], [0, 0], []);
test([0, 1], [0, 0], [{A: 1, B: 0}]);
test([1, 1], [0, 0], [{A: 1, B: 0}]);
test([0, 0], [0, 1], [{A: 0, B: 1}]);
test([0, 1], [0, 1], [{A: 0, B: 1}, {A: 1, B: 0}]);
test([1, 1], [0, 1], [{A: 1, B: 0}]);
test([0, 0], [1, 1], [{A: 0, B: 1}]);
test([0, 1], [1, 1], [{A: 0, B: 1}]);
test([1, 1], [1, 1], []);
});
});
describe('lt', function() {
it('should work when A < B', function() {
let solver = new Solver();
solver.decl('A', 100);
solver.decl('B', 101);
solver.lt('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([{A: 100, B: 101}]);
});
it('should work when A <= B', function() {
let solver = new Solver();
solver.decl('A', 100);
solver.decl('B', fixt_arrdom_range(100, 101));
solver.lt('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([{A: 100, B: 101}]);
});
it('should work when A >= B', function() {
let solver = new Solver();
solver.decl('A', fixt_arrdom_range(100, 101));
solver.decl('B', fixt_arrdom_range(100, 100));
solver.lt('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([]);
});
it('should work when A <= B <= A', function() {
let solver = new Solver();
solver.decl('A', fixt_arrdom_range(100, 102));
solver.decl('B', fixt_arrdom_range(101, 101));
solver.lt('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([{A: 100, B: 101}]);
});
it('should work when B <= A <= B', function() {
let solver = new Solver();
solver.decl('A', fixt_arrdom_range(101, 101));
solver.decl('B', fixt_arrdom_range(100, 102));
solver.lt('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([{A: 101, B: 102}]);
});
it('should work A > B', function() {
let solver = new Solver();
solver.decl('A', fixt_arrdom_range(101, 101));
solver.decl('B', fixt_arrdom_range(100, 100));
solver.lt('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([]);
});
describe('pre-computable', function() {
function preLt(desc, A, B, out) {
it(desc, function() {
let solver = new Solver();
solver.decl('A', A);
solver.decl('B', B);
solver.lt('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql(out);
expect(solver.config.allConstraints.length, 'constraint count').to.eql(0);
});
}
preLt('should not create a constraint if A is solved as number', 101, fixt_arrdom_range(100, 102), [{A: 101, B: 102}]);
preLt('should not create a constraint if A is solved as array', fixt_arrdom_range(101, 101), fixt_arrdom_range(100, 102), [{A: 101, B: 102}]);
preLt('should not create a constraint if B is solved as number', fixt_arrdom_range(100, 102), 101, [{A: 100, B: 101}]);
preLt('should not create a constraint if B is solved as array', fixt_arrdom_range(100, 102), fixt_arrdom_range(101, 101), [{A: 100, B: 101}]);
preLt('should not create a constraint if A and B solved as number and reject', 100, 99, []);
preLt('should not create a constraint if A and B solved as number and pass', 100, 101, [{A: 100, B: 101}]);
preLt('should not create a constraint if A and B solved as array and reject', fixt_arrdom_range(100, 100), fixt_arrdom_range(99, 99), []);
preLt('should not create a constraint if A and B solved as array and pass', fixt_arrdom_range(100, 100), fixt_arrdom_range(101, 101), [{A: 100, B: 101}]);
});
describe('brute force bool table', function() {
function test(A, B, out) {
it('test: A=[' + A + '] B=[' + B + '] out=' + JSON.stringify(out).replace(/"/g, ''), function() {
let solver = new Solver();
solver.decl('A', A);
solver.decl('B', B);
solver.lt('A', 'B');
solver.solve({max: 5}); // only 4 possible outcomes; 00 01 10 11 or none
expect(solver.solutions).to.eql(out);
});
}
test([0, 0], [0, 0], []);
test([0, 1], [0, 0], []);
test([1, 1], [0, 0], []);
test([0, 0], [0, 1], [{A: 0, B: 1}]);
test([0, 1], [0, 1], [{A: 0, B: 1}]);
test([1, 1], [0, 1], []);
test([0, 0], [1, 1], [{A: 0, B: 1}]);
test([0, 1], [1, 1], [{A: 0, B: 1}]);
test([1, 1], [1, 1], []);
});
});
describe('lte', function() {
it('should work when A < B', function() {
let solver = new Solver();
solver.decl('A', 100);
solver.decl('B', 101);
solver.lte('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([{A: 100, B: 101}]);
});
it('should work when A <= B', function() {
let solver = new Solver();
solver.decl('A', 100);
solver.decl('B', fixt_arrdom_range(100, 101));
solver.lte('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([{A: 100, B: 100}, {A: 100, B: 101}]);
});
it('should work when A >= B', function() {
let solver = new Solver();
solver.decl('A', fixt_arrdom_range(100, 101));
solver.decl('B', fixt_arrdom_range(100, 100));
solver.lte('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([{A: 100, B: 100}]);
});
it('should work when A <= B <= A', function() {
let solver = new Solver();
solver.decl('A', fixt_arrdom_range(100, 102));
solver.decl('B', fixt_arrdom_range(101, 101));
solver.lte('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([{A: 100, B: 101}, {A: 101, B: 101}]);
});
it('should work when B <= A <= B', function() {
let solver = new Solver();
solver.decl('A', fixt_arrdom_range(101, 101));
solver.decl('B', fixt_arrdom_range(100, 102));
solver.lte('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([{A: 101, B: 101}, {A: 101, B: 102}]);
});
it('should work A > B', function() {
let solver = new Solver();
solver.decl('A', fixt_arrdom_range(101, 101));
solver.decl('B', fixt_arrdom_range(100, 100));
solver.lte('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([]);
});
describe('pre-computable', function() {
function preLte(desc, A, B, out) {
it(desc, function() {
let solver = new Solver();
solver.decl('A', A);
solver.decl('B', B);
solver.lte('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql(out);
expect(solver.config.allConstraints.length, 'constraint count').to.eql(0);
});
}
preLte('should not create a constraint if A is solved as number', 101, fixt_arrdom_range(100, 102), [{A: 101, B: 101}, {A: 101, B: 102}]);
preLte('should not create a constraint if A is solved as array', fixt_arrdom_range(101, 101), fixt_arrdom_range(100, 102), [{A: 101, B: 101}, {A: 101, B: 102}]);
preLte('should not create a constraint if B is solved as number', fixt_arrdom_range(100, 102), 101, [{A: 100, B: 101}, {A: 101, B: 101}]);
preLte('should not create a constraint if B is solved as array', fixt_arrdom_range(100, 102), fixt_arrdom_range(101, 101), [{A: 100, B: 101}, {A: 101, B: 101}]);
preLte('should not create a constraint if A and B solved as number and reject', 100, 99, []);
preLte('should not create a constraint if A and B solved as number and pass', 100, 100, [{A: 100, B: 100}]);
preLte('should not create a constraint if A and B solved as array and reject', fixt_arrdom_range(100, 100), fixt_arrdom_range(99, 99), []);
preLte('should not create a constraint if A and B solved as array and pass', fixt_arrdom_range(100, 100), fixt_arrdom_range(100, 100), [{A: 100, B: 100}]);
});
describe('brute force bool table', function() {
function test(A, B, out) {
it('test: A=[' + A + '] B=[' + B + '] out=' + JSON.stringify(out).replace(/"/g, ''), function() {
let solver = new Solver();
solver.decl('A', A);
solver.decl('B', B);
solver.lte('A', 'B');
solver.solve({max: 5}); // only 4 possible outcomes; 00 01 10 11 or none
expect(solver.solutions).to.eql(out);
});
}
test([0, 0], [0, 0], [{A: 0, B: 0}]);
test([0, 1], [0, 0], [{A: 0, B: 0}]);
test([1, 1], [0, 0], []);
test([0, 0], [0, 1], [{A: 0, B: 0}, {A: 0, B: 1}]);
test([0, 1], [0, 1], [{A: 0, B: 0}, {A: 0, B: 1}, {A: 1, B: 1}]);
test([1, 1], [0, 1], [{A: 1, B: 1}]);
test([0, 0], [1, 1], [{A: 0, B: 1}]);
test([0, 1], [1, 1], [{A: 0, B: 1}, {A: 1, B: 1}]);
test([1, 1], [1, 1], [{A: 1, B: 1}]);
});
});
describe('gt', function() {
it('should work when A < B', function() {
let solver = new Solver();
solver.decl('A', 100);
solver.decl('B', 101);
solver.gt('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([]);
});
it('should work when A <= B', function() {
let solver = new Solver();
solver.decl('A', 100);
solver.decl('B', fixt_arrdom_range(100, 101));
solver.gt('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([]);
});
it('should work when A >= B', function() {
let solver = new Solver();
solver.decl('A', fixt_arrdom_range(100, 101));
solver.decl('B', fixt_arrdom_range(100, 100));
solver.gt('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([{A: 101, B: 100}]);
});
it('should work when A <= B <= A', function() {
let solver = new Solver();
solver.decl('A', fixt_arrdom_range(100, 102));
solver.decl('B', fixt_arrdom_range(101, 101));
solver.gt('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([{A: 102, B: 101}]);
});
it('should work when B <= A <= B', function() {
let solver = new Solver();
solver.decl('A', fixt_arrdom_range(101, 101));
solver.decl('B', fixt_arrdom_range(100, 102));
solver.gt('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([{A: 101, B: 100}]);
});
it('should work A > B', function() {
let solver = new Solver();
solver.decl('A', fixt_arrdom_range(101, 101));
solver.decl('B', fixt_arrdom_range(100, 100));
solver.gt('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([{A: 101, B: 100}]);
});
describe('pre-computable', function() {
function preGt(desc, A, B, out) {
it(desc, function() {
let solver = new Solver();
solver.decl('A', A);
solver.decl('B', B);
solver.gt('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql(out);
expect(solver.config.allConstraints.length, 'constraint count').to.eql(0);
});
}
preGt('should not create a constraint if A is solved as number', 101, fixt_arrdom_range(100, 102), [{A: 101, B: 100}]);
preGt('should not create a constraint if A is solved as array', fixt_arrdom_range(101, 101), fixt_arrdom_range(100, 102), [{A: 101, B: 100}]);
preGt('should not create a constraint if B is solved as number', fixt_arrdom_range(100, 102), 101, [{A: 102, B: 101}]);
preGt('should not create a constraint if B is solved as array', fixt_arrdom_range(100, 102), fixt_arrdom_range(101, 101), [{A: 102, B: 101}]);
preGt('should not create a constraint if A and B solved as number and reject', 99, 100, []);
preGt('should not create a constraint if A and B solved as number and pass', 101, 100, [{A: 101, B: 100}]);
preGt('should not create a constraint if A and B solved as array and reject', fixt_arrdom_range(99, 99), fixt_arrdom_range(100, 100), []);
preGt('should not create a constraint if A and B solved as array and pass', fixt_arrdom_range(101, 101), fixt_arrdom_range(100, 100), [{A: 101, B: 100}]);
});
describe('brute force bool table', function() {
function test(A, B, out) {
it('test: A=[' + A + '] B=[' + B + '] out=' + JSON.stringify(out).replace(/"/g, ''), function() {
let solver = new Solver();
solver.decl('A', A);
solver.decl('B', B);
solver.gt('A', 'B');
solver.solve({max: 5}); // only 4 possible outcomes; 00 01 10 11 or none
expect(solver.solutions).to.eql(out);
});
}
test([0, 0], [0, 0], []);
test([0, 1], [0, 0], [{A: 1, B: 0}]);
test([1, 1], [0, 0], [{A: 1, B: 0}]);
test([0, 0], [0, 1], []);
test([0, 1], [0, 1], [{A: 1, B: 0}]);
test([1, 1], [0, 1], [{A: 1, B: 0}]);
test([0, 0], [1, 1], []);
test([0, 1], [1, 1], []);
test([1, 1], [1, 1], []);
});
});
describe('gte', function() {
it('should work when A < B', function() {
let solver = new Solver();
solver.decl('A', 100);
solver.decl('B', 101);
solver.gte('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([]);
});
it('should work when A <= B', function() {
let solver = new Solver();
solver.decl('A', 100);
solver.decl('B', fixt_arrdom_range(100, 101));
solver.gte('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([{A: 100, B: 100}]);
});
it('should work when A >= B', function() {
let solver = new Solver();
solver.decl('A', fixt_arrdom_range(100, 101));
solver.decl('B', fixt_arrdom_range(100, 100));
solver.gte('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([{A: 100, B: 100}, {A: 101, B: 100}]);
});
it('should work when A <= B <= A', function() {
let solver = new Solver();
solver.decl('A', fixt_arrdom_range(100, 102));
solver.decl('B', fixt_arrdom_range(101, 101));
solver.gte('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([{A: 101, B: 101}, {A: 102, B: 101}]);
});
it('should work when B <= A <= B', function() {
let solver = new Solver();
solver.decl('A', fixt_arrdom_range(101, 101));
solver.decl('B', fixt_arrdom_range(100, 102));
solver.gte('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([{A: 101, B: 100}, {A: 101, B: 101}]);
});
it('should work A > B', function() {
let solver = new Solver();
solver.decl('A', fixt_arrdom_range(101, 101));
solver.decl('B', fixt_arrdom_range(100, 100));
solver.gte('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql([{A: 101, B: 100}]);
});
describe('pre-computable', function() {
function preGte(desc, A, B, out) {
it(desc, function() {
let solver = new Solver();
solver.decl('A', A);
solver.decl('B', B);
solver.gte('A', 'B');
let solution = solver.solve({});
expect(solution).to.eql(out);
expect(solver.config.allConstraints.length, 'constraint count').to.eql(0);
});
}
preGte('should not create a constraint if A is solved as number', 101, fixt_arrdom_range(100, 102), [{A: 101, B: 100}, {A: 101, B: 101}]);
preGte('should not create a constraint if A is solved as array', fixt_arrdom_range(101, 101), fixt_arrdom_range(100, 102), [{A: 101, B: 100}, {A: 101, B: 101}]);
preGte('should not create a constraint if B is solved as number', fixt_arrdom_range(100, 102), 101, [{A: 101, B: 101}, {A: 102, B: 101}]);
preGte('should not create a constraint if B is solved as array', fixt_arrdom_range(100, 102), fixt_arrdom_range(101, 101), [{A: 101, B: 101}, {A: 102, B: 101}]);
preGte('should not create a constraint if A and B solved as number and reject', 99, 100, []);
preGte('should not create a constraint if A and B solved as number and pass', 101, 100, [{A: 101, B: 100}]);
preGte('should not create a constraint if A and B solved as array and reject', fixt_arrdom_range(99, 99), fixt_arrdom_range(100, 100), []);
preGte('should not create a constraint if A and B solved as array and pass', fixt_arrdom_range(101, 101), fixt_arrdom_range(100, 100), [{A: 101, B: 100}]);
});
describe('brute force bool table', function() {
function test(A, B, out) {
it('test: A=[' + A + '] B=[' + B + '] out=' + JSON.stringify(out).replace(/"/g, ''), function() {
let solver = new Solver();
solver.decl('A', A);
solver.decl('B', B);
solver.gte('A', 'B');
solver.solve({max: 5}); // only 4 possible outcomes; 00 01 10 11 or none
expect(solver.solutions).to.eql(out);
});
}
test([0, 0], [0, 0], [{A: 0, B: 0}]);
test([0, 1], [0, 0], [{A: 0, B: 0}, {A: 1, B: 0}]);
test([1, 1], [0, 0], [{A: 1, B: 0}]);
test([0, 0], [0, 1], [{A: 0, B: 0}]);
test([0, 1], [0, 1], [{A: 0, B: 0}, {A: 1, B: 0}, {A: 1, B: 1}]);
test([1, 1], [0, 1], [{A: 1, B: 0}, {A: 1, B: 1}]);
test([0, 0], [1, 1], []);
test([0, 1], [1, 1], [{A: 1, B: 1}]);
test([1, 1], [1, 1], [{A: 1, B: 1}]);
});
});
describe('reifier (conceptual)', function() {
it('should find two solutions with a constant left', function() {
let solver = new Solver();
solver.decl('A', 0);
solver.decl('B', [0, 1]);
solver.decl('C', [0, 1]);
solver.isLt('A', 'B', 'C');
let solution = solver.solve({});
expect(solution).to.eql([{A: 0, B: 0, C: 0}, {A: 0, B: 1, C: 1}]);
});
it('should find two solutions with a constant right', function() {
let solver = new Solver();
solver.decl('A', [0, 1]);
solver.decl('B', 0);
solver.decl('C', [0, 1]);
solver.isLt('A', 'B', 'C');
let solution = solver.solve({});
expect(solution).to.eql([{A: 0, B: 0, C: 0}, {A: 1, B: 0, C: 0}]);
});
describe('exhaustive bool tables to check optimizations in propagator_addReified', function() {
describe('eq', function() {
function test(domain1, domain2, domain3, out, desc) {
it('should solve despite optimizations. ' + [domain__debug(domain1), '==', domain__debug(domain2), '->', domain__debug(domain3)] + ' solves to: ' + (JSON.stringify(out).replace(/"/g, '')) + (desc ? '; ' + desc : ''), function() {
let solver = new Solver();
let A = solver.decl('A', domain1);
let B = solver.decl('B', domain2);
let C = solver.decl('C', domain3);
solver.isEq(A, B, C);
solver.solve({vars: ['A', 'B', 'C']});
expect(solver.solutions).to.eql(out);
});
}
[
// pure bools
{A: [0, 0], B: [0, 0], C: [0, 0], out: []},
{A: [0, 0], B: [0, 0], C: [0, 1], out: [{A: 0, B: 0, C: 1}]},
{A: [0, 0], B: [0, 0], C: [1, 1], out: [{A: 0, B: 0, C: 1}]},
{A: [0, 0], B: [0, 1], C: [0, 0], out: [{A: 0, B: 1, C: 0}]},
{A: [0, 0], B: [0, 1], C: [0, 1], out: [{A: 0, B: 0, C: 1}, {A: 0, B: 1, C: 0}]},
{A: [0, 0], B: [0, 1], C: [1, 1], out: [{A: 0, B: 0, C: 1}]},
{A: [0, 0], B: [1, 1], C: [0, 0], out: [{A: 0, B: 1, C: 0}]},
{A: [0, 0], B: [1, 1], C: [0, 1], out: [{A: 0, B: 1, C: 0}]},
{A: [0, 0], B: [1, 1], C: [1, 1], out: []},
{A: [0, 1], B: [0, 0], C: [0, 0], out: [{A: 1, B: 0, C: 0}]},
{A: [0, 1], B: [0, 0], C: [0, 1], out: [{A: 0, B: 0, C: 1}, {A: 1, B: 0, C: 0}]},
{A: [0, 1], B: [0, 0], C: [1, 1], out: [{A: 0, B: 0, C: 1}]},
{A: [0, 1], B: [0, 1], C: [0, 0], out: [{A: 0, B: 1, C: 0}, {A: 1, B: 0, C: 0}]},
{A: [0, 1], B: [0, 1], C: [0, 1], out: [{A: 0, B: 0, C: 1}, {A: 0, B: 1, C: 0}, {A: 1, B: 0, C: 0}, {A: 1, B: 1, C: 1}]},
{A: [0, 1], B: [0, 1], C: [1, 1], out: [{A: 0, B: 0, C: 1}, {A: 1, B: 1, C: 1}]},
{A: [0, 1], B: [1, 1], C: [0, 0], out: [{A: 0, B: 1, C: 0}]},
{A: [0, 1], B: [1, 1], C: [0, 1], out: [{A: 0, B: 1, C: 0}, {A: 1, B: 1, C: 1}]},
{A: [0, 1], B: [1, 1], C: [1, 1], out: [{A: 1, B: 1, C: 1}]},
{A: [1, 1], B: [0, 0], C: [0, 0], out: [{A: 1, B: 0, C: 0}]},
{A: [1, 1], B: [0, 0], C: [0, 1], out: [{A: 1, B: 0, C: 0}]},
{A: [1, 1], B: [0, 0], C: [1, 1], out: []},
{A: [1, 1], B: [0, 1], C: [0, 0], out: [{A: 1, B: 0, C: 0}]},
{A: [1, 1], B: [0, 1], C: [0, 1], out: [{A: 1, B: 0, C: 0}, {A: 1, B: 1, C: 1}]},
{A: [1, 1], B: [0, 1], C: [1, 1], out: [{A: 1, B: 1, C: 1}]},
{A: [1, 1], B: [1, 1], C: [0, 0], out: []},
{A: [1, 1], B: [1, 1], C: [0, 1], out: [{A: 1, B: 1, C: 1}]},
{A: [1, 1], B: [1, 1], C: [1, 1], out: [{A: 1, B: 1, C: 1}]},
// booly, same but with C = [0 0 5 5]
{A: [0, 0], B: [0, 0], C: [0, 0], out: []},
{A: [0, 0], B: [0, 0], C: [0, 0, 5, 5], out: [{A: 0, B: 0, C: 5}]},
{A: [0, 0], B: [0, 0], C: [5, 5], out: [{A: 0, B: 0, C: 5}]},
{A: [0, 0], B: [0, 1], C: [0, 0], out: [{A: 0, B: 1, C: 0}]},
{A: [0, 0], B: [0, 1], C: [0, 0, 5, 5], out: [{A: 0, B: 0, C: 5}, {A: 0, B: 1, C: 0}]},
{A: [0, 0], B: [0, 1], C: [5, 5], out: [{A: 0, B: 0, C: 5}]},
{A: [0, 0], B: [1, 1], C: [0, 0], out: [{A: 0, B: 1, C: 0}]},
{A: [0, 0], B: [1, 1], C: [0, 0, 5, 5], out: [{A: 0, B: 1, C: 0}]},
{A: [0, 0], B: [1, 1], C: [5, 5], out: []},
{A: [0, 1], B: [0, 0], C: [0, 0], out: [{A: 1, B: 0, C: 0}]},
{A: [0, 1], B: [0, 0], C: [0, 0, 5, 5], out: [{A: 0, B: 0, C: 5}, {A: 1, B: 0, C: 0}]},
{A: [0, 1], B: [0, 0], C: [5, 5], out: [{A: 0, B: 0, C: 5}]},
{A: [0, 1], B: [0, 1], C: [0, 0], out: [{A: 0, B: 1, C: 0}, {A: 1, B: 0, C: 0}]},
{A: [0, 1], B: [0, 1], C: [0, 0, 5, 5], out: [{A: 0, B: 0, C: 5}, {A: 0, B: 1, C: 0}, {A: 1, B: 0, C: 0}, {A: 1, B: 1, C: 5}]},
{A: [0, 1], B: [0, 1], C: [5, 5], out: [{A: 0, B: 0, C: 5}, {A: 1, B: 1, C: 5}]},
{A: [0, 1], B: [1, 1], C: [0, 0], out: [{A: 0, B: 1, C: 0}]},
{A: [0, 1], B: [1, 1], C: [0, 0, 5, 5], out: [{A: 0, B: 1, C: 0}, {A: 1, B: 1, C: 5}]},
{A: [0, 1], B: [1, 1], C: [5, 5], out: [{A: 1, B: 1, C: 5}]},
{A: [1, 1], B: [0, 0], C: [0, 0], out: [{A: 1, B: 0, C: 0}]},
{A: [1, 1], B: [0, 0], C: [0, 0, 5, 5], out: [{A: 1, B: 0, C: 0}]},
{A: [1, 1], B: [0, 0], C: [5, 5], out: []},
{A: [1, 1], B: [0, 1], C: [0, 0], out: [{A: 1, B: 0, C: 0}]},
{A: [1, 1], B: [0, 1], C: [0, 0, 5, 5], out: [{A: 1, B: 0, C: 0}, {A: 1, B: 1, C: 5}]},
{A: [1, 1], B: [0, 1], C: [5, 5], out: [{A: 1, B: 1, C: 5}]},
{A: [1, 1], B: [1, 1], C: [0, 0], out: []},
{A: [1, 1], B: [1, 1], C: [0, 0, 5, 5], out: [{A: 1, B: 1, C: 5}]},
{A: [1, 1], B: [1, 1], C: [5, 5], out: [{A: 1, B: 1, C: 5}]},
].forEach(testCase => test(testCase.A, testCase.B, testCase.C, testCase.out));
});
describe('neq', function() {
function test(domain1, domain2, domain3, out, desc) {
it('should solve despite optimizations. ' + [domain__debug(domain1), '!=', domain__debug(domain2), '->', domain__debug(domain3)] + ' solves to: ' + (JSON.stringify(out).replace(/"/g, '')) + (desc ? '; ' + desc : ''), function() {
let solver = new Solver();
let A = solver.decl('A', domain1);
let B = solver.decl('B', domain2);
let C = solver.decl('C', domain3);
solver.isNeq(A, B, C);
solver.solve({vars: ['A', 'B', 'C']});
expect(solver.solutions).to.eql(out);
});
}
[
// pure bools
{A: [0, 0], B: [0, 0], C: [0, 0], out: [{A: 0, B: 0, C: 0}]},
{A: [0, 0], B: [0, 0], C: [0, 1], out: [{A: 0, B: 0, C: 0}]},
{A: [0, 0], B: [0, 0], C: [1, 1], out: []},
{A: [0, 0], B: [0, 1], C: [0, 0], out: [{A: 0, B: 0, C: 0}]},
{A: [0, 0], B: [0, 1], C: [0, 1], out: [{A: 0, B: 0, C: 0}, {A: 0, B: 1, C: 1}]},
{A: [0, 0], B: [0, 1], C: [1, 1], out: [{A: 0, B: 1, C: 1}]},
{A: [0, 0], B: [1, 1], C: [0, 0], out: []},
{A: [0, 0], B: [1, 1], C: [0, 1], out: [{A: 0, B: 1, C: 1}]},
{A: [0, 0], B: [1, 1], C: [1, 1], out: [{A: 0, B: 1, C: 1}]},
{A: [0, 1], B: [0, 0], C: [0, 0], out: [{A: 0, B: 0, C: 0}]},
{A: [0, 1], B: [0, 0], C: [0, 1], out: [{A: 0, B: 0, C: 0}, {A: 1, B: 0, C: 1}]},
{A: [0, 1], B: [0, 0], C: [1, 1], out: [{A: 1, B: 0, C: 1}]},
{A: [0, 1], B: [0, 1], C: [0, 0], out: [{A: 0, B: 0, C: 0}, {A: 1, B: 1, C: 0}]},
{A: [0, 1], B: [0, 1], C: [0, 1], out: [{A: 0, B: 0, C: 0}, {A: 0, B: 1, C: 1}, {A: 1, B: 0, C: 1}, {A: 1, B: 1, C: 0}]},
{A: [0, 1], B: [0, 1], C: [1, 1], out: [{A: 0, B: 1, C: 1}, {A: 1, B: 0, C: 1}]},
{A: [0, 1], B: [1, 1], C: [0, 0], out: [{A: 1, B: 1, C: 0}]},
{A: [0, 1], B: [1, 1], C: [0, 1], out: [{A: 0, B: 1, C: 1}, {A: 1, B: 1, C: 0}]},
{A: [0, 1], B: [1, 1], C: [1, 1], out: [{A: 0, B: 1, C: 1}]},
{A: [1, 1], B: [0, 0], C: [0, 0], out: []},
{A: [1, 1], B: [0, 0], C: [0, 1], out: [{A: 1, B: 0, C: 1}]},
{A: [1, 1], B: [0, 0], C: [1, 1], out: [{A: 1, B: 0, C: 1}]},
{A: [1, 1], B: [0, 1], C: [0, 0], out: [{A: 1, B: 1, C: 0}]},
{A: [1, 1], B: [0, 1], C: [0, 1], out: [{A: 1, B: 0, C: 1}, {A: 1, B: 1, C: 0}]},
{A: [1, 1], B: [0, 1], C: [1, 1], out: [{A: 1, B: 0, C: 1}]},
{A: [1, 1], B: [1, 1], C: [0, 0], out: [{A: 1, B: 1, C: 0}]},
{A: [1, 1], B: [1, 1], C: [0, 1], out: [{A: 1, B: 1, C: 0}]},
{A: [1, 1], B: [1, 1], C: [1, 1], out: []},
// booly, same but with C = [0 0 5 5]
{A: [0, 0], B: [0, 0], C: [0, 0], out: [{A: 0, B: 0, C: 0}]},
{A: [0, 0], B: [0, 0], C: [0, 0, 5, 5], out: [{A: 0, B: 0, C: 0}]},
{A: [0, 0], B: [0, 0], C: [5, 5], out: []},
{A: [0, 0], B: [0, 1], C: [0, 0], out: [{A: 0, B: 0, C: 0}]},
{A: [0, 0], B: [0, 1], C: [0, 0, 5, 5], out: [{A: 0, B: 0, C: 0}, {A: 0, B: 1, C: 5}]},
{A: [0, 0], B: [0, 1], C: [5, 5], out: [{A: 0, B: 1, C: 5}]},
{A: [0, 0], B: [1, 1], C: [0, 0], out: []},
{A: [0, 0], B: [1, 1], C: [0, 0, 5, 5], out: [{A: 0, B: 1, C: 5}]},
{A: [0, 0], B: [1, 1], C: [5, 5], out: [{A: 0, B: 1, C: 5}]},
{A: [0, 1], B: [0, 0], C: [0, 0], out: [{A: 0, B: 0, C: 0}]},
{A: [0, 1], B: [0, 0], C: [0, 0, 5, 5], out: [{A: 0, B: 0, C: 0}, {A: 1, B: 0, C: 5}]},
{A: [0, 1], B: [0, 0], C: [5, 5], out: [{A: 1, B: 0, C: 5}]},
{A: [0, 1], B: [0, 1], C: [0, 0], out: [{A: 0, B: 0, C: 0}, {A: 1, B: 1, C: 0}]},
{A: [0, 1], B: [0, 1], C: [0, 0, 5, 5], out: [{A: 0, B: 0, C: 0}, {A: 0, B: 1, C: 5}, {A: 1, B: 0, C: 5}, {A: 1, B: 1, C: 0}]},
{A: [0, 1], B: [0, 1], C: [5, 5], out: [{A: 0, B: 1, C: 5}, {A: 1, B: 0, C: 5}]},
{A: [0, 1], B: [1, 1], C: [0, 0], out: [{A: 1, B: 1, C: 0}]},
{A: [0, 1], B: [1, 1], C: [0, 0, 5, 5], out: [{A: 0, B: 1, C: 5}, {A: 1, B: 1, C: 0}]},
{A: [0, 1], B: [1, 1], C: [5, 5], out: [{A: 0, B: 1, C: 5}]},
{A: [1, 1], B: [0, 0], C: [0, 0], out: []},
{A: [1, 1], B: [0, 0], C: [0, 0, 5, 5], out: [{A: 1, B: 0, C: 5}]},
{A: [1, 1], B: [0, 0], C: [5, 5], out: [{A: 1, B: 0, C: 5}]},
{A: [1, 1], B: [0, 1], C: [0, 0], out: [{A: 1, B: 1, C: 0}]},
{A: [1, 1], B: [0, 1], C: [0, 0, 5, 5], out: [{A: 1, B: 0, C: 5}, {A: 1, B: 1, C: 0}]},
{A: [1, 1], B: [0, 1], C: [5, 5], out: [{A: 1, B: 0, C: 5}]},
{A: [1, 1], B: [1, 1], C: [0, 0], out: [{A: 1, B: 1, C: 0}]},
{A: [1, 1], B: [1, 1], C: [0, 0, 5, 5], out: [{A: 1, B: 1, C: 0}]},
{A: [1, 1], B: [1, 1], C: [5, 5], out: []},
].forEach(testCase => test(testCase.A, testCase.B, testCase.C, testCase.out));
});
describe('lt-', function() {
function test(domain1, domain2, domain3, out, desc) {
it('should solve despite optimizations. ' + [domain__debug(domain1), '<', domain__debug(domain2), '->', domain__debug(domain3)] + ' solves to: ' + (JSON.stringify(out).replace(/"/g, '')) + (desc ? '; ' + desc : ''), function() {
let solver = new Solver();
let A = solver.decl('A', domain1);
let B = solver.decl('B', domain2);
let C = solver.decl('C', domain3);
solver.isLt(A, B, C);
solver.solve({vars: ['A', 'B', 'C']});
expect(solver.solutions).to.eql(out);
});
}
[
// pure bools
{A: [0, 0], B: [0, 0], C: [0, 0], out: [{A: 0, B: 0, C: 0}]},
{A: [0, 0], B: [0, 0], C: [0, 1], out: [{A: 0, B: 0, C: 0}]},
{A: [0, 0], B: [0, 0], C: [1, 1], out: []},
{A: [0, 0], B: [0, 1], C: [0, 0], out: [{A: 0, B: 0, C: 0}]},
{A: [0, 0], B: [0, 1], C: [0, 1], out: [{A: 0, B: 0, C: 0}, {A: 0, B: 1, C: 1}]},
{A: [0, 0], B: [0, 1], C: [1, 1], out: [{A: 0, B: 1, C: 1}]},
{A: [0, 0], B: [1, 1], C: [0, 0], out: []},
{A: [0, 0], B: [1, 1], C: [0, 1], out: [{A: 0, B: 1, C: 1}]},
{A: [0, 0], B: [1, 1], C: [1, 1], out: [{A: 0, B: 1, C: 1}]},
{A: [0, 1], B: [0, 0], C: [0, 0], out: [{A: 0, B: 0, C: 0}, {A: 1, B: 0, C: 0}]},
{A: [0, 1], B: [0, 0], C: [0, 1], out: [{A: 0, B: 0, C: 0}, {A: 1, B: 0, C: 0}]},
{A: [0, 1], B: [0, 0], C: [1, 1], out: []},
{A: [0, 1], B: [0, 1], C: [0, 0], out: [{A: 0, B: 0, C: 0}, {A: 1, B: 0, C: 0}, {A: 1, B: 1, C: 0}]},
{A: [0, 1], B: [0, 1], C: [0, 1], out: [{A: 0, B: 0, C: 0}, {A: 0, B: 1, C: 1}, {A: 1, B: 0, C: 0}, {A: 1, B: 1, C: 0}]},
{A: [0, 1], B: [0, 1], C: [1, 1], out: [{A: 0, B: 1, C: 1}]},
{A: [0, 1], B: [1, 1], C: [0, 0], out: [{A: 1, B: 1, C: 0}]},
{A: [0, 1], B: [1, 1], C: [0, 1], out: [{A: 0, B: 1, C: 1}, {A: 1, B: 1, C: 0}]},
{A: [0, 1], B: [1, 1], C: [1, 1], out: [{A: 0, B: 1, C: 1}]},
{A: [1, 1], B: [0, 0], C: [0, 0], out: [{A: 1, B: 0, C: 0}]},
{A: [1, 1], B: [0, 0], C: [0, 1], out: [{A: 1, B: 0, C: 0}]},
{A: [1, 1], B: [0, 0], C: [1, 1], out: []},
{A: [1, 1], B: [0, 1], C: [0, 0], out: [{A: 1, B: 0, C: 0}, {A: 1, B: 1, C: 0}]},
{A: [1, 1], B: [0, 1], C: [0, 1], out: [{A: 1, B: 0, C: 0}, {A: 1, B: 1, C: 0}]},
{A: [1, 1], B: [0, 1], C: [1, 1], out: []},
{A: [1, 1], B: [1, 1], C: [0, 0], out: [{A: 1, B: 1, C: 0}]},
{A: [1, 1], B: [1, 1], C: [0, 1], out: [{A: 1, B: 1, C: 0}]},
{A: [1, 1], B: [1, 1], C: [1, 1], out: []},
// booly, same but with C = [0 0 5 5]
{A: [0, 0], B: [0, 0], C: [0, 0], out: [{A: 0, B: 0, C: 0}]},
{A: [0, 0], B: [0, 0], C: [0, 0, 5, 5], out: [{A: 0, B: 0, C: 0}]},
{A: [0, 0], B: [0, 0], C: [5, 5], out: []},
{A: [0, 0], B: [0, 1], C: [0, 0], out: [{A: 0, B: 0, C: 0}]},
{A: [0, 0], B: [0, 1], C: [0, 0, 5, 5], out: [{A: 0, B: 0, C: 0}, {A: 0, B: 1, C: 5}]},
{A: [0, 0], B: [0, 1], C: [5, 5], out: [{A: 0, B: 1, C: 5}]},
{A: [0, 0], B: [1, 1], C: [0, 0], out: []},
{A: [0, 0], B: [1, 1], C: [0, 0, 5, 5], out: [{A: 0, B: 1, C: 5}]},
{A: [0, 0], B: [1, 1], C: [5, 5], out: [{A: 0, B: 1, C: 5}]},
{A: [0, 1], B: [0, 0], C: [0, 0], out: [{A: 0, B: 0, C: 0}, {A: 1, B: 0, C: 0}]},
{A: [0, 1], B: [0, 0], C: [0, 0, 5, 5], out: [{A: 0, B: 0, C: 0}, {A: 1, B: 0, C: 0}]},
{A: [0, 1], B: [0, 0], C: [5, 5], out: []},
{A: [0, 1], B: [0, 1], C: [0, 0], out: [{A: 0, B: 0, C: 0}, {A: 1, B: 0, C: 0}, {A: 1, B: 1, C: 0}]},
{A: [0, 1], B: [0, 1], C: [0, 0, 5, 5], out: [{A: 0, B: 0, C: 0}, {A: 0, B: 1, C: 5}, {A: 1, B: 0, C: 0}, {A: 1, B: 1, C: 0}]},
{A: [0, 1], B: [0, 1], C: [5, 5], out: [{A: 0, B: 1, C: 5}]},
{A: [0, 1], B: [1, 1], C: [0, 0], out: [{A: 1, B: 1, C: 0}]},
{A: [0, 1], B: [1, 1], C: [0, 0, 5, 5], out: [{A: 0, B: 1, C: 5}, {A: 1, B: 1, C: 0}]},
{A: [0, 1], B: [1, 1], C: [5, 5], out: [{A: 0, B: 1, C: 5}]},
{A: [1, 1], B: [0, 0], C: [0, 0], out: [{A: 1, B: 0, C: 0}]},
{A: [1, 1], B: [0, 0], C: [0, 0, 5, 5], out: [{A: 1, B: 0, C: 0}]},
{A: [1, 1], B: [0, 0], C: [5, 5], out: []},
{A: [1, 1], B: [0, 1], C: [0, 0], out: [{A: 1, B: 0, C: 0}, {A: 1, B: 1, C: 0}]},
{A: [1, 1], B: [0, 1], C: [0, 0, 5, 5], out: [{A: 1, B: 0, C: 0}, {A: 1, B: 1, C: 0}]},
{A: [1, 1], B: [0, 1], C: [5, 5], out: []},
{A: [1, 1], B: [1, 1], C: [0, 0], out: [{A: 1, B: 1, C: 0}]},
{A: [1, 1], B: [1, 1], C: [0, 0, 5, 5], out: [{A: 1, B: 1, C: 0}]},
{A: [1, 1], B: [1, 1], C: [5, 5], out: []},
].forEach(testCase => test(testCase.A, testCase.B, testCase.C, testCase.out));
});
describe('lte', function() {
function test(domain1, domain2, domain3, out, desc) {
it('should solve despite optimizations. ' + [domain__debug(domain1), '<=', domain__debug(domain2), '->', domain__debug(domain3)] + ' solves to: ' + (JSON.stringify(out).replace(/"/g, '')) + (desc ? '; ' + desc : ''), function() {
let solver = new Solver();
let A = solver.decl('A', domain1);
let B = solver.decl('B', domain2);
let C = solver.decl('C', domain3);
solver.isLte(A, B, C);
solver.solve({vars: ['A', 'B', 'C']});
expect(solver.solutions).to.eql(out);
});
}
[
// pure bools
{A: [0, 0], B: [0, 0], C: [0, 0], out: []},
{A: [0, 0], B: [0, 0], C: [0, 1], out: [{A: 0, B: 0, C: 1}]},
{A: [0, 0], B: [0, 0], C: [1, 1], out: [{A: 0, B: 0, C: 1}]},
{A: [0, 0], B: [0, 1], C: [0, 0], out: []},
{A: [0, 0], B: [0, 1], C: [0, 1], out: [{A: 0, B: 0, C: 1}, {A: 0, B: 1, C: 1}]},
{A: [0, 0], B: [0, 1], C: [1, 1], out: [{A: 0, B: 0, C: 1}, {A: 0, B: 1, C: 1}]},
{A: [0, 0], B: [1, 1], C: [0, 0], out: []},
{A: [0, 0], B: [1, 1], C: [0, 1], out: [{A: 0, B: 1, C: 1}]},
{A: [0, 0], B: [1, 1], C: [1, 1], out: [{A: 0, B: 1, C: 1}]},
{A: [0, 1], B: [0, 0], C: [0, 0], out: [{A: 1, B: 0, C: 0}]},
{A: [0, 1], B: [0, 0], C: [0, 1], out: [{A: 0, B: 0, C: 1}, {A: 1, B: 0, C: 0}]},
{A: [0, 1], B: [0, 0], C: [1, 1], out: [{A: 0, B: 0, C: 1}]},
{A: [0, 1], B: [0, 1], C: [0, 0], out: [{A: 1, B: 0, C: 0}]},
{A: [0, 1], B: [0, 1], C: [0, 1], out: [{A: 0, B: 0, C: 1}, {A: 0, B: 1, C: 1}, {A: 1, B: 0, C: 0}, {A: 1, B: 1, C: 1}]},
{A: [0, 1], B: [0, 1], C: [1, 1], out: [{A: 0, B: 0, C: 1}, {A: 0, B: 1, C: 1}, {A: 1, B: 1, C: 1}]},
{A: [0, 1], B: [1, 1], C: [0, 0], out: []},
{A: [0, 1], B: [1, 1], C: [0, 1], out: [{A: 0, B: 1, C: 1}, {A: 1, B: 1, C: 1}]},
{A: [0, 1], B: [1, 1], C: [1, 1], out: [{A: 0, B: 1, C: 1}, {A: 1, B: 1, C: 1}]},
{A: [1, 1], B: [0, 0], C: [0, 0], out: [{A: 1, B: 0, C: 0}]},
{A: [1, 1], B: [0, 0], C: [0, 1], out: [{A: 1, B: 0, C: 0}]},
{A: [1, 1], B: [0, 0], C: [1, 1], out: []},
{A: [1, 1], B: [0, 1], C: [0, 0], out: [{A: 1, B: 0, C: 0}]},
{A: [1, 1], B: [0, 1], C: [0, 1], out: [{A: 1, B: 0, C: 0}, {A: 1, B: 1, C: 1}]},
{A: [1, 1], B: [0, 1], C: [1, 1], out: [{A: 1, B: 1, C: 1}]},
{A: [1, 1], B: [1, 1], C: [0, 0], out: []},
{A: [1, 1], B: [1, 1], C: [0, 1], out: [{A: 1, B: 1, C: 1}]},
{A: [1, 1], B: [1, 1], C: [1, 1], out: [{A: 1, B: 1, C: 1}]},
// booly, same but with C = [0 0 5 5]
{A: [0, 0], B: [0, 0], C: [0, 0], out: []},
{A: [0, 0], B: [0, 0], C: [0, 0, 5, 5], out: [{A: 0, B: 0, C: 5}]},
{A: [0, 0], B: [0, 0], C: [5, 5], out: [{A: 0, B: 0, C: 5}]},
{A: [0, 0], B: [0, 1], C: [0, 0], out: []},
{A: [0, 0], B: [0, 1], C: [0, 0, 5, 5], out: [{A: 0, B: 0, C: 5}, {A: 0, B: 1, C: 5}]},
{A: [0, 0], B: [0, 1], C: [5, 5], out: [{A: 0, B: 0, C: 5}, {A: 0, B: 1, C: 5}]},
{A: [0, 0], B: [1, 1], C: [0, 0], out: []},
{A: [0, 0], B: [1, 1], C: [0, 0, 5, 5], out: [{A: 0, B: 1, C: 5}]},
{A: [0, 0], B: [1, 1], C: [5, 5], out: [{A: 0, B: 1, C: 5}]},
{A: [0, 1], B: [0, 0], C: [0, 0], out: [{A: 1, B: 0, C: 0}]},
{A: [0, 1], B: [0, 0], C: [0, 0, 5, 5], out: [{A: 0, B: 0, C: 5}, {A: 1, B: 0, C: 0}]},
{A: [0, 1], B: [0, 0], C: [5, 5], out: [{A: 0, B: 0, C: 5}]},
{A: [0, 1], B: [0, 1], C: [0, 0], out: [{A: 1, B: 0, C: 0}]},
{A: [0, 1], B: [0, 1], C: [0, 0, 5, 5], out: [{A: 0, B: 0, C: 5}, {A: 0, B: 1, C: 5}, {A: 1, B: 0, C: 0}, {A: 1, B: 1, C: 5}]},
{A: [0, 1], B: [0, 1], C: [5, 5], out: [{A: 0, B: 0, C: 5}, {A: 0, B: 1, C: 5}, {A: 1, B: 1, C: 5}]},
{A: [0, 1], B: [1, 1], C: [0, 0], out: []},
{A: [0, 1], B: [1, 1], C: [0, 0, 5, 5], out: [{A: 0, B: 1, C: 5}, {A: 1, B: 1, C: 5}]},
{A: [0, 1], B: [1, 1], C: [5, 5], out: [{A: 0, B: 1, C: 5}, {A: 1, B: 1, C: 5}]},
{A: [1, 1], B: [0, 0], C: [0, 0], out: [{A: 1, B: 0, C: 0}]},
{A: [1, 1], B: [0, 0], C: [0, 0, 5, 5], out: [{A: 1, B: 0, C: 0}]},
{A: [1, 1], B: [0, 0], C: [5, 5], out: []},
{A: [1, 1], B: [0, 1], C: [0, 0], out: [{A: 1, B: 0, C: 0}]},
{A: [1, 1], B: [0, 1], C: [0, 0, 5, 5], out: [{A: 1, B: 0, C: 0}, {A: 1, B: 1, C: 5}]},
{A: [1, 1], B: [0, 1], C: [5, 5], out: [{A: 1, B: 1, C: 5}]},
{A: [1, 1], B: [1, 1], C: [0, 0], out: []},
{A: [1, 1], B: [1, 1], C: [0, 0, 5, 5], out: [{A: 1, B: 1, C: 5}]},
{A: [1, 1], B: [1, 1], C: [5, 5], out: [{A: 1, B: 1, C: 5}]},
].forEach(testCase => test(testCase.A, testCase.B, testCase.C, testCase.out));
});
// note: gt and gte map to lt and lte so there's no real need to test them as well... but we could :)
});
});
describe('plus', function() {
it('should work with simple case', function() {
let solver = new Solver();
solver.decl('A', 100);
solver.decl('B', 101);
solver.decl('C', fixt_arrdom_range(150, 250));
solver.plus('A', 'B', 'C');
let solution = solver.solve({});
expect(solution).to.eql([{A: 100, B: 101, C: 201}]);
});
function testABC(A, B, C, solves) {
it(`should work with A=${A} B=${B} C=${C} -> ${solves}`, function() {
let solver = new Solver();
solver.decl('A', A);
solver.decl('B', B);
solver.decl('C', C);
solver.plus('A', 'B', 'C');
let solution = solver.solve({});
expect(solution).to.eql(solves);
});
}
testABC(0, 1, 1, [{A: 0, B: 1, C: 1}]);
testABC(1, 0, 1, [{A: 1, B: 0, C: 1}]);
testABC(0, 0, 0, [{A: 0, B: 0, C: 0}]);
testABC(1, 1, 2, [{A: 1, B: 1, C: 2}]);
testABC(fixt_arrdom_range(100, 110), fixt_arrdom_range(50, 60), fixt_arrdom_range(150, 151), [
{A: 100, B: 50, C: 150},
{A: 100, B: 51, C: 151},
{A: 101, B: 50, C: 151},
]);
it('should work without C', function() {
let solver = new Solver();
solver.decl('A', fixt_arrdom_range(100, 102));
solver.decl('B', fixt_arrdom_range(50, 52));
solver.plus('A', 'B');
let solution = solver.solve({});
expect(stripAnonVarsFromArrays(solution)).to.eql([
// Note: order is not relevant to the test!
{ A