PageRenderTime 44ms CodeModel.GetById 22ms 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
  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])
  1069. if len(uniq(data[u])) != len(data[u]):
  1070. if multiedges is False:
  1071. from sage.misc.prandom import choice
  1072. raise ValueError("Non-multigraph input dict has multiple edges (%s,%s)"%(u, choice([v for v in data[u] if data[u].count(v) > 1])))
  1073. if multiedges is None: multiedges = True
  1074. if multiedges is None: multiedges = False
  1075. num_verts = len(verts)
  1076. elif format == 'NX':
  1077. if weighted is None:
  1078. if isinstance(data, networkx.Graph):
  1079. weighted = False
  1080. if multiedges is None:
  1081. multiedges = False
  1082. if loops is None:
  1083. loops = False
  1084. else:
  1085. weighted = True
  1086. if multiedges is None:
  1087. multiedges = True
  1088. if loops is None:
  1089. loops = True
  1090. num_verts = data.order()
  1091. verts = data.nodes()
  1092. data = data.adj
  1093. format = 'dict_of_dicts'
  1094. elif format in ['int', 'elliptic_curve_congruence']:
  1095. if weighted is None: weighted = False
  1096. if multiedges is None: multiedges = False
  1097. if loops is None: loops = False
  1098. if format == 'int': num_verts = data
  1099. else:
  1100. num_verts = len(data)
  1101. curves = data
  1102. verts = [curve.cremona_label() for curve in data]
  1103. # weighted, multiedges, loops, verts and num_verts should now be set
  1104. if implementation == 'networkx':
  1105. import networkx
  1106. from sage.graphs.base.graph_backends import NetworkXGraphBackend
  1107. if format == 'Graph':
  1108. self._backend = NetworkXGraphBackend(data.networkx_graph())
  1109. self._weighted = weighted
  1110. self.allow_loops(loops)
  1111. self.allow_multiple_edges(multiedges)
  1112. else:
  1113. if multiedges:
  1114. self._backend = NetworkXGraphBackend(networkx.MultiGraph())
  1115. else:
  1116. self._backend = NetworkXGraphBackend(networkx.Graph())
  1117. self._weighted = weighted
  1118. self.allow_loops(loops)
  1119. self.allow_multiple_edges(multiedges)
  1120. if verts is not None:
  1121. self.add_vertices(verts)
  1122. else:
  1123. self.add_vertices(range(num_verts))
  1124. elif implementation == 'c_graph':
  1125. if multiedges or weighted:
  1126. if not sparse:
  1127. raise RuntimeError("Multiedge and weighted c_graphs must be sparse.")
  1128. from sage.graphs.base.sparse_graph import SparseGraphBackend
  1129. from sage.graphs.base.dense_graph import DenseGraphBackend
  1130. CGB = SparseGraphBackend if sparse else DenseGraphBackend
  1131. if format == 'Graph':
  1132. self._backend = CGB(0, directed=False)
  1133. self.add_vertices(verts)
  1134. self._weighted = weighted
  1135. self.allow_loops(loops, check=False)
  1136. self.allow_multiple_edges(multiedges, check=False)
  1137. for u,v,l in data.edge_iterator():
  1138. self._backend.add_edge(u,v,l,False)
  1139. else:
  1140. if verts is not None:
  1141. self._backend = CGB(0, directed=False)
  1142. self.add_vertices(verts)
  1143. else:
  1144. self._backend = CGB(num_verts, directed=False)
  1145. self._weighted = weighted
  1146. self.allow_loops(loops, check=False)
  1147. self.allow_multiple_edges(multiedges, check=False)
  1148. self._backend.directed = False
  1149. else:
  1150. raise NotImplementedError("Supported implementations: networkx, c_graph.")
  1151. if format == 'graph6':
  1152. k = 0
  1153. for i in xrange(n):
  1154. for j in xrange(i):
  1155. if m[k] == '1':
  1156. self.add_edge(i, j)
  1157. k += 1
  1158. elif format == 'sparse6':
  1159. for i,j in edges:
  1160. self.add_edge(i,j)
  1161. elif format == 'adjacency_matrix':
  1162. e = []
  1163. if weighted:
  1164. for i,j in data.nonzero_positions():
  1165. if i <= j:
  1166. e.append((i,j,data[i][j]))
  1167. elif multiedges:
  1168. for i,j in data.nonzero_positions():
  1169. if i <= j:
  1170. e += [(i,j)]*int(data[i][j])
  1171. else:
  1172. for i,j in data.nonzero_positions():
  1173. if i <= j:
  1174. e.append((i,j))
  1175. self.add_edges(e)
  1176. elif format == 'incidence_matrix':
  1177. self.add_edges(positions)
  1178. elif format == 'Graph':
  1179. self.name(data.name())
  1180. elif format == 'rule':
  1181. verts = list(verts)
  1182. for u in xrange(num_verts):
  1183. for v in xrange(u+1):
  1184. uu,vv = verts[u], verts[v]
  1185. if f(uu,vv):
  1186. self.add_edge(uu,vv)
  1187. elif format == 'dict_of_dicts':
  1188. if convert_empty_dict_labels_to_None:
  1189. for u in data:
  1190. for v in data[u]:
  1191. if hash(u) <= hash(v) or v not in data or u not in data[v]:
  1192. if multiedges:
  1193. self.add_edges([(u,v,l) for l in data[u][v]])
  1194. else:
  1195. self.add_edge((u,v,data[u][v] if data[u][v] != {} else None))
  1196. else:
  1197. for u in data:
  1198. for v in data[u]:
  1199. if hash(u) <= hash(v) or v not in data or u not in data[v]:
  1200. if multiedges:
  1201. self.add_edges([(u,v,l) for l in data[u][v]])
  1202. else:
  1203. self.add_edge((u,v,data[u][v]))
  1204. elif format == 'dict_of_lists':
  1205. for u in data:
  1206. for v in data[u]:
  1207. if multiedges or hash(u) <= hash(v) or \
  1208. v not in data or u not in data[v]:
  1209. self.add_edge(u,v)
  1210. elif format == 'elliptic_curve_congruence':
  1211. from sage.rings.arith import lcm, prime_divisors
  1212. from sage.rings.fast_arith import prime_range
  1213. from sage.misc.misc import prod
  1214. for i in xrange(self.order()):
  1215. for j in xrange(i):
  1216. E = curves[i]
  1217. F = curves[j]
  1218. M = E.conductor()
  1219. N = F.conductor()
  1220. MN = lcm(M, N)
  1221. p_MN = prime_divisors(MN)
  1222. lim = prod([(j^(MN.ord(j)) + j^(MN.ord(j)-1)) for j in p_MN])
  1223. a_E = E.anlist(lim)
  1224. a_F = F.anlist(lim)
  1225. l_list = [p for p in prime_range(lim) if p not in p_MN ]
  1226. p_edges = l_list
  1227. for l in l_list:
  1228. n = a_E[l] - a_F[l]
  1229. if n != 0:
  1230. P = prime_divisors(n)
  1231. p_edges = [p for p in p_edges if p in P]
  1232. if len(p_edges) > 0:
  1233. self.add_edge(E.cremona_label(), F.cremona_label(), str(p_edges)[1:-1])
  1234. else:
  1235. assert format == 'int'
  1236. self._pos = pos
  1237. self._boundary = boundary
  1238. if format != 'Graph' or name is not None:
  1239. self.name(name)
  1240. ### Formats
  1241. def graph6_string(self):
  1242. """
  1243. Returns the graph6 representation of the graph as an ASCII string.
  1244. Only valid for simple (no loops, multiple edges) graphs on 0 to
  1245. 262143 vertices.
  1246. EXAMPLES::
  1247. sage: G = graphs.KrackhardtKiteGraph()
  1248. sage: G.graph6_string()
  1249. 'IvUqwK@?G'
  1250. """
  1251. n = self.order()
  1252. if n > 262143:
  1253. raise ValueError('graph6 format supports graphs on 0 to 262143 vertices only.')
  1254. elif self.has_loops() or self.has_multiple_edges():
  1255. raise ValueError('graph6 format supports only simple graphs (no loops, no multiple edges)')
  1256. else:
  1257. return generic_graph_pyx.N(n) + generic_graph_pyx.R(self._bit_vector())
  1258. def sparse6_string(self):
  1259. """
  1260. Returns the sparse6 representation of the graph as an ASCII string.
  1261. Only valid for undirected graphs on 0 to 262143 vertices, but loops
  1262. and multiple edges are permitted.
  1263. EXAMPLES::
  1264. sage: G = graphs.BullGraph()
  1265. sage: G.sparse6_string()
  1266. ':Da@en'
  1267. ::
  1268. sage: G = Graph()
  1269. sage: G.sparse6_string()
  1270. ':?'
  1271. ::
  1272. sage: G = Graph(loops=True, multiedges=True,sparse=True)
  1273. sage: Graph(':?',sparse=True) == G
  1274. True
  1275. """
  1276. n = self.order()
  1277. if n == 0:
  1278. return ':?'
  1279. if n > 262143:
  1280. raise ValueError('sparse6 format supports graphs on 0 to 262143 vertices only.')
  1281. else:
  1282. vertices = self.vertices()
  1283. n = len(vertices)
  1284. edges = self.edges(labels=False)
  1285. for i in range(len(edges)): # replace edge labels with natural numbers (by index in vertices)
  1286. edges[i] = (vertices.index(edges[i][0]),vertices.index(edges[i][1]))
  1287. # order edges 'reverse lexicographically', that is, for
  1288. # edge (a,b) and edge (c,d) first compare b and d, then a and c;
  1289. edges.sort(key=lambda e: (e[1],e[0]))
  1290. # encode bit vector
  1291. from math import ceil
  1292. from sage.misc.functional import log
  1293. k = int(ceil(log(n,2)))
  1294. v = 0
  1295. i = 0
  1296. m = 0
  1297. s = ''
  1298. while m < len(edges):
  1299. if edges[m][1] > v + 1:
  1300. sp = generic_graph_pyx.binary(edges[m][1])
  1301. sp = '0'*(k-len(sp)) + sp
  1302. s += '1' + sp
  1303. v = edges[m][1]
  1304. elif edges[m][1] == v + 1:
  1305. sp = generic_graph_pyx.binary(edges[m][0])
  1306. sp = '0'*(k-len(sp)) + sp
  1307. s += '1' + sp
  1308. v += 1
  1309. m += 1
  1310. else:
  1311. sp = generic_graph_pyx.binary(edges[m][0])
  1312. sp = '0'*(k-len(sp)) + sp
  1313. s += '0' + sp
  1314. m += 1
  1315. # encode s as a 6-string, as in R(x), but padding with 1's
  1316. # pad on the right to make a multiple of 6
  1317. s = s + ( '1' * ((6 - len(s))%6) )
  1318. # split into groups of 6, and convert numbers to decimal, adding 63
  1319. six_bits = ''
  1320. for i in range(len(s)/6):
  1321. six_bits += chr( int( s[6*i:6*(i+1)], 2) + 63 )
  1322. return ':' + generic_graph_pyx.N(n) + six_bits
  1323. ### Attributes
  1324. def is_directed(self):
  1325. """
  1326. Since graph is undirected, returns False.
  1327. EXAMPLES::
  1328. sage: Graph().is_directed()
  1329. False
  1330. """
  1331. return False
  1332. ### Properties
  1333. def is_even_hole_free(self, certificate = False):
  1334. r"""
  1335. Tests whether ``self`` contains an induced even hole.
  1336. A Hole is a cycle of length at least 4 (included). It is said
  1337. to be even (resp. odd) if its length is even (resp. odd).
  1338. Even-hole-free graphs always contain a bisimplicial vertex,
  1339. which ensures that their chromatic number is at most twice
  1340. their clique number [ABCHRS08]_.
  1341. INPUT:
  1342. - ``certificate`` (boolean) -- When ``certificate = False``,
  1343. this method only returns ``True`` or ``False``. If
  1344. ``certificate = True``, the subgraph found is returned
  1345. instead of ``False``.
  1346. EXAMPLE:
  1347. Is the Petersen Graph even-hole-free ::
  1348. sage: g = graphs.PetersenGraph()
  1349. sage: g.is_even_hole_free()
  1350. False
  1351. As any chordal graph is hole-free, interval graphs behave the
  1352. same way::
  1353. sage: g = graphs.RandomInterval(20)
  1354. sage: g.is_even_hole_free()
  1355. True
  1356. It is clear, though, that a random Bipartite Graph which is
  1357. not a forest has an even hole::
  1358. sage: g = graphs.RandomBipartite(10, 10, .5)
  1359. sage: g.is_even_hole_free() and not g.is_forest()
  1360. False
  1361. We can check the certificate returned is indeed an even
  1362. cycle::
  1363. sage: if not g.is_forest():
  1364. ... cycle = g.is_even_hole_free(certificate = True)
  1365. ... if cycle.order() % 2 == 1:
  1366. ... print "Error !"
  1367. ... if not cycle.is_isomorphic(
  1368. ... graphs.CycleGraph(cycle.order())):
  1369. ... print "Error !"
  1370. ...
  1371. sage: print "Everything is Fine !"
  1372. Everything is Fine !
  1373. TESTS:
  1374. Bug reported in #9925, and fixed by #9420::
  1375. sage: g = Graph(':SiBFGaCEF_@CE`DEGH`CEFGaCDGaCDEHaDEF`CEH`ABCDEF')
  1376. sage: g.is_even_hole_free()
  1377. False
  1378. sage: g.is_even_hole_free(certificate = True)
  1379. Subgraph of (): Looped multi-graph on 4 vertices
  1380. Making sure there are no other counter-examples around ::
  1381. sage: t = lambda x : (Graph(x).is_forest() or
  1382. ... isinstance(Graph(x).is_even_hole_free(certificate = True),Graph))
  1383. sage: all( t(graphs.RandomBipartite(10,10,.5)) for i in range(100) )
  1384. True
  1385. REFERENCE:
  1386. .. [ABCHRS08] L. Addario-Berry, M. Chudnovsky, F. Havet, B. Reed, P. Seymour
  1387. Bisimplicial vertices in even-hole-free graphs
  1388. Journal of Combinatorial Theory, Series B
  1389. vol 98, n.6 pp 1119-1164, 2008
  1390. """
  1391. from sage.graphs.graph_generators import GraphGenerators
  1392. girth = self.girth()
  1393. if girth > self.order():
  1394. start = 4
  1395. elif girth % 2 == 0:
  1396. if not certificate:
  1397. return False
  1398. start = girth
  1399. else:
  1400. start = girth + 1
  1401. while start <= self.order():
  1402. subgraph = self.subgraph_search(GraphGenerators().CycleGraph(start), induced = True)
  1403. if not subgraph is None:
  1404. if certificate:
  1405. return subgraph
  1406. else:
  1407. return False
  1408. start = start + 2
  1409. return True
  1410. def is_odd_hole_free(self, certificate = False):
  1411. r"""
  1412. Tests whether ``self`` contains an induced odd hole.
  1413. A Hole is a cycle of length at least 4 (included). It is said
  1414. to be even (resp. odd) if its length is even (resp. odd).
  1415. It is interesting to notice that while it is polynomial to
  1416. check whether a graph has an odd hole or an odd antihole [CRST06]_, it is
  1417. not known whether testing for one of these two cases
  1418. independently is polynomial too.
  1419. INPUT:
  1420. - ``certificate`` (boolean) -- When ``certificate = False``,
  1421. this method only returns ``True`` or ``False``. If
  1422. ``certificate = True``, the subgraph found is returned
  1423. instead of ``False``.
  1424. EXAMPLE:
  1425. Is the Petersen Graph odd-hole-free ::
  1426. sage: g = graphs.PetersenGraph()
  1427. sage: g.is_odd_hole_free()
  1428. False
  1429. Which was to be expected, as its girth is 5 ::
  1430. sage: g.girth()
  1431. 5
  1432. We can check the certificate returned is indeed a 5-cycle::
  1433. sage: cycle = g.is_odd_hole_free(certificate = True)
  1434. sage: cycle.is_isomorphic(graphs.CycleGraph(5))
  1435. True
  1436. As any chordal graph is hole-free, no interval graph has an odd hole::
  1437. sage: g = graphs.RandomInterval(20)
  1438. sage: g.is_odd_hole_free()
  1439. True
  1440. REFERENCES:
  1441. .. [CRST06] M. Chudnovsky, G. Cornuejols, X. Liu, P. Seymour, K. Vuskovic
  1442. Recognizing berge graphs
  1443. Combinatorica vol 25, n 2, pages 143--186
  1444. 2005
  1445. """
  1446. from sage.graphs.graph_generators import GraphGenerators
  1447. girth = self.odd_girth()
  1448. if girth > self.order():
  1449. return True
  1450. if girth == 3:
  1451. start = 5
  1452. else:
  1453. if not certificate:
  1454. return False
  1455. start = girth
  1456. while start <= self.order():
  1457. subgraph = self.subgraph_search(GraphGenerators().CycleGraph(start), induced = True)
  1458. if not subgraph is None:
  1459. if certificate:
  1460. return subgraph
  1461. else:
  1462. return False
  1463. start += 2
  1464. return True
  1465. def is_line_graph(self, certificate = False):
  1466. r"""
  1467. Tests wether the graph is a line graph.
  1468. INPUT:
  1469. - ``certificate`` (boolean) -- whether to return a certificate
  1470. when the graph is *not* a line graph. When ``certificate``
  1471. is set to ``True``, and if the graph is not a line graph,
  1472. the method returns a subgraph isomorphic to one of the 9
  1473. forbidden induced subgraphs of a line graph (instead of the
  1474. usual ``False``)
  1475. TODO:
  1476. This methods sequentially tests each of the forbidden
  1477. subgraphs, which is a very slow method. There exist much
  1478. better algorithms, including those which are actually able to
  1479. return a graph whose line graph is isomorphic to the given
  1480. graph.
  1481. EXAMPLES:
  1482. A complete graph is always the line graph of a star::
  1483. sage: graphs.CompleteGraph(5).is_line_graph()
  1484. True
  1485. The Petersen Graph not being claw-free, it is not a line
  1486. graph:
  1487. sage: graphs.PetersenGraph().is_line_graph()
  1488. False
  1489. This is indeed the subgraph returned::
  1490. sage: C = graphs.PetersenGraph().is_line_graph(certificate = True)
  1491. sage: C.is_isomorphic(graphs.ClawGraph())
  1492. True
  1493. """
  1494. from sage.graphs.graph_generators import graphs
  1495. for g in graphs.line_graph_forbidden_subgraphs():
  1496. h = self.subgraph_search(g, induced = True)
  1497. if h is not None:
  1498. if certificate:
  1499. return h
  1500. else:
  1501. return False
  1502. return True
  1503. def is_bipartite(self, certificate = False):
  1504. """
  1505. Returns ``True`` if graph `G` is bipartite, ``False`` if not.
  1506. Traverse the graph G with breadth-first-search and color nodes.
  1507. INPUT:
  1508. - ``certificate`` -- whether to return a certificate (``False`` by
  1509. default). If set to ``True``, the certificate returned in a proper
  1510. 2-coloring when `G` is bipartite, and an odd cycle otherwise.
  1511. EXAMPLES::
  1512. sage: graphs.CycleGraph(4).is_bipartite()
  1513. True
  1514. sage: graphs.CycleGraph(5).is_bipartite()
  1515. False
  1516. A random graph is very rarely bipartite::
  1517. sage: g = graphs.PetersenGraph()
  1518. sage: g.is_bipartite()
  1519. False
  1520. sage: false, oddcycle = g.is_bipartite(certificate = True)
  1521. sage: len(oddcycle) % 2
  1522. 1
  1523. """
  1524. color = {}
  1525. # For any uncolored vertex in the graph (to ensure we do the right job
  1526. # when the graph is not connected !)
  1527. for u in self:
  1528. if u in color:
  1529. continue
  1530. # Let us run a BFS starting from u
  1531. queue = [u]
  1532. color[u] = 1
  1533. while queue:
  1534. v = queue.pop(0)
  1535. c = 1-color[v]
  1536. for w in self.neighbor_iterator(v):
  1537. # If the vertex has already been colored
  1538. if w in color:
  1539. # The graph is not bipartite !
  1540. if color[w] == color[v]:
  1541. # Should we return an odd cycle ?
  1542. if certificate:
  1543. # We build the first half of the cycle, i.e. a
  1544. # u-w path
  1545. cycle = self.shortest_path(u,w)
  1546. # The second half is a v-u path, but there may
  1547. # be common vertices in the two paths. But we
  1548. # can avoid that !
  1549. for v in self.shortest_path(v,u):
  1550. if v in cycle:
  1551. return False, cycle[cycle.index(v):]
  1552. else:
  1553. cycle.append(v)
  1554. else:
  1555. return False
  1556. # We color a new vertex
  1557. else:
  1558. color[w] = c
  1559. queue.append(w)
  1560. if certificate:
  1561. return True, color
  1562. else:
  1563. return True
  1564. def is_triangle_free(self, algorithm='bitset'):
  1565. r"""
  1566. Returns whether ``self`` is triangle-free
  1567. INPUT:
  1568. - ``algorithm`` -- (default: ``'bitset'``) specifies the algorithm to
  1569. use among:
  1570. - ``'matrix'`` -- tests if the trace of the adjacency matrix is
  1571. positive.
  1572. - ``'bitset'`` -- encodes adjacencies into bitsets and uses fast
  1573. bitset operations to test if the input graph contains a
  1574. triangle. This method is generaly faster than stantard matrix
  1575. multiplication.
  1576. EXAMPLE:
  1577. The Petersen Graph is triangle-free::
  1578. sage: g = graphs.PetersenGraph()
  1579. sage: g.is_triangle_free()
  1580. True
  1581. or a complete Bipartite Graph::
  1582. sage: G = graphs.CompleteBipartiteGraph(5,6)
  1583. sage: G.is_triangle_free(algorithm='matrix')
  1584. True
  1585. sage: G.is_triangle_free(algorithm='bitset')
  1586. True
  1587. a tripartite graph, though, contains many triangles::
  1588. sage: G = (3 * graphs.CompleteGraph(5)).complement()
  1589. sage: G.is_triangle_free(algorithm='matrix')
  1590. False
  1591. sage: G.is_triangle_free(algorithm='bitset')
  1592. False
  1593. TESTS:
  1594. Comparison of algorithms::
  1595. sage: for i in xrange(10): # long test
  1596. ... G = graphs.RandomBarabasiAlbert(50,2)
  1597. ... bm = G.is_triangle_free(algorithm='matrix')
  1598. ... bb = G.is_triangle_free(algorithm='bitset')
  1599. ... if bm != bb:
  1600. ... print "That's not good!"
  1601. Asking for an unknown algorithm::
  1602. sage: g.is_triangle_free(algorithm='tip top')
  1603. Traceback (most recent call last):
  1604. ...
  1605. ValueError: Algorithm 'tip top' not yet implemented. Please contribute.
  1606. """
  1607. if algorithm=='bitset':
  1608. from sage.misc.bitset import Bitset
  1609. N = self.num_verts()
  1610. map = {}
  1611. i = 0
  1612. B = {}
  1613. for u in self.vertex_iterator():
  1614. map[u] = i
  1615. i += 1
  1616. B[u] = Bitset(capacity=N)
  1617. # map adjacency to bitsets
  1618. for u,v in self.edge_iterator(labels=None):
  1619. B[u].add(map[v])
  1620. B[v].add(map[u])
  1621. # map lengths 2 paths to bitsets
  1622. BB = Bitset(capacity=N)
  1623. for u in self.vertex_iterator():
  1624. BB.clear()
  1625. for v in self.vertex_iterator():
  1626. if B[u]&B[v]:
  1627. BB.add(map[v])
  1628. # search for triangles
  1629. if B[u]&BB:
  1630. return False
  1631. return True
  1632. elif algorithm=='matrix':
  1633. return (self.adjacency_matrix()**3).trace() == 0
  1634. else:
  1635. raise ValueError("Algorithm '%s' not yet implemented. Please contribute." %(algorithm))
  1636. def is_split(self):
  1637. r"""
  1638. Returns ``True`` if the graph is a Split graph, ``False`` otherwise.
  1639. A Graph `G` is said to be a split graph if its vertices `V(G)`
  1640. can be partitioned into two sets `K` and `I` such that the
  1641. vertices of `K` induce a complete graphe, and those of `I` are
  1642. an independent set.
  1643. There is a simple test to check whether a graph is a split
  1644. graph (see, for instance, the book "Graph Classes, a survey"
  1645. [GraphClasses]_ page 203) :
  1646. Given the degree sequence `d_1 \geq ... \geq d_n` of `G`, a graph
  1647. is a split graph if and only if :
  1648. .. MATH::
  1649. \sum_{i=1}^\omega d_i = \omega (\omega - 1) + \sum_{i=\omega + 1}^nd_i
  1650. where `\omega = max \{i:d_i\geq i-1\}`.
  1651. EXAMPLES:
  1652. Split graphs are, in particular, chordal graphs. Hence, The Petersen graph
  1653. can not be split::
  1654. sage: graphs.PetersenGraph().is_split()
  1655. False
  1656. We can easily build some "random" split graph by creating a
  1657. complete graph, and adding vertices only connected
  1658. to some random vertices of the clique::
  1659. sage: g = graphs.CompleteGraph(10)
  1660. sage: sets = Subsets(Set(range(10)))
  1661. sage: for i in range(10, 25):
  1662. ... g.add_edges([(i,k) for k in sets.random_element()])
  1663. sage: g.is_split()
  1664. True
  1665. REFERENCES:
  1666. .. [GraphClasses] A. Brandstadt, VB Le and JP Spinrad
  1667. Graph classes: a survey
  1668. SIAM Monographs on Discrete Mathematics and Applications},
  1669. 1999
  1670. """
  1671. # our degree sequence is numbered from 0 to n-1, so to avoid
  1672. # any mistake, let's fix it :-)
  1673. degree_sequence = [0] + sorted(self.degree(), reverse = True)
  1674. for (i, d) in enumerate(degree_sequence):
  1675. if d >= i - 1:
  1676. omega = i
  1677. else:
  1678. break
  1679. left = sum(degree_sequence[:omega + 1])
  1680. right = omega * (omega - 1) + sum(degree_sequence[omega + 1:])
  1681. return left == right
  1682. def is_perfect(self, certificate = False):
  1683. r"""
  1684. Tests whether the graph is perfect.
  1685. A graph `G` is said to be perfect if `\chi(H)=\omega(H)` hold
  1686. for any induced subgraph `H\subseteq_i G` (and so for `G`
  1687. itself, too), where `\chi(H)` represents the chromatic number
  1688. of `H`, and `\omega(H)` its clique number. The Strong Perfect
  1689. Graph Theorem [SPGT]_ gives another characterization of
  1690. perfect graphs:
  1691. A graph is perfect if and only if it contains no odd hole
  1692. (cycle on an odd number `k` of vertices, `k>3`) nor any odd
  1693. antihole (complement of a hole) as an induced subgraph.
  1694. INPUT:
  1695. - ``certificate`` (boolean) -- whether to return
  1696. a certificate (default : ``False``)
  1697. OUTPUT:
  1698. When ``certificate = False``, this function returns
  1699. a boolean value. When ``certificate = True``, it returns
  1700. a subgraph of ``self`` isomorphic to an odd hole or an odd
  1701. antihole if any, and ``None`` otherwise.
  1702. EXAMPLE:
  1703. A Bipartite Graph is always perfect ::
  1704. sage: g = graphs.RandomBipartite(8,4,.5)
  1705. sage: g.is_perfect()
  1706. True
  1707. Interval Graphs, which are chordal graphs, too ::
  1708. sage: g = graphs.RandomInterval(7)
  1709. sage: g.is_perfect()
  1710. True
  1711. The PetersenGraph, which is triangle-free and
  1712. has chromatic number 3 is obviously not perfect::
  1713. sage: g = graphs.PetersenGraph()
  1714. sage: g.is_perfect()
  1715. False
  1716. We can obtain an induced 5-cycle as a certificate::
  1717. sage: g.is_perfect(certificate = True)
  1718. Subgraph of (Petersen graph): Graph on 5 vertices
  1719. TEST:
  1720. Check that :trac:`13546` has been fixed::
  1721. sage: Graph(':FgGE@I@GxGs').is_perfect()
  1722. False
  1723. sage: g = Graph({0: [2, 3, 4, 5],
  1724. ... 1: [3, 4, 5, 6],
  1725. ... 2: [0, 4, 5, 6],
  1726. ... 3: [0, 1, 5, 6],
  1727. ... 4: [0, 1, 2, 6],
  1728. ... 5: [0, 1, 2, 3],
  1729. ... 6: [1, 2, 3, 4]})
  1730. sage: g.is_perfect()
  1731. False
  1732. REFERENCES:
  1733. .. [SPGT] M. Chudnovsky, N. Robertson, P. Seymour, R. Thomas.
  1734. The strong perfect graph theorem
  1735. Annals of Mathematics
  1736. vol 164, number 1, pages 51--230
  1737. 2006
  1738. TESTS::
  1739. sage: Graph(':Ab').is_perfect()
  1740. Traceback (most recent call last):
  1741. ...
  1742. ValueError: This method is only defined for simple graphs, and yours is not one of them !
  1743. sage: g = Graph()
  1744. sage: g.allow_loops(True)
  1745. sage: g.add_edge(0,0)
  1746. sage: g.edges()
  1747. [(0, 0, None)]
  1748. sage: g.is_perfect()
  1749. Traceback (most recent call last):
  1750. ...
  1751. ValueError: This method is only defined for simple graphs, and yours is not one of them !
  1752. """
  1753. if self.has_multiple_edges() or self.has_loops():
  1754. raise ValueError("This method is only defined for simple graphs,"
  1755. " and yours is not one of them !")
  1756. if self.is_bipartite():
  1757. return True if not certificate else None
  1758. self_complement = self.complement()
  1759. self_complement.remove_loops()
  1760. self_complement.remove_multiple_edges()
  1761. if self_complement.is_bipartite():
  1762. return True if not certificate else None
  1763. answer = self.is_odd_hole_free(certificate = certificate)
  1764. if not (answer is True):
  1765. return answer
  1766. return self_complement.is_odd_hole_free(certificate = certificate)
  1767. def is_strongly_regular(self, parameters=False):
  1768. r"""
  1769. Tests whether ``self`` is strongly regular.
  1770. A graph `G` is said to be strongly regular with parameters (n, k,
  1771. \lambda, \mu)` if and only if:
  1772. * `G` has `n` vertices.
  1773. * `G` is `k`-regular.
  1774. * Any two adjacent vertices of `G` have `\lambda` common neighbors.
  1775. * Any two non-adjacent vertices of `G` have `\mu` common neighbors.
  1776. INPUT:
  1777. - ``parameters`` (boolean) -- whether to return the quadruple `(n,
  1778. k,\lambda,\mu)`. If ``parameters = False`` (default), this method only
  1779. returns ``True`` and ``False`` answers. If ``parameters=True``, the
  1780. ``True`` answers are replaced by quadruples `(n, k,\lambda,\mu)`. See
  1781. definition above.
  1782. EXAMPLES:
  1783. Petersen's graph is strongly regular::
  1784. sage: g = graphs.PetersenGraph()
  1785. sage: g.is_strongly_regular()
  1786. True
  1787. sage: g.is_strongly_regular(parameters = True)
  1788. (10, 3, 0, 1)
  1789. And Clebsch's graph is too::
  1790. sage: g = graphs.ClebschGraph()
  1791. sage: g.is_strongly_regular()
  1792. True
  1793. sage: g.is_strongly_regular(parameters = True)
  1794. (16, 5, 0, 2)
  1795. But Chvatal's graph is not::
  1796. sage: g = graphs.ChvatalGraph()
  1797. sage: g.is_strongly_regular()
  1798. False
  1799. """
  1800. degree = self.degree()
  1801. k = degree[0]
  1802. if not all(d == k for d in degree):
  1803. return False
  1804. if self.is_clique():
  1805. l = self.order()-2
  1806. m = 0
  1807. elif self.size() == 0:
  1808. l = 0
  1809. m = 0
  1810. else:
  1811. l = m = None
  1812. for u in self:
  1813. nu = set(self.neighbors(u))
  1814. for v in self:
  1815. if u == v:
  1816. continue
  1817. nv = set(self.neighbors(v))
  1818. inter = len(nu&nv)
  1819. if v in nu:
  1820. if l is None:
  1821. l = inter
  1822. else:
  1823. if l != inter:
  1824. return False
  1825. else:
  1826. if m is None:
  1827. m = inter
  1828. else:
  1829. if m != inter:
  1830. return False
  1831. if parameters:
  1832. return (self.order(),k,l,m)
  1833. else:
  1834. return True
  1835. def odd_girth(self):
  1836. r"""
  1837. Returns the odd girth of self.
  1838. The odd girth of a graph is defined as the smallest cycle of odd length.
  1839. OUTPUT:
  1840. The odd girth of ``self``.
  1841. EXAMPLES:
  1842. The McGee graph has girth 7 and therefore its odd girth is 7 as well. ::
  1843. sage: G = graphs.McGeeGraph()
  1844. sage: G.odd_girth()
  1845. 7
  1846. Any complete graph on more than 2 vertices contains a triangle and has
  1847. thus odd girth 3. ::
  1848. sage: G = graphs.CompleteGraph(10)
  1849. sage: G.odd_girth()
  1850. 3
  1851. Every bipartite graph has no odd cycles and consequently odd girth of
  1852. infinity. ::
  1853. sage: G = graphs.CompleteBipartiteGraph(100,100)
  1854. sage: G.odd_girth()
  1855. +Infinity
  1856. .. SEEALSO::
  1857. * :meth:`~sage.graphs.generic_graph.GenericGraph.girth` -- computes
  1858. the girth of a graph.
  1859. REFERENCES:
  1860. The property relating the odd girth to the coefficients of the
  1861. characteristic polynomial is an old result from algebraic graph theory
  1862. see
  1863. .. [Har62] Harary, F (1962). The determinant of the adjacency matrix of
  1864. a graph, SIAM Review 4, 202-210
  1865. .. [Biggs93] Biggs, N. L. Algebraic Graph Theory, 2nd ed. Cambridge,
  1866. England: Cambridge University Press, pp. 45, 1993.
  1867. TESTS::
  1868. sage: graphs.CycleGraph(5).odd_girth()
  1869. 5
  1870. sage: graphs.CycleGraph(11).odd_girth()
  1871. 11
  1872. """
  1873. ch = ((self.am()).charpoly()).coeffs()
  1874. n = self.order()
  1875. for i in xrange(n-1,-1,-2):
  1876. if ch[i] != 0:
  1877. return n-i
  1878. from sage.rings.infinity import Infinity
  1879. return Infinity
  1880. def is_edge_transitive(self):
  1881. """
  1882. Returns true if self is an edge transitive graph.
  1883. A graph is edge-transitive if its automorphism group acts transitively
  1884. on its edge set.
  1885. Equivalently, if there exists for any pair of edges `uv,u'v'\in E(G)` an
  1886. automorphism `\phi` of `G` such that `\phi(uv)=u'v'` (note this does not
  1887. necessarily mean that `\phi(u)=u'` and `\phi(v)=v'`).
  1888. See :wikipedia:`the wikipedia article on edge-transitive graphs
  1889. <Edge-transitive_graph>` for more information.
  1890. .. SEEALSO::
  1891. - :meth:`~Graph.is_arc_transitive`
  1892. - :meth:`~Graph.is_half_transitive`
  1893. - :meth:`~Graph.is_semi_symmetric`
  1894. EXAMPLES::
  1895. sage: P = graphs.PetersenGraph()
  1896. sage: P.is_edge_transitive()
  1897. True
  1898. sage: C = graphs.CubeGraph(3)
  1899. sage: C.is_edge_transitive()
  1900. True
  1901. sage: G = graphs.GrayGraph()
  1902. sage: G.is_edge_transitive()
  1903. True
  1904. sage: P = graphs.PathGraph(4)
  1905. sage: P.is_edge_transitive()
  1906. False
  1907. """
  1908. from sage.interfaces.gap import gap
  1909. if self.size() == 0:
  1910. return True
  1911. A,T = self.automorphism_group(translation=True)
  1912. e = self.edge_iterator(labels=False).next()
  1913. e = [T[e[0]], T[e[1]]]
  1914. return gap("OrbitLength("+str(A._gap_())+",Set(" + str(e) + "),OnSets);") == self.size()
  1915. def is_arc_transitive(self):
  1916. """
  1917. Returns true if self is an arc-transitive graph
  1918. A graph is arc-transitive if its automorphism group acts transitively on
  1919. its pairs of adjacent vertices.
  1920. Equivalently, if there exists for any pair of edges `uv,u'v'\in E(G)` an
  1921. automorphism `\phi_1` of `G` such that `\phi_1(u)=u'` and
  1922. `\phi_1(v)=v'`, as well as another automorphism `\phi_2` of `G` such
  1923. that `\phi_2(u)=v'` and `\phi_2(v)=u'`
  1924. See :wikipedia:`the wikipedia article on arc-transitive graphs
  1925. <arc-transitive_graph>` for more information.
  1926. .. SEEALSO::
  1927. - :meth:`~Graph.is_edge_transitive`
  1928. - :meth:`~Graph.is_half_transitive`
  1929. - :meth:`~Graph.is_semi_symmetric`
  1930. EXAMPLES::
  1931. sage: P = graphs.PetersenGraph()
  1932. sage: P.is_arc_transitive()
  1933. True
  1934. sage: G = graphs.GrayGraph()
  1935. sage: G.is_arc_transitive()
  1936. False
  1937. """
  1938. from sage.interfaces.gap import gap
  1939. if self.size() == 0:
  1940. return True
  1941. A,T = self.automorphism_group(translation=True)
  1942. e = self.edge_iterator(labels=False).next()
  1943. e = [T[e[0]], T[e[1]]]
  1944. return gap("OrbitLength("+str(A._gap_())+",Set(" + str(e) + "),OnTuples);") == 2*self.size()
  1945. def is_half_transitive(self):
  1946. """
  1947. Returns true if self is a half-transitive graph.
  1948. A graph is is half-transitive if it is both vertex and edge transitive
  1949. but not arc-transitive.
  1950. See :wikipedia:`the wikipedia article on half-transitive graphs
  1951. <half-transitive_graph>` for more information.
  1952. .. SEEALSO::
  1953. - :meth:`~Graph.is_edge_transitive`
  1954. - :meth:`~Graph.is_arc_transitive`
  1955. - :meth:`~Graph.is_semi_symmetric`
  1956. EXAMPLES:
  1957. The Petersen Graph is not half-transitive::
  1958. sage: P = graphs.PetersenGraph()
  1959. sage: P.is_half_transitive()
  1960. False
  1961. The smallest half-transitive graph is the Holt Graph::
  1962. sage: H = graphs.HoltGraph()
  1963. sage: H.is_half_transitive()
  1964. True
  1965. """
  1966. # A half-transitive graph always has only vertices of even degree
  1967. if not all(d%2 == 0 for d in self.degree_iterator()):
  1968. return False
  1969. return (self.is_edge_transitive() and
  1970. self.is_vertex_transitive() and
  1971. not self.is_arc_transitive())
  1972. def is_semi_symmetric(self):
  1973. """
  1974. Returns true if self is semi-symmetric.
  1975. A graph is semi-symmetric if it is regular, edge-transitve but not
  1976. vertex-transitive.
  1977. See :wikipedia:`the wikipedia article on semi-symmetric graphs
  1978. <Semi-symmetric_graph>` for more information.
  1979. .. SEEALSO::
  1980. - :meth:`~Graph.is_edge_transitive`
  1981. - :meth:`~Graph.is_arc_transitive`
  1982. - :meth:`~Graph.is_half-transitive`
  1983. EXAMPLES:
  1984. The Petersen graph is not semi-symmetric::
  1985. sage: P = graphs.PetersenGraph()
  1986. sage: P.is_semi_symmetric()
  1987. False
  1988. The Gray graph is the smallest possible semi-symmetric graph::
  1989. sage: G = graphs.GrayGraph()
  1990. sage: G.is_semi_symmetric()
  1991. True
  1992. Another well known semi-symmetric graph is the Ljubljana graph::
  1993. sage: L = graphs.LjubljanaGraph()
  1994. sage: L.is_semi_symmetric()
  1995. True
  1996. """
  1997. # A semi-symmetric graph is always bipartite
  1998. if not self.is_bipartite() :
  1999. return False
  2000. return (self.is_regular() and
  2001. self.is_edge_transitive() and not
  2002. self.is_vertex_transitive())
  2003. def degree_constrained_subgraph(self, bounds=None, solver=None, verbose=0):
  2004. r"""
  2005. Returns a degree-constrained subgraph.
  2006. Given a graph `G` and two functions `f, g:V(G)\rightarrow \mathbb Z`
  2007. such that `f \leq g`, a degree-constrained subgraph in `G` is
  2008. a subgraph `G' \subseteq G` such that for any vertex `v \in G`,
  2009. `f(v) \leq d_{G'}(v) \leq g(v)`.
  2010. INPUT:
  2011. - ``bounds`` -- (default: ``None``) Two possibilities:
  2012. - A dictionary whose keys are the vertices, and values a pair of
  2013. real values ``(min,max)`` corresponding to the values
  2014. `(f(v),g(v))`.
  2015. - A function associating to each vertex a pair of
  2016. real values ``(min,max)`` corresponding to the values
  2017. `(f(v),g(v))`.
  2018. - ``solver`` -- (default: ``None``) Specify a Linear Program (LP)
  2019. solver to be used. If set to ``None``, the default one is used. For
  2020. more information on LP solvers and which default solver is used, see
  2021. the method
  2022. :meth:`solve <sage.numerical.mip.MixedIntegerLinearProgram.solve>`
  2023. of the class
  2024. :class:`MixedIntegerLinearProgram <sage.numerical.mip.MixedIntegerLinearProgram>`.
  2025. - ``verbose`` -- integer (default: ``0``). Sets the level of
  2026. verbosity. Set to 0 by default, which means quiet.
  2027. OUTPUT:
  2028. - When a solution exists, this method outputs the degree-constained
  2029. subgraph as a Graph object.
  2030. - When no solution exists, returns ``False``.
  2031. .. NOTE::
  2032. - This algorithm computes the degree-constrained subgraph of minimum weight.
  2033. - If the graph's edges are weighted, these are taken into account.
  2034. - This problem can be solved in polynomial time.
  2035. EXAMPLES:
  2036. Is there a perfect matching in an even cycle? ::
  2037. sage: g = graphs.CycleGraph(6)
  2038. sage: bounds = lambda x: [1,1]
  2039. sage: m = g.degree_constrained_subgraph(bounds=bounds)
  2040. sage: m.size()
  2041. 3
  2042. """
  2043. from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException
  2044. p = MixedIntegerLinearProgram(maximization=False, solver=solver)
  2045. b = p.new_variable()
  2046. reorder = lambda x,y: (x,y) if x<y else (y,x)
  2047. if bounds is None:
  2048. raise ValueError,"The `bounds` keyword can not be equal to None"
  2049. elif isinstance(bounds,dict):
  2050. f_bounds = lambda x: bounds[x]
  2051. else:
  2052. f_bounds = bounds
  2053. if self.weighted():
  2054. from sage.rings.real_mpfr import RR
  2055. weight = lambda x: x if x in RR else 1
  2056. else:
  2057. weight = lambda x: 1
  2058. for v in self:
  2059. minimum,maximum = f_bounds(v)
  2060. p.add_constraint(p.sum([ b[reorder(x,y)]*weight(l) for x,y,l in self.edges_incident(v)]), min=minimum, max=maximum)
  2061. p.set_objective(p.sum([ b[reorder(x,y)]*weight(l) for x,y,l in self.edge_iterator()]))
  2062. p.set_binary(b)
  2063. try:
  2064. p.solve(log=verbose)
  2065. g = self.copy()
  2066. b = p.get_values(b)
  2067. g.delete_edges([(x,y) for x,y,_ in g.edge_iterator() if b[reorder(x,y)] < 0.5])
  2068. return g
  2069. except MIPSolverException:
  2070. return False
  2071. ### Orientations
  2072. def strong_orientation(self):
  2073. r"""
  2074. Returns a strongly connected orientation of the current graph. See
  2075. also the :wikipedia:`Strongly_connected_component`.
  2076. An orientation of an undirected graph is a digraph obtained by
  2077. giving an unique direction to each of its edges. An orientation
  2078. is said to be strong if there is a directed path between each
  2079. pair of vertices.
  2080. If the graph is 2-edge-connected, a strongly connected orientation
  2081. can be found in linear time. If the given graph is not 2-connected,
  2082. the orientation returned will ensure that each 2-connected component
  2083. has a strongly connected orientation.
  2084. OUTPUT:
  2085. A digraph representing an orientation of the current graph.
  2086. .. NOTE::
  2087. - This method assumes the graph is connected.
  2088. - This algorithm works in O(m).
  2089. EXAMPLE:
  2090. For a 2-regular graph, a strong orientation gives to each vertex
  2091. an out-degree equal to 1::
  2092. sage: g = graphs.CycleGraph(5)
  2093. sage: g.strong_orientation().out_degree()
  2094. [1, 1, 1, 1, 1]
  2095. The Petersen Graph is 2-edge connected. It then has a strongly
  2096. connected orientation::
  2097. sage: g = graphs.PetersenGraph()
  2098. sage: o = g.strong_orientation()
  2099. sage: len(o.strongly_connected_components())
  2100. 1
  2101. The same goes for the CubeGraph in any dimension ::
  2102. sage: for i in range(2,5):
  2103. ... g = graphs.CubeGraph(i)
  2104. ... o = g.strong_orientation()
  2105. ... len(o.strongly_connected_components())
  2106. 1
  2107. 1
  2108. 1
  2109. """
  2110. from sage.graphs.all import DiGraph
  2111. d = DiGraph(multiedges=self.allows_multiple_edges())
  2112. id = {}
  2113. i = 0
  2114. # The algorithm works through a depth-first search. Any edge
  2115. # used in the depth-first search is oriented in the direction
  2116. # in which it has been used. All the other edges are oriented
  2117. # backward
  2118. v = self.vertex_iterator().next()
  2119. seen = {}
  2120. i=1
  2121. # Time at which the vertices have been discovered
  2122. seen[v] = i
  2123. # indicates the stack of edges to explore
  2124. next = self.edges_incident(v)
  2125. while next:
  2126. e = next.pop(-1)
  2127. # We assume e[0] to be a `seen` vertex
  2128. e = e if seen.get(e[0],False) != False else (e[1],e[0],e[2])
  2129. # If we discovered a new vertex
  2130. if seen.get(e[1],False) == False:
  2131. d.add_edge(e)
  2132. next.extend([ee for ee in self.edges_incident(e[1]) if (((e[0],e[1]) != (ee[0],ee[1])) and ((e[0],e[1]) != (ee[1],ee[0])))])
  2133. i+=1
  2134. seen[e[1]]=i
  2135. # Else, we orient the edges backward
  2136. else:
  2137. if seen[e[0]] < seen[e[1]]:
  2138. d.add_edge((e[1],e[0],e[2]))
  2139. else:
  2140. d.add_edge(e)
  2141. # Case of multiple edges. If another edge has already been inserted, we add the new one
  2142. # in the opposite direction.
  2143. tmp = None
  2144. for e in self.multiple_edges():
  2145. if tmp == (e[0],e[1]):
  2146. if d.has_edge(e[0].e[1]):
  2147. d.add_edge(e[1],e[0],e[2])
  2148. else:
  2149. d.add_edge(e)
  2150. tmp = (e[0],e[1])
  2151. return d
  2152. def minimum_outdegree_orientation(self, use_edge_labels=False, solver=None, verbose=0):
  2153. r"""
  2154. Returns an orientation of ``self`` with the smallest possible maximum
  2155. outdegree.
  2156. Given a Graph `G`, is is polynomial to compute an orientation
  2157. `D` of the edges of `G` such that the maximum out-degree in
  2158. `D` is minimized. This problem, though, is NP-complete in the
  2159. weighted case [AMOZ06]_.
  2160. INPUT:
  2161. - ``use_edge_labels`` -- boolean (default: ``False``)
  2162. - When set to ``True``, uses edge labels as weights to
  2163. compute the orientation and assumes a weight of `1`
  2164. when there is no value available for a given edge.
  2165. - When set to ``False`` (default), gives a weight of 1
  2166. to all the edges.
  2167. - ``solver`` -- (default: ``None``) Specify a Linear Program (LP)
  2168. solver to be used. If set to ``None``, the default one is used. For
  2169. more information on LP solvers and which default solver is used, see
  2170. the method
  2171. :meth:`solve <sage.numerical.mip.MixedIntegerLinearProgram.solve>`
  2172. of the class
  2173. :class:`MixedIntegerLinearProgram <sage.numerical.mip.MixedIntegerLinearProgram>`.
  2174. - ``verbose`` -- integer (default: ``0``). Sets the level of
  2175. verbosity. Set to 0 by default, which means quiet.
  2176. EXAMPLE:
  2177. Given a complete bipartite graph `K_{n,m}`, the maximum out-degree
  2178. of an optimal orientation is `\left\lceil \frac {nm} {n+m}\right\rceil`::
  2179. sage: g = graphs.CompleteBipartiteGraph(3,4)
  2180. sage: o = g.minimum_outdegree_orientation()
  2181. sage: max(o.out_degree()) == ceil((4*3)/(3+4))
  2182. True
  2183. REFERENCES:
  2184. .. [AMOZ06] Asahiro, Y. and Miyano, E. and Ono, H. and Zenmyo, K.
  2185. Graph orientation algorithms to minimize the maximum outdegree
  2186. Proceedings of the 12th Computing: The Australasian Theory Symposium
  2187. Volume 51, page 20
  2188. Australian Computer Society, Inc. 2006
  2189. """
  2190. if self.is_directed():
  2191. raise ValueError("Cannot compute an orientation of a DiGraph. "+\
  2192. "Please convert it to a Graph if you really mean it.")
  2193. if use_edge_labels:
  2194. from sage.rings.real_mpfr import RR
  2195. weight = lambda u,v : self.edge_label(u,v) if self.edge_label(u,v) in RR else 1
  2196. else:
  2197. weight = lambda u,v : 1
  2198. from sage.numerical.mip import MixedIntegerLinearProgram
  2199. p = MixedIntegerLinearProgram(maximization=False, solver=solver)
  2200. # The orientation of an edge is boolean
  2201. # and indicates whether the edge uv
  2202. # with u<v goes from u to v ( equal to 0 )
  2203. # or from v to u ( equal to 1)
  2204. orientation = p.new_variable(dim=2)
  2205. degree = p.new_variable()
  2206. # Whether an edge adjacent to a vertex u counts
  2207. # positively or negatively
  2208. outgoing = lambda u,v,variable : (1-variable) if u>v else variable
  2209. for u in self:
  2210. p.add_constraint(p.sum([weight(u,v)*outgoing(u,v,orientation[min(u,v)][max(u,v)]) for v in self.neighbors(u)])-degree['max'],max=0)
  2211. p.set_objective(degree['max'])
  2212. p.set_binary(orientation)
  2213. p.solve(log=verbose)
  2214. orientation = p.get_values(orientation)
  2215. # All the edges from self are doubled in O
  2216. # ( one in each direction )
  2217. from sage.graphs.digraph import DiGraph
  2218. O = DiGraph(self)
  2219. # Builds the list of edges that should be removed
  2220. edges=[]
  2221. for u,v in self.edge_iterator(labels=None):
  2222. # assumes u<v
  2223. if u>v:
  2224. u,v=v,u
  2225. if orientation[min(u,v)][max(u,v)] == 1:
  2226. edges.append((max(u,v),min(u,v)))
  2227. else:
  2228. edges.append((min(u,v),max(u,v)))
  2229. O.delete_edges(edges)
  2230. return O
  2231. def bounded_outdegree_orientation(self, bound):
  2232. r"""
  2233. Computes an orientation of ``self`` such that every vertex `v`
  2234. has out-degree less than `b(v)`
  2235. INPUT:
  2236. - ``bound`` -- Maximum bound on the out-degree. Can be of
  2237. three different types :
  2238. * An integer `k`. In this case, computes an orientation
  2239. whose maximum out-degree is less than `k`.
  2240. * A dictionary associating to each vertex its associated
  2241. maximum out-degree.
  2242. * A function associating to each vertex its associated
  2243. maximum out-degree.
  2244. OUTPUT:
  2245. A DiGraph representing the orientation if it exists. A
  2246. ``ValueError`` exception is raised otherwise.
  2247. ALGORITHM:
  2248. The problem is solved through a maximum flow :
  2249. Given a graph `G`, we create a ``DiGraph`` `D` defined on
  2250. `E(G)\cup V(G)\cup \{s,t\}`. We then link `s` to all of `V(G)`
  2251. (these edges having a capacity equal to the bound associated
  2252. to each element of `V(G)`), and all the elements of `E(G)` to
  2253. `t` . We then link each `v \in V(G)` to each of its incident
  2254. edges in `G`. A maximum integer flow of value `|E(G)|`
  2255. corresponds to an admissible orientation of `G`. Otherwise,
  2256. none exists.
  2257. EXAMPLES:
  2258. There is always an orientation of a graph `G` such that a
  2259. vertex `v` has out-degree at most `\lceil \frac {d(v)} 2
  2260. \rceil`::
  2261. sage: g = graphs.RandomGNP(40, .4)
  2262. sage: b = lambda v : ceil(g.degree(v)/2)
  2263. sage: D = g.bounded_outdegree_orientation(b)
  2264. sage: all( D.out_degree(v) <= b(v) for v in g )
  2265. True
  2266. Chvatal's graph, being 4-regular, can be oriented in such a
  2267. way that its maximum out-degree is 2::
  2268. sage: g = graphs.ChvatalGraph()
  2269. sage: D = g.bounded_outdegree_orientation(2)
  2270. sage: max(D.out_degree())
  2271. 2
  2272. For any graph `G`, it is possible to compute an orientation
  2273. such that the maximum out-degree is at most the maximum
  2274. average degree of `G` divided by 2. Anything less, though, is
  2275. impossible.
  2276. sage: g = graphs.RandomGNP(40, .4)
  2277. sage: mad = g.maximum_average_degree()
  2278. Hence this is possible ::
  2279. sage: d = g.bounded_outdegree_orientation(ceil(mad/2))
  2280. While this is not::
  2281. sage: try:
  2282. ... g.bounded_outdegree_orientation(ceil(mad/2-1))
  2283. ... print "Error"
  2284. ... except ValueError:
  2285. ... pass
  2286. TESTS:
  2287. As previously for random graphs, but more intensively::
  2288. sage: for i in xrange(30): # long time (up to 6s on sage.math, 2012)
  2289. ... g = graphs.RandomGNP(40, .4)
  2290. ... b = lambda v : ceil(g.degree(v)/2)
  2291. ... D = g.bounded_outdegree_orientation(b)
  2292. ... if not (
  2293. ... all( D.out_degree(v) <= b(v) for v in g ) or
  2294. ... D.size() != g.size()):
  2295. ... print "Something wrong happened"
  2296. """
  2297. from sage.graphs.all import DiGraph
  2298. n = self.order()
  2299. if n == 0:
  2300. return DiGraph()
  2301. vertices = self.vertices()
  2302. vertices_id = dict(map(lambda (x,y):(y,x), list(enumerate(vertices))))
  2303. b = {}
  2304. # Checking the input type. We make a dictionay out of it
  2305. if isinstance(bound, dict):
  2306. b = bound
  2307. else:
  2308. try:
  2309. b = dict(zip(vertices,map(bound, vertices)))
  2310. except TypeError:
  2311. b = dict(zip(vertices, [bound]*n))
  2312. d = DiGraph()
  2313. # Adding the edges (s,v) and ((u,v),t)
  2314. d.add_edges( ('s', vertices_id[v], b[v]) for v in vertices)
  2315. d.add_edges( ((vertices_id[u], vertices_id[v]), 't', 1)
  2316. for (u,v) in self.edges(labels=None) )
  2317. # each v is linked to its incident edges
  2318. for u,v in self.edges(labels = None):
  2319. u,v = vertices_id[u], vertices_id[v]
  2320. d.add_edge(u, (u,v), 1)
  2321. d.add_edge(v, (u,v), 1)
  2322. # Solving the maximum flow
  2323. value, flow = d.flow('s','t', value_only = False, integer = True, use_edge_labels = True)
  2324. if value != self.size():
  2325. raise ValueError("No orientation exists for the given bound")
  2326. D = DiGraph()
  2327. D.add_vertices(vertices)
  2328. # The flow graph may not contain all the vertices, if they are
  2329. # not part of the flow...
  2330. for u in [x for x in range(n) if x in flow]:
  2331. for (uu,vv) in flow.neighbors_out(u):
  2332. v = vv if vv != u else uu
  2333. D.add_edge(vertices[u], vertices[v])
  2334. # I do not like when a method destroys the embedding ;-)
  2335. D.set_pos(self.get_pos())
  2336. return D
  2337. ### Coloring
  2338. def bipartite_color(self):
  2339. """
  2340. Returns a dictionary with vertices as the keys and the color class
  2341. as the values. Fails with an error if the graph is not bipartite.
  2342. EXAMPLES::
  2343. sage: graphs.CycleGraph(4).bipartite_color()
  2344. {0: 1, 1: 0, 2: 1, 3: 0}
  2345. sage: graphs.CycleGraph(5).bipartite_color()
  2346. Traceback (most recent call last):
  2347. ...
  2348. RuntimeError: Graph is not bipartite.
  2349. """
  2350. isit, certificate = self.is_bipartite(certificate = True)
  2351. if isit:
  2352. return certificate
  2353. else:
  2354. raise RuntimeError("Graph is not bipartite.")
  2355. def bipartite_sets(self):
  2356. """
  2357. Returns `(X,Y)` where `X` and `Y` are the nodes in each bipartite set of
  2358. graph `G`. Fails with an error if graph is not bipartite.
  2359. EXAMPLES::
  2360. sage: graphs.CycleGraph(4).bipartite_sets()
  2361. (set([0, 2]), set([1, 3]))
  2362. sage: graphs.CycleGraph(5).bipartite_sets()
  2363. Traceback (most recent call last):
  2364. ...
  2365. RuntimeError: Graph is not bipartite.
  2366. """
  2367. color = self.bipartite_color()
  2368. left = set([])
  2369. right = set([])
  2370. for u,s in color.iteritems():
  2371. if s:
  2372. left.add(u)
  2373. else:
  2374. right.add(u)
  2375. return left, right
  2376. def chromatic_number(self, algorithm="DLX", verbose = 0):
  2377. r"""
  2378. Returns the minimal number of colors needed to color the vertices
  2379. of the graph `G`.
  2380. INPUT:
  2381. - ``algorithm`` -- Select an algorithm from the following supported
  2382. algorithms:
  2383. - If ``algorithm="DLX"`` (default), the chromatic number is
  2384. computed using the dancing link algorithm. It is
  2385. inefficient speedwise to compute the chromatic number through
  2386. the dancing link algorithm because this algorithm computes
  2387. *all* the possible colorings to check that one exists.
  2388. - If ``algorithm="CP"``, the chromatic number is computed
  2389. using the coefficients of the chromatic polynomial. Again, this
  2390. method is inefficient in terms of speed and it only useful for
  2391. small graphs.
  2392. - If ``algorithm="MILP"``, the chromatic number is computed using a
  2393. mixed integer linear program. The performance of this implementation
  2394. is affected by whether optional MILP solvers have been installed
  2395. (see the :mod:`MILP module <sage.numerical.mip>`, or Sage's tutorial
  2396. on Linear Programming).
  2397. - ``verbose`` -- integer (default: ``0``). Sets the level of verbosity
  2398. for the MILP algorithm. Its default value is 0, which means *quiet*.
  2399. .. SEEALSO::
  2400. For more functions related to graph coloring, see the
  2401. module :mod:`sage.graphs.graph_coloring`.
  2402. EXAMPLES::
  2403. sage: G = Graph({0: [1, 2, 3], 1: [2]})
  2404. sage: G.chromatic_number(algorithm="DLX")
  2405. 3
  2406. sage: G.chromatic_number(algorithm="MILP")
  2407. 3
  2408. sage: G.chromatic_number(algorithm="CP")
  2409. 3
  2410. TESTS::
  2411. sage: G = Graph({0: [1, 2, 3], 1: [2]})
  2412. sage: G.chromatic_number(algorithm="foo")
  2413. Traceback (most recent call last):
  2414. ...
  2415. ValueError: The 'algorithm' keyword must be set to either 'DLX', 'MILP' or 'CP'.
  2416. """
  2417. # default built-in algorithm; bad performance
  2418. if algorithm == "DLX":
  2419. from sage.graphs.graph_coloring import chromatic_number
  2420. return chromatic_number(self)
  2421. # Algorithm with good performance, but requires an optional
  2422. # package: choose any of GLPK or CBC.
  2423. elif algorithm == "MILP":
  2424. from sage.graphs.graph_coloring import vertex_coloring
  2425. return vertex_coloring(self, value_only=True, verbose = verbose)
  2426. # another algorithm with bad performance; only good for small graphs
  2427. elif algorithm == "CP":
  2428. f = self.chromatic_polynomial()
  2429. i = 0
  2430. while f(i) == 0:
  2431. i += 1
  2432. return i
  2433. else:
  2434. raise ValueError("The 'algorithm' keyword must be set to either 'DLX', 'MILP' or 'CP'.")
  2435. def coloring(self, algorithm="DLX", hex_colors=False, verbose = 0):
  2436. r"""
  2437. Returns the first (optimal) proper vertex-coloring found.
  2438. INPUT:
  2439. - ``algorithm`` -- Select an algorithm from the following supported
  2440. algorithms:
  2441. - If ``algorithm="DLX"`` (default), the coloring is computed using the
  2442. dancing link algorithm.
  2443. - If ``algorithm="MILP"``, the coloring is computed using a mixed
  2444. integer linear program. The performance of this implementation is
  2445. affected by whether optional MILP solvers have been installed (see
  2446. the :mod:`MILP module <sage.numerical.mip>`).
  2447. - ``hex_colors`` -- (default: ``False``) if ``True``, return a
  2448. dictionary which can easily be used for plotting.
  2449. - ``verbose`` -- integer (default: ``0``). Sets the level of verbosity
  2450. for the MILP algorithm. Its default value is 0, which means *quiet*.
  2451. .. SEEALSO::
  2452. For more functions related to graph coloring, see the
  2453. module :mod:`sage.graphs.graph_coloring`.
  2454. EXAMPLES::
  2455. sage: G = Graph("Fooba")
  2456. sage: P = G.coloring(algorithm="MILP"); P
  2457. [[2, 1, 3], [0, 6, 5], [4]]
  2458. sage: P = G.coloring(algorithm="DLX"); P
  2459. [[1, 2, 3], [0, 5, 6], [4]]
  2460. sage: G.plot(partition=P)
  2461. sage: H = G.coloring(hex_colors=True, algorithm="MILP")
  2462. sage: for c in sorted(H.keys()):
  2463. ... print c, H[c]
  2464. #0000ff [4]
  2465. #00ff00 [0, 6, 5]
  2466. #ff0000 [2, 1, 3]
  2467. sage: H = G.coloring(hex_colors=True, algorithm="DLX")
  2468. sage: for c in sorted(H.keys()):
  2469. ... print c, H[c]
  2470. #0000ff [4]
  2471. #00ff00 [1, 2, 3]
  2472. #ff0000 [0, 5, 6]
  2473. sage: G.plot(vertex_colors=H)
  2474. TESTS::
  2475. sage: G.coloring(algorithm="foo")
  2476. Traceback (most recent call last):
  2477. ...
  2478. ValueError: The 'algorithm' keyword must be set to either 'DLX' or 'MILP'.
  2479. """
  2480. if algorithm == "MILP":
  2481. from sage.graphs.graph_coloring import vertex_coloring
  2482. return vertex_coloring(self, hex_colors=hex_colors, verbose = verbose)
  2483. elif algorithm == "DLX":
  2484. from sage.graphs.graph_coloring import first_coloring
  2485. return first_coloring(self, hex_colors=hex_colors)
  2486. else:
  2487. raise ValueError("The 'algorithm' keyword must be set to either 'DLX' or 'MILP'.")
  2488. def matching(self, value_only=False, algorithm="Edmonds", use_edge_labels=True, solver=None, verbose=0):
  2489. r"""
  2490. Returns a maximum weighted matching of the graph
  2491. represented by the list of its edges. For more information, see the
  2492. `Wikipedia article on matchings
  2493. <http://en.wikipedia.org/wiki/Matching_%28graph_theory%29>`_.
  2494. Given a graph `G` such that each edge `e` has a weight `w_e`,
  2495. a maximum matching is a subset `S` of the edges of `G` of
  2496. maximum weight such that no two edges of `S` are incident
  2497. with each other.
  2498. As an optimization problem, it can be expressed as:
  2499. .. math::
  2500. \mbox{Maximize : }&\sum_{e\in G.edges()} w_e b_e\\
  2501. \mbox{Such that : }&\forall v \in G, \sum_{(u,v)\in G.edges()} b_{(u,v)}\leq 1\\
  2502. &\forall x\in G, b_x\mbox{ is a binary variable}
  2503. INPUT:
  2504. - ``value_only`` -- boolean (default: ``False``). When set to
  2505. ``True``, only the cardinal (or the weight) of the matching is
  2506. returned.
  2507. - ``algorithm`` -- string (default: ``"Edmonds"``)
  2508. - ``"Edmonds"`` selects Edmonds' algorithm as implemented in NetworkX
  2509. - ``"LP"`` uses a Linear Program formulation of the matching problem
  2510. - ``use_edge_labels`` -- boolean (default: ``False``)
  2511. - When set to ``True``, computes a weighted matching where each edge
  2512. is weighted by its label. (If an edge has no label, `1` is assumed.)
  2513. - When set to ``False``, each edge has weight `1`.
  2514. - ``solver`` -- (default: ``None``) Specify a Linear Program (LP)
  2515. solver to be used. If set to ``None``, the default one is used. For
  2516. more information on LP solvers and which default solver is used, see
  2517. the method
  2518. :meth:`solve <sage.numerical.mip.MixedIntegerLinearProgram.solve>`
  2519. of the class
  2520. :class:`MixedIntegerLinearProgram <sage.numerical.mip.MixedIntegerLinearProgram>`.
  2521. - ``verbose`` -- integer (default: ``0``). Sets the level of
  2522. verbosity. Set to 0 by default, which means quiet.
  2523. Only useful when ``algorithm == "LP"``.
  2524. ALGORITHM:
  2525. The problem is solved using Edmond's algorithm implemented in
  2526. NetworkX, or using Linear Programming depending on the value of
  2527. ``algorithm``.
  2528. EXAMPLES:
  2529. Maximum matching in a Pappus Graph::
  2530. sage: g = graphs.PappusGraph()
  2531. sage: g.matching(value_only=True)
  2532. 9.0
  2533. Same test with the Linear Program formulation::
  2534. sage: g = graphs.PappusGraph()
  2535. sage: g.matching(algorithm="LP", value_only=True)
  2536. 9.0
  2537. TESTS:
  2538. If ``algorithm`` is set to anything different from ``"Edmonds"`` or
  2539. ``"LP"``, an exception is raised::
  2540. sage: g = graphs.PappusGraph()
  2541. sage: g.matching(algorithm="somethingdifferent")
  2542. Traceback (most recent call last):
  2543. ...
  2544. ValueError: algorithm must be set to either "Edmonds" or "LP"
  2545. """
  2546. from sage.rings.real_mpfr import RR
  2547. weight = lambda x: x if x in RR else 1
  2548. if algorithm == "Edmonds":
  2549. import networkx
  2550. if use_edge_labels:
  2551. g = networkx.Graph()
  2552. for u, v, l in self.edges():
  2553. g.add_edge(u, v, attr_dict={"weight": weight(l)})
  2554. else:
  2555. g = self.networkx_graph(copy=False)
  2556. d = networkx.max_weight_matching(g)
  2557. if value_only:
  2558. if use_edge_labels:
  2559. return sum([weight(self.edge_label(u, v))
  2560. for u, v in d.iteritems()]) * 0.5
  2561. else:
  2562. return Integer(len(d)/2)
  2563. else:
  2564. return [(u, v, self.edge_label(u, v))
  2565. for u, v in d.iteritems() if u < v]
  2566. elif algorithm == "LP":
  2567. from sage.numerical.mip import MixedIntegerLinearProgram
  2568. g = self
  2569. # returns the weight of an edge considering it may not be
  2570. # weighted ...
  2571. p = MixedIntegerLinearProgram(maximization=True, solver=solver)
  2572. b = p.new_variable(dim=2)
  2573. p.set_objective(
  2574. p.sum([weight(w) * b[min(u, v)][max(u, v)]
  2575. for u, v, w in g.edges()]))
  2576. # for any vertex v, there is at most one edge incident to v in
  2577. # the maximum matching
  2578. for v in g.vertex_iterator():
  2579. p.add_constraint(
  2580. p.sum([b[min(u, v)][max(u, v)]
  2581. for u in g.neighbors(v)]), max=1)
  2582. p.set_binary(b)
  2583. if value_only:
  2584. if use_edge_labels:
  2585. return p.solve(objective_only=True, log=verbose)
  2586. else:
  2587. return Integer(round(p.solve(objective_only=True, log=verbose)))
  2588. else:
  2589. p.solve(log=verbose)
  2590. b = p.get_values(b)
  2591. return [(u, v, w) for u, v, w in g.edges()
  2592. if b[min(u, v)][max(u, v)] == 1]
  2593. else:
  2594. raise ValueError('algorithm must be set to either "Edmonds" or "LP"')
  2595. def has_homomorphism_to(self, H, core = False, solver = None, verbose = 0):
  2596. r"""
  2597. Checks whether there is a homomorphism between two graphs.
  2598. A homomorphism from a graph `G` to a graph `H` is a function
  2599. `\phi:V(G)\mapsto V(H)` such that for any edge `uv \in E(G)` the pair
  2600. `\phi(u)\phi(v)` is an edge of `H`.
  2601. Saying that a graph can be `k`-colored is equivalent to saying that it
  2602. has a homomorphism to `K_k`, the complete graph on `k` elements.
  2603. For more information, see the `Wikipedia article on graph homomorphisms
  2604. <Graph_homomorphism>`_.
  2605. INPUT:
  2606. - ``H`` -- the graph to which ``self`` should be sent.
  2607. - ``core`` (boolean) -- whether to minimize the size of the mapping's
  2608. image (see note below). This is set to ``False`` by default.
  2609. - ``solver`` -- (default: ``None``) Specify a Linear Program (LP)
  2610. solver to be used. If set to ``None``, the default one is used. For
  2611. more information on LP solvers and which default solver is used, see
  2612. the method
  2613. :meth:`solve <sage.numerical.mip.MixedIntegerLinearProgram.solve>`
  2614. of the class
  2615. :class:`MixedIntegerLinearProgram <sage.numerical.mip.MixedIntegerLinearProgram>`.
  2616. - ``verbose`` -- integer (default: ``0``). Sets the level of
  2617. verbosity. Set to 0 by default, which means quiet.
  2618. .. NOTE::
  2619. One can compute the core of a graph (with respect to homomorphism)
  2620. with this method ::
  2621. sage: g = graphs.CycleGraph(10)
  2622. sage: mapping = g.has_homomorphism_to(g, core = True)
  2623. sage: print "The size of the core is",len(set(mapping.values()))
  2624. The size of the core is 2
  2625. OUTPUT:
  2626. This method returns ``False`` when the homomorphism does not exist, and
  2627. returns the homomorphism otherwise as a dictionnary associating a vertex
  2628. of `H` to a vertex of `G`.
  2629. EXAMPLE:
  2630. Is Petersen's graph 3-colorable::
  2631. sage: P = graphs.PetersenGraph()
  2632. sage: P.has_homomorphism_to(graphs.CompleteGraph(3)) is not False
  2633. True
  2634. An odd cycle admits a homomorphism to a smaller odd cycle, but not to an
  2635. even cycle::
  2636. sage: g = graphs.CycleGraph(9)
  2637. sage: g.has_homomorphism_to(graphs.CycleGraph(5)) is not False
  2638. True
  2639. sage: g.has_homomorphism_to(graphs.CycleGraph(7)) is not False
  2640. True
  2641. sage: g.has_homomorphism_to(graphs.CycleGraph(4)) is not False
  2642. False
  2643. """
  2644. from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException
  2645. p = MixedIntegerLinearProgram(solver=solver, maximization = False)
  2646. b = p.new_variable(binary = True)
  2647. # Each vertex has an image
  2648. for ug in self:
  2649. p.add_constraint(p.sum([b[ug,uh] for uh in H]) == 1)
  2650. nonedges = H.complement().edges(labels = False)
  2651. for ug,vg in self.edges(labels = False):
  2652. # Two adjacent vertices cannot be mapped to the same element
  2653. for uh in H:
  2654. p.add_constraint(b[ug,uh] + b[vg,uh] <= 1)
  2655. # Two adjacent vertices cannot be mapped to no adjacent vertices
  2656. for uh,vh in nonedges:
  2657. p.add_constraint(b[ug,uh] + b[vg,vh] <= 1)
  2658. p.add_constraint(b[ug,vh] + b[vg,uh] <= 1)
  2659. # Minimize the mapping's size
  2660. if core:
  2661. # the value of m is one if the corresponding vertex of h is used.
  2662. m = p.new_variable()
  2663. for uh in H:
  2664. for ug in self:
  2665. p.add_constraint(b[ug,uh] <= m[uh])
  2666. p.set_objective(p.sum([m[vh] for vh in H]))
  2667. try:
  2668. p.solve(log = verbose)
  2669. b = p.get_values(b)
  2670. mapping = dict(map(lambda y:y[0],filter(lambda x:x[1], b.items())))
  2671. return mapping
  2672. except MIPSolverException:
  2673. return False
  2674. def fractional_chromatic_index(self, verbose_constraints = 0, verbose = 0):
  2675. r"""
  2676. Computes the fractional chromatic index of ``self``
  2677. The fractional chromatic index is a relaxed version of edge-coloring. An
  2678. edge coloring of a graph being actually a covering of its edges into the
  2679. smallest possible number of matchings, the fractional chromatic index of
  2680. a graph `G` is the smallest real value `\chi_f(G)` such that there
  2681. exists a list of matchings `M_1, ..., M_k` of `G` and coefficients
  2682. `\alpha_1, ..., \alpha_k` with the property that each edge is covered by
  2683. the matchings in the following relaxed way
  2684. .. MATH::
  2685. \forall e \in E(G), \sum_{e \in M_i} \alpha_i \geq 1
  2686. For more information, see the `Wikipedia article on fractional coloring
  2687. <http://en.wikipedia.org/wiki/Fractional_coloring>`_.
  2688. ALGORITHM:
  2689. The fractional chromatic index is computed through Linear Programming
  2690. through its dual. The LP solved by sage is actually:
  2691. .. MATH::
  2692. \mbox{Maximize : }&\sum_{e\in E(G)} r_{e}\\
  2693. \mbox{Such that : }&\\
  2694. &\forall M\text{ matching }\subseteq G, \sum_{e\in M}r_{v}\leq 1\\
  2695. INPUT:
  2696. - ``verbose_constraints`` -- whether to display which constraints are
  2697. being generated.
  2698. - ``verbose`` -- level of verbosity required from the LP solver
  2699. .. NOTE::
  2700. This implementation can be improved by computing matchings through a
  2701. LP formulation, and not using the Python implementation of Edmonds'
  2702. algorithm (which requires to copy the graph, etc). It may be more
  2703. efficient to write the matching problem as a LP, as we would then
  2704. just have to update the weights on the edges between each call to
  2705. ``solve`` (and so avoiding the generation of all the constraints).
  2706. EXAMPLE:
  2707. The fractional chromatic index of a `C_5` is `5/2`::
  2708. sage: g = graphs.CycleGraph(5)
  2709. sage: g.fractional_chromatic_index()
  2710. 2.5
  2711. """
  2712. from sage.numerical.mip import MixedIntegerLinearProgram
  2713. g = self.copy()
  2714. p = MixedIntegerLinearProgram(constraint_generation = True)
  2715. # One variable per edge
  2716. r = p.new_variable(dim = 2)
  2717. R = lambda x,y : r[x][y] if x<y else r[y][x]
  2718. # We want to maximize the sum of weights on the edges
  2719. p.set_objective( p.sum( R(u,v) for u,v in g.edges(labels = False)))
  2720. # Each edge being by itself a matching, its weight can not be more than
  2721. # 1
  2722. for u,v in g.edges(labels = False):
  2723. p.add_constraint( R(u,v), max = 1)
  2724. obj = p.solve(log = verbose)
  2725. while True:
  2726. # Updating the value on the edges of g
  2727. for u,v in g.edges(labels = False):
  2728. g.set_edge_label(u,v,p.get_values(R(u,v)))
  2729. # Computing a matching of maximum weight...
  2730. matching = g.matching()
  2731. # If the maximum matching has weight at most 1, we are done !
  2732. if sum(map(lambda x:x[2],matching)) <= 1:
  2733. break
  2734. # Otherwise, we add a new constraint
  2735. if verbose_constraints:
  2736. print "Adding a constraint on matching : ",matching
  2737. p.add_constraint( p.sum( R(u,v) for u,v,_ in matching), max = 1)
  2738. # And solve again
  2739. obj = p.solve(log = verbose)
  2740. # Accomplished !
  2741. return obj
  2742. def maximum_average_degree(self, value_only=True, solver = None, verbose = 0):
  2743. r"""
  2744. Returns the Maximum Average Degree (MAD) of the current graph.
  2745. The Maximum Average Degree (MAD) of a graph is defined as
  2746. the average degree of its densest subgraph. More formally,
  2747. ``Mad(G) = \max_{H\subseteq G} Ad(H)``, where `Ad(G)` denotes
  2748. the average degree of `G`.
  2749. This can be computed in polynomial time.
  2750. INPUT:
  2751. - ``value_only`` (boolean) -- ``True`` by default
  2752. - If ``value_only=True``, only the numerical
  2753. value of the `MAD` is returned.
  2754. - Else, the subgraph of `G` realizing the `MAD`
  2755. is returned.
  2756. - ``solver`` -- (default: ``None``) Specify a Linear Program (LP)
  2757. solver to be used. If set to ``None``, the default one is used. For
  2758. more information on LP solvers and which default solver is used, see
  2759. the method
  2760. :meth:`solve <sage.numerical.mip.MixedIntegerLinearProgram.solve>`
  2761. of the class
  2762. :class:`MixedIntegerLinearProgram <sage.numerical.mip.MixedIntegerLinearProgram>`.
  2763. - ``verbose`` -- integer (default: ``0``). Sets the level of
  2764. verbosity. Set to 0 by default, which means quiet.
  2765. EXAMPLES:
  2766. In any graph, the `Mad` is always larger than the average
  2767. degree::
  2768. sage: g = graphs.RandomGNP(20,.3)
  2769. sage: mad_g = g.maximum_average_degree()
  2770. sage: g.average_degree() <= mad_g
  2771. True
  2772. Unlike the average degree, the `Mad` of the disjoint
  2773. union of two graphs is the maximum of the `Mad` of each
  2774. graphs::
  2775. sage: h = graphs.RandomGNP(20,.3)
  2776. sage: mad_h = h.maximum_average_degree()
  2777. sage: (g+h).maximum_average_degree() == max(mad_g, mad_h)
  2778. True
  2779. The subgraph of a regular graph realizing the maximum
  2780. average degree is always the whole graph ::
  2781. sage: g = graphs.CompleteGraph(5)
  2782. sage: mad_g = g.maximum_average_degree(value_only=False)
  2783. sage: g.is_isomorphic(mad_g)
  2784. True
  2785. This also works for complete bipartite graphs ::
  2786. sage: g = graphs.CompleteBipartiteGraph(3,4)
  2787. sage: mad_g = g.maximum_average_degree(value_only=False)
  2788. sage: g.is_isomorphic(mad_g)
  2789. True
  2790. """
  2791. g = self
  2792. from sage.numerical.mip import MixedIntegerLinearProgram
  2793. p = MixedIntegerLinearProgram(maximization=True, solver = solver)
  2794. d = p.new_variable()
  2795. one = p.new_variable()
  2796. # Reorders u and v so that uv and vu are not considered
  2797. # to be different edges
  2798. reorder = lambda u,v : (min(u,v),max(u,v))
  2799. for u,v in g.edge_iterator(labels=False):
  2800. p.add_constraint( one[ reorder(u,v) ] - 2*d[u] , max = 0 )
  2801. p.add_constraint( one[ reorder(u,v) ] - 2*d[v] , max = 0 )
  2802. p.add_constraint( p.sum([d[v] for v in g]), max = 1)
  2803. p.set_objective( p.sum([ one[reorder(u,v)] for u,v in g.edge_iterator(labels=False)]) )
  2804. obj = p.solve(log = verbose)
  2805. # Paying attention to numerical error :
  2806. # The zero values could be something like 0.000000000001
  2807. # so I can not write l > 0
  2808. # And the non-zero, though they should be equal to
  2809. # 1/(order of the optimal subgraph) may be a bit lower
  2810. # setting the minimum to 1/(10 * size of the whole graph )
  2811. # should be safe :-)
  2812. m = 1/(10 *Integer(g.order()))
  2813. g_mad = g.subgraph([v for v,l in p.get_values(d).iteritems() if l>m ])
  2814. if value_only:
  2815. return g_mad.average_degree()
  2816. else:
  2817. return g_mad
  2818. def independent_set_of_representatives(self, family, solver=None, verbose=0):
  2819. r"""
  2820. Returns an independent set of representatives.
  2821. Given a graph `G` and and a family `F=\{F_i:i\in [1,...,k]\}` of
  2822. subsets of ``g.vertices()``, an Independent Set of Reprersentatives
  2823. (ISR) is an assignation of a vertex `v_i\in F_i` to each set `F_i`
  2824. such that `v_i != v_j` if `i<j` (they are represdentatives) and the
  2825. set `\cup_{i}v_i` is an independent set in `G`.
  2826. It generalizes, for example, graph coloring and graph list coloring.
  2827. (See [AhaBerZiv07]_ for more information.)
  2828. INPUT:
  2829. - ``family`` -- A list of lists defining the family `F`
  2830. (actually, a Family of subsets of ``G.vertices()``).
  2831. - ``solver`` -- (default: ``None``) Specify a Linear Program (LP)
  2832. solver to be used. If set to ``None``, the default one is used. For
  2833. more information on LP solvers and which default solver is used, see
  2834. the method
  2835. :meth:`solve <sage.numerical.mip.MixedIntegerLinearProgram.solve>`
  2836. of the class
  2837. :class:`MixedIntegerLinearProgram <sage.numerical.mip.MixedIntegerLinearProgram>`.
  2838. - ``verbose`` -- integer (default: ``0``). Sets the level of
  2839. verbosity. Set to 0 by default, which means quiet.
  2840. OUTPUT:
  2841. - A list whose `i^{\mbox{th}}` element is the representativeof the
  2842. `i^{\mbox{th}}` element of the ``family`` list. If there is no ISR,
  2843. ``None`` is returned.
  2844. EXAMPLES:
  2845. For a bipartite graph missing one edge, the solution is as expected::
  2846. sage: g = graphs.CompleteBipartiteGraph(3,3)
  2847. sage: g.delete_edge(1,4)
  2848. sage: g.independent_set_of_representatives([[0,1,2],[3,4,5]])
  2849. [1, 4]
  2850. The Petersen Graph is 3-colorable, which can be expressed as an
  2851. independent set of representatives problem : take 3 disjoint copies
  2852. of the Petersen Graph, each one representing one color. Then take
  2853. as a partition of the set of vertices the family defined by the three
  2854. copies of each vertex. The ISR of such a family
  2855. defines a 3-coloring::
  2856. sage: g = 3 * graphs.PetersenGraph()
  2857. sage: n = g.order()/3
  2858. sage: f = [[i,i+n,i+2*n] for i in xrange(n)]
  2859. sage: isr = g.independent_set_of_representatives(f)
  2860. sage: c = [floor(i/n) for i in isr]
  2861. sage: color_classes = [[],[],[]]
  2862. sage: for v,i in enumerate(c):
  2863. ... color_classes[i].append(v)
  2864. sage: for classs in color_classes:
  2865. ... g.subgraph(classs).size() == 0
  2866. True
  2867. True
  2868. True
  2869. REFERENCE:
  2870. .. [AhaBerZiv07] R. Aharoni and E. Berger and R. Ziv
  2871. Independent systems of representatives in weighted graphs
  2872. Combinatorica vol 27, num 3, p253--267
  2873. 2007
  2874. """
  2875. from sage.numerical.mip import MixedIntegerLinearProgram
  2876. p=MixedIntegerLinearProgram(solver=solver)
  2877. # Boolean variable indicating whether the vertex
  2878. # is the representative of some set
  2879. vertex_taken=p.new_variable()
  2880. # Boolean variable in two dimension whose first
  2881. # element is a vertex and whose second element
  2882. # is one of the sets given as arguments.
  2883. # When true, indicated that the vertex is the representent
  2884. # of the corresponding set
  2885. classss=p.new_variable(dim=2)
  2886. # Associates to the vertices the classes
  2887. # to which they belong
  2888. lists=dict([(v,[]) for v in self.vertex_iterator()])
  2889. for i,f in enumerate(family):
  2890. [lists[v].append(i) for v in f]
  2891. # a classss has exactly one representant
  2892. p.add_constraint(p.sum([classss[v][i] for v in f]),max=1,min=1)
  2893. # A vertex represents at most one classss (vertex_taken is binary), and
  2894. # vertex_taken[v]==1 if v is the representative of some classss
  2895. [p.add_constraint(p.sum([classss[v][i] for i in lists[v]])-vertex_taken[v],max=0) for v in self.vertex_iterator()]
  2896. # Two adjacent vertices can not both be representants of a set
  2897. for (u,v) in self.edges(labels=None):
  2898. p.add_constraint(vertex_taken[u]+vertex_taken[v],max=1)
  2899. p.set_objective(None)
  2900. p.set_binary(vertex_taken)
  2901. p.set_binary(classss)
  2902. try:
  2903. p.solve(log=verbose)
  2904. except StandardError:
  2905. return None
  2906. classss=p.get_values(classss)
  2907. repr=[]
  2908. for i,f in enumerate(family):
  2909. for v in f:
  2910. if classss[v][i]==1:
  2911. repr.append(v)
  2912. break
  2913. return repr
  2914. def minor(self, H, solver=None, verbose=0):
  2915. r"""
  2916. Returns the vertices of a minor isomorphic to `H` in the current graph.
  2917. We say that a graph `G` has a `H`-minor (or that it has
  2918. a graph isomorphic to `H` as a minor), if for all `h\in H`,
  2919. there exist disjoint sets `S_h \subseteq V(G)` such that
  2920. once the vertices of each `S_h` have been merged to create
  2921. a new graph `G'`, this new graph contains `H` as a subgraph.
  2922. For more information, see the
  2923. `Wikipedia article on graph minor <http://en.wikipedia.org/wiki/Minor_%28graph_theory%29>`_.
  2924. INPUT:
  2925. - ``H`` -- The minor to find for in the current graph.
  2926. - ``solver`` -- (default: ``None``) Specify a Linear Program (LP)
  2927. solver to be used. If set to ``None``, the default one is used. For
  2928. more information on LP solvers and which default solver is used, see
  2929. the method
  2930. :meth:`solve <sage.numerical.mip.MixedIntegerLinearProgram.solve>`
  2931. of the class
  2932. :class:`MixedIntegerLinearProgram <sage.numerical.mip.MixedIntegerLinearProgram>`.
  2933. - ``verbose`` -- integer (default: ``0``). Sets the level of
  2934. verbosity. Set to 0 by default, which means quiet.
  2935. OUTPUT:
  2936. A dictionary associating to each vertex of `H` the set of vertices
  2937. in the current graph representing it.
  2938. ALGORITHM:
  2939. Mixed Integer Linear Programming
  2940. COMPLEXITY:
  2941. Theoretically, when `H` is fixed, testing for the existence of
  2942. a `H`-minor is polynomial. The known algorithms are highly
  2943. exponential in `H`, though.
  2944. .. NOTE::
  2945. This function can be expected to be *very* slow, especially
  2946. where the minor does not exist.
  2947. EXAMPLES:
  2948. Trying to find a minor isomorphic to `K_4` in
  2949. the `4\times 4` grid::
  2950. sage: g = graphs.GridGraph([4,4])
  2951. sage: h = graphs.CompleteGraph(4)
  2952. sage: L = g.minor(h)
  2953. sage: gg = g.subgraph(flatten(L.values(), max_level = 1))
  2954. sage: _ = [gg.merge_vertices(l) for l in L.values() if len(l)>1]
  2955. sage: gg.is_isomorphic(h)
  2956. True
  2957. We can also try to prove this way that the Petersen graph
  2958. is not planar, as it has a `K_5` minor::
  2959. sage: g = graphs.PetersenGraph()
  2960. sage: K5_minor = g.minor(graphs.CompleteGraph(5)) # long time
  2961. And even a `K_{3,3}` minor::
  2962. sage: K33_minor = g.minor(graphs.CompleteBipartiteGraph(3,3)) # long time
  2963. (It is much faster to use the linear-time test of
  2964. planarity in this situation, though.)
  2965. As there is no cycle in a tree, looking for a `K_3` minor is useless.
  2966. This function will raise an exception in this case::
  2967. sage: g = graphs.RandomGNP(20,.5)
  2968. sage: g = g.subgraph(edges = g.min_spanning_tree())
  2969. sage: g.is_tree()
  2970. True
  2971. sage: L = g.minor(graphs.CompleteGraph(3))
  2972. Traceback (most recent call last):
  2973. ...
  2974. ValueError: This graph has no minor isomorphic to H !
  2975. """
  2976. from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException
  2977. p = MixedIntegerLinearProgram(solver=solver)
  2978. # sorts an edge
  2979. S = lambda (x,y) : (x,y) if x<y else (y,x)
  2980. # rs = Representative set of a vertex
  2981. # for h in H, v in G is such that rs[h][v] == 1 if and only if v
  2982. # is a representant of h in self
  2983. rs = p.new_variable(dim=2)
  2984. for v in self:
  2985. p.add_constraint(p.sum([rs[h][v] for h in H]), max = 1)
  2986. # We ensure that the set of representatives of a
  2987. # vertex h contains a tree, and thus is connected
  2988. # edges represents the edges of the tree
  2989. edges = p.new_variable(dim = 2)
  2990. # there can be a edge for h between two vertices
  2991. # only if those vertices represent h
  2992. for u,v in self.edges(labels=None):
  2993. for h in H:
  2994. p.add_constraint(edges[h][S((u,v))] - rs[h][u], max = 0 )
  2995. p.add_constraint(edges[h][S((u,v))] - rs[h][v], max = 0 )
  2996. # The number of edges of the tree in h is exactly the cardinal
  2997. # of its representative set minus 1
  2998. for h in H:
  2999. p.add_constraint(p.sum([edges[h][S(e)] for e in self.edges(labels=None)])-p.sum([rs[h][v] for v in self]), min=-1, max=-1)
  3000. # a tree has no cycle
  3001. epsilon = 1/(5*Integer(self.order()))
  3002. r_edges = p.new_variable(dim=2)
  3003. for h in H:
  3004. for u,v in self.edges(labels=None):
  3005. p.add_constraint(r_edges[h][(u,v)] + r_edges[h][(v,u)] - edges[h][S((u,v))], min = 0)
  3006. for v in self:
  3007. p.add_constraint(p.sum([r_edges[h][(u,v)] for u in self.neighbors(v)]), max = 1-epsilon)
  3008. # Once the representative sets are described, we must ensure
  3009. # there are arcs corresponding to those of H between them
  3010. h_edges = p.new_variable(dim=2)
  3011. for h1, h2 in H.edges(labels=None):
  3012. for v1, v2 in self.edges(labels=None):
  3013. p.add_constraint(h_edges[(h1,h2)][S((v1,v2))] - rs[h2][v2], max = 0)
  3014. p.add_constraint(h_edges[(h1,h2)][S((v1,v2))] - rs[h1][v1], max = 0)
  3015. p.add_constraint(h_edges[(h2,h1)][S((v1,v2))] - rs[h1][v2], max = 0)
  3016. p.add_constraint(h_edges[(h2,h1)][S((v1,v2))] - rs[h2][v1], max = 0)
  3017. p.add_constraint(p.sum([h_edges[(h1,h2)][S(e)] + h_edges[(h2,h1)][S(e)] for e in self.edges(labels=None) ]), min = 1)
  3018. p.set_binary(rs)
  3019. p.set_binary(edges)
  3020. p.set_objective(None)
  3021. try:
  3022. p.solve(log=verbose)
  3023. except MIPSolverException:
  3024. raise ValueError("This graph has no minor isomorphic to H !")
  3025. rs = p.get_values(rs)
  3026. rs_dict = {}
  3027. for h in H:
  3028. rs_dict[h] = [v for v in self if rs[h][v]==1]
  3029. return rs_dict
  3030. ### Convexity
  3031. def convexity_properties(self):
  3032. r"""
  3033. Returns a ``ConvexityProperties`` objet corresponding to ``self``.
  3034. This object contains the methods related to convexity in graphs (convex
  3035. hull, hull number) and caches useful information so that it becomes
  3036. comparatively cheaper to compute the convex hull of many different sets
  3037. of the same graph.
  3038. .. SEEALSO::
  3039. In order to know what can be done through this object, please refer
  3040. to module :mod:`sage.graphs.convexity_properties`.
  3041. .. NOTE::
  3042. If you want to compute many convex hulls, keep this object in memory
  3043. ! When it is created, it builds a table of useful information to
  3044. compute convex hulls. As a result ::
  3045. sage: g = graphs.PetersenGraph()
  3046. sage: g.convexity_properties().hull([1, 3])
  3047. [1, 2, 3]
  3048. sage: g.convexity_properties().hull([3, 7])
  3049. [2, 3, 7]
  3050. Is a terrible waste of computations, while ::
  3051. sage: g = graphs.PetersenGraph()
  3052. sage: CP = g.convexity_properties()
  3053. sage: CP.hull([1, 3])
  3054. [1, 2, 3]
  3055. sage: CP.hull([3, 7])
  3056. [2, 3, 7]
  3057. Makes perfect sense.
  3058. """
  3059. from sage.graphs.convexity_properties import ConvexityProperties
  3060. return ConvexityProperties(self)
  3061. ### Centrality
  3062. def centrality_betweenness(self, k=None, normalized=True, weight=None,
  3063. endpoints=False, seed=None):
  3064. r"""
  3065. Returns the betweenness centrality (fraction of number of
  3066. shortest paths that go through each vertex) as a dictionary
  3067. keyed by vertices. The betweenness is normalized by default to
  3068. be in range (0,1). This wraps NetworkX's implementation of the
  3069. algorithm described in [Brandes2003]_.
  3070. Measures of the centrality of a vertex within a graph determine
  3071. the relative importance of that vertex to its graph. Vertices
  3072. that occur on more shortest paths between other vertices have
  3073. higher betweenness than vertices that occur on less.
  3074. INPUT:
  3075. - ``normalized`` - boolean (default True) - if set to False,
  3076. result is not normalized.
  3077. - ``k`` - integer or None (default None) - if set to an integer,
  3078. use ``k`` node samples to estimate betweenness. Higher values
  3079. give better approximations.
  3080. - ``weight`` - None or string. If set to a string, use that
  3081. attribute of the nodes as weight. ``weight = True`` is
  3082. equivalent to ``weight = "weight"``
  3083. - ``endpoints`` - Boolean. If set to True it includes the
  3084. endpoints in the shortest paths count
  3085. REFERENCE:
  3086. .. [Brandes2003] Ulrik Brandes. (2003). Faster Evaluation of
  3087. Shortest-Path Based Centrality Indices. [Online] Available:
  3088. http://citeseer.nj.nec.com/brandes00faster.html
  3089. EXAMPLES::
  3090. sage: (graphs.ChvatalGraph()).centrality_betweenness()
  3091. {0: 0.06969696969696969, 1: 0.06969696969696969,
  3092. 2: 0.0606060606060606, 3: 0.0606060606060606,
  3093. 4: 0.06969696969696969, 5: 0.06969696969696969,
  3094. 6: 0.0606060606060606, 7: 0.0606060606060606,
  3095. 8: 0.0606060606060606, 9: 0.0606060606060606,
  3096. 10: 0.0606060606060606, 11: 0.0606060606060606}
  3097. sage: (graphs.ChvatalGraph()).centrality_betweenness(
  3098. ... normalized=False)
  3099. {0: 3.833333333333333, 1: 3.833333333333333, 2: 3.333333333333333,
  3100. 3: 3.333333333333333, 4: 3.833333333333333, 5: 3.833333333333333,
  3101. 6: 3.333333333333333, 7: 3.333333333333333, 8: 3.333333333333333,
  3102. 9: 3.333333333333333, 10: 3.333333333333333,
  3103. 11: 3.333333333333333}
  3104. sage: D = DiGraph({0:[1,2,3], 1:[2], 3:[0,1]})
  3105. sage: D.show(figsize=[2,2])
  3106. sage: D = D.to_undirected()
  3107. sage: D.show(figsize=[2,2])
  3108. sage: D.centrality_betweenness()
  3109. {0: 0.16666666666666666, 1: 0.16666666666666666, 2: 0.0, 3: 0.0}
  3110. """
  3111. import networkx
  3112. return networkx.betweenness_centrality(self.networkx_graph(copy=False),
  3113. k=k, normalized=normalized, weight=weight, endpoints=endpoints,
  3114. seed=seed)
  3115. def centrality_degree(self, v=None):
  3116. r"""
  3117. Returns the degree centrality (fraction of vertices connected to)
  3118. as a dictionary of values keyed by vertex. The degree centrality is
  3119. normalized to be in range (0,1).
  3120. Measures of the centrality of a vertex within a graph determine the
  3121. relative importance of that vertex to its graph. Degree centrality
  3122. measures the number of links incident upon a vertex.
  3123. INPUT:
  3124. - ``v`` - a vertex label (to find degree centrality of
  3125. only one vertex)
  3126. EXAMPLES::
  3127. sage: (graphs.ChvatalGraph()).centrality_degree()
  3128. {0: 0.36363636363636365, 1: 0.36363636363636365, 2: 0.36363636363636365, 3: 0.36363636363636365, 4: 0.36363636363636365, 5: 0.36363636363636365, 6: 0.36363636363636365, 7: 0.36363636363636365, 8: 0.36363636363636365, 9: 0.36363636363636365, 10: 0.36363636363636365, 11: 0.36363636363636365}
  3129. sage: D = DiGraph({0:[1,2,3], 1:[2], 3:[0,1]})
  3130. sage: D.show(figsize=[2,2])
  3131. sage: D = D.to_undirected()
  3132. sage: D.show(figsize=[2,2])
  3133. sage: D.centrality_degree()
  3134. {0: 1.0, 1: 1.0, 2: 0.6666666666666666, 3: 0.6666666666666666}
  3135. sage: D.centrality_degree(v=1)
  3136. 1.0
  3137. """
  3138. import networkx
  3139. if v==None:
  3140. return networkx.degree_centrality(self.networkx_graph(copy=False))
  3141. else:
  3142. return networkx.degree_centrality(self.networkx_graph(copy=False))[v]
  3143. def centrality_closeness(self, v=None):
  3144. r"""
  3145. Returns the closeness centrality (1/average distance to all
  3146. vertices) as a dictionary of values keyed by vertex. The degree
  3147. centrality is normalized to be in range (0,1).
  3148. Measures of the centrality of a vertex within a graph determine the
  3149. relative importance of that vertex to its graph. 'Closeness
  3150. centrality may be defined as the total graph-theoretic distance of
  3151. a given vertex from all other vertices... Closeness is an inverse
  3152. measure of centrality in that a larger value indicates a less
  3153. central actor while a smaller value indicates a more central
  3154. actor,' [Borgatti95]_.
  3155. INPUT:
  3156. - ``v`` - a vertex label (to find degree centrality of
  3157. only one vertex)
  3158. REFERENCE:
  3159. .. [Borgatti95] Stephen P Borgatti. (1995). Centrality and AIDS.
  3160. [Online] Available:
  3161. http://www.analytictech.com/networks/centaids.htm
  3162. EXAMPLES::
  3163. sage: (graphs.ChvatalGraph()).centrality_closeness()
  3164. {0: 0.61111111111111..., 1: 0.61111111111111..., 2: 0.61111111111111..., 3: 0.61111111111111..., 4: 0.61111111111111..., 5: 0.61111111111111..., 6: 0.61111111111111..., 7: 0.61111111111111..., 8: 0.61111111111111..., 9: 0.61111111111111..., 10: 0.61111111111111..., 11: 0.61111111111111...}
  3165. sage: D = DiGraph({0:[1,2,3], 1:[2], 3:[0,1]})
  3166. sage: D.show(figsize=[2,2])
  3167. sage: D = D.to_undirected()
  3168. sage: D.show(figsize=[2,2])
  3169. sage: D.centrality_closeness()
  3170. {0: 1.0, 1: 1.0, 2: 0.75, 3: 0.75}
  3171. sage: D.centrality_closeness(v=1)
  3172. 1.0
  3173. """
  3174. import networkx
  3175. return networkx.closeness_centrality(self.networkx_graph(copy=False), v)
  3176. ### Constructors
  3177. def to_directed(self, implementation='c_graph', sparse=None):
  3178. """
  3179. Returns a directed version of the graph. A single edge becomes two
  3180. edges, one in each direction.
  3181. EXAMPLES::
  3182. sage: graphs.PetersenGraph().to_directed()
  3183. Petersen graph: Digraph on 10 vertices
  3184. """
  3185. if sparse is None:
  3186. from sage.graphs.base.dense_graph import DenseGraphBackend
  3187. sparse = (not isinstance(self._backend, DenseGraphBackend))
  3188. from sage.graphs.all import DiGraph
  3189. D = DiGraph(name=self.name(), pos=self._pos, boundary=self._boundary,
  3190. multiedges=self.allows_multiple_edges(),
  3191. implementation=implementation, sparse=sparse)
  3192. D.name(self.name())
  3193. D.add_vertices(self.vertex_iterator())
  3194. for u,v,l in self.edge_iterator():
  3195. D.add_edge(u,v,l)
  3196. D.add_edge(v,u,l)
  3197. if hasattr(self, '_embedding'):
  3198. from copy import copy
  3199. D._embedding = copy(self._embedding)
  3200. D._weighted = self._weighted
  3201. return D
  3202. def to_undirected(self):
  3203. """
  3204. Since the graph is already undirected, simply returns a copy of
  3205. itself.
  3206. EXAMPLES::
  3207. sage: graphs.PetersenGraph().to_undirected()
  3208. Petersen graph: Graph on 10 vertices
  3209. """
  3210. from copy import copy
  3211. return copy(self)
  3212. ### Visualization
  3213. def write_to_eps(self, filename, **options):
  3214. r"""
  3215. Writes a plot of the graph to ``filename`` in ``eps`` format.
  3216. INPUT:
  3217. - ``filename`` -- a string
  3218. - ``**options`` -- same layout options as :meth:`.layout`
  3219. EXAMPLES::
  3220. sage: P = graphs.PetersenGraph()
  3221. sage: P.write_to_eps(tmp_filename(ext='.eps'))
  3222. It is relatively simple to include this file in a LaTeX
  3223. document. ``\usepackagegraphics`` must appear in the
  3224. preamble, and ``\includegraphics{filename.eps}`` will include
  3225. the file. To compile the document to ``pdf`` with ``pdflatex``
  3226. the file needs first to be converted to ``pdf``, for example
  3227. with ``ps2pdf filename.eps filename.pdf``.
  3228. """
  3229. from sage.graphs.print_graphs import print_graph_eps
  3230. pos = self.layout(**options)
  3231. [xmin, xmax, ymin, ymax] = self._layout_bounding_box(pos)
  3232. for v in pos:
  3233. pos[v] = (1.8*(pos[v][0] - xmin)/(xmax - xmin) - 0.9, 1.8*(pos[v][1] - ymin)/(ymax - ymin) - 0.9)
  3234. if filename[-4:] != '.eps':
  3235. filename += '.eps'
  3236. f = open(filename, 'w')
  3237. f.write( print_graph_eps(self.vertices(), self.edge_iterator(), pos) )
  3238. f.close()
  3239. def topological_minor(self, H, vertices = False, paths = False, solver=None, verbose=0):
  3240. r"""
  3241. Returns a topological `H`-minor from ``self`` if one exists.
  3242. We say that a graph `G` has a topological `H`-minor (or that
  3243. it has a graph isomorphic to `H` as a topological minor), if
  3244. `G` contains a subdivision of a graph isomorphic to `H` (=
  3245. obtained from `H` through arbitrary subdivision of its edges)
  3246. as a subgraph.
  3247. For more information, see the `Wikipedia article on graph minor
  3248. :wikipedia:`Minor_(graph_theory)`.
  3249. INPUT:
  3250. - ``H`` -- The topological minor to find in the current graph.
  3251. - ``solver`` -- (default: ``None``) Specify a Linear Program (LP)
  3252. solver to be used. If set to ``None``, the default one is used. For
  3253. more information on LP solvers and which default solver is used, see
  3254. the method
  3255. :meth:`solve <sage.numerical.mip.MixedIntegerLinearProgram.solve>`
  3256. of the class
  3257. :class:`MixedIntegerLinearProgram <sage.numerical.mip.MixedIntegerLinearProgram>`.
  3258. - ``verbose`` -- integer (default: ``0``). Sets the level of
  3259. verbosity. Set to 0 by default, which means quiet.
  3260. OUTPUT:
  3261. The topological `H`-minor found is returned as a subgraph `M`
  3262. of ``self``, such that the vertex `v` of `M` that represents a
  3263. vertex `h\in H` has ``h`` as a label (see
  3264. :meth:`get_vertex <sage.graphs.generic_graph.GenericGraph.get_vertex>`
  3265. and
  3266. :meth:`set_vertex <sage.graphs.generic_graph.GenericGraph.set_vertex>`),
  3267. and such that every edge of `M` has as a label the edge of `H`
  3268. it (partially) represents.
  3269. If no topological minor is found, this method returns
  3270. ``False``.
  3271. ALGORITHM:
  3272. Mixed Integer Linear Programming.
  3273. COMPLEXITY:
  3274. Theoretically, when `H` is fixed, testing for the existence of
  3275. a topological `H`-minor is polynomial. The known algorithms
  3276. are highly exponential in `H`, though.
  3277. .. NOTE::
  3278. This function can be expected to be *very* slow, especially where
  3279. the topological minor does not exist.
  3280. (CPLEX seems to be *much* more efficient than GLPK on this kind of
  3281. problem)
  3282. EXAMPLES:
  3283. Petersen's graph has a topological `K_4`-minor::
  3284. sage: g = graphs.PetersenGraph()
  3285. sage: g.topological_minor(graphs.CompleteGraph(4))
  3286. Subgraph of (Petersen graph): Graph on ...
  3287. And a topological `K_{3,3}`-minor::
  3288. sage: g.topological_minor(graphs.CompleteBipartiteGraph(3,3))
  3289. Subgraph of (Petersen graph): Graph on ...
  3290. And of course, a tree has no topological `C_3`-minor::
  3291. sage: g = graphs.RandomGNP(15,.3)
  3292. sage: g = g.subgraph(edges = g.min_spanning_tree())
  3293. sage: g.topological_minor(graphs.CycleGraph(3))
  3294. False
  3295. """
  3296. # Useful alias ...
  3297. G = self
  3298. from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException
  3299. p = MixedIntegerLinearProgram()
  3300. # This is an existence problem
  3301. p.set_objective(None)
  3302. #######################
  3303. # Vertex representant #
  3304. #######################
  3305. #
  3306. # v_repr[h][g] = 1 if vertex h from H is represented by vertex
  3307. # g from G, 0 otherwise
  3308. v_repr = p.new_variable(binary = True, dim = 2)
  3309. # Exactly one representant per vertex of H
  3310. for h in H:
  3311. p.add_constraint( p.sum( v_repr[h][g] for g in G), min = 1, max = 1)
  3312. # A vertex of G can only represent one vertex of H
  3313. for g in G:
  3314. p.add_constraint( p.sum( v_repr[h][g] for h in H), max = 1)
  3315. ###################
  3316. # Is representent #
  3317. ###################
  3318. #
  3319. # is_repr[v] = 1 if v represents some vertex of H
  3320. is_repr = p.new_variable(binary = True)
  3321. for g in G:
  3322. for h in H:
  3323. p.add_constraint( v_repr[h][g] - is_repr[g], max = 0)
  3324. ###################################
  3325. # paths between the representents #
  3326. ###################################
  3327. #
  3328. # For any edge (h1,h2) in H, we have a corresponding path in G
  3329. # between the representants of h1 and h2. Which means there is
  3330. # a flow of intensity 1 from one to the other.
  3331. # We are then writing a flow problem for each edge of H.
  3332. #
  3333. # The variable flow[(h1,h2)][(g1,g2)] indicates the amount of
  3334. # flow on the edge (g1,g2) representing the edge (h1,h2).
  3335. flow = p.new_variable(binary = True, dim = 2)
  3336. # This lambda function returns the balance of flow
  3337. # corresponding to commodity C at vertex v v
  3338. flow_in = lambda C, v : p.sum( flow[C][(v,u)] for u in G.neighbors(v) )
  3339. flow_out = lambda C, v : p.sum( flow[C][(u,v)] for u in G.neighbors(v) )
  3340. flow_balance = lambda C, v : flow_in(C,v) - flow_out(C,v)
  3341. for h1,h2 in H.edges(labels = False):
  3342. for v in G:
  3343. # The flow balance depends on whether the vertex v is
  3344. # a representant of h1 or h2 in G, or a reprensentant
  3345. # of none
  3346. p.add_constraint( flow_balance((h1,h2),v) == v_repr[h1][v] - v_repr[h2][v] )
  3347. #############################
  3348. # Internal vertex of a path #
  3349. #############################
  3350. #
  3351. # is_internal[C][g] = 1 if a vertex v from G is located on the
  3352. # path representing the edge (=commodity) C
  3353. is_internal = p.new_variable(dim = 2, binary = True)
  3354. # When is a vertex internal for a commodity ?
  3355. for C in H.edges(labels = False):
  3356. for g in G:
  3357. p.add_constraint( flow_in(C,g) + flow_out(C,g) - is_internal[C][g], max = 1)
  3358. ############################
  3359. # Two paths do not cross ! #
  3360. ############################
  3361. # A vertex can only be internal for one commodity, and zero if
  3362. # the vertex is a representent
  3363. for g in G:
  3364. p.add_constraint( p.sum( is_internal[C][g] for C in H.edges(labels = False))
  3365. + is_repr[g], max = 1 )
  3366. # (The following inequalities are not necessary, but they seem
  3367. # to be of help (the solvers find the answer quicker when they
  3368. # are added)
  3369. # The flow on one edge can go in only one direction. Besides,
  3370. # it can belong to at most one commodity and has a maximum
  3371. # intensity of 1.
  3372. for g1,g2 in G.edges(labels = None):
  3373. p.add_constraint( p.sum( flow[C][(g1,g2)] for C in H.edges(labels = False) )
  3374. + p.sum( flow[C][(g2,g1)] for C in H.edges(labels = False) ),
  3375. max = 1)
  3376. # Now we can solve the problem itself !
  3377. try:
  3378. p.solve(solver = solver, log = verbose)
  3379. except MIPSolverException:
  3380. return False
  3381. minor = G.subgraph()
  3382. is_repr = p.get_values(is_repr)
  3383. v_repr = p.get_values(v_repr)
  3384. flow = p.get_values(flow)
  3385. for u,v in minor.edges(labels = False):
  3386. used = False
  3387. for C in H.edges(labels = False):
  3388. if flow[C][(u,v)] + flow[C][(v,u)] > .5:
  3389. used = True
  3390. minor.set_edge_label(u,v,C)
  3391. break
  3392. if not used:
  3393. minor.delete_edge(u,v)
  3394. minor.delete_vertices( [v for v in minor
  3395. if minor.degree(v) == 0 ] )
  3396. for g in minor:
  3397. if is_repr[g] > .5:
  3398. for h in H:
  3399. if v_repr[h][v] > .5:
  3400. minor.set_vertex(g,h)
  3401. break
  3402. return minor
  3403. ### Cliques
  3404. def cliques_maximal(self):
  3405. """
  3406. Returns the list of all maximal cliques, with each clique represented
  3407. by a list of vertices. A clique is an induced complete subgraph, and a
  3408. maximal clique is one not contained in a larger one.
  3409. .. NOTE::
  3410. Currently only implemented for undirected graphs. Use to_undirected
  3411. to convert a digraph to an undirected graph.
  3412. ALGORITHM:
  3413. This function is based on NetworkX's implementation of the Bron and
  3414. Kerbosch Algorithm [BroKer1973]_.
  3415. REFERENCE:
  3416. .. [BroKer1973] Coen Bron and Joep Kerbosch. (1973). Algorithm 457:
  3417. Finding All Cliques of an Undirected Graph. Commun. ACM. v
  3418. 16. n 9. pages 575-577. ACM Press. [Online] Available:
  3419. http://www.ram.org/computing/rambin/rambin.html
  3420. EXAMPLES::
  3421. sage: graphs.ChvatalGraph().cliques_maximal()
  3422. [[0, 1], [0, 4], [0, 6], [0, 9], [2, 1], [2, 3], [2, 6], [2, 8], [3, 4], [3, 7], [3, 9], [5, 1], [5, 4], [5, 10], [5, 11], [7, 1], [7, 8], [7, 11], [8, 4], [8, 10], [10, 6], [10, 9], [11, 6], [11, 9]]
  3423. sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
  3424. sage: G.show(figsize=[2,2])
  3425. sage: G.cliques_maximal()
  3426. [[0, 1, 2], [0, 1, 3]]
  3427. sage: C=graphs.PetersenGraph()
  3428. sage: C.cliques_maximal()
  3429. [[0, 1], [0, 4], [0, 5], [2, 1], [2, 3], [2, 7], [3, 4], [3, 8], [6, 1], [6, 8], [6, 9], [7, 5], [7, 9], [8, 5], [9, 4]]
  3430. sage: C = Graph('DJ{')
  3431. sage: C.cliques_maximal()
  3432. [[4, 0], [4, 1, 2, 3]]
  3433. """
  3434. import networkx
  3435. return sorted(networkx.find_cliques(self.networkx_graph(copy=False)))
  3436. cliques = deprecated_function_alias(5739, cliques_maximal)
  3437. def clique_maximum(self, algorithm="Cliquer"):
  3438. """
  3439. Returns the vertex set of a maximal order complete subgraph.
  3440. INPUT:
  3441. - ``algorithm`` -- the algorithm to be used :
  3442. - If ``algorithm = "Cliquer"`` (default) - This wraps the C program
  3443. Cliquer [NisOst2003]_.
  3444. - If ``algorithm = "MILP"``, the problem is solved through a Mixed
  3445. Integer Linear Program.
  3446. (see :class:`MixedIntegerLinearProgram <sage.numerical.mip>`)
  3447. .. NOTE::
  3448. Currently only implemented for undirected graphs. Use to_undirected
  3449. to convert a digraph to an undirected graph.
  3450. ALGORITHM:
  3451. This function is based on Cliquer [NisOst2003]_.
  3452. EXAMPLES:
  3453. Using Cliquer (default)::
  3454. sage: C=graphs.PetersenGraph()
  3455. sage: C.clique_maximum()
  3456. [7, 9]
  3457. sage: C = Graph('DJ{')
  3458. sage: C.clique_maximum()
  3459. [1, 2, 3, 4]
  3460. Through a Linear Program::
  3461. sage: len(C.clique_maximum(algorithm = "MILP"))
  3462. 4
  3463. TESTS:
  3464. Wrong algorithm::
  3465. sage: C.clique_maximum(algorithm = "BFS")
  3466. Traceback (most recent call last):
  3467. ...
  3468. NotImplementedError: Only 'MILP' and 'Cliquer' are supported.
  3469. """
  3470. if algorithm=="Cliquer":
  3471. from sage.graphs.cliquer import max_clique
  3472. return max_clique(self)
  3473. elif algorithm == "MILP":
  3474. return self.complement().independent_set(algorithm = algorithm)
  3475. else:
  3476. raise NotImplementedError("Only 'MILP' and 'Cliquer' are supported.")
  3477. def clique_number(self, algorithm="Cliquer", cliques=None):
  3478. r"""
  3479. Returns the order of the largest clique of the graph (the clique
  3480. number).
  3481. .. NOTE::
  3482. Currently only implemented for undirected graphs. Use ``to_undirected``
  3483. to convert a digraph to an undirected graph.
  3484. INPUT:
  3485. - ``algorithm`` -- the algorithm to be used :
  3486. - If ``algorithm = "Cliquer"`` - This wraps the C program Cliquer [NisOst2003]_.
  3487. - If ``algorithm = "networkx"`` - This function is based on NetworkX's implementation
  3488. of the Bron and Kerbosch Algorithm [BroKer1973]_.
  3489. - If ``algorithm = "MILP"``, the problem is solved through a Mixed
  3490. Integer Linear Program.
  3491. (see :class:`MixedIntegerLinearProgram <sage.numerical.mip>`)
  3492. - ``cliques`` - an optional list of cliques that can be input if
  3493. already computed. Ignored unless ``algorithm=="networkx"``.
  3494. ALGORITHM:
  3495. This function is based on Cliquer [NisOst2003]_ and [BroKer1973]_.
  3496. EXAMPLES::
  3497. sage: C = Graph('DJ{')
  3498. sage: C.clique_number()
  3499. 4
  3500. sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
  3501. sage: G.show(figsize=[2,2])
  3502. sage: G.clique_number()
  3503. 3
  3504. TESTS::
  3505. sage: g = graphs.PetersenGraph()
  3506. sage: g.clique_number(algorithm="MILP")
  3507. 2
  3508. """
  3509. if algorithm=="Cliquer":
  3510. from sage.graphs.cliquer import clique_number
  3511. return clique_number(self)
  3512. elif algorithm=="networkx":
  3513. import networkx
  3514. return networkx.graph_clique_number(self.networkx_graph(copy=False),cliques)
  3515. elif algorithm == "MILP":
  3516. return len(self.complement().independent_set(algorithm = algorithm))
  3517. else:
  3518. raise NotImplementedError("Only 'networkx' 'MILP' and 'Cliquer' are supported.")
  3519. def cliques_number_of(self, vertices=None, cliques=None):
  3520. """
  3521. Returns a dictionary of the number of maximal cliques containing each
  3522. vertex, keyed by vertex. (Returns a single value if
  3523. only one input vertex).
  3524. .. NOTE::
  3525. Currently only implemented for undirected graphs. Use to_undirected
  3526. to convert a digraph to an undirected graph.
  3527. INPUT:
  3528. - ``vertices`` - the vertices to inspect (default is
  3529. entire graph)
  3530. - ``cliques`` - list of cliques (if already
  3531. computed)
  3532. EXAMPLES::
  3533. sage: C = Graph('DJ{')
  3534. sage: C.cliques_number_of()
  3535. {0: 1, 1: 1, 2: 1, 3: 1, 4: 2}
  3536. sage: E = C.cliques_maximal()
  3537. sage: E
  3538. [[4, 0], [4, 1, 2, 3]]
  3539. sage: C.cliques_number_of(cliques=E)
  3540. {0: 1, 1: 1, 2: 1, 3: 1, 4: 2}
  3541. sage: F = graphs.Grid2dGraph(2,3)
  3542. sage: X = F.cliques_number_of()
  3543. sage: for v in sorted(X.iterkeys()):
  3544. ... print v, X[v]
  3545. (0, 0) 2
  3546. (0, 1) 3
  3547. (0, 2) 2
  3548. (1, 0) 2
  3549. (1, 1) 3
  3550. (1, 2) 2
  3551. sage: F.cliques_number_of(vertices=[(0, 1), (1, 2)])
  3552. {(0, 1): 3, (1, 2): 2}
  3553. sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
  3554. sage: G.show(figsize=[2,2])
  3555. sage: G.cliques_number_of()
  3556. {0: 2, 1: 2, 2: 1, 3: 1}
  3557. """
  3558. import networkx
  3559. return networkx.number_of_cliques(self.networkx_graph(copy=False), vertices, cliques)
  3560. def cliques_get_max_clique_graph(self, name=''):
  3561. """
  3562. Returns a graph constructed with maximal cliques as vertices, and
  3563. edges between maximal cliques with common members in the original
  3564. graph.
  3565. .. NOTE::
  3566. Currently only implemented for undirected graphs. Use to_undirected
  3567. to convert a digraph to an undirected graph.
  3568. INPUT:
  3569. - ``name`` - The name of the new graph.
  3570. EXAMPLES::
  3571. sage: (graphs.ChvatalGraph()).cliques_get_max_clique_graph()
  3572. Graph on 24 vertices
  3573. sage: ((graphs.ChvatalGraph()).cliques_get_max_clique_graph()).show(figsize=[2,2], vertex_size=20, vertex_labels=False)
  3574. sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
  3575. sage: G.show(figsize=[2,2])
  3576. sage: G.cliques_get_max_clique_graph()
  3577. Graph on 2 vertices
  3578. sage: (G.cliques_get_max_clique_graph()).show(figsize=[2,2])
  3579. """
  3580. import networkx
  3581. return Graph(networkx.make_max_clique_graph(self.networkx_graph(copy=False), name=name, create_using=networkx.MultiGraph()))
  3582. def cliques_get_clique_bipartite(self, **kwds):
  3583. """
  3584. Returns a bipartite graph constructed such that maximal cliques are the
  3585. right vertices and the left vertices are retained from the given
  3586. graph. Right and left vertices are connected if the bottom vertex
  3587. belongs to the clique represented by a top vertex.
  3588. .. NOTE::
  3589. Currently only implemented for undirected graphs. Use to_undirected
  3590. to convert a digraph to an undirected graph.
  3591. EXAMPLES::
  3592. sage: (graphs.ChvatalGraph()).cliques_get_clique_bipartite()
  3593. Bipartite graph on 36 vertices
  3594. sage: ((graphs.ChvatalGraph()).cliques_get_clique_bipartite()).show(figsize=[2,2], vertex_size=20, vertex_labels=False)
  3595. sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
  3596. sage: G.show(figsize=[2,2])
  3597. sage: G.cliques_get_clique_bipartite()
  3598. Bipartite graph on 6 vertices
  3599. sage: (G.cliques_get_clique_bipartite()).show(figsize=[2,2])
  3600. """
  3601. from bipartite_graph import BipartiteGraph
  3602. import networkx
  3603. return BipartiteGraph(networkx.make_clique_bipartite(self.networkx_graph(copy=False), **kwds))
  3604. def independent_set(self, algorithm = "Cliquer", value_only = False, reduction_rules = True, solver = None, verbosity = 0):
  3605. r"""
  3606. Returns a maximum independent set.
  3607. An independent set of a graph is a set of pairwise non-adjacent
  3608. vertices. A maximum independent set is an independent set of maximum
  3609. cardinality. It induces an empty subgraph.
  3610. Equivalently, an independent set is defined as the complement of a
  3611. vertex cover.
  3612. INPUT:
  3613. - ``algorithm`` -- the algorithm to be used
  3614. * If ``algorithm = "Cliquer"`` (default), the problem is solved
  3615. using Cliquer [NisOst2003]_.
  3616. (see the :mod:`Cliquer modules <sage.graphs.cliquer>`)
  3617. * If ``algorithm = "MILP"``, the problem is solved through a Mixed
  3618. Integer Linear Program.
  3619. (see :class:`MixedIntegerLinearProgram <sage.numerical.mip>`)
  3620. - ``value_only`` -- boolean (default: ``False``). If set to ``True``,
  3621. only the size of a maximum independent set is returned. Otherwise,
  3622. a maximum independent set is returned as a list of vertices.
  3623. - ``reduction_rules`` -- (default: ``True``) Specify if the reductions
  3624. rules from kernelization must be applied as pre-processing or not.
  3625. See [ACFLSS04]_ for more details. Note that depending on the
  3626. instance, it might be faster to disable reduction rules.
  3627. - ``solver`` -- (default: ``None``) Specify a Linear Program (LP)
  3628. solver to be used. If set to ``None``, the default one is used. For
  3629. more information on LP solvers and which default solver is used, see
  3630. the method
  3631. :meth:`solve <sage.numerical.mip.MixedIntegerLinearProgram.solve>`
  3632. of the class
  3633. :class:`MixedIntegerLinearProgram <sage.numerical.mip.MixedIntegerLinearProgram>`.
  3634. - ``verbosity`` -- non-negative integer (default: ``0``). Set the level
  3635. of verbosity you want from the linear program solver. Since the
  3636. problem of computing an independent set is `NP`-complete, its solving
  3637. may take some time depending on the graph. A value of 0 means that
  3638. there will be no message printed by the solver. This option is only
  3639. useful if ``algorithm="MILP"``.
  3640. .. NOTE::
  3641. While Cliquer is usually (and by far) the most efficient of the two
  3642. implementations, the Mixed Integer Linear Program formulation
  3643. sometimes proves faster on very "symmetrical" graphs.
  3644. EXAMPLES:
  3645. Using Cliquer::
  3646. sage: C = graphs.PetersenGraph()
  3647. sage: C.independent_set()
  3648. [0, 3, 6, 7]
  3649. As a linear program::
  3650. sage: C = graphs.PetersenGraph()
  3651. sage: len(C.independent_set(algorithm = "MILP"))
  3652. 4
  3653. """
  3654. my_cover = self.vertex_cover(algorithm=algorithm, value_only=value_only, reduction_rules=reduction_rules, solver=solver, verbosity=verbosity)
  3655. if value_only:
  3656. return self.order() - my_cover
  3657. else:
  3658. return [u for u in self.vertices() if not u in my_cover]
  3659. def vertex_cover(self, algorithm = "Cliquer", value_only = False,
  3660. reduction_rules = True, solver = None, verbosity = 0):
  3661. r"""
  3662. Returns a minimum vertex cover of self represented by a set of vertices.
  3663. A minimum vertex cover of a graph is a set `S` of vertices such that
  3664. each edge is incident to at least one element of `S`, and such that `S`
  3665. is of minimum cardinality. For more information, see the
  3666. :wikipedia:`Wikipedia article on vertex cover <Vertex_cover>`.
  3667. Equivalently, a vertex cover is defined as the complement of an
  3668. independent set.
  3669. As an optimization problem, it can be expressed as follows:
  3670. .. MATH::
  3671. \mbox{Minimize : }&\sum_{v\in G} b_v\\
  3672. \mbox{Such that : }&\forall (u,v) \in G.edges(), b_u+b_v\geq 1\\
  3673. &\forall x\in G, b_x\mbox{ is a binary variable}
  3674. INPUT:
  3675. - ``algorithm`` -- string (default: ``"Cliquer"``). Indicating
  3676. which algorithm to use. It can be one of those two values.
  3677. - ``"Cliquer"`` will compute a minimum vertex cover
  3678. using the Cliquer package.
  3679. - ``"MILP"`` will compute a minimum vertex cover through a mixed
  3680. integer linear program.
  3681. - ``value_only`` -- boolean (default: ``False``). If set to ``True``,
  3682. only the size of a minimum vertex cover is returned. Otherwise,
  3683. a minimum vertex cover is returned as a list of vertices.
  3684. - ``reduction_rules`` -- (default: ``True``) Specify if the reductions
  3685. rules from kernelization must be applied as pre-processing or not.
  3686. See [ACFLSS04]_ for more details. Note that depending on the
  3687. instance, it might be faster to disable reduction rules.
  3688. - ``solver`` -- (default: ``None``) Specify a Linear Program (LP)
  3689. solver to be used. If set to ``None``, the default one is used. For
  3690. more information on LP solvers and which default solver is used, see
  3691. the method
  3692. :meth:`solve <sage.numerical.mip.MixedIntegerLinearProgram.solve>`
  3693. of the class
  3694. :class:`MixedIntegerLinearProgram <sage.numerical.mip.MixedIntegerLinearProgram>`.
  3695. - ``verbosity`` -- non-negative integer (default: ``0``). Set the level
  3696. of verbosity you want from the linear program solver. Since the
  3697. problem of computing a vertex cover is `NP`-complete, its solving may
  3698. take some time depending on the graph. A value of 0 means that there
  3699. will be no message printed by the solver. This option is only useful
  3700. if ``algorithm="MILP"``.
  3701. EXAMPLES:
  3702. On the Pappus graph::
  3703. sage: g = graphs.PappusGraph()
  3704. sage: g.vertex_cover(value_only=True)
  3705. 9
  3706. TESTS:
  3707. The two algorithms should return the same result::
  3708. sage: g = graphs.RandomGNP(10,.5)
  3709. sage: vc1 = g.vertex_cover(algorithm="MILP")
  3710. sage: vc2 = g.vertex_cover(algorithm="Cliquer")
  3711. sage: len(vc1) == len(vc2)
  3712. True
  3713. The cardinality of the vertex cover is unchanged when reduction rules are used. First for trees::
  3714. sage: for i in range(20):
  3715. ... g = graphs.RandomTree(20)
  3716. ... vc1_set = g.vertex_cover()
  3717. ... vc1 = len(vc1_set)
  3718. ... vc2 = g.vertex_cover(value_only = True, reduction_rules = False)
  3719. ... if vc1 != vc2:
  3720. ... print "Error :", vc1, vc2
  3721. ... print "With reduction rules :", vc1
  3722. ... print "Without reduction rules :", vc2
  3723. ... break
  3724. ... g.delete_vertices(vc1_set)
  3725. ... if g.size() != 0:
  3726. ... print "This thing is not a vertex cover !"
  3727. Then for random GNP graphs::
  3728. sage: for i in range(20):
  3729. ... g = graphs.RandomGNP(50,4/50)
  3730. ... vc1_set = g.vertex_cover()
  3731. ... vc1 = len(vc1_set)
  3732. ... vc2 = g.vertex_cover(value_only = True, reduction_rules = False)
  3733. ... if vc1 != vc2:
  3734. ... print "Error :", vc1, vc2
  3735. ... print "With reduction rules :", vc1
  3736. ... print "Without reduction rules :", vc2
  3737. ... break
  3738. ... g.delete_vertices(vc1_set)
  3739. ... if g.size() != 0:
  3740. ... print "This thing is not a vertex cover !"
  3741. Given a wrong algorithm::
  3742. sage: graphs.PetersenGraph().vertex_cover(algorithm = "guess")
  3743. Traceback (most recent call last):
  3744. ...
  3745. ValueError: The algorithm must be either "Cliquer" or "MILP".
  3746. REFERENCE:
  3747. .. [ACFLSS04] F. N. Abu-Khzam, R. L. Collins, M. R. Fellows, M. A.
  3748. Langston, W. H. Suters, and C. T. Symons: Kernelization Algorithm for
  3749. the Vertex Cover Problem: Theory and Experiments. *SIAM ALENEX/ANALCO*
  3750. 2004: 62-69.
  3751. """
  3752. g = self
  3753. ppset = []
  3754. folded_vertices = []
  3755. ###################
  3756. # Reduction rules #
  3757. ###################
  3758. if reduction_rules:
  3759. # We apply simple reduction rules allowing to identify vertices that
  3760. # belongs to an optimal vertex cover
  3761. # We first create manually a copy of the graph to prevent creating
  3762. # multi-edges when merging vertices, if edges have labels (e.g., weights).
  3763. g = self.copy()
  3764. degree_at_most_two = set([u for u,du in g.degree(labels = True).items() if du <= 2])
  3765. while degree_at_most_two:
  3766. u = degree_at_most_two.pop()
  3767. du = g.degree(u)
  3768. if du == 0:
  3769. # RULE 1: isolated vertices are not part of the cover. We
  3770. # simply remove them from the graph. The degree of such
  3771. # vertices may have been reduced to 0 while applying other
  3772. # reduction rules
  3773. g.delete_vertex(u)
  3774. elif du == 1:
  3775. # RULE 2: If a vertex u has degree 1, we select its neighbor
  3776. # v and remove both u and v from g.
  3777. v = g.neighbors(u)[0]
  3778. ppset.append(v)
  3779. g.delete_vertex(u)
  3780. for w in g.neighbors(v):
  3781. if g.degree(w) <= 3:
  3782. # The degree of w will be at most two after the
  3783. # deletion of v
  3784. degree_at_most_two.add(w)
  3785. g.delete_vertex(v)
  3786. degree_at_most_two.discard(v)
  3787. elif du == 2:
  3788. v,w = g.neighbors(u)
  3789. if g.has_edge(v,w):
  3790. # RULE 3: If the neighbors v and w of a degree 2 vertex
  3791. # u are incident, then we select both v and w and remove
  3792. # u, v, and w from g.
  3793. ppset.append(v)
  3794. ppset.append(w)
  3795. g.delete_vertex(u)
  3796. neigh = set(g.neighbors(v) + g.neighbors(w)).difference(set([v,w]))
  3797. g.delete_vertex(v)
  3798. g.delete_vertex(w)
  3799. for z in neigh:
  3800. if g.degree(z) <= 2:
  3801. degree_at_most_two.add(z)
  3802. else:
  3803. # RULE 4, folded vertices: If the neighbors v and w of a
  3804. # degree 2 vertex u are not incident, then we contract
  3805. # edges (u, v), (u,w). Then, if the solution contains u,
  3806. # we replace it with v and w. Otherwise, we let u in the
  3807. # solution.
  3808. neigh = set(g.neighbors(v) + g.neighbors(w)).difference(set([u,v,w]))
  3809. g.delete_vertex(v)
  3810. g.delete_vertex(w)
  3811. for z in neigh:
  3812. g.add_edge(u,z)
  3813. folded_vertices += [(u,v,w)]
  3814. if g.degree(u) <= 2:
  3815. degree_at_most_two.add(u)
  3816. degree_at_most_two.discard(v)
  3817. degree_at_most_two.discard(w)
  3818. # RULE 5:
  3819. # TODO: add extra reduction rules
  3820. ##################
  3821. # Main Algorithm #
  3822. ##################
  3823. if g.order() == 0:
  3824. # Reduction rules were sufficients to get the solution
  3825. size_cover_g = 0
  3826. cover_g = []
  3827. elif algorithm == "Cliquer":
  3828. from sage.graphs.cliquer import max_clique
  3829. independent = max_clique(g.complement())
  3830. if value_only:
  3831. size_cover_g = g.order() - len(independent)
  3832. else:
  3833. cover_g = [u for u in g.vertices() if not u in independent]
  3834. elif algorithm == "MILP":
  3835. from sage.numerical.mip import MixedIntegerLinearProgram
  3836. p = MixedIntegerLinearProgram(maximization=False, solver=solver)
  3837. b = p.new_variable()
  3838. # minimizes the number of vertices in the set
  3839. p.set_objective(p.sum([b[v] for v in g.vertices()]))
  3840. # an edge contains at least one vertex of the minimum vertex cover
  3841. for (u,v) in g.edges(labels=None):
  3842. p.add_constraint(b[u] + b[v], min=1)
  3843. p.set_binary(b)
  3844. if value_only:
  3845. size_cover_g = p.solve(objective_only=True, log=verbosity)
  3846. else:
  3847. p.solve(log=verbosity)
  3848. b = p.get_values(b)
  3849. cover_g = [v for v in g.vertices() if b[v] == 1]
  3850. else:
  3851. raise ValueError("The algorithm must be either \"Cliquer\" or \"MILP\".")
  3852. #########################
  3853. # Returning the results #
  3854. #########################
  3855. # We finally reconstruct the solution according the reduction rules
  3856. if value_only:
  3857. return len(ppset) + len(folded_vertices) + size_cover_g
  3858. else:
  3859. # RULES 2 and 3:
  3860. cover_g.extend(ppset)
  3861. # RULE 4:
  3862. folded_vertices.reverse()
  3863. for u,v,w in folded_vertices:
  3864. if u in cover_g:
  3865. cover_g.remove(u)
  3866. cover_g += [v,w]
  3867. else:
  3868. cover_g += [u]
  3869. cover_g.sort()
  3870. return cover_g
  3871. def cliques_vertex_clique_number(self, algorithm="cliquer", vertices=None,
  3872. cliques=None):
  3873. """
  3874. Returns a dictionary of sizes of the largest maximal cliques containing
  3875. each vertex, keyed by vertex. (Returns a single value if only one
  3876. input vertex).
  3877. .. NOTE::
  3878. Currently only implemented for undirected graphs. Use to_undirected
  3879. to convert a digraph to an undirected graph.
  3880. INPUT:
  3881. - ``algorithm`` - either ``cliquer`` or ``networkx``
  3882. - ``cliquer`` - This wraps the C program Cliquer [NisOst2003]_.
  3883. - ``networkx`` - This function is based on NetworkX's implementation
  3884. of the Bron and Kerbosch Algorithm [BroKer1973]_.
  3885. - ``vertices`` - the vertices to inspect (default is entire graph).
  3886. Ignored unless ``algorithm=='networkx'``.
  3887. - ``cliques`` - list of cliques (if already computed). Ignored unless
  3888. ``algorithm=='networkx'``.
  3889. EXAMPLES::
  3890. sage: C = Graph('DJ{')
  3891. sage: C.cliques_vertex_clique_number()
  3892. {0: 2, 1: 4, 2: 4, 3: 4, 4: 4}
  3893. sage: E = C.cliques_maximal()
  3894. sage: E
  3895. [[4, 0], [4, 1, 2, 3]]
  3896. sage: C.cliques_vertex_clique_number(cliques=E,algorithm="networkx")
  3897. {0: 2, 1: 4, 2: 4, 3: 4, 4: 4}
  3898. sage: F = graphs.Grid2dGraph(2,3)
  3899. sage: X = F.cliques_vertex_clique_number(algorithm="networkx")
  3900. sage: for v in sorted(X.iterkeys()):
  3901. ... print v, X[v]
  3902. (0, 0) 2
  3903. (0, 1) 2
  3904. (0, 2) 2
  3905. (1, 0) 2
  3906. (1, 1) 2
  3907. (1, 2) 2
  3908. sage: F.cliques_vertex_clique_number(vertices=[(0, 1), (1, 2)])
  3909. {(0, 1): 2, (1, 2): 2}
  3910. sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
  3911. sage: G.show(figsize=[2,2])
  3912. sage: G.cliques_vertex_clique_number()
  3913. {0: 3, 1: 3, 2: 3, 3: 3}
  3914. """
  3915. if algorithm=="cliquer":
  3916. from sage.graphs.cliquer import clique_number
  3917. if vertices==None:
  3918. vertices=self
  3919. value={}
  3920. for v in vertices:
  3921. value[v] = 1+clique_number(self.subgraph(self.neighbors(v)))
  3922. self.subgraph(self.neighbors(v)).plot()
  3923. return value
  3924. elif algorithm=="networkx":
  3925. import networkx
  3926. return networkx.node_clique_number(self.networkx_graph(copy=False),vertices, cliques)
  3927. else:
  3928. raise NotImplementedError("Only 'networkx' and 'cliquer' are supported.")
  3929. def cliques_containing_vertex(self, vertices=None, cliques=None):
  3930. """
  3931. Returns the cliques containing each vertex, represented as a dictionary
  3932. of lists of lists, keyed by vertex. (Returns a single list if only one
  3933. input vertex).
  3934. .. NOTE::
  3935. Currently only implemented for undirected graphs. Use to_undirected
  3936. to convert a digraph to an undirected graph.
  3937. INPUT:
  3938. - ``vertices`` - the vertices to inspect (default is
  3939. entire graph)
  3940. - ``cliques`` - list of cliques (if already
  3941. computed)
  3942. EXAMPLES::
  3943. sage: C = Graph('DJ{')
  3944. sage: C.cliques_containing_vertex()
  3945. {0: [[4, 0]], 1: [[4, 1, 2, 3]], 2: [[4, 1, 2, 3]], 3: [[4, 1, 2, 3]], 4: [[4, 0], [4, 1, 2, 3]]}
  3946. sage: E = C.cliques_maximal()
  3947. sage: E
  3948. [[4, 0], [4, 1, 2, 3]]
  3949. sage: C.cliques_containing_vertex(cliques=E)
  3950. {0: [[4, 0]], 1: [[4, 1, 2, 3]], 2: [[4, 1, 2, 3]], 3: [[4, 1, 2, 3]], 4: [[4, 0], [4, 1, 2, 3]]}
  3951. sage: F = graphs.Grid2dGraph(2,3)
  3952. sage: X = F.cliques_containing_vertex()
  3953. sage: for v in sorted(X.iterkeys()):
  3954. ... print v, X[v]
  3955. (0, 0) [[(0, 1), (0, 0)], [(1, 0), (0, 0)]]
  3956. (0, 1) [[(0, 1), (0, 0)], [(0, 1), (0, 2)], [(0, 1), (1, 1)]]
  3957. (0, 2) [[(0, 1), (0, 2)], [(1, 2), (0, 2)]]
  3958. (1, 0) [[(1, 0), (0, 0)], [(1, 0), (1, 1)]]
  3959. (1, 1) [[(0, 1), (1, 1)], [(1, 2), (1, 1)], [(1, 0), (1, 1)]]
  3960. (1, 2) [[(1, 2), (0, 2)], [(1, 2), (1, 1)]]
  3961. sage: F.cliques_containing_vertex(vertices=[(0, 1), (1, 2)])
  3962. {(0, 1): [[(0, 1), (0, 0)], [(0, 1), (0, 2)], [(0, 1), (1, 1)]], (1, 2): [[(1, 2), (0, 2)], [(1, 2), (1, 1)]]}
  3963. sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]})
  3964. sage: G.show(figsize=[2,2])
  3965. sage: G.cliques_containing_vertex()
  3966. {0: [[0, 1, 2], [0, 1, 3]], 1: [[0, 1, 2], [0, 1, 3]], 2: [[0, 1, 2]], 3: [[0, 1, 3]]}
  3967. """
  3968. import networkx
  3969. return networkx.cliques_containing_node(self.networkx_graph(copy=False),vertices, cliques)
  3970. def clique_complex(self):
  3971. """
  3972. Returns the clique complex of self. This is the largest simplicial complex on
  3973. the vertices of self whose 1-skeleton is self.
  3974. This is only makes sense for undirected simple graphs.
  3975. EXAMPLES::
  3976. sage: g = Graph({0:[1,2],1:[2],4:[]})
  3977. sage: g.clique_complex()
  3978. Simplicial complex with vertex set (0, 1, 2, 4) and facets {(4,), (0, 1, 2)}
  3979. sage: h = Graph({0:[1,2,3,4],1:[2,3,4],2:[3]})
  3980. sage: x = h.clique_complex()
  3981. sage: x
  3982. Simplicial complex with vertex set (0, 1, 2, 3, 4) and facets {(0, 1, 4), (0, 1, 2, 3)}
  3983. sage: i = x.graph()
  3984. sage: i==h
  3985. True
  3986. sage: x==i.clique_complex()
  3987. True
  3988. """
  3989. if self.is_directed() or self.has_loops() or self.has_multiple_edges():
  3990. raise ValueError("Self must be an undirected simple graph to have a clique complex.")
  3991. import sage.homology.simplicial_complex
  3992. C = sage.homology.simplicial_complex.SimplicialComplex(self.cliques_maximal(), maximality_check=True)
  3993. C._graph = self
  3994. return C
  3995. ### Miscellaneous
  3996. def cores(self, k = None, with_labels=False):
  3997. """
  3998. Returns the core number for each vertex in an ordered list.
  3999. (for homomorphisms cores, see the :meth:`Graph.has_homomorphism_to`
  4000. method)
  4001. **DEFINITIONS**
  4002. * *K-cores* in graph theory were introduced by Seidman in 1983 and by
  4003. Bollobas in 1984 as a method of (destructively) simplifying graph
  4004. topology to aid in analysis and visualization. They have been more
  4005. recently defined as the following by Batagelj et al:
  4006. *Given a graph `G` with vertices set `V` and edges set `E`, the
  4007. `k`-core of `G` is the graph obtained from `G` by recursively removing
  4008. the vertices with degree less than `k`, for as long as there are any.*
  4009. This operation can be useful to filter or to study some properties of
  4010. the graphs. For instance, when you compute the 2-core of graph G, you
  4011. are cutting all the vertices which are in a tree part of graph. (A
  4012. tree is a graph with no loops). [WPkcore]_
  4013. [PSW1996]_ defines a `k`-core of `G` as the largest subgraph (it is
  4014. unique) of `G` with minimum degree at least `k`.
  4015. * Core number of a vertex
  4016. The core number of a vertex `v` is the largest integer `k` such that
  4017. `v` belongs to the `k`-core of `G`.
  4018. * Degeneracy
  4019. The *degeneracy* of a graph `G`, usually denoted `\delta^*(G)`, is the
  4020. smallest integer `k` such that the graph `G` can be reduced to the
  4021. empty graph by iteratively removing vertices of degree `\leq
  4022. k`. Equivalently, `\delta^*(G)=k` if `k` is the smallest integer such
  4023. that the `k`-core of `G` is empty.
  4024. **IMPLEMENTATION**
  4025. This implementation is based on the NetworkX implementation of
  4026. the algorithm described in [BZ]_.
  4027. **INPUT**
  4028. - ``k`` (integer)
  4029. * If ``k = None`` (default), returns the core number for each vertex.
  4030. * If ``k`` is an integer, returns a pair ``(ordering, core)``, where
  4031. ``core`` is the list of vertices in the `k`-core of ``self``, and
  4032. ``ordering`` is an elimination order for the other vertices such
  4033. that each vertex is of degree strictly less than `k` when it is to
  4034. be eliminated from the graph.
  4035. - ``with_labels`` (boolean)
  4036. * When set to ``False``, and ``k = None``, the method returns a list
  4037. whose `i` th element is the core number of the `i` th vertex. When
  4038. set to ``True``, the method returns a dictionary whose keys are
  4039. vertices, and whose values are the corresponding core numbers.
  4040. By default, ``with_labels = False``.
  4041. .. SEEALSO::
  4042. * Graph cores is also a notion related to graph homomorphisms. For
  4043. this second meaning, see :meth:`Graph.has_homomorphism_to`.
  4044. REFERENCE:
  4045. .. [WPkcore] K-core. Wikipedia. (2007). [Online] Available:
  4046. http://en.wikipedia.org/wiki/K-core
  4047. .. [PSW1996] Boris Pittel, Joel Spencer and Nicholas Wormald. Sudden
  4048. Emergence of a Giant k-Core in a Random
  4049. Graph. (1996). J. Combinatorial Theory. Ser B 67. pages
  4050. 111-151. [Online] Available:
  4051. http://cs.nyu.edu/cs/faculty/spencer/papers/k-core.pdf
  4052. .. [BZ] Vladimir Batagelj and Matjaz Zaversnik. An `O(m)`
  4053. Algorithm for Cores Decomposition of
  4054. Networks. arXiv:cs/0310049v1. [Online] Available:
  4055. http://arxiv.org/abs/cs/0310049
  4056. EXAMPLES::
  4057. sage: (graphs.FruchtGraph()).cores()
  4058. [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
  4059. sage: (graphs.FruchtGraph()).cores(with_labels=True)
  4060. {0: 3, 1: 3, 2: 3, 3: 3, 4: 3, 5: 3, 6: 3, 7: 3, 8: 3, 9: 3, 10: 3, 11: 3}
  4061. sage: a=random_matrix(ZZ,20,x=2,sparse=True, density=.1)
  4062. sage: b=Graph(20)
  4063. sage: b.add_edges(a.nonzero_positions())
  4064. sage: cores=b.cores(with_labels=True); cores
  4065. {0: 3, 1: 3, 2: 3, 3: 3, 4: 2, 5: 2, 6: 3, 7: 1, 8: 3, 9: 3, 10: 3, 11: 3, 12: 3, 13: 3, 14: 2, 15: 3, 16: 3, 17: 3, 18: 3, 19: 3}
  4066. sage: [v for v,c in cores.items() if c>=2] # the vertices in the 2-core
  4067. [0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
  4068. Checking the 2-core of a random lobster is indeed the empty set::
  4069. sage: g = graphs.RandomLobster(20,.5,.5)
  4070. sage: ordering, core = g.cores(2)
  4071. sage: len(core) == 0
  4072. True
  4073. """
  4074. # compute the degrees of each vertex
  4075. degrees=self.degree(labels=True)
  4076. # sort vertices by degree. Store in a list and keep track of
  4077. # where a specific degree starts (effectively, the list is
  4078. # sorted by bins).
  4079. verts= sorted( degrees.keys(), key=lambda x: degrees[x])
  4080. bin_boundaries=[0]
  4081. curr_degree=0
  4082. for i,v in enumerate(verts):
  4083. if degrees[v]>curr_degree:
  4084. bin_boundaries.extend([i]*(degrees[v]-curr_degree))
  4085. curr_degree=degrees[v]
  4086. vert_pos = dict((v,pos) for pos,v in enumerate(verts))
  4087. # Set up initial guesses for core and lists of neighbors.
  4088. core= degrees
  4089. nbrs=dict((v,set(self.neighbors(v))) for v in self)
  4090. # form vertex core building up from smallest
  4091. for v in verts:
  4092. # If all the vertices have a degree larger than k, we can
  4093. # return our answer if k != None
  4094. if k is not None and core[v] >= k:
  4095. return verts[:vert_pos[v]], verts[vert_pos[v]:]
  4096. for u in nbrs[v]:
  4097. if core[u] > core[v]:
  4098. nbrs[u].remove(v)
  4099. # cleverly move u to the end of the next smallest
  4100. # bin (i.e., subtract one from the degree of u).
  4101. # We do this by swapping u with the first vertex
  4102. # in the bin that contains u, then incrementing
  4103. # the bin boundary for the bin that contains u.
  4104. pos=vert_pos[u]
  4105. bin_start=bin_boundaries[core[u]]
  4106. vert_pos[u]=bin_start
  4107. vert_pos[verts[bin_start]]=pos
  4108. verts[bin_start],verts[pos]=verts[pos],verts[bin_start]
  4109. bin_boundaries[core[u]]+=1
  4110. core[u] -= 1
  4111. if k is not None:
  4112. return verts, []
  4113. if with_labels:
  4114. return core
  4115. else:
  4116. return core.values()
  4117. def modular_decomposition(self):
  4118. r"""
  4119. Returns the modular decomposition of the current graph.
  4120. Crash course on modular decomposition:
  4121. A module `M` of a graph `G` is a proper subset of its vertices
  4122. such that for all `u \in V(G)-M, v,w\in M` the relation `u
  4123. \sim v \Leftrightarrow u \sim w` holds, where `\sim` denotes
  4124. the adjacency relation in `G`. Equivalently, `M \subset V(G)`
  4125. is a module if all its vertices have the same adjacency
  4126. relations with each vertex outside of the module (vertex by
  4127. vertex).
  4128. Hence, for a set like a module, it is very easy to encode the
  4129. information of the adjacencies between the vertices inside and
  4130. outside the module -- we can actually add a new vertex `v_M`
  4131. to our graph representing our module `M`, and let `v_M` be
  4132. adjacent to `u\in V(G)-M` if and only if some `v\in M` (and
  4133. hence all the vertices contained in the module) is adjacent to
  4134. `u`. We can now independently (and recursively) study the
  4135. structure of our module `M` and the new graph `G-M+\{v_M\}`,
  4136. without any loss of information.
  4137. Here are two very simple modules :
  4138. * A connected component `C` (or the union of some --but
  4139. not all-- of them) of a disconnected graph `G`, for
  4140. instance, is a module, as no vertex of `C` has a
  4141. neighbor outside of it.
  4142. * An anticomponent `C` (or the union of some --but not
  4143. all-- of them) of an non-anticonnected graph `G`, for
  4144. the same reason (it is just the complement of the
  4145. previous graph !).
  4146. These modules being of special interest, the disjoint union of
  4147. graphs is called a Parallel composition, and the complement of
  4148. a disjoint union is called a Parallel composition. A graph
  4149. whose only modules are singletons is called Prime.
  4150. For more information on modular decomposition, in particular
  4151. for an explanation of the terms "Parallel," "Prime" and
  4152. "Serie," see the `Wikipedia article on modular decomposition
  4153. <http://en.wikipedia.org/wiki/Modular_decomposition>`_.
  4154. You may also be interested in the survey from Michel Habib and
  4155. Christophe Paul entitled "A survey on Algorithmic aspects of
  4156. modular decomposition" [HabPau10]_.
  4157. OUTPUT:
  4158. A pair of two values (recursively encoding the decomposition) :
  4159. * The type of the current module :
  4160. * ``"Parallel"``
  4161. * ``"Prime"``
  4162. * ``"Serie"``
  4163. * The list of submodules (as list of pairs ``(type, list)``,
  4164. recursively...) or the vertex's name if the module is a
  4165. singleton.
  4166. EXAMPLES:
  4167. The Bull Graph is prime::
  4168. sage: graphs.BullGraph().modular_decomposition()
  4169. ('Prime', [3, 4, 0, 1, 2])
  4170. The Petersen Graph too::
  4171. sage: graphs.PetersenGraph().modular_decomposition()
  4172. ('Prime', [2, 6, 3, 9, 7, 8, 0, 1, 5, 4])
  4173. This a clique on 5 vertices with 2 pendant edges, though, has a more
  4174. interesting decomposition ::
  4175. sage: g = graphs.CompleteGraph(5)
  4176. sage: g.add_edge(0,5)
  4177. sage: g.add_edge(0,6)
  4178. sage: g.modular_decomposition()
  4179. ('Serie', [0, ('Parallel', [5, ('Serie', [1, 4, 3, 2]), 6])])
  4180. ALGORITHM:
  4181. This function uses a C implementation of a 2-step algorithm
  4182. implemented by Fabien de Montgolfier [FMDec]_ :
  4183. * Computation of a factorizing permutation [HabibViennot1999]_.
  4184. * Computation of the tree itself [CapHabMont02]_.
  4185. .. SEEALSO::
  4186. - :meth:`is_prime` -- Tests whether a graph is prime.
  4187. REFERENCE:
  4188. .. [FMDec] Fabien de Montgolfier
  4189. http://www.liafa.jussieu.fr/~fm/algos/index.html
  4190. .. [HabibViennot1999] Michel Habib, Christiphe Paul, Laurent Viennot
  4191. Partition refinement techniques: An interesting algorithmic tool kit
  4192. International Journal of Foundations of Computer Science
  4193. vol. 10 n2 pp.147--170, 1999
  4194. .. [CapHabMont02] C. Capelle, M. Habib et F. de Montgolfier
  4195. Graph decomposition and Factorising Permutations
  4196. Discrete Mathematics and Theoretical Computer Sciences, vol 5 no. 1 , 2002.
  4197. .. [HabPau10] Michel Habib and Christophe Paul
  4198. A survey of the algorithmic aspects of modular decomposition
  4199. Computer Science Review
  4200. vol 4, number 1, pages 41--59, 2010
  4201. http://www.lirmm.fr/~paul/md-survey.pdf
  4202. """
  4203. from sage.misc.stopgap import stopgap
  4204. stopgap("Graph.modular_decomposition is known to return wrong results",13744)
  4205. from sage.graphs.modular_decomposition.modular_decomposition import modular_decomposition
  4206. D = modular_decomposition(self)
  4207. id_label = dict(enumerate(self.vertices()))
  4208. relabel = lambda x : (x[0], map(relabel,x[1])) if isinstance(x,tuple) else id_label[x]
  4209. return relabel(D)
  4210. def is_prime(self):
  4211. r"""
  4212. Tests whether the current graph is prime. A graph is prime if
  4213. all its modules are trivial (i.e. empty, all of the graph or
  4214. singletons)-- see `self.modular_decomposition?`.
  4215. EXAMPLE:
  4216. The Petersen Graph and the Bull Graph are both prime ::
  4217. sage: graphs.PetersenGraph().is_prime()
  4218. True
  4219. sage: graphs.BullGraph().is_prime()
  4220. True
  4221. Though quite obviously, the disjoint union of them is not::
  4222. sage: (graphs.PetersenGraph() + graphs.BullGraph()).is_prime()
  4223. False
  4224. """
  4225. D = self.modular_decomposition()
  4226. return D[0] == "Prime" and len(D[1]) == self.order()
  4227. def _gomory_hu_tree(self, vertices=None, method="FF"):
  4228. r"""
  4229. Returns a Gomory-Hu tree associated to self.
  4230. This function is the private counterpart of ``gomory_hu_tree()``,
  4231. with the difference that it has an optional argument
  4232. needed for recursive computations, which the user is not
  4233. interested in defining himself.
  4234. See the documentation of ``gomory_hu_tree()`` for more information.
  4235. INPUT:
  4236. - ``vertices`` - a set of "real" vertices, as opposed to the
  4237. fakes one introduced during the computations. This variable is
  4238. useful for the algorithm and for recursion purposes.
  4239. - ``method`` -- There are currently two different
  4240. implementations of this method :
  4241. * If ``method = "FF"`` (default), a Python
  4242. implementation of the Ford-Fulkerson algorithm is
  4243. used.
  4244. * If ``method = "LP"``, the flow problem is solved using
  4245. Linear Programming.
  4246. EXAMPLE:
  4247. This function is actually tested in ``gomory_hu_tree()``, this
  4248. example is only present to have a doctest coverage of 100%.
  4249. sage: g = graphs.PetersenGraph()
  4250. sage: t = g._gomory_hu_tree()
  4251. """
  4252. from sage.sets.set import Set
  4253. # The default capacity of an arc is 1
  4254. from sage.rings.real_mpfr import RR
  4255. capacity = lambda label: label if label in RR else 1
  4256. # Keeping the graph's embedding
  4257. pos = False
  4258. # Small case, not really a problem ;-)
  4259. if self.order() == 1:
  4260. return self.copy()
  4261. # This is a sign that this is the first call
  4262. # to this recursive function
  4263. if vertices is None:
  4264. # Now is the time to care about positions
  4265. pos = self.get_pos()
  4266. # if the graph is not connected, returns the union
  4267. # of the Gomory-Hu tree of each component
  4268. if not self.is_connected():
  4269. g = Graph()
  4270. for cc in self.connected_components_subgraphs():
  4271. g = g.union(cc._gomory_hu_tree(method=method))
  4272. g.set_pos(self.get_pos())
  4273. return g
  4274. # All the vertices is this graph are the "real ones"
  4275. vertices = Set(self.vertices())
  4276. # There may be many vertices, though only one which is "real"
  4277. if len(vertices) == 1:
  4278. g = Graph()
  4279. g.add_vertex(vertices[0])
  4280. return g
  4281. # Take any two vertices
  4282. u,v = vertices[0:2]
  4283. # Recovers the following values
  4284. # flow is the connectivity between u and v
  4285. # edges of a min cut
  4286. # sets1, sets2 are the two sides of the edge cut
  4287. flow,edges,[set1,set2] = self.edge_cut(u, v, use_edge_labels=True, vertices=True, method=method)
  4288. # One graph for each part of the previous one
  4289. g1,g2 = self.subgraph(set1), self.subgraph(set2)
  4290. # Adding the fake vertex to each part
  4291. g1_v = Set(set2)
  4292. g2_v = Set(set1)
  4293. g1.add_vertex(g1_v)
  4294. g1.add_vertex(g2_v)
  4295. # Each part of the graph had many edges going to the other part
  4296. # Now that we have a new fake vertex in each part
  4297. # we just say that the edges which were in the cut and going
  4298. # to the other side are now going to this fake vertex
  4299. # We must preserve the labels. They sum.
  4300. for e in edges:
  4301. x,y = e[0],e[1]
  4302. # Assumes x is in g1
  4303. if x in g2:
  4304. x,y = y,x
  4305. # If the edge x-g1_v exists, adds to its label the capacity of arc xy
  4306. if g1.has_edge(x, g1_v):
  4307. g1.set_edge_label(x, g1_v, g1.edge_label(x, g1_v) + capacity(self.edge_label(x, y)))
  4308. else:
  4309. # Otherwise, creates it with the good label
  4310. g1.add_edge(x, g1_v, capacity(self.edge_label(x, y)))
  4311. # Same thing for g2
  4312. if g2.has_edge(y, g2_v):
  4313. g2.set_edge_label(y, g2_v, g2.edge_label(y, g2_v) + capacity(self.edge_label(x, y)))
  4314. else:
  4315. g2.add_edge(y, g2_v, capacity(self.edge_label(x, y)))
  4316. # Recursion for the two new graphs... The new "real" vertices are the intersection with
  4317. # with the previous set of "real" vertices
  4318. g1_tree = g1._gomory_hu_tree(vertices=(vertices & Set(g1.vertices())), method=method)
  4319. g2_tree = g2._gomory_hu_tree(vertices=(vertices & Set(g2.vertices())), method=method)
  4320. # Union of the two partial trees ( it is disjoint, but
  4321. # disjoint_union does not preserve the name of the vertices )
  4322. g = g1_tree.union(g2_tree)
  4323. # An edge to connect them, with the appropriate label
  4324. g.add_edge(g1_tree.vertex_iterator().next(), g2_tree.vertex_iterator().next(), flow)
  4325. if pos:
  4326. g.set_pos(pos)
  4327. return g
  4328. def gomory_hu_tree(self, method="FF"):
  4329. r"""
  4330. Returns a Gomory-Hu tree of self.
  4331. Given a tree `T` with labeled edges representing capacities, it is very
  4332. easy to determine the maximal flow between any pair of vertices :
  4333. it is the minimal label on the edges of the unique path between them.
  4334. Given a graph `G`, a Gomory-Hu tree `T` of `G` is a tree
  4335. with the same set of vertices, and such that the maximal flow
  4336. between any two vertices is the same in `G` as in `T`. See the
  4337. `Wikipedia article on Gomory-Hu tree <http://en.wikipedia.org/wiki/Gomory%E2%80%93Hu_tree>`_.
  4338. Note that, in general, a graph admits more than one Gomory-Hu tree.
  4339. INPUT:
  4340. - ``method`` -- There are currently two different
  4341. implementations of this method :
  4342. * If ``method = "FF"`` (default), a Python
  4343. implementation of the Ford-Fulkerson algorithm is
  4344. used.
  4345. * If ``method = "LP"``, the flow problems are solved
  4346. using Linear Programming.
  4347. OUTPUT:
  4348. A graph with labeled edges
  4349. EXAMPLE:
  4350. Taking the Petersen graph::
  4351. sage: g = graphs.PetersenGraph()
  4352. sage: t = g.gomory_hu_tree()
  4353. Obviously, this graph is a tree::
  4354. sage: t.is_tree()
  4355. True
  4356. Note that if the original graph is not connected, then the
  4357. Gomory-Hu tree is in fact a forest::
  4358. sage: (2*g).gomory_hu_tree().is_forest()
  4359. True
  4360. sage: (2*g).gomory_hu_tree().is_connected()
  4361. False
  4362. On the other hand, such a tree has lost nothing of the initial
  4363. graph connectedness::
  4364. sage: all([ t.flow(u,v) == g.flow(u,v) for u,v in Subsets( g.vertices(), 2 ) ])
  4365. True
  4366. Just to make sure, we can check that the same is true for two vertices
  4367. in a random graph::
  4368. sage: g = graphs.RandomGNP(20,.3)
  4369. sage: t = g.gomory_hu_tree()
  4370. sage: g.flow(0,1) == t.flow(0,1)
  4371. True
  4372. And also the min cut::
  4373. sage: g.edge_connectivity() == min(t.edge_labels())
  4374. True
  4375. """
  4376. return self._gomory_hu_tree(method=method)
  4377. def two_factor_petersen(self):
  4378. r"""
  4379. Returns a decomposition of the graph into 2-factors.
  4380. Petersen's 2-factor decomposition theorem asserts that any
  4381. `2r`-regular graph `G` can be decomposed into 2-factors.
  4382. Equivalently, it means that the edges of any `2r`-regular
  4383. graphs can be partitionned in `r` sets `C_1,\dots,C_r` such
  4384. that for all `i`, the set `C_i` is a disjoint union of cycles
  4385. ( a 2-regular graph ).
  4386. As any graph of maximal degree `\Delta` can be completed into
  4387. a regular graph of degree `2\lceil\frac\Delta 2\rceil`, this
  4388. result also means that the edges of any graph of degree `\Delta`
  4389. can be partitionned in `r=2\lceil\frac\Delta 2\rceil` sets
  4390. `C_1,\dots,C_r` such that for all `i`, the set `C_i` is a
  4391. graph of maximal degree `2` ( a disjoint union of paths
  4392. and cycles ).
  4393. EXAMPLE:
  4394. The Complete Graph on `7` vertices is a `6`-regular graph, so it can
  4395. be edge-partitionned into `2`-regular graphs::
  4396. sage: g = graphs.CompleteGraph(7)
  4397. sage: classes = g.two_factor_petersen()
  4398. sage: for c in classes:
  4399. ... gg = Graph()
  4400. ... gg.add_edges(c)
  4401. ... print max(gg.degree())<=2
  4402. True
  4403. True
  4404. True
  4405. sage: Set(set(classes[0]) | set(classes[1]) | set(classes[2])).cardinality() == g.size()
  4406. True
  4407. ::
  4408. sage: g = graphs.CirculantGraph(24, [7, 11])
  4409. sage: cl = g.two_factor_petersen()
  4410. sage: g.plot(edge_colors={'black':cl[0], 'red':cl[1]})
  4411. """
  4412. d = self.eulerian_orientation()
  4413. # This new graph is bipartite, and built the following way :
  4414. #
  4415. # To each vertex v of the digraph are associated two vertices,
  4416. # a sink (-1,v) and a source (1,v)
  4417. # Any edge (u,v) in the digraph is then added as ((-1,u),(1,v))
  4418. from sage.graphs.graph import Graph
  4419. g = Graph()
  4420. g.add_edges([((-1,u),(1,v)) for (u,v) in d.edge_iterator(labels=None)])
  4421. # This new bipartite graph is now edge_colored
  4422. from sage.graphs.graph_coloring import edge_coloring
  4423. classes = edge_coloring(g)
  4424. # The edges in the classes are of the form ((-1,u),(1,v))
  4425. # and have to be translated back to (u,v)
  4426. classes_b = []
  4427. for c in classes:
  4428. classes_b.append([(u,v) for ((uu,u),(vv,v)) in c])
  4429. return classes_b
  4430. # Aliases to functions defined in Cython modules
  4431. import types
  4432. import sage.graphs.weakly_chordal
  4433. Graph.is_long_hole_free = types.MethodType(sage.graphs.weakly_chordal.is_long_hole_free, None, Graph)
  4434. Graph.is_long_antihole_free = types.MethodType(sage.graphs.weakly_chordal.is_long_antihole_free, None, Graph)
  4435. Graph.is_weakly_chordal = types.MethodType(sage.graphs.weakly_chordal.is_weakly_chordal, None, Graph)
  4436. import sage.graphs.chrompoly
  4437. Graph.chromatic_polynomial = types.MethodType(sage.graphs.chrompoly.chromatic_polynomial, None, Graph)
  4438. import sage.graphs.graph_decompositions.rankwidth
  4439. Graph.rank_decomposition = types.MethodType(sage.graphs.graph_decompositions.rankwidth.rank_decomposition, None, Graph)
  4440. import sage.graphs.matchpoly
  4441. Graph.matching_polynomial = types.MethodType(sage.graphs.matchpoly.matching_polynomial, None, Graph)
  4442. import sage.graphs.cliquer
  4443. Graph.cliques_maximum = types.MethodType(sage.graphs.cliquer.all_max_clique, None, Graph)
  4444. import sage.graphs.graph_decompositions.graph_products
  4445. Graph.is_cartesian_product = types.MethodType(sage.graphs.graph_decompositions.graph_products.is_cartesian_product, None, Graph)
  4446. def compare_edges(x, y):
  4447. """
  4448. This function has been deprecated.
  4449. Compare edge x to edge y, return -1 if x y, 1 if x y, else 0.
  4450. TEST::
  4451. sage: G = graphs.PetersenGraph()
  4452. sage: E = G.edges()
  4453. sage: from sage.graphs.graph import compare_edges
  4454. sage: compare_edges(E[0], E[2])
  4455. doctest:...: DeprecationWarning: compare_edges(x,y) is deprecated. Use statement 'cmp(x[1],y[1]) or cmp(x[0],y[0])' instead.
  4456. See http://trac.sagemath.org/13192 for details.
  4457. -1
  4458. """
  4459. from sage.misc.superseded import deprecation
  4460. deprecation(13192, "compare_edges(x,y) is deprecated. Use statement 'cmp(x[1],y[1]) or cmp(x[0],y[0])' instead.")
  4461. if x[1] < y[1]:
  4462. return -1
  4463. elif x[1] > y[1]:
  4464. return 1
  4465. elif x[1] == y[1]:
  4466. if x[0] < y[0]:
  4467. return -1
  4468. if x[0] > y[0]:
  4469. return 1
  4470. else:
  4471. return 0