你得到的错误是由于你的函数的else
分支试图x
像一个二维数组一样切片(因为它使用两个索引表达式:1..number_rows
和i
)即使一些调用点正在传递一个一维数组/向量(或所以我假设基于您的描述和错误消息)。默认情况下,Chapel 仅支持使用单个索引表达式切片一维数组和使用两个索引表达式切片二维数组;否则会导致无法解决的访问错误,例如您遇到的错误。
我相信修复相当简单:您希望编译器折叠函数的条件,以便它只考虑1Dthen
时的分支和2D时的分支。然后,2D 切片表达式只有在合法时才会被评估。x
else
x
Chapel 折叠测试是param
表达式的条件(意味着可以在编译时评估表达式)。数组的等级是一个param
值,因此您的条件非常接近被折叠,除非您将等级存储到变量 ( var number_columns
) 中并在条件中使用它。因为编译器通常不能知道变量的值,var
所以测试表达式 ( number_columns == 1
) 中的存在会禁用其折叠条件的能力(即使你和我可以看到变量是用 a 初始化的param
并且此后没有更改) .
一种解决方法是声明number_columns
为param
:
param number_columns: int = DX.rank;
...
if number_columns == 1 then {
这将导致条件的测试成为一个param
表达式,因为 (a)number_columns
现在是 a param
, (b)1
是 a param
,并且 (c) Chapel 支持==
比较param int
s 并返回 a 的实现param bool
。结果,现在可以在编译时评估表达式,并且条件将被折叠,使得对于给定的 1D 或 2D 形式,只有 1D 或 2D 版本将持续存在x
。
也就是说,一个更简单的解决方法是简单地使测试原因DX
直接与排名有关:
if DX.rank == 1 then {
这将导致条件被折叠,原因与之前的重写相同。
(请注意,这实际上可能是您想要的,因为可能number_columns
应该更像是x.shape(2)
而不是x
排名,这将导致它始终为 1 或 2?)。
为此,这里建议使用说明性调用重写您的代码,并建议inner_function()
接受一维数组:
config var n = 3;
var v: [1..n] real = -1;
writeln(v);
writeln(outer_function(v));
var D2 = {1..n, 1..n};
var A: [D2] real = [(i,j) in D2] i + j / 10.0;
writeln(A);
writeln(outer_function(A));
proc outer_function(x: [?DX]) {
var number_rows: int = x.shape(1);
var number_columns: int = if x.rank == 1 then 1 else x.shape(2);
var result: [1..number_columns] real;
if x.rank == 1 then {
result[1] = inner_function(x);
} else {
var column_domain: domain(1) = {1..number_columns};
for i in column_domain do {
result[i] = inner_function(x[1..number_rows, i]);
}
}
return result;
}
proc inner_function(x: [?DX]) {
if x.rank != 1 then
compilerError("inner_function only accepts 1D arrays");
return + reduce x;
}
请注意,myinner_function()
同样依赖于条件的折叠,仅在inner_function()
传递等级不为 1 的数组的事件中生成编译器错误(尝试调用inner_function(A)
以触发此编译器错误)。
假设我在你想要的轨道上,这里有一个更干净(更灵活)的实现outer_function()
:
proc outer_function(x: [?DX]) {
if x.rank == 1 {
return inner_function(x);
} else {
var result: [DX.dim(2)] real;
for i in result.domain do {
result[i] = inner_function(x[DX.dim(1), i]);
}
return result;
}
}
在这里,我做了两件主要的事情和一件次要的事情:
- 利用条件将被折叠以使每个分支返回不同类型的事实——一维案例将返回一个标量,二维案例将返回一个一维数组
- 用于
DX.dim(i)
引用定义维度的范围,DX
以便此函数无论DX
具有基于 1 的索引还是基于 0 的索引(或基于 b 的索引)都可以工作,并将这些索引保留在result
它创建和返回的向量中
- 删除了
then
使用大括号/复合语句定义条件主体时不需要的关键字。