From eefea4228ded615260967fd114c81b013ac909cb Mon Sep 17 00:00:00 2001 From: Giorgos Mousa Date: Sun, 5 May 2024 21:40:23 +0300 Subject: [PATCH 1/4] Support morphisms in `Matroid` constructor --- src/sage/matroids/constructor.py | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/sage/matroids/constructor.py b/src/sage/matroids/constructor.py index cecfead568a..afbba5b58f5 100644 --- a/src/sage/matroids/constructor.py +++ b/src/sage/matroids/constructor.py @@ -533,6 +533,23 @@ def Matroid(groundset=None, data=None, **kwds): sage: M.base_ring() Integer Ring + A morphism representation of a :class:`LinearMatroid` can also be used as + input:: + + sage: M = matroids.catalog.Fano() + sage: A = M.representation(order=True, labels=True); A + (Generic morphism: + From: Free module generated by {'a', 'b', 'c', 'd', 'e', 'f', 'g'} over + Finite Field of size 2 + To: Free module generated by {0, 1, 2} over Finite Field of size 2, + ['a', 'b', 'c', 'd', 'e', 'f', 'g']) + sage: N = Matroid(A); N + Binary matroid of rank 3 on 7 elements, type (3, 0) + sage: N.groundset() + frozenset({'a', 'b', 'c', 'd', 'e', 'f', 'g'}) + sage: M.is_isomorphic(N) + True + #. Rank function: Any function mapping subsets to integers can be used as input:: @@ -713,7 +730,7 @@ def Matroid(groundset=None, data=None, **kwds): if data is None: for k in ['bases', 'independent_sets', 'circuits', 'nonspanning_circuits', 'flats', 'graph', 'matrix', - 'reduced_matrix', 'rank_function', 'revlex', + 'reduced_matrix', 'morphism', 'rank_function', 'revlex', 'circuit_closures', 'matroid']: if k in kwds: data = kwds.pop(k) @@ -734,6 +751,8 @@ def Matroid(groundset=None, data=None, **kwds): key = 'graph' elif is_Matrix(data): key = 'matrix' + elif isinstance(data, sage.modules.with_basis.morphism.ModuleMorphism) or isinstance(data, tuple): + key = 'morphism' elif isinstance(data, sage.matroids.matroid.Matroid): key = 'matroid' elif isinstance(data, str): @@ -856,9 +875,15 @@ def Matroid(groundset=None, data=None, **kwds): M = GraphicMatroid(G, groundset=groundset) # Matrices: - elif key in ['matrix', 'reduced_matrix']: + elif key in ['matrix', 'reduced_matrix', 'morphism']: A = data is_reduced = (key == 'reduced_matrix') + if key == 'morphism': + if isinstance(data, tuple): + A = data[0] + groundset = data[1] + if isinstance(A, sage.modules.with_basis.morphism.ModuleMorphism): + A = A.matrix() # Fix the representation if not is_Matrix(A): From c94f52407df1d5ff8a5188185540eaab53ab6742 Mon Sep 17 00:00:00 2001 From: Giorgos Mousa Date: Sun, 5 May 2024 21:57:06 +0300 Subject: [PATCH 2/4] Mention new `morphism` keyword in docstrings --- src/sage/matroids/constructor.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/matroids/constructor.py b/src/sage/matroids/constructor.py index afbba5b58f5..bb989f4605b 100644 --- a/src/sage/matroids/constructor.py +++ b/src/sage/matroids/constructor.py @@ -188,6 +188,7 @@ def Matroid(groundset=None, data=None, **kwds): ``reduced_matrix = A`` then the matroid is represented by `[I\ \ A]` where `I` is an appropriately sized identity matrix. + - ``morphism`` -- A morphism representation of the matroid. - ``rank_function`` -- A function that computes the rank of each subset. Can only be provided together with a groundset. - ``circuit_closures`` -- Either a list of tuples ``(k, C)`` with ``C`` From 796dd1694a017ef9318c4c242844eb672b6b8f2a Mon Sep 17 00:00:00 2001 From: Giorgos Mousa Date: Tue, 7 May 2024 02:43:41 +0300 Subject: [PATCH 3/4] Get groundset from morphism domain --- src/sage/matroids/constructor.py | 62 +++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/src/sage/matroids/constructor.py b/src/sage/matroids/constructor.py index bb989f4605b..a1f5e403c3c 100644 --- a/src/sage/matroids/constructor.py +++ b/src/sage/matroids/constructor.py @@ -189,6 +189,7 @@ def Matroid(groundset=None, data=None, **kwds): then the matroid is represented by `[I\ \ A]` where `I` is an appropriately sized identity matrix. - ``morphism`` -- A morphism representation of the matroid. + - ``reduced_morphism`` -- A reduced morphism representation of the matroid. - ``rank_function`` -- A function that computes the rank of each subset. Can only be provided together with a groundset. - ``circuit_closures`` -- Either a list of tuples ``(k, C)`` with ``C`` @@ -538,17 +539,42 @@ def Matroid(groundset=None, data=None, **kwds): input:: sage: M = matroids.catalog.Fano() - sage: A = M.representation(order=True, labels=True); A - (Generic morphism: - From: Free module generated by {'a', 'b', 'c', 'd', 'e', 'f', 'g'} over - Finite Field of size 2 - To: Free module generated by {0, 1, 2} over Finite Field of size 2, - ['a', 'b', 'c', 'd', 'e', 'f', 'g']) + sage: A = M.representation(order=True); A + Generic morphism: + From: Free module generated by {'a', 'b', 'c', 'd', 'e', 'f', 'g'} over + Finite Field of size 2 + To: Free module generated by {0, 1, 2} over Finite Field of size 2 + sage: A._unicode_art_matrix() + a b c d e f g + 0⎛1 0 0 0 1 1 1⎞ + 1⎜0 1 0 1 0 1 1⎟ + 2⎝0 0 1 1 1 0 1⎠ sage: N = Matroid(A); N Binary matroid of rank 3 on 7 elements, type (3, 0) sage: N.groundset() frozenset({'a', 'b', 'c', 'd', 'e', 'f', 'g'}) - sage: M.is_isomorphic(N) + sage: M == N + True + + The keywords `morphism` and `reduced_morphism` are also available:: + + sage: M = matroids.catalog.RelaxedNonFano("abcdefg") + sage: A = M.representation(order=True, reduced=True); A + Generic morphism: + From: Free module generated by {'d', 'e', 'f', 'g'} over + Finite Field in w of size 2^2 + To: Free module generated by {'a', 'b', 'c'} over + Finite Field in w of size 2^2 + sage: A._unicode_art_matrix() + d e f g + a⎛1 1 0 1⎞ + b⎜1 0 1 1⎟ + c⎝0 1 w 1⎠ + sage: N = Matroid(reduced_morphism=A); N + Quaternary matroid of rank 3 on 7 elements + sage: N.groundset() + frozenset({'a', 'b', 'c', 'd', 'e', 'f', 'g'}) + sage: M == N True #. Rank function: @@ -731,8 +757,8 @@ def Matroid(groundset=None, data=None, **kwds): if data is None: for k in ['bases', 'independent_sets', 'circuits', 'nonspanning_circuits', 'flats', 'graph', 'matrix', - 'reduced_matrix', 'morphism', 'rank_function', 'revlex', - 'circuit_closures', 'matroid']: + 'reduced_matrix', 'morphism', 'reduced_morphism', + 'rank_function', 'revlex', 'circuit_closures', 'matroid']: if k in kwds: data = kwds.pop(k) key = k @@ -752,7 +778,9 @@ def Matroid(groundset=None, data=None, **kwds): key = 'graph' elif is_Matrix(data): key = 'matrix' - elif isinstance(data, sage.modules.with_basis.morphism.ModuleMorphism) or isinstance(data, tuple): + elif isinstance(data, sage.modules.with_basis.morphism.ModuleMorphism) or ( + isinstance(data, tuple) and + isinstance(data[0], sage.modules.with_basis.morphism.ModuleMorphism)): key = 'morphism' elif isinstance(data, sage.matroids.matroid.Matroid): key = 'matroid' @@ -876,15 +904,17 @@ def Matroid(groundset=None, data=None, **kwds): M = GraphicMatroid(G, groundset=groundset) # Matrices: - elif key in ['matrix', 'reduced_matrix', 'morphism']: + elif key in ['matrix', 'reduced_matrix', 'morphism', 'reduced_morphism']: A = data - is_reduced = (key == 'reduced_matrix') - if key == 'morphism': + is_reduced = (key == 'reduced_matrix' or key == 'reduced_morphism') + if key == 'morphism' or key == 'reduced_morphism': if isinstance(data, tuple): A = data[0] - groundset = data[1] - if isinstance(A, sage.modules.with_basis.morphism.ModuleMorphism): - A = A.matrix() + if groundset is None: + groundset = list(A.domain().basis().keys()) + if is_reduced: + groundset = list(A.codomain().basis().keys()) + groundset + A = A.matrix() # Fix the representation if not is_Matrix(A): From 13e499ac034da22bebac9f0edd8b7daf54331b19 Mon Sep 17 00:00:00 2001 From: Giorgos Mousa Date: Tue, 7 May 2024 04:14:52 +0300 Subject: [PATCH 4/4] Constructor: Support `LinearMatroid` representation with `labels=True` Also get groundset labels --- src/sage/matroids/constructor.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/sage/matroids/constructor.py b/src/sage/matroids/constructor.py index a1f5e403c3c..07e8597fdb8 100644 --- a/src/sage/matroids/constructor.py +++ b/src/sage/matroids/constructor.py @@ -556,7 +556,7 @@ def Matroid(groundset=None, data=None, **kwds): sage: M == N True - The keywords `morphism` and `reduced_morphism` are also available:: + The keywords ``morphism`` and ``reduced_morphism`` are also available:: sage: M = matroids.catalog.RelaxedNonFano("abcdefg") sage: A = M.representation(order=True, reduced=True); A @@ -776,7 +776,8 @@ def Matroid(groundset=None, data=None, **kwds): Graph = () if isinstance(data, Graph): key = 'graph' - elif is_Matrix(data): + elif is_Matrix(data) or ( + isinstance(data, tuple) and is_Matrix(data[0])): key = 'matrix' elif isinstance(data, sage.modules.with_basis.morphism.ModuleMorphism) or ( isinstance(data, tuple) and @@ -907,9 +908,14 @@ def Matroid(groundset=None, data=None, **kwds): elif key in ['matrix', 'reduced_matrix', 'morphism', 'reduced_morphism']: A = data is_reduced = (key == 'reduced_matrix' or key == 'reduced_morphism') + if isinstance(data, tuple): + A = data[0] + if key == 'matrix' or key == 'reduced_matrix': + if groundset is None: + groundset = data[1] + if is_reduced: + groundset += data[2] if key == 'morphism' or key == 'reduced_morphism': - if isinstance(data, tuple): - A = data[0] if groundset is None: groundset = list(A.domain().basis().keys()) if is_reduced: