gvtool_tred.c 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. /*************************************************************************
  2. * Copyright (c) 2011 AT&T Intellectual Property
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * https://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors: Details at https://graphviz.org
  9. *************************************************************************/
  10. /*
  11. * Written by Stephen North
  12. * Updated by Emden Gansner
  13. * Adapted to gvToolTred(g) by John Ellson
  14. */
  15. /*
  16. * performs an inplace transitive reduction on a graph
  17. */
  18. #include "config.h"
  19. #include <stdio.h>
  20. #include <cgraph/cgraph.h>
  21. #include <gvc/gvc.h>
  22. typedef struct {
  23. Agrec_t h;
  24. int mark;
  25. } Agmarknodeinfo_t;
  26. #define MARK(n) (((Agmarknodeinfo_t*)(n->base.data))->mark)
  27. #define agrootof(n) ((n)->root)
  28. static int dfs(Agnode_t * n, Agedge_t * link, int warn)
  29. {
  30. Agedge_t *e;
  31. Agedge_t *f;
  32. Agraph_t *g = agrootof(n);
  33. MARK(n) = 1;
  34. for (e = agfstin(g, n); e; e = f) {
  35. f = agnxtin(g, e);
  36. if (e == link)
  37. continue;
  38. if (MARK(agtail(e)))
  39. agdelete(g, e);
  40. }
  41. for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
  42. if (MARK(aghead(e))) {
  43. if (!warn) {
  44. warn++;
  45. fprintf(stderr,
  46. "warning: %s has cycle(s), transitive reduction not unique\n",
  47. agnameof(g));
  48. fprintf(stderr, "cycle involves edge %s -> %s\n",
  49. agnameof(agtail(e)), agnameof(aghead(e)));
  50. }
  51. } else
  52. warn = dfs(aghead(e), AGOUT2IN(e), warn);
  53. }
  54. MARK(n) = 0;
  55. return warn;
  56. }
  57. int gvToolTred(Agraph_t * g)
  58. {
  59. Agnode_t *n;
  60. int warn = 0;
  61. if (agisdirected(g)) {
  62. aginit(g, AGNODE, "info", sizeof(Agmarknodeinfo_t), true);
  63. for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
  64. warn = dfs(n, NULL, warn);
  65. }
  66. agclean(g, AGNODE, "info");
  67. } else {
  68. fprintf(stderr, "warning: %s is not a directed graph, not attempting tred\n",
  69. agnameof(g));
  70. }
  71. return 0; // FIXME - return proper errors
  72. }