% Questo programma consiste di due parti, la prima riordina un set di n numeri usando un metodo % basato sul confronto tra coppie (ordine quadratico) ed un secondo metodo che sfrutta % il partizionamento (ordine nlog(n)). Questo viene fatto per diversi valori di n. % Nella seconda parte, per ciascun metodo vengono stimati i parametri di un modello teorico % per il costo computazionale del metodo in funzione di n e vengono plottati i due modelli % assieme ai costi misurati. % Commenti a cura di Luigi Lunardon e Vittorio Maio clear close all m=10; for jl=1:m n=100*jl num(jl)=n; x=rand(1,n); zx=x; % In questo specifico caso riordineremo m vettori creati in maniera random formati da un numero di elementi che % varia da 100 a 100*m. Nel vettore zx salviamo il vettore x in modo da utilizzare per ogni n % lo stesso set di numeri con entrambi i metodi. % Metodo basato sul confronto tra coppie tic % Calcoliamo il costo computazionale for i=1:n-1 imin1=find(x==min(x)); imin=min(imin1); y(i)=min(x); w=ones(length(x)-1,1); kk=1; for k=1:length(x) if k == imin else w(kk)=x(k); kk=kk+1; end end x=w; end y(n)=x; tempo1(jl)=toc; % salviamo in tempo1 il tempo di calcolo x=zx; % Metodo basato sul partizionamento tic % Calcoliamo il costo computazionale % L'idea del metodo di partizionamento e' quella di operare ricorsivamente la divisione % dei numeri di un insieme in due sottinsiemi: da un lato gli elementi <= di un certo % valore e nell'altro quelli > (in questo programma l'elemento di confronto e' la media % aritmetica dei numeri). Il costo computazionale medio e' ridotto a n*log(n). Il codice seguente % utilizza la funzione part, da noi preparata e salvata col nome di part.m. L'input di part % e' un vettore x di numeri. L'output e' un vettore xx con le stesse dimensioni, le cui % prime k componenti contengono le componenti di x minori o uguali alla soglia, mentre le % restanti componenti sono le rimanenti componenti di x. In output part fornisce anche il valore % di k. Data la partizione corrente degli n numeri, quella successiva viene costruita applicando % la funzione part a ciascun elemento della partizione. [xx nn]=part(x); k=2; % numero iniziale di elementi della partizione kold=1; index=zeros(1,3); index(2)=nn; index(3)=n; % posizioni degli estremi sinistri-1 degli elementi della partizione corrente. % index e' un vettore la cui componente i indica che l'elemento i della partizione corrente % ha inizio nella posizione i+1. L'ultima componente di index e' sempre n. Il metodo ha bisogno % di un criterio di arresto. Percio' non possiamo usare un ciclo for, ma usiamo un ciclo while. % Il ciclo while in matlab lavora esattamente come in C, all'inizio del ciclo verifica una certa % condizione e se e' vera continua il ciclo. Il criterio d'arresto e' qui che la partizione prima e % dopo un'iterazione non cambi numero di elementi. while k>kold kold=k; index1=zeros(1); x=xx; kk=1; % contatore degli elementi della partizione successiva for j=1:k % loop sugli elementi della partizione corrente z=x(index(j)+1:index(j+1)); % vettore dell'elemento j della partizione corrente if max(z)>min(z) %Se z non ha gli elementi tutti uguali, viene applicata part [zz nn]=part(z); index1(kk+1)=index(j)+nn; index1(kk+2)=index(j+1); % posizioni degli estremi sinistri-1 degli elementi della partizione successiva kk=kk+2; % abbiamo diviso l'elemento j della partizione corrente in due else zz=z; index1(kk+1)=index(j+1); % non abbiamo diviso l'elemento j della partizione corrente in due kk=kk+1; end xx(index(j)+1:index(j+1))=zz; % Sostituiamo il vettore z dell'elemento j della partizione corrente con quello diviso in due (zz). end k=kk-1; % nuovo numero di elementi della partizione index=index1; end tempo2(jl)=toc; % salviamo in tempo2 il tempo di calcolo cc(jl)= sum(abs(xx-y)); end sum(cc) % verifica che i due metodi danno lo stesso risultato plot(num,tempo1,'+') hold on plot(num,tempo2,'*') % Abbiamo plottato sullo stesso grafico i tempi corrispondenti al riordinamento di un vettore % prima con il primo metodo e poi con il secondo. Si tratta ora di determinare il modello teorico % del tempo impiegato versus n. Per fare cio' useremo un fit non lineare ossia un'interpolazione dei dati % sperimentali che sfrutta la conoscenza a priori del modello teorico non lineare (in questo caso % in realta' i due modelli sono lineari, ma utilizziamo lo stesso il fit non lineare per scopi % didattici). Vediamo come funziona il comando nlinfit: nlinfit(indip, dip, @model, beta). % indip e dip sono rispettivamente i vettori con i valori della variabile indipendente e % dipendente della funzione non lineare. model e' una funzione matlab da noi definita con cui, %a partire dal vettore dei valori della variabile indipendente e di quello dei parametri (beta), % si ottiene il vettore dei valori della variabile dipendente. Il metodo di minimizzazione % alla base di nlinfit e' locale e richiede l'inizializzazione dei valori dei parametri (vettore % beta). La funzione nlinfit da' come output il vettore beta con i suoi valori ottimali (quelli % che minimizzano la somma degli scarti tra i valori sperimentali della variabile dipendente % e quelli calcolati col modello teorico a partire dai valori della variabile indipendente). beta(1)=tempo2(m)/num(m)/log(num(m)); % inizializzazione del parametro del modello beta=nlinfit(num, tempo2, @model2, beta); zzz=linspace(num(1), num(m), 1000); yyy=model2(beta, zzz); beta(1)=tempo1(m)/num(m)^2; beta(2)=0; % inizializzazione dei parametri del modello beta=nlinfit(num, tempo1, @model1, beta); xxx=model1(beta, zzz); % Calcolate le interpolanti non resta che plottarle. plot(zzz, xxx) plot(zzz, yyy) print -dpdf plot1.pdf %-------------------------------------------------------------------------------------- % mettere in un file chiamato part.m % Quella di seguito e' una funzione MATLAB da noi costruita. Le funzioni sono sequenze di % comandi esterne al main e strutturate per adempiere ad un compito specifico. Le funzioni vengono % scritte, salvate come file nome_funzione.m e poi richiamate all'interno del main, scrivendo % output=nome_funzione(input). Le variabili interne alla funzione sono chiamate variabili % locali e non sono visibili nel main se non sono di output. La funzione qui di seguito ha in % input un vettore x, ed in output un vettore y ottenuto come partizione di x. % Le prime k componenti di y sono i valori di x minori o uguali della media delle componenti di x % mentre le restanti componenti hanno valore maggiore della media. In output abbiamo anche % il valore di k. % La sintassi usata per definire una funzione e' la seguente: %function [valori di output non separati da virgole]=nome_funzione(elementi dell'imput separati % da virgole) function [y n1] = part(x) m=min(x); M=max(x); % Le funzioni max(x) e min(x) restituiscono rispettivamente il massimo e il minimo valore di un % vettore x. p=(M+m)/2; if m < M % non facciamo nessuna operazione se gli elementi di x sono tutti uguali fra loro. % Altrimenti per prima cosa salviamo nel vettore i1 le posizioni delle componenti di x che sono % minori o uguali a p. Per questo utilizziamo il comando find(x<=p). Il comando find ha come % argomento la condizione richiesta e crea il vettore con le posizioni delle componenti % che la soddisfano. i1=find(x<=p); x1=x(i1); % Scriviamo il vettore x1 che ha come elementi gli elementi di x che % si trovano nelle posizioni indicate da i1. n1=length(x1); i2=find(x>p);% Ripetiamo lo stesso procedimento per creare il vettore x2 x2=x(i2); y=[ x1 x2]; % scriviamo il vettore y come concatenazione dei due. else y=x; 'ATTENZIONE dati tutti uguali' end %-------------------------------------------------------------------------------------- % mettere in un file chiamato model1.m function yy=model(beta,ttt) yy=beta(1)*ttt.^2+beta(2)*ttt; %-------------------------------------------------------------------------------------- % mettere in un file chiamato model2.m function yy=model(beta,ttt) yy=beta(1)*ttt.*log(ttt);