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

Merge MatSpace and Generic.MatSpace #1849

Merged
merged 2 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
9 changes: 5 additions & 4 deletions docs/src/matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ For the most part, one doesn't want to work directly with the `MatSpaceElem` typ
but with an abstract type called `Generic.Mat` which includes `MatSpaceElem` and views
thereof.

Parents of generic matrices (matrix spaces) have type `Generic.MatSpace{T}`. Parents of
Parents of generic matrices (matrix spaces) have type `MatSpace{T}`. Parents of
matrices in a matrix algebra have type `Generic.MatRing{T}`.

The dimensions and base ring $R$ of a generic matrix are stored in its parent object,
Expand All @@ -47,9 +47,10 @@ demand.
## Abstract types

The generic matrix types (matrix spaces) belong to the abstract type
`MatElem{T}` and the matrix space parent types belong to
`MatSpace{T}`. Similarly the generic matrix algebra matrix types belong
to the abstract type `MatRingElem{T}` and the parent types belong to
`MatElem{T}` and the all matrix space parents are of the concrete type
`MatSpace{T}`.
On the other hand, the generic matrix algebra matrix types belong
to the abstract type `MatRingElem{T}` and the parent types belong to the abstract
`MatRing{T}` Note that both
the concrete type of a matrix space parent object and the abstract class it belongs to
have the name `MatElem`, therefore disambiguation is required to specify which is
Expand Down
4 changes: 2 additions & 2 deletions docs/src/matrix_interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ performance.

## Types and parents

AbstractAlgebra provides two abstract types for matrix spaces and their elements:
AbstractAlgebra provides two types for matrix spaces and their elements:

* `MatSpace{T}` is the abstract type for matrix space parent types
* `MatSpace{T}` is the concrete type for matrix space parent types
* `MatElem{T}` is the abstract type for matrix types belonging to a matrix space

It also provides two abstract types for matrix algebras and their elements:
Expand Down
2 changes: 1 addition & 1 deletion docs/src/visualizing_types.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,4 @@ are defined over.
- `Generic.LaurentSeriesFieldElem{T}` (`Generic.LaurentSeriesField{T}`)
- `Generic.ResidueRingElem{T}` (`Generic.ResidueRing{T}`)
- `Generic.FracFieldElem{T}` (`Generic.FracField{T}`)
- `Generic.Mat{T}` (`Generic.MatSpace{T}`)
- `Generic.Mat{T}` (`MatSpace{T}`)
2 changes: 2 additions & 0 deletions src/AbstractAlgebra.jl
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ const NCRingElement = Union{NCRingElem, Integer, Rational, AbstractFloat}

const FieldElement = Union{FieldElem, Rational, AbstractFloat}

include("ConcreteTypes.jl")

###############################################################################
#
# Fundamental interface for AbstractAlgebra
Expand Down
2 changes: 0 additions & 2 deletions src/AbstractTypes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,6 @@ abstract type ResidueField{T} <: Field end

abstract type FracField{T} <: Field end

abstract type MatSpace{T} <: Module{T} end

abstract type MatRing{T} <: NCRing end

abstract type FreeAssociativeAlgebra{T} <: NCRing end
Expand Down
18 changes: 18 additions & 0 deletions src/ConcreteTypes.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
###############################################################################
#
# Mat space
#
###############################################################################

struct MatSpace{T <: NCRingElement} <: Module{T}
base_ring::NCRing
nrows::Int
ncols::Int

function MatSpace{T}(R::NCRing, r::Int, c::Int, cached::Bool = true) where T <: NCRingElement
# TODO/FIXME: `cached` is ignored and only exists for backwards compatibility
@assert elem_type(R) === T
(r < 0 || c < 0) && error("Dimensions must be non-negative")
return new{T}(R, r, c)
end
end
3 changes: 3 additions & 0 deletions src/Generic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,7 @@ Base.@deprecate_binding ResidueRingElem EuclideanRingResidueRingElem
@deprecate hom(M::DirectSumModule{T}, N::DirectSumModule{T}, mp::Vector{ModuleHomomorphism{T}}) where T hom_direct_sum(M, N, mp)
@deprecate hom(A::DirectSumModule{T}, B::DirectSumModule{T}, M::Matrix{<:Map{<:AbstractAlgebra.FPModule{T}, <:AbstractAlgebra.FPModule{T}}}) where {T} hom_direct_sum(A, B, M)

# Deprecated for 0.44
#Base.@deprecate_binding MatSpace AbstractAlgebra.MatSpace false

end # generic
99 changes: 67 additions & 32 deletions src/Matrix.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
#
###############################################################################

base_ring_type(::Type{<:MatSpace{T}}) where T <: NCRingElement = parent_type(T)
elem_type(::Type{MatSpace{T}}) where {T <: NCRingElement} = dense_matrix_type(T)

parent_type(::Type{<:MatElem{T}}) where {T <: NCRingElement} = MatSpace{T}

base_ring_type(::Type{MatSpace{T}}) where T <: NCRingElement = parent_type(T)

base_ring(a::MatSpace{T}) where {T <: NCRingElement} = a.base_ring::parent_type(T)

Expand Down Expand Up @@ -48,6 +52,41 @@
return nothing
end

_checkbounds(i::Int, j::Int) = 1 <= j <= i

_checkbounds(i::Int, j::AbstractVector{Int}) = all(jj -> 1 <= jj <= i, j)

function _checkbounds(A, i::Union{Int, AbstractVector{Int}}, j::Union{Int, AbstractVector{Int}})
(_checkbounds(nrows(A), i) && _checkbounds(ncols(A), j)) ||
Base.throw_boundserror(A, (i, j))
end

function _checkbounds(A, rows::AbstractArray{Int}, cols::AbstractArray{Int})
Base.has_offset_axes(rows, cols) && throw(ArgumentError("offset arrays are not supported"))
isempty(rows) || _checkbounds(nrows(A), first(rows)) && _checkbounds(nrows(A), last(rows)) ||

Check warning on line 66 in src/Matrix.jl

View check run for this annotation

Codecov / codecov/patch

src/Matrix.jl#L64-L66

Added lines #L64 - L66 were not covered by tests
throw(BoundsError(A, rows))
isempty(cols) || _checkbounds(ncols(A), first(cols)) && _checkbounds(ncols(A), last(cols)) ||

Check warning on line 68 in src/Matrix.jl

View check run for this annotation

Codecov / codecov/patch

src/Matrix.jl#L68

Added line #L68 was not covered by tests
throw(BoundsError(A, cols))
end

function check_square(A::MatrixElem{T}) where T <: NCRingElement
is_square(A) || throw(DomainError(A, "matrix must be square"))
A
end

function check_square(S::MatSpace)
nrows(S) == ncols(S) || throw(DomainError(S, "matrices must be square"))
S
end

check_square(S::MatRing) = S

Check warning on line 82 in src/Matrix.jl

View check run for this annotation

Codecov / codecov/patch

src/Matrix.jl#L82

Added line #L82 was not covered by tests

###############################################################################
#
# Parent object call overload
#
###############################################################################

# create a zero matrix
function (s::MatSpace{T})() where {T <: NCRingElement}
return zero_matrix(base_ring(s), nrows(s), ncols(s))::eltype(s)
Expand All @@ -60,16 +99,12 @@
M = s() # zero matrix
R = base_ring(s)
if R == base_ring(a)
for i = 1:nrows(s)
for j = 1:ncols(s)
M[i, j] = a[i, j]
end
for i = 1:nrows(s), j = 1:ncols(s)
M[i, j] = a[i, j]
end
else
for i = 1:nrows(s)
for j = 1:ncols(s)
M[i, j] = R(a[i, j])
end
for i = 1:nrows(s), j = 1:ncols(s)
M[i, j] = R(a[i, j])

Check warning on line 107 in src/Matrix.jl

View check run for this annotation

Codecov / codecov/patch

src/Matrix.jl#L106-L107

Added lines #L106 - L107 were not covered by tests
end
end
return M
Expand All @@ -86,34 +121,30 @@
return M
end

_checkbounds(i::Int, j::Int) = 1 <= j <= i

_checkbounds(i::Int, j::AbstractVector{Int}) = all(jj -> 1 <= jj <= i, j)

function _checkbounds(A, i::Union{Int, AbstractVector{Int}}, j::Union{Int, AbstractVector{Int}})
(_checkbounds(nrows(A), i) && _checkbounds(ncols(A), j)) ||
Base.throw_boundserror(A, (i, j))
end
# convert a Julia matrix
function (a::MatSpace{T})(b::AbstractMatrix{S}) where {T <: NCRingElement, S}
_check_dim(nrows(a), ncols(a), b)
R = base_ring(a)

function _checkbounds(A, rows::AbstractArray{Int}, cols::AbstractArray{Int})
Base.has_offset_axes(rows, cols) && throw(ArgumentError("offset arrays are not supported"))
isempty(rows) || _checkbounds(nrows(A), first(rows)) && _checkbounds(nrows(A), last(rows)) ||
throw(BoundsError(A, rows))
isempty(cols) || _checkbounds(ncols(A), first(cols)) && _checkbounds(ncols(A), last(cols)) ||
throw(BoundsError(A, cols))
end
# minor optimization for MatSpaceElem
if S === T && dense_matrix_type(T) === Generic.MatSpaceElem{T} && all(x -> R === parent(x), b)
return Generic.MatSpaceElem{T}(R, b)
end

function check_square(A::MatrixElem{T}) where T <: NCRingElement
is_square(A) || throw(DomainError(A, "matrix must be square"))
A
# generic code
M = a() # zero matrix
for i = 1:nrows(a), j = 1:ncols(a)
M[i, j] = R(b[i, j])
end
return M
end

function check_square(S::MatSpace)
nrows(S) == ncols(S) || throw(DomainError(S, "matrices must be square"))
S
# convert a Julia vector
function (a::MatSpace{T})(b::AbstractVector) where T <: NCRingElement
_check_dim(nrows(a), ncols(a), b)
return a(transpose(reshape(b, a.ncols, a.nrows)))
end

check_square(S::MatRing) = S

###############################################################################
#
Expand Down Expand Up @@ -7023,7 +7054,11 @@
the ring $R$.
"""
function matrix_space(R::NCRing, r::Int, c::Int; cached::Bool = true)
return Generic.matrix_space(R, r, c; cached)
# TODO: the 'cached' argument is ignored and mainly here for backwards compatibility
# (and perhaps future compatibility, in case we need it again)
(r < 0 || c < 0) && error("Dimensions must be non-negative")
T = elem_type(R)
return MatSpace{T}(R, r, c)
end

###############################################################################
Expand Down
18 changes: 1 addition & 17 deletions src/generic/GenericTypes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1051,29 +1051,13 @@ end

###############################################################################
#
# MatSpace / Mat
# Mat
#
###############################################################################

const NCRingElement = Union{NCRingElem, RingElement}

# All MatSpaceElem's and views thereof
abstract type Mat{T} <: MatElem{T} end

# not really a mathematical ring
struct MatSpace{T <: NCRingElement} <: AbstractAlgebra.MatSpace{T}
base_ring::NCRing
nrows::Int
ncols::Int

function MatSpace{T}(R::NCRing, r::Int, c::Int, cached::Bool = true) where T <: NCRingElement
# TODO/FIXME: `cached` is ignored and only exists for backwards compatibility
@assert elem_type(R) === T
(r < 0 || c < 0) && error("Dimensions must be non-negative")
return new{T}(R, r, c)
end
end

struct MatSpaceElem{T <: NCRingElement} <: Mat{T}
base_ring::NCRing
entries::Matrix{T}
Expand Down
64 changes: 0 additions & 64 deletions src/generic/Matrix.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@
#
###############################################################################

parent_type(::Type{<:MatElem{T}}) where {T <: NCRingElement} = MatSpace{T}

elem_type(::Type{MatSpace{T}}) where {T <: NCRingElement} = dense_matrix_type(T)

@doc raw"""
parent(a::AbstractAlgebra.MatElem)

Expand Down Expand Up @@ -43,20 +39,6 @@ dense_matrix_type(::Type{T}) where T <: NCRingElement = MatSpaceElem{T}
#
###############################################################################

@doc raw"""
number_of_rows(a::MatSpace)

Return the number of rows of the given matrix space.
"""
number_of_rows(a::Generic.MatSpace) = a.nrows

@doc raw"""
number_of_columns(a::MatSpace)

Return the number of columns of the given matrix space.
"""
number_of_columns(a::Generic.MatSpace) = a.ncols

number_of_rows(a::Union{Mat, MatRingElem}) = size(a.entries, 1)

number_of_columns(a::Union{Mat,MatRingElem}) = size(a.entries, 2)
Expand Down Expand Up @@ -142,52 +124,6 @@ function promote_rule(::Type{S}, ::Type{U}) where {T <: NCRingElement, S <: Mat{
promote_rule(T, U) == T ? MatSpaceElem{T} : Union{}
end

###############################################################################
#
# Parent object call overload
#
###############################################################################



# convert a Julia matrix
function (a::Generic.MatSpace{T})(b::AbstractMatrix{S}) where {T <: NCRingElement, S}
_check_dim(nrows(a), ncols(a), b)
R = base_ring(a)

# minor optimization for MatSpaceElem
if S === T && dense_matrix_type(T) === MatSpaceElem{T} && all(x -> R === parent(x), b)
return MatSpaceElem{T}(R, b)
end

# generic code
M = a() # zero matrix
for i = 1:nrows(a), j = 1:ncols(a)
M[i, j] = R(b[i, j])
end
return M
end

# convert a Julia vector
function (a::Generic.MatSpace{T})(b::AbstractVector) where T <: NCRingElement
_check_dim(nrows(a), ncols(a), b)
return a(transpose(reshape(b, a.ncols, a.nrows)))
end

###############################################################################
#
# matrix_space constructor
#
###############################################################################

function matrix_space(R::AbstractAlgebra.NCRing, r::Int, c::Int; cached::Bool = true)
# TODO: the 'cached' argument is ignored and mainly here for backwards compatibility
# (and perhaps future compatibility, in case we need it again)
(r < 0 || c < 0) && error("Dimensions must be non-negative")
T = elem_type(R)
return Generic.MatSpace{T}(R, r, c)
end

function AbstractAlgebra.add!(A::Mat{T}, B::Mat{T}, C::Mat{T}) where T
A.entries .= B.entries .+ C.entries
return A
Expand Down
1 change: 1 addition & 0 deletions src/generic/imports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ import ..AbstractAlgebra: LowercaseOff
import ..AbstractAlgebra: Map
import ..AbstractAlgebra: NCRing
import ..AbstractAlgebra: NCRingElem
import ..AbstractAlgebra: NCRingElement
import ..AbstractAlgebra: O
import ..AbstractAlgebra: Perm
import ..AbstractAlgebra: Ring
Expand Down
14 changes: 7 additions & 7 deletions test/generic/Matrix-test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ AbstractAlgebra.divexact(x::F2Elem, y::F2Elem) = y.x ? x : throw(DivideError())
Random.rand(rng::AbstractRNG, sp::Random.SamplerTrivial{F2}) = F2Elem(rand(rng, Bool))
Random.gentype(::Type{F2}) = F2Elem

const F2MatSpace = AbstractAlgebra.Generic.MatSpace{F2Elem}
const F2MatSpace = MatSpace{F2Elem}

(S::F2MatSpace)() = zero_matrix(F2(), S.nrows, S.ncols)

Expand Down Expand Up @@ -120,16 +120,16 @@ end
@test S === matrix_space(R, 3, 3)

@test elem_type(S) == Generic.MatSpaceElem{elem_type(R)}
@test elem_type(Generic.MatSpace{elem_type(R)}) == Generic.MatSpaceElem{elem_type(R)}
@test parent_type(Generic.MatSpaceElem{elem_type(R)}) == Generic.MatSpace{elem_type(R)}
@test base_ring_type(Generic.MatSpace{elem_type(R)}) == typeof(R)
@test elem_type(MatSpace{elem_type(R)}) == Generic.MatSpaceElem{elem_type(R)}
@test parent_type(Generic.MatSpaceElem{elem_type(R)}) == MatSpace{elem_type(R)}
@test base_ring_type(MatSpace{elem_type(R)}) == typeof(R)
@test base_ring_type(Generic.MatSpaceElem{elem_type(R)}) == typeof(R)
@test base_ring_type(S) == typeof(R)
@test base_ring(S) == R
@test nrows(S) == 3
@test ncols(S) == 3

@test typeof(S) <: Generic.MatSpace
@test typeof(S) <: MatSpace

f = S(t^2 + 1)

Expand Down Expand Up @@ -353,8 +353,8 @@ end
@test base_ring(S) == R

@test elem_type(S) == Generic.MatSpaceElem{elem_type(R)}
@test elem_type(Generic.MatSpace{elem_type(R)}) == Generic.MatSpaceElem{elem_type(R)}
@test parent_type(Generic.MatSpaceElem{elem_type(R)}) == Generic.MatSpace{elem_type(R)}
@test elem_type(MatSpace{elem_type(R)}) == Generic.MatSpaceElem{elem_type(R)}
@test parent_type(Generic.MatSpaceElem{elem_type(R)}) == MatSpace{elem_type(R)}

@test dense_matrix_type(R) == elem_type(S)
@test dense_matrix_type(R(1)) == elem_type(S)
Expand Down
Loading