|
@@ -1,79 +0,0 @@
|
|
|
-import SugiyamaOptimizerStep, {Context} from "../../abstract/sugiyama-based/SugiyamaOptimizerStep.js";
|
|
|
|
|
-import OptimizerError from "../../errors/OptimizerError.js";
|
|
|
|
|
-import XDirectedGraph from "../../../graphs/types/XDirectedGraph.js";
|
|
|
|
|
-import XVertex from "../../../graphs/types/XVertex.js";
|
|
|
|
|
-
|
|
|
|
|
-export default class LayerAssignmentStep extends SugiyamaOptimizerStep {
|
|
|
|
|
- process(context: Context): Context {
|
|
|
|
|
- const { acyclicGraph } = context;
|
|
|
|
|
-
|
|
|
|
|
- if(!acyclicGraph)
|
|
|
|
|
- throw new OptimizerError("Directed acyclic graph is null or undefined");
|
|
|
|
|
-
|
|
|
|
|
- context.layers = this.assignLayers(acyclicGraph);
|
|
|
|
|
-
|
|
|
|
|
- console.log(context.layers)
|
|
|
|
|
-
|
|
|
|
|
- return super.process(context);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- protected assignLayers(graph: XDirectedGraph): XVertex[][] {
|
|
|
|
|
- const topologicalOrder = this.topologicalSort(graph);
|
|
|
|
|
-
|
|
|
|
|
- const layers = new Map<XVertex, number>()
|
|
|
|
|
-
|
|
|
|
|
- for(const vertex of topologicalOrder) {
|
|
|
|
|
- const inputs = graph.getInputs(vertex.id);
|
|
|
|
|
-
|
|
|
|
|
- if(inputs.length == 0) {
|
|
|
|
|
- layers.set(vertex, 0);
|
|
|
|
|
- } else {
|
|
|
|
|
- const maxInputsLayer = Math.max(
|
|
|
|
|
- ...inputs.map((input) => layers.get(input) ?? 0)
|
|
|
|
|
- );
|
|
|
|
|
- layers.set(vertex, maxInputsLayer + 1);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- const maxLayer = Math.max(...layers.values());
|
|
|
|
|
- const result: XVertex[][] = Array.from({ length: maxLayer + 1 }, () => []);
|
|
|
|
|
-
|
|
|
|
|
- for(const [vertex, layer] of layers)
|
|
|
|
|
- result[layer]!.push(vertex);
|
|
|
|
|
-
|
|
|
|
|
- return result;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private topologicalSort(graph: XDirectedGraph): XVertex[] {
|
|
|
|
|
- const degreeMap = new Map<XVertex, number>();
|
|
|
|
|
-
|
|
|
|
|
- for(const vertex of graph.vertices)
|
|
|
|
|
- degreeMap.set(vertex, graph.getInputs(vertex.id).length);
|
|
|
|
|
-
|
|
|
|
|
- const stack: XVertex[] = [];
|
|
|
|
|
-
|
|
|
|
|
- for(const [vertex, degree] of degreeMap)
|
|
|
|
|
- if(degree == 0)
|
|
|
|
|
- stack.push(vertex);
|
|
|
|
|
-
|
|
|
|
|
- const result: XVertex[] = [];
|
|
|
|
|
-
|
|
|
|
|
- while(stack.length > 0) {
|
|
|
|
|
- const curr = stack.shift()!;
|
|
|
|
|
- result.push(curr);
|
|
|
|
|
-
|
|
|
|
|
- for(const neighbour of graph.getOutputs(curr.id)) {
|
|
|
|
|
- const newDegree = (degreeMap.get(neighbour) ?? 0) - 1;
|
|
|
|
|
- degreeMap.set(neighbour, newDegree);
|
|
|
|
|
-
|
|
|
|
|
- if(newDegree == 0)
|
|
|
|
|
- stack.push(neighbour);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if(result.length != graph.vertices.length)
|
|
|
|
|
- throw new OptimizerError("Cycle is detected..")
|
|
|
|
|
-
|
|
|
|
|
- return result;
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|