Skip to content
Snippets Groups Projects
Commit 156b14e3 authored by David Sehnal's avatar David Sehnal
Browse files

moved some code from ordered set to sorted array

parent 6b79fa85
No related branches found
No related tags found
No related merge requests found
......@@ -46,7 +46,7 @@ export function areIntersecting(a: OrderedSetImpl, b: OrderedSetImpl) {
if (I.is(b)) return I.areIntersecting(a, b);
return areIntersectingSI(b, a);
} else if (I.is(b)) return areIntersectingSI(a, b);
return areIntersectingSS(a, b);
return S.areIntersecting(a, b);
}
/** Check if the 2nd argument is a subset of the 1st */
......@@ -55,7 +55,7 @@ export function isSubset(a: OrderedSetImpl, b: OrderedSetImpl) {
if (I.is(b)) return I.isSubInterval(a, b);
return isSubsetIS(a, b);
} else if (I.is(b)) return isSubsetSI(a, b);
return isSubsetSS(a, b);
return S.isSubset(a, b);
}
export function findPredecessorIndex(set: OrderedSetImpl, x: number) {
......@@ -75,7 +75,7 @@ export function union(a: OrderedSetImpl, b: OrderedSetImpl) {
if (I.is(b)) return unionII(a, b);
return unionSI(b, a);
} else if (I.is(b)) return unionSI(a, b);
return unionSS(a, b);
return ofSortedArray(S.union(a, b));
}
export function intersect(a: OrderedSetImpl, b: OrderedSetImpl) {
......@@ -83,7 +83,7 @@ export function intersect(a: OrderedSetImpl, b: OrderedSetImpl) {
if (I.is(b)) return I.intersect(a, b);
return intersectSI(b, a);
} else if (I.is(b)) return intersectSI(a, b);
return intersectSS(a, b);
return ofSortedArray(S.intersect(a, b));
}
export function subtract(a: OrderedSetImpl, b: OrderedSetImpl) {
......@@ -91,26 +91,7 @@ export function subtract(a: OrderedSetImpl, b: OrderedSetImpl) {
if (I.is(b)) return subtractII(a, b);
return subtractIS(a, b);
} else if (I.is(b)) return subtractSI(a, b);
return subtractSS(a, b);
}
const _maxIntRangeRet = { startI: 0, startJ: 0, endI: 0, endJ: 0 };
// 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;
return ofSortedArray(S.subtract(a, b));
}
function areEqualIS(a: I, b: S) { return I.size(a) === S.size(b) && I.start(a) === S.start(b) && I.end(a) === S.end(b); }
......@@ -119,19 +100,6 @@ function areIntersectingSI(a: S, b: I) {
return areRangesIntersecting(a, b);
}
function areIntersectingSS(a: S, b: S) {
if (a === b) return true;
let { startI: i, startJ: j, endI, endJ } = getSuitableIntersectionRange(a, b);
while (i < endI && j < endJ) {
const x = a[i], y = b[j];
if (x < y) { i++; }
else if (x > y) { j++; }
else return true;
}
return false;
}
function isSubsetSI(a: S, b: I) {
const minB = I.min(b), maxB = I.max(b);
if (maxB - minB + 1 === 0) return true;
......@@ -148,24 +116,6 @@ function isSubsetIS(a: I, b: S) {
return minB >= minA && maxA <= maxB;
}
function isSubsetSS(a: S, b: S) {
if (a === b) return true;
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 = a[i], y = b[j];
if (x < y) { i++; }
else if (x > y) { j++; }
else { i++; j++; equal++; }
}
return equal === lenB;
}
function areRangesIntersecting(a: OrderedSetImpl, b: OrderedSetImpl) {
const sa = size(a), sb = size(b);
if (sa === 0 && sb === 0) return true;
......@@ -213,56 +163,6 @@ function unionSI(a: S, b: I) {
return ofSortedArray(indices);
}
function unionSS(a: S, b: S) {
if (a === b) return a;
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 = a[i], y = b[j];
if (x < y) { i++; }
else if (x > y) { j++; }
else { i++; j++; commonCount++; }
}
const lenA = a.length, lenB = b.length;
// A === B || B is subset of A ==> A
if ((commonCount === lenA && commonCount === lenB) || commonCount === lenB) return a;
// A is subset of B ===> B
if (commonCount === lenA) return b;
const resultSize = lenA + lenB - commonCount;
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);
}
const indices = new Int32Array(lenA + lenB - commonCount);
let offset = 0;
// insert the "prefixes"
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 = 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++] = a[i];
for (; j < lenB; j++) indices[offset++] = b[j];
return ofSortedArray(indices);
}
function intersectSI(a: S, b: I) {
if (!I.size(b)) return Empty;
......@@ -279,41 +179,6 @@ function intersectSI(a: S, b: I) {
return ofSortedArray(indices);
}
function intersectSS(a: S, b: S) {
if (a === b) return a;
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 = a[i], y = b[j];
if (x < y) { i++; }
else if (x > y) { j++; }
else { i++; j++; commonCount++; }
}
const lenA = a.length, lenB = b.length;
// no common elements
if (!commonCount) return Empty;
// A === B || B is subset of A ==> B
if ((commonCount === lenA && commonCount === lenB) || commonCount === lenB) return b;
// A is subset of B ==> A
if (commonCount === lenA) return a;
const indices = new Int32Array(commonCount);
let offset = 0;
i = sI;
j = sJ;
while (i < endI && j < endJ) {
const x = a[i], y = b[j];
if (x < y) { i++; }
else if (x > y) { j++; }
else { indices[offset++] = x; i++; j++; }
}
return ofSortedArray(indices);
}
function subtractII(a: I, b: I) {
if (I.areEqual(a, b)) return Empty;
if (!I.areIntersecting(a, b)) return a;
......@@ -387,44 +252,4 @@ function subtractIS(a: I, b: S) {
}
for (let i = last + 1; i <= max; i++) ret[offset++] = i;
return ofSortedArray(ret);
}
function subtractSS(a: S, b: S) {
if (a === b) return Empty;
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 = 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 a;
// A === B || A is subset of B ===> Empty
if (commonCount >= lenA) return Empty;
const indices = new Int32Array(lenA - commonCount);
let offset = 0;
// insert the "prefix"
for (let k = 0; k < sI; k++) indices[offset++] = a[k];
i = sI;
j = sJ;
while (i < endI && j < endJ) {
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++] = a[i];
return ofSortedArray(indices);
}
\ No newline at end of file
......@@ -10,6 +10,9 @@ import Interval from '../interval'
type Nums = ArrayLike<number>
export const Empty: Nums = []
export function ofSortedArray(xs: Nums) {
if (xs.length < 1) throw new Error('Sorted arrays must be non-empty.');
return xs;
......@@ -101,4 +104,172 @@ function binarySearchPredIndexRange(xs: Nums, value: number, start: number, end:
}
if (min > max) return max + 1;
return xs[min] >= value ? min : min + 1;
}
export function areIntersecting(a: Nums, b: Nums) {
if (a === b) return true;
let { startI: i, startJ: j, endI, endJ } = getSuitableIntersectionRange(a, b);
while (i < endI && j < endJ) {
const x = a[i], y = b[j];
if (x < y) { i++; }
else if (x > y) { j++; }
else return true;
}
return false;
}
export function isSubset(a: Nums, b: Nums) {
if (a === b) return true;
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 = a[i], y = b[j];
if (x < y) { i++; }
else if (x > y) { j++; }
else { i++; j++; equal++; }
}
return equal === lenB;
}
export function union(a: Nums, b: Nums) {
if (a === b) return a;
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 = a[i], y = b[j];
if (x < y) { i++; }
else if (x > y) { j++; }
else { i++; j++; commonCount++; }
}
const lenA = a.length, lenB = b.length;
// A === B || B is subset of A ==> A
if ((commonCount === lenA && commonCount === lenB) || commonCount === lenB) return a;
// A is subset of B ===> B
if (commonCount === lenA) return b;
const indices = new Int32Array(lenA + lenB - commonCount);
let offset = 0;
// insert the "prefixes"
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 = 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++] = a[i];
for (; j < lenB; j++) indices[offset++] = b[j];
return ofSortedArray(indices);
}
export function intersect(a: Nums, b: Nums) {
if (a === b) return a;
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 = a[i], y = b[j];
if (x < y) { i++; }
else if (x > y) { j++; }
else { i++; j++; commonCount++; }
}
const lenA = a.length, lenB = b.length;
// no common elements
if (!commonCount) return Empty;
// A === B || B is subset of A ==> B
if ((commonCount === lenA && commonCount === lenB) || commonCount === lenB) return b;
// A is subset of B ==> A
if (commonCount === lenA) return a;
const indices = new Int32Array(commonCount);
let offset = 0;
i = sI;
j = sJ;
while (i < endI && j < endJ) {
const x = a[i], y = b[j];
if (x < y) { i++; }
else if (x > y) { j++; }
else { indices[offset++] = x; i++; j++; }
}
return ofSortedArray(indices);
}
export function subtract(a: Nums, b: Nums) {
if (a === b) return Empty;
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 = 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 a;
// A === B || A is subset of B ===> Empty
if (commonCount >= lenA) return Empty;
const indices = new Int32Array(lenA - commonCount);
let offset = 0;
// insert the "prefix"
for (let k = 0; k < sI; k++) indices[offset++] = a[k];
i = sI;
j = sJ;
while (i < endI && j < endJ) {
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++] = a[i];
return ofSortedArray(indices);
}
const _maxIntRangeRet = { startI: 0, startJ: 0, endI: 0, endJ: 0 };
// for small sets, just gets the whole range, for large sets does a bunch of binary searches
export function getSuitableIntersectionRange(a: Nums, b: Nums) {
const la = a.length, lb = b.length;
const ratio = la / lb;
if (ratio <= 0.5 || ratio >= 2 || (la >= 128 && lb >= 128)) {
_maxIntRangeRet.startI = findPredecessorIndex(a, start(b));
_maxIntRangeRet.startJ = findPredecessorIndex(b, start(a));
_maxIntRangeRet.endI = findPredecessorIndex(a, end(b));
_maxIntRangeRet.endJ = findPredecessorIndex(b, end(a));
} else {
_maxIntRangeRet.startI = 0;
_maxIntRangeRet.startJ = 0;
_maxIntRangeRet.endI = la;
_maxIntRangeRet.endJ = lb;
}
return _maxIntRangeRet;
}
\ No newline at end of file
......@@ -25,12 +25,18 @@ namespace SortedArray {
export const hashCode: (array: SortedArray) => number = Impl.hashCode as any;
export const areEqual: (a: SortedArray, b: SortedArray) => boolean = Impl.areEqual as any;
export const areIntersecting: (a: SortedArray, b: SortedArray) => boolean = Impl.areIntersecting as any;
export const isSubset: (a: SortedArray, b: SortedArray) => boolean = Impl.isSubset as any;
export const union: (a: SortedArray, b: SortedArray) => SortedArray = Impl.union as any;
export const intersect: (a: SortedArray, b: SortedArray) => SortedArray = Impl.intersect as any;
export const subtract: (a: SortedArray, b: SortedArray) => SortedArray = Impl.subtract as any;
export const findPredecessorIndex: (array: SortedArray, x: number) => number = Impl.findPredecessorIndex as any;
export const findPredecessorIndexInInterval: (array: SortedArray, x: number, bounds: Interval) => number = Impl.findPredecessorIndexInInterval as any;
export const findRange: (array: SortedArray, min: number, max: number) => Interval = Impl.findRange as any;
}
interface SortedArray extends ReadonlyArray<number> { '@type': 'int-sorted-array' }
interface SortedArray extends ArrayLike<number> { '@type': 'int-sorted-array' }
export default SortedArray
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment