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