Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linear univariate time variant model implemented? #321

Open
jsimons8 opened this issue Sep 19, 2023 · 8 comments
Open

Linear univariate time variant model implemented? #321

jsimons8 opened this issue Sep 19, 2023 · 8 comments

Comments

@jsimons8
Copy link

I was wondering if the method LinearUnivariateTimeVariant was already implemented?

The call

Ze = [[1.; 0] for _ in 1:15];
Te = [[1. 1; 0 1] for _ in 1:15];
Re = [[1. 0; 0 1] for _ in 1:15];
de = convert(Array{Float64,1},zeros(15));
ce = [[0., 0] for _ in 1:15];
He = tv_observational_noise;
Qe = [[1. 0; 0 1] for _ in 1:15];

tv_var_model = StateSpaceModels.LinearUnivariateTimeVariant(mu_hat_i[1,1,:],Ze,Te,Re,de,ce,He,Qe)

where tv_observational_noise is a Vector{Float64} with the same (15) number of elements. This call yielded the following error:

MethodError: no method matching LinearUnivariateTimeVariant(::Vector{Float64}, ::Vector{Vector{Float64}}, ::Vector{Matrix{Float64}}, ::Vector{Matrix{Float64}}, ::Vector{Float64}, ::Vector{Vector{Float64}}, ::Vector{Float64}, ::Vector{Matrix{Float64}})

Given, I have observed all types, I am wondering if this is because the method is not implemented?

If it is implemented, do you think you can help me fix the call? Moreover, I was hoping to estimate the time-independent Q_t hyperparameter but the method definition seems to ask for a Q_t without the possibility of its estimation.

@guilhermebodin
Copy link
Member

Do you have a Minimal working example? A script with some fake data that breaks in the same way.

@jsimons8
Copy link
Author

Hi Guilherme,

Yes, the following code fragment is self-contained:

using StateSpaceModels
Jnn=15;
y = rand(Jnn);
Ze = [[1.; 0] for _ in 1:Jnn];
Te = [[1. 1; 0 1] for _ in 1:Jnn];
Re = [[1. 0; 0 1] for _ in 1:Jnn];
de = convert(Array{Float64,1},zeros(Jnn));
ce = [[0., 0] for _ in 1:Jnn];
He = rand(Jnn);
Qe = [[1. 0; 0 1] for _ in 1:Jnn];

tv_var_model = StateSpaceModels.LinearUnivariateTimeVariant(y,Ze,Te,Re,de,ce,He,Qe)

That produces the same error. Also, would estimation of time-invariant Q_t be possible? Thank you so much!

@raphaelsaavedra
Copy link
Member

Hi @jsimons8, the issue is that you're not parametrizing LinearUnivariateTimeVariant. If you run the following it should work:

LinearUnivariateTimeVariant{Float64}(y,Ze,Te,Re,de,ce,He,Qe)

Maybe we should set Float64 to be the default parameter and have a constructor that doesn't take a type. I think this hasn't come up because this isn't part of the usual public API (we tend to use the models instead of a system directly)

@jsimons8
Copy link
Author

Hi @raphaelsaavedra thank you so much! That indeed solves the issue. Now, is it possible to somehow instruct the package to estimate $Q_t$, which I did not want to restrict? Greetings from Cambridge :-)

@jsimons8
Copy link
Author

Oh and somehow the command fit!(tv_var_model) throws the error MethodError: no method matching fit!(::LinearUnivariateTimeVariant{Float64})

I am not sure how to proceed. The type LinearUnivariateTimeVariant is exactly what I needed.

@raphaelsaavedra
Copy link
Member

Not too sure on the question about estimating Qt from a system – maybe @guilhermebodin will know. Admittedly it's been a while since I've properly maintained the package.

On the reason why you're getting that MethodError, it's because fit! isn't implemented for systems, only for models (see the full error message below):

ERROR: MethodError: no method matching fit!(::LinearUnivariateTimeVariant{Float64})
Closest candidates are:
  fit!(::StateSpaceModel; filter, optimizer, save_hyperparameter_distribution) at ~/.julia/packages/StateSpaceModels/DmxMT/src/fit.jl:29
  fit!(::Naive) at ~/.julia/packages/StateSpaceModels/DmxMT/src/models/naive_models.jl:46
  fit!(::SeasonalNaive) at ~/.julia/packages/StateSpaceModels/DmxMT/src/models/naive_models.jl:114
  ...

There are two main ways you can proceed IMO. One is see if what you're trying to do falls under any existing model in the package. If not, you can implement a new model type (define it as a subtype of StateSpaceModel) and it should work. You can take a look at existing models for reference.

@jsimons8
Copy link
Author

Great, so you mean writing something like locallevel.jl with the relevant snippet being:

mutable struct LocalLevel <: StateSpaceModel
    hyperparameters::HyperParameters
    system::LinearUnivariateTimeInvariant
    results::Results

    function LocalLevel(y::Vector{Fl}) where Fl

        # Define system matrices
        Z = ones(Fl, 1)
        T = ones(Fl, 1, 1)
        R = ones(Fl, 1, 1)
        d = zero(Fl)
        c = zeros(Fl, 1)
        H = one(Fl)
        Q = ones(Fl, 1, 1)

        system = LinearUnivariateTimeInvariant{Fl}(y, Z, T, R, d, c, H, Q)

        # Define hyperparameters names
        names = ["sigma2_ε", "sigma2_η"]
        hyperparameters = HyperParameters{Fl}(names)

        return new(hyperparameters, system, Results{Fl}())
    end
end

Do you have any resources on how to work on a modification of the package?

@guilhermebodin
Copy link
Member

guilhermebodin commented Sep 19, 2023

You can implemented them oustide of the package in your own code or create a new model in the models folder. To be able to fit you have to declare a new model, just like local level and implement some methods.

The fit function will check it for you if every method is implemented.

"""
    has_fit_methods(model_type::Type{<:StateSpaceModel}) -> Bool

Verify if a certain `StateSpaceModel` has the necessary methods to perform `fit!``.
"""
function has_fit_methods(model_type::Type{<:StateSpaceModel})
    tuple_with_model_type = Tuple{model_type}
    m1 = hasmethod(default_filter, tuple_with_model_type)
    m2 = hasmethod(initial_hyperparameters!, tuple_with_model_type)
    m3 = hasmethod(constrain_hyperparameters!, tuple_with_model_type)
    m4 = hasmethod(unconstrain_hyperparameters!, tuple_with_model_type)
    m5 = hasmethod(fill_model_system!, tuple_with_model_type)
    return m1 && m2 && m3 && m4 && m5
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants