diff --git a/package-lock.json b/package-lock.json index cfd951679b3a503d8fb86785c98a3e978ea34abc..7c59de544f879018656eb92fe3ca8a026f1778de 100644 Binary files a/package-lock.json and b/package-lock.json differ diff --git a/package.json b/package.json index 8b2461c3bca1f54cf53d321765792e1699f3f797..11d5d2928bdf2f8ea44b689a06a48c7199bf81ea 100644 --- a/package.json +++ b/package.json @@ -41,10 +41,10 @@ "rollup-plugin-json": "^2.3.0", "rollup-plugin-node-resolve": "^3.0.0", "rollup-watch": "^4.3.1", - "ts-jest": "^21.1.3", + "ts-jest": "^21.1.4", "tslint": "^5.8.0", "typescript": "^2.5.3", - "uglify-js": "^3.1.5", + "uglify-js": "^3.1.6", "util.promisify": "^1.0.0" }, "dependencies": {} diff --git a/src/mol-base/collections/integer/impl/ordered-set.ts b/src/mol-base/collections/integer/impl/ordered-set.ts index 68e152c0da9815587cca06d3d25d940a17e6509e..050a41ca0feca76be263318a5845da8a0a5eb008 100644 --- a/src/mol-base/collections/integer/impl/ordered-set.ts +++ b/src/mol-base/collections/integer/impl/ordered-set.ts @@ -95,11 +95,21 @@ export function subtract(a: OrderedSetImpl, b: OrderedSetImpl) { } const _maxIntRangeRet = { startI: 0, startJ: 0, endI: 0, endJ: 0 }; -function getMaxIntersectionRange(a: S, b: S) { - _maxIntRangeRet.startI = S.findPredecessorIndex(a, S.start(b)); - _maxIntRangeRet.startJ = S.findPredecessorIndex(b, S.start(a)); - _maxIntRangeRet.endI = S.findPredecessorIndex(a, S.end(b)); - _maxIntRangeRet.endJ = S.findPredecessorIndex(b, S.end(a)); +// for small sets, just gets the whole range, for large sets does a bunch of binary searches +function getSuitableIntersectionRange(a: S, b: S) { + const la = a.length, lb = b.length; + const ratio = la / lb; + if (ratio <= 0.5 || ratio >= 2 || (la >= 128 && lb >= 128)) { + _maxIntRangeRet.startI = S.findPredecessorIndex(a, S.start(b)); + _maxIntRangeRet.startJ = S.findPredecessorIndex(b, S.start(a)); + _maxIntRangeRet.endI = S.findPredecessorIndex(a, S.end(b)); + _maxIntRangeRet.endJ = S.findPredecessorIndex(b, S.end(a)); + } else { + _maxIntRangeRet.startI = 0; + _maxIntRangeRet.startJ = 0; + _maxIntRangeRet.endI = la; + _maxIntRangeRet.endJ = lb; + } return _maxIntRangeRet; } @@ -112,10 +122,9 @@ function areIntersectingSI(a: S, b: I) { function areIntersectingSS(a: S, b: S) { if (a === b) return true; - const xs = S.values(a), ys = S.values(b); - let { startI: i, startJ: j, endI, endJ } = getMaxIntersectionRange(a, b); + let { startI: i, startJ: j, endI, endJ } = getSuitableIntersectionRange(a, b); while (i < endI && j < endJ) { - const x = xs[i], y = ys[j]; + const x = a[i], y = b[j]; if (x < y) { i++; } else if (x > y) { j++; } else return true; @@ -142,15 +151,14 @@ function isSubsetIS(a: I, b: S) { function isSubsetSS(a: S, b: S) { if (a === b) return true; - const xs = S.values(a), ys = S.values(b); - const lenB = ys.length; - let { startI: i, startJ: j, endI, endJ } = getMaxIntersectionRange(a, b); + const lenB = b.length; + let { startI: i, startJ: j, endI, endJ } = getSuitableIntersectionRange(a, b); // must be able to advance by lenB elements if (endJ - j < lenB || endI - i < lenB) return false; let equal = 0; while (i < endI && j < endJ) { - const x = xs[i], y = ys[j]; + const x = a[i], y = b[j]; if (x < y) { i++; } else if (x > y) { j++; } else { i++; j++; equal++; } @@ -196,12 +204,11 @@ function unionSI(a: S, b: I) { const min = I.min(b), max = I.max(b); const r = S.findRange(a, min, max); const start = I.start(r), end = I.end(r); - const xs = S.values(a); - const indices = new Int32Array(start + (xs.length - end) + bSize); + const indices = new Int32Array(start + (a.length - end) + bSize); let offset = 0; - for (let i = 0; i < start; i++) indices[offset++] = xs[i]; + for (let i = 0; i < start; i++) indices[offset++] = a[i]; for (let i = min; i <= max; i++) indices[offset++] = i; - for (let i = end, _i = xs.length; i < _i; i++) indices[offset] = xs[i]; + for (let i = end, _i = a.length; i < _i; i++) indices[offset] = a[i]; return ofSortedArray(indices); } @@ -209,25 +216,24 @@ function unionSI(a: S, b: I) { function unionSS(a: S, b: S) { if (a === b) return a; - const xs = S.values(a), ys = S.values(b); - const { startI: sI, startJ: sJ, endI, endJ } = getMaxIntersectionRange(a, b); + const { startI: sI, startJ: sJ, endI, endJ } = getSuitableIntersectionRange(a, b); let i = sI, j = sJ; let commonCount = 0; while (i < endI && j < endJ) { - const x = xs[i], y = ys[j]; + const x = a[i], y = b[j]; if (x < y) { i++; } else if (x > y) { j++; } else { i++; j++; commonCount++; } } - const lenA = xs.length, lenB = ys.length; + const lenA = a.length, lenB = b.length; // A === B || B is subset of A ==> A - if ((commonCount === lenA && commonCount === lenB) || commonCount === lenB) return xs; + if ((commonCount === lenA && commonCount === lenB) || commonCount === lenB) return a; // A is subset of B ===> B - if (commonCount === lenA) return ys; + if (commonCount === lenA) return b; const resultSize = lenA + lenB - commonCount; - const l = Math.min(xs[0], ys[0]), r = Math.max(xs[lenA - 1], ys[lenB - 1]); + const l = Math.min(a[0], b[0]), r = Math.max(a[lenA - 1], b[lenB - 1]); // is this just a range? if (resultSize === r - l + 1) { return I.ofRange(l, r); @@ -237,22 +243,22 @@ function unionSS(a: S, b: S) { let offset = 0; // insert the "prefixes" - for (let k = 0; k < sI; k++) indices[offset++] = xs[k]; - for (let k = 0; k < sJ; k++) indices[offset++] = ys[k]; + for (let k = 0; k < sI; k++) indices[offset++] = a[k]; + for (let k = 0; k < sJ; k++) indices[offset++] = b[k]; // insert the common part i = sI; j = sJ; while (i < endI && j < endJ) { - const x = xs[i], y = ys[j]; + const x = a[i], y = b[j]; if (x < y) { indices[offset++] = x; i++; } else if (x > y) { indices[offset++] = y; j++; } else { indices[offset++] = x; i++; j++; } } // insert the "tail" - for (; i < lenA; i++) indices[offset++] = xs[i]; - for (; j < lenB; j++) indices[offset++] = ys[j]; + for (; i < lenA; i++) indices[offset++] = a[i]; + for (; j < lenB; j++) indices[offset++] = b[j]; return ofSortedArray(indices); } @@ -265,11 +271,10 @@ function intersectSI(a: S, b: I) { const resultSize = end - start; if (!resultSize) return Empty; - const xs = S.values(a); const indices = new Int32Array(resultSize); let offset = 0; for (let i = start; i < end; i++) { - indices[offset++] = xs[i]; + indices[offset++] = a[i]; } return ofSortedArray(indices); } @@ -277,18 +282,17 @@ function intersectSI(a: S, b: I) { function intersectSS(a: S, b: S) { if (a === b) return a; - const xs = S.values(a), ys = S.values(b); - const { startI: sI, startJ: sJ, endI, endJ } = getMaxIntersectionRange(a, b); + const { startI: sI, startJ: sJ, endI, endJ } = getSuitableIntersectionRange(a, b); let i = sI, j = sJ; let commonCount = 0; while (i < endI && j < endJ) { - const x = xs[i], y = ys[j]; + const x = a[i], y = b[j]; if (x < y) { i++; } else if (x > y) { j++; } else { i++; j++; commonCount++; } } - const lenA = xs.length, lenB = ys.length; + const lenA = a.length, lenB = b.length; // no common elements if (!commonCount) return Empty; // A === B || B is subset of A ==> B @@ -301,7 +305,7 @@ function intersectSS(a: S, b: S) { i = sI; j = sJ; while (i < endI && j < endJ) { - const x = xs[i], y = ys[j]; + const x = a[i], y = b[j]; if (x < y) { i++; } else if (x > y) { j++; } else { indices[offset++] = x; i++; j++; } @@ -340,19 +344,18 @@ function subtractSI(a: S, b: I) { // is empty? if (max < min) return a; - const xs = S.values(a); const r = S.findRange(a, min, max); const start = I.start(r), end = I.end(r); - const resultSize = xs.length - (end - start); + const resultSize = a.length - (end - start); // A is subset of B if (resultSize <= 0) return Empty; // No common elements - if (resultSize === xs.length) return xs; + if (resultSize === a.length) return a; const ret = new Int32Array(resultSize); let offset = 0; - for (let i = 0; i < start; i++) ret[offset++] = xs[i]; - for (let i = end, _i = xs.length; i < _i; i++) ret[offset++] = xs[i]; + for (let i = 0; i < start; i++) ret[offset++] = a[i]; + for (let i = end, _i = a.length; i < _i; i++) ret[offset++] = a[i]; return ofSortedArray(ret); } @@ -374,10 +377,9 @@ function subtractIS(a: I, b: S) { // A is subset of B if (resultSize <= 0) return Empty; - const xs = S.values(b); const ret = new Int32Array(resultSize); - const li = xs.length - 1; - const fst = xs[Math.min(start, li)], last = xs[Math.min(end, li)]; + const li = b.length - 1; + const fst = b[Math.min(start, li)], last = b[Math.min(end, li)]; let offset = 0; for (let i = min; i < fst; i++) ret[offset++] = i; for (let i = fst; i <= last; i++) { @@ -390,21 +392,19 @@ function subtractIS(a: I, b: S) { function subtractSS(a: S, b: S) { if (a === b) return Empty; - const xs = S.values(a), ys = S.values(b); - const lenA = xs.length; - - const { startI: sI, startJ: sJ, endI, endJ } = getMaxIntersectionRange(a, b); + const lenA = a.length; + const { startI: sI, startJ: sJ, endI, endJ } = getSuitableIntersectionRange(a, b); let i = sI, j = sJ; let commonCount = 0; while (i < endI && j < endJ) { - const x = xs[i], y = ys[j]; + const x = a[i], y = b[j]; if (x < y) { i++; } else if (x > y) { j++; } else { i++; j++; commonCount++; } } // A isnt intersecting B ===> A - if (!commonCount) return xs; + if (!commonCount) return a; // A === B || A is subset of B ===> Empty if (commonCount >= lenA) return Empty; @@ -412,19 +412,19 @@ function subtractSS(a: S, b: S) { let offset = 0; // insert the "prefix" - for (let k = 0; k < sI; k++) indices[offset++] = xs[k]; + for (let k = 0; k < sI; k++) indices[offset++] = a[k]; i = sI; j = sJ; while (i < endI && j < endJ) { - const x = xs[i], y = ys[j]; + const x = a[i], y = b[j]; if (x < y) { indices[offset++] = x; i++; } else if (x > y) { j++; } else { i++; j++; } } // insert the "tail" - for (; i < lenA; i++) indices[offset++] = xs[i]; + for (; i < lenA; i++) indices[offset++] = a[i]; return ofSortedArray(indices); } \ No newline at end of file diff --git a/src/mol-base/collections/integer/sorted-array.ts b/src/mol-base/collections/integer/sorted-array.ts index d30f572c81a88cd3f92cdbd2b23100404193ad6c..1a95711d7f1bde939caa546b5760b44ecd093fc4 100644 --- a/src/mol-base/collections/integer/sorted-array.ts +++ b/src/mol-base/collections/integer/sorted-array.ts @@ -12,8 +12,6 @@ namespace SortedArray { export const ofSortedArray: (xs: ArrayLike<number>) => SortedArray = Impl.ofSortedArray as any; export const is: (v: any) => v is Interval = Impl.is as any; - export const values: (array: SortedArray) => ArrayLike<number> = (xs) => xs as any; - export const has: (array: SortedArray, x: number) => boolean = Impl.has as any; export const indexOf: (array: SortedArray, x: number) => number = Impl.indexOf as any; export const indexOfInterval: (array: SortedArray, x: number, bounds: Interval) => number = Impl.indexOfInterval as any; @@ -33,6 +31,6 @@ namespace SortedArray { export const findRange: (array: SortedArray, min: number, max: number) => Interval = Impl.findRange as any; } -interface SortedArray { '@type': 'int-sorted-array' } +interface SortedArray extends ReadonlyArray<number> { '@type': 'int-sorted-array' } export default SortedArray \ No newline at end of file