Un giacobino approssimativo con differenze finite può causare instabilità nel metodo Newton?


13

Ho implementato un solutore all'indietro-Euler in Python 3 (usando numpy). Per mia comodità e come esercizio, ho anche scritto una piccola funzione che calcola un'approssimazione di differenza finita del gradiente in modo che non debba sempre determinare analiticamente il giacobino (se è anche possibile!).

Usando le descrizioni fornite in Ascher e Petzold 1998 , ho scritto questa funzione che determina il gradiente in un dato punto x:

def jacobian(f,x,d=4):
    '''computes the gradient (Jacobian) at a point for a multivariate function.

    f: function for which the gradient is to be computed
    x: position vector of the point for which the gradient is to be computed
    d: parameter to determine perturbation value eps, where eps = 10^(-d).
        See Ascher und Petzold 1998 p.54'''

    x = x.astype(np.float64,copy=False)
    n = np.size(x)
    t = 1 # Placeholder for the time step
    jac = np.zeros([n,n])
    eps = 10**(-d)
    for j in np.arange(0,n):
        yhat = x.copy()
        ytilde = x.copy()
        yhat[j] = yhat[j]+eps
        ytilde[j] = ytilde[j]-eps
        jac[:,j] = 1/(2*eps)*(f(t,yhat)-f(t,ytilde))
    return jac

Ho testato questa funzione prendendo una funzione multivariata per il pendolo e confrontando il simbolico giacobino con il gradiente determinato numericamente per un intervallo di punti. Sono rimasto soddisfatto dei risultati del test, l'errore era di circa 1e-10. Quando ho risolto l'ODE per il pendolo usando l'approssimativo giacobino, ha funzionato anche molto bene; Non sono riuscito a rilevare alcuna differenza tra i due.

Quindi ho provato a provarlo con il seguente PDE (equazione di Fisher in 1D):

tu=X(KXu)+λ(u(C-u))

usando una discretizzazione a differenza finita.

Ora il metodo di Newton esplode nel primo timestep:

/home/sfbosch/Fisher-Equation.py:40: RuntimeWarning: overflow encountered in multiply
  du = (k/(h**2))*np.dot(K,u) + lmbda*(u*(C-u))
./newton.py:31: RuntimeWarning: invalid value encountered in subtract
  jac[:,j] = 1/(2*eps)*(f(t,yhut)-f(t,yschlange))
Traceback (most recent call last):
  File "/home/sfbosch/Fisher-Equation.py", line 104, in <module>
    fisher1d(ts,dt,h,L,k,C,lmbda)
  File "/home/sfbosch/Fisher-Equation.py", line 64, in fisher1d
    t,xl = euler.implizit(fisherode,ts,u0,dt)
  File "./euler.py", line 47, in implizit
    yi = nt.newton(g,y,maxiter,tol,Jg)
  File "./newton.py", line 54, in newton
    dx = la.solve(A,b)
  File "/usr/lib64/python3.3/site-packages/scipy/linalg/basic.py", line 73, in solve
    a1, b1 = map(np.asarray_chkfinite,(a,b))
  File "/usr/lib64/python3.3/site-packages/numpy/lib/function_base.py", line 613, in asarray_chkfinite
    "array must not contain infs or NaNs")
ValueError: array must not contain infs or NaNs

Ciò accade per una varietà di valori eps, ma stranamente, solo quando la dimensione del passo spaziale PDE e la dimensione del passo temporale sono impostate in modo tale che la condizione Courant – Friedrichs – Lewy non sia soddisfatta. Altrimenti funziona. (Questo è il comportamento che ti aspetteresti se risolvi con Euler in avanti!)

Per completezza, ecco la funzione per il metodo Newton:

def newton(f,x0,maxiter=160,tol=1e-4,jac=jacobian):
    '''Newton's Method.

    f: function to be evaluated
    x0: initial value for the iteration
    maxiter: maximum number of iterations (default 160)
    tol: error tolerance (default 1e-4)
    jac: the gradient function (Jacobian) where jac(fun,x)'''

    x = x0
    err = tol + 1
    k = 0
    t = 1 # Placeholder for the time step
    while err > tol and k < maxiter:
        A = jac(f,x)
        b = -f(t,x)
        dx = la.solve(A,b)
        x = x + dx
        k = k + 1
        err = np.linalg.norm(dx)
    if k >= maxiter:
        print("Maxiter reached. Result may be inaccurate.")
        print("k = %d" % k)
    return x

(La funzione la.solve è scipy.linalg.solve.)

Sono fiducioso che la mia implementazione di Euler all'indietro sia in ordine, perché l'ho testata usando una funzione per il giacobino e ho ottenuto risultati stabili.

Nel debugger posso vedere che newton () gestisce 35 iterazioni prima che si verifichi l'errore. Questo numero rimane lo stesso per ogni eps che ho provato.

Un'osservazione aggiuntiva: quando computo il gradiente con FDA e una funzione usando la condizione iniziale come input e confrontando i due variando la dimensione di epsilon, l'errore cresce man mano che epsilon si restringe. Mi sarei aspettato che fosse grande all'inizio, poi diventasse più piccolo, poi di nuovo più grande man mano che epsilon si restringe. Quindi un errore nella mia implementazione del Jacobian è un presupposto ragionevole, ma in tal caso, è così sottile che non riesco a vederlo. EDIT: ho modificato jacobian () per usare forward invece di differenze centrali, e ora osservo lo sviluppo previsto dell'errore. Tuttavia, newton () non riesce ancora a convergere. Osservando dx nell'iterazione di Newton, vedo che cresce solo, non c'è nemmeno una fluttuazione: quasi raddoppia (fattore 1.9) ad ogni passo, con il fattore che diventa progressivamente più grande.

Ascher e Petzold menzionano che le approssimazioni delle differenze per il giacobino non sempre funzionano bene. Un giacobino approssimativo con differenze finite può causare instabilità nel metodo di Newton? O la causa è altrove? In quale altro modo potrei affrontare questo problema?


1
"Sono fiducioso che la mia implementazione di Euler all'indietro sia in ordine, perché l'ho testata usando una funzione per il giacobino e ho ottenuto risultati stabili." Si prega di precisare. Stai dicendo che hai lo stesso problema con un giacobino esatto e la soluzione converge alla soluzione esatta del PDE? Questa è un'informazione importante.
David Ketcheson,

@DavidKetcheson Sì, è quello che sto dicendo. Mi scuso se la mia terminologia è errata o incompleta. (Suppongo che avrei dovuto dire anche "ottengo risultati stabili e attesi")
Stephen Bosch,

Risposte:


3

Più di un lungo commento che altro:

Usando le descrizioni fornite in Ascher e Petzold 1998, ho scritto questa funzione che determina il gradiente in un dato punto x:

Guarda il codice per l'approssimazione del quoziente di differenza delle meridiane per avere un'idea migliore di cosa dovresti fare in un'implementazione. Ascher and Petzold è un buon libro per iniziare, ma SUNDIALS è effettivamente utilizzato nei lavori di produzione e quindi è stato testato meglio. (Inoltre, SUNDIALS è legato a DASPK, su cui Petzold ha lavorato.)

Ascher e Petzold menzionano che le approssimazioni delle differenze per il giacobino non sempre funzionano bene. Un giacobino approssimativo con differenze finite può causare instabilità nel metodo di Newton?

Empiricamente, i giacobini approssimativi possono causare fallimenti di convergenza nel metodo di Newton. Non so che li definirei come "instabilità"; in alcuni casi, non è possibile raggiungere le tolleranze di errore desiderate nei criteri di terminazione. In altri casi, potrebbe manifestarsi come instabilità. Sono quasi certo che ci sia un risultato più quantitativo su questo fenomeno nel libro sui metodi numerici di Higham, o nella discussione di Hairer e Wanner sui metodi W.

O la causa è altrove? In quale altro modo potrei affrontare questo problema?

Dipende da dove pensi che potrebbe essere l'errore. Se sei estremamente fiducioso nella tua implementazione di Eulero all'indietro, non inizierei da lì. L'esperienza mi ha reso paranoico nelle mie implementazioni di metodi numerici, quindi se fossi in me, inizierei codificando alcuni problemi di test davvero di base (un paio di problemi lineari rigidi e rigidi, l'equazione del calore con un'approssimazione di differenza finita centrata, cose del genere) e utilizzerei il metodo delle soluzioni fabbricate per assicurarmi di sapere quale sarà la soluzione e con cosa dovrei confrontarmi.

Tuttavia, ne hai già fatto un po ':

Sono fiducioso che la mia implementazione di Euler all'indietro sia in ordine, perché l'ho testata usando una funzione per il giacobino e ho ottenuto risultati stabili.

Sarebbe la prossima cosa che testerei: usare un giacobino analitico. Dopodiché, potresti anche guardare gli autovalori estremi della tua differenza finita giacobina nella remota possibilità di trovarti nella regione instabile di Eulero arretrato. Guardare gli autovalori estremi del tuo Jacobiano analitico come base per il confronto potrebbe darti un'idea. Supponendo che tutti provino, il problema è probabilmente nella soluzione di Newton.


Grazie per l'analisi ponderata (più il suggerimento SUNDIALS e le fonti alternative). Il mio professore ha suggerito di impostare lambda = 0, sostenendo che la FDA del PDE diventa lineare, quindi ci aspetteremmo che il Jacobiano della FDA sia uguale al Jacobiano analitico. Quando lo faccio, gestisce tre timestep, newton () colpendo ogni volta ogni volta, prima di esplodere come prima.
Stephen Bosch,

Ha anche affermato che non era pratica comune usare giacobiani approssimati per risolvere i PDE e ha suggerito che potrebbe avere problemi a causa dei molti gradi di libertà (senza fornire una spiegazione, sebbene abbia appena esaminato la discussione di Hairer e Wanner sui metodi W, Vedo che probabilmente non è banale).
Stephen Bosch,

1
La dichiarazione del tuo professore è alquanto sorprendente, data la quantità di letteratura sull'argomento, ad esempio questa famosa recensione di Knoll e Keyes . Probabilmente avrei dovuto citare questo articolo nella mia risposta, poiché le fonti nella bibliografia potrebbero anche essere di qualche aiuto nella diagnosi dei tuoi problemi.
Geoff Oxberry,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.