inst/slowtests/test.mem.R

# test.mem.R: test earth C code memory usage under both normal and error conditions
#
# TODO With some versions of R, test.mem gives different results per run.
#      First seen Sep 2020, R 4.0.3.

source("test.prolog.R")
library(earth)

# the data we will build the models on
ncases <- 10
x <- matrix(1:ncases, ncol=1)
colnames(x) <- "x"
max <- max(x)
y <- sin(3 * x / max(x))
colnames(y) <- "y"

nmodels <- 5
nlm            <- double(length=nmodels) # mem used for each lm model
nstandardearth <- double(length=nmodels) # mem used for each earth model
ngoodallowed   <- double(length=nmodels)
nbadallowed    <- double(length=nmodels)
nbadendspan    <- double(length=nmodels)

max.mem.change <- function(mem.start, gc.start)
{
    mem <- memory.size() # MBytes (on non windows platforms, will always be Inf)
    gc <- gc(full=TRUE) # returns cells left after garbage collection
    # max(abs(mem - mem.start),
    #     abs(gc[1,1] - gc.start[1,1]),  # Ncells
    #     abs(gc[2,1] - gc.start[2,1]))  # Vcells
    mem <- abs(mem - mem.start)
    ncells <- abs(gc[1,1] - gc.start[1,1])
    vcells <- abs(gc[2,1] - gc.start[2,1])
    printf("mem %g ncells %g vcells %g\n", mem, ncells, vcells)
    max(mem, ncells, vcells)
}
plotmem <- function(nlm, nstandardearth, ngoodallowed, nbadallowed, nbadendspan)
{
    min <- min(nlm, nstandardearth, ngoodallowed, nbadallowed, nbadendspan)
    max <- max(nlm, nstandardearth, ngoodallowed, nbadallowed, nbadendspan)
    min <- min - 1
    max <- max + 3
    yjitter <- (max - min) / 130 # minimize overplotting

    # in the graphs, lines should be horizontal (at least after the first iter)
    # if a line increases after the first iter, it means that memory is not being released
    plot( 1:nmodels, nlm, type="l", main="memory used by each model",
                          xlab="nmodels", ylab="memory change", ylim=c(min, max))
    lines(1:nmodels, nstandardearth + 1 * yjitter, col=2)
    lines(1:nmodels, ngoodallowed   + 2 * yjitter, col=3)
    lines(1:nmodels, nbadallowed    + 3 * yjitter, col=1, lty=2)
    lines(1:nmodels, nbadendspan    + 4 * yjitter, col=2, lty=2)

    legend(x="topright", bg="white",
           legend=c("lm", "standardearth", "goodallowed", "badallowed", "badendspan"),
           lty=c(1,1,1,2,2),
           col=c(1,2,3,1,2))
}
good.allowedfunc  <- function(degree, pred, parents, namesx, first)
{
    pred != 999
}
bad.allowedfunc  <- function(degree, pred, parents, namesx, first)
{
    # this stop is silent because call earth using try(..., silent=TRUE)
    stop("early exit from bad.allowedfunc")
}
cat("initial redundant run of lm\n") # else initial nlm very large
                                     # (probably because some function is allocating a static buffer)
print(summary(lm(y~x)))
for(i in 0:nmodels) {
    try(lm(y~x), silent=FALSE)
    gc <- gc(full=TRUE)
    if(i <= 0) {
        mem.start <- memory.size()
        gc.start <- gc(full=TRUE)
    } else
        nlm[i] <- max.mem.change(mem.start, gc.start)
}
cat("actual run of lm\n")
# We use 0:nmodels, because we build the first model at iter 0,
# but don't save results from iter 0 (i.e. we the ignore first model).
# This is because the first model sometimes leaves some memory allocated (why?).
print(summary(lm(y~x)))
for(i in 0:nmodels) {
    try(lm(y~x), silent=FALSE)
    gc <- gc(full=TRUE)
    if(i <= 0) {
        mem.start <- memory.size()
        gc.start <- gc(full=TRUE)
    } else
        nlm[i] <- max.mem.change(mem.start, gc.start)
}
# standard earth model
cat("earth(y~x)\n")
print(summary(earth(y~x)))
for(i in 0:nmodels) {
    try(earth(y~x), silent=FALSE)
    gc <- gc(full=TRUE)
    if(i <= 0) {
        mem.start <- memory.size()
        gc.start <- gc(full=TRUE)
    } else
        nstandardearth[i] <- max.mem.change(mem.start, gc.start)
}
# earth model with an allowed func
cat("earth(y~x, allowed = good.allowedfunc)\n")
print(summary(earth(y~x, allowed = good.allowedfunc)))
for(i in 0:nmodels) {
    try(earth(y~x, allowed = good.allowedfunc), silent=FALSE)
    gc <- gc(full=TRUE)
    if(i <= 0) {
        mem.start <- memory.size()
        gc.start <- gc(full=TRUE)
    } else
        ngoodallowed[i] <- max.mem.change(mem.start, gc.start)
}
# try earth model with an allowed func which causes an error
cat("earth(y~x, allowed = bad.allowedfunc)\n")
expect.err(try(earth(y~x, allowed = bad.allowedfunc), silent=FALSE), "early exit from bad.allowedfunc")
for(i in 0:nmodels) {
    try(earth(y~x, allowed = bad.allowedfunc), silent=TRUE)
    gc <- gc(full=TRUE)
    if(i <= 0) {
        mem.start <- memory.size()
        gc.start <- gc(full=TRUE)
    } else
        nbadallowed[i] <- max.mem.change(mem.start, gc.start)
}

# try earth model with an arg that causes error in ForwardPass in earth.c
cat("earth(y~x, Adjust.endspan = -999\n")
expect.err(try(earth(y~x, Adjust.endspan = -999), silent=FALSE), "Adjust.endspan is -999 but should be between 0 and 10")
for(i in 0:nmodels) {
    try(earth(y~x, Adjust.endspan = -999), silent=TRUE)
    gc <- gc(full=TRUE)
    if(i <= 0) {
        mem.start <- memory.size()
        gc.start <- gc(full=TRUE)
    } else
        nbadendspan[i] <- max.mem.change(mem.start, gc.start)
}

cat("nlm           "); print(nlm)
cat("nstandardearth"); print(nstandardearth)
cat("ngoodallowed  "); print(ngoodallowed)
cat("nbadallowed   "); print(nbadallowed)
cat("nbadendspan   "); print(nbadendspan)

# printf("\n                             Min       1stQ     Median       Mean      3rdQ        Max\n")
# printf("lm                    %s\n", paste0(sprintf("% 10.3f", summary(nlm)), collapse=" "))
# printf("standardearth         %s\n", paste0(sprintf("% 10.3f", summary(nstandardearth)), collapse=" "))
# printf("goodallowed           %s\n", paste0(sprintf("% 10.3f", summary(ngoodallowed)), collapse=" "))
# printf("badallowed            %s\n", paste0(sprintf("% 10.3f", summary(nbadallowed)), collapse=" "))
# printf("badendspan            %s\n", paste0(sprintf("% 10.3f", summary(nbadendspan)), collapse=" "))

# plot the data we are modeling
plot(1:nrow(x), y, type="b", pch=20, xlab="x", main="the data we are modeling")

# plot memory used for each model
plotmem(nlm, nstandardearth, ngoodallowed, nbadallowed, nbadendspan)

source("test.epilog.R")

Try the earth package in your browser

Any scripts or data that you put into this service are public.

earth documentation built on Feb. 16, 2023, 6:07 p.m.