web-dev-qa-db-fra.com

Matrice de longueur inconnue dans MATLAB?

J'essaie de mettre en place une matrice nulle de longueur variable avec deux colonnes dans lesquelles je peux produire les résultats d'une boucle while (avec l'intention de l'utiliser pour stocker les données de pas de la méthode d'Euler avec des pas de temps ajustés). La longueur sera déterminée par le nombre d'itérations de la boucle.

Je me demande s'il y a un moyen de le faire pendant que je lance la boucle ou si je dois le configurer pour commencer, et comment procéder.

24
Flick

si le nombre de colonnes est fixe, vous pouvez toujours ajouter des lignes à votre matrice (à l'intérieur de la boucle)

par exemple.

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

bien sûr, si vous connaissez le nombre d'itérations avant la boucle while, il est plus efficace de pré-allouer la matrice

14
LiorH

Une autre approche qui a à l'esprit les performances tout en essayant d'être économe en espace consiste à préallouer la mémoire en grands lots, en ajoutant plus de lots au besoin. Ceci est bien adapté si vous devez ajouter un grand nombre d'articles sans savoir combien au préalable.

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

[~ # ~] modifier [~ # ~] : À titre de comparaison temporelle, considérons les cas suivants:

  1. Le même code que ci-dessus fait pour 50000 itérations.
  2. Préallouer la matrice entière au préalable: list = zeros(50000,2); list(k,:) = [x y];
  3. Ajout dynamique de vecteurs à la matrice: list = []; list(k,:) = [x y];

Sur ma machine, les résultats ont été:

1) Le temps écoulé est 0,080214 secondes .
2) Le temps écoulé est de 0,065513 seconde.
3) Le temps écoulé est de 24,433315 secondes.


Mettre à jour:

Suite aux discussions dans les commentaires, j'ai relancé certains tests en utilisant la dernière version R2014b. La conclusion est que les versions récentes de MATLAB ont considérablement amélioré les performances de croissance automatique des baies!

Cependant, il y a un hic; le tableau doit croître sur la dernière dimension (colonnes dans le cas de matrices 2D). C'est pourquoi l'ajout de lignes comme prévu à l'origine est encore trop lent sans préallocation. C'est là que la solution proposée ci-dessus peut vraiment aider (en étendant le tableau par lots).

Voir ici pour l'ensemble complet de tests: https://Gist.github.com/amroamroamro/0f104986796f2e0aa618

47
Amro

MATLAB utilise le typage dynamique avec une gestion automatique de la mémoire. Cela signifie que vous n'avez pas besoin de déclarer une matrice de taille fixe avant de l'utiliser - vous pouvez la modifier au fur et à mesure et MATLAB allouera dynamiquement de la mémoire pour vous.

MAIS c'est moyen plus efficace d'allouer de la mémoire à la matrice en premier et puis utilisez-le. Mais si vos programmes ont besoin de ce type de flexibilité, allez-y.

Je suppose que vous devez continuer à ajouter des lignes à votre matrice. Le code suivant devrait fonctionner.

Matrix = [];

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

disp(Matrix);

Ici, nous réallouons dynamiquement l'espace requis pour Matrix chaque fois que vous ajoutez une nouvelle ligne. Si vous connaissez au préalable, disons, une limite supérieure du nombre de lignes que vous allez avoir, vous pouvez déclarer Matrix = zeros(20,2) puis insérer chaque ligne dans la matrice de manière incrémentielle.

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

Une autre saveur de la même chose que Jacob a postée.

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

Une chose "sympa" à ce sujet est que vous pouvez deviner une taille minimale pour améliorer les performances.

Cela pourrait également être intéressant: http://www.mathworks.com/help/matlab/math/resizing-and-reshaping-matrices.html#f1-8876

4
ccook