dagre-d3.js (130672B)
1 ;(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ 2 var global=self;/** 3 * @license 4 * Copyright (c) 2012-2013 Chris Pettitt 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 global.dagreD3 = require('./index'); 25 26 },{"./index":2}],2:[function(require,module,exports){ 27 /** 28 * @license 29 * Copyright (c) 2012-2013 Chris Pettitt 30 * 31 * Permission is hereby granted, free of charge, to any person obtaining a copy 32 * of this software and associated documentation files (the "Software"), to deal 33 * in the Software without restriction, including without limitation the rights 34 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 35 * copies of the Software, and to permit persons to whom the Software is 36 * furnished to do so, subject to the following conditions: 37 * 38 * The above copyright notice and this permission notice shall be included in 39 * all copies or substantial portions of the Software. 40 * 41 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 42 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 43 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 44 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 45 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 46 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 47 * THE SOFTWARE. 48 */ 49 module.exports = { 50 Digraph: require('graphlib').Digraph, 51 Renderer: require('./lib/Renderer'), 52 json: require('graphlib').converter.json, 53 layout: require('dagre').layout, 54 version: require('./lib/version') 55 }; 56 57 },{"./lib/Renderer":3,"./lib/version":4,"dagre":11,"graphlib":28}],3:[function(require,module,exports){ 58 var layout = require('dagre').layout; 59 60 var d3; 61 try { d3 = require('d3'); } catch (_) { d3 = window.d3; } 62 63 module.exports = Renderer; 64 65 function Renderer() { 66 // Set up defaults... 67 this._layout = layout(); 68 69 this.drawNodes(defaultDrawNodes); 70 this.drawEdgeLabels(defaultDrawEdgeLabels); 71 this.drawEdgePaths(defaultDrawEdgePaths); 72 this.positionNodes(defaultPositionNodes); 73 this.positionEdgeLabels(defaultPositionEdgeLabels); 74 this.positionEdgePaths(defaultPositionEdgePaths); 75 this.transition(defaultTransition); 76 this.postLayout(defaultPostLayout); 77 this.postRender(defaultPostRender); 78 79 this.edgeInterpolate('bundle'); 80 this.edgeTension(0.95); 81 } 82 83 Renderer.prototype.layout = function(layout) { 84 if (!arguments.length) { return this._layout; } 85 this._layout = layout; 86 return this; 87 }; 88 89 Renderer.prototype.drawNodes = function(drawNodes) { 90 if (!arguments.length) { return this._drawNodes; } 91 this._drawNodes = bind(drawNodes, this); 92 return this; 93 }; 94 95 Renderer.prototype.drawEdgeLabels = function(drawEdgeLabels) { 96 if (!arguments.length) { return this._drawEdgeLabels; } 97 this._drawEdgeLabels = bind(drawEdgeLabels, this); 98 return this; 99 }; 100 101 Renderer.prototype.drawEdgePaths = function(drawEdgePaths) { 102 if (!arguments.length) { return this._drawEdgePaths; } 103 this._drawEdgePaths = bind(drawEdgePaths, this); 104 return this; 105 }; 106 107 Renderer.prototype.positionNodes = function(positionNodes) { 108 if (!arguments.length) { return this._positionNodes; } 109 this._positionNodes = bind(positionNodes, this); 110 return this; 111 }; 112 113 Renderer.prototype.positionEdgeLabels = function(positionEdgeLabels) { 114 if (!arguments.length) { return this._positionEdgeLabels; } 115 this._positionEdgeLabels = bind(positionEdgeLabels, this); 116 return this; 117 }; 118 119 Renderer.prototype.positionEdgePaths = function(positionEdgePaths) { 120 if (!arguments.length) { return this._positionEdgePaths; } 121 this._positionEdgePaths = bind(positionEdgePaths, this); 122 return this; 123 }; 124 125 Renderer.prototype.transition = function(transition) { 126 if (!arguments.length) { return this._transition; } 127 this._transition = bind(transition, this); 128 return this; 129 }; 130 131 Renderer.prototype.postLayout = function(postLayout) { 132 if (!arguments.length) { return this._postLayout; } 133 this._postLayout = bind(postLayout, this); 134 return this; 135 }; 136 137 Renderer.prototype.postRender = function(postRender) { 138 if (!arguments.length) { return this._postRender; } 139 this._postRender = bind(postRender, this); 140 return this; 141 }; 142 143 Renderer.prototype.edgeInterpolate = function(edgeInterpolate) { 144 if (!arguments.length) { return this._edgeInterpolate; } 145 this._edgeInterpolate = edgeInterpolate; 146 return this; 147 }; 148 149 Renderer.prototype.edgeTension = function(edgeTension) { 150 if (!arguments.length) { return this._edgeTension; } 151 this._edgeTension = edgeTension; 152 return this; 153 }; 154 155 Renderer.prototype.run = function(graph, svg) { 156 // First copy the input graph so that it is not changed by the rendering 157 // process. 158 graph = copyAndInitGraph(graph); 159 160 // Create layers 161 svg 162 .selectAll('g.edgePaths, g.edgeLabels, g.nodes') 163 .data(['edgePaths', 'edgeLabels', 'nodes']) 164 .enter() 165 .append('g') 166 .attr('class', function(d) { return d; }); 167 168 169 // Create node and edge roots, attach labels, and capture dimension 170 // information for use with layout. 171 var svgNodes = this._drawNodes(graph, svg.select('g.nodes')); 172 var svgEdgeLabels = this._drawEdgeLabels(graph, svg.select('g.edgeLabels')); 173 174 svgNodes.each(function(u) { calculateDimensions(this, graph.node(u)); }); 175 svgEdgeLabels.each(function(e) { calculateDimensions(this, graph.edge(e)); }); 176 177 // Now apply the layout function 178 var result = runLayout(graph, this._layout); 179 180 // Run any user-specified post layout processing 181 this._postLayout(result, svg); 182 183 var svgEdgePaths = this._drawEdgePaths(graph, svg.select('g.edgePaths')); 184 185 // Apply the layout information to the graph 186 this._positionNodes(result, svgNodes); 187 this._positionEdgeLabels(result, svgEdgeLabels); 188 this._positionEdgePaths(result, svgEdgePaths); 189 190 this._postRender(result, svg); 191 192 return result; 193 }; 194 195 function copyAndInitGraph(graph) { 196 var copy = graph.copy(); 197 198 // Init labels if they were not present in the source graph 199 copy.nodes().forEach(function(u) { 200 var value = copy.node(u); 201 if (value === undefined) { 202 value = {}; 203 copy.node(u, value); 204 } 205 if (!('label' in value)) { value.label = ''; } 206 }); 207 208 copy.edges().forEach(function(e) { 209 var value = copy.edge(e); 210 if (value === undefined) { 211 value = {}; 212 copy.edge(e, value); 213 } 214 if (!('label' in value)) { value.label = ''; } 215 }); 216 217 return copy; 218 } 219 220 function calculateDimensions(group, value) { 221 var bbox = group.getBBox(); 222 value.width = bbox.width; 223 value.height = bbox.height; 224 } 225 226 function runLayout(graph, layout) { 227 var result = layout.run(graph); 228 229 // Copy labels to the result graph 230 graph.eachNode(function(u, value) { result.node(u).label = value.label; }); 231 graph.eachEdge(function(e, u, v, value) { result.edge(e).label = value.label; }); 232 233 return result; 234 } 235 236 function defaultDrawNodes(g, root) { 237 var nodes = g.nodes().filter(function(u) { return !isComposite(g, u); }); 238 239 var svgNodes = root 240 .selectAll('g.node') 241 .classed('enter', false) 242 .data(nodes, function(u) { return u; }); 243 244 svgNodes.selectAll('*').remove(); 245 246 svgNodes 247 .enter() 248 .append('g') 249 .style('opacity', 0) 250 .attr('class', 'node enter'); 251 252 svgNodes.each(function(u) { addLabel(g.node(u), d3.select(this), 10, 10); }); 253 254 this._transition(svgNodes.exit()) 255 .style('opacity', 0) 256 .remove(); 257 258 return svgNodes; 259 } 260 261 function defaultDrawEdgeLabels(g, root) { 262 var svgEdgeLabels = root 263 .selectAll('g.edgeLabel') 264 .classed('enter', false) 265 .data(g.edges(), function (e) { return e; }); 266 267 svgEdgeLabels.selectAll('*').remove(); 268 269 svgEdgeLabels 270 .enter() 271 .append('g') 272 .style('opacity', 0) 273 .attr('class', 'edgeLabel enter'); 274 275 svgEdgeLabels.each(function(e) { addLabel(g.edge(e), d3.select(this), 0, 0); }); 276 277 this._transition(svgEdgeLabels.exit()) 278 .style('opacity', 0) 279 .remove(); 280 281 return svgEdgeLabels; 282 } 283 284 var defaultDrawEdgePaths = function(g, root) { 285 var svgEdgePaths = root 286 .selectAll('g.edgePath') 287 .classed('enter', false) 288 .data(g.edges(), function(e) { return e; }); 289 290 svgEdgePaths 291 .enter() 292 .append('g') 293 .attr('class', 'edgePath enter') 294 .append('path') 295 .style('opacity', 0) 296 .attr('marker-end', 'url(#arrowhead)'); 297 298 this._transition(svgEdgePaths.exit()) 299 .style('opacity', 0) 300 .remove(); 301 302 return svgEdgePaths; 303 }; 304 305 function defaultPositionNodes(g, svgNodes, svgNodesEnter) { 306 function transform(u) { 307 var value = g.node(u); 308 return 'translate(' + value.x + ',' + value.y + ')'; 309 } 310 311 // For entering nodes, position immediately without transition 312 svgNodes.filter('.enter').attr('transform', transform); 313 314 this._transition(svgNodes) 315 .style('opacity', 1) 316 .attr('transform', transform); 317 } 318 319 function defaultPositionEdgeLabels(g, svgEdgeLabels) { 320 function transform(e) { 321 var value = g.edge(e); 322 var point = findMidPoint(value.points); 323 return 'translate(' + point.x + ',' + point.y + ')'; 324 } 325 326 // For entering edge labels, position immediately without transition 327 svgEdgeLabels.filter('.enter').attr('transform', transform); 328 329 this._transition(svgEdgeLabels) 330 .style('opacity', 1) 331 .attr('transform', transform); 332 } 333 334 function defaultPositionEdgePaths(g, svgEdgePaths) { 335 var interpolate = this._edgeInterpolate, 336 tension = this._edgeTension; 337 338 function calcPoints(e) { 339 var value = g.edge(e); 340 var source = g.node(g.incidentNodes(e)[0]); 341 var target = g.node(g.incidentNodes(e)[1]); 342 var points = value.points.slice(); 343 344 var p0 = points.length === 0 ? target : points[0]; 345 var p1 = points.length === 0 ? source : points[points.length - 1]; 346 347 points.unshift(intersectRect(source, p0)); 348 // TODO: use bpodgursky's shortening algorithm here 349 points.push(intersectRect(target, p1)); 350 351 return d3.svg.line() 352 .x(function(d) { return d.x; }) 353 .y(function(d) { return d.y; }) 354 .interpolate(interpolate) 355 .tension(tension) 356 (points); 357 } 358 359 svgEdgePaths.filter('.enter').selectAll('path') 360 .attr('d', calcPoints); 361 362 this._transition(svgEdgePaths.selectAll('path')) 363 .attr('d', calcPoints) 364 .style('opacity', 1); 365 } 366 367 // By default we do not use transitions 368 function defaultTransition(selection) { 369 return selection; 370 } 371 372 function defaultPostLayout() { 373 // Do nothing 374 } 375 376 function defaultPostRender(graph, root) { 377 if (graph.isDirected() && root.select('#arrowhead').empty()) { 378 root 379 .append('svg:defs') 380 .append('svg:marker') 381 .attr('id', 'arrowhead') 382 .attr('viewBox', '0 0 10 10') 383 .attr('refX', 8) 384 .attr('refY', 5) 385 .attr('markerUnits', 'strokewidth') 386 .attr('markerWidth', 8) 387 .attr('markerHeight', 5) 388 .attr('orient', 'auto') 389 .append('svg:path') 390 .attr('d', 'M 0 0 L 10 5 L 0 10 z'); 391 } 392 } 393 394 function addLabel(node, root, marginX, marginY) { 395 // Add the rect first so that it appears behind the label 396 var label = node.label; 397 var rect = root.append('rect'); 398 var labelSvg = root.append('g'); 399 400 if (label[0] === '<') { 401 addForeignObjectLabel(label, labelSvg); 402 // No margin for HTML elements 403 marginX = marginY = 0; 404 } else { 405 addTextLabel(label, 406 labelSvg, 407 Math.floor(node.labelCols), 408 node.labelCut); 409 } 410 411 var bbox = root.node().getBBox(); 412 413 labelSvg.attr('transform', 414 'translate(' + (-bbox.width / 2) + ',' + (-bbox.height / 2) + ')'); 415 416 rect 417 .attr('rx', 5) 418 .attr('ry', 5) 419 .attr('x', -(bbox.width / 2 + marginX)) 420 .attr('y', -(bbox.height / 2 + marginY)) 421 .attr('width', bbox.width + 2 * marginX) 422 .attr('height', bbox.height + 2 * marginY); 423 } 424 425 function addForeignObjectLabel(label, root) { 426 var fo = root 427 .append('foreignObject') 428 .attr('width', '100000'); 429 430 var w, h; 431 fo 432 .append('xhtml:div') 433 .style('float', 'left') 434 // TODO find a better way to get dimensions for foreignObjects... 435 .html(function() { return label; }) 436 .each(function() { 437 w = this.clientWidth; 438 h = this.clientHeight; 439 }); 440 441 fo 442 .attr('width', w) 443 .attr('height', h); 444 } 445 446 function addTextLabel(label, root, labelCols, labelCut) { 447 if (labelCut === undefined) labelCut = "false"; 448 labelCut = (labelCut.toString().toLowerCase() === "true"); 449 450 var node = root 451 .append('text') 452 .attr('text-anchor', 'left'); 453 454 label = label.replace(/\\n/g, "\n"); 455 456 var arr = labelCols ? wordwrap(label, labelCols, labelCut) : label; 457 arr = arr.split("\n"); 458 for (var i = 0; i < arr.length; i++) { 459 node 460 .append('tspan') 461 .attr('dy', '1em') 462 .attr('x', '1') 463 .text(arr[i]); 464 } 465 } 466 467 // Thanks to 468 // http://james.padolsey.com/javascript/wordwrap-for-javascript/ 469 function wordwrap (str, width, cut, brk) { 470 brk = brk || '\n'; 471 width = width || 75; 472 cut = cut || false; 473 474 if (!str) { return str; } 475 476 var regex = '.{1,' +width+ '}(\\s|$)' + (cut ? '|.{' +width+ '}|.+$' : '|\\S+?(\\s|$)'); 477 478 return str.match( RegExp(regex, 'g') ).join( brk ); 479 } 480 481 function findMidPoint(points) { 482 var midIdx = points.length / 2; 483 if (points.length % 2) { 484 return points[Math.floor(midIdx)]; 485 } else { 486 var p0 = points[midIdx - 1]; 487 var p1 = points[midIdx]; 488 return {x: (p0.x + p1.x) / 2, y: (p0.y + p1.y) / 2}; 489 } 490 } 491 492 function intersectRect(rect, point) { 493 var x = rect.x; 494 var y = rect.y; 495 496 // For now we only support rectangles 497 498 // Rectangle intersection algorithm from: 499 // http://math.stackexchange.com/questions/108113/find-edge-between-two-boxes 500 var dx = point.x - x; 501 var dy = point.y - y; 502 var w = rect.width / 2; 503 var h = rect.height / 2; 504 505 var sx, sy; 506 if (Math.abs(dy) * w > Math.abs(dx) * h) { 507 // Intersection is top or bottom of rect. 508 if (dy < 0) { 509 h = -h; 510 } 511 sx = dy === 0 ? 0 : h * dx / dy; 512 sy = h; 513 } else { 514 // Intersection is left or right of rect. 515 if (dx < 0) { 516 w = -w; 517 } 518 sx = w; 519 sy = dx === 0 ? 0 : w * dy / dx; 520 } 521 522 return {x: x + sx, y: y + sy}; 523 } 524 525 function isComposite(g, u) { 526 return 'children' in g && g.children(u).length; 527 } 528 529 function bind(func, thisArg) { 530 // For some reason PhantomJS occassionally fails when using the builtin bind, 531 // so we check if it is available and if not, use a degenerate polyfill. 532 if (func.bind) { 533 return func.bind(thisArg); 534 } 535 536 return function() { 537 return func.apply(thisArg, arguments); 538 }; 539 } 540 541 },{"d3":10,"dagre":11}],4:[function(require,module,exports){ 542 module.exports = '0.1.5'; 543 544 },{}],5:[function(require,module,exports){ 545 exports.Set = require('./lib/Set'); 546 exports.PriorityQueue = require('./lib/PriorityQueue'); 547 exports.version = require('./lib/version'); 548 549 },{"./lib/PriorityQueue":6,"./lib/Set":7,"./lib/version":9}],6:[function(require,module,exports){ 550 module.exports = PriorityQueue; 551 552 /** 553 * A min-priority queue data structure. This algorithm is derived from Cormen, 554 * et al., "Introduction to Algorithms". The basic idea of a min-priority 555 * queue is that you can efficiently (in O(1) time) get the smallest key in 556 * the queue. Adding and removing elements takes O(log n) time. A key can 557 * have its priority decreased in O(log n) time. 558 */ 559 function PriorityQueue() { 560 this._arr = []; 561 this._keyIndices = {}; 562 } 563 564 /** 565 * Returns the number of elements in the queue. Takes `O(1)` time. 566 */ 567 PriorityQueue.prototype.size = function() { 568 return this._arr.length; 569 }; 570 571 /** 572 * Returns the keys that are in the queue. Takes `O(n)` time. 573 */ 574 PriorityQueue.prototype.keys = function() { 575 return this._arr.map(function(x) { return x.key; }); 576 }; 577 578 /** 579 * Returns `true` if **key** is in the queue and `false` if not. 580 */ 581 PriorityQueue.prototype.has = function(key) { 582 return key in this._keyIndices; 583 }; 584 585 /** 586 * Returns the priority for **key**. If **key** is not present in the queue 587 * then this function returns `undefined`. Takes `O(1)` time. 588 * 589 * @param {Object} key 590 */ 591 PriorityQueue.prototype.priority = function(key) { 592 var index = this._keyIndices[key]; 593 if (index !== undefined) { 594 return this._arr[index].priority; 595 } 596 }; 597 598 /** 599 * Returns the key for the minimum element in this queue. If the queue is 600 * empty this function throws an Error. Takes `O(1)` time. 601 */ 602 PriorityQueue.prototype.min = function() { 603 if (this.size() === 0) { 604 throw new Error("Queue underflow"); 605 } 606 return this._arr[0].key; 607 }; 608 609 /** 610 * Inserts a new key into the priority queue. If the key already exists in 611 * the queue this function returns `false`; otherwise it will return `true`. 612 * Takes `O(n)` time. 613 * 614 * @param {Object} key the key to add 615 * @param {Number} priority the initial priority for the key 616 */ 617 PriorityQueue.prototype.add = function(key, priority) { 618 var keyIndices = this._keyIndices; 619 if (!(key in keyIndices)) { 620 var arr = this._arr; 621 var index = arr.length; 622 keyIndices[key] = index; 623 arr.push({key: key, priority: priority}); 624 this._decrease(index); 625 return true; 626 } 627 return false; 628 }; 629 630 /** 631 * Removes and returns the smallest key in the queue. Takes `O(log n)` time. 632 */ 633 PriorityQueue.prototype.removeMin = function() { 634 this._swap(0, this._arr.length - 1); 635 var min = this._arr.pop(); 636 delete this._keyIndices[min.key]; 637 this._heapify(0); 638 return min.key; 639 }; 640 641 /** 642 * Decreases the priority for **key** to **priority**. If the new priority is 643 * greater than the previous priority, this function will throw an Error. 644 * 645 * @param {Object} key the key for which to raise priority 646 * @param {Number} priority the new priority for the key 647 */ 648 PriorityQueue.prototype.decrease = function(key, priority) { 649 var index = this._keyIndices[key]; 650 if (priority > this._arr[index].priority) { 651 throw new Error("New priority is greater than current priority. " + 652 "Key: " + key + " Old: " + this._arr[index].priority + " New: " + priority); 653 } 654 this._arr[index].priority = priority; 655 this._decrease(index); 656 }; 657 658 PriorityQueue.prototype._heapify = function(i) { 659 var arr = this._arr; 660 var l = 2 * i, 661 r = l + 1, 662 largest = i; 663 if (l < arr.length) { 664 largest = arr[l].priority < arr[largest].priority ? l : largest; 665 if (r < arr.length) { 666 largest = arr[r].priority < arr[largest].priority ? r : largest; 667 } 668 if (largest !== i) { 669 this._swap(i, largest); 670 this._heapify(largest); 671 } 672 } 673 }; 674 675 PriorityQueue.prototype._decrease = function(index) { 676 var arr = this._arr; 677 var priority = arr[index].priority; 678 var parent; 679 while (index !== 0) { 680 parent = index >> 1; 681 if (arr[parent].priority < priority) { 682 break; 683 } 684 this._swap(index, parent); 685 index = parent; 686 } 687 }; 688 689 PriorityQueue.prototype._swap = function(i, j) { 690 var arr = this._arr; 691 var keyIndices = this._keyIndices; 692 var origArrI = arr[i]; 693 var origArrJ = arr[j]; 694 arr[i] = origArrJ; 695 arr[j] = origArrI; 696 keyIndices[origArrJ.key] = i; 697 keyIndices[origArrI.key] = j; 698 }; 699 700 },{}],7:[function(require,module,exports){ 701 var util = require('./util'); 702 703 module.exports = Set; 704 705 /** 706 * Constructs a new Set with an optional set of `initialKeys`. 707 * 708 * It is important to note that keys are coerced to String for most purposes 709 * with this object, similar to the behavior of JavaScript's Object. For 710 * example, the following will add only one key: 711 * 712 * var s = new Set(); 713 * s.add(1); 714 * s.add("1"); 715 * 716 * However, the type of the key is preserved internally so that `keys` returns 717 * the original key set uncoerced. For the above example, `keys` would return 718 * `[1]`. 719 */ 720 function Set(initialKeys) { 721 this._size = 0; 722 this._keys = {}; 723 724 if (initialKeys) { 725 for (var i = 0, il = initialKeys.length; i < il; ++i) { 726 this.add(initialKeys[i]); 727 } 728 } 729 } 730 731 /** 732 * Returns a new Set that represents the set intersection of the array of given 733 * sets. 734 */ 735 Set.intersect = function(sets) { 736 if (sets.length === 0) { 737 return new Set(); 738 } 739 740 var result = new Set(!util.isArray(sets[0]) ? sets[0].keys() : sets[0]); 741 for (var i = 1, il = sets.length; i < il; ++i) { 742 var resultKeys = result.keys(), 743 other = !util.isArray(sets[i]) ? sets[i] : new Set(sets[i]); 744 for (var j = 0, jl = resultKeys.length; j < jl; ++j) { 745 var key = resultKeys[j]; 746 if (!other.has(key)) { 747 result.remove(key); 748 } 749 } 750 } 751 752 return result; 753 }; 754 755 /** 756 * Returns a new Set that represents the set union of the array of given sets. 757 */ 758 Set.union = function(sets) { 759 var totalElems = util.reduce(sets, function(lhs, rhs) { 760 return lhs + (rhs.size ? rhs.size() : rhs.length); 761 }, 0); 762 var arr = new Array(totalElems); 763 764 var k = 0; 765 for (var i = 0, il = sets.length; i < il; ++i) { 766 var cur = sets[i], 767 keys = !util.isArray(cur) ? cur.keys() : cur; 768 for (var j = 0, jl = keys.length; j < jl; ++j) { 769 arr[k++] = keys[j]; 770 } 771 } 772 773 return new Set(arr); 774 }; 775 776 /** 777 * Returns the size of this set in `O(1)` time. 778 */ 779 Set.prototype.size = function() { 780 return this._size; 781 }; 782 783 /** 784 * Returns the keys in this set. Takes `O(n)` time. 785 */ 786 Set.prototype.keys = function() { 787 return values(this._keys); 788 }; 789 790 /** 791 * Tests if a key is present in this Set. Returns `true` if it is and `false` 792 * if not. Takes `O(1)` time. 793 */ 794 Set.prototype.has = function(key) { 795 return key in this._keys; 796 }; 797 798 /** 799 * Adds a new key to this Set if it is not already present. Returns `true` if 800 * the key was added and `false` if it was already present. Takes `O(1)` time. 801 */ 802 Set.prototype.add = function(key) { 803 if (!(key in this._keys)) { 804 this._keys[key] = key; 805 ++this._size; 806 return true; 807 } 808 return false; 809 }; 810 811 /** 812 * Removes a key from this Set. If the key was removed this function returns 813 * `true`. If not, it returns `false`. Takes `O(1)` time. 814 */ 815 Set.prototype.remove = function(key) { 816 if (key in this._keys) { 817 delete this._keys[key]; 818 --this._size; 819 return true; 820 } 821 return false; 822 }; 823 824 /* 825 * Returns an array of all values for properties of **o**. 826 */ 827 function values(o) { 828 var ks = Object.keys(o), 829 len = ks.length, 830 result = new Array(len), 831 i; 832 for (i = 0; i < len; ++i) { 833 result[i] = o[ks[i]]; 834 } 835 return result; 836 } 837 838 },{"./util":8}],8:[function(require,module,exports){ 839 /* 840 * This polyfill comes from 841 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray 842 */ 843 if(!Array.isArray) { 844 exports.isArray = function (vArg) { 845 return Object.prototype.toString.call(vArg) === '[object Array]'; 846 }; 847 } else { 848 exports.isArray = Array.isArray; 849 } 850 851 /* 852 * Slightly adapted polyfill from 853 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce 854 */ 855 if ('function' !== typeof Array.prototype.reduce) { 856 exports.reduce = function(array, callback, opt_initialValue) { 857 'use strict'; 858 if (null === array || 'undefined' === typeof array) { 859 // At the moment all modern browsers, that support strict mode, have 860 // native implementation of Array.prototype.reduce. For instance, IE8 861 // does not support strict mode, so this check is actually useless. 862 throw new TypeError( 863 'Array.prototype.reduce called on null or undefined'); 864 } 865 if ('function' !== typeof callback) { 866 throw new TypeError(callback + ' is not a function'); 867 } 868 var index, value, 869 length = array.length >>> 0, 870 isValueSet = false; 871 if (1 < arguments.length) { 872 value = opt_initialValue; 873 isValueSet = true; 874 } 875 for (index = 0; length > index; ++index) { 876 if (array.hasOwnProperty(index)) { 877 if (isValueSet) { 878 value = callback(value, array[index], index, array); 879 } 880 else { 881 value = array[index]; 882 isValueSet = true; 883 } 884 } 885 } 886 if (!isValueSet) { 887 throw new TypeError('Reduce of empty array with no initial value'); 888 } 889 return value; 890 }; 891 } else { 892 exports.reduce = function(array, callback, opt_initialValue) { 893 return array.reduce(callback, opt_initialValue); 894 }; 895 } 896 897 },{}],9:[function(require,module,exports){ 898 module.exports = '1.1.3'; 899 900 },{}],10:[function(require,module,exports){ 901 require("./d3"); 902 module.exports = d3; 903 (function () { delete this.d3; })(); // unset global 904 905 },{}],11:[function(require,module,exports){ 906 /* 907 Copyright (c) 2012-2013 Chris Pettitt 908 909 Permission is hereby granted, free of charge, to any person obtaining a copy 910 of this software and associated documentation files (the "Software"), to deal 911 in the Software without restriction, including without limitation the rights 912 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 913 copies of the Software, and to permit persons to whom the Software is 914 furnished to do so, subject to the following conditions: 915 916 The above copyright notice and this permission notice shall be included in 917 all copies or substantial portions of the Software. 918 919 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 920 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 921 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 922 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 923 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 924 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 925 THE SOFTWARE. 926 */ 927 exports.Digraph = require("graphlib").Digraph; 928 exports.Graph = require("graphlib").Graph; 929 exports.layout = require("./lib/layout"); 930 exports.version = require("./lib/version"); 931 932 },{"./lib/layout":12,"./lib/version":27,"graphlib":28}],12:[function(require,module,exports){ 933 var util = require('./util'), 934 rank = require('./rank'), 935 order = require('./order'), 936 CGraph = require('graphlib').CGraph, 937 CDigraph = require('graphlib').CDigraph; 938 939 module.exports = function() { 940 // External configuration 941 var config = { 942 // How much debug information to include? 943 debugLevel: 0, 944 // Max number of sweeps to perform in order phase 945 orderMaxSweeps: order.DEFAULT_MAX_SWEEPS, 946 // Use network simplex algorithm in ranking 947 rankSimplex: false, 948 // Rank direction. Valid values are (TB, LR) 949 rankDir: 'TB' 950 }; 951 952 // Phase functions 953 var position = require('./position')(); 954 955 // This layout object 956 var self = {}; 957 958 self.orderIters = util.propertyAccessor(self, config, 'orderMaxSweeps'); 959 960 self.rankSimplex = util.propertyAccessor(self, config, 'rankSimplex'); 961 962 self.nodeSep = delegateProperty(position.nodeSep); 963 self.edgeSep = delegateProperty(position.edgeSep); 964 self.universalSep = delegateProperty(position.universalSep); 965 self.rankSep = delegateProperty(position.rankSep); 966 self.rankDir = util.propertyAccessor(self, config, 'rankDir'); 967 self.debugAlignment = delegateProperty(position.debugAlignment); 968 969 self.debugLevel = util.propertyAccessor(self, config, 'debugLevel', function(x) { 970 util.log.level = x; 971 position.debugLevel(x); 972 }); 973 974 self.run = util.time('Total layout', run); 975 976 self._normalize = normalize; 977 978 return self; 979 980 /* 981 * Constructs an adjacency graph using the nodes and edges specified through 982 * config. For each node and edge we add a property `dagre` that contains an 983 * object that will hold intermediate and final layout information. Some of 984 * the contents include: 985 * 986 * 1) A generated ID that uniquely identifies the object. 987 * 2) Dimension information for nodes (copied from the source node). 988 * 3) Optional dimension information for edges. 989 * 990 * After the adjacency graph is constructed the code no longer needs to use 991 * the original nodes and edges passed in via config. 992 */ 993 function initLayoutGraph(inputGraph) { 994 var g = new CDigraph(); 995 996 inputGraph.eachNode(function(u, value) { 997 if (value === undefined) value = {}; 998 g.addNode(u, { 999 width: value.width, 1000 height: value.height 1001 }); 1002 if (value.hasOwnProperty('rank')) { 1003 g.node(u).prefRank = value.rank; 1004 } 1005 }); 1006 1007 // Set up subgraphs 1008 if (inputGraph.parent) { 1009 inputGraph.nodes().forEach(function(u) { 1010 g.parent(u, inputGraph.parent(u)); 1011 }); 1012 } 1013 1014 inputGraph.eachEdge(function(e, u, v, value) { 1015 if (value === undefined) value = {}; 1016 var newValue = { 1017 e: e, 1018 minLen: value.minLen || 1, 1019 width: value.width || 0, 1020 height: value.height || 0, 1021 points: [] 1022 }; 1023 1024 g.addEdge(null, u, v, newValue); 1025 }); 1026 1027 // Initial graph attributes 1028 var graphValue = inputGraph.graph() || {}; 1029 g.graph({ 1030 rankDir: graphValue.rankDir || config.rankDir, 1031 orderRestarts: graphValue.orderRestarts 1032 }); 1033 1034 return g; 1035 } 1036 1037 function run(inputGraph) { 1038 var rankSep = self.rankSep(); 1039 var g; 1040 try { 1041 // Build internal graph 1042 g = util.time('initLayoutGraph', initLayoutGraph)(inputGraph); 1043 1044 if (g.order() === 0) { 1045 return g; 1046 } 1047 1048 // Make space for edge labels 1049 g.eachEdge(function(e, s, t, a) { 1050 a.minLen *= 2; 1051 }); 1052 self.rankSep(rankSep / 2); 1053 1054 // Determine the rank for each node. Nodes with a lower rank will appear 1055 // above nodes of higher rank. 1056 util.time('rank.run', rank.run)(g, config.rankSimplex); 1057 1058 // Normalize the graph by ensuring that every edge is proper (each edge has 1059 // a length of 1). We achieve this by adding dummy nodes to long edges, 1060 // thus shortening them. 1061 util.time('normalize', normalize)(g); 1062 1063 // Order the nodes so that edge crossings are minimized. 1064 util.time('order', order)(g, config.orderMaxSweeps); 1065 1066 // Find the x and y coordinates for every node in the graph. 1067 util.time('position', position.run)(g); 1068 1069 // De-normalize the graph by removing dummy nodes and augmenting the 1070 // original long edges with coordinate information. 1071 util.time('undoNormalize', undoNormalize)(g); 1072 1073 // Reverses points for edges that are in a reversed state. 1074 util.time('fixupEdgePoints', fixupEdgePoints)(g); 1075 1076 // Restore delete edges and reverse edges that were reversed in the rank 1077 // phase. 1078 util.time('rank.restoreEdges', rank.restoreEdges)(g); 1079 1080 // Construct final result graph and return it 1081 return util.time('createFinalGraph', createFinalGraph)(g, inputGraph.isDirected()); 1082 } finally { 1083 self.rankSep(rankSep); 1084 } 1085 } 1086 1087 /* 1088 * This function is responsible for 'normalizing' the graph. The process of 1089 * normalization ensures that no edge in the graph has spans more than one 1090 * rank. To do this it inserts dummy nodes as needed and links them by adding 1091 * dummy edges. This function keeps enough information in the dummy nodes and 1092 * edges to ensure that the original graph can be reconstructed later. 1093 * 1094 * This method assumes that the input graph is cycle free. 1095 */ 1096 function normalize(g) { 1097 var dummyCount = 0; 1098 g.eachEdge(function(e, s, t, a) { 1099 var sourceRank = g.node(s).rank; 1100 var targetRank = g.node(t).rank; 1101 if (sourceRank + 1 < targetRank) { 1102 for (var u = s, rank = sourceRank + 1, i = 0; rank < targetRank; ++rank, ++i) { 1103 var v = '_D' + (++dummyCount); 1104 var node = { 1105 width: a.width, 1106 height: a.height, 1107 edge: { id: e, source: s, target: t, attrs: a }, 1108 rank: rank, 1109 dummy: true 1110 }; 1111 1112 // If this node represents a bend then we will use it as a control 1113 // point. For edges with 2 segments this will be the center dummy 1114 // node. For edges with more than two segments, this will be the 1115 // first and last dummy node. 1116 if (i === 0) node.index = 0; 1117 else if (rank + 1 === targetRank) node.index = 1; 1118 1119 g.addNode(v, node); 1120 g.addEdge(null, u, v, {}); 1121 u = v; 1122 } 1123 g.addEdge(null, u, t, {}); 1124 g.delEdge(e); 1125 } 1126 }); 1127 } 1128 1129 /* 1130 * Reconstructs the graph as it was before normalization. The positions of 1131 * dummy nodes are used to build an array of points for the original 'long' 1132 * edge. Dummy nodes and edges are removed. 1133 */ 1134 function undoNormalize(g) { 1135 g.eachNode(function(u, a) { 1136 if (a.dummy) { 1137 if ('index' in a) { 1138 var edge = a.edge; 1139 if (!g.hasEdge(edge.id)) { 1140 g.addEdge(edge.id, edge.source, edge.target, edge.attrs); 1141 } 1142 var points = g.edge(edge.id).points; 1143 points[a.index] = { x: a.x, y: a.y, ul: a.ul, ur: a.ur, dl: a.dl, dr: a.dr }; 1144 } 1145 g.delNode(u); 1146 } 1147 }); 1148 } 1149 1150 /* 1151 * For each edge that was reversed during the `acyclic` step, reverse its 1152 * array of points. 1153 */ 1154 function fixupEdgePoints(g) { 1155 g.eachEdge(function(e, s, t, a) { if (a.reversed) a.points.reverse(); }); 1156 } 1157 1158 function createFinalGraph(g, isDirected) { 1159 var out = isDirected ? new CDigraph() : new CGraph(); 1160 out.graph(g.graph()); 1161 g.eachNode(function(u, value) { out.addNode(u, value); }); 1162 g.eachNode(function(u) { out.parent(u, g.parent(u)); }); 1163 g.eachEdge(function(e, u, v, value) { 1164 out.addEdge(value.e, u, v, value); 1165 }); 1166 1167 // Attach bounding box information 1168 var maxX = 0, maxY = 0; 1169 g.eachNode(function(u, value) { 1170 if (!g.children(u).length) { 1171 maxX = Math.max(maxX, value.x + value.width / 2); 1172 maxY = Math.max(maxY, value.y + value.height / 2); 1173 } 1174 }); 1175 g.eachEdge(function(e, u, v, value) { 1176 var maxXPoints = Math.max.apply(Math, value.points.map(function(p) { return p.x; })); 1177 var maxYPoints = Math.max.apply(Math, value.points.map(function(p) { return p.y; })); 1178 maxX = Math.max(maxX, maxXPoints + value.width / 2); 1179 maxY = Math.max(maxY, maxYPoints + value.height / 2); 1180 }); 1181 out.graph().width = maxX; 1182 out.graph().height = maxY; 1183 1184 return out; 1185 } 1186 1187 /* 1188 * Given a function, a new function is returned that invokes the given 1189 * function. The return value from the function is always the `self` object. 1190 */ 1191 function delegateProperty(f) { 1192 return function() { 1193 if (!arguments.length) return f(); 1194 f.apply(null, arguments); 1195 return self; 1196 }; 1197 } 1198 }; 1199 1200 1201 },{"./order":13,"./position":18,"./rank":19,"./util":26,"graphlib":28}],13:[function(require,module,exports){ 1202 var util = require('./util'), 1203 crossCount = require('./order/crossCount'), 1204 initLayerGraphs = require('./order/initLayerGraphs'), 1205 initOrder = require('./order/initOrder'), 1206 sortLayer = require('./order/sortLayer'); 1207 1208 module.exports = order; 1209 1210 // The maximum number of sweeps to perform before finishing the order phase. 1211 var DEFAULT_MAX_SWEEPS = 24; 1212 order.DEFAULT_MAX_SWEEPS = DEFAULT_MAX_SWEEPS; 1213 1214 /* 1215 * Runs the order phase with the specified `graph, `maxSweeps`, and 1216 * `debugLevel`. If `maxSweeps` is not specified we use `DEFAULT_MAX_SWEEPS`. 1217 * If `debugLevel` is not set we assume 0. 1218 */ 1219 function order(g, maxSweeps) { 1220 if (arguments.length < 2) { 1221 maxSweeps = DEFAULT_MAX_SWEEPS; 1222 } 1223 1224 var restarts = g.graph().orderRestarts || 0; 1225 1226 var layerGraphs = initLayerGraphs(g); 1227 // TODO: remove this when we add back support for ordering clusters 1228 layerGraphs.forEach(function(lg) { 1229 lg = lg.filterNodes(function(u) { return !g.children(u).length; }); 1230 }); 1231 1232 var iters = 0, 1233 currentBestCC, 1234 allTimeBestCC = Number.MAX_VALUE, 1235 allTimeBest = {}; 1236 1237 function saveAllTimeBest() { 1238 g.eachNode(function(u, value) { allTimeBest[u] = value.order; }); 1239 } 1240 1241 for (var j = 0; j < Number(restarts) + 1 && allTimeBestCC !== 0; ++j) { 1242 currentBestCC = Number.MAX_VALUE; 1243 initOrder(g, restarts > 0); 1244 1245 util.log(2, 'Order phase start cross count: ' + g.graph().orderInitCC); 1246 1247 var i, lastBest, cc; 1248 for (i = 0, lastBest = 0; lastBest < 4 && i < maxSweeps && currentBestCC > 0; ++i, ++lastBest, ++iters) { 1249 sweep(g, layerGraphs, i); 1250 cc = crossCount(g); 1251 if (cc < currentBestCC) { 1252 lastBest = 0; 1253 currentBestCC = cc; 1254 if (cc < allTimeBestCC) { 1255 saveAllTimeBest(); 1256 allTimeBestCC = cc; 1257 } 1258 } 1259 util.log(3, 'Order phase start ' + j + ' iter ' + i + ' cross count: ' + cc); 1260 } 1261 } 1262 1263 Object.keys(allTimeBest).forEach(function(u) { 1264 if (!g.children || !g.children(u).length) { 1265 g.node(u).order = allTimeBest[u]; 1266 } 1267 }); 1268 g.graph().orderCC = allTimeBestCC; 1269 1270 util.log(2, 'Order iterations: ' + iters); 1271 util.log(2, 'Order phase best cross count: ' + g.graph().orderCC); 1272 } 1273 1274 function predecessorWeights(g, nodes) { 1275 var weights = {}; 1276 nodes.forEach(function(u) { 1277 weights[u] = g.inEdges(u).map(function(e) { 1278 return g.node(g.source(e)).order; 1279 }); 1280 }); 1281 return weights; 1282 } 1283 1284 function successorWeights(g, nodes) { 1285 var weights = {}; 1286 nodes.forEach(function(u) { 1287 weights[u] = g.outEdges(u).map(function(e) { 1288 return g.node(g.target(e)).order; 1289 }); 1290 }); 1291 return weights; 1292 } 1293 1294 function sweep(g, layerGraphs, iter) { 1295 if (iter % 2 === 0) { 1296 sweepDown(g, layerGraphs, iter); 1297 } else { 1298 sweepUp(g, layerGraphs, iter); 1299 } 1300 } 1301 1302 function sweepDown(g, layerGraphs) { 1303 var cg; 1304 for (i = 1; i < layerGraphs.length; ++i) { 1305 cg = sortLayer(layerGraphs[i], cg, predecessorWeights(g, layerGraphs[i].nodes())); 1306 } 1307 } 1308 1309 function sweepUp(g, layerGraphs) { 1310 var cg; 1311 for (i = layerGraphs.length - 2; i >= 0; --i) { 1312 sortLayer(layerGraphs[i], cg, successorWeights(g, layerGraphs[i].nodes())); 1313 } 1314 } 1315 1316 },{"./order/crossCount":14,"./order/initLayerGraphs":15,"./order/initOrder":16,"./order/sortLayer":17,"./util":26}],14:[function(require,module,exports){ 1317 var util = require('../util'); 1318 1319 module.exports = crossCount; 1320 1321 /* 1322 * Returns the cross count for the given graph. 1323 */ 1324 function crossCount(g) { 1325 var cc = 0; 1326 var ordering = util.ordering(g); 1327 for (var i = 1; i < ordering.length; ++i) { 1328 cc += twoLayerCrossCount(g, ordering[i-1], ordering[i]); 1329 } 1330 return cc; 1331 } 1332 1333 /* 1334 * This function searches through a ranked and ordered graph and counts the 1335 * number of edges that cross. This algorithm is derived from: 1336 * 1337 * W. Barth et al., Bilayer Cross Counting, JGAA, 8(2) 179–194 (2004) 1338 */ 1339 function twoLayerCrossCount(g, layer1, layer2) { 1340 var indices = []; 1341 layer1.forEach(function(u) { 1342 var nodeIndices = []; 1343 g.outEdges(u).forEach(function(e) { nodeIndices.push(g.node(g.target(e)).order); }); 1344 nodeIndices.sort(function(x, y) { return x - y; }); 1345 indices = indices.concat(nodeIndices); 1346 }); 1347 1348 var firstIndex = 1; 1349 while (firstIndex < layer2.length) firstIndex <<= 1; 1350 1351 var treeSize = 2 * firstIndex - 1; 1352 firstIndex -= 1; 1353 1354 var tree = []; 1355 for (var i = 0; i < treeSize; ++i) { tree[i] = 0; } 1356 1357 var cc = 0; 1358 indices.forEach(function(i) { 1359 var treeIndex = i + firstIndex; 1360 ++tree[treeIndex]; 1361 while (treeIndex > 0) { 1362 if (treeIndex % 2) { 1363 cc += tree[treeIndex + 1]; 1364 } 1365 treeIndex = (treeIndex - 1) >> 1; 1366 ++tree[treeIndex]; 1367 } 1368 }); 1369 1370 return cc; 1371 } 1372 1373 },{"../util":26}],15:[function(require,module,exports){ 1374 var nodesFromList = require('graphlib').filter.nodesFromList, 1375 /* jshint -W079 */ 1376 Set = require('cp-data').Set; 1377 1378 module.exports = initLayerGraphs; 1379 1380 /* 1381 * This function takes a compound layered graph, g, and produces an array of 1382 * layer graphs. Each entry in the array represents a subgraph of nodes 1383 * relevant for performing crossing reduction on that layer. 1384 */ 1385 function initLayerGraphs(g) { 1386 var ranks = []; 1387 1388 function dfs(u) { 1389 if (u === null) { 1390 g.children(u).forEach(function(v) { dfs(v); }); 1391 return; 1392 } 1393 1394 var value = g.node(u); 1395 value.minRank = ('rank' in value) ? value.rank : Number.MAX_VALUE; 1396 value.maxRank = ('rank' in value) ? value.rank : Number.MIN_VALUE; 1397 var uRanks = new Set(); 1398 g.children(u).forEach(function(v) { 1399 var rs = dfs(v); 1400 uRanks = Set.union([uRanks, rs]); 1401 value.minRank = Math.min(value.minRank, g.node(v).minRank); 1402 value.maxRank = Math.max(value.maxRank, g.node(v).maxRank); 1403 }); 1404 1405 if ('rank' in value) uRanks.add(value.rank); 1406 1407 uRanks.keys().forEach(function(r) { 1408 if (!(r in ranks)) ranks[r] = []; 1409 ranks[r].push(u); 1410 }); 1411 1412 return uRanks; 1413 } 1414 dfs(null); 1415 1416 var layerGraphs = []; 1417 ranks.forEach(function(us, rank) { 1418 layerGraphs[rank] = g.filterNodes(nodesFromList(us)); 1419 }); 1420 1421 return layerGraphs; 1422 } 1423 1424 },{"cp-data":5,"graphlib":28}],16:[function(require,module,exports){ 1425 var crossCount = require('./crossCount'), 1426 util = require('../util'); 1427 1428 module.exports = initOrder; 1429 1430 /* 1431 * Given a graph with a set of layered nodes (i.e. nodes that have a `rank` 1432 * attribute) this function attaches an `order` attribute that uniquely 1433 * arranges each node of each rank. If no constraint graph is provided the 1434 * order of the nodes in each rank is entirely arbitrary. 1435 */ 1436 function initOrder(g, random) { 1437 var layers = []; 1438 1439 g.eachNode(function(u, value) { 1440 var layer = layers[value.rank]; 1441 if (g.children && g.children(u).length > 0) return; 1442 if (!layer) { 1443 layer = layers[value.rank] = []; 1444 } 1445 layer.push(u); 1446 }); 1447 1448 layers.forEach(function(layer) { 1449 if (random) { 1450 util.shuffle(layer); 1451 } 1452 layer.forEach(function(u, i) { 1453 g.node(u).order = i; 1454 }); 1455 }); 1456 1457 var cc = crossCount(g); 1458 g.graph().orderInitCC = cc; 1459 g.graph().orderCC = Number.MAX_VALUE; 1460 } 1461 1462 },{"../util":26,"./crossCount":14}],17:[function(require,module,exports){ 1463 var util = require('../util'); 1464 /* 1465 Digraph = require('graphlib').Digraph, 1466 topsort = require('graphlib').alg.topsort, 1467 nodesFromList = require('graphlib').filter.nodesFromList; 1468 */ 1469 1470 module.exports = sortLayer; 1471 1472 /* 1473 function sortLayer(g, cg, weights) { 1474 var result = sortLayerSubgraph(g, null, cg, weights); 1475 result.list.forEach(function(u, i) { 1476 g.node(u).order = i; 1477 }); 1478 return result.constraintGraph; 1479 } 1480 */ 1481 1482 function sortLayer(g, cg, weights) { 1483 var ordering = []; 1484 var bs = {}; 1485 g.eachNode(function(u, value) { 1486 ordering[value.order] = u; 1487 var ws = weights[u]; 1488 if (ws.length) { 1489 bs[u] = util.sum(ws) / ws.length; 1490 } 1491 }); 1492 1493 var toSort = g.nodes().filter(function(u) { return bs[u] !== undefined; }); 1494 toSort.sort(function(x, y) { 1495 return bs[x] - bs[y] || g.node(x).order - g.node(y).order; 1496 }); 1497 1498 for (var i = 0, j = 0, jl = toSort.length; j < jl; ++i) { 1499 if (bs[ordering[i]] !== undefined) { 1500 g.node(toSort[j++]).order = i; 1501 } 1502 } 1503 } 1504 1505 // TOOD: re-enable constrained sorting once we have a strategy for handling 1506 // undefined barycenters. 1507 /* 1508 function sortLayerSubgraph(g, sg, cg, weights) { 1509 cg = cg ? cg.filterNodes(nodesFromList(g.children(sg))) : new Digraph(); 1510 1511 var nodeData = {}; 1512 g.children(sg).forEach(function(u) { 1513 if (g.children(u).length) { 1514 nodeData[u] = sortLayerSubgraph(g, u, cg, weights); 1515 nodeData[u].firstSG = u; 1516 nodeData[u].lastSG = u; 1517 } else { 1518 var ws = weights[u]; 1519 nodeData[u] = { 1520 degree: ws.length, 1521 barycenter: ws.length > 0 ? util.sum(ws) / ws.length : 0, 1522 list: [u] 1523 }; 1524 } 1525 }); 1526 1527 resolveViolatedConstraints(g, cg, nodeData); 1528 1529 var keys = Object.keys(nodeData); 1530 keys.sort(function(x, y) { 1531 return nodeData[x].barycenter - nodeData[y].barycenter; 1532 }); 1533 1534 var result = keys.map(function(u) { return nodeData[u]; }) 1535 .reduce(function(lhs, rhs) { return mergeNodeData(g, lhs, rhs); }); 1536 return result; 1537 } 1538 1539 /* 1540 function mergeNodeData(g, lhs, rhs) { 1541 var cg = mergeDigraphs(lhs.constraintGraph, rhs.constraintGraph); 1542 1543 if (lhs.lastSG !== undefined && rhs.firstSG !== undefined) { 1544 if (cg === undefined) { 1545 cg = new Digraph(); 1546 } 1547 if (!cg.hasNode(lhs.lastSG)) { cg.addNode(lhs.lastSG); } 1548 cg.addNode(rhs.firstSG); 1549 cg.addEdge(null, lhs.lastSG, rhs.firstSG); 1550 } 1551 1552 return { 1553 degree: lhs.degree + rhs.degree, 1554 barycenter: (lhs.barycenter * lhs.degree + rhs.barycenter * rhs.degree) / 1555 (lhs.degree + rhs.degree), 1556 list: lhs.list.concat(rhs.list), 1557 firstSG: lhs.firstSG !== undefined ? lhs.firstSG : rhs.firstSG, 1558 lastSG: rhs.lastSG !== undefined ? rhs.lastSG : lhs.lastSG, 1559 constraintGraph: cg 1560 }; 1561 } 1562 1563 function mergeDigraphs(lhs, rhs) { 1564 if (lhs === undefined) return rhs; 1565 if (rhs === undefined) return lhs; 1566 1567 lhs = lhs.copy(); 1568 rhs.nodes().forEach(function(u) { lhs.addNode(u); }); 1569 rhs.edges().forEach(function(e, u, v) { lhs.addEdge(null, u, v); }); 1570 return lhs; 1571 } 1572 1573 function resolveViolatedConstraints(g, cg, nodeData) { 1574 // Removes nodes `u` and `v` from `cg` and makes any edges incident on them 1575 // incident on `w` instead. 1576 function collapseNodes(u, v, w) { 1577 // TODO original paper removes self loops, but it is not obvious when this would happen 1578 cg.inEdges(u).forEach(function(e) { 1579 cg.delEdge(e); 1580 cg.addEdge(null, cg.source(e), w); 1581 }); 1582 1583 cg.outEdges(v).forEach(function(e) { 1584 cg.delEdge(e); 1585 cg.addEdge(null, w, cg.target(e)); 1586 }); 1587 1588 cg.delNode(u); 1589 cg.delNode(v); 1590 } 1591 1592 var violated; 1593 while ((violated = findViolatedConstraint(cg, nodeData)) !== undefined) { 1594 var source = cg.source(violated), 1595 target = cg.target(violated); 1596 1597 var v; 1598 while ((v = cg.addNode(null)) && g.hasNode(v)) { 1599 cg.delNode(v); 1600 } 1601 1602 // Collapse barycenter and list 1603 nodeData[v] = mergeNodeData(g, nodeData[source], nodeData[target]); 1604 delete nodeData[source]; 1605 delete nodeData[target]; 1606 1607 collapseNodes(source, target, v); 1608 if (cg.incidentEdges(v).length === 0) { cg.delNode(v); } 1609 } 1610 } 1611 1612 function findViolatedConstraint(cg, nodeData) { 1613 var us = topsort(cg); 1614 for (var i = 0; i < us.length; ++i) { 1615 var u = us[i]; 1616 var inEdges = cg.inEdges(u); 1617 for (var j = 0; j < inEdges.length; ++j) { 1618 var e = inEdges[j]; 1619 if (nodeData[cg.source(e)].barycenter >= nodeData[u].barycenter) { 1620 return e; 1621 } 1622 } 1623 } 1624 } 1625 */ 1626 1627 },{"../util":26}],18:[function(require,module,exports){ 1628 var util = require('./util'); 1629 1630 /* 1631 * The algorithms here are based on Brandes and Köpf, "Fast and Simple 1632 * Horizontal Coordinate Assignment". 1633 */ 1634 module.exports = function() { 1635 // External configuration 1636 var config = { 1637 nodeSep: 50, 1638 edgeSep: 10, 1639 universalSep: null, 1640 rankSep: 30 1641 }; 1642 1643 var self = {}; 1644 1645 self.nodeSep = util.propertyAccessor(self, config, 'nodeSep'); 1646 self.edgeSep = util.propertyAccessor(self, config, 'edgeSep'); 1647 // If not null this separation value is used for all nodes and edges 1648 // regardless of their widths. `nodeSep` and `edgeSep` are ignored with this 1649 // option. 1650 self.universalSep = util.propertyAccessor(self, config, 'universalSep'); 1651 self.rankSep = util.propertyAccessor(self, config, 'rankSep'); 1652 self.debugLevel = util.propertyAccessor(self, config, 'debugLevel'); 1653 1654 self.run = run; 1655 1656 return self; 1657 1658 function run(g) { 1659 g = g.filterNodes(util.filterNonSubgraphs(g)); 1660 1661 var layering = util.ordering(g); 1662 1663 var conflicts = findConflicts(g, layering); 1664 1665 var xss = {}; 1666 ['u', 'd'].forEach(function(vertDir) { 1667 if (vertDir === 'd') layering.reverse(); 1668 1669 ['l', 'r'].forEach(function(horizDir) { 1670 if (horizDir === 'r') reverseInnerOrder(layering); 1671 1672 var dir = vertDir + horizDir; 1673 var align = verticalAlignment(g, layering, conflicts, vertDir === 'u' ? 'predecessors' : 'successors'); 1674 xss[dir]= horizontalCompaction(g, layering, align.pos, align.root, align.align); 1675 1676 if (config.debugLevel >= 3) 1677 debugPositioning(vertDir + horizDir, g, layering, xss[dir]); 1678 1679 if (horizDir === 'r') flipHorizontally(xss[dir]); 1680 1681 if (horizDir === 'r') reverseInnerOrder(layering); 1682 }); 1683 1684 if (vertDir === 'd') layering.reverse(); 1685 }); 1686 1687 balance(g, layering, xss); 1688 1689 g.eachNode(function(v) { 1690 var xs = []; 1691 for (var alignment in xss) { 1692 var alignmentX = xss[alignment][v]; 1693 posXDebug(alignment, g, v, alignmentX); 1694 xs.push(alignmentX); 1695 } 1696 xs.sort(function(x, y) { return x - y; }); 1697 posX(g, v, (xs[1] + xs[2]) / 2); 1698 }); 1699 1700 // Align y coordinates with ranks 1701 var y = 0, reverseY = g.graph().rankDir === 'BT' || g.graph().rankDir === 'RL'; 1702 layering.forEach(function(layer) { 1703 var maxHeight = util.max(layer.map(function(u) { return height(g, u); })); 1704 y += maxHeight / 2; 1705 layer.forEach(function(u) { 1706 posY(g, u, reverseY ? -y : y); 1707 }); 1708 y += maxHeight / 2 + config.rankSep; 1709 }); 1710 1711 // Translate layout so that top left corner of bounding rectangle has 1712 // coordinate (0, 0). 1713 var minX = util.min(g.nodes().map(function(u) { return posX(g, u) - width(g, u) / 2; })); 1714 var minY = util.min(g.nodes().map(function(u) { return posY(g, u) - height(g, u) / 2; })); 1715 g.eachNode(function(u) { 1716 posX(g, u, posX(g, u) - minX); 1717 posY(g, u, posY(g, u) - minY); 1718 }); 1719 } 1720 1721 /* 1722 * Generate an ID that can be used to represent any undirected edge that is 1723 * incident on `u` and `v`. 1724 */ 1725 function undirEdgeId(u, v) { 1726 return u < v 1727 ? u.toString().length + ':' + u + '-' + v 1728 : v.toString().length + ':' + v + '-' + u; 1729 } 1730 1731 function findConflicts(g, layering) { 1732 var conflicts = {}, // Set of conflicting edge ids 1733 pos = {}, // Position of node in its layer 1734 prevLayer, 1735 currLayer, 1736 k0, // Position of the last inner segment in the previous layer 1737 l, // Current position in the current layer (for iteration up to `l1`) 1738 k1; // Position of the next inner segment in the previous layer or 1739 // the position of the last element in the previous layer 1740 1741 if (layering.length <= 2) return conflicts; 1742 1743 function updateConflicts(v) { 1744 var k = pos[v]; 1745 if (k < k0 || k > k1) { 1746 conflicts[undirEdgeId(currLayer[l], v)] = true; 1747 } 1748 } 1749 1750 layering[1].forEach(function(u, i) { pos[u] = i; }); 1751 for (var i = 1; i < layering.length - 1; ++i) { 1752 prevLayer = layering[i]; 1753 currLayer = layering[i+1]; 1754 k0 = 0; 1755 l = 0; 1756 1757 // Scan current layer for next node that is incident to an inner segement 1758 // between layering[i+1] and layering[i]. 1759 for (var l1 = 0; l1 < currLayer.length; ++l1) { 1760 var u = currLayer[l1]; // Next inner segment in the current layer or 1761 // last node in the current layer 1762 pos[u] = l1; 1763 k1 = undefined; 1764 1765 if (g.node(u).dummy) { 1766 var uPred = g.predecessors(u)[0]; 1767 // Note: In the case of self loops and sideways edges it is possible 1768 // for a dummy not to have a predecessor. 1769 if (uPred !== undefined && g.node(uPred).dummy) 1770 k1 = pos[uPred]; 1771 } 1772 if (k1 === undefined && l1 === currLayer.length - 1) 1773 k1 = prevLayer.length - 1; 1774 1775 if (k1 !== undefined) { 1776 for (; l <= l1; ++l) { 1777 g.predecessors(currLayer[l]).forEach(updateConflicts); 1778 } 1779 k0 = k1; 1780 } 1781 } 1782 } 1783 1784 return conflicts; 1785 } 1786 1787 function verticalAlignment(g, layering, conflicts, relationship) { 1788 var pos = {}, // Position for a node in its layer 1789 root = {}, // Root of the block that the node participates in 1790 align = {}; // Points to the next node in the block or, if the last 1791 // element in the block, points to the first block's root 1792 1793 layering.forEach(function(layer) { 1794 layer.forEach(function(u, i) { 1795 root[u] = u; 1796 align[u] = u; 1797 pos[u] = i; 1798 }); 1799 }); 1800 1801 layering.forEach(function(layer) { 1802 var prevIdx = -1; 1803 layer.forEach(function(v) { 1804 var related = g[relationship](v), // Adjacent nodes from the previous layer 1805 mid; // The mid point in the related array 1806 1807 if (related.length > 0) { 1808 related.sort(function(x, y) { return pos[x] - pos[y]; }); 1809 mid = (related.length - 1) / 2; 1810 related.slice(Math.floor(mid), Math.ceil(mid) + 1).forEach(function(u) { 1811 if (align[v] === v) { 1812 if (!conflicts[undirEdgeId(u, v)] && prevIdx < pos[u]) { 1813 align[u] = v; 1814 align[v] = root[v] = root[u]; 1815 prevIdx = pos[u]; 1816 } 1817 } 1818 }); 1819 } 1820 }); 1821 }); 1822 1823 return { pos: pos, root: root, align: align }; 1824 } 1825 1826 // This function deviates from the standard BK algorithm in two ways. First 1827 // it takes into account the size of the nodes. Second it includes a fix to 1828 // the original algorithm that is described in Carstens, "Node and Label 1829 // Placement in a Layered Layout Algorithm". 1830 function horizontalCompaction(g, layering, pos, root, align) { 1831 var sink = {}, // Mapping of node id -> sink node id for class 1832 maybeShift = {}, // Mapping of sink node id -> { class node id, min shift } 1833 shift = {}, // Mapping of sink node id -> shift 1834 pred = {}, // Mapping of node id -> predecessor node (or null) 1835 xs = {}; // Calculated X positions 1836 1837 layering.forEach(function(layer) { 1838 layer.forEach(function(u, i) { 1839 sink[u] = u; 1840 maybeShift[u] = {}; 1841 if (i > 0) 1842 pred[u] = layer[i - 1]; 1843 }); 1844 }); 1845 1846 function updateShift(toShift, neighbor, delta) { 1847 if (!(neighbor in maybeShift[toShift])) { 1848 maybeShift[toShift][neighbor] = delta; 1849 } else { 1850 maybeShift[toShift][neighbor] = Math.min(maybeShift[toShift][neighbor], delta); 1851 } 1852 } 1853 1854 function placeBlock(v) { 1855 if (!(v in xs)) { 1856 xs[v] = 0; 1857 var w = v; 1858 do { 1859 if (pos[w] > 0) { 1860 var u = root[pred[w]]; 1861 placeBlock(u); 1862 if (sink[v] === v) { 1863 sink[v] = sink[u]; 1864 } 1865 var delta = sep(g, pred[w]) + sep(g, w); 1866 if (sink[v] !== sink[u]) { 1867 updateShift(sink[u], sink[v], xs[v] - xs[u] - delta); 1868 } else { 1869 xs[v] = Math.max(xs[v], xs[u] + delta); 1870 } 1871 } 1872 w = align[w]; 1873 } while (w !== v); 1874 } 1875 } 1876 1877 // Root coordinates relative to sink 1878 util.values(root).forEach(function(v) { 1879 placeBlock(v); 1880 }); 1881 1882 // Absolute coordinates 1883 // There is an assumption here that we've resolved shifts for any classes 1884 // that begin at an earlier layer. We guarantee this by visiting layers in 1885 // order. 1886 layering.forEach(function(layer) { 1887 layer.forEach(function(v) { 1888 xs[v] = xs[root[v]]; 1889 if (v === root[v] && v === sink[v]) { 1890 var minShift = 0; 1891 if (v in maybeShift && Object.keys(maybeShift[v]).length > 0) { 1892 minShift = util.min(Object.keys(maybeShift[v]) 1893 .map(function(u) { 1894 return maybeShift[v][u] + (u in shift ? shift[u] : 0); 1895 } 1896 )); 1897 } 1898 shift[v] = minShift; 1899 } 1900 }); 1901 }); 1902 1903 layering.forEach(function(layer) { 1904 layer.forEach(function(v) { 1905 xs[v] += shift[sink[root[v]]] || 0; 1906 }); 1907 }); 1908 1909 return xs; 1910 } 1911 1912 function findMinCoord(g, layering, xs) { 1913 return util.min(layering.map(function(layer) { 1914 var u = layer[0]; 1915 return xs[u]; 1916 })); 1917 } 1918 1919 function findMaxCoord(g, layering, xs) { 1920 return util.max(layering.map(function(layer) { 1921 var u = layer[layer.length - 1]; 1922 return xs[u]; 1923 })); 1924 } 1925 1926 function balance(g, layering, xss) { 1927 var min = {}, // Min coordinate for the alignment 1928 max = {}, // Max coordinate for the alginment 1929 smallestAlignment, 1930 shift = {}; // Amount to shift a given alignment 1931 1932 function updateAlignment(v) { 1933 xss[alignment][v] += shift[alignment]; 1934 } 1935 1936 var smallest = Number.POSITIVE_INFINITY; 1937 for (var alignment in xss) { 1938 var xs = xss[alignment]; 1939 min[alignment] = findMinCoord(g, layering, xs); 1940 max[alignment] = findMaxCoord(g, layering, xs); 1941 var w = max[alignment] - min[alignment]; 1942 if (w < smallest) { 1943 smallest = w; 1944 smallestAlignment = alignment; 1945 } 1946 } 1947 1948 // Determine how much to adjust positioning for each alignment 1949 ['u', 'd'].forEach(function(vertDir) { 1950 ['l', 'r'].forEach(function(horizDir) { 1951 var alignment = vertDir + horizDir; 1952 shift[alignment] = horizDir === 'l' 1953 ? min[smallestAlignment] - min[alignment] 1954 : max[smallestAlignment] - max[alignment]; 1955 }); 1956 }); 1957 1958 // Find average of medians for xss array 1959 for (alignment in xss) { 1960 g.eachNode(updateAlignment); 1961 } 1962 } 1963 1964 function flipHorizontally(xs) { 1965 for (var u in xs) { 1966 xs[u] = -xs[u]; 1967 } 1968 } 1969 1970 function reverseInnerOrder(layering) { 1971 layering.forEach(function(layer) { 1972 layer.reverse(); 1973 }); 1974 } 1975 1976 function width(g, u) { 1977 switch (g.graph().rankDir) { 1978 case 'LR': return g.node(u).height; 1979 case 'RL': return g.node(u).height; 1980 default: return g.node(u).width; 1981 } 1982 } 1983 1984 function height(g, u) { 1985 switch(g.graph().rankDir) { 1986 case 'LR': return g.node(u).width; 1987 case 'RL': return g.node(u).width; 1988 default: return g.node(u).height; 1989 } 1990 } 1991 1992 function sep(g, u) { 1993 if (config.universalSep !== null) { 1994 return config.universalSep; 1995 } 1996 var w = width(g, u); 1997 var s = g.node(u).dummy ? config.edgeSep : config.nodeSep; 1998 return (w + s) / 2; 1999 } 2000 2001 function posX(g, u, x) { 2002 if (g.graph().rankDir === 'LR' || g.graph().rankDir === 'RL') { 2003 if (arguments.length < 3) { 2004 return g.node(u).y; 2005 } else { 2006 g.node(u).y = x; 2007 } 2008 } else { 2009 if (arguments.length < 3) { 2010 return g.node(u).x; 2011 } else { 2012 g.node(u).x = x; 2013 } 2014 } 2015 } 2016 2017 function posXDebug(name, g, u, x) { 2018 if (g.graph().rankDir === 'LR' || g.graph().rankDir === 'RL') { 2019 if (arguments.length < 3) { 2020 return g.node(u)[name]; 2021 } else { 2022 g.node(u)[name] = x; 2023 } 2024 } else { 2025 if (arguments.length < 3) { 2026 return g.node(u)[name]; 2027 } else { 2028 g.node(u)[name] = x; 2029 } 2030 } 2031 } 2032 2033 function posY(g, u, y) { 2034 if (g.graph().rankDir === 'LR' || g.graph().rankDir === 'RL') { 2035 if (arguments.length < 3) { 2036 return g.node(u).x; 2037 } else { 2038 g.node(u).x = y; 2039 } 2040 } else { 2041 if (arguments.length < 3) { 2042 return g.node(u).y; 2043 } else { 2044 g.node(u).y = y; 2045 } 2046 } 2047 } 2048 2049 function debugPositioning(align, g, layering, xs) { 2050 layering.forEach(function(l, li) { 2051 var u, xU; 2052 l.forEach(function(v) { 2053 var xV = xs[v]; 2054 if (u) { 2055 var s = sep(g, u) + sep(g, v); 2056 if (xV - xU < s) 2057 console.log('Position phase: sep violation. Align: ' + align + '. Layer: ' + li + '. ' + 2058 'U: ' + u + ' V: ' + v + '. Actual sep: ' + (xV - xU) + ' Expected sep: ' + s); 2059 } 2060 u = v; 2061 xU = xV; 2062 }); 2063 }); 2064 } 2065 }; 2066 2067 },{"./util":26}],19:[function(require,module,exports){ 2068 var util = require('./util'), 2069 acyclic = require('./rank/acyclic'), 2070 initRank = require('./rank/initRank'), 2071 feasibleTree = require('./rank/feasibleTree'), 2072 constraints = require('./rank/constraints'), 2073 simplex = require('./rank/simplex'), 2074 components = require('graphlib').alg.components, 2075 filter = require('graphlib').filter; 2076 2077 exports.run = run; 2078 exports.restoreEdges = restoreEdges; 2079 2080 /* 2081 * Heuristic function that assigns a rank to each node of the input graph with 2082 * the intent of minimizing edge lengths, while respecting the `minLen` 2083 * attribute of incident edges. 2084 * 2085 * Prerequisites: 2086 * 2087 * * Each edge in the input graph must have an assigned 'minLen' attribute 2088 */ 2089 function run(g, useSimplex) { 2090 expandSelfLoops(g); 2091 2092 // If there are rank constraints on nodes, then build a new graph that 2093 // encodes the constraints. 2094 util.time('constraints.apply', constraints.apply)(g); 2095 2096 expandSidewaysEdges(g); 2097 2098 // Reverse edges to get an acyclic graph, we keep the graph in an acyclic 2099 // state until the very end. 2100 util.time('acyclic', acyclic)(g); 2101 2102 // Convert the graph into a flat graph for ranking 2103 var flatGraph = g.filterNodes(util.filterNonSubgraphs(g)); 2104 2105 // Assign an initial ranking using DFS. 2106 initRank(flatGraph); 2107 2108 // For each component improve the assigned ranks. 2109 components(flatGraph).forEach(function(cmpt) { 2110 var subgraph = flatGraph.filterNodes(filter.nodesFromList(cmpt)); 2111 rankComponent(subgraph, useSimplex); 2112 }); 2113 2114 // Relax original constraints 2115 util.time('constraints.relax', constraints.relax(g)); 2116 2117 // When handling nodes with constrained ranks it is possible to end up with 2118 // edges that point to previous ranks. Most of the subsequent algorithms assume 2119 // that edges are pointing to successive ranks only. Here we reverse any "back 2120 // edges" and mark them as such. The acyclic algorithm will reverse them as a 2121 // post processing step. 2122 util.time('reorientEdges', reorientEdges)(g); 2123 } 2124 2125 function restoreEdges(g) { 2126 acyclic.undo(g); 2127 } 2128 2129 /* 2130 * Expand self loops into three dummy nodes. One will sit above the incident 2131 * node, one will be at the same level, and one below. The result looks like: 2132 * 2133 * /--<--x--->--\ 2134 * node y 2135 * \--<--z--->--/ 2136 * 2137 * Dummy nodes x, y, z give us the shape of a loop and node y is where we place 2138 * the label. 2139 * 2140 * TODO: consolidate knowledge of dummy node construction. 2141 * TODO: support minLen = 2 2142 */ 2143 function expandSelfLoops(g) { 2144 g.eachEdge(function(e, u, v, a) { 2145 if (u === v) { 2146 var x = addDummyNode(g, e, u, v, a, 0, false), 2147 y = addDummyNode(g, e, u, v, a, 1, true), 2148 z = addDummyNode(g, e, u, v, a, 2, false); 2149 g.addEdge(null, x, u, {minLen: 1, selfLoop: true}); 2150 g.addEdge(null, x, y, {minLen: 1, selfLoop: true}); 2151 g.addEdge(null, u, z, {minLen: 1, selfLoop: true}); 2152 g.addEdge(null, y, z, {minLen: 1, selfLoop: true}); 2153 g.delEdge(e); 2154 } 2155 }); 2156 } 2157 2158 function expandSidewaysEdges(g) { 2159 g.eachEdge(function(e, u, v, a) { 2160 if (u === v) { 2161 var origEdge = a.originalEdge, 2162 dummy = addDummyNode(g, origEdge.e, origEdge.u, origEdge.v, origEdge.value, 0, true); 2163 g.addEdge(null, u, dummy, {minLen: 1}); 2164 g.addEdge(null, dummy, v, {minLen: 1}); 2165 g.delEdge(e); 2166 } 2167 }); 2168 } 2169 2170 function addDummyNode(g, e, u, v, a, index, isLabel) { 2171 return g.addNode(null, { 2172 width: isLabel ? a.width : 0, 2173 height: isLabel ? a.height : 0, 2174 edge: { id: e, source: u, target: v, attrs: a }, 2175 dummy: true, 2176 index: index 2177 }); 2178 } 2179 2180 function reorientEdges(g) { 2181 g.eachEdge(function(e, u, v, value) { 2182 if (g.node(u).rank > g.node(v).rank) { 2183 g.delEdge(e); 2184 value.reversed = true; 2185 g.addEdge(e, v, u, value); 2186 } 2187 }); 2188 } 2189 2190 function rankComponent(subgraph, useSimplex) { 2191 var spanningTree = feasibleTree(subgraph); 2192 2193 if (useSimplex) { 2194 util.log(1, 'Using network simplex for ranking'); 2195 simplex(subgraph, spanningTree); 2196 } 2197 normalize(subgraph); 2198 } 2199 2200 function normalize(g) { 2201 var m = util.min(g.nodes().map(function(u) { return g.node(u).rank; })); 2202 g.eachNode(function(u, node) { node.rank -= m; }); 2203 } 2204 2205 },{"./rank/acyclic":20,"./rank/constraints":21,"./rank/feasibleTree":22,"./rank/initRank":23,"./rank/simplex":25,"./util":26,"graphlib":28}],20:[function(require,module,exports){ 2206 var util = require('../util'); 2207 2208 module.exports = acyclic; 2209 module.exports.undo = undo; 2210 2211 /* 2212 * This function takes a directed graph that may have cycles and reverses edges 2213 * as appropriate to break these cycles. Each reversed edge is assigned a 2214 * `reversed` attribute with the value `true`. 2215 * 2216 * There should be no self loops in the graph. 2217 */ 2218 function acyclic(g) { 2219 var onStack = {}, 2220 visited = {}, 2221 reverseCount = 0; 2222 2223 function dfs(u) { 2224 if (u in visited) return; 2225 visited[u] = onStack[u] = true; 2226 g.outEdges(u).forEach(function(e) { 2227 var t = g.target(e), 2228 value; 2229 2230 if (u === t) { 2231 console.error('Warning: found self loop "' + e + '" for node "' + u + '"'); 2232 } else if (t in onStack) { 2233 value = g.edge(e); 2234 g.delEdge(e); 2235 value.reversed = true; 2236 ++reverseCount; 2237 g.addEdge(e, t, u, value); 2238 } else { 2239 dfs(t); 2240 } 2241 }); 2242 2243 delete onStack[u]; 2244 } 2245 2246 g.eachNode(function(u) { dfs(u); }); 2247 2248 util.log(2, 'Acyclic Phase: reversed ' + reverseCount + ' edge(s)'); 2249 2250 return reverseCount; 2251 } 2252 2253 /* 2254 * Given a graph that has had the acyclic operation applied, this function 2255 * undoes that operation. More specifically, any edge with the `reversed` 2256 * attribute is again reversed to restore the original direction of the edge. 2257 */ 2258 function undo(g) { 2259 g.eachEdge(function(e, s, t, a) { 2260 if (a.reversed) { 2261 delete a.reversed; 2262 g.delEdge(e); 2263 g.addEdge(e, t, s, a); 2264 } 2265 }); 2266 } 2267 2268 },{"../util":26}],21:[function(require,module,exports){ 2269 exports.apply = function(g) { 2270 function dfs(sg) { 2271 var rankSets = {}; 2272 g.children(sg).forEach(function(u) { 2273 if (g.children(u).length) { 2274 dfs(u); 2275 return; 2276 } 2277 2278 var value = g.node(u), 2279 prefRank = value.prefRank; 2280 if (prefRank !== undefined) { 2281 if (!checkSupportedPrefRank(prefRank)) { return; } 2282 2283 if (!(prefRank in rankSets)) { 2284 rankSets.prefRank = [u]; 2285 } else { 2286 rankSets.prefRank.push(u); 2287 } 2288 2289 var newU = rankSets[prefRank]; 2290 if (newU === undefined) { 2291 newU = rankSets[prefRank] = g.addNode(null, { originalNodes: [] }); 2292 g.parent(newU, sg); 2293 } 2294 2295 redirectInEdges(g, u, newU, prefRank === 'min'); 2296 redirectOutEdges(g, u, newU, prefRank === 'max'); 2297 2298 // Save original node and remove it from reduced graph 2299 g.node(newU).originalNodes.push({ u: u, value: value, parent: sg }); 2300 g.delNode(u); 2301 } 2302 }); 2303 2304 addLightEdgesFromMinNode(g, sg, rankSets.min); 2305 addLightEdgesToMaxNode(g, sg, rankSets.max); 2306 } 2307 2308 dfs(null); 2309 }; 2310 2311 function checkSupportedPrefRank(prefRank) { 2312 if (prefRank !== 'min' && prefRank !== 'max' && prefRank.indexOf('same_') !== 0) { 2313 console.error('Unsupported rank type: ' + prefRank); 2314 return false; 2315 } 2316 return true; 2317 } 2318 2319 function redirectInEdges(g, u, newU, reverse) { 2320 g.inEdges(u).forEach(function(e) { 2321 var origValue = g.edge(e), 2322 value; 2323 if (origValue.originalEdge) { 2324 value = origValue; 2325 } else { 2326 value = { 2327 originalEdge: { e: e, u: g.source(e), v: g.target(e), value: origValue }, 2328 minLen: g.edge(e).minLen 2329 }; 2330 } 2331 2332 // Do not reverse edges for self-loops. 2333 if (origValue.selfLoop) { 2334 reverse = false; 2335 } 2336 2337 if (reverse) { 2338 // Ensure that all edges to min are reversed 2339 g.addEdge(null, newU, g.source(e), value); 2340 value.reversed = true; 2341 } else { 2342 g.addEdge(null, g.source(e), newU, value); 2343 } 2344 }); 2345 } 2346 2347 function redirectOutEdges(g, u, newU, reverse) { 2348 g.outEdges(u).forEach(function(e) { 2349 var origValue = g.edge(e), 2350 value; 2351 if (origValue.originalEdge) { 2352 value = origValue; 2353 } else { 2354 value = { 2355 originalEdge: { e: e, u: g.source(e), v: g.target(e), value: origValue }, 2356 minLen: g.edge(e).minLen 2357 }; 2358 } 2359 2360 // Do not reverse edges for self-loops. 2361 if (origValue.selfLoop) { 2362 reverse = false; 2363 } 2364 2365 if (reverse) { 2366 // Ensure that all edges from max are reversed 2367 g.addEdge(null, g.target(e), newU, value); 2368 value.reversed = true; 2369 } else { 2370 g.addEdge(null, newU, g.target(e), value); 2371 } 2372 }); 2373 } 2374 2375 function addLightEdgesFromMinNode(g, sg, minNode) { 2376 if (minNode !== undefined) { 2377 g.children(sg).forEach(function(u) { 2378 // The dummy check ensures we don't add an edge if the node is involved 2379 // in a self loop or sideways edge. 2380 if (u !== minNode && !g.outEdges(minNode, u).length && !g.node(u).dummy) { 2381 g.addEdge(null, minNode, u, { minLen: 0 }); 2382 } 2383 }); 2384 } 2385 } 2386 2387 function addLightEdgesToMaxNode(g, sg, maxNode) { 2388 if (maxNode !== undefined) { 2389 g.children(sg).forEach(function(u) { 2390 // The dummy check ensures we don't add an edge if the node is involved 2391 // in a self loop or sideways edge. 2392 if (u !== maxNode && !g.outEdges(u, maxNode).length && !g.node(u).dummy) { 2393 g.addEdge(null, u, maxNode, { minLen: 0 }); 2394 } 2395 }); 2396 } 2397 } 2398 2399 /* 2400 * This function "relaxes" the constraints applied previously by the "apply" 2401 * function. It expands any nodes that were collapsed and assigns the rank of 2402 * the collapsed node to each of the expanded nodes. It also restores the 2403 * original edges and removes any dummy edges pointing at the collapsed nodes. 2404 * 2405 * Note that the process of removing collapsed nodes also removes dummy edges 2406 * automatically. 2407 */ 2408 exports.relax = function(g) { 2409 // Save original edges 2410 var originalEdges = []; 2411 g.eachEdge(function(e, u, v, value) { 2412 var originalEdge = value.originalEdge; 2413 if (originalEdge) { 2414 originalEdges.push(originalEdge); 2415 } 2416 }); 2417 2418 // Expand collapsed nodes 2419 g.eachNode(function(u, value) { 2420 var originalNodes = value.originalNodes; 2421 if (originalNodes) { 2422 originalNodes.forEach(function(originalNode) { 2423 originalNode.value.rank = value.rank; 2424 g.addNode(originalNode.u, originalNode.value); 2425 g.parent(originalNode.u, originalNode.parent); 2426 }); 2427 g.delNode(u); 2428 } 2429 }); 2430 2431 // Restore original edges 2432 originalEdges.forEach(function(edge) { 2433 g.addEdge(edge.e, edge.u, edge.v, edge.value); 2434 }); 2435 }; 2436 2437 },{}],22:[function(require,module,exports){ 2438 /* jshint -W079 */ 2439 var Set = require('cp-data').Set, 2440 /* jshint +W079 */ 2441 Digraph = require('graphlib').Digraph, 2442 util = require('../util'); 2443 2444 module.exports = feasibleTree; 2445 2446 /* 2447 * Given an acyclic graph with each node assigned a `rank` attribute, this 2448 * function constructs and returns a spanning tree. This function may reduce 2449 * the length of some edges from the initial rank assignment while maintaining 2450 * the `minLen` specified by each edge. 2451 * 2452 * Prerequisites: 2453 * 2454 * * The input graph is acyclic 2455 * * Each node in the input graph has an assigned `rank` attribute 2456 * * Each edge in the input graph has an assigned `minLen` attribute 2457 * 2458 * Outputs: 2459 * 2460 * A feasible spanning tree for the input graph (i.e. a spanning tree that 2461 * respects each graph edge's `minLen` attribute) represented as a Digraph with 2462 * a `root` attribute on graph. 2463 * 2464 * Nodes have the same id and value as that in the input graph. 2465 * 2466 * Edges in the tree have arbitrarily assigned ids. The attributes for edges 2467 * include `reversed`. `reversed` indicates that the edge is a 2468 * back edge in the input graph. 2469 */ 2470 function feasibleTree(g) { 2471 var remaining = new Set(g.nodes()), 2472 tree = new Digraph(); 2473 2474 if (remaining.size() === 1) { 2475 var root = g.nodes()[0]; 2476 tree.addNode(root, {}); 2477 tree.graph({ root: root }); 2478 return tree; 2479 } 2480 2481 function addTightEdges(v) { 2482 var continueToScan = true; 2483 g.predecessors(v).forEach(function(u) { 2484 if (remaining.has(u) && !slack(g, u, v)) { 2485 if (remaining.has(v)) { 2486 tree.addNode(v, {}); 2487 remaining.remove(v); 2488 tree.graph({ root: v }); 2489 } 2490 2491 tree.addNode(u, {}); 2492 tree.addEdge(null, u, v, { reversed: true }); 2493 remaining.remove(u); 2494 addTightEdges(u); 2495 continueToScan = false; 2496 } 2497 }); 2498 2499 g.successors(v).forEach(function(w) { 2500 if (remaining.has(w) && !slack(g, v, w)) { 2501 if (remaining.has(v)) { 2502 tree.addNode(v, {}); 2503 remaining.remove(v); 2504 tree.graph({ root: v }); 2505 } 2506 2507 tree.addNode(w, {}); 2508 tree.addEdge(null, v, w, {}); 2509 remaining.remove(w); 2510 addTightEdges(w); 2511 continueToScan = false; 2512 } 2513 }); 2514 return continueToScan; 2515 } 2516 2517 function createTightEdge() { 2518 var minSlack = Number.MAX_VALUE; 2519 remaining.keys().forEach(function(v) { 2520 g.predecessors(v).forEach(function(u) { 2521 if (!remaining.has(u)) { 2522 var edgeSlack = slack(g, u, v); 2523 if (Math.abs(edgeSlack) < Math.abs(minSlack)) { 2524 minSlack = -edgeSlack; 2525 } 2526 } 2527 }); 2528 2529 g.successors(v).forEach(function(w) { 2530 if (!remaining.has(w)) { 2531 var edgeSlack = slack(g, v, w); 2532 if (Math.abs(edgeSlack) < Math.abs(minSlack)) { 2533 minSlack = edgeSlack; 2534 } 2535 } 2536 }); 2537 }); 2538 2539 tree.eachNode(function(u) { g.node(u).rank -= minSlack; }); 2540 } 2541 2542 while (remaining.size()) { 2543 var nodesToSearch = !tree.order() ? remaining.keys() : tree.nodes(); 2544 for (var i = 0, il = nodesToSearch.length; 2545 i < il && addTightEdges(nodesToSearch[i]); 2546 ++i); 2547 if (remaining.size()) { 2548 createTightEdge(); 2549 } 2550 } 2551 2552 return tree; 2553 } 2554 2555 function slack(g, u, v) { 2556 var rankDiff = g.node(v).rank - g.node(u).rank; 2557 var maxMinLen = util.max(g.outEdges(u, v) 2558 .map(function(e) { return g.edge(e).minLen; })); 2559 return rankDiff - maxMinLen; 2560 } 2561 2562 },{"../util":26,"cp-data":5,"graphlib":28}],23:[function(require,module,exports){ 2563 var util = require('../util'), 2564 topsort = require('graphlib').alg.topsort; 2565 2566 module.exports = initRank; 2567 2568 /* 2569 * Assigns a `rank` attribute to each node in the input graph and ensures that 2570 * this rank respects the `minLen` attribute of incident edges. 2571 * 2572 * Prerequisites: 2573 * 2574 * * The input graph must be acyclic 2575 * * Each edge in the input graph must have an assigned 'minLen' attribute 2576 */ 2577 function initRank(g) { 2578 var sorted = topsort(g); 2579 2580 sorted.forEach(function(u) { 2581 var inEdges = g.inEdges(u); 2582 if (inEdges.length === 0) { 2583 g.node(u).rank = 0; 2584 return; 2585 } 2586 2587 var minLens = inEdges.map(function(e) { 2588 return g.node(g.source(e)).rank + g.edge(e).minLen; 2589 }); 2590 g.node(u).rank = util.max(minLens); 2591 }); 2592 } 2593 2594 },{"../util":26,"graphlib":28}],24:[function(require,module,exports){ 2595 module.exports = { 2596 slack: slack 2597 }; 2598 2599 /* 2600 * A helper to calculate the slack between two nodes (`u` and `v`) given a 2601 * `minLen` constraint. The slack represents how much the distance between `u` 2602 * and `v` could shrink while maintaining the `minLen` constraint. If the value 2603 * is negative then the constraint is currently violated. 2604 * 2605 This function requires that `u` and `v` are in `graph` and they both have a 2606 `rank` attribute. 2607 */ 2608 function slack(graph, u, v, minLen) { 2609 return Math.abs(graph.node(u).rank - graph.node(v).rank) - minLen; 2610 } 2611 2612 },{}],25:[function(require,module,exports){ 2613 var util = require('../util'), 2614 rankUtil = require('./rankUtil'); 2615 2616 module.exports = simplex; 2617 2618 function simplex(graph, spanningTree) { 2619 // The network simplex algorithm repeatedly replaces edges of 2620 // the spanning tree with negative cut values until no such 2621 // edge exists. 2622 initCutValues(graph, spanningTree); 2623 while (true) { 2624 var e = leaveEdge(spanningTree); 2625 if (e === null) break; 2626 var f = enterEdge(graph, spanningTree, e); 2627 exchange(graph, spanningTree, e, f); 2628 } 2629 } 2630 2631 /* 2632 * Set the cut values of edges in the spanning tree by a depth-first 2633 * postorder traversal. The cut value corresponds to the cost, in 2634 * terms of a ranking's edge length sum, of lengthening an edge. 2635 * Negative cut values typically indicate edges that would yield a 2636 * smaller edge length sum if they were lengthened. 2637 */ 2638 function initCutValues(graph, spanningTree) { 2639 computeLowLim(spanningTree); 2640 2641 spanningTree.eachEdge(function(id, u, v, treeValue) { 2642 treeValue.cutValue = 0; 2643 }); 2644 2645 // Propagate cut values up the tree. 2646 function dfs(n) { 2647 var children = spanningTree.successors(n); 2648 for (var c in children) { 2649 var child = children[c]; 2650 dfs(child); 2651 } 2652 if (n !== spanningTree.graph().root) { 2653 setCutValue(graph, spanningTree, n); 2654 } 2655 } 2656 dfs(spanningTree.graph().root); 2657 } 2658 2659 /* 2660 * Perform a DFS postorder traversal, labeling each node v with 2661 * its traversal order 'lim(v)' and the minimum traversal number 2662 * of any of its descendants 'low(v)'. This provides an efficient 2663 * way to test whether u is an ancestor of v since 2664 * low(u) <= lim(v) <= lim(u) if and only if u is an ancestor. 2665 */ 2666 function computeLowLim(tree) { 2667 var postOrderNum = 0; 2668 2669 function dfs(n) { 2670 var children = tree.successors(n); 2671 var low = postOrderNum; 2672 for (var c in children) { 2673 var child = children[c]; 2674 dfs(child); 2675 low = Math.min(low, tree.node(child).low); 2676 } 2677 tree.node(n).low = low; 2678 tree.node(n).lim = postOrderNum++; 2679 } 2680 2681 dfs(tree.graph().root); 2682 } 2683 2684 /* 2685 * To compute the cut value of the edge parent -> child, we consider 2686 * it and any other graph edges to or from the child. 2687 * parent 2688 * | 2689 * child 2690 * / \ 2691 * u v 2692 */ 2693 function setCutValue(graph, tree, child) { 2694 var parentEdge = tree.inEdges(child)[0]; 2695 2696 // List of child's children in the spanning tree. 2697 var grandchildren = []; 2698 var grandchildEdges = tree.outEdges(child); 2699 for (var gce in grandchildEdges) { 2700 grandchildren.push(tree.target(grandchildEdges[gce])); 2701 } 2702 2703 var cutValue = 0; 2704 2705 // TODO: Replace unit increment/decrement with edge weights. 2706 var E = 0; // Edges from child to grandchild's subtree. 2707 var F = 0; // Edges to child from grandchild's subtree. 2708 var G = 0; // Edges from child to nodes outside of child's subtree. 2709 var H = 0; // Edges from nodes outside of child's subtree to child. 2710 2711 // Consider all graph edges from child. 2712 var outEdges = graph.outEdges(child); 2713 var gc; 2714 for (var oe in outEdges) { 2715 var succ = graph.target(outEdges[oe]); 2716 for (gc in grandchildren) { 2717 if (inSubtree(tree, succ, grandchildren[gc])) { 2718 E++; 2719 } 2720 } 2721 if (!inSubtree(tree, succ, child)) { 2722 G++; 2723 } 2724 } 2725 2726 // Consider all graph edges to child. 2727 var inEdges = graph.inEdges(child); 2728 for (var ie in inEdges) { 2729 var pred = graph.source(inEdges[ie]); 2730 for (gc in grandchildren) { 2731 if (inSubtree(tree, pred, grandchildren[gc])) { 2732 F++; 2733 } 2734 } 2735 if (!inSubtree(tree, pred, child)) { 2736 H++; 2737 } 2738 } 2739 2740 // Contributions depend on the alignment of the parent -> child edge 2741 // and the child -> u or v edges. 2742 var grandchildCutSum = 0; 2743 for (gc in grandchildren) { 2744 var cv = tree.edge(grandchildEdges[gc]).cutValue; 2745 if (!tree.edge(grandchildEdges[gc]).reversed) { 2746 grandchildCutSum += cv; 2747 } else { 2748 grandchildCutSum -= cv; 2749 } 2750 } 2751 2752 if (!tree.edge(parentEdge).reversed) { 2753 cutValue += grandchildCutSum - E + F - G + H; 2754 } else { 2755 cutValue -= grandchildCutSum - E + F - G + H; 2756 } 2757 2758 tree.edge(parentEdge).cutValue = cutValue; 2759 } 2760 2761 /* 2762 * Return whether n is a node in the subtree with the given 2763 * root. 2764 */ 2765 function inSubtree(tree, n, root) { 2766 return (tree.node(root).low <= tree.node(n).lim && 2767 tree.node(n).lim <= tree.node(root).lim); 2768 } 2769 2770 /* 2771 * Return an edge from the tree with a negative cut value, or null if there 2772 * is none. 2773 */ 2774 function leaveEdge(tree) { 2775 var edges = tree.edges(); 2776 for (var n in edges) { 2777 var e = edges[n]; 2778 var treeValue = tree.edge(e); 2779 if (treeValue.cutValue < 0) { 2780 return e; 2781 } 2782 } 2783 return null; 2784 } 2785 2786 /* 2787 * The edge e should be an edge in the tree, with an underlying edge 2788 * in the graph, with a negative cut value. Of the two nodes incident 2789 * on the edge, take the lower one. enterEdge returns an edge with 2790 * minimum slack going from outside of that node's subtree to inside 2791 * of that node's subtree. 2792 */ 2793 function enterEdge(graph, tree, e) { 2794 var source = tree.source(e); 2795 var target = tree.target(e); 2796 var lower = tree.node(target).lim < tree.node(source).lim ? target : source; 2797 2798 // Is the tree edge aligned with the graph edge? 2799 var aligned = !tree.edge(e).reversed; 2800 2801 var minSlack = Number.POSITIVE_INFINITY; 2802 var minSlackEdge; 2803 if (aligned) { 2804 graph.eachEdge(function(id, u, v, value) { 2805 if (id !== e && inSubtree(tree, u, lower) && !inSubtree(tree, v, lower)) { 2806 var slack = rankUtil.slack(graph, u, v, value.minLen); 2807 if (slack < minSlack) { 2808 minSlack = slack; 2809 minSlackEdge = id; 2810 } 2811 } 2812 }); 2813 } else { 2814 graph.eachEdge(function(id, u, v, value) { 2815 if (id !== e && !inSubtree(tree, u, lower) && inSubtree(tree, v, lower)) { 2816 var slack = rankUtil.slack(graph, u, v, value.minLen); 2817 if (slack < minSlack) { 2818 minSlack = slack; 2819 minSlackEdge = id; 2820 } 2821 } 2822 }); 2823 } 2824 2825 if (minSlackEdge === undefined) { 2826 var outside = []; 2827 var inside = []; 2828 graph.eachNode(function(id) { 2829 if (!inSubtree(tree, id, lower)) { 2830 outside.push(id); 2831 } else { 2832 inside.push(id); 2833 } 2834 }); 2835 throw new Error('No edge found from outside of tree to inside'); 2836 } 2837 2838 return minSlackEdge; 2839 } 2840 2841 /* 2842 * Replace edge e with edge f in the tree, recalculating the tree root, 2843 * the nodes' low and lim properties and the edges' cut values. 2844 */ 2845 function exchange(graph, tree, e, f) { 2846 tree.delEdge(e); 2847 var source = graph.source(f); 2848 var target = graph.target(f); 2849 2850 // Redirect edges so that target is the root of its subtree. 2851 function redirect(v) { 2852 var edges = tree.inEdges(v); 2853 for (var i in edges) { 2854 var e = edges[i]; 2855 var u = tree.source(e); 2856 var value = tree.edge(e); 2857 redirect(u); 2858 tree.delEdge(e); 2859 value.reversed = !value.reversed; 2860 tree.addEdge(e, v, u, value); 2861 } 2862 } 2863 2864 redirect(target); 2865 2866 var root = source; 2867 var edges = tree.inEdges(root); 2868 while (edges.length > 0) { 2869 root = tree.source(edges[0]); 2870 edges = tree.inEdges(root); 2871 } 2872 2873 tree.graph().root = root; 2874 2875 tree.addEdge(null, source, target, {cutValue: 0}); 2876 2877 initCutValues(graph, tree); 2878 2879 adjustRanks(graph, tree); 2880 } 2881 2882 /* 2883 * Reset the ranks of all nodes based on the current spanning tree. 2884 * The rank of the tree's root remains unchanged, while all other 2885 * nodes are set to the sum of minimum length constraints along 2886 * the path from the root. 2887 */ 2888 function adjustRanks(graph, tree) { 2889 function dfs(p) { 2890 var children = tree.successors(p); 2891 children.forEach(function(c) { 2892 var minLen = minimumLength(graph, p, c); 2893 graph.node(c).rank = graph.node(p).rank + minLen; 2894 dfs(c); 2895 }); 2896 } 2897 2898 dfs(tree.graph().root); 2899 } 2900 2901 /* 2902 * If u and v are connected by some edges in the graph, return the 2903 * minimum length of those edges, as a positive number if v succeeds 2904 * u and as a negative number if v precedes u. 2905 */ 2906 function minimumLength(graph, u, v) { 2907 var outEdges = graph.outEdges(u, v); 2908 if (outEdges.length > 0) { 2909 return util.max(outEdges.map(function(e) { 2910 return graph.edge(e).minLen; 2911 })); 2912 } 2913 2914 var inEdges = graph.inEdges(u, v); 2915 if (inEdges.length > 0) { 2916 return -util.max(inEdges.map(function(e) { 2917 return graph.edge(e).minLen; 2918 })); 2919 } 2920 } 2921 2922 },{"../util":26,"./rankUtil":24}],26:[function(require,module,exports){ 2923 /* 2924 * Returns the smallest value in the array. 2925 */ 2926 exports.min = function(values) { 2927 return Math.min.apply(Math, values); 2928 }; 2929 2930 /* 2931 * Returns the largest value in the array. 2932 */ 2933 exports.max = function(values) { 2934 return Math.max.apply(Math, values); 2935 }; 2936 2937 /* 2938 * Returns `true` only if `f(x)` is `true` for all `x` in `xs`. Otherwise 2939 * returns `false`. This function will return immediately if it finds a 2940 * case where `f(x)` does not hold. 2941 */ 2942 exports.all = function(xs, f) { 2943 for (var i = 0; i < xs.length; ++i) { 2944 if (!f(xs[i])) { 2945 return false; 2946 } 2947 } 2948 return true; 2949 }; 2950 2951 /* 2952 * Accumulates the sum of elements in the given array using the `+` operator. 2953 */ 2954 exports.sum = function(values) { 2955 return values.reduce(function(acc, x) { return acc + x; }, 0); 2956 }; 2957 2958 /* 2959 * Returns an array of all values in the given object. 2960 */ 2961 exports.values = function(obj) { 2962 return Object.keys(obj).map(function(k) { return obj[k]; }); 2963 }; 2964 2965 exports.shuffle = function(array) { 2966 for (i = array.length - 1; i > 0; --i) { 2967 var j = Math.floor(Math.random() * (i + 1)); 2968 var aj = array[j]; 2969 array[j] = array[i]; 2970 array[i] = aj; 2971 } 2972 }; 2973 2974 exports.propertyAccessor = function(self, config, field, setHook) { 2975 return function(x) { 2976 if (!arguments.length) return config[field]; 2977 config[field] = x; 2978 if (setHook) setHook(x); 2979 return self; 2980 }; 2981 }; 2982 2983 /* 2984 * Given a layered, directed graph with `rank` and `order` node attributes, 2985 * this function returns an array of ordered ranks. Each rank contains an array 2986 * of the ids of the nodes in that rank in the order specified by the `order` 2987 * attribute. 2988 */ 2989 exports.ordering = function(g) { 2990 var ordering = []; 2991 g.eachNode(function(u, value) { 2992 var rank = ordering[value.rank] || (ordering[value.rank] = []); 2993 rank[value.order] = u; 2994 }); 2995 return ordering; 2996 }; 2997 2998 /* 2999 * A filter that can be used with `filterNodes` to get a graph that only 3000 * includes nodes that do not contain others nodes. 3001 */ 3002 exports.filterNonSubgraphs = function(g) { 3003 return function(u) { 3004 return g.children(u).length === 0; 3005 }; 3006 }; 3007 3008 /* 3009 * Returns a new function that wraps `func` with a timer. The wrapper logs the 3010 * time it takes to execute the function. 3011 * 3012 * The timer will be enabled provided `log.level >= 1`. 3013 */ 3014 function time(name, func) { 3015 return function() { 3016 var start = new Date().getTime(); 3017 try { 3018 return func.apply(null, arguments); 3019 } finally { 3020 log(1, name + ' time: ' + (new Date().getTime() - start) + 'ms'); 3021 } 3022 }; 3023 } 3024 time.enabled = false; 3025 3026 exports.time = time; 3027 3028 /* 3029 * A global logger with the specification `log(level, message, ...)` that 3030 * will log a message to the console if `log.level >= level`. 3031 */ 3032 function log(level) { 3033 if (log.level >= level) { 3034 console.log.apply(console, Array.prototype.slice.call(arguments, 1)); 3035 } 3036 } 3037 log.level = 0; 3038 3039 exports.log = log; 3040 3041 },{}],27:[function(require,module,exports){ 3042 module.exports = '0.4.5'; 3043 3044 },{}],28:[function(require,module,exports){ 3045 exports.Graph = require("./lib/Graph"); 3046 exports.Digraph = require("./lib/Digraph"); 3047 exports.CGraph = require("./lib/CGraph"); 3048 exports.CDigraph = require("./lib/CDigraph"); 3049 require("./lib/graph-converters"); 3050 3051 exports.alg = { 3052 isAcyclic: require("./lib/alg/isAcyclic"), 3053 components: require("./lib/alg/components"), 3054 dijkstra: require("./lib/alg/dijkstra"), 3055 dijkstraAll: require("./lib/alg/dijkstraAll"), 3056 findCycles: require("./lib/alg/findCycles"), 3057 floydWarshall: require("./lib/alg/floydWarshall"), 3058 postorder: require("./lib/alg/postorder"), 3059 preorder: require("./lib/alg/preorder"), 3060 prim: require("./lib/alg/prim"), 3061 tarjan: require("./lib/alg/tarjan"), 3062 topsort: require("./lib/alg/topsort") 3063 }; 3064 3065 exports.converter = { 3066 json: require("./lib/converter/json.js") 3067 }; 3068 3069 var filter = require("./lib/filter"); 3070 exports.filter = { 3071 all: filter.all, 3072 nodesFromList: filter.nodesFromList 3073 }; 3074 3075 exports.version = require("./lib/version"); 3076 3077 },{"./lib/CDigraph":30,"./lib/CGraph":31,"./lib/Digraph":32,"./lib/Graph":33,"./lib/alg/components":34,"./lib/alg/dijkstra":35,"./lib/alg/dijkstraAll":36,"./lib/alg/findCycles":37,"./lib/alg/floydWarshall":38,"./lib/alg/isAcyclic":39,"./lib/alg/postorder":40,"./lib/alg/preorder":41,"./lib/alg/prim":42,"./lib/alg/tarjan":43,"./lib/alg/topsort":44,"./lib/converter/json.js":46,"./lib/filter":47,"./lib/graph-converters":48,"./lib/version":50}],29:[function(require,module,exports){ 3078 /* jshint -W079 */ 3079 var Set = require("cp-data").Set; 3080 /* jshint +W079 */ 3081 3082 module.exports = BaseGraph; 3083 3084 function BaseGraph() { 3085 // The value assigned to the graph itself. 3086 this._value = undefined; 3087 3088 // Map of node id -> { id, value } 3089 this._nodes = {}; 3090 3091 // Map of edge id -> { id, u, v, value } 3092 this._edges = {}; 3093 3094 // Used to generate a unique id in the graph 3095 this._nextId = 0; 3096 } 3097 3098 // Number of nodes 3099 BaseGraph.prototype.order = function() { 3100 return Object.keys(this._nodes).length; 3101 }; 3102 3103 // Number of edges 3104 BaseGraph.prototype.size = function() { 3105 return Object.keys(this._edges).length; 3106 }; 3107 3108 // Accessor for graph level value 3109 BaseGraph.prototype.graph = function(value) { 3110 if (arguments.length === 0) { 3111 return this._value; 3112 } 3113 this._value = value; 3114 }; 3115 3116 BaseGraph.prototype.hasNode = function(u) { 3117 return u in this._nodes; 3118 }; 3119 3120 BaseGraph.prototype.node = function(u, value) { 3121 var node = this._strictGetNode(u); 3122 if (arguments.length === 1) { 3123 return node.value; 3124 } 3125 node.value = value; 3126 }; 3127 3128 BaseGraph.prototype.nodes = function() { 3129 var nodes = []; 3130 this.eachNode(function(id) { nodes.push(id); }); 3131 return nodes; 3132 }; 3133 3134 BaseGraph.prototype.eachNode = function(func) { 3135 for (var k in this._nodes) { 3136 var node = this._nodes[k]; 3137 func(node.id, node.value); 3138 } 3139 }; 3140 3141 BaseGraph.prototype.hasEdge = function(e) { 3142 return e in this._edges; 3143 }; 3144 3145 BaseGraph.prototype.edge = function(e, value) { 3146 var edge = this._strictGetEdge(e); 3147 if (arguments.length === 1) { 3148 return edge.value; 3149 } 3150 edge.value = value; 3151 }; 3152 3153 BaseGraph.prototype.edges = function() { 3154 var es = []; 3155 this.eachEdge(function(id) { es.push(id); }); 3156 return es; 3157 }; 3158 3159 BaseGraph.prototype.eachEdge = function(func) { 3160 for (var k in this._edges) { 3161 var edge = this._edges[k]; 3162 func(edge.id, edge.u, edge.v, edge.value); 3163 } 3164 }; 3165 3166 BaseGraph.prototype.incidentNodes = function(e) { 3167 var edge = this._strictGetEdge(e); 3168 return [edge.u, edge.v]; 3169 }; 3170 3171 BaseGraph.prototype.addNode = function(u, value) { 3172 if (u === undefined || u === null) { 3173 do { 3174 u = "_" + (++this._nextId); 3175 } while (this.hasNode(u)); 3176 } else if (this.hasNode(u)) { 3177 throw new Error("Graph already has node '" + u + "'"); 3178 } 3179 this._nodes[u] = { id: u, value: value }; 3180 return u; 3181 }; 3182 3183 BaseGraph.prototype.delNode = function(u) { 3184 this._strictGetNode(u); 3185 this.incidentEdges(u).forEach(function(e) { this.delEdge(e); }, this); 3186 delete this._nodes[u]; 3187 }; 3188 3189 // inMap and outMap are opposite sides of an incidence map. For example, for 3190 // Graph these would both come from the _incidentEdges map, while for Digraph 3191 // they would come from _inEdges and _outEdges. 3192 BaseGraph.prototype._addEdge = function(e, u, v, value, inMap, outMap) { 3193 this._strictGetNode(u); 3194 this._strictGetNode(v); 3195 3196 if (e === undefined || e === null) { 3197 do { 3198 e = "_" + (++this._nextId); 3199 } while (this.hasEdge(e)); 3200 } 3201 else if (this.hasEdge(e)) { 3202 throw new Error("Graph already has edge '" + e + "'"); 3203 } 3204 3205 this._edges[e] = { id: e, u: u, v: v, value: value }; 3206 addEdgeToMap(inMap[v], u, e); 3207 addEdgeToMap(outMap[u], v, e); 3208 3209 return e; 3210 }; 3211 3212 // See note for _addEdge regarding inMap and outMap. 3213 BaseGraph.prototype._delEdge = function(e, inMap, outMap) { 3214 var edge = this._strictGetEdge(e); 3215 delEdgeFromMap(inMap[edge.v], edge.u, e); 3216 delEdgeFromMap(outMap[edge.u], edge.v, e); 3217 delete this._edges[e]; 3218 }; 3219 3220 BaseGraph.prototype.copy = function() { 3221 var copy = new this.constructor(); 3222 copy.graph(this.graph()); 3223 this.eachNode(function(u, value) { copy.addNode(u, value); }); 3224 this.eachEdge(function(e, u, v, value) { copy.addEdge(e, u, v, value); }); 3225 copy._nextId = this._nextId; 3226 return copy; 3227 }; 3228 3229 BaseGraph.prototype.filterNodes = function(filter) { 3230 var copy = new this.constructor(); 3231 copy.graph(this.graph()); 3232 this.eachNode(function(u, value) { 3233 if (filter(u)) { 3234 copy.addNode(u, value); 3235 } 3236 }); 3237 this.eachEdge(function(e, u, v, value) { 3238 if (copy.hasNode(u) && copy.hasNode(v)) { 3239 copy.addEdge(e, u, v, value); 3240 } 3241 }); 3242 return copy; 3243 }; 3244 3245 BaseGraph.prototype._strictGetNode = function(u) { 3246 var node = this._nodes[u]; 3247 if (node === undefined) { 3248 throw new Error("Node '" + u + "' is not in graph"); 3249 } 3250 return node; 3251 }; 3252 3253 BaseGraph.prototype._strictGetEdge = function(e) { 3254 var edge = this._edges[e]; 3255 if (edge === undefined) { 3256 throw new Error("Edge '" + e + "' is not in graph"); 3257 } 3258 return edge; 3259 }; 3260 3261 function addEdgeToMap(map, v, e) { 3262 (map[v] || (map[v] = new Set())).add(e); 3263 } 3264 3265 function delEdgeFromMap(map, v, e) { 3266 var vEntry = map[v]; 3267 vEntry.remove(e); 3268 if (vEntry.size() === 0) { 3269 delete map[v]; 3270 } 3271 } 3272 3273 3274 },{"cp-data":5}],30:[function(require,module,exports){ 3275 var Digraph = require("./Digraph"), 3276 compoundify = require("./compoundify"); 3277 3278 var CDigraph = compoundify(Digraph); 3279 3280 module.exports = CDigraph; 3281 3282 CDigraph.fromDigraph = function(src) { 3283 var g = new CDigraph(), 3284 graphValue = src.graph(); 3285 3286 if (graphValue !== undefined) { 3287 g.graph(graphValue); 3288 } 3289 3290 src.eachNode(function(u, value) { 3291 if (value === undefined) { 3292 g.addNode(u); 3293 } else { 3294 g.addNode(u, value); 3295 } 3296 }); 3297 src.eachEdge(function(e, u, v, value) { 3298 if (value === undefined) { 3299 g.addEdge(null, u, v); 3300 } else { 3301 g.addEdge(null, u, v, value); 3302 } 3303 }); 3304 return g; 3305 }; 3306 3307 CDigraph.prototype.toString = function() { 3308 return "CDigraph " + JSON.stringify(this, null, 2); 3309 }; 3310 3311 },{"./Digraph":32,"./compoundify":45}],31:[function(require,module,exports){ 3312 var Graph = require("./Graph"), 3313 compoundify = require("./compoundify"); 3314 3315 var CGraph = compoundify(Graph); 3316 3317 module.exports = CGraph; 3318 3319 CGraph.fromGraph = function(src) { 3320 var g = new CGraph(), 3321 graphValue = src.graph(); 3322 3323 if (graphValue !== undefined) { 3324 g.graph(graphValue); 3325 } 3326 3327 src.eachNode(function(u, value) { 3328 if (value === undefined) { 3329 g.addNode(u); 3330 } else { 3331 g.addNode(u, value); 3332 } 3333 }); 3334 src.eachEdge(function(e, u, v, value) { 3335 if (value === undefined) { 3336 g.addEdge(null, u, v); 3337 } else { 3338 g.addEdge(null, u, v, value); 3339 } 3340 }); 3341 return g; 3342 }; 3343 3344 CGraph.prototype.toString = function() { 3345 return "CGraph " + JSON.stringify(this, null, 2); 3346 }; 3347 3348 },{"./Graph":33,"./compoundify":45}],32:[function(require,module,exports){ 3349 /* 3350 * This file is organized with in the following order: 3351 * 3352 * Exports 3353 * Graph constructors 3354 * Graph queries (e.g. nodes(), edges() 3355 * Graph mutators 3356 * Helper functions 3357 */ 3358 3359 var util = require("./util"), 3360 BaseGraph = require("./BaseGraph"), 3361 /* jshint -W079 */ 3362 Set = require("cp-data").Set; 3363 /* jshint +W079 */ 3364 3365 module.exports = Digraph; 3366 3367 /* 3368 * Constructor to create a new directed multi-graph. 3369 */ 3370 function Digraph() { 3371 BaseGraph.call(this); 3372 3373 /*! Map of sourceId -> {targetId -> Set of edge ids} */ 3374 this._inEdges = {}; 3375 3376 /*! Map of targetId -> {sourceId -> Set of edge ids} */ 3377 this._outEdges = {}; 3378 } 3379 3380 Digraph.prototype = new BaseGraph(); 3381 Digraph.prototype.constructor = Digraph; 3382 3383 /* 3384 * Always returns `true`. 3385 */ 3386 Digraph.prototype.isDirected = function() { 3387 return true; 3388 }; 3389 3390 /* 3391 * Returns all successors of the node with the id `u`. That is, all nodes 3392 * that have the node `u` as their source are returned. 3393 * 3394 * If no node `u` exists in the graph this function throws an Error. 3395 * 3396 * @param {String} u a node id 3397 */ 3398 Digraph.prototype.successors = function(u) { 3399 this._strictGetNode(u); 3400 return Object.keys(this._outEdges[u]) 3401 .map(function(v) { return this._nodes[v].id; }, this); 3402 }; 3403 3404 /* 3405 * Returns all predecessors of the node with the id `u`. That is, all nodes 3406 * that have the node `u` as their target are returned. 3407 * 3408 * If no node `u` exists in the graph this function throws an Error. 3409 * 3410 * @param {String} u a node id 3411 */ 3412 Digraph.prototype.predecessors = function(u) { 3413 this._strictGetNode(u); 3414 return Object.keys(this._inEdges[u]) 3415 .map(function(v) { return this._nodes[v].id; }, this); 3416 }; 3417 3418 /* 3419 * Returns all nodes that are adjacent to the node with the id `u`. In other 3420 * words, this function returns the set of all successors and predecessors of 3421 * node `u`. 3422 * 3423 * @param {String} u a node id 3424 */ 3425 Digraph.prototype.neighbors = function(u) { 3426 return Set.union([this.successors(u), this.predecessors(u)]).keys(); 3427 }; 3428 3429 /* 3430 * Returns all nodes in the graph that have no in-edges. 3431 */ 3432 Digraph.prototype.sources = function() { 3433 var self = this; 3434 return this._filterNodes(function(u) { 3435 // This could have better space characteristics if we had an inDegree function. 3436 return self.inEdges(u).length === 0; 3437 }); 3438 }; 3439 3440 /* 3441 * Returns all nodes in the graph that have no out-edges. 3442 */ 3443 Digraph.prototype.sinks = function() { 3444 var self = this; 3445 return this._filterNodes(function(u) { 3446 // This could have better space characteristics if we have an outDegree function. 3447 return self.outEdges(u).length === 0; 3448 }); 3449 }; 3450 3451 /* 3452 * Returns the source node incident on the edge identified by the id `e`. If no 3453 * such edge exists in the graph this function throws an Error. 3454 * 3455 * @param {String} e an edge id 3456 */ 3457 Digraph.prototype.source = function(e) { 3458 return this._strictGetEdge(e).u; 3459 }; 3460 3461 /* 3462 * Returns the target node incident on the edge identified by the id `e`. If no 3463 * such edge exists in the graph this function throws an Error. 3464 * 3465 * @param {String} e an edge id 3466 */ 3467 Digraph.prototype.target = function(e) { 3468 return this._strictGetEdge(e).v; 3469 }; 3470 3471 /* 3472 * Returns an array of ids for all edges in the graph that have the node 3473 * `target` as their target. If the node `target` is not in the graph this 3474 * function raises an Error. 3475 * 3476 * Optionally a `source` node can also be specified. This causes the results 3477 * to be filtered such that only edges from `source` to `target` are included. 3478 * If the node `source` is specified but is not in the graph then this function 3479 * raises an Error. 3480 * 3481 * @param {String} target the target node id 3482 * @param {String} [source] an optional source node id 3483 */ 3484 Digraph.prototype.inEdges = function(target, source) { 3485 this._strictGetNode(target); 3486 var results = Set.union(util.values(this._inEdges[target])).keys(); 3487 if (arguments.length > 1) { 3488 this._strictGetNode(source); 3489 results = results.filter(function(e) { return this.source(e) === source; }, this); 3490 } 3491 return results; 3492 }; 3493 3494 /* 3495 * Returns an array of ids for all edges in the graph that have the node 3496 * `source` as their source. If the node `source` is not in the graph this 3497 * function raises an Error. 3498 * 3499 * Optionally a `target` node may also be specified. This causes the results 3500 * to be filtered such that only edges from `source` to `target` are included. 3501 * If the node `target` is specified but is not in the graph then this function 3502 * raises an Error. 3503 * 3504 * @param {String} source the source node id 3505 * @param {String} [target] an optional target node id 3506 */ 3507 Digraph.prototype.outEdges = function(source, target) { 3508 this._strictGetNode(source); 3509 var results = Set.union(util.values(this._outEdges[source])).keys(); 3510 if (arguments.length > 1) { 3511 this._strictGetNode(target); 3512 results = results.filter(function(e) { return this.target(e) === target; }, this); 3513 } 3514 return results; 3515 }; 3516 3517 /* 3518 * Returns an array of ids for all edges in the graph that have the `u` as 3519 * their source or their target. If the node `u` is not in the graph this 3520 * function raises an Error. 3521 * 3522 * Optionally a `v` node may also be specified. This causes the results to be 3523 * filtered such that only edges between `u` and `v` - in either direction - 3524 * are included. IF the node `v` is specified but not in the graph then this 3525 * function raises an Error. 3526 * 3527 * @param {String} u the node for which to find incident edges 3528 * @param {String} [v] option node that must be adjacent to `u` 3529 */ 3530 Digraph.prototype.incidentEdges = function(u, v) { 3531 if (arguments.length > 1) { 3532 return Set.union([this.outEdges(u, v), this.outEdges(v, u)]).keys(); 3533 } else { 3534 return Set.union([this.inEdges(u), this.outEdges(u)]).keys(); 3535 } 3536 }; 3537 3538 /* 3539 * Returns a string representation of this graph. 3540 */ 3541 Digraph.prototype.toString = function() { 3542 return "Digraph " + JSON.stringify(this, null, 2); 3543 }; 3544 3545 /* 3546 * Adds a new node with the id `u` to the graph and assigns it the value 3547 * `value`. If a node with the id is already a part of the graph this function 3548 * throws an Error. 3549 * 3550 * @param {String} u a node id 3551 * @param {Object} [value] an optional value to attach to the node 3552 */ 3553 Digraph.prototype.addNode = function(u, value) { 3554 u = BaseGraph.prototype.addNode.call(this, u, value); 3555 this._inEdges[u] = {}; 3556 this._outEdges[u] = {}; 3557 return u; 3558 }; 3559 3560 /* 3561 * Removes a node from the graph that has the id `u`. Any edges incident on the 3562 * node are also removed. If the graph does not contain a node with the id this 3563 * function will throw an Error. 3564 * 3565 * @param {String} u a node id 3566 */ 3567 Digraph.prototype.delNode = function(u) { 3568 BaseGraph.prototype.delNode.call(this, u); 3569 delete this._inEdges[u]; 3570 delete this._outEdges[u]; 3571 }; 3572 3573 /* 3574 * Adds a new edge to the graph with the id `e` from a node with the id `source` 3575 * to a node with an id `target` and assigns it the value `value`. This graph 3576 * allows more than one edge from `source` to `target` as long as the id `e` 3577 * is unique in the set of edges. If `e` is `null` the graph will assign a 3578 * unique identifier to the edge. 3579 * 3580 * If `source` or `target` are not present in the graph this function will 3581 * throw an Error. 3582 * 3583 * @param {String} [e] an edge id 3584 * @param {String} source the source node id 3585 * @param {String} target the target node id 3586 * @param {Object} [value] an optional value to attach to the edge 3587 */ 3588 Digraph.prototype.addEdge = function(e, source, target, value) { 3589 return BaseGraph.prototype._addEdge.call(this, e, source, target, value, 3590 this._inEdges, this._outEdges); 3591 }; 3592 3593 /* 3594 * Removes an edge in the graph with the id `e`. If no edge in the graph has 3595 * the id `e` this function will throw an Error. 3596 * 3597 * @param {String} e an edge id 3598 */ 3599 Digraph.prototype.delEdge = function(e) { 3600 BaseGraph.prototype._delEdge.call(this, e, this._inEdges, this._outEdges); 3601 }; 3602 3603 // Unlike BaseGraph.filterNodes, this helper just returns nodes that 3604 // satisfy a predicate. 3605 Digraph.prototype._filterNodes = function(pred) { 3606 var filtered = []; 3607 this.eachNode(function(u) { 3608 if (pred(u)) { 3609 filtered.push(u); 3610 } 3611 }); 3612 return filtered; 3613 }; 3614 3615 3616 },{"./BaseGraph":29,"./util":49,"cp-data":5}],33:[function(require,module,exports){ 3617 /* 3618 * This file is organized with in the following order: 3619 * 3620 * Exports 3621 * Graph constructors 3622 * Graph queries (e.g. nodes(), edges() 3623 * Graph mutators 3624 * Helper functions 3625 */ 3626 3627 var util = require("./util"), 3628 BaseGraph = require("./BaseGraph"), 3629 /* jshint -W079 */ 3630 Set = require("cp-data").Set; 3631 /* jshint +W079 */ 3632 3633 module.exports = Graph; 3634 3635 /* 3636 * Constructor to create a new undirected multi-graph. 3637 */ 3638 function Graph() { 3639 BaseGraph.call(this); 3640 3641 /*! Map of nodeId -> { otherNodeId -> Set of edge ids } */ 3642 this._incidentEdges = {}; 3643 } 3644 3645 Graph.prototype = new BaseGraph(); 3646 Graph.prototype.constructor = Graph; 3647 3648 /* 3649 * Always returns `false`. 3650 */ 3651 Graph.prototype.isDirected = function() { 3652 return false; 3653 }; 3654 3655 /* 3656 * Returns all nodes that are adjacent to the node with the id `u`. 3657 * 3658 * @param {String} u a node id 3659 */ 3660 Graph.prototype.neighbors = function(u) { 3661 this._strictGetNode(u); 3662 return Object.keys(this._incidentEdges[u]) 3663 .map(function(v) { return this._nodes[v].id; }, this); 3664 }; 3665 3666 /* 3667 * Returns an array of ids for all edges in the graph that are incident on `u`. 3668 * If the node `u` is not in the graph this function raises an Error. 3669 * 3670 * Optionally a `v` node may also be specified. This causes the results to be 3671 * filtered such that only edges between `u` and `v` are included. If the node 3672 * `v` is specified but not in the graph then this function raises an Error. 3673 * 3674 * @param {String} u the node for which to find incident edges 3675 * @param {String} [v] option node that must be adjacent to `u` 3676 */ 3677 Graph.prototype.incidentEdges = function(u, v) { 3678 this._strictGetNode(u); 3679 if (arguments.length > 1) { 3680 this._strictGetNode(v); 3681 return v in this._incidentEdges[u] ? this._incidentEdges[u][v].keys() : []; 3682 } else { 3683 return Set.union(util.values(this._incidentEdges[u])).keys(); 3684 } 3685 }; 3686 3687 /* 3688 * Returns a string representation of this graph. 3689 */ 3690 Graph.prototype.toString = function() { 3691 return "Graph " + JSON.stringify(this, null, 2); 3692 }; 3693 3694 /* 3695 * Adds a new node with the id `u` to the graph and assigns it the value 3696 * `value`. If a node with the id is already a part of the graph this function 3697 * throws an Error. 3698 * 3699 * @param {String} u a node id 3700 * @param {Object} [value] an optional value to attach to the node 3701 */ 3702 Graph.prototype.addNode = function(u, value) { 3703 u = BaseGraph.prototype.addNode.call(this, u, value); 3704 this._incidentEdges[u] = {}; 3705 return u; 3706 }; 3707 3708 /* 3709 * Removes a node from the graph that has the id `u`. Any edges incident on the 3710 * node are also removed. If the graph does not contain a node with the id this 3711 * function will throw an Error. 3712 * 3713 * @param {String} u a node id 3714 */ 3715 Graph.prototype.delNode = function(u) { 3716 BaseGraph.prototype.delNode.call(this, u); 3717 delete this._incidentEdges[u]; 3718 }; 3719 3720 /* 3721 * Adds a new edge to the graph with the id `e` between a node with the id `u` 3722 * and a node with an id `v` and assigns it the value `value`. This graph 3723 * allows more than one edge between `u` and `v` as long as the id `e` 3724 * is unique in the set of edges. If `e` is `null` the graph will assign a 3725 * unique identifier to the edge. 3726 * 3727 * If `u` or `v` are not present in the graph this function will throw an 3728 * Error. 3729 * 3730 * @param {String} [e] an edge id 3731 * @param {String} u the node id of one of the adjacent nodes 3732 * @param {String} v the node id of the other adjacent node 3733 * @param {Object} [value] an optional value to attach to the edge 3734 */ 3735 Graph.prototype.addEdge = function(e, u, v, value) { 3736 return BaseGraph.prototype._addEdge.call(this, e, u, v, value, 3737 this._incidentEdges, this._incidentEdges); 3738 }; 3739 3740 /* 3741 * Removes an edge in the graph with the id `e`. If no edge in the graph has 3742 * the id `e` this function will throw an Error. 3743 * 3744 * @param {String} e an edge id 3745 */ 3746 Graph.prototype.delEdge = function(e) { 3747 BaseGraph.prototype._delEdge.call(this, e, this._incidentEdges, this._incidentEdges); 3748 }; 3749 3750 3751 },{"./BaseGraph":29,"./util":49,"cp-data":5}],34:[function(require,module,exports){ 3752 /* jshint -W079 */ 3753 var Set = require("cp-data").Set; 3754 /* jshint +W079 */ 3755 3756 module.exports = components; 3757 3758 /** 3759 * Finds all [connected components][] in a graph and returns an array of these 3760 * components. Each component is itself an array that contains the ids of nodes 3761 * in the component. 3762 * 3763 * This function only works with undirected Graphs. 3764 * 3765 * [connected components]: http://en.wikipedia.org/wiki/Connected_component_(graph_theory) 3766 * 3767 * @param {Graph} g the graph to search for components 3768 */ 3769 function components(g) { 3770 var results = []; 3771 var visited = new Set(); 3772 3773 function dfs(v, component) { 3774 if (!visited.has(v)) { 3775 visited.add(v); 3776 component.push(v); 3777 g.neighbors(v).forEach(function(w) { 3778 dfs(w, component); 3779 }); 3780 } 3781 } 3782 3783 g.nodes().forEach(function(v) { 3784 var component = []; 3785 dfs(v, component); 3786 if (component.length > 0) { 3787 results.push(component); 3788 } 3789 }); 3790 3791 return results; 3792 } 3793 3794 },{"cp-data":5}],35:[function(require,module,exports){ 3795 var PriorityQueue = require("cp-data").PriorityQueue; 3796 3797 module.exports = dijkstra; 3798 3799 /** 3800 * This function is an implementation of [Dijkstra's algorithm][] which finds 3801 * the shortest path from **source** to all other nodes in **g**. This 3802 * function returns a map of `u -> { distance, predecessor }`. The distance 3803 * property holds the sum of the weights from **source** to `u` along the 3804 * shortest path or `Number.POSITIVE_INFINITY` if there is no path from 3805 * **source**. The predecessor property can be used to walk the individual 3806 * elements of the path from **source** to **u** in reverse order. 3807 * 3808 * This function takes an optional `weightFunc(e)` which returns the 3809 * weight of the edge `e`. If no weightFunc is supplied then each edge is 3810 * assumed to have a weight of 1. This function throws an Error if any of 3811 * the traversed edges have a negative edge weight. 3812 * 3813 * This function takes an optional `incidentFunc(u)` which returns the ids of 3814 * all edges incident to the node `u` for the purposes of shortest path 3815 * traversal. By default this function uses the `g.outEdges` for Digraphs and 3816 * `g.incidentEdges` for Graphs. 3817 * 3818 * This function takes `O((|E| + |V|) * log |V|)` time. 3819 * 3820 * [Dijkstra's algorithm]: http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm 3821 * 3822 * @param {Graph} g the graph to search for shortest paths from **source** 3823 * @param {Object} source the source from which to start the search 3824 * @param {Function} [weightFunc] optional weight function 3825 * @param {Function} [incidentFunc] optional incident function 3826 */ 3827 function dijkstra(g, source, weightFunc, incidentFunc) { 3828 var results = {}, 3829 pq = new PriorityQueue(); 3830 3831 function updateNeighbors(e) { 3832 var incidentNodes = g.incidentNodes(e), 3833 v = incidentNodes[0] !== u ? incidentNodes[0] : incidentNodes[1], 3834 vEntry = results[v], 3835 weight = weightFunc(e), 3836 distance = uEntry.distance + weight; 3837 3838 if (weight < 0) { 3839 throw new Error("dijkstra does not allow negative edge weights. Bad edge: " + e + " Weight: " + weight); 3840 } 3841 3842 if (distance < vEntry.distance) { 3843 vEntry.distance = distance; 3844 vEntry.predecessor = u; 3845 pq.decrease(v, distance); 3846 } 3847 } 3848 3849 weightFunc = weightFunc || function() { return 1; }; 3850 incidentFunc = incidentFunc || (g.isDirected() 3851 ? function(u) { return g.outEdges(u); } 3852 : function(u) { return g.incidentEdges(u); }); 3853 3854 g.eachNode(function(u) { 3855 var distance = u === source ? 0 : Number.POSITIVE_INFINITY; 3856 results[u] = { distance: distance }; 3857 pq.add(u, distance); 3858 }); 3859 3860 var u, uEntry; 3861 while (pq.size() > 0) { 3862 u = pq.removeMin(); 3863 uEntry = results[u]; 3864 if (uEntry.distance === Number.POSITIVE_INFINITY) { 3865 break; 3866 } 3867 3868 incidentFunc(u).forEach(updateNeighbors); 3869 } 3870 3871 return results; 3872 } 3873 3874 },{"cp-data":5}],36:[function(require,module,exports){ 3875 var dijkstra = require("./dijkstra"); 3876 3877 module.exports = dijkstraAll; 3878 3879 /** 3880 * This function finds the shortest path from each node to every other 3881 * reachable node in the graph. It is similar to [alg.dijkstra][], but 3882 * instead of returning a single-source array, it returns a mapping of 3883 * of `source -> alg.dijksta(g, source, weightFunc, incidentFunc)`. 3884 * 3885 * This function takes an optional `weightFunc(e)` which returns the 3886 * weight of the edge `e`. If no weightFunc is supplied then each edge is 3887 * assumed to have a weight of 1. This function throws an Error if any of 3888 * the traversed edges have a negative edge weight. 3889 * 3890 * This function takes an optional `incidentFunc(u)` which returns the ids of 3891 * all edges incident to the node `u` for the purposes of shortest path 3892 * traversal. By default this function uses the `outEdges` function on the 3893 * supplied graph. 3894 * 3895 * This function takes `O(|V| * (|E| + |V|) * log |V|)` time. 3896 * 3897 * [alg.dijkstra]: dijkstra.js.html#dijkstra 3898 * 3899 * @param {Graph} g the graph to search for shortest paths from **source** 3900 * @param {Function} [weightFunc] optional weight function 3901 * @param {Function} [incidentFunc] optional incident function 3902 */ 3903 function dijkstraAll(g, weightFunc, incidentFunc) { 3904 var results = {}; 3905 g.eachNode(function(u) { 3906 results[u] = dijkstra(g, u, weightFunc, incidentFunc); 3907 }); 3908 return results; 3909 } 3910 3911 },{"./dijkstra":35}],37:[function(require,module,exports){ 3912 var tarjan = require("./tarjan"); 3913 3914 module.exports = findCycles; 3915 3916 /* 3917 * Given a Digraph **g** this function returns all nodes that are part of a 3918 * cycle. Since there may be more than one cycle in a graph this function 3919 * returns an array of these cycles, where each cycle is itself represented 3920 * by an array of ids for each node involved in that cycle. 3921 * 3922 * [alg.isAcyclic][] is more efficient if you only need to determine whether 3923 * a graph has a cycle or not. 3924 * 3925 * [alg.isAcyclic]: isAcyclic.js.html#isAcyclic 3926 * 3927 * @param {Digraph} g the graph to search for cycles. 3928 */ 3929 function findCycles(g) { 3930 return tarjan(g).filter(function(cmpt) { return cmpt.length > 1; }); 3931 } 3932 3933 },{"./tarjan":43}],38:[function(require,module,exports){ 3934 module.exports = floydWarshall; 3935 3936 /** 3937 * This function is an implementation of the [Floyd-Warshall algorithm][], 3938 * which finds the shortest path from each node to every other reachable node 3939 * in the graph. It is similar to [alg.dijkstraAll][], but it handles negative 3940 * edge weights and is more efficient for some types of graphs. This function 3941 * returns a map of `source -> { target -> { distance, predecessor }`. The 3942 * distance property holds the sum of the weights from `source` to `target` 3943 * along the shortest path of `Number.POSITIVE_INFINITY` if there is no path 3944 * from `source`. The predecessor property can be used to walk the individual 3945 * elements of the path from `source` to `target` in reverse order. 3946 * 3947 * This function takes an optional `weightFunc(e)` which returns the 3948 * weight of the edge `e`. If no weightFunc is supplied then each edge is 3949 * assumed to have a weight of 1. 3950 * 3951 * This function takes an optional `incidentFunc(u)` which returns the ids of 3952 * all edges incident to the node `u` for the purposes of shortest path 3953 * traversal. By default this function uses the `outEdges` function on the 3954 * supplied graph. 3955 * 3956 * This algorithm takes O(|V|^3) time. 3957 * 3958 * [Floyd-Warshall algorithm]: https://en.wikipedia.org/wiki/Floyd-Warshall_algorithm 3959 * [alg.dijkstraAll]: dijkstraAll.js.html#dijkstraAll 3960 * 3961 * @param {Graph} g the graph to search for shortest paths from **source** 3962 * @param {Function} [weightFunc] optional weight function 3963 * @param {Function} [incidentFunc] optional incident function 3964 */ 3965 function floydWarshall(g, weightFunc, incidentFunc) { 3966 var results = {}, 3967 nodes = g.nodes(); 3968 3969 weightFunc = weightFunc || function() { return 1; }; 3970 incidentFunc = incidentFunc || (g.isDirected() 3971 ? function(u) { return g.outEdges(u); } 3972 : function(u) { return g.incidentEdges(u); }); 3973 3974 nodes.forEach(function(u) { 3975 results[u] = {}; 3976 results[u][u] = { distance: 0 }; 3977 nodes.forEach(function(v) { 3978 if (u !== v) { 3979 results[u][v] = { distance: Number.POSITIVE_INFINITY }; 3980 } 3981 }); 3982 incidentFunc(u).forEach(function(e) { 3983 var incidentNodes = g.incidentNodes(e), 3984 v = incidentNodes[0] !== u ? incidentNodes[0] : incidentNodes[1], 3985 d = weightFunc(e); 3986 if (d < results[u][v].distance) { 3987 results[u][v] = { distance: d, predecessor: u }; 3988 } 3989 }); 3990 }); 3991 3992 nodes.forEach(function(k) { 3993 var rowK = results[k]; 3994 nodes.forEach(function(i) { 3995 var rowI = results[i]; 3996 nodes.forEach(function(j) { 3997 var ik = rowI[k]; 3998 var kj = rowK[j]; 3999 var ij = rowI[j]; 4000 var altDistance = ik.distance + kj.distance; 4001 if (altDistance < ij.distance) { 4002 ij.distance = altDistance; 4003 ij.predecessor = kj.predecessor; 4004 } 4005 }); 4006 }); 4007 }); 4008 4009 return results; 4010 } 4011 4012 },{}],39:[function(require,module,exports){ 4013 var topsort = require("./topsort"); 4014 4015 module.exports = isAcyclic; 4016 4017 /* 4018 * Given a Digraph **g** this function returns `true` if the graph has no 4019 * cycles and returns `false` if it does. This algorithm returns as soon as it 4020 * detects the first cycle. 4021 * 4022 * Use [alg.findCycles][] if you need the actual list of cycles in a graph. 4023 * 4024 * [alg.findCycles]: findCycles.js.html#findCycles 4025 * 4026 * @param {Digraph} g the graph to test for cycles 4027 */ 4028 function isAcyclic(g) { 4029 try { 4030 topsort(g); 4031 } catch (e) { 4032 if (e instanceof topsort.CycleException) return false; 4033 throw e; 4034 } 4035 return true; 4036 } 4037 4038 },{"./topsort":44}],40:[function(require,module,exports){ 4039 /* jshint -W079 */ 4040 var Set = require("cp-data").Set; 4041 /* jshint +W079 */ 4042 4043 module.exports = postorder; 4044 4045 // Postorder traversal of g, calling f for each visited node. Assumes the graph 4046 // is a tree. 4047 function postorder(g, root, f) { 4048 var visited = new Set(); 4049 if (g.isDirected()) { 4050 throw new Error("This function only works for undirected graphs"); 4051 } 4052 function dfs(u, prev) { 4053 if (visited.has(u)) { 4054 throw new Error("The input graph is not a tree: " + g); 4055 } 4056 visited.add(u); 4057 g.neighbors(u).forEach(function(v) { 4058 if (v !== prev) dfs(v, u); 4059 }); 4060 f(u); 4061 } 4062 dfs(root); 4063 } 4064 4065 },{"cp-data":5}],41:[function(require,module,exports){ 4066 /* jshint -W079 */ 4067 var Set = require("cp-data").Set; 4068 /* jshint +W079 */ 4069 4070 module.exports = preorder; 4071 4072 // Preorder traversal of g, calling f for each visited node. Assumes the graph 4073 // is a tree. 4074 function preorder(g, root, f) { 4075 var visited = new Set(); 4076 if (g.isDirected()) { 4077 throw new Error("This function only works for undirected graphs"); 4078 } 4079 function dfs(u, prev) { 4080 if (visited.has(u)) { 4081 throw new Error("The input graph is not a tree: " + g); 4082 } 4083 visited.add(u); 4084 f(u); 4085 g.neighbors(u).forEach(function(v) { 4086 if (v !== prev) dfs(v, u); 4087 }); 4088 } 4089 dfs(root); 4090 } 4091 4092 },{"cp-data":5}],42:[function(require,module,exports){ 4093 var Graph = require("../Graph"), 4094 PriorityQueue = require("cp-data").PriorityQueue; 4095 4096 module.exports = prim; 4097 4098 /** 4099 * [Prim's algorithm][] takes a connected undirected graph and generates a 4100 * [minimum spanning tree][]. This function returns the minimum spanning 4101 * tree as an undirected graph. This algorithm is derived from the description 4102 * in "Introduction to Algorithms", Third Edition, Cormen, et al., Pg 634. 4103 * 4104 * This function takes a `weightFunc(e)` which returns the weight of the edge 4105 * `e`. It throws an Error if the graph is not connected. 4106 * 4107 * This function takes `O(|E| log |V|)` time. 4108 * 4109 * [Prim's algorithm]: https://en.wikipedia.org/wiki/Prim's_algorithm 4110 * [minimum spanning tree]: https://en.wikipedia.org/wiki/Minimum_spanning_tree 4111 * 4112 * @param {Graph} g the graph used to generate the minimum spanning tree 4113 * @param {Function} weightFunc the weight function to use 4114 */ 4115 function prim(g, weightFunc) { 4116 var result = new Graph(), 4117 parents = {}, 4118 pq = new PriorityQueue(), 4119 u; 4120 4121 function updateNeighbors(e) { 4122 var incidentNodes = g.incidentNodes(e), 4123 v = incidentNodes[0] !== u ? incidentNodes[0] : incidentNodes[1], 4124 pri = pq.priority(v); 4125 if (pri !== undefined) { 4126 var edgeWeight = weightFunc(e); 4127 if (edgeWeight < pri) { 4128 parents[v] = u; 4129 pq.decrease(v, edgeWeight); 4130 } 4131 } 4132 } 4133 4134 if (g.order() === 0) { 4135 return result; 4136 } 4137 4138 g.eachNode(function(u) { 4139 pq.add(u, Number.POSITIVE_INFINITY); 4140 result.addNode(u); 4141 }); 4142 4143 // Start from an arbitrary node 4144 pq.decrease(g.nodes()[0], 0); 4145 4146 var init = false; 4147 while (pq.size() > 0) { 4148 u = pq.removeMin(); 4149 if (u in parents) { 4150 result.addEdge(null, u, parents[u]); 4151 } else if (init) { 4152 throw new Error("Input graph is not connected: " + g); 4153 } else { 4154 init = true; 4155 } 4156 4157 g.incidentEdges(u).forEach(updateNeighbors); 4158 } 4159 4160 return result; 4161 } 4162 4163 },{"../Graph":33,"cp-data":5}],43:[function(require,module,exports){ 4164 module.exports = tarjan; 4165 4166 /** 4167 * This function is an implementation of [Tarjan's algorithm][] which finds 4168 * all [strongly connected components][] in the directed graph **g**. Each 4169 * strongly connected component is composed of nodes that can reach all other 4170 * nodes in the component via directed edges. A strongly connected component 4171 * can consist of a single node if that node cannot both reach and be reached 4172 * by any other specific node in the graph. Components of more than one node 4173 * are guaranteed to have at least one cycle. 4174 * 4175 * This function returns an array of components. Each component is itself an 4176 * array that contains the ids of all nodes in the component. 4177 * 4178 * [Tarjan's algorithm]: http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm 4179 * [strongly connected components]: http://en.wikipedia.org/wiki/Strongly_connected_component 4180 * 4181 * @param {Digraph} g the graph to search for strongly connected components 4182 */ 4183 function tarjan(g) { 4184 if (!g.isDirected()) { 4185 throw new Error("tarjan can only be applied to a directed graph. Bad input: " + g); 4186 } 4187 4188 var index = 0, 4189 stack = [], 4190 visited = {}, // node id -> { onStack, lowlink, index } 4191 results = []; 4192 4193 function dfs(u) { 4194 var entry = visited[u] = { 4195 onStack: true, 4196 lowlink: index, 4197 index: index++ 4198 }; 4199 stack.push(u); 4200 4201 g.successors(u).forEach(function(v) { 4202 if (!(v in visited)) { 4203 dfs(v); 4204 entry.lowlink = Math.min(entry.lowlink, visited[v].lowlink); 4205 } else if (visited[v].onStack) { 4206 entry.lowlink = Math.min(entry.lowlink, visited[v].index); 4207 } 4208 }); 4209 4210 if (entry.lowlink === entry.index) { 4211 var cmpt = [], 4212 v; 4213 do { 4214 v = stack.pop(); 4215 visited[v].onStack = false; 4216 cmpt.push(v); 4217 } while (u !== v); 4218 results.push(cmpt); 4219 } 4220 } 4221 4222 g.nodes().forEach(function(u) { 4223 if (!(u in visited)) { 4224 dfs(u); 4225 } 4226 }); 4227 4228 return results; 4229 } 4230 4231 },{}],44:[function(require,module,exports){ 4232 module.exports = topsort; 4233 topsort.CycleException = CycleException; 4234 4235 /* 4236 * Given a graph **g**, this function returns an ordered list of nodes such 4237 * that for each edge `u -> v`, `u` appears before `v` in the list. If the 4238 * graph has a cycle it is impossible to generate such a list and 4239 * **CycleException** is thrown. 4240 * 4241 * See [topological sorting](https://en.wikipedia.org/wiki/Topological_sorting) 4242 * for more details about how this algorithm works. 4243 * 4244 * @param {Digraph} g the graph to sort 4245 */ 4246 function topsort(g) { 4247 if (!g.isDirected()) { 4248 throw new Error("topsort can only be applied to a directed graph. Bad input: " + g); 4249 } 4250 4251 var visited = {}; 4252 var stack = {}; 4253 var results = []; 4254 4255 function visit(node) { 4256 if (node in stack) { 4257 throw new CycleException(); 4258 } 4259 4260 if (!(node in visited)) { 4261 stack[node] = true; 4262 visited[node] = true; 4263 g.predecessors(node).forEach(function(pred) { 4264 visit(pred); 4265 }); 4266 delete stack[node]; 4267 results.push(node); 4268 } 4269 } 4270 4271 var sinks = g.sinks(); 4272 if (g.order() !== 0 && sinks.length === 0) { 4273 throw new CycleException(); 4274 } 4275 4276 g.sinks().forEach(function(sink) { 4277 visit(sink); 4278 }); 4279 4280 return results; 4281 } 4282 4283 function CycleException() {} 4284 4285 CycleException.prototype.toString = function() { 4286 return "Graph has at least one cycle"; 4287 }; 4288 4289 },{}],45:[function(require,module,exports){ 4290 // This file provides a helper function that mixes-in Dot behavior to an 4291 // existing graph prototype. 4292 4293 /* jshint -W079 */ 4294 var Set = require("cp-data").Set; 4295 /* jshint +W079 */ 4296 4297 module.exports = compoundify; 4298 4299 // Extends the given SuperConstructor with the ability for nodes to contain 4300 // other nodes. A special node id `null` is used to indicate the root graph. 4301 function compoundify(SuperConstructor) { 4302 function Constructor() { 4303 SuperConstructor.call(this); 4304 4305 // Map of object id -> parent id (or null for root graph) 4306 this._parents = {}; 4307 4308 // Map of id (or null) -> children set 4309 this._children = {}; 4310 this._children[null] = new Set(); 4311 } 4312 4313 Constructor.prototype = new SuperConstructor(); 4314 Constructor.prototype.constructor = Constructor; 4315 4316 Constructor.prototype.parent = function(u, parent) { 4317 this._strictGetNode(u); 4318 4319 if (arguments.length < 2) { 4320 return this._parents[u]; 4321 } 4322 4323 if (u === parent) { 4324 throw new Error("Cannot make " + u + " a parent of itself"); 4325 } 4326 if (parent !== null) { 4327 this._strictGetNode(parent); 4328 } 4329 4330 this._children[this._parents[u]].remove(u); 4331 this._parents[u] = parent; 4332 this._children[parent].add(u); 4333 }; 4334 4335 Constructor.prototype.children = function(u) { 4336 if (u !== null) { 4337 this._strictGetNode(u); 4338 } 4339 return this._children[u].keys(); 4340 }; 4341 4342 Constructor.prototype.addNode = function(u, value) { 4343 u = SuperConstructor.prototype.addNode.call(this, u, value); 4344 this._parents[u] = null; 4345 this._children[u] = new Set(); 4346 this._children[null].add(u); 4347 return u; 4348 }; 4349 4350 Constructor.prototype.delNode = function(u) { 4351 // Promote all children to the parent of the subgraph 4352 var parent = this.parent(u); 4353 this._children[u].keys().forEach(function(child) { 4354 this.parent(child, parent); 4355 }, this); 4356 4357 this._children[parent].remove(u); 4358 delete this._parents[u]; 4359 delete this._children[u]; 4360 4361 return SuperConstructor.prototype.delNode.call(this, u); 4362 }; 4363 4364 Constructor.prototype.copy = function() { 4365 var copy = SuperConstructor.prototype.copy.call(this); 4366 this.nodes().forEach(function(u) { 4367 copy.parent(u, this.parent(u)); 4368 }, this); 4369 return copy; 4370 }; 4371 4372 Constructor.prototype.filterNodes = function(filter) { 4373 var self = this, 4374 copy = SuperConstructor.prototype.filterNodes.call(this, filter); 4375 4376 var parents = {}; 4377 function findParent(u) { 4378 var parent = self.parent(u); 4379 if (parent === null || copy.hasNode(parent)) { 4380 parents[u] = parent; 4381 return parent; 4382 } else if (parent in parents) { 4383 return parents[parent]; 4384 } else { 4385 return findParent(parent); 4386 } 4387 } 4388 4389 copy.eachNode(function(u) { copy.parent(u, findParent(u)); }); 4390 4391 return copy; 4392 }; 4393 4394 return Constructor; 4395 } 4396 4397 },{"cp-data":5}],46:[function(require,module,exports){ 4398 var Graph = require("../Graph"), 4399 Digraph = require("../Digraph"), 4400 CGraph = require("../CGraph"), 4401 CDigraph = require("../CDigraph"); 4402 4403 exports.decode = function(nodes, edges, Ctor) { 4404 Ctor = Ctor || Digraph; 4405 4406 if (typeOf(nodes) !== "Array") { 4407 throw new Error("nodes is not an Array"); 4408 } 4409 4410 if (typeOf(edges) !== "Array") { 4411 throw new Error("edges is not an Array"); 4412 } 4413 4414 if (typeof Ctor === "string") { 4415 switch(Ctor) { 4416 case "graph": Ctor = Graph; break; 4417 case "digraph": Ctor = Digraph; break; 4418 case "cgraph": Ctor = CGraph; break; 4419 case "cdigraph": Ctor = CDigraph; break; 4420 default: throw new Error("Unrecognized graph type: " + Ctor); 4421 } 4422 } 4423 4424 var graph = new Ctor(); 4425 4426 nodes.forEach(function(u) { 4427 graph.addNode(u.id, u.value); 4428 }); 4429 4430 // If the graph is compound, set up children... 4431 if (graph.parent) { 4432 nodes.forEach(function(u) { 4433 if (u.children) { 4434 u.children.forEach(function(v) { 4435 graph.parent(v, u.id); 4436 }); 4437 } 4438 }); 4439 } 4440 4441 edges.forEach(function(e) { 4442 graph.addEdge(e.id, e.u, e.v, e.value); 4443 }); 4444 4445 return graph; 4446 }; 4447 4448 exports.encode = function(graph) { 4449 var nodes = []; 4450 var edges = []; 4451 4452 graph.eachNode(function(u, value) { 4453 var node = {id: u, value: value}; 4454 if (graph.children) { 4455 var children = graph.children(u); 4456 if (children.length) { 4457 node.children = children; 4458 } 4459 } 4460 nodes.push(node); 4461 }); 4462 4463 graph.eachEdge(function(e, u, v, value) { 4464 edges.push({id: e, u: u, v: v, value: value}); 4465 }); 4466 4467 var type; 4468 if (graph instanceof CDigraph) { 4469 type = "cdigraph"; 4470 } else if (graph instanceof CGraph) { 4471 type = "cgraph"; 4472 } else if (graph instanceof Digraph) { 4473 type = "digraph"; 4474 } else if (graph instanceof Graph) { 4475 type = "graph"; 4476 } else { 4477 throw new Error("Couldn't determine type of graph: " + graph); 4478 } 4479 4480 return { nodes: nodes, edges: edges, type: type }; 4481 }; 4482 4483 function typeOf(obj) { 4484 return Object.prototype.toString.call(obj).slice(8, -1); 4485 } 4486 4487 },{"../CDigraph":30,"../CGraph":31,"../Digraph":32,"../Graph":33}],47:[function(require,module,exports){ 4488 /* jshint -W079 */ 4489 var Set = require("cp-data").Set; 4490 /* jshint +W079 */ 4491 4492 exports.all = function() { 4493 return function() { return true; }; 4494 }; 4495 4496 exports.nodesFromList = function(nodes) { 4497 var set = new Set(nodes); 4498 return function(u) { 4499 return set.has(u); 4500 }; 4501 }; 4502 4503 },{"cp-data":5}],48:[function(require,module,exports){ 4504 var Graph = require("./Graph"), 4505 Digraph = require("./Digraph"); 4506 4507 // Side-effect based changes are lousy, but node doesn't seem to resolve the 4508 // requires cycle. 4509 4510 /** 4511 * Returns a new directed graph using the nodes and edges from this graph. The 4512 * new graph will have the same nodes, but will have twice the number of edges: 4513 * each edge is split into two edges with opposite directions. Edge ids, 4514 * consequently, are not preserved by this transformation. 4515 */ 4516 Graph.prototype.toDigraph = 4517 Graph.prototype.asDirected = function() { 4518 var g = new Digraph(); 4519 this.eachNode(function(u, value) { g.addNode(u, value); }); 4520 this.eachEdge(function(e, u, v, value) { 4521 g.addEdge(null, u, v, value); 4522 g.addEdge(null, v, u, value); 4523 }); 4524 return g; 4525 }; 4526 4527 /** 4528 * Returns a new undirected graph using the nodes and edges from this graph. 4529 * The new graph will have the same nodes, but the edges will be made 4530 * undirected. Edge ids are preserved in this transformation. 4531 */ 4532 Digraph.prototype.toGraph = 4533 Digraph.prototype.asUndirected = function() { 4534 var g = new Graph(); 4535 this.eachNode(function(u, value) { g.addNode(u, value); }); 4536 this.eachEdge(function(e, u, v, value) { 4537 g.addEdge(e, u, v, value); 4538 }); 4539 return g; 4540 }; 4541 4542 },{"./Digraph":32,"./Graph":33}],49:[function(require,module,exports){ 4543 // Returns an array of all values for properties of **o**. 4544 exports.values = function(o) { 4545 var ks = Object.keys(o), 4546 len = ks.length, 4547 result = new Array(len), 4548 i; 4549 for (i = 0; i < len; ++i) { 4550 result[i] = o[ks[i]]; 4551 } 4552 return result; 4553 }; 4554 4555 },{}],50:[function(require,module,exports){ 4556 module.exports = '0.7.4'; 4557 4558 },{}]},{},[1]) 4559 ;