passagemath-graphs 10.6.1rc1__cp310-cp310-musllinux_1_2_aarch64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. passagemath_graphs-10.6.1rc1.dist-info/METADATA +292 -0
  2. passagemath_graphs-10.6.1rc1.dist-info/RECORD +260 -0
  3. passagemath_graphs-10.6.1rc1.dist-info/WHEEL +5 -0
  4. passagemath_graphs-10.6.1rc1.dist-info/top_level.txt +2 -0
  5. passagemath_graphs.libs/libgcc_s-69c45f16.so.1 +0 -0
  6. passagemath_graphs.libs/libgmp-8e78bd9b.so.10.5.0 +0 -0
  7. passagemath_graphs.libs/libstdc++-1f1a71be.so.6.0.33 +0 -0
  8. sage/all__sagemath_graphs.py +39 -0
  9. sage/combinat/abstract_tree.py +2723 -0
  10. sage/combinat/all__sagemath_graphs.py +34 -0
  11. sage/combinat/binary_tree.py +5306 -0
  12. sage/combinat/cluster_algebra_quiver/all.py +22 -0
  13. sage/combinat/cluster_algebra_quiver/cluster_seed.py +5208 -0
  14. sage/combinat/cluster_algebra_quiver/interact.py +124 -0
  15. sage/combinat/cluster_algebra_quiver/mutation_class.py +625 -0
  16. sage/combinat/cluster_algebra_quiver/mutation_type.py +1555 -0
  17. sage/combinat/cluster_algebra_quiver/quiver.py +2290 -0
  18. sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +2468 -0
  19. sage/combinat/designs/MOLS_handbook_data.py +570 -0
  20. sage/combinat/designs/all.py +58 -0
  21. sage/combinat/designs/bibd.py +1655 -0
  22. sage/combinat/designs/block_design.py +1071 -0
  23. sage/combinat/designs/covering_array.py +269 -0
  24. sage/combinat/designs/covering_design.py +530 -0
  25. sage/combinat/designs/database.py +5615 -0
  26. sage/combinat/designs/design_catalog.py +122 -0
  27. sage/combinat/designs/designs_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  28. sage/combinat/designs/designs_pyx.pxd +21 -0
  29. sage/combinat/designs/designs_pyx.pyx +993 -0
  30. sage/combinat/designs/difference_family.py +3951 -0
  31. sage/combinat/designs/difference_matrices.py +279 -0
  32. sage/combinat/designs/evenly_distributed_sets.cpython-310-aarch64-linux-gnu.so +0 -0
  33. sage/combinat/designs/evenly_distributed_sets.pyx +661 -0
  34. sage/combinat/designs/ext_rep.py +1064 -0
  35. sage/combinat/designs/gen_quadrangles_with_spread.cpython-310-aarch64-linux-gnu.so +0 -0
  36. sage/combinat/designs/gen_quadrangles_with_spread.pyx +339 -0
  37. sage/combinat/designs/group_divisible_designs.py +361 -0
  38. sage/combinat/designs/incidence_structures.py +2357 -0
  39. sage/combinat/designs/latin_squares.py +581 -0
  40. sage/combinat/designs/orthogonal_arrays.py +2244 -0
  41. sage/combinat/designs/orthogonal_arrays_build_recursive.py +1780 -0
  42. sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-310-aarch64-linux-gnu.so +0 -0
  43. sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +967 -0
  44. sage/combinat/designs/resolvable_bibd.py +815 -0
  45. sage/combinat/designs/steiner_quadruple_systems.py +1306 -0
  46. sage/combinat/designs/subhypergraph_search.cpython-310-aarch64-linux-gnu.so +0 -0
  47. sage/combinat/designs/subhypergraph_search.pyx +530 -0
  48. sage/combinat/designs/twographs.py +306 -0
  49. sage/combinat/finite_state_machine.py +14874 -0
  50. sage/combinat/finite_state_machine_generators.py +2006 -0
  51. sage/combinat/graph_path.py +448 -0
  52. sage/combinat/interval_posets.py +3908 -0
  53. sage/combinat/nu_tamari_lattice.py +269 -0
  54. sage/combinat/ordered_tree.py +1446 -0
  55. sage/combinat/posets/all.py +46 -0
  56. sage/combinat/posets/bubble_shuffle.py +247 -0
  57. sage/combinat/posets/cartesian_product.py +493 -0
  58. sage/combinat/posets/d_complete.py +182 -0
  59. sage/combinat/posets/elements.py +273 -0
  60. sage/combinat/posets/forest.py +30 -0
  61. sage/combinat/posets/hasse_cython.cpython-310-aarch64-linux-gnu.so +0 -0
  62. sage/combinat/posets/hasse_cython.pyx +174 -0
  63. sage/combinat/posets/hasse_diagram.py +3672 -0
  64. sage/combinat/posets/hochschild_lattice.py +158 -0
  65. sage/combinat/posets/incidence_algebras.py +794 -0
  66. sage/combinat/posets/lattices.py +5117 -0
  67. sage/combinat/posets/linear_extension_iterator.cpython-310-aarch64-linux-gnu.so +0 -0
  68. sage/combinat/posets/linear_extension_iterator.pyx +292 -0
  69. sage/combinat/posets/linear_extensions.py +1037 -0
  70. sage/combinat/posets/mobile.py +275 -0
  71. sage/combinat/posets/moebius_algebra.py +776 -0
  72. sage/combinat/posets/poset_examples.py +2178 -0
  73. sage/combinat/posets/posets.py +9360 -0
  74. sage/combinat/rooted_tree.py +1070 -0
  75. sage/combinat/shard_order.py +239 -0
  76. sage/combinat/tamari_lattices.py +384 -0
  77. sage/combinat/yang_baxter_graph.py +923 -0
  78. sage/databases/all__sagemath_graphs.py +1 -0
  79. sage/databases/knotinfo_db.py +1231 -0
  80. sage/ext_data/all__sagemath_graphs.py +1 -0
  81. sage/ext_data/graphs/graph_plot_js.html +330 -0
  82. sage/ext_data/kenzo/CP2.txt +45 -0
  83. sage/ext_data/kenzo/CP3.txt +349 -0
  84. sage/ext_data/kenzo/CP4.txt +4774 -0
  85. sage/ext_data/kenzo/README.txt +49 -0
  86. sage/ext_data/kenzo/S4.txt +20 -0
  87. sage/graphs/all.py +42 -0
  88. sage/graphs/asteroidal_triples.cpython-310-aarch64-linux-gnu.so +0 -0
  89. sage/graphs/asteroidal_triples.pyx +320 -0
  90. sage/graphs/base/all.py +1 -0
  91. sage/graphs/base/boost_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  92. sage/graphs/base/boost_graph.pxd +106 -0
  93. sage/graphs/base/boost_graph.pyx +3045 -0
  94. sage/graphs/base/c_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  95. sage/graphs/base/c_graph.pxd +106 -0
  96. sage/graphs/base/c_graph.pyx +5096 -0
  97. sage/graphs/base/dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  98. sage/graphs/base/dense_graph.pxd +28 -0
  99. sage/graphs/base/dense_graph.pyx +801 -0
  100. sage/graphs/base/graph_backends.cpython-310-aarch64-linux-gnu.so +0 -0
  101. sage/graphs/base/graph_backends.pxd +5 -0
  102. sage/graphs/base/graph_backends.pyx +797 -0
  103. sage/graphs/base/overview.py +85 -0
  104. sage/graphs/base/sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  105. sage/graphs/base/sparse_graph.pxd +90 -0
  106. sage/graphs/base/sparse_graph.pyx +1653 -0
  107. sage/graphs/base/static_dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  108. sage/graphs/base/static_dense_graph.pxd +5 -0
  109. sage/graphs/base/static_dense_graph.pyx +1032 -0
  110. sage/graphs/base/static_sparse_backend.cpython-310-aarch64-linux-gnu.so +0 -0
  111. sage/graphs/base/static_sparse_backend.pxd +27 -0
  112. sage/graphs/base/static_sparse_backend.pyx +1583 -0
  113. sage/graphs/base/static_sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  114. sage/graphs/base/static_sparse_graph.pxd +37 -0
  115. sage/graphs/base/static_sparse_graph.pyx +1375 -0
  116. sage/graphs/bipartite_graph.py +2732 -0
  117. sage/graphs/centrality.cpython-310-aarch64-linux-gnu.so +0 -0
  118. sage/graphs/centrality.pyx +1038 -0
  119. sage/graphs/cographs.py +519 -0
  120. sage/graphs/comparability.cpython-310-aarch64-linux-gnu.so +0 -0
  121. sage/graphs/comparability.pyx +851 -0
  122. sage/graphs/connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
  123. sage/graphs/connectivity.pxd +157 -0
  124. sage/graphs/connectivity.pyx +4813 -0
  125. sage/graphs/convexity_properties.cpython-310-aarch64-linux-gnu.so +0 -0
  126. sage/graphs/convexity_properties.pxd +16 -0
  127. sage/graphs/convexity_properties.pyx +870 -0
  128. sage/graphs/digraph.py +4754 -0
  129. sage/graphs/digraph_generators.py +1993 -0
  130. sage/graphs/distances_all_pairs.cpython-310-aarch64-linux-gnu.so +0 -0
  131. sage/graphs/distances_all_pairs.pxd +12 -0
  132. sage/graphs/distances_all_pairs.pyx +2938 -0
  133. sage/graphs/domination.py +1363 -0
  134. sage/graphs/dot2tex_utils.py +100 -0
  135. sage/graphs/edge_connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
  136. sage/graphs/edge_connectivity.pyx +1215 -0
  137. sage/graphs/generators/all.py +1 -0
  138. sage/graphs/generators/basic.py +1769 -0
  139. sage/graphs/generators/chessboard.py +538 -0
  140. sage/graphs/generators/classical_geometries.py +1611 -0
  141. sage/graphs/generators/degree_sequence.py +235 -0
  142. sage/graphs/generators/distance_regular.cpython-310-aarch64-linux-gnu.so +0 -0
  143. sage/graphs/generators/distance_regular.pyx +2846 -0
  144. sage/graphs/generators/families.py +4759 -0
  145. sage/graphs/generators/intersection.py +565 -0
  146. sage/graphs/generators/platonic_solids.py +262 -0
  147. sage/graphs/generators/random.py +2623 -0
  148. sage/graphs/generators/smallgraphs.py +5741 -0
  149. sage/graphs/generators/world_map.py +724 -0
  150. sage/graphs/generic_graph.py +26867 -0
  151. sage/graphs/generic_graph_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  152. sage/graphs/generic_graph_pyx.pxd +34 -0
  153. sage/graphs/generic_graph_pyx.pyx +1673 -0
  154. sage/graphs/genus.cpython-310-aarch64-linux-gnu.so +0 -0
  155. sage/graphs/genus.pyx +622 -0
  156. sage/graphs/graph.py +9645 -0
  157. sage/graphs/graph_coloring.cpython-310-aarch64-linux-gnu.so +0 -0
  158. sage/graphs/graph_coloring.pyx +2284 -0
  159. sage/graphs/graph_database.py +1177 -0
  160. sage/graphs/graph_decompositions/all.py +1 -0
  161. sage/graphs/graph_decompositions/bandwidth.cpython-310-aarch64-linux-gnu.so +0 -0
  162. sage/graphs/graph_decompositions/bandwidth.pyx +428 -0
  163. sage/graphs/graph_decompositions/clique_separators.cpython-310-aarch64-linux-gnu.so +0 -0
  164. sage/graphs/graph_decompositions/clique_separators.pyx +616 -0
  165. sage/graphs/graph_decompositions/cutwidth.cpython-310-aarch64-linux-gnu.so +0 -0
  166. sage/graphs/graph_decompositions/cutwidth.pyx +753 -0
  167. sage/graphs/graph_decompositions/fast_digraph.cpython-310-aarch64-linux-gnu.so +0 -0
  168. sage/graphs/graph_decompositions/fast_digraph.pxd +13 -0
  169. sage/graphs/graph_decompositions/fast_digraph.pyx +212 -0
  170. sage/graphs/graph_decompositions/graph_products.cpython-310-aarch64-linux-gnu.so +0 -0
  171. sage/graphs/graph_decompositions/graph_products.pyx +508 -0
  172. sage/graphs/graph_decompositions/modular_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  173. sage/graphs/graph_decompositions/modular_decomposition.pxd +27 -0
  174. sage/graphs/graph_decompositions/modular_decomposition.pyx +1536 -0
  175. sage/graphs/graph_decompositions/slice_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  176. sage/graphs/graph_decompositions/slice_decomposition.pxd +18 -0
  177. sage/graphs/graph_decompositions/slice_decomposition.pyx +1106 -0
  178. sage/graphs/graph_decompositions/tree_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  179. sage/graphs/graph_decompositions/tree_decomposition.pxd +17 -0
  180. sage/graphs/graph_decompositions/tree_decomposition.pyx +1996 -0
  181. sage/graphs/graph_decompositions/vertex_separation.cpython-310-aarch64-linux-gnu.so +0 -0
  182. sage/graphs/graph_decompositions/vertex_separation.pxd +5 -0
  183. sage/graphs/graph_decompositions/vertex_separation.pyx +1963 -0
  184. sage/graphs/graph_editor.py +82 -0
  185. sage/graphs/graph_generators.py +3314 -0
  186. sage/graphs/graph_generators_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  187. sage/graphs/graph_generators_pyx.pyx +95 -0
  188. sage/graphs/graph_input.py +812 -0
  189. sage/graphs/graph_latex.py +2064 -0
  190. sage/graphs/graph_list.py +410 -0
  191. sage/graphs/graph_plot.py +1756 -0
  192. sage/graphs/graph_plot_js.py +338 -0
  193. sage/graphs/hyperbolicity.cpython-310-aarch64-linux-gnu.so +0 -0
  194. sage/graphs/hyperbolicity.pyx +1704 -0
  195. sage/graphs/hypergraph_generators.py +364 -0
  196. sage/graphs/independent_sets.cpython-310-aarch64-linux-gnu.so +0 -0
  197. sage/graphs/independent_sets.pxd +13 -0
  198. sage/graphs/independent_sets.pyx +402 -0
  199. sage/graphs/isgci.py +1033 -0
  200. sage/graphs/isoperimetric_inequalities.cpython-310-aarch64-linux-gnu.so +0 -0
  201. sage/graphs/isoperimetric_inequalities.pyx +489 -0
  202. sage/graphs/line_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  203. sage/graphs/line_graph.pyx +743 -0
  204. sage/graphs/lovasz_theta.py +77 -0
  205. sage/graphs/matching.py +1633 -0
  206. sage/graphs/matching_covered_graph.py +3590 -0
  207. sage/graphs/orientations.py +1489 -0
  208. sage/graphs/partial_cube.py +459 -0
  209. sage/graphs/path_enumeration.cpython-310-aarch64-linux-gnu.so +0 -0
  210. sage/graphs/path_enumeration.pyx +2040 -0
  211. sage/graphs/pq_trees.py +1129 -0
  212. sage/graphs/print_graphs.py +201 -0
  213. sage/graphs/schnyder.py +865 -0
  214. sage/graphs/spanning_tree.cpython-310-aarch64-linux-gnu.so +0 -0
  215. sage/graphs/spanning_tree.pyx +1457 -0
  216. sage/graphs/strongly_regular_db.cpython-310-aarch64-linux-gnu.so +0 -0
  217. sage/graphs/strongly_regular_db.pyx +3340 -0
  218. sage/graphs/traversals.cpython-310-aarch64-linux-gnu.so +0 -0
  219. sage/graphs/traversals.pxd +9 -0
  220. sage/graphs/traversals.pyx +1872 -0
  221. sage/graphs/trees.cpython-310-aarch64-linux-gnu.so +0 -0
  222. sage/graphs/trees.pxd +15 -0
  223. sage/graphs/trees.pyx +310 -0
  224. sage/graphs/tutte_polynomial.py +713 -0
  225. sage/graphs/views.cpython-310-aarch64-linux-gnu.so +0 -0
  226. sage/graphs/views.pyx +794 -0
  227. sage/graphs/weakly_chordal.cpython-310-aarch64-linux-gnu.so +0 -0
  228. sage/graphs/weakly_chordal.pyx +604 -0
  229. sage/groups/all__sagemath_graphs.py +1 -0
  230. sage/groups/perm_gps/all__sagemath_graphs.py +1 -0
  231. sage/groups/perm_gps/partn_ref/all__sagemath_graphs.py +1 -0
  232. sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-310-aarch64-linux-gnu.so +0 -0
  233. sage/groups/perm_gps/partn_ref/refinement_graphs.pxd +38 -0
  234. sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +1666 -0
  235. sage/knots/all.py +6 -0
  236. sage/knots/free_knotinfo_monoid.py +507 -0
  237. sage/knots/gauss_code.py +291 -0
  238. sage/knots/knot.py +682 -0
  239. sage/knots/knot_table.py +284 -0
  240. sage/knots/knotinfo.py +2900 -0
  241. sage/knots/link.py +4715 -0
  242. sage/sandpiles/all.py +13 -0
  243. sage/sandpiles/examples.py +225 -0
  244. sage/sandpiles/sandpile.py +6365 -0
  245. sage/topology/all.py +22 -0
  246. sage/topology/cell_complex.py +1214 -0
  247. sage/topology/cubical_complex.py +1976 -0
  248. sage/topology/delta_complex.py +1806 -0
  249. sage/topology/filtered_simplicial_complex.py +744 -0
  250. sage/topology/moment_angle_complex.py +823 -0
  251. sage/topology/simplicial_complex.py +5160 -0
  252. sage/topology/simplicial_complex_catalog.py +92 -0
  253. sage/topology/simplicial_complex_examples.py +1680 -0
  254. sage/topology/simplicial_complex_homset.py +205 -0
  255. sage/topology/simplicial_complex_morphism.py +836 -0
  256. sage/topology/simplicial_set.py +4102 -0
  257. sage/topology/simplicial_set_catalog.py +55 -0
  258. sage/topology/simplicial_set_constructions.py +2954 -0
  259. sage/topology/simplicial_set_examples.py +865 -0
  260. sage/topology/simplicial_set_morphism.py +1464 -0
@@ -0,0 +1,812 @@
1
+ # sage_setup: distribution = sagemath-graphs
2
+ r"""
3
+ Functions for reading/building graphs/digraphs
4
+
5
+ This module gathers functions needed to build a graph from any other data.
6
+
7
+ .. NOTE::
8
+
9
+ This is an **internal** module of Sage. All features implemented here are
10
+ made available to end-users through the constructors of :class:`Graph` and
11
+ :class:`DiGraph`.
12
+
13
+ Note that because they are called by the constructors of :class:`Graph` and
14
+ :class:`DiGraph`, most of these functions modify a graph inplace.
15
+
16
+ {INDEX_OF_FUNCTIONS}
17
+
18
+ Functions
19
+ ---------
20
+ """
21
+ from sage.cpython.string import bytes_to_str
22
+ from sage.misc.rest_index_of_methods import gen_rest_table_index
23
+ import sys
24
+
25
+
26
+ def from_graph6(G, g6_string):
27
+ r"""
28
+ Fill ``G`` with the data of a graph6 string.
29
+
30
+ INPUT:
31
+
32
+ - ``G`` -- a graph
33
+
34
+ - ``g6_string`` -- a graph6 string
35
+
36
+ EXAMPLES::
37
+
38
+ sage: from sage.graphs.graph_input import from_graph6
39
+ sage: g = Graph()
40
+ sage: from_graph6(g, 'IheA@GUAo')
41
+ sage: g.is_isomorphic(graphs.PetersenGraph())
42
+ True
43
+ """
44
+ from .generic_graph_pyx import length_and_string_from_graph6, binary_string_from_graph6
45
+
46
+ if isinstance(g6_string, bytes):
47
+ g6_string = bytes_to_str(g6_string)
48
+ elif not isinstance(g6_string, str):
49
+ raise ValueError('if input format is graph6, then g6_string must be a string')
50
+ n = g6_string.find('\n')
51
+ if n == -1:
52
+ n = len(g6_string)
53
+ ss = g6_string[:n]
54
+ n, s = length_and_string_from_graph6(ss)
55
+ m = binary_string_from_graph6(s, n)
56
+ expected = n * (n - 1) // 2 + (6 - n * (n - 1) // 2) % 6
57
+ if len(m) > expected:
58
+ raise RuntimeError("the string (%s) seems corrupt: for n = %d, the string is too long" % (ss, n))
59
+ elif len(m) < expected:
60
+ raise RuntimeError("the string (%s) seems corrupt: for n = %d, the string is too short" % (ss, n))
61
+ G.add_vertices(range(n))
62
+ k = 0
63
+ for i in range(n):
64
+ for j in range(i):
65
+ if m[k] == '1':
66
+ G._backend.add_edge(i, j, None, False)
67
+ k += 1
68
+
69
+
70
+ def from_sparse6(G, g6_string):
71
+ r"""
72
+ Fill ``G`` with the data of a sparse6 string.
73
+
74
+ INPUT:
75
+
76
+ - ``G`` -- a graph
77
+
78
+ - ``g6_string`` -- a sparse6 string
79
+
80
+ EXAMPLES::
81
+
82
+ sage: from sage.graphs.graph_input import from_sparse6
83
+ sage: g = Graph()
84
+ sage: from_sparse6(g, ':I`ES@obGkqegW~')
85
+ sage: g.is_isomorphic(graphs.PetersenGraph())
86
+ True
87
+ """
88
+ from .generic_graph_pyx import length_and_string_from_graph6, int_to_binary_string
89
+
90
+ if isinstance(g6_string, bytes):
91
+ g6_string = bytes_to_str(g6_string)
92
+ elif not isinstance(g6_string, str):
93
+ raise ValueError('if input format is graph6, then g6_string must be a string')
94
+
95
+ n = g6_string.find('\n')
96
+ if n == -1:
97
+ n = len(g6_string)
98
+ s = g6_string[:n]
99
+ n, s = length_and_string_from_graph6(s[1:])
100
+ if not n:
101
+ edges = []
102
+ else:
103
+ from sage.rings.integer_ring import ZZ
104
+ k = int((ZZ(n) - 1).nbits())
105
+ ords = [ord(i) for i in s]
106
+ if any(o > 126 or o < 63 for o in ords):
107
+ raise RuntimeError("the string seems corrupt: valid characters are \n" + ''.join(chr(i) for i in range(63, 127)))
108
+ bits = ''.join(int_to_binary_string(o-63).zfill(6) for o in ords)
109
+ if not k:
110
+ b = [int(x) for x in bits]
111
+ x = [0] * len(b)
112
+ else:
113
+ b = []
114
+ x = []
115
+ for i in range(0, len(bits)-k, k+1):
116
+ b.append(int(bits[i:i+1], 2))
117
+ x.append(int(bits[i+1:i+k+1], 2))
118
+ v = 0
119
+ edges = []
120
+ for i in range(len(b)):
121
+ v += b[i] # +1 if b[i] == 1 else 0
122
+ if x[i] > v:
123
+ v = x[i]
124
+ else:
125
+ if v < n:
126
+ edges.append((x[i], v))
127
+ G.add_vertices(range(n))
128
+ G.add_edges(edges)
129
+
130
+
131
+ def from_dig6(G, dig6_string):
132
+ r"""
133
+ Fill ``G`` with the data of a dig6 string.
134
+
135
+ INPUT:
136
+
137
+ - ``G`` -- a graph
138
+
139
+ - ``dig6_string`` -- a dig6 string
140
+
141
+ EXAMPLES::
142
+
143
+ sage: from sage.graphs.graph_input import from_dig6
144
+ sage: g = DiGraph()
145
+ sage: from_dig6(g, digraphs.Circuit(10).dig6_string())
146
+ sage: g.is_isomorphic(digraphs.Circuit(10))
147
+ True
148
+
149
+ The string may represent a directed graph with loops::
150
+
151
+ sage: L = DiGraph(loops=True)
152
+ sage: from_dig6(L, 'CW`C')
153
+ sage: L.edges(labels=False, sort=True)
154
+ [(0, 1), (0, 2), (1, 2), (2, 3), (3, 3)]
155
+ """
156
+ from .generic_graph_pyx import length_and_string_from_graph6, binary_string_from_dig6
157
+ if isinstance(dig6_string, bytes):
158
+ dig6_string = bytes_to_str(dig6_string)
159
+ elif not isinstance(dig6_string, str):
160
+ raise ValueError('if input format is dig6, then dig6_string must be a string')
161
+ n = dig6_string.find('\n')
162
+ if n == -1:
163
+ n = len(dig6_string)
164
+ ss = dig6_string[:n]
165
+ n, s = length_and_string_from_graph6(ss)
166
+ m = binary_string_from_dig6(s, n)
167
+ expected = n**2
168
+ if len(m) > expected:
169
+ raise RuntimeError("the string (%s) seems corrupt: for n = %d, the string is too long" % (ss, n))
170
+ elif len(m) < expected:
171
+ raise RuntimeError("the string (%s) seems corrupt: for n = %d, the string is too short" % (ss, n))
172
+ G.add_vertices(range(n))
173
+ k = 0
174
+ for i in range(n):
175
+ for j in range(n):
176
+ if m[k] == '1':
177
+ G._backend.add_edge(i, j, None, True)
178
+ k += 1
179
+
180
+
181
+ def from_seidel_adjacency_matrix(G, M):
182
+ r"""
183
+ Fill ``G`` with the data of a Seidel adjacency matrix.
184
+
185
+ INPUT:
186
+
187
+ - ``G`` -- a graph
188
+
189
+ - ``M`` -- a Seidel adjacency matrix
190
+
191
+ EXAMPLES::
192
+
193
+ sage: from sage.graphs.graph_input import from_seidel_adjacency_matrix
194
+ sage: g = Graph()
195
+ sage: sam = graphs.PetersenGraph().seidel_adjacency_matrix() # needs sage.modules
196
+ sage: from_seidel_adjacency_matrix(g, sam) # needs sage.modules
197
+ sage: g.is_isomorphic(graphs.PetersenGraph()) # needs sage.modules
198
+ True
199
+ """
200
+ from sage.structure.element import Matrix
201
+ from sage.rings.integer_ring import ZZ
202
+ assert isinstance(M, Matrix)
203
+
204
+ if M.base_ring() != ZZ:
205
+ try:
206
+ M = M.change_ring(ZZ)
207
+ except TypeError:
208
+ raise ValueError("the adjacency matrix of a Seidel graph must" +
209
+ " have only 0,1,-1 integer entries")
210
+
211
+ if M.is_sparse():
212
+ entries = set(M[i, j] for i, j in M.nonzero_positions())
213
+ else:
214
+ entries = set(M.list())
215
+
216
+ if any(e < -1 or e > 1 for e in entries):
217
+ raise ValueError("the adjacency matrix of a Seidel graph must" +
218
+ " have only 0,1,-1 integer entries")
219
+ if any(i == j for i, j in M.nonzero_positions()):
220
+ raise ValueError("the adjacency matrix of a Seidel graph must" +
221
+ " have 0s on the main diagonal")
222
+ if not M.is_symmetric():
223
+ raise ValueError("the adjacency matrix of a Seidel graph must be symmetric")
224
+
225
+ G.add_vertices(range(M.nrows()))
226
+ G.add_edges((i, j) for i, j in M.nonzero_positions() if i <= j and M[i, j] < 0)
227
+
228
+
229
+ def from_adjacency_matrix(G, M, loops=False, multiedges=False, weighted=False):
230
+ r"""
231
+ Fill ``G`` with the data of an adjacency matrix.
232
+
233
+ INPUT:
234
+
235
+ - ``G`` -- a :class:`Graph` or :class:`DiGraph`
236
+
237
+ - ``M`` -- an adjacency matrix
238
+
239
+ - ``loops``, ``multiedges``, ``weighted`` -- booleans (default: ``False``);
240
+ whether to consider the graph as having loops, multiple edges, or weights
241
+
242
+ EXAMPLES::
243
+
244
+ sage: from sage.graphs.graph_input import from_adjacency_matrix
245
+ sage: g = Graph()
246
+ sage: from_adjacency_matrix(g, graphs.PetersenGraph().adjacency_matrix()) # needs sage.modules
247
+ sage: g.is_isomorphic(graphs.PetersenGraph()) # needs sage.modules
248
+ True
249
+ """
250
+ from sage.structure.element import Matrix
251
+ from sage.rings.integer_ring import ZZ
252
+ assert isinstance(M, Matrix)
253
+ # note: the adjacency matrix might be weighted and hence not
254
+ # necessarily consists of integers
255
+ if not weighted and M.base_ring() != ZZ:
256
+ try:
257
+ M = M.change_ring(ZZ)
258
+ except TypeError:
259
+ if weighted is False:
260
+ raise ValueError("the adjacency matrix of a non-weighted graph" +
261
+ " must have only nonnegative integer entries")
262
+ weighted = True
263
+
264
+ if M.is_sparse():
265
+ entries = set(M[i, j] for i, j in M.nonzero_positions())
266
+ else:
267
+ entries = set(M.list())
268
+
269
+ if not weighted and any(e < 0 for e in entries):
270
+ if weighted is False:
271
+ raise ValueError("the adjacency matrix of a non-weighted graph" +
272
+ " must have only nonnegative integer entries")
273
+ weighted = True
274
+ if multiedges is None:
275
+ multiedges = False
276
+ if weighted is None:
277
+ weighted = False
278
+
279
+ if multiedges is None:
280
+ multiedges = ((not weighted) and any(e != 0 and e != 1 for e in entries))
281
+
282
+ if not loops and any(M[i, i] for i in range(M.nrows())):
283
+ if loops is False:
284
+ raise ValueError("the adjacency matrix of a non-weighted graph" +
285
+ " must have zeroes on the diagonal")
286
+ loops = True
287
+ if loops is None:
288
+ loops = False
289
+ G.allow_loops(loops, check=False)
290
+ G.allow_multiple_edges(multiedges, check=False)
291
+ G.add_vertices(range(M.nrows()))
292
+ if G.is_directed():
293
+ pairs = M.nonzero_positions()
294
+ else:
295
+ pairs = ((i, j) for i, j in M.nonzero_positions() if i <= j)
296
+ if weighted:
297
+ G.add_edges((i, j, M[i][j]) for i, j in pairs)
298
+ elif multiedges:
299
+ G.add_edges((i, j) for i, j in pairs for _ in range(int(M[i][j])))
300
+ else:
301
+ G.add_edges((i, j) for i, j in pairs)
302
+ G._weighted = weighted
303
+
304
+
305
+ def from_incidence_matrix(G, M, loops=False, multiedges=False, weighted=False):
306
+ r"""
307
+ Fill ``G`` with the data of an incidence matrix.
308
+
309
+ INPUT:
310
+
311
+ - ``G`` -- a graph
312
+
313
+ - ``M`` -- an incidence matrix
314
+
315
+ - ``loops``, ``multiedges``, ``weighted`` -- booleans (default: ``False``);
316
+ whether to consider the graph as having loops, multiple edges, or weights
317
+
318
+ EXAMPLES::
319
+
320
+ sage: from sage.graphs.graph_input import from_incidence_matrix
321
+ sage: g = Graph()
322
+ sage: from_incidence_matrix(g, graphs.PetersenGraph().incidence_matrix()) # needs sage.modules
323
+ sage: g.is_isomorphic(graphs.PetersenGraph()) # needs sage.modules
324
+ True
325
+ """
326
+ from sage.structure.element import Matrix
327
+ assert isinstance(M, Matrix)
328
+
329
+ oriented = any(M[pos] < 0 for pos in M.nonzero_positions(copy=False))
330
+
331
+ positions = []
332
+ for i in range(M.ncols()):
333
+ NZ = M.nonzero_positions_in_column(i)
334
+ if len(NZ) == 1:
335
+ if oriented:
336
+ raise ValueError("column {} of the (oriented) incidence "
337
+ "matrix contains only one nonzero value".format(i))
338
+ elif M[NZ[0], i] != 2:
339
+ raise ValueError("each column of a non-oriented incidence "
340
+ "matrix must sum to 2, but column {} does not".format(i))
341
+ if loops is None:
342
+ loops = True
343
+ positions.append((NZ[0], NZ[0]))
344
+ elif (len(NZ) != 2 or
345
+ (oriented and not ((M[NZ[0], i] == +1 and M[NZ[1], i] == -1) or
346
+ (M[NZ[0], i] == -1 and M[NZ[1], i] == +1))) or
347
+ (not oriented and (M[NZ[0], i] != 1 or M[NZ[1], i] != 1))):
348
+ msg = "there must be one or two nonzero entries per column in an incidence matrix, "
349
+ msg += "got entries {} in column {}".format([M[j, i] for j in NZ], i)
350
+ raise ValueError(msg)
351
+ else:
352
+ positions.append(tuple(NZ))
353
+
354
+ if weighted is None:
355
+ G._weighted = False
356
+ if multiedges is None:
357
+ total = len(positions)
358
+ multiedges = len(set(positions)) < total
359
+ G.allow_loops(False if loops is None else loops, check=False)
360
+ G.allow_multiple_edges(multiedges, check=False)
361
+ G.add_vertices(range(M.nrows()))
362
+ G.add_edges(positions)
363
+
364
+
365
+ def from_oriented_incidence_matrix(G, M, loops=False, multiedges=False, weighted=False):
366
+ r"""
367
+ Fill ``G`` with the data of an *oriented* incidence matrix.
368
+
369
+ An oriented incidence matrix is the incidence matrix of a directed graph, in
370
+ which each non-loop edge corresponds to a `+1` and a `-1`, indicating its
371
+ source and destination.
372
+
373
+ INPUT:
374
+
375
+ - ``G`` -- a :class:`DiGraph`
376
+
377
+ - ``M`` -- an incidence matrix
378
+
379
+ - ``loops``, ``multiedges``, ``weighted`` -- booleans (default: ``False``);
380
+ whether to consider the graph as having loops, multiple edges, or weights
381
+
382
+ .. NOTE:: ``weighted`` is currently ignored.
383
+
384
+ EXAMPLES::
385
+
386
+ sage: from sage.graphs.graph_input import from_oriented_incidence_matrix
387
+ sage: g = DiGraph()
388
+ sage: im = digraphs.Circuit(10).incidence_matrix() # needs sage.modules
389
+ sage: from_oriented_incidence_matrix(g, im) # needs sage.modules
390
+ sage: g.is_isomorphic(digraphs.Circuit(10)) # needs sage.modules
391
+ True
392
+
393
+ TESTS:
394
+
395
+ Fix bug reported in :issue:`22985`::
396
+
397
+ sage: DiGraph(matrix ([[1,0,0,1],[0,0,1,1],[0,0,1,1]]).transpose()) # needs sage.modules
398
+ Traceback (most recent call last):
399
+ ...
400
+ ValueError: each column represents an edge: -1 goes to 1
401
+
402
+ Handle incidence matrix containing a column with only zeros (:issue:`29275`)::
403
+
404
+ sage: m = Matrix([[0,1],[0,-1],[0,0]]); m # needs sage.modules
405
+ [ 0 1]
406
+ [ 0 -1]
407
+ [ 0 0]
408
+ sage: G = DiGraph(m, format='incidence_matrix') # needs sage.modules
409
+ sage: list(G.edges(sort=True, labels=False)) # needs sage.modules
410
+ [(1, 0)]
411
+
412
+ Handle incidence matrix [[1],[-1]] (:issue:`29275`)::
413
+
414
+ sage: m = Matrix([[1],[-1]]); m # needs sage.modules
415
+ [ 1]
416
+ [-1]
417
+ sage: G = DiGraph(m, format='incidence_matrix') # needs sage.modules
418
+ sage: list(G.edges(sort=True, labels=False)) # needs sage.modules
419
+ [(1, 0)]
420
+ """
421
+ from sage.structure.element import Matrix
422
+ assert isinstance(M, Matrix)
423
+
424
+ positions = []
425
+ for c in M.columns():
426
+ NZ = c.nonzero_positions()
427
+ if not NZ:
428
+ continue
429
+ if len(NZ) != 2:
430
+ raise ValueError("there must be two nonzero entries (-1 & 1) per column")
431
+ L = sorted([c[i] for i in NZ])
432
+ if L != [-1, 1]:
433
+ raise ValueError("each column represents an edge: -1 goes to 1")
434
+ if c[NZ[0]] == -1:
435
+ positions.append(tuple(NZ))
436
+ else:
437
+ positions.append((NZ[1], NZ[0]))
438
+ if multiedges is None:
439
+ total = len(positions)
440
+ multiedges = len(set(positions)) < total
441
+ G.allow_loops(bool(loops), check=False)
442
+ G.allow_multiple_edges(multiedges, check=False)
443
+ G.add_vertices(range(M.nrows()))
444
+ G.add_edges(positions)
445
+
446
+
447
+ def from_dict_of_dicts(G, M, loops=False, multiedges=False, weighted=False, convert_empty_dict_labels_to_None=False):
448
+ r"""
449
+ Fill ``G`` with the data of a dictionary of dictionaries.
450
+
451
+ INPUT:
452
+
453
+ - ``G`` -- a graph
454
+
455
+ - ``M`` -- dictionary of dictionaries
456
+
457
+ - ``loops``, ``multiedges``, ``weighted`` -- booleans (default: ``False``);
458
+ whether to consider the graph as having loops, multiple edges, or weights
459
+
460
+ - ``convert_empty_dict_labels_to_None`` -- booleans (default: ``False``);
461
+ whether to adjust for empty dicts instead of ``None`` in NetworkX default
462
+ edge labels
463
+
464
+ EXAMPLES::
465
+
466
+ sage: from sage.graphs.graph_input import from_dict_of_dicts
467
+ sage: g = Graph()
468
+ sage: from_dict_of_dicts(g, graphs.PetersenGraph().to_dictionary(edge_labels=True))
469
+ sage: g.is_isomorphic(graphs.PetersenGraph())
470
+ True
471
+
472
+ The resulting order of vertices is unspecified but deterministic::
473
+
474
+ sage: from sage.graphs.graph_input import from_dict_of_dicts
475
+ sage: g = Graph()
476
+ sage: from_dict_of_dicts(g, {i: {} for i in range(99, 90, -1)})
477
+ sage: g.vertices(sort=False)
478
+ [99, 98, 97, 96, 95, 94, 93, 92, 91]
479
+
480
+ TESTS:
481
+
482
+ :issue:`32831` is fixed::
483
+
484
+ sage: DiGraph({0: {}, 1: {}, 2: {}, 3: {}, 4: {}})
485
+ Digraph on 5 vertices
486
+ """
487
+ if any(not isinstance(M[u], dict) for u in M):
488
+ raise ValueError("input dict must be a consistent format")
489
+
490
+ if not loops:
491
+ if any(u in neighb for u, neighb in M.items()):
492
+ if loops is False:
493
+ u = next(u for u, neighb in M.items() if u in neighb)
494
+ raise ValueError("the graph was built with loops=False but input M has a loop at {}".format(u))
495
+ loops = True
496
+ if loops is None:
497
+ loops = False
498
+ if weighted is None:
499
+ G._weighted = False
500
+ input_multiedges = multiedges
501
+ if multiedges is not False:
502
+ if not all(isinstance(M[u][v], list) for u in M for v in M[u]):
503
+ if multiedges:
504
+ raise ValueError("dict of dicts for multigraph must be in the format {v: {u: list}}")
505
+ multiedges = False
506
+ if multiedges is None and M:
507
+ multiedges = True
508
+
509
+ G.allow_loops(loops, check=False)
510
+ G.allow_multiple_edges(multiedges, check=False)
511
+ # Use keys of a dictionary instead of a set, to preserve insertion order
512
+ verts = dict(M)
513
+ for d in M.values():
514
+ verts.update(d)
515
+ G.add_vertices(verts.keys())
516
+ if convert_empty_dict_labels_to_None:
517
+ def relabel(x):
518
+ return x if x != {} else None
519
+ else:
520
+ def relabel(x):
521
+ return x
522
+
523
+ is_directed = G.is_directed()
524
+ if not is_directed and multiedges:
525
+ v_to_id = {v: i for i, v in enumerate(verts.keys())}
526
+ for u in M:
527
+ for v in M[u]:
528
+ if v_to_id[u] <= v_to_id[v] or v not in M or u not in M[v] or u == v:
529
+ for label in M[u][v]:
530
+ G._backend.add_edge(u, v, relabel(label), False)
531
+ elif multiedges:
532
+ for u in M:
533
+ for v in M[u]:
534
+ for label in M[u][v]:
535
+ G._backend.add_edge(u, v, relabel(label), is_directed)
536
+ else:
537
+ for u in M:
538
+ for v in M[u]:
539
+ G._backend.add_edge(u, v, relabel(M[u][v]), is_directed)
540
+ if not G.size() and input_multiedges is not True:
541
+ G.allow_multiple_edges(False, check=False)
542
+
543
+
544
+ def from_dict_of_lists(G, D, loops=False, multiedges=False, weighted=False):
545
+ r"""
546
+ Fill ``G`` with the data of a dictionary of lists.
547
+
548
+ INPUT:
549
+
550
+ - ``G`` -- a :class:`Graph` or :class:`DiGraph`
551
+
552
+ - ``D`` -- dictionary of lists
553
+
554
+ - ``loops``, ``multiedges``, ``weighted`` -- booleans (default: ``False``);
555
+ whether to consider the graph as having loops, multiple edges, or weights
556
+
557
+ EXAMPLES::
558
+
559
+ sage: from sage.graphs.graph_input import from_dict_of_lists
560
+ sage: g = Graph()
561
+ sage: from_dict_of_lists(g, graphs.PetersenGraph().to_dictionary())
562
+ sage: g.is_isomorphic(graphs.PetersenGraph())
563
+ True
564
+
565
+ The resulting order of vertices is unspecified but deterministic::
566
+
567
+ sage: from sage.graphs.graph_input import from_dict_of_lists
568
+ sage: g = Graph()
569
+ sage: from_dict_of_lists(g, {i: [] for i in range(99, 90, -1)})
570
+ sage: g.vertices(sort=False)
571
+ [99, 98, 97, 96, 95, 94, 93, 92, 91]
572
+ """
573
+ # Use keys of a dictionary instead of a set, to preserve insertion order
574
+ verts = dict(D)
575
+ verts.update({v: None for l in D.values() for v in l})
576
+ if not loops:
577
+ if any(u in neighb for u, neighb in D.items()):
578
+ if loops is False:
579
+ u = next(u for u, neighb in D.items() if u in neighb)
580
+ raise ValueError("the graph was built with loops=False but input D has a loop at {}".format(u))
581
+ loops = True
582
+ if loops is None:
583
+ loops = False
584
+ if weighted is None:
585
+ G._weighted = False
586
+ if not multiedges:
587
+ for u in D:
588
+ if len(set(D[u])) != len(D[u]):
589
+ if multiedges is False:
590
+ v = next(v for v in D[u] if D[u].count(v) > 1)
591
+ raise ValueError("non-multigraph got several edges (%s, %s)" % (u, v))
592
+ multiedges = True
593
+ break
594
+ if multiedges is None:
595
+ multiedges = False
596
+ G.allow_loops(loops, check=False)
597
+ G.allow_multiple_edges(multiedges, check=False)
598
+ G.add_vertices(verts.keys())
599
+
600
+ is_directed = G.is_directed()
601
+ if not is_directed and multiedges:
602
+ v_to_id = {v: i for i, v in enumerate(verts.keys())}
603
+ for u in D:
604
+ for v in D[u]:
605
+ if (v_to_id[u] <= v_to_id[v] or
606
+ v not in D or u not in D[v] or u == v):
607
+ G._backend.add_edge(u, v, None, False)
608
+ else:
609
+ for u in D:
610
+ for v in D[u]:
611
+ G._backend.add_edge(u, v, None, is_directed)
612
+
613
+
614
+ def from_networkx_graph(G, gnx, weighted=None, loops=None, multiedges=None,
615
+ convert_empty_dict_labels_to_None=None):
616
+ r"""
617
+ Fill `G` with the data of a NetworkX (di)graph.
618
+
619
+ INPUT:
620
+
621
+ - ``G`` -- a :class:`Graph` or :class:`DiGraph`
622
+
623
+ - ``gnx`` -- a NetworkX ``Graph``, ``MultiGraph``, ``DiGraph`` or
624
+ ``MultiDiGraph``
625
+
626
+ - ``weighted`` -- boolean (default: ``None``); whether graph thinks of
627
+ itself as weighted or not. See
628
+ :meth:`~sage.graphs.generic_graph.GenericGraph.weighted`.
629
+
630
+ - ``loops`` -- boolean (default: ``None``); whether to allow loops
631
+
632
+ - ``multiedges`` -- boolean (default: ``None``); whether to allow multiple
633
+ edges
634
+
635
+ - ``convert_empty_dict_labels_to_None`` -- boolean (default: ``None``);
636
+ whether to replace the default edge labels used by NetworkX (empty
637
+ dictionaries) by ``None``, the default Sage edge label. When set to
638
+ ``False``, empty dictionaries are not converted to ``None``.
639
+
640
+ EXAMPLES:
641
+
642
+ Feeding a :class:`Graph` with a NetworkX ``Graph``::
643
+
644
+ sage: # needs networkx
645
+ sage: from sage.graphs.graph_input import from_networkx_graph
646
+ sage: import networkx
647
+ sage: G = Graph()
648
+ sage: _ = gnx = networkx.Graph()
649
+ sage: _ = gnx.add_edge(0, 1)
650
+ sage: _ = gnx.add_edge(1, 2)
651
+ sage: from_networkx_graph(G, gnx)
652
+ sage: G.edges(sort=True, labels=False)
653
+ [(0, 1), (1, 2)]
654
+
655
+ Feeding a :class:`Graph` with a NetworkX ``MultiGraph``::
656
+
657
+ sage: # needs networkx
658
+ sage: G = Graph()
659
+ sage: gnx = networkx.MultiGraph()
660
+ sage: _ = gnx.add_edge(0, 1)
661
+ sage: _ = gnx.add_edge(0, 1)
662
+ sage: from_networkx_graph(G, gnx)
663
+ sage: G.edges(sort=True, labels=False)
664
+ [(0, 1), (0, 1)]
665
+ sage: G = Graph()
666
+ sage: from_networkx_graph(G, gnx, multiedges=False)
667
+ sage: G.edges(sort=True, labels=False)
668
+ [(0, 1)]
669
+
670
+ When feeding a :class:`Graph` `G` with a NetworkX ``DiGraph`` `D`, `G` has
671
+ one edge `(u, v)` whenever `D` has arc `(u, v)` or `(v, u)` or both::
672
+
673
+ sage: # needs networkx
674
+ sage: G = Graph()
675
+ sage: D = networkx.DiGraph()
676
+ sage: _ = D.add_edge(0, 1)
677
+ sage: from_networkx_graph(G, D)
678
+ sage: G.edges(sort=True, labels=False)
679
+ [(0, 1)]
680
+ sage: G = Graph()
681
+ sage: _ = D.add_edge(1, 0)
682
+ sage: from_networkx_graph(G, D)
683
+ sage: G.edges(sort=True, labels=False)
684
+ [(0, 1)]
685
+
686
+ When feeding a :class:`Graph` `G` with a NetworkX ``MultiDiGraph`` `D`, the
687
+ number of edges between `u` and `v` in `G` is the maximum between the number
688
+ of arcs `(u, v)` and the number of arcs `(v, u)` in D`::
689
+
690
+ sage: # needs networkx
691
+ sage: G = Graph()
692
+ sage: D = networkx.MultiDiGraph()
693
+ sage: _ = D.add_edge(0, 1)
694
+ sage: _ = D.add_edge(1, 0)
695
+ sage: _ = D.add_edge(1, 0)
696
+ sage: D.edges()
697
+ OutMultiEdgeDataView([(0, 1), (1, 0), (1, 0)])
698
+ sage: from_networkx_graph(G, D)
699
+ sage: G.edges(sort=True, labels=False)
700
+ [(0, 1), (0, 1)]
701
+
702
+ Feeding a :class:`DiGraph` with a NetworkX ``DiGraph``::
703
+
704
+ sage: # needs networkx
705
+ sage: from sage.graphs.graph_input import from_networkx_graph
706
+ sage: import networkx
707
+ sage: G = DiGraph()
708
+ sage: _ = gnx = networkx.DiGraph()
709
+ sage: _ = gnx.add_edge(0, 1)
710
+ sage: _ = gnx.add_edge(1, 2)
711
+ sage: from_networkx_graph(G, gnx)
712
+ sage: G.edges(sort=True, labels=False)
713
+ [(0, 1), (1, 2)]
714
+
715
+ Feeding a :class:`DiGraph` with a NetworkX ``MultiDiGraph``::
716
+
717
+ sage: # needs networkx
718
+ sage: G = DiGraph()
719
+ sage: gnx = networkx.MultiDiGraph()
720
+ sage: _ = gnx.add_edge(0, 1)
721
+ sage: _ = gnx.add_edge(0, 1)
722
+ sage: from_networkx_graph(G, gnx)
723
+ sage: G.edges(sort=True, labels=False)
724
+ [(0, 1), (0, 1)]
725
+ sage: G = DiGraph()
726
+ sage: from_networkx_graph(G, gnx, multiedges=False)
727
+ sage: G.edges(sort=True, labels=False)
728
+ [(0, 1)]
729
+
730
+ When feeding a :class:`DiGraph` `G` with a NetworkX ``Graph`` `H`, `G` has
731
+ both arcs `(u, v)` and `(v, u)` if `G` has edge `(u, v)`::
732
+
733
+ sage: # needs networkx
734
+ sage: G = DiGraph()
735
+ sage: H = networkx.Graph()
736
+ sage: _ = H.add_edge(0, 1)
737
+ sage: from_networkx_graph(G, H)
738
+ sage: G.edges(labels=False, sort=True)
739
+ [(0, 1), (1, 0)]
740
+
741
+ When feeding a :class:`DiGraph` `G` with a NetworkX ``MultiGraph`` `H`, `G`
742
+ has `k` arcs `(u, v)` and `k` arcs `(v, u)` if `H` has `k` edges `(u, v)`,
743
+ unless parameter ``multiedges`` is set to ``False``::
744
+
745
+ sage: # needs networkx
746
+ sage: G = DiGraph()
747
+ sage: H = networkx.MultiGraph()
748
+ sage: _ = H.add_edge(0, 1)
749
+ sage: _ = H.add_edge(0, 1)
750
+ sage: _ = H.add_edge(0, 1)
751
+ sage: H.edges()
752
+ MultiEdgeDataView([(0, 1), (0, 1), (0, 1)])
753
+ sage: from_networkx_graph(G, H)
754
+ sage: G.edges(labels=False, sort=True)
755
+ [(0, 1), (0, 1), (0, 1), (1, 0), (1, 0), (1, 0)]
756
+ sage: G = DiGraph()
757
+ sage: from_networkx_graph(G, H, multiedges=False)
758
+ sage: G.edges(labels=False, sort=True)
759
+ [(0, 1), (1, 0)]
760
+
761
+ TESTS:
762
+
763
+ The first parameter must be a :class:`Graph` or :class:`DiGraph`::
764
+
765
+ sage: from sage.graphs.graph_input import from_networkx_graph
766
+ sage: from_networkx_graph("foo", "bar")
767
+ Traceback (most recent call last):
768
+ ...
769
+ ValueError: the first parameter must a Sage Graph or DiGraph
770
+
771
+ The second parameter must be a NetworkX ``Graph``, ``MultiGraph``,
772
+ ``DiGraph`` or ``MultiDiGraph``::
773
+
774
+ sage: from sage.graphs.graph_input import from_networkx_graph
775
+ sage: from_networkx_graph(Graph(), "bar") # needs networkx
776
+ Traceback (most recent call last):
777
+ ...
778
+ ValueError: the second parameter must be a NetworkX (Multi)(Di)Graph
779
+ """
780
+ from sage.graphs.graph import Graph
781
+ from sage.graphs.digraph import DiGraph
782
+ if not isinstance(G, (Graph, DiGraph)):
783
+ raise ValueError("the first parameter must a Sage Graph or DiGraph")
784
+ import networkx
785
+ if not isinstance(gnx, (networkx.Graph, networkx.DiGraph)):
786
+ raise ValueError("the second parameter must be a NetworkX (Multi)(Di)Graph")
787
+
788
+ if G.is_directed() != gnx.is_directed():
789
+ if gnx.is_directed():
790
+ gnx = gnx.to_undirected()
791
+ else:
792
+ gnx = gnx.to_directed()
793
+
794
+ if weighted is None:
795
+ if multiedges is None:
796
+ multiedges = gnx.is_multigraph()
797
+ if loops is None:
798
+ loops = any(u == v for u, v in gnx.edges())
799
+
800
+ G.allow_loops(loops, check=False)
801
+ G.allow_multiple_edges(multiedges, check=False)
802
+ G.add_vertices(gnx.nodes())
803
+ G.set_vertices(gnx.nodes(data=True))
804
+ if convert_empty_dict_labels_to_None is not False:
805
+ def r(label):
806
+ return None if label == {} else label
807
+ G.add_edges((u, v, r(ll)) for u, v, ll in gnx.edges(data=True))
808
+ else:
809
+ G.add_edges(gnx.edges(data=True))
810
+
811
+
812
+ __doc__ = __doc__.format(INDEX_OF_FUNCTIONS=gen_rest_table_index(sys.modules[__name__]))