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

MatrixSpace: Support constructing Hom(CombinatorialFreeModule) #37514

Merged
merged 12 commits into from
Apr 27, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
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
33 changes: 20 additions & 13 deletions src/sage/matrix/args.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -324,21 +324,27 @@ cdef class MatrixArgs:

sage: from sage.matrix.args import MatrixArgs
sage: MatrixArgs().finalized()
<MatrixArgs for Full MatrixSpace of 0 by 0 dense matrices over Integer Ring; typ=ZERO; entries=None>
<MatrixArgs for Full MatrixSpace of 0 by 0 dense matrices over
Integer Ring; typ=ZERO; entries=None>
sage: MatrixArgs(1).finalized()
<MatrixArgs for Full MatrixSpace of 1 by 1 dense matrices over Integer Ring; typ=ZERO; entries=None>
<MatrixArgs for Full MatrixSpace of 1 by 1 dense matrices over
Integer Ring; typ=ZERO; entries=None>
sage: MatrixArgs(1, 1, 3).finalized()
<MatrixArgs for Full MatrixSpace of 1 by 1 dense matrices over Integer Ring; typ=SCALAR; entries=3>
<MatrixArgs for Full MatrixSpace of 1 by 1 dense matrices over
Integer Ring; typ=SCALAR; entries=3>
sage: MatrixArgs(1, 1, 1, 1).finalized()
Traceback (most recent call last):
...
TypeError: too many arguments in matrix constructor
sage: MatrixArgs(3, nrows=1, ncols=1).finalized()
<MatrixArgs for Full MatrixSpace of 1 by 1 dense matrices over Integer Ring; typ=SCALAR; entries=3>
<MatrixArgs for Full MatrixSpace of 1 by 1 dense matrices over
Integer Ring; typ=SCALAR; entries=3>
sage: MatrixArgs(3, nrows=1).finalized()
<MatrixArgs for Full MatrixSpace of 1 by 1 dense matrices over Integer Ring; typ=SCALAR; entries=3>
<MatrixArgs for Full MatrixSpace of 1 by 1 dense matrices over
Integer Ring; typ=SCALAR; entries=3>
sage: MatrixArgs(3, ncols=1).finalized()
<MatrixArgs for Full MatrixSpace of 1 by 1 dense matrices over Integer Ring; typ=SCALAR; entries=3>
<MatrixArgs for Full MatrixSpace of 1 by 1 dense matrices over
Integer Ring; typ=SCALAR; entries=3>
"""
self.base = ring
if nrows is not None:
Expand Down Expand Up @@ -639,8 +645,8 @@ cdef class MatrixArgs:

INPUT:

- ``convert`` -- if True, the matrix is guaranteed to have
the correct parent matrix space. If False, the input matrix
- ``convert`` -- if ``True``, the matrix is guaranteed to have
the correct parent matrix space. If ``False``, the input matrix
may be returned even if it lies in the wrong space.

.. NOTE::
Expand Down Expand Up @@ -730,7 +736,7 @@ cdef class MatrixArgs:

INPUT:

- ``convert`` -- If True, the entries are converted to the base
- ``convert`` -- If ``True``, the entries are converted to the base
ring. Otherwise, the entries are returned as given.

.. NOTE::
Expand Down Expand Up @@ -790,11 +796,12 @@ cdef class MatrixArgs:

cpdef dict dict(self, bint convert=True) noexcept:
"""
Return the entries of the matrix as a dict. The keys of this
dict are the non-zero positions ``(i,j)``. The corresponding
value is the entry at that position. Zero values are skipped.
Return the entries of the matrix as a :class:`dict`.

If ``convert`` is True, the entries are converted to the base
The keys of this :class:`dict` are the non-zero positions ``(i,j)``. The
corresponding value is the entry at that position. Zero values are skipped.

If ``convert`` is ``True``, the entries are converted to the base
ring. Otherwise, the entries are returned as given.

EXAMPLES::
Expand Down
22 changes: 11 additions & 11 deletions src/sage/matrix/constructor.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def matrix(*args, **kwds):

INPUT:

The matrix command takes the entries of a matrix, optionally
The :func:`matrix` command takes the entries of a matrix, optionally
preceded by a ring and the dimensions of the matrix, and returns a
matrix.

Expand All @@ -49,11 +49,11 @@ def matrix(*args, **kwds):
columns. You can create a matrix of zeros by passing an empty list
or the integer zero for the entries. To construct a multiple of
the identity (`cI`), you can specify square dimensions and pass in
`c`. Calling matrix() with a Sage object may return something that
makes sense. Calling matrix() with a NumPy array will convert the
`c`. Calling :func:`matrix` with a Sage object may return something that
makes sense. Calling :func:`matrix` with a NumPy array will convert the
array to a matrix.

All arguments (even the positional) are optional.
All arguments (even the positional ones) are optional.

Positional and keyword arguments:

Expand Down Expand Up @@ -135,37 +135,37 @@ def matrix(*args, **kwds):

::

sage: v1=vector((1,2,3))
sage: v2=vector((4,5,6))
sage: v1 = vector((1,2,3))
sage: v2 = vector((4,5,6))
sage: m = matrix([v1,v2]); m; m.parent()
[1 2 3]
[4 5 6]
Full MatrixSpace of 2 by 3 dense matrices over Integer Ring

::

sage: m = matrix(QQ,2,[1,2,3,4,5,6]); m; m.parent()
sage: m = matrix(QQ, 2, [1,2,3,4,5,6]); m; m.parent()
[1 2 3]
[4 5 6]
Full MatrixSpace of 2 by 3 dense matrices over Rational Field

::

sage: m = matrix(QQ,2,3,[1,2,3,4,5,6]); m; m.parent()
sage: m = matrix(QQ, 2, 3, [1,2,3,4,5,6]); m; m.parent()
[1 2 3]
[4 5 6]
Full MatrixSpace of 2 by 3 dense matrices over Rational Field

::

sage: m = matrix({(0,1): 2, (1,1):2/5}); m; m.parent()
sage: m = matrix({(0,1): 2, (1,1): 2/5}); m; m.parent()
[ 0 2]
[ 0 2/5]
Full MatrixSpace of 2 by 2 sparse matrices over Rational Field

::

sage: m = matrix(QQ,2,3,{(1,1): 2}); m; m.parent()
sage: m = matrix(QQ, 2, 3, {(1,1): 2}); m; m.parent()
[0 0 0]
[0 2 0]
Full MatrixSpace of 2 by 3 sparse matrices over Rational Field
Expand Down Expand Up @@ -234,7 +234,7 @@ def matrix(*args, **kwds):

::

sage: M = Matrix([[1,2,3],[4,5,6],[7,8,9]], immutable=True)
sage: M = Matrix([[1,2,3], [4,5,6], [7,8,9]], immutable=True)
sage: M[0] = [9,9,9]
Traceback (most recent call last):
...
Expand Down
181 changes: 112 additions & 69 deletions src/sage/matrix/matrix_space.py
Original file line number Diff line number Diff line change
Expand Up @@ -434,9 +434,73 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation):

class MatrixSpace(UniqueRepresentation, Parent):
"""
The space of matrices of given size and base ring
The space of matrices of given size and base ring.

EXAMPLES:
INPUT:

- ``base_ring`` -- a ring

- ``nrows`` or ``row_keys`` -- (nonnegative integer) the number of rows, or
a finite family of arbitrary objects that index the rows of the matrix

- ``ncols`` or ``column_keys`` -- (nonnegative integer, default ``nrows``)
the number of columns, or a finite family of arbitrary objects that index
the columns of the matrix

- ``sparse`` -- (boolean, default ``False``) whether or not matrices
are given a sparse representation

- ``implementation`` -- (optional, a string or a matrix class) a possible
implementation. Depending on the base ring, the string can be

- ``'generic'`` -- on any base rings

- ``'flint'`` -- for integers and rationals

- ``'meataxe'`` -- finite fields using the optional package :ref:`spkg_meataxe`

- ``'m4ri'`` -- for characteristic 2 using the :ref:`spkg_m4ri` library

- ``'linbox-float'`` -- for integer mod rings up to `2^8 = 256`

- ``'linbox-double'`` -- for integer mod rings up to
`floor(2^26*sqrt(2) + 1/2) = 94906266`

- ``'numpy'`` -- for real and complex floating point numbers

OUTPUT: a matrix space or, more generally, a homspace between free modules.

This factory function creates instances of various specialized classes
depending on the input. Not all combinations of options are
implemented.

- If the parameters ``row_keys`` or ``column_keys`` are provided, they
must be finite families of objects. In this case, instances of
:class:`CombinatorialFreeModule` are created via the factory function
:func:`FreeModule`. Then the homspace between these modules is returned.

EXAMPLES::

sage: MatrixSpace(QQ, 2)
Full MatrixSpace of 2 by 2 dense matrices over Rational Field
sage: MatrixSpace(ZZ, 3, 2)
Full MatrixSpace of 3 by 2 dense matrices over Integer Ring
sage: MatrixSpace(ZZ, 3, sparse=False)
Full MatrixSpace of 3 by 3 dense matrices over Integer Ring

sage: MatrixSpace(ZZ, 10, 5)
Full MatrixSpace of 10 by 5 dense matrices over Integer Ring
sage: MatrixSpace(ZZ, 10, 5).category()
Category of infinite enumerated finite dimensional modules with basis over
(Dedekind domains and euclidean domains
and infinite enumerated sets and metric spaces)
sage: MatrixSpace(ZZ, 10, 10).category()
Category of infinite enumerated finite dimensional algebras with basis over
(Dedekind domains and euclidean domains
and infinite enumerated sets and metric spaces)
sage: MatrixSpace(QQ, 10).category()
Category of infinite finite dimensional algebras with basis over
(number fields and quotient fields and metric spaces)

Some examples of square 2 by 2 rational matrices::

Expand All @@ -463,8 +527,7 @@ class MatrixSpace(UniqueRepresentation, Parent):
sage: B[1,1]
[0 0]
[0 1]
sage: A = MS.matrix([1,2,3,4])
sage: A
sage: A = MS.matrix([1,2,3,4]); A
[1 2]
[3 4]

Expand All @@ -476,19 +539,27 @@ class MatrixSpace(UniqueRepresentation, Parent):
[ 9 12 15]
[19 26 33]

Using ``row_keys`` and ``column_keys``::

sage: MS = MatrixSpace(ZZ, ['u', 'v'], ['a', 'b', 'c']); MS
Set of Morphisms
from Free module generated by {'a', 'b', 'c'} over Integer Ring
to Free module generated by {'u', 'v'} over Integer Ring
in Category of finite dimensional modules with basis over Integer Ring

Check categories::

sage: MatrixSpace(ZZ,10,5)
sage: MatrixSpace(ZZ, 10, 5)
Full MatrixSpace of 10 by 5 dense matrices over Integer Ring
sage: MatrixSpace(ZZ,10,5).category()
sage: MatrixSpace(ZZ, 10, 5).category()
Category of infinite enumerated finite dimensional modules with basis over
(Dedekind domains and euclidean domains
and infinite enumerated sets and metric spaces)
sage: MatrixSpace(ZZ,10,10).category()
sage: MatrixSpace(ZZ, 10, 10).category()
Category of infinite enumerated finite dimensional algebras with basis over
(Dedekind domains and euclidean domains
and infinite enumerated sets and metric spaces)
sage: MatrixSpace(QQ,10).category()
sage: MatrixSpace(QQ, 10).category()
Category of infinite finite dimensional algebras with basis over
(number fields and quotient fields and metric spaces)

Expand Down Expand Up @@ -539,11 +610,14 @@ class MatrixSpace(UniqueRepresentation, Parent):
"""

@staticmethod
def __classcall__(cls, base_ring, nrows, ncols=None, sparse=False, implementation=None, **kwds):
def __classcall__(cls, base_ring,
nrows_or_row_keys=None, ncols_or_column_keys=None,
sparse=False, implementation=None, *,
nrows=None, ncols=None,
row_keys=None, column_keys=None,
**kwds):
"""
Normalize the arguments to call the ``__init__`` constructor.

See the documentation in ``__init__``.
Normalize the arguments to call the ``__init__`` constructor or delegate to another class.

TESTS::

Expand Down Expand Up @@ -588,13 +662,35 @@ def __classcall__(cls, base_ring, nrows, ncols=None, sparse=False, implementatio
"""
if base_ring not in _Rings:
raise TypeError("base_ring (=%s) must be a ring" % base_ring)
nrows = int(nrows)
if ncols is None:

if ncols_or_column_keys is not None:
try:
ncols = int(ncols_or_column_keys)
except (TypeError, ValueError):
column_keys = ncols_or_column_keys

if nrows_or_row_keys is not None:
try:
nrows = int(nrows_or_row_keys)
except (TypeError, ValueError):
row_keys = nrows_or_row_keys

if ncols is None and column_keys is None:
ncols = nrows
else:
ncols = int(ncols)
column_keys = row_keys

sparse = bool(sparse)

if row_keys is not None or column_keys is not None:
from sage.categories.homset import Hom
from sage.modules.free_module import FreeModule

domain = FreeModule(base_ring, rank=ncols, basis_keys=column_keys,
sparse=sparse, **kwds)
codomain = FreeModule(base_ring, rank=nrows, basis_keys=row_keys,
sparse=sparse, **kwds)
return Hom(domain, codomain)

if nrows < 0:
raise ArithmeticError("nrows must be nonnegative")
if ncols < 0:
Expand All @@ -608,59 +704,6 @@ def __classcall__(cls, base_ring, nrows, ncols=None, sparse=False, implementatio

def __init__(self, base_ring, nrows, ncols, sparse, implementation):
r"""
INPUT:

- ``base_ring``

- ``nrows`` - (positive integer) the number of rows

- ``ncols`` - (positive integer, default nrows) the number of
columns

- ``sparse`` - (boolean, default false) whether or not matrices
are given a sparse representation

- ``implementation`` -- (optional, a string or a matrix class) a possible
implementation. Depending on the base ring the string can be

- ``'generic'`` - on any base rings

- ``'flint'`` - for integers and rationals

- ``'meataxe'`` - finite fields, needs to install the optional package meataxe

- ``m4ri`` - for characteristic 2 using M4RI library

- ``linbox-float`` - for integer mod rings up to `2^8 = 256`

- ``linbox-double`` - for integer mod rings up to
`floor(2^26*sqrt(2) + 1/2) = 94906266`

- ``numpy`` - for real and complex floating point numbers

EXAMPLES::

sage: MatrixSpace(QQ, 2)
Full MatrixSpace of 2 by 2 dense matrices over Rational Field
sage: MatrixSpace(ZZ, 3, 2)
Full MatrixSpace of 3 by 2 dense matrices over Integer Ring
sage: MatrixSpace(ZZ, 3, sparse=False)
Full MatrixSpace of 3 by 3 dense matrices over Integer Ring

sage: MatrixSpace(ZZ,10,5)
Full MatrixSpace of 10 by 5 dense matrices over Integer Ring
sage: MatrixSpace(ZZ,10,5).category()
Category of infinite enumerated finite dimensional modules with basis over
(Dedekind domains and euclidean domains
and infinite enumerated sets and metric spaces)
sage: MatrixSpace(ZZ,10,10).category()
Category of infinite enumerated finite dimensional algebras with basis over
(Dedekind domains and euclidean domains
and infinite enumerated sets and metric spaces)
sage: MatrixSpace(QQ,10).category()
Category of infinite finite dimensional algebras with basis over
(number fields and quotient fields and metric spaces)

TESTS:

We test that in the real or complex double dense case,
Expand Down
Loading