Skip to content

Commit b4edf82

Browse files
committed
port in changes from sieve-visualize
1 parent 0347964 commit b4edf82

File tree

3 files changed

+65
-9
lines changed

3 files changed

+65
-9
lines changed

src/core/graph.ts

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ import {Log} from "./util";
1010
/**
1111
* A generic precedence graph.
1212
*/
13+
14+
export interface HierarchyGraphLevel<T> {
15+
name: string,
16+
nodes: T[],
17+
childrenLevels: Array<HierarchyGraphLevel<T>>,
18+
}
1319
export class PrecedenceGraph<T> {
1420
/**
1521
* A map from nodes to the set of their upstream neighbors.
@@ -189,10 +195,10 @@ export class PrecedenceGraph<T> {
189195
* @param edgesWithIssue An array containing arrays with [origin, effect].
190196
* Denotes edges in the graph that causes issues to the execution, will be visualized as `--x` in mermaid.
191197
*/
192-
toMermaidString(edgesWithIssue?: Array<[T, T]>): string {
198+
toMermaidString(edgesWithIssue?: Array<[T, T]>, hierarchy?: HierarchyGraphLevel<T>): string {
193199
if (edgesWithIssue == null) edgesWithIssue = [];
194-
let result = "graph";
195-
const nodeToNumber = new Map<T, number>();
200+
let result = "graph\n";
201+
const nodeToSymbolString = new Map<T, string>();
196202
const getNodeString = (node: T, def: string): string => {
197203
if (node == null || node?.toString === Object.prototype.toString) {
198204
console.error(
@@ -205,27 +211,45 @@ export class PrecedenceGraph<T> {
205211
return node.toString();
206212
};
207213

208-
// Build a block here since we only need `counter` temporarily here
214+
if (hierarchy != null) {
215+
let counter = 0;
216+
const recurse = (h: HierarchyGraphLevel<T>, level: number): void => {
217+
const indent = " ".repeat(level);
218+
result += level === 0 ? "" : `${indent}subgraph "${h.name}"\n`;
219+
for (const v of h.nodes) {
220+
result += `${indent} ${counter}["${getNodeString(v, String(counter))}"]\n`
221+
nodeToSymbolString.set(v, `${counter++}`);
222+
}
223+
for (const c of h.childrenLevels) {
224+
recurse(c, level + 1);
225+
}
226+
result += level === 0 ? "" : `${indent}end\n`;
227+
}
209228

229+
recurse(hierarchy, 0);
230+
}
231+
232+
// Build a block here since we only need `counter` temporarily here
210233
// We use numbers instead of names of reactors directly as node names
211234
// in mermaid.js because mermaid has strict restrictions regarding
212235
// what could be used as names of the node.
213236
{
214237
let counter = 0;
215238
for (const v of this.getNodes()) {
216-
result += `\n${counter}["${getNodeString(v, String(counter))}"]`;
217-
nodeToNumber.set(v, counter++);
239+
if (nodeToSymbolString.has(v)) { continue; }
240+
result += `\nmissing${counter}["${getNodeString(v, String(counter))}"]`;
241+
nodeToSymbolString.set(v, `missing${counter++}`);
218242
}
219243
}
220244
// This is the effect
221245
for (const s of this.getNodes()) {
222246
// This is the origin
223247
for (const t of this.getUpstreamNeighbors(s)) {
224-
result += `\n${nodeToNumber.get(t)}`;
248+
result += `\n${nodeToSymbolString.get(t)}`;
225249
result += edgesWithIssue.some((v) => v[0] === t && v[1] === s)
226250
? " --x "
227251
: " --> ";
228-
result += `${nodeToNumber.get(s)}`;
252+
result += `${nodeToSymbolString.get(s)}`;
229253
}
230254
}
231255
return result;

src/core/reactor.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ import {
4242
Startup,
4343
Shutdown,
4444
WritableMultiPort,
45-
Dummy
45+
Dummy,
46+
HierarchyGraphLevel
4647
} from "./internal";
4748
import {v4 as uuidv4} from "uuid";
4849
import {Bank} from "./bank";
@@ -952,6 +953,35 @@ export abstract class Reactor extends Component {
952953
return graph;
953954
}
954955

956+
public _getNodeHierarchyLevels(depth = -1): HierarchyGraphLevel<Port<unknown> | Reaction<Variable[]>> {
957+
this._addHierarchicalDependencies();
958+
this._addRPCDependencies();
959+
960+
const hierarchy: HierarchyGraphLevel<Port<unknown> | Reaction<Variable[]>> = {
961+
// names could be duplicate which mermaid don't like, better be unique
962+
name: `${this._getFullyQualifiedName()}`,
963+
// I think _getReactions and _getMutations might contain children reactions.
964+
// So filter by owner might be needed?
965+
nodes: ([...this._findOwnPorts()] as Array<(Port<unknown> | Reaction<Variable[]>)>)
966+
// reactor is private so we must use bracket
967+
// eslint-disable-next-line @typescript-eslint/dot-notation
968+
.concat([...this._getReactions()].filter((x) => (x["reactor"] === this)))
969+
// eslint-disable-next-line @typescript-eslint/dot-notation
970+
.concat([...this._getMutations()].filter((x) => (x["reactor"] === this))),
971+
childrenLevels: []
972+
};
973+
974+
if (depth !== 0) {
975+
// Sometimes there's duplicative children??
976+
for (const r of this._getOwnReactors()) {
977+
if (r._getContainer() === this) {
978+
hierarchy.childrenLevels.push(r._getNodeHierarchyLevels(depth - 1));
979+
}
980+
}
981+
}
982+
return hierarchy;
983+
}
984+
955985
/**
956986
* Return the reactors that this reactor owns.
957987
*/

src/core/util.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import ULog from "ulog";
2+
import { readFileSync } from 'fs';
23

34
/**
45
* Utilities for the reactor runtime.
@@ -184,3 +185,4 @@ export class Log {
184185
}
185186
}
186187
}
188+

0 commit comments

Comments
 (0)