假设我想声明一个具有ncol
列的矩阵mat
,其中ncol
是一些数据foo
的函数。我可以用下面的data
块来实现这一点,这需要我向Stan传递一个带有ncol
值的数据文件。
在数据文件中不包含ncol
的情况下,如何在Stan程序中实现这一点
data{
vector[2] foo;
int ncol; // assume ncol = sum(foo)
matrix[2, ncol] mat;
}
下面我描述了我考虑过的一些方法,但我不确定它们是否有效以及为什么无效。
方法1:在数据块中进行操作和分配
对data
块内的ncol
进行运算和赋值。但是,Stan参考手册指出,data
块中不允许进行分配。因此,这不应该起作用:
data{
vector[2] foo;
int ncol = sum(foo); // illegal: assignment isn't allowed in data!
matrix[2, ncol] mat;
}
方法2:将操作和分配移动到转换的数据块
在transformed_data
块中分配。我的理解是,我不能将数据直接传递到transformed_data
块中的对象,这意味着如果我将数据移动到mat
,我将无法将数据传递到那里(见下文(。类似地,我无法通过将mat
保留在data
中来解决这个问题,因为它的维度将取决于transformed_data
,这是非法的。
data{
vector[2] foo;
}
transformed_data{
int ncol = sum(foo);
matrix[2, ncol] mat; // can't read and assign to `mat` because it's not in `data`?
}
方法3:操作但不在数据块中签名
在mat
的声明中计算但不分配ncol
的值。我认为这不会起作用,除非foo
总是先读入,而且我不确定它是否合法。
data{
vector[2] foo;
matrix[2, sum(foo)] mat; // possible illegal in data block?
}
方法3在这方面取得了成功,而所有其他方法都没有。它是合法的,因为:
- 在
data
块中声明的对象可以在data
块内的后续声明中使用 - 它不会为
data
块中声明的对象赋值。这有点微妙,因为它确实计算用于声明对象的值
在下文中,我展示了方法3成功地完成了我在问题中想要做的事情,而其他方法则没有。
基线示例:传递rstan
额外数据
# Code that does not be changed across runs
# Packages
library(rstan)
# Program file name
relpath <- "example_stan_program.stan"
# Function to run the Stan program with specified presets
run_example <- function(model_code, data){
stan(model_code = model_code,
data = data,
iter = 1, warmup = 0,
chains = 1, cores = 1,
refresh = 0,
algorithm = "Fixed_param",
verbose = F)
}
# Baseline Stan program
baseline <- "
data{
array[2] int foo;
int bar; // assumes bar = sum(foo)
matrix[2, bar] mat;
}
transformed data{
print(foo);
print(bar);
print(mat);
}
"
# Baseline data
dat_baseline <- list(
foo = c(1,1),
bar = sum(c(1,1)),
mat = matrix(1:4, nrow = 2, ncol = 2)
)
# Run program
out <- run_example(baseline, dat_baseline)
#> [1,1]
#> 2
#> [[1,3],[2,4]]
方法3:在data
块中无赋值计算
operate <- "
data{
array[2] int foo;
matrix[2, sum(foo)] mat;
}
transformed data{
print(foo);
print(mat);
}
"
# Example Data
dat_operate <- list(
foo = c(1,1),
mat = matrix(1:4, nrow = 2, ncol = 2)
)
# Run program (we could also get bar in transformed_data if desired)
out <- run_example(operate, dat_operate)
#> [1,1]
#> [[1,3],[2,4]]
演示其他方法不成功
方法1:在data
中操作和分配(错误(
operate <- "
data{
array[2] int foo;
int bar = sum(foo); // cannot assign in data block
matrix[2, bar] mat;
}
transformed data{
print(foo);
print(bar);
print(mat);
}
"
# Example Data
dat_operate <- list(
foo = c(1,1),
mat = matrix(1:4, nrow = 2, ncol = 2)
)
# Run program
out <- run_example(operate, dat_operate)
#> Error in stanc(file = file, model_code = model_code, model_name = model_name, : 0
#>
#> Syntax error in 'string', line 3, column 12 to column 15, parsing error:
#>
#> Cannot assign to variables in the `data` or `parameters` blocks; expected ';'
#> after variable declaration.
方法2:在transformed data
中进行运算和分配(无错误,但为空矩阵(
operate_tr <- "
data{
array[2] int foo;
}
transformed data{
int bar = sum(foo);
matrix[2, bar] mat; // empty because values not read in data block
print(foo);
print(bar);
print(mat);
}
"
# Example Data
dat_operate_tr <- list(
foo = c(1,1),
mat = matrix(1:4, nrow = 2, ncol = 2)
)
# Run program
out <- run_example(operate_tr, dat_operate_tr)
#> [1,1]
#> 2
#> [[nan,nan],[nan,nan]]