Introduction aux mathématiques numériques
Ceci est le "Bonjour, monde!" des PDE (Partial Differential Equations). L'équation de Laplace ou de diffusion apparaît souvent en physique, par exemple l'équation de la chaleur, la déformation, la dynamique des fluides, etc. et pas chanter "99 bouteilles de bière, ..." cette tâche est donnée en 1D. Vous pouvez interpréter cela comme une robe en caoutchouc attachée à un mur aux deux extrémités avec une certaine force appliquée.
Sur un [0,1]
domaine, trouvez une fonction u
pour une fonction source donnée f
et des valeurs limites u_L
et u_R
telles que:
-u'' = f
u(0) = u_L
u(1) = u_R
u''
désigne la dérivée seconde de u
Cela peut être résolu purement théorique mais votre tâche est de le résoudre numériquement sur un domaine discrétisé x pour les N
points:
- x =
{i/(N-1) | i=0..N-1}
ou 1:{(i-1)/(N-1) | i=1..N}
h = 1/(N-1)
est l'espacement
Contribution
f
comme fonction ou expression ou chaîneu_L
, enu_R
tant que valeurs à virgule flottanteN
comme entier> = 2
Production
- Array, List, une sorte de chaîne séparée de
u
telle sorte queu_i == u(x_i)
Exemples
Exemple 1
Entrée: f = -2
, u_L = u_R = 0
, N = 10
(Ne pas prendre f=-2
mal, ce n'est pas une valeur , mais une fonction constante que le rendement -2
pour tous x
Il est comme une force de gravité constante sur notre corde..)
Production: [-0.0, -0.09876543209876543, -0.1728395061728395, -0.22222222222222224, -0.24691358024691357, -0.24691358024691357, -0.22222222222222224, -0.1728395061728395, -0.09876543209876547, -0.0]
Il existe une solution exacte simple: u = -x*(1-x)
Exemple 2
Entrée: f = 10*x
, u_L = 0
u_R = 1
, N = 15
(Ici il y a beaucoup de vent debout sur le côté droit)
Production: [ 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 solution exacte pour cela indique: u = 1/3*(8*x-5*x^3)
Exemple 3
Entrée: f = sin(2*pi*x)
, u_L = u_R = 1
, N = 20
(Quelqu'un a brisé la gravité ou il y a une sorte de haut et sous le vent)
Production: [ 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.]
Ici, la solution exacte est u = (sin(2*π*x))/(4*π^2)+1
Exemple 4
Entrée: f = exp(x^2)
, u_L = u_R = 0
,N=30
Production:
[ 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. ]
Notez la légère asymétrie
FDM
Une méthode possible pour résoudre ce problème est la méthode des différences finies :
- réécrire
-u_i'' = f_i
comme (-u_{i-1} + 2u_i - u{i+1})/h² = f_i
ce qui équivaut-u_{i-1} + 2u_i - u{i+1} = h²f_i
- Configurez les équations:
- Qui sont égaux à une équation matrice-vecteur:
- Résolvez cette équation et sortez le
u_i
Une implémentation de ceci pour démonstration 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)
Implémentation alternative sans algèbre matricielle (en utilisant la méthode 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
Vous pouvez cependant utiliser toute autre méthode pour résoudre l'équation de Laplace. Si vous utilisez une méthode itérative, vous devez itérer jusqu'à ce que le résidu |b-Au|<1e-6
, avec b
être le vecteur de droiteu_L,f_1h²,f_2h²,...
Remarques
En fonction de votre méthode de résolution, il se peut que vous ne résolviez pas les exemples exactement aux solutions données. Au moins pour N->infinity
l'erreur devrait approcher de zéro.
Les failles standard sont interdites , les fonctions intégrées pour les PDE sont autorisées.
Prime
Un bonus de -30% pour l'affichage de la solution, graphique ou ASCII.
Gagnant
Ceci est codegolf, donc le code le plus court en octets gagne!
f(x) = exp(x^2)
.log(log(x))
ousqrt(1-x^4)
qui ont une intégrale, qui n'est cependant pas exprimable dans les fonctions élémentaires.u(x) = 1/2 (-sqrt(π) x erfi(x)+sqrt(π) erfi(1) x+e^(x^2)-e x+x-1)
n'est pas exactement calculable.Réponses:
Mathematica, 52,5 octets (= 75 * (1 - 30%))
+0,7 octets par commentaire de @flawr.
Cela trace la sortie.
par exemple
Explication
Résolvez la fonction
u
.Subdivide
l'intervalle [0,1] en N (4e entrée) parties.Mappez
u
à la sortie deSubdivide
.Tracez le résultat final.
Solution non graphique: 58 octets
la source
f(x) = exp(x^2)
NDSolve
pour le cas général des solutions non élémentaires.Matlab,
84, 81,279,1 octets = 113 - 30%Notez que dans cet exemple, j'utilise des vecteurs de ligne, cela signifie que la matrice
A
est transposée.f
est considéré comme une poignée de fonction,a,b
sont les contraintes de Dirichlet gauche / droite.Pour l'exemple,
f = 10*x, u_L = 0 u_R = 1, N = 15
cela se traduit par:la source
R,
123,2 102,998,7 octets (141-30%)Edit: enregistré une poignée d'octets grâce à @Angs!
Si quelqu'un souhaite modifier les images, n'hésitez pas à le faire. Il s'agit essentiellement d'une adaptation R des versions matlab et python publiées.
Non golfé et expliqué:
Exemples et cas de test:
La fonction nommée et non golfée peut être appelée en utilisant:
Notez que l'
f
argument est une fonction R.Pour exécuter la version golfée, utilisez simplement
(function(...){...})(args)
la source
is.numeric(f)
chèque si vous déclarezf
comme fonction, il n'est pas nécessaire de le passer directement dans l'appel de fonction au solveur.f
comme une fonction afin que vous n'ayez pas à vérifier si c'est une constante (fonction).f
d'être toujours numérique.f = (function(x)-2)
fonctionne pour le premier exemple, donc il n'y a jamais besoin de le fairerep
.x<-0:10/10;f<-function(x){-2};10^-2*sapply(x,f)
si f (x) n'est pas garanti pour être vectorisé ou tout simplement10^-2*f(x)
s'ilf
est vectorisé (laplace(Vectorize(function(x)2),0,0,10
)f
comme fonction appropriée.Haskell,
195168octetsLa lisibilité a pris un coup. Non golfé:
TODO: Impression en
8371 octets.Laisse-moi voir:
Oh!
la source
Axiom,
579460 octetsdé-golfer et tester
la fonction pour la question est m (,,,) le code ci-dessus est mis dans le fichier "file.input" et chargé dans Axiom. Le résultat dépend de la fonction digits ().
si quelqu'un pense que ce n'est pas du golf => il ou elle peut montrer comment le faire ... merci
PS
il semble que les 6 chiffres après le. pour e ^ (x ^ 2) ne sont pas corrects ici ou dans les exemples mais ici j'augmente les chiffres mais les nombres ne changent pas ... pour moi cela signifie que les nombres dans l'exemple sont faux. Pourquoi tous les autres n'ont pas montré leurs chiffres?
pour le péché (2 *% pi * x) il y a aussi des problèmes
"Ici, la solution exacte est u = (sin (2 * π * x)) / (4 * π ^ 2) +1" j'ai copié la solution exacte pour x = 1/19:
dans WolframAlpha https://www.wolframalpha.com/input/?i=(sin(2% CF% 80% 2F19))% 2F (4 % CF% 80% 5E2)% 2B1 il en résulte
1.0083001 proposé comme résultat est différent au 4ème chiffre du résultat réel 1.00822473 ... (et non pas au 6ème)
la source
f=-2
exemple a une solution analytique et numérique correspondante.