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 all 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 @@ -679,6 +679,96 @@ def matrix(self, base_ring=None, side="left"):
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)

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

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

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

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

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=?)
cpdef element(self, bint immutable=?)
cpdef list list(self, bint convert=?)
cpdef dict dict(self, bint convert=?)

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