Einführung in die Numerische Mathematik
Dies ist das "Hallo, Welt!" von PDEs (Partielle Differentialgleichungen). Die Laplace- oder Diffusionsgleichung wird in der Physik häufig verwendet, z. B. Wärmegleichung, Verformung, Fluiddynamik usw. Da das reale Leben 3D ist, möchten wir jedoch "Hallo, Welt!" und nicht singen "99 flaschen bier, ..." diese aufgabe ist in 1D gegeben. Sie können dies als eine Gummimantel interpretieren, die an beiden Enden mit etwas Kraft an einer Wand befestigt ist.
[0,1]
Suchen Sie in einer Domain eine Funktion u
für bestimmte Quellfunktionen f
und Grenzwerte, u_L
und zwar u_R
so, dass:
-u'' = f
u(0) = u_L
u(1) = u_R
u''
bezeichnet die zweite Ableitung von u
Dies kann rein theoretisch gelöst werden, aber Ihre Aufgabe ist es, es numerisch in einer diskretisierten Domäne x nach N
Punkten zu lösen :
- x =
{i/(N-1) | i=0..N-1}
oder 1-basiert:{(i-1)/(N-1) | i=1..N}
h = 1/(N-1)
ist der Abstand
Eingang
f
als Funktion oder Ausdruck oder Zeichenfolgeu_L
,u_R
Als GleitkommawerteN
als ganze Zahl> = 2
Ausgabe
- Array, List, eine Art separater String
u
davonu_i == u(x_i)
Beispiele
Beispiel 1
Input: f = -2
, u_L = u_R = 0
, N = 10
(nehmen Sie nicht f=-2
falsch, es ist kein Wert , sondern eine konstante Funktion , dass die Renditen -2
für alle x
Es ist wie eine konstante Schwerkraft auf unserem Seil..)
Ausgabe: [-0.0, -0.09876543209876543, -0.1728395061728395, -0.22222222222222224, -0.24691358024691357, -0.24691358024691357, -0.22222222222222224, -0.1728395061728395, -0.09876543209876547, -0.0]
Es gibt eine einfache exakte Lösung: u = -x*(1-x)
Beispiel 2
Input: f = 10*x
, u_L = 0
u_R = 1
, N = 15
(Hier gibt es eine Menge gegen den Wind auf der rechten Seite)
Ausgabe: [ 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.]
Die genaue Lösung hierfür lautet: u = 1/3*(8*x-5*x^3)
Beispiel 3
Input: f = sin(2*pi*x)
, u_L = u_R = 1
, N = 20
(jemand brach die Schwerkraft , oder es ist eine Art von Up- und Abwind)
Ausgabe: [ 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.]
Hier ist die genaue Lösung u = (sin(2*π*x))/(4*π^2)+1
Beispiel 4
Input: f = exp(x^2)
, u_L = u_R = 0
,N=30
Ausgabe:
[ 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. ]
Beachten Sie die leichte Unsymmetrie
FDM
Eine mögliche Methode, um dies zu lösen, ist die Finite-Differenz-Methode :
- umschreiben
-u_i'' = f_i
als (-u_{i-1} + 2u_i - u{i+1})/h² = f_i
was gleich ist-u_{i-1} + 2u_i - u{i+1} = h²f_i
- Stellen Sie die Gleichungen auf:
- Welche sind gleich einer Matrix-Vektor-Gleichung:
- Lösen Sie diese Gleichung und geben Sie die aus
u_i
Eine Implementierung davon zur Demonstration in 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)
Alternative Implementierung ohne Matrixalgebra (unter Verwendung der Jacobi-Methode )
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
Sie können jedoch eine andere Methode verwenden, um die Laplace-Gleichung zu lösen. Wenn Sie eine iterative Methode verwenden, sollten Sie bis zum Residuum iterieren |b-Au|<1e-6
, wobei b
dies der Vektor auf der rechten Seite istu_L,f_1h²,f_2h²,...
Anmerkungen
Abhängig von Ihrer Lösungsmethode lösen Sie die Beispiele möglicherweise nicht genau mit den angegebenen Lösungen. Zumindest für N->infinity
den Fehler sollte sich Null nähern.
Standard-Schlupflöcher sind nicht zulässig, eingebaute PDEs sind zulässig.
Bonus
Ein Bonus von -30% für die Anzeige der Lösung, entweder grafisch oder ASCII-artig.
Gewinnen
Das ist Codegolf, also gewinnt der kürzeste Code in Bytes!
f(x) = exp(x^2)
.log(log(x))
odersqrt(1-x^4)
die ein Integral haben, das sich aber in Elementarfunktionen nicht ausdrücken lässt.u(x) = 1/2 (-sqrt(π) x erfi(x)+sqrt(π) erfi(1) x+e^(x^2)-e x+x-1)
nicht genau berechenbar ist.Antworten:
Mathematica, 52,5 Byte (= 75 * (1 - 30%))
+0,7 Bytes pro Kommentar von @flawr.
Dies zeichnet die Ausgabe.
z.B
Erläuterung
Löse für die Funktion
u
.Subdivide
das Intervall [0,1] in N (4. Eingabe) Teile.Map
u
auf die Ausgabe vonSubdivide
.Zeichnen Sie das Endergebnis.
Lösung ohne Grafik: 58 Byte
quelle
f(x) = exp(x^2)
NDSolve
für den allgemeinen Fall nicht-elementarer Lösungen verwenden.Matlab,
84, 81,279,1 Bytes = 113 - 30%Beachten Sie, dass in diesem Beispiel ich Zeilenvektoren verwende, das bedeutet, dass die Matrix
A
transponiert ist.f
wird als Funktionshandle genommen,a,b
sind die Dirichlet-Beschränkungen links / rechts.Für das Beispiel
f = 10*x, u_L = 0 u_R = 1, N = 15
ergibt dies:quelle
R,
123,2 102,998,7 Bytes (141-30%)Bearbeiten: Eine Handvoll Bytes dank @Angs gespeichert!
Wenn jemand die Bilder bearbeiten möchte, kann er dies gerne tun. Dies ist im Grunde eine R-Anpassung sowohl der Matlab- als auch der Python-Version.
Ungolfed & erklärt:
Beispiel & Testfälle:
Die Funktion named und ungolfed kann folgendermaßen aufgerufen werden:
Notiere dass der
f
Argument eine R-Funktion ist.Um die Golfversion zu starten, verwenden Sie einfach
(function(...){...})(args)
quelle
is.numeric(f)
Prüfung verwerfen, wenn Sief
als Funktion deklarieren . Es ist nicht erforderlich, sie direkt im Funktionsaufruf an den Solver zu übergeben.f
so ändern, dass er als Funktion akzeptiert wird, sodass Sie nicht prüfen müssen, ob es sich um eine Konstante (Funktion) handelt.f
, jemals numerisch zu sein.f = (function(x)-2)
funktioniert für das erste Beispiel, es ist also nie nötigrep
.x<-0:10/10;f<-function(x){-2};10^-2*sapply(x,f)
wenn f (x) nicht als vektorisiert unter Quarantäne gestellt wird, oder nur,10^-2*f(x)
wennf
vektorisiert ist (laplace(Vectorize(function(x)2),0,0,10
)f
als richtige Funktion an.Haskell,
195168 BytesDie Lesbarkeit hat einiges gekostet. Ungolfed:
TODO: Drucken in
8371 Bytes.Lass mich sehen:
D'oh!
quelle
Axiom,
579.460Bytesentgolfen und testen
die funktion für die frage ist m (,,,) der obige code wird in die datei "file.input" gestellt und in axiom geladen. Das Ergebnis hängt von der Funktion digits () ab.
Wenn jemand denkt, dass es kein Golfspiel ist => kann er oder sie zeigen, wie es geht ... danke
PS
es scheint die 6 Zahlen nach dem. für e ^ (x ^ 2) sind hier oder in den Beispielen nicht in Ordnung, aber hier erhöhe ich die Ziffern, aber die Zahlen ändern sich nicht ... für mich bedeutet das, dass die Zahlen im Beispiel falsch sind. Warum haben alle anderen ihre Nummern nicht gezeigt?
für sin (2 *% pi * x) gibt es auch probleme
"Hier ist die exakte Lösung u = (sin (2 * π * x)) / (4 * π ^ 2) +1" Ich habe die exakte Lösung für x = 1/19 kopiert:
in WolframAlpha https://www.wolframalpha.com/input/?i=(sin(2% CF% 80% 2F19))% 2F (4 % CF% 80% 5E2)% 2B1 ist das Ergebnis
1.0083001 als Ergebnis vorgeschlagen unterscheidet sich in der 4. Ziffer vom tatsächlichen Ergebnis 1.00822473 ... (und nicht 6.)
quelle
f=-2
Beispiel eine passende analytische und numerische Lösung.