Skip to content

Understanding why MovingHorizonEstimator Hessians are always fully dense #368

@franckgaga

Description

@franckgaga

Hello @gdalle !

I'm having the same problem as #193 but for the MovingHorizonEstimator (MHE) instead of the NonLinMPC, that is, a fully-dense sparsity pattern for the Hessian of the objective function, when I'm 99.9% sure that many zeros are in fact global zeros. Note that I applied the equivalent improvements of #202 but for the MHE (on PR #216), so the problem seems to be elsewhere. I put too much time on trying to figure out why, so I'm asking for your help. What debugging method did you use to find out the two results mentioned here ? To be clearer, I want to handle structural sparsity better in the MHE, but I cannot find where the problem is in update_prediction! and obj_nonlinprog methods.

By using ModelPredictiveControl.jl v2.4.1 (registered in a few minutes, else you can dev it), here's a MRE:

using ModelPredictiveControl, ControlSystemsBase

Ts = 4.0
A =  [  0.800737  0.0       0.0  0.0
        0.0       0.606531  0.0  0.0
        0.0       0.0       0.8  0.0
        0.0       0.0       0.0  0.6    ]
Bu = [  0.378599  0.378599
        -0.291167  0.291167
        0.0       0.0
        0.0       0.0                   ]
Bd = [  0; 0; 0.5; 0.5;;                ]
C =  [  1.0  0.0  0.684   0.0
        0.0  1.0  0.0    -0.4736        ]
Dd = [  0.19; -0.148;;                  ]
Du = zeros(2,2)
model = LinModel(ss(A,[Bu Bd],C,[Du Dd],Ts),Ts,i_d=[3])
model = setop!(model, uop=[10,10], yop=[50,30], dop=[5])

using DifferentiationInterface, SparseConnectivityTracer, SparseMatrixColorings
import ForwardDiff
hessian = AutoSparse(AutoForwardDiff(), sparsity_detector=TracerSparsityDetector(), coloring_algorithm=GreedyColoringAlgorithm())
# hessian = AutoSparse(AutoForwardDiff(), sparsity_detector=TracerLocalSparsityDetector(), coloring_algorithm=GreedyColoringAlgorithm())

function gc!(LHS, X̂e, V̂e, Ŵe, Ue, Yem, De, P̄, x̄, p, ε)
    N = length(X̂e)÷6
    LHS .= 0
    for i in eachindex(LHS)
        if i  N
            LHS[i] = X̂e[6*(i-1)+1] - 0 - ε
        end
    end
    return nothing
end

mhe = MovingHorizonEstimator(model; He=10, hessian, gc!, nc=11)
using JuMP; unset_time_limit_sec(mhe.optim)
res = sim!(mhe, 15, x̂_0=zeros(6), d_step=[-2.0])
info = getinfo(mhe)
display(info[:∇²J])

giving with TracerSparsityDetector:

66×66 SparseArrays.SparseMatrixCSC{Float64, Int64} with 4356 stored entries:
⎡⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⎤
⎢⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⎥
⎢⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⎥
⎢⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⎥
⎢⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⎥
⎢⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⎥
⎢⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⎥
⎢⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⎥
⎢⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⎥
⎢⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⎥
⎢⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⎥
⎢⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⎥
⎢⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⎥
⎣⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⎦

and with TracerLocalSparsityDetector:

66×66 SparseArrays.SparseMatrixCSC{Float64, Int64} with 2178 stored entries:
⎡⣕⣽⣪⣪⣗⣕⣕⣯⣪⣺⣕⣕⣽⣪⣪⣗⣕⣕⣯⣪⣺⣕⣕⣽⣪⣪⣗⣕⎤
⎢⡪⣺⢕⢕⡯⡪⡪⣗⢕⢽⡪⡪⣺⢕⢕⡯⡪⡪⣗⢕⢽⡪⡪⣺⢕⢕⡯⡪⎥
⎢⢝⢽⡫⡫⣟⢝⢝⡯⡫⣻⢝⢝⢽⡫⡫⣟⢝⢝⡯⡫⣻⢝⢝⢽⡫⡫⣟⢝⎥
⎢⡵⣽⢮⢮⡷⡵⡵⣯⢮⢾⡵⡵⣽⢮⢮⡷⡵⡵⣯⢮⢾⡵⡵⣽⢮⢮⡷⡵⎥
⎢⣪⣺⣕⣕⣯⣪⣪⣗⣕⣽⣪⣪⣺⣕⣕⣯⣪⣪⣗⣕⣽⣪⣪⣺⣕⣕⣯⣪⎥
⎢⢕⢽⡪⡪⣗⢕⢕⡯⡪⣺⢕⢕⢽⡪⡪⣗⢕⢕⡯⡪⣺⢕⢕⢽⡪⡪⣗⢕⎥
⎢⡳⣻⢞⢞⡷⡳⡳⣟⢞⢾⡳⡳⣻⢞⢞⡷⡳⡳⣟⢞⢾⡳⡳⣻⢞⢞⡷⡳⎥
⎢⢮⢾⡵⡵⣯⢮⢮⡷⡵⣽⢮⢮⢾⡵⡵⣯⢮⢮⡷⡵⣽⢮⢮⢾⡵⡵⣯⢮⎥
⎢⢕⢽⡪⡪⣗⢕⢕⡯⡪⣺⢕⢕⢽⡪⡪⣗⢕⢕⡯⡪⣺⢕⢕⢽⡪⡪⣗⢕⎥
⎢⡫⣻⢝⢝⡯⡫⡫⣟⢝⢽⡫⡫⣻⢝⢝⡯⡫⡫⣟⢝⢽⡫⡫⣻⢝⢝⡯⡫⎥
⎢⢞⢾⡳⡳⣟⢞⢞⡷⡳⣻⢞⢞⢾⡳⡳⣟⢞⢞⡷⡳⣻⢞⢞⢾⡳⡳⣟⢞⎥
⎢⣕⣽⣪⣪⣗⣕⣕⣯⣪⣺⣕⣕⣽⣪⣪⣗⣕⣕⣯⣪⣺⣕⣕⣽⣪⣪⣗⣕⎥
⎢⡪⣺⢕⢕⡯⡪⡪⣗⢕⢽⡪⡪⣺⢕⢕⡯⡪⡪⣗⢕⢽⡪⡪⣺⢕⢕⡯⡪⎥
⎣⢝⢽⡫⡫⣟⢝⢝⡯⡫⣻⢝⢝⢽⡫⡫⣟⢝⢝⡯⡫⣻⢝⢝⢽⡫⡫⣟⢝⎦

Many thanks for your time !

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions