我正在挖掘Chapel,我被困在函数中切割矩阵。接收矩阵的函数如下:
proc outer_function(x: [?DX]) {
var number_rows: int = x.shape(1);
var number_columns: int = DX.rank;
var result: [1..number_columns] real;
if number_columns == 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;
}
即,outer_function
可以接收向量或矩阵。如果它接收到一个向量,则使用相同的输入参数调用inner_function
。如果outer_function
收到矩阵,那么我想按列对输入矩阵进行切片并调用inner_function
。
问题是用x[1..number_rows, i]
或x[{1..number_rows}, i]
切片输入矩阵会在编译时抛出错误:
x[1..number_rows, i]
:错误:未解析的'[domain(1,int(64),false)] int(64)'by'[range(int(64),bounded,false),int( 64)]'x[{1..number_rows}, i]
:错误:未解析'[domain(1,int(64),false)] int(64)'by'[domain(1,int(64),false),int( 64)]'我需要帮助才能找出我收到此错误的原因,以及是否有更多像Chapel一样的方法来实现我想要做的事情。
答案 0 :(得分:1)
您获得的错误是由于您的函数else
分支正在尝试将x
切片,就好像它是一个2D数组(因为它使用了两个索引表达式:1..number_rows
和i
)即使一些callite传入一维数组/向量(或者我假设基于你的描述和错误消息)。默认情况下,Chapel仅支持使用单个索引表达式和使用两个索引表达式的2D数组切片1D数组;否则会导致未解决的访问错误,例如您正在获取的错误。
我相信修复非常简单:您希望编译器折叠您的函数的条件,以便在then
为1D且x
时仅考虑else
分支} x
为2D时的分支。然后,只有在合法的情况下才会评估2D切片表达式。
Chapel折叠条件,其测试为param
表达式(意味着可以在编译时计算表达式)。数组的等级是param
值,因此您的条件非常接近折叠,除非您将等级存储到变量(var number_columns
)中并在条件中使用它。因为编译器通常不知道变量的值,所以测试表达式中var
的存在(number_columns == 1
)会禁用它折叠条件的能力(即使你和我能看到)变量用param
初始化,之后没有改变。
一种解决方法是将number_columns
声明为param
:
param number_columns: int = DX.rank;
...
if number_columns == 1 then {
这会导致条件测试成为param
表达式,因为(a)number_columns
现在是param
,(b)1
是param
和(c)Chapel支持==
的实施,比较param int
并返回param bool
。因此,现在可以在编译时评估表达式,并且条件将被折叠,使得对于给定的1D或2D正式x
,仅1D或2D版本将持续存在。
也就是说,一个更简单的解决办法就是直接测试DX
等级的测试原因:
if DX.rank == 1 then {
这将导致条件折叠的原因与之前的重写相同。
(请注意,这可能实际上是您想要的,因为大概number_columns
应该更像x.shape(2)
而不是x
的排名,这将导致它永远是1或2?)。
为此,我们建议使用说明性调用重写代码,并建议接受1D数组的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;
}
请注意,我的inner_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),此函数都将起作用index)并保留它创建并返回的result
向量中的那些索引then
关键字。