Skip to content

Commit

Permalink
Merge branch 'master' into lg/unsafe-freeassalg
Browse files Browse the repository at this point in the history
  • Loading branch information
fingolfin authored Oct 10, 2024
2 parents 2a47bbb + 5170909 commit 5abbbe4
Show file tree
Hide file tree
Showing 24 changed files with 213 additions and 152 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "AbstractAlgebra"
uuid = "c3fe647b-3220-5bb0-a1ea-a7954cac585d"
version = "0.43.4"
version = "0.43.5"

[deps]
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
Expand Down
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
1 change: 1 addition & 0 deletions src/MatRing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ end


function characteristic(a::MatRing)
iszero(a.n) && return 1
return characteristic(base_ring(a))
end

Expand Down
121 changes: 81 additions & 40 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 @@ function _check_bases(a, b)
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)) ||
throw(BoundsError(A, rows))
isempty(cols) || _checkbounds(ncols(A), first(cols)) && _checkbounds(ncols(A), last(cols)) ||
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

###############################################################################
#
# 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 @@ function (s::MatSpace{T})(a::MatrixElem{T}) where {T <: NCRingElement}
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])
end
end
return M
Expand All @@ -86,34 +121,30 @@ function (s::MatSpace)(b::NCRingElement)
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 @@ -208,14 +239,6 @@ zero(x::MatrixElem{T}, R::NCRing=base_ring(x)) where T <: NCRingElement = zero(x
zero(x::MatrixElem{T}, R::NCRing, r::Int, c::Int) where T <: NCRingElement = zero!(similar(x, R, r, c))
zero(x::MatrixElem{T}, r::Int, c::Int) where T <: NCRingElement = zero(x, base_ring(x), r, c)

function zero!(x::MatrixElem{T}) where T <: NCRingElement
R = base_ring(x)
for i = 1:nrows(x), j = 1:ncols(x)
x[i, j] = zero(R)
end
x
end

@doc raw"""
one(a::MatSpace)
Expand Down Expand Up @@ -836,6 +859,20 @@ function *(x::MatElem{T}, y::MatElem{T}) where {T <: NCRingElement}
return A
end

###############################################################################
#
# Unsafe functions
#
###############################################################################

function zero!(x::MatrixElem{T}) where T <: NCRingElement
R = base_ring(x)
for i = 1:nrows(x), j = 1:ncols(x)
x[i, j] = zero(R)
end
x
end

function add!(c::MatrixElem{T}, a::MatrixElem{T}, b::MatrixElem{T}) where T <: NCRingElement
check_parent(a, b)
check_parent(a, c)
Expand Down Expand Up @@ -7023,7 +7060,11 @@ Return parent object corresponding to the space of $r\times c$ matrices over
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
30 changes: 30 additions & 0 deletions src/Rings.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,21 @@ function isequal(a::RingElem, b::RingElem)
return parent(a) == parent(b) && a == b
end

# Implement `isapprox` for ring elements via equality by default. On the one
# hand, we need isapprox methods to be able to conformance test series rings.
# On the other hand this is essentially the only sensible thing to do in
# positive characteristic so we might as well do it in a generic method.
function Base.isapprox(x::NCRingElem, y::NCRingElem;
atol::Real=0, rtol::Real=0,
nans::Bool=false, norm::Function=abs)
if is_exact_type(typeof(x)) && is_exact_type(typeof(y))
@req is_zero(atol) "non-zero atol not supported"
@req is_zero(rtol) "non-zero rtol not supported"
return x == y
end
throw(NotImplementedError(:isapprox, x, y))
end

"""
divexact(x, y; check::Bool=true)
Expand Down Expand Up @@ -172,6 +187,21 @@ end
#
###############################################################################

@doc raw"""
is_trivial(R::NCRing)
Test whether the ring $R$ is trivial. A ring is trivial if it consists
of a single element, or equivalently if its characteristic is 1. Such
rings are also called zero rings.
"""
is_trivial(F::NCRing) = characteristic(F) == 1
is_trivial(F::Field) = false

@doc raw"""
is_perfect(F::Field)
Test whether the field $F$ is perfect.
"""
is_perfect(F::Field) = characteristic(F) == 0 || F isa FinField ||
throw(NotImplementedError(:is_perfect, F))

Expand Down
3 changes: 0 additions & 3 deletions src/fundamental_interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
#
###############################################################################

# TODO: Move more generic functions to this file.

###############################################################################
#
# Parents, elements and data type methods
Expand Down Expand Up @@ -34,7 +32,6 @@ true
"""
function parent end

# TODO: Give example
@doc raw"""
elem_type(parent)
elem_type(parent_type)
Expand Down
2 changes: 1 addition & 1 deletion src/generic/AbsMSeries.jl
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ end

###############################################################################
#
# Unsafe operators
# Unsafe functions
#
###############################################################################

Expand Down
2 changes: 1 addition & 1 deletion src/generic/FunctionField.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1103,7 +1103,7 @@ end

###############################################################################
#
# Unsafe operators
# Unsafe functions
#
###############################################################################

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
Loading

0 comments on commit 5abbbe4

Please sign in to comment.