UNPKG

finitedomain

Version:

A fast feature rich finite domain solver

1,031 lines (835 loc) 96.8 kB
// a domain, in this lib, is a set of numbers denoted by lo-hi range pairs (inclusive) // for memory and performance reasons finitedomain has three different representations for a domain; // - arrdom: an array with number pairs. mostly used by external apis because its easier to deal with. GC sensitive. // - numdom: a 31bit field where each bit represents the inclusion of a value of its index (0 through 30). 31st bit unused // - strdom: each value of an arrdom encoded as a double 16bit character. fixed range size (4 characters). import expect from '../fixtures/mocha_proxy.fixt'; import { fixt_arrdom_nums, fixt_arrdom_range, fixt_assertStrings, fixt_dom_clone, fixt_dom_empty, fixt_dom_nums, fixt_dom_range, fixt_dom_solved, fixt_domainEql, fixt_numdom_empty, fixt_numdom_nums, fixt_numdom_range, fixt_numdom_solved, fixt_strdom_empty, fixt_strdom_nums, fixt_strdom_range, fixt_strdom_ranges, fixt_strdom_value, } from '../fixtures/domain.fixt'; import { NO_SUCH_VALUE, SMALL_MAX_NUM, SUP, } from '../../src/helpers'; import { EMPTY, NOT_FOUND, STR_RANGE_SIZE, domain_arrToSmallest, domain_str_closeGaps, domain_containsValue, domain_createRange, domain_numnum_createRangeZeroToMax, domain_createValue, domain_divby, domain_fromListToArrdom, domain_getFirstIntersectingValue, domain_getValue, domain_hasNoZero, domain_intersection, domain_isSolved, domain_isZero, domain_max, _domain_str_mergeOverlappingRanges, //domain_middleElement, domain_min, domain_mul, domain_numToStr, domain_str_rangeIndexOf, domain_removeGte, domain_removeLte, domain_removeValue, domain_resolveAsBooly, domain_sharesNoElements, domain_str_simplify, domain_size, _domain_str_quickSortRanges, domain_toArr, domain_toList, domain_toSmallest, domain__debug, } from '../../src/domain'; const FLOOR_FRACTIONS = true; const CEIL_FRACTIONS = false; describe('src/domain.spec', function() { describe('EMPTY', function() { it('should be empty', function() { expect(EMPTY).to.eql(fixt_dom_empty()); }); }); describe('domain_createValue', function() { it('should exist', function() { expect(domain_createValue).to.be.a('function'); }); describe('numdoms', function() { it('should convert small solved values to nums', function() { fixt_domainEql(domain_createRange(0, 10), domain_createRange(0, 10)); fixt_domainEql(domain_createRange(20, SMALL_MAX_NUM), domain_createRange(20, SMALL_MAX_NUM)); fixt_domainEql(domain_createRange(0, SMALL_MAX_NUM), domain_createRange(0, SMALL_MAX_NUM)); }); it('should convert small solved values to nums', function() { expect(domain_createValue(0)).to.eql(fixt_numdom_solved(0)); expect(domain_createValue(1)).to.eql(fixt_numdom_solved(1)); expect(domain_createValue(5)).to.eql(fixt_numdom_solved(5)); expect(domain_createValue(8)).to.eql(fixt_numdom_solved(8)); expect(domain_createValue(12)).to.eql(fixt_numdom_solved(12)); expect(domain_createValue(18)).to.eql(fixt_numdom_solved(18)); expect(domain_createValue(21)).to.eql(fixt_numdom_solved(21)); expect(domain_createValue(29)).to.eql(fixt_numdom_solved(29)); expect(domain_createValue(30)).to.eql(fixt_numdom_solved(30)); }); }); describe('strdoms', function() { it('should convert small values to nums', function() { expect(domain_createValue(31)).to.eql(fixt_numdom_solved(31)); expect(domain_createValue(32)).to.eql(fixt_numdom_solved(32)); expect(domain_createValue(100)).to.eql(fixt_numdom_solved(100)); expect(domain_createValue(56548)).to.eql(fixt_numdom_solved(56548)); expect(domain_createValue(447)).to.eql(fixt_numdom_solved(447)); expect(domain_createValue(SUP)).to.eql(fixt_numdom_solved(SUP)); expect(domain_createValue(SUP - 1)).to.eql(fixt_numdom_solved(SUP - 1)); }); }); }); describe('domain_createRange', function() { it('should exist', function() { expect(domain_createRange).to.be.a('function'); }); describe('numdoms', function() { it('should convert small values to nums', function() { expect(domain_createRange(0, 0)).to.eql(fixt_numdom_solved(0)); expect(domain_createRange(0, 1)).to.eql(fixt_numdom_range(0, 1)); expect(domain_createRange(0, 29)).to.eql(fixt_numdom_range(0, 29)); expect(domain_createRange(0, 30)).to.eql(fixt_numdom_range(0, 30)); expect(domain_createRange(29, 30)).to.eql(fixt_numdom_range(29, 30)); expect(domain_createRange(30, 30)).to.eql(fixt_numdom_solved(30)); expect(domain_createRange(8, 14)).to.eql(fixt_numdom_range(8, 14)); expect(domain_createRange(5, 21)).to.eql(fixt_numdom_range(5, 21)); expect(domain_createRange(24, 28)).to.eql(fixt_numdom_range(24, 28)); }); }); describe('strdoms', function() { it('should convert small values to nums', function() { fixt_assertStrings(domain_createRange(0, SUP), fixt_strdom_range(0, SUP)); expect(domain_createRange(SUP, SUP)).to.eql(fixt_numdom_solved(SUP)); fixt_assertStrings(domain_createRange(SUP - 1, SUP), fixt_strdom_range(SUP - 1, SUP)); fixt_assertStrings(domain_createRange(200, 2000), fixt_strdom_range(200, 2000)); expect(domain_createRange(SUP - 1, SUP - 1)).to.eql(fixt_numdom_solved(SUP - 1)); fixt_assertStrings(domain_createRange(0, SUP - 1), fixt_strdom_range(0, SUP - 1)); fixt_assertStrings(domain_createRange(5, 53243), fixt_strdom_range(5, 53243)); expect(domain_createRange(85755487, 85755487)).to.eql(fixt_numdom_solved(85755487)); }); }); }); describe('domain_createRangeZeroToMax', function() { const ZERO = 1 << 0; const ONE = 1 << 1; const TWO = 1 << 2; const THREE = 1 << 3; const FOUR = 1 << 4; const FIVE = 1 << 5; const SIX = 1 << 6; const SEVEN = 1 << 7; const EIGHT = 1 << 8; const NINE = 1 << 9; const TEN = 1 << 10; const ELEVEN = 1 << 11; const TWELVE = 1 << 12; const THIRTEEN = 1 << 13; const FOURTEEN = 1 << 14; const FIFTEEN = 1 << 15; const SIXTEEN = 1 << 16; const SEVENTEEN = 1 << 17; const EIGHTEEN = 1 << 18; const NINETEEN = 1 << 19; const TWENTY = 1 << 20; const TWENTYONE = 1 << 21; const TWENTYTWO = 1 << 22; const TWENTYTHREE = 1 << 23; const TWENTYFOUR = 1 << 24; const TWENTYFIVE = 1 << 25; const TWENTYSIX = 1 << 26; const TWENTYSEVEN = 1 << 27; const TWENTYEIGHT = 1 << 28; const TWENTYNINE = 1 << 29; const THIRTY = 1 << 30; it('should work', function() { expect(_ => domain_numnum_createRangeZeroToMax(ZERO)).to.throw('INVALID INPUT'); expect(domain_numnum_createRangeZeroToMax(ONE)).to.eql(ZERO | ONE); expect(domain_numnum_createRangeZeroToMax(TWO)).to.eql(ZERO | ONE | TWO); expect(domain_numnum_createRangeZeroToMax(THREE)).to.eql(ZERO | ONE | TWO | THREE); expect(domain_numnum_createRangeZeroToMax(FOUR)).to.eql(ZERO | ONE | TWO | THREE | FOUR); expect(domain_numnum_createRangeZeroToMax(SIX)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX); expect(domain_numnum_createRangeZeroToMax(SEVEN)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN); expect(domain_numnum_createRangeZeroToMax(EIGHT)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT); expect(domain_numnum_createRangeZeroToMax(NINE)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE); expect(domain_numnum_createRangeZeroToMax(TEN)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN); expect(domain_numnum_createRangeZeroToMax(ELEVEN)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN); expect(domain_numnum_createRangeZeroToMax(TWELVE)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE); expect(domain_numnum_createRangeZeroToMax(THIRTEEN)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN); expect(domain_numnum_createRangeZeroToMax(FOURTEEN)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN); expect(domain_numnum_createRangeZeroToMax(FIFTEEN)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN); expect(domain_numnum_createRangeZeroToMax(SIXTEEN)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN); expect(domain_numnum_createRangeZeroToMax(SEVENTEEN)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN); expect(domain_numnum_createRangeZeroToMax(EIGHTEEN)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN | EIGHTEEN); expect(domain_numnum_createRangeZeroToMax(NINETEEN)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN | EIGHTEEN | NINETEEN); expect(domain_numnum_createRangeZeroToMax(TWENTY)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN | EIGHTEEN | NINETEEN | TWENTY); expect(domain_numnum_createRangeZeroToMax(TWENTYONE)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN | EIGHTEEN | NINETEEN | TWENTY | TWENTYONE); expect(domain_numnum_createRangeZeroToMax(TWENTYTWO)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN | EIGHTEEN | NINETEEN | TWENTY | TWENTYONE | TWENTYTWO); expect(domain_numnum_createRangeZeroToMax(TWENTYTHREE)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN | EIGHTEEN | NINETEEN | TWENTY | TWENTYONE | TWENTYTWO | TWENTYTHREE); expect(domain_numnum_createRangeZeroToMax(TWENTYFOUR)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN | EIGHTEEN | NINETEEN | TWENTY | TWENTYONE | TWENTYTWO | TWENTYTHREE | TWENTYFOUR); expect(domain_numnum_createRangeZeroToMax(TWENTYFIVE)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN | EIGHTEEN | NINETEEN | TWENTY | TWENTYONE | TWENTYTWO | TWENTYTHREE | TWENTYFOUR | TWENTYFIVE); expect(domain_numnum_createRangeZeroToMax(TWENTYSIX)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN | EIGHTEEN | NINETEEN | TWENTY | TWENTYONE | TWENTYTWO | TWENTYTHREE | TWENTYFOUR | TWENTYFIVE | TWENTYSIX); expect(domain_numnum_createRangeZeroToMax(TWENTYSEVEN)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN | EIGHTEEN | NINETEEN | TWENTY | TWENTYONE | TWENTYTWO | TWENTYTHREE | TWENTYFOUR | TWENTYFIVE | TWENTYSIX | TWENTYSEVEN); expect(domain_numnum_createRangeZeroToMax(TWENTYEIGHT)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN | EIGHTEEN | NINETEEN | TWENTY | TWENTYONE | TWENTYTWO | TWENTYTHREE | TWENTYFOUR | TWENTYFIVE | TWENTYSIX | TWENTYSEVEN | TWENTYEIGHT); expect(domain_numnum_createRangeZeroToMax(TWENTYNINE)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN | EIGHTEEN | NINETEEN | TWENTY | TWENTYONE | TWENTYTWO | TWENTYTHREE | TWENTYFOUR | TWENTYFIVE | TWENTYSIX | TWENTYSEVEN | TWENTYEIGHT | TWENTYNINE); expect(domain_numnum_createRangeZeroToMax(THIRTY)).to.eql(ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE | TEN | ELEVEN | TWELVE | THIRTEEN | FOURTEEN | FIFTEEN | SIXTEEN | SEVENTEEN | EIGHTEEN | NINETEEN | TWENTY | TWENTYONE | TWENTYTWO | TWENTYTHREE | TWENTYFOUR | TWENTYFIVE | TWENTYSIX | TWENTYSEVEN | TWENTYEIGHT | TWENTYNINE | THIRTY); }); }); describe('fromListToArrdom', function() { it('should exist', function() { expect(domain_fromListToArrdom).to.be.a('function'); }); it('should return empty array for empty lists', function() { expect(domain_fromListToArrdom([])).to.eql([]); }); describe('numdoms', function() { it('should work with [0,0]', function() { expect(domain_fromListToArrdom([0])).to.eql(fixt_arrdom_nums(0)); expect(domain_fromListToArrdom([0, 0])).to.eql(fixt_arrdom_nums(0)); }); it('should work with [0,1]', function() { expect(domain_fromListToArrdom([0, 1])).to.eql(fixt_arrdom_nums(0, 1)); expect(domain_fromListToArrdom([1, 0])).to.eql(fixt_arrdom_nums(0, 1)); expect(domain_fromListToArrdom([0, 0, 1, 1])).to.eql(fixt_arrdom_nums(0, 1)); expect(domain_fromListToArrdom([1, 1, 0, 0])).to.eql(fixt_arrdom_nums(0, 1)); }); it('should throw with negative elements', function() { expect(() => domain_fromListToArrdom([10, 1, -1, 0])).to.throw('A_OOB_INDICATES_BUG'); expect(() => domain_fromListToArrdom([10, 1, -1, 0, 10, 1, -1, 0, 10, 1, -1, 0])).to.throw('A_OOB_INDICATES_BUG'); }); it('should not sort input array', function() { let list = [4, 3, 8, 2]; domain_fromListToArrdom(list, true, true); expect(list).to.eql([4, 3, 8, 2]); }); }); describe('strdoms', function() { it('should work with [SUP,SUP]', function() { expect(domain_fromListToArrdom([SUP])).to.eql(fixt_arrdom_nums(SUP)); expect(domain_fromListToArrdom([SUP, SUP])).to.eql(fixt_arrdom_nums(SUP)); }); it('should work with [SUP-1,SUP]', function() { expect(domain_fromListToArrdom([SUP - 1, SUP])).to.eql(fixt_arrdom_nums(SUP - 1, SUP)); expect(domain_fromListToArrdom([SUP, SUP - 1])).to.eql(fixt_arrdom_nums(SUP, SUP - 1)); expect(domain_fromListToArrdom([SUP - 1, SUP - 1, SUP, SUP])).to.eql(fixt_arrdom_nums(SUP - 1, SUP)); expect(domain_fromListToArrdom([SUP - 1, SUP - 1, SUP, SUP])).to.eql(fixt_arrdom_nums(SUP - 1, SUP)); }); it('should throw with negative elements', function() { expect(() => domain_fromListToArrdom([SUP, 1, -1, 0])).to.throw('A_OOB_INDICATES_BUG'); expect(() => domain_fromListToArrdom([SUP, 1, -1, 0, 10, 1, -1, 0, 10, 1, -1, 0])).to.throw('A_OOB_INDICATES_BUG'); }); it('should not sort input array', function() { let list = [4, SUP, 3, 8, 2]; let domain = domain_fromListToArrdom(list); expect(list).to.eql([4, SUP, 3, 8, 2]); // not changed expect(domain).to.eql(fixt_arrdom_nums(2, SUP, 3, 4, 8)); }); }); }); describe('getValue', function() { it('should exist', function() { expect(domain_getValue).to.be.a('function'); }); describe('strdom', function() { it('should return NOT_FOUND if the domain has more than two values', function() { expect(domain_getValue(fixt_strdom_ranges([10, 20], [30, 40]))).to.equal(NOT_FOUND); }); it('should return NOT_FOUND if the domain is empty', function() { expect(domain_getValue(fixt_numdom_empty())).to.eql(NO_SUCH_VALUE); }); it('should return NO_SUCH_VALUE if the two elements are not equal', function() { expect(domain_getValue(fixt_strdom_nums(321, 1))).to.equal(NO_SUCH_VALUE); }); it('should return value if both elements are same', function() { expect(domain_getValue(fixt_strdom_nums(1700))).to.equal(1700); expect(domain_getValue(fixt_strdom_nums(SUP))).to.equal(SUP); expect(domain_getValue(fixt_strdom_nums(SUP - 1))).to.equal(SUP - 1); expect(domain_getValue(fixt_strdom_nums(32))).to.equal(32); expect(domain_getValue(fixt_strdom_nums(0))).to.equal(0); }); }); describe('numdom', function() { it('should return NOT_FOUND if the domain has more than two values', function() { expect(domain_getValue(fixt_numdom_nums(10, 12))).to.equal(NOT_FOUND); }); it('should return NOT_FOUND if the domain is empty', function() { let A = fixt_numdom_empty(); expect(domain_getValue(A)).to.equal(NOT_FOUND); }); it('should return 12 if it only contains 12', function() { expect(domain_getValue(fixt_numdom_nums(12))).to.equal(12); }); it('should return 0 if it only contains 0', function() { expect(domain_getValue(fixt_numdom_nums(0))).to.equal(0); }); }); describe('solved numdom', function() { it('should work with solved numdoms', function() { for (let i = 0; i <= SMALL_MAX_NUM; ++i) { expect(domain_getValue(fixt_numdom_solved(i)), 'i=' + i).to.equal(i); } }); }); }); describe('toList', function() { it('should exist', function() { expect(domain_toList).to.be.a('function'); }); it('should require a domain', function() { expect(() => domain_toList()).to.throw('ONLY_NORDOM'); }); describe('strdom', function() { it('should work', function() { expect(domain_toList(fixt_strdom_nums(SUP))).to.eql([SUP]); expect(domain_toList(fixt_strdom_nums(SUP - 1, SUP))).to.eql([SUP - 1, SUP]); expect(domain_toList(fixt_strdom_nums(32))).to.eql([32]); expect(domain_toList(fixt_strdom_nums(0))).to.eql([0]); }); }); describe('numdom', function() { it('should accept empty domain', function() { expect(domain_toList(fixt_numdom_empty())).to.eql([]); }); it('[0,0]', function() { expect(domain_toList(fixt_numdom_nums(0))).to.eql([0]); }); it('[0,1]', function() { expect(domain_toList(fixt_numdom_nums(0, 1))).to.eql([0, 1]); }); it('[1,1]', function() { expect(domain_toList(fixt_numdom_nums(1))).to.eql([1]); }); }); describe('solved numdom', function() { it('should work with solved numdoms', function() { for (let i = 0; i <= SMALL_MAX_NUM; ++i) { expect(domain_toList(fixt_numdom_solved(i)), 'i=' + i).to.eql([i]); } }); }); }); describe('getFirstIntersectingValue ', function() { describe('strdom', function() { it('should work with SUP range', function() { let A = fixt_strdom_range(SUP - 3, SUP); expect(domain_getFirstIntersectingValue(A, [SUP])).to.eql(SUP); expect(domain_getFirstIntersectingValue(A, [SUP, 10, 9, 7]), '[0,10,9,7]').to.eql(SUP); expect(domain_getFirstIntersectingValue(A, [10, 9, 7, SUP]), '[10,9,7,0]').to.eql(SUP); expect(domain_getFirstIntersectingValue(A, [SUP - 1])).to.eql(SUP - 1); expect(domain_getFirstIntersectingValue(A, [SUP - 2])).to.eql(SUP - 2); expect(domain_getFirstIntersectingValue(A, [SUP - 3])).to.eql(SUP - 3); expect(domain_getFirstIntersectingValue(A, [99, 100])).to.eql(NO_SUCH_VALUE); }); it('should work with multiple ranges', function() { let A = fixt_strdom_ranges([SUP - 14, SUP - 10], [SUP - 4, SUP]); expect(domain_getFirstIntersectingValue(A, [SUP])).to.eql(SUP); expect(domain_getFirstIntersectingValue(A, [SUP, SUP - 10, SUP - 11])).to.eql(SUP); expect(domain_getFirstIntersectingValue(A, [SUP - 10, SUP - 11, SUP, SUP - 12])).to.eql(SUP - 10); expect(domain_getFirstIntersectingValue(A, [SUP - 1])).to.eql(SUP - 1); expect(domain_getFirstIntersectingValue(A, [SUP - 100, SUP - 12])).to.eql(SUP - 12); expect(domain_getFirstIntersectingValue(A, [SUP - 12, SUP - 100])).to.eql(SUP - 12); }); it('should return NO_SUCH_VALUE if the list not intersect with domain', function() { let A = fixt_strdom_ranges([SUP - 24, SUP - 20], [SUP - 14, SUP - 10], [SUP - 4, SUP]); expect(domain_getFirstIntersectingValue(A, [99, 5, SUP - 12, 11])).to.eql(SUP - 12); expect(domain_getFirstIntersectingValue(A, [99, 5])).to.eql(NO_SUCH_VALUE); }); it('should throw for negative values', function() { let A = fixt_strdom_ranges([SUP - 24, SUP - 20], [SUP - 14, SUP - 10], [SUP - 4, SUP]); expect(() => domain_getFirstIntersectingValue(A, [99, -1, SUP - 12, 11])).to.throw('A_OOB_INDICATES_BUG'); expect(() => domain_getFirstIntersectingValue(A, [99, -1])).to.throw('A_OOB_INDICATES_BUG'); }); }); describe('numdom', function() { it('should work with single range', function() { let A = fixt_numdom_range(0, 3); expect(domain_getFirstIntersectingValue(A, [0])).to.eql(0); expect(domain_getFirstIntersectingValue(A, [0, 10, 9, 7]), '[0,10,9,7]').to.eql(0); expect(domain_getFirstIntersectingValue(A, [10, 9, 7, 0]), '[10,9,7,0]').to.eql(0); expect(domain_getFirstIntersectingValue(A, [1])).to.eql(1); expect(domain_getFirstIntersectingValue(A, [2])).to.eql(2); expect(domain_getFirstIntersectingValue(A, [3])).to.eql(3); expect(domain_getFirstIntersectingValue(A, [99, 100])).to.eql(NO_SUCH_VALUE); }); it('should work with zero domain', function() { let A = fixt_numdom_nums(0); expect(domain_getFirstIntersectingValue(A, [0])).to.eql(0); expect(domain_getFirstIntersectingValue(A, [0, 10, 11])).to.eql(0); expect(domain_getFirstIntersectingValue(A, [10, 11, 0, 12])).to.eql(0); expect(domain_getFirstIntersectingValue(A, [1])).to.eql(NO_SUCH_VALUE); expect(domain_getFirstIntersectingValue(A, [1, 2, 3, 4, 5])).to.eql(NO_SUCH_VALUE); }); it('should work with multiple ranges', function() { let A = fixt_numdom_nums(0, 1, 2, 3, 4, 10, 11, 12, 13, 14); expect(domain_getFirstIntersectingValue(A, [0])).to.eql(0); expect(domain_getFirstIntersectingValue(A, [0, 10, 11])).to.eql(0); expect(domain_getFirstIntersectingValue(A, [10, 11, 0, 12])).to.eql(10); expect(domain_getFirstIntersectingValue(A, [1])).to.eql(1); expect(domain_getFirstIntersectingValue(A, [100, 12])).to.eql(12); expect(domain_getFirstIntersectingValue(A, [12, 100])).to.eql(12); }); it('should return NO_SUCH_VALUE if the list not intersect with domain', function() { let A = fixt_numdom_nums(0, 1, 2, 3, 4, 10, 11, 12, 13, 14); expect(domain_getFirstIntersectingValue(A, [99, 5, 12, 11])).to.eql(12); expect(domain_getFirstIntersectingValue(A, [99, 5])).to.eql(NO_SUCH_VALUE); }); it('should throw for negative values', function() { let A = fixt_numdom_nums(0, 1, 2, 3, 4, 10, 11, 12, 13, 14); expect(() => domain_getFirstIntersectingValue(A, [99, -1, 12, 11])).to.throw('A_OOB_INDICATES_BUG'); expect(() => domain_getFirstIntersectingValue(A, [99, -1])).to.throw('A_OOB_INDICATES_BUG'); }); }); describe('solved numdom', function() { it('should work with solved numdoms', function() { for (let i = 0; i <= SMALL_MAX_NUM; ++i) { // test for list with target (i) as first, middle, last, and // not-existing element. also empty list and only i. expect(domain_getFirstIntersectingValue(fixt_numdom_solved(i), [i]), 'i=' + i).to.equal(i); expect(domain_getFirstIntersectingValue(fixt_numdom_solved(i), [i, 500, SUP]), 'i=' + i).to.equal(i); expect(domain_getFirstIntersectingValue(fixt_numdom_solved(i), [500, i, SUP]), 'i=' + i).to.equal(i); expect(domain_getFirstIntersectingValue(fixt_numdom_solved(i), [500, SUP, i]), 'i=' + i).to.equal(i); expect(domain_getFirstIntersectingValue(fixt_numdom_solved(i), [500, SUP]), 'i=' + i).to.equal(NO_SUCH_VALUE); expect(domain_getFirstIntersectingValue(fixt_numdom_solved(i), []), 'i=' + i).to.equal(NO_SUCH_VALUE); } }); }); }); describe('containsValue', function() { it('should exist', function() { expect(domain_containsValue).to.be.a('function'); }); describe('arrdom', function() { describe('should return true if domain contains given value', function() { it('one range in domain', function() { expect(domain_containsValue(fixt_strdom_range(SUP - 10, SUP), SUP - 5)).to.equal(true); }); it('multiple ranges in domain', function() { expect(domain_containsValue(fixt_strdom_ranges([SUP - 60, SUP - 50], [SUP - 30, SUP - 20], [SUP - 10, SUP]), SUP - 25)).to.equal(true); }); }); describe('should return false if domain does not contain value', function() { it('empty array', function() { expect(domain_containsValue(fixt_numdom_empty(), 0)).to.equal(false); }); it('one range in domain', function() { expect(domain_containsValue(fixt_strdom_range(SUP - 10, SUP), 25)).to.equal(false); }); it('multiple ranges in domain', function() { expect(domain_containsValue(fixt_strdom_ranges([SUP - 60, SUP - 50], [SUP - 30, SUP - 20], [SUP - 10, SUP]), SUP - 15)).to.equal(false); }); }); }); describe('numdom', function() { describe('should return true if domain contains given value', function() { it('one range in domain', function() { expect(domain_containsValue(fixt_numdom_range(0, 10), 5)).to.equal(true); }); it('multiple ranges in domain', function() { expect(domain_containsValue(fixt_numdom_nums(0, 1, 2, 4, 5, 8, 9, 10, 11), 9)).to.equal(true); }); }); describe('should return false if domain does not contain value', function() { it('empty array', function() { expect(domain_containsValue(fixt_numdom_empty(), 0)).to.equal(false); }); it('one range in domain', function() { expect(domain_containsValue(fixt_numdom_range(0, 10), 25)).to.equal(false); }); it('multiple ranges in domain', function() { expect(domain_containsValue(fixt_numdom_nums(0, 1, 2, 4, 5, 8, 9, 10, 11), 6)).to.equal(false); }); }); }); describe('solved numdom', function() { it('should work with solved numdoms', function() { for (let i = 0; i <= SMALL_MAX_NUM; ++i) { // do a search that passes, fails, and is oob expect(domain_containsValue(fixt_numdom_solved(i), 0), 'i=' + i + ',q=0').to.equal(i === 0); expect(domain_containsValue(fixt_numdom_solved(i), 1), 'i=' + i + ',q=1').to.equal(i === 1); expect(domain_containsValue(fixt_numdom_solved(i), SUP), 'i=' + i + ',q=SUP').to.equal(false); } }); }); describe('large value in numdom range', function() { it('should return false when numbers are oob for bitdom ranges', function() { expect(domain_containsValue(fixt_numdom_range(0, 10), 10000)).to.equal(false); expect(domain_containsValue(fixt_numdom_range(0, 10), 1760)).to.equal(false); // this value is a regression that uncovered a bug expect(_ => domain_containsValue(fixt_numdom_range(0, 10), -1)).to.throw('OOB'); expect(_ => domain_containsValue(fixt_numdom_range(0, 10), -10000)).to.throw('OOB'); }); }); }); describe('domain_rangeIndexOf', function() { it('should exist', function() { expect(domain_str_rangeIndexOf).to.be.a('function'); }); describe('should return index of range offset that encloses value', function() { // note: not range index, but index on the set of numbers which represents range pairs it('one range in domain', function() { expect(domain_str_rangeIndexOf(fixt_strdom_range(SUP - 10, SUP), SUP - 5)).to.eql(0); }); it('multiple ranges in domain', function() { expect(domain_str_rangeIndexOf(fixt_strdom_ranges([SUP - 60, SUP - 50], [SUP - 30, SUP - 20], [SUP - 10, SUP]), SUP - 50)).to.eql(0); expect(domain_str_rangeIndexOf(fixt_strdom_ranges([SUP - 60, SUP - 50], [SUP - 30, SUP - 20], [SUP - 10, SUP]), SUP - 25)).to.eql(1 * STR_RANGE_SIZE); expect(domain_str_rangeIndexOf(fixt_strdom_ranges([SUP - 60, SUP - 50], [SUP - 30, SUP - 20], [SUP - 10, SUP]), SUP - 5)).to.eql(2 * STR_RANGE_SIZE); }); }); describe('should return NOT_FOUND if domain does not contain value', function() { it('empty array', function() { expect(_ => domain_str_rangeIndexOf(fixt_strdom_empty(), 0)).to.throw('NOT_EMPTY_STR'); }); it('one range in domain', function() { expect(domain_str_rangeIndexOf(fixt_strdom_range(SUP - 10, SUP), SUP - 25)).to.eql(NOT_FOUND); }); it('multiple ranges in domain', function() { expect(domain_str_rangeIndexOf(fixt_strdom_ranges([SUP - 60, SUP - 50], [SUP - 30, SUP - 20], [SUP - 10, SUP]), SUP - 15)).to.eql(NOT_FOUND); }); }); }); describe('domain_removeValue', function() { it('should exist', function() { expect(domain_removeValue).to.be.a('function'); }); it('should reject an invalid value', function() { // (only numbers are valid values) expect(() => domain_removeValue(fixt_dom_nums(1, 2, 3), '15')).to.throw('VALUE_SHOULD_BE_VALID_DOMAIN_ELEMENT'); expect(() => domain_removeValue(fixt_dom_nums(1, 2, 3), ['15'])).to.throw('VALUE_SHOULD_BE_VALID_DOMAIN_ELEMENT'); }); describe('strdom', function() { it('should require a domain', function() { expect(() => domain_removeValue(null, 15)).to.throw('ONLY_NORDOM'); }); // target: 5 // 012 456 89 -> 012 4 6 89 // 012 567 -> 012 67 // 01 345 -> 01 34 // 01 345 89 -> 01 34 89 // 012 5 789 -> 012 789 // 5 789 -> 789 // 012 5 -> 012 // 789 -> 789 // 012 -> 012 // 5 -> empty // empty -> empty function test(domain, value, expectation) { it(`should remove [${value}] from [${domain__debug(domain)}] resulting in [${domain__debug(expectation)}]`, function() { let clone = fixt_dom_clone(domain); let result = domain_removeValue(fixt_dom_clone(domain), value); expect(domain, 'should not change').to.eql(clone); if (typeof expectation === 'string') fixt_assertStrings(result, expectation); else expect(result).to.equal(expectation); // output is a numdom expect(result).to.eql(expectation); }); } test(fixt_strdom_ranges([100, 102], [104, 106], [108, 109]), 105, fixt_strdom_ranges([100, 102], [104, 104], [106, 106], [108, 109])); test(fixt_strdom_ranges([100, 102], [104, 106]), 105, fixt_strdom_ranges([100, 102], [104, 104], [106, 106])); test(fixt_strdom_ranges([100, 101], [103, 105]), 105, fixt_strdom_ranges([100, 101], [103, 104])); test(fixt_strdom_ranges([100, 101], [103, 105], [108, 109]), 105, fixt_strdom_ranges([100, 101], [103, 104], [108, 109])); test(fixt_strdom_ranges([100, 102], [105, 105], [107, 109]), 105, fixt_strdom_ranges([100, 102], [107, 109])); test(fixt_strdom_ranges([105, 105], [107, 109]), 105, fixt_strdom_ranges([107, 109])); test(fixt_strdom_ranges([100, 102], [105, 105]), 105, fixt_strdom_ranges([100, 102])); test(fixt_strdom_ranges([107, 109]), 105, fixt_strdom_ranges([107, 109])); test(fixt_strdom_ranges([100, 102]), 105, fixt_strdom_ranges([100, 102])); test(fixt_strdom_ranges([105, 105]), 105, fixt_numdom_empty()); test(fixt_strdom_ranges([32, 32]), 32, fixt_numdom_empty()); test(fixt_strdom_ranges([SUP, SUP]), SUP, fixt_numdom_empty()); test(fixt_strdom_ranges([SUP - 1, SUP - 1]), SUP - 1, fixt_numdom_empty()); test(fixt_strdom_ranges([SUP - 1, SUP]), SUP, fixt_numdom_solved(SUP - 1)); }); describe('numdom', function() { // target: 5 // 012 456 89 -> 012 4 6 89 // 012 567 -> 012 67 // 01 345 -> 01 34 // 01 345 89 -> 01 34 89 // 012 5 789 -> 012 789 // 5 789 -> 789 // 012 5 -> 012 // 789 -> 789 // 012 -> 012 // 5 -> empty // empty -> empty function test(domain, value, output) { it(`should remove [${value}] from [${domain}] resulting in [${output}]`, function() { expect(domain_removeValue(domain, value)).to.eql(output); }); } test(fixt_numdom_nums(0, 1, 2, 4, 5, 6, 8, 9), 5, fixt_numdom_nums(0, 1, 2, 4, 6, 8, 9)); test(fixt_numdom_nums(0, 1, 2, 4, 5, 6), 5, fixt_numdom_nums(0, 1, 2, 4, 6)); test(fixt_numdom_nums(0, 1, 3, 4, 5), 5, fixt_numdom_nums(0, 1, 3, 4)); test(fixt_numdom_nums(0, 1, 3, 4, 5, 8, 9), 5, fixt_numdom_nums(0, 1, 3, 4, 8, 9)); test(fixt_numdom_nums(0, 1, 2, 5, 7, 8, 9), 5, fixt_numdom_nums(0, 1, 2, 7, 8, 9)); test(fixt_numdom_nums(5, 7, 8, 9), 5, fixt_numdom_nums(7, 8, 9)); test(fixt_numdom_nums(0, 1, 2, 5), 5, fixt_numdom_nums(0, 1, 2)); test(fixt_numdom_nums(7, 8, 9), 5, fixt_numdom_nums(7, 8, 9)); test(fixt_numdom_nums(0, 1, 2), 5, fixt_numdom_nums(0, 1, 2)); test(fixt_numdom_nums(5), 5, fixt_numdom_nums()); }); describe('solved numdom', function() { it('should work with solved numdoms', function() { let nums = [0, 1, 10, 100, 1000, SUP - 1, SUP]; for (let i = 0; i < nums.length; ++i) { let n = nums[i]; // do a search that passes and one that fails expect(domain_removeValue(fixt_numdom_solved(n), n), 'n=' + n + ',q=' + n).to.equal(fixt_dom_empty()); expect(domain_removeValue(fixt_numdom_solved(n), 5), 'n=' + n + ',q=5').to.equal(fixt_numdom_solved(n)); } }); }); }); describe('domain_sharesNoElements', function() { it('should exist', function() { expect(domain_sharesNoElements).to.be.a('function'); }); describe('strdom', function() { it('unit tests', function() { expect(domain_sharesNoElements(fixt_strdom_range(1, SUP), fixt_strdom_range(500, 600))).to.eql(false); expect(domain_sharesNoElements(fixt_strdom_range(1, SUP - 10), fixt_strdom_range(SUP - 5, SUP))).to.eql(true); expect(domain_sharesNoElements(fixt_strdom_range(500, 600), fixt_strdom_range(1, SUP))).to.eql(false); expect(domain_sharesNoElements(fixt_strdom_range(SUP - 5, SUP), fixt_strdom_range(1, SUP - 10))).to.eql(true); }); }); describe('numdom', function() { it('unit tests', function() { expect(domain_sharesNoElements(fixt_numdom_range(1, 20), fixt_numdom_range(15, 25))).to.eql(false); expect(domain_sharesNoElements(fixt_numdom_range(1, 20), fixt_numdom_range(25, 27))).to.eql(true); expect(domain_sharesNoElements(fixt_numdom_range(15, 25), fixt_numdom_range(1, 20))).to.eql(false); expect(domain_sharesNoElements(fixt_numdom_range(25, 27), fixt_numdom_range(1, 20))).to.eql(true); }); }); describe('soldom', function() { it('unit tests', function() { //expect(domain_sharesNoElements(fixt_numdom_range(1, 20), fixt_numdom_solved(15))).to.eql(false); //expect(domain_sharesNoElements(fixt_numdom_range(1, 20), fixt_numdom_solved(25))).to.eql(true); //expect(domain_sharesNoElements(fixt_numdom_solved(15), fixt_numdom_range(1, 20))).to.eql(false); //expect(domain_sharesNoElements(fixt_numdom_solved(25), fixt_numdom_range(1, 20))).to.eql(true); expect(domain_sharesNoElements(fixt_numdom_solved(500), fixt_strdom_range(1, SUP))).to.eql(false); expect(domain_sharesNoElements(fixt_numdom_solved(SUP), fixt_strdom_range(1, SUP - 10))).to.eql(true); expect(domain_sharesNoElements(fixt_numdom_solved(20), fixt_numdom_solved(20))).to.eql(false); expect(domain_sharesNoElements(fixt_numdom_solved(20), fixt_numdom_solved(0))).to.eql(true); expect(domain_sharesNoElements(fixt_numdom_solved(0), fixt_numdom_solved(20))).to.eql(true); }); }); }); describe('domain_min', function() { it('should exist', function() { expect(domain_min).to.be.a('function'); }); it('arrdom', function() { expect(domain_min(fixt_strdom_ranges([0, 10], [100, 300]))).to.eql(0); expect(domain_min(fixt_strdom_ranges([0, 10], [100, SUP]))).to.eql(0); expect(domain_min(fixt_strdom_ranges([1, 1], [100, SUP]))).to.eql(1); expect(domain_min(fixt_strdom_ranges([100, 100]))).to.eql(100); expect(domain_min(fixt_strdom_ranges([SUP, SUP]))).to.eql(SUP); expect(domain_min(fixt_strdom_ranges([SUP - 1, SUP]))).to.eql(SUP - 1); }); it('numdom', function() { for (let i = 0; i <= SMALL_MAX_NUM; ++i) { // basically trying each small domain range from [0,30] to [30,30] expect(domain_min(fixt_numdom_nums(i)), i + ' | i').to.eql(i); expect(domain_min(fixt_numdom_nums(i, 30)), i + ' | 30').to.eql(i); } }); }); describe('domain_max', function() { it('should exist', function() { expect(domain_max).to.be.a('function'); }); it('arrdom', function() { expect(domain_max(fixt_strdom_ranges([0, 10], [100, 300]))).to.eql(300); expect(domain_max(fixt_strdom_ranges([0, 10], [100, SUP]))).to.eql(SUP); expect(domain_max(fixt_strdom_ranges([1, 1], [100, SUP]))).to.eql(SUP); expect(domain_max(fixt_strdom_ranges([100, 100]))).to.eql(100); expect(domain_max(fixt_strdom_ranges([SUP, SUP]))).to.eql(SUP); expect(domain_max(fixt_strdom_ranges([SUP - 1, SUP]))).to.eql(SUP); }); it('numdom', function() { for (let i = 0; i <= SMALL_MAX_NUM; ++i) { // basically trying each small domain range from [0,30] to [30,30] expect(domain_max(fixt_numdom_nums(0, i)), '0 | ' + i).to.eql(i); } }); }); describe('domain_mergeOverlappingInline', function() { it('should exist', function() { expect(_domain_str_mergeOverlappingRanges).to.be.a('function'); }); it('should throw for domains as numbers', function() { expect(_ => _domain_str_mergeOverlappingRanges(fixt_numdom_nums(1))).to.throw('ONLY_STRDOM'); }); it('should return empty domain for empty domain', function() { expect(_domain_str_mergeOverlappingRanges(fixt_strdom_empty()), fixt_strdom_empty()); }); it('should return same range for single range domain', function() { fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_range(910, 9100)), fixt_strdom_range(910, 9100)); fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_range(930, 9213)), fixt_strdom_range(930, 9213)); fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_range(90, 91)), fixt_strdom_range(90, 91)); fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_range(SUP, SUP)), fixt_strdom_range(SUP, SUP)); fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_range(SUP - 1, SUP)), fixt_strdom_range(SUP - 1, SUP)); }); it('should return same if not overlapping', function() { fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([910, 9100], [9200, 9300])), fixt_strdom_ranges([910, 9100], [9200, 9300])); fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([90, 90], [92, 92])), fixt_strdom_ranges([90, 90], [92, 92])); fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([90, 90], [SUP, SUP])), fixt_strdom_ranges([90, 90], [SUP, SUP])); }); it('should merge if two domains overlap', function() { fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([90, 91], [91, 92])), fixt_strdom_range(90, 92)); fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([90, 950], [925, 975])), fixt_strdom_range(90, 975)); fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([9213, 9278], [9244, 9364])), fixt_strdom_range(9213, 9364)); fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([910, 920], [930, 940], [935, 945], [950, 960])), fixt_strdom_ranges([910, 920], [930, 945], [950, 960])); }); it('should merge if two domains touch', function() { fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([90, 90], [91, 91])), fixt_strdom_range(90, 91)); fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([90, 91], [92, 93])), fixt_strdom_range(90, 93)); fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([90, 910], [910, 920])), fixt_strdom_range(90, 920)); }); it('should chain merges', function() { fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([90, 90], [91, 91], [92, 92])), fixt_strdom_range(90, 92)); fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([90, 91], [91, 92], [92, 93])), fixt_strdom_range(90, 93)); fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([90, 90], [91, 92], [92, 93])), fixt_strdom_range(90, 93)); fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([91, 92], [92, 93])), fixt_strdom_range(91, 93)); }); it('should make sure resulting range wraps both ranges', function() { fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([90, 90], [90, 91])), fixt_strdom_range(90, 91)); fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([90, 91], [90, 90])), fixt_strdom_range(90, 91)); fixt_assertStrings(_domain_str_mergeOverlappingRanges(fixt_strdom_ranges([90, 910], [914, 916], [915, 920], [916, 919], [917, 918])), fixt_strdom_ranges([90, 910], [914, 920])); }); }); describe('domain_simplifyInline', function() { it('should exist', function() { expect(domain_str_simplify).to.be.a('function'); }); it('should throw for domains as numbers', function() { expect(_ => domain_str_simplify(fixt_numdom_empty())).to.throw('ONLY_STRDOM'); expect(_ => domain_str_simplify(fixt_numdom_nums(1, 3, 9))).to.throw('ONLY_STRDOM'); expect(_ => domain_str_simplify()).to.throw('ONLY_STRDOM'); }); it('should work with empty domain', function() { let arr = fixt_strdom_empty(); expect(domain_str_simplify(arr)).to.eql(fixt_dom_empty()); }); it('should return a solved domain if it has one range', function() { fixt_assertStrings(domain_str_simplify(fixt_strdom_range(90, 91)), fixt_strdom_range(90, 91)); expect(domain_str_simplify(fixt_strdom_range(SUP, SUP))).to.eql(fixt_numdom_solved(SUP)); }); it('should work if domain is not changed', function() { fixt_assertStrings(domain_str_simplify(fixt_strdom_ranges([91, 92], [920, 930])), fixt_strdom_ranges([91, 92], [920, 930])); fixt_assertStrings(domain_str_simplify(fixt_strdom_ranges([91, 92], [920, SUP])), fixt_strdom_ranges([91, 92], [920, SUP])); }); it('should simplify back-to-back domains', function() { fixt_assertStrings(domain_str_simplify(fixt_strdom_ranges([91, 92], [92, 93])), fixt_strdom_range(91, 93)); fixt_assertStrings(domain_str_simplify(fixt_strdom_ranges([91, 92], [92, SUP])), fixt_strdom_range(91, SUP)); }); it('should simplify swapped back-to-back domains', function() { fixt_assertStrings(domain_str_simplify(fixt_strdom_ranges([92, 93], [91, 92])), fixt_strdom_range(91, 93)); fixt_assertStrings(domain_str_simplify(fixt_strdom_ranges([92, SUP], [91, 92])), fixt_strdom_range(91, SUP)); }); }); describe('intersection', function() { it('should exist', function() { expect(domain_intersection).to.be.a('function'); }); it('should require two domains', function() { expect(() => domain_intersection()).to.throw('ONLY_NORDOM'); expect(() => domain_intersection(fixt_numdom_empty())).to.throw('ONLY_NORDOM'); expect(() => domain_intersection(null, fixt_numdom_empty())).to.throw('ONLY_NORDOM'); }); it('should return empty numdom', function() { expect(domain_intersection(fixt_numdom_empty(), fixt_numdom_empty())).to.eql(fixt_dom_empty()); }); it('should throw for EMPTY_STR', function() { expect(_ => domain_intersection(fixt_strdom_empty(), fixt_strdom_empty())).to.throw('empty domains are always numdoms'); expect(_ => domain_intersection(fixt_strdom_empty(), fixt_numdom_empty())).to.throw('empty domains are always numdoms'); expect(_ => domain_intersection(fixt_numdom_empty(), fixt_strdom_empty())).to.throw('empty domains are always numdoms'); }); describe('strdom', function() { it('should handle empty domain with single element domain', function() { expect(domain_intersection(fixt_numdom_empty(), fixt_strdom_range(90, 91))).to.eql(fixt_dom_empty()); }); it('should handle empty domain with multi element domain', function() { expect(domain_intersection(fixt_numdom_empty(), fixt_strdom_ranges([90, 91], [93, 95]))).to.eql(fixt_dom_empty()); }); it('should handle single element domain with empty domain', function() { expect(domain_intersection(fixt_strdom_range(90, 91), fixt_numdom_empty())).to.eql(fixt_dom_empty()); }); it('should handle single element domain with empty domain', function() { expect(domain_intersection(fixt_strdom_ranges([90, 91], [93, 95]), fixt_numdom_empty())).to.eql(fixt_dom_empty()); }); it('should handle single element domains', function() { expect(domain_intersection(fixt_strdom_range(90, 91), fixt_strdom_range(93, 95))).to.eql(fixt_dom_empty()); }); it('should intersect single element domains', function() { fixt_assertStrings(domain_intersection(fixt_strdom_range(90, 95), fixt_strdom_range(93, 100)), fixt_strdom_range(93, 95)); }); it('should intersect single element domains reversed', function() { fixt_assertStrings(domain_intersection(fixt_strdom_range(93, 100), fixt_strdom_range(90, 95)), fixt_strdom_range(93, 95)); }); it('should handle single element domain with multi element domain', function() { expect(domain_intersection(fixt_strdom_range(90, 91), fixt_strdom_ranges([10, 20], [30, 40]))).to.eql(fixt_dom_empty()); }); it('should handle multi element domain with single element domain', function() { expect(domain_intersection(fixt_strdom_ranges([0, 1], [10, 120]), fixt_strdom_range(130, 140))).to.eql(fixt_dom_empty()); }); it('should intersect single element domain with multi element domain', function() { expect(domain_intersection(fixt_strdom_range(5, 16), fixt_strdom_ranges([10, 20], [30, 40]))).to.eql(fixt_numdom_range(10, 16)); }); it('should intersect multi element domain with single element domain', function() { fixt_assertStrings(domain_intersection(fixt_strdom_ranges([0, 1], [25, 35]), fixt_strdom_range(30, 40)), fixt_strdom_range(30, 35)); }); it('should handle multi element domains', function() { expect(domain_intersection(fixt_strdom_ranges([0, 1], [10, 120]), fixt_strdom_ranges([130, 140], [150, 160]))).to.eql(fixt_dom_empty()); }); it('should intersect multi element domains', function() { fixt_assertStrings(domain_intersection(fixt_strdom_ranges([0, 1], [10, 35]), fixt_strdom_ranges([30, 40], [50, 60])), fixt_strdom_range(30, 35)); }); it('should return two ranges if a range in one domain intersects with two ranges of the other domain', function() { fixt_assertStrings(domain_intersection(fixt_strdom_range(15, 35), fixt_strdom_ranges([10, 20], [30, 40])), fixt_strdom_ranges([15, 20], [30, 35])); }); it('should divide and conquer some random tests 1', function() { // copy(JSON.stringify(function f(n) { // var arr = []; // while (--n > 0) { // var t = Math.floor(Math.random() * 100); // arr.push(t, t+Math.floor(Math.random() * 20)); // } // return arr; // }(10).map(function(a){ // return [Math.min(a[0],a[1]), Math.max(a[0], a[1])]; // })).replace(/,/g, ', ')) let a = fixt_strdom_ranges([10, 23], [29, 38], [49, 49], [54, 68], [77, 78], [84, 100]); let b = fixt_strdom_ranges([1, 1], [3, 21], [25, 38], [54, 67], [70, 84], [88, 107]); fixt_assertStrings(domain_intersection(a, b), fixt_strdom_ranges([10, 21], [29, 38], [54, 67], [77, 78], [84, 84], [88, 100])); }); it('should divide and conquer some random tests 2', function() { let a = fixt_strdom_ranges([17, 23], [37, 78], [85, 104]); let b = fixt_strdom_ranges([6, 25], [47, 56], [58, 60], [64, 67], [83, 103]); fixt_assertStrings(domain_intersection(a, b), fixt_strdom_ranges([17, 23], [47, 56], [58, 60], [64, 67], [85, 103])); });