Skip to content

Commit 2f71d58

Browse files
committed
see NEWS
1 parent 1246b75 commit 2f71d58

File tree

14 files changed

+367
-72
lines changed

14 files changed

+367
-72
lines changed

DESCRIPTION

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
Package: tsissm
22
Type: Package
33
Title: Linear Innovations State Space Unobserved Components Model
4-
Version: 1.0.1
4+
Version: 1.0.2
55
Authors@R: c(person("Alexios", "Galanos", role = c("aut", "cre"), comment = c(ORCID = "0009-0000-9308-0457"), email = "alexios@4dscape.com"))
66
Maintainer: Alexios Galanos <alexios@4dscape.com>
77
Description: Unobserved components time series model using the linear innovations state space representation (single source of error) with choice of error distributions and option for dynamic variance. Methods for estimation using automatic differentiation, automatic model selection and ensembling, prediction, filtering, simulation and backtesting. Based on the model described in Hyndman et al (2012) <doi:10.1198/jasa.2011.tm09771>.
88
Depends: R (>= 4.1.0), Rcpp (>= 0.12.9), tsmethods (>= 1.0.0)
99
LinkingTo: Rcpp (>= 0.12.9), TMB, RcppEigen
10-
Imports: TMB (>= 1.7.20), methods, tsaux, tsdistributions, zoo, xts, copula, flextable, data.table, sandwich, nloptr, RTMB, viridisLite, future, future.apply, progressr
10+
Imports: TMB (>= 1.7.20), methods, tsaux, tsdistributions, zoo, xts, copula, flextable, data.table, sandwich, nloptr, Rsolnp, RTMB, viridisLite, future, future.apply, progressr
1111
Suggests:
1212
rmarkdown,
1313
tstests,

NAMESPACE

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export(as_flextable)
4949
export(bread)
5050
export(estfun)
5151
export(hresiduals)
52+
export(issm_control)
5253
export(issm_modelspec)
5354
import(data.table)
5455
import(methods)
@@ -62,6 +63,7 @@ importFrom(RTMB,eigen)
6263
importFrom(RTMB,matrix)
6364
importFrom(Rcpp,evalCpp)
6465
importFrom(Rcpp,loadModule)
66+
importFrom(Rsolnp,csolnp)
6567
importFrom(TMB,MakeADFun)
6668
importFrom(copula,P2p)
6769
importFrom(copula,normalCopula)

NEWS.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
# tsissm 1.0.2
2+
3+
* The SLSQP solver (from nloptr) sometimes will return NaN for the parameters. Added a stop
4+
clause else it may crash the process (due to RTMB eigen crashing).
5+
* Added option for solnp solver (csolnp from Rsolnp)
6+
* Added a solver control function (issm_control)
7+
18
# tsissm 1.0.1
29

310
* Initial CRAN submission based on complete re-write of model on github which was

R/backtest.R

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#' @param seed an value specifying if and how the random number generator should
2121
#' be initialized (\sQuote{seeded}). Either NULL or an integer that will be used in a
2222
#' call to set.seed before simulating the response vectors.
23+
#' @param solver either \dQuote{nlortr} or \dQuote{solnp}.
2324
#' @param trace whether to show the progress bar. The user is expected to have
2425
#' set up appropriate handlers for this using the \dQuote{progressr} package.
2526
#' @param ... not used.
@@ -56,7 +57,7 @@
5657
#'
5758
tsbacktest.tsissm.autospec <- function(object, start = floor(length(object$y)/2), end = length(object$y),
5859
h = 1, estimate_every = 1, rolling = FALSE, weights_scheme = c("AIC","BIC","U"), weights = NULL,
59-
seed = NULL, trace = FALSE, ...)
60+
seed = NULL, solver = "nloptr", trace = FALSE, ...)
6061
{
6162
if (object$top_n > 1) {
6263
top_n <- object$top_n
@@ -67,9 +68,10 @@ tsbacktest.tsissm.autospec <- function(object, start = floor(length(object$y)/2)
6768
weights_scheme <- "U"
6869
}
6970
out <- .backtest_ensemble(object, start = start, end = end, h = h, estimate_every = estimate_every, rolling = rolling, weights_scheme = weights_scheme,
70-
weights = weights, seed = seed, trace = trace)
71+
weights = weights, seed = seed, solver = solver, trace = trace)
7172
} else {
72-
out <- .backtest_top(object, start = start, end = end, h = h, estimate_every = estimate_every, rolling = rolling, seed = seed, trace = trace)
73+
out <- .backtest_top(object, start = start, end = end, h = h, estimate_every = estimate_every, rolling = rolling, seed = seed, solver = solver,
74+
trace = trace)
7375
}
7476
return(out)
7577
}
@@ -78,7 +80,7 @@ tsbacktest.tsissm.autospec <- function(object, start = floor(length(object$y)/2)
7880
#' @rdname tsbacktest
7981
#' @export
8082
tsbacktest.tsissm.spec <- function(object, start = floor(length(object$target$y_orig)/2), end = length(object$target$y_orig),
81-
h = 1, estimate_every = 1, rolling = FALSE, seed = NULL, trace = FALSE, ...)
83+
h = 1, estimate_every = 1, rolling = FALSE, seed = NULL, solver = "nloptr", trace = FALSE, ...)
8284
{
8385
parameter <- b <- forecast_dates <- NULL
8486
data <- xts(object$target$y_orig, object$target$index)
@@ -150,7 +152,7 @@ tsbacktest.tsissm.spec <- function(object, start = floor(length(object$target$y_
150152
sampling = object$target$sampling, sample_n = object$variance$sample_n,
151153
init_garch = object$variance$init_variance, garch_order = object$variance$order,
152154
variance = object$variance$type, distribution = object$distribution$type)
153-
mod <- try(estimate(spec, scores = FALSE), silent = TRUE)
155+
mod <- try(estimate(spec, solver = solver, scores = FALSE), silent = TRUE)
154156
model_coef <- coef(mod)
155157
log_lik <- as.numeric(logLik(mod))
156158
aic <- as.numeric(AIC(mod))
@@ -240,7 +242,8 @@ tsbacktest.tsissm.spec <- function(object, start = floor(length(object$target$y_
240242
}
241243

242244
.backtest_top <- function(object, start = floor(length(object$y)/2), end = length(object$y), h = 1,
243-
estimate_every = 1, rolling = FALSE, seed = NULL, trace = FALSE, ...)
245+
estimate_every = 1, rolling = FALSE, seed = NULL, solver = "nloptr",
246+
trace = FALSE, ...)
244247
{
245248
parameter <- b <- forecast_dates <- NULL
246249
data <- object$y
@@ -302,7 +305,7 @@ tsbacktest.tsissm.spec <- function(object, start = floor(length(object$target$y_
302305
sampling = object$sampling, sample_n = object$sample_n,
303306
init_garch = object$init_garch, garch_order = object$garch_order,
304307
variance = object$variance, distribution = object$distribution, top_n = 1)
305-
mod <- try(estimate(spec, trace = FALSE), silent = TRUE)
308+
mod <- try(estimate(spec, solver = solver, trace = FALSE), silent = TRUE)
306309
model_coef <- coef(mod)
307310
log_lik <- as.numeric(logLik(mod))
308311
aic <- as.numeric(AIC(mod))
@@ -391,7 +394,7 @@ tsbacktest.tsissm.spec <- function(object, start = floor(length(object$target$y_
391394

392395
.backtest_ensemble <- function(object, start = floor(length(object$y)/2), end = length(object$y),
393396
h = 1, estimate_every = 1, rolling = FALSE, weights_scheme = c("U","AIC","BIC"), weights = NULL,
394-
seed = NULL, trace = FALSE, ...)
397+
seed = NULL, solver = "nloptr", trace = FALSE, ...)
395398
{
396399
if (weights_scheme == "U") {
397400
wfun <- function(x) {
@@ -467,7 +470,7 @@ tsbacktest.tsissm.spec <- function(object, start = floor(length(object$target$y_
467470
sampling = object$sampling, sample_n = object$sample_n,
468471
init_garch = object$init_garch, garch_order = object$garch_order,
469472
variance = object$variance, distribution = object$distribution, top_n = top_n)
470-
mod <- try(estimate(spec, trace = FALSE), silent = TRUE)
473+
mod <- try(estimate(spec, solver = solver, trace = FALSE), silent = TRUE)
471474
w <- wfun(mod)
472475
L <- index_table[[i]]
473476
M <- split(L, by = "filter_date")

R/constraint.R

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ make_constraint <- function(spec, fun, issmenv) {
287287
constraint_fun <- NULL
288288
} else {
289289
constraint_fun <- function(pars, fun, issmenv) {
290+
if (any(is.nan(pars))) stop("\nsolver returned NaN values. Try a different algorithm.")
290291
con <- unlist(sapply(C, do.call, list(pars, fun, issmenv)))
291292
jac <- do.call(rbind, lapply(J, function(x) x(pars, fun, issmenv)))
292293
return(list("constraints" = con, "jacobian" = jac))
@@ -295,6 +296,151 @@ make_constraint <- function(spec, fun, issmenv) {
295296
return(constraint_fun)
296297
}
297298

299+
300+
make_constraint_solnp <- function(spec, fun, issmenv) {
301+
# case 1 only level
302+
# case 2 only level and GARCH
303+
# case 3 only level and arma
304+
# case 4 only level and arma and GARCH
305+
# case 5 level +
306+
# case 6 level + and GARCH
307+
# case 7 level + and arma
308+
# case 8 level + and arma and GARCH
309+
case_id <- model_case(spec)
310+
use_case <- c(0, 0, 0)
311+
not_null <- 0
312+
if (case_id[2] == 0) {
313+
issm_c <- function(pars, fun, issmenv) {
314+
NULL
315+
}
316+
issm_j <- function(pars, fun, issmenv) {
317+
NULL
318+
}
319+
} else {
320+
not_null <- not_null + 1
321+
issm_c <- function(pars, fun, issmenv) {
322+
issmenv$constraint$fn(pars)
323+
}
324+
issm_j <- function(pars, fun, issmenv) {
325+
if (all(abs(issmenv$constraint$report(pars)$tmp - 1) <= 1e-12)) {
326+
J <- matrix(1, ncol = length(pars), nrow = 1)
327+
} else {
328+
J <- issmenv$constraint$gr(pars)
329+
}
330+
return(J)
331+
}
332+
use_case[1] <- 1
333+
}
334+
if (case_id[3] > 0) {
335+
arma_order <- spec$arma$order
336+
if (arma_order[1] > 1 & arma_order[2] > 1) {
337+
not_null <- not_null + 1
338+
arma_c <- function(pars, fun, issmenv) {
339+
c(issmenv$arcons$fn(pars),issmenv$macons$fn(pars))
340+
}
341+
arma_j <- function(pars, fun, issmenv) {
342+
rbind(issmenv$arcons$gr(pars), issmenv$macons$gr(pars))
343+
}
344+
} else if (arma_order[1] > 1 & arma_order[2] <= 1) {
345+
not_null <- not_null + 1
346+
arma_c <- function(pars, fun, issmenv) {
347+
issmenv$arcons$fn(pars)
348+
}
349+
arma_j <- function(pars, fun, issmenv) {
350+
issmenv$arcons$gr(pars)
351+
}
352+
} else if (arma_order[1] <= 1 & arma_order[2] > 1) {
353+
not_null <- not_null + 1
354+
arma_c <- function(pars, fun, issmenv) {
355+
issmenv$macons$fn(pars)
356+
}
357+
arma_j <- function(pars, fun, issmenv) {
358+
issmenv$macons$gr(pars)
359+
}
360+
} else {
361+
arma_c <- function(pars, fun, issmenv) {
362+
NULL
363+
}
364+
arma_j <- function(pars, fun, issmenv) {
365+
NULL
366+
}
367+
}
368+
use_case[2] <- 1
369+
} else {
370+
arma_c <- function(pars, fun, issmenv) {
371+
NULL
372+
}
373+
arma_j <- function(pars, fun, issmenv) {
374+
NULL
375+
}
376+
}
377+
if (case_id[4] > 0) {
378+
not_null <- not_null + 1
379+
garch_c <- function(pars, fun, issmenv) {
380+
garch_constraint(pars, fun, issmenv)
381+
}
382+
garch_j <- function(pars, fun, issmenv){
383+
garch_jacobian(pars, fun, issmenv)
384+
}
385+
use_case[3] <- 1
386+
} else {
387+
garch_c <- function(pars, fun, issmenv) {
388+
NULL
389+
}
390+
garch_j <- function(pars, fun, issmenv){
391+
NULL
392+
}
393+
}
394+
395+
C <- list()
396+
J <- list()
397+
k <- 0
398+
if (use_case[1] == 1) {
399+
k <- k + 1
400+
C[[k]] <- issm_c
401+
J[[k]] <- issm_j
402+
}
403+
if (use_case[2] == 1) {
404+
k <- k + 1
405+
C[[k]] <- arma_c
406+
J[[k]] <- arma_j
407+
}
408+
if (use_case[3] == 1) {
409+
k <- k + 1
410+
C[[k]] <- garch_c
411+
J[[k]] <- garch_j
412+
}
413+
414+
if (sum(use_case) == 0) {
415+
constraint_fun <- NULL
416+
constraint_jac <- NULL
417+
ineq_lower <- NULL
418+
ineq_upper <- NULL
419+
} else {
420+
if (not_null > 0) {
421+
n_c <- length(unlist(sapply(C, do.call, list(fun$par, fun, issmenv))))
422+
constraint_fun <- function(pars, fun, issmenv) {
423+
if (any(is.nan(pars))) stop("\nsolver returned NaN values. Try a different algorithm.")
424+
con <- unlist(sapply(C, do.call, list(pars, fun, issmenv)))
425+
return(con)
426+
}
427+
constraint_jac <- function(pars, fun, issmenv) {
428+
if (any(is.nan(pars))) stop("\nsolver returned NaN values. Try a different algorithm.")
429+
jac <- do.call(rbind, lapply(J, function(x) x(pars, fun, issmenv)))
430+
return(jac)
431+
}
432+
ineq_lower <- rep(-1e8, n_c)
433+
ineq_upper <- rep(0, n_c)
434+
} else {
435+
constraint_fun <- NULL
436+
constraint_jac <- NULL
437+
ineq_lower <- NULL
438+
ineq_upper <- NULL
439+
}
440+
}
441+
return(list(ineq_fn = constraint_fun, ineq_jac = constraint_jac, ineq_lower = ineq_lower, ineq_upper = ineq_upper))
442+
}
443+
298444
companion_matrix <- function(params) {
299445
n <- length(params)
300446
if (params[n] == 0) stop("The last parameter must not be zero to form a monic polynomial.")

0 commit comments

Comments
 (0)