Pode um jacobiano aproximado com diferenças finitas causar instabilidade no método de Newton?

13

Eu implementei um solucionador de Euler para trás no python 3 (usando numpy). Para minha própria conveniência e como exercício, também escrevi uma pequena função que calcula uma aproximação de diferença finita do gradiente para que nem sempre seja necessário determinar analiticamente o jacobiano (se é que isso é possível!).

Usando as descrições fornecidas em Ascher e Petzold 1998 , escrevi esta função que determina o gradiente em um determinado ponto 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

Testei essa função usando uma função multivariada para o pêndulo e comparando o jacobiano simbólico ao gradiente determinado numericamente para uma série de pontos. Fiquei satisfeito com os resultados do teste, o erro foi em torno de 1e-10. Quando resolvi o ODE para o pêndulo usando o jacobiano aproximado, ele também funcionou muito bem; Não consegui detectar nenhuma diferença entre os dois.

Então tentei testá-lo com o seguinte PDE (equação de Fisher em 1D):

tvocê=x(kxvocê)+λ(você(C-você))

usando uma discretização por diferenças finitas.

Agora, o método de Newton explode no primeiro intervalo de tempo:

/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

Isso ocorre para uma variedade de valores eps, mas estranhamente, apenas quando o tamanho da etapa espacial do PDE e o tamanho da etapa do tempo são definidos para que a condição de Courant – Friedrichs – Lewy não seja atendida. Caso contrário, funciona. (Esse é o comportamento que você esperaria se resolvesse com o Euler avançado!)

Para completar, aqui está a função do 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

(A função la.solve é scipy.linalg.solve.)

Estou confiante de que minha implementação Euler para trás está em ordem, porque a testei usando uma função para o Jacobiano e obtenho resultados estáveis.

Eu posso ver no depurador que newton () gerencia 35 iterações antes que o erro ocorra. Esse número permanece o mesmo para todos os eps que tentei.

Uma observação adicional: quando computo o gradiente com o FDA e uma função usando a condição inicial como entrada e comparo os dois enquanto varia o tamanho do epsilon, o erro aumenta à medida que o epsilon diminui. Eu esperaria que fosse grande a princípio, depois diminuísse e depois aumentasse novamente à medida que o epsilon diminui. Portanto, um erro na minha implementação do jacobiano é uma suposição razoável, mas, se for, é tão sutil que não consigo vê-lo. EDIT: Modifiquei jacobian () para usar as diferenças avançadas em vez das centrais, e agora observo o desenvolvimento esperado do erro. No entanto, newton () ainda não converge. Observando dx na iteração de Newton, vejo que ela apenas cresce, não há sequer uma flutuação: quase dobra (fator 1.9) a cada passo, com o fator aumentando progressivamente.

Ascher e Petzold mencionam que as aproximações das diferenças para os jacobianos nem sempre funcionam bem. Pode um jacobiano aproximado com diferenças finitas causar instabilidade no método de Newton? Ou a causa está em outro lugar? De que outra forma eu poderia abordar esse problema?

Stephen Bosch
fonte
1
"Estou confiante de que minha implementação de Euler para trás está em ordem, porque a testei usando uma função para os jacobianos e obtenho resultados estáveis". Por favor, esclareça. Você está dizendo que executa o mesmo problema com um jacobiano exato e a solução converge para a solução exata do PDE? Essa é uma informação importante.
David Ketcheson
@DavidKetcheson Sim, é isso que estou dizendo. Desculpas se minha terminologia está incorreta ou incompleta. (Suponho que eu também deveria ter dito "Eu obtenho resultados estáveis ​​e esperados").
Stephen Bosch

Respostas:

3

Mais um longo comentário do que qualquer outra coisa:

Usando as descrições fornecidas em Ascher e Petzold 1998, escrevi esta função que determina o gradiente em um determinado ponto x:

Veja o código da aproximação do quociente de diferença da SUNDIALS para ter uma idéia melhor do que você deve fazer em uma implementação. Ascher e Petzold é um bom livro para começar, mas SUNDIALS é realmente usado no trabalho de produção e, portanto, foi melhor testado. (Além disso, SUNDIALS está relacionado ao DASPK, no qual Petzold trabalhou.)

Ascher e Petzold mencionam que as aproximações das diferenças para os jacobianos nem sempre funcionam bem. Pode um jacobiano aproximado com diferenças finitas causar instabilidade no método de Newton?

Empiricamente, os jacobianos aproximados podem causar falhas de convergência no método de Newton. Não sei se os caracterizaria como "instabilidade"; em alguns casos, simplesmente não é possível atingir as tolerâncias de erro desejadas nos critérios de encerramento. Em outros casos, pode se manifestar como uma instabilidade. Estou quase certo de que haja um resultado mais quantitativo sobre esse fenômeno no livro de métodos numéricos de Higham, ou na discussão de Hairer e Wanner sobre os métodos W.

Ou a causa está em outro lugar? De que outra forma eu poderia abordar esse problema?

Depende de onde você acha que o erro pode estar. Se você está extremamente confiante na implementação do Euler para trás, eu não começaria por aí. A experiência me deixou paranóica nas implementações de métodos numéricos; portanto, se fosse eu, começaria a codificar alguns problemas de teste realmente básicos (alguns problemas lineares não rígidos e rígidos, a equação do calor com uma aproximação de diferença finita centralizada, coisas assim) e eu usaria o método de soluções fabricadas para garantir a mim mesmo que sei qual será a solução e com o que devo comparar.

No entanto, você já fez algo disso:

Estou confiante de que minha implementação Euler para trás está em ordem, porque a testei usando uma função para o Jacobiano e obtenho resultados estáveis.

Essa seria a próxima coisa que eu testaria: use um jacobiano analítico. Depois disso, você também pode olhar para os autovalores extremas de sua diferença finita jacobiana com a pequena chance de estar na região instável de Euler retrógrado. Observar os autovalores extremas de seu jacobiano analítico como base de comparação pode fornecer algumas dicas. Supondo que todos verifiquem, o problema provavelmente está na resolução de Newton.

Geoff Oxberry
fonte
Obrigado pela análise cuidadosa (mais a dica SUNDIALS e as fontes alternativas). Meu professor sugeriu definir lambda = 0, argumentando que o FDA do PDE se torna linear, então esperamos que o Jacobiano do FDA seja igual ao Jacobiano analítico. Quando faço isso, ele gerencia três timesteps, newton () e atinge maxiter a cada vez, antes de finalmente explodir como antes.
Stephen Bosch
Ele também disse que não era uma prática comum usar jacobianos aproximados para resolver EDPs e sugeriu que poderia estar tendo problemas devido aos muitos graus de liberdade (sem fornecer uma explicação, apesar de ter acabado de examinar a discussão de Hairer e Wanner sobre os métodos W, Percebo que provavelmente não é trivial).
Stephen Bosch
1
A afirmação de seu professor é um tanto surpreendente, dada a quantidade de literatura sobre o assunto, por exemplo, esta famosa revisão de Knoll e Keyes . Provavelmente eu deveria ter citado este artigo na minha resposta, pois as fontes da bibliografia também podem ajudar no diagnóstico de seus problemas.
Geoff Oxberry