acyclic.js 1.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. import _ from 'lodash'
  2. import greedyFAS from './greedy-fas'
  3. function run (g) {
  4. const fas = (g.graph().acyclicer === 'greedy'
  5. ? greedyFAS(g, weightFn(g))
  6. : dfsFAS(g))
  7. _.forEach(fas, function (e) {
  8. const label = g.edge(e)
  9. g.removeEdge(e)
  10. label.forwardName = e.name
  11. label.reversed = true
  12. g.setEdge(e.w, e.v, label, _.uniqueId('rev'))
  13. })
  14. function weightFn (g) {
  15. return function (e) {
  16. return g.edge(e).weight
  17. }
  18. }
  19. }
  20. function dfsFAS (g) {
  21. const fas = []
  22. const stack = {}
  23. const visited = {}
  24. function dfs (v) {
  25. if (_.has(visited, v)) {
  26. return
  27. }
  28. visited[v] = true
  29. stack[v] = true
  30. _.forEach(g.outEdges(v), function (e) {
  31. if (_.has(stack, e.w)) {
  32. fas.push(e)
  33. } else {
  34. dfs(e.w)
  35. }
  36. })
  37. delete stack[v]
  38. }
  39. _.forEach(g.nodes(), dfs)
  40. return fas
  41. }
  42. function undo (g) {
  43. _.forEach(g.edges(), function (e) {
  44. const label = g.edge(e)
  45. if (label.reversed) {
  46. g.removeEdge(e)
  47. const forwardName = label.forwardName
  48. delete label.reversed
  49. delete label.forwardName
  50. g.setEdge(e.w, e.v, label, forwardName)
  51. }
  52. })
  53. }
  54. export default {
  55. run,
  56. undo
  57. }