parent-dummy-chains.js 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import _ from 'lodash'
  2. function parentDummyChains (g) {
  3. const postorderNums = postorder(g)
  4. _.forEach(g.graph().dummyChains, function (v) {
  5. let node = g.node(v)
  6. const edgeObj = node.edgeObj
  7. const pathData = findPath(g, postorderNums, edgeObj.v, edgeObj.w)
  8. const path = pathData.path
  9. const lca = pathData.lca
  10. let pathIdx = 0
  11. let pathV = path[pathIdx]
  12. let ascending = true
  13. while (v !== edgeObj.w) {
  14. node = g.node(v)
  15. if (ascending) {
  16. while ((pathV = path[pathIdx]) !== lca &&
  17. g.node(pathV).maxRank < node.rank) {
  18. pathIdx++
  19. }
  20. if (pathV === lca) {
  21. ascending = false
  22. }
  23. }
  24. if (!ascending) {
  25. while (pathIdx < path.length - 1 &&
  26. g.node(pathV = path[pathIdx + 1]).minRank <= node.rank) {
  27. pathIdx++
  28. }
  29. pathV = path[pathIdx]
  30. }
  31. g.setParent(v, pathV)
  32. v = g.successors(v)[0]
  33. }
  34. })
  35. }
  36. // Find a path from v to w through the lowest common ancestor (LCA). Return the
  37. // full path and the LCA.
  38. function findPath (g, postorderNums, v, w) {
  39. const vPath = []
  40. const wPath = []
  41. const low = Math.min(postorderNums[v].low, postorderNums[w].low)
  42. const lim = Math.max(postorderNums[v].lim, postorderNums[w].lim)
  43. let parent
  44. let lca
  45. // Traverse up from v to find the LCA
  46. parent = v
  47. do {
  48. parent = g.parent(parent)
  49. vPath.push(parent)
  50. } while (parent &&
  51. (postorderNums[parent].low > low || lim > postorderNums[parent].lim))
  52. lca = parent
  53. // Traverse from w to LCA
  54. parent = w
  55. while ((parent = g.parent(parent)) !== lca) {
  56. wPath.push(parent)
  57. }
  58. return { path: vPath.concat(wPath.reverse()), lca: lca }
  59. }
  60. function postorder (g) {
  61. const result = {}
  62. let lim = 0
  63. function dfs (v) {
  64. const low = lim
  65. _.forEach(g.children(v), dfs)
  66. result[v] = { low: low, lim: lim++ }
  67. }
  68. _.forEach(g.children(), dfs)
  69. return result
  70. }
  71. export default parentDummyChains