前言
由于 Chapel 矩阵表示为数组,因此这个问题等价于:
“如何从教堂的文件中读取数组”。
理想情况下,一个csv
模块或一个专门的 IO 格式化程序(类似于JSON 格式化程序)会更优雅地处理csv
I/O,但这个答案反映了自 Chapel 1.16 预发布时可用的数组 I/O 选项。
密集阵列 I/O
密集数组是最简单的情况,因为DefaultRectangular
数组(Chapel 数组的默认值type
)带有一个.readWriteThis(f)
方法。此方法允许使用内置write()
和read()
方法读取和写入数组,如下所示:
var A: [1..5, 1..5] real;
// Give this array some values
[(i,j) in A.domain] A[i,j] = i + 10*j;
var writer = open('dense.txt', iomode.cw).writer();
writer.write(A);
writer.close();
var B: [1..5, 1..5] real;
var reader = open('dense.txt', iomode.r).reader();
reader.read(B);
reader.close();
assert(A == B);
dense.txt
看起来像这样:
11.0 21.0 31.0 41.0 51.0
12.0 22.0 32.0 42.0 52.0
13.0 23.0 33.0 43.0 53.0
14.0 24.0 34.0 44.0 54.0
15.0 25.0 35.0 45.0 55.0
但是,这假设您事先知道数组形状。我们可以通过在文件顶部写入数组形状来移除这个约束,如下所示:
var A: [1..5, 1..5] real;
[(i,j) in A.domain] A[i,j] = i + 10*j;
var writer = open('dense.txt', iomode.cw).writer();
writer.writeln(A.shape);
writer.write(A);
writer.close();
var reader = open('dense.txt', iomode.r).reader();
var shape: 2*int;
reader.read(shape);
var B: [1..shape[1], 1..shape[2]] real;
reader.read(B);
reader.close();
assert(A == B);
现在,dense.txt
看起来像这样:
(5, 5)
11.0 21.0 31.0 41.0 51.0
12.0 22.0 32.0 42.0 52.0
13.0 23.0 33.0 43.0 53.0
14.0 24.0 34.0 44.0 54.0
15.0 25.0 35.0 45.0 55.0
稀疏阵列 I/O
稀疏数组需要做更多的工作,因为DefaultSparse
数组(稀疏 Chapel 数组的默认值type
)仅提供一种.writeThis(f)
方法,而.readThis(f)
在 Chapel 1.16 预发行版中不提供方法。这意味着我们内置了对写入稀疏数组的支持,但不支持读取它们。
由于您特别要求 csv 格式,我们将在 csv 中执行稀疏数组:
// Create parent domain, sparse subdomain, and sparse array
const D = {1..10, 1..10};
var spD: sparse subdomain(D);
var A: [spD] real;
// Add some non-zeros:
spD += [(1,1), (1,5), (2,7), (5, 4), (6, 6), (9,3), (10,10)];
// Set non-zeros to 1.0 (to make things interesting?)
A = 1.0;
var writer = open('sparse.csv', iomode.cw).writer();
// Write shape
writer.writef('%n,%n\n', A.shape[1], A.shape[2]);
// Iterate over non-zero indices, writing: i,j,value
for (i,j) in spD {
writer.writef('%n,%n,%n\n', i, j, A[i,j]);
}
writer.close();
var reader = open('sparse.csv', iomode.r).reader();
// Read shape
var shape: 2*int;
reader.readf('%n,%n', shape[1], shape[2]);
// Create parent domain, sparse subdomain, and sparse array
const Bdom = {1..shape[1], 1..shape[2]};
var spBdom: sparse subdomain(Bdom);
var B: [spBdom] real;
// This is an optimization that bulk-adds the indices. We could instead add
// the indices directly to spBdom and the value to B[i,j] each iteration
var indices: [1..0] 2*int,
values: [1..0] real;
// Variables to be read into
var i, j: int,
val: real;
while reader.readf('%n,%n,%n', i, j, val) {
indices.push_back((i,j));
values.push_back(val);
}
// bulk add the indices to spBdom and add values to B element-wise
spBdom += indices;
for (ij, v) in zip(indices, values) {
B[ij] = v;
}
reader.close();
// Sparse arrays can't be zippered with anything other than their domains and
// sibling arrays, so we need to do an element-wise assertion:
assert(A.domain == B.domain);
for (i,j) in A.domain {
assert(A[i,j] == B[i,j]);
}
sparse.csv
看起来像这样:
10,10
1,1,1
1,5,1
2,7,1
5,4,1
6,6,1
9,3,1
10,10,1
矩阵市场模块
最后,我会提到有一个使用矩阵市场格式MatrixMarket
支持密集和稀疏数组 I/O 的封装模块。这目前没有显示在公共文档中,因为一旦包管理器足够可靠,它就会作为一个独立的包移出,但你可以在你的教堂程序中使用它,目前。use MatrixMarket;
这是源代码,其中包括接口文档作为注释。
如果您更喜欢从示例中学习,而不是文档和源代码,这里是测试。