tests/testthat/test-difeq-delay.R

context("discrete, with delays")

test_that("fib", {
  ## Here's a fun simple example; the Fibonacci sequence:
  ##
  ## TODO: Because I can't get the 0 into the history buffer to start
  ## with, this is not quite correct, so it's really fib(2) and up.
  fib <- function(i, y, p) {
    y + yprev(i - 1L)
  }
  y0 <- 1
  i <- 0:10
  res <- difeq(y0, i, fib, NULL, n_history = 2, return_step = FALSE)
  expect_equal(res[1:11], c(1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144))

  h <- attr(res, "history")
  expect_equal(attr(h, "n"), 1L)
  expect_equal(dim(h), c(2, 2))

  res2 <- difeq(y0, i, fib, NULL, return_step = FALSE, n_history = 20)
  h2 <- attr(res2, "history")
  expect_equal(dim(h2), c(2, 11))
  expect_equal(h2[, 10:11], h, check.attributes = FALSE)
})

test_that("prev and output", {
  growth <- function(i, y, p) {
    ret <- y + p
    attr(ret, "output") <- yprev(i - 1L)
    ret
  }

  n <- 5
  y0 <- runif(n)
  p <- runif(n)
  i <- 0:10
  i2 <- seq(0, 10, by = 2)

  cmp <- t(y0 + outer(p, i))
  cmp2 <- t(y0 + outer(p, i2))

  res <- difeq(y0, i, growth, p, return_step = FALSE, n_out = 5,
               n_history = 2L, return_output_with_y = FALSE)
  expect_equal(res, cmp, check.attributes = FALSE)
  output <- attr(res, "output")
  expect_equal(output, rbind(y0, cmp[-nrow(cmp), ], deparse.level = 0))

  res2 <- difeq(y0, i2, growth, p, return_step = FALSE, n_out = 5,
                n_history = 2L, return_output_with_y = FALSE)
  expect_equal(res2, cmp2, check.attributes = FALSE)
  output2 <- attr(res2, "output")
  expect_equal(output2, output[i2 + 1, ])
})

test_that("yprev permutations", {
  rhs <- function(i, y, p) {
    iprev <- i - 1
    if (p == "one") {
      for (i in seq_along(y)) {
        y[i] <- y[i] + yprev(iprev, i)
      }
    } else if (p == "idx") {
      y <- y + yprev(iprev, seq_along(y))
    } else { # all
      y <- y + yprev(iprev)
    }
    y
  }

  i <- seq(0:10)
  y0 <- runif(5)
  res1 <- difeq(y0, i, rhs, "one", return_initial = TRUE, n_history = 2L)
  res2 <- difeq(y0, i, rhs, "idx", return_initial = TRUE, n_history = 2L)
  res3 <- difeq(y0, i, rhs, "all", return_initial = TRUE, n_history = 2L)

  cmp <- matrix(y0, length(i), length(y0), byrow = TRUE)
  for (j in 2:length(i)) {
    cmp[j, ] <- cmp[j - 1, ] + cmp[max(1, j - 2), ]
  }

  expect_equal(res1[, -1], cmp, check.attributes = FALSE)
  expect_equal(res2, res1)
  expect_equal(res3, res1)
})

test_that("yprev invalid input", {
  rhs <- function(i, y, p) {
    type <- p$type
    lag <- p$lag
    idx <- p$idx
    iprev <- if (is.numeric(lag)) i - lag else lag
    if (type == "one") {
      for (i in seq_along(idx)) {
        j <- idx[[i]]
        yp <- yprev(iprev, j)
        y[j] <- y[j] + yp
      }
    } else if (type == "idx") {
      yp <- yprev(iprev, idx)
      y[idx] <- y[idx] + yp
    } else { # all
      y <- y + yprev(iprev)
    }
    y
  }

  i <- seq(0:10)
  y0 <- runif(5)
  cmp <- matrix(y0, length(y0), length(i))
  for (j in 2:length(i)) {
    cmp[, j] <- cmp[, j - 1] + cmp[, max(1, j - 2)]
  }
  cmp <- t(cmp)

  p <- list(lag = 1.0, idx = as.numeric(seq_along(y0)), type = "one")
  res1 <- difeq(y0, i, rhs, p, n_history = 2L, return_initial = TRUE)
  expect_equal(res1[, -1], cmp, check.attributes = FALSE)

  p <- list(lag = 1.0, idx = as.numeric(seq_along(y0)), type = "idx")
  res1 <- difeq(y0, i, rhs, p, n_history = 2L, return_initial = TRUE)
  expect_equal(res1[, -1], cmp, check.attributes = FALSE)

  p <- list(lag = 1.0, idx = as.numeric(seq_along(y0) + 1), type = "one")
  expect_error(difeq(y0, i, rhs, p, n_history = 2L, return_initial = TRUE),
               "out of bounds")
  p <- list(lag = 1.0, idx = as.integer(seq_along(y0) + 1L), type = "one")
  expect_error(difeq(y0, i, rhs, p, n_history = 2L, return_initial = TRUE),
               "out of bounds")

  p <- list(lag = 1.0, idx = "one", type = "one")
  expect_error(difeq(y0, i, rhs, p, n_history = 2L, return_initial = TRUE),
               "Invalid type")
  p <- list(lag = 1.0, idx = c("one", "two"), type = "idx")
  expect_error(difeq(y0, i, rhs, p, n_history = 2L, return_initial = TRUE),
               "Invalid type")

  p <- list(lag = - 1.0, type = "one", idx = 1L)
  expect_error(difeq(y0, i, rhs, p, n_history = 2L, return_initial = TRUE),
               "did not find step")
  p <- list(lag = - 1.0, type = "idx", idx = 1L)
  expect_error(difeq(y0, i, rhs, p, n_history = 2L, return_initial = TRUE),
               "did not find step")
  p <- list(lag = - 1.0, type = "all")
  expect_error(difeq(y0, i, rhs, p, n_history = 2L, return_initial = TRUE),
               "did not find step")

  p <- list(lag = NULL, type = "all")
  expect_error(difeq(y0, i, rhs, p, n_history = 2L, return_initial = TRUE),
               "Expected a scalar")
  p <- list(lag = c(1L, 2L), type = "all")
  expect_error(difeq(y0, i, rhs, p, n_history = 2L, return_initial = TRUE),
               "Expected a scalar")
  p <- list(lag = "one", type = "all")
  expect_error(difeq(y0, i, rhs, p, n_history = 2L, return_initial = TRUE),
               "Expected an integer")
})

test_that("integer lag", {
  growth <- function(i, y, p) {
    y + yprev(i - 1L)
  }

  i <- seq(0:10)
  y0 <- runif(5)
  p <- numeric(0) # no parameters

  cmp <- matrix(y0, length(y0), length(i))
  for (j in 2:length(i)) {
    cmp[, j] <- cmp[, j - 1] + cmp[, max(1, j - 2)]
  }
  cmp <- t(cmp)

  res <- difeq(y0, i, growth, p, n_history = 2L,
               return_history = FALSE, return_step = FALSE)
  expect_equal(res, cmp)

  res <- difeq(y0, i, "growth", p, n_history = 2L, dllname = "dde_growth_int",
               return_history = FALSE, return_step = FALSE)
  expect_equal(res, cmp)
})

test_that("restart", {
  growth <- function(i, y, p) {
    ret <- y + p
    attr(ret, "output") <- yprev(i - 5L)
    ret
  }

  n <- 5L
  y0 <- runif(n)
  p <- runif(n)

  tt <- 0:50
  tc <- 20
  tt1 <- tt[tt <= tc]
  tt2 <- tt[tt >= tc]

  cmp <- y0 + outer(p, tt)

  res <- difeq(y0, tt, growth, p, n_out = n, n_history = 100L,
               restartable = FALSE)
  h <- attr(res, "history")
  expect_null(attr(res, "ptr"))
  expect_null(attr(res, "restart_data"))

  res1 <- difeq(y0, tt1, growth, p,  n_out = n, n_history = 100L,
                restartable = TRUE)

  ## We have useful things here:
  expect_is(attr(res1, "ptr"), "externalptr")
  expect_is(attr(res1, "restart_data"), "list")

  ## Do the restart
  res2 <- difeq_continue(res1, tt2, copy = FALSE)
  h2 <- attr(res2, "history")

  ## This is key; do all history elements match up:
  expect_equal(h2, h)

  expect_equal(res2[1, ], res1[nrow(res1), ])
  expect_equal(res, rbind(res1, res2[-1, ]), check.attributes = FALSE)
})

test_that("change y on restart", {
  growth <- function(i, y, p) {
    ret <- y + p
    attr(ret, "output") <- yprev(i - 5L)
    ret
  }

  n <- 5L
  y0 <- runif(n)
  p <- runif(n)

  tt <- 0:50
  tc <- 20
  it2 <- tt >= tc
  tt1 <- tt[tt <= tc]
  tt2 <- tt[it2]

  i <- seq_len(n) + 1L
  j <- i + n

  res <- difeq(y0, tt, growth, p, n_out = n, n_history = 100L,
               restartable = FALSE)
  h <- attr(res, "history")

  res1 <- difeq(y0, tt1, growth, p,  n_out = n, n_history = 100L,
                restartable = TRUE)
  y1 <- res1[nrow(res1), i] + 1
  res2 <- difeq_continue(res1, tt2, y1, copy = FALSE)
  h2 <- attr(res2, "history")

  expect_equal(res2[, 1], res[it2, 1])
  ## All offset by one:
  expect_equal(res2[, i], res[it2, i] + 1)

  ## Need to work out what I did here to get the output confirmed;
  ## it's lagged, but can't recall by what.
  expect_equal(res[-(1:5), j],
               res[seq_len(nrow(res) - 5), i])
  ## Cool, we're off by one, which probably means that we failed to
  ## get the correct number out, or it's set incorrectly in the
  ## history (most likely).
  ##
  ## TODO: this would be easiest to debug with plain output rather
  ## than lagged.  More testing will be added and I can pick that up
  ## later.
  ##
  ##   expect_equal(res2[-(1:5), j],
  ##                res2[seq_len(nrow(res2) - 5), i])
})
richfitz/dde documentation built on Jan. 19, 2024, 5:42 p.m.