Model Structures
model_structures.Rd
These tools define and implement model structures where the model parameters are represented
by an affine function of some free (deep) parameters. As an example consider
multivariate ARMA models. The AR coefficients \(a_k\), the MA coefficients \(b_k\)
and the (left) square root of the noise covariance matrix, \(L\) say, are vectorized and stacked
into a (long) parameter vector as
$$\pi = (\mbox{vec}(a_1)',\ldots,\mbox{vec}(a_p)',
\mbox{vec}(b_1)',\ldots,\mbox{vec}(b_q)',\mbox{vec}(L)')'$$
This parameter vector then is written as
$$\pi = h + H\theta$$
where \(\theta\) represents the free parameters. Of course the matrix \(H\) is assumed to have
full column rank. This parameterization scheme is quite flexible. In particular, ARMA and
state space models in echelon form may be represented by this scheme.
Templates and the related tools are mainly used for estimation and for the generation of (random) models
for simulations and testing.
Usage
model2template(
model,
sigma_L = c("as_given", "chol", "symm", "identity", "full_normalized")
)
tmpl_arma_pq(
m,
n,
p,
q,
sigma_L = c("chol", "symm", "identity", "full_normalized")
)
tmpl_arma_echelon(
nu,
n = length(nu),
sigma_L = c("chol", "symm", "identity", "full_normalized")
)
tmpl_rmfd_pq(
m,
n,
p,
q,
sigma_L = c("chol", "symm", "identity", "full_normalized")
)
tmpl_rmfd_echelon(
nu,
m = length(nu),
sigma_L = c("chol", "symm", "identity", "full_normalized")
)
tmpl_stsp_full(
m,
n,
s,
sigma_L = c("chol", "symm", "identity", "full_normalized")
)
tmpl_stsp_ar(m, p, sigma_L = c("chol", "symm", "identity", "full_normalized"))
tmpl_stsp_echelon(
nu,
n = length(nu),
sigma_L = c("chol", "symm", "identity", "full_normalized")
)
Arguments
- model
- sigma_L
(character string) determines the form of the (left) square root of the noise covariance \(\Sigma\). The choice
"chol"
gives a lower triangular matrix,"symm"
gives a symmetric matrix and"identity"
corresponds to a fixed (identity) matrix. The proceduremodel2template
has an additional option"as_given"
which means that the structure of the square rootsigma_L
is completely determined by thesigma_L
slot of the given model.- m
output dimension
- n
input dimension (= number of shocks = dimension of the noise process)
- p
order of the AR polynomial for ARMA models, respectively the order of the right factor polynomial \(c(z)\) in an RMFD model.
- q
order of the MA polynomial for ARMA models, respectively the order of the left factor polynomial \(d(z)\) in an RMFD model.
- nu
vector of Kronecker indices. For ARMA models the Kronecker indices describe the basis rows and for RMFD models the basis columns of the Hankel matrix of the impulse response coefficients.
- s
state dimension for state space models.
Details
The functions model2template
and tmpl_***
generate model "templates" which
represent certain model structures, where the model parameters are affine functions of some
free, respectively deep, parameters.
The template contains information about the model structure in the following slots
h, H
represent the vector \(h\) and the marix \(H\) as described above. (The vector \(\pi\) of stacked model parameters is represented as \(\pi = h +H \theta\) where \(\theta\) is a vector of deep parameters.)class=["armamod"|"rmfdmod"|"stspmod"]
: determines whether the template parametrizes ARMA, RMFD or state space models.order
: an integer vector which contains the dimensions and orders of the model. For ARMA and RMFD modelsorder = c(m,n,p,q)
and for state space modelsorder = c(m,n,s)
.n.par
: the number of free parameters, i.e. the dimension of the vector \(\theta\).nu
: This optional slot contains the Kronecker indices \(\nu\).
model2template:
The function model2template()
takes an armamod()
, rmfdmod()
, or stspmod()
object
where the free parameters are coded as NA
's, NaN
's or Inf
's and
constructs a corresponding model template.
For the parametrization of the (left) square root, \(L\) say, of the noise covariance \(\Sigma = LL'\)
the following choices are possible: In the case sigma_L = "as_given"
the
slot model$sigma_L
of the given model
is used to construct the template: NA
entries
are considered as free and all other entries as fixed. For the choice sigma_L = "chol"
first all entries of model$sigma_L
above the diagonal are set to zero and then
the template is constructed as above. In the case sigma_L = "symm"
the matrix model$sigma_L
is first replaced by a symmetric one and then the template
is constructed (according to the NA
's) such that the square root L=sigma_L
is always
symmetric. The choice sigma_L = "identity"
sets the matrix L = sigma_L
to the
identity matrix.
Finally, the choice sigma_L = "full_normalized"
sets the diagonal elements equal to ones and all other elements to NAs in L = sigma_L
.
tmpl_:*
The functions tmpl_***
implement the following model structures:
- tmpl_arma_pq
ARMA models (
armamod()
) with prescribed orders \((p,q\)).- tmpl_arma_echelon
ARMA models (
armamod()
) in echelon form, with given Kronecker indices \(\nu\).- tmpl_rmfd_pq
RMFD models (
rmfdmod()
) with prescribed orders \((p,q\)).- tmpl_rmfd_echelon
RMFD models (
rmfdmod()
) in echelon form, with Kronecker indices \(\nu\). Note that for RMFD models the Kronecker indices refer to the basis of the column space of the Hankel matrix of the impulse response coefficients.- tmpl_stsp_full
Fully parametrized state space models (
stspmod()
) with given state space dimension \(s\), i.e. a models where each entry in the matrices \(A,B,C\) is considered non-fixed.- tmpl_stsp_echelon
State space models (
stspmod()
) in echelon form, with given Kronecker indices \(\nu\).- tmpl_state space_ar
State space model representations (
stspmod()
) of AR models with given order \(p\). Here only the "square" case \(m=n\) is implemented.
For these model structures the impulse response (transfer function) is scaled such that the \((m,n)\)-dimensional lag zero coefficient, \(k_0\) say, is of the form
- \(m=n\)
\(k_0\) is the \(m\)-dimensional identity matrix.
- \(m<n\)
The first \(m\) columns of \(k_0\) form the \(m\)-dimensional identity matrix and the remaining columns are zero.
- \(m>n\)
The first \(n\) rows of \(k_0\) form the \(n\)-dimensional identity matrix and the remaining rows are free.
For the parametrization of the (left) square root \(L\) of the noise covariance \(\Sigma = LL'\)
the following choices are possible: For sigma_L="chol"
the matrix \(L\) is lower triangular
(all entries on and below the main diagonal are considered as free and the entries above the diagonal are zero).
For sigma_L="symm"
the matrix \(L\) is symmetric (all entries on and below the main diagonal are considered
as free and the entries above the diagonal are such that \(L=L'\) holds).
For sigma_L="identity"
the matrix \(L\) is fixed to the \(n\)-dimensional identity matrix.
For sigma_L="full_normalized"
the diagonal elements of the matrix \(L\) are fixed to ones and all other elements are free.
See also
r_model()
, fill_template()
, ll()
, ll_theta()
and other estimation procedures
Examples
# ######################################################
# construct a template from a model
# ######################################################
# Let us consider scalar ARMA(5,1) models
# for quarterly data with a strong seasonal component.
# In order to have parsimonious models we want a[2]=a[3]=0:
model = armamod(lmfd(a = c(1,NA,0,0,NA,NA), b = c(1,NA)))
tmpl = model2template(model)
# Let's see how the "free" parameters are mapped to the model parameters
print(cbind(tmpl$h, tmpl$H))
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] 1 0 0 0 0
#> [2,] 0 1 0 0 0
#> [3,] 0 0 0 0 0
#> [4,] 0 0 0 0 0
#> [5,] 0 0 1 0 0
#> [6,] 0 0 0 1 0
#> [7,] 1 0 0 0 0
#> [8,] 0 0 0 0 1
#> [9,] 1 0 0 0 0
th = -(1:tmpl$n.par)
fill_template(th, tmpl)
#> ARMA model [1,1] with orders p = 5 and q = 1
#> AR polynomial a(z):
#> z^0 [,1] z^1 [,1] z^2 [,1] z^3 [,1] z^4 [,1] z^5 [,1]
#> [1,] 1 -1 0 0 -2 -3
#> MA polynomial b(z):
#> z^0 [,1] z^1 [,1]
#> [1,] 1 -4
#> Left square root of noise covariance Sigma:
#> u[1]
#> u[1] 1
# Generate a random model with this structure
th0 = rnorm(tmpl$n.par, sd = 0.1)
model = fill_template(th0, tmpl)
# Extract the "free" parameters from the model
th = extract_theta(model, tmpl)
all.equal(th, th0)
#> [1] TRUE
# This model structure fixes sigma_L = 1.
# If we change sigma_L = 2 then the model does not fit to the template.
model$sigma_L = 2
# the default choice on_error = 'ignore', tells
# extract_theta to ignore this misfit:
th = extract_theta(model, tmpl, on_error = 'ignore')
# with on_error = 'warn' we get a warning and
# with on_error = 'stop' would throw an error.
th = extract_theta(model, tmpl, on_error = 'warn')
#> Warning: model does not match template. max(abs(res)) = 1
# We may also "ignore" sigma_L
th = extract_theta(model, tmpl, on_error = 'stop', ignore_sigma_L=TRUE)
# If the orders/class of template and model does not fit
if (FALSE) {
model = armamod(lmfd(a = c(1,1), b = c(1,1)))
extract_theta(model, tmpl)
model = stspmod(stsp(D = 1))
extract_theta(model, tmpl)
}
# ######################################################
# the parameter "sigma_L"
# ######################################################
# consider a state space model (with 1 state) for a 3-dimensional process
model = stspmod(stsp(A = 1, B = c(1,0,0), C = c(1,1,1), D = diag(3)))
# We may specify an arbitrary structure for the left square root (L = sigma_L)
# of the noise covariance Sigma. Any NA entry is considered as a "free" parameter.
L = matrix(c(0, NA, 1, 0, 2, 3, NA, 1, 1), nrow = 3, ncol = 3)
L
#> [,1] [,2] [,3]
#> [1,] 0 0 NA
#> [2,] NA 2 1
#> [3,] 1 3 1
# L has 2 NA entries and thus we get a model structure with 2 free parameters.
model$sigma_L = L
tmpl = model2template(model, sigma_L = 'as_given')
th = -(1:tmpl$n.par)
fill_template(th, tmpl)
#> state space model [3,3] with s = 1 states
#> s[1] u[1] u[2] u[3]
#> s[1] 1 1 0 0
#> x[1] 1 1 0 0
#> x[2] 1 0 1 0
#> x[3] 1 0 0 1
#> Left square root of noise covariance Sigma:
#> u[1] u[2] u[3]
#> u[1] 0 0 -2
#> u[2] -1 2 1
#> u[3] 1 3 1
# The choice sigma_L = 'chol' forces L to be lower triangular.
# In the case considered here, we get a model structure with 1 free parameter.
tmpl = model2template(model, sigma_L = 'chol')
th = -(1:tmpl$n.par)
fill_template(th, tmpl)
#> state space model [3,3] with s = 1 states
#> s[1] u[1] u[2] u[3]
#> s[1] 1 1 0 0
#> x[1] 1 1 0 0
#> x[2] 1 0 1 0
#> x[3] 1 0 0 1
#> Left square root of noise covariance Sigma:
#> u[1] u[2] u[3]
#> u[1] 0 0 0
#> u[2] -1 2 0
#> u[3] 1 3 1
# The choice sigma_L = 'symm' forces L = sigma_L to be symmetric.
# In the case considered here we thus get a model structure with 2 free parameters.
tmpl = model2template(model, sigma_L = 'symm')
th = -(1:tmpl$n.par)
fill_template(th, tmpl)
#> state space model [3,3] with s = 1 states
#> s[1] u[1] u[2] u[3]
#> s[1] 1 1 0 0
#> x[1] 1 1 0 0
#> x[2] 1 0 1 0
#> x[3] 1 0 0 1
#> Left square root of noise covariance Sigma:
#> u[1] u[2] u[3]
#> u[1] 0 -1 -2
#> u[2] -1 2 2
#> u[3] -2 2 1
# The choice sigma_L = 'identity' set L equal to the identity matrix,
# i.e. sigma_L is fixed.
tmpl = model2template(model, sigma_L = 'identity')
th = numeric(0)
fill_template(th, tmpl)
#> state space model [3,3] with s = 1 states
#> s[1] u[1] u[2] u[3]
#> s[1] 1 1 0 0
#> x[1] 1 1 0 0
#> x[2] 1 0 1 0
#> x[3] 1 0 0 1
#> Left square root of noise covariance Sigma:
#> u[1] u[2] u[3]
#> u[1] 1 0 0
#> u[2] 0 1 0
#> u[3] 0 0 1
tmpl$n.par # there are no free parameters: tmpl$n.par = 0
#> [1] 0
# The choice sigma_L = 'full_normalized' sets the diagonal elements of L equal to ones,
# and leaves all other elements free.
tmpl = model2template(model, sigma_L = 'full_normalized')
th = -(1:tmpl$n.par)
fill_template(th, tmpl)
#> state space model [3,3] with s = 1 states
#> s[1] u[1] u[2] u[3]
#> s[1] 1 1 0 0
#> x[1] 1 1 0 0
#> x[2] 1 0 1 0
#> x[3] 1 0 0 1
#> Left square root of noise covariance Sigma:
#> u[1] u[2] u[3]
#> u[1] 1 -3 -5
#> u[2] -1 1 -6
#> u[3] -2 -4 1
# ######################################################
# ARMA(p,q) models
# ######################################################
m = 2 # output dimension
p = 1 # AR order
q = 1 # MA order
# model structure with lower triangular sigma_L
tmpl = tmpl_arma_pq(m, n = m, p, q, sigma_L = "chol")
th = rnorm(tmpl$n.par)
th = -(1:tmpl$n.par)
fill_template(th, tmpl)
#> ARMA model [2,2] with orders p = 1 and q = 1
#> AR polynomial a(z):
#> z^0 [,1] [,2] z^1 [,1] [,2]
#> [1,] 1 0 -1 -3
#> [2,] 0 1 -2 -4
#> MA polynomial b(z):
#> z^0 [,1] [,2] z^1 [,1] [,2]
#> [1,] 1 0 -5 -7
#> [2,] 0 1 -6 -8
#> Left square root of noise covariance Sigma:
#> u[1] u[2]
#> u[1] -9 0
#> u[2] -10 -11
# model structure with symmetric sigma_L
tmpl = tmpl_arma_pq(m, n = m, p, q, sigma_L = "symm")
fill_template(th, tmpl)
#> ARMA model [2,2] with orders p = 1 and q = 1
#> AR polynomial a(z):
#> z^0 [,1] [,2] z^1 [,1] [,2]
#> [1,] 1 0 -1 -3
#> [2,] 0 1 -2 -4
#> MA polynomial b(z):
#> z^0 [,1] [,2] z^1 [,1] [,2]
#> [1,] 1 0 -5 -7
#> [2,] 0 1 -6 -8
#> Left square root of noise covariance Sigma:
#> u[1] u[2]
#> u[1] -9 -10
#> u[2] -10 -11
# model structure with sigma_L = I
tmpl = tmpl_arma_pq(m, n = m, p, q, sigma_L = "identity")
# here the number of free paramaters is of course (by 3) smaller
# than for the above model structures!
fill_template(th[1:(length(th)-3)], tmpl)
#> ARMA model [2,2] with orders p = 1 and q = 1
#> AR polynomial a(z):
#> z^0 [,1] [,2] z^1 [,1] [,2]
#> [1,] 1 0 -1 -3
#> [2,] 0 1 -2 -4
#> MA polynomial b(z):
#> z^0 [,1] [,2] z^1 [,1] [,2]
#> [1,] 1 0 -5 -7
#> [2,] 0 1 -6 -8
#> Left square root of noise covariance Sigma:
#> u[1] u[2]
#> u[1] 1 0
#> u[2] 0 1
# ######################################################
# RMFD(p,q) models y[t] = d(z) c(z)^-1 e[t]
# ######################################################
m = 2 # output dimension
p = 1 # order of c(z)
q = 1 # order of d(z)
# model structure with lower triangular sigma_L
tmpl = tmpl_rmfd_pq(m, n = m, p, q, sigma_L = "chol")
th = rnorm(tmpl$n.par)
th = -(1:tmpl$n.par)
fill_template(th, tmpl)
#> RMFD model [2,2] with orders p = 1 and q = 1
#> right factor polynomial c(z):
#> z^0 [,1] [,2] z^1 [,1] [,2]
#> [1,] 1 0 -1 -5
#> [2,] 0 1 -2 -6
#> left factor polynomial d(z):
#> z^0 [,1] [,2] z^1 [,1] [,2]
#> [1,] 1 0 -3 -7
#> [2,] 0 1 -4 -8
#> Left square root of noise covariance Sigma:
#> u[1] u[2]
#> u[1] -9 0
#> u[2] -10 -11
# model structure with symmetric sigma_L
tmpl = tmpl_rmfd_pq(m, n = m, p, q, sigma_L = "symm")
fill_template(th, tmpl)
#> RMFD model [2,2] with orders p = 1 and q = 1
#> right factor polynomial c(z):
#> z^0 [,1] [,2] z^1 [,1] [,2]
#> [1,] 1 0 -1 -5
#> [2,] 0 1 -2 -6
#> left factor polynomial d(z):
#> z^0 [,1] [,2] z^1 [,1] [,2]
#> [1,] 1 0 -3 -7
#> [2,] 0 1 -4 -8
#> Left square root of noise covariance Sigma:
#> u[1] u[2]
#> u[1] -9 -10
#> u[2] -10 -11
# model structure with sigma_L = I
tmpl = tmpl_rmfd_pq(m, n = m, p, q, sigma_L = "identity")
# here the number of free paramaters is of course (by 3) smaller
# than for the above model structures!
fill_template(th[1:(length(th)-3)], tmpl)
#> RMFD model [2,2] with orders p = 1 and q = 1
#> right factor polynomial c(z):
#> z^0 [,1] [,2] z^1 [,1] [,2]
#> [1,] 1 0 -1 -5
#> [2,] 0 1 -2 -6
#> left factor polynomial d(z):
#> z^0 [,1] [,2] z^1 [,1] [,2]
#> [1,] 1 0 -3 -7
#> [2,] 0 1 -4 -8
#> Left square root of noise covariance Sigma:
#> u[1] u[2]
#> u[1] 1 0
#> u[2] 0 1
# ######################################################
# state space models in echelon form
# ######################################################
nu = c(3,2,4) # Kronecker indices
m = length(nu) # number of outputs/inputs
tmpl = tmpl_stsp_echelon(nu = nu)
# generate a random vector of parameters.
# Note that "tmpl$n.par" contains the number free parameters.
th = rnorm(tmpl$n.par)
# generate a model according to this structure with the parameters th
model = fill_template(th, tmpl)
print(model)
#> state space model [3,3] with s = 9 states
#> s[1] s[2] s[3] s[4] s[5] s[6] s[7]
#> s[1] 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000
#> s[2] 0.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000
#> s[3] 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000
#> s[4] 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 1.0000000
#> s[5] 0.2519982 0.4220592 -0.1881357 0.2609883 -0.2607866 1.4539629 0.8169292
#> s[6] 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000
#> s[7] -0.6310808 -0.8168256 0.6378934 -0.8083954 -1.2758842 0.4452803 2.3498250
#> s[8] 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000
#> s[9] -0.1254608 1.0654308 -0.9414362 1.3279969 -0.6934213 1.3784487 1.3532302
#> x[1] 1.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000
#> x[2] 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000
#> x[3] 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 0.0000000
#> s[8] s[9] u[1] u[2] u[3]
#> s[1] 0.0000000 0.000000 0.89482725 -0.2505194 0.3626429
#> s[2] 0.0000000 0.000000 -0.66277106 0.5191435 -1.6379086
#> s[3] 0.0000000 0.000000 -0.04653891 0.5605856 -1.9044280
#> s[4] 0.0000000 0.000000 0.50392793 -1.0478871 0.6271379
#> s[5] 0.0000000 0.000000 0.54400109 0.1904240 -0.3163896
#> s[6] 1.0000000 0.000000 -0.63383495 -1.9099229 1.3870629
#> s[7] -1.6470537 0.000000 -0.63844553 1.2686734 0.6587962
#> s[8] 0.0000000 1.000000 0.94879046 -0.5287059 -1.0988064
#> s[9] -0.6173196 1.524712 -0.14137696 1.0182452 -0.3185121
#> x[1] 0.0000000 0.000000 1.00000000 0.0000000 0.0000000
#> x[2] 0.0000000 0.000000 0.00000000 1.0000000 0.0000000
#> x[3] 0.0000000 0.000000 0.00000000 0.0000000 1.0000000
#> Left square root of noise covariance Sigma:
#> u[1] u[2] u[3]
#> u[1] -0.9264656 0.0000000 0.0000000
#> u[2] -0.6843278 0.7157282 0.0000000
#> u[3] -0.1501794 -0.2785365 0.4083184
# we can extract the free parameters from this given model
all.equal(th, extract_theta(model, tmpl, on_error = 'stop'))
#> [1] TRUE
# check the impulse response
k = impresp(model, lag.max = 2*sum(nu) + 1)
# the lag zero coeffcient k[0] is equal to the identity
all.equal(unclass(k$irf)[,,1], diag(m))
#> [1] TRUE
# check the Kronecker indices
all.equal(rationalmatrices::pseries2nu(k$irf), nu)
#> [1] TRUE