2009-10-10 41 views
24

Estoy tratando de configurar una matriz cero de longitud variable con dos columnas en las que puedo mostrar los resultados de un ciclo while (con la intención de usarlo para almacenar los datos del paso del método de Euler con pasos de tiempo ajustados) . La longitud estará determinada por el número de iteraciones del ciclo.¿Matriz de longitud desconocida en MATLAB?

Me pregunto si hay una manera de hacerlo mientras estoy ejecutando el ciclo o si necesito configurarlo para empezar, y cómo hacerlo.

+0

Además, si se trata de una tarea de clase y tiene que mostrar las iteraciones; puedes usar sprintf dentro de tu implementación de Euler. – ccook

+0

Otra pregunta relacionada: [Agregar un vector a una matriz MATLAB vacía] (http://stackoverflow.com/q/781410/97160) – Amro

Respuesta

14

si el número de columnas es fijo siempre se puede añadir filas a la matriz (dentro del bucle)

por ejemplo,

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

, por supuesto, si se conoce el número de iteraciones antes de que el bucle while que es más eficiente para asignar previamente la matriz

+0

¡Muchas gracias! Esto tiene sentido para mí. Piensas que para una unidad de programación nos enseñarían algo de eso, pero en su lugar nos arrojarían a los lobos. Gracias por salvarme :) – Flick

+2

Usar la sintaxis alternativa para la última línea del código anterior hace que sea más explícito que está extendiendo la matriz: 'mat (end + 1, :) = new_row;' – nhowe

7

MATLAB utiliza el tipado dinámico con gestión de memoria automática. Esto significa que no necesita declarar una matriz de un tamaño fijo antes de usarla; puede cambiarla a medida que avanza y MATLAB asignará dinámicamente memoria para usted.

PERO es manera más eficiente para asignar memoria para la matriz primero y entonces usarlo. Pero si tus programas necesitan este tipo de flexibilidad, hazlo.

Supongo que debe seguir agregando filas a su matriz. El siguiente código debería funcionar.

Matrix = []; 

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

disp(Matrix); 

Aquí, estamos reasignar dinámicamente el espacio necesario para Matrix cada vez que se agrega una nueva fila. Si sabe de antemano, por ejemplo, un límite superior en el número de filas que va a tener, puede declarar Matrix = zeros(20,2) y luego insertar cada fila en la matriz de forma incremental.

% 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 Lo uso todo el tiempo. Tenga en cuenta que también puede usar un contador y Matlab hará crecer la matriz. – ccook

+0

Estoy empezando a ver lo que estás haciendo y por qué es eficiente. Muy útil, gracias. – Flick

47

Otro enfoque que tiene en cuenta el rendimiento al mismo tiempo tratando de ser eficiente con el espacio, es realizar una asignación previa de memoria en grandes lotes, añadiendo más lotes según sea necesario. Esto es muy adecuado si tiene que agregar una gran cantidad de elementos sin saber cuántos de antemano.

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 

EDITAR: A modo de comparación tiempo, considere los siguientes casos:

  1. El mismo código que el anterior hecho por 50000 iteraciones.
  2. preasignación toda la matriz de antemano: list = zeros(50000,2); list(k,:) = [x y];
  3. vectores dinámicamente la adición a la matriz: list = []; list(k,:) = [x y];

En mi máquina, los resultados fueron:

1) Tiempo transcurrido es 0,080214 segundo.
2) El tiempo transcurrido es 0.065513 segundos.
3) El tiempo transcurrido es 24.433315 segundos.


Actualizar:

Tras los debates en los comentarios, he vuelva a realizar algunas pruebas utilizando la versión más reciente R2014b. La conclusión es que las versiones recientes de MATLAB han mejorado enormemente el rendimiento del crecimiento automático de matrices.

Sin embargo, hay una trampa; la matriz debe crecer a lo largo de la última dimensión (columnas en el caso de las matrices 2D). Es por eso que agregar filas como originalmente se pretendía es aún demasiado lento sin preasignación. Aquí es donde la solución propuesta anteriormente puede ayudar realmente (ampliando la matriz en lotes).

ver aquí para el conjunto completo de pruebas: https://gist.github.com/amroamroamro/0f104986796f2e0aa618

+4

woohoo! un punto perspicaz + medidas para corroborarlo. Gracias. –

+8

p.s. la mayoría de los métodos de tamaño variable (como las clases de cuerdas) no usan un tamaño de bloque fijo, sino que aumentan el tamaño mediante un factor multiplicativo K (generalmente K = 2). Esto limita el número de pasos de asignación a O (log N), y si le importa la eficiencia de la memoria, siempre puede elegir K = 1.2 o 1.1 y manejar el cálculo matemático para negociar la eficiencia/# de los pasos de asignación. –

+5

probablemente tenga razón ... podría modificar fácilmente el código para hacerlo. También se pueden ajustar varios parámetros: cuándo aumentar el tamaño, cuánto, quizás incluso un factor de crecimiento (comience en K = 1.1 y aumente hasta 2) – Amro

Cuestiones relacionadas