2

这次我有一个名为“matrix.csv”的矩阵——在一个文件中——我想读入它。我可以用两种方式来做,密集和稀疏。

稠密

matrix.csv

3.0, 0.8, 1.1, 0.0, 2.0
0.8, 3.0, 1.3, 1.0, 0.0
1.1, 1.3, 4.0, 0.5, 1.7
0.0, 1.0, 0.5, 3.0, 1.5
2.0, 0.0, 1.7, 1.5, 3.0

matrix.csv
1,1,3.0
1,2,0,8
1,3,1.1
// 1,4 is missing
1,5,2.0
...
5,5,3.0

假设文件很大。在这两种情况下,我都想将它们读入具有适当尺寸的矩阵中。在密集的情况下,我可能不需要提供元数据。第二,我在想我应该提供矩阵的“框架”,比如

matrix.csv
nrows:5
ncols:5

但我不知道标准模式。

== 更新 ==

有点难找,但是mmreadsp可以将您的一天从“使服务器崩溃”变为“在 11 秒内完成”。感谢 Brad Cray(化名)指出!

4

2 回答 2

1

前言

由于 Chapel 矩阵表示为数组,因此这个问题等价于:

“如何从教堂的文件中读取数组”。

理想情况下,一个csv模块或一个专门的 IO 格式化程序(类似于JSON 格式化程序)会更优雅地处理csvI/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;

这是源代码,其中包括接口文档作为注释。

如果您更喜欢从示例中学习,而不是文档和源代码,这里是测试。

于 2017-08-26T18:17:29.543 回答
0

向教授致敬。鲁道夫·齐特尼和教授。彼得·沃彭卡

在此处输入图像描述 (如果有人碰巧记得 PC 工具实用程序,由 Zitny 教授开创和创作的矩阵工具同样对于大型 F77 FEM 矩阵的智能抽象表示必不可少,使用COMMON-block 和类似技巧来处理大型和稀疏矩阵数字处理项目中的高效存储和操作...)


观察:

关于需要有“框架”以构建稀疏矩阵的最后一句话,我不能更不同意。

矩阵永远只是对某种形式主义的一种解释

虽然 sparse-matrix 在矩阵上共享相同的视图,但作为解释,每个此类模块的实现始终严格基于某些具体表示

总是使用不同的单元布局策略来处理不同类型的稀疏性(诀窍是在尝试对此类矩阵执行经典矩阵/向量操作时,使用[SPACE]单元元素的最低需求,同时具有一些可接受的处理开销([TIME]通常没有用户知道或“手动”打扰底层稀疏矩阵表示,用于存储单元格值,以及如何将其最佳解码/翻译成目标稀疏矩阵的表示)。

直观地说,矩阵工具会以尽可能紧凑的内存布局向您展示每个表示形式(就像在 PC 工具中它压缩了您的硬盘一样,放置扇区数据以避免任何不必要的非连续 HDD 容量被浪费)和非常(逐个类型特定的)表示感知处理程序然后将为任何外部观察者提供完整的错觉,这是假设矩阵解释所需的(在计算阶段) .

因此,让我们首先意识到,不知道有关用于稀疏矩阵表示的平台特定规则的所有细节,无论是在源端(python-?、JSON-meta-payload-? 等)还是在目标端(LinearAlgebraver-1.16 尚未确认不公开(WIP),没有太多要开始实施的事情。

(但未知的)稀疏矩阵表示(无论是 DMA 访问或 CSP 通道或非 InRAM 存储或 InRAM 内存映射的任何其他方式)的实际实现不会改变单比特交叉表示xlator的解决方案。file://

作为数学家,您可能会喜欢表示的概念不是康托集驱动的(遇到(几乎)无限的、密集的枚举)对象,而是使用 Vopenka 的替代集理论(在 Vopenka 的“关于科学基础的沉思”中深入地介绍了历史和数学背景,非常可爱) 已经带来并完善了对这些情况的更密切的看法,但定义范围仍在不断变化(不仅是由观察者观点的实际敏锐度引起的,而且在这种原则的更广泛和一般意义上),留下 pi -class 和 sigma-class semi-sets 准备好持续处理新出现的细节,因为它们进入我们公认的关于观察到的(和数学化的)视图的部分(一旦出现在定义范围的“前面”)现象。

稀疏矩阵(作为表示)帮助我们建立我们需要的解释,以便在“作为矩阵”的进一步处理中使用迄今为止获得的数据单元。

这就是说,工作流程总是需要先验知识:

a)稀疏矩阵源系统表示中使用的约束和规则
b)中介通道施加的附加约束(表达性、格式、自我修复/容易出错),无论它是文件、CSP 通道或 ZeroMQ / nanomsg 智能套接字信号/消息平面分布式代理基础设施
c)施加在目标系统表示中的约束和规则,设置用于定义/加载/存储/进一步处理和计算稀疏矩阵类型的规则在目标计算生态系统中的选择必须满足/遵循

不知道a)会在为成功和高效的交叉表示管道准备策略时引入不必要的大开销,即从源端表示转换常见解释以进入b)。忽略c)总是会导致惩罚——在b)对目标表示的沟通解释的重建期间,在目标生态系统中支付额外的开销。

于 2017-08-24T22:36:15.523 回答