2012-02-13 9 views
5

Quindi reserve è molto utile quando si ha un'idea approssimativa dei requisiti di dimensione. Qualcuno sa di un metodo simile per pre-allocare gli array in MATLAB?Pre-allocazione della memoria in MATLAB à la std :: vector :: reserve (n)

Io non sono veramente interessati a metodi hacky (ma efficaci) come la seguente:

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

potresti trovare questa risposta utile: http://stackoverflow.com/a/1549094/97160 – Amro

+0

@Amro: Sì, ottima risposta come sempre . Ma speravo che ci fosse qualche funzione "magica" di MATLAB che avevo trascurato. – Jacob

risposta

3

Il modo "hacky" è l'unico modo per farlo. Tuttavia, non è necessario controllare i i < = numel (x). La matrice sarà ampliato automaticamente (ma senza serie raddoppio):

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

EDIT: Per farla semplice, pur mantenendo la matrice raddoppio, è possibile scrivere una classe, o semplicemente un paio di funzioni di supporto (sotto).

EDIT2: l'utilizzo delle funzioni di supporto rallenterà le cose rispetto all'hack manuale. In MATLAB 2010 è ancora molto più veloce della crescita ingenua. In MATLAB 2011 l'approccio ingenuo è in realtà più veloce, suggerendo che questa versione ha un'assegnazione più intelligente. Forse è abbastanza veloce da non aver bisogno di nessun trucco. Grazie a Andrew Janke per averlo indicato.

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 

EDIT (da AndrewJanke)

Ecco il codice per confrontare la velocità delle implementazioni.

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

Il controllo nella domanda originale ha implementato un algoritmo per raddoppiare la dimensione dell'allocazione in overflow, con conseguente riallocazioni 'O (log (n)) '(4 in questo caso). La crescita naturale di Matlab cresce solo di un elemento alla volta, per 9000 riallocazioni in questo esempio. – Pursuit

+0

@ Inseguimento: esattamente. Questo è anche ciò che fa "reserve". – Jacob

+0

rasmus: -1 No. La funzione chiamata overhead (e probabile sconfitta delle ottimizzazioni sul posto del JIT) rende questa implementazione della funzione helper molto più lenta dell'espansione manuale di Jacob, o anche l'ingenuo non preallocato 'x = 0; per i = 1: n; x (i) = i; codice di fine'. Hai provato questo? In Matlab, e in altri linguaggi, è necessario considerare il costo delle operazioni e misurare effettivamente le prestazioni del codice che si ritiene sia un'ottimizzazione. Fare una lezione sarebbe anche peggio a causa di spese generali più elevate. –

0

C'è una via a riservare memoria per una struttura in MATLAB 7.6 (R2008a) utilizzando i comandi STRUCT e REPMAT.

ESEMPIO 1: Una struttura con due campi

s.field1 s.field2

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

ESEMPIO 2: Una struttura con un campo con un sottocampo

s.field1.subfield

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

ESEMPIO 3: Una serie di strutture

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

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

Questo non funziona. Guarda il numero di byte assegnati a 'v' con' whos v' mentre aggiungi dati ad esso; non è pre-assegnato Per esempio. 'whos v; v (1) .field1 = 10; whos v; v (2) .field1 = 20; whos v' – Jacob

1

la soluzione più pulita per l'esempio che hai fornito è quello di iterare indietro.

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

Questo non funziona nei casi in cui la dimensione finale è in realtà sconosciuta, ma è venuto in aiuto per me più spesso di quanto mi sarei aspettato.


Altrimenti solitamente implemento un algoritmo "doppio su overflow" come mostrato nella domanda originale.

La soluzione pulita consiste nel racchiudere una classe Matlab attorno a un algoritmo di ridimensionamento vettoriale rispettabile e quindi utilizzare tale classe. Non sono a conoscenza di alcun motivo per cui una tale classe non possa essere costruita, ma in realtà non mi sono mai seduto e ho cercato di implementarlo.(Sono curioso di sapere se un esempio esiste già nello scambio di file.)

+0

alcune implementazioni sono state suggerite da @woodchips qui: http://stackoverflow.com/a/3251547/ 97160 – Amro

Problemi correlati