Browse Source

better types for IntAdjacencyGraph and GridLookup3D

Alexander Rose 5 years ago
parent
commit
5f8a4b6be4

+ 12 - 12
src/mol-math/geometry/lookup3d/grid.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author David Sehnal <david.sehnal@gmail.com>
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
@@ -17,19 +17,19 @@ interface GridLookup3D<T = number> extends Lookup3D<T> {
     readonly buckets: { readonly offset: ArrayLike<number>, readonly count: ArrayLike<number>, readonly array: ArrayLike<number> }
 }
 
-function GridLookup3D(data: PositionData, cellSizeOrCount?: Vec3 | number): GridLookup3D {
-    return new GridLookup3DImpl(data, cellSizeOrCount);
+function GridLookup3D<T extends number = number>(data: PositionData, cellSizeOrCount?: Vec3 | number): GridLookup3D<T> {
+    return new GridLookup3DImpl<T>(data, cellSizeOrCount);
 }
 
 export { GridLookup3D }
 
-class GridLookup3DImpl implements GridLookup3D<number> {
-    private ctx: QueryContext;
+class GridLookup3DImpl<T extends number = number> implements GridLookup3D<T> {
+    private ctx: QueryContext<T>;
     boundary: Lookup3D['boundary'];
     buckets: GridLookup3D['buckets'];
-    result: Result<number>
+    result: Result<T>
 
-    find(x: number, y: number, z: number, radius: number): Result<number> {
+    find(x: number, y: number, z: number, radius: number): Result<T> {
         this.ctx.x = x;
         this.ctx.y = y;
         this.ctx.z = z;
@@ -50,7 +50,7 @@ class GridLookup3DImpl implements GridLookup3D<number> {
 
     constructor(data: PositionData, cellSizeOrCount?: Vec3 | number) {
         const structure = build(data, cellSizeOrCount);
-        this.ctx = createContext(structure);
+        this.ctx = createContext<T>(structure);
         this.boundary = { box: structure.boundingBox, sphere: structure.boundingSphere };
         this.buckets = { offset: structure.bucketOffset, count: structure.bucketCounts, array: structure.bucketArray };
         this.result = this.ctx.result
@@ -236,21 +236,21 @@ function build(data: PositionData, cellSizeOrCount?: Vec3 | number) {
     return _build(state);
 }
 
-interface QueryContext {
+interface QueryContext<T extends number = number> {
     grid: Grid3D,
     x: number,
     y: number,
     z: number,
     radius: number,
-    result: Result<number>,
+    result: Result<T>,
     isCheck: boolean
 }
 
-function createContext(grid: Grid3D): QueryContext {
+function createContext<T extends number = number>(grid: Grid3D): QueryContext<T> {
     return { grid, x: 0.1, y: 0.1, z: 0.1, radius: 0.1, result: Result.create(), isCheck: false }
 }
 
-function query(ctx: QueryContext): boolean {
+function query<T extends number = number>(ctx: QueryContext<T>): boolean {
     const { min, size: [sX, sY, sZ], bucketOffset, bucketCounts, bucketArray, grid, data: { x: px, y: py, z: pz, indices, radius }, delta, maxRadius } = ctx.grid;
     const { radius: inputRadius, isCheck, x, y, z, result } = ctx;
 

+ 43 - 42
src/mol-math/graph/int-adjacency-graph.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author David Sehnal <david.sehnal@gmail.com>
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
@@ -7,6 +7,7 @@
 
 import { arrayPickIndices, cantorPairing } from '../../mol-data/util';
 import { LinkedIndex, SortedArray } from '../../mol-data/int';
+import { AssignableArrayLike } from '../../mol-util/type-helpers';
 
 /**
  * Represent a graph using vertex adjacency list.
@@ -16,10 +17,10 @@ import { LinkedIndex, SortedArray } from '../../mol-data/int';
  *
  * Edge properties are indexed same as in the arrays a and b.
  */
-export interface IntAdjacencyGraph<EdgeProps extends IntAdjacencyGraph.EdgePropsBase = {}> {
+export interface IntAdjacencyGraph<VertexIndex extends number, EdgeProps extends IntAdjacencyGraph.EdgePropsBase> {
     readonly offset: ArrayLike<number>,
-    readonly a: ArrayLike<number>,
-    readonly b: ArrayLike<number>,
+    readonly a: ArrayLike<VertexIndex>,
+    readonly b: ArrayLike<VertexIndex>,
     readonly vertexCount: number,
     readonly edgeCount: number,
     readonly edgeProps: Readonly<EdgeProps>
@@ -33,25 +34,25 @@ export interface IntAdjacencyGraph<EdgeProps extends IntAdjacencyGraph.EdgeProps
      *
      * `getEdgeIndex(i, j) === getEdgeIndex(j, i)`
      */
-    getEdgeIndex(i: number, j: number): number,
+    getEdgeIndex(i: VertexIndex, j: VertexIndex): number,
     /**
      * Get the edge index between i-th and j-th vertex.
      * -1 if the edge does not exist.
      *
      * `getEdgeIndex(i, j) !== getEdgeIndex(j, i)`
      */
-    getDirectedEdgeIndex(i: number, j: number): number,
-    getVertexEdgeCount(i: number): number
+    getDirectedEdgeIndex(i: VertexIndex, j: VertexIndex): number,
+    getVertexEdgeCount(i: VertexIndex): number
 }
 
 export namespace IntAdjacencyGraph {
     export type EdgePropsBase = { [name: string]: ArrayLike<any> }
 
-    class IntGraphImpl implements IntAdjacencyGraph<any> {
+    class IntGraphImpl<VertexIndex extends number, EdgeProps extends IntAdjacencyGraph.EdgePropsBase> implements IntAdjacencyGraph<VertexIndex, EdgeProps> {
         readonly vertexCount: number;
-        readonly edgeProps: object;
+        readonly edgeProps: EdgeProps;
 
-        getEdgeIndex(i: number, j: number): number {
+        getEdgeIndex(i: VertexIndex, j: VertexIndex): number {
             let a, b;
             if (i < j) { a = i; b = j; }
             else { a = j; b = i; }
@@ -61,28 +62,28 @@ export namespace IntAdjacencyGraph {
             return -1;
         }
 
-        getDirectedEdgeIndex(i: number, j: number): number {
+        getDirectedEdgeIndex(i: VertexIndex, j: VertexIndex): number {
             for (let t = this.offset[i], _t = this.offset[i + 1]; t < _t; t++) {
                 if (this.b[t] === j) return t;
             }
             return -1;
         }
 
-        getVertexEdgeCount(i: number): number {
+        getVertexEdgeCount(i: VertexIndex): number {
             return this.offset[i + 1] - this.offset[i];
         }
 
-        constructor(public offset: ArrayLike<number>, public a: ArrayLike<number>, public b: ArrayLike<number>, public edgeCount: number, edgeProps?: any) {
+        constructor(public offset: ArrayLike<number>, public a: ArrayLike<VertexIndex>, public b: ArrayLike<VertexIndex>, public edgeCount: number, edgeProps?: EdgeProps) {
             this.vertexCount = offset.length - 1;
-            this.edgeProps = edgeProps || {};
+            this.edgeProps = (edgeProps || {}) as EdgeProps;
         }
     }
 
-    export function create<EdgeProps extends IntAdjacencyGraph.EdgePropsBase = {}>(offset: ArrayLike<number>, a: ArrayLike<number>, b: ArrayLike<number>, edgeCount: number, edgeProps?: EdgeProps): IntAdjacencyGraph<EdgeProps> {
-        return new IntGraphImpl(offset, a, b, edgeCount, edgeProps) as IntAdjacencyGraph<EdgeProps>;
+    export function create<VertexIndex extends number, EdgeProps extends IntAdjacencyGraph.EdgePropsBase>(offset: ArrayLike<number>, a: ArrayLike<VertexIndex>, b: ArrayLike<VertexIndex>, edgeCount: number, edgeProps?: EdgeProps): IntAdjacencyGraph<VertexIndex, EdgeProps> {
+        return new IntGraphImpl(offset, a, b, edgeCount, edgeProps) as IntAdjacencyGraph<VertexIndex, EdgeProps>;
     }
 
-    export class EdgeBuilder {
+    export class EdgeBuilder<VertexIndex extends number> {
         private bucketFill: Int32Array;
         private current = 0;
         private curA: number = 0;
@@ -92,11 +93,11 @@ export namespace IntAdjacencyGraph {
         edgeCount: number;
         /** the size of the A and B arrays */
         slotCount: number;
-        a: Int32Array;
-        b: Int32Array;
+        a: AssignableArrayLike<VertexIndex>;
+        b: AssignableArrayLike<VertexIndex>;
 
-        createGraph<EdgeProps extends IntAdjacencyGraph.EdgePropsBase = {}>(edgeProps?: EdgeProps) {
-            return create(this.offsets, this.a, this.b, this.edgeCount, edgeProps);
+        createGraph<EdgeProps extends IntAdjacencyGraph.EdgePropsBase>(edgeProps: EdgeProps) {
+            return create<VertexIndex, EdgeProps>(this.offsets, this.a, this.b, this.edgeCount, edgeProps);
         }
 
         /**
@@ -139,7 +140,7 @@ export namespace IntAdjacencyGraph {
             prop[this.curB] = value;
         }
 
-        constructor(public vertexCount: number, public xs: ArrayLike<number>, public ys: ArrayLike<number>) {
+        constructor(public vertexCount: number, public xs: ArrayLike<VertexIndex>, public ys: ArrayLike<VertexIndex>) {
             this.edgeCount = xs.length;
             this.offsets = new Int32Array(this.vertexCount + 1);
             this.bucketFill = new Int32Array(this.vertexCount);
@@ -155,12 +156,12 @@ export namespace IntAdjacencyGraph {
             }
             this.offsets[this.vertexCount] = offset;
             this.slotCount = offset;
-            this.a = new Int32Array(offset);
-            this.b = new Int32Array(offset);
+            this.a = new Int32Array(offset) as unknown as AssignableArrayLike<VertexIndex>;
+            this.b = new Int32Array(offset) as unknown as AssignableArrayLike<VertexIndex>;
         }
     }
 
-    export class DirectedEdgeBuilder {
+    export class DirectedEdgeBuilder<VertexIndex extends number> {
         private bucketFill: Int32Array;
         private current = 0;
         private curA: number = 0;
@@ -172,7 +173,7 @@ export namespace IntAdjacencyGraph {
         a: Int32Array;
         b: Int32Array;
 
-        createGraph<EdgeProps extends IntAdjacencyGraph.EdgePropsBase = {}>(edgeProps?: EdgeProps) {
+        createGraph<EdgeProps extends IntAdjacencyGraph.EdgePropsBase>(edgeProps: EdgeProps) {
             return create(this.offsets, this.a, this.b, this.edgeCount, edgeProps);
         }
 
@@ -209,7 +210,7 @@ export namespace IntAdjacencyGraph {
             prop[this.curA] = value;
         }
 
-        constructor(public vertexCount: number, public xs: ArrayLike<number>, public ys: ArrayLike<number>) {
+        constructor(public vertexCount: number, public xs: ArrayLike<VertexIndex>, public ys: ArrayLike<VertexIndex>) {
             this.edgeCount = xs.length;
             this.offsets = new Int32Array(this.vertexCount + 1);
             this.bucketFill = new Int32Array(this.vertexCount);
@@ -229,12 +230,12 @@ export namespace IntAdjacencyGraph {
         }
     }
 
-    export class UniqueEdgeBuilder {
-        private xs: number[] = [];
-        private ys: number[] = [];
+    export class UniqueEdgeBuilder<VertexIndex extends number> {
+        private xs: VertexIndex[] = [];
+        private ys: VertexIndex[] = [];
         private included = new Set<number>();
 
-        addEdge(i: number, j: number) {
+        addEdge(i: VertexIndex, j: VertexIndex) {
             let u = i, v = j;
             if (i > j) { u = j; v = i; }
             const id = cantorPairing(u, v);
@@ -245,7 +246,7 @@ export namespace IntAdjacencyGraph {
             return true;
         }
 
-        getGraph(): IntAdjacencyGraph {
+        getGraph(): IntAdjacencyGraph<VertexIndex, {}> {
             return fromVertexPairs(this.vertexCount, this.xs, this.ys);
         }
 
@@ -258,13 +259,13 @@ export namespace IntAdjacencyGraph {
         }
     }
 
-    export function fromVertexPairs(vertexCount: number, xs: number[], ys: number[]) {
+    export function fromVertexPairs<V extends number>(vertexCount: number, xs: V[], ys: V[]) {
         const graphBuilder = new IntAdjacencyGraph.EdgeBuilder(vertexCount, xs, ys);
         graphBuilder.addAllEdges();
-        return graphBuilder.createGraph();
+        return graphBuilder.createGraph({});
     }
 
-    export function induceByVertices<P extends IntAdjacencyGraph.EdgePropsBase>(graph: IntAdjacencyGraph<P>, vertexIndices: ArrayLike<number>): IntAdjacencyGraph<P> {
+    export function induceByVertices<V extends number, P extends IntAdjacencyGraph.EdgePropsBase>(graph: IntAdjacencyGraph<V, P>, vertexIndices: ArrayLike<number>): IntAdjacencyGraph<V, P> {
         const { b, offset, vertexCount, edgeProps } = graph;
         const vertexMap = new Int32Array(vertexCount);
         for (let i = 0, _i = vertexIndices.length; i < _i; i++) vertexMap[vertexIndices[i]] = i + 1;
@@ -279,8 +280,8 @@ export namespace IntAdjacencyGraph {
 
         const newOffsets = new Int32Array(vertexIndices.length + 1);
         const edgeIndices = new Int32Array(2 * newEdgeCount);
-        const newA = new Int32Array(2 * newEdgeCount);
-        const newB = new Int32Array(2 * newEdgeCount);
+        const newA = new Int32Array(2 * newEdgeCount) as unknown as AssignableArrayLike<V>;
+        const newB = new Int32Array(2 * newEdgeCount) as unknown as AssignableArrayLike<V>;
         let eo = 0, vo = 0;
         for (let i = 0; i < vertexCount; i++) {
             if (vertexMap[i] === 0) continue;
@@ -289,8 +290,8 @@ export namespace IntAdjacencyGraph {
                 const bb = vertexMap[b[j]];
                 if (bb === 0) continue;
 
-                newA[eo] = aa;
-                newB[eo] = bb - 1;
+                newA[eo] = aa as V;
+                newB[eo] = bb - 1 as V;
                 edgeIndices[eo] = j;
                 eo++;
             }
@@ -305,7 +306,7 @@ export namespace IntAdjacencyGraph {
         return create(newOffsets, newA, newB, newEdgeCount, newEdgeProps);
     }
 
-    export function connectedComponents(graph: IntAdjacencyGraph): { componentCount: number, componentIndex: Int32Array } {
+    export function connectedComponents(graph: IntAdjacencyGraph<any, any>): { componentCount: number, componentIndex: Int32Array } {
         const vCount = graph.vertexCount;
 
         if (vCount === 0) return { componentCount: 0, componentIndex: new Int32Array(0) };
@@ -357,7 +358,7 @@ export namespace IntAdjacencyGraph {
      *
      * Returns true if verticesA and verticesB are intersecting.
      */
-    export function areVertexSetsConnected(graph: IntAdjacencyGraph, verticesA: SortedArray<number>, verticesB: SortedArray<number>, maxDistance: number): boolean {
+    export function areVertexSetsConnected(graph: IntAdjacencyGraph<any, any>, verticesA: SortedArray<number>, verticesB: SortedArray<number>, maxDistance: number): boolean {
         // check if A and B are intersecting, this handles maxDistance = 0
         if (SortedArray.areIntersecting(verticesA, verticesB)) return true;
         if (maxDistance < 1) return false;
@@ -371,7 +372,7 @@ export namespace IntAdjacencyGraph {
     }
 }
 
-function areVertexSetsConnectedImpl(graph: IntAdjacencyGraph, frontier: ArrayLike<number>, target: SortedArray<number>, distance: number, visited: Set<number>): boolean {
+function areVertexSetsConnectedImpl(graph: IntAdjacencyGraph<any, any>, frontier: ArrayLike<number>, target: SortedArray<number>, distance: number, visited: Set<number>): boolean {
     const { b: neighbor, offset } = graph;
     const newFrontier: number[] = [];
 

+ 5 - 4
src/mol-model-props/computed/interactions/common.ts

@@ -8,19 +8,20 @@ import { IntAdjacencyGraph } from '../../../mol-math/graph'
 import { InterUnitGraph } from '../../../mol-math/graph/inter-unit-graph'
 import { Unit } from '../../../mol-model/structure'
 import { AssignableArrayLike } from '../../../mol-util/type-helpers'
+import { Features } from './features'
 
 type IntraProps = {
     readonly type: ArrayLike<InteractionType>
     readonly flag: AssignableArrayLike<InteractionFlag>
 }
-export type InteractionsIntraContacts = IntAdjacencyGraph<IntraProps>
+export type InteractionsIntraContacts = IntAdjacencyGraph<Features.FeatureIndex, IntraProps>
 
 export { InteractionsInterContacts }
 type InterProps = { type: InteractionType, flag: InteractionFlag }
-type InteractionsInterContacts = InterUnitGraph<Unit, number, InterProps>
+type InteractionsInterContacts = InterUnitGraph<Unit, Features.FeatureIndex, InterProps>
 namespace InteractionsInterContacts {
-    export class Pair extends InterUnitGraph.UnitPairEdges<Unit, number, InterProps> {}
-    export type Info = InterUnitGraph.EdgeInfo<number, InterProps>
+    export class Pair extends InterUnitGraph.UnitPairEdges<Unit, Features.FeatureIndex, InterProps> {}
+    export type Info = InterUnitGraph.EdgeInfo<Features.FeatureIndex, InterProps>
 }
 
 export const enum InteractionFlag {

+ 19 - 19
src/mol-model-props/computed/interactions/contacts-builder.ts

@@ -7,7 +7,7 @@
 import { Features } from './features';
 import { IntAdjacencyGraph } from '../../../mol-math/graph';
 import { InteractionType, InteractionsIntraContacts, InteractionsInterContacts, InteractionFlag } from './common';
-import { Unit, StructureElement } from '../../../mol-model/structure/structure';
+import { Unit } from '../../../mol-model/structure/structure';
 import { InterUnitGraph } from '../../../mol-math/graph/inter-unit-graph';
 import { UniqueArray } from '../../../mol-data/generic';
 import { NumberArray } from '../../../mol-util/type-helpers';
@@ -15,18 +15,18 @@ import { NumberArray } from '../../../mol-util/type-helpers';
 export { IntraContactsBuilder }
 
 interface IntraContactsBuilder {
-    add: (indexA: number, indexB: number, type: InteractionType) => void
+    add: (indexA: Features.FeatureIndex, indexB: Features.FeatureIndex, type: InteractionType) => void
     getContacts: () => InteractionsIntraContacts
 }
 
 namespace IntraContactsBuilder {
     export function create(features: Features, elementsCount: number): IntraContactsBuilder {
-        const aIndices: number[] = []
-        const bIndices: number[] = []
+        const aIndices: Features.FeatureIndex[] = []
+        const bIndices: Features.FeatureIndex[] = []
         const types: number[] = []
 
         return {
-            add(indexA: number, indexB: number, type: InteractionType) {
+            add(indexA: Features.FeatureIndex, indexB: Features.FeatureIndex, type: InteractionType) {
                 aIndices[aIndices.length] = indexA
                 bIndices[bIndices.length] = indexB
                 types[types.length] = type
@@ -50,7 +50,7 @@ export { InterContactsBuilder }
 interface InterContactsBuilder {
     startUnitPair: (unitA: Unit, unitB: Unit) => void
     finishUnitPair: () => void
-    add: (indexA: number, indexB: number, type: InteractionType) => void
+    add: (indexA: Features.FeatureIndex, indexB: Features.FeatureIndex, type: InteractionType) => void
     getContacts: () => InteractionsInterContacts
 }
 
@@ -65,9 +65,9 @@ namespace InterContactsBuilder {
         let uB: Unit
         let mapAB: Map<number, InteractionsInterContacts.Info[]>
         let mapBA: Map<number, InteractionsInterContacts.Info[]>
-        let bondedA: UniqueArray<StructureElement.UnitIndex, StructureElement.UnitIndex>
-        let bondedB: UniqueArray<StructureElement.UnitIndex, StructureElement.UnitIndex>
-        let bondCount: number
+        let linkedA: UniqueArray<Features.FeatureIndex, Features.FeatureIndex>
+        let linkedB: UniqueArray<Features.FeatureIndex, Features.FeatureIndex>
+        let linkCount: number
 
         const map = new Map<number, InteractionsInterContacts.Pair[]>();
 
@@ -77,21 +77,21 @@ namespace InterContactsBuilder {
                 uB = unitB
                 mapAB = new Map()
                 mapBA = new Map()
-                bondedA = UniqueArray.create()
-                bondedB = UniqueArray.create()
-                bondCount = 0
+                linkedA = UniqueArray.create()
+                linkedB = UniqueArray.create()
+                linkCount = 0
             },
             finishUnitPair() {
-                if (bondCount === 0) return
-                addMapEntry(map, uA.id, new InteractionsInterContacts.Pair(uA, uB, bondCount, bondedA.array, mapAB))
-                addMapEntry(map, uB.id, new InteractionsInterContacts.Pair(uB, uA, bondCount, bondedB.array, mapBA))
+                if (linkCount === 0) return
+                addMapEntry(map, uA.id, new InteractionsInterContacts.Pair(uA, uB, linkCount, linkedA.array, mapAB))
+                addMapEntry(map, uB.id, new InteractionsInterContacts.Pair(uB, uA, linkCount, linkedB.array, mapBA))
             },
-            add(indexA: number, indexB: number, type: InteractionType) {
+            add(indexA: Features.FeatureIndex, indexB: Features.FeatureIndex, type: InteractionType) {
                 addMapEntry(mapAB, indexA, { indexB, props: { type, flag: InteractionFlag.None } })
                 addMapEntry(mapBA, indexB, { indexB: indexA, props: { type, flag: InteractionFlag.None } })
-                UniqueArray.add(bondedA, indexA, indexA)
-                UniqueArray.add(bondedB, indexB, indexB)
-                bondCount += 1
+                UniqueArray.add(linkedA, indexA, indexA)
+                UniqueArray.add(linkedB, indexB, indexB)
+                linkCount += 1
             },
             getContacts() {
                 return new InterUnitGraph(map);

+ 1 - 1
src/mol-model-props/computed/interactions/contacts.ts

@@ -192,7 +192,7 @@ export function addStructureContacts(structure: Structure, unitA: Unit.Atomic, f
 
     builder.startUnitPair(unitA, unitB)
 
-    for (let i = 0; i < count; ++i) {
+    for (let i = 0 as Features.FeatureIndex; i < count; ++i) {
         Vec3.set(imageA, xA[i], yA[i], zA[i])
         if (isNotIdentity) Vec3.transformMat4(imageA, imageA, imageTransform)
         if (Vec3.squaredDistance(imageA, center) > testDistanceSq) continue

+ 7 - 7
src/mol-model-props/computed/interactions/features.ts

@@ -29,7 +29,7 @@ interface Features {
     readonly members: ArrayLike<StructureElement.UnitIndex>
 
     /** lookup3d based on center coordinates, in invariant coordinate space */
-    readonly lookup3d: GridLookup3D
+    readonly lookup3d: GridLookup3D<Features.FeatureIndex>
     /** maps unit elements to features, range for unit element i is offsets[i] to offsets[i + 1] */
     readonly elementsIndex: Features.ElementsIndex
 
@@ -60,7 +60,7 @@ namespace Features {
     }
 
     export type Subset = {
-        readonly indices: OrderedSet
+        readonly indices: OrderedSet<FeatureIndex>
         readonly lookup3d: GridLookup3D
     }
 
@@ -92,13 +92,13 @@ namespace Features {
     }
 
     export function create(elementsCount: number, data: Data): Features {
-        let lookup3d: GridLookup3D
+        let lookup3d: GridLookup3D<FeatureIndex>
         let elementsIndex: ElementsIndex
 
         return {
             ...data,
             get lookup3d() {
-                return lookup3d || (lookup3d = GridLookup3D({ x: data.x, y: data.y, z: data.z, indices: OrderedSet.ofBounds(0, data.count) }))
+                return lookup3d || (lookup3d = GridLookup3D({ x: data.x, y: data.y, z: data.z, indices: OrderedSet.ofBounds(0 as FeatureIndex, data.count as FeatureIndex) }))
             },
             get elementsIndex() {
                 return elementsIndex || (elementsIndex = createElementsIndex(data, elementsCount))
@@ -116,7 +116,7 @@ namespace Features {
         for (let i = 0; i < count; ++i) {
             if (types.has(_types[i])) _indices.push(i)
         }
-        const indices = SortedArray.ofSortedArray(_indices)
+        const indices = SortedArray.ofSortedArray<FeatureIndex>(_indices)
 
         return {
             indices,
@@ -129,7 +129,7 @@ namespace Features {
     export interface Info {
         unit: Unit.Atomic,
         types: ArrayLike<FeatureType>,
-        feature: number,
+        feature: FeatureIndex,
         x: ArrayLike<number>
         y: ArrayLike<number>
         z: ArrayLike<number>
@@ -144,7 +144,7 @@ namespace Features {
         return {
             unit,
             types: features.types,
-            feature: -1,
+            feature: -1 as any,
             x: features.x,
             y: features.y,
             z: features.z,

+ 22 - 22
src/mol-model-props/computed/interactions/interactions.ts

@@ -39,13 +39,13 @@ namespace Interactions {
         interactions: Interactions
         unitA: Unit
         /** Index into features of unitA */
-        indexA: number
+        indexA: Features.FeatureIndex
         unitB: Unit
         /** Index into features of unitB */
-        indexB: number
+        indexB: Features.FeatureIndex
     }
 
-    export function Location(interactions?: Interactions, unitA?: Unit, indexA?: number, unitB?: Unit, indexB?: number): Location {
+    export function Location(interactions?: Interactions, unitA?: Unit, indexA?: Features.FeatureIndex, unitB?: Unit, indexB?: Features.FeatureIndex): Location {
         return { kind: 'interaction-location', interactions: interactions as any, unitA: unitA as any, indexA: indexA as any, unitB: unitB as any, indexB: indexB as any };
     }
 
@@ -68,10 +68,10 @@ namespace Interactions {
         readonly links: ReadonlyArray<{
             unitA: Unit
             /** Index into features of unitA */
-            indexA: number
+            indexA: Features.FeatureIndex
             unitB: Unit
             /** Index into features of unitB */
-            indexB: number
+            indexB: Features.FeatureIndex
         }>
     }
 
@@ -111,7 +111,7 @@ const FeatureProviders = [
     MetalProvider, MetalBindingProvider,
 ]
 
-const LinkProviders = {
+const ContactProviders = {
     'ionic': IonicProvider,
     'pi-stacking': PiStackingProvider,
     'cation-pi': CationPiProvider,
@@ -121,12 +121,12 @@ const LinkProviders = {
     'hydrophobic': HydrophobicProvider,
     'metal-coordination': MetalCoordinationProvider,
 }
-type LinkProviders = typeof LinkProviders
+type ContactProviders = typeof ContactProviders
 
 function getProvidersParams() {
-    const params: { [k in keyof LinkProviders]: PD.Group<LinkProviders[k]['params']> } = Object.create(null)
-    Object.keys(LinkProviders).forEach(k => {
-        (params as any)[k] = PD.Group(LinkProviders[k as keyof LinkProviders].params)
+    const params: { [k in keyof ContactProviders]: PD.Group<ContactProviders[k]['params']> } = Object.create(null)
+    Object.keys(ContactProviders).forEach(k => {
+        (params as any)[k] = PD.Group(ContactProviders[k as keyof ContactProviders].params)
     })
     return params
 }
@@ -140,7 +140,7 @@ export const InteractionsParams = {
         // 'hydrophobic',
         'metal-coordination',
         // 'weak-hydrogen-bonds',
-    ], PD.objectToOptions(LinkProviders)),
+    ], PD.objectToOptions(ContactProviders)),
     contacts: PD.Group(ContactsParams, { isFlat: true }),
     ...getProvidersParams()
 }
@@ -151,14 +151,14 @@ export async function computeInteractions(runtime: RuntimeContext, structure: St
     const p = { ...PD.getDefaultValues(InteractionsParams), ...props }
     await ValenceModelProvider.attach(structure).runInContext(runtime)
 
-    const linkProviders: ContactProvider<any>[] = []
-    Object.keys(LinkProviders).forEach(k => {
-        if (p.types.includes(k)) linkProviders.push(LinkProviders[k as keyof typeof LinkProviders])
+    const contactProviders: ContactProvider<any>[] = []
+    Object.keys(ContactProviders).forEach(k => {
+        if (p.types.includes(k)) contactProviders.push(ContactProviders[k as keyof typeof ContactProviders])
     })
-    const linkTesters = linkProviders.map(l => l.createTester(p[l.name as keyof InteractionsProps]))
+    const contactTesters = contactProviders.map(l => l.createTester(p[l.name as keyof InteractionsProps]))
 
     const requiredFeatures = new Set<FeatureType>()
-    linkTesters.forEach(l => SetUtils.add(requiredFeatures, l.requiredFeatures))
+    contactTesters.forEach(l => SetUtils.add(requiredFeatures, l.requiredFeatures))
     const featureProviders = FeatureProviders.filter(f => SetUtils.areIntersecting(requiredFeatures, f.types))
 
     const unitsFeatures = IntMap.Mutable<Features>()
@@ -170,15 +170,15 @@ export async function computeInteractions(runtime: RuntimeContext, structure: St
             await runtime.update({ message: 'computing interactions', current: i, max: il })
         }
         const features = findUnitFeatures(structure, group.units[0], featureProviders)
-        const intraUnitLinks = findIntraUnitContacts(structure, group.units[0], features, linkTesters, p.contacts)
+        const intraUnitContacts = findIntraUnitContacts(structure, group.units[0], features, contactTesters, p.contacts)
         for (let j = 0, jl = group.units.length; j < jl; ++j) {
             const u = group.units[j]
             unitsFeatures.set(u.id, features)
-            unitsContacts.set(u.id, intraUnitLinks)
+            unitsContacts.set(u.id, intraUnitContacts)
         }
     }
 
-    const contacts = findInterUnitContacts(structure, unitsFeatures, linkTesters, p.contacts)
+    const contacts = findInterUnitContacts(structure, unitsFeatures, contactTesters, p.contacts)
 
     const interactions = { unitsFeatures, unitsContacts, contacts }
     refineInteractions(structure, interactions)
@@ -197,11 +197,11 @@ function findUnitFeatures(structure: Structure, unit: Unit, featureProviders: Fe
 }
 
 function findIntraUnitContacts(structure: Structure, unit: Unit, features: Features, contactTesters: ReadonlyArray<ContactTester>, props: ContactsProps) {
-    const linksBuilder = IntraContactsBuilder.create(features, unit.elements.length)
+    const builder = IntraContactsBuilder.create(features, unit.elements.length)
     if (Unit.isAtomic(unit)) {
-        addUnitContacts(structure, unit, features, linksBuilder, contactTesters, props)
+        addUnitContacts(structure, unit, features, builder, contactTesters, props)
     }
-    return linksBuilder.getContacts()
+    return builder.getContacts()
 }
 
 function findInterUnitContacts(structure: Structure, unitsFeatures: IntMap<Features>, contactTesters: ReadonlyArray<ContactTester>, props: ContactsProps) {

+ 2 - 2
src/mol-model-props/computed/secondary-structure/dssp/common.ts

@@ -17,7 +17,7 @@ export interface DSSPContext {
         oldOrdering: boolean
     },
     getResidueFlag: (f: DSSPType) => SecondaryStructureType,
-    getFlagName: (f: DSSPType) => String,
+    getFlagName: (f: DSSPType) => string,
 
     unit: Unit.Atomic
     proteinInfo: ProteinInfo
@@ -53,7 +53,7 @@ namespace DSSPType {
     }
 }
 
-export type DsspHbonds = IntAdjacencyGraph<{ readonly energies: ArrayLike<number> }>
+export type DsspHbonds = IntAdjacencyGraph<number, { readonly energies: ArrayLike<number> }>
 
 export interface Ladder {
     previousLadder: number,

+ 2 - 2
src/mol-model/structure/structure/unit.ts

@@ -128,7 +128,7 @@ namespace Unit {
         getChild(elements: StructureElement.Set): Unit,
         applyOperator(id: number, operator: SymmetryOperator, dontCompose?: boolean /* = false */): Unit,
 
-        readonly lookup3d: Lookup3D
+        readonly lookup3d: Lookup3D<StructureElement.UnitIndex>
         readonly polymerElements: SortedArray<ElementIndex>
         readonly gapElements: SortedArray<ElementIndex>
         /**
@@ -138,7 +138,7 @@ namespace Unit {
     }
 
     interface BaseProperties {
-        lookup3d: ValueRef<Lookup3D | undefined>,
+        lookup3d: ValueRef<Lookup3D<StructureElement.UnitIndex> | undefined>,
         principalAxes: ValueRef<PrincipalAxes | undefined>,
         polymerElements: ValueRef<SortedArray<ElementIndex> | undefined>
         gapElements: ValueRef<SortedArray<ElementIndex> | undefined>

+ 2 - 2
src/mol-model/structure/structure/unit/bonds/data.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author David Sehnal <david.sehnal@gmail.com>
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
@@ -12,7 +12,7 @@ import StructureElement from '../../element';
 import { Bond } from '../bonds';
 import { InterUnitGraph } from '../../../../../mol-math/graph/inter-unit-graph';
 
-type IntraUnitBonds = IntAdjacencyGraph<{ readonly order: ArrayLike<number>, readonly flags: ArrayLike<BondType.Flag> }>
+type IntraUnitBonds = IntAdjacencyGraph<StructureElement.UnitIndex, { readonly order: ArrayLike<number>, readonly flags: ArrayLike<BondType.Flag> }>
 
 namespace IntraUnitBonds {
     export const Empty: IntraUnitBonds = IntAdjacencyGraph.create([], [], [], 0, { flags: [], order: [] });

+ 6 - 5
src/mol-model/structure/structure/unit/bonds/intra-compute.ts

@@ -13,8 +13,9 @@ import { BondComputationProps, getElementIdx, MetalsSet, getElementThreshold, is
 import { SortedArray } from '../../../../../mol-data/int';
 import { StructConn, ComponentBond } from '../../../../../mol-model-formats/structure/mmcif/bonds';
 import { getIntraBondOrderFromTable } from '../../../model/properties/atomic/bonds';
+import StructureElement from '../../element';
 
-function getGraph(atomA: number[], atomB: number[], _order: number[], _flags: number[], atomCount: number): IntraUnitBonds {
+function getGraph(atomA: StructureElement.UnitIndex[], atomB: StructureElement.UnitIndex[], _order: number[], _flags: number[], atomCount: number): IntraUnitBonds {
     const builder = new IntAdjacencyGraph.EdgeBuilder(atomCount, atomA, atomB);
     const flags = new Uint16Array(builder.slotCount);
     const order = new Int8Array(builder.slotCount);
@@ -40,15 +41,15 @@ function _computeBonds(unit: Unit.Atomic, props: BondComputationProps): IntraUni
     const structConn = unit.model.sourceData.kind === 'mmCIF' ? StructConn.get(unit.model) : void 0;
     const component = unit.model.sourceData.kind === 'mmCIF' ? ComponentBond.get(unit.model) : void 0;
 
-    const atomA: number[] = [];
-    const atomB: number[] = [];
+    const atomA: StructureElement.UnitIndex[] = [];
+    const atomB: StructureElement.UnitIndex[] = [];
     const flags: number[] = [];
     const order: number[] = [];
 
     let lastResidue = -1;
     let componentMap: Map<string, Map<string, { flags: number, order: number }>> | undefined = void 0;
 
-    for (let _aI = 0; _aI < atomCount; _aI++) {
+    for (let _aI = 0 as StructureElement.UnitIndex; _aI < atomCount; _aI++) {
         const aI =  atoms[_aI];
         const raI = residueIndex[aI];
         const compId = label_comp_id.value(raI);
@@ -78,7 +79,7 @@ function _computeBonds(unit: Unit.Atomic, props: BondComputationProps): IntraUni
                 if (se.distance > MAX_RADIUS) continue;
 
                 for (const p of se.partners) {
-                    const _bI = SortedArray.indexOf(unit.elements, p.atomIndex);
+                    const _bI = SortedArray.indexOf(unit.elements, p.atomIndex) as StructureElement.UnitIndex;
                     if (_bI < 0) continue;
                     atomA[atomA.length] = _aI;
                     atomB[atomB.length] = _bI;