leda.py 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. """
  2. Read graphs in LEDA format.
  3. LEDA is a C++ class library for efficient data types and algorithms.
  4. Format
  5. ------
  6. See http://www.algorithmic-solutions.info/leda_guide/graphs/leda_native_graph_fileformat.html
  7. """
  8. # Original author: D. Eppstein, UC Irvine, August 12, 2003.
  9. # The original code at http://www.ics.uci.edu/~eppstein/PADS/ is public domain.
  10. __all__ = ["read_leda", "parse_leda"]
  11. import networkx as nx
  12. from networkx.exception import NetworkXError
  13. from networkx.utils import open_file
  14. @open_file(0, mode="rb")
  15. @nx._dispatchable(graphs=None, returns_graph=True)
  16. def read_leda(path, encoding="UTF-8"):
  17. """Read graph in LEDA format from path.
  18. Parameters
  19. ----------
  20. path : file or string
  21. Filename or file handle to read.
  22. Filenames ending in .gz or .bz2 will be decompressed.
  23. Returns
  24. -------
  25. G : NetworkX graph
  26. Examples
  27. --------
  28. >>> G = nx.read_leda("file.leda") # doctest: +SKIP
  29. References
  30. ----------
  31. .. [1] http://www.algorithmic-solutions.info/leda_guide/graphs/leda_native_graph_fileformat.html
  32. """
  33. lines = (line.decode(encoding) for line in path)
  34. G = parse_leda(lines)
  35. return G
  36. @nx._dispatchable(graphs=None, returns_graph=True)
  37. def parse_leda(lines):
  38. """Read graph in LEDA format from string or iterable.
  39. Parameters
  40. ----------
  41. lines : string or iterable
  42. Data in LEDA format.
  43. Returns
  44. -------
  45. G : NetworkX graph
  46. Examples
  47. --------
  48. >>> G = nx.parse_leda(string) # doctest: +SKIP
  49. References
  50. ----------
  51. .. [1] http://www.algorithmic-solutions.info/leda_guide/graphs/leda_native_graph_fileformat.html
  52. """
  53. if isinstance(lines, str):
  54. lines = iter(lines.split("\n"))
  55. lines = iter(
  56. [
  57. line.rstrip("\n")
  58. for line in lines
  59. if not (line.startswith(("#", "\n")) or line == "")
  60. ]
  61. )
  62. for i in range(3):
  63. next(lines)
  64. # Graph
  65. du = int(next(lines)) # -1=directed, -2=undirected
  66. if du == -1:
  67. G = nx.DiGraph()
  68. else:
  69. G = nx.Graph()
  70. # Nodes
  71. n = int(next(lines)) # number of nodes
  72. node = {}
  73. for i in range(1, n + 1): # LEDA counts from 1 to n
  74. symbol = next(lines).rstrip().strip("|{}| ")
  75. if symbol == "":
  76. symbol = str(i) # use int if no label - could be trouble
  77. node[i] = symbol
  78. G.add_nodes_from([s for i, s in node.items()])
  79. # Edges
  80. m = int(next(lines)) # number of edges
  81. for i in range(m):
  82. try:
  83. s, t, reversal, label = next(lines).split()
  84. except BaseException as err:
  85. raise NetworkXError(f"Too few fields in LEDA.GRAPH edge {i + 1}") from err
  86. # BEWARE: no handling of reversal edges
  87. G.add_edge(node[int(s)], node[int(t)], label=label[2:-2])
  88. return G