Introducción a la matemática numérica
Este es el "¡Hola Mundo!" de PDE (ecuaciones diferenciales parciales). La ecuación de Laplace o difusión aparece a menudo en física, por ejemplo, ecuación de calor, deformación, dinámica de fluidos, etc. Como la vida real es 3D, pero queremos decir "¡Hola, mundo!" y no cantar "99 botellas de cerveza, ..." esta tarea se da en 1D. Puede interpretar esto como una túnica de goma atada a una pared en ambos extremos con cierta fuerza aplicada.
En un [0,1]
dominio, encuentre una función u
para la función fuente dada f
y los valores límite u_L
y u_R
tal que:
-u'' = f
u(0) = u_L
u(1) = u_R
u''
denota la segunda derivada de u
Esto puede resolverse puramente teórico, pero su tarea es resolverlo numéricamente en un dominio discretizado x para N
puntos:
- x =
{i/(N-1) | i=0..N-1}
o basado en 1:{(i-1)/(N-1) | i=1..N}
h = 1/(N-1)
es el espacio
Entrada
f
como función o expresión o cadenau_L
,u_R
como valores de coma flotanteN
como entero> = 2
Salida
- Matriz, Lista, algún tipo de cadena separada de
u
tal manera queu_i == u(x_i)
Ejemplos
Ejemplo 1
Entrada: f = -2
, u_L = u_R = 0
, N = 10
(no tome f=-2
mal, no es un valor, sino una función constante que los retornos -2
para todos x
Es como una fuerza de la gravedad constante en nuestra cuerda.).
Salida: [-0.0, -0.09876543209876543, -0.1728395061728395, -0.22222222222222224, -0.24691358024691357, -0.24691358024691357, -0.22222222222222224, -0.1728395061728395, -0.09876543209876547, -0.0]
Existe una solución exacta fácil: u = -x*(1-x)
Ejemplo 2
Entrada: f = 10*x
, u_L = 0
u_R = 1
, N = 15
(Aquí hay una gran cantidad de viento arriba a la derecha)
Salida: [ 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.]
La solución exacta para esto dice: u = 1/3*(8*x-5*x^3)
Ejemplo 3
Entrada: f = sin(2*pi*x)
, u_L = u_R = 1
, N = 20
(Alguien rompió la gravedad o hay una especie de arriba y la dirección del viento)
Salida: [ 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.]
Aquí la solución exacta es u = (sin(2*π*x))/(4*π^2)+1
Ejemplo 4
Entrada: f = exp(x^2)
, u_L = u_R = 0
,N=30
Salida:
[ 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. ]
Tenga en cuenta la ligera asimetría
FDM
Un posible método para resolver esto es el método de diferencia finita :
- reescribir
-u_i'' = f_i
como (-u_{i-1} + 2u_i - u{i+1})/h² = f_i
que es igual-u_{i-1} + 2u_i - u{i+1} = h²f_i
- Configura las ecuaciones:
- Que son iguales a una ecuación matriz-vector:
- Resuelve esta ecuación y genera el
u_i
Una implementación de esto para demostración en 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)
Implementación alternativa sin Matrix Algebra (usando el 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
Sin embargo, puede usar cualquier otro método para resolver la ecuación de Laplace. Si usa un método iterativo, debe iterar hasta el residual |b-Au|<1e-6
, b
siendo el vector del lado derechou_L,f_1h²,f_2h²,...
Notas
Dependiendo de su método de solución, es posible que no resuelva los ejemplos exactamente para las soluciones dadas. Al menos para N->infinity
el error debe acercarse a cero.
Las lagunas estándar no están permitidas , se permiten incorporaciones para PDE.
Prima
Una bonificación de -30% para mostrar la solución, ya sea gráfica o ASCII-art.
Victorioso
¡Esto es codegolf, por lo que gana el código más corto en bytes!
f(x) = exp(x^2)
.log(log(x))
osqrt(1-x^4)
que tienen una integral, que sin embargo no se puede expresar en funciones elementales.u(x) = 1/2 (-sqrt(π) x erfi(x)+sqrt(π) erfi(1) x+e^(x^2)-e x+x-1)
no es exactamente calculable.Respuestas:
Mathematica, 52.5 bytes (= 75 * (1 - 30%))
+0.7 bytes por comentario de @flawr.
Esto traza la salida.
p.ej
Explicación
Resolver para la función
u
.Subdivide
el intervalo [0,1] en N (cuarta entrada) partes.Mapa
u
a la salida deSubdivide
.Trazar el resultado final.
Solución no gráfica: 58 bytes
fuente
f(x) = exp(x^2)
NDSolve
para el caso general de soluciones no elementales.Matlab,
84, 81.279.1 bytes = 113 - 30%Tenga en cuenta que en este ejemplo utilizo vectores de fila, esto significa que la matriz
A
se transpone.f
se toma como un manejador de funciones,a,b
son las contracciones de Dirichlet del lado izquierdo / derecho.Para el ejemplo,
f = 10*x, u_L = 0 u_R = 1, N = 15
esto resulta en:fuente
R,
123,2 102,998,7 bytes (141-30%)Editar: ¡Ahorré un puñado de bytes gracias a @Angs!
Si alguien quiere editar las imágenes, siéntase libre de hacerlo. Esto es básicamente una adaptación R de las versiones de Matlab y Python publicadas.
Ungolfed y explicado:
Ejemplo y casos de prueba:
La función nombrada y no reflejada se puede llamar usando:
Tenga en cuenta que el
f
argumento es una función R.Para ejecutar la versión de golf simplemente use
(function(...){...})(args)
fuente
is.numeric(f)
cheque si declaraf
como función, no es necesario pasarlo directamente en la llamada de función al solucionador.f
como una función para que no tenga que verificar el caso, es una constante (función).f
ser numérico.f = (function(x)-2)
funciona para el primer ejemplo, por lo que nunca es necesariorep
.x<-0:10/10;f<-function(x){-2};10^-2*sapply(x,f)
si f (x) no está garantizado para ser vectorizado o simplemente10^-2*f(x)
sif
está vectorizado (laplace(Vectorize(function(x)2),0,0,10
)f
como una función adecuada.Haskell,
195168 bytesLa legibilidad recibió un gran golpe. Sin golf:
TODO: Imprimiendo en
8371 bytes.Déjame ver:
D'oh!
fuente
Axioma,
579460 bytesdeshazte de él y prueba
la función para la pregunta es m (,,,) el código anterior se coloca en el archivo "file.input" y se carga en Axiom. El resultado depende de la función digits ().
si alguien piensa que no es golf => él o ella puede mostrar cómo hacerlo ... gracias
PD
Parecen los 6 números después del. para e ^ (x ^ 2) no están bien aquí o en los ejemplos, pero aquí aumento los dígitos pero los números no cambian ... para mí significa que los números en el ejemplo están mal. ¿Por qué todos los demás no han mostrado sus números?
para sin (2 *% pi * x) también hay problemas
"Aquí la solución exacta es u = (sin (2 * π * x)) / (4 * π ^ 2) +1" copié la solución exacta para x = 1/19:
en WolframAlpha https://www.wolframalpha.com/input/?i=(sin(2% CF% 80% 2F19))% 2F (4 % CF% 80% 5E2)% 2B1 resulta
1.0083001 propuesto como resultado es diferente en el cuarto dígito del resultado real 1.00822473 ... (y no sexto)
fuente
f=-2
ejemplo tiene una solución analítica y numérica coincidente.