Skip to content

Commit 11e1813

Browse files
Make the ManifoldUpdate much more efficient (#134)
* Make the ManifoldUpdate much more efficient * Improve the ManifoldUpdate docstring
1 parent 5a1c666 commit 11e1813

File tree

1 file changed

+37
-13
lines changed

1 file changed

+37
-13
lines changed

src/callbacks.jl

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,46 @@
11
function manifoldupdate!(integ, residualf; maxiters=100, ϵ₁=1e-25, ϵ₂=1e-15)
2-
@unpack x, SolProj = integ.cache
3-
f(m) = residualf(SolProj * m)
4-
return copy!(x, manifoldupdate(x, f; maxiters=maxiters, ϵ₁=ϵ₁, ϵ₂=ϵ₂))
5-
end
2+
m, C = integ.cache.x
63

7-
function manifoldupdate(x, f; maxiters=100, ϵ₁=1e-25, ϵ₂=1e-15)
8-
m, C = x
9-
m_i = copy(m)
4+
# Create some caches
5+
@unpack SolProj, tmp, H, x_tmp, x_tmp2 = integ.cache
6+
z_tmp = residualf(mul!(tmp, SolProj, m))
7+
result = DiffResults.JacobianResult(z_tmp, tmp)
8+
d = length(z_tmp)
9+
H = H[1:d, :]
10+
S = SquarerootMatrix(C.squareroot[1:d, :], C.mat[1:d, 1:d])
11+
m_tmp, C_tmp = x_tmp
1012

13+
m_i = copy(m)
1114
local m_i_new, C_i_new
1215
for i in 1:maxiters
13-
z = f(m_i)
14-
J = ForwardDiff.jacobian(f, m_i)
15-
S = X_A_Xt(C, J)
16+
u_i = mul!(tmp, SolProj, m_i)
17+
18+
ForwardDiff.jacobian!(result, residualf, u_i)
19+
z = DiffResults.value(result)
20+
J = DiffResults.jacobian(result)
1621

17-
m_i_new, C_i_new = update(x, Gaussian(z .+ (J * (m - m_i)), S), J)
22+
mul!(H, J, SolProj)
23+
X_A_Xt!(S, C, H)
1824

19-
if norm(m_i_new .- m_i) < ϵ₁ && norm(z) < ϵ₂
25+
# m_i_new, C_i_new = update(x, Gaussian(z .+ (H * (m - m_i)), S), H)
26+
# More efficient update with less allocations:
27+
K = C * (H' / S)
28+
m_tmp .= m_i .- m
29+
mul!(z_tmp, H, m_tmp)
30+
z_tmp .-= z
31+
mul!(m_tmp, K, z_tmp)
32+
m_i_new = m_tmp .+= m
33+
34+
if (norm(m_i_new .- m_i) < ϵ₁ && norm(z) < ϵ₂) || (i == maxiters)
35+
C_i_new = X_A_Xt!(C_tmp, C, (I - K * H))
2036
break
2137
end
2238
m_i = m_i_new
2339
end
24-
return Gaussian(m_i_new, C_i_new)
40+
41+
copy!(integ.cache.x, Gaussian(m_i_new, C_i_new))
42+
43+
return nothing
2544
end
2645

2746
"""
@@ -33,6 +52,11 @@ Update the state to satisfy a zero residual function via iterated extended Kalma
3352
performs an iterated extended Kalman filter update to keep the residual measurement to be
3453
zero. Additional arguments and keyword arguments for the `DiscreteCallback` can be passed.
3554
55+
The residual function should be `residual(u::AbstractVector)::AbstractVector`, that is
56+
_it should not be in-place_ (whereas DiffEqCallback.jl's `ManifoldProjection`) is.
57+
If you encounter `SingularException`s, make sure that the residual function is such that
58+
its Jacobian has full rank.
59+
3660
# Additional keyword arguments
3761
- `maxiters::Int`: Maximum number of IEKF iterations.
3862
Setting this to 1 results in a single standard EKF update.

0 commit comments

Comments
 (0)