From 6afe8085558c8f4a0f9f53931aa09dc1b3a3516a Mon Sep 17 00:00:00 2001
From: David Sehnal <david.sehnal@gmail.com>
Date: Tue, 17 Jul 2018 19:38:06 +0200
Subject: [PATCH] wip mol-model/query

---
 src/mol-model/structure/query.ts              |  4 +-
 src/mol-model/structure/query/context.ts      | 18 ++++-
 .../structure/query/queries/combinators.ts    |  5 ++
 .../structure/query/queries/filters.ts        | 41 ++++++++++
 .../query/{ => queries}/generators.ts         | 34 ++++-----
 .../query/{ => queries}/modifiers.ts          | 24 +++---
 src/perf-tests/tasks.ts                       | 76 +++++++++++++++++--
 7 files changed, 161 insertions(+), 41 deletions(-)
 create mode 100644 src/mol-model/structure/query/queries/combinators.ts
 create mode 100644 src/mol-model/structure/query/queries/filters.ts
 rename src/mol-model/structure/query/{ => queries}/generators.ts (86%)
 rename src/mol-model/structure/query/{ => queries}/modifiers.ts (79%)

diff --git a/src/mol-model/structure/query.ts b/src/mol-model/structure/query.ts
index e4f3190a4..775112fbc 100644
--- a/src/mol-model/structure/query.ts
+++ b/src/mol-model/structure/query.ts
@@ -7,8 +7,8 @@
 import { StructureSelection } from './query/selection'
 import { StructureQuery } from './query/query'
 export * from './query/context'
-import * as generators from './query/generators'
-import * as modifiers from './query/modifiers'
+import * as generators from './query/queries/generators'
+import * as modifiers from './query/queries/modifiers'
 import pred from './query/predicates'
 
 export const Queries = {
diff --git a/src/mol-model/structure/query/context.ts b/src/mol-model/structure/query/context.ts
index eedd8d3e3..5c94becb6 100644
--- a/src/mol-model/structure/query/context.ts
+++ b/src/mol-model/structure/query/context.ts
@@ -9,16 +9,19 @@ import { Structure, StructureElement } from '../structure';
 
 export interface QueryContextView {
     readonly element: StructureElement;
+    readonly currentStructure: Structure;
 }
 
 export class QueryContext implements QueryContextView {
     private currentStack: StructureElement[] = [];
+    private currentLocked = false;
 
-    readonly structure: Structure;
+    readonly inputStructure: Structure;
     readonly taskCtx: RuntimeContext;
 
     /** Current element */
     readonly element: StructureElement = StructureElement.create();
+    readonly currentStructure: Structure = void 0 as any;
 
     pushCurrentElement(): StructureElement {
         this.currentStack[this.currentStack.length] = this.element;
@@ -30,8 +33,19 @@ export class QueryContext implements QueryContextView {
         (this.element as StructureElement) = this.currentStack.pop()!;
     }
 
+    lockCurrentStructure(structure: Structure) {
+        if (this.currentLocked) throw new Error('Current structure already locked.');
+        this.currentLocked = true;
+        (this.currentStructure as Structure) = structure;
+    }
+
+    unlockCurrentStructure() {
+        this.currentLocked = false;
+        (this.currentStructure as any) = void 0;
+    }
+
     constructor(structure: Structure, taskCtx: RuntimeContext) {
-        this.structure = structure;
+        this.inputStructure = structure;
         this.taskCtx = taskCtx;
     }
 }
diff --git a/src/mol-model/structure/query/queries/combinators.ts b/src/mol-model/structure/query/queries/combinators.ts
new file mode 100644
index 000000000..de7200ac1
--- /dev/null
+++ b/src/mol-model/structure/query/queries/combinators.ts
@@ -0,0 +1,5 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
diff --git a/src/mol-model/structure/query/queries/filters.ts b/src/mol-model/structure/query/queries/filters.ts
new file mode 100644
index 000000000..9bd5a50d2
--- /dev/null
+++ b/src/mol-model/structure/query/queries/filters.ts
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+// import { StructureQuery } from '../query'
+// import { StructureSelection } from '../selection'
+// import { Unit, StructureProperties as P, Structure } from '../../structure'
+// import { Segmentation, SortedArray } from 'mol-data/int'
+// import { LinearGroupingBuilder } from '../utils/builders';
+// import { QueryPredicate, QueryFn, QueryContextView } from '../context';
+
+// export function pick(query: StructureQuery, pred: QueryPredicate): StructureQuery {
+//     return async ctx => {
+//         const sel = await query(ctx);
+
+//         if (StructureSelection.isSingleton(sel)) {
+//             const ret = StructureSelection.LinearBuilder(ctx.inputStructure);
+//             for (const unit of ctx.inputStructure.units) {
+//                 const { elements } = unit;
+//                 for (let i = 0, _i = elements.length; i < _i; i++) {
+//                     // TODO: optimize this somehow???
+//                     const s = Structure.create([unit.getChild(SortedArray.ofSingleton(elements[i]))]);
+//                     ctx.lockCurrentStructure(s);
+//                     if (pred(ctx)) ret.add(s);
+//                     ctx.unlockCurrentStructure();
+//                 }
+//             }
+//             return ret.getSelection();
+//         } else {
+//             const ret = StructureSelection.LinearBuilder(ctx.inputStructure);
+//             for (const s of sel.structures) {
+//                 ctx.lockCurrentStructure(s);
+//                 if (pred(ctx)) ret.add(s);
+//                 ctx.unlockCurrentStructure();
+//             }
+//             return ret.getSelection();
+//         }
+//     };
+// }
diff --git a/src/mol-model/structure/query/generators.ts b/src/mol-model/structure/query/queries/generators.ts
similarity index 86%
rename from src/mol-model/structure/query/generators.ts
rename to src/mol-model/structure/query/queries/generators.ts
index 01f16cccb..8454c781f 100644
--- a/src/mol-model/structure/query/generators.ts
+++ b/src/mol-model/structure/query/queries/generators.ts
@@ -4,14 +4,14 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import { StructureQuery } from './query'
-import { StructureSelection } from './selection'
-import { Unit, StructureProperties as P } from '../structure'
+import { StructureQuery } from '../query'
+import { StructureSelection } from '../selection'
+import { Unit, StructureProperties as P } from '../../structure'
 import { Segmentation } from 'mol-data/int'
-import { LinearGroupingBuilder } from './utils/builders';
-import { QueryPredicate, QueryFn, QueryContextView } from './context';
+import { LinearGroupingBuilder } from '../utils/builders';
+import { QueryPredicate, QueryFn, QueryContextView } from '../context';
 
-export const all: StructureQuery = async (ctx) => StructureSelection.Singletons(ctx.structure, ctx.structure);
+export const all: StructureQuery = async (ctx) => StructureSelection.Singletons(ctx.inputStructure, ctx.inputStructure);
 
 export interface AtomsQueryParams {
     entityTest: QueryPredicate,
@@ -45,10 +45,10 @@ export function atoms(params?: Partial<AtomsQueryParams>): StructureQuery {
 
 function atomGroupsLinear(atomTest: QueryPredicate): StructureQuery {
     return async (ctx) => {
-        const { structure } = ctx;
-        const { units } = structure;
+        const { inputStructure } = ctx;
+        const { units } = inputStructure;
         const l = ctx.pushCurrentElement();
-        const builder = structure.subsetBuilder(true);
+        const builder = inputStructure.subsetBuilder(true);
 
         let progress = 0;
         for (const unit of units) {
@@ -66,16 +66,16 @@ function atomGroupsLinear(atomTest: QueryPredicate): StructureQuery {
             if (ctx.taskCtx.shouldUpdate) await ctx.taskCtx.update({ message: 'Atom Groups', current: progress, max: units.length });
         }
         ctx.popCurrentElement();
-        return StructureSelection.Singletons(structure, builder.getStructure());
+        return StructureSelection.Singletons(inputStructure, builder.getStructure());
     };
 }
 
 function atomGroupsSegmented({ entityTest, chainTest, residueTest, atomTest }: AtomsQueryParams): StructureQuery {
     return async (ctx) => {
-        const { structure } = ctx;
-        const { units } = structure;
+        const { inputStructure } = ctx;
+        const { units } = inputStructure;
         const l = ctx.pushCurrentElement();
-        const builder = structure.subsetBuilder(true);
+        const builder = inputStructure.subsetBuilder(true);
 
         let progress = 0;
         for (const unit of units) {
@@ -115,16 +115,16 @@ function atomGroupsSegmented({ entityTest, chainTest, residueTest, atomTest }: A
             if (ctx.taskCtx.shouldUpdate) await ctx.taskCtx.update({ message: 'Atom Groups', current: progress, max: units.length });
         }
         ctx.popCurrentElement();
-        return StructureSelection.Singletons(structure, builder.getStructure());
+        return StructureSelection.Singletons(inputStructure, builder.getStructure());
     };
 }
 
 function atomGroupsGrouped({ entityTest, chainTest, residueTest, atomTest, groupBy }: AtomsQueryParams): StructureQuery {
     return async (ctx) => {
-        const { structure } = ctx;
-        const { units } = structure;
+        const { inputStructure } = ctx;
+        const { units } = inputStructure;
         const l = ctx.pushCurrentElement();
-        const builder = new LinearGroupingBuilder(structure);
+        const builder = new LinearGroupingBuilder(inputStructure);
 
         let progress = 0;
         for (const unit of units) {
diff --git a/src/mol-model/structure/query/modifiers.ts b/src/mol-model/structure/query/queries/modifiers.ts
similarity index 79%
rename from src/mol-model/structure/query/modifiers.ts
rename to src/mol-model/structure/query/queries/modifiers.ts
index 42dea2f05..7943e9e7f 100644
--- a/src/mol-model/structure/query/modifiers.ts
+++ b/src/mol-model/structure/query/queries/modifiers.ts
@@ -6,11 +6,11 @@
 
 import { Segmentation } from 'mol-data/int';
 import { RuntimeContext } from 'mol-task';
-import { Structure, Unit } from '../structure';
-import { StructureQuery } from './query';
-import { StructureSelection } from './selection';
-import { UniqueStructuresBuilder } from './utils/builders';
-import { StructureUniqueSubsetBuilder } from '../structure/util/unique-subset-builder';
+import { Structure, Unit } from '../../structure';
+import { StructureQuery } from '../query';
+import { StructureSelection } from '../selection';
+import { UniqueStructuresBuilder } from '../utils/builders';
+import { StructureUniqueSubsetBuilder } from '../../structure/util/unique-subset-builder';
 
 function getWholeResidues(ctx: RuntimeContext, source: Structure, structure: Structure) {
     const builder = source.subsetBuilder(true);
@@ -41,12 +41,12 @@ export function wholeResidues(query: StructureQuery, isFlat: boolean): Structure
     return async (ctx) => {
         const inner = await query(ctx);
         if (StructureSelection.isSingleton(inner)) {
-            return StructureSelection.Singletons(ctx.structure, getWholeResidues(ctx.taskCtx, ctx.structure, inner.structure));
+            return StructureSelection.Singletons(ctx.inputStructure, getWholeResidues(ctx.taskCtx, ctx.inputStructure, inner.structure));
         } else {
-            const builder = new UniqueStructuresBuilder(ctx.structure);
+            const builder = new UniqueStructuresBuilder(ctx.inputStructure);
             let progress = 0;
             for (const s of inner.structures) {
-                builder.add(getWholeResidues(ctx.taskCtx, ctx.structure, s));
+                builder.add(getWholeResidues(ctx.taskCtx, ctx.inputStructure, s));
                 progress++;
                 if (ctx.taskCtx.shouldUpdate) await ctx.taskCtx.update({ message: 'Whole Residues', current: progress, max: inner.structures.length });
             }
@@ -87,13 +87,13 @@ export function includeSurroundings(query: StructureQuery, params: IncludeSurrou
     return async (ctx) => {
         const inner = await query(ctx);
         if (StructureSelection.isSingleton(inner)) {
-            const surr = await getIncludeSurroundings(ctx.taskCtx, ctx.structure, inner.structure, params);
-            const ret = StructureSelection.Singletons(ctx.structure, surr);
+            const surr = await getIncludeSurroundings(ctx.taskCtx, ctx.inputStructure, inner.structure, params);
+            const ret = StructureSelection.Singletons(ctx.inputStructure, surr);
             return ret;
         } else {
-            const builder = new UniqueStructuresBuilder(ctx.structure);
+            const builder = new UniqueStructuresBuilder(ctx.inputStructure);
             for (const s of inner.structures) {
-                builder.add(await getIncludeSurroundings(ctx.taskCtx, ctx.structure, s, params));
+                builder.add(await getIncludeSurroundings(ctx.taskCtx, ctx.inputStructure, s, params));
             }
             return builder.getSelection();
         }
diff --git a/src/perf-tests/tasks.ts b/src/perf-tests/tasks.ts
index c1fa6c9c9..f0c0eb86b 100644
--- a/src/perf-tests/tasks.ts
+++ b/src/perf-tests/tasks.ts
@@ -98,20 +98,80 @@ export namespace Tasks {
             .on('cycle', (e: any) => console.log(String(e.target)))
             .run();
     }
+
+    function add(x: number, y: number) {
+        return x + y;
+    }
+
+    // async function addAs(x: number, y: number) {
+    //     return x + y;
+    // }
+
+    async function opAsync(n: number) {
+        let ret = 0;
+        for (let i = 0; i < n; i++) {
+            const v = add(i, i + 1);
+            ret += (v as any).then ? await v : v;
+        }
+        return ret;
+    }
+
+    function opNormal(n: number) {
+        let ret = 0;
+        for (let i = 0; i < n; i++) {
+            ret += add(i, i + 1);
+        }
+        return ret;
+    }
+
+    export async function awaitF() {
+        const N = 10000000;
+
+        console.time('async');
+        console.log(await opAsync(N));
+        console.timeEnd('async');
+
+        console.time('async');
+        console.log(await opAsync(N));
+        console.timeEnd('async');
+
+        console.time('async');
+        console.log(await opAsync(N));
+        console.timeEnd('async');
+
+        console.time('normal');
+        console.log(opNormal(N));
+        console.timeEnd('normal');
+        console.time('normal');
+        console.log(opNormal(N));
+        console.timeEnd('normal');
+        console.time('normal');
+        console.log(opNormal(N));
+        console.timeEnd('normal');
+
+        // const suite = new B.Suite();
+        // suite
+        //     .add(`async`, async () => { return await opAsync(100000); })
+        //     .add(`normal`, () => { return opNormal(100000); })
+        //     .on('cycle', (e: any) => console.log(String(e.target)))
+        //     .run();
+    }
 }
 
 (async function() {
     // await Tasks.testImmediate();
     // await Tasks.testImmediate();
 
-    await Tasks.baseline();
-    await Tasks.yielding();
-    await Tasks.yielding1();
-    await Tasks.testYielding();
-    await Tasks.baseline();
-    await Tasks.yielding();
-    await Tasks.yielding1();
-    await Tasks.testYielding();
+    // await Tasks.baseline();
+    // await Tasks.yielding();
+    // await Tasks.yielding1();
+    // await Tasks.testYielding();
+    // await Tasks.baseline();
+    // await Tasks.yielding();
+    // await Tasks.yielding1();
+    // await Tasks.testYielding();
+
+    await Tasks.awaitF();
 }())
 
 // console.time('test')
-- 
GitLab