2012-02-13 6 views
5

Así que reserve es bastante útil cuando tiene una idea aproximada de los requisitos de tamaño. ¿Alguien sabe de un método similar para preasignar matrices en MATLAB?Preasignar memoria en MATLAB a la std :: vector :: reserve (n)

No estoy realmente interesado en métodos hacky (pero efectivo) como las siguientes:

x = zeros(1000,1); 
for i = 1:10000 
    if i > numel(x) 
     x = [x;zeros(size(x))]; 
    end 
    x(i) = rand; 
end 
x(i+1:end) = []; 
+2

puede encontrar esta respuesta útil: http://stackoverflow.com/a/1549094/97160 – Amro

+0

@Amro: Sí, gran respuesta como siempre . Pero esperaba que hubiera una función "mágica" de MATLAB que había pasado por alto. – Jacob

Respuesta

3

La forma "hacky" es la única manera de hacerlo. Sin embargo, no necesita verificar i < = numel (x). La gama se ampliará automáticamente (pero sin duplicar matriz):

x = zeros(1000,1); 
for i = 1:10000 
    x(i) = rand; 
end 
x(i+1:end) = []; 

EDIT: Para que sea sencillo al tiempo que conserva la matriz de duplicación, puede escribir una clase, o simplemente un par de funciones de ayuda (abajo).

EDIT2: El uso de las funciones de ayuda ralentizará las cosas en comparación con el hack manual. En MATLAB 2010, todavía es mucho más rápido que el crecimiento ingenuo. En MATLAB 2011, el enfoque ingenuo es realmente más rápido, lo que sugiere que esta versión tiene una asignación más inteligente. Quizás es lo suficientemente rápido para que no se necesite ningún hack. Gracias a Andrew Janke por señalar esto.

function listtest() 
    n = 10000; 
    l = new_list(); 
    for i=1:n 
     l = list_append(l, i); 
    end 
    a = list_to_array(l); 
end 

function l = new_list() 
    l = [0 0]; 
end 
function l = list_append(l, e) 
    if l(1)+1 == length(l) 
     l(length(l)*2) = 0; 
    end 
    l(1) = l(1)+1; 
    l(l(1)+1) = e; 
end 
function a = list_to_array(l) 
    a = l(2:1+l(1)); 
end 

EDITAR (de AndrewJanke)

Aquí está el código para comparar la velocidad de las implementaciones.

function manual_reserve_example(n) 
x = zeros(1000,1); 
for i = 1:n 
    if i > numel(x) 
     x = [x;zeros(size(x))]; 
    end 
    x(i) = i; 
end 
x(i+1:end) = []; 
end 

function naive_growth(n) 
x = 0; 
for i = 1:n 
    x(i) = i; 
end 
end 

function compare_them(n) 
fprintf('Doing %d elements in Matlab R%s\n', n, version('-release')); 
tic; 
naive_growth(n); 
fprintf('%30s %.6f sec\n', 'naive_growth', toc); 
tic; 
manual_reserve_example(n); 
fprintf('%30s %.6f sec\n', 'manual_reserve', toc); 
tic; 
listtest(n); 
fprintf('%30s %.6f sec\n', 'listtest', toc); 
end 
+2

La comprobación en la pregunta original implementó un algoritmo para duplicar el tamaño de asignación en el desbordamiento, lo que resulta en reasignaciones 'O (log (n))' (4 en este caso). El crecimiento natural de Matlab solo crece un elemento a la vez, para 9000 reasignaciones en este ejemplo. – Pursuit

+0

@Pursuit: Exactamente. Esto es lo que 'reserva 'también. – Jacob

+0

rasmus: -1 No. La sobrecarga de llamada de función (y la probable derrota de las optimizaciones en contexto del JIT) hace que esta implementación de la función auxiliar sea mucho más lenta que la expansión manual de Jacob, o incluso el 'x = 0 no preinstalado ingenuo; para i = 1: n; x (i) = i; código final ¿Has probado esto? En Matlab, y en otros idiomas, debe considerar el costo de las operaciones y realmente medir el rendimiento del código que considera una optimización. Hacer una clase sería aún peor debido a una mayor sobrecarga. –

0

Hay una manera de asignar previamente memoria para una estructura en MATLAB 7.6 (R2008a) usando los comandos STRUCT y REPMAT.

Ejemplo 1: Una estructura con dos campos

s.field1 s.field2

s = struct('field1',cell(1),'field2',cell(1)); 

Ejemplo 2: una estructura con un campo con un subcampo

s.field1.subfield

s = struct('field1',struct('subfield',cell(1))); 

EJEMPLO 3: Una matriz de estructuras

v (1) .field1 ... v (100) .field1

s = struct('field1',cell(1)); 
v = repmat(s,100,1); 
+0

Eso no funciona. Mire la cantidad de bytes asignados a 'v' con' whos v' mientras agrega datos; no está preasignado P.ej. 'whos v; v (1) .field1 = 10; whos v; v (2) .field1 = 20; whos v' – Jacob

1

La solución más limpia para el ejemplo que ha proporcionado es para recorrer hacia atrás.

for i = 10000:-1:1 
    x(i) = rand; 
end 

Esto no funciona en los casos en que el tamaño final es en realidad desconocida, pero ha sido muy útil para mí más a menudo de lo que hubiera esperado.


De lo contrario, generalmente implemento un algoritmo de "doble desbordamiento" como se muestra en la pregunta original.

La solución limpia es envolver una clase Matlab alrededor de un algoritmo respetable de tamaño de vector, y luego usar esa clase. No tengo conocimiento de ninguna razón por la cual no se pueda construir una clase de este tipo, pero nunca me senté e intenté implementarla.(Tengo curiosidad si ya existe un ejemplo en el intercambio de archivos en algún lugar.)

+0

algunas implementaciones fueron sugeridas por @woodchips aquí: http://stackoverflow.com/a/3251547/ 97160 – Amro

Cuestiones relacionadas