graphlib.core.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173
  1. (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.graphlib = f()}})(function(){var define,module,exports;return (function(){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);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.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}return e})()({1:[function(require,module,exports){
  2. module.exports = {
  3. Graph: require('./lib/graph'),
  4. json: require('./lib/json'),
  5. alg: require('./lib/alg')
  6. }
  7. },{"./lib/alg":8,"./lib/graph":16,"./lib/json":17}],2:[function(require,module,exports){
  8. var _ = require('../lodash')
  9. module.exports = components
  10. function components (g) {
  11. const visited = {}
  12. const cmpts = []
  13. let cmpt
  14. function dfs (v) {
  15. if (_.has(visited, v)) return
  16. visited[v] = true
  17. cmpt.push(v)
  18. _.each(g.successors(v), dfs)
  19. _.each(g.predecessors(v), dfs)
  20. }
  21. _.each(g.nodes(), function (v) {
  22. cmpt = []
  23. dfs(v)
  24. if (cmpt.length) {
  25. cmpts.push(cmpt)
  26. }
  27. })
  28. return cmpts
  29. }
  30. },{"../lodash":18}],3:[function(require,module,exports){
  31. var _ = require('../lodash')
  32. module.exports = dfs
  33. /*
  34. * A helper that preforms a pre- or post-order traversal on the input graph
  35. * and returns the nodes in the order they were visited. If the graph is
  36. * undirected then this algorithm will navigate using neighbors. If the graph
  37. * is directed then this algorithm will navigate using successors.
  38. *
  39. * Order must be one of "pre" or "post".
  40. */
  41. function dfs (g, vs, order) {
  42. if (!_.isArray(vs)) {
  43. vs = [vs]
  44. }
  45. var navigation = (g.isDirected() ? g.successors : g.neighbors).bind(g)
  46. const acc = []
  47. const visited = {}
  48. _.each(vs, function (v) {
  49. if (!g.hasNode(v)) {
  50. throw new Error('Graph does not have node: ' + v)
  51. }
  52. doDfs(g, v, order === 'post', visited, navigation, acc)
  53. })
  54. return acc
  55. }
  56. function doDfs (g, v, postorder, visited, navigation, acc) {
  57. if (!_.has(visited, v)) {
  58. visited[v] = true
  59. if (!postorder) { acc.push(v) }
  60. _.each(navigation(v), function (w) {
  61. doDfs(g, w, postorder, visited, navigation, acc)
  62. })
  63. if (postorder) { acc.push(v) }
  64. }
  65. }
  66. },{"../lodash":18}],4:[function(require,module,exports){
  67. const dijkstra = require('./dijkstra')
  68. const _ = require('../lodash')
  69. module.exports = dijkstraAll
  70. function dijkstraAll (g, weightFunc, edgeFunc) {
  71. return _.transform(g.nodes(), function (acc, v) {
  72. acc[v] = dijkstra(g, v, weightFunc, edgeFunc)
  73. }, {})
  74. }
  75. },{"../lodash":18,"./dijkstra":5}],5:[function(require,module,exports){
  76. const _ = require('../lodash')
  77. const PriorityQueue = require('../data/priority-queue')
  78. module.exports = dijkstra
  79. var DEFAULT_WEIGHT_FUNC = _.constant(1)
  80. function dijkstra (g, source, weightFn, edgeFn) {
  81. return runDijkstra(g, String(source),
  82. weightFn || DEFAULT_WEIGHT_FUNC,
  83. edgeFn || function (v) { return g.outEdges(v) })
  84. }
  85. function runDijkstra (g, source, weightFn, edgeFn) {
  86. const results = {}
  87. const pq = new PriorityQueue()
  88. let v, vEntry
  89. var updateNeighbors = function (edge) {
  90. const w = edge.v !== v ? edge.v : edge.w
  91. const wEntry = results[w]
  92. const weight = weightFn(edge)
  93. const distance = vEntry.distance + weight
  94. if (weight < 0) {
  95. throw new Error('dijkstra does not allow negative edge weights. ' +
  96. 'Bad edge: ' + edge + ' Weight: ' + weight)
  97. }
  98. if (distance < wEntry.distance) {
  99. wEntry.distance = distance
  100. wEntry.predecessor = v
  101. pq.decrease(w, distance)
  102. }
  103. }
  104. g.nodes().forEach(function (v) {
  105. var distance = v === source ? 0 : Number.POSITIVE_INFINITY
  106. results[v] = { distance: distance }
  107. pq.add(v, distance)
  108. })
  109. while (pq.size() > 0) {
  110. v = pq.removeMin()
  111. vEntry = results[v]
  112. if (vEntry.distance === Number.POSITIVE_INFINITY) {
  113. break
  114. }
  115. edgeFn(v).forEach(updateNeighbors)
  116. }
  117. return results
  118. }
  119. },{"../data/priority-queue":15,"../lodash":18}],6:[function(require,module,exports){
  120. const _ = require('../lodash')
  121. const tarjan = require('./tarjan')
  122. module.exports = findCycles
  123. function findCycles (g) {
  124. return _.filter(tarjan(g), function (cmpt) {
  125. return cmpt.length > 1 || (cmpt.length === 1 && g.hasEdge(cmpt[0], cmpt[0]))
  126. })
  127. }
  128. },{"../lodash":18,"./tarjan":13}],7:[function(require,module,exports){
  129. var _ = require('../lodash')
  130. module.exports = floydWarshall
  131. var DEFAULT_WEIGHT_FUNC = _.constant(1)
  132. function floydWarshall (g, weightFn, edgeFn) {
  133. return runFloydWarshall(g,
  134. weightFn || DEFAULT_WEIGHT_FUNC,
  135. edgeFn || function (v) { return g.outEdges(v) })
  136. }
  137. function runFloydWarshall (g, weightFn, edgeFn) {
  138. const results = {}
  139. const nodes = g.nodes()
  140. nodes.forEach(function (v) {
  141. results[v] = {}
  142. results[v][v] = { distance: 0 }
  143. nodes.forEach(function (w) {
  144. if (v !== w) {
  145. results[v][w] = { distance: Number.POSITIVE_INFINITY }
  146. }
  147. })
  148. edgeFn(v).forEach(function (edge) {
  149. const w = edge.v === v ? edge.w : edge.v
  150. const d = weightFn(edge)
  151. results[v][w] = { distance: d, predecessor: v }
  152. })
  153. })
  154. nodes.forEach(function (k) {
  155. var rowK = results[k]
  156. nodes.forEach(function (i) {
  157. var rowI = results[i]
  158. nodes.forEach(function (j) {
  159. var ik = rowI[k]
  160. var kj = rowK[j]
  161. var ij = rowI[j]
  162. var altDistance = ik.distance + kj.distance
  163. if (altDistance < ij.distance) {
  164. ij.distance = altDistance
  165. ij.predecessor = kj.predecessor
  166. }
  167. })
  168. })
  169. })
  170. return results
  171. }
  172. },{"../lodash":18}],8:[function(require,module,exports){
  173. module.exports = {
  174. components: require('./components'),
  175. dijkstra: require('./dijkstra'),
  176. dijkstraAll: require('./dijkstra-all'),
  177. findCycles: require('./find-cycles'),
  178. floydWarshall: require('./floyd-warshall'),
  179. isAcyclic: require('./is-acyclic'),
  180. postorder: require('./postorder'),
  181. preorder: require('./preorder'),
  182. prim: require('./prim'),
  183. tarjan: require('./tarjan'),
  184. topsort: require('./topsort')
  185. }
  186. },{"./components":2,"./dijkstra":5,"./dijkstra-all":4,"./find-cycles":6,"./floyd-warshall":7,"./is-acyclic":9,"./postorder":10,"./preorder":11,"./prim":12,"./tarjan":13,"./topsort":14}],9:[function(require,module,exports){
  187. var topsort = require('./topsort')
  188. module.exports = isAcyclic
  189. function isAcyclic (g) {
  190. try {
  191. topsort(g)
  192. } catch (e) {
  193. if (e instanceof topsort.CycleException) {
  194. return false
  195. }
  196. throw e
  197. }
  198. return true
  199. }
  200. },{"./topsort":14}],10:[function(require,module,exports){
  201. var dfs = require('./dfs')
  202. module.exports = postorder
  203. function postorder (g, vs) {
  204. return dfs(g, vs, 'post')
  205. }
  206. },{"./dfs":3}],11:[function(require,module,exports){
  207. var dfs = require('./dfs')
  208. module.exports = preorder
  209. function preorder (g, vs) {
  210. return dfs(g, vs, 'pre')
  211. }
  212. },{"./dfs":3}],12:[function(require,module,exports){
  213. const _ = require('../lodash')
  214. const Graph = require('../graph')
  215. const PriorityQueue = require('../data/priority-queue')
  216. module.exports = prim
  217. function prim (g, weightFunc) {
  218. const result = new Graph()
  219. const parents = {}
  220. const pq = new PriorityQueue()
  221. let v
  222. function updateNeighbors (edge) {
  223. const w = edge.v === v ? edge.w : edge.v
  224. const pri = pq.priority(w)
  225. if (pri !== undefined) {
  226. var edgeWeight = weightFunc(edge)
  227. if (edgeWeight < pri) {
  228. parents[w] = v
  229. pq.decrease(w, edgeWeight)
  230. }
  231. }
  232. }
  233. if (g.nodeCount() === 0) {
  234. return result
  235. }
  236. _.each(g.nodes(), function (v) {
  237. pq.add(v, Number.POSITIVE_INFINITY)
  238. result.setNode(v)
  239. })
  240. // Start from an arbitrary node
  241. pq.decrease(g.nodes()[0], 0)
  242. var init = false
  243. while (pq.size() > 0) {
  244. v = pq.removeMin()
  245. if (_.has(parents, v)) {
  246. result.setEdge(v, parents[v])
  247. } else if (init) {
  248. throw new Error('Input graph is not connected: ' + g)
  249. } else {
  250. init = true
  251. }
  252. g.nodeEdges(v).forEach(updateNeighbors)
  253. }
  254. return result
  255. }
  256. },{"../data/priority-queue":15,"../graph":16,"../lodash":18}],13:[function(require,module,exports){
  257. var _ = require('../lodash')
  258. module.exports = tarjan
  259. function tarjan (g) {
  260. let index = 0
  261. const stack = []
  262. const visited = {} // node id -> { onStack, lowlink, index }
  263. const results = []
  264. function dfs (v) {
  265. var entry = visited[v] = {
  266. onStack: true,
  267. lowlink: index,
  268. index: index++
  269. }
  270. stack.push(v)
  271. g.successors(v).forEach(function (w) {
  272. if (!_.has(visited, w)) {
  273. dfs(w)
  274. entry.lowlink = Math.min(entry.lowlink, visited[w].lowlink)
  275. } else if (visited[w].onStack) {
  276. entry.lowlink = Math.min(entry.lowlink, visited[w].index)
  277. }
  278. })
  279. if (entry.lowlink === entry.index) {
  280. const cmpt = []
  281. let w
  282. do {
  283. w = stack.pop()
  284. visited[w].onStack = false
  285. cmpt.push(w)
  286. } while (v !== w)
  287. results.push(cmpt)
  288. }
  289. }
  290. g.nodes().forEach(function (v) {
  291. if (!_.has(visited, v)) {
  292. dfs(v)
  293. }
  294. })
  295. return results
  296. }
  297. },{"../lodash":18}],14:[function(require,module,exports){
  298. const _ = require('../lodash')
  299. module.exports = topsort
  300. topsort.CycleException = CycleException
  301. function topsort (g) {
  302. const visited = {}
  303. const stack = {}
  304. const results = []
  305. function visit (node) {
  306. if (_.has(stack, node)) {
  307. throw new CycleException()
  308. }
  309. if (!_.has(visited, node)) {
  310. stack[node] = true
  311. visited[node] = true
  312. _.each(g.predecessors(node), visit)
  313. delete stack[node]
  314. results.push(node)
  315. }
  316. }
  317. _.each(g.sinks(), visit)
  318. if (_.size(visited) !== g.nodeCount()) {
  319. throw new CycleException()
  320. }
  321. return results
  322. }
  323. function CycleException () {}
  324. CycleException.prototype = new Error() // must be an instance of Error to pass testing
  325. },{"../lodash":18}],15:[function(require,module,exports){
  326. const _ = require('../lodash')
  327. module.exports = PriorityQueue
  328. /**
  329. * A min-priority queue data structure. This algorithm is derived from Cormen,
  330. * et al., "Introduction to Algorithms". The basic idea of a min-priority
  331. * queue is that you can efficiently (in O(1) time) get the smallest key in
  332. * the queue. Adding and removing elements takes O(log n) time. A key can
  333. * have its priority decreased in O(log n) time.
  334. */
  335. function PriorityQueue () {
  336. this._arr = []
  337. this._keyIndices = {}
  338. }
  339. /**
  340. * Returns the number of elements in the queue. Takes `O(1)` time.
  341. */
  342. PriorityQueue.prototype.size = function () {
  343. return this._arr.length
  344. }
  345. /**
  346. * Returns the keys that are in the queue. Takes `O(n)` time.
  347. */
  348. PriorityQueue.prototype.keys = function () {
  349. return this._arr.map(function (x) { return x.key })
  350. }
  351. /**
  352. * Returns `true` if **key** is in the queue and `false` if not.
  353. */
  354. PriorityQueue.prototype.has = function (key) {
  355. return _.has(this._keyIndices, key)
  356. }
  357. /**
  358. * Returns the priority for **key**. If **key** is not present in the queue
  359. * then this function returns `undefined`. Takes `O(1)` time.
  360. *
  361. * @param {Object} key
  362. */
  363. PriorityQueue.prototype.priority = function (key) {
  364. var index = this._keyIndices[key]
  365. if (index !== undefined) {
  366. return this._arr[index].priority
  367. }
  368. }
  369. /**
  370. * Returns the key for the minimum element in this queue. If the queue is
  371. * empty this function throws an Error. Takes `O(1)` time.
  372. */
  373. PriorityQueue.prototype.min = function () {
  374. if (this.size() === 0) {
  375. throw new Error('Queue underflow')
  376. }
  377. return this._arr[0].key
  378. }
  379. /**
  380. * Inserts a new key into the priority queue. If the key already exists in
  381. * the queue this function returns `false`; otherwise it will return `true`.
  382. * Takes `O(n)` time.
  383. *
  384. * @param {Object} key the key to add
  385. * @param {Number} priority the initial priority for the key
  386. */
  387. PriorityQueue.prototype.add = function (key, priority) {
  388. var keyIndices = this._keyIndices
  389. key = String(key)
  390. if (!_.has(keyIndices, key)) {
  391. var arr = this._arr
  392. var index = arr.length
  393. keyIndices[key] = index
  394. arr.push({key: key, priority: priority})
  395. this._decrease(index)
  396. return true
  397. }
  398. return false
  399. }
  400. /**
  401. * Removes and returns the smallest key in the queue. Takes `O(log n)` time.
  402. */
  403. PriorityQueue.prototype.removeMin = function () {
  404. this._swap(0, this._arr.length - 1)
  405. var min = this._arr.pop()
  406. delete this._keyIndices[min.key]
  407. this._heapify(0)
  408. return min.key
  409. }
  410. /**
  411. * Decreases the priority for **key** to **priority**. If the new priority is
  412. * greater than the previous priority, this function will throw an Error.
  413. *
  414. * @param {Object} key the key for which to raise priority
  415. * @param {Number} priority the new priority for the key
  416. */
  417. PriorityQueue.prototype.decrease = function (key, priority) {
  418. var index = this._keyIndices[key]
  419. if (priority > this._arr[index].priority) {
  420. throw new Error('New priority is greater than current priority. ' +
  421. 'Key: ' + key + ' Old: ' + this._arr[index].priority + ' New: ' + priority)
  422. }
  423. this._arr[index].priority = priority
  424. this._decrease(index)
  425. }
  426. PriorityQueue.prototype._heapify = function (i) {
  427. const arr = this._arr
  428. const l = 2 * i
  429. const r = l + 1
  430. let largest = i
  431. if (l < arr.length) {
  432. largest = arr[l].priority < arr[largest].priority ? l : largest
  433. if (r < arr.length) {
  434. largest = arr[r].priority < arr[largest].priority ? r : largest
  435. }
  436. if (largest !== i) {
  437. this._swap(i, largest)
  438. this._heapify(largest)
  439. }
  440. }
  441. }
  442. PriorityQueue.prototype._decrease = function (index) {
  443. var arr = this._arr
  444. var priority = arr[index].priority
  445. var parent
  446. while (index !== 0) {
  447. parent = index >> 1
  448. if (arr[parent].priority < priority) {
  449. break
  450. }
  451. this._swap(index, parent)
  452. index = parent
  453. }
  454. }
  455. PriorityQueue.prototype._swap = function (i, j) {
  456. var arr = this._arr
  457. var keyIndices = this._keyIndices
  458. var origArrI = arr[i]
  459. var origArrJ = arr[j]
  460. arr[i] = origArrJ
  461. arr[j] = origArrI
  462. keyIndices[origArrJ.key] = i
  463. keyIndices[origArrI.key] = j
  464. }
  465. },{"../lodash":18}],16:[function(require,module,exports){
  466. const _ = require('./lodash')
  467. module.exports = Graph
  468. const DEFAULT_EDGE_NAME = '\x00'
  469. const GRAPH_NODE = '\x00'
  470. const EDGE_KEY_DELIM = '\x01'
  471. // Implementation notes:
  472. //
  473. // * Node id query functions should return string ids for the nodes
  474. // * Edge id query functions should return an "edgeObj", edge object, that is
  475. // composed of enough information to uniquely identify an edge: {v, w, name}.
  476. // * Internally we use an "edgeId", a stringified form of the edgeObj, to
  477. // reference edges. This is because we need a performant way to look these
  478. // edges up and, object properties, which have string keys, are the closest
  479. // we're going to get to a performant hashtable in JavaScript.
  480. function Graph (opts) {
  481. this._isDirected = _.has(opts, 'directed') ? opts.directed : true
  482. this._isMultigraph = _.has(opts, 'multigraph') ? opts.multigraph : false
  483. this._isCompound = _.has(opts, 'compound') ? opts.compound : false
  484. // Label for the graph itself
  485. this._label = undefined
  486. // Defaults to be set when creating a new node
  487. this._defaultNodeLabelFn = _.constant(undefined)
  488. // Defaults to be set when creating a new edge
  489. this._defaultEdgeLabelFn = _.constant(undefined)
  490. // v -> label
  491. this._nodes = {}
  492. if (this._isCompound) {
  493. // v -> parent
  494. this._parent = {}
  495. // v -> children
  496. this._children = {}
  497. this._children[GRAPH_NODE] = {}
  498. }
  499. // v -> edgeObj
  500. this._in = {}
  501. // u -> v -> Number
  502. this._preds = {}
  503. // v -> edgeObj
  504. this._out = {}
  505. // v -> w -> Number
  506. this._sucs = {}
  507. // e -> edgeObj
  508. this._edgeObjs = {}
  509. // e -> label
  510. this._edgeLabels = {}
  511. }
  512. /* Number of nodes in the graph. Should only be changed by the implementation. */
  513. Graph.prototype._nodeCount = 0
  514. /* Number of edges in the graph. Should only be changed by the implementation. */
  515. Graph.prototype._edgeCount = 0
  516. /* === Graph functions ========= */
  517. Graph.prototype.isDirected = function () {
  518. return this._isDirected
  519. }
  520. Graph.prototype.isMultigraph = function () {
  521. return this._isMultigraph
  522. }
  523. Graph.prototype.isCompound = function () {
  524. return this._isCompound
  525. }
  526. Graph.prototype.setGraph = function (label) {
  527. this._label = label
  528. return this
  529. }
  530. Graph.prototype.graph = function () {
  531. return this._label
  532. }
  533. /* === Node functions ========== */
  534. Graph.prototype.setDefaultNodeLabel = function (newDefault) {
  535. if (!_.isFunction(newDefault)) {
  536. newDefault = _.constant(newDefault)
  537. }
  538. this._defaultNodeLabelFn = newDefault
  539. return this
  540. }
  541. Graph.prototype.nodeCount = function () {
  542. return this._nodeCount
  543. }
  544. Graph.prototype.nodes = function () {
  545. return _.keys(this._nodes)
  546. }
  547. Graph.prototype.sources = function () {
  548. var self = this
  549. return _.filter(this.nodes(), function (v) {
  550. return _.isEmpty(self._in[v])
  551. })
  552. }
  553. Graph.prototype.sinks = function () {
  554. var self = this
  555. return _.filter(this.nodes(), function (v) {
  556. return _.isEmpty(self._out[v])
  557. })
  558. }
  559. Graph.prototype.setNodes = function (vs, value) {
  560. var args = arguments
  561. var self = this
  562. _.each(vs, function (v) {
  563. if (args.length > 1) {
  564. self.setNode(v, value)
  565. } else {
  566. self.setNode(v)
  567. }
  568. })
  569. return this
  570. }
  571. Graph.prototype.setNode = function (v, value) {
  572. if (_.has(this._nodes, v)) {
  573. if (arguments.length > 1) {
  574. this._nodes[v] = value
  575. }
  576. return this
  577. }
  578. this._nodes[v] = arguments.length > 1 ? value : this._defaultNodeLabelFn(v)
  579. if (this._isCompound) {
  580. this._parent[v] = GRAPH_NODE
  581. this._children[v] = {}
  582. this._children[GRAPH_NODE][v] = true
  583. }
  584. this._in[v] = {}
  585. this._preds[v] = {}
  586. this._out[v] = {}
  587. this._sucs[v] = {}
  588. ++this._nodeCount
  589. return this
  590. }
  591. Graph.prototype.node = function (v) {
  592. return this._nodes[v]
  593. }
  594. Graph.prototype.hasNode = function (v) {
  595. return _.has(this._nodes, v)
  596. }
  597. Graph.prototype.removeNode = function (v) {
  598. var self = this
  599. if (_.has(this._nodes, v)) {
  600. var removeEdge = function (e) { self.removeEdge(self._edgeObjs[e]) }
  601. delete this._nodes[v]
  602. if (this._isCompound) {
  603. this._removeFromParentsChildList(v)
  604. delete this._parent[v]
  605. _.each(this.children(v), function (child) {
  606. self.setParent(child)
  607. })
  608. delete this._children[v]
  609. }
  610. _.each(_.keys(this._in[v]), removeEdge)
  611. delete this._in[v]
  612. delete this._preds[v]
  613. _.each(_.keys(this._out[v]), removeEdge)
  614. delete this._out[v]
  615. delete this._sucs[v]
  616. --this._nodeCount
  617. }
  618. return this
  619. }
  620. Graph.prototype.setParent = function (v, parent) {
  621. if (!this._isCompound) {
  622. throw new Error('Cannot set parent in a non-compound graph')
  623. }
  624. if (_.isUndefined(parent)) {
  625. parent = GRAPH_NODE
  626. } else {
  627. // Coerce parent to string
  628. parent += ''
  629. for (var ancestor = parent;
  630. !_.isUndefined(ancestor);
  631. ancestor = this.parent(ancestor)) {
  632. if (ancestor === v) {
  633. throw new Error('Setting ' + parent + ' as parent of ' + v +
  634. ' would create a cycle')
  635. }
  636. }
  637. this.setNode(parent)
  638. }
  639. this.setNode(v)
  640. this._removeFromParentsChildList(v)
  641. this._parent[v] = parent
  642. this._children[parent][v] = true
  643. return this
  644. }
  645. Graph.prototype._removeFromParentsChildList = function (v) {
  646. delete this._children[this._parent[v]][v]
  647. }
  648. Graph.prototype.parent = function (v) {
  649. if (this._isCompound) {
  650. var parent = this._parent[v]
  651. if (parent !== GRAPH_NODE) {
  652. return parent
  653. }
  654. }
  655. }
  656. Graph.prototype.children = function (v) {
  657. if (_.isUndefined(v)) {
  658. v = GRAPH_NODE
  659. }
  660. if (this._isCompound) {
  661. var children = this._children[v]
  662. if (children) {
  663. return _.keys(children)
  664. }
  665. } else if (v === GRAPH_NODE) {
  666. return this.nodes()
  667. } else if (this.hasNode(v)) {
  668. return []
  669. }
  670. }
  671. Graph.prototype.predecessors = function (v) {
  672. var predsV = this._preds[v]
  673. if (predsV) {
  674. return _.keys(predsV)
  675. }
  676. }
  677. Graph.prototype.successors = function (v) {
  678. var sucsV = this._sucs[v]
  679. if (sucsV) {
  680. return _.keys(sucsV)
  681. }
  682. }
  683. Graph.prototype.neighbors = function (v) {
  684. var preds = this.predecessors(v)
  685. if (preds) {
  686. return _.union(preds, this.successors(v))
  687. }
  688. }
  689. Graph.prototype.isLeaf = function (v) {
  690. var neighbors
  691. if (this.isDirected()) {
  692. neighbors = this.successors(v)
  693. } else {
  694. neighbors = this.neighbors(v)
  695. }
  696. return neighbors.length === 0
  697. }
  698. Graph.prototype.filterNodes = function (filter) {
  699. var copy = new this.constructor({
  700. directed: this._isDirected,
  701. multigraph: this._isMultigraph,
  702. compound: this._isCompound
  703. })
  704. copy.setGraph(this.graph())
  705. var self = this
  706. _.each(this._nodes, function (value, v) {
  707. if (filter(v)) {
  708. copy.setNode(v, value)
  709. }
  710. })
  711. _.each(this._edgeObjs, function (e) {
  712. if (copy.hasNode(e.v) && copy.hasNode(e.w)) {
  713. copy.setEdge(e, self.edge(e))
  714. }
  715. })
  716. var parents = {}
  717. function findParent (v) {
  718. var parent = self.parent(v)
  719. if (parent === undefined || copy.hasNode(parent)) {
  720. parents[v] = parent
  721. return parent
  722. } else if (parent in parents) {
  723. return parents[parent]
  724. } else {
  725. return findParent(parent)
  726. }
  727. }
  728. if (this._isCompound) {
  729. _.each(copy.nodes(), function (v) {
  730. copy.setParent(v, findParent(v))
  731. })
  732. }
  733. return copy
  734. }
  735. /* === Edge functions ========== */
  736. Graph.prototype.setDefaultEdgeLabel = function (newDefault) {
  737. if (!_.isFunction(newDefault)) {
  738. newDefault = _.constant(newDefault)
  739. }
  740. this._defaultEdgeLabelFn = newDefault
  741. return this
  742. }
  743. Graph.prototype.edgeCount = function () {
  744. return this._edgeCount
  745. }
  746. Graph.prototype.edges = function () {
  747. return _.values(this._edgeObjs)
  748. }
  749. Graph.prototype.setPath = function (vs, value) {
  750. const self = this
  751. const args = arguments
  752. _.reduce(vs, function (v, w) {
  753. if (args.length > 1) {
  754. self.setEdge(v, w, value)
  755. } else {
  756. self.setEdge(v, w)
  757. }
  758. return w
  759. })
  760. return this
  761. }
  762. /*
  763. * setEdge(v, w, [value, [name]])
  764. * setEdge({ v, w, [name] }, [value])
  765. */
  766. Graph.prototype.setEdge = function () {
  767. let v, w, name, value
  768. let valueSpecified = false
  769. const arg0 = arguments[0]
  770. if (typeof arg0 === 'object' && arg0 !== null && 'v' in arg0) {
  771. v = arg0.v
  772. w = arg0.w
  773. name = arg0.name
  774. if (arguments.length === 2) {
  775. value = arguments[1]
  776. valueSpecified = true
  777. }
  778. } else {
  779. v = arg0
  780. w = arguments[1]
  781. name = arguments[3]
  782. if (arguments.length > 2) {
  783. value = arguments[2]
  784. valueSpecified = true
  785. }
  786. }
  787. v = '' + v
  788. w = '' + w
  789. if (!_.isUndefined(name)) {
  790. name = '' + name
  791. }
  792. var e = edgeArgsToId(this._isDirected, v, w, name)
  793. if (_.has(this._edgeLabels, e)) {
  794. if (valueSpecified) {
  795. this._edgeLabels[e] = value
  796. }
  797. return this
  798. }
  799. if (!_.isUndefined(name) && !this._isMultigraph) {
  800. throw new Error('Cannot set a named edge when isMultigraph = false')
  801. }
  802. // It didn't exist, so we need to create it.
  803. // First ensure the nodes exist.
  804. this.setNode(v)
  805. this.setNode(w)
  806. this._edgeLabels[e] = valueSpecified ? value : this._defaultEdgeLabelFn(v, w, name)
  807. var edgeObj = edgeArgsToObj(this._isDirected, v, w, name)
  808. // Ensure we add undirected edges in a consistent way.
  809. v = edgeObj.v
  810. w = edgeObj.w
  811. Object.freeze(edgeObj)
  812. this._edgeObjs[e] = edgeObj
  813. incrementOrInitEntry(this._preds[w], v)
  814. incrementOrInitEntry(this._sucs[v], w)
  815. this._in[w][e] = edgeObj
  816. this._out[v][e] = edgeObj
  817. this._edgeCount++
  818. return this
  819. }
  820. Graph.prototype.edge = function (v, w, name) {
  821. var e = (arguments.length === 1
  822. ? edgeObjToId(this._isDirected, arguments[0])
  823. : edgeArgsToId(this._isDirected, v, w, name))
  824. return this._edgeLabels[e]
  825. }
  826. Graph.prototype.hasEdge = function (v, w, name) {
  827. var e = (arguments.length === 1
  828. ? edgeObjToId(this._isDirected, arguments[0])
  829. : edgeArgsToId(this._isDirected, v, w, name))
  830. return _.has(this._edgeLabels, e)
  831. }
  832. Graph.prototype.removeEdge = function (v, w, name) {
  833. const e = (arguments.length === 1
  834. ? edgeObjToId(this._isDirected, arguments[0])
  835. : edgeArgsToId(this._isDirected, v, w, name))
  836. const edge = this._edgeObjs[e]
  837. if (edge) {
  838. v = edge.v
  839. w = edge.w
  840. delete this._edgeLabels[e]
  841. delete this._edgeObjs[e]
  842. decrementOrRemoveEntry(this._preds[w], v)
  843. decrementOrRemoveEntry(this._sucs[v], w)
  844. delete this._in[w][e]
  845. delete this._out[v][e]
  846. this._edgeCount--
  847. }
  848. return this
  849. }
  850. Graph.prototype.inEdges = function (v, u) {
  851. var inV = this._in[v]
  852. if (inV) {
  853. var edges = _.values(inV)
  854. if (!u) {
  855. return edges
  856. }
  857. return _.filter(edges, function (edge) { return edge.v === u })
  858. }
  859. }
  860. Graph.prototype.outEdges = function (v, w) {
  861. var outV = this._out[v]
  862. if (outV) {
  863. var edges = _.values(outV)
  864. if (!w) {
  865. return edges
  866. }
  867. return _.filter(edges, function (edge) { return edge.w === w })
  868. }
  869. }
  870. Graph.prototype.nodeEdges = function (v, w) {
  871. var inEdges = this.inEdges(v, w)
  872. if (inEdges) {
  873. return inEdges.concat(this.outEdges(v, w))
  874. }
  875. }
  876. function incrementOrInitEntry (map, k) {
  877. if (map[k]) {
  878. map[k]++
  879. } else {
  880. map[k] = 1
  881. }
  882. }
  883. function decrementOrRemoveEntry (map, k) {
  884. if (!--map[k]) { delete map[k] }
  885. }
  886. function edgeArgsToId (isDirected, v_, w_, name) {
  887. var v = '' + v_
  888. var w = '' + w_
  889. if (!isDirected && v > w) {
  890. var tmp = v
  891. v = w
  892. w = tmp
  893. }
  894. return v + EDGE_KEY_DELIM + w + EDGE_KEY_DELIM +
  895. (_.isUndefined(name) ? DEFAULT_EDGE_NAME : name)
  896. }
  897. function edgeArgsToObj (isDirected, v_, w_, name) {
  898. var v = '' + v_
  899. var w = '' + w_
  900. if (!isDirected && v > w) {
  901. var tmp = v
  902. v = w
  903. w = tmp
  904. }
  905. var edgeObj = { v: v, w: w }
  906. if (name) {
  907. edgeObj.name = name
  908. }
  909. return edgeObj
  910. }
  911. function edgeObjToId (isDirected, edgeObj) {
  912. return edgeArgsToId(isDirected, edgeObj.v, edgeObj.w, edgeObj.name)
  913. }
  914. },{"./lodash":18}],17:[function(require,module,exports){
  915. const _ = require('./lodash')
  916. const Graph = require('./graph')
  917. module.exports = {
  918. write: write,
  919. read: read
  920. }
  921. function write (g) {
  922. var json = {
  923. options: {
  924. directed: g.isDirected(),
  925. multigraph: g.isMultigraph(),
  926. compound: g.isCompound()
  927. },
  928. nodes: writeNodes(g),
  929. edges: writeEdges(g)
  930. }
  931. if (!_.isUndefined(g.graph())) {
  932. json.value = _.clone(g.graph())
  933. }
  934. return json
  935. }
  936. function writeNodes (g) {
  937. return _.map(g.nodes(), function (v) {
  938. const nodeValue = g.node(v)
  939. const parent = g.parent(v)
  940. const node = { v: v }
  941. if (!_.isUndefined(nodeValue)) {
  942. node.value = nodeValue
  943. }
  944. if (!_.isUndefined(parent)) {
  945. node.parent = parent
  946. }
  947. return node
  948. })
  949. }
  950. function writeEdges (g) {
  951. return _.map(g.edges(), function (e) {
  952. const edgeValue = g.edge(e)
  953. const edge = { v: e.v, w: e.w }
  954. if (!_.isUndefined(e.name)) {
  955. edge.name = e.name
  956. }
  957. if (!_.isUndefined(edgeValue)) {
  958. edge.value = edgeValue
  959. }
  960. return edge
  961. })
  962. }
  963. function read (json) {
  964. var g = new Graph(json.options).setGraph(json.value)
  965. _.each(json.nodes, function (entry) {
  966. g.setNode(entry.v, entry.value)
  967. if (entry.parent) {
  968. g.setParent(entry.v, entry.parent)
  969. }
  970. })
  971. _.each(json.edges, function (entry) {
  972. g.setEdge({ v: entry.v, w: entry.w, name: entry.name }, entry.value)
  973. })
  974. return g
  975. }
  976. },{"./graph":16,"./lodash":18}],18:[function(require,module,exports){
  977. /* global window */
  978. var lodash
  979. if (typeof require === 'function') {
  980. try {
  981. lodash = require('lodash')
  982. } catch (e) {}
  983. }
  984. if (!lodash) {
  985. lodash = window._
  986. }
  987. module.exports = lodash
  988. },{"lodash":undefined}]},{},[1])(1)
  989. });