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

Refactoring AtomSet (part 2)

parent ecbe3d2e
Branches
No related tags found
No related merge requests found
...@@ -6,12 +6,14 @@ ...@@ -6,12 +6,14 @@
import { iterableToArray } from '../util' import { iterableToArray } from '../util'
// TODO: rename to "linear map" and just do key value mapping from index?
/** Immutable by convention IntMap */ /** Immutable by convention IntMap */
interface IntMap<T> { interface IntMap<T> {
has(key: number): boolean, has(key: number): boolean,
keys(): IterableIterator<number>, keys(): IterableIterator<number>,
values(): IterableIterator<T>, values(): IterableIterator<T>,
get(key: number): T | undefined, get(key: number): T,
readonly size: number readonly size: number
} }
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
class EquivalenceClassesImpl<K, V> { class EquivalenceClassesImpl<K, V> {
private id = 0; private id = 0;
private byHash: { [hash: number]: { id: number, keys: K[], value: V }[] } = Object.create(null); private byHash = new Map<number, { id: number, keys: K[], value: V }[]>();
readonly groups: K[][] = []; readonly groups: K[][] = [];
...@@ -19,8 +19,8 @@ class EquivalenceClassesImpl<K, V> { ...@@ -19,8 +19,8 @@ class EquivalenceClassesImpl<K, V> {
add(key: K, a: V) { add(key: K, a: V) {
const hash = this.getHash(a); const hash = this.getHash(a);
if (!!this.byHash[hash]) { if (this.byHash.has(hash)) {
const groups = this.byHash[hash]; const groups = this.byHash.get(hash)!;
for (let i = 0, _i = groups.length; i < _i; i++) { for (let i = 0, _i = groups.length; i < _i; i++) {
const group = groups[i]; const group = groups[i];
if (this.areEqual(a, group.value)) { if (this.areEqual(a, group.value)) {
...@@ -33,7 +33,7 @@ class EquivalenceClassesImpl<K, V> { ...@@ -33,7 +33,7 @@ class EquivalenceClassesImpl<K, V> {
return group.id; return group.id;
} else { } else {
const group = this.createGroup(key, a); const group = this.createGroup(key, a);
this.byHash[hash] = [group]; this.byHash.set(hash, [group]);
return group.id; return group.id;
} }
} }
......
...@@ -12,12 +12,12 @@ interface SetLike<T> { ...@@ -12,12 +12,12 @@ interface SetLike<T> {
class HashSetImpl<T> implements SetLike<T> { class HashSetImpl<T> implements SetLike<T> {
size: number = 0; size: number = 0;
private byHash: { [hash: number]: T[] } = Object.create(null); private byHash = new Map<number, T[]>();
add(a: T) { add(a: T) {
const hash = this.getHash(a); const hash = this.getHash(a);
if (!!this.byHash[hash]) { if (this.byHash.has(hash)) {
const xs = this.byHash[hash]; const xs = this.byHash.get(hash)!;
for (let i = 0, _i = xs.length; i < _i; i++) { for (let i = 0, _i = xs.length; i < _i; i++) {
if (this.areEqual(a, xs[i])) return false; if (this.areEqual(a, xs[i])) return false;
} }
...@@ -25,7 +25,7 @@ class HashSetImpl<T> implements SetLike<T> { ...@@ -25,7 +25,7 @@ class HashSetImpl<T> implements SetLike<T> {
this.size++; this.size++;
return true; return true;
} else { } else {
this.byHash[hash] = [a]; this.byHash.set(hash, [a]);
this.size++; this.size++;
return true; return true;
} }
...@@ -33,8 +33,8 @@ class HashSetImpl<T> implements SetLike<T> { ...@@ -33,8 +33,8 @@ class HashSetImpl<T> implements SetLike<T> {
has(v: T) { has(v: T) {
const hash = this.getHash(v); const hash = this.getHash(v);
if (!this.byHash[hash]) return false; if (!this.byHash.has(hash)) return false;
const xs = this.byHash[hash]; const xs = this.byHash.get(hash)!;
for (let i = 0, _i = xs.length; i < _i; i++) { for (let i = 0, _i = xs.length; i < _i; i++) {
if (this.areEqual(v, xs[i])) return true; if (this.areEqual(v, xs[i])) return true;
} }
......
...@@ -35,10 +35,10 @@ describe('atom set', () => { ...@@ -35,10 +35,10 @@ describe('atom set', () => {
}); });
it('multi', () => { it('multi', () => {
const set = AtomSet.create({ const gen = AtomSet.Generator();
1: OrderedSet.ofSortedArray([4, 6, 7]), gen.add(1, OrderedSet.ofSortedArray([4, 6, 7]));
3: OrderedSet.ofRange(0, 1), gen.add(3, OrderedSet.ofRange(0, 1));
}); const set = gen.getSet();
const ret = [p(1, 4), p(1, 6), p(1, 7), p(3, 0), p(3, 1)]; const ret = [p(1, 4), p(1, 6), p(1, 7), p(3, 0), p(3, 1)];
expect(AtomSet.atomCount(set)).toBe(ret.length); expect(AtomSet.atomCount(set)).toBe(ret.length);
expect(setToPairs(set)).toEqual([p(1, 4), p(1, 6), p(1, 7), p(3, 0), p(3, 1)]); expect(setToPairs(set)).toEqual([p(1, 4), p(1, 6), p(1, 7), p(3, 0), p(3, 1)]);
...@@ -52,16 +52,16 @@ describe('atom set', () => { ...@@ -52,16 +52,16 @@ describe('atom set', () => {
it('element at / index of', () => { it('element at / index of', () => {
const control: Atom[] = []; const control: Atom[] = [];
const sets = Object.create(null); const gen = AtomSet.Generator();
for (let i = 1; i < 10; i++) { for (let i = 1; i < 10; i++) {
const set = []; const set = [];
for (let j = 1; j < 7; j++) { for (let j = 1; j < 7; j++) {
control[control.length] = p(i * i, j * j + 1); control[control.length] = p(i * i, j * j + 1);
set[set.length] = j * j + 1; set[set.length] = j * j + 1;
} }
sets[i * i] = OrderedSet.ofSortedArray(set); gen.add(i * i, OrderedSet.ofSortedArray(set));
} }
const ms = AtomSet.create(sets); const ms = gen.getSet();
for (let i = 0; i < control.length; i++) { for (let i = 0; i < control.length; i++) {
expect(Atom.areEqual(AtomSet.atomGetAt(ms, i), control[i])).toBe(true); expect(Atom.areEqual(AtomSet.atomGetAt(ms, i), control[i])).toBe(true);
} }
......
...@@ -105,14 +105,14 @@ function atomGroupsSegmented({ entityTest, chainTest, residueTest, atomTest }: A ...@@ -105,14 +105,14 @@ function atomGroupsSegmented({ entityTest, chainTest, residueTest, atomTest }: A
class LinearGroupingBuilder { class LinearGroupingBuilder {
private builders: AtomSet.Builder[] = []; private builders: AtomSet.Builder[] = [];
private builderMap: { [key: string]: AtomSet.Builder } = Object.create(null); private builderMap = new Map<string, AtomSet.Builder>();
add(key: any, unit: number, atom: number) { add(key: any, unit: number, atom: number) {
let b = this.builderMap[key]; let b = this.builderMap.get(key);
if (!b) { if (!b) {
b = AtomSet.LinearBuilder(this.structure.atoms); b = AtomSet.LinearBuilder(this.structure.atoms);
this.builders[this.builders.length] = b; this.builders[this.builders.length] = b;
this.builderMap[key] = b; this.builderMap.set(key, b);
} }
b.add(unit, atom); b.add(unit, atom);
} }
......
...@@ -7,13 +7,13 @@ ...@@ -7,13 +7,13 @@
import { OrderedSet, SortedArray, Iterator } from 'mol-data/int' import { OrderedSet, SortedArray, Iterator } from 'mol-data/int'
import Atom from '../atom' import Atom from '../atom'
import * as Impl from './set/impl' import * as Impl from './set/impl'
import createBuilder, { Builder as AtomSetBuilder } from './set/builder' import * as Builders from './set/builder'
/** A map-like representation of grouped atom set */ /** A map-like representation of grouped atom set */
namespace AtomSet { namespace AtomSet {
export const Empty: AtomSet = Impl.Empty as any; export const Empty: AtomSet = Impl.Empty as any;
export const create: (data: Atom | ArrayLike<Atom> | { [unitId: number]: OrderedSet }) => AtomSet = Impl.create as any; export const create: (data: Atom | ArrayLike<Atom>) => AtomSet = Impl.create as any;
export const unitCount: (set: AtomSet) => number = Impl.keyCount as any; export const unitCount: (set: AtomSet) => number = Impl.keyCount as any;
export const unitIds: (set: AtomSet) => SortedArray = Impl.getKeys as any; export const unitIds: (set: AtomSet) => SortedArray = Impl.getKeys as any;
...@@ -38,9 +38,12 @@ namespace AtomSet { ...@@ -38,9 +38,12 @@ namespace AtomSet {
export const intersect: (a: AtomSet, b: AtomSet) => AtomSet = Impl.intersect as any; export const intersect: (a: AtomSet, b: AtomSet) => AtomSet = Impl.intersect as any;
export const subtract: (a: AtomSet, b: AtomSet) => AtomSet = Impl.subtract as any; export const subtract: (a: AtomSet, b: AtomSet) => AtomSet = Impl.subtract as any;
export type Builder = AtomSetBuilder export type Builder = Builders.Builder
export function LinearBuilder(parent: AtomSet): Builder { return createBuilder(parent, true); } export const LinearBuilder = Builders.LinearBuilder
export function UnsortedBuilder(parent: AtomSet): Builder { return createBuilder(parent, false); } export const UnsortedBuilder = Builders.UnsortedBuilder
export interface Generator { add(unit: number, set: OrderedSet): void, getSet(): AtomSet }
export const Generator: () => Generator = Impl.Generator as any
// TODO: bounding sphere // TODO: bounding sphere
// TODO: distance, areWithIn? // TODO: distance, areWithIn?
......
...@@ -6,21 +6,21 @@ ...@@ -6,21 +6,21 @@
import AtomSet from '../set' import AtomSet from '../set'
import Atom from '../../atom' import Atom from '../../atom'
import { OrderedSet } from 'mol-data/int' import { OrderedSet, IntMap } from 'mol-data/int'
import { sortArray } from 'mol-data/util/sort' import { sortArray } from 'mol-data/util/sort'
export class Builder { export class Builder {
private keys: number[] = []; private keys: number[] = [];
private units: number[][] = Object.create(null); private units = IntMap.Mutable<number[]>();
private currentUnit: number[] = []; private currentUnit: number[] = [];
atomCount = 0; atomCount = 0;
add(u: number, a: number) { add(u: number, a: number) {
const unit = this.units[u]; const unit = this.units.get(u);
if (!!unit) { unit[unit.length] = a; } if (!!unit) { unit[unit.length] = a; }
else { else {
this.units[u] = [a]; this.units.set(u, [a]);
this.keys[this.keys.length] = u; this.keys[this.keys.length] = u;
} }
this.atomCount++; this.atomCount++;
...@@ -31,40 +31,44 @@ export class Builder { ...@@ -31,40 +31,44 @@ export class Builder {
commitUnit(u: number) { commitUnit(u: number) {
if (this.currentUnit.length === 0) return; if (this.currentUnit.length === 0) return;
this.keys[this.keys.length] = u; this.keys[this.keys.length] = u;
this.units[u] = this.currentUnit; this.units.set(u, this.currentUnit);
} }
getSet(): AtomSet { getSet(): AtomSet {
const sets: { [key: number]: OrderedSet } = Object.create(null); const generator = AtomSet.Generator();
let allEqual = this.keys.length === AtomSet.unitCount(this.parent); let allEqual = this.keys.length === AtomSet.unitCount(this.parent);
for (let i = 0, _i = this.keys.length; i < _i; i++) { for (let i = 0, _i = this.keys.length; i < _i; i++) {
const k = this.keys[i]; const k = this.keys[i];
const unit = this.units[k]; const unit = this.units.get(k);
const l = unit.length; const l = unit.length;
if (!this.sorted && l > 1) sortArray(unit); if (!this.sorted && l > 1) sortArray(unit);
const set = l === 1 ? OrderedSet.ofSingleton(unit[0]) : OrderedSet.ofSortedArray(unit); const set = l === 1 ? OrderedSet.ofSingleton(unit[0]) : OrderedSet.ofSortedArray(unit);
const parentSet = AtomSet.unitGetById(this.parent, k); const parentSet = AtomSet.unitGetById(this.parent, k);
if (OrderedSet.areEqual(set, parentSet)) { if (OrderedSet.areEqual(set, parentSet)) {
sets[k] = parentSet; generator.add(k, parentSet);
} else { } else {
sets[k] = set; generator.add(k, set);
allEqual = false; allEqual = false;
} }
} }
return allEqual ? this.parent : AtomSet.create(sets); return allEqual ? this.parent : generator.getSet();
} }
singleton(): Atom { singleton(): Atom {
const u = this.keys[0]; const u = this.keys[0];
return Atom.create(u, this.units[u][0]); return Atom.create(u, this.units.get(u)[0]);
} }
constructor(private parent: AtomSet, private sorted: boolean) { } constructor(private parent: AtomSet, private sorted: boolean) { }
} }
export default function createBuilder(parent: AtomSet, sorted: boolean) { export function LinearBuilder(parent: AtomSet) {
return new Builder(parent, sorted); return new Builder(parent, true);
}
export function UnsortedBuilder(parent: AtomSet) {
return new Builder(parent, false);
} }
\ No newline at end of file
...@@ -11,15 +11,14 @@ import Atom from '../../atom' ...@@ -11,15 +11,14 @@ import Atom from '../../atom'
/** Long and painful implementation starts here */ /** Long and painful implementation starts here */
export interface AtomSetElements { sets: IntMap<OrderedSet>, offsets: number[], hashCode: number, keys: SortedArray } export interface AtomSetElements { sets: IntMap<OrderedSet>, offsets: Int32Array, hashCode: number, keys: SortedArray }
export type AtomSetImpl = Atom | AtomSetElements export type AtomSetImpl = Atom | AtomSetElements
export const Empty: AtomSetImpl = { sets: IntMap.Empty, offsets: [0], hashCode: 0, keys: SortedArray.Empty }; export const Empty: AtomSetImpl = { sets: IntMap.Empty, offsets: new Int32Array(1), hashCode: 0, keys: SortedArray.Empty };
export function create(data: Atom | ArrayLike<Atom> | { [id: number]: OrderedSet }): AtomSetImpl { export function create(data: Atom | ArrayLike<Atom>): AtomSetImpl {
if (typeof data === 'number' || Atom.is(data)) return data; if (typeof data === 'number' || Atom.is(data)) return data;
if (isArrayLike(data)) return ofAtoms(data); return ofAtoms(data);
return ofObject(data as { [id: number]: OrderedSet });
} }
export function isSingleton(set: AtomSetImpl) { export function isSingleton(set: AtomSetImpl) {
...@@ -154,7 +153,7 @@ class ElementsIterator implements Iterator<Atom> { ...@@ -154,7 +153,7 @@ class ElementsIterator implements Iterator<Atom> {
return false; return false;
} }
this.unit = this.elements.keys[this.setIndex]; this.unit = this.elements.keys[this.setIndex];
this.currentSet = this.elements.sets.get(this.unit)!; this.currentSet = this.elements.sets.get(this.unit);
this.currentIndex = 0; this.currentIndex = 0;
this.currentSize = OrderedSet.size(this.currentSet); this.currentSize = OrderedSet.size(this.currentSet);
return true; return true;
...@@ -172,60 +171,57 @@ export function values(set: AtomSetImpl): Iterator<Atom> { ...@@ -172,60 +171,57 @@ export function values(set: AtomSetImpl): Iterator<Atom> {
return new ElementsIterator(set as AtomSetElements); return new ElementsIterator(set as AtomSetElements);
} }
function isArrayLike(x: any): x is ArrayLike<Atom> { export class AtomSetGenerator {
return x && (typeof x.length === 'number' && (Array.isArray(x) || !!x.buffer)); private keys: number[] = [];
private sets = IntMap.Mutable<OrderedSet>();
add(unit: number, set: OrderedSet) {
if (OrderedSet.size(set) === 0) return;
this.keys[this.keys.length] = unit;
this.sets.set(unit, set);
} }
function ofObject(data: { [id: number]: OrderedSet }) { addUnion(unit: number, set: OrderedSet) {
const keys = []; if (OrderedSet.size(set) === 0) return;
const _keys = Object.keys(data); if (this.sets.has(unit)) {
for (let i = 0, _i = _keys.length; i < _i; i++) { this.sets.set(unit, OrderedSet.union(this.sets.get(unit), set));
const k = +_keys[i]; } else {
if (OrderedSet.size(data[k]) > 0) keys[keys.length] = k; this.keys[this.keys.length] = unit;
} this.sets.set(unit, set);
if (!keys.length) return Empty;
if (keys.length === 1) {
const set = data[keys[0]];
if (OrderedSet.size(set) === 1) return Atom.create(keys[0], OrderedSet.getAt(set, 0));
} }
return ofObject1(keys, data);
} }
function ofObject1(keys: number[], data: { [id: number]: OrderedSet }) { getSet(): AtomSetImpl {
if (keys.length === 1) { return ofKeysAndSets(this.keys, this.sets);
const k = keys[0];
const set = data[k];
if (OrderedSet.size(set) === 1) return Atom.create(k, OrderedSet.getAt(set, 0));
} }
sortArray(keys);
return _createObjectOrdered(SortedArray.ofSortedArray(keys), data);
} }
function ofObjectOrdered(keys: SortedArray, data: { [id: number]: OrderedSet }) { export function Generator() {
if (keys.length === 1) { return new AtomSetGenerator();
const k = keys[0];
const set = data[k];
if (OrderedSet.size(set) === 1) return Atom.create(k, OrderedSet.getAt(set, 0));
}
return _createObjectOrdered(keys, data);
} }
function _createObjectOrdered(keys: SortedArray, data: { [id: number]: OrderedSet }): AtomSetElements { function ofKeysAndSetsElemements(keys: number[], sets: IntMap<OrderedSet>): AtomSetElements {
const sets = IntMap.Mutable<OrderedSet>(); sortArray(keys);
const offsets = [0];
let runningSize = 0; let runningSize = 0;
const offsets = new Int32Array(keys.length + 1);
for (let i = 0, _i = keys.length; i < _i; i++) { for (let i = 0, _i = keys.length; i < _i; i++) {
const k = keys[i]; runningSize += OrderedSet.size(sets.get(keys[i]));
const set = data[k]; offsets[i + 1] = runningSize;
sets.set(k, set); }
runningSize += OrderedSet.size(set); return { keys: SortedArray.ofSortedArray(keys), sets: IntMap.asImmutable(sets), offsets, hashCode: -1 };
offsets[offsets.length] = runningSize; }
function ofKeysAndSets(keys: number[], sets: IntMap<OrderedSet>) {
if (keys.length === 1) {
const set = sets.get(keys[0]);
if (OrderedSet.size(set) === 1) return Atom.create(keys[0], OrderedSet.getAt(set, 0));
} }
return { sets, keys, offsets, hashCode: - 1 }; return ofKeysAndSetsElemements(keys, sets);
} }
function getUniqueElements(xs: number[]) { function getUniqueElements(xs: number[]): number[] {
let count = 1; let count = 1;
for (let i = 1, _i = xs.length; i < _i; i++) { for (let i = 1, _i = xs.length; i < _i; i++) {
if (xs[i - 1] !== xs[i]) count++; if (xs[i - 1] !== xs[i]) count++;
...@@ -239,7 +235,7 @@ function getUniqueElements(xs: number[]) { ...@@ -239,7 +235,7 @@ function getUniqueElements(xs: number[]) {
return ret; return ret;
} }
function normalizeArray(xs: number[]) { function normalizeArray(xs: number[]): number[] {
sortArray(xs); sortArray(xs);
for (let i = 1, _i = xs.length; i < _i; i++) { for (let i = 1, _i = xs.length; i < _i; i++) {
if (xs[i - 1] === xs[i]) return getUniqueElements(xs); if (xs[i - 1] === xs[i]) return getUniqueElements(xs);
...@@ -249,23 +245,28 @@ function normalizeArray(xs: number[]) { ...@@ -249,23 +245,28 @@ function normalizeArray(xs: number[]) {
function ofAtoms(xs: ArrayLike<Atom>) { function ofAtoms(xs: ArrayLike<Atom>) {
if (xs.length === 0) return Empty; if (xs.length === 0) return Empty;
const sets: { [key: number]: number[] } = Object.create(null);
const elements = IntMap.Mutable<number[]>();
const keys: number[] = [];
for (let i = 0, _i = xs.length; i < _i; i++) { for (let i = 0, _i = xs.length; i < _i; i++) {
const x = xs[i]; const x = xs[i];
const u = Atom.unit(x), v = Atom.index(x); const u = Atom.unit(x), v = Atom.index(x);
const set = sets[u]; if (elements.has(u)) {
if (set) set[set.length] = v; const set = elements.get(u);
else sets[u] = [v]; set[set.length] = v;
} else {
keys[keys.length] = u;
elements.set(u, [v]);
} }
const ret: { [key: number]: OrderedSet } = Object.create(null);
const keys = [];
const _keys = Object.keys(sets);
for (let i = 0, _i = _keys.length; i < _i; i++) {
const k = +_keys[i];
keys[keys.length] = k;
ret[k] = OrderedSet.ofSortedArray(normalizeArray(sets[k]));
} }
return ofObject1(keys, ret);
const sets = IntMap.Mutable<OrderedSet>();
for (let i = 0, _i = keys.length; i < _i; i++) {
const k = keys[i];
sets.set(k, OrderedSet.ofSortedArray(normalizeArray(elements.get(k))));
}
return ofKeysAndSets(keys, sets);
} }
function getOffsetIndex(xs: ArrayLike<number>, value: number) { function getOffsetIndex(xs: ArrayLike<number>, value: number) {
...@@ -288,7 +289,7 @@ function getAtE(set: AtomSetElements, i: number): Atom { ...@@ -288,7 +289,7 @@ function getAtE(set: AtomSetElements, i: number): Atom {
const o = getOffsetIndex(offsets, i); const o = getOffsetIndex(offsets, i);
if (o >= offsets.length - 1) return 0 as any; if (o >= offsets.length - 1) return 0 as any;
const k = keys[o]; const k = keys[o];
const e = OrderedSet.getAt(set.sets.get(k)!, i - offsets[o]); const e = OrderedSet.getAt(set.sets.get(k), i - offsets[o]);
return Atom.create(k, e); return Atom.create(k, e);
} }
...@@ -297,7 +298,7 @@ function indexOfE(set: AtomSetElements, t: Atom) { ...@@ -297,7 +298,7 @@ function indexOfE(set: AtomSetElements, t: Atom) {
const u = Atom.unit(t); const u = Atom.unit(t);
const setIdx = SortedArray.indexOf(keys, u); const setIdx = SortedArray.indexOf(keys, u);
if (setIdx < 0) return -1; if (setIdx < 0) return -1;
const o = OrderedSet.indexOf(set.sets.get(u)!, Atom.index(t)); const o = OrderedSet.indexOf(set.sets.get(u), Atom.index(t));
if (o < 0) return -1; if (o < 0) return -1;
return set.offsets[setIdx] + o; return set.offsets[setIdx] + o;
} }
...@@ -308,7 +309,7 @@ function computeHash(set: AtomSetElements) { ...@@ -308,7 +309,7 @@ function computeHash(set: AtomSetElements) {
for (let i = 0, _i = keys.length; i < _i; i++) { for (let i = 0, _i = keys.length; i < _i; i++) {
const k = keys[i]; const k = keys[i];
hash = (31 * hash + k) | 0; hash = (31 * hash + k) | 0;
hash = (31 * hash + OrderedSet.hashCode(sets.get(k)!)) | 0; hash = (31 * hash + OrderedSet.hashCode(sets.get(k))) | 0;
} }
hash = (31 * hash + size(set)) | 0; hash = (31 * hash + size(set)) | 0;
hash = hash1(hash); hash = hash1(hash);
...@@ -326,14 +327,14 @@ function areEqualEE(a: AtomSetElements, b: AtomSetElements) { ...@@ -326,14 +327,14 @@ function areEqualEE(a: AtomSetElements, b: AtomSetElements) {
const { sets: bSets } = b; const { sets: bSets } = b;
for (let i = 0, _i = keys.length; i < _i; i++) { for (let i = 0, _i = keys.length; i < _i; i++) {
const k = keys[i]; const k = keys[i];
if (!OrderedSet.areEqual(aSets.get(k)!, bSets.get(k)!)) return false; if (!OrderedSet.areEqual(aSets.get(k), bSets.get(k))) return false;
} }
return true; return true;
} }
function areIntersectingNE(a: Atom, b: AtomSetElements) { function areIntersectingNE(a: Atom, b: AtomSetElements) {
const u = Atom.unit(a); const u = Atom.unit(a);
return b.sets.has(u) && OrderedSet.has(b.sets.get(u)!, Atom.index(a)); return b.sets.has(u) && OrderedSet.has(b.sets.get(u), Atom.index(a));
} }
function areIntersectingEE(a: AtomSetElements, b: AtomSetElements) { function areIntersectingEE(a: AtomSetElements, b: AtomSetElements) {
...@@ -354,7 +355,7 @@ function areIntersectingEE(a: AtomSetElements, b: AtomSetElements) { ...@@ -354,7 +355,7 @@ function areIntersectingEE(a: AtomSetElements, b: AtomSetElements) {
function intersectNE(a: Atom, b: AtomSetElements) { function intersectNE(a: Atom, b: AtomSetElements) {
const u = Atom.unit(a); const u = Atom.unit(a);
return b.sets.has(u) && OrderedSet.has(b.sets.get(u)!, Atom.index(a)) ? a : Empty; return b.sets.has(u) && OrderedSet.has(b.sets.get(u), Atom.index(a)) ? a : Empty;
} }
function intersectEE(a: AtomSetElements, b: AtomSetElements) { function intersectEE(a: AtomSetElements, b: AtomSetElements) {
...@@ -365,20 +366,16 @@ function intersectEE(a: AtomSetElements, b: AtomSetElements) { ...@@ -365,20 +366,16 @@ function intersectEE(a: AtomSetElements, b: AtomSetElements) {
const r = SortedArray.findRange(keysA, SortedArray.min(keysB), SortedArray.max(keysB)); const r = SortedArray.findRange(keysA, SortedArray.min(keysB), SortedArray.max(keysB));
const start = Interval.start(r), end = Interval.end(r); const start = Interval.start(r), end = Interval.end(r);
const keys = [], ret = Object.create(null);
const { sets: aSets } = a; const { sets: aSets } = a;
const { sets: bSets } = b; const { sets: bSets } = b;
const generator = Generator();
for (let i = start; i < end; i++) { for (let i = start; i < end; i++) {
const k = keysA[i]; const k = keysA[i];
const bk = bSets.get(k); const bk = bSets.get(k);
if (!bk) continue; if (!bk) continue;
const intersection = OrderedSet.intersect(aSets.get(k)!, bk); generator.add(k, OrderedSet.intersect(aSets.get(k), bk));
if (OrderedSet.size(intersection) > 0) {
keys[keys.length] = k;
ret[k] = intersection;
}
} }
return ofObjectOrdered(SortedArray.ofSortedArray(keys), ret); return generator.getSet();
} }
function subtractNE(a: Atom, b: AtomSetElements) { function subtractNE(a: Atom, b: AtomSetElements) {
...@@ -390,20 +387,24 @@ function subtractEN(a: AtomSetElements, b: Atom): AtomSetImpl { ...@@ -390,20 +387,24 @@ function subtractEN(a: AtomSetElements, b: Atom): AtomSetImpl {
const u = Atom.unit(b), v = Atom.index(b); const u = Atom.unit(b), v = Atom.index(b);
const { sets: aSets } = a; const { sets: aSets } = a;
const set = aSets.get(u)!; const set = aSets.get(u);
if (OrderedSet.size(set) === 1) { if (OrderedSet.size(set) === 1) {
// remove the entire unit. // remove the entire unit.
throw 'nyi' const generator = Generator();
//return ofObjectOrdered(SortedArray.subtract(a.keys, SortedArray.ofSingleton(u)), a); for (let i = 0, _i = a.keys.length; i < _i; i++) {
const k = a.keys[i];
if (k !== u) generator.add(k, aSets.get(k))
}
return generator.getSet();
} else { } else {
const ret: { [key: number]: OrderedSet } = Object.create(null); const generator = Generator();
for (let i = 0, _i = a.keys.length; i < _i; i++) { for (let i = 0, _i = a.keys.length; i < _i; i++) {
const k = a.keys[i]; const k = a.keys[i];
if (k === u) { if (k === u) generator.add(k, OrderedSet.subtract(set, OrderedSet.ofSingleton(v)))
ret[k] = OrderedSet.subtract(set, OrderedSet.ofSingleton(v)); else generator.add(k, aSets.get(k))
} else ret[k] = aSets.get(k)!;
} }
return ofObjectOrdered(a.keys, ret); return generator.getSet();
} }
} }
...@@ -415,34 +416,28 @@ function subtractEE(a: AtomSetElements, b: AtomSetElements) { ...@@ -415,34 +416,28 @@ function subtractEE(a: AtomSetElements, b: AtomSetElements) {
const r = SortedArray.findRange(keysA, SortedArray.min(keysB), SortedArray.max(keysB)); const r = SortedArray.findRange(keysA, SortedArray.min(keysB), SortedArray.max(keysB));
const start = Interval.start(r), end = Interval.end(r); const start = Interval.start(r), end = Interval.end(r);
const keys = [], ret = Object.create(null); const generator = Generator();
const { sets: aSets } = a; const { sets: aSets } = a;
const { sets: bSets } = b; const { sets: bSets } = b;
for (let i = 0; i < start; i++) { for (let i = 0; i < start; i++) {
const k = keysA[i]; const k = keysA[i];
keys[keys.length] = k; generator.add(k, aSets.get(k));
ret[k] = aSets.get(k);
} }
for (let i = start; i < end; i++) { for (let i = start; i < end; i++) {
const k = keysA[i]; const k = keysA[i];
const ak = aSets.get(k)!, bk = bSets.get(k); const ak = aSets.get(k), bk = bSets.get(k);
if (!!bk) { if (!!bk) {
const subtraction = OrderedSet.subtract(ak, bk); const subtraction = OrderedSet.subtract(ak, bk);
if (OrderedSet.size(subtraction) > 0) { generator.add(k, subtraction);
keys[keys.length] = k;
ret[k] = subtraction;
}
} else { } else {
keys[keys.length] = k; generator.add(k, ak);
ret[k] = ak;
} }
} }
for (let i = end, _i = keysA.length; i < _i; i++) { for (let i = end, _i = keysA.length; i < _i; i++) {
const k = keysA[i]; const k = keysA[i];
keys[keys.length] = k; generator.add(k, aSets.get(k));
ret[k] = aSets.get(k);
} }
return ofObjectOrdered(SortedArray.ofSortedArray(keys), ret); return generator.getSet();
} }
function findUnion(sets: ArrayLike<AtomSetImpl>) { function findUnion(sets: ArrayLike<AtomSetImpl>) {
...@@ -453,16 +448,16 @@ function findUnion(sets: ArrayLike<AtomSetImpl>) { ...@@ -453,16 +448,16 @@ function findUnion(sets: ArrayLike<AtomSetImpl>) {
const eCount = { count: 0 }; const eCount = { count: 0 };
const ns = unionN(sets, eCount); const ns = unionN(sets, eCount);
if (!eCount.count) return ns; if (!eCount.count) return ns;
const ret = Object.create(null); const generator = Generator();
for (let i = 0, _i = sets.length; i < _i; i++) { for (let i = 0, _i = sets.length; i < _i; i++) {
const s = sets[i]; const s = sets[i];
if (typeof s !== 'number') unionInto(ret, s as AtomSetElements); if (typeof s !== 'number') unionInto(generator, s as AtomSetElements);
} }
if (size(ns as AtomSetImpl) > 0) { if (size(ns as AtomSetImpl) > 0) {
if (typeof ns === 'number') unionIntoN(ret, ns as any); if (typeof ns === 'number') unionIntoN(generator, ns as any);
else unionInto(ret, ns as AtomSetElements); else unionInto(generator, ns as AtomSetElements);
} }
return ofObject(ret); return generator.getSet();
} }
function unionN(sets: ArrayLike<AtomSetImpl>, eCount: { count: number }) { function unionN(sets: ArrayLike<AtomSetImpl>, eCount: { count: number }) {
...@@ -483,23 +478,16 @@ function unionN(sets: ArrayLike<AtomSetImpl>, eCount: { count: number }) { ...@@ -483,23 +478,16 @@ function unionN(sets: ArrayLike<AtomSetImpl>, eCount: { count: number }) {
return ofAtoms(packed as any); return ofAtoms(packed as any);
} }
function unionInto(data: { [key: number]: OrderedSet }, a: AtomSetElements) { function unionInto(builder: AtomSetGenerator, a: AtomSetElements) {
const keys = a.keys; const keys = a.keys;
const { sets: aSets } = a; const { sets: aSets } = a;
for (let i = 0, _i = keys.length; i < _i; i++) { for (let i = 0, _i = keys.length; i < _i; i++) {
const k = keys[i]; const k = keys[i];
const set = data[k]; builder.addUnion(k, aSets.get(k));
if (set) data[k] = OrderedSet.union(set, aSets.get(k)!);
else data[k] = aSets.get(k)!;
} }
} }
function unionIntoN(data: { [key: number]: OrderedSet }, a: Atom) { function unionIntoN(builder: AtomSetGenerator, a: Atom) {
const u = Atom.unit(a); const u = Atom.unit(a);
const set = data[u]; builder.addUnion(u, OrderedSet.ofSingleton(Atom.index(a)));
if (set) {
data[u] = OrderedSet.union(set, OrderedSet.ofSingleton(Atom.index(a)));
} else {
data[u] = OrderedSet.ofSingleton(Atom.index(a));
}
} }
\ No newline at end of file
...@@ -37,7 +37,7 @@ namespace Structure { ...@@ -37,7 +37,7 @@ namespace Structure {
for (let c = 0; c < chains.count; c++) { for (let c = 0; c < chains.count; c++) {
const unit = Unit.create(model, SymmetryOperator.Default); const unit = Unit.create(model, SymmetryOperator.Default);
builder.addUnit(unit); builder.addUnit(unit);
builder.addAtoms(unit.id, OrderedSet.ofBounds(chains.segments[c], chains.segments[c + 1])); builder.setAtoms(unit.id, OrderedSet.ofBounds(chains.segments[c], chains.segments[c + 1]));
} }
return builder.getStructure(); return builder.getStructure();
...@@ -46,20 +46,20 @@ namespace Structure { ...@@ -46,20 +46,20 @@ namespace Structure {
export interface Builder { export interface Builder {
add(unit: Unit, atoms: OrderedSet): void, add(unit: Unit, atoms: OrderedSet): void,
addUnit(unit: Unit): void, addUnit(unit: Unit): void,
addAtoms(unitId: number, atoms: OrderedSet): void, setAtoms(unitId: number, atoms: OrderedSet): void,
getStructure(): Structure, getStructure(): Structure,
readonly atomCount: number readonly atomCount: number
} }
class BuilderImpl implements Builder { class BuilderImpl implements Builder {
private units = Object.create(null); private units = Object.create(null);
private atoms = Object.create(null); private atoms = AtomSet.Generator();
atomCount = 0; atomCount = 0;
add(unit: Unit, atoms: OrderedSet) { this.addUnit(unit); this.addAtoms(unit.id, atoms); } add(unit: Unit, atoms: OrderedSet) { this.addUnit(unit); this.setAtoms(unit.id, atoms); }
addUnit(unit: Unit) { this.units[unit.id] = unit; } addUnit(unit: Unit) { this.units[unit.id] = unit; }
addAtoms(unitId: number, atoms: OrderedSet) { this.atoms[unitId] = atoms; this.atomCount += OrderedSet.size(atoms); } setAtoms(unitId: number, atoms: OrderedSet) { this.atoms.add(unitId, atoms); this.atomCount += OrderedSet.size(atoms); }
getStructure(): Structure { return this.atomCount > 0 ? Structure.create(this.units, AtomSet.create(this.atoms)) : Empty; } getStructure(): Structure { return this.atomCount > 0 ? Structure.create(this.units, this.atoms.getSet()) : Empty; }
} }
export function Builder(): Builder { return new BuilderImpl(); } export function Builder(): Builder { return new BuilderImpl(); }
......
...@@ -77,6 +77,7 @@ export namespace PropertyAccess { ...@@ -77,6 +77,7 @@ export namespace PropertyAccess {
l.unit = units[unitIds[i]]; l.unit = units[unitIds[i]];
const set = AtomSet.unitGetByIndex(atoms, i); const set = AtomSet.unitGetByIndex(atoms, i);
for (let j = 0, _j = OrdSet.size(set); j < _j; j++) { for (let j = 0, _j = OrdSet.size(set); j < _j; j++) {
l.atom = OrdSet.getAt(set, j); l.atom = OrdSet.getAt(set, j);
s += p(l); s += p(l);
...@@ -274,8 +275,8 @@ export namespace PropertyAccess { ...@@ -274,8 +275,8 @@ export namespace PropertyAccess {
// return; // return;
console.log(baseline(models[0])); console.log('bs', baseline(models[0]));
console.log(sumProperty(structures[0], l => l.unit.model.conformation.atomId.value(l.atom))); console.log('sp', sumProperty(structures[0], l => l.unit.model.conformation.atomId.value(l.atom)));
console.log(sumPropertySegmented(structures[0], l => l.unit.model.conformation.atomId.value(l.atom))); console.log(sumPropertySegmented(structures[0], l => l.unit.model.conformation.atomId.value(l.atom)));
//console.log(sumPropertySegmentedMutable(structures[0], l => l.unit.model.conformation.atomId.value(l.atom))); //console.log(sumPropertySegmentedMutable(structures[0], l => l.unit.model.conformation.atomId.value(l.atom)));
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment