Compile errors with derivatives

51 views
Skip to first unread message

Christopher Jackson

unread,
Jul 22, 2024, 10:24:16 AM7/22/24
to nimble-users
Hi,

I am keen to use derivative-based algorithms in NIMBLE, but am having trouble getting models to compile with buildDerivs turned on in user-defined functions.

A minimal example of the kind of thing that breaks is below.  It works with the integer() argument changed to a double().  But the manual had given me the impression that the auto-differentiator would just ignore any integer arguments?   What have I missed?

Thanks,
Chris


fn <- nimbleFunction(
  run = function(mu = double(),
                 x = integer()){
    return(0.0)
    returnType(double())
  },
  buildDerivs = TRUE
)

ncode <- nimbleCode({
  y <- fn(mu, x)
})

nmod <- nimbleModel(code = ncode, data=list(mu=1,x=0), buildDerivs=TRUE)
nmodc <- compileNimble(nmod)
printErrors()

[...snip]

P_61_ncode_MID_53_nfCode.cpp: In member function 'virtual CppAD::AD<double> y_L1_UID_1256::calculate_ADproxyModel(const indexedNodeInfo&) const':
P_61_ncode_MID_53_nfCode.cpp:73:28: error: cannot convert 'std::conditional<true, CppAD::AD<double>, void>::type' {aka 'CppAD::AD<double>'} to 'int' in assignment
73 | Interm_4081 = stoch_ind_get((**ADproxyModel_x), 0);

Perry de Valpine

unread,
Jul 22, 2024, 11:13:30 AM7/22/24
to Christopher Jackson, nimble-users
Hi Chris,

Thanks for the question. 

The answer is in section 16.5.2.2 of the User Manual, but I get it that it might have been hard to find there. Also that is a newer section of the User Manual, I believe only in our latest version (1.2.0). The documentation of programming with AD is a bit hard to organize with a balance of high-level messages and low-level details. Suggestions welcome. Maybe we can bullet-point some of TL;DR tips.

Here is the story. It's true that declaring an argument to be of type integer will mean it will not have derivatives tracked. However, if the function is going to be called from a model, that won't work because all model variables are implemented as doubles, even when they will actually only ever take integer values. Therefore all arguments should be declared as double and the ADbreak method should be used if you want to stop derivative tracking. This should work:

fn <- nimbleFunction(
  run = function(mu = double(),
                 x = double()){
   x2 <- ADbreak(x) # now use x2 instead of x

    return(0.0)
    returnType(double())
  },
  buildDerivs = TRUE
)

HTH,
Perry

--
You received this message because you are subscribed to the Google Groups "nimble-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to nimble-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/nimble-users/1e2f66cc-7b41-4998-9ee8-19a7d27057a5n%40googlegroups.com.

Christopher Jackson

unread,
Jul 23, 2024, 2:35:28 PM7/23/24
to nimble-users
Thanks, Perry, that makes sense.  

I had been looking at section 16.3, "How to support derivatives in user-defined functions and distributions".  There is an example of a distribution used in a model there.  I wonder if an example of a function would be helpful too, since it works a bit differently? 

Chris

Christopher Jackson

unread,
Jul 24, 2024, 12:08:55 PM7/24/24
to nimble-users
The other thing that threw me is that the start of 16.5 says "From here on, this part of the chapter is oriented towards algorithm developers.", but this is knowledge needed for just using a user-defined function in a model with built-in algorithms. 

Chris

Perry de Valpine

unread,
Jul 24, 2024, 3:06:48 PM7/24/24
to Christopher Jackson, nimble-users
Thanks for both notes on the user manual. Those are helpful!


Reply all
Reply to author
Forward
0 new messages