1+ module  ForwardDiffStaticArraysExt
2+ 
3+ using  ForwardDiff, StaticArrays
4+ using  ForwardDiff. LinearAlgebra
5+ using  ForwardDiff. DiffResults
6+ using  ForwardDiff:  Dual, partials, GradientConfig, JacobianConfig, HessianConfig, Tag, Chunk,
7+                    gradient, hessian, jacobian, gradient!, hessian!, jacobian!,
8+                    extract_gradient!, extract_jacobian!, extract_value!,
9+                    vector_mode_gradient, vector_mode_gradient!,
10+                    vector_mode_jacobian, vector_mode_jacobian!, valtype, value, _lyap_div!
11+ using  DiffResults:  DiffResult, ImmutableDiffResult, MutableDiffResult
12+ 
13+ @generated  function  dualize (:: Type{T} , x:: StaticArray ) where  T
14+     N =  length (x)
15+     dx =  Expr (:tuple , [:(Dual {T} (x[$ i], chunk, Val {$i} ())) for  i in  1 : N]. .. )
16+     V =  StaticArrays. similar_type (x, Dual{T,eltype (x),N})
17+     return  quote 
18+         chunk =  Chunk {$N} ()
19+         $ (Expr (:meta , :inline ))
20+         return  $ V ($ (dx))
21+     end 
22+ end 
23+ 
24+ @inline  static_dual_eval (:: Type{T} , f, x:: StaticArray ) where  T =  f (dualize (T, x))
25+ 
26+ function  LinearAlgebra. eigvals (A:: Symmetric{<:Dual{Tg,T,N}, <:StaticArrays.StaticMatrix} ) where  {Tg,T<: Real ,N}
27+     λ,Q =  eigen (Symmetric (value .(parent (A))))
28+     parts =  ntuple (j ->  diag (Q'  *  getindex .(partials .(A), j) *  Q), N)
29+     Dual {Tg} .(λ, tuple .(parts... ))
30+ end 
31+ 
32+ function  LinearAlgebra. eigen (A:: Symmetric{<:Dual{Tg,T,N}, <:StaticArrays.StaticMatrix} ) where  {Tg,T<: Real ,N}
33+     λ =  eigvals (A)
34+     _,Q =  eigen (Symmetric (value .(parent (A))))
35+     parts =  ntuple (j ->  Q* ForwardDiff. _lyap_div! (Q'  *  getindex .(partials .(A), j) *  Q -  Diagonal (getindex .(partials .(λ), j)), value .(λ)), N)
36+     Eigen (λ,Dual {Tg} .(Q, tuple .(parts... )))
37+ end 
38+ 
39+ #  Gradient
40+ @inline  ForwardDiff. gradient (f, x:: StaticArray )                      =  vector_mode_gradient (f, x)
41+ @inline  ForwardDiff. gradient (f, x:: StaticArray , cfg:: GradientConfig ) =  gradient (f, x)
42+ @inline  ForwardDiff. gradient (f, x:: StaticArray , cfg:: GradientConfig , :: Val ) =  gradient (f, x)
43+ 
44+ @inline  ForwardDiff. gradient! (result:: Union{AbstractArray,DiffResult} , f, x:: StaticArray ) =  vector_mode_gradient! (result, f, x)
45+ @inline  ForwardDiff. gradient! (result:: Union{AbstractArray,DiffResult} , f, x:: StaticArray , cfg:: GradientConfig ) =  gradient! (result, f, x)
46+ @inline  ForwardDiff. gradient! (result:: Union{AbstractArray,DiffResult} , f, x:: StaticArray , cfg:: GradientConfig , :: Val ) =  gradient! (result, f, x)
47+ 
48+ @generated  function  extract_gradient (:: Type{T} , y:: Real , x:: S ) where  {T,S<: StaticArray }
49+     result =  Expr (:tuple , [:(partials (T, y, $ i)) for  i in  1 : length (x)]. .. )
50+     return  quote 
51+         $ (Expr (:meta , :inline ))
52+         V =  StaticArrays. similar_type (S, valtype ($ y))
53+         return  V ($ result)
54+     end 
55+ end 
56+ 
57+ @inline  function  ForwardDiff. vector_mode_gradient (f, x:: StaticArray )
58+     T =  typeof (Tag (f, eltype (x)))
59+     return  extract_gradient (T, static_dual_eval (T, f, x), x)
60+ end 
61+ 
62+ @inline  function  ForwardDiff. vector_mode_gradient! (result, f, x:: StaticArray )
63+     T =  typeof (Tag (f, eltype (x)))
64+     return  extract_gradient! (T, result, static_dual_eval (T, f, x))
65+ end 
66+ 
67+ #  Jacobian
68+ @inline  ForwardDiff. jacobian (f, x:: StaticArray ) =  vector_mode_jacobian (f, x)
69+ @inline  ForwardDiff. jacobian (f, x:: StaticArray , cfg:: JacobianConfig ) =  jacobian (f, x)
70+ @inline  ForwardDiff. jacobian (f, x:: StaticArray , cfg:: JacobianConfig , :: Val ) =  jacobian (f, x)
71+ 
72+ @inline  ForwardDiff. jacobian! (result:: Union{AbstractArray,DiffResult} , f, x:: StaticArray ) =  vector_mode_jacobian! (result, f, x)
73+ @inline  ForwardDiff. jacobian! (result:: Union{AbstractArray,DiffResult} , f, x:: StaticArray , cfg:: JacobianConfig ) =  jacobian! (result, f, x)
74+ @inline  ForwardDiff. jacobian! (result:: Union{AbstractArray,DiffResult} , f, x:: StaticArray , cfg:: JacobianConfig , :: Val ) =  jacobian! (result, f, x)
75+ 
76+ @generated  function  extract_jacobian (:: Type{T} , ydual:: StaticArray , x:: S ) where  {T,S<: StaticArray }
77+     M, N =  length (ydual), length (x)
78+     result =  Expr (:tuple , [:(partials (T, ydual[$ i], $ j)) for  i in  1 : M, j in  1 : N]. .. )
79+     return  quote 
80+         $ (Expr (:meta , :inline ))
81+         V =  StaticArrays. similar_type (S, valtype (eltype ($ ydual)), Size ($ M, $ N))
82+         return  V ($ result)
83+     end 
84+ end 
85+ 
86+ function  extract_jacobian (:: Type{T} , ydual:: AbstractArray , x:: StaticArray ) where  T
87+     result =  similar (ydual, valtype (eltype (ydual)), length (ydual), length (x))
88+     return  extract_jacobian! (T, result, ydual, length (x))
89+ end 
90+ 
91+ @inline  function  ForwardDiff. vector_mode_jacobian (f, x:: StaticArray )
92+     T =  typeof (Tag (f, eltype (x)))
93+     return  extract_jacobian (T, static_dual_eval (T, f, x), x)
94+ end 
95+ 
96+ @inline  function  ForwardDiff. vector_mode_jacobian! (result, f, x:: StaticArray )
97+     T =  typeof (Tag (f, eltype (x)))
98+     ydual =  static_dual_eval (T, f, x)
99+     result =  extract_jacobian! (T, result, ydual, length (x))
100+     result =  extract_value! (T, result, ydual)
101+     return  result
102+ end 
103+ 
104+ @inline  function  ForwardDiff. vector_mode_jacobian! (result:: ImmutableDiffResult , f, x:: StaticArray )
105+     T =  typeof (Tag (f, eltype (x)))
106+     ydual =  static_dual_eval (T, f, x)
107+     result =  DiffResults. jacobian! (result, extract_jacobian (T, ydual, x))
108+     result =  DiffResults. value! (d ->  value (T,d), result, ydual)
109+     return  result
110+ end 
111+ 
112+ #  Hessian
113+ ForwardDiff. hessian (f, x:: StaticArray ) =  jacobian (y ->  gradient (f, y), x)
114+ ForwardDiff. hessian (f, x:: StaticArray , cfg:: HessianConfig ) =  hessian (f, x)
115+ ForwardDiff. hessian (f, x:: StaticArray , cfg:: HessianConfig , :: Val ) =  hessian (f, x)
116+ 
117+ ForwardDiff. hessian! (result:: AbstractArray , f, x:: StaticArray ) =  jacobian! (result, y ->  gradient (f, y), x)
118+ 
119+ ForwardDiff. hessian! (result:: MutableDiffResult , f, x:: StaticArray ) =  hessian! (result, f, x, HessianConfig (f, result, x))
120+ 
121+ ForwardDiff. hessian! (result:: ImmutableDiffResult , f, x:: StaticArray , cfg:: HessianConfig ) =  hessian! (result, f, x)
122+ ForwardDiff. hessian! (result:: ImmutableDiffResult , f, x:: StaticArray , cfg:: HessianConfig , :: Val ) =  hessian! (result, f, x)
123+ 
124+ function  ForwardDiff. hessian! (result:: ImmutableDiffResult , f, x:: StaticArray )
125+     T =  typeof (Tag (f, eltype (x)))
126+     d1 =  dualize (T, x)
127+     d2 =  dualize (T, d1)
128+     fd2 =  f (d2)
129+     val =  value (T,value (T,fd2))
130+     grad =  extract_gradient (T,value (T,fd2), x)
131+     hess =  extract_jacobian (T,partials (T,fd2), x)
132+     result =  DiffResults. hessian! (result, hess)
133+     result =  DiffResults. gradient! (result, grad)
134+     result =  DiffResults. value! (result, val)
135+     return  result
136+ end 
137+ 
138+ end 
0 commit comments