Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

matrix, Graph.incidence_matrix, LinearMatroid.representation: Support constructing Hom(CombinatorialFreeModule) elements #37692

Merged
merged 32 commits into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
04f3655
Merge branch 'MatrixSpaceCFM' into matrix_keys
mkoeppe Mar 29, 2024
4a65059
matrix: Handle column_keys, row_keys
mkoeppe Mar 1, 2024
faf6094
matrix: Delegate to new method MatrixArgs.element
mkoeppe Mar 2, 2024
c0689fe
MatrixArgs.set_space: Handle case of homset
mkoeppe Mar 2, 2024
5ab473a
fix MatrixArgs.element
xuluze Mar 4, 2024
b00bcde
WIP
mkoeppe Mar 12, 2024
fabf5c8
Fixup
mkoeppe Mar 12, 2024
6a9ddb8
src/sage/modules/free_module.py: Allow passing both rank and basis_ke…
mkoeppe Mar 13, 2024
4bc6dd9
src/sage/matrix/args.pyx: Handle initialization when nrows, ncols are…
mkoeppe Mar 13, 2024
c76a6e6
src/sage/matrix/args.pyx: Fix side of intermediate matrix
mkoeppe Mar 13, 2024
9385b1f
src/sage/matrix/args.pyx, src/sage/matrix/constructor.pyx: Fixups
mkoeppe Mar 13, 2024
05a824a
Merge branch 'clang16' into matrix_keys
mkoeppe Mar 29, 2024
c01fc08
Merge branch 'border_matrix' into matrix_keys
mkoeppe Mar 29, 2024
a4b65a9
src/sage/categories/finite_dimensional_modules_with_basis.py: Add met…
mkoeppe Mar 13, 2024
7ade84c
MatrixArgs._ensure_nrows_ncols: inline
mkoeppe Mar 29, 2024
a8c8303
MatrixArgs.element: Remove parameter 'convert', add doc
mkoeppe Mar 29, 2024
bd2c464
MatrixArgs.set_{row,column}_keys: Add examples
mkoeppe Mar 29, 2024
4aa9e0e
GenericGraph.adjacency_matrix: If vertices=True, edges=True, construc…
mkoeppe Mar 30, 2024
ceedc39
Matrix_mod2_dense.str: Accept and pass on parameters left_border, ...
mkoeppe Mar 30, 2024
a887566
LinearMatroid.representation: if order=True, return a morphism
mkoeppe Mar 30, 2024
0a59764
src/sage/modules/free_module.py: Fix doctest output
mkoeppe Mar 30, 2024
ddb6f25
Merge branch 'border_matrix' into matrix_keys
mkoeppe Mar 30, 2024
642d569
GenericGraph.incidence_matrix: Remove misleading indentation of docte…
mkoeppe Mar 30, 2024
85a4a50
src/sage/matrix/constructor.pyx: Expand a doctest
mkoeppe Mar 30, 2024
705608a
GenericGraph.incidence_matrix: Expand doctest
mkoeppe Mar 30, 2024
94a2b7a
Merge branch 'MatrixSpaceCFM' into matrix_keys
mkoeppe Apr 1, 2024
219e188
Apply suggestions from code review
mkoeppe Apr 4, 2024
7377b9f
Merge branch 'MatrixSpaceCFM' into matrix_keys
mkoeppe Apr 4, 2024
7c9f4de
Merge branch 'MatrixSpaceCFM' into matrix_keys
mkoeppe Apr 8, 2024
d283252
Merge remote-tracking branch 'upstream/develop' into matrix_keys
mkoeppe Apr 9, 2024
6126a52
Merge branch 'MatrixSpaceCFM' into matrix_keys
mkoeppe Apr 20, 2024
3e71e20
Merge remote-tracking branch 'upstream/develop' into matrix_keys
mkoeppe Apr 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions src/sage/categories/finite_dimensional_modules_with_basis.py
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,96 @@
m.set_immutable()
return m

def _repr_matrix(self):
r"""
Return a string representation of this morphism (as a matrix).

EXAMPLES::

sage: M = matrix(ZZ, [[1, 0, 0], [0, 1, 0]],
....: column_keys=['a', 'b', 'c'],
....: row_keys=['v', 'w']); M
Generic morphism:
From: Free module generated by {'a', 'b', 'c'} over Integer Ring
To: Free module generated by {'v', 'w'} over Integer Ring
sage: M._repr_ = M._repr_matrix
sage: M # indirect doctest
a b c
v[1 0 0]
w[0 1 0]
"""
matrix = self.matrix()

from sage.matrix.constructor import options

if matrix.nrows() <= options.max_rows() and matrix.ncols() <= options.max_cols():
return matrix.str(top_border=self.domain().basis().keys(),
left_border=self.codomain().basis().keys())

return repr(matrix)

Check warning on line 705 in src/sage/categories/finite_dimensional_modules_with_basis.py

View check run for this annotation

Codecov / codecov/patch

src/sage/categories/finite_dimensional_modules_with_basis.py#L705

Added line #L705 was not covered by tests

def _ascii_art_matrix(self):
r"""
Return an ASCII art representation of this morphism (as a matrix).

EXAMPLES::

sage: M = matrix(ZZ, [[1, 0, 0], [0, 1, 0]],
....: column_keys=['a', 'b', 'c'],
....: row_keys=['v', 'w']); M
Generic morphism:
From: Free module generated by {'a', 'b', 'c'} over Integer Ring
To: Free module generated by {'v', 'w'} over Integer Ring
sage: M._ascii_art_ = M._ascii_art_matrix
sage: ascii_art(M) # indirect doctest
a b c
v[1 0 0]
w[0 1 0]
"""
matrix = self.matrix()

from sage.matrix.constructor import options

if matrix.nrows() <= options.max_rows() and matrix.ncols() <= options.max_cols():
return matrix.str(character_art=True,
top_border=self.domain().basis().keys(),
left_border=self.codomain().basis().keys())

from sage.typeset.ascii_art import AsciiArt

Check warning on line 734 in src/sage/categories/finite_dimensional_modules_with_basis.py

View check run for this annotation

Codecov / codecov/patch

src/sage/categories/finite_dimensional_modules_with_basis.py#L734

Added line #L734 was not covered by tests

return AsciiArt(repr(self).splitlines())

Check warning on line 736 in src/sage/categories/finite_dimensional_modules_with_basis.py

View check run for this annotation

Codecov / codecov/patch

src/sage/categories/finite_dimensional_modules_with_basis.py#L736

Added line #L736 was not covered by tests

def _unicode_art_matrix(self):
r"""
Return a unicode art representation of this morphism (as a matrix).

EXAMPLES::

sage: M = matrix(ZZ, [[1, 0, 0], [0, 1, 0]],
....: column_keys=['a', 'b', 'c'],
....: row_keys=['v', 'w']); M
Generic morphism:
From: Free module generated by {'a', 'b', 'c'} over Integer Ring
To: Free module generated by {'v', 'w'} over Integer Ring
sage: M._unicode_art_ = M._unicode_art_matrix
sage: unicode_art(M) # indirect doctest
a b c
v⎛1 0 0⎞
w⎝0 1 0⎠
"""
matrix = self.matrix()

from sage.matrix.constructor import options

if matrix.nrows() <= options.max_rows() and matrix.ncols() <= options.max_cols():
return matrix.str(unicode=True, character_art=True,
top_border=self.domain().basis().keys(),
left_border=self.codomain().basis().keys())

from sage.typeset.unicode_art import UnicodeArt

Check warning on line 765 in src/sage/categories/finite_dimensional_modules_with_basis.py

View check run for this annotation

Codecov / codecov/patch

src/sage/categories/finite_dimensional_modules_with_basis.py#L765

Added line #L765 was not covered by tests

return UnicodeArt(repr(self).splitlines())

Check warning on line 767 in src/sage/categories/finite_dimensional_modules_with_basis.py

View check run for this annotation

Codecov / codecov/patch

src/sage/categories/finite_dimensional_modules_with_basis.py#L767

Added line #L767 was not covered by tests

def __invert__(self):
"""
Return the inverse morphism of ``self``.
Expand Down
70 changes: 59 additions & 11 deletions src/sage/graphs/generic_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -2126,15 +2126,23 @@ def incidence_matrix(self, oriented=None, sparse=True, vertices=None, edges=None
- ``sparse`` -- boolean (default: ``True``); whether to use a sparse or
a dense matrix

- ``vertices`` -- list (default: ``None``); when specified, the `i`-th
row of the matrix corresponds to the `i`-th vertex in the ordering of
``vertices``, otherwise, the `i`-th row of the matrix corresponds to
the `i`-th vertex in the ordering given by method :meth:`vertices`.
- ``vertices`` -- list, ``None``, or ``True`` (default: ``None``);

- ``edges`` -- list (default: ``None``); when specified, the `i`-th
column of the matrix corresponds to the `i`-th edge in the ordering of
``edges``, otherwise, the `i`-th column of the matrix corresponds to
the `i`-th edge in the ordering given by method :meth:`edge_iterator`.
- when a list, the `i`-th row of the matrix corresponds to the `i`-th
vertex in the ordering of ``vertices``,
- when ``None``, the `i`-th row of the matrix corresponds to
the `i`-th vertex in the ordering given by method :meth:`vertices`,
- when ``True``, construct a morphism of free modules instead of a matrix,
where the codomain's basis is indexed by the vertices.

- ``edges`` -- list, ``None``, or ``True`` (default: ``None``);

- when a list, the `i`-th column of the matrix corresponds to the `i`-th
edge in the ordering of ``edges``,
- when ``None``, the `i`-th column of the matrix corresponds to
the `i`-th edge in the ordering given by method :meth:`edge_iterator`,
- when ``True``, construct a morphism of free modules instead of a matrix,
where the domain's basis is indexed by the edges.

- ``base_ring`` -- a ring (default: ``ZZ``); the base ring of the matrix
space to use.
Expand Down Expand Up @@ -2258,6 +2266,32 @@ def incidence_matrix(self, oriented=None, sparse=True, vertices=None, edges=None
ValueError: matrix is immutable; please change a copy instead
(i.e., use copy(M) to change a copy of M).

Creating a module morphism::

sage: # needs sage.modules
sage: D12 = posets.DivisorLattice(12).hasse_diagram()
sage: phi_VE = D12.incidence_matrix(vertices=True, edges=True); phi_VE
Generic morphism:
From: Free module generated by
{(1, 2), (1, 3), (2, 4), (2, 6), (3, 6), (4, 12), (6, 12)}
over Integer Ring
To: Free module generated by {1, 2, 3, 4, 6, 12} over Integer Ring
sage: print(phi_VE._unicode_art_matrix())
(1, 2) (1, 3) (2, 4) (2, 6) (3, 6) (4, 12) (6, 12)
1⎛ -1 -1 0 0 0 0 0⎞
2⎜ 1 0 -1 -1 0 0 0⎟
3⎜ 0 1 0 0 -1 0 0⎟
4⎜ 0 0 1 0 0 -1 0⎟
6⎜ 0 0 0 1 1 0 -1⎟
12⎝ 0 0 0 0 0 1 1⎠
sage: E = phi_VE.domain()
sage: P1 = E.monomial((2, 4)) + E.monomial((4, 12)); P1
B[(2, 4)] + B[(4, 12)]
sage: P2 = E.monomial((2, 6)) + E.monomial((6, 12)); P2
B[(2, 6)] + B[(6, 12)]
sage: phi_VE(P1 - P2)
0

TESTS::

sage: P5 = graphs.PathGraph(5)
Expand All @@ -2279,15 +2313,24 @@ def incidence_matrix(self, oriented=None, sparse=True, vertices=None, edges=None
if oriented is None:
oriented = self.is_directed()

if vertices is None:
row_keys = None
if vertices is True:
vertices = self.vertices(sort=False)
row_keys = tuple(vertices) # because a list is not hashable
elif vertices is None:
vertices = self.vertices(sort=False)
elif (len(vertices) != self.num_verts() or
set(vertices) != set(self.vertex_iterator())):
raise ValueError("parameter vertices must be a permutation of the vertices")

column_keys = None
verts = {v: i for i, v in enumerate(vertices)}
if edges is None:
edges = self.edge_iterator(labels=False)
use_edge_labels = kwds.pop('use_edge_labels', False)
if edges is True:
edges = self.edges(labels=use_edge_labels)
column_keys = tuple(edges) # because an EdgesView is not hashable
elif edges is None:
edges = self.edge_iterator(labels=use_edge_labels)
elif len(edges) != self.size():
raise ValueError("parameter edges must be a permutation of the edges")
else:
Expand Down Expand Up @@ -2319,8 +2362,13 @@ def reorder(u, v):
m[verts[e[0]], i] += 1
m[verts[e[1]], i] += 1

if row_keys is not None or column_keys is not None:
m.set_immutable()
return matrix(m, row_keys=row_keys, column_keys=column_keys)

if immutable:
m.set_immutable()

return m

def distance_matrix(self, vertices=None, *, base_ring=None, **kwds):
Expand Down
23 changes: 22 additions & 1 deletion src/sage/matrix/args.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,15 @@ cdef class MatrixArgs:
cdef public Parent space # parent of matrix
cdef public Parent base # parent of entries
cdef public long nrows, ncols
cdef public object row_keys, column_keys
cdef public object entries
cdef entries_type typ
cdef public bint sparse
cdef public dict kwds # **kwds for MatrixSpace()
cdef bint is_finalized

cpdef Matrix matrix(self, bint convert=?) noexcept
cpdef element(self, bint immutable=?) noexcept
cpdef list list(self, bint convert=?) noexcept
cpdef dict dict(self, bint convert=?) noexcept

Expand Down Expand Up @@ -89,7 +91,11 @@ cdef class MatrixArgs:
raise ArithmeticError("number of columns must be non-negative")
cdef long p = self.ncols
if p != -1 and p != n:
raise ValueError(f"inconsistent number of columns: should be {p} but got {n}")
raise ValueError(f"inconsistent number of columns: should be {p} "
f"but got {n}")
if self.column_keys is not None and n != len(self.column_keys):
raise ValueError(f"inconsistent number of columns: should be cardinality of {self.column_keys} "
f"but got {n}")
self.ncols = n

cdef inline int set_nrows(self, long n) except -1:
Expand All @@ -102,8 +108,23 @@ cdef class MatrixArgs:
cdef long p = self.nrows
if p != -1 and p != n:
raise ValueError(f"inconsistent number of rows: should be {p} but got {n}")
if self.row_keys is not None and n != len(self.row_keys):
raise ValueError(f"inconsistent number of rows: should be cardinality of {self.row_keys} "
f"but got {n}")
self.nrows = n

cdef inline int _ensure_nrows_ncols(self) except -1:
r"""
Make sure that the number of rows and columns is set.
If ``row_keys`` or ``column_keys`` is not finite, this can raise an exception.
"""
if self.nrows == -1:
self.nrows = len(self.row_keys)
if self.ncols == -1:
self.ncols = len(self.column_keys)

cpdef int set_column_keys(self, column_keys) except -1
cpdef int set_row_keys(self, row_keys) except -1
cpdef int set_space(self, space) except -1

cdef int finalize(self) except -1
Expand Down
Loading
Loading