Skip to content

Commit

Permalink
UniformScaling as a map and doc updates
Browse files Browse the repository at this point in the history
  • Loading branch information
daanhb committed Jan 25, 2025
1 parent 6ef0593 commit b3d9f3d
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 17 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Documentation
on:
push:
branches:
- master # update to match your development branch (master, main, dev, trunk, ...)
- main
tags: '*'
pull_request:

Expand Down
2 changes: 1 addition & 1 deletion docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@ makedocs(;
)

deploydocs(;
repo="github.com/JuliaApproximation/FunctionMaps.jl", devbranch="master",
repo="github.com/JuliaApproximation/FunctionMaps.jl.git", devbranch="master",
)
2 changes: 1 addition & 1 deletion src/generic/jacobian.jl
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ end
const NumberLike = Union{Number,UniformScaling}

"""
to_matrix(::Type{T}, A[, b])
to_matrix(T, A[, b])
Convert the `A` in the affine map `A*x` or `A*x+b` with domaintype `T` to a matrix.
"""
Expand Down
19 changes: 17 additions & 2 deletions src/generic/map.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ domaintype(::Type{<:Map{T}}) where {T} = T
"""
codomaintype(m[, T])
What is the codomain type of the function map `m`, given that `T` is its domain type?
What is the type of a point in the codomain of the function map `m`?
The second argument optionally specifies a domain type `T`.
"""
codomaintype(m) = codomaintype(m, domaintype(m))
codomaintype(m, ::Type{T}) where {T} = _codomaintype(typeof(m), T)
Expand All @@ -42,14 +44,27 @@ _codomaintype(M::Type{<:TypedMap{T,U}}, ::Type{Any}) where {T,U} = U
prectype(::Type{<:Map{T}}) where T = prectype(T)
numtype(::Type{<:Map{T}}) where T = numtype(T)

"""
isrealmap(m)
Is the map real-valued?
A map is real-valued if both its domain and codomain types are real.
"""
isrealmap(m) = isrealtype(domaintype(m)) && isrealtype(codomaintype(m))
isrealmap(::UniformScaling{T}) where {T} = isrealtype(T)

convert(::Type{Map{T}}, m::Map{T}) where {T} = m
convert(::Type{Map{T}}, m::Map{S}) where {S,T} = similarmap(m, T)
convert(::Type{TypedMap{T,U}}, m::TypedMap{T,U}) where {T,U} = m
convert(::Type{TypedMap{T,U}}, m::TypedMap) where {T,U} = similarmap(m, T, U)

"""
convert_domaintype(T, m)
Convert the given map to a map such that its `domaintype` is `T`.
See also: [`domaintype`](@ref).
"""
convert_domaintype(::Type{T}, map::Map{T}) where {T} = map
convert_domaintype(::Type{U}, map::Map{T}) where {T,U} = convert(Map{U}, map)
convert_domaintype(::Type{Any}, map) = map
Expand Down
68 changes: 56 additions & 12 deletions src/types/affine.jl
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@

"""
AbstractAffineMap{T} <: Map{T}
An affine map has the general form `y = A*x + b`.
We use `affinematrix(m)` and `affinevector(m)` to denote `A` and `b` respectively. Concrete
subtypes include linear maps of the form `y = A*x` and translations of the
form `y = x + b`.
We use `affinematrix(m)` and `affinevector(m)` to denote `A` and `b`
respectively. Concrete subtypes include linear maps of the form `y = A*x`
and translations of the form `y = x + b`.
See also: [`affinematrix`](@ref), [`affinevector`](@ref).
"""
abstract type AbstractAffineMap{T} <: Map{T} end

Expand All @@ -27,11 +31,8 @@ function _affine_applymap!(y, m, x, A, b)
y
end

_affine_A_isreal(A) = isreal(A)
_affine_A_isreal(::UniformScaling{T}) where T = isrealtype(T)

isrealmap(m::AbstractAffineMap) = _affine_isrealmap(m, unsafe_matrix(m), unsafe_vector(m))
_affine_isrealmap(m, A, b) = _affine_A_isreal(A) && isreal(b)
_affine_isrealmap(m, A, b) = isrealmap(A) && isreal(b)

jacobian(m::AbstractAffineMap{T}) where {T} = ConstantMap{T}(affinematrix(m))
jacobian(m::AbstractAffineMap, x) = affinematrix(m)
Expand All @@ -48,10 +49,24 @@ function diffvolume(m::AbstractAffineMap{T}) where T
ConstantMap{T}(c)
end

islinearmap(m::Map) = false
"""
islinearmap(m)
Is `m` a linear map?
"""
islinearmap(m) = false
islinearmap(m::AbstractAffineMap) = _affine_islinearmap(m, unsafe_vector(m))
_affine_islinearmap(m, b) = all(b .== 0)

"""
isaffinemap(m)
Is `m` an affine map?
If `m` is affine, then it has the form `m(x) = A*x+b`.
See also: [`affinematrix`](@ref), [`affinevector`](@ref).
"""
isaffinemap(m) = false
isaffinemap(m::Map) = islinearmap(m) || isconstantmap(m)
isaffinemap(m::AbstractAffineMap) = true
Expand Down Expand Up @@ -94,7 +109,10 @@ map_stencil_parentheses(m::AbstractAffineMap) = true
########################

"""
LinearMap{T} <: AbstractAffineMap{T}
The supertype of all linear maps `y = A*x`.
Concrete subtypes may differ in how `A` is represented.
"""
abstract type LinearMap{T} <: AbstractAffineMap{T} end
Expand Down Expand Up @@ -233,9 +251,6 @@ leftinverse(m::GenericLinearMap{T,AA}) where {T<:AbstractVector,AA<:Number} =
rightinverse(m::GenericLinearMap{T,AA}) where {T<:AbstractVector,AA<:Number} =
LinearMap{T}(inv(m.A))

convert(::Type{Map}, A::UniformScaling) = GenericLinearMap{Vector{Any}}(A)
convert(::Type{Map{T}}, A::UniformScaling) where {T} = GenericLinearMap{T}(A)

"A `ScalarLinearMap` is a linear map `y = A*x` for scalars."
struct ScalarLinearMap{T} <: LinearMap{T}
A :: T
Expand Down Expand Up @@ -409,11 +424,25 @@ GenericTranslation{T}(b::Number) where {T<:Number} =


"""
The supertype of all affine maps that store `A` and `b`.
AffineMap{T} <: AbstractAffineMap{T}
The supertype of all affine maps that store `A` and `b`.
Concrete subtypes differ in how `A` and `b` are represented.
"""
abstract type AffineMap{T} <: AbstractAffineMap{T} end

"""
AffineMap(A, b)
Return an affine map with an appropriate concrete type depending on the arguments
`A` and `b`.
# Examples
```julia
julia> AffineMap(2, 3)
x -> 2 * x + 3
```
"""
AffineMap(A::Number, b::Number) = ScalarAffineMap(A, b)
AffineMap(A::StaticMatrix, b::StaticVector) = StaticAffineMap(A, b)
AffineMap(A::Matrix, b::Vector) = VectorAffineMap(A, b)
Expand Down Expand Up @@ -587,3 +616,18 @@ StaticAffineMap{T,N,M}(A::AbstractMatrix, b::AbstractVector) where {T,N,M} =

convert(::Type{Map{SVector{N,T}}}, m::VectorAffineMap) where {N,T} =
StaticAffineMap{T,N}(m.A, m.b)


###########################
# Uniform scaling as a map
###########################

convert(::Type{Map}, A::UniformScaling) = GenericLinearMap{Vector{Any}}(A)
convert(::Type{Map{T}}, A::UniformScaling) where {T} = GenericLinearMap{T}(A)

# I(4) returns a diagonal matrix: the action of I is multiplication
applymap(I::UniformScaling, x) = I*x
domaintype(::UniformScaling{T}) where T = T
islinearmap(::UniformScaling) = true
affinematrix(I::UniformScaling) = I
affinevector(I::UniformScaling) = zerovector(I)

0 comments on commit b3d9f3d

Please sign in to comment.