Avaliação numérica da integral altamente oscilatória

11

Em deste curso avançado sobre aplicações da teoria de função complexa em um ponto em um exercício integral altamente oscilatório

I(λ)=cos(λcosx)sinxxdx

deve ser aproximado para grandes valores de usando o método do ponto de sela no plano complexo.λ

Devido à sua natureza altamente oscilatória, é muito difícil avaliar essa integral usando a maioria dos outros métodos. Estes são dois fragmentos do gráfico do integrando para em escalas diferentes:λ=10

cos (10 cos (x)) sin (x) / x

Uma aproximação assintótica de ordem principal é

I1(λ)=cos(λ14π)2πλ

e um refinamento adicional (muito menor) adiciona o termo

I2(λ)=18sin(λ14π)2πλ3

Um gráfico dos valores aproximados em função de tem a seguinte aparência:λ

I (lambda) aprox.

Agora vem a minha pergunta: para ver visualmente quão boa é a aproximação, eu gostaria de compará-la com o "valor real" da integral ou, mais precisamente, com uma boa aproximação à mesma integral usando um algoritmo independente. Devido à pequenez da correção subliminar, eu esperaria que isso fosse bem próximo.

Tentei avaliar a integral para alguns usando outros algoritmos, mas com muito pouco sucesso: o Mathematica e o Matlab, usando o integrador numérico padrão, não conseguem produzir um valor significativo (e relatam isso explicitamente), mpmath usando os dois pontos de exponencial substituição e o método Gauss-Legendre produzem resultados muito ruidosos, embora tenha uma leve tendência a oscilar em torno dos valores que o método do ponto de sela fornece, pois esse gráfico pode mostrar:λtanh(sinh)

mpmath approx

Finalmente, tentei a sorte com um integrador de Monte-Carlo usando um exemplo de importância que implementei, mas também não consegui obter resultados estáveis.

Alguém tem uma idéia de como essa integral pode ser avaliada independentemente para qualquer valor fixo de ou menos?λ>1

doetoe
fonte
A função é uniforme?
nicoguaro
Sim, é até
doetoe 04/06/19
Você já tentou transformar sua integral em uma ODE?
nicoguaro
1
Não, a diferenciação escreve e, em seguida, resolve a equação diferencial numericamente. x
nicoguaro
1
Seu primeiro gráfico parece mostrar uma função diferente do seu integrando. Nomeadamente, parece que substituído por . Ou seja, o enredo é da funçãoλλxx(cos(λxcosx)sincx)
Ruslan

Respostas:

12

Use o teorema de Plancherel para avaliar esta integral.

A idéia básica é que, para duas funções ,f,g

I=f(x)g(x)dx=F(k)G(k)dk

onde são as transformadas de Fourier de . Suas funções têm suporte relativamente pequeno no domínio espectral. Aqui, e devem ter uma transformação analítica de Fourier (ou série), como a expansão Jacobi-Anger . Você pode truncar a série infinita em termos aproximadamente devido ao decaimento função Besselpara. Espero que isto ajude.F,Gf,gsinx/xrect(k)cos(λcosx)λ|Jn(x)|n>|x|

Editar : Na verdade, você deve usar as representações da série Fourier aqui em vez das transformações. O caminho da transformação leva a derivar a representação assintótica que você já possui (acontece que é apenas ). O teorema de Plancherel acima também funciona para as séries de Fourier com um domínio de integração de na última integral.πJ0(λ)[0,2π]

smh
fonte
Obrigado, esta é uma ideia muito boa!
doetoe
7

A chave para a avaliação das integrais oscilatórias é truncar a integral no ponto certo. Neste exemplo, você precisa escolher o limite superior do formulário Antes de explicar por que deve funcionar, deixe-me mostrar primeiro que ele realmente produz bons resultados.

πN+π2

Assintóticos

É fácil adivinhar que séries assintóticas têm a forma Para verificar numericamente se é suficiente traçar a diferença entre uma expressão assintótica integral e principal.

I(λ)2πλ[cos(λπ4)+c1sin(λπ4)λ+c2cos(λπ4)λ2+c3sin(λπ4)λ3+]
c1=18

int := NIntegrate[Cos[l*Cos[x]]*Sinc[x], {x, 0, 20.5*Pi}]; 
Plot[{l*(Sqrt[2*l/Pi]*int - Cos[l-Pi/4]), Sin[l-Pi/4]/8}, {l, Pi/4, 20}]

Como resultado, você obtém um seno bastante agradável, que coincide com o que você derivou acima.

18

Se você deseja encontrar os seguintes coeficientes, um pedaço de código um pouco mais sofisticado, se necessário. A idéia do código abaixo é usar vários valores-limite superiores altos e "mediar" seus resultados.

J[l_?NumericQ] := Block[{n=500},
  f[k_] := NIntegrate[Cos[l*Cos[x]]*Sinc[x], {x,0,(n+k)*Pi+Pi/2},
  Method->{"DoubleExponential"}, AccuracyGoal->14, MaxRecursion->100];
  1/2*((f[0]+f[1])/2+(f[1]+f[2])/2)
]
t = Table[{l, l^2*(Sqrt[2*l/Pi]*J[l] - Cos[l-Pi/4] - 1/8*Sin[l-Pi/4]/l)}, 
    {l, 4*Pi+Pi/4, 12*Pi+Pi/4, Pi/36}];
Fit[t, Table[Cos[l-Pi/4+Pi/2*n]/l^n, {n, 0, 10}], l]

Isso produz a seguinte resposta.

c2=9128,c3=751024,c4=367532768,

Explicação

Exemplo simples

Para a ilustração, vou usar um exemplo mais simples da integral senoidal Deixe-me imaginar que estou interessado no valor , mas não o conheço.

S(x)=0xsin(y)ydy.
S()=π2

seno

Você vê que oscila em torno de seu valor limite de forma semelhante à soma parcial de alternância na série de sinais oscila com o corte superior. Quando você deseja estimar essa soma, de acordo com o método de aceleração da série Euler, você deve tomar Ou em termos de função seno-integral, você deve integrá-lo até o ponto entre o máximo e o mínimo de oscilações. Como é claramente visto no gráfico, esse ponto é dado aproximadamente por para grandes valores de argumento. De maneira mais geral, esse ponto é aquele em queocorre.S(x)

SN=n=1N(1)nn.
SSN+12(1)N+1N+1.
S(x)0πN+π2sinxxdx
max|S(x)|

Seu problema

Voltando à integral do curso de Konstantin e Yaroslav, você pode ver que ela se comporta exatamente da mesma maneira que o seno - integral como uma função do limite superior. Isso significa que você só precisa calcular os valores com . Abaixo está o gráfico de vários desses valores com .

Ix0(λ)=20x0cos(λcos(x))sinc(x)dx
x0=πN+π2λ=12π

tab = Table[{x0, 2*NIntegrate[Cos[12*Pi*Cos[x]]*Sinc[x], {x, 0, x0}, 
     Method->{"DoubleExponential"}, AccuracyGoal->12, MaxRecursion->100]},
    {x0, 10*Pi+Pi/2, 30*Pi+Pi/2, Pi}];
tab1 = Table[(tab[[i]] + tab[[i+1]])/2, {i,1,Length[tab]-1}];
ListPlot[{tab, tab1}]

acc

Aqui você pode ver o resultado de outro método de aceleração. Reorganizo somas parciais da seguinte maneira e obtenho uma nova sequência que converge muito mais rapidamente. Esse truque também é útil se você deseja avaliar a integral com alta precisão.

SN=12(SN+SN+1)
SN

David Saykin
fonte
Agradável! Os instrutores do curso são seus professores da vida real? Seu curso é fantástico, embora muito difícil e em ritmo acelerado
doetoe
@doetoe sim, eu sou um estudante da Konstantin. Ele compartilhou comigo um link para sua pergunta.
precisa saber é o seguinte
6

O método de Ooura para integrais senoidais de Fourier funciona aqui, veja:

Ooura, Takuya e Masatake Mori, uma fórmula exponencial dupla e robusta para integrais do tipo Fourier. Jornal de matemática computacional e aplicada 112.1-2 (1999): 229-241.

Eu escrevi uma implementação desse algoritmo, mas nunca trabalhei para obtê-lo rapidamente (digamos, nós / pesos de cache), mas mesmo assim, estou obtendo resultados consistentes em tudo além da precisão de flutuação:

float     = 0.0154244
double    = 0.943661538060268
long dbl  = 0.943661538066058702
quad      = 0.943661538066060288748574485677942
oct       = 0.943661538066060288748574485680878906503533004997613278231689169604876
asymptotic= 0.944029734

Aqui está o código:

#include <iostream>
#include <boost/math/quadrature/ooura_fourier_integrals.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/multiprecision/float128.hpp>
#include <boost/multiprecision/cpp_bin_float.hpp>

template<class Real>
Real asymptotic(Real lambda) {
    using std::sin;
    using std::cos;
    using boost::math::constants::pi;
    Real I1 = cos(lambda - pi<Real>()/4)*sqrt(2*pi<Real>()/lambda);
    Real I2 = sin(lambda - pi<Real>()/4)*sqrt(2*pi<Real>()/(lambda*lambda*lambda))/8;
    return I1 + I2;
}

template<class Real>
Real osc(Real lambda) {
    using std::cos;
    using boost::math::quadrature::ooura_fourier_sin;
    auto f = [&lambda](Real x)->Real { return cos(lambda*cos(x))/x; };
    Real omega = 1;
    Real Is = ooura_fourier_sin<decltype(f), Real>(f, omega);
    return 2*Is;
}

template<class Real>
void print(Real val) {
   std::cout << std::defaultfloat;
   std::cout << std::setprecision(std::numeric_limits<Real>::digits10);
   std::cout <<  val <<  " = " << std::hexfloat << val;
}

int main() {
    using boost::multiprecision::float128;
    float128  s = 7;
    std::cout << "Asymptotic = " << std::setprecision(std::numeric_limits<float128>::digits10) << asymptotic(s) << "\n";
    std::cout << "float precision = ";
    print(osc(7.0f));
    std::cout << "\n";
    std::cout << "double precision= ";
    print(osc(7.0));
    std::cout << "\n";
    std::cout << "long double     = ";
    print(osc(7.0L));
    std::cout << "\n";
    print(osc(s));

    print(osc(boost::multiprecision::cpp_bin_float_oct(7)));
    std::cout << "\n";
}

Você realmente não consegue ver a diferença entre a quadratura e o assintótico, porque eles ficam um em cima do outro, exceto como : λ0insira a descrição da imagem aqui

user14717
fonte
Obrigado, isso é muito bom! Ainda não o fiz funcionar, minha instalação do impulso não é compatível, mas estou baixando a versão mais recente agora.
doetoe
Só para ter certeza: em 23 você tem cos (lambda * cos (x)) / x, sem o fator sin (x) do integrando. É ooura_fourier_sin que assume esse fator sin (x) para multiplicar o integrando passado a ele?
doetoe
Eu consegui funcionar. Ele e suas dependências parecem ser apenas de cabeçalho, então nem precisei instalar ou compilar (exceto o executável). Espero que seja incluído no impulso!
doetoe
@doetoe: Sim, o fator está implícito e incorporado aos pesos da quadratura. Estou pensando em acelerar, refatorando-o para armazenar em cache os nós e pesos; veremos! sin(x)
user14717
@doetoe: Foi mesclado no Boost 1.71. A API é um pouco diferente do que essa resposta fornece.
user14717