passagemath-graphs 10.5.10__cp39-cp39-macosx_14_0_arm64.whl → 10.5.43__cp39-cp39-macosx_14_0_arm64.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 (140) hide show
  1. {passagemath_graphs-10.5.10.dist-info → passagemath_graphs-10.5.43.dist-info}/METADATA +126 -30
  2. passagemath_graphs-10.5.43.dist-info/RECORD +256 -0
  3. {passagemath_graphs-10.5.10.dist-info → passagemath_graphs-10.5.43.dist-info}/WHEEL +2 -1
  4. passagemath_graphs.dylibs/libgmp.10.dylib +0 -0
  5. sage/all__sagemath_graphs.py +5 -0
  6. sage/combinat/abstract_tree.py +1 -1
  7. sage/combinat/binary_tree.py +1 -1
  8. sage/combinat/cluster_algebra_quiver/all.py +1 -1
  9. sage/combinat/cluster_algebra_quiver/cluster_seed.py +28 -24
  10. sage/combinat/cluster_algebra_quiver/interact.py +4 -0
  11. sage/combinat/designs/MOLS_handbook_data.py +5 -5
  12. sage/combinat/designs/bibd.py +10 -9
  13. sage/combinat/designs/covering_array.py +3 -3
  14. sage/combinat/designs/covering_design.py +2 -1
  15. sage/combinat/designs/database.py +11 -10
  16. sage/combinat/designs/designs_pyx.cpython-39-darwin.so +0 -0
  17. sage/combinat/designs/designs_pyx.pyx +13 -45
  18. sage/combinat/designs/difference_family.py +6 -6
  19. sage/combinat/designs/difference_matrices.py +1 -1
  20. sage/combinat/designs/evenly_distributed_sets.cpython-39-darwin.so +0 -0
  21. sage/combinat/designs/evenly_distributed_sets.pyx +15 -22
  22. sage/combinat/designs/ext_rep.py +9 -14
  23. sage/combinat/designs/gen_quadrangles_with_spread.cpython-39-darwin.so +0 -0
  24. sage/combinat/designs/gen_quadrangles_with_spread.pyx +1 -1
  25. sage/combinat/designs/group_divisible_designs.py +1 -1
  26. sage/combinat/designs/incidence_structures.py +8 -8
  27. sage/combinat/designs/latin_squares.py +1 -1
  28. sage/combinat/designs/orthogonal_arrays_build_recursive.py +8 -7
  29. sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-39-darwin.so +0 -0
  30. sage/combinat/designs/resolvable_bibd.py +1 -1
  31. sage/combinat/designs/steiner_quadruple_systems.py +1 -1
  32. sage/combinat/designs/subhypergraph_search.cpython-39-darwin.so +0 -0
  33. sage/combinat/designs/subhypergraph_search.pyx +9 -9
  34. sage/combinat/finite_state_machine_generators.py +2 -2
  35. sage/combinat/graph_path.py +3 -3
  36. sage/combinat/interval_posets.py +10 -10
  37. sage/combinat/ordered_tree.py +1 -1
  38. sage/combinat/posets/cartesian_product.py +1 -1
  39. sage/combinat/posets/d_complete.py +1 -1
  40. sage/combinat/posets/forest.py +1 -1
  41. sage/combinat/posets/hasse_cython.cpython-39-darwin.so +0 -0
  42. sage/combinat/posets/hasse_diagram.py +8 -6
  43. sage/combinat/posets/incidence_algebras.py +8 -8
  44. sage/combinat/posets/lattices.py +28 -4
  45. sage/combinat/posets/linear_extension_iterator.cpython-39-darwin.so +0 -0
  46. sage/combinat/posets/linear_extension_iterator.pyx +2 -0
  47. sage/combinat/posets/linear_extensions.py +7 -16
  48. sage/combinat/posets/moebius_algebra.py +1 -1
  49. sage/combinat/posets/poset_examples.py +1 -1
  50. sage/combinat/posets/posets.py +54 -56
  51. sage/combinat/rooted_tree.py +3 -3
  52. sage/combinat/tamari_lattices.py +1 -1
  53. sage/ext_data/kenzo/CP2.txt +45 -0
  54. sage/ext_data/kenzo/CP3.txt +349 -0
  55. sage/ext_data/kenzo/CP4.txt +4774 -0
  56. sage/ext_data/kenzo/README.txt +49 -0
  57. sage/ext_data/kenzo/S4.txt +20 -0
  58. sage/graphs/asteroidal_triples.cpython-39-darwin.so +0 -0
  59. sage/graphs/base/boost_graph.cpython-39-darwin.so +0 -0
  60. sage/graphs/base/boost_graph.pxd +1 -1
  61. sage/graphs/base/boost_graph.pyx +1 -1
  62. sage/graphs/base/c_graph.cpython-39-darwin.so +0 -0
  63. sage/graphs/base/c_graph.pxd +4 -4
  64. sage/graphs/base/c_graph.pyx +270 -184
  65. sage/graphs/base/dense_graph.cpython-39-darwin.so +0 -0
  66. sage/graphs/base/graph_backends.cpython-39-darwin.so +0 -0
  67. sage/graphs/base/sparse_graph.cpython-39-darwin.so +0 -0
  68. sage/graphs/base/static_dense_graph.cpython-39-darwin.so +0 -0
  69. sage/graphs/base/static_sparse_backend.cpython-39-darwin.so +0 -0
  70. sage/graphs/base/static_sparse_backend.pyx +93 -6
  71. sage/graphs/base/static_sparse_graph.cpython-39-darwin.so +0 -0
  72. sage/graphs/base/static_sparse_graph.pyx +1 -1
  73. sage/graphs/bipartite_graph.py +0 -1
  74. sage/graphs/centrality.cpython-39-darwin.so +0 -0
  75. sage/graphs/centrality.pyx +0 -0
  76. sage/graphs/comparability.cpython-39-darwin.so +0 -0
  77. sage/graphs/comparability.pyx +172 -138
  78. sage/graphs/connectivity.cpython-39-darwin.so +0 -0
  79. sage/graphs/connectivity.pyx +194 -18
  80. sage/graphs/convexity_properties.cpython-39-darwin.so +0 -0
  81. sage/graphs/digraph_generators.py +118 -74
  82. sage/graphs/distances_all_pairs.cpython-39-darwin.so +0 -0
  83. sage/graphs/distances_all_pairs.pyx +145 -27
  84. sage/graphs/edge_connectivity.cpython-39-darwin.so +0 -0
  85. sage/graphs/generators/basic.py +471 -130
  86. sage/graphs/generators/distance_regular.cpython-39-darwin.so +0 -0
  87. sage/graphs/generators/distance_regular.pyx +12 -12
  88. sage/graphs/generators/families.py +2 -2
  89. sage/graphs/generators/random.py +8 -13
  90. sage/graphs/generators/smallgraphs.py +12 -11
  91. sage/graphs/generic_graph.py +687 -265
  92. sage/graphs/generic_graph_pyx.cpython-39-darwin.so +0 -0
  93. sage/graphs/genus.cpython-39-darwin.so +0 -0
  94. sage/graphs/graph.py +12 -46
  95. sage/graphs/graph_coloring.cpython-39-darwin.so +0 -0
  96. sage/graphs/graph_database.py +1 -1
  97. sage/graphs/graph_decompositions/bandwidth.cpython-39-darwin.so +0 -0
  98. sage/graphs/graph_decompositions/clique_separators.cpython-39-darwin.so +0 -0
  99. sage/graphs/graph_decompositions/cutwidth.cpython-39-darwin.so +0 -0
  100. sage/graphs/graph_decompositions/fast_digraph.cpython-39-darwin.so +0 -0
  101. sage/graphs/graph_decompositions/graph_products.cpython-39-darwin.so +0 -0
  102. sage/graphs/graph_decompositions/modular_decomposition.cpython-39-darwin.so +0 -0
  103. sage/graphs/graph_decompositions/slice_decomposition.cpython-39-darwin.so +0 -0
  104. sage/graphs/graph_decompositions/tree_decomposition.cpython-39-darwin.so +0 -0
  105. sage/graphs/graph_decompositions/vertex_separation.cpython-39-darwin.so +0 -0
  106. sage/graphs/graph_generators.py +110 -55
  107. sage/graphs/graph_generators_pyx.cpython-39-darwin.so +0 -0
  108. sage/graphs/graph_latex.py +1 -1
  109. sage/graphs/graph_list.py +2 -3
  110. sage/graphs/graph_plot.py +225 -30
  111. sage/graphs/hyperbolicity.cpython-39-darwin.so +0 -0
  112. sage/graphs/independent_sets.cpython-39-darwin.so +0 -0
  113. sage/graphs/isgci.py +3 -8
  114. sage/graphs/isoperimetric_inequalities.cpython-39-darwin.so +0 -0
  115. sage/graphs/line_graph.cpython-39-darwin.so +0 -0
  116. sage/graphs/matching.py +14 -25
  117. sage/graphs/matching_covered_graph.py +871 -60
  118. sage/graphs/orientations.py +190 -134
  119. sage/graphs/path_enumeration.cpython-39-darwin.so +0 -0
  120. sage/graphs/path_enumeration.pyx +25 -25
  121. sage/graphs/spanning_tree.cpython-39-darwin.so +0 -0
  122. sage/graphs/strongly_regular_db.cpython-39-darwin.so +0 -0
  123. sage/graphs/strongly_regular_db.pyx +54 -52
  124. sage/graphs/traversals.cpython-39-darwin.so +0 -0
  125. sage/graphs/traversals.pyx +114 -46
  126. sage/graphs/trees.cpython-39-darwin.so +0 -0
  127. sage/graphs/views.cpython-39-darwin.so +0 -0
  128. sage/graphs/weakly_chordal.cpython-39-darwin.so +0 -0
  129. sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-39-darwin.so +0 -0
  130. sage/knots/free_knotinfo_monoid.py +2 -3
  131. sage/knots/knot.py +1 -1
  132. sage/knots/knotinfo.py +4 -4
  133. sage/knots/link.py +58 -57
  134. sage/sandpiles/sandpile.py +2 -3
  135. sage/topology/cell_complex.py +1 -1
  136. sage/topology/cubical_complex.py +7 -7
  137. sage/topology/delta_complex.py +4 -4
  138. sage/topology/simplicial_complex.py +7 -22
  139. passagemath_graphs-10.5.10.dist-info/RECORD +0 -251
  140. {passagemath_graphs-10.5.10.dist-info → passagemath_graphs-10.5.43.dist-info}/top_level.txt +0 -0
@@ -71,6 +71,7 @@ AUTHORS:
71
71
  ``lexicographic_product()`` | Return the lexicographic product of ``self`` and ``other``.
72
72
  ``load_afile()`` | Load the matching covered graph specified in the given file into the current object.
73
73
  ``merge_vertices()`` | Merge vertices.
74
+ ``minor()`` | Return the vertices of a minor isomorphic to `H` in the current graph.
74
75
  ``random_subgraph()`` | Return a random matching covered subgraph containing each vertex with probability ``p``.
75
76
  ``save_afile()`` | Save the graph to file in alist format.
76
77
  ``strong_product()`` | Return the strong product of ``self`` and ``other``.
@@ -82,6 +83,7 @@ AUTHORS:
82
83
  ``subgraph_search_iterator()`` | Return an iterator over the labelled copies of (matching covered) ``G`` in ``self``.
83
84
  ``tensor_product()`` | Return the tensor product of ``self`` and ``other``.
84
85
  ``to_undirected()`` | Return an undirected Graph instance of the matching covered graph.
86
+ ``topological_minor()`` | Return a topological `H`-minor from ``self`` if one exists.
85
87
  ``transitive_closure()`` | Return the transitive closure of the matching covered graph.
86
88
  ``transitive_reduction()`` | Return a transitive reduction of the matching covered graph.
87
89
  ``union()`` | Return the union of ``self`` and ``other``.
@@ -94,12 +96,10 @@ AUTHORS:
94
96
  :delim: |
95
97
 
96
98
  ``bricks_and_braces()`` | Return the list of (underlying simple graph of) the bricks and braces of the (matching covered) graph.
97
- ``is_brace()`` | Check if the (matching covered) graph is a brace.
98
- ``is_brick()`` | Check if the (matching covered) graph is a brick.
99
99
  ``number_of_braces()`` | Return the number of braces.
100
100
  ``number_of_bricks()`` | Return the number of bricks.
101
101
  ``number_of_petersen_bricks()`` | Return the number of Petersen bricks.
102
- ``tight_cut_decomposition()`` | Return a tight cut decomposition.
102
+ ``tight_cut_decomposition()`` | Return a maximal set of laminar nontrivial tight cuts and a corresponding vertex set partition.
103
103
 
104
104
  **Removability and ear decomposition**
105
105
 
@@ -1618,13 +1618,13 @@ class MatchingCoveredGraph(Graph):
1618
1618
 
1619
1619
  .. SEEALSO::
1620
1620
 
1621
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`,
1622
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`,
1623
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`,
1624
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`,
1625
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`,
1626
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`,
1627
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops`
1621
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`
1622
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`
1623
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`
1624
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`
1625
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`
1626
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`
1627
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops`
1628
1628
  """
1629
1629
  if new:
1630
1630
  raise ValueError('loops are not allowed in '
@@ -1659,13 +1659,13 @@ class MatchingCoveredGraph(Graph):
1659
1659
 
1660
1660
  .. SEEALSO::
1661
1661
 
1662
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`,
1663
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`,
1664
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`,
1665
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`,
1666
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`,
1667
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`,
1668
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops`
1662
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`
1663
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`
1664
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`
1665
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`
1666
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`
1667
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`
1668
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops`
1669
1669
  """
1670
1670
  return False
1671
1671
 
@@ -2059,8 +2059,7 @@ class MatchingCoveredGraph(Graph):
2059
2059
 
2060
2060
  sage: J = G.copy()
2061
2061
  sage: J.delete_vertices(B)
2062
- sage: all(len(K)%2 != 0 for K in J.connected_components())
2063
- ...
2062
+ sage: all(len(K)%2 != 0 for K in J.connected_components(sort=True))
2064
2063
  True
2065
2064
 
2066
2065
  Let `B` be a maximal barrier in a matching covered graph `G` and let
@@ -2069,7 +2068,7 @@ class MatchingCoveredGraph(Graph):
2069
2068
  `v` is the end of that edge in `V(K)`, then `M \cap E(K)` is a perfect
2070
2069
  matching of `K - v`::
2071
2070
 
2072
- sage: K = J.subgraph(vertices=(J.connected_components())[0])
2071
+ sage: K = J.subgraph(vertices=(J.connected_components(sort=True))[0])
2073
2072
  sage: # Let F := \partial_G(K) and T := M \cap F
2074
2073
  sage: F = [edge for edge in G.edge_iterator()
2075
2074
  ....: if (edge[0] in K and edge[1] not in K)
@@ -2093,7 +2092,7 @@ class MatchingCoveredGraph(Graph):
2093
2092
  `G - B` is factor critical::
2094
2093
 
2095
2094
  sage: all((K.subgraph(vertices=connected_component)).is_factor_critical()
2096
- ....: for connected_component in K.connected_components()
2095
+ ....: for connected_component in K.connected_components(sort=True)
2097
2096
  ....: )
2098
2097
  True
2099
2098
 
@@ -2253,13 +2252,13 @@ class MatchingCoveredGraph(Graph):
2253
2252
 
2254
2253
  .. SEEALSO::
2255
2254
 
2256
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`,
2257
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`,
2258
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`,
2259
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`,
2260
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`,
2261
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`,
2262
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops`
2255
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`
2256
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`
2257
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`
2258
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`
2259
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`
2260
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`
2261
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops`
2263
2262
  """
2264
2263
  return False
2265
2264
 
@@ -2348,6 +2347,820 @@ class MatchingCoveredGraph(Graph):
2348
2347
  raise ValueError('algorithm must be set to \'Edmonds\', '
2349
2348
  '\'LP_matching\' or \'LP\'')
2350
2349
 
2350
+ @doc_index('Bricks, braces and tight cut decomposition')
2351
+ def is_brace(self, coNP_certificate=False):
2352
+ r"""
2353
+ Check if the (matching covered) graph is a brace.
2354
+
2355
+ A matching covered graph which is free of nontrivial tight cuts is
2356
+ called a *brace* if it is bipartite. Let `G := (A \cup B, E)` be a
2357
+ bipartite matching covered graph on six or more vertices. The
2358
+ following statements are equivalent [LM2024]_:
2359
+
2360
+ 1. `G` is a brace (aka free of nontrivial tight cuts).
2361
+ 2. `G - a_1 - a_2 - b_1 - b_2` has a perfect matching for any two
2362
+ distinct vertices `a_1` and `a_2` in `A` and any two distinct
2363
+ vertices `b_1` and `b_2` in `B`.
2364
+ 3. `G` is two extendable (any two nonadjacent distinct edges can be
2365
+ extended to some perfect matching of `G`).
2366
+ 4. `|N(X)| \geq |X| + 2`, for all `X ⊂ A` such that `0 < |X| <
2367
+ |A| - 1`, where `N(S) := \{b \mid (a, b) \in E ∧ a \in S\}` is called
2368
+ the neighboring set of `S`.
2369
+ 5. `G - a - b` is matching covered, for some perfect matching `M` of
2370
+ `G` and for each edge `ab` in `M`.
2371
+
2372
+ We shall be using the 5th characterization mentioned above in order
2373
+ to determine whether the provided bipartite matching covered graph
2374
+ is a brace or not using *M*-alternating tree search [LZ2001]_.
2375
+
2376
+ INPUT:
2377
+
2378
+ - ``coNP_certificate`` -- boolean (default: ``False``)
2379
+
2380
+ OUTPUT:
2381
+
2382
+ - If the input matching covered graph is not bipartite, a
2383
+ :exc:`ValueError` is returned.
2384
+
2385
+ - If the input bipartite matching covered graph is a brace, a boolean
2386
+ ``True`` is returned if ``coNP_certificate`` is set to ``False``
2387
+ otherwise a 5-tuple ``(True, None, None, None, None)`` is returned.
2388
+
2389
+ - If the input bipartite matching covered graph is not a brace, a
2390
+ boolean ``False`` is returned if ``coNP_certificate`` is set to
2391
+ ``False`` otherwise a 5-tuple of
2392
+
2393
+ 1. a boolean ``False``,
2394
+
2395
+ 2. a list of edges constituting a nontrivial tight cut (which is a
2396
+ nontrivial barrier cut)
2397
+
2398
+ 3. a set of vertices of one of the shores of the nontrivial tight cut
2399
+
2400
+ 4. a string 'nontrivial tight cut'
2401
+
2402
+ 5. a set of vertices showing the respective barrier
2403
+
2404
+ is returned.
2405
+
2406
+ EXAMPLES:
2407
+
2408
+ The complete graph on two vertices `K_2` is the smallest brace::
2409
+
2410
+ sage: K = graphs.CompleteGraph(2)
2411
+ sage: G = MatchingCoveredGraph(K)
2412
+ sage: G.is_brace()
2413
+ True
2414
+
2415
+ The cycle graph on four vertices `C_4` is a brace::
2416
+
2417
+ sage: C = graphs.CycleGraph(4)
2418
+ sage: G = MatchingCoveredGraph(C)
2419
+ sage: G.is_brace()
2420
+ True
2421
+
2422
+ Each graph that is isomorphic to a biwheel is a brace::
2423
+
2424
+ sage: B = graphs.BiwheelGraph(15)
2425
+ sage: G = MatchingCoveredGraph(B)
2426
+ sage: G.is_brace()
2427
+ True
2428
+
2429
+ A circular ladder graph of order eight or more on `2n` vertices for
2430
+ an even `n` is a brace::
2431
+
2432
+ sage: n = 10
2433
+ sage: CL = graphs.CircularLadderGraph(n)
2434
+ sage: G = MatchingCoveredGraph(CL)
2435
+ sage: G.is_brace()
2436
+ True
2437
+
2438
+ A moebius ladder graph of order six or more on `2n` vertices for an odd
2439
+ `n` is a brace::
2440
+
2441
+ sage: n = 11
2442
+ sage: ML = graphs.MoebiusLadderGraph(n)
2443
+ sage: G = MatchingCoveredGraph(ML)
2444
+ sage: G.is_brace()
2445
+ True
2446
+
2447
+ Note that the union of the above mentioned four families of braces,
2448
+ that are:
2449
+
2450
+ 1. the biwheel graph ``BiwheelGraph(n)``,
2451
+ 2. the circular ladder graph ``CircularLadderGraph(n)`` for even ``n``,
2452
+ 3. the moebius ladder graph ``MoebiusLadderGraph(n)`` for odd ``n``,
2453
+
2454
+ is referred to as the *McCuaig* *family* *of* *braces.*
2455
+
2456
+ The only simple brace of order six is the complete graph of the same
2457
+ order, that is `K_{3, 3}`::
2458
+
2459
+ sage: L = list(graphs(6,
2460
+ ....: lambda G: G.size() <= 15 and
2461
+ ....: G.is_bipartite())
2462
+ ....: )
2463
+ sage: L = list(G for G in L if G.is_connected() and
2464
+ ....: G.is_matching_covered()
2465
+ ....: )
2466
+ sage: M = list(MatchingCoveredGraph(G) for G in L)
2467
+ sage: B = list(G for G in M if G.is_brace())
2468
+ sage: K = graphs.CompleteBipartiteGraph(3, 3)
2469
+ sage: G = MatchingCoveredGraph(K)
2470
+ sage: next(iter(B)).is_isomorphic(G)
2471
+ True
2472
+
2473
+ The nonplanar `K_{3, 3}`-free brace Heawood graph is the unique cubic
2474
+ graph of girth six with the fewest number of vertices (that is 14).
2475
+ Note that by `K_{3, 3}`-free, it shows that the Heawood graph does not
2476
+ contain a subgraph that is isomophic to a graph obtained by
2477
+ bisubdivision of `K_{3, 3}`::
2478
+
2479
+ sage: K = graphs.CompleteBipartiteGraph(3, 3)
2480
+ sage: J = graphs.HeawoodGraph()
2481
+ sage: H = MatchingCoveredGraph(J)
2482
+ sage: H.is_brace() and not H.is_planar() and \
2483
+ ....: H.is_regular(k=3) and H.girth() == 6
2484
+ True
2485
+
2486
+ Braces of order six or more are 3-connected::
2487
+
2488
+ sage: H = graphs.HexahedralGraph()
2489
+ sage: G = MatchingCoveredGraph(H)
2490
+ sage: G.is_brace() and G.is_triconnected()
2491
+ True
2492
+
2493
+ Braces of order four or more are 2-extendable::
2494
+
2495
+ sage: H = graphs.EllinghamHorton54Graph()
2496
+ sage: G = MatchingCoveredGraph(H)
2497
+ sage: G.is_brace()
2498
+ True
2499
+ sage: e = next(G.edge_iterator(labels=False)); f = None
2500
+ sage: for f in G.edge_iterator(labels=False):
2501
+ ....: if not (set(e) & set(f)):
2502
+ ....: break
2503
+ sage: S = [u for x in [e, f] for u in set(x)]
2504
+ sage: J = H.copy(); J.delete_vertices(S)
2505
+ sage: M = Graph(J.matching())
2506
+ sage: M.add_edges([e, f])
2507
+ sage: if all(d == 1 for d in M.degree()) and \
2508
+ ....: G.order() == M.order() and \
2509
+ ....: G.order() == 2*M.size():
2510
+ ....: print(f'graph {G} is 2-extendable')
2511
+ graph Ellingham-Horton 54-graph is 2-extendable
2512
+
2513
+ Every edge in a brace of order at least six is removable::
2514
+
2515
+ sage: H = graphs.CircularLadderGraph(8)
2516
+ sage: G = MatchingCoveredGraph(H)
2517
+ sage: # len(G.removble_edges()) == G.size()
2518
+ # True
2519
+
2520
+ Every brace of order eight has the hexahedral graph as a spanning
2521
+ subgraph::
2522
+
2523
+ sage: H = graphs.HexahedralGraph()
2524
+ sage: L = list(graphs(8,
2525
+ ....: lambda G: G.size() <= 28 and
2526
+ ....: G.is_bipartite())
2527
+ ....: )
2528
+ sage: L = list(G for G in L if G.is_connected() and
2529
+ ....: G.is_matching_covered()
2530
+ ....: )
2531
+ sage: M = list(MatchingCoveredGraph(G) for G in L)
2532
+ sage: B = list(G for G in M if G.is_brace())
2533
+ sage: C = list(G for G in M if Graph(G).subgraph_search(H) is not None)
2534
+ sage: B == C
2535
+ True
2536
+
2537
+ For every brace `G[A, B]` of order at least six, the graph
2538
+ `G - a_1 - a_2 - b_1 - b_2` has a perfect matching for any two distinct
2539
+ vertices `a_1` and `a_2` in `A` and any two distinct vertices `b_1` and
2540
+ `b_2` in `B`::
2541
+
2542
+ sage: H = graphs.CompleteBipartiteGraph(10, 10)
2543
+ sage: G = MatchingCoveredGraph(H)
2544
+ sage: G.is_brace()
2545
+ True
2546
+ sage: S = [0, 1, 10, 12]
2547
+ sage: G.delete_vertices(S)
2548
+ sage: G.has_perfect_matching()
2549
+ True
2550
+
2551
+ For a brace `G[A, B]` of order six or more, `|N(X)| \geq |X| + 2`, for
2552
+ all `X \subset A` such that `0 < |X| <|A| - 1`, where
2553
+ `N(S) := \{b | (a, b) \in E \^ a \in S\}` is called the neighboring set
2554
+ of `S`::
2555
+
2556
+ sage: H = graphs.MoebiusLadderGraph(15)
2557
+ sage: G = MatchingCoveredGraph(H)
2558
+ sage: G.is_brace()
2559
+ True
2560
+ sage: A, _ = G.bipartite_sets()
2561
+ sage: # needs random
2562
+ sage: X = random.sample(list(A), random.randint(1, len(A) - 1))
2563
+ sage: N = {v for u in X for v in G.neighbor_iterator(u)}
2564
+ sage: len(N) >= len(X) + 2
2565
+ True
2566
+
2567
+ For a brace `G` of order four or more with a perfect matching `M`, the
2568
+ graph `G - a - b` is matching covered for each edge `(a, b)` in `M`::
2569
+
2570
+ sage: H = graphs.HeawoodGraph()
2571
+ sage: G = MatchingCoveredGraph(H)
2572
+ sage: G.is_brace()
2573
+ True
2574
+ sage: M = G.get_matching()
2575
+ sage: L = []
2576
+ sage: for a, b, *_ in M:
2577
+ ....: J = G.copy(); J.delete_vertices([a, b])
2578
+ ....: if J.is_matching_covered():
2579
+ ....: L.append(J)
2580
+ sage: len(L) == len(M)
2581
+ True
2582
+
2583
+ A cycle graph of order six or more is a bipartite matching covered
2584
+ graph, but is not a brace::
2585
+
2586
+ sage: C = graphs.CycleGraph(10)
2587
+ sage: G = MatchingCoveredGraph(C)
2588
+ sage: G.is_brace()
2589
+ False
2590
+
2591
+ A ladder graph of order six or more is a bipartite matching covered
2592
+ graph, that is not a brace. The tight cut decomposition of a ladder
2593
+ graph produces a list graphs the underlying graph of each of which
2594
+ is isomorphic to a 4-cycle::
2595
+
2596
+ sage: L = graphs.LadderGraph(10)
2597
+ sage: G = MatchingCoveredGraph(L)
2598
+ sage: G.is_brace()
2599
+ False
2600
+
2601
+ One may set the ``coNP_certificate`` to be ``True``::
2602
+
2603
+ sage: H = graphs.HexahedralGraph()
2604
+ sage: G = MatchingCoveredGraph(H)
2605
+ sage: G.is_brace(coNP_certificate=True)
2606
+ (True, None, None, None, None)
2607
+ sage: C = graphs.CycleGraph(6)
2608
+ sage: D = MatchingCoveredGraph(C)
2609
+ sage: is_brace, nontrivial_tight_cut, nontrivial_odd_component, \
2610
+ ....: nontrivial_tight_cut_variant, cut_identifier = \
2611
+ ....: D.is_brace(coNP_certificate=True)
2612
+ sage: is_brace is False
2613
+ True
2614
+ sage: J = C.subgraph(vertices=nontrivial_odd_component)
2615
+ sage: J.is_isomorphic(graphs.PathGraph(3))
2616
+ True
2617
+ sage: len(nontrivial_tight_cut) == 2
2618
+ True
2619
+ sage: nontrivial_tight_cut_variant
2620
+ 'nontrivial barrier cut'
2621
+ sage: # Corresponding barrier
2622
+ sage: cut_identifier == {a for u, v, *_ in nontrivial_tight_cut for a in [u, v] \
2623
+ ....: if a not in nontrivial_odd_component}
2624
+ True
2625
+ sage: for u, v, *_ in nontrivial_tight_cut:
2626
+ ....: assert (u in nontrivial_odd_component and v not in nontrivial_odd_component)
2627
+ sage: L = graphs.LadderGraph(3) # A ladder graph with two constituent braces
2628
+ sage: G = MatchingCoveredGraph(L)
2629
+ sage: is_brace, nontrivial_tight_cut, nontrivial_odd_component, cut_variant, cut_identifier = \
2630
+ ....: G.is_brace(coNP_certificate=True)
2631
+ sage: is_brace is False
2632
+ True
2633
+ sage: G1 = L.copy()
2634
+ sage: G1.merge_vertices(list(nontrivial_odd_component))
2635
+ sage: G1.to_simple().is_isomorphic(graphs.CycleGraph(4))
2636
+ True
2637
+ sage: G2 = L.copy()
2638
+ sage: G2.merge_vertices([v for v in G if v not in nontrivial_odd_component])
2639
+ sage: G2.to_simple().is_isomorphic(graphs.CycleGraph(4))
2640
+ True
2641
+ sage: cut_variant
2642
+ 'nontrivial barrier cut'
2643
+ sage: cut_identifier == {a for u, v, *_ in nontrivial_tight_cut for a in [u, v] \
2644
+ ....: if a not in nontrivial_odd_component}
2645
+ True
2646
+ sage: H = graphs.CompleteBipartiteGraph(3, 3)
2647
+ sage: H.delete_edge(0, 3)
2648
+ sage: G = MatchingCoveredGraph(H)
2649
+ sage: G.is_brace(coNP_certificate=True)
2650
+ (False,
2651
+ [(4, 1, None), (5, 1, None), (4, 2, None), (5, 2, None)],
2652
+ {0, 4, 5},
2653
+ 'nontrivial barrier cut',
2654
+ {1, 2})
2655
+
2656
+ If the input matching covered graph is nonbipartite, a
2657
+ :exc:`ValueError` is thrown::
2658
+
2659
+ sage: K4 = graphs.CompleteGraph(4)
2660
+ sage: G = MatchingCoveredGraph(K4)
2661
+ sage: G.is_brace()
2662
+ Traceback (most recent call last):
2663
+ ...
2664
+ ValueError: the input graph is not bipartite
2665
+ sage: P = graphs.PetersenGraph()
2666
+ sage: H = MatchingCoveredGraph(P)
2667
+ sage: H.is_brace(coNP_certificate=True)
2668
+ Traceback (most recent call last):
2669
+ ...
2670
+ ValueError: the input graph is not bipartite
2671
+
2672
+ .. SEEALSO::
2673
+
2674
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.is_brick`
2675
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.bricks_and_braces`
2676
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_braces`
2677
+ """
2678
+ if not self.is_bipartite():
2679
+ raise ValueError('the input graph is not bipartite')
2680
+
2681
+ if self.order() < 6:
2682
+ return (True, None, None, None, None) if coNP_certificate else True
2683
+
2684
+ A, B = self.bipartite_sets()
2685
+ matching = set(self.get_matching())
2686
+ matching_neighbor = {x: y for u, v, *_ in matching for x, y in [(u, v), (v, u)]}
2687
+
2688
+ for e in matching:
2689
+ u, v, *_ = e
2690
+
2691
+ # Let G denote the undirected graph self, and
2692
+ # let the graph H(e) := G — u — v
2693
+ H = Graph(self, multiedges=False)
2694
+ H.delete_vertices([u, v])
2695
+
2696
+ if not H.is_connected() or not H.is_matching_covered(list(matching - set([e]))):
2697
+ if not coNP_certificate:
2698
+ return False
2699
+
2700
+ # Construct the digraph D(e)(A ∪ B, F) defined as follows:
2701
+ from sage.graphs.digraph import DiGraph
2702
+ D = DiGraph()
2703
+
2704
+ # For each edge (a, b) in E(H(e)) ∩ M with a in A, b —> a in D(e).
2705
+ # For each edge (a, b) in E(H(e)) with a in A, a —> b in D(e).
2706
+ for a, b in H.edge_iterator(labels=False, sort_vertices=True):
2707
+
2708
+ if a in B:
2709
+ a, b = b, a
2710
+
2711
+ D.add_edge((a, b))
2712
+ if matching_neighbor[a] == b:
2713
+ D.add_edge((b, a))
2714
+
2715
+ # H(e) is matching covered iff D(e) is strongly connected.
2716
+ # Check if D(e) is strongly connected using Kosaraju's algorithm
2717
+ def dfs(x, visited, neighbor_iterator):
2718
+ stack = [x] # a stack of xertices
2719
+
2720
+ while stack:
2721
+ x = stack.pop()
2722
+ visited.add(x)
2723
+
2724
+ for y in neighbor_iterator(x):
2725
+ if y not in visited:
2726
+ stack.append(y)
2727
+
2728
+ root = next(D.vertex_iterator())
2729
+
2730
+ visited_in = set()
2731
+ dfs(root, visited_in, D.neighbor_in_iterator)
2732
+
2733
+ # Since D(e) is not strongly connected, it has a directed cut T(e).
2734
+ # Note that by definition of D(e), it follows that T(e) ⊆ E(H(e)) — M.
2735
+ # Thus, T(e) is a cut of H(e), which has a shore X such that every edge of T(e) is
2736
+ # incident with a vertex in X ∩ B.
2737
+
2738
+ # Moreover, M — e is a perfect matching of H(e), and thus, |X ∩ A| = |X ∩ B|
2739
+ # Consequently, Y := X + v is a shore of a nontrivial tight cut T of G
2740
+
2741
+ if len(visited_in) != D.order():
2742
+ X = visited_in
2743
+ else:
2744
+ X = set()
2745
+ dfs(root, X, D.neighbor_out_iterator)
2746
+
2747
+ color_class = None
2748
+
2749
+ for a, b in H.edge_iterator(labels=False, sort_vertices=True):
2750
+ if (a in X) ^ (b in X):
2751
+ x = a if a in A else b
2752
+ color_class = x not in X
2753
+ break
2754
+
2755
+ # Obtain the color class Z ∈ {A, B} such that X ∩ Z is a vertex cover for T(e)
2756
+ # Thus, obtain Y := X + v
2757
+ X.add(u if (not color_class and u in A) or (color_class and u in B) or (color_class is None) else v)
2758
+
2759
+ # Compute the nontrivial tight cut C := ∂(Y)
2760
+ C = [(x, y, w) if x in X else (y, x, w)
2761
+ for x, y, w in self.edge_iterator(sort_vertices=True)
2762
+ if (x in X) ^ (y in X)]
2763
+
2764
+ # Obtain the barrier Z
2765
+ Z = None
2766
+
2767
+ if (u in X and u in A) or (v in X and v in A):
2768
+ Z = {b for b in B if b not in X}
2769
+ else:
2770
+ Z = {a for a in A if a not in X}
2771
+
2772
+ return (False, C, set(X), 'nontrivial barrier cut', Z)
2773
+
2774
+ return (True, None, None, None, None) if coNP_certificate else True
2775
+
2776
+ @doc_index('Bricks, braces and tight cut decomposition')
2777
+ def is_brick(self, coNP_certificate=False):
2778
+ r"""
2779
+ Check if the (matching covered) graph is a brick.
2780
+
2781
+ A matching covered graph which is free of nontrivial tight cuts is
2782
+ called a *brick* if it is nonbipartite. A nonbipartite matching covered
2783
+ graph is a brick if and only if it is 3-connected and bicritical
2784
+ [LM2024]_.
2785
+
2786
+ INPUT:
2787
+
2788
+ - ``coNP_certificate`` -- boolean (default: ``False``)
2789
+
2790
+ OUTPUT:
2791
+
2792
+ - If the input matching covered graph is bipartite, a :exc:`ValueError`
2793
+ is returned.
2794
+
2795
+ - If the input nonbipartite matching covered graph is a brick, a
2796
+ boolean ``True`` is returned if ``coNP_certificate`` is set to
2797
+ ``False``, otherwise a 5-tuple ``(True, None, None, None, None)`` is
2798
+ returned.
2799
+
2800
+ - If the input nonbipartite matching covered graph is not a brick, a
2801
+ boolean ``False`` is returned if ``coNP_certificate`` is set to
2802
+ ``False``.
2803
+
2804
+ - If ``coNP_certificate`` is set to ``True`` and the input nonbipartite
2805
+ graph is not a brick, a 5-tuple of
2806
+
2807
+ 1. a boolean ``False``,
2808
+
2809
+ 2. a list of lists of edges, each list constituting a nontrivial
2810
+ tight cut collectively representing a laminar tight cut,
2811
+
2812
+ 3. a list of set of vertices of one of the shores of those respective
2813
+ nontrivial tight cuts:
2814
+
2815
+ #. In case of nontrivial barrier cuts, each of the shores is a
2816
+ nontrivial odd component with respect to a nontrivial barrier,
2817
+ thus the returned list forms mutually exclusive collection of
2818
+ (odd) sets.
2819
+
2820
+ #. Otherwise each of the nontrivial tight cuts is a 2-separation
2821
+ cut, each of the shores form a subset sequence, with the
2822
+ `i` th shore being a proper subset of the `i + 1` th shore.
2823
+
2824
+ 4. a string showing whether the nontrivial tight cuts are barrier
2825
+ cuts (if the string is 'nontrivial barrier cut'), or 2-separation
2826
+ cuts (if the string is 'nontrivial 2-separation cut')
2827
+
2828
+ 5. a set of vertices showing the respective barrier if the
2829
+ nontrivial tight cuts are barrier cuts, or otherwise
2830
+ a set of two vertices constituting the corresponding
2831
+ two vertex cut (in this case the nontrivial tight cuts are
2832
+ 2-separation cuts)
2833
+
2834
+ is returned.
2835
+
2836
+ EXAMPLES:
2837
+
2838
+ The complete graph on four vertices `K_4` is the smallest brick::
2839
+
2840
+ sage: K = graphs.CompleteGraph(4)
2841
+ sage: G = MatchingCoveredGraph(K)
2842
+ sage: G.is_brick()
2843
+ True
2844
+
2845
+ The triangular cicular ladder (a graph on six vertices), aka
2846
+ `\overline{C_6}` is a brick::
2847
+
2848
+ sage: C6Bar = graphs.CircularLadderGraph(3)
2849
+ sage: G = MatchingCoveredGraph(C6Bar)
2850
+ sage: G.is_brick()
2851
+ True
2852
+
2853
+ Each of Petersen graph, Bicorn graph, Tricorn graph, Cubeplex graph,
2854
+ Twinplex graph, Wagner graph is a brick::
2855
+
2856
+ sage: MatchingCoveredGraph(graphs.PetersenGraph()).is_brick() and \
2857
+ ....: MatchingCoveredGraph(graphs.StaircaseGraph(4)).is_brick() and \
2858
+ ....: MatchingCoveredGraph(graphs.TricornGraph()).is_brick() and \
2859
+ ....: MatchingCoveredGraph(graphs.CubeplexGraph()).is_brick() and \
2860
+ ....: MatchingCoveredGraph(graphs.TwinplexGraph()).is_brick() and \
2861
+ ....: MatchingCoveredGraph(graphs.WagnerGraph()).is_brick()
2862
+ True
2863
+
2864
+ The Murty graph is the smallest simple brick that is not odd-intercyclic::
2865
+
2866
+ sage: M = graphs.MurtyGraph()
2867
+ sage: G = MatchingCoveredGraph(M)
2868
+ sage: G.is_brick()
2869
+ True
2870
+
2871
+ A circular ladder graph of order six or more on `2n` vertices for an
2872
+ odd `n` is a brick::
2873
+
2874
+ sage: n = 11
2875
+ sage: CL = graphs.CircularLadderGraph(n)
2876
+ sage: G = MatchingCoveredGraph(CL)
2877
+ sage: G.is_brick()
2878
+ True
2879
+
2880
+ A moebius ladder graph of order eight or more on `2n` vertices for an
2881
+ even `n` is a brick::
2882
+
2883
+ sage: n = 10
2884
+ sage: ML = graphs.MoebiusLadderGraph(n)
2885
+ sage: G = MatchingCoveredGraph(ML)
2886
+ sage: G.is_brick()
2887
+ True
2888
+
2889
+ A wheel graph of an even order is a brick::
2890
+
2891
+ sage: W = graphs.WheelGraph(10)
2892
+ sage: G = MatchingCoveredGraph(W)
2893
+ sage: G.is_brick()
2894
+ True
2895
+
2896
+ A graph that is isomorphic to a truncated biwheel graph is a brick::
2897
+
2898
+ sage: TB = graphs.TruncatedBiwheelGraph(15)
2899
+ sage: G = MatchingCoveredGraph(TB)
2900
+ sage: G.is_brick()
2901
+ True
2902
+
2903
+ Each of the graphs in the staircase graph family with order eight or
2904
+ more is a brick::
2905
+
2906
+ sage: ST = graphs.StaircaseGraph(9)
2907
+ sage: G = MatchingCoveredGraph(ST)
2908
+ sage: G.is_brick()
2909
+ True
2910
+
2911
+ Bricks are 3-connected::
2912
+
2913
+ sage: P = graphs.PetersenGraph()
2914
+ sage: G = MatchingCoveredGraph(P)
2915
+ sage: G.is_brick()
2916
+ True
2917
+ sage: G.is_triconnected()
2918
+ True
2919
+
2920
+ Bricks are bicritical::
2921
+
2922
+ sage: P = graphs.PetersenGraph()
2923
+ sage: G = MatchingCoveredGraph(P)
2924
+ sage: G.is_brick()
2925
+ True
2926
+ sage: G.is_bicritical()
2927
+ True
2928
+
2929
+ Examples of nonbipartite matching covered graphs that are not
2930
+ bricks::
2931
+
2932
+ sage: H = Graph([
2933
+ ....: (0, 3), (0, 4), (0, 7),
2934
+ ....: (1, 3), (1, 5), (1, 7),
2935
+ ....: (2, 3), (2, 6), (2, 7),
2936
+ ....: (4, 5), (4, 6), (5, 6)
2937
+ ....: ])
2938
+ sage: G = MatchingCoveredGraph(H)
2939
+ sage: G.is_bipartite()
2940
+ False
2941
+ sage: G.is_bicritical()
2942
+ False
2943
+ sage: G.is_triconnected()
2944
+ True
2945
+ sage: G.is_brick()
2946
+ False
2947
+ sage: H = Graph([
2948
+ ....: (0, 1), (0, 2), (0, 3), (0, 4), (1, 2),
2949
+ ....: (1, 5), (2, 5), (3, 4), (3, 5), (4, 5)
2950
+ ....: ])
2951
+ sage: G = MatchingCoveredGraph(H)
2952
+ sage: G.is_bipartite()
2953
+ False
2954
+ sage: G.is_bicritical()
2955
+ True
2956
+ sage: G.is_triconnected()
2957
+ False
2958
+ sage: G.is_brick()
2959
+ False
2960
+
2961
+ One may set the ``coNP_certificate`` to be ``True``::
2962
+
2963
+ sage: K4 = graphs.CompleteGraph(4)
2964
+ sage: G = MatchingCoveredGraph(K4)
2965
+ sage: G.is_brick(coNP_certificate=True)
2966
+ (True, None, None, None, None)
2967
+ sage: # K(4) ⊙ K(3, 3) is nonbipartite but not a brick
2968
+ sage: H = graphs.MurtyGraph(); H.delete_edge(0, 1)
2969
+ sage: G = MatchingCoveredGraph(H)
2970
+ sage: G.is_brick(coNP_certificate=True)
2971
+ (False, [[(5, 2, None), (6, 3, None), (7, 4, None)]], [{5, 6, 7}],
2972
+ 'nontrivial barrier cut', {2, 3, 4})
2973
+ sage: H = Graph([
2974
+ ....: (0, 12), (0, 13), (0, 15), (1, 4), (1, 13), (1, 14),
2975
+ ....: (1, 19), (2, 4), (2, 13), (2, 14), (2, 17), (3, 9),
2976
+ ....: (3, 13), (3, 16), (3, 21), (4, 6), (4, 7), (5, 7),
2977
+ ....: (5, 8), (5, 12), (6, 8), (6, 11), (7, 10), (8, 9),
2978
+ ....: (9, 10), (10, 11), (11, 12), (14, 15), (14, 16), (15, 16),
2979
+ ....: (17, 18), (17, 21), (18, 19), (18, 20), (19, 20), (20, 21)
2980
+ ....: ])
2981
+ sage: G = MatchingCoveredGraph(H)
2982
+ sage: G.is_brick(coNP_certificate=True)
2983
+ (False,
2984
+ [[(12, 0, None), (4, 1, None), (4, 2, None), (9, 3, None)],
2985
+ [(19, 1, None), (17, 2, None), (21, 3, None)],
2986
+ [(15, 0, None), (14, 1, None), (14, 2, None), (16, 3, None)]],
2987
+ [{4, 5, 6, 7, 8, 9, 10, 11, 12}, {17, 18, 19, 20, 21}, {14, 15, 16}],
2988
+ 'nontrivial barrier cut', {0, 1, 2, 3})
2989
+ sage: J = Graph([
2990
+ ....: (0, 1), (0, 2), (0, 3), (0, 4), (0, 5),
2991
+ ....: (0, 6), (0, 7), (0, 8), (0, 9), (0, 10),
2992
+ ....: (1, 2), (1, 11), (2, 11), (3, 4), (3, 11),
2993
+ ....: (4, 11), (5, 6), (5, 11), (6, 11), (7, 8),
2994
+ ....: (7, 11), (8, 11), (9, 10), (9, 11), (10, 11)
2995
+ ....: ])
2996
+ sage: G = MatchingCoveredGraph(J)
2997
+ sage: G.is_brick(coNP_certificate=True)
2998
+ (False,
2999
+ [[(0, 3, None),
3000
+ (0, 4, None),
3001
+ (0, 5, None),
3002
+ (0, 6, None),
3003
+ (0, 7, None),
3004
+ (0, 8, None),
3005
+ (0, 9, None),
3006
+ (0, 10, None),
3007
+ (1, 11, None),
3008
+ (2, 11, None)],
3009
+ [(0, 5, None),
3010
+ (0, 6, None),
3011
+ (0, 7, None),
3012
+ (0, 8, None),
3013
+ (0, 9, None),
3014
+ (0, 10, None),
3015
+ (1, 11, None),
3016
+ (2, 11, None),
3017
+ (3, 11, None),
3018
+ (4, 11, None)],
3019
+ [(0, 7, None),
3020
+ (0, 8, None),
3021
+ (0, 9, None),
3022
+ (0, 10, None),
3023
+ (1, 11, None),
3024
+ (2, 11, None),
3025
+ (3, 11, None),
3026
+ (4, 11, None),
3027
+ (5, 11, None),
3028
+ (6, 11, None)],
3029
+ [(0, 9, None),
3030
+ (0, 10, None),
3031
+ (1, 11, None),
3032
+ (2, 11, None),
3033
+ (3, 11, None),
3034
+ (4, 11, None),
3035
+ (5, 11, None),
3036
+ (6, 11, None),
3037
+ (7, 11, None),
3038
+ (8, 11, None)]],
3039
+ [{0, 1, 2},
3040
+ {0, 1, 2, 3, 4},
3041
+ {0, 1, 2, 3, 4, 5, 6},
3042
+ {0, 1, 2, 3, 4, 5, 6, 7, 8}],
3043
+ 'nontrivial 2-separation cut',
3044
+ {0, 11})
3045
+
3046
+ If the input matching covered graph is bipartite, a
3047
+ :exc:`ValueError` is thrown::
3048
+
3049
+ sage: H = graphs.HexahedralGraph()
3050
+ sage: G = MatchingCoveredGraph(H)
3051
+ sage: G.is_brick()
3052
+ Traceback (most recent call last):
3053
+ ...
3054
+ ValueError: the input graph is bipartite
3055
+ sage: J = graphs.HeawoodGraph()
3056
+ sage: G = MatchingCoveredGraph(J)
3057
+ sage: G.is_brick(coNP_certificate=True)
3058
+ Traceback (most recent call last):
3059
+ ...
3060
+ ValueError: the input graph is bipartite
3061
+
3062
+ .. SEEALSO::
3063
+
3064
+ - :meth:`~sage.graphs.graph.Graph.is_bicritical`
3065
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.is_brace`
3066
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.bricks_and_braces`
3067
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_bricks`
3068
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_petersen_bricks`
3069
+ """
3070
+ if self.is_bipartite():
3071
+ raise ValueError('the input graph is bipartite')
3072
+
3073
+ # Check if G is bicritical
3074
+ bicritical, certificate = self.is_bicritical(coNP_certificate=True)
3075
+
3076
+ if not bicritical:
3077
+ if not coNP_certificate:
3078
+ return False
3079
+
3080
+ # G has a pair of vertices u, v such that G - u - v is not matching
3081
+ # covered, thus has a nontrivial barrier B containing both u and v.
3082
+ u, _ = certificate
3083
+ B = self.maximal_barrier(u)
3084
+
3085
+ H = Graph(self)
3086
+ H.delete_vertices(B)
3087
+
3088
+ # Let K be a nontrivial odd component of H := G - B. Note that
3089
+ # there exists at least one such K since G is nonbipartite
3090
+ nontrivial_odd_components = [
3091
+ set(component) for component in H.connected_components(sort=True)
3092
+ if len(component) % 2 and len(component) > 1
3093
+ ]
3094
+
3095
+ # Find a laminar set of nontrivial barrier cuts
3096
+ C = [[(u, v, w) if u in nontrivial_odd_component else (v, u, w)
3097
+ for u, v, w in self.edge_iterator()
3098
+ if (u in nontrivial_odd_component) ^ (v in nontrivial_odd_component)]
3099
+ for nontrivial_odd_component in nontrivial_odd_components]
3100
+
3101
+ return (False, C, nontrivial_odd_components, 'nontrivial barrier cut', B)
3102
+
3103
+ # Check if G is 3-connected
3104
+ if self.is_triconnected():
3105
+ return (True, None, None, None, None) if coNP_certificate else True
3106
+
3107
+ # G has a 2-vertex cut
3108
+ # Compute the SPQR-tree decomposition
3109
+ spqr_tree = self.spqr_tree()
3110
+ two_vertex_cut = []
3111
+
3112
+ # Check for 2-vertex cuts in a P node
3113
+ # Since the graph is matching covered, it is free of cut vertices
3114
+ # It can be shown using counting arguments that the spqr tree
3115
+ # decomposition for a bicritical graph, that is 2-connected but not
3116
+ # 3-connected, is free of 'S' nodes
3117
+ for u in spqr_tree:
3118
+ if u[0] == 'P':
3119
+ two_vertex_cut.extend(u[1])
3120
+ break
3121
+
3122
+ # If no 2-vertex cut found, look for R nodes
3123
+ if not two_vertex_cut:
3124
+ from collections import Counter
3125
+ R_frequency = Counter()
3126
+
3127
+ for t, g in spqr_tree:
3128
+ if t == 'R':
3129
+ R_frequency.update(g)
3130
+
3131
+ # R frequency must be at least 2,
3132
+ # since the graph is 2-connected but not 3-connected
3133
+ two_vertex_cut = [u for u, f in R_frequency.items() if f >= 2][:2]
3134
+
3135
+ # We obtain a 2-vertex cut (u, v)
3136
+ H = Graph(self)
3137
+ H.delete_vertices(two_vertex_cut)
3138
+
3139
+ # Check if all components of H are odd
3140
+ components = H.connected_components(sort=True)
3141
+
3142
+ # Find a nontrivial odd component
3143
+ nontrivial_tight_cut_variation = 'nontrivial 2-separation cut'
3144
+ nontrivial_odd_components = []
3145
+
3146
+ for index, component in enumerate(components):
3147
+ if index == len(components) - 1:
3148
+ continue
3149
+ elif not index:
3150
+ nontrivial_odd_components.append(set(components[0] + [two_vertex_cut[0]]))
3151
+ else:
3152
+ nontrivial_odd_component = nontrivial_odd_components[-1].copy()
3153
+ nontrivial_odd_component.update(component)
3154
+ nontrivial_odd_components.append(nontrivial_odd_component)
3155
+
3156
+ C = [[(u, v, w) if u in nontrivial_odd_component else (v, u, w)
3157
+ for u, v, w in self.edge_iterator()
3158
+ if (u in nontrivial_odd_component) ^ (v in nontrivial_odd_component)]
3159
+ for nontrivial_odd_component in nontrivial_odd_components]
3160
+
3161
+ # Edge (u, v, w) in C are formatted so that u is in a nontrivial odd component
3162
+ return (False, C, nontrivial_odd_components, nontrivial_tight_cut_variation, set(two_vertex_cut)) if coNP_certificate else False
3163
+
2351
3164
  @doc_index('Overwritten methods')
2352
3165
  def loop_edges(self, labels=True):
2353
3166
  r"""
@@ -2418,13 +3231,13 @@ class MatchingCoveredGraph(Graph):
2418
3231
 
2419
3232
  .. SEEALSO::
2420
3233
 
2421
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`,
2422
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`,
2423
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`,
2424
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`,
2425
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`,
2426
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`,
2427
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops`
3234
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`
3235
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`
3236
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`
3237
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`
3238
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`
3239
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`
3240
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops`
2428
3241
  """
2429
3242
  return []
2430
3243
 
@@ -2485,13 +3298,13 @@ class MatchingCoveredGraph(Graph):
2485
3298
 
2486
3299
  .. SEEALSO::
2487
3300
 
2488
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`,
2489
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`,
2490
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`,
2491
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`,
2492
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`,
2493
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`,
2494
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops`
3301
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`
3302
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`
3303
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`
3304
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`
3305
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`
3306
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`
3307
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops`
2495
3308
  """
2496
3309
  return []
2497
3310
 
@@ -2557,13 +3370,13 @@ class MatchingCoveredGraph(Graph):
2557
3370
 
2558
3371
  .. SEEALSO::
2559
3372
 
2560
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`,
2561
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`,
2562
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`,
2563
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`,
2564
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`,
2565
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`,
2566
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops`
3373
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`
3374
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`
3375
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`
3376
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`
3377
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`
3378
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`
3379
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops`
2567
3380
  """
2568
3381
  return 0
2569
3382
 
@@ -2582,7 +3395,7 @@ class MatchingCoveredGraph(Graph):
2582
3395
  INPUT:
2583
3396
 
2584
3397
  - ``vertices`` -- (default: ``None``) iterator container of vertex
2585
- labels correponding to which the looped edges are to be removed. If
3398
+ labels corresponding to which the looped edges are to be removed. If
2586
3399
  ``vertices`` is ``None``, remove all loops.
2587
3400
 
2588
3401
  OUTPUT:
@@ -2649,13 +3462,13 @@ class MatchingCoveredGraph(Graph):
2649
3462
 
2650
3463
  .. SEEALSO::
2651
3464
 
2652
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`,
2653
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`,
2654
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`,
2655
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`,
2656
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`,
2657
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`,
2658
- :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`
3465
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`
3466
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`
3467
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`
3468
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`
3469
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`
3470
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`
3471
+ - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`
2659
3472
  """
2660
3473
  from collections.abc import Iterable
2661
3474
 
@@ -2663,8 +3476,6 @@ class MatchingCoveredGraph(Graph):
2663
3476
  raise TypeError(f'\'{vertices.__class__.__name__}\' '
2664
3477
  'object is not iterable')
2665
3478
 
2666
- return
2667
-
2668
3479
  @doc_index('Miscellaneous methods')
2669
3480
  def update_matching(self, matching):
2670
3481
  r"""
@@ -2752,4 +3563,4 @@ class MatchingCoveredGraph(Graph):
2752
3563
  raise exception
2753
3564
 
2754
3565
 
2755
- __doc__ = __doc__.replace('{INDEX_OF_METHODS}', gen_thematic_rest_table_index(MatchingCoveredGraph, only_local_functions=False))
3566
+ __doc__ = __doc__.replace('{INDEX_OF_METHODS}', gen_thematic_rest_table_index(MatchingCoveredGraph, only_local_functions=False))