integer-valued uniform distribution

19 views
Skip to first unread message

Brook Milligan

unread,
Jun 26, 2025, 10:42:12 AM6/26/25
to nimble-users
Hi,

I need an integer-valued uniform distribution for a prior, but it is unclear that one is provided by NIMBLE. Am I missing it or is it missing?

Thanks for your help.

Cheers,
Brook

Chris Paciorek

unread,
Jun 26, 2025, 11:23:18 AM6/26/25
to Brook Milligan, nimble-users
hi Brook,

You could use `dcat` for this, provided the valid integer values are positive. You'd need to set the probability parameter vector equal to 1/K for the K valid values. And if the valid integers are not sequential, you'd need to set appropriate elements of the probability vector to 0.  (And if the valid integers were not all positive, you could take the random variable that has dcat as its distribution and use subtraction to map onto the actual integers of interest.)

It would also be possible to create a user-defined distribution.

If there are lots of gaps and you are using MCMC, it may make sampling less efficient.

-chris

--
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 visit https://groups.google.com/d/msgid/nimble-users/408A7630-30B2-40FB-8B11-C97BE063D169%40nmsu.edu.

Brook Milligan

unread,
Jun 26, 2025, 1:06:41 PM6/26/25
to paci...@stat.berkeley.edu, nimble-users
Hi Chris,

Thanks for the quick reply. Good to know that I am not missing something obvious in the manual.

I am trying the user-defined route, as that seems cleaner. Here is my attempt:

# integer-valued uniform distribution
dUnif <- nimbleFunction(
run = function(x = integer(),
min = integer(0,default=0),
max = integer(0,default=1),
log=integer(0,default=FALSE))
{
returnType(double())
if (x < min | x > max) {
p <- 0
} else {
p <- 1 / (max - min + 1)
}
if (log) return (log(p)) else return (p)
}
)
rUnif <- nimbleFunction(
run = function(n = integer(),
min = integer(0,default=0),
max = integer(0,default=1))
{
returnType(integer())
if (n != 1) stop('only n=1 is supported')
s <- runif(n=n,min=min,max=max+1)
s <- floor(s)
s <- as.integer(s)
return (s)
}
)
registerDistributions(list(
dUnif=list(BUGSdist="dUnif(min,max)",
types=c("min=integer()","max=integer()"),
discrete=TRUE)))

N ~ dUnif(min=0,max=10)

The error from compiling the model is the following, which comes from rUnif():

Error: Number of dimensions 1 of the return() argument does not match number 0 given in the returnType() statement. This occurred for: return(s)

It seems that the NIMBLE version of runif() must return a vector, even when n=1?

Any help greatly appreciated, as this is likely obvious to those of you more versed in user-defined distributions.

Thanks a lot.

Cheers,
Brook

> On Jun 26, 2025, at 09:22, 'Chris Paciorek' via nimble-users <nimble...@googlegroups.com> wrote:
>
> hi Brook,
>
> You could use `dcat` for this, provided the valid integer values are positive. You'd need to set the probability parameter vector equal to 1/K for the K valid values. And if the valid integers are not sequential, you'd need to set appropriate elements of the probability vector to 0. (And if the valid integers were not all positive, you could take the random variable that has dcat as its distribution and use subtraction to map onto the actual integers of interest.)
>
> It would also be possible to create a user-defined distribution.
>
> If there are lots of gaps and you are using MCMC, it may make sampling less efficient.
>
> -chris
>
> On Thu, Jun 26, 2025 at 7:42 AM 'Brook Milligan' via nimble-users <nimble...@googlegroups.com> wrote:
> Hi,
>
> I need an integer-valued uniform distribution for a prior, but it is unclear that one is provided by NIMBLE. Am I missing it or is it missing?
>
> Thanks for your help.
>
> Cheers,
> Brook
>
> --
> 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 tonimble-user...@googlegroups.com.
> --
> 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 tonimble-user...@googlegroups.com.
> To view this discussion visit https://groups.google.com/d/msgid/nimble-users/CA%2B7Ts_orXr5nfNh3p1GiEk-wV-uoR8NgxgGQLY-SZh2FGeQ3xw%40mail.gmail.com.

Chris Paciorek

unread,
Jun 26, 2025, 2:28:09 PM6/26/25
to Brook Milligan, nimble-users
Yeah, since you have `n` as the first arg to `runif`, the nimble compiler is treating `s` as a vector.

Also, you can't redefine `s` to be an integer because variable types must stay constant in nimbleFunction code since that code is translated into C++.

Finally (and this is minor, since it should work to use `integer()` as you have it), all model variables are treated as doubles (i.e., floating point/real-valued numbers), so you might as well do that within your `rUnif`. Unless one is working with very large numbers, integer-valued reals are represented exactly, so this won't be a numerical issue.

So taking account of all that, try this:

```
rUnif <- nimbleFunction(
    run = function(n = integer(),
                   min = double(0,default=0),
                   max = double(0,default=1))
          {
            returnType(double())

            if (n != 1)  stop('only n=1 is supported')
            s <- runif(n=1,min=min,max=max+1)
            s <- floor(s)
            return (s)
          }
)
```

It should be fine to use `integer()` in your `dUnif`. The compiler will handle things behind the scenes. But you could change those to double() as well.
Reply all
Reply to author
Forward
0 new messages