-
Notifications
You must be signed in to change notification settings - Fork 12
/
common.jl
151 lines (122 loc) · 6.06 KB
/
common.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
isreal(::Type{<:Real}) = true
isreal(::Type{<:Complex}) = false
isreal(::Type{T}) where {T} = isreal(eltype(T))
const StaticTypes = Union{Number,<:StaticVector{N} where N,<:NTuple{N,Any} where N}
"What is the euclidean dimension of the given type (if applicable)?"
euclideandimension(::Type{T}) where {T <: Number} = 1
euclideandimension(::Type{T}) where {N,T <: StaticVector{N}} = N
euclideandimension(::Type{T}) where {N,T <: NTuple{N,Any}} = N
# Does not apply to Vector{T}: we don't know its dimension
unitvector(d::Domain{T}, dim) where {N,S,T<:SVector{N,S}} = SVector{N,S}(ntuple(i -> i==dim, N))
function unitvector(d::Domain{T}, dim) where {T<:AbstractVector}
p = zeros(eltype(T), dimension(d))
p[dim] = 1
p
end
unitvector(d::Domain{T}, dim) where {T<:Number} = (@assert dim==1; one(T))
origin(d::Domain{T}) where {T <: StaticTypes} = zero(T)
function origin(d::Domain{T}) where {T <: AbstractVector}
p = similar(point_in_domain(d))
fill!(p, 0)
convert(T, p)
end
"Apply the `hash` function recursively to the given arguments."
hashrec(x) = hash(x)
hashrec(x, args...) = hash(x, hashrec(args...))
# Workaround for #88, manually compute the hash of an array using all its elements
hashrec() = zero(UInt)
function hashrec(A::AbstractArray, args...)
h = hash(size(A))
for x in A
h = hash(x, h)
end
hash(h, hashrec(args...))
end
#################
# Precision type
#################
"The floating point precision type associated with the argument."
prectype(x) = prectype(typeof(x))
prectype(::Type{<:Complex{T}}) where {T} = prectype(T)
prectype(::Type{<:AbstractArray{T}}) where {T} = prectype(T)
prectype(::Type{NTuple{N,T}}) where {N,T} = prectype(T)
prectype(::Type{Tuple{A}}) where {A} = prectype(A)
prectype(::Type{Tuple{A,B}}) where {A,B} = prectype(A,B)
prectype(::Type{Tuple{A,B,C}}) where {A,B,C} = prectype(A,B,C)
@generated function prectype(T::Type{<:Tuple{Vararg}})
quote $(promote_type(map(prectype, T.parameters[1].parameters)...)) end
end
prectype(::Type{T}) where {T<:AbstractFloat} = T
prectype(::Type{T}) where {T<:Number} = prectype(float(T))
prectype(a...) = promote_type(map(prectype, a)...)
"Convert `x` such that its `prectype` equals `U`."
convert_prectype(x, ::Type{U}) where {U} = convert(to_prectype(typeof(x),U), x)
# function convert_prectype(x, ::Type{U}) where {U}
# @warn "The order of arguments of convert_prectype has changed."
# prectype(U, x)
# end
"Return the type to which `U` can be converted, such that the `prectype` becomes `T`."
to_prectype(::Type{T}, ::Type{U}) where {T,U} = error("Don't know how to convert the numtype of $(T) to $(U).")
to_prectype(::Type{T}, ::Type{U}) where {T <: Real,U <: Real} = U
to_prectype(::Type{Complex{T}}, ::Type{U}) where {T <: Real,U <: Real} = Complex{U}
to_prectype(::Type{SVector{N,T}}, ::Type{U}) where {N,T,U} = SVector{N,to_prectype(T,U)}
to_prectype(::Type{Vector{T}}, ::Type{U}) where {T,U} = Vector{to_prectype(T,U)}
"Promote the precision types of the arguments to a joined supertype."
promote_prectype(a) = a
promote_prectype(a, b) = _promote_prectype(prectype(a,b), a, b)
promote_prectype(a, b, c...) = _promote_prectype(prectype(a,b,c...), a, b, c...)
_promote_prectype(U, a) = convert_prectype(a, U)
_promote_prectype(U, a, b) = convert_prectype(a, U), convert_prectype(b, U)
_promote_prectype(U, a, b, c...) =
(convert_prectype(a, U), convert_prectype(b, U), _promote_prectype(U, c...)...)
#################
# Numeric type
#################
"The numeric element type of x in a Euclidean space."
numtype(x) = numtype(typeof(x))
numtype(::Type{T}) where {T<:Number} = T
numtype(::Type{T}) where {T} = eltype(T)
numtype(::Type{NTuple{N,T}}) where {N,T} = T
numtype(::Type{Tuple{A,B}}) where {A,B} = promote_type(numtype(A), numtype(B))
numtype(::Type{Tuple{A,B,C}}) where {A,B,C} = promote_type(numtype(A), numtype(B), numtype(C))
numtype(::Type{Tuple{A,B,C,D}}) where {A,B,C,D} = promote_type(numtype(A), numtype(B), numtype(C), numtype(D))
@generated function numtype(T::Type{<:Tuple{Vararg}})
quote $(promote_type(T.parameters[1].parameters...)) end
end
numtype(a...) = promote_type(map(numtype, a)...)
"Convert `x` such that its `numtype` equals `U`."
convert_numtype(x, ::Type{U}) where {U} = convert(to_numtype(typeof(x),U), x)
to_numtype(::Type{T}, ::Type{U}) where {T,U} = error("Don't know how to convert the numtype of $(T) to $(U).")
to_numtype(::Type{T}, ::Type{U}) where {T <: Number,U <: Number} = U
to_numtype(::Type{SVector{N,T}}, ::Type{U}) where {N,T,U} = SVector{N,to_numtype(T,U)}
to_numtype(::Type{Vector{T}}, ::Type{U}) where {T,U} = Vector{to_numtype(T,U)}
"Promote the numeric types of the arguments to a joined supertype."
promote_numtype(a) = a
promote_numtype(a, b) = _promote_numtype(numtype(a,b), a, b)
promote_numtype(a, b, c...) = _promote_numtype(numtype(a,b,c...), a, b, c...)
_promote_numtype(U, a) = convert_numtype(a, U)
_promote_numtype(U, a, b) = convert_numtype(a, U), convert_numtype(b, U)
_promote_numtype(U, a, b, c...) =
(convert_numtype(a, U), convert_numtype(b, U), _promote_numtype(U, c...)...)
## Conversion from nested vectors to flat vectors and back
"""
Convert a vector from a cartesian format to a nested tuple according to the
given dimensions.
For example:
`convert_fromcartesian([1,2,3,4,5], Val{(2,2,1)}()) -> ([1,2],[3,4],5)`
"""
@generated function convert_fromcartesian(x::AbstractVector, ::Val{DIM}) where {DIM}
dimsum = [0; cumsum([d for d in DIM])]
E = Expr(:tuple, [ (dimsum[i+1]-dimsum[i] > 1 ? Expr(:call, :SVector, [:(x[$j]) for j = dimsum[i]+1:dimsum[i+1]]...) : :(x[$(dimsum[i+1])])) for i in 1:length(DIM)]...)
return quote $(E) end
end
"The inverse function of `convert_fromcartesian`."
@generated function convert_tocartesian(x, ::Val{DIM}) where {DIM}
dimsum = [0; cumsum([d for d in DIM])]
E = vcat([[:(x[$i][$j]) for j in 1:DIM[i]] for i in 1:length(DIM)]...)
quote SVector($(E...)) end
end
# we use matrix_pinv rather than pinv to preserve static matrices
matrix_pinv(A) = pinv(A)
matrix_pinv(A::SMatrix{M,N}) where {M,N} = SMatrix{N,M}(pinv(A))
matrix_pinv(A::SVector{N}) where {N} = convert(Transpose{Float64, SVector{N,Float64}}, pinv(A))