diff --git a/src/mol-base/collections/_spec/int-tuple.spec.ts b/src/mol-base/collections/_spec/int-tuple.spec.ts
index acdfb01b60fa661c69c73ff72b264ba4586413c9..6ff7827c44d1b843a2fe185469553afca6b9d7e7 100644
--- a/src/mol-base/collections/_spec/int-tuple.spec.ts
+++ b/src/mol-base/collections/_spec/int-tuple.spec.ts
@@ -4,7 +4,7 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import IntTuple from '../int-tuple'
+import IntTuple from '../integer/tuple'
 
 describe('int pair', () => {
     it('works', () => {
diff --git a/src/mol-base/collections/_spec/interval.spec.ts b/src/mol-base/collections/_spec/interval.spec.ts
index cda22df8eaf9cde2c640ca6e2216b02dc1772dac..015d541234de67e3340d686d5ab0c5bde2daf8c5 100644
--- a/src/mol-base/collections/_spec/interval.spec.ts
+++ b/src/mol-base/collections/_spec/interval.spec.ts
@@ -4,7 +4,7 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import Interval from '../interval'
+import Interval from '../integer/interval'
 
 describe('interval', () => {
     function testI(name: string, a: Interval, b: Interval) {
diff --git a/src/mol-base/collections/_spec/ordered-set.spec.ts b/src/mol-base/collections/_spec/ordered-set.spec.ts
index 41b70f708458908e4ae701bc333650ec709d7881..28927b185d0e0143bb8be5be3d9bd18bd1fd49ef 100644
--- a/src/mol-base/collections/_spec/ordered-set.spec.ts
+++ b/src/mol-base/collections/_spec/ordered-set.spec.ts
@@ -4,8 +4,8 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import OrderedSet from '../ordered-set'
-import Interval from '../interval'
+import OrderedSet from '../integer/ordered-set'
+import Interval from '../integer/interval'
 
 describe('ordered set', () => {
     function ordSetToArray(set: OrderedSet) {
diff --git a/src/mol-base/collections/_spec/segmentation.spec.ts b/src/mol-base/collections/_spec/segmentation.spec.ts
index 8cd02e2482bca7847f98cddb9a2eff83618e5175..cac55f128def003f9af3b3ac5bf46a8e352778db 100644
--- a/src/mol-base/collections/_spec/segmentation.spec.ts
+++ b/src/mol-base/collections/_spec/segmentation.spec.ts
@@ -4,10 +4,10 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import OrderedSet from '../ordered-set'
-import Interval from '../interval'
-import Segmentation from '../segmentation'
-import SortedArray from '../sorted-array'
+import OrderedSet from '../integer/ordered-set'
+import Interval from '../integer/interval'
+import Segmentation from '../integer/segmentation'
+import SortedArray from '../integer/sorted-array'
 
 describe('segments', () => {
     const data = OrderedSet.ofSortedArray([4, 9, 10, 11, 14, 15, 16]);
diff --git a/src/mol-base/collections/_spec/sorted-array.spec.ts b/src/mol-base/collections/_spec/sorted-array.spec.ts
index d0e3ab9e674c4f1c08e97661a1fa9b8b1cd93205..9a8871e645443b51d74b2eec3038222bb52c9fa2 100644
--- a/src/mol-base/collections/_spec/sorted-array.spec.ts
+++ b/src/mol-base/collections/_spec/sorted-array.spec.ts
@@ -4,8 +4,8 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import Interval from '../interval'
-import SortedArray from '../sorted-array'
+import Interval from '../integer/interval'
+import SortedArray from '../integer/sorted-array'
 
 describe('sortedArray', () => {
     function testI(name: string, a: Interval, b: Interval) {
diff --git a/src/mol-base/collections/impl/interval.ts b/src/mol-base/collections/impl/interval.ts
deleted file mode 100644
index 6f810a8f1e39dddc356b57ab54dde24b05a58d13..0000000000000000000000000000000000000000
--- a/src/mol-base/collections/impl/interval.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author David Sehnal <david.sehnal@gmail.com>
- */
-
-import IntTuple from '../int-tuple'
-
-export const Empty = IntTuple.Zero;
-export function ofRange(min: number, max: number) { return max < min ? IntTuple.create(min, min) : IntTuple.create(min, max + 1); }
-export function ofBounds(min: number, max: number) { return max <= min ? IntTuple.create(min, min) : IntTuple.create(min, max); }
-export const is = IntTuple.is;
-
-export const start = IntTuple.fst;
-export const end = IntTuple.snd;
-export const min = IntTuple.fst;
-export function max(i: IntTuple) { return IntTuple.snd(i) - 1; }
-export function size(i: IntTuple) { return IntTuple.snd(i) - IntTuple.fst(i); }
-export const hashCode = IntTuple.hashCode;
-
-export function has(int: IntTuple, v: number) { return IntTuple.fst(int) <= v && v < IntTuple.snd(int); }
-export function indexOf(int: IntTuple, x: number) { const m = start(int); return x >= m && x < end(int) ? x - m : -1; }
-export function getAt(int: IntTuple, i: number) { return IntTuple.fst(int) + i; }
-
-export const areEqual = IntTuple.areEqual;
-export function areIntersecting(a: IntTuple, b: IntTuple) {
-    const sa = size(a), sb = size(b);
-    if (sa === 0 && sb === 0) return true;
-    return sa > 0 && sb > 0 && max(a) >= min(b) && min(a) <= max(b);
-}
-export function isSubInterval(a: IntTuple, b: IntTuple) {
-    if (!size(a)) return size(b) === 0;
-    if (!size(b)) return true;
-    return start(a) <= start(b) && end(a) >= end(b);
-}
-
-export function findPredecessorIndex(int: IntTuple, v: number) {
-    const s = start(int);
-    if (v <= s) return 0;
-    const e = end(int);
-    if (v >= e) return e - s;
-    return v - s;
-}
-
-export function findPredecessorIndexInInterval(int: IntTuple, x: number, bounds: IntTuple) {
-    const ret = findPredecessorIndex(int, x);
-    const s = start(bounds), e = end(bounds);
-    return ret <= s ? s : ret >= e ? e : ret;
-}
-
-export function findRange(int: IntTuple, min: number, max: number) {
-    return ofBounds(findPredecessorIndex(int, min), findPredecessorIndex(int, max + 1));
-}
-
-export function intersect(a: IntTuple, b: IntTuple) {
-    if (!areIntersecting(a, b)) return Empty;
-    return ofBounds(Math.max(start(a), start(b)), Math.min(end(a), end(b)));
-}
\ No newline at end of file
diff --git a/src/mol-base/collections/integer/impl/interval.ts b/src/mol-base/collections/integer/impl/interval.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2f29f47e762c32c75ba83ff52a32392f58e943d5
--- /dev/null
+++ b/src/mol-base/collections/integer/impl/interval.ts
@@ -0,0 +1,58 @@
+/**
+ * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import Tuple from '../tuple'
+
+export const Empty = Tuple.Zero;
+export function ofRange(min: number, max: number) { return max < min ? Tuple.create(min, min) : Tuple.create(min, max + 1); }
+export function ofBounds(min: number, max: number) { return max <= min ? Tuple.create(min, min) : Tuple.create(min, max); }
+export const is = Tuple.is;
+
+export const start = Tuple.fst;
+export const end = Tuple.snd;
+export const min = Tuple.fst;
+export function max(i: Tuple) { return Tuple.snd(i) - 1; }
+export function size(i: Tuple) { return Tuple.snd(i) - Tuple.fst(i); }
+export const hashCode = Tuple.hashCode;
+
+export function has(int: Tuple, v: number) { return Tuple.fst(int) <= v && v < Tuple.snd(int); }
+export function indexOf(int: Tuple, x: number) { const m = start(int); return x >= m && x < end(int) ? x - m : -1; }
+export function getAt(int: Tuple, i: number) { return Tuple.fst(int) + i; }
+
+export const areEqual = Tuple.areEqual;
+export function areIntersecting(a: Tuple, b: Tuple) {
+    const sa = size(a), sb = size(b);
+    if (sa === 0 && sb === 0) return true;
+    return sa > 0 && sb > 0 && max(a) >= min(b) && min(a) <= max(b);
+}
+export function isSubInterval(a: Tuple, b: Tuple) {
+    if (!size(a)) return size(b) === 0;
+    if (!size(b)) return true;
+    return start(a) <= start(b) && end(a) >= end(b);
+}
+
+export function findPredecessorIndex(int: Tuple, v: number) {
+    const s = start(int);
+    if (v <= s) return 0;
+    const e = end(int);
+    if (v >= e) return e - s;
+    return v - s;
+}
+
+export function findPredecessorIndexInInterval(int: Tuple, x: number, bounds: Tuple) {
+    const ret = findPredecessorIndex(int, x);
+    const s = start(bounds), e = end(bounds);
+    return ret <= s ? s : ret >= e ? e : ret;
+}
+
+export function findRange(int: Tuple, min: number, max: number) {
+    return ofBounds(findPredecessorIndex(int, min), findPredecessorIndex(int, max + 1));
+}
+
+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)));
+}
\ No newline at end of file
diff --git a/src/mol-base/collections/impl/ordered-set.ts b/src/mol-base/collections/integer/impl/ordered-set.ts
similarity index 100%
rename from src/mol-base/collections/impl/ordered-set.ts
rename to src/mol-base/collections/integer/impl/ordered-set.ts
diff --git a/src/mol-base/collections/impl/segmentation.ts b/src/mol-base/collections/integer/impl/segmentation.ts
similarity index 98%
rename from src/mol-base/collections/impl/segmentation.ts
rename to src/mol-base/collections/integer/impl/segmentation.ts
index 1fd21916ece5276ee06627b3cf3afa3df41363bf..af0dc24883368c8758d5b02a94329b62e544de2a 100644
--- a/src/mol-base/collections/impl/segmentation.ts
+++ b/src/mol-base/collections/integer/impl/segmentation.ts
@@ -4,7 +4,7 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import Iterator from '../iterator'
+import Iterator from '../../iterator'
 import OrderedSet from '../ordered-set'
 import Interval from '../interval'
 import SortedArray from '../sorted-array'
diff --git a/src/mol-base/collections/impl/sorted-array.ts b/src/mol-base/collections/integer/impl/sorted-array.ts
similarity index 97%
rename from src/mol-base/collections/impl/sorted-array.ts
rename to src/mol-base/collections/integer/impl/sorted-array.ts
index 376a4bf19705f382a2b695cda57709179f05ec39..30c7292fc74a251961f607dc9f24019c4b992c42 100644
--- a/src/mol-base/collections/impl/sorted-array.ts
+++ b/src/mol-base/collections/integer/impl/sorted-array.ts
@@ -4,8 +4,8 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import { sortArray } from '../sort'
-import { hash3, hash4 } from '../hash-functions'
+import { sortArray } from '../../sort'
+import { hash3, hash4 } from '../../hash-functions'
 import Interval from '../interval'
 
 type Nums = ArrayLike<number>
diff --git a/src/mol-base/collections/interval.ts b/src/mol-base/collections/integer/interval.ts
similarity index 100%
rename from src/mol-base/collections/interval.ts
rename to src/mol-base/collections/integer/interval.ts
diff --git a/src/mol-base/collections/ordered-set.ts b/src/mol-base/collections/integer/ordered-set.ts
similarity index 95%
rename from src/mol-base/collections/ordered-set.ts
rename to src/mol-base/collections/integer/ordered-set.ts
index 1be957f3618d92e0547c3c9a6d97e1e61e2e72f0..76bb495cf2bedbf5e4b973fdd7eedc6de83f6844 100644
--- a/src/mol-base/collections/ordered-set.ts
+++ b/src/mol-base/collections/integer/ordered-set.ts
@@ -4,10 +4,8 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-//import * as Base from './ordered-set/base'
 import * as Base from './impl/ordered-set'
 import Interval from './interval'
-import SegmentIterator from './ordered-set/segment-iterator'
 
 namespace OrderedSet {
     export const Empty: OrderedSet = Base.Empty as any;
diff --git a/src/mol-base/collections/segmentation.ts b/src/mol-base/collections/integer/segmentation.ts
similarity index 96%
rename from src/mol-base/collections/segmentation.ts
rename to src/mol-base/collections/integer/segmentation.ts
index a270e7a2397f13d64f976e72107c9fe96fadb6fc..6225478c9e9bc3fb22d9efc18e2bc236300eca5c 100644
--- a/src/mol-base/collections/segmentation.ts
+++ b/src/mol-base/collections/integer/segmentation.ts
@@ -4,7 +4,7 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import Iterator from './iterator'
+import Iterator from '../iterator'
 import Interval from './interval'
 import OrderedSet from './ordered-set'
 import SortedArray from './sorted-array'
diff --git a/src/mol-base/collections/sorted-array.ts b/src/mol-base/collections/integer/sorted-array.ts
similarity index 100%
rename from src/mol-base/collections/sorted-array.ts
rename to src/mol-base/collections/integer/sorted-array.ts
diff --git a/src/mol-base/collections/int-tuple.ts b/src/mol-base/collections/integer/tuple.ts
similarity index 98%
rename from src/mol-base/collections/int-tuple.ts
rename to src/mol-base/collections/integer/tuple.ts
index da27ab08f9dce6c63e9f7bfcb23a96314a58c300..19ad017c579dc45551226da26e49ae9545629159 100644
--- a/src/mol-base/collections/int-tuple.ts
+++ b/src/mol-base/collections/integer/tuple.ts
@@ -4,7 +4,7 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import { hash2 } from './hash-functions'
+import { hash2 } from '../hash-functions'
 
 /**
  * Represents a pair of two integers as a double,
diff --git a/src/mol-data/_spec/atom-set.spec.ts b/src/mol-data/_spec/atom-set.spec.ts
index b34cbc2ca25abdb916009da38a7758b07ae50b59..4239e2af8f7c53f0fd2e14e809637f954a119c90 100644
--- a/src/mol-data/_spec/atom-set.spec.ts
+++ b/src/mol-data/_spec/atom-set.spec.ts
@@ -4,8 +4,8 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import IntTuple from '../../mol-base/collections/int-tuple'
-import OrderedSet from '../../mol-base/collections/ordered-set'
+import IntTuple from '../../mol-base/collections/integer/tuple'
+import OrderedSet from '../../mol-base/collections/integer/ordered-set'
 import AtomSet from '../atom-set'
 
 describe('atom set', () => {
diff --git a/src/mol-data/atom-set.ts b/src/mol-data/atom-set.ts
index abf072be780461fefdbb56551f321751edd152a8..d638c30fc90abf1f905a8335e0d4e6f1b7e557c9 100644
--- a/src/mol-data/atom-set.ts
+++ b/src/mol-data/atom-set.ts
@@ -4,9 +4,9 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import OrderedSet from '../mol-base/collections/ordered-set'
+import OrderedSet from '../mol-base/collections/integer/ordered-set'
 import Iterator from '../mol-base/collections/iterator'
-import IntTuple from '../mol-base/collections/int-tuple'
+import Tuple from '../mol-base/collections/integer/tuple'
 import * as Base from './atom-set/base'
 import createBuilder from './atom-set/builder'
 
@@ -14,7 +14,7 @@ import createBuilder from './atom-set/builder'
 namespace AtomSet {
     export const Empty: AtomSet = Base.Empty as any;
 
-    export const create: (data: IntTuple | ArrayLike<IntTuple> | IntTuple | { [id: number]: OrderedSet }) => AtomSet = Base.create as any;
+    export const create: (data: Tuple | ArrayLike<Tuple> | Tuple | { [id: number]: OrderedSet }) => AtomSet = Base.create as any;
 
     export const units: (set: AtomSet) => OrderedSet = Base.getKeys as any;
     export const unitCount: (set: AtomSet) => number = Base.keyCount as any;
@@ -24,10 +24,10 @@ namespace AtomSet {
     export const getByKey: (set: AtomSet, key: number) => OrderedSet = Base.getByKey as any;
     export const getByIndex: (set: AtomSet, i: number) => OrderedSet = Base.getByIndex as any;
 
-    export const hasAtom: (set: AtomSet, x: IntTuple) => boolean = Base.hasTuple as any;
-    export const indexOfAtom: (set: AtomSet, x: IntTuple) => number = Base.indexOf as any;
-    export const getAtomAt: (set: AtomSet, i: number) => IntTuple = Base.getAt as any;
-    export const atoms: (set: AtomSet) => Iterator<IntTuple> = Base.values as any;
+    export const hasAtom: (set: AtomSet, x: Tuple) => boolean = Base.hasTuple as any;
+    export const indexOfAtom: (set: AtomSet, x: Tuple) => number = Base.indexOf as any;
+    export const getAtomAt: (set: AtomSet, i: number) => Tuple = Base.getAt as any;
+    export const atoms: (set: AtomSet) => Iterator<Tuple> = Base.values as any;
 
     export const atomCount: (set: AtomSet) => number = Base.size as any;
 
diff --git a/src/mol-data/atom-set/base.ts b/src/mol-data/atom-set/base.ts
index c5105a51e8440a8b65c8fb93e39ec45724a5e343..5df7aa753354f3b41ec64975af4c4b84bde9633a 100644
--- a/src/mol-data/atom-set/base.ts
+++ b/src/mol-data/atom-set/base.ts
@@ -4,22 +4,22 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import OrderedSet from '../../mol-base/collections/ordered-set'
+import OrderedSet from '../../mol-base/collections/integer/ordered-set'
 import Iterator from '../../mol-base/collections/iterator'
-import IntTuple from '../../mol-base/collections/int-tuple'
-import Interval from '../../mol-base/collections/interval'
+import Tuple from '../../mol-base/collections/integer/tuple'
+import Interval from '../../mol-base/collections/integer/interval'
 import { sortArray } from '../../mol-base/collections/sort'
 import { hash1 } from '../../mol-base/collections/hash-functions'
 
 /** Long and painful implementation starts here */
 
 export interface AtomSetElements { [id: number]: OrderedSet, offsets: number[], hashCode: number, keys: OrderedSet }
-export type AtomSetImpl = IntTuple | AtomSetElements
+export type AtomSetImpl = Tuple | AtomSetElements
 
 export const Empty: AtomSetImpl = { offsets: [0], hashCode: 0, keys: OrderedSet.Empty };
 
-export function create(data: IntTuple | ArrayLike<IntTuple> | { [id: number]: OrderedSet }): AtomSetImpl {
-    if (typeof data === 'number' || IntTuple.is(data)) return data;
+export function create(data: Tuple | ArrayLike<Tuple> | { [id: number]: OrderedSet }): AtomSetImpl {
+    if (typeof data === 'number' || Tuple.is(data)) return data;
     if (isArrayLike(data)) return ofTuples(data);
     return ofObject(data as { [id: number]: OrderedSet });
 }
@@ -39,42 +39,42 @@ export function keyCount(set: AtomSetImpl): number {
 }
 
 export function hasKey(set: AtomSetImpl, key: number): boolean {
-    if (typeof set === 'number') return IntTuple.fst(set) === key;
+    if (typeof set === 'number') return Tuple.fst(set) === key;
     return OrderedSet.has((set as AtomSetElements).keys, key);
 }
 
 export function getKey(set: AtomSetImpl, index: number): number {
-    if (typeof set === 'number') return IntTuple.fst(set);
+    if (typeof set === 'number') return Tuple.fst(set);
     return OrderedSet.getAt((set as AtomSetElements).keys, index);
 }
 
-export function hasTuple(set: AtomSetImpl, t: IntTuple): boolean {
-    if (typeof set === 'number') return IntTuple.areEqual(t, set);
-    const unit = IntTuple.fst(t);
+export function hasTuple(set: AtomSetImpl, t: Tuple): boolean {
+    if (typeof set === 'number') return Tuple.areEqual(t, set);
+    const unit = Tuple.fst(t);
     return OrderedSet.has((set as AtomSetElements).keys, unit)
-        ? OrderedSet.has((set as AtomSetElements)[unit], IntTuple.snd(t)) : false;
+        ? OrderedSet.has((set as AtomSetElements)[unit], Tuple.snd(t)) : false;
 }
 
 export function getByKey(set: AtomSetImpl, key: number): OrderedSet {
     if (typeof set === 'number') {
-        return IntTuple.fst(set) === key ? OrderedSet.ofSingleton(IntTuple.snd(set)) : OrderedSet.Empty;
+        return Tuple.fst(set) === key ? OrderedSet.ofSingleton(Tuple.snd(set)) : OrderedSet.Empty;
     }
     return OrderedSet.has((set as AtomSetElements).keys, key) ? (set as AtomSetElements)[key] : OrderedSet.Empty;
 }
 
 export function getByIndex(set: AtomSetImpl, index: number): OrderedSet {
-    if (typeof set === 'number') return index === 0 ? OrderedSet.ofSingleton(IntTuple.snd(set)) : OrderedSet.Empty;
+    if (typeof set === 'number') return index === 0 ? OrderedSet.ofSingleton(Tuple.snd(set)) : OrderedSet.Empty;
     const key = OrderedSet.getAt((set as AtomSetElements).keys, index);
     return (set as AtomSetElements)[key] || OrderedSet.Empty;
 }
 
-export function getAt(set: AtomSetImpl, i: number): IntTuple {
+export function getAt(set: AtomSetImpl, i: number): Tuple {
     if (typeof set === 'number') return set;
     return getAtE(set as AtomSetElements, i);
 }
 
-export function indexOf(set: AtomSetImpl, t: IntTuple) {
-    if (typeof set === 'number') return IntTuple.areEqual(set, t) ? 0 : -1;
+export function indexOf(set: AtomSetImpl, t: Tuple) {
+    if (typeof set === 'number') return Tuple.areEqual(set, t) ? 0 : -1;
     return indexOfE(set as AtomSetElements, t);
 }
 
@@ -85,14 +85,14 @@ export function size(set: AtomSetImpl) {
 }
 
 export function hashCode(set: AtomSetImpl) {
-    if (typeof set === 'number') return IntTuple.hashCode(set);
+    if (typeof set === 'number') return Tuple.hashCode(set);
     if ((set as AtomSetElements).hashCode !== -1) return (set as AtomSetElements).hashCode;
     return computeHash((set as AtomSetElements));
 }
 
 export function areEqual(a: AtomSetImpl, b: AtomSetImpl) {
     if (typeof a === 'number') {
-        if (typeof b === 'number') return IntTuple.areEqual(a, b);
+        if (typeof b === 'number') return Tuple.areEqual(a, b);
         return false;
     }
     if (typeof b === 'number') return false;
@@ -101,7 +101,7 @@ export function areEqual(a: AtomSetImpl, b: AtomSetImpl) {
 
 export function areIntersecting(a: AtomSetImpl, b: AtomSetImpl) {
     if (typeof a === 'number') {
-        if (typeof b === 'number') return IntTuple.areEqual(a, b);
+        if (typeof b === 'number') return Tuple.areEqual(a, b);
         return areIntersectingNE(a, b as AtomSetElements);
     }
     if (typeof b === 'number') return areIntersectingNE(b, a as AtomSetElements);
@@ -110,7 +110,7 @@ export function areIntersecting(a: AtomSetImpl, b: AtomSetImpl) {
 
 export function intersect(a: AtomSetImpl, b: AtomSetImpl) {
     if (typeof a === 'number') {
-        if (typeof b === 'number') return IntTuple.areEqual(a, b) ? a : Empty;
+        if (typeof b === 'number') return Tuple.areEqual(a, b) ? a : Empty;
         return intersectNE(a, b as AtomSetElements);
     }
     if (typeof b === 'number') return intersectNE(b, a as AtomSetElements);
@@ -119,7 +119,7 @@ export function intersect(a: AtomSetImpl, b: AtomSetImpl) {
 
 export function subtract(a: AtomSetImpl, b: AtomSetImpl) {
     if (typeof a === 'number') {
-        if (typeof b === 'number') return IntTuple.areEqual(a, b) ? Empty : a;
+        if (typeof b === 'number') return Tuple.areEqual(a, b) ? Empty : a;
         return subtractNE(a, b as AtomSetElements);
     }
     if (typeof b === 'number') return subtractEN(a as AtomSetElements, b);
@@ -134,7 +134,7 @@ export function unionMany(sets: ArrayLike<AtomSetImpl>) {
     return findUnion(sets);
 }
 
-class ElementsIterator implements Iterator<IntTuple> {
+class ElementsIterator implements Iterator<Tuple> {
     private unit: number = 0;
     private keyCount: number;
     private setIndex = -1;
@@ -147,13 +147,13 @@ class ElementsIterator implements Iterator<IntTuple> {
     next() { const value = this.move(); return { value, done: this.done } }
 
     move() {
-        if (this.done) return IntTuple.Zero;
+        if (this.done) return Tuple.Zero;
 
         if (this.currentIndex >= this.currentSize) {
-            if (!this.advance()) return IntTuple.Zero;
+            if (!this.advance()) return Tuple.Zero;
         }
 
-        return IntTuple.create(this.unit, OrderedSet.getAt(this.currentSet, this.currentIndex++));
+        return Tuple.create(this.unit, OrderedSet.getAt(this.currentSet, this.currentIndex++));
     }
 
     private advance() {
@@ -175,12 +175,12 @@ class ElementsIterator implements Iterator<IntTuple> {
     }
 }
 
-export function values(set: AtomSetImpl): Iterator<IntTuple> {
-    if (typeof set === 'number') return Iterator.Value(set as IntTuple);
+export function values(set: AtomSetImpl): Iterator<Tuple> {
+    if (typeof set === 'number') return Iterator.Value(set as Tuple);
     return new ElementsIterator(set as AtomSetElements);
 }
 
-function isArrayLike(x: any): x is ArrayLike<IntTuple> {
+function isArrayLike(x: any): x is ArrayLike<Tuple> {
     return x && (typeof x.length === 'number' && (x instanceof Array || !!x.buffer));
 }
 
@@ -193,7 +193,7 @@ function ofObject(data: { [id: number]: OrderedSet }) {
     if (!keys.length) return Empty;
     if (keys.length === 1) {
         const set = data[keys[0]];
-        if (OrderedSet.size(set) === 1) return IntTuple.create(keys[0], OrderedSet.getAt(set, 0));
+        if (OrderedSet.size(set) === 1) return Tuple.create(keys[0], OrderedSet.getAt(set, 0));
     }
     return ofObject1(keys, data);
 }
@@ -202,7 +202,7 @@ function ofObject1(keys: number[], data: { [id: number]: OrderedSet }) {
     if (keys.length === 1) {
         const k = keys[0];
         const set = data[k];
-        if (OrderedSet.size(set) === 1) return IntTuple.create(k, OrderedSet.getAt(set, 0));
+        if (OrderedSet.size(set) === 1) return Tuple.create(k, OrderedSet.getAt(set, 0));
     }
     sortArray(keys);
     return _createObjectOrdered(OrderedSet.ofSortedArray(keys), data);
@@ -212,7 +212,7 @@ function ofObjectOrdered(keys: OrderedSet, data: { [id: number]: OrderedSet }) {
     if (OrderedSet.size(keys) === 1) {
         const k = OrderedSet.getAt(keys, 0);
         const set = data[k];
-        if (OrderedSet.size(set) === 1) return IntTuple.create(k, OrderedSet.getAt(set, 0));
+        if (OrderedSet.size(set) === 1) return Tuple.create(k, OrderedSet.getAt(set, 0));
     }
     return _createObjectOrdered(keys, data);
 }
@@ -256,12 +256,12 @@ function normalizeArray(xs: number[]) {
     return xs;
 }
 
-function ofTuples(xs: ArrayLike<IntTuple>) {
+function ofTuples(xs: ArrayLike<Tuple>) {
     if (xs.length === 0) return Empty;
     const sets: { [key: number]: number[] } = Object.create(null);
     for (let i = 0, _i = xs.length; i < _i; i++) {
         const x = xs[i];
-        const u = IntTuple.fst(x), v = IntTuple.snd(x);
+        const u = Tuple.fst(x), v = Tuple.snd(x);
         const set = sets[u];
         if (set) set[set.length] = v;
         else sets[u] = [v];
@@ -291,21 +291,21 @@ function getOffsetIndex(xs: ArrayLike<number>, value: number) {
     return value < xs[min] ? min - 1 : min;
 }
 
-function getAtE(set: AtomSetElements, i: number): IntTuple {
+function getAtE(set: AtomSetElements, i: number): Tuple {
     const { offsets, keys } = set;
     const o = getOffsetIndex(offsets, i);
     if (o >= offsets.length - 1) return 0 as any;
     const k = OrderedSet.getAt(keys, o);
     const e = OrderedSet.getAt(set[k], i - offsets[o]);
-    return IntTuple.create(k, e);
+    return Tuple.create(k, e);
 }
 
-function indexOfE(set: AtomSetElements, t: IntTuple) {
+function indexOfE(set: AtomSetElements, t: Tuple) {
     const { keys } = set;
-    const u = IntTuple.fst(t);
+    const u = Tuple.fst(t);
     const setIdx = OrderedSet.indexOf(keys, u);
     if (setIdx < 0) return -1;
-    const o = OrderedSet.indexOf(set[u], IntTuple.snd(t));
+    const o = OrderedSet.indexOf(set[u], Tuple.snd(t));
     if (o < 0) return -1;
     return set.offsets[setIdx] + o;
 }
@@ -337,9 +337,9 @@ function areEqualEE(a: AtomSetElements, b: AtomSetElements) {
     return true;
 }
 
-function areIntersectingNE(a: IntTuple, b: AtomSetElements) {
-    const u = IntTuple.fst(a);
-    return OrderedSet.has(b.keys, u) && OrderedSet.has(b[u], IntTuple.snd(a));
+function areIntersectingNE(a: Tuple, b: AtomSetElements) {
+    const u = Tuple.fst(a);
+    return OrderedSet.has(b.keys, u) && OrderedSet.has(b[u], Tuple.snd(a));
 }
 
 function areIntersectingEE(a: AtomSetElements, b: AtomSetElements) {
@@ -355,9 +355,9 @@ function areIntersectingEE(a: AtomSetElements, b: AtomSetElements) {
     return false;
 }
 
-function intersectNE(a: IntTuple, b: AtomSetElements) {
-    const u = IntTuple.fst(a);
-    return OrderedSet.has(b.keys, u) && OrderedSet.has(b[u], IntTuple.snd(a)) ? a : Empty;
+function intersectNE(a: Tuple, b: AtomSetElements) {
+    const u = Tuple.fst(a);
+    return OrderedSet.has(b.keys, u) && OrderedSet.has(b[u], Tuple.snd(a)) ? a : Empty;
 }
 
 function intersectEE(a: AtomSetElements, b: AtomSetElements) {
@@ -382,14 +382,14 @@ function intersectEE(a: AtomSetElements, b: AtomSetElements) {
     return ofObjectOrdered(OrderedSet.ofSortedArray(keys), ret);
 }
 
-function subtractNE(a: IntTuple, b: AtomSetElements) {
-    const u = IntTuple.fst(a);
-    return OrderedSet.has(b.keys, u) && OrderedSet.has(b[u], IntTuple.snd(a)) ? Empty : a;
+function subtractNE(a: Tuple, b: AtomSetElements) {
+    const u = Tuple.fst(a);
+    return OrderedSet.has(b.keys, u) && OrderedSet.has(b[u], Tuple.snd(a)) ? Empty : a;
 }
 
-function subtractEN(a: AtomSetElements, b: IntTuple): AtomSetImpl {
+function subtractEN(a: AtomSetElements, b: Tuple): AtomSetImpl {
     const aKeys =  a.keys;
-    const u = IntTuple.fst(b), v = IntTuple.snd(b);
+    const u = Tuple.fst(b), v = Tuple.snd(b);
     if (!OrderedSet.has(aKeys, u) || !OrderedSet.has(a[u], v)) return a;
     const set = a[u];
     if (OrderedSet.size(set) === 1) {
@@ -470,7 +470,7 @@ function unionN(sets: ArrayLike<AtomSetImpl>, eCount: { count: number }) {
     }
     eCount.count = countE;
     if (!countN) return Empty;
-    if (countN === sets.length) return ofTuples(sets as ArrayLike<IntTuple>);
+    if (countN === sets.length) return ofTuples(sets as ArrayLike<Tuple>);
     const packed = new Float64Array(countN);
     let offset = 0;
     for (let i = 0, _i = sets.length; i < _i; i++) {
@@ -490,12 +490,12 @@ function unionInto(data: { [key: number]: OrderedSet }, a: AtomSetElements) {
     }
 }
 
-function unionIntoN(data: { [key: number]: OrderedSet }, a: IntTuple) {
-    const u = IntTuple.fst(a);
+function unionIntoN(data: { [key: number]: OrderedSet }, a: Tuple) {
+    const u = Tuple.fst(a);
     const set = data[u];
     if (set) {
-        data[u] = OrderedSet.union(set, OrderedSet.ofSingleton(IntTuple.snd(a)));
+        data[u] = OrderedSet.union(set, OrderedSet.ofSingleton(Tuple.snd(a)));
     } else {
-        data[u] = OrderedSet.ofSingleton(IntTuple.snd(a));
+        data[u] = OrderedSet.ofSingleton(Tuple.snd(a));
     }
 }
\ No newline at end of file
diff --git a/src/mol-data/atom-set/builder.ts b/src/mol-data/atom-set/builder.ts
index 2dea6847090240df273bb75f3e89483b324bda6a..d28cbe641e0c250e3f6ea94437aa7a3becbb8d2b 100644
--- a/src/mol-data/atom-set/builder.ts
+++ b/src/mol-data/atom-set/builder.ts
@@ -5,7 +5,7 @@
  */
 
 import AtomSet from '../atom-set'
-import OrderedSet from '../../mol-base/collections/ordered-set'
+import OrderedSet from '../../mol-base/collections/integer/ordered-set'
 import { sortArray } from '../../mol-base/collections/sort'
 
 class Builder {
diff --git a/src/mol-data/model.ts b/src/mol-data/model.ts
index 9f4f207b50de6af75450de68cdcd555ea98e5be3..14d427b4323380a4f21dc3c69a5441bae435fd3c 100644
--- a/src/mol-data/model.ts
+++ b/src/mol-data/model.ts
@@ -7,7 +7,7 @@
 import * as Formats from './model/formats'
 import CommonInterface from './model/interfaces/common'
 import MacromoleculeInterface from './model/interfaces/common'
-import OrderedSet from '../mol-base/collections/ordered-set'
+import Segmentation from '../mol-base/collections/integer/segmentation'
 
 interface Model {
     data: Formats.RawData,
@@ -15,14 +15,8 @@ interface Model {
     common: CommonInterface,
     macromolecule: MacromoleculeInterface
 
-    // Atom offsets of the "i-th chain" stored as a closed-open range [chainSegments[i], chainSegments[i + 1])
-    chainSegments: OrderedSet,
-    // Atom offsets of the "i-th residue" stored as a closed-open range [residueSegments[i], residueSegments[i + 1])
-    residueSegments: OrderedSet,
-    // Mapping from a residue index to chain index
-    residueChainIndex: ArrayLike<number>,
-    // Mapping from an atom into to residue index
-    atomResidueIndex: ArrayLike<number>
+    chains: Segmentation,
+    residues: Segmentation
 }
 
 export default Model
\ No newline at end of file
diff --git a/src/perf-tests/sets.ts b/src/perf-tests/sets.ts
index 61ef46bee5d287028d1706f0db4bf68ebe388832..e5fc1e389b89ef1693c981fed756bccfeba12a80 100644
--- a/src/perf-tests/sets.ts
+++ b/src/perf-tests/sets.ts
@@ -1,9 +1,9 @@
 import * as B from 'benchmark'
-import IntTuple from '../mol-base/collections/int-tuple'
-import OrdSet from '../mol-base/collections/ordered-set'
+import Tuple from '../mol-base/collections/integer/tuple'
+import OrdSet from '../mol-base/collections/integer/ordered-set'
 import AtomSet from '../mol-data/atom-set'
-import Segmentation from '../mol-base/collections/segmentation'
-import SortedArray from '../mol-base/collections/sorted-array'
+import Segmentation from '../mol-base/collections/integer/segmentation'
+import SortedArray from '../mol-base/collections/integer/sorted-array'
 
 export namespace Iteration {
     const U = 1000, V = 2500;
@@ -29,13 +29,13 @@ export namespace Iteration {
     export function iterators() {
         let s = 0;
         const it = AtomSet.atoms(ms);
-        for (let v = it.move(); !it.done; v = it.move()) s += IntTuple.snd(v);
+        for (let v = it.move(); !it.done; v = it.move()) s += Tuple.snd(v);
         return s;
     }
 
     export function elementAt() {
         let s = 0;
-        for (let i = 0, _i = AtomSet.atomCount(ms); i < _i; i++) s += IntTuple.snd(AtomSet.getAtomAt(ms, i));
+        for (let i = 0, _i = AtomSet.atomCount(ms); i < _i; i++) s += Tuple.snd(AtomSet.getAtomAt(ms, i));
         return s;
     }
 
@@ -234,26 +234,26 @@ export namespace Build {
 
 export namespace Tuples {
     function createData(n: number) {
-        const ret: IntTuple[] = new Float64Array(n) as any;
+        const ret: Tuple[] = new Float64Array(n) as any;
         for (let i = 0; i < n; i++) {
-            ret[i] = IntTuple.create(i, i * i + 1);
+            ret[i] = Tuple.create(i, i * i + 1);
         }
         return ret;
     }
 
-    function sum1(data: ArrayLike<IntTuple>) {
+    function sum1(data: ArrayLike<Tuple>) {
         let s = 0;
         for (let i = 0, _i = data.length; i < _i; i++) {
-            s += IntTuple.fst(data[i]) + IntTuple.snd(data[i]);
+            s += Tuple.fst(data[i]) + Tuple.snd(data[i]);
         }
         return s;
     }
 
-    function sum2(data: ArrayLike<IntTuple>) {
+    function sum2(data: ArrayLike<Tuple>) {
         let s = 0;
         for (let i = 0, _i = data.length; i < _i; i++) {
             const t = data[i];
-            s += IntTuple.fst(t) + IntTuple.snd(t);
+            s += Tuple.fst(t) + Tuple.snd(t);
         }
         return s;
     }