Bladeren bron

added intersectionSize to interval, sorted-array, ordered-set

Alexander Rose 6 jaren geleden
bovenliggende
commit
a8d057aa0c

+ 6 - 0
src/mol-data/int/_spec/interval.spec.ts

@@ -73,4 +73,10 @@ describe('interval', () => {
     test('predIndexInt3', Interval.findPredecessorIndexInInterval(Interval.ofRange(3, 10), 5, Interval.ofRange(2, 6)), 2);
 
     testI('findRange', Interval.findRange(r05, 2, 3), Interval.ofRange(2, 3));
+
+    test('intersectionSize1', Interval.intersectionSize(Interval.ofRange(0, 5), Interval.ofRange(0, 5)), 6);
+    test('intersectionSize2', Interval.intersectionSize(Interval.ofRange(0, 5), Interval.ofRange(1, 2)), 2);
+    test('intersectionSize3', Interval.intersectionSize(Interval.ofRange(1, 2), Interval.ofRange(0, 5)), 2);
+    test('intersectionSize4', Interval.intersectionSize(Interval.ofRange(0, 5), Interval.ofRange(3, 8)), 3);
+    test('intersectionSize5', Interval.intersectionSize(Interval.ofRange(0, 5), Interval.ofRange(6, 8)), 0);
 });

+ 7 - 0
src/mol-data/int/_spec/ordered-set.spec.ts

@@ -116,6 +116,13 @@ describe('ordered set', () => {
         expect(OrderedSet.findRange(arr136, 2, 7)).toEqual(iB(1, 3));
     })
 
+    it('intersectionSize', () => {
+        expect(OrderedSet.intersectionSize(arr136, range1_4)).toEqual(2);
+        expect(OrderedSet.intersectionSize(arr12369, range1_4)).toEqual(3);
+        expect(OrderedSet.intersectionSize(OrderedSet.ofSortedArray([12, 13, 16]), range1_4)).toEqual(0);
+        expect(OrderedSet.intersectionSize(OrderedSet.ofSortedArray([1, 2, 4]), range1_4)).toEqual(3);
+    })
+
     testEq('union ES', OrderedSet.union(empty, singleton10), [10]);
     testEq('union ER', OrderedSet.union(empty, range1_4), [1, 2, 3, 4]);
     testEq('union EA', OrderedSet.union(empty, arr136), [1, 3, 6]);

+ 2 - 0
src/mol-data/int/_spec/sorted-array.spec.ts

@@ -63,6 +63,8 @@ describe('sortedArray', () => {
         compareArrays(SortedArray.indicesOf(SortedArray.ofSortedArray([10, 11, 12]), SortedArray.ofSortedArray([10, 12, 14])), [0, 2]);
     })
 
+    test('intersectionSize', SortedArray.intersectionSize(a1234, a2468), 2);
+
     // console.log(Interval.findPredecessorIndexInInterval(Interval.ofBounds(0, 3), 2, Interval.ofBounds(0, 3)))
     // console.log(SortedArray.findPredecessorIndexInInterval(SortedArray.ofSortedArray([0, 1, 2]), 2, Interval.ofBounds(0, 3)))
 });

+ 4 - 0
src/mol-data/int/impl/interval.ts

@@ -58,4 +58,8 @@ export function findRange(int: Tuple, min: number, max: number) {
 export function intersect(a: Tuple, b: Tuple) {
     if (!areIntersecting(a, b)) return Empty;
     return ofBounds(Math.max(start(a), start(b)), Math.min(end(a), end(b)));
+}
+
+export function intersectionSize(a: Tuple, b: Tuple) {
+    return size(findRange(a, min(b), max(b)))
 }

+ 14 - 0
src/mol-data/int/impl/ordered-set.ts

@@ -72,6 +72,14 @@ export function findRange(set: OrderedSetImpl, min: number, max: number) {
     return I.is(set) ? I.findRange(set, min, max) : S.findRange(set, min, max);
 }
 
+export function intersectionSize(a: OrderedSetImpl, b: OrderedSetImpl): number {
+    if (I.is(a)) {
+        if (I.is(b)) return I.intersectionSize(a, b);
+        return intersectionSizeSI(b, a);
+    } else if (I.is(b)) return intersectionSizeSI(a, b);
+    return S.intersectionSize(a, b);
+}
+
 export function union(a: OrderedSetImpl, b: OrderedSetImpl) {
     if (I.is(a)) {
         if (I.is(b)) return unionII(a, b);
@@ -165,6 +173,12 @@ function unionSI(a: S, b: I) {
     return ofSortedArray(indices);
 }
 
+function intersectionSizeSI(a: S, b: I): number {
+    if (!I.size(b)) return 0;
+    const r = S.findRange(a, I.min(b), I.max(b));
+    return I.end(r) - I.start(r);
+}
+
 function intersectSI(a: S, b: I) {
     if (!I.size(b)) return Empty;
 

+ 23 - 19
src/mol-data/int/impl/sorted-array.ts

@@ -161,15 +161,8 @@ export function isSubset(a: Nums, b: Nums) {
 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 { startI, startJ, endI, endJ } = getSuitableIntersectionRange(a, b);
+    const commonCount = getCommonCount(a, b, startI, startJ, endI, endJ);
 
     const lenA = a.length, lenB = b.length;
     // A === B || B is subset of A ==> A
@@ -181,12 +174,12 @@ export function union(a: Nums, b: Nums) {
     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];
+    for (let k = 0; k < startI; k++) indices[offset++] = a[k];
+    for (let k = 0; k < startJ; k++) indices[offset++] = b[k];
 
     // insert the common part
-    i = sI;
-    j = sJ;
+    let i = startI;
+    let j = startJ;
     while (i < endI && j < endJ) {
         const x = a[i], y = b[j];
         if (x < y) { indices[offset++] = x; i++; }
@@ -201,11 +194,14 @@ export function union(a: Nums, b: Nums) {
     return ofSortedArray(indices);
 }
 
-export function intersect(a: Nums, b: Nums) {
-    if (a === b) return a;
+export function intersectionSize(a: Nums, b: Nums) {
+    if (a === b) return size(a);
+    const { startI, startJ, endI, endJ } = getSuitableIntersectionRange(a, b);
+    return getCommonCount(a, b, startI, startJ, endI, endJ);
+}
 
-    const { startI: sI, startJ: sJ, endI, endJ } = getSuitableIntersectionRange(a, b);
-    let i = sI, j = sJ;
+function getCommonCount(a: Nums, b: Nums, startI: number, startJ: number, endI: number, endJ: number) {
+    let i = startI, j = startJ;
     let commonCount = 0;
     while (i < endI && j < endJ) {
         const x = a[i], y = b[j];
@@ -213,6 +209,14 @@ export function intersect(a: Nums, b: Nums) {
         else if (x > y) { j++; }
         else { i++; j++; commonCount++; }
     }
+    return commonCount;
+}
+
+export function intersect(a: Nums, b: Nums) {
+    if (a === b) return a;
+
+    const { startI, startJ, endI, endJ } = getSuitableIntersectionRange(a, b);
+    const commonCount = getCommonCount(a, b, startI, startJ, endI, endJ);
 
     const lenA = a.length, lenB = b.length;
     // no common elements
@@ -224,8 +228,8 @@ export function intersect(a: Nums, b: Nums) {
 
     const indices = new Int32Array(commonCount);
     let offset = 0;
-    i = sI;
-    j = sJ;
+    let i = startI;
+    let j = startJ;
     while (i < endI && j < endJ) {
         const x = a[i], y = b[j];
         if (x < y) { i++; }

+ 2 - 0
src/mol-data/int/interval.ts

@@ -45,6 +45,8 @@ namespace Interval {
     export const findPredecessorIndex: <T extends number = number>(interval: Interval<T>, x: T) => number = Impl.findPredecessorIndex as any;
     export const findPredecessorIndexInInterval: <T extends number = number>(interval: Interval<T>, x: T, bounds: Interval) => number = Impl.findPredecessorIndexInInterval as any;
     export const findRange: <T extends number = number>(interval: Interval<T>, min: T, max: T) => Interval = Impl.findRange as any;
+    /** Size of the intersection of the two intervals */
+    export const intersectionSize: <T extends number = number>(a: Interval<T>, b: Interval<T>) => number = Impl.intersectionSize as any;
 
     /** Get a new interval that is the intersection of the two intervals */
     export const intersect: <T extends number = number>(a: Interval<T>, b: Interval<T>) => Interval<T> = Impl.intersect as any;

+ 1 - 0
src/mol-data/int/ordered-set.ts

@@ -40,6 +40,7 @@ namespace OrderedSet {
     export const findPredecessorIndex: <T extends number = number>(set: OrderedSet<T>, x: number) => number = Base.findPredecessorIndex as any;
     export const findPredecessorIndexInInterval: <T extends number = number>(set: OrderedSet<T>, x: T, range: Interval) => number = Base.findPredecessorIndexInInterval as any;
     export const findRange: <T extends number = number>(set: OrderedSet<T>, min: T, max: T) => Interval = Base.findRange as any;
+    export const intersectionSize: <T extends number = number>(a: OrderedSet<T>, b: OrderedSet<T>) => number = Base.intersectionSize as any;
 
     export function forEach<T extends number, Ctx>(set: OrderedSet<T>, f: (v: T, i: number, ctx: Ctx) => void, ctx?: Ctx): Ctx {
         return Base.forEach(set as any, f as any, ctx);

+ 1 - 0
src/mol-data/int/sorted-array.ts

@@ -42,6 +42,7 @@ namespace SortedArray {
     export const findPredecessorIndex: <T extends number = number>(array: SortedArray<T>, x: T) => number = Impl.findPredecessorIndex as any;
     export const findPredecessorIndexInInterval: <T extends number = number>(array: SortedArray<T>, x: T, bounds: Interval) => number = Impl.findPredecessorIndexInInterval as any;
     export const findRange: <T extends number = number>(array: SortedArray<T>, min: T, max: T) => Interval = Impl.findRange as any;
+    export const intersectionSize: <T extends number = number>(a: SortedArray<T>, b: SortedArray<T>) => number = Impl.intersectionSize as any;
 
     export const deduplicate: <T extends number = number>(array: SortedArray<T>) => SortedArray<T> = Impl.deduplicate as any;
     /** Returns indices of xs in the array. E.g. indicesOf([10, 11, 12], [10, 12]) ==> [0, 2] */

+ 2 - 3
src/mol-geo/representation/structure/visual/util/polymer.ts

@@ -41,8 +41,7 @@ export function getPolymerElementCount(unit: Unit) {
         case Unit.Kind.Gaussians:
             while (polymerIt.hasNext) {
                 const { start, end } = polymerIt.move()
-                // TODO add OrderedSet.intersectionSize
-                count += OrderedSet.size(OrderedSet.intersect(Interval.ofBounds(elements[start], elements[end - 1]), elements))
+                count += OrderedSet.intersectionSize(Interval.ofBounds(elements[start], elements[end - 1]), elements)
             }
             break
     }
@@ -222,7 +221,7 @@ export class AtomicPolymerBackboneIterator<T extends number = number> implements
         }
 
         this.hasNext = residueIt.hasNext || polymerIt.hasNext
-        
+
         // console.log('hasNext', this.hasNext)
         // console.log('value', this.value)