dag.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. export class Edge {
  2. inputNode: Node;
  3. outputNode: Node;
  4. _linkTo(node, direction) {
  5. if (direction <= 0) {
  6. node.inputEdges.push(this);
  7. }
  8. if (direction >= 0) {
  9. node.outputEdges.push(this);
  10. }
  11. node.edges.push(this);
  12. }
  13. link(inputNode: Node, outputNode: Node) {
  14. this.unlink();
  15. this.inputNode = inputNode;
  16. this.outputNode = outputNode;
  17. this._linkTo(inputNode, 1);
  18. this._linkTo(outputNode, -1);
  19. return this;
  20. }
  21. unlink() {
  22. let pos;
  23. const inode = this.inputNode;
  24. const onode = this.outputNode;
  25. if (!(inode && onode)) {
  26. return;
  27. }
  28. pos = inode.edges.indexOf(this);
  29. if (pos > -1) {
  30. inode.edges.splice(pos, 1);
  31. }
  32. pos = onode.edges.indexOf(this);
  33. if (pos > -1) {
  34. onode.edges.splice(pos, 1);
  35. }
  36. pos = inode.outputEdges.indexOf(this);
  37. if (pos > -1) {
  38. inode.outputEdges.splice(pos, 1);
  39. }
  40. pos = onode.inputEdges.indexOf(this);
  41. if (pos > -1) {
  42. onode.inputEdges.splice(pos, 1);
  43. }
  44. this.inputNode = null;
  45. this.outputNode = null;
  46. }
  47. }
  48. export class Node {
  49. name: string;
  50. edges: Edge[];
  51. inputEdges: Edge[];
  52. outputEdges: Edge[];
  53. constructor(name: string) {
  54. this.name = name;
  55. this.edges = [];
  56. this.inputEdges = [];
  57. this.outputEdges = [];
  58. }
  59. getEdgeFrom(from: string | Node): Edge {
  60. if (!from) {
  61. return null;
  62. }
  63. if (typeof from === 'object') {
  64. return this.inputEdges.find(e => e.inputNode.name === from.name);
  65. }
  66. return this.inputEdges.find(e => e.inputNode.name === from);
  67. }
  68. getEdgeTo(to: string | Node): Edge {
  69. if (!to) {
  70. return null;
  71. }
  72. if (typeof to === 'object') {
  73. return this.outputEdges.find(e => e.outputNode.name === to.name);
  74. }
  75. return this.outputEdges.find(e => e.outputNode.name === to);
  76. }
  77. getOptimizedInputEdges(): Edge[] {
  78. const toBeRemoved = [];
  79. this.inputEdges.forEach(e => {
  80. const inputEdgesNodes = e.inputNode.inputEdges.map(e => e.inputNode);
  81. inputEdgesNodes.forEach(n => {
  82. const edgeToRemove = n.getEdgeTo(this.name);
  83. if (edgeToRemove) {
  84. toBeRemoved.push(edgeToRemove);
  85. }
  86. });
  87. });
  88. return this.inputEdges.filter(e => toBeRemoved.indexOf(e) === -1);
  89. }
  90. }
  91. export class Graph {
  92. nodes = {};
  93. constructor() {}
  94. createNode(name: string): Node {
  95. const n = new Node(name);
  96. this.nodes[name] = n;
  97. return n;
  98. }
  99. createNodes(names: string[]): Node[] {
  100. const nodes = [];
  101. names.forEach(name => {
  102. nodes.push(this.createNode(name));
  103. });
  104. return nodes;
  105. }
  106. link(input: string | string[] | Node | Node[], output: string | string[] | Node | Node[]): Edge[] {
  107. let inputArr = [];
  108. let outputArr = [];
  109. const inputNodes = [];
  110. const outputNodes = [];
  111. if (input instanceof Array) {
  112. inputArr = input;
  113. } else {
  114. inputArr = [input];
  115. }
  116. if (output instanceof Array) {
  117. outputArr = output;
  118. } else {
  119. outputArr = [output];
  120. }
  121. for (let n = 0; n < inputArr.length; n++) {
  122. const i = inputArr[n];
  123. if (typeof i === 'string') {
  124. inputNodes.push(this.getNode(i));
  125. } else {
  126. inputNodes.push(i);
  127. }
  128. }
  129. for (let n = 0; n < outputArr.length; n++) {
  130. const i = outputArr[n];
  131. if (typeof i === 'string') {
  132. outputNodes.push(this.getNode(i));
  133. } else {
  134. outputNodes.push(i);
  135. }
  136. }
  137. const edges = [];
  138. inputNodes.forEach(input => {
  139. outputNodes.forEach(output => {
  140. edges.push(this.createEdge().link(input, output));
  141. });
  142. });
  143. return edges;
  144. }
  145. createEdge(): Edge {
  146. return new Edge();
  147. }
  148. getNode(name: string): Node {
  149. return this.nodes[name];
  150. }
  151. }
  152. export const printGraph = (g: Graph) => {
  153. Object.keys(g.nodes).forEach(name => {
  154. const n = g.nodes[name];
  155. let outputEdges = n.outputEdges.map(e => e.outputNode.name).join(', ');
  156. if (!outputEdges) {
  157. outputEdges = '<none>';
  158. }
  159. let inputEdges = n.inputEdges.map(e => e.inputNode.name).join(', ');
  160. if (!inputEdges) {
  161. inputEdges = '<none>';
  162. }
  163. console.log(`${n.name}:\n - links to: ${outputEdges}\n - links from: ${inputEdges}`);
  164. });
  165. };