PageRenderTime 66ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/devel/sage-main/sage/graphs/graph.py

https://bitbucket.org/tkluck/sage-integration-staging
Python | 5876 lines | 5631 code | 5 blank | 240 comment | 14 complexity | 8982a646dd053ee38919b63f8f5ac3ad MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. r"""
  2. Undirected graphs
  3. This module implements functions and operations involving undirected
  4. graphs.
  5. **Graph basic operations:**
  6. .. csv-table::
  7. :class: contentstable
  8. :widths: 30, 70
  9. :delim: |
  10. :meth:`~Graph.write_to_eps` | Writes a plot of the graph to ``filename`` in ``eps`` format.
  11. :meth:`~Graph.to_undirected` | Since the graph is already undirected, simply returns a copy of itself.
  12. :meth:`~Graph.to_directed` | Returns a directed version of the graph.
  13. :meth:`~Graph.sparse6_string` | Returns the sparse6 representation of the graph as an ASCII string.
  14. :meth:`~Graph.graph6_string` | Returns the graph6 representation of the graph as an ASCII string.
  15. :meth:`~Graph.bipartite_sets` | Returns `(X,Y)` where X and Y are the nodes in each bipartite set of graph.
  16. :meth:`~Graph.bipartite_color` | Returns a dictionary with vertices as the keys and the color class as the values.
  17. :meth:`~Graph.is_directed` | Since graph is undirected, returns False.
  18. **Distances:**
  19. .. csv-table::
  20. :class: contentstable
  21. :widths: 30, 70
  22. :delim: |
  23. :meth:`~Graph.centrality_closeness` | Returns the closeness centrality (1/average distance to all vertices)
  24. :meth:`~Graph.centrality_degree` | Returns the degree centrality
  25. :meth:`~Graph.centrality_betweenness` | Returns the betweenness centrality
  26. **Graph properties:**
  27. .. csv-table::
  28. :class: contentstable
  29. :widths: 30, 70
  30. :delim: |
  31. :meth:`~Graph.is_prime` | Tests whether the current graph is prime.
  32. :meth:`~Graph.is_split` | Returns ``True`` if the graph is a Split graph, ``False`` otherwise.
  33. :meth:`~Graph.is_triangle_free` | Returns whether ``self`` is triangle-free.
  34. :meth:`~Graph.is_bipartite` | Returns True if graph G is bipartite, False if not.
  35. :meth:`~Graph.is_line_graph` | Tests wether the graph is a line graph.
  36. :meth:`~Graph.is_odd_hole_free` | Tests whether ``self`` contains an induced odd hole.
  37. :meth:`~Graph.is_even_hole_free` | Tests whether ``self`` contains an induced even hole.
  38. :meth:`~Graph.is_cartesian_product` | Tests whether ``self`` is a cartesian product of graphs.
  39. :meth:`~Graph.is_long_hole_free` | Tests whether ``self`` contains an induced cycle of length at least 5.
  40. :meth:`~Graph.is_long_antihole_free` | Tests whether ``self`` contains an induced anticycle of length at least 5.
  41. :meth:`~Graph.is_weakly_chordal` | Tests whether ``self`` is weakly chordal.
  42. :meth:`~Graph.is_strongly_regular` | Tests whether ``self`` is strongly regular.
  43. :meth:`~Graph.odd_girth` | Returns the odd girth of ``self``.
  44. :meth:`~Graph.is_edge_transitive` | Returns true if self is edge-transitive.
  45. :meth:`~Graph.is_arc_transitive` | Returns true if self is arc-transitive.
  46. :meth:`~Graph.is_half_transitive` | Returns true if self is a half-transitive graph.
  47. :meth:`~Graph.is_semi_symmetric` | Returns true if self is a semi-symmetric graph.
  48. **Connectivity and orientations:**
  49. .. csv-table::
  50. :class: contentstable
  51. :widths: 30, 70
  52. :delim: |
  53. :meth:`~Graph.gomory_hu_tree` | Returns a Gomory-Hu tree of self.
  54. :meth:`~Graph.minimum_outdegree_orientation` | Returns an orientation of ``self`` with the smallest possible maximum outdegree
  55. :meth:`~Graph.bounded_outdegree_orientation` | Computes an orientation of ``self`` such that every vertex `v` has out-degree less than `b(v)`
  56. :meth:`~Graph.strong_orientation` | Returns a strongly connected orientation of the current graph.
  57. :meth:`~Graph.degree_constrained_subgraph` | Returns a degree-constrained subgraph.
  58. **Clique-related methods:**
  59. .. csv-table::
  60. :class: contentstable
  61. :widths: 30, 70
  62. :delim: |
  63. :meth:`~Graph.clique_complex` | Returns the clique complex of self
  64. :meth:`~Graph.cliques_containing_vertex` | Returns the cliques containing each vertex
  65. :meth:`~Graph.cliques_vertex_clique_number` | Returns a dictionary of sizes of the largest maximal cliques containing each vertex
  66. :meth:`~Graph.cliques_get_clique_bipartite` | Returns a bipartite graph constructed such that maximal cliques are the right vertices and the left vertices are retained from the given graph
  67. :meth:`~Graph.cliques_get_max_clique_graph` | Returns a graph constructed with maximal cliques as vertices, and edges between maximal cliques sharing vertices.
  68. :meth:`~Graph.cliques_number_of` | Returns a dictionary of the number of maximal cliques containing each vertex, keyed by vertex.
  69. :meth:`~Graph.clique_number` | Returns the order of the largest clique of the graph.
  70. :meth:`~Graph.clique_maximum` | Returns the vertex set of a maximal order complete subgraph.
  71. :meth:`~Graph.cliques_maximum` | Returns the list of all maximum cliques
  72. :meth:`~Graph.cliques_maximal` | Returns the list of all maximal cliques
  73. **Algorithmically hard stuff:**
  74. .. csv-table::
  75. :class: contentstable
  76. :widths: 30, 70
  77. :delim: |
  78. :meth:`~Graph.vertex_cover` | Returns a minimum vertex cover of self
  79. :meth:`~Graph.independent_set` | Returns a maximum independent set.
  80. :meth:`~Graph.topological_minor` | Returns a topological `H`-minor from ``self`` if one exists.
  81. :meth:`~Graph.convexity_properties` | Returns a ``ConvexityProperties`` objet corresponding to ``self``.
  82. :meth:`~Graph.matching_polynomial` | Computes the matching polynomial of the graph `G`.
  83. :meth:`~Graph.rank_decomposition` | Returns an rank-decomposition of ``self`` achieving optiml rank-width.
  84. :meth:`~Graph.minor` | Returns the vertices of a minor isomorphic to `H` in the current graph.
  85. :meth:`~Graph.independent_set_of_representatives` | Returns an independent set of representatives.
  86. :meth:`~Graph.coloring` | Returns the first (optimal) proper vertex-coloring found.
  87. :meth:`~Graph.has_homomorphism_to` | Checks whether there is a morphism between two graphs.
  88. :meth:`~Graph.chromatic_number` | Returns the minimal number of colors needed to color the vertices of the graph.
  89. :meth:`~Graph.chromatic_polynomial` | Returns the chromatic polynomial of the graph.
  90. :meth:`~Graph.is_perfect` | Tests whether the graph is perfect.
  91. **Leftovers:**
  92. .. csv-table::
  93. :class: contentstable
  94. :widths: 30, 70
  95. :delim: |
  96. :meth:`~Graph.cores` | Returns the core number for each vertex in an ordered list.
  97. :meth:`~Graph.matching` | Returns a maximum weighted matching of the graph
  98. :meth:`~Graph.fractional_chromatic_index` | Computes the fractional chromatic index of ``self``
  99. :meth:`~Graph.modular_decomposition` | Returns the modular decomposition of the current graph.
  100. :meth:`~Graph.maximum_average_degree` | Returns the Maximum Average Degree (MAD) of the current graph.
  101. :meth:`~Graph.two_factor_petersen` | Returns a decomposition of the graph into 2-factors.
  102. AUTHORS:
  103. - Robert L. Miller (2006-10-22): initial version
  104. - William Stein (2006-12-05): Editing
  105. - Robert L. Miller (2007-01-13): refactoring, adjusting for
  106. NetworkX-0.33, fixed plotting bugs (2007-01-23): basic tutorial,
  107. edge labels, loops, multiple edges and arcs (2007-02-07): graph6
  108. and sparse6 formats, matrix input
  109. - Emily Kirkmann (2007-02-11): added graph_border option to plot
  110. and show
  111. - Robert L. Miller (2007-02-12): vertex color-maps, graph
  112. boundaries, graph6 helper functions in Cython
  113. - Robert L. Miller Sage Days 3 (2007-02-17-21): 3d plotting in
  114. Tachyon
  115. - Robert L. Miller (2007-02-25): display a partition
  116. - Robert L. Miller (2007-02-28): associate arbitrary objects to
  117. vertices, edge and arc label display (in 2d), edge coloring
  118. - Robert L. Miller (2007-03-21): Automorphism group, isomorphism
  119. check, canonical label
  120. - Robert L. Miller (2007-06-07-09): NetworkX function wrapping
  121. - Michael W. Hansen (2007-06-09): Topological sort generation
  122. - Emily Kirkman, Robert L. Miller Sage Days 4: Finished wrapping
  123. NetworkX
  124. - Emily Kirkman (2007-07-21): Genus (including circular planar,
  125. all embeddings and all planar embeddings), all paths, interior
  126. paths
  127. - Bobby Moretti (2007-08-12): fixed up plotting of graphs with
  128. edge colors differentiated by label
  129. - Jason Grout (2007-09-25): Added functions, bug fixes, and
  130. general enhancements
  131. - Robert L. Miller (Sage Days 7): Edge labeled graph isomorphism
  132. - Tom Boothby (Sage Days 7): Miscellaneous awesomeness
  133. - Tom Boothby (2008-01-09): Added graphviz output
  134. - David Joyner (2009-2): Fixed docstring bug related to GAP.
  135. - Stephen Hartke (2009-07-26): Fixed bug in blocks_and_cut_vertices()
  136. that caused an incorrect result when the vertex 0 was a cut vertex.
  137. - Stephen Hartke (2009-08-22): Fixed bug in blocks_and_cut_vertices()
  138. where the list of cut_vertices is not treated as a set.
  139. - Anders Jonsson (2009-10-10): Counting of spanning trees and out-trees added.
  140. - Nathann Cohen (2009-09) : Cliquer, Connectivity, Flows
  141. and everything that uses Linear Programming
  142. and class numerical.MIP
  143. - Nicolas M. Thiery (2010-02): graph layout code refactoring, dot2tex/graphviz interface
  144. - David Coudert (2012-04) : Reduction rules in vertex_cover.
  145. - Birk Eisermann (2012-06): added recognition of weakly chordal graphs and
  146. long-hole-free / long-antihole-free graphs
  147. Graph Format
  148. ------------
  149. Supported formats
  150. ~~~~~~~~~~~~~~~~~
  151. Sage Graphs can be created from a wide range of inputs. A few
  152. examples are covered here.
  153. - NetworkX dictionary format:
  154. ::
  155. sage: d = {0: [1,4,5], 1: [2,6], 2: [3,7], 3: [4,8], 4: [9], \
  156. 5: [7, 8], 6: [8,9], 7: [9]}
  157. sage: G = Graph(d); G
  158. Graph on 10 vertices
  159. sage: G.plot().show() # or G.show()
  160. - A NetworkX graph:
  161. ::
  162. sage: import networkx
  163. sage: K = networkx.complete_bipartite_graph(12,7)
  164. sage: G = Graph(K)
  165. sage: G.degree()
  166. [7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12, 12]
  167. - graph6 or sparse6 format:
  168. ::
  169. sage: s = ':I`AKGsaOs`cI]Gb~'
  170. sage: G = Graph(s, sparse=True); G
  171. Looped multi-graph on 10 vertices
  172. sage: G.plot().show() # or G.show()
  173. Note that the ``\`` character is an escape character in Python, and
  174. also a character used by graph6 strings:
  175. ::
  176. sage: G = Graph('Ihe\n@GUA')
  177. Traceback (most recent call last):
  178. ...
  179. RuntimeError: The string (Ihe) seems corrupt: for n = 10, the string is too short.
  180. In Python, the escaped character ``\`` is represented by ``\\``:
  181. ::
  182. sage: G = Graph('Ihe\\n@GUA')
  183. sage: G.plot().show() # or G.show()
  184. - adjacency matrix: In an adjacency matrix, each column and each
  185. row represent a vertex. If a 1 shows up in row `i`, column
  186. `j`, there is an edge `(i,j)`.
  187. ::
  188. sage: M = Matrix([(0,1,0,0,1,1,0,0,0,0),(1,0,1,0,0,0,1,0,0,0), \
  189. (0,1,0,1,0,0,0,1,0,0), (0,0,1,0,1,0,0,0,1,0),(1,0,0,1,0,0,0,0,0,1), \
  190. (1,0,0,0,0,0,0,1,1,0), (0,1,0,0,0,0,0,0,1,1),(0,0,1,0,0,1,0,0,0,1), \
  191. (0,0,0,1,0,1,1,0,0,0), (0,0,0,0,1,0,1,1,0,0)])
  192. sage: M
  193. [0 1 0 0 1 1 0 0 0 0]
  194. [1 0 1 0 0 0 1 0 0 0]
  195. [0 1 0 1 0 0 0 1 0 0]
  196. [0 0 1 0 1 0 0 0 1 0]
  197. [1 0 0 1 0 0 0 0 0 1]
  198. [1 0 0 0 0 0 0 1 1 0]
  199. [0 1 0 0 0 0 0 0 1 1]
  200. [0 0 1 0 0 1 0 0 0 1]
  201. [0 0 0 1 0 1 1 0 0 0]
  202. [0 0 0 0 1 0 1 1 0 0]
  203. sage: G = Graph(M); G
  204. Graph on 10 vertices
  205. sage: G.plot().show() # or G.show()
  206. - incidence matrix: In an incidence matrix, each row represents a
  207. vertex and each column represents an edge.
  208. ::
  209. sage: M = Matrix([(-1,0,0,0,1,0,0,0,0,0,-1,0,0,0,0), \
  210. (1,-1,0,0,0,0,0,0,0,0,0,-1,0,0,0),(0,1,-1,0,0,0,0,0,0,0,0,0,-1,0,0), \
  211. (0,0,1,-1,0,0,0,0,0,0,0,0,0,-1,0),(0,0,0,1,-1,0,0,0,0,0,0,0,0,0,-1), \
  212. (0,0,0,0,0,-1,0,0,0,1,1,0,0,0,0),(0,0,0,0,0,0,0,1,-1,0,0,1,0,0,0), \
  213. (0,0,0,0,0,1,-1,0,0,0,0,0,1,0,0),(0,0,0,0,0,0,0,0,1,-1,0,0,0,1,0), \
  214. (0,0,0,0,0,0,1,-1,0,0,0,0,0,0,1)])
  215. sage: M
  216. [-1 0 0 0 1 0 0 0 0 0 -1 0 0 0 0]
  217. [ 1 -1 0 0 0 0 0 0 0 0 0 -1 0 0 0]
  218. [ 0 1 -1 0 0 0 0 0 0 0 0 0 -1 0 0]
  219. [ 0 0 1 -1 0 0 0 0 0 0 0 0 0 -1 0]
  220. [ 0 0 0 1 -1 0 0 0 0 0 0 0 0 0 -1]
  221. [ 0 0 0 0 0 -1 0 0 0 1 1 0 0 0 0]
  222. [ 0 0 0 0 0 0 0 1 -1 0 0 1 0 0 0]
  223. [ 0 0 0 0 0 1 -1 0 0 0 0 0 1 0 0]
  224. [ 0 0 0 0 0 0 0 0 1 -1 0 0 0 1 0]
  225. [ 0 0 0 0 0 0 1 -1 0 0 0 0 0 0 1]
  226. sage: G = Graph(M); G
  227. Graph on 10 vertices
  228. sage: G.plot().show() # or G.show()
  229. sage: DiGraph(matrix(2,[0,0,-1,1]), format="incidence_matrix")
  230. Traceback (most recent call last):
  231. ...
  232. ValueError: There must be two nonzero entries (-1 & 1) per column.
  233. - a list of edges::
  234. sage: g = Graph([(1,3),(3,8),(5,2)])
  235. sage: g
  236. Graph on 5 vertices
  237. Generators
  238. ----------
  239. If you wish to iterate through all the isomorphism types of graphs,
  240. type, for example::
  241. sage: for g in graphs(4):
  242. ... print g.spectrum()
  243. [0, 0, 0, 0]
  244. [1, 0, 0, -1]
  245. [1.4142135623..., 0, 0, -1.4142135623...]
  246. [2, 0, -1, -1]
  247. [1.7320508075..., 0, 0, -1.7320508075...]
  248. [1, 1, -1, -1]
  249. [1.6180339887..., 0.6180339887..., -0.6180339887..., -1.6180339887...]
  250. [2.1700864866..., 0.3111078174..., -1, -1.4811943040...]
  251. [2, 0, 0, -2]
  252. [2.5615528128..., 0, -1, -1.5615528128...]
  253. [3, -1, -1, -1]
  254. For some commonly used graphs to play with, type
  255. ::
  256. sage: graphs.[tab] # not tested
  257. and hit {tab}. Most of these graphs come with their own custom
  258. plot, so you can see how people usually visualize these graphs.
  259. ::
  260. sage: G = graphs.PetersenGraph()
  261. sage: G.plot().show() # or G.show()
  262. sage: G.degree_histogram()
  263. [0, 0, 0, 10]
  264. sage: G.adjacency_matrix()
  265. [0 1 0 0 1 1 0 0 0 0]
  266. [1 0 1 0 0 0 1 0 0 0]
  267. [0 1 0 1 0 0 0 1 0 0]
  268. [0 0 1 0 1 0 0 0 1 0]
  269. [1 0 0 1 0 0 0 0 0 1]
  270. [1 0 0 0 0 0 0 1 1 0]
  271. [0 1 0 0 0 0 0 0 1 1]
  272. [0 0 1 0 0 1 0 0 0 1]
  273. [0 0 0 1 0 1 1 0 0 0]
  274. [0 0 0 0 1 0 1 1 0 0]
  275. ::
  276. sage: S = G.subgraph([0,1,2,3])
  277. sage: S.plot().show() # or S.show()
  278. sage: S.density()
  279. 1/2
  280. ::
  281. sage: G = GraphQuery(display_cols=['graph6'], num_vertices=7, diameter=5)
  282. sage: L = G.get_graphs_list()
  283. sage: graphs_list.show_graphs(L)
  284. .. _Graph:labels:
  285. Labels
  286. ------
  287. Each vertex can have any hashable object as a label. These are
  288. things like strings, numbers, and tuples. Each edge is given a
  289. default label of ``None``, but if specified, edges can
  290. have any label at all. Edges between vertices `u` and
  291. `v` are represented typically as ``(u, v, l)``, where
  292. ``l`` is the label for the edge.
  293. Note that vertex labels themselves cannot be mutable items::
  294. sage: M = Matrix( [[0,0],[0,0]] )
  295. sage: G = Graph({ 0 : { M : None } })
  296. Traceback (most recent call last):
  297. ...
  298. TypeError: mutable matrices are unhashable
  299. However, if one wants to define a dictionary, with the same keys
  300. and arbitrary objects for entries, one can make that association::
  301. sage: d = {0 : graphs.DodecahedralGraph(), 1 : graphs.FlowerSnark(), \
  302. 2 : graphs.MoebiusKantorGraph(), 3 : graphs.PetersenGraph() }
  303. sage: d[2]
  304. Moebius-Kantor Graph: Graph on 16 vertices
  305. sage: T = graphs.TetrahedralGraph()
  306. sage: T.vertices()
  307. [0, 1, 2, 3]
  308. sage: T.set_vertices(d)
  309. sage: T.get_vertex(1)
  310. Flower Snark: Graph on 20 vertices
  311. Database
  312. --------
  313. There is a database available for searching for graphs that satisfy
  314. a certain set of parameters, including number of vertices and
  315. edges, density, maximum and minimum degree, diameter, radius, and
  316. connectivity. To see a list of all search parameter keywords broken
  317. down by their designated table names, type
  318. ::
  319. sage: graph_db_info()
  320. {...}
  321. For more details on data types or keyword input, enter
  322. ::
  323. sage: GraphQuery? # not tested
  324. The results of a query can be viewed with the show method, or can be
  325. viewed individually by iterating through the results:
  326. ::
  327. sage: Q = GraphQuery(display_cols=['graph6'],num_vertices=7, diameter=5)
  328. sage: Q.show()
  329. Graph6
  330. --------------------
  331. F@?]O
  332. F@OKg
  333. F?`po
  334. F?gqg
  335. FIAHo
  336. F@R@o
  337. FA_pW
  338. FGC{o
  339. FEOhW
  340. Show each graph as you iterate through the results:
  341. ::
  342. sage: for g in Q:
  343. ... show(g)
  344. Visualization
  345. -------------
  346. To see a graph `G` you are working with, there
  347. are three main options. You can view the graph in two dimensions via
  348. matplotlib with ``show()``. ::
  349. sage: G = graphs.RandomGNP(15,.3)
  350. sage: G.show()
  351. And you can view it in three dimensions via jmol with ``show3d()``. ::
  352. sage: G.show3d()
  353. Or it can be rendered with `\mbox{\rm\LaTeX}`. This requires the right
  354. additions to a standard `\mbox{\rm\TeX}` installation. Then standard
  355. Sage commands, such as ``view(G)`` will display the graph, or
  356. ``latex(G)`` will produce a string suitable for inclusion in a
  357. `\mbox{\rm\LaTeX}` document. More details on this are at
  358. the :mod:`sage.graphs.graph_latex` module. ::
  359. sage: from sage.graphs.graph_latex import check_tkz_graph
  360. sage: check_tkz_graph() # random - depends on TeX installation
  361. sage: latex(G)
  362. \begin{tikzpicture}
  363. ...
  364. \end{tikzpicture}
  365. Methods
  366. -------
  367. """
  368. #*****************************************************************************
  369. # Copyright (C) 2006 - 2007 Robert L. Miller <rlmillster@gmail.com>
  370. #
  371. # Distributed under the terms of the GNU General Public License (GPL)
  372. # http://www.gnu.org/licenses/
  373. #*****************************************************************************
  374. from sage.rings.integer import Integer
  375. from sage.misc.superseded import deprecated_function_alias
  376. import sage.graphs.generic_graph_pyx as generic_graph_pyx
  377. from sage.graphs.generic_graph import GenericGraph
  378. from sage.graphs.digraph import DiGraph
  379. class Graph(GenericGraph):
  380. r"""
  381. Undirected graph.
  382. A graph is a set of vertices connected by edges. See also the
  383. :wikipedia:`Wikipedia article on graphs <Graph_(mathematics)>`.
  384. One can very easily create a graph in Sage by typing::
  385. sage: g = Graph()
  386. By typing the name of the graph, one can get some basic information
  387. about it::
  388. sage: g
  389. Graph on 0 vertices
  390. This graph is not very interesting as it is by default the empty graph.
  391. But Sage contains a large collection of pre-defined graph classes that
  392. can be listed this way:
  393. * Within a Sage session, type ``graphs.``
  394. (Do not press "Enter", and do not forget the final period ".")
  395. * Hit "tab".
  396. You will see a list of methods which will construct named graphs. For
  397. example::
  398. sage: g = graphs.PetersenGraph()
  399. sage: g.plot()
  400. or::
  401. sage: g = graphs.ChvatalGraph()
  402. sage: g.plot()
  403. In order to obtain more information about these graph constructors, access
  404. the documentation using the command ``graphs.RandomGNP?``.
  405. Once you have defined the graph you want, you can begin to work on it
  406. by using the almost 200 functions on graphs in the Sage library!
  407. If your graph is named ``g``, you can list these functions as previously
  408. this way
  409. * Within a Sage session, type ``g.``
  410. (Do not press "Enter", and do not forget the final period "." )
  411. * Hit "tab".
  412. As usual, you can get some information about what these functions do by
  413. typing (e.g. if you want to know about the ``diameter()`` method)
  414. ``g.diameter?``.
  415. If you have defined a graph ``g`` having several connected components
  416. (i.e. ``g.is_connected()`` returns False), you can print each one of its
  417. connected components with only two lines::
  418. sage: for component in g.connected_components():
  419. ... g.subgraph(component).plot()
  420. INPUT:
  421. - ``data`` -- can be any of the following (see the ``format`` argument):
  422. #. An integer specifying the number of vertices
  423. #. A dictionary of dictionaries
  424. #. A dictionary of lists
  425. #. A NumPy matrix or ndarray
  426. #. A Sage adjacency matrix or incidence matrix
  427. #. A pygraphviz graph
  428. #. A SciPy sparse matrix
  429. #. A NetworkX graph
  430. - ``pos`` - a positioning dictionary: for example, the
  431. spring layout from NetworkX for the 5-cycle is::
  432. {0: [-0.91679746, 0.88169588],
  433. 1: [ 0.47294849, 1.125 ],
  434. 2: [ 1.125 ,-0.12867615],
  435. 3: [ 0.12743933,-1.125 ],
  436. 4: [-1.125 ,-0.50118505]}
  437. - ``name`` - (must be an explicitly named parameter,
  438. i.e., ``name="complete")`` gives the graph a name
  439. - ``loops`` - boolean, whether to allow loops (ignored
  440. if data is an instance of the ``Graph`` class)
  441. - ``multiedges`` - boolean, whether to allow multiple
  442. edges (ignored if data is an instance of the ``Graph`` class)
  443. - ``weighted`` - whether graph thinks of itself as
  444. weighted or not. See ``self.weighted()``
  445. - ``format`` - if None, Graph tries to guess- can be
  446. several values, including:
  447. - ``'int'`` - an integer specifying the number of vertices in an
  448. edge-free graph with vertices labelled from 0 to n-1
  449. - ``'graph6'`` - Brendan McKay's graph6 format, in a
  450. string (if the string has multiple graphs, the first graph is
  451. taken)
  452. - ``'sparse6'`` - Brendan McKay's sparse6 format, in a
  453. string (if the string has multiple graphs, the first graph is
  454. taken)
  455. - ``'adjacency_matrix'`` - a square Sage matrix M,
  456. with M[i,j] equal to the number of edges {i,j}
  457. - ``'weighted_adjacency_matrix'`` - a square Sage
  458. matrix M, with M[i,j] equal to the weight of the single edge {i,j}.
  459. Given this format, weighted is ignored (assumed True).
  460. - ``'incidence_matrix'`` - a Sage matrix, with one
  461. column C for each edge, where if C represents {i, j}, C[i] is -1
  462. and C[j] is 1
  463. - ``'elliptic_curve_congruence'`` - data must be an
  464. iterable container of elliptic curves, and the graph produced has
  465. each curve as a vertex (it's Cremona label) and an edge E-F
  466. labelled p if and only if E is congruent to F mod p
  467. - ``NX`` - data must be a NetworkX Graph.
  468. .. NOTE::
  469. As Sage's default edge labels is ``None`` while NetworkX uses
  470. ``{}``, the ``{}`` labels of a NetworkX graph are automatically
  471. set to ``None`` when it is converted to a Sage graph. This
  472. behaviour can be overruled by setting the keyword
  473. ``convert_empty_dict_labels_to_None`` to ``False`` (it is
  474. ``True`` by default).
  475. - ``boundary`` - a list of boundary vertices, if
  476. empty, graph is considered as a 'graph without boundary'
  477. - ``implementation`` - what to use as a backend for
  478. the graph. Currently, the options are either 'networkx' or
  479. 'c_graph'
  480. - ``sparse`` - only for implementation == 'c_graph'.
  481. Whether to use sparse or dense graphs as backend. Note that
  482. currently dense graphs do not have edge labels, nor can they be
  483. multigraphs
  484. - ``vertex_labels`` - only for implementation == 'c_graph'.
  485. Whether to allow any object as a vertex (slower), or
  486. only the integers 0, ..., n-1, where n is the number of vertices.
  487. - ``convert_empty_dict_labels_to_None`` - this arguments sets
  488. the default edge labels used by NetworkX (empty dictionaries)
  489. to be replaced by None, the default Sage edge label. It is
  490. set to ``True`` iff a NetworkX graph is on the input.
  491. EXAMPLES:
  492. We illustrate the first seven input formats (the other two
  493. involve packages that are currently not standard in Sage):
  494. #. An integer giving the number of vertices::
  495. sage: g = Graph(5); g
  496. Graph on 5 vertices
  497. sage: g.vertices()
  498. [0, 1, 2, 3, 4]
  499. sage: g.edges()
  500. []
  501. #. A dictionary of dictionaries::
  502. sage: g = Graph({0:{1:'x',2:'z',3:'a'}, 2:{5:'out'}}); g
  503. Graph on 5 vertices
  504. The labels ('x', 'z', 'a', 'out') are labels for edges. For
  505. example, 'out' is the label for the edge on 2 and 5. Labels can be
  506. used as weights, if all the labels share some common parent.
  507. ::
  508. sage: a,b,c,d,e,f = sorted(SymmetricGroup(3))
  509. sage: Graph({b:{d:'c',e:'p'}, c:{d:'p',e:'c'}})
  510. Graph on 4 vertices
  511. #. A dictionary of lists::
  512. sage: g = Graph({0:[1,2,3], 2:[4]}); g
  513. Graph on 5 vertices
  514. #. A list of vertices and a function describing adjacencies. Note
  515. that the list of vertices and the function must be enclosed in a
  516. list (i.e., [list of vertices, function]).
  517. Construct the Paley graph over GF(13).
  518. ::
  519. sage: g=Graph([GF(13), lambda i,j: i!=j and (i-j).is_square()])
  520. sage: g.vertices()
  521. [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
  522. sage: g.adjacency_matrix()
  523. [0 1 0 1 1 0 0 0 0 1 1 0 1]
  524. [1 0 1 0 1 1 0 0 0 0 1 1 0]
  525. [0 1 0 1 0 1 1 0 0 0 0 1 1]
  526. [1 0 1 0 1 0 1 1 0 0 0 0 1]
  527. [1 1 0 1 0 1 0 1 1 0 0 0 0]
  528. [0 1 1 0 1 0 1 0 1 1 0 0 0]
  529. [0 0 1 1 0 1 0 1 0 1 1 0 0]
  530. [0 0 0 1 1 0 1 0 1 0 1 1 0]
  531. [0 0 0 0 1 1 0 1 0 1 0 1 1]
  532. [1 0 0 0 0 1 1 0 1 0 1 0 1]
  533. [1 1 0 0 0 0 1 1 0 1 0 1 0]
  534. [0 1 1 0 0 0 0 1 1 0 1 0 1]
  535. [1 0 1 1 0 0 0 0 1 1 0 1 0]
  536. Construct the line graph of a complete graph.
  537. ::
  538. sage: g=graphs.CompleteGraph(4)
  539. sage: line_graph=Graph([g.edges(labels=false), \
  540. lambda i,j: len(set(i).intersection(set(j)))>0], \
  541. loops=False)
  542. sage: line_graph.vertices()
  543. [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
  544. sage: line_graph.adjacency_matrix()
  545. [0 1 1 1 1 0]
  546. [1 0 1 1 0 1]
  547. [1 1 0 0 1 1]
  548. [1 1 0 0 1 1]
  549. [1 0 1 1 0 1]
  550. [0 1 1 1 1 0]
  551. #. A NumPy matrix or ndarray::
  552. sage: import numpy
  553. sage: A = numpy.array([[0,1,1],[1,0,1],[1,1,0]])
  554. sage: Graph(A)
  555. Graph on 3 vertices
  556. #. A graph6 or sparse6 string: Sage automatically recognizes
  557. whether a string is in graph6 or sparse6 format::
  558. sage: s = ':I`AKGsaOs`cI]Gb~'
  559. sage: Graph(s,sparse=True)
  560. Looped multi-graph on 10 vertices
  561. ::
  562. sage: G = Graph('G?????')
  563. sage: G = Graph("G'?G?C")
  564. Traceback (most recent call last):
  565. ...
  566. RuntimeError: The string seems corrupt: valid characters are
  567. ?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
  568. sage: G = Graph('G??????')
  569. Traceback (most recent call last):
  570. ...
  571. RuntimeError: The string (G??????) seems corrupt: for n = 8, the string is too long.
  572. ::
  573. sage: G = Graph(":I'AKGsaOs`cI]Gb~")
  574. Traceback (most recent call last):
  575. ...
  576. RuntimeError: The string seems corrupt: valid characters are
  577. ?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
  578. There are also list functions to take care of lists of graphs::
  579. sage: s = ':IgMoqoCUOqeb\n:I`AKGsaOs`cI]Gb~\n:I`EDOAEQ?PccSsge\N\n'
  580. sage: graphs_list.from_sparse6(s)
  581. [Looped multi-graph on 10 vertices, Looped multi-graph on 10 vertices, Looped multi-graph on 10 vertices]
  582. #. A Sage matrix:
  583. Note: If format is not specified, then Sage assumes a symmetric square
  584. matrix is an adjacency matrix, otherwise an incidence matrix.
  585. - an adjacency matrix::
  586. sage: M = graphs.PetersenGraph().am(); M
  587. [0 1 0 0 1 1 0 0 0 0]
  588. [1 0 1 0 0 0 1 0 0 0]
  589. [0 1 0 1 0 0 0 1 0 0]
  590. [0 0 1 0 1 0 0 0 1 0]
  591. [1 0 0 1 0 0 0 0 0 1]
  592. [1 0 0 0 0 0 0 1 1 0]
  593. [0 1 0 0 0 0 0 0 1 1]
  594. [0 0 1 0 0 1 0 0 0 1]
  595. [0 0 0 1 0 1 1 0 0 0]
  596. [0 0 0 0 1 0 1 1 0 0]
  597. sage: Graph(M)
  598. Graph on 10 vertices
  599. ::
  600. sage: Graph(matrix([[1,2],[2,4]]),loops=True,sparse=True)
  601. Looped multi-graph on 2 vertices
  602. sage: M = Matrix([[0,1,-1],[1,0,-1/2],[-1,-1/2,0]]); M
  603. [ 0 1 -1]
  604. [ 1 0 -1/2]
  605. [ -1 -1/2 0]
  606. sage: G = Graph(M,sparse=True); G
  607. Graph on 3 vertices
  608. sage: G.weighted()
  609. True
  610. - an incidence matrix::
  611. sage: M = Matrix(6, [-1,0,0,0,1, 1,-1,0,0,0, 0,1,-1,0,0, 0,0,1,-1,0, 0,0,0,1,-1, 0,0,0,0,0]); M
  612. [-1 0 0 0 1]
  613. [ 1 -1 0 0 0]
  614. [ 0 1 -1 0 0]
  615. [ 0 0 1 -1 0]
  616. [ 0 0 0 1 -1]
  617. [ 0 0 0 0 0]
  618. sage: Graph(M)
  619. Graph on 6 vertices
  620. sage: Graph(Matrix([[1],[1],[1]]))
  621. Traceback (most recent call last):
  622. ...
  623. ValueError: Non-symmetric or non-square matrix assumed to be an incidence matrix: There must be two nonzero entries (-1 & 1) per column.
  624. sage: Graph(Matrix([[1],[1],[0]]))
  625. Traceback (most recent call last):
  626. ...
  627. ValueError: Non-symmetric or non-square matrix assumed to be an incidence matrix: Each column represents an edge: -1 goes to 1.
  628. sage: M = Matrix([[0,1,-1],[1,0,-1],[-1,-1,0]]); M
  629. [ 0 1 -1]
  630. [ 1 0 -1]
  631. [-1 -1 0]
  632. sage: Graph(M,sparse=True)
  633. Graph on 3 vertices
  634. sage: M = Matrix([[0,1,1],[1,0,1],[-1,-1,0]]); M
  635. [ 0 1 1]
  636. [ 1 0 1]
  637. [-1 -1 0]
  638. sage: Graph(M)
  639. Traceback (most recent call last):
  640. ...
  641. ValueError: Non-symmetric or non-square matrix assumed to be an incidence matrix: Each column represents an edge: -1 goes to 1.
  642. ::
  643. sage: MA = Matrix([[1,2,0], [0,2,0], [0,0,1]]) # trac 9714
  644. sage: MI = Graph(MA, format='adjacency_matrix').incidence_matrix(); MI
  645. [-1 -1 0 0 0 1]
  646. [ 1 1 0 1 1 0]
  647. [ 0 0 1 0 0 0]
  648. sage: Graph(MI).edges(labels=None)
  649. [(0, 0), (0, 1), (0, 1), (1, 1), (1, 1), (2, 2)]
  650. sage: M = Matrix([[1], [-1]]); M
  651. [ 1]
  652. [-1]
  653. sage: Graph(M).edges()
  654. [(0, 1, None)]
  655. #. a list of edges, or labelled edges::
  656. sage: g = Graph([(1,3),(3,8),(5,2)])
  657. sage: g
  658. Graph on 5 vertices
  659. ::
  660. sage: g = Graph([(1,2,"Peace"),(7,-9,"and"),(77,2, "Love")])
  661. sage: g
  662. Graph on 5 vertices
  663. sage: g = Graph([(0, 2, '0'), (0, 2, '1'), (3, 3, '2')])
  664. sage: g.loops()
  665. [(3, 3, '2')]
  666. #. A NetworkX MultiGraph::
  667. sage: import networkx
  668. sage: g = networkx.MultiGraph({0:[1,2,3], 2:[4]})
  669. sage: Graph(g)
  670. Graph on 5 vertices
  671. #. A NetworkX graph::
  672. sage: import networkx
  673. sage: g = networkx.Graph({0:[1,2,3], 2:[4]})
  674. sage: DiGraph(g)
  675. Digraph on 5 vertices
  676. Note that in all cases, we copy the NetworkX structure.
  677. ::
  678. sage: import networkx
  679. sage: g = networkx.Graph({0:[1,2,3], 2:[4]})
  680. sage: G = Graph(g, implementation='networkx')
  681. sage: H = Graph(g, implementation='networkx')
  682. sage: G._backend._nxg is H._backend._nxg
  683. False
  684. """
  685. _directed = False
  686. def __init__(self, data=None, pos=None, loops=None, format=None,
  687. boundary=[], weighted=None, implementation='c_graph',
  688. sparse=True, vertex_labels=True, name=None,
  689. multiedges=None, convert_empty_dict_labels_to_None=None):
  690. """
  691. TESTS::
  692. sage: G = Graph()
  693. sage: loads(dumps(G)) == G
  694. True
  695. sage: a = matrix(2,2,[1,0,0,1])
  696. sage: Graph(a).adjacency_matrix() == a
  697. True
  698. sage: a = matrix(2,2,[2,0,0,1])
  699. sage: Graph(a,sparse=True).adjacency_matrix() == a
  700. True
  701. The positions are copied when the graph is built from
  702. another graph ::
  703. sage: g = graphs.PetersenGraph()
  704. sage: h = Graph(g)
  705. sage: g.get_pos() == h.get_pos()
  706. True
  707. Or from a DiGraph ::
  708. sage: d = DiGraph(g)
  709. sage: h = Graph(d)
  710. sage: g.get_pos() == h.get_pos()
  711. True
  712. Loops are not counted as multiedges (see trac 11693) and edges
  713. are not counted twice ::
  714. sage: Graph([[1,1]],multiedges=False).num_edges()
  715. 1
  716. sage: Graph([[1,2],[1,2]],multiedges=True).num_edges()
  717. 2
  718. Invalid sequence of edges given as an input (they do not all
  719. have the same length)::
  720. sage: g = Graph([(1,2),(2,3),(2,3,4)])
  721. Traceback (most recent call last):
  722. ...
  723. ValueError: Edges input must all follow the same format.
  724. Two different labels given for the same edge in a graph
  725. without multiple edges::
  726. sage: g = Graph([(1,2,3),(1,2,4)], multiedges = False)
  727. Traceback (most recent call last):
  728. ...
  729. ValueError: Two different labels given for the same edge in a graph without multiple edges.
  730. The same edge included more than once in a graph without
  731. multiple edges::
  732. sage: g = Graph([[1,2],[1,2]],multiedges=False)
  733. Traceback (most recent call last):
  734. ...
  735. ValueError: Non-multigraph input dict has multiple edges (1,2)
  736. An empty list or dictionary defines a simple graph
  737. (:trac:`10441` and :trac:`12910`)::
  738. sage: Graph([])
  739. Graph on 0 vertices
  740. sage: Graph({})
  741. Graph on 0 vertices
  742. sage: # not "Multi-graph on 0 vertices"
  743. Verify that the int format works as expected (:trac:`12557`)::
  744. sage: Graph(2).adjacency_matrix()
  745. [0 0]
  746. [0 0]
  747. sage: Graph(3) == Graph(3,format='int')
  748. True
  749. Problem with weighted adjacency matrix (:trac:`13919`)::
  750. sage: B = {0:{1:2,2:5,3:4},1:{2:2,4:7},2:{3:1,4:4,5:3},3:{5:4},4:{5:1,6:5},5:{6:7}}
  751. sage: grafo3 = Graph(B,weighted=True)
  752. sage: matad = grafo3.weighted_adjacency_matrix()
  753. sage: grafo4 = Graph(matad,format = "adjacency_matrix", weighted=True)
  754. sage: grafo4.shortest_path(0,6,by_weight=True)
  755. [0, 1, 2, 5, 4, 6]
  756. """
  757. GenericGraph.__init__(self)
  758. msg = ''
  759. from sage.structure.element import is_Matrix
  760. from sage.misc.misc import uniq
  761. if format is None and isinstance(data, str):
  762. if data[:10] == ">>graph6<<":
  763. data = data[10:]
  764. format = 'graph6'
  765. elif data[:11] == ">>sparse6<<":
  766. data = data[11:]
  767. format = 'sparse6'
  768. elif data[0] == ':':
  769. format = 'sparse6'
  770. else:
  771. format = 'graph6'
  772. if format is None and is_Matrix(data):
  773. if data.is_square() and data == data.transpose():
  774. format = 'adjacency_matrix'
  775. else:
  776. format = 'incidence_matrix'
  777. msg += "Non-symmetric or non-square matrix assumed to be an incidence matrix: "
  778. if format is None and isinstance(data, Graph):
  779. format = 'Graph'
  780. from sage.graphs.all import DiGraph
  781. if format is None and isinstance(data, DiGraph):
  782. data = data.to_undirected()
  783. format = 'Graph'
  784. if format is None and isinstance(data,list) and \
  785. len(data)>=2 and callable(data[1]):
  786. format = 'rule'
  787. if format is None and isinstance(data,dict):
  788. keys = data.keys()
  789. if len(keys) == 0: format = 'dict_of_dicts'
  790. else:
  791. if isinstance(data[keys[0]], list):
  792. format = 'dict_of_lists'
  793. elif isinstance(data[keys[0]], dict):
  794. format = 'dict_of_dicts'
  795. if format is None and hasattr(data, 'adj'):
  796. import networkx
  797. if isinstance(data, (networkx.DiGraph, networkx.MultiDiGraph)):
  798. data = data.to_undirected()
  799. format = 'NX'
  800. elif isinstance(data, (networkx.Graph, networkx.MultiGraph)):
  801. format = 'NX'
  802. if format is None and isinstance(data, (int, Integer)):
  803. format = 'int'
  804. if format is None and data is None:
  805. format = 'int'
  806. data = 0
  807. # Input is a list of edges
  808. if format is None and isinstance(data, list):
  809. # If we are given a list (we assume it is a list of
  810. # edges), we convert the problem to a dict_of_dicts or a
  811. # dict_of_lists
  812. edges = data
  813. # Along the process, we are assuming all edges have the
  814. # same length. If it is not true, a ValueError will occur
  815. try:
  816. # The list is empty
  817. if not data:
  818. data = {}
  819. format = 'dict_of_dicts'
  820. # The edges are not labelled
  821. elif len(data[0]) == 2:
  822. data = {}
  823. for u,v in edges:
  824. if not u in data:
  825. data[u] = []
  826. if not v in data:
  827. data[v] = []
  828. data[u].append(v)
  829. format = 'dict_of_lists'
  830. # The edges are labelled
  831. elif len(data[0]) == 3:
  832. data = {}
  833. for u,v,l in edges:
  834. if not u in data:
  835. data[u] = {}
  836. if not v in data:
  837. data[v] = {}
  838. # Now the keys exists, and are dictionaries ...
  839. # If we notice for the first time that there
  840. # are multiple edges, we update the whole
  841. # dictionary so that data[u][v] is a list
  842. if (multiedges is None and (u in data[v])):
  843. multiedges = True
  844. for uu, dd in data.iteritems():
  845. for vv, ddd in dd.iteritems():
  846. dd[vv] = [ddd]
  847. # If multiedges is set to False while the same
  848. # edge is present in the list with different
  849. # values of its label
  850. elif (multiedges is False and
  851. (u in data[v] and data[v][u] != l)):
  852. raise ValueError("MULTIEDGE")
  853. # Now we are behaving as if multiedges == None
  854. # means multiedges = False. If something bad
  855. # happens later, the whole dictionary will be
  856. # updated anyway
  857. if multiedges is True:
  858. if v not in data[u]:
  859. data[u][v] = []
  860. data[v][u] = []
  861. data[u][v].append(l)
  862. if u != v:
  863. data[v][u].append(l)
  864. else:
  865. data[u][v] = l
  866. data[v][u] = l
  867. format = 'dict_of_dicts'
  868. except ValueError as ve:
  869. if str(ve) == "MULTIEDGE":
  870. raise ValueError("Two different labels given for the same edge in a graph without multiple edges.")
  871. else:
  872. raise ValueError("Edges input must all follow the same format.")
  873. if format is None:
  874. import networkx
  875. data = networkx.MultiGraph(data)
  876. format = 'NX'
  877. # At this point, format has been set.
  878. # adjust for empty dicts instead of None in NetworkX default edge labels
  879. if convert_empty_dict_labels_to_None is None:
  880. convert_empty_dict_labels_to_None = (format == 'NX')
  881. verts = None
  882. if format == 'graph6':
  883. if loops is None: loops = False
  884. if weighted is None: weighted = False
  885. if multiedges is None: multiedges = False
  886. if not isinstance(data, str):
  887. raise ValueError('If input format is graph6, then data must be a string.')
  888. n = data.find('\n')
  889. if n == -1:
  890. n = len(data)
  891. ss = data[:n]
  892. n, s = generic_graph_pyx.N_inverse(ss)
  893. m = generic_graph_pyx.R_inverse(s, n)
  894. expected = n*(n-1)/2 + (6 - n*(n-1)/2)%6
  895. if len(m) > expected:
  896. raise RuntimeError("The string (%s) seems corrupt: for n = %d, the string is too long."%(ss,n))
  897. elif len(m) < expected:
  898. raise RuntimeError("The string (%s) seems corrupt: for n = %d, the string is too short."%(ss,n))
  899. num_verts = n
  900. elif format == 'sparse6':
  901. if loops is None: loops = True
  902. if weighted is None: weighted = False
  903. if multiedges is None: multiedges = True
  904. from math import ceil, floor
  905. from sage.misc.functional import log
  906. n = data.find('\n')
  907. if n == -1:
  908. n = len(data)
  909. s = data[:n]
  910. n, s = generic_graph_pyx.N_inverse(s[1:])
  911. if n == 0:
  912. edges = []
  913. else:
  914. k = int(ceil(log(n,2)))
  915. ords = [ord(i) for i in s]
  916. if any(o > 126 or o < 63 for o in ords):
  917. raise RuntimeError("The string seems corrupt: valid characters are \n" + ''.join([chr(i) for i in xrange(63,127)]))
  918. bits = ''.join([generic_graph_pyx.binary(o-63).zfill(6) for o in ords])
  919. b = []
  920. x = []
  921. for i in xrange(int(floor(len(bits)/(k+1)))):
  922. b.append(int(bits[(k+1)*i:(k+1)*i+1],2))
  923. x.append(int(bits[(k+1)*i+1:(k+1)*i+k+1],2))
  924. v = 0
  925. edges = []
  926. for i in xrange(len(b)):
  927. if b[i] == 1:
  928. v += 1
  929. if x[i] > v:
  930. v = x[i]
  931. else:
  932. if v < n:
  933. edges.append((x[i],v))
  934. num_verts = n
  935. elif format in ['adjacency_matrix', 'incidence_matrix']:
  936. assert is_Matrix(data)
  937. if format == 'weighted_adjacency_matrix':
  938. if weighted is False:
  939. raise ValueError("Format was weighted_adjacency_matrix but weighted was False.")
  940. if weighted is None: weighted = True
  941. if multiedges is None: multiedges = False
  942. format = 'adjacency_matrix'
  943. if format == 'adjacency_matrix':
  944. entries = uniq(data.list())
  945. for e in entries:
  946. try:
  947. e = int(e)
  948. assert e >= 0
  949. except StandardError:
  950. if weighted is False:
  951. raise ValueError("Non-weighted graph's"+
  952. " adjacency matrix must have only nonnegative"+
  953. " integer entries")
  954. weighted = True
  955. if multiedges is None: multiedges = False
  956. break
  957. if weighted is None:
  958. weighted = False
  959. if multiedges is None:
  960. multiedges = ((not weighted) and sorted(entries) != [0,1])
  961. for i in xrange(data.nrows()):
  962. if data[i,i] != 0:
  963. if loops is None: loops = True
  964. elif not loops:
  965. raise ValueError("Non-looped graph's adjacency"+
  966. " matrix must have zeroes on the diagonal.")
  967. break
  968. num_verts = data.nrows()
  969. elif format == 'incidence_matrix':
  970. try:
  971. positions = []
  972. for c in data.columns():
  973. NZ = c.nonzero_positions()
  974. if len(NZ) == 1:
  975. if loops is None:
  976. loops = True
  977. elif not loops:
  978. msg += "There must be two nonzero entries (-1 & 1) per column."
  979. assert False
  980. positions.append((NZ[0], NZ[0]))
  981. elif len(NZ) != 2:
  982. msg += "There must be two nonzero entries (-1 & 1) per column."
  983. assert False
  984. else:
  985. positions.append(tuple(NZ))
  986. L = uniq(c.list())
  987. L.sort()
  988. if data.nrows() != (2 if len(NZ) == 2 else 1):
  989. desirable = [-1, 0, 1] if len(NZ) == 2 else [0, 1]
  990. else:
  991. desirable = [-1, 1] if len(NZ) == 2 else [1]
  992. if L != desirable:
  993. msg += "Each column represents an edge: -1 goes to 1."
  994. assert False
  995. if loops is None: loops = False
  996. if weighted is None: weighted = False
  997. if multiedges is None:
  998. total = len(positions)
  999. multiedges = ( len(uniq(positions)) < total )
  1000. except AssertionError:
  1001. raise ValueError(msg)
  1002. num_verts = data.nrows()
  1003. elif format == 'Graph':
  1004. if loops is None: loops = data.allows_loops()
  1005. elif not loops and data.has_loops():
  1006. raise ValueError("No loops but input graph has loops.")
  1007. if multiedges is None: multiedges = data.allows_multiple_edges()
  1008. elif not multiedges:
  1009. e = data.edges(labels=False)
  1010. e = [sorted(f) for f in e]
  1011. if len(e) != len(uniq(e)):
  1012. raise ValueError("No multiple edges but input graph"+
  1013. " has multiple edges.")
  1014. if weighted is None: weighted = data.weighted()
  1015. num_verts = data.num_verts()
  1016. verts = data.vertex_iterator()
  1017. if data.get_pos() is not None:
  1018. pos = data.get_pos().copy()
  1019. elif format == 'rule':
  1020. f = data[1]
  1021. if loops is None: loops = any(f(v,v) for v in data[0])
  1022. if multiedges is None: multiedges = False
  1023. if weighted is None: weighted = False
  1024. num_verts = len(data[0])
  1025. verts = data[0]
  1026. elif format == 'dict_of_dicts':
  1027. if not all(isinstance(data[u], dict) for u in data):
  1028. raise ValueError("Input dict must be a consistent format.")
  1029. verts = set(data.keys())
  1030. if loops is None or loops is False:
  1031. for u in data:
  1032. if u in data[u]:
  1033. if loops is None: loops = True
  1034. elif loops is False:
  1035. raise ValueError("No loops but dict has loops.")
  1036. break
  1037. if loops is None: loops = False
  1038. if weighted is None: weighted = False
  1039. for u in data:
  1040. for v in data[u]:
  1041. if v not in verts: verts.add(v)
  1042. if hash(u) > hash(v):
  1043. if v in data and u in data[v]:
  1044. if data[u][v] != data[v][u]:
  1045. raise ValueError("Dict does not agree on edge (%s,%s)"%(u,v))
  1046. continue
  1047. if multiedges is not False and not isinstance(data[u][v], list):
  1048. if multiedges is None: multiedges = False
  1049. if multiedges:
  1050. raise ValueError("Dict of dicts for multigraph must be in the format {v : {u : list}}")
  1051. if multiedges is None and len(data) > 0:
  1052. multiedges = True
  1053. num_verts = len(verts)
  1054. elif format == 'dict_of_lists':
  1055. if not all(isinstance(data[u], list) for u in data):
  1056. raise ValueError("Input dict must be a consistent format.")
  1057. verts = set(data.keys())
  1058. if loops is None or loops is False:
  1059. for u in data:
  1060. if u in data[u]:
  1061. if loops is None: loops = True
  1062. elif loops is False:
  1063. raise ValueError("No loops but dict has loops.")
  1064. break
  1065. if loops is None: loops = False
  1066. if weighted is None: weighted = False
  1067. for u in data:
  1068. verts=verts.union([v for v in data[u] if v not in verts])

Large files files are truncated, but you can click here to view the full file