Матрица неизвестной длины в MATLAB? - PullRequest
24 голосов
/ 10 октября 2009

Я пытаюсь установить нулевую матрицу переменной длины с двумя столбцами, в которые я могу вывести результаты цикла while (с целью использовать его для хранения данных шага из метода Эйлера с отрегулированными временными шагами ). Длина будет определяться количеством итераций цикла.

Мне интересно, есть ли способ, которым я могу сделать это, пока я выполняю цикл, или мне нужно настроить его для начала, и как это сделать.

Ответы [ 4 ]

47 голосов
/ 11 октября 2009

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

BLOCK_SIZE = 2000;                          % initial capacity (& increment size)
listSize = BLOCK_SIZE;                      % current list capacity
list = zeros(listSize, 2);                  % actual list
listPtr = 1;                                % pointer to last free position

while rand<1-1e-5                           % (around 1e5 iterations on avrg)
  % push items on list
  list(listPtr,:) = [rand rand];            % store new item
  listPtr = listPtr + 1;                    % increment position pointer

  % add new block of memory if needed
  if( listPtr+(BLOCK_SIZE/10) > listSize )  % less than 10%*BLOCK_SIZE free slots
    listSize = listSize + BLOCK_SIZE;       % add new BLOCK_SIZE slots
    list(listPtr+1:listSize,:) = 0;
  end
end
list(listPtr:end,:) = [];                   % remove unused slots

РЕДАКТИРОВАТЬ : Для сравнения времени рассмотрим следующие случаи:

  1. Тот же код, что и выше, для 50000 итераций.
  2. Предварительное выделение всей матрицы: list = zeros(50000,2); list(k,:) = [x y];
  3. Динамическое добавление векторов в матрицу: list = []; list(k,:) = [x y];

На моей машине результаты были:

1) Истекшее время составляет 0,080214 секунды .
2) Истекшее время составляет 0,065513 секунд.
3) Прошедшее время составляет 24,433315 секунд.


Обновление:

После обсуждения в комментариях я перезапустил несколько тестов, используя последнюю версию R2014b. Делается вывод, что последние версии MATLAB значительно улучшили производительность автоматического роста массива!

Однако есть одна загвоздка; массив должен расти по последнему измерению (столбцы в случае двумерных матриц). Вот почему добавление строк, как первоначально предполагалось, все еще слишком медленное без предварительного выделения. В этом случае предложенное выше решение действительно может помочь (путем расширения массива партиями).

Смотрите здесь полный набор тестов: https://gist.github.com/amroamroamro/0f104986796f2e0aa618

14 голосов
/ 10 октября 2009

если количество столбцов фиксировано, вы всегда можете добавить строки в матрицу (внутри цикла)

, например

while (....)
   .....
   new_row =[x y] ; % new row with values x & y
   mat = [mat ; new_row]; 

конечно, если вы знаете количество итераций до цикла while, более эффективно предварительно выделить матрицу

7 голосов
/ 10 октября 2009

MATLAB использует динамическую типизацию с автоматическим управлением памятью. Это означает, что вам не нужно объявлять матрицу фиксированного размера перед ее использованием - вы можете изменять ее по мере продвижения, и MATLAB будет динамически выделять память для вас.

НО способ эффективнее сначала выделить память для матрицы, а , а затем использовать ее. Но если вашим программам нужна такая гибкость, сделайте это.

Полагаю, вам нужно добавлять строки в матрицу. Следующий код должен работать.

Matrix = [];

while size(Matrix,1) <= 10
    Matrix = [Matrix;rand(1,2)];
end

disp(Matrix);

Здесь мы динамически перераспределяем пространство, необходимое для Matrix каждый раз, когда вы добавляете новую строку. Если вы заранее знаете, скажем, верхнюю границу количества строк, которое у вас будет, вы можете объявить Matrix = zeros(20,2) и затем постепенно добавлять каждую строку в матрицу.

% Allocate space using the upper bound of rows (20)
Matrix = zeros(20,2);
k = 1;
for k = 1:10
   Matrix(k,:) = rand(1,2);
end
% Remove the rest of the dummy rows
Matrix(k+1:end,:) = [];
4 голосов
/ 10 октября 2009

Еще один вариант того же, что написал Иаков.

for counter = 1:10
    Matrix(counter,:) = rand(1,2);
end
disp(Matrix);

Одна «хорошая» вещь об этом - вы можете угадать минимальный размер, чтобы улучшить производительность.

Это также может быть интересно: http://www.mathworks.com/help/matlab/math/resizing-and-reshaping-matrices.html#f1-88760

...