UNPKG

finitedomain

Version:

A fast feature rich finite domain solver

1,273 lines (1,005 loc) 76.6 kB
import expect from '../../fixtures/mocha_proxy.fixt'; import { fixt_arrdom_nums, fixt_arrdom_range, fixt_arrdom_ranges, fixt_arrdom_solved, fixt_dom_empty, fixt_dom_nums, fixt_dom_range, fixt_dom_ranges, fixt_dom_solved, fixt_domainEql, } from '../../fixtures/domain.fixt'; import { LOG_FLAG_CHOICE, LOG_FLAG_NONE, ASSERT_SET_LOG, } from '../../../src/helpers'; import { domain__debug, } from '../../../src/domain'; import distribute_getNextDomainForVar, { FIRST_CHOICE, SECOND_CHOICE, THIRD_CHOICE, NO_CHOICE, _distribute_getNextDomainForVar, distribution_valueByList, distribution_valueByMarkov, distribution_valueByMax, distribution_valueByMid, distribution_valueByMin, distribution_valueByMinMaxCycle, distribution_valueBySplitMax, distribution_valueBySplitMin, } from '../../../src/distribution/value'; import { config_create, config_addVarRange, config_addVarDomain, } from '../../../src/config'; import { space_createRoot, space_getDomainArr, space_initFromConfig, } from '../../../src/space'; import Solver from '../../../src/solver'; describe('distribution/value.spec', function() { it('should exist', function() { expect(distribute_getNextDomainForVar).to.be.a('function'); // TODO: test this function properly }); it('should throw for unknown name', function() { let config = config_create(); let space = space_createRoot(); expect(_ => _distribute_getNextDomainForVar('error', space, config)).to.throw('unknown next var func'); }); describe('distribution_valueByThrow', function() { it('should throw', function() { let config = config_create(); let space = space_createRoot(); expect(_ => _distribute_getNextDomainForVar('throw', space, config)).to.throw('not expecting to pick this distributor'); }); }); describe('distribution naive', function() { it('should work', function() { let config = config_create(); config_addVarRange(config, 'A', 0, 0); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); let dom = _distribute_getNextDomainForVar('naive', space, config, A); fixt_domainEql(dom, fixt_dom_nums(0)); }); }); describe('distribution_valueByMin', function() { it('should exist', function() { expect(distribution_valueByMin).to.be.a('function'); }); describe('with array', function() { it('should pick lo for FIRST_CHOICE ', function() { let config = config_create(); config_addVarRange(config, 'A', 101, 102); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); fixt_domainEql(distribution_valueByMin(space, A, FIRST_CHOICE), fixt_dom_solved(101)); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(101, 102)); }); it('should pick domain^lo for SECOND_CHOICE', function() { let config = config_create(); config_addVarRange(config, 'A', 101, 102); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMin(space, A, FIRST_CHOICE); fixt_domainEql(distribution_valueByMin(space, A, SECOND_CHOICE), fixt_dom_solved(102)); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(101, 102)); }); it('should return NO_CHOICE for THIRD_CHOICE', function() { let config = config_create(); config_addVarRange(config, 'A', 101, 102); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMin(space, A, FIRST_CHOICE); distribution_valueByMin(space, A, SECOND_CHOICE); expect(distribution_valueByMin(space, A, THIRD_CHOICE)).to.eql(NO_CHOICE); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(101, 102)); }); it('should intersect and not use lower range blindly for FIRST_CHOICE', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_ranges([110, 111], [113, 120])); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); fixt_domainEql(distribution_valueByMin(space, A, FIRST_CHOICE), fixt_dom_solved(110)); }); it('should intersect and not use lower range blindly for SECOND_CHOICE', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_ranges([110, 111], [113, 120])); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMin(space, A, FIRST_CHOICE); fixt_domainEql(distribution_valueByMin(space, A, SECOND_CHOICE), fixt_dom_ranges([111, 111], [113, 120])); }); it('should reject a "solved" var', function() { let config = config_create(); config_addVarRange(config, 'A', 110, 110); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); // note: only rejects with ASSERTs expect(() => distribution_valueByMin(space, A, FIRST_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); expect(() => distribution_valueByMin(space, A, SECOND_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); expect(() => distribution_valueByMin(space, A, THIRD_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); }); it('should reject a "rejected" var', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_nums(0)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); space.vardoms[A] = fixt_dom_empty(); // note: only rejects with ASSERTs expect(() => distribution_valueByMin(space, A, FIRST_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); expect(() => distribution_valueByMin(space, A, SECOND_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); expect(() => distribution_valueByMin(space, A, THIRD_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); }); }); describe('with numbers', function() { it('should pick lo for FIRST_CHOICE ', function() { let config = config_create(); config_addVarRange(config, 'A', 1, 2); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); fixt_domainEql(distribution_valueByMin(space, A, FIRST_CHOICE), fixt_dom_nums(1)); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_nums(1, 2)); }); it('should pick hi for SECOND_CHOICE', function() { let config = config_create(); config_addVarRange(config, 'A', 1, 2); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMin(space, A, FIRST_CHOICE); fixt_domainEql(distribution_valueByMin(space, A, SECOND_CHOICE), fixt_dom_solved(2)); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_nums(1, 2)); }); it('should return NO_CHOICE for THIRD_CHOICE', function() { let config = config_create(); config_addVarRange(config, 'A', 1, 2); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMin(space, A, FIRST_CHOICE); distribution_valueByMin(space, A, SECOND_CHOICE); expect(distribution_valueByMin(space, A, THIRD_CHOICE)).to.eql(NO_CHOICE); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_nums(1, 2)); }); it('should intersect and not use lower range blindly for FIRST_CHOICE', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_nums(10, 11, 13, 14, 15)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); fixt_domainEql(distribution_valueByMin(space, A, FIRST_CHOICE), fixt_dom_nums(10)); }); it('should intersect and not use lower range blindly for SECOND_CHOICE', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_nums(10, 11, 13, 14, 15)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMin(space, A, FIRST_CHOICE); fixt_domainEql(distribution_valueByMin(space, A, SECOND_CHOICE), fixt_dom_nums(11, 13, 14, 15)); }); it('should reject a "solved" var', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_nums(10)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); // note: only rejects with ASSERTs expect(() => distribution_valueByMin(space, A, FIRST_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); expect(() => distribution_valueByMin(space, A, SECOND_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); expect(() => distribution_valueByMin(space, A, THIRD_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); }); it('should reject a "rejected" var', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_nums(100)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); space.vardoms[A] = fixt_dom_empty(); // note: only rejects with ASSERTs expect(() => distribution_valueByMin(space, A, FIRST_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); expect(() => distribution_valueByMin(space, A, SECOND_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); expect(() => distribution_valueByMin(space, A, THIRD_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); }); }); describe('with LOG', function() { before(function() { ASSERT_SET_LOG(LOG_FLAG_CHOICE); }); it('should improve test coverage by enabling logging', function() { let config = config_create(); config_addVarRange(config, 'A', 1, 2); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMin(space, A, FIRST_CHOICE); expect(true).to.eql(true); }); after(function() { ASSERT_SET_LOG(LOG_FLAG_NONE); }); }); }); describe('distribution_valueByList', function() { it('should exist', function() { expect(distribution_valueByList).to.be.a('function'); }); function test(choice, inDomain, list, outDomain) { let desc = 'choice: ' + choice + ', input: ' + domain__debug(inDomain) + ', list: [' + list + '], output: ' + domain__debug(outDomain); it(desc, function() { let solver = new Solver(); solver.decl('A', inDomain, { valtype: 'list', list: list, }); solver._prepare({}); let space = solver.state.space; let config = solver.config; expect(space._class).to.eql('$space'); expect(config._class).to.eql('$config'); let A = config.allVarNames.indexOf('A'); if (choice !== FIRST_CHOICE) distribution_valueByList(space, config, A, FIRST_CHOICE); if (choice !== SECOND_CHOICE) distribution_valueByList(space, config, A, SECOND_CHOICE); let domain = distribution_valueByList(space, config, A, choice); if (outDomain === NO_CHOICE) expect(domain).to.eql(NO_CHOICE); else fixt_domainEql(domain, outDomain); }); } test(FIRST_CHOICE, fixt_arrdom_range(0, 500), [5, 10, 6], fixt_dom_solved(5)); test(FIRST_CHOICE, fixt_arrdom_range(10, 500), [5, 10, 6], fixt_dom_solved(10)); test(FIRST_CHOICE, fixt_arrdom_range(10, 500), [5, 4, 6, 2], NO_CHOICE); test(SECOND_CHOICE, fixt_arrdom_range(0, 500), [5, 10, 6], fixt_arrdom_ranges([0, 4], [6, 500])); test(SECOND_CHOICE, fixt_arrdom_range(10, 500), [5, 10, 6], fixt_arrdom_range(11, 500)); test(SECOND_CHOICE, fixt_arrdom_range(10, 500), [5, 4, 6, 2], NO_CHOICE); describe('with LOG', function() { before(function() { ASSERT_SET_LOG(LOG_FLAG_CHOICE); }); it('should improve test coverage by enabling logging', function() { let solver = new Solver(); solver.decl('A', undefined, { valtype: 'list', list: [5, 10, 6], }); solver._prepare({}); let space = solver.state.space; let config = solver.config; let varIndex = 0; let choiceIndex = FIRST_CHOICE; expect(space._class).to.eql('$space'); expect(config._class).to.eql('$config'); distribution_valueByList(space, config, varIndex, choiceIndex); expect(true).to.eql(true); }); after(function() { ASSERT_SET_LOG(LOG_FLAG_NONE); }); }); }); describe('distribution_valueByMarkov', function() { it('should return NO_CHOICE if it receives no values', function() { let solver = new Solver(); solver.decl('A', undefined, { valtype: 'markov', matrix: [{ vector: [], }], legend: [], }); solver._prepare({}); let space = solver.state.space; let config = solver.config; let varIndex = 0; let choiceIndex = FIRST_CHOICE; expect(space._class).to.eql('$space'); expect(config._class).to.eql('$config'); let value = distribution_valueByMarkov(space, config, varIndex, choiceIndex); expect(value).to.eql(NO_CHOICE); }); it('should throw if given domain is solved', function() { let solver = new Solver(); solver.decl('A', 100, { valtype: 'markov', matrix: [{ vector: [100], }], legend: [1], }); solver._prepare({}); let space = solver.state.space; let config = solver.config; let varIndex = 0; let choiceIndex = SECOND_CHOICE; // ! expect(space._class).to.eql('$space'); expect(config._class).to.eql('$config'); fixt_domainEql(space.vardoms[varIndex], fixt_dom_nums(100)); space._lastChosenValue = 100; expect(_ => distribution_valueByMarkov(space, config, varIndex, choiceIndex)).to.throw('DOMAIN_SHOULD_BE_UNDETERM'); }); describe('with LOG', function() { before(function() { ASSERT_SET_LOG(LOG_FLAG_CHOICE); }); it('should improve test coverage by enabling logging', function() { let solver = new Solver(); solver.decl('A', undefined, { valtype: 'markov', matrix: [{ vector: [], }], legend: [], }); solver._prepare({}); let space = solver.state.space; let config = solver.config; let varIndex = 0; let choiceIndex = FIRST_CHOICE; expect(space._class).to.eql('$space'); expect(config._class).to.eql('$config'); distribution_valueByMarkov(space, config, varIndex, choiceIndex); expect(true).to.eql(true); }); after(function() { ASSERT_SET_LOG(LOG_FLAG_NONE); }); }); }); describe('distribution_valueByMax', function() { it('should exist', function() { expect(distribution_valueByMax).to.be.a('function'); }); describe('with array', function() { it('should pick lo for FIRST_CHOICE ', function() { let config = config_create(); config_addVarRange(config, 'A', 101, 102); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); fixt_domainEql(distribution_valueByMax(space, A, FIRST_CHOICE), fixt_dom_range(102, 102)); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(101, 102)); }); it('should pick hi for SECOND_CHOICE', function() { let config = config_create(); config_addVarRange(config, 'A', 101, 102); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMax(space, A, FIRST_CHOICE); fixt_domainEql(distribution_valueByMax(space, A, SECOND_CHOICE), fixt_dom_solved(101)); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(101, 102)); }); it('should return NO_CHOICE for THIRD_CHOICE', function() { let config = config_create(); config_addVarRange(config, 'A', 101, 102); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMax(space, A, FIRST_CHOICE); distribution_valueByMax(space, A, SECOND_CHOICE); expect(distribution_valueByMax(space, A, THIRD_CHOICE)).to.eql(NO_CHOICE); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(101, 102)); }); it('should intersect and not use lower range blindly for FIRST_CHOICE', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_ranges([110, 117], [119, 120])); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); fixt_domainEql(distribution_valueByMax(space, A, FIRST_CHOICE), fixt_dom_solved(120)); }); it('should intersect and not use lower range blindly for SECOND_CHOICE', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_ranges([110, 117], [119, 120])); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMax(space, A, FIRST_CHOICE); fixt_domainEql(distribution_valueByMax(space, A, SECOND_CHOICE), fixt_dom_ranges([110, 117], [119, 119])); }); it('should reject a "solved" var', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_solved(120)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); // note: only rejects with ASSERTs expect(() => distribution_valueByMax(space, A, FIRST_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); expect(() => distribution_valueByMax(space, A, SECOND_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); expect(() => distribution_valueByMax(space, A, THIRD_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); }); it('should reject a "rejected" var', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_nums(100)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); space.vardoms[A] = fixt_dom_empty(); // note: only rejects with ASSERTs expect(() => distribution_valueByMax(space, A, FIRST_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); expect(() => distribution_valueByMax(space, A, SECOND_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); expect(() => distribution_valueByMax(space, A, THIRD_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); }); }); describe('with numbers', function() { it('should pick lo for FIRST_CHOICE ', function() { let config = config_create(); config_addVarRange(config, 'A', 6, 10); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); fixt_domainEql(distribution_valueByMax(space, A, FIRST_CHOICE), fixt_dom_nums(10)); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(6, 10)); }); it('should pick hi for SECOND_CHOICE', function() { let config = config_create(); config_addVarRange(config, 'A', 6, 10); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMax(space, A, FIRST_CHOICE); fixt_domainEql(distribution_valueByMax(space, A, SECOND_CHOICE), fixt_dom_range(6, 9)); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(6, 10)); }); it('should return NO_CHOICE for third choice', function() { let config = config_create(); config_addVarRange(config, 'A', 6, 10); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMax(space, A, FIRST_CHOICE); distribution_valueByMax(space, A, SECOND_CHOICE); expect(distribution_valueByMax(space, A, THIRD_CHOICE)).to.eql(NO_CHOICE); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(6, 10)); }); it('should intersect and not use lower range blindly for FIRST_CHOICE', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_nums(2, 3, 4, 6, 7, 8, 10, 11)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); fixt_domainEql(distribution_valueByMax(space, A, FIRST_CHOICE), fixt_dom_nums(11)); }); it('should intersect and not use lower range blindly for SECOND_CHOICE', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_nums(2, 3, 4, 6, 7, 8, 10, 11)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMax(space, A, FIRST_CHOICE); fixt_domainEql(distribution_valueByMax(space, A, SECOND_CHOICE), fixt_dom_nums(2, 3, 4, 6, 7, 8, 10)); }); it('should reject a "solved" var', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_nums(0)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); // note: only rejects with ASSERTs expect(() => distribution_valueByMax(space, A, FIRST_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); expect(() => distribution_valueByMax(space, A, SECOND_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); expect(() => distribution_valueByMax(space, A, THIRD_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); }); it('should reject a "rejected" var', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_nums(100)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); space.vardoms[A] = fixt_dom_empty(); // note: only rejects with ASSERTs expect(() => distribution_valueByMax(space, A, FIRST_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); expect(() => distribution_valueByMax(space, A, SECOND_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); expect(() => distribution_valueByMax(space, A, THIRD_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); }); }); describe('with LOG', function() { before(function() { ASSERT_SET_LOG(LOG_FLAG_CHOICE); }); it('should improve test coverage by enabling logging', function() { let config = config_create(); config_addVarRange(config, 'A', 1, 2); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMax(space, A, FIRST_CHOICE); expect(true).to.eql(true); }); after(function() { ASSERT_SET_LOG(LOG_FLAG_NONE); }); }); }); describe('distribution_valueByMid', function() { // note: counts elements in domain and takes the middle one, not by value // note: for uneven elements in a domains it takes the first value above middle it('should exist', function() { expect(distribution_valueByMid).to.be.a('function'); }); describe('with array', function() { describe('binary', function() { it('should pick hi for FIRST_CHOICE ', function() { let config = config_create(); config_addVarRange(config, 'A', 101, 102); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); fixt_domainEql(distribution_valueByMid(space, A, FIRST_CHOICE), fixt_dom_range(102, 102)); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(101, 102)); }); it('should pick hi for SECOND_CHOICE', function() { let config = config_create(); config_addVarRange(config, 'A', 101, 102); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMid(space, A, FIRST_CHOICE); fixt_domainEql(distribution_valueByMid(space, A, SECOND_CHOICE), fixt_dom_solved(101)); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(101, 102)); }); it('should return NO_CHOICE for THIRD_CHOICE', function() { let config = config_create(); config_addVarRange(config, 'A', 101, 102); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); expect(distribution_valueByMid(space, A, THIRD_CHOICE)).to.eql(NO_CHOICE); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(101, 102)); }); }); describe('ternary', function() { it('should pick mid for FIRST_CHOICE ', function() { let config = config_create(); config_addVarRange(config, 'A', 101, 103); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); fixt_domainEql(distribution_valueByMid(space, A, FIRST_CHOICE), fixt_dom_range(102, 102)); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(101, 103)); }); it('should remove mid for SECOND_CHOICE', function() { let config = config_create(); config_addVarRange(config, 'A', 101, 103); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMid(space, A, FIRST_CHOICE); fixt_domainEql(distribution_valueByMid(space, A, SECOND_CHOICE), fixt_dom_ranges([101, 101], [103, 103])); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(101, 103)); }); it('should return NO_CHOICE for THIRD_CHOICE', function() { let config = config_create(); config_addVarRange(config, 'A', 101, 103); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMid(space, A, FIRST_CHOICE); distribution_valueByMid(space, A, SECOND_CHOICE); expect(distribution_valueByMid(space, A, THIRD_CHOICE)).to.eql(NO_CHOICE); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(101, 103)); }); }); describe('quad', function() { it('should pick low-mid for FIRST_CHOICE ', function() { let config = config_create(); config_addVarRange(config, 'A', 101, 104); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); fixt_domainEql(distribution_valueByMid(space, A, FIRST_CHOICE), fixt_dom_range(103, 103)); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(101, 104)); }); it('should remove mid for SECOND_CHOICE', function() { let config = config_create(); config_addVarRange(config, 'A', 101, 104); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMid(space, A, FIRST_CHOICE); fixt_domainEql(distribution_valueByMid(space, A, SECOND_CHOICE), fixt_dom_ranges([101, 102], [104, 104])); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(101, 104)); }); it('should return NO_CHOICE for THIRD_CHOICE', function() { let config = config_create(); config_addVarRange(config, 'A', 101, 104); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMid(space, A, FIRST_CHOICE); distribution_valueByMid(space, A, SECOND_CHOICE); expect(distribution_valueByMid(space, A, THIRD_CHOICE)).to.eql(NO_CHOICE); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(101, 104)); }); }); describe('100-120', function() { it('should pick mid for FIRST_CHOICE ', function() { let config = config_create(); config_addVarRange(config, 'A', 100, 120); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); fixt_domainEql(distribution_valueByMid(space, A, FIRST_CHOICE), fixt_dom_range(110, 110)); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(100, 120)); }); it('should remove mid for SECOND_CHOICE', function() { let config = config_create(); config_addVarRange(config, 'A', 100, 120); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMid(space, A, FIRST_CHOICE); fixt_domainEql(distribution_valueByMid(space, A, SECOND_CHOICE), fixt_dom_ranges([100, 109], [111, 120])); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(100, 120)); }); it('should return NO_CHOICE for THIRD_CHOICE', function() { let config = config_create(); config_addVarRange(config, 'A', 100, 120); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMid(space, A, FIRST_CHOICE); distribution_valueByMid(space, A, SECOND_CHOICE); expect(distribution_valueByMid(space, A, THIRD_CHOICE)).to.eql(NO_CHOICE); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(100, 120)); }); }); describe('100-121', function() { it('should pick hi-mid for FIRST_CHOICE ', function() { let config = config_create(); config_addVarRange(config, 'A', 100, 121); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); fixt_domainEql(distribution_valueByMid(space, A, FIRST_CHOICE), fixt_dom_range(111, 111)); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(100, 121)); }); it('should remove mid for SECOND_CHOICE', function() { let config = config_create(); config_addVarRange(config, 'A', 100, 121); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMid(space, A, FIRST_CHOICE); fixt_domainEql(distribution_valueByMid(space, A, SECOND_CHOICE), fixt_dom_ranges([100, 110], [112, 121])); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(100, 121)); }); it('should return NO_CHOICE for THIRD_CHOICE', function() { let config = config_create(); config_addVarRange(config, 'A', 100, 121); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMid(space, A, FIRST_CHOICE); distribution_valueByMid(space, A, SECOND_CHOICE); expect(distribution_valueByMid(space, A, THIRD_CHOICE)).to.eql(NO_CHOICE); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(100, 121)); }); }); it('should intersect and not use lower range blindly for FIRST_CHOICE', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_ranges([110, 112], [118, 120])); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); fixt_domainEql(distribution_valueByMid(space, A, FIRST_CHOICE), fixt_dom_solved(118)); }); it('should intersect and not use lower range blindly for SECOND_CHOICE', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_ranges([110, 112], [118, 120])); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMid(space, A, FIRST_CHOICE); fixt_domainEql(distribution_valueByMid(space, A, SECOND_CHOICE), fixt_dom_ranges([110, 112], [119, 120])); }); it('should reject a "solved" var', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_solved(120)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); // note: only rejects with ASSERTs expect(() => distribution_valueByMid(space, A, FIRST_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); expect(() => distribution_valueByMid(space, A, SECOND_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); expect(() => distribution_valueByMid(space, A, THIRD_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); }); it('should reject a "rejected" var', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_nums(100)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); space.vardoms[A] = fixt_dom_empty(); // note: only rejects with ASSERTs expect(() => distribution_valueByMid(space, A, FIRST_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); expect(() => distribution_valueByMid(space, A, SECOND_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); expect(() => distribution_valueByMid(space, A, THIRD_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); }); }); describe('with numbers', function() { describe('binary', function() { it('should pick hi for FIRST_CHOICE ', function() { let config = config_create(); config_addVarRange(config, 'A', 1, 2); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); fixt_domainEql(distribution_valueByMid(space, A, FIRST_CHOICE), fixt_dom_nums(2)); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_nums(1, 2)); }); it('should pick hi for SECOND_CHOICE', function() { let config = config_create(); config_addVarRange(config, 'A', 1, 2); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMid(space, A, FIRST_CHOICE); fixt_domainEql(distribution_valueByMid(space, A, SECOND_CHOICE), fixt_dom_solved(1)); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_nums(1, 2)); }); it('should return NO_CHOICE for THIRD_CHOICE', function() { let config = config_create(); config_addVarRange(config, 'A', 1, 2); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); expect(distribution_valueByMid(space, A, THIRD_CHOICE)).to.eql(NO_CHOICE); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_nums(1, 2)); }); }); describe('ternary', function() { it('should pick mid for FIRST_CHOICE ', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_nums(1, 2, 3)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); fixt_domainEql(distribution_valueByMid(space, A, FIRST_CHOICE), fixt_dom_nums(2)); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_nums(1, 2, 3)); }); it('should remove mid for SECOND_CHOICE', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_nums(1, 2, 3)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMid(space, A, FIRST_CHOICE); fixt_domainEql(distribution_valueByMid(space, A, SECOND_CHOICE), fixt_dom_nums(1, 3)); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_nums(1, 2, 3)); }); it('should return NO_CHOICE for THIRD_CHOICE', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_nums(1, 2, 3)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMid(space, A, FIRST_CHOICE); distribution_valueByMid(space, A, SECOND_CHOICE); expect(distribution_valueByMid(space, A, THIRD_CHOICE)).to.eql(NO_CHOICE); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_nums(1, 2, 3)); }); }); describe('quad', function() { it('should pick low-mid for FIRST_CHOICE ', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_nums(1, 2, 3, 4)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); fixt_domainEql(distribution_valueByMid(space, A, FIRST_CHOICE), fixt_dom_nums(3)); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_nums(1, 2, 3, 4)); }); it('should remove mid for SECOND_CHOICE', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_nums(1, 2, 3, 4)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMid(space, A, FIRST_CHOICE); fixt_domainEql(distribution_valueByMid(space, A, SECOND_CHOICE), fixt_dom_nums(1, 2, 4)); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_nums(1, 2, 3, 4)); }); it('should return NO_CHOICE for THIRD_CHOICE', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_nums(1, 2, 3, 4)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMid(space, A, FIRST_CHOICE); distribution_valueByMid(space, A, SECOND_CHOICE); expect(distribution_valueByMid(space, A, THIRD_CHOICE)).to.eql(NO_CHOICE); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_nums(1, 2, 3, 4)); }); }); describe('0-10', function() { it('should pick mid for FIRST_CHOICE ', function() { let config = config_create(); config_addVarRange(config, 'A', 0, 10); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); fixt_domainEql(distribution_valueByMid(space, A, FIRST_CHOICE), fixt_dom_nums(5)); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(0, 10)); }); it('should remove mid for SECOND_CHOICE', function() { let config = config_create(); config_addVarRange(config, 'A', 0, 10); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMid(space, A, FIRST_CHOICE); fixt_domainEql(distribution_valueByMid(space, A, SECOND_CHOICE), fixt_dom_nums(0, 1, 2, 3, 4, 6, 7, 8, 9, 10)); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(0, 10)); }); it('should return NO_CHOICE for THIRD_CHOICE', function() { let config = config_create(); config_addVarRange(config, 'A', 0, 10); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMid(space, A, FIRST_CHOICE); distribution_valueByMid(space, A, SECOND_CHOICE); expect(distribution_valueByMid(space, A, THIRD_CHOICE)).to.eql(NO_CHOICE); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(0, 10)); }); }); describe('100-121', function() { it('should pick hi-mid for FIRST_CHOICE ', function() { let config = config_create(); config_addVarRange(config, 'A', 0, 11); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); fixt_domainEql(distribution_valueByMid(space, A, FIRST_CHOICE), fixt_dom_nums(6)); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(0, 11)); }); it('should remove mid for SECOND_CHOICE', function() { let config = config_create(); config_addVarRange(config, 'A', 0, 11); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMid(space, A, FIRST_CHOICE); fixt_domainEql(distribution_valueByMid(space, A, SECOND_CHOICE), fixt_dom_nums(0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11)); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(0, 11)); }); it('should return NO_CHOICE for THIRD_CHOICE', function() { let config = config_create(); config_addVarRange(config, 'A', 0, 11); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMid(space, A, FIRST_CHOICE); distribution_valueByMid(space, A, SECOND_CHOICE); expect(distribution_valueByMid(space, A, THIRD_CHOICE)).to.eql(NO_CHOICE); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(0, 11)); }); }); it('should pick lo for FIRST_CHOICE ', function() { let config = config_create(); config_addVarRange(config, 'A', 0, 1); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); fixt_domainEql(distribution_valueByMid(space, A, FIRST_CHOICE), fixt_dom_nums(1)); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(0, 1)); }); it('should pick hi for SECOND_CHOICE', function() { let config = config_create(); config_addVarRange(config, 'A', 0, 1); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMid(space, A, FIRST_CHOICE); fixt_domainEql(distribution_valueByMid(space, A, SECOND_CHOICE), fixt_dom_solved(0)); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(0, 1)); }); it('should return NO_CHOICE for THIRD_CHOICE', function() { let config = config_create(); config_addVarRange(config, 'A', 0, 1); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMid(space, A, FIRST_CHOICE); distribution_valueByMid(space, A, SECOND_CHOICE); expect(distribution_valueByMid(space, A, THIRD_CHOICE)).to.eql(NO_CHOICE); fixt_domainEql(space_getDomainArr(space, A), fixt_arrdom_range(0, 1)); }); it('should intersect and not use lower range blindly for FIRST_CHOICE', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_nums(0, 1, 2, 8, 9, 10)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); fixt_domainEql(distribution_valueByMid(space, A, FIRST_CHOICE), fixt_dom_nums(8)); }); it('should intersect and not use lower range blindly for SECOND_CHOICE', function() { let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_nums(0, 1, 2, 8, 9, 10)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMid(space, A, FIRST_CHOICE); fixt_domainEql(distribution_valueByMid(space, A, SECOND_CHOICE), fixt_dom_nums(0, 1, 2, 9, 10)); }); it('should reject a "solved" var', function() { // note: only rejects with ASSERTs let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_nums(5)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); expect(() => distribution_valueByMid(space, A, FIRST_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); expect(() => distribution_valueByMid(space, A, SECOND_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); expect(() => distribution_valueByMid(space, A, THIRD_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); }); it('should reject a "rejected" var', function() { // note: only rejects with ASSERTs // note: only rejects with ASSERTs let config = config_create(); config_addVarDomain(config, 'A', fixt_arrdom_nums(100)); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); space.vardoms[A] = fixt_dom_empty(); expect(() => distribution_valueByMid(space, A, FIRST_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); expect(() => distribution_valueByMid(space, A, SECOND_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); expect(() => distribution_valueByMid(space, A, THIRD_CHOICE)).to.throw('DOMAIN_SHOULD_BE_UNDETERMINED'); }); }); describe('with LOG', function() { before(function() { ASSERT_SET_LOG(LOG_FLAG_CHOICE); }); it('should improve test coverage by enabling logging', function() { let config = config_create(); config_addVarRange(config, 'A', 1, 2); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); distribution_valueByMid(space, A, FIRST_CHOICE); expect(true).to.eql(true); }); after(function() { ASSERT_SET_LOG(LOG_FLAG_NONE); }); }); }); describe('distribution_valueBySplitMin', function() { it('should exist', function() { expect(distribution_valueBySplitMin).to.be.a('function'); }); it('should throw if choice is not a number', function() { let config = config_create(); config_addVarRange(config, 'A', 110, 120); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); expect(_ => distribution_valueBySplitMin(space, A, undefined)).to.throw('CHOICE_SHOULD_BE_NUMBER'); }); describe('with array', function() { it('should pick lower half for FIRST_CHOICE ', function() { let config = config_create(); config_addVarRange(config, 'A', 110, 120); let space = space_createRoot(); space_initFromConfig(space, config); let A = config.allVarNames.indexOf('A'); fixt_domainEql(distribution_valueBySplitMin(space, A, FIRST_CHOICE), fixt_dom_range(110, 115));