Introdução à Matemática Numérica
Este é o "Olá, mundo!" de PDEs (Equações Diferenciais Parciais). A equação de Laplace ou difusão aparece frequentemente em física, por exemplo, equação de calor, deformação, dinâmica de fluidos, etc ... Como a vida real é 3D, mas queremos dizer "Olá, mundo!" e não cantar "99 garrafas de cerveja, ...", esta tarefa é dada em 1D. Você pode interpretar isso como uma túnica de borracha amarrada a uma parede nas duas extremidades com alguma força aplicada a ela.
Em um [0,1]
domínio, encontre uma função u
para determinada função de origem f
e valores de limite u_L
e de u_R
forma que:
-u'' = f
u(0) = u_L
u(1) = u_R
u''
denota a segunda derivada de u
Isso pode ser resolvido puramente teórico, mas sua tarefa é resolvê-lo numericamente em um domínio discretizado x para obter N
pontos:
- x =
{i/(N-1) | i=0..N-1}
ou com base em 1:{(i-1)/(N-1) | i=1..N}
h = 1/(N-1)
é o espaçamento
Entrada
f
como função ou expressão ou stringu_L
,u_R
como valores de ponto flutuanteN
como inteiro> = 2
Resultado
- Array, List, algum tipo de string separada de
u
tal modo queu_i == u(x_i)
Exemplos
Exemplo 1
Entrada: f = -2
, u_L = u_R = 0
, N = 10
(não pegue f=-2
errado, não é um valor, mas uma função constante que os retornos -2
para todo x
É como uma força de gravidade constante em nosso corda..)
Resultado: [-0.0, -0.09876543209876543, -0.1728395061728395, -0.22222222222222224, -0.24691358024691357, -0.24691358024691357, -0.22222222222222224, -0.1728395061728395, -0.09876543209876547, -0.0]
Existe uma solução exata e fácil: u = -x*(1-x)
Exemplo 2
Entrada: f = 10*x
, u_L = 0
u_R = 1
, N = 15
(Aqui há um monte de contra o vento no lado direito)
Resultado: [ 0., 0.1898688, 0.37609329, 0.55502915, 0.72303207, 0.87645773, 1.01166181, 1.125, 1.21282799, 1.27150146, 1.29737609, 1.28680758, 1.2361516, 1.14176385, 1.]
A solução exata para esses estados: u = 1/3*(8*x-5*x^3)
Exemplo 3
Entrada: f = sin(2*pi*x)
, u_L = u_R = 1
, N = 20
(Alguém quebrou gravidade ou há uma espécie de cima e na direção do vento)
Resultado: [ 1., 1.0083001, 1.01570075, 1.02139999, 1.0247802, 1.0254751, 1.02340937, 1.01880687, 1.01216636, 1.00420743, 0.99579257, 0.98783364, 0.98119313, 0.97659063, 0.9745249, 0.9752198, 0.97860001, 0.98429925, 0.9916999, 1.]
Aqui a solução exata é u = (sin(2*π*x))/(4*π^2)+1
Exemplo 4
Entrada: f = exp(x^2)
, u_L = u_R = 0
,N=30
Resultado:
[ 0. 0.02021032 0.03923016 0.05705528 0.07367854 0.0890899
0.10327633 0.11622169 0.12790665 0.13830853 0.14740113 0.15515453
0.16153488 0.1665041 0.17001962 0.172034 0.17249459 0.17134303
0.16851482 0.1639387 0.15753606 0.1492202 0.13889553 0.12645668
0.11178744 0.09475961 0.07523169 0.05304738 0.02803389 0. ]
Observe a leve simetria
FDM
Um método possível para resolver isso é o método das diferenças finitas :
- reescrever
-u_i'' = f_i
como (-u_{i-1} + 2u_i - u{i+1})/h² = f_i
que é igual-u_{i-1} + 2u_i - u{i+1} = h²f_i
- Configure as equações:
- Que são iguais a uma equação de vetor de matriz:
- Resolva esta equação e produza o
u_i
Uma implementação disso para demonstração em Python:
import matplotlib.pyplot as plt
import numpy as np
def laplace(f, uL, uR, N):
h = 1./(N-1)
x = [i*h for i in range(N)]
A = np.zeros((N,N))
b = np.zeros((N,))
A[0,0] = 1
b[0] = uL
for i in range(1,N-1):
A[i,i-1] = -1
A[i,i] = 2
A[i,i+1] = -1
b[i] = h**2*f(x[i])
A[N-1,N-1] = 1
b[N-1] = uR
u = np.linalg.solve(A,b)
plt.plot(x,u,'*-')
plt.show()
return u
print laplace(lambda x:-2, 0, 0, 10)
print laplace(lambda x:10*x, 0, 1, 15)
print laplace(lambda x:np.sin(2*np.pi*x), 1, 1, 20)
Implementação alternativa sem Álgebra Matricial (usando o método Jacobi )
def laplace(f, uL, uR, N):
h=1./(N-1)
b=[f(i*h)*h*h for i in range(N)]
b[0],b[-1]=uL,uR
u = [0]*N
def residual():
return np.sqrt(sum(r*r for r in[b[i] + u[i-1] - 2*u[i] + u[i+1] for i in range(1,N-1)]))
def jacobi():
return [uL] + [0.5*(b[i] + u[i-1] + u[i+1]) for i in range(1,N-1)] + [uR]
while residual() > 1e-6:
u = jacobi()
return u
No entanto, você pode usar qualquer outro método para resolver a equação de Laplace. Se você usar um método iterativo, iterará até o residual |b-Au|<1e-6
, b
sendo o vetor do lado direitou_L,f_1h²,f_2h²,...
Notas
Dependendo do seu método de solução, você pode não resolver os exemplos exatamente para as soluções fornecidas. Pelo menos para N->infinity
o erro deve se aproximar de zero.
As brechas padrão são proibidas , os internos para PDEs são permitidos.
Bônus
Um bônus de -30% para exibir a solução, gráfica ou ASCII-art.
Ganhando
Isso é codegolf, então o código mais curto em bytes vence!
f(x) = exp(x^2)
.log(log(x))
ousqrt(1-x^4)
que possuem uma integral, que, no entanto, não é expressável em funções elementares.u(x) = 1/2 (-sqrt(π) x erfi(x)+sqrt(π) erfi(1) x+e^(x^2)-e x+x-1)
não é exatamente calculável.Respostas:
Mathematica, 52,5 bytes (= 75 * (1 - 30%))
+0,7 bytes por comentário de @flawr.
Isso plota a saída.
por exemplo
Explicação
Resolva para a função
u
.Subdivide
o intervalo [0,1] em N (quarta entrada) partes.Mapeie
u
para a saída deSubdivide
.Traçar o resultado final.
Solução não gráfica: 58 bytes
fonte
f(x) = exp(x^2)
NDSolve
no caso geral de soluções não elementares.Matlab,
84, 81.279.1 bytes = 113 - 30%Observe que, neste exemplo, eu uso vetores de linha, isso significa que a matriz
A
é transposta.f
é tomado como identificador de função,a,b
são as restrições de Dirichlet do lado esquerdo / direito.Para o exemplo,
f = 10*x, u_L = 0 u_R = 1, N = 15
isso resulta em:fonte
R,
123,2 102,998,7 bytes (141-30%)Editar: salvou um punhado de bytes graças a @Angs!
Se alguém quiser editar as imagens, sinta-se à vontade para fazê-lo. Esta é basicamente uma adaptação em R das versões matlab e python postadas.
Ungolfed & explicou:
Exemplos e casos de teste:
A função nomeada e ungolfed pode ser chamada usando:
Observe que o
f
argumento é uma função R.Para executar a versão golfed simplesmente use
(function(...){...})(args)
fonte
is.numeric(f)
verificação se você declararf
como função, não é necessário passá-lo diretamente na chamada de função para o solucionador.f
como uma função, para não precisar verificar se o caso é uma constante (função).f
ser numérico.f = (function(x)-2)
funciona para o primeiro exemplo, por isso nunca é necessáriorep
.x<-0:10/10;f<-function(x){-2};10^-2*sapply(x,f)
, se f (x) não é quaranteed a ser vetorizado ou apenas10^-2*f(x)
sef
está vetorizado (laplace(Vectorize(function(x)2),0,0,10
)f
como uma função adequada.Haskell,
195168 bytesA legibilidade levou bastante sucesso. Ungolfed:
TODO: Imprimindo em
8371 bytes.Deixa eu ver:
D'oh!
fonte
Axioma,
579.460bytesungolf-lo e testar
a função da pergunta é m (,,,) o código acima é colocado no arquivo "file.input" e carregado no Axiom. O resultado depende da função digits ().
se alguém achar que não é jogador de golfe => ele ou ela pode mostrar como fazer isso ... obrigado
PS
parece que os 6 números depois da. para e ^ (x ^ 2) não está ok aqui ou nos exemplos, mas aqui eu aumento os dígitos, mas os números não mudam ... para mim, isso significa que os números no exemplo estão errados. Por que todos os outros não mostraram seus números?
para o pecado (2 *% pi * x) também existem problemas
"Aqui a solução exata é u = (sin (2 * π * x)) / (4 * π ^ 2) +1" copiei a solução exata para x = 1/19:
em WolframAlpha https://www.wolframalpha.com/input/?i=(sin(2% CF% 80% 2F19))% 2F (4 % CF% 80% 5E2)% 2B1 resultado
1.0083001 proposto como resultado é diferente no quarto dígito do resultado real 1.00822473 ... (e não no sexto)
fonte
f=-2
exemplo tem uma solução analítica e numérica correspondente.