nimble-dev / nimble

The base NIMBLE package for R
http://R-nimble.org
BSD 3-Clause "New" or "Revised" License
158 stars 24 forks source link

inconsistent/confusing warning about nimbleFunction not yet created #1356

Closed paciorek closed 10 months ago

paciorek commented 12 months ago

When using nimOptim or the (being drafted) nimIntegrate, we get the warning variable '<some_nimbleFunction>' has not been created yet when the output of optim is assigned to a variable. When instead the output is directly returned, the warning is not given. It looks like this relates to how typeEnv$.AllowUnknowns is set in sizeAssign vs. sizeReturn. In sizeAssign we set it to FALSE before calling asserts <- recurseSetSizes(code, symTab, typeEnv, useArgs = c(FALSE, TRUE)), but we don't do that before calling recurseSetSizes in sizeReturn.

@perrydv do you have any idea why we handle .AllowUnknowns differently in these two situations?

Here's an example.

    objectiveFunction_inner <- nimbleFunction(
         run = function(par = double(1), power = double(0), scaling = double(0)) {
             return(sum(par) * exp(-sum(par ^ power) / scaling))
             returnType(double(0))
         }
    )
    objectiveFunction <- nimbleFunction(
        run = function(par = double(1)) {
            return(objectiveFunction_inner(par, 2, 3))
             returnType(double(0))
         }
     )
     optimizer <- nimbleFunction(
         run = function(method = character(0), fnscale = double(0)) {
             control <- optimDefaultControl()
             control$fnscale <- fnscale
             par <- c(0.1, -0.1)
             return(optim(par, objectiveFunction, method = method, control = control))   # NO WARNING
            ## If the following two lines replace the previous line, there is a WARNING.
             ## out <- optim(par, objectiveFunction, method = method, control = control)) 
             ## return(out)
             returnType(optimResultNimbleList())
         }
     )
     cOptimizer <- compileNimble(optimizer)   
paciorek commented 11 months ago

This duplicates (accidentally) #1295 but has more detail so I've closed 1295.

paciorek commented 11 months ago

Relatedly, missing variables are handled differently outside of optim. In the following, compilation of both causes an error from the C++ compiler, but in the former case, there is a warning about b being missing.

test <- nimbleFunction(
    run = function() {
        a  <- 7
        c <- a+b  # warning about 'b' not yet created, then C++ compilation fails
        return(c)
        returnType(double(0))
    })

test2 <- nimbleFunction(
    run = function() {
        a  <- 7
        return(a+b)   # no warning, C++ compilation fails
        returnType(double(0))
    })
paciorek commented 11 months ago

My thinking at the moment is there are two issues here.

paciorek commented 11 months ago

Branch fix_1356 has changes to address both issues. For the first issue I set .AllowUnknowns to FALSE in sizeReturn. For the second, I flag the function argument of nimOptim as something not to warn about when not finding in the symbol table.

I am not seeing the full context here in terms of the size processing so my suggested fixes will need a review from @perrydv .

I will file a separate issue about the question of warning vs. error in the case above of b not being found.