If else statement works inappropriately
MillyLiu87 opened this issue · comments
For testing if-else statement in Metabayes package, the following steps were carried out:
- model
model = metajags(
model = {
#core model
for (i in 1:n) {
if(x[i] >= 0)
{
y[i] <- 3_x[i]
}
else{
y[i] <- x[i]
}
}
}
) - data
x = sample(-2:2, 20, replace = TRUE)
y = 2_x
n = 20 - run
jags = run.jags(code(model), data = list(n = n, x = x), n.chains=2, "y") - result
One samples for x could be
-2 0 1 2 2 0 2 2 -2 2 2 -2 -2 2 1 -2 2 1 0 1
And using the model, the samples for y would be
-6 0 3 6 6 0 6 6 -6 6 6 -6 -6 6 3 -6 6 3 0 3
It seems the else statement was not executed.
It is claimed that the R expression in if condition is evaluated immediately when the Metajags specification is compiled. The question would be which value in x is evaluated?
Thanks for the bug report!
In fact, the results are consistent with how the if/else
statement is intended to work in metajags. The if/else
statement, unlike the ifelse
function, is evaluated only once: when the metajags code is compiled into JAGS code. It seems like you might be looking for functionality provided by the ifelse
function. I will explain with an example.
First, let's run the code you have provided in a fresh environment:
library(metabayes)
library(runjags)
# we will remove any existing objects from the R environment so that
# the metajags call is evaluated "fresh"
rm(list = ls())
model = metajags(
model = {
#core model
for (i in 1:n) {
if(x[i] >= 0)
{
y[i] <- 3 * x[i]
}
else{
y[i] <- x[i]
}
}
}
)
## Error in eval(expr, envir, enclos) : object 'x' not found
The code failed because metajags tried to evaluate expression x[i] >= 0
in R (not JAGS) at the moment of compilation, and x
has not been defined yet. To get the code to run, we can define x
first:
x = sample(-2:2, 20, replace = TRUE)
i = 1
x
## [1] -2 2 0 -2 -1 -1 -2 0 1 -2 1 -2 -2 2 0 1 -2 2 2 -1
model = metajags(
model = {
#core model
for (i in 1:n) {
if(x[i] >= 0)
{
y[i] <- 3 * x[i]
}
else{
y[i] <- x[i]
}
}
}
)
The metajags code now compiles because we have defined x
and i
, so metajags can evaluate x[i] >= 0
. However, it will only evaluate this once, and then substitute the appropriate branch into the JAGS code. We can see this by looking at the compiled JAGS code:
model
## metajags code:
##
## 1 model {
## 2 for (i in 1 : n) {
## 3
## 4 y[i] <- x[i];
## 5 }
Since the first element of x
is less than 0
, x[i] <= 0
evaluates to FALSE
and the if/else
statement is replaced with the contents of the else
branch, y[i] <- x[i]
(had x[1]
been greater than or equal to 0
, this would have been y[i] <- 3 * x[i]
).
The if/else
statement is intended for use in meta-programming: e.g., if you want to use R variables and expressions to choose between different specifications for parts of your model, you might use the if/else
statement. However, in your case, I think you are looking for the ifelse
function, which is evaluated during sampling and not at compile time.
For example, I think you want something like the following model:
model = metajags(
model = {
#core model
for (i in 1:n) {
y[i] <- ifelse(x[i] >= 0, 3 * x[i], x[i])
}
}
)
We can inspect the model to see that ifelse
is not evaluated at compile time:
model
## metajags code:
##
## 1 model {
## 2 for (i in 1 : n) {
## 3 y[i] <- ifelse(x[i] >= 0,3 * x[i],x[i]);
## 4 }
## 5 }
We can run the model:
n = length(x)
jags = run.jags(code(model), data = list(n = n, x = x), n.chains=2, "y")
## Compiling rjags model...
## Calling the simulation using the rjags method...
## Note: the model did not require adaptation
## Burning in the model for 4000 iterations...
##
## |
## |**************************************************| 100%
## Running the model for 10000 iterations...
##
## |
## |**************************************************| 100%
## Simulation complete
## Calculating summary statistics...
## Note: The monitored variables 'y[1]', 'y[2]', 'y[3]', 'y[4]', 'y[5]',
## 'y[6]', 'y[7]', 'y[8]', 'y[9]', 'y[10]', 'y[11]', 'y[12]', 'y[13]',
## 'y[14]', 'y[15]', 'y[16]', 'y[17]', 'y[18]', 'y[19]' and 'y[20]' appear
## to be non-stochastic; they will not be included in the convergence
## diagnostic
## Finished running the simulation
## Warning message:
## No initial values were provided - JAGS will use the same initial values for all chains
And then compare against the correct results:
correct_y = ifelse(x >= 0, 3 * x, x)
rbind(summary(jags)[,"Mean"], correct_y)
## y[1] y[2] y[3] y[4] y[5] y[6] y[7] y[8] y[9] y[10] y[11] y[12] y[13]
## -2 6 0 -2 -1 -1 -2 0 3 -2 3 -2 -2
## correct_y -2 6 0 -2 -1 -1 -2 0 3 -2 3 -2 -2
## y[14] y[15] y[16] y[17] y[18] y[19] y[20]
## 6 0 3 -2 6 6 -1
## correct_y 6 0 3 -2 6 6 -1