From 88744a970ddc5c10e6722f35eb1f5c65b305dbe1 Mon Sep 17 00:00:00 2001 From: Sacha Froment <sfroment42@gmail.com> Date: Tue, 18 Feb 2025 15:54:26 +0100 Subject: [PATCH 1/2] perf: better topo dfs perf Signed-off-by: Sacha Froment <sfroment42@gmail.com> --- packages/object/src/hashgraph/index.ts | 21 +++++++++++++-------- packages/object/src/utils/objectSet.ts | 5 +++++ packages/object/tests/actiontypes.test.ts | 15 ++++++++++----- 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/packages/object/src/hashgraph/index.ts b/packages/object/src/hashgraph/index.ts index f0c3edc7b..1d0524f9f 100644 --- a/packages/object/src/hashgraph/index.ts +++ b/packages/object/src/hashgraph/index.ts @@ -166,16 +166,20 @@ export class HashGraph { dfsTopologicalSortIterative(origin: Hash, subgraph: ObjectSet<Hash>): Hash[] { const visited = new ObjectSet<Hash>(); - const result: Hash[] = []; - const stack: Hash[] = [origin]; + const result: Hash[] = Array(subgraph.size); + const stack: Hash[] = Array(subgraph.size); const processing = new ObjectSet<Hash>(); + let resultIndex = subgraph.size - 1; + let stackIndex = 0; + stack[stackIndex] = origin; - while (stack.length > 0) { - const node = stack[stack.length - 1]; + while (resultIndex >= 0) { + const node = stack[stackIndex]; if (visited.has(node)) { - stack.pop(); - result.push(node); + result[resultIndex] = node; + stackIndex--; + resultIndex--; processing.delete(node); continue; } @@ -188,13 +192,14 @@ export class HashGraph { for (const neighbor of neighbors.sort()) { if (processing.has(neighbor)) throw new Error("Graph contains a cycle!"); if (subgraph.has(neighbor) && !visited.has(neighbor)) { - stack.push(neighbor); + stackIndex++; + stack[stackIndex] = neighbor; } } } } - return result.reverse(); + return result; } /* Topologically sort the vertices in the whole hashgraph or the past of a given vertex. */ diff --git a/packages/object/src/utils/objectSet.ts b/packages/object/src/utils/objectSet.ts index cd11095b9..94fc20628 100644 --- a/packages/object/src/utils/objectSet.ts +++ b/packages/object/src/utils/objectSet.ts @@ -1,19 +1,24 @@ export class ObjectSet<T extends string | number | symbol> { set: { [key in T]: boolean }; + size: number; constructor(iterable: Iterable<T> = []) { this.set = {} as { [key in T]: boolean }; + this.size = 0; for (const item of iterable) { this.set[item] = true; + this.size++; } } add(item: T): void { this.set[item] = true; + this.size++; } delete(item: T): void { delete this.set[item]; + this.size--; } has(item: T): boolean { diff --git a/packages/object/tests/actiontypes.test.ts b/packages/object/tests/actiontypes.test.ts index bf798d8d7..13eee4827 100644 --- a/packages/object/tests/actiontypes.test.ts +++ b/packages/object/tests/actiontypes.test.ts @@ -89,23 +89,28 @@ describe("Test: ActionTypes (Nop and Swap)", () => { addMul.add(5); drp.merge(drp2.vertices); drp2.merge(drp.vertices); - + vi.setSystemTime(new Date(Date.UTC(1998, 11, 21))); addMul.mul(5); + vi.setSystemTime(new Date(Date.UTC(1998, 11, 22))); addMul.add(5); + vi.setSystemTime(new Date(Date.UTC(1998, 11, 23))); addMul2.add(5); drp.merge(drp2.vertices); drp2.merge(drp.vertices); - expect(addMul.query_value()).toBe(75); - expect(addMul2.query_value()).toBe(75); + expect(addMul.query_value()).toBe(55); + expect(addMul2.query_value()).toBe(55); addMul2.mul(2); + vi.setSystemTime(new Date(Date.UTC(1998, 11, 24))); addMul2.add(2); + vi.setSystemTime(new Date(Date.UTC(1998, 11, 25))); addMul.add(3); + vi.setSystemTime(new Date(Date.UTC(1998, 11, 26))); addMul.mul(3); drp.merge(drp2.vertices); drp2.merge(drp.vertices); - expect(addMul.query_value()).toBe(480); - expect(addMul2.query_value()).toBe(480); + expect(addMul.query_value()).toBe(510); + expect(addMul2.query_value()).toBe(510); }); }); From 427f7e006a122af0318c678c31e263ed3dd22403 Mon Sep 17 00:00:00 2001 From: Jan Lewandowski <lewandowski.jan@o2.pl> Date: Wed, 19 Feb 2025 16:26:48 +0100 Subject: [PATCH 2/2] fix: objectset and tets --- packages/object/src/linearize/pairSemantics.ts | 1 - packages/object/src/utils/objectSet.ts | 4 ++++ packages/object/tests/actiontypes.test.ts | 11 ++++------- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/object/src/linearize/pairSemantics.ts b/packages/object/src/linearize/pairSemantics.ts index 9c3d3066c..7e18f747e 100644 --- a/packages/object/src/linearize/pairSemantics.ts +++ b/packages/object/src/linearize/pairSemantics.ts @@ -58,6 +58,5 @@ export function linearizePairSemantics( } } } - return result; } diff --git a/packages/object/src/utils/objectSet.ts b/packages/object/src/utils/objectSet.ts index 94fc20628..ce70bdf9e 100644 --- a/packages/object/src/utils/objectSet.ts +++ b/packages/object/src/utils/objectSet.ts @@ -12,11 +12,15 @@ export class ObjectSet<T extends string | number | symbol> { } add(item: T): void { + if (this.has(item)) return; + this.set[item] = true; this.size++; } delete(item: T): void { + if (!this.has(item)) return; + delete this.set[item]; this.size--; } diff --git a/packages/object/tests/actiontypes.test.ts b/packages/object/tests/actiontypes.test.ts index 13eee4827..939023b35 100644 --- a/packages/object/tests/actiontypes.test.ts +++ b/packages/object/tests/actiontypes.test.ts @@ -89,16 +89,13 @@ describe("Test: ActionTypes (Nop and Swap)", () => { addMul.add(5); drp.merge(drp2.vertices); drp2.merge(drp.vertices); - vi.setSystemTime(new Date(Date.UTC(1998, 11, 21))); addMul.mul(5); - vi.setSystemTime(new Date(Date.UTC(1998, 11, 22))); addMul.add(5); - vi.setSystemTime(new Date(Date.UTC(1998, 11, 23))); addMul2.add(5); drp.merge(drp2.vertices); drp2.merge(drp.vertices); - expect(addMul.query_value()).toBe(55); - expect(addMul2.query_value()).toBe(55); + expect(addMul.query_value()).toBe(75); + expect(addMul2.query_value()).toBe(75); addMul2.mul(2); vi.setSystemTime(new Date(Date.UTC(1998, 11, 24))); @@ -109,8 +106,8 @@ describe("Test: ActionTypes (Nop and Swap)", () => { addMul.mul(3); drp.merge(drp2.vertices); drp2.merge(drp.vertices); - expect(addMul.query_value()).toBe(510); - expect(addMul2.query_value()).toBe(510); + expect(addMul.query_value()).toBe(480); + expect(addMul2.query_value()).toBe(480); }); });