UNPKG

finitedomain

Version:

A fast feature rich finite domain solver

491 lines (429 loc) 21.2 kB
import expect from '../../fixtures/mocha_proxy.fixt'; import { fixt_arrdom_nums, fixt_arrdom_range, fixt_arrdom_ranges, fixt_dom_empty, fixt_dom_nums, fixt_dom_range, fixt_dom_ranges, fixt_dom_solved, fixt_domainEql, } from '../../fixtures/domain.fixt'; import { LOG_FLAG_PROPSTEPS, LOG_FLAG_NONE, SUB, SUP, ASSERT_SET_LOG, } from '../../../src/helpers'; import { domain__debug, domain_toArr, } from '../../../src/domain'; import { config_addVarDomain, config_create, } from '../../../src/config'; import { space_createRoot, space_initFromConfig, } from '../../../src/space'; import { propagator_neqStepBare, } from '../../../src/propagators/neq'; describe('propagators/neq.spec', function() { it('should exist', function() { expect(propagator_neqStepBare).to.be.a('function'); }); it('should expect args', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_nums(11, 15)); config_addVarDomain(config, 'B', fixt_arrdom_nums(5, 8)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); let B = config.allVarNames.indexOf('B'); expect(_ => propagator_neqStepBare(space, config, A, B)).not.to.throw(); expect(_ => propagator_neqStepBare()).to.throw('SHOULD_GET_SPACE'); expect(_ => propagator_neqStepBare(space)).to.throw('VAR_INDEX_SHOULD_BE_NUMBER'); expect(_ => propagator_neqStepBare(space, config, A)).to.throw('VAR_INDEX_SHOULD_BE_NUMBER'); expect(_ => propagator_neqStepBare(space, undefined, B)).to.throw('VAR_INDEX_SHOULD_BE_NUMBER'); expect(_ => propagator_neqStepBare(undefined, A, B)).to.throw('SHOULD_GET_SPACE'); }); it('should throw for empty domains', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_nums(9, 10)); config_addVarDomain(config, 'B', fixt_arrdom_nums(11, 15)); config_addVarDomain(config, 'C', fixt_arrdom_nums(100)); config_addVarDomain(config, 'D', fixt_arrdom_nums(100)); let space = space_createRoot(); space_initFromConfig(space, config); space.vardoms[config.allVarNames.indexOf('C')] = fixt_dom_empty(); space.vardoms[config.allVarNames.indexOf('D')] = fixt_dom_empty(); let A = config.allVarNames.indexOf('A'); let B = config.allVarNames.indexOf('B'); let C = config.allVarNames.indexOf('C'); let D = config.allVarNames.indexOf('D'); expect(_ => propagator_neqStepBare(space, config, A, B)).not.to.throw(); expect(_ => propagator_neqStepBare(space, config, A, D)).to.throw('SHOULD_NOT_BE_REJECTED'); expect(_ => propagator_neqStepBare(space, config, C, B)).to.throw('SHOULD_NOT_BE_REJECTED'); expect(_ => propagator_neqStepBare(space, config, C, D)).to.throw('SHOULD_NOT_BE_REJECTED'); }); describe('should not change anything as long as both domains are unsolved', function() { function test(domain1, domain2) { it(`should not change anything (left-right): ${[domain1, domain2].join('|')}`, function() { let config = config_create(); config_addVarDomain(config, 'A', domain_toArr(domain1)); config_addVarDomain(config, 'B', domain_toArr(domain2)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); let B = config.allVarNames.indexOf('B'); propagator_neqStepBare(space, config, A, B); fixt_domainEql(space.vardoms[A], domain1); fixt_domainEql(space.vardoms[B], domain2); }); it(`should not change anything (right-left): ${[domain2, domain1].join('|')}`, function() { let config = config_create(); config_addVarDomain(config, 'A', domain_toArr(domain2)); config_addVarDomain(config, 'B', domain_toArr(domain1)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); let B = config.allVarNames.indexOf('B'); propagator_neqStepBare(space, config, A, B); fixt_domainEql(space.vardoms[A], domain2); fixt_domainEql(space.vardoms[B], domain1); }); } describe('with array', function() { // these are the (non-solved) cases plucked from eq tests test(fixt_dom_range(SUB, SUP), fixt_dom_ranges([0, 10], [20, 140])); test(fixt_dom_range(SUP - 1, SUP), fixt_dom_range(SUP - 1, SUP)); test(fixt_dom_range(20, 50), fixt_dom_range(20, 50)); test(fixt_dom_ranges([0, 10], [20, 30], [40, 50]), fixt_dom_ranges([0, 10], [20, 30], [40, 50])); test(fixt_dom_ranges([0, 10], [25, 25], [40, 50]), fixt_dom_ranges([0, 10], [25, 25], [40, 50])); test(fixt_dom_range(SUP - 2, SUP), fixt_dom_range(SUP - 2, SUP)); test(fixt_dom_ranges([0, 10], [20, 30], [40, 50]), fixt_dom_ranges([5, 15], [25, 35])); test(fixt_dom_ranges([0, 10], [20, 30], [40, 50]), fixt_dom_ranges([SUB, SUP])); test(fixt_dom_range(SUP - 2, SUP), fixt_dom_range(SUP - 3, SUP - 1)); test(fixt_dom_range(SUP - 2, SUP), fixt_dom_range(SUP - 4, SUP - 1)); }); describe('with numbers', function() { test(fixt_dom_range(0, 1), fixt_dom_range(0, 1)); test(fixt_dom_range(2, 5), fixt_dom_range(2, 5)); test(fixt_dom_range(0, 1), fixt_dom_range(0, 2)); test(fixt_dom_range(0, 2), fixt_dom_range(0, 3)); test(fixt_dom_range(0, 2), fixt_dom_range(0, 4)); }); }); describe('with one solved domain', function() { function test(solvedDomain, unsolvedDomainBefore, unsolvedDomainAfter) { it(`should not change anything (right-left): [${[domain_toArr(solvedDomain), domain_toArr(unsolvedDomainBefore)].join(']|[')}]`, function() { let config = config_create(); config_addVarDomain(config, 'A', domain_toArr(solvedDomain)); config_addVarDomain(config, 'B', domain_toArr(unsolvedDomainBefore)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); let B = config.allVarNames.indexOf('B'); propagator_neqStepBare(space, config, A, B); fixt_domainEql(space.vardoms[A], solvedDomain); fixt_domainEql(space.vardoms[B], unsolvedDomainAfter); }); it(`should remove solved domain from unsolve domain (left-right): [${[unsolvedDomainBefore, solvedDomain].join(']|[')}]`, function() { let config = config_create(); config_addVarDomain(config, 'A', domain_toArr(unsolvedDomainBefore)); config_addVarDomain(config, 'B', domain_toArr(solvedDomain)); let space = space_createRoot(); space_initFromConfig(space, config); let B = config.allVarNames.indexOf('B'); let A = config.allVarNames.indexOf('A'); propagator_neqStepBare(space, config, A, B); fixt_domainEql(space.vardoms[A], unsolvedDomainAfter); fixt_domainEql(space.vardoms[B], solvedDomain); }); } describe('with array', function() { test(fixt_dom_range(SUP, SUP), fixt_dom_range(SUP - 1, SUP), fixt_dom_solved(SUP - 1)); test(fixt_dom_range(SUP - 1, SUP - 1), fixt_dom_range(SUP - 1, SUP), fixt_dom_solved(SUP)); test(fixt_dom_range(SUP, SUP), fixt_dom_range(SUP - 50, SUP), fixt_dom_range(SUP - 50, SUP - 1)); test(fixt_dom_range(120, 120), fixt_dom_ranges([120, SUP - 1]), fixt_dom_range(121, SUP - 1)); test(fixt_dom_range(910, 910), fixt_dom_ranges([910, 910], [912, 950]), fixt_dom_ranges([912, 950])); test(fixt_dom_range(910, 910), fixt_dom_ranges([90, 98], [910, 910], [912, 920]), fixt_dom_ranges([90, 98], [912, 920])); test(fixt_dom_range(910, 910), fixt_dom_ranges([90, 910], [912, 950]), fixt_dom_ranges([90, 909], [912, 950])); test(fixt_dom_range(91, 91), fixt_dom_range(90, 93), fixt_dom_ranges([90, 90], [92, 93])); }); describe('with numbers', function() { test(fixt_dom_nums(0), fixt_dom_range(0, 1), fixt_dom_solved(1)); test(fixt_dom_nums(1), fixt_dom_range(0, 1), fixt_dom_solved(0)); test(fixt_dom_nums(0), fixt_dom_range(0, 15), fixt_dom_range(1, 15)); test(fixt_dom_nums(2), fixt_dom_range(2, 5), fixt_dom_range(3, 5)); test(fixt_dom_nums(10), fixt_dom_nums(10, 13, 14, 15), fixt_dom_range(13, 15)); test(fixt_dom_nums(10), fixt_dom_nums(0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 13, 14, 15), fixt_dom_nums(0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 13, 14, 15)); test(fixt_dom_nums(4), fixt_dom_nums(0, 1, 2, 3, 4, 10, 12, 13, 14, 15), fixt_dom_nums(0, 1, 2, 3, 10, 12, 13, 14, 15)); test(fixt_dom_nums(1), fixt_dom_range(0, 3), fixt_dom_nums(0, 2, 3)); }); }); describe('two neq solved domains', function() { function test(domain1, domain2) { it(`should be "solved" (left-right): ${[domain__debug(domain1), domain__debug(domain2)].join('|')}`, function() { let config = config_create(); config_addVarDomain(config, 'A', domain_toArr(domain1)); config_addVarDomain(config, 'B', domain_toArr(domain2)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); let B = config.allVarNames.indexOf('B'); propagator_neqStepBare(space, config, A, B); fixt_domainEql(space.vardoms[A], domain1); fixt_domainEql(space.vardoms[B], domain2); }); it(`should be "solved" (right-left): ${[domain__debug(domain1), domain__debug(domain2)].join('|')}`, function() { let config = config_create(); config_addVarDomain(config, 'A', domain_toArr(domain2)); config_addVarDomain(config, 'B', domain_toArr(domain1)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); let B = config.allVarNames.indexOf('B'); propagator_neqStepBare(space, config, A, B); fixt_domainEql(space.vardoms[A], domain2); fixt_domainEql(space.vardoms[B], domain1); }); it(`should reject if same (left-left): ${[domain__debug(domain1), domain__debug(domain2)].join('|')}`, function() { let config = config_create(); config_addVarDomain(config, 'A', domain_toArr(domain1)); config_addVarDomain(config, 'B', domain_toArr(domain1)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); let B = config.allVarNames.indexOf('B'); propagator_neqStepBare(space, config, A, B); fixt_domainEql(space.vardoms[A], fixt_dom_empty()); fixt_domainEql(space.vardoms[B], fixt_dom_empty()); }); it(`should reject if same (right-right): ${[domain__debug(domain1), domain__debug(domain2)].join('|')}`, function() { let config = config_create(); config_addVarDomain(config, 'A', domain_toArr(domain2)); config_addVarDomain(config, 'B', domain_toArr(domain2)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); let B = config.allVarNames.indexOf('B'); propagator_neqStepBare(space, config, A, B); fixt_domainEql(space.vardoms[A], fixt_dom_empty()); fixt_domainEql(space.vardoms[B], fixt_dom_empty()); }); } describe('with array', function() { test(fixt_dom_solved(SUP), fixt_dom_solved(SUP - 1)); test(fixt_dom_solved(SUP - 1), fixt_dom_solved(SUP - 2)); test(fixt_dom_solved(SUP - 1), fixt_dom_solved(SUP - 20)); test(fixt_dom_solved(SUP), fixt_dom_solved(500)); test(fixt_dom_solved(800), fixt_dom_solved(801)); }); describe('with numbers', function() { test(fixt_dom_nums(0), fixt_dom_nums(1)); test(fixt_dom_nums(1), fixt_dom_nums(2)); test(fixt_dom_nums(1), fixt_dom_nums(15)); test(fixt_dom_nums(0), fixt_dom_nums(5)); test(fixt_dom_nums(8), fixt_dom_nums(1)); }); describe('with solved numbers', function() { test(fixt_dom_solved(0), fixt_dom_solved(1)); test(fixt_dom_solved(1), fixt_dom_solved(2)); test(fixt_dom_solved(1), fixt_dom_solved(15)); test(fixt_dom_solved(0), fixt_dom_solved(5)); test(fixt_dom_solved(8), fixt_dom_solved(1)); }); }); describe('with LOG', function() { before(function() { ASSERT_SET_LOG(LOG_FLAG_PROPSTEPS); }); it('should improve test coverage by enabling logging', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_range(SUB, SUP)); config_addVarDomain(config, 'B', fixt_arrdom_ranges([0, 10], [20, 300])); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); let B = config.allVarNames.indexOf('B'); propagator_neqStepBare(space, config, A, B); expect(true).to.eql(true); }); after(function() { ASSERT_SET_LOG(LOG_FLAG_NONE); }); }); }); // TOFIX: migrate and dedupe these tests: // describe('fdvar_forceNeqInline', function() { // // these tests are pretty much tbd // // it('should exist', function() { // expect(fdvar_forceNeqInline).to.be.a('function'); // }); // // describe('with array', function() { // // it('should return NO_CHANGES if neither domain is solved', function() { // let A = fdvar_create('A', specDomainCreateRanges([10, 20], [30, 40], [50, 60])); // let B = fdvar_create('B', specDomainCreateRanges([15, 35], [40, 50])); // let R = fdvar_forceNeqInline(A, B); // // expect(R).to.eql(NO_CHANGES); // expect(A).to.eql(fdvar_create('A', specDomainCreateRanges([10, 20], [30, 40], [50, 60]))); // expect(B).to.eql(fdvar_create('B', specDomainCreateRanges([15, 35], [40, 50]))); // }); // // it('should return SOME_CHANGES if left domain is solved', function() { // let A = fdvar_create('A', specDomainCreateRanges([20, 20])); // let B = fdvar_create('B', specDomainCreateRanges([15, 35], [40, 50])); // let R = fdvar_forceNeqInline(A, B); // // expect(R).to.eql(SOME_CHANGES); // expect(A).to.eql(fdvar_create('A', specDomainCreateRanges([20, 20]))); // expect(B).to.eql(fdvar_create('B', specDomainCreateRanges([15, 19], [21, 35], [40, 50]))); // }); // // it('should return SOME_CHANGES if right domain is solved', function() { // let A = fdvar_create('A', specDomainCreateRanges([15, 35], [40, 50])); // let B = fdvar_create('B', specDomainCreateRanges([20, 20])); // let R = fdvar_forceNeqInline(A, B); // // expect(R).to.eql(SOME_CHANGES); // expect(A).to.eql(fdvar_create('A', specDomainCreateRanges([15, 19], [21, 35], [40, 50]))); // expect(B).to.eql(fdvar_create('B', specDomainCreateRanges([20, 20]))); // }); // // it('should return NO_CHANGES if domains are equal but not solved (small)', function() { // let A = fdvar_create('A', specDomainCreateRanges([SUP - 1, SUP])); // let B = fdvar_create('B', specDomainCreateRanges([SUP - 1, SUP])); // let R = fdvar_forceNeqInline(A, B); // // expect(R).to.eql(NO_CHANGES); // expect(A).to.eql(fdvar_create('A', specDomainCreateRanges([SUP - 1, SUP]))); // expect(B).to.eql(fdvar_create('B', specDomainCreateRanges([SUP - 1, SUP]))); // }); // // it('should return NO_CHANGES if domains are equal but not solved (large)', function() { // let A = fdvar_create('A', specDomainCreateRanges([10, 20], [30, 40], [50, 60])); // let B = fdvar_create('B', specDomainCreateRanges([10, 20], [30, 40], [50, 60])); // let R = fdvar_forceNeqInline(A, B); // // expect(R).to.eql(NO_CHANGES); // expect(A).to.eql(fdvar_create('A', specDomainCreateRanges([10, 20], [30, 40], [50, 60]))); // expect(B).to.eql(fdvar_create('B', specDomainCreateRanges([10, 20], [30, 40], [50, 60]))); // }); // // // TOFIX: this exposes a serious problem with assumptions on solved vars // it('should return REJECTED if domains resolved to same value', function() { // let A = fdvar_create('A', specDomainCreateRanges([SUP, SUP])); // let B = fdvar_create('B', specDomainCreateRanges([SUP, SUP])); // let R = fdvar_forceNeqInline(A, B); // // expect(R).to.eql(REJECTED); // expect(A).to.eql(fdvar_create('A', specDomainCreateRanges([SUP, SUP]))); // expect(B).to.eql(fdvar_create('B', specDomainSmallEmpty())); // }); // // it('should return NO_CHANGES both domains solve to different value', function() { // let A = fdvar_create('A', specDomainCreateRanges([30, 30])); // let B = fdvar_create('B', specDomainCreateRanges([40, 40])); // let R = fdvar_forceNeqInline(A, B); // // expect(R).to.eql(NO_CHANGES); // expect(A).to.eql(fdvar_create('A', specDomainCreateRanges([30, 30]))); // expect(B).to.eql(fdvar_create('B', specDomainCreateRanges([40, 40]))); // }); // }); // // describe('with numbers', function() { // // it('should return SOME_CHANGES if right side was solved and the left wasnt', function() { // let A = fdvar_create('A', specDomainSmallNums(1, 2, 3, 6, 7, 8)); // let B = fdvar_create('B', specDomainSmallNums(2)); // let R = fdvar_forceNeqInline(A, B); // // expect(R).to.eql(SOME_CHANGES); // expect(A).to.eql(fdvar_create('A', specDomainSmallNums(1, 3, 6, 7, 8))); // expect(B).to.eql(fdvar_create('B', specDomainSmallNums(2))); // }); // // it('should return SOME_CHANGES if left side was solved and the right had it', function() { // let A = fdvar_create('A', specDomainSmallNums(2)); // let B = fdvar_create('B', specDomainSmallNums(1, 2, 3, 6, 7, 8)); // let R = fdvar_forceNeqInline(A, B); // // expect(R).to.eql(SOME_CHANGES); // expect(A).to.eql(fdvar_create('A', specDomainSmallNums(2))); // expect(B).to.eql(fdvar_create('B', specDomainSmallNums(1, 3, 6, 7, 8))); // }); // // it('should return NO_CHANGES if right side was solved and the left already did not have it', function() { // let A = fdvar_create('A', specDomainSmallNums(1, 2, 3, 6, 7, 8)); // let B = fdvar_create('B', specDomainSmallNums(4)); // let R = fdvar_forceNeqInline(A, B); // // expect(R).to.eql(NO_CHANGES); // expect(A).to.eql(fdvar_create('A', specDomainSmallNums(1, 2, 3, 6, 7, 8))); // expect(B).to.eql(fdvar_create('B', specDomainSmallNums(4))); // }); // // it('should return NO_CHANGES if left side was solved and the right already did not have it', function() { // let A = fdvar_create('A', specDomainSmallNums(4)); // let B = fdvar_create('B', specDomainSmallNums(1, 2, 3, 6, 7, 8)); // let R = fdvar_forceNeqInline(A, B); // // expect(R).to.eql(NO_CHANGES); // expect(A).to.eql(fdvar_create('A', specDomainSmallNums(4))); // expect(B).to.eql(fdvar_create('B', specDomainSmallNums(1, 2, 3, 6, 7, 8))); // }); // // it('should return NO_CHANGES if neither domain is solved', function() { // let A = fdvar_create('A', specDomainSmallNums(1, 2, 3, 6, 7, 8)); // let B = fdvar_create('B', specDomainSmallNums(2, 3, 4, 5, 6, 7)); // let R = fdvar_forceNeqInline(A, B); // // expect(R).to.eql(NO_CHANGES); // expect(A).to.eql(fdvar_create('A', specDomainSmallNums(1, 2, 3, 6, 7, 8))); // expect(B).to.eql(fdvar_create('B', specDomainSmallNums(2, 3, 4, 5, 6, 7))); // }); // // it('should return NO_CHANGES if both domains are solved to different value', function() { // let A = fdvar_create('A', specDomainSmallNums(0)); // let B = fdvar_create('B', specDomainSmallNums(1)); // let R = fdvar_forceNeqInline(A, B); // // expect(R).to.eql(NO_CHANGES); // expect(A).to.eql(fdvar_create('A', specDomainSmallNums(0))); // expect(B).to.eql(fdvar_create('B', specDomainSmallNums(1))); // }); // }); // // describe('with array and numbers', function() { // // it('should work with an array and a number', function() { // let A = fdvar_create('A', specDomainCreateRange(10, 100)); // let B = fdvar_create('B', specDomainSmallRange(5, 15)); // let R = fdvar_forceNeqInline(A, B); // // expect(R).to.eql(NO_CHANGES); // expect(A).to.eql(fdvar_create('A', specDomainCreateRange(10, 100))); // expect(B).to.eql(fdvar_create('B', specDomainSmallRange(5, 15))); // }); // // it('should work with a numbert and an array', function() { // let A = fdvar_create('A', specDomainSmallNums(1, 2, 3, 10, 11, 13)); // let B = fdvar_create('B', specDomainCreateRange(8, 100)); // let R = fdvar_forceNeqInline(A, B); // // expect(R).to.eql(NO_CHANGES); // expect(A).to.eql(fdvar_create('A', specDomainSmallNums(1, 2, 3, 10, 11, 13))); // expect(B).to.eql(fdvar_create('B', specDomainCreateRange(8, 100))); // }); // }); // });