¿Puede un jacobiano aproximado con diferencias finitas causar inestabilidad en el método de Newton?

13

He implementado un solucionador de Euler hacia atrás en Python 3 (usando numpy). Para mi propia conveniencia y como ejercicio, también escribí una pequeña función que calcula una aproximación de diferencia finita del gradiente para que no siempre tenga que determinar el jacobiano analíticamente (¡si es posible!).

Usando las descripciones proporcionadas en Ascher y Petzold 1998 , escribí esta función que determina el gradiente en un punto dado 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

Probé esta función tomando una función multivariada para el péndulo y comparando el jacobiano simbólico con el gradiente determinado numéricamente para un rango de puntos. Estaba satisfecho con los resultados de la prueba, el error fue de alrededor de 1e-10. Cuando resolví el ODE para el péndulo usando el jacobiano aproximado, también funcionó muy bien; No pude detectar ninguna diferencia entre los dos.

Luego intenté probarlo con la siguiente PDE (ecuación de Fisher en 1D):

ttu=X(kXtu)+λ(tu(C-tu))

utilizando una discreta diferenciación finita.

Ahora el método de Newton explota en el primer paso:

/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

Esto sucede para una variedad de valores de eps, pero extrañamente, solo cuando el tamaño de paso espacial PDE y el tamaño de paso de tiempo se establecen de modo que no se cumpla la condición de Courant-Friedrichs-Lewy. De lo contrario, funciona. (¡Este es el comportamiento que esperarías si resolvieras con Euler adelante!)

Para completar, aquí está la función para el Método 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 función la.solve es scipy.linalg.solve).

Estoy seguro de que mi implementación anterior de Euler está en orden, porque la he probado usando una función para el jacobiano y obtengo resultados estables.

Puedo ver en el depurador que newton () gestiona 35 iteraciones antes de que ocurra el error. Este número sigue siendo el mismo para cada eps que he probado.

Una observación adicional: cuando calculo el gradiente con la FDA y una función usando la condición inicial como entrada y comparo los dos al variar el tamaño de épsilon, el error crece a medida que épsilon se reduce. Al principio, esperaría que fuera grande, luego más pequeño y luego más grande a medida que el épsilon se encoge. Entonces, un error en mi implementación del Jacobian es una suposición razonable, pero si es así, es tan sutil que no puedo verlo. EDITAR: Modifiqué jacobian () para usar adelante en lugar de las diferencias centrales, y ahora observo el desarrollo esperado del error. Sin embargo, newton () todavía no puede converger. Al observar dx en la iteración de Newton, veo que solo crece, ni siquiera hay una fluctuación: casi se duplica (factor 1.9) con cada paso, con el factor cada vez más grande.

Ascher y Petzold mencionan que las aproximaciones de diferencia para el jacobiano no siempre funcionan bien. ¿Puede un jacobiano aproximado con diferencias finitas causar inestabilidad en el método de Newton? ¿O es la causa en otro lugar? ¿De qué otra forma podría abordar este problema?

Stephen Bosch
fuente
1
"Estoy seguro de que mi implementación anterior de Euler está en orden, porque la probé usando una función para el jacobiano y obtuve resultados estables". Por favor aclarar ¿Está diciendo que tiene el mismo problema con un jacobiano exacto y que la solución converge con la solución exacta del PDE? Esa es información importante.
David Ketcheson
@DavidKetcheson Sí, eso es lo que estoy diciendo. Disculpas si mi terminología es incorrecta o incompleta. (Supongo que también debería haber dicho "obtengo resultados estables y esperados")
Stephen Bosch,

Respuestas:

3

Un comentario más largo que cualquier otra cosa:

Usando las descripciones proporcionadas en Ascher y Petzold 1998, escribí esta función que determina el gradiente en un punto dado x:

Mire el código para la aproximación del cociente de diferencia de SUNDIALS para tener una mejor idea de lo que debe hacer en una implementación. Ascher and Petzold es un buen libro para comenzar, pero SUNDIALS se usa realmente en el trabajo de producción y, por lo tanto, se ha probado mejor. (Además, SUNDIALS está relacionado con DASPK, en el que trabajó Petzold).

Ascher y Petzold mencionan que las aproximaciones de diferencia para el jacobiano no siempre funcionan bien. ¿Puede un jacobiano aproximado con diferencias finitas causar inestabilidad en el método de Newton?

Empíricamente, los jacobianos aproximados pueden causar fallas de convergencia en el método de Newton. No sé si los caracterizaría como "inestabilidad"; en algunos casos, simplemente no es posible lograr las tolerancias de error deseadas en los criterios de terminación. En otros casos, podría manifestarse como una inestabilidad. Estoy casi seguro de que hay un resultado más cuantitativo en este fenómeno en el libro de métodos numéricos de Higham, o en la discusión de Hairer y Wanner sobre los métodos W.

¿O es la causa en otro lugar? ¿De qué otra forma podría abordar este problema?

Depende de dónde creas que podría estar el error. Si tienes mucha confianza en tu implementación de Euler hacia atrás, no comenzaría allí. La experiencia me ha vuelto paranoico en mis implementaciones de métodos numéricos, por lo que si fuera yo, comenzaría codificando algunos problemas de prueba realmente básicos (un par de problemas lineales rígidos y no rígidos, la ecuación de calor con una aproximación de diferencia finita centrada, cosas así) y usaría el método de soluciones fabricadas para asegurarme de que sé cuál será la solución y contra qué debería compararme.

Sin embargo, ya has hecho algo de eso:

Estoy seguro de que mi implementación anterior de Euler está en orden, porque la he probado usando una función para el jacobiano y obtengo resultados estables.

Eso sería lo siguiente que probaría: usar un jacobiano analítico. Después de eso, también puede observar los valores propios extremos de su diferencia finita jacobiana en caso de que se encuentre en la región inestable de Euler atrasado. Mirar los valores propios extremos de su analítico jacobiano como base para la comparación podría darle una idea. Suponiendo que todos revisen, el problema probablemente esté en la solución de Newton.

Geoff Oxberry
fuente
Gracias por el análisis reflexivo (más la sugerencia SUNDIALS y las fuentes alternativas). Mi profesor sugirió establecer lambda = 0, argumentando que la FDA del PDE se vuelve lineal, por lo que esperaríamos que la FDA Jacobian sea igual a la analítica Jacobian. Cuando hago esto, maneja tres veces, newton () golpea el maxitro cada vez, antes de explotar finalmente como antes.
Stephen Bosch
También dijo que no era una práctica común usar jacobianos aproximados para resolver PDEs y sugirió que podría estar teniendo problemas debido a los muchos grados de libertad (sin proporcionar una explicación, aunque solo había visto la discusión de Hairer y Wanner sobre los métodos W, Puedo ver que probablemente no sea trivial).
Stephen Bosch
1
La declaración de su profesor es algo sorprendente, dada la cantidad de literatura sobre el tema, por ejemplo, esta famosa revisión de Knoll y Keyes . Probablemente debería haber citado este documento en mi respuesta, ya que las fuentes en la bibliografía también pueden ser de alguna ayuda para diagnosticar sus problemas.
Geoff Oxberry