diff --git a/CITATION.cff b/CITATION.cff index 72deb44fad5..1938b78e614 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -4,8 +4,8 @@ title: SageMath abstract: SageMath is a free open-source mathematics software system. authors: - name: "The SageMath Developers" -version: 10.7.beta0 +version: 10.6.rc1 doi: 10.5281/zenodo.8042260 -date-released: 2025-04-02 +date-released: 2025-03-27 repository-code: "https://github.com/sagemath/sage" url: "https://www.sagemath.org/" diff --git a/VERSION.txt b/VERSION.txt index a8182cad2a2..61b8ce4c26e 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 10.7.beta0, Release Date: 2025-04-02 +SageMath version 10.6.rc1, Release Date: 2025-03-27 \ No newline at end of file diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index f2737af8125..2c5ceb8574e 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,3 +1,3 @@ tarball=configure-VERSION.tar.gz -sha1=3371667ee074aefdde8fc64ad60928a29a1e3578 -sha256=4e93801f29ba7d242285ed1461300586b50db56474e84cefe0b793f8dbf54842 +sha1=b864ca0eb94c01c9e724699ac6d797a65b5acbb0 +sha256=5aa6946e6a99eeac2b829f2146338eeef8537a3134b4289078c8417092ecaaf2 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index e3ab7a4e733..efc4b892210 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -a2b47d65bcbe9d176b07208feb6aae513fc41244 +8dab37468c9feb4a5a1fcc22bbccc12321aaa475 diff --git a/build/pkgs/sage_conf/version_requirements.txt b/build/pkgs/sage_conf/version_requirements.txt index 419d756a4fe..d3b1f01678d 100644 --- a/build/pkgs/sage_conf/version_requirements.txt +++ b/build/pkgs/sage_conf/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-conf ~= 10.7b0 +sage-conf ~= 10.6rc1 diff --git a/build/pkgs/sage_docbuild/version_requirements.txt b/build/pkgs/sage_docbuild/version_requirements.txt index ad4df678b5f..c9d29949628 100644 --- a/build/pkgs/sage_docbuild/version_requirements.txt +++ b/build/pkgs/sage_docbuild/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-docbuild ~= 10.7b0 +sage-docbuild ~= 10.6rc1 diff --git a/build/pkgs/sage_setup/version_requirements.txt b/build/pkgs/sage_setup/version_requirements.txt index 8854d0565e1..e2827abd3e3 100644 --- a/build/pkgs/sage_setup/version_requirements.txt +++ b/build/pkgs/sage_setup/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-setup ~= 10.7b0 +sage-setup ~= 10.6rc1 diff --git a/build/pkgs/sage_sws2rst/version_requirements.txt b/build/pkgs/sage_sws2rst/version_requirements.txt index edab228fd92..a399eab717c 100644 --- a/build/pkgs/sage_sws2rst/version_requirements.txt +++ b/build/pkgs/sage_sws2rst/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-sws2rst ~= 10.7b0 +sage-sws2rst ~= 10.6rc1 diff --git a/build/pkgs/sagelib/version_requirements.txt b/build/pkgs/sagelib/version_requirements.txt index 9edac169699..18a520aa379 100644 --- a/build/pkgs/sagelib/version_requirements.txt +++ b/build/pkgs/sagelib/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-standard ~= 10.7b0 +sagemath-standard ~= 10.6rc1 diff --git a/build/pkgs/sagemath_bliss/version_requirements.txt b/build/pkgs/sagemath_bliss/version_requirements.txt index 08ac1726895..681278704e0 100644 --- a/build/pkgs/sagemath_bliss/version_requirements.txt +++ b/build/pkgs/sagemath_bliss/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-bliss ~= 10.7b0 +sagemath-bliss ~= 10.6rc1 diff --git a/build/pkgs/sagemath_categories/version_requirements.txt b/build/pkgs/sagemath_categories/version_requirements.txt index 941acf92940..70814dcc35a 100644 --- a/build/pkgs/sagemath_categories/version_requirements.txt +++ b/build/pkgs/sagemath_categories/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-categories ~= 10.7b0 +sagemath-categories ~= 10.6rc1 diff --git a/build/pkgs/sagemath_coxeter3/version_requirements.txt b/build/pkgs/sagemath_coxeter3/version_requirements.txt index 769cd88ae0a..4b5ac58eeea 100644 --- a/build/pkgs/sagemath_coxeter3/version_requirements.txt +++ b/build/pkgs/sagemath_coxeter3/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-coxeter3 ~= 10.7b0 +sagemath-coxeter3 ~= 10.6rc1 diff --git a/build/pkgs/sagemath_environment/version_requirements.txt b/build/pkgs/sagemath_environment/version_requirements.txt index 088fcd8bac7..e2430199cac 100644 --- a/build/pkgs/sagemath_environment/version_requirements.txt +++ b/build/pkgs/sagemath_environment/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-environment ~= 10.7b0 +sagemath-environment ~= 10.6rc1 diff --git a/build/pkgs/sagemath_mcqd/version_requirements.txt b/build/pkgs/sagemath_mcqd/version_requirements.txt index 2ca953771bf..f7db6aaec4b 100644 --- a/build/pkgs/sagemath_mcqd/version_requirements.txt +++ b/build/pkgs/sagemath_mcqd/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-mcqd ~= 10.7b0 +sagemath-mcqd ~= 10.6rc1 diff --git a/build/pkgs/sagemath_meataxe/version_requirements.txt b/build/pkgs/sagemath_meataxe/version_requirements.txt index 0e2e5bd9079..27ad3837234 100644 --- a/build/pkgs/sagemath_meataxe/version_requirements.txt +++ b/build/pkgs/sagemath_meataxe/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-meataxe ~= 10.7b0 +sagemath-meataxe ~= 10.6rc1 diff --git a/build/pkgs/sagemath_objects/version_requirements.txt b/build/pkgs/sagemath_objects/version_requirements.txt index a7140a18257..55aec53afc7 100644 --- a/build/pkgs/sagemath_objects/version_requirements.txt +++ b/build/pkgs/sagemath_objects/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-objects ~= 10.7b0 +sagemath-objects ~= 10.6rc1 diff --git a/build/pkgs/sagemath_repl/version_requirements.txt b/build/pkgs/sagemath_repl/version_requirements.txt index 72d123ec0aa..173877b4ac3 100644 --- a/build/pkgs/sagemath_repl/version_requirements.txt +++ b/build/pkgs/sagemath_repl/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-repl ~= 10.7b0 +sagemath-repl ~= 10.6rc1 diff --git a/build/pkgs/sagemath_sirocco/version_requirements.txt b/build/pkgs/sagemath_sirocco/version_requirements.txt index ea9b793c30b..d4a5073ec18 100644 --- a/build/pkgs/sagemath_sirocco/version_requirements.txt +++ b/build/pkgs/sagemath_sirocco/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-sirocco ~= 10.7b0 +sagemath-sirocco ~= 10.6rc1 diff --git a/build/pkgs/sagemath_tdlib/version_requirements.txt b/build/pkgs/sagemath_tdlib/version_requirements.txt index ab71b4f63f4..f1cb914df46 100644 --- a/build/pkgs/sagemath_tdlib/version_requirements.txt +++ b/build/pkgs/sagemath_tdlib/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-tdlib ~= 10.7b0 +sagemath-tdlib ~= 10.6rc1 diff --git a/pkgs/sage-conf/VERSION.txt b/pkgs/sage-conf/VERSION.txt index 2422e1b6f38..672aeee174f 100644 --- a/pkgs/sage-conf/VERSION.txt +++ b/pkgs/sage-conf/VERSION.txt @@ -1 +1 @@ -10.7.beta0 +10.6.rc1 diff --git a/pkgs/sage-conf_conda/VERSION.txt b/pkgs/sage-conf_conda/VERSION.txt index 2422e1b6f38..672aeee174f 100644 --- a/pkgs/sage-conf_conda/VERSION.txt +++ b/pkgs/sage-conf_conda/VERSION.txt @@ -1 +1 @@ -10.7.beta0 +10.6.rc1 diff --git a/pkgs/sage-conf_pypi/VERSION.txt b/pkgs/sage-conf_pypi/VERSION.txt index 2422e1b6f38..672aeee174f 100644 --- a/pkgs/sage-conf_pypi/VERSION.txt +++ b/pkgs/sage-conf_pypi/VERSION.txt @@ -1 +1 @@ -10.7.beta0 +10.6.rc1 diff --git a/pkgs/sage-docbuild/VERSION.txt b/pkgs/sage-docbuild/VERSION.txt index 2422e1b6f38..672aeee174f 100644 --- a/pkgs/sage-docbuild/VERSION.txt +++ b/pkgs/sage-docbuild/VERSION.txt @@ -1 +1 @@ -10.7.beta0 +10.6.rc1 diff --git a/pkgs/sage-setup/VERSION.txt b/pkgs/sage-setup/VERSION.txt index 2422e1b6f38..672aeee174f 100644 --- a/pkgs/sage-setup/VERSION.txt +++ b/pkgs/sage-setup/VERSION.txt @@ -1 +1 @@ -10.7.beta0 +10.6.rc1 diff --git a/pkgs/sage-sws2rst/VERSION.txt b/pkgs/sage-sws2rst/VERSION.txt index 2422e1b6f38..672aeee174f 100644 --- a/pkgs/sage-sws2rst/VERSION.txt +++ b/pkgs/sage-sws2rst/VERSION.txt @@ -1 +1 @@ -10.7.beta0 +10.6.rc1 diff --git a/pkgs/sagemath-bliss/VERSION.txt b/pkgs/sagemath-bliss/VERSION.txt index 2422e1b6f38..672aeee174f 100644 --- a/pkgs/sagemath-bliss/VERSION.txt +++ b/pkgs/sagemath-bliss/VERSION.txt @@ -1 +1 @@ -10.7.beta0 +10.6.rc1 diff --git a/pkgs/sagemath-categories/VERSION.txt b/pkgs/sagemath-categories/VERSION.txt index 2422e1b6f38..672aeee174f 100644 --- a/pkgs/sagemath-categories/VERSION.txt +++ b/pkgs/sagemath-categories/VERSION.txt @@ -1 +1 @@ -10.7.beta0 +10.6.rc1 diff --git a/pkgs/sagemath-coxeter3/VERSION.txt b/pkgs/sagemath-coxeter3/VERSION.txt index 2422e1b6f38..672aeee174f 100644 --- a/pkgs/sagemath-coxeter3/VERSION.txt +++ b/pkgs/sagemath-coxeter3/VERSION.txt @@ -1 +1 @@ -10.7.beta0 +10.6.rc1 diff --git a/pkgs/sagemath-environment/VERSION.txt b/pkgs/sagemath-environment/VERSION.txt index 2422e1b6f38..672aeee174f 100644 --- a/pkgs/sagemath-environment/VERSION.txt +++ b/pkgs/sagemath-environment/VERSION.txt @@ -1 +1 @@ -10.7.beta0 +10.6.rc1 diff --git a/pkgs/sagemath-mcqd/VERSION.txt b/pkgs/sagemath-mcqd/VERSION.txt index 2422e1b6f38..672aeee174f 100644 --- a/pkgs/sagemath-mcqd/VERSION.txt +++ b/pkgs/sagemath-mcqd/VERSION.txt @@ -1 +1 @@ -10.7.beta0 +10.6.rc1 diff --git a/pkgs/sagemath-meataxe/VERSION.txt b/pkgs/sagemath-meataxe/VERSION.txt index 2422e1b6f38..672aeee174f 100644 --- a/pkgs/sagemath-meataxe/VERSION.txt +++ b/pkgs/sagemath-meataxe/VERSION.txt @@ -1 +1 @@ -10.7.beta0 +10.6.rc1 diff --git a/pkgs/sagemath-objects/VERSION.txt b/pkgs/sagemath-objects/VERSION.txt index 2422e1b6f38..672aeee174f 100644 --- a/pkgs/sagemath-objects/VERSION.txt +++ b/pkgs/sagemath-objects/VERSION.txt @@ -1 +1 @@ -10.7.beta0 +10.6.rc1 diff --git a/pkgs/sagemath-repl/VERSION.txt b/pkgs/sagemath-repl/VERSION.txt index 2422e1b6f38..672aeee174f 100644 --- a/pkgs/sagemath-repl/VERSION.txt +++ b/pkgs/sagemath-repl/VERSION.txt @@ -1 +1 @@ -10.7.beta0 +10.6.rc1 diff --git a/pkgs/sagemath-sirocco/VERSION.txt b/pkgs/sagemath-sirocco/VERSION.txt index 2422e1b6f38..672aeee174f 100644 --- a/pkgs/sagemath-sirocco/VERSION.txt +++ b/pkgs/sagemath-sirocco/VERSION.txt @@ -1 +1 @@ -10.7.beta0 +10.6.rc1 diff --git a/pkgs/sagemath-tdlib/VERSION.txt b/pkgs/sagemath-tdlib/VERSION.txt index 2422e1b6f38..672aeee174f 100644 --- a/pkgs/sagemath-tdlib/VERSION.txt +++ b/pkgs/sagemath-tdlib/VERSION.txt @@ -1 +1 @@ -10.7.beta0 +10.6.rc1 diff --git a/src/VERSION.txt b/src/VERSION.txt index 2422e1b6f38..672aeee174f 100644 --- a/src/VERSION.txt +++ b/src/VERSION.txt @@ -1 +1 @@ -10.7.beta0 +10.6.rc1 diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index c76df17b8c2..12cde0e99e6 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -4,6 +4,6 @@ # which stops "setup.py develop" from rewriting it as a Python file. : # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='10.7.beta0' -SAGE_RELEASE_DATE='2025-04-02' -SAGE_VERSION_BANNER='SageMath version 10.7.beta0, Release Date: 2025-04-02' +SAGE_VERSION='10.6.rc1' +SAGE_RELEASE_DATE='2025-03-27' +SAGE_VERSION_BANNER='SageMath version 10.6.rc1, Release Date: 2025-03-27' diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index cddaee3484e..7365949ec90 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -73,8 +73,6 @@ ``random_subgraph()`` | Return a random matching covered subgraph containing each vertex with probability ``p``. ``save_afile()`` | Save the graph to file in alist format. ``strong_product()`` | Return the strong product of ``self`` and ``other``. - ``subdivide_edge()`` | Subdivide an edge `k` times. - ``subdivide_edges()`` | Subdivide `k` times edges from an iterable container. ``subgraph()`` | Return the matching covered subgraph containing the given vertices and edges. ``subgraph_search()`` | Return a copy of (matching covered) ``G`` in ``self``. ``subgraph_search_count()`` | Return the number of labelled occurrences of (matching covered) ``G`` in ``self``. @@ -107,8 +105,6 @@ :delim: | ``add_ear()`` | Add an ear to the graph with the provided end vertices number of internal vertices. - ``bisubdivide_edge()`` | Bisubdivide an edge `k` times. - ``bisubdivide_edges()`` | Bisubdivide `k` times edges from an iterable container. ``efficient_ear_decomposition()`` | Return a matching covered ear decomposition computed at the fastest possible time. ``is_removable_double_ear()`` | Check whether the pair of ears form a removable double ear. ``is_removable_doubleton()`` | Check whether the pair of edges constitute a removable doubleton. @@ -930,7 +926,7 @@ def add_edge(self, u, v=None, label=None): property of matching covered, then the graph is updated and nothing is returned. - - If the edge is provided with an invalid format, a :exc:`ValueError` + - If the edge is provided in an invalid format, a :exc:`ValueError` is returned. WARNING: @@ -1193,7 +1189,7 @@ def add_edges(self, edges, loops=False): property of matching covered, then the graph is updated and nothing is returned. - - If ``edges`` is provided with an invalid format, a :exc:`ValueError` + - If ``edges`` is provided in an invalid format, a :exc:`ValueError` is returned. EXAMPLES: @@ -3470,6 +3466,500 @@ def remove_loops(self, vertices=None): raise TypeError(f'\'{vertices.__class__.__name__}\' ' 'object is not iterable') + @doc_index('Overwritten methods') + def subdivide_edge(self, *args): + r""" + Subdivide an edge `k` times. + + .. NOTE:: + + This method overwrites the + :meth:`~sage.graphs.generic_graph.GenericGraph.subdivide_edge` + method to ensure that resultant graph is also matching covered. + + INPUT: + + The following forms are all accepted to subdivide `8` times the edge + between vertices `1` and `2` labeled with ``'label'``. + + - ``G.subdivide_edge(1, 2, 8 )`` + - ``G.subdivide_edge((1, 2), 8 )`` + - ``G.subdivide_edge(1, 2, 'label', 8 )`` + - ``G.subdivide_edge((1, 2, 'label'), 8 )`` + + .. NOTE:: + + * If the given edge is labelled with `l`, all the edges created by + the subdivision will have the same label. + + * If no label given, the label obtained from + :meth:`~sage.graphs.generic_graph.GenericGraph.edge_label` will + be used. If multiple such labels are present, the first one in + the returned list will be used. + + * The number of subdivisions must be a nonnegative even integer in + order to ensure the resultant graph is matching covered. + + * In the context of matching covered graphs, *bisubdividing* an edge + *t* times is defined as subdividing the edge *2t* times, for some + nonnegative integer *t*. + + * For two input arguments, the first one must be of the form + `(u, v)` or `(u, v, label)` + + OUTPUT: + + - If an existent edge is provided with a valid format and the parameter + ``k`` in the argument is a nonnegative even integer then the graph is + updated and nothing is returned, otherwise a :exc:`ValueError` is + returned if ``k`` is not a nonnegative even integer, + + - If the graph does not contain the edge provided, a :exc:`ValueError` + is returned. Also, a :exc:`ValueError` is thrown in case the provided + arguments are not valid. + + EXAMPLES: + + Subdividing `4` times an edge of the Petersen graph. Please note that + the perfect matching captured at ``self.get_matching()`` also gets + updated:: + + sage: P = graphs.PetersenGraph() + sage: G = MatchingCoveredGraph(P) + sage: V, E = set(G.vertices()), list(G.edges(sort=True, sort_vertices=True)) + sage: M = set(G.get_matching()) + sage: G.subdivide_edge(0, 1, 4) + sage: W, F = set(G.vertices()), list(G.edges(sort=True, sort_vertices=True)) + sage: N = set(G.get_matching()) + sage: sorted(W - V) + [10, 11, 12, 13] + sage: sorted([f for f in F if f not in E]), sorted([e for e in E if e not in F]) + ([(0, 10, None), (1, 13, None), (10, 11, None), (11, 12, None), + (12, 13, None)], [(0, 1, None)]) + sage: if (0, 1, None) in M: + ....: assert sorted(N - M), sorted(M - N) == \ + ....: ([(0, 10, None), (1, 13, None), (11, 12, None)], [(0, 1, None)]) + ....: else: + ....: assert sorted(N - M), sorted(M - N) == \ + ....: ([(10, 11, None), (12, 13, None)], []) + + Subdividing a multiple edge/ some multiple edges:: + + sage: K = graphs.CycleGraph(4) + sage: K.allow_multiple_edges(1) + sage: K.add_edges([(0, 1, 2), (0, 1, 3), (0, 1, 0.5)]) + sage: K.delete_edge(0, 1, None) + sage: G = MatchingCoveredGraph(K) + sage: V, E = set(G.vertices()), list(G.edges(sort=True, sort_vertices=True)) + sage: G.edge_label(0, 1) + [2, 3, 0.500000000000000] + sage: G.subdivide_edge((0, 1), 6) # the edge: (0, 1, 2) + sage: G.subdivide_edge((0, 1, 3), 2) # the edge: (0, 1, 3) + sage: G.subdivide_edge(1, 2, None, 2) # the edge: (1, 2, None) + sage: W, F = set(G.vertices()), list(G.edges(sort=True, sort_vertices=True)) + sage: sorted(W - V) + [4, 5, 6, 7, 8, 9, 10, 11, 12, 13] + sage: sorted([f for f in F if f not in E]), sorted([e for e in E if e not in F]) + ([(0, 4, 2), (0, 10, 3), (1, 9, 2), (1, 11, 3), (1, 12, None), (2, 13, None), + (4, 5, 2), (5, 6, 2), (6, 7, 2), (7, 8, 2), (8, 9, 2), (10, 11, 3), + (12, 13, None)], [(0, 1, 2), (0, 1, 3), (1, 2, None)]) + + Setting ``k`` to `0` does not change the graph:: + + sage: H = G.copy() + sage: G.subdivide_edge(0, 4, 0) # the edge: (0, 4, None) + sage: H == G and H.edges(sort=True) == G.edges(sort=True) + True + + If too many or too less arguments are given, an exception is raised:: + + sage: G.subdivide_edge(0, 1, 'label', 4, 6) + Traceback (most recent call last): + ... + ValueError: this method takes at least 2 and at most 4 arguments + sage: G.subdivide_edge((0, 1, 'label', 4)) + Traceback (most recent call last): + ... + ValueError: this method takes at least 2 and at most 4 arguments + + A :exc:`ValueError` is returned for `k` being in an invalid format or + being not an even nonnegative, or for nonexistent or invalid edges:: + + sage: G.subdivide_edge(0, 4, 'label') # No. of subdivision: 'label' + Traceback (most recent call last): + ... + TypeError: '<' not supported between instances of 'str' and 'int' + sage: G.subdivide_edge(0, 4, 3) # No. of subdivisions: 3 + Traceback (most recent call last): + ... + ValueError: the number of subdivisions must be a nonnegative even integer, + but found 3 + sage: G.subdivide_edge(0, 4, -1) # No. of subdivisions: -1 + Traceback (most recent call last): + ... + ValueError: the number of subdivisions must be a nonnegative even integer, + but found -1 + sage: G.subdivide_edge(0, 4, 0.5) # No. of subdivisions: 0.5 + Traceback (most recent call last): + ... + ValueError: the number of subdivisions must be a nonnegative even integer, + but found 0.500000000000000 + sage: G.subdivide_edge(0, 5, 4) + Traceback (most recent call last): + ... + ValueError: the given edge (0, 5, None) does not exist + sage: G.subdivide_edge((0, 5), 4) + Traceback (most recent call last): + ... + ValueError: the given edge (0, 5, None) does not exist + sage: G.subdivide_edge((0, 1, 'label', None), 4) + Traceback (most recent call last): + ... + ValueError: for two input arguments, the first one must be of the form + (u, v) or (u, v, l), but found: (0, 1, 'label', None) + sage: G.subdivide_edge((0), 4) + Traceback (most recent call last): + ... + TypeError: object of type 'sage.rings.integer.Integer' has no len() + + .. SEEALSO:: + + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.subdivide_edges` + """ + u, v, l, k = None, None, None, None + + if len(args) == 2: + edge, k = args + + if len(edge) == 2: + u, v = edge + if not self.has_edge(u, v): + raise ValueError(f'the given edge {(u, v, None)} does not exist') + + l = self.edge_label(u, v) + if self.allows_multiple_edges() and isinstance(l, list): + l = l[0] + + elif len(edge) == 3: + u, v, l = edge + + else: + raise ValueError('for two input arguments, the first one must be ' + f'of the form (u, v) or (u, v, l), but found: {edge}') + + elif len(args) == 3: + u, v, k = args + + if not self.has_edge(u, v): + raise ValueError(f'the given edge {(u, v, None)} does not exist') + + l = self.edge_label(u, v) + if isinstance(l, list): + l = next(iter(l)) + + elif len(args) == 4: + u, v, l, k = args + + else: + raise ValueError('this method takes at least 2 and at most 4 arguments') + + if not self.has_edge(u, v, l): + raise ValueError(f'the given edge {(u, v, l)} does not exist') + + if k < 0 or k % 2: + raise ValueError('the number of subdivisions must be a ' + f'nonnegative even integer, but found {k}') + + if k == 0: + return + + new_vertices = [self._backend.add_vertex(None) for _ in range(k)] + + M = Graph(self.get_matching()) + if M.has_edge(u, v, l): + M.delete_edge(u, v, l) + + self._backend.del_edge(u, v, l, self._directed) + self._backend.add_edges( + [(u, new_vertices[0], l), (new_vertices[-1], v, l)] + + [(new_vertices[i], new_vertices[i + 1], l) for i in range(k - 1)], + self._directed, remove_loops=True + ) + + if M.degree(u): + M.add_edges( + [(new_vertices[i], new_vertices[i + 1], l) for i in range(0, k - 1, 2)] + ) + else: + M.add_edges( + [(u, new_vertices[0], l), (new_vertices[-1], v, l)] + + [(new_vertices[i], new_vertices[i + 1], l) for i in range(1, k - 1, 2)] + ) + + self.update_matching(M) + + @doc_index('Overwritten methods') + def subdivide_edges(self, edges, k): + r""" + Subdivide `k` times edges from an iterable container. + + For more information on the behaviour of this method, please refer to + the documentation of + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.subdivide_edge`. + + .. NOTE:: + + This method overwrites the + :meth:`~sage.graphs.generic_graph.GenericGraph.subdivide_edges` + method to ensure that resultant graph is also matching covered. + + INPUT: + + - ``edges`` -- an iterable of edges, each of which given either as + ``(u, v)`` or ``(u, v, 'label')`` + + - ``k`` -- a nonnegative even integer; common length of the + subdivisions + + .. NOTE:: + + * If the given edge is labelled with `l`, all the edges created by + the subdivision will have the same label. + + * If no label given, the label obtained from + :meth:`~sage.graphs.generic_graph.GenericGraph.edge_label` will + be used. If multiple such labels are present, the first one in + the returned list will be used. + + * The number of subdivisions must be a nonnegative even integer in + order to ensure the resultant graph is matching covered. + + * In the context of matching covered graphs, *bisubdividing* an edge + *t* times is defined as subdividing the edge *2t* times, for some + nonnegative integer *t*. + + * Please note that if a single edge is present in the iterable, it + is considered only one time for the subdivision operation. + + OUTPUT: + + - If existent edges are provided with a valid format and the parameter + ``k`` in the argument is a nonnegative even integer then the graph is + updated and nothing is returned, otherwise a :exc:`ValueError` is + returned if ``k`` is not a nonnegative even integer, + + - If the graph does not contain at least one of the edges provided, a + :exc:`ValueError` is returned. Also, a :exc:`ValueError` is thrown in case + the provided arguments are not valid. + + EXAMPLES: + + Subdividing each edge of `K_4` some even number of times. Please note + that the perfect matching captured at ``self.get_matching()`` also gets + updated:: + + sage: C = graphs.CycleGraph(4) + sage: G = MatchingCoveredGraph(C) + sage: V, E = set(G.vertices()), list(G.edges(sort=True, sort_vertices=True)) + sage: M = set(G.get_matching()) + sage: G.subdivide_edges(E, 2) + sage: W, F = set(G.vertices()), list(G.edges(sort=True, sort_vertices=True)) + sage: N = set(G.get_matching()) + sage: sorted(W - V) + [4, 5, 6, 7, 8, 9, 10, 11] + sage: sorted([f for f in F if f not in E]), sorted([e for e in E if e not in F]) + ([(0, 4, None), (0, 6, None), (1, 5, None), (1, 8, None), + (2, 9, None), (2, 10, None), (3, 7, None), (3, 11, None), + (4, 5, None), (6, 7, None), (8, 9, None), (10, 11, None)], + [(0, 1, None), (0, 3, None), (1, 2, None), (2, 3, None)]) + sage: if (0, 1, None) in M: + ....: assert sorted(N - M), sorted(M - N) == \ + ....: ([(0, 8, None), (1, 9, None), (2, 4, None), (3, 5, None), \ + ....: (6, 7, None), (10, 11, None)], [(0, 1, None), (2, 3, None)]) + ....: else: + ....: assert sorted(N - M), sorted(M - N) == \ + ....: ([(0, 6, None), (1, 10, None), (2, 11, None), (3, 7, None), \ + ....: (4, 5, None), (8, 9, None)], [(0, 3, None), (1, 2, None)]) + + If a single is present multiple times in the iterable, if that many (or + more) edges are present in the graph, each of those edges gets subdivided:: + + sage: C = graphs.CycleGraph(4) + sage: G = MatchingCoveredGraph(C) + sage: G.allow_multiple_edges(True) + sage: G.add_edges([(0, 1)] * 3) + sage: V, E = set(G.vertices()), list(G.edges(sort=True, sort_vertices=True)) + sage: M = list(G.get_matching()) + sage: G.subdivide_edges([(0, 1), (0, 1, None)], 2) + sage: W, F = set(G.vertices()), list(G.edges(sort=True, sort_vertices=True)) + sage: N = set(G.get_matching()) + sage: sorted(W - V) + [4, 5, 6, 7] + sage: sorted([f for f in F if f not in E]), sorted([e for e in E if e not in F]) + ([(0, 4, None), (0, 6, None), (1, 5, None), (1, 7, None), + (4, 5, None), (6, 7, None)], [(0, 1, None), (0, 1, None)]) + sage: if (0, 1, None) in M: + ....: assert sorted(N - M), sorted(M - N) == \ + ....: ([(0, 4, None), (1, 5, None)], [(0, 1, None)]) + ....: assert sorted(N - M), sorted(M - N) == \ + ....: ([(4, 5, None)], []) + + Subdividing edges with at least one of which is a multiple edge:: + + sage: T = graphs.TricornGraph() + sage: G = MatchingCoveredGraph(T) + sage: G.allow_multiple_edges(True) + sage: G.add_edges([ + ....: (0, 1, 2), (0, 1, 3), + ....: (2, 3, 0.5), (2, 3, 4) + ....: ]) + sage: G.delete_edge(0, 1, None) + sage: V, E = set(G.vertices()), list(G.edges(sort=True, sort_vertices=True)) + sage: G.subdivide_edges([(0, 1), (1, 2), (2, 3)], 4) + ....: # edges considered: (0, 1, 2), (1, 2, None), (2, 3, None) + sage: W, F = set(G.vertices()), list(G.edges(sort=True, sort_vertices=True)) + sage: sorted(W - V) + [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21] + sage: sorted([f for f in F if f not in E]), sorted([e for e in E if e not in F]) + ([(0, 10, 2), (1, 13, 2), (1, 14, None), (2, 17, None), + (2, 18, None), (3, 21, None), (10, 11, 2), (11, 12, 2), + (12, 13, 2), (14, 15, None), (15, 16, None), (16, 17, None), + (18, 19, None), (19, 20, None), (20, 21, None)], + [(0, 1, 2), (1, 2, None), (2, 3, None)]) + + Setting ``k`` to `0` does not change the graph:: + + sage: H = G.copy() + sage: G.subdivide_edges([(0, 10), (1, 13), (2, 17)], 0) + sage: H == G and H.edges(sort=True) == G.edges(sort=True) + True + + Subdividing edges with at least one of which is nonexistent:: + + sage: G.subdivide_edges([(4, 5), (1, 5)], 4) + ....: # edges considered: (4, 5, None), (1, 5, None) + Traceback (most recent call last): + ... + ValueError: the given edge (1, 5, None) does not exist + sage: G.subdivide_edges([(0, 4), (0, 4, None)], 4) + Traceback (most recent call last): + ... + ValueError: input contains 2 copies of the edge (0, 4, None), + but the graph contains 1 + + When ``k`` is not a nonnegative even integer:: + + sage: G.subdivide_edges([(0, 1), (1, 2), (2, 3)], 3) + Traceback (most recent call last): + ... + ValueError: the number of subdivisions must be a nonnegative even integer, but found 3 + + Providing a noniterable object as ``edges``:: + + sage: G.subdivide_edges(G.order(), 4) + Traceback (most recent call last): + ... + ValueError: expected an iterable of edges, but got a non-iterable object + + Providing arguments in an invalid format:: + + sage: G.subdivide_edges([(0, ), (0, 1, 'label')], 4) + Traceback (most recent call last): + ... + ValueError: need more than 1 value to unpack for edge: (0,) + sage: G.subdivide_edges([(0, 1, 2, 4), (0, 1, 'label')], 4) + Traceback (most recent call last): + ... + ValueError: too many values to unpack (expected 2) for edge: (0, 1, 2, 4) + sage: G.subdivide_edges([0, (0, 1, 'label')], 4) + Traceback (most recent call last): + ... + TypeError: input edge 0 is of unknown type + + .. SEEALSO:: + + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.subdivide_edge` + """ + from collections.abc import Iterable + if not isinstance(edges, Iterable): + raise ValueError('expected an iterable of edges, but got a non-iterable object') + + if k < 0 or k % 2: + raise ValueError('the number of subdivisions must be a ' + f'nonnegative even integer, but found {k}') + + if k == 0: + return + + for i, edge in enumerate(edges): + if hasattr(edge, '__len__'): + if len(edge) <= 1: + raise ValueError('need more than 1 value to unpack ' + f'for edge: {edge}') + + elif len(edge) > 3: + raise ValueError('too many values to unpack (expected 2) ' + f'for edge: {edge}') + + else: + raise TypeError(f'input edge {edge} is of unknown type') + + u, v, l = None, None, None + + if len(edge) == 2: + u, v = edge + if not self.has_edge(u, v): + raise ValueError(f'the given edge {(u, v, None)} does not exist') + + l = self.edge_label(u, v) + if self.allows_multiple_edges() and isinstance(l, list): + l = l[0] + + elif len(edge) == 3: + u, v, l = edge + + edges[i] = (u, v, l) + + from collections import Counter + edge_frequency = Counter(edges) + + for edge, n in edge_frequency.items(): + u, v, l = edge + + labels = self.edge_label(u, v) + c = labels.count(l) if self.allows_multiple_edges() and isinstance(labels, list) else 1 + + if c < n: + raise ValueError(f'input contains {n} copies of the edge ' + f'{edge}, but the graph contains {c}') + + new_vertices = [self._backend.add_vertex(None) for _ in range(k * len(edges))] + M = Graph(self.get_matching()) + + for i, edge in enumerate(edges): + u, v, l = edge + + self._backend.del_edge(u, v, l, self._directed) + self._backend.add_edges( + [(u, new_vertices[i * k], l), (new_vertices[(i + 1) * k - 1], v, l)] + + [(new_vertices[i * k + j], new_vertices[i * k + j + 1], l) for j in range(k - 1)], + self._directed, remove_loops=True + ) + + if M.has_edge(u, v, l): + M.delete_edge(u, v, l) + + if M.degree(u): + M.add_edges((new_vertices[i * k + j], new_vertices[i * k + j + 1], l) + for j in range(0, k - 1, 2)) + else: + M.add_edges( + [(u, new_vertices[i * k], l), (new_vertices[(i + 1) * k - 1], v, l)] + + [(new_vertices[i * k + j], new_vertices[i * k + j + 1], l) for j in range(1, k - 1, 2)] + ) + + self.update_matching(M) + @doc_index('Miscellaneous methods') def update_matching(self, matching): r""" @@ -3557,4 +4047,4 @@ def update_matching(self, matching): raise exception -__doc__ = __doc__.replace('{INDEX_OF_METHODS}', gen_thematic_rest_table_index(MatchingCoveredGraph, only_local_functions=False)) +__doc__ = __doc__.replace('{INDEX_OF_METHODS}', gen_thematic_rest_table_index(MatchingCoveredGraph, only_local_functions=False)) \ No newline at end of file diff --git a/src/sage/version.py b/src/sage/version.py index c5a29d9d727..aca8b9a4bf7 100644 --- a/src/sage/version.py +++ b/src/sage/version.py @@ -1,5 +1,5 @@ # Sage version information for Python scripts # This file is auto-generated by the sage-update-version script, do not edit! -version = '10.7.beta0' -date = '2025-04-02' -banner = 'SageMath version 10.7.beta0, Release Date: 2025-04-02' +version = '10.6.rc1' +date = '2025-03-27' +banner = 'SageMath version 10.6.rc1, Release Date: 2025-03-27'