2009-10-10 24 views
24

Próbuję ustawić zerową macierz o zmiennej długości z dwiema kolumnami, w której mogę wyprowadzić wyniki pętli while (z zamiarem wykorzystania go do przechowywania danych kroku z metody Eulera z dopasowanymi krokami czasu) . Długość będzie określona przez liczbę iteracji pętli.Macierz o nieznanej długości w MATLAB?

Zastanawiam się, czy jest sposób, w jaki mogę to zrobić, gdy uruchamiam pętlę lub czy muszę ją ustawić na początek i jak to zrobić.

+0

również, jeżeli jest to dla przypisania klasy i trzeba pokazać iteracji; możesz użyć sprintf w swojej implementacji Eulera. – ccook

+0

Inne powiązane pytanie: [Dołączanie wektora do pustej macierzy MATLAB] (http://stackoverflow.com/q/781410/97160) – Amro

Odpowiedz

14

jeżeli liczba kolumn jest stała zawsze można dodać wiersze do macierzy (wewnątrz pętli)

np

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

oczywiście jeśli znasz numer iteracji pętli while zanim to jest bardziej wydajny wstępnie przeznaczyć matrycy

+0

Dziękuję bardzo! To ma dla mnie sens. Myślisz o jednostce programistycznej, której nas uczą, ale zamiast tego rzucają nas do wilków. Dzięki za uratowanie mnie :) – Flick

+2

Używanie alternatywnej składni dla ostatniej linii powyższego kodu sprawia, że ​​bardziej wyraźnie mówisz o rozszerzeniu macierzy: 'mat (end + 1, :) = new_row;' – nhowe

7

MATLAB wykorzystuje dynamiczne pisanie z automatycznym zarządzaniem pamięcią. Oznacza to, że nie musisz zadeklarować macierzy o stałym rozmiarze przed jej użyciem - możesz ją zmienić, a MATLAB dynamicznie przydzieli pamięć dla ciebie.

ale jest sposób bardziej efektywne alokacji pamięci dla matrycy pierwszej i następnie użyciem. Ale jeśli twoje programy wymagają tego rodzaju elastyczności, idź do niego.

Zgaduję, że musisz nadal dołączać wiersze do macierzy. Poniższy kod powinien działać.

Matrix = []; 

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

disp(Matrix); 

Tutaj jesteśmy dynamicznie realokacji przestrzeń wymaganą do Matrix każdym razem dodać nowy wiersz. Jeśli wiesz wcześniej, powiedz górną granicę liczby wierszy, które będziesz mieć, możesz zadeklarować Matrix = zeros(20,2), a następnie wstawić każdy wiersz do macierzy przyrostowo.

% 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,:) = []; 
+0

+1 Używam tego cały czas. Zauważ, że możesz także po prostu użyć licznika, a Matlab zwiększy tablicę. – ccook

+0

Zaczynam widzieć, co robisz i dlaczego jest to skuteczne. Bardzo pomocna, dziękuję. – Flick

47

Innym podejściem, które ma na uwadze wydajność, a jednocześnie stara się być przestrzeń efektywny, jest przydzielenia pamięci w dużych partiach, dodając więcej partie ile potrzeba. Jest to dobrze dopasowane, jeśli musisz dodać dużą liczbę przedmiotów, nie wiedząc, ile wcześniej.

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 

EDIT: Dla porównania w czasie, należy rozważyć następujące przypadki:

  1. Ten sam kod jak wyżej zrobić dla 50000 iteracji.
  2. Preallocating całą macierz uprzednio: list = zeros(50000,2); list(k,:) = [x y];
  3. dynamicznie dodanie wektorów do macierzy: list = []; list(k,:) = [x y];

moim komputerze, wyniki były następujące:

1) Upływający czas jest 0,080214 sekundy.
2) Upływający czas wynosi 0,065513 sekund.
3) Upływający czas to 24.433315 sekund.


Aktualizacja:

Po dyskusji w komentarzach, ja ponownie uruchomić kilka testów z wykorzystaniem najnowszej wersji R2014b. Wniosek jest taki, że ostatnie wersje programu MATLAB znacznie poprawiły wydajność automatycznego zwiększania macierzy!

Jest jednak haczyk; tablica musi rosnąć w ostatnim wymiarze (kolumny w przypadku macierzy 2D). Dlatego dołączanie wierszy, jak pierwotnie zamierzano, jest wciąż zbyt wolne bez wcześniejszej alokacji. To jest miejsce, w którym powyższe proponowane rozwiązanie może naprawdę pomóc (poprzez rozszerzenie tablicy w partiach).

Patrz tutaj dla pełnego zestawu testów: https://gist.github.com/amroamroamro/0f104986796f2e0aa618

+4

woohoo! wnikliwe punkty + pomiary, aby je potwierdzić. dzięki. –

+8

p.s. większość metod o zmiennych rozmiarach (takich jak klasy łańcuchowe) nie używa stałego rozmiaru bloku, ale raczej zwiększa rozmiar przez współczynnik multiplikatywny K (zwykle K = 2). Ogranicza to liczbę kroków alokacji do O (log N), a jeśli zależy Ci na wydajności pamięci, zawsze możesz wybrać K = 1,2 lub 1,1 i zająć się obliczaniem wyniku matematycznego, aby wyliczyć efektywność/# kroków alokacji. –

+5

prawdopodobnie masz rację. Możesz łatwo zmodyfikować kod, aby to zrobić. Można również dostroić wiele parametrów: kiedy zwiększać rozmiar, o ile, być może nawet rosnący czynnik (zaczynać od K = 1,1 i zwiększać do 2) – Amro

Powiązane problemy