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

collections

parent 424121fe
No related branches found
No related tags found
No related merge requests found
...@@ -184,6 +184,7 @@ describe('ordered set', () => { ...@@ -184,6 +184,7 @@ describe('ordered set', () => {
expect(OrderedSet.isSubset(arr136, OrderedSet.ofSortedArray([1, 3, 7]))).toBe(false); expect(OrderedSet.isSubset(arr136, OrderedSet.ofSortedArray([1, 3, 7]))).toBe(false);
expect(OrderedSet.isSubset(OrderedSet.ofSortedArray([0, 1, 2, 3, 7, 10]), OrderedSet.ofSortedArray([1, 3, 7]))).toBe(true); expect(OrderedSet.isSubset(OrderedSet.ofSortedArray([0, 1, 2, 3, 7, 10]), OrderedSet.ofSortedArray([1, 3, 7]))).toBe(true);
expect(OrderedSet.isSubset(arr136, OrderedSet.ofSortedArray([1, 3, 10, 45]))).toBe(false); expect(OrderedSet.isSubset(arr136, OrderedSet.ofSortedArray([1, 3, 10, 45]))).toBe(false);
expect(OrderedSet.isSubset(arr136, OrderedSet.ofSortedArray([12, 13, 16]))).toBe(false);
}); });
it('access/membership', () => { it('access/membership', () => {
...@@ -235,6 +236,10 @@ describe('ordered set', () => { ...@@ -235,6 +236,10 @@ describe('ordered set', () => {
testEq('union AA', OrderedSet.union(arr136, OrderedSet.ofSortedArray([2, 4, 6, 7])), [1, 2, 3, 4, 6, 7]); testEq('union AA', OrderedSet.union(arr136, OrderedSet.ofSortedArray([2, 4, 6, 7])), [1, 2, 3, 4, 6, 7]);
testEq('union AA1', OrderedSet.union(arr136, OrderedSet.ofSortedArray([2, 3, 4, 6, 7])), [1, 2, 3, 4, 6, 7]); testEq('union AA1', OrderedSet.union(arr136, OrderedSet.ofSortedArray([2, 3, 4, 6, 7])), [1, 2, 3, 4, 6, 7]);
testEq('union AA2', OrderedSet.union(arr136, OrderedSet.ofSortedArray([2, 4, 5, 6, 7])), [1, 2, 3, 4, 5, 6, 7]); testEq('union AA2', OrderedSet.union(arr136, OrderedSet.ofSortedArray([2, 4, 5, 6, 7])), [1, 2, 3, 4, 5, 6, 7]);
testEq('union AA3', OrderedSet.union(OrderedSet.ofSortedArray([1, 3]), OrderedSet.ofSortedArray([2, 4])), [1, 2, 3, 4]);
testEq('union AA4', OrderedSet.union(OrderedSet.ofSortedArray([1, 3]), OrderedSet.ofSortedArray([1, 3, 4])), [1, 3, 4]);
testEq('union AA5', OrderedSet.union(OrderedSet.ofSortedArray([1, 3, 4]), OrderedSet.ofSortedArray([1, 3])), [1, 3, 4]);
it('union AA6', () => expect(OrderedSet.union(arr136, OrderedSet.ofSortedArray([1, 3, 6]))).toBe(arr136));
testEq('intersect ES', OrderedSet.intersect(empty, singleton10), []); testEq('intersect ES', OrderedSet.intersect(empty, singleton10), []);
testEq('intersect ER', OrderedSet.intersect(empty, range1_4), []); testEq('intersect ER', OrderedSet.intersect(empty, range1_4), []);
...@@ -246,6 +251,7 @@ describe('ordered set', () => { ...@@ -246,6 +251,7 @@ describe('ordered set', () => {
testEq('intersect RR2', OrderedSet.intersect(range1_4, OrderedSet.ofRange(3, 5)), [3, 4]); testEq('intersect RR2', OrderedSet.intersect(range1_4, OrderedSet.ofRange(3, 5)), [3, 4]);
testEq('intersect RA', OrderedSet.intersect(range1_4, arr136), [1, 3]); testEq('intersect RA', OrderedSet.intersect(range1_4, arr136), [1, 3]);
testEq('intersect AA', OrderedSet.intersect(arr136, OrderedSet.ofSortedArray([2, 3, 4, 6, 7])), [3, 6]); testEq('intersect AA', OrderedSet.intersect(arr136, OrderedSet.ofSortedArray([2, 3, 4, 6, 7])), [3, 6]);
it('intersect AA1', () => expect(OrderedSet.union(arr136, OrderedSet.ofSortedArray([1, 3, 6]))).toBe(arr136));
testEq('subtract ES', OrderedSet.subtract(empty, singleton10), []); testEq('subtract ES', OrderedSet.subtract(empty, singleton10), []);
testEq('subtract ER', OrderedSet.subtract(empty, range1_4), []); testEq('subtract ER', OrderedSet.subtract(empty, range1_4), []);
......
...@@ -152,7 +152,11 @@ function hasA(set: SortedArray, x: number) { return x >= set[0] && x <= set[set. ...@@ -152,7 +152,11 @@ function hasA(set: SortedArray, x: number) { return x >= set[0] && x <= set[set.
function indexOfA(set: SortedArray, x: number) { return x >= set[0] && x <= set[set.length - 1] ? binarySearch(set, x) : -1; } function indexOfA(set: SortedArray, x: number) { return x >= set[0] && x <= set[set.length - 1] ? binarySearch(set, x) : -1; }
function binarySearch(xs: SortedArray, value: number) { function binarySearch(xs: SortedArray, value: number) {
let min = 0, max = xs.length - 1; return binarySearchRange(xs, value, 0, xs.length);
}
function binarySearchRange(xs: SortedArray, value: number, start: number, end: number) {
let min = start, max = end - 1;
while (min <= max) { while (min <= max) {
if (min + 11 > max) { if (min + 11 > max) {
for (let i = min; i <= max; i++) { for (let i = min; i <= max; i++) {
...@@ -234,17 +238,17 @@ function areIntersectingAA(xs: SortedArray, ys: SortedArray) { ...@@ -234,17 +238,17 @@ function areIntersectingAA(xs: SortedArray, ys: SortedArray) {
return false; return false;
} }
function isSubsetAA(xs: SortedArray, ys: SortedArray) { function isSubsetAA(a: SortedArray, b: SortedArray) {
if (xs === ys) return true; if (a === b) return true;
const lenB = ys.length; const lenB = b.length;
let { i, j, endA, endB } = getMaxIntersectionRange(xs, ys); let { i, j, endA, endB } = getMaxIntersectionRange(a, b);
// the 2nd array must be able to advance by at least lenB elements // must be able to advance by lenB elements
if (endB - j + 1 < lenB || endA - j + 1 < lenB) return false; if (endB - j + 1 < lenB || endA - i + 1 < lenB) return false;
let equal = 0; let equal = 0;
while (i <= endA && j <= endB) { while (i <= endA && j <= endB) {
const x = xs[i], y = ys[j]; const x = a[i], y = b[j];
if (x < y) { i++; } if (x < y) { i++; }
else if (x > y) { j++; } else if (x > y) { j++; }
else { i++; j++; equal++; } else { i++; j++; equal++; }
...@@ -302,8 +306,6 @@ function unionAR(a: SortedArray, b: Range) { ...@@ -302,8 +306,6 @@ function unionAR(a: SortedArray, b: Range) {
function unionAA(a: SortedArray, b: SortedArray) { function unionAA(a: SortedArray, b: SortedArray) {
if (a === b) return a; if (a === b) return a;
const lenA = a.length, lenB = b.length;
let { i: sI, j: sJ, endA, endB } = getMaxIntersectionRange(a, b); let { i: sI, j: sJ, endA, endB } = getMaxIntersectionRange(a, b);
let i = sI, j = sJ; let i = sI, j = sJ;
let commonCount = 0; let commonCount = 0;
...@@ -314,8 +316,11 @@ function unionAA(a: SortedArray, b: SortedArray) { ...@@ -314,8 +316,11 @@ function unionAA(a: SortedArray, b: SortedArray) {
else { i++; j++; commonCount++; } else { i++; j++; commonCount++; }
} }
if (!commonCount) return a; const lenA = a.length, lenB = b.length;
if (commonCount >= lenA) return OrderedSet.Empty // 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 resultSize = lenA + lenB - commonCount;
const l = Math.min(a[0], b[0]), r = Math.max(a[lenA - 1], b[lenB - 1]); const l = Math.min(a[0], b[0]), r = Math.max(a[lenA - 1], b[lenB - 1]);
...@@ -375,27 +380,33 @@ function intersectAR(a: SortedArray, r: Range) { ...@@ -375,27 +380,33 @@ function intersectAR(a: SortedArray, r: Range) {
return OrderedSet.ofSortedArray(indices); return OrderedSet.ofSortedArray(indices);
} }
function intersectAA(xs: SortedArray, ys: SortedArray) { function intersectAA(a: SortedArray, b: SortedArray) {
if (xs === ys) return xs; if (a === b) return a;
let { i: sI, j: sJ, endA, endB } = getMaxIntersectionRange(xs, ys); let { i: sI, j: sJ, endA, endB } = getMaxIntersectionRange(a, b);
let i = sI, j = sJ; let i = sI, j = sJ;
let resultSize = 0; let commonCount = 0;
while (i <= endA && j <= endB) { while (i <= endA && j <= endB) {
const x = xs[i], y = ys[j]; const x = a[i], y = b[j];
if (x < y) { i++; } if (x < y) { i++; }
else if (x > y) { j++; } else if (x > y) { j++; }
else { i++; j++; resultSize++; } else { i++; j++; commonCount++; }
} }
if (!resultSize) return OrderedSet.Empty; const lenA = a.length, lenB = b.length;
// no common elements
const indices = new Int32Array(resultSize); if (!commonCount) return OrderedSet.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; let offset = 0;
i = sI; i = sI;
j = sJ; j = sJ;
while (i <= endA && j <= endB) { while (i <= endA && j <= endB) {
const x = xs[i], y = ys[j]; const x = a[i], y = b[j];
if (x < y) { i++; } if (x < y) { i++; }
else if (x > y) { j++; } else if (x > y) { j++; }
else { indices[offset++] = x; i++; j++; } else { indices[offset++] = x; i++; j++; }
...@@ -417,6 +428,7 @@ function substractRR(a: Range, b: Range) { ...@@ -417,6 +428,7 @@ function substractRR(a: Range, b: Range) {
if (isRangeSubset(a, b)) { if (isRangeSubset(a, b)) {
// this splits the interval into two, gotta represent it as a set. // this splits the interval into two, gotta represent it as a set.
const l = _sRB.fst - _sRA.fst, r = _sRA.snd - _sRB.snd; const l = _sRB.fst - _sRA.fst, r = _sRA.snd - _sRB.snd;
// TODO: check if l === 0 || r === 0 ==> result would be a range
const ret = new Int32Array(l + r); const ret = new Int32Array(l + r);
let offset = 0; let offset = 0;
for (let i = 0; i < l; i++) ret[offset++] = _sRA.fst + i; for (let i = 0; i < l; i++) ret[offset++] = _sRA.fst + i;
...@@ -439,7 +451,11 @@ function subtractAR(a: SortedArray, b: Range) { ...@@ -439,7 +451,11 @@ function subtractAR(a: SortedArray, b: Range) {
const min = _sAR.fst, max = _sAR.snd; const min = _sAR.fst, max = _sAR.snd;
const { start, end } = getStartEnd(a, min, max); const { start, end } = getStartEnd(a, min, max);
const size = a.length - (end - start); const size = a.length - (end - start);
// A is subset of B
if (size <= 0) return OrderedSet.Empty; if (size <= 0) return OrderedSet.Empty;
// No common elements
if (size === a.length) return a;
const ret = new Int32Array(size); const ret = new Int32Array(size);
let offset = 0; let offset = 0;
for (let i = 0; i < start; i++) ret[offset++] = a[i]; for (let i = 0; i < start; i++) ret[offset++] = a[i];
...@@ -458,15 +474,21 @@ function subtractRA(a: Range, b: SortedArray) { ...@@ -458,15 +474,21 @@ function subtractRA(a: Range, b: SortedArray) {
const rSize = max - min + 1; const rSize = max - min + 1;
const { start, end } = getStartEnd(b, min, max); const { start, end } = getStartEnd(b, min, max);
const commonCount = end - start; const commonCount = end - start;
// No common elements.
if (commonCount === 0) return a;
const resultSize = rSize - commonCount; const resultSize = rSize - commonCount;
// A is subset of B
if (resultSize <= 0) return OrderedSet.Empty; if (resultSize <= 0) return OrderedSet.Empty;
const ret = new Int32Array(resultSize); const ret = new Int32Array(resultSize);
const li = b.length - 1; const li = b.length - 1;
const fst = b[Math.min(start, li)], last = b[Math.min(end, li)]; const fst = b[Math.min(start, li)], last = b[Math.min(end, li)];
let offset = 0; let offset = 0;
for (let i = min; i < fst; i++) ret[offset++] = i; for (let i = min; i < fst; i++) ret[offset++] = i;
for (let i = fst; i <= last; i++) { for (let i = fst; i <= last; i++) {
if (binarySearch(b, i) < 0) ret[offset++] = i; if (binarySearchRange(b, i, start, end) < 0) ret[offset++] = i;
} }
for (let i = last + 1; i <= max; i++) ret[offset++] = i; for (let i = last + 1; i <= max; i++) ret[offset++] = i;
return OrderedSet.ofSortedArray(ret); return OrderedSet.ofSortedArray(ret);
...@@ -487,7 +509,9 @@ function subtractAA(a: SortedArray, b: SortedArray) { ...@@ -487,7 +509,9 @@ function subtractAA(a: SortedArray, b: SortedArray) {
else { i++; j++; commonCount++; } else { i++; j++; commonCount++; }
} }
// A isnt intersecting B ===> A
if (!commonCount) return a; if (!commonCount) return a;
// A === B || A is subset of B ===> Empty
if (commonCount >= lenA) return OrderedSet.Empty; if (commonCount >= lenA) return OrderedSet.Empty;
const indices = new Int32Array(lenA - commonCount); const indices = new Int32Array(lenA - commonCount);
......
...@@ -8,6 +8,11 @@ ...@@ -8,6 +8,11 @@
interface Model { interface Model {
// Incremented when data changes
dataVersion: number,
// Incremented when the underlying conformation changes
conformationVersion: number,
} }
export default Model export default Model
...@@ -21,7 +21,7 @@ export interface Unit extends Readonly<{ ...@@ -21,7 +21,7 @@ export interface Unit extends Readonly<{
id: number, id: number,
// Each unit can only contain atoms from a single "chain" // Each unit can only contain atoms from a single "chain"
// the reason for this is to make symmetry and assembly transforms fast // the reason for this is to make certain basic data transforms fast
// without having to look at the actual contents of the unit // without having to look at the actual contents of the unit
// multiple units can point to the same chain // multiple units can point to the same chain
chainIndex: number, chainIndex: number,
...@@ -30,7 +30,7 @@ export interface Unit extends Readonly<{ ...@@ -30,7 +30,7 @@ export interface Unit extends Readonly<{
model: Model, model: Model,
// Determines the operation applied to this unit. // Determines the operation applied to this unit.
// The transform and and inverse a baked into the "getPosition" function // The transform and and inverse are baked into the "getPosition" function
operator: Operator operator: Operator
}> { }> {
// returns the untransformed position. Used for spatial queries. // returns the untransformed position. Used for spatial queries.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment