Matlab errore codice su calcolo di un punto critico con metodo di Newton

Angus1956
Allora il problema dice questo:



Il mio codice è questo:









Il problema è che mi da questo errore (e inoltre le iterate le calcola male dato che viene Nan):




Ma non capisco effettivamente dove sia l'errore, mi sono messo a rileggerlo e tutto ma non riesco a risolvere, qualcuno mi sa dire? Grazie.

Risposte
feddy
Il messaggio di errore ti sta dicendo che stai cercando di accedere alla seconda posizione, ma ciò non è consentito perché la size dell'array è 1.

Se vuoi avere una speranza che il tuo codice venga debuggato, copia e incollato qui usando gli appositi tag [code][/code] e inserendo il codice in mezzo, invece di copiare e incollare immagini (che sarebbe anche sconsigliato :) )

feddy
Nel secondo punto devi usare il teorema fondamentale del calcolo integrale

Angus1956
"feddy":
Nel secondo punto devi usare il teorema fondamentale del calcolo integrale

si infatti l ho usato, ora ti mando il codice, grazie

Angus1956
[quote="feddy"]Il messaggio di errore ti sta dicendo che stai cercando di accedere alla seconda posizione, ma ciò non è consentito perché la size dell'array è 1.

Se vuoi avere una speranza che il tuo codice venga debuggato, copia e incollato qui usando gli appositi tag
[/code] e inserendo il codice in mezzo, invece di copiare e incollare immagini (che sarebbe anche sconsigliato <!-- s:) --><img src="/datas/uploads/forum/emoji/icon_smile.gif" alt=":)" title="Smile" /><!-- s:) --> )[/quote]<br />
<br />
Questo è lo script:<br />
<br />
[code]g=@(t)(exp(-t).*(t-1));
m=15;
a=0;
b=5;
f=@(x)( (x(:,end)-0)/6/m.*( g(x(:,1))+2*sum(g(x(:,3:2:2*m)),2)+4*sum(g(x(:,2:2:2*m)),2)+g(x(:,2*m+1))) );
f1= @(x)(exp(-x).*(x-1));
k=0;
t=linspace(a,b,100);
for tt=t
    k=k+1; 
    x(k,:)=linspace(0,tt,2*m+1);
end
figure(1)
hold on
plot(t,f(x),'k','LineWidth',4)
tolf=1e-10;
tola=1e-10;
tolr=1e-10;
maxit=100;
x0=2;
[valmax]=minf(f1,x0,tolr,tola,tolf,maxit);
plot(valmax,f(valmax),'r')


Mentre questa è la funzione:

function [valmax]=minf(f1,x_0,tollr,tolla,tollf,maxit)
valmax=x_0;
h=1e-4;
y=f1(valmax);
d=2*h*y/(f1(valmax+h)-f1(valmax-h));
flag=2;
for k=1:maxit
    valmax=valmax-d;
    y=f1(valmax);
    res(k)=abs(y);
    if abs(y)<tollf, flag=0; return, end
    if abs(d)<tollr*abs(valmax)+tolla, flag=1; return, end
    d=2*h*y/(f1(valmax+h)-f1(valmax-h));
    display(valmax)
end

feddy
Cosa succede se selezioni $x_0=1.5$ come guess iniziale?

Qualche appunto "stilistico" che però risultano molto importanti quando si lavora:
-) Se condividi un codice, per quanto piccolo sia, assicurati che chi lo riceve possa essere in grado di farlo girare. In questo caso, mancava un end alla fine della function. Ovviamente non è stato un problema in questo caso, tuttavia in contesti più generali/complicati che ti troverai ad affrontare è fondamentale che quanto condiviso sia immediatamente in grado di girare, in modo da facilitare chi collabora con te.
-) Cercare di non riscrivere tutto da capo. Il metodo di Newton è qualcosa di generico, non andrebbe specializzato a casi particolari. In questo caso, chiunque sia un minimo del settore capisce che stai stimando la derivata prima con un rapporto incrementale. Tuttavia, una buona definizione di quella funzione dovrebbe prevedere il caso in cui l'utente voglia che la derivata prima sia stimata o no. Ovviamente la traccia dice altro ed è giusto che tu la segua. Inoltre, almeno dal punto di vista didattico può essere utilissimo riscrivere molte volte le stesse cose per imparare. Come dicevo prima, però, nella pratica è utile cercare di evitare di riscrivere funzioni identiche in modo da minimizzare la possibilità di errori.
-) Commenta. Non bisogna commentare compulsivamente ogni linea, però le parti più cruciali di un codice andrebbero descritte con parole chiave così che è chiaro a chi legge il tuo codice (MA soprattutto al te futuro) cosa stai facendo. Di nuovo, in questo caso non serve a chi legge visto che è qualcosa di "standard". Ma è bene tenerlo a mente.

Angus1956
Ho visto che mi da errore quando va a calcolare [code]f(valmax)[\code] alla fine, poichè dice index in position 2 exceeds array bounds. Index must not exceed 1.

feddy
Certo, l'errore è quello di prima. Ma controlla il valore di "valmax" ora. Non sarà più NaN

Angus1956
"feddy":
Certo, l'errore è quello di prima. Ma controlla il valore di "valmax" ora. Non sarà più NaN

si è vero, ora mi ha dato $0,5$ poi $0,8$ poi $0,9$ e infine $1$ che è il punto critico, ma come faccio a emttere il punto sul grafico $(valmax,f(valmax))$ se non me lo fa mettere?

feddy
Tu stai calcolando lo zero di $f1$, non di $f$... dunque credo dovresti mostrare la storia di convergence per $f1$. Ad ogni modo, il problema è che valmax è un double, mentre f prende una matrice come input (infatti scrivi x(:,etc)).

Oltretutto, quello che ti viene chiesto è un grafico dove in ascissa hai il numero di iterazione e in ordinata il residuo. Dunque dovresti salvarti la storia dei residui dentro il metodo di Newton. Ti torna?

Angus1956
"feddy":
Tu stai calcolando lo zero di $f1$, non di $f$... dunque credo dovresti mostrare la storia di convergence per $f1$. Ad ogni modo, il problema è che valmax è un double, mentre f prende una matrice come input (infatti scrivi x(:,etc)).

Oltretutto, quello che ti viene chiesto è un grafico dove in ascissa hai il numero di iterazione e in ordinata il residuo. Dunque dovresti salvarti la storia dei residui dentro il metodo di Newton. Ti torna?

Intendi il terzo punto che mi dice di mettere il punto $(x_k,f_k)$ nella figura 1? (che poi la storia dei residui l ho salvata infatti oh scritto
res(k)=abs(y)
però tu credo che stai parlando della parte 2, che effettivamente mi sono scordato di scrivere ma non era quello il problema.

feddy
No parlo del secondo punto, dove ti viene chiesta la Figura 2.

feddy
Il problema è che la tua $f$ è definita avendo in mente una quadratura composita. Per semplificarti la vita nel plot puoi definirla come

newfe1 = @(x) integral(g,0,x);

Questa chiaramente puoi valutarla per valmax. Ora sto viaggiando quindi non ho il tempo di scriverti una soluzione più elegante :)

Angus1956
Vabe in caso lo approssimo quel valore con una formula di quadratura, direi che può andar bene, sennò no saprei

feddy
il problema è che posso usare solo formule di quadratura (parlo per il corso) e non funzioni prestabilite, quindi devo per forza fare cosi...

D'accordo. In tal caso puoi definire f così:

function I = f(x)
%metodo di simpson per integrare g tra 0 e x
end


quindi per ogni valore scalare ritorna uno scalare, e in particolare puoi valutare f(valmax). Ad ogni modo è la parte più semplice dell'esercizio... a questo punto è più una questione di gusti che altro :-)

Angus1956
"feddy":

D'accordo. In tal caso puoi definire f così:

function I = f(x)
%metodo di simpson per integrare g tra 0 e x
end

Quindi tu dici di definire una funzione che mi approssima il valore di dell'integrale in un punto, ma poi dovrei crearci un vettore per fare il grafico? C'è come faccio a fare il grafico di $F$ con delle approssimazioni puntuali, faccio il plot per ogni coppia $(x,y)$? ma così non mi viene una funzione continua..., mentre se intendi di approssimare solo il valore $(x_k,f(x_k))$ allora sono d accordo perchè anche io ho detto cosi prima, ma basare l'intera funzione su approssimazioni puntuali invece che su handle di approssimazioni, non so se possa venire bene....

feddy
Se $x$ è il vettore di punti per i quali vuoi conoscere il valore di $F$, non vedo dove sia il problema. E' come quando vuoi plottare il grafico di $f(x)=\sin(x)$. Quello che scrviersti
plot(x,sin(x))


Ho fatto quanto intendevo nel seguente codice. Non sono abituato a scrivere codice MatLab e ho scritto in fretta dunque lo stile non è il migliore, ma l'output dovrebbe convincerti (In rosso il minimo)

clear all
close all

global g;
global m;
g=@(t)(exp(-t).*(t-1));
m=15;
a=0;
b=5;

x = linspace(0,5,100);
v = [];
for i=1:length(x)
    v = [v,f(x(i))];
end
plot(x,v,'*')
f1= @(x)(exp(-x).*(x-1));
tolf=1e-10;
tola=1e-10;
tolr=1e-10;
maxit=100;
x0=1.5;
[valmax]=minf(f1,x0,tolr,tola,tolf,maxit);
f(valmax)
hold on
plot(valmax,f(valmax),'*')


function [valmax]=minf(f1,x_0,tollr,tolla,tollf,maxit)
valmax=x_0;
h=1e-4;
y=f1(valmax);
d=2*h*y/(f1(valmax+h)-f1(valmax-h));
flag=2;
for k=1:maxit
    valmax=valmax-d;
    y=f1(valmax);
    res(k)=abs(y);
    if abs(y)<tollf, flag=0; return, end
    if abs(d)<tollr*abs(valmax)+tolla, flag=1; return, end
    d=2*h*y/(f1(valmax+h)-f1(valmax-h));
    display(valmax)
end
end

function I=f(x)
% Integra da 0 a x la funzione g
global g;
global m
h = ((x)/2)/m; 
xx = linspace(0,x,m);

I = 0;
for i = 1:m-1
    I = I + h/3*(g(xx(i)) + 4*g((xx(i)+xx(i+1))/2) + g(xx(i+1)));
end
end


feddy
Per completezza:


Angus1956
Ah ok, va bene.

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.