/
utils.jl
131 lines (115 loc) · 3.64 KB
/
utils.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
@doc raw"""
usinc(θ::Real)
Unnormalized version of `sinc` function, i.e. $\operatorname{usinc}(θ) = \frac{\sin(θ)}{θ}$.
This is equivalent to `sinc(θ/π)`.
"""
@inline usinc(θ::Real) = θ == 0 ? one(θ) : isinf(θ) ? zero(θ) : sin(θ) / θ
@doc raw"""
usinc_from_cos(x::Real)
Unnormalized version of `sinc` function, i.e. $\operatorname{usinc}(θ) = \frac{\sin(θ)}{θ}$,
computed from $x = cos(θ)$.
"""
@inline function usinc_from_cos(x::Real)
return if x >= 1
one(x)
elseif x <= -1
zero(x)
else
sqrt(1 - x^2) / acos(x)
end
end
allocate(p, s::Size{S}) where {S} = similar(p, S...)
allocate(p::StaticArray, s::Size{S}) where {S} = similar(p, maybesize(s))
allocate(p, ::Type{T}, s::Size{S}) where {S,T} = similar(p, T, S...)
allocate(p::StaticArray, ::Type{T}, s::Size{S}) where {S,T} = similar(p, T, maybesize(s))
"""
eigen_safe(x)
Compute the eigendecomposition of `x`. If `x` is a `StaticMatrix`, it is
converted to a `Matrix` before the decomposition.
"""
@inline eigen_safe(x; kwargs...) = eigen(x; kwargs...)
@inline function eigen_safe(x::StaticMatrix; kwargs...)
s = size(x)
E = eigen!(Matrix(parent(x)); kwargs...)
return Eigen(SizedVector{s[1]}(E.values), SizedMatrix{s...}(E.vectors))
end
"""
log_safe(x)
Compute the matrix logarithm of `x`. If `x` is a `StaticMatrix`, it is
converted to a `Matrix` before computing the log.
"""
@inline log_safe(x) = log(x)
@inline function log_safe(x::StaticMatrix)
s = Size(x)
return SizedMatrix{s[1],s[2]}(log(Matrix(parent(x))))
end
@generated maybesize(s::Size{S}) where {S} = prod(S) > 100 ? S : :(s)
"""
select_from_tuple(t::NTuple{N, Any}, positions::Val{P})
Selects elements of tuple `t` at positions specified by the second argument.
For example `select_from_tuple(("a", "b", "c"), Val((3, 1, 1)))` returns
`("c", "a", "a")`.
"""
@generated function select_from_tuple(t::NTuple{N,Any}, positions::Val{P}) where {N,P}
for k in P
(k < 0 || k > N) && error("positions must be between 1 and $N")
end
return Expr(:tuple, [Expr(:ref, :t, k) for k in P]...)
end
"""
size_to_tuple(::Type{S}) where S<:Tuple
Converts a size given by `Tuple{N, M, ...}` into a tuple `(N, M, ...)`.
"""
Base.@pure size_to_tuple(::Type{S}) where {S<:Tuple} = tuple(S.parameters...)
"""
ziptuples(a, b[, c[, d[, e]]])
Zips tuples `a`, `b`, and remaining in a fast, type-stable way. If they have different
lengths, the result is trimmed to the length of the shorter tuple.
"""
@generated function ziptuples(a::NTuple{N,Any}, b::NTuple{M,Any}) where {N,M}
ex = Expr(:tuple)
for i in 1:min(N, M)
push!(ex.args, :((a[$i], b[$i])))
end
return ex
end
@generated function ziptuples(
a::NTuple{N,Any},
b::NTuple{M,Any},
c::NTuple{L,Any},
) where {N,M,L}
ex = Expr(:tuple)
for i in 1:min(N, M, L)
push!(ex.args, :((a[$i], b[$i], c[$i])))
end
return ex
end
@generated function ziptuples(
a::NTuple{N,Any},
b::NTuple{M,Any},
c::NTuple{L,Any},
d::NTuple{K,Any},
) where {N,M,L,K}
ex = Expr(:tuple)
for i in 1:min(N, M, L, K)
push!(ex.args, :((a[$i], b[$i], c[$i], d[$i])))
end
return ex
end
@generated function ziptuples(
a::NTuple{N,Any},
b::NTuple{M,Any},
c::NTuple{L,Any},
d::NTuple{K,Any},
e::NTuple{J,Any},
) where {N,M,L,K,J}
ex = Expr(:tuple)
for i in 1:min(N, M, L, K, J)
push!(ex.args, :((a[$i], b[$i], c[$i], d[$i], e[$i])))
end
return ex
end
# TODO: make a better implementation for StaticArrays
function LinearAlgebra.eigvals(A::StaticArray, B::StaticArray; kwargs...)
return eigvals(Array(A), Array(B); kwargs...)
end