Проблемы с указанием nzmax в разреженной команде из MATLAB

Я хотел бы создать разреженную матрицу размера n × n. Как обычно, i, j — индексы строк и столбцов, s — значения. Команда

    S=sparse(i,j,s,n,n);

работает нормально, но использует много памяти при создании S. Согласно документации MATLAB использует nzmax=length(s) по умолчанию. Чтобы сэкономить память, я хочу указать nzmax для S, который я могу вычислить заранее. В целях тестирования (я уже создал S с помощью приведенной выше команды) я вычисляю

    nonzeros=nzmax(S);

и позвони

    S=sparse(i,j,s,n,n,nonzeros);

Обратите внимание, что в моем примере ненулевые значения намного меньше длины (длин). Кроме того, nnz(S)=nzmax(S). Затем я получаю сообщение об ошибке

Ошибка при использовании разреженного: индекс превышает размеры матрицы.

Может кто-нибудь объяснить мне это поведение, пожалуйста? Какое возможное решение/обходной путь?

Позвольте мне добавить фрагмент кода в качестве примера

   i=randi(10,1000,1);
   j=randi(10,1000,1);
   s=rand(1000,1);
   ell=size((unique([i j],'rows')),1);
   S=sparse(i,j,s,10,10,ell);
Error using sparse: Index exceeds matrix dimensions.
   S=sparse(i,j,s,10,10);
   nnz(S)
ans = 100
   ell
ell =  100
   nzmax(S)
ans =  100

person Matthias    schedule 04.11.2014    source источник
comment
Итак, у вас есть дублирующиеся пары индексов, верно? Проверьте spalloc.   -  person Stewie Griffin    schedule 04.11.2014
comment
Да, у меня есть дублирующиеся пары индексов. Как я могу эффективно генерировать матрицу S при использовании spalloc?   -  person Matthias    schedule 04.11.2014


Ответы (1)


Как насчет использования accumarray, указав, что вы работаете с разреженными матрицами (6-й аргумент):

n = 100;
num = 10000;
i = randi(n,num,1);
j = randi(n,num,1);
s = ones(num, 1);

A = accumarray([i, j], s, [n,n], [], 0, true);

При этом используется следующая структура для accumarray:

A = accumarray(subs,val,sz,fun,fillval,issparse)

Альтернативой является использование spalloc в первую очередь. Таким образом, вы должны избежать инициализации по умолчанию.

A = spalloc(n, n, non_z);
A(sub2ind(size(A),i,j)) = s;

Еще одна альтернатива — использовать unique с 'rows' в качестве второго входа для подсчета количества уникальных пар индексов.

uni_ind = numel(unique([i,j], 'rows'));
A = sparse(i, j, s, n, n, uni_ind);
person Stewie Griffin    schedule 04.11.2014
comment
Спасибо, Роберт, версии accumarray работают. Кажется, что это немного медленнее, чем разреженная версия. Однако на моем компьютере (память 16 ГБ) для накопления памяти требовалось 44% памяти, а для разреженных 30% (согласно верхней команде в терминале Linux). У меня nnz(S)=27 984 002 и размер(S)=4 000 000 x 4 000 000. S требуется около 460 МБ только в соответствии с чьей командой в MATLAB. - person Matthias; 04.11.2014
comment
Более того, как написано в вопросе, я могу вычислить ненулевые значения, которые соответствуют вашему uni_ind, но тогда MATLAB выдает ошибку. - person Matthias; 04.11.2014
comment
К сожалению, это не работает, потому что индексы (i,j) могут встречаться несколько раз. Мне просто интересно, почему MATLAB выдает ошибку при указании правильного количества ненулевых значений. - person Matthias; 04.11.2014
comment
да. Он увеличивается, если я не указываю nzmax, потому что тогда по умолчанию nzmax=length(s), что в моем случае примерно в 10-20 раз больше, чем необходимо. Если я укажу предположительно правильное значение, он вообще не работает. - person Matthias; 04.11.2014
comment
Очень хороший accumarray ответ. - person chappjc; 04.11.2014