Есть ли удобный способ заполнить разреженный массив случайными значениями в Chapel? - PullRequest
3 голосов
/ 06 августа 2020

Я работаю над сравнением умножения матриц с языками и без них, и я пытаюсь использовать разреженные матрицы для работы с модулем линейной алгебры. Я планирую использовать blockdist и разбивать его вручную с помощью циклов, но я хочу увидеть, смогу ли я получить ускорение, просто используя что-то попроще. Если есть простой способ работы с blockdist, на который я не обращаю внимания, я был бы признателен. В любом случае, я могу заставить код работать и увидеть ускорение, когда я просто заполняю разреженные массивы одним значением, но заполнение его случайными значениями, похоже, не работает:

use LayoutCS;
use Time;
use LinearAlgebra, Norm;
use LinearAlgebra.Sparse;
use Random;
use IO;

writeln("Please type the filename with your matrix dimensions. One matrix on each line. The rows in the second need to match the columns in the first");
var filename: string;
filename = stdin.read(string);

// Open an input file with the specified filename in read mode.
var infile = open(filename, iomode.r);
var reader = infile.reader();

// Read the number of rows and columns in the array in from the file.
var r = reader.read(int), c = reader.read(int);

const parentDom = {1..r, 1..c};
var csrDom: sparse subdomain(parentDom) dmapped CS();
var A: [csrDom] real; 
A = 2; //instead of this I would like to do something like fillRandom(A) but it seems to not work

var X: [1..r, 1..c] real; 
fillRandom(X);

//read in the other matrix
var r1 = reader.read(int), c1 = reader.read(int);

const parentDom1 = {1..r1, 1..c1};
var csrDom1: sparse subdomain(parentDom1) dmapped CS();
var B: [csrDom1] real;
B = 3; //same thing as with matrix A

var Y: [1..r1, 1..c1] real; 
fillRandom(Y);

// Close the file.
reader.close();
infile.close();

var t: Timer; //sets up timer
t.start();

var result: [1..r, 1..c1] real; //sets up matrix for results
  
forall i in 1..r do //goes through rows in 1st
  for j in 1..c1 do //goes through 2nd matrix columns
    for k in 1..c do { //goes through columns in 1st
      result[i, j] += X[i, k] * Y[k, j]; //adds the multiplications to the new slot in results
    }

t.stop();
writeln("multiplication took ", t.elapsed()," seconds");
t.clear();


t.start();
var res = A * B;
t.stop();

writeln("loc multiplication took ", t.elapsed()," seconds");
t.clear();

Не работает fillRandom не работает с разреженными массивами или я делаю это неправильно? Нужно ли мне go через и вручную назначать каждое значение в массиве с помощью al oop? Также, конечно, возможно, что я нахожусь на совершенно неправильном пути, и мне следует больше смотреть на blockdist, и я определенно буду признателен за любые советы или подсказки по этому поводу, поскольку я не совсем уверен, как я буду работать, чтобы убедиться, что каждая параллельная задача действительно выполняется в правильных разделах локали, созданных blockdist.

Заранее спасибо!

1 Ответ

1 голос
/ 07 августа 2020

Не работает ли fillRandom с разреженными массивами или я делаю это неправильно?

Random.fillRandom() не поддерживает разреженные массивы в Chapel сегодня (1.22.0). Однако я думаю, что это было бы разумным запросом функции, если вы были бы заинтересованы в регистрации проблемы GitHub по нему.

Даже если fillRandom поддерживает разреженные массивы, пользователю все равно нужно будет указать, какие элементы ненулевое значение перед заполнением этих ненулевых элементов случайными значениями. Это делается путем добавления индексов в виде (int, int) кортежей (или массивов (int, int) кортежей) в разреженный домен.

Вот небольшой пример генерации сжатого массива разреженных строк (CSR) размером 100x100 с 10 не -нулевые случайные элементы:

/* Example tested with Chapel 1.22 */
import LayoutCS.{CS, isCSType};
import Random;

/* Parent domain dimensions: NxN */
config const N = 100;
/* Number of non-zero elements */
config const nnz = 10;

const parentDom = {1..N, 1..N};
var csrDom: sparse subdomain(parentDom) dmapped CS();
var A: [csrDom] real;

populate(A, csrDom, nnz);

// Print non-zero elements
for (i,j) in csrDom do
  writeln((i,j), ':', A[i, j]);


/* Populate sparse matrix with `nnz` random values */
proc populate(ref A, ref ADom, nnz: int) where isCSType(ADom.dist.type) && isCSType(A.domain.dist.type) {

  // Generate array of random non-zero indices
  var indices: [1..nnz] 2*int;
  var randomIndices = Random.createRandomStream(eltType=int);

  // Replace any duplicate indices with a new random index
  for idx in indices {
    var newIdx = idx;
    while indices.find(newIdx)(1) {
      newIdx = (randomIndices.getNext(ADom.dim(0).low, ADom.dim(0).high),
                randomIndices.getNext(ADom.dim(1).low, ADom.dim(1).high));
    }
    idx = newIdx;
  }

  // Add the non-zero indices to the CSR domain
  ADom += indices;

  // Generate random elements - maybe fillRandom(A) could do this for us some day
  var randomElements = Random.createRandomStream(eltType=A.eltType);
  for idx in ADom {
    A[idx] = randomElements.getNext();
  }
}
...