Skip to content

Commit c963e64

Browse files
committed
reorganisation
1 parent a8db302 commit c963e64

File tree

10 files changed

+656
-671
lines changed

10 files changed

+656
-671
lines changed

src/FunctionMaps.jl

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,12 @@ export composedmap
2929
# from generic/product.jl
3030
export productmap
3131

32-
# from types/basic.jl
32+
# from concrete/basic.jl
3333
export IdentityMap,
3434
StaticIdentityMap, VectorIdentityMap,
3535
ZeroMap, UnityMap, ConstantMap,
3636
isconstantmap, mapconstant
37-
# from types/affine.jl
37+
# from concrete/affine
3838
export AffineMap, Translation, LinearMap,
3939
affinematrix, affinevector,
4040
islinearmap, isaffinemap
@@ -50,9 +50,13 @@ include("generic/jacobian.jl")
5050
include("generic/composite.jl")
5151
include("generic/product.jl")
5252
include("generic/isomorphism.jl")
53-
include("types/basic.jl")
54-
include("types/affine.jl")
55-
include("types/coordinates.jl")
56-
include("types/arithmetics.jl")
53+
include("concrete/basic.jl")
54+
include("concrete/affine/abstractaffine.jl")
55+
include("concrete/affine/linear.jl")
56+
include("concrete/affine/translation.jl")
57+
include("concrete/affine/affine.jl")
58+
include("concrete/affine/special.jl")
59+
include("concrete/coordinates.jl")
60+
include("concrete/arithmetics.jl")
5761

5862
end
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
2+
"""
3+
AbstractAffineMap{T} <: Map{T}
4+
5+
An affine map has the general form `y = A*x + b`.
6+
7+
We use `affinematrix(m)` and `affinevector(m)` to denote `A` and `b`
8+
respectively. Concrete subtypes include linear maps of the form `y = A*x`
9+
and translations of the form `y = x + b`.
10+
11+
See also: [`affinematrix`](@ref), [`affinevector`](@ref).
12+
"""
13+
abstract type AbstractAffineMap{T} <: Map{T} end
14+
15+
unsafe_matrix(m::AbstractAffineMap) = m.A
16+
unsafe_vector(m::AbstractAffineMap) = m.b
17+
18+
"Return the matrix `A` in the affine map `Ax+b`."
19+
affinematrix(m::AbstractAffineMap) = to_matrix(domaintype(m), unsafe_matrix(m), unsafe_vector(m))
20+
21+
"Return the vector `b` in the affine map `Ax+b`."
22+
affinevector(m::AbstractAffineMap) = to_vector(domaintype(m), unsafe_matrix(m), unsafe_vector(m))
23+
24+
applymap(m::AbstractAffineMap, x) = _affine_applymap(m, x, unsafe_matrix(m), unsafe_vector(m))
25+
_affine_applymap(m, x, A, b) = A*x + b
26+
27+
applymap!(y, m::AbstractAffineMap, x) = _affine_applymap!(y, m, x, unsafe_matrix(m), unsafe_vector(m))
28+
function _affine_applymap!(y, m, x, A, b)
29+
mul!(y, A, x)
30+
y .+= b
31+
y
32+
end
33+
34+
isrealmap(m::AbstractAffineMap) = _affine_isrealmap(m, unsafe_matrix(m), unsafe_vector(m))
35+
_affine_isrealmap(m, A, b) = isrealmap(A) && isreal(b)
36+
37+
jacobian(m::AbstractAffineMap{T}) where {T} = ConstantMap{T}(affinematrix(m))
38+
jacobian(m::AbstractAffineMap, x) = affinematrix(m)
39+
40+
jacdet(m::AbstractAffineMap, x) = _affine_jacdet(m, x, unsafe_matrix(m))
41+
_affine_jacdet(m, x, A) = det(A)
42+
_affine_jacdet(m, x::Number, A::UniformScaling) = A.λ
43+
_affine_jacdet(m, x::AbstractVector, A::Number) = A^length(x)
44+
_affine_jacdet(m, x::AbstractVector, A::UniformScaling) = A.λ^length(x)
45+
46+
function diffvolume(m::AbstractAffineMap{T}) where T
47+
J = jacobian(m)
48+
c = sqrt(det(affinevector(J)'*affinevector(J)))
49+
ConstantMap{T}(c)
50+
end
51+
52+
"""
53+
islinearmap(m)
54+
55+
Is `m` a linear map?
56+
"""
57+
islinearmap(m) = false
58+
islinearmap(m::AbstractAffineMap) = _affine_islinearmap(m, unsafe_vector(m))
59+
_affine_islinearmap(m, b) = all(b .== 0)
60+
61+
"""
62+
isaffinemap(m)
63+
64+
Is `m` an affine map?
65+
66+
If `m` is affine, then it has the form `m(x) = A*x+b`.
67+
68+
See also: [`affinematrix`](@ref), [`affinevector`](@ref).
69+
"""
70+
isaffinemap(m) = false
71+
isaffinemap(m::Map) = islinearmap(m) || isconstantmap(m)
72+
isaffinemap(m::AbstractAffineMap) = true
73+
74+
isequalmap(m1::AbstractAffineMap, m2::AbstractAffineMap) =
75+
affinematrix(m1) == affinematrix(m2) && affinevector(m1) == affinevector(m2)
76+
77+
isequalmap(m1::AbstractAffineMap, m2::IdentityMap) =
78+
islinearmap(m1) && affinematrix(m1) == affinematrix(m2)
79+
isequalmap(m1::IdentityMap, m2::AbstractAffineMap) = isequalmap(m2, m1)
80+
81+
map_hash(m::AbstractAffineMap, h::UInt) = hashrec("AbstractAffineMap", affinematrix(m), affinevector(m), h)
82+
83+
mapsize(m::AbstractAffineMap) = _affine_mapsize(m, domaintype(m), unsafe_matrix(m), unsafe_vector(m))
84+
_affine_mapsize(m, T, A::AbstractArray, b) = size(A)
85+
_affine_mapsize(m, T, A::AbstractVector, b::AbstractVector) = (length(A),)
86+
_affine_mapsize(m, T, A::Number, b::Number) = ()
87+
_affine_mapsize(m, T, A::Number, b::AbstractVector) = (length(b),length(b))
88+
_affine_mapsize(m, T, A::UniformScaling, b::Number) = ()
89+
_affine_mapsize(m, T, A::UniformScaling, b) = (length(b),length(b))
90+
91+
92+
Display.displaystencil(m::AbstractAffineMap) = vcat(["x -> "], map_stencil(m, 'x'))
93+
show(io::IO, mime::MIME"text/plain", m::AbstractAffineMap) = composite_show(io, mime, m)
94+
95+
map_stencil(m::AbstractAffineMap, x) = _affine_map_stencil(m, x, unsafe_matrix(m), unsafe_vector(m))
96+
_affine_map_stencil(m, x, A, b) = [A, " * ", x, " + ", b]
97+
_affine_map_stencil(m, x, A, b::Real) =
98+
b >= 0 ? [A, " * ", x, " + ", b] : [A, " * ", x, " - ", abs(b)]
99+
100+
map_stencil_broadcast(m::AbstractAffineMap, x) = _affine_map_stencil_broadcast(m, x, unsafe_matrix(m), unsafe_vector(m))
101+
_affine_map_stencil_broadcast(m, x, A, b) = [A, " .* ", x, " .+ ", b]
102+
_affine_map_stencil_broadcast(m, x, A::Number, b) = [A, " * ", x, " .+ ", b]
103+
104+
map_object_parentheses(m::AbstractAffineMap) = true
105+
map_stencil_parentheses(m::AbstractAffineMap) = true

src/concrete/affine/affine.jl

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
"""
2+
AffineMap{T} <: AbstractAffineMap{T}
3+
4+
The supertype of all affine maps that store `A` and `b`.
5+
Concrete subtypes differ in how `A` and `b` are represented.
6+
"""
7+
abstract type AffineMap{T} <: AbstractAffineMap{T} end
8+
9+
"""
10+
AffineMap(A, b)
11+
12+
Return an affine map with an appropriate concrete type depending on the arguments
13+
`A` and `b`.
14+
15+
# Examples
16+
```julia
17+
julia> AffineMap(2, 3)
18+
x -> 2 * x + 3
19+
```
20+
"""
21+
AffineMap(A::Number, b::Number) = ScalarAffineMap(A, b)
22+
AffineMap(A::StaticMatrix, b::StaticVector) = StaticAffineMap(A, b)
23+
AffineMap(A::Matrix, b::Vector) = VectorAffineMap(A, b)
24+
AffineMap(A::UniformScaling{Bool}, b::Number) = ScalarAffineMap(one(b), b)
25+
AffineMap(A, b) = GenericAffineMap(A, b)
26+
27+
AffineMap{T}(A::Number, b::Number) where {T<:Number} = ScalarAffineMap{T}(A, b)
28+
AffineMap{T}(A::AbstractMatrix, b::AbstractVector) where {N,S,T<:SVector{N,S}} = StaticAffineMap{S,N}(A, b)
29+
AffineMap{T}(A::Matrix, b::Vector) where {S,T<:Vector{S}} = VectorAffineMap{S}(A, b)
30+
AffineMap{T}(A::UniformScaling{Bool}, b::Number) where {T} = ScalarAffineMap{T}(one(T), b)
31+
AffineMap{T}(A, b) where {T} = GenericAffineMap{T}(A, b)
32+
33+
similarmap(m::AffineMap, ::Type{T}) where {T} = AffineMap{T}(m.A, m.b)
34+
35+
convert(::Type{AffineMap}, m) = (@assert isaffinemap(m); AffineMap(affinematrix(m), affinevector(m)))
36+
convert(::Type{AffineMap{T}}, m) where {T} = (@assert isaffinemap(m); AffineMap{T}(affinematrix(m), affinevector(m)))
37+
# avoid ambiguity errors with convert(::Type{T}, x::T) in Base:
38+
convert(::Type{AffineMap}, m::AffineMap) = m
39+
convert(::Type{AffineMap{T}}, m::AffineMap{T}) where T = m
40+
41+
# If y = A*x+b, then x = inv(A)*(y-b) = inv(A)*y - inv(A)*b
42+
inverse(m::AffineMap) = (@assert issquaremap(m); AffineMap(inv(m.A), -inv(m.A)*m.b))
43+
inverse(m::AffineMap, x) = (@assert issquaremap(m); m.A \ (x-m.b))
44+
45+
function leftinverse(m::AffineMap)
46+
@assert isoverdetermined(m)
47+
pA = matrix_pinv(m.A)
48+
AffineMap(pA, -pA*m.b)
49+
end
50+
function rightinverse(m::AffineMap)
51+
@assert isunderdetermined(m)
52+
pA = matrix_pinv(m.A)
53+
AffineMap(pA, -pA*m.b)
54+
end
55+
function leftinverse(m::AffineMap, x)
56+
@assert isoverdetermined(m)
57+
m.A \ (x-m.b)
58+
end
59+
function rightinverse(m::AffineMap, x)
60+
@assert isunderdetermined(m)
61+
m.A \ (x-m.b)
62+
end
63+
64+
65+
"An affine map for any combination of types of `A` and `b`."
66+
struct GenericAffineMap{T,AA,B} <: AffineMap{T}
67+
A :: AA
68+
b :: B
69+
end
70+
71+
GenericAffineMap(A, b) = GenericAffineMap{typeof(b)}(A, b)
72+
GenericAffineMap(A::AbstractVector{S}, b::AbstractVector{T}) where {S,T} =
73+
GenericAffineMap{promote_type(S,T)}(A, b)
74+
GenericAffineMap(A::AbstractArray{S}, b::AbstractVector{T}) where {S,T} =
75+
GenericAffineMap{Vector{promote_type(S,T)}}(A, b)
76+
GenericAffineMap(A::StaticMatrix{M,N,S}, b::StaticVector{M,T}) where {M,N,S,T} =
77+
GenericAffineMap{SVector{N,promote_type(S,T)}}(A, b)
78+
GenericAffineMap(A::StaticMatrix{M,N,S}, b::AbstractVector{T}) where {M,N,S,T} =
79+
GenericAffineMap{SVector{N,promote_type(S,T)}}(A, b)
80+
GenericAffineMap(A::S, b::AbstractVector{T}) where {S<:Number,T} =
81+
GenericAffineMap{Vector{promote_type(S,T)}}(A, b)
82+
GenericAffineMap(A::S, b::StaticVector{N,T}) where {S<:Number,N,T} =
83+
GenericAffineMap{SVector{N,promote_type(S,T)}}(A, b)
84+
GenericAffineMap(A::UniformScaling{Bool}, b) =
85+
GenericAffineMap(UniformScaling{eltype(b)}(1), b)
86+
87+
88+
# Fallback routine for generic A and b, special cases follow
89+
GenericAffineMap{T}(A, b) where {T} = GenericAffineMap{T,typeof(A),typeof(b)}(A, b)
90+
91+
GenericAffineMap{T}(A::AbstractVector{S}, b::AbstractVector{U}) where {T<:Number,S,U} =
92+
GenericAffineMap{T}(convert(AbstractVector{T}, A), convert(AbstractVector{T}, b))
93+
GenericAffineMap{T}(A::AbstractVector{T}, b::AbstractVector{T}) where {T<:Number} =
94+
GenericAffineMap{T,typeof(A),typeof(b)}(A, b)
95+
GenericAffineMap{T}(A::Number, b) where {T} = GenericAffineMap{T,eltype(T),typeof(b)}(A, b)
96+
GenericAffineMap{T}(A::Number, b::AbstractVector) where {N,S,T <: StaticVector{N,S}} =
97+
GenericAffineMap{T,S,SVector{N,S}}(A, b)
98+
# Promote element types of abstract arrays
99+
GenericAffineMap{T}(A::AbstractArray, b::AbstractVector) where {S,T<:AbstractVector{S}} =
100+
GenericAffineMap{T}(convert(AbstractArray{eltype(T)},A), convert(AbstractVector{eltype(T)}, b))
101+
GenericAffineMap{T}(A::AbstractArray{S}, b::AbstractVector{S}) where {S,T<:AbstractVector{S}} =
102+
GenericAffineMap{T,typeof(A),typeof(b)}(A, b)
103+
GenericAffineMap{T}(A::UniformScaling{Bool}, b::AbstractVector) where {S,T<:AbstractVector{S}} =
104+
GenericAffineMap{T}(A*one(S), convert(AbstractVector{S}, b))
105+
GenericAffineMap{T}(A::UniformScaling{S}, b::AbstractVector{S}) where {S,T<:AbstractVector{S}} =
106+
GenericAffineMap{T,typeof(A),typeof(b)}(A, b)
107+
108+
109+
similarmap(m::GenericAffineMap, ::Type{T}) where {T} = AffineMap{T}(m.A, m.b)
110+
111+
convert(::Type{GenericAffineMap{T}}, m::GenericAffineMap) where {T} =
112+
GenericAffineMap{T}(m.A, m.b)
113+
114+
115+
116+
"An affine map with scalar representation."
117+
struct ScalarAffineMap{T} <: AffineMap{T}
118+
A :: T
119+
b :: T
120+
end
121+
122+
ScalarAffineMap(A, b) = ScalarAffineMap(promote(A, b)...)
123+
124+
isrealmap(m::ScalarAffineMap{T}) where {T} = isrealtype(T)
125+
126+
show(io::IO, m::ScalarAffineMap) = show_scalar_affine_map(io, m.A, m.b)
127+
show_scalar_affine_map(io, A::Real, b::Real) = print(io, "x -> $(A) * x", b < 0 ? " - " : " + ", abs(b))
128+
show_scalar_affine_map(io, A::Complex, b::Complex) = print(io, "x -> ($(A)) * x + ", b)
129+
show_scalar_affine_map(io, A, b) = print(io, "x -> ($(A)) * x + $(b)")
130+
131+
132+
convert(::Type{ScalarAffineMap{T}}, m::ScalarAffineMap) where {T} =
133+
ScalarAffineMap{T}(m.A, m.b)
134+
135+
"An affine map with array and vector representation."
136+
struct VectorAffineMap{T} <: AffineMap{Vector{T}}
137+
A :: Matrix{T}
138+
b :: Vector{T}
139+
end
140+
141+
VectorAffineMap(A::AbstractArray{T}, b::AbstractVector{T}) where {T} =
142+
VectorAffineMap{T}(A, b)
143+
function VectorAffineMap(A::AbstractArray{S}, b::AbstractVector{T}) where {S,T}
144+
U = promote_type(S,T)
145+
VectorAffineMap(convert(AbstractArray{U}, A), convert(AbstractVector{U}, b))
146+
end
147+
148+
convert(::Type{VectorAffineMap{T}}, m::VectorAffineMap) where {T} =
149+
VectorAffineMap{T}(m.A, m.b)
150+
151+
152+
153+
"An affine map with representation using static arrays."
154+
struct StaticAffineMap{T,N,M,L} <: AffineMap{SVector{N,T}}
155+
A :: SMatrix{M,N,T,L}
156+
b :: SVector{M,T}
157+
end
158+
159+
# Constructors:
160+
# - first, we deduce T
161+
StaticAffineMap(A::AbstractMatrix{T}, b::AbstractVector{T}) where {T} =
162+
StaticAffineMap{T}(A, b)
163+
function StaticAffineMap(A::AbstractMatrix{S}, b::AbstractVector{T}) where {S,T}
164+
U = promote_type(S,T)
165+
StaticAffineMap(convert(AbstractMatrix{U}, A), convert(AbstractVector{U}, b))
166+
end
167+
168+
StaticAffineMap{T}(A::AbstractMatrix, b::AbstractVector) where {T} =
169+
StaticAffineMap{T}(convert(AbstractMatrix{T}, A), convert(AbstractVector{T}, b))
170+
171+
# - then, we determine N and/or M, from the arguments
172+
function StaticAffineMap{T}(A::AbstractMatrix{T}, b::StaticVector{M,T}) where {T,M}
173+
@assert size(A) == (M,M)
174+
StaticAffineMap{T,M,M}(A, b)
175+
end
176+
StaticAffineMap{T}(A::StaticMatrix{M,N,T}, b::AbstractVector) where {T,N,M} =
177+
StaticAffineMap{T,N,M}(A, b)
178+
StaticAffineMap{T}(A::StaticMatrix{M,N,T}, b::StaticVector{M,T}) where {T,N,M} =
179+
StaticAffineMap{T,N,M}(A, b)
180+
# line below catches ambiguity error
181+
StaticAffineMap{T}(A::StaticMatrix{M1,N,T}, b::StaticVector{M2,T}) where {T,N,M1,M2} =
182+
throw(ArgumentError("Non-matching dimensions"))
183+
StaticAffineMap{T,N}(A::AbstractMatrix, b::AbstractVector) where {T,N} =
184+
StaticAffineMap{T,N,N}(A, b)
185+
StaticAffineMap{T,N}(A::StaticMatrix{M,N}, b::AbstractVector) where {T,N,M} =
186+
StaticAffineMap{T,N,M}(A, b)
187+
188+
# - finally invoke the constructor (and implicitly convert the data if necessary)
189+
StaticAffineMap{T,N,M}(A::AbstractMatrix, b::AbstractVector) where {T,N,M} =
190+
StaticAffineMap{T,N,M,M*N}(A, b)
191+
192+
convert(::Type{Map{SVector{N,T}}}, m::VectorAffineMap) where {N,T} =
193+
StaticAffineMap{T,N}(m.A, m.b)

0 commit comments

Comments
 (0)