Wprowadzenie do matematyki numerycznej
To jest „Witaj, świecie!” PDE (równania różniczkowe cząstkowe). Równanie Laplace'a lub dyfuzji pojawia się często w fizyce, na przykład równanie ciepła, deformacja, dynamika płynów itp. Tak jak w prawdziwym życiu jest 3D, ale chcemy powiedzieć „Cześć, świecie!” i nie zaśpiewajcie „99 butelek piwa ...” to zadanie podano w 1D. Możesz to zinterpretować jako gumową szatę przywiązaną do ściany na obu końcach z użyciem pewnej siły.
W [0,1]
domenie znajdź funkcję u
dla danej funkcji źródłowej f
i wartości brzegowych u_L
i u_R
taką, aby:
-u'' = f
u(0) = u_L
u(1) = u_R
u''
oznacza drugą pochodną u
Można to rozwiązać czysto teoretycznie, ale Twoim zadaniem jest rozwiązanie go liczbowo na dyskretnej domenie x dla N
punktów:
- x =
{i/(N-1) | i=0..N-1}
lub w oparciu o 1:{(i-1)/(N-1) | i=1..N}
h = 1/(N-1)
to odstępy
Wejście
f
jako funkcja lub wyrażenie lub ciągu_L
,u_R
jako wartości zmiennoprzecinkoweN
jako liczba całkowita> = 2
Wynik
- Tablica, lista, jakiś oddzielny ciąg
u
takich znakówu_i == u(x_i)
Przykłady
Przykład 1
Wejście: f = -2
, u_L = u_R = 0
, N = 10
(nie ma f=-2
źle, to nie jest wartością stałą, ale funkcja, która powraca -2
do wszystkich x
To jak stałą grawitacji życie naszej liny.).
Wynik: [-0.0, -0.09876543209876543, -0.1728395061728395, -0.22222222222222224, -0.24691358024691357, -0.24691358024691357, -0.22222222222222224, -0.1728395061728395, -0.09876543209876547, -0.0]
Istnieje łatwe dokładne rozwiązanie: u = -x*(1-x)
Przykład 2
Wejście: f = 10*x
, u_L = 0
u_R = 1
, N = 15
(Tu jest dużo wiatr z prawej strony)
Wynik: [ 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.]
Dokładne rozwiązanie tego stanu: u = 1/3*(8*x-5*x^3)
Przykład 3
Wejście: f = sin(2*pi*x)
, u_L = u_R = 1
, N = 20
(Ktoś złamał grawitacji lub nie jest rodzajem górę iz wiatrem)
Wynik: [ 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.]
Oto dokładne rozwiązanie u = (sin(2*π*x))/(4*π^2)+1
Przykład 4
Wejście: f = exp(x^2)
, u_L = u_R = 0
,N=30
Wynik:
[ 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. ]
Zwróć uwagę na niewielką asymetrię
FDM
Jedną z możliwych metod rozwiązania tego problemu jest metoda różnic skończonych :
- przepisz
-u_i'' = f_i
jako (-u_{i-1} + 2u_i - u{i+1})/h² = f_i
co jest równe-u_{i-1} + 2u_i - u{i+1} = h²f_i
- Skonfiguruj równania:
- Które są równe równaniu macierz-wektor:
- Rozwiąż to równanie i wyślij
u_i
Jedna implementacja tego do demonstracji w Pythonie:
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)
Alternatywne wdrożenie bez Matrycy Algebry (przy użyciu metody 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
Możesz jednak użyć dowolnej innej metody, aby rozwiązać równanie Laplace'a. Jeśli używasz metody iteracyjnej, powinieneś iterować do reszty |b-Au|<1e-6
, b
będąc wektorem po prawej stronieu_L,f_1h²,f_2h²,...
Notatki
W zależności od metody rozwiązania przykłady mogą nie zostać rozwiązane dokładnie dla podanych rozwiązań. Przynajmniej N->infinity
błąd powinien zbliżyć się do zera.
Standardowe luki są niedozwolone , dozwolone są wbudowane PDE.
Premia
Premia w wysokości -30% za wyświetlenie rozwiązania graficznego lub ASCII-art.
Zwycięski
To jest codegolf, więc wygrywa najkrótszy kod w bajtach!
f(x) = exp(x^2)
. Z.log(log(x))
lub,sqrt(1-x^4)
które mają całkę, która jednak nie jest wyrażalna w funkcjach elementarnych.u(x) = 1/2 (-sqrt(π) x erfi(x)+sqrt(π) erfi(1) x+e^(x^2)-e x+x-1)
nie jest dokładnie obliczalny.Odpowiedzi:
Mathematica, 52,5 bajtów (= 75 * (1-30%))
+0,7 bajtów na komentarz @flawr.
To drukuje dane wyjściowe.
na przykład
Wyjaśnienie
Rozwiąż dla funkcji
u
.Subdivide
przedział [0,1] na części N (4. wejście).Odwzoruj
u
na wynikSubdivide
.Wykreśl wynik końcowy.
Rozwiązanie inne niż graficzne: 58 bajtów
źródło
f(x) = exp(x^2)
NDSolve
do ogólnego przypadku rozwiązań nie elementarnych.Matlab,
84, 81,279,1 bajtów = 113–30%Zauważ, że w tym przykładzie używam wektorów wierszy, co oznacza, że macierz
A
jest transponowana.f
jest traktowany jako uchwyt funkcyjny,a,b
są to ograniczenia Dirichleta po lewej / prawej stronie.Na przykład
f = 10*x, u_L = 0 u_R = 1, N = 15
powoduje to:źródło
R,
123,2 102,998,7 bajtów (141-30%)Edycja: Zaoszczędź garść bajtów dzięki @Angs!
Jeśli ktoś chce edytować zdjęcia, możesz to zrobić. Jest to w zasadzie adaptacja R zarówno opublikowanych wersji Matlaba, jak i Pythona.
Niegolfowane i wyjaśnione:
Przykłady i przypadki testowe:
Nazwaną i nie golfową funkcję można wywołać za pomocą:
Zauważ, że
f
argument jest funkcją R.Aby uruchomić wersję golfową, wystarczy użyć
(function(...){...})(args)
źródło
is.numeric(f)
czeku, jeśli zadeklarujeszf
jako funkcję, nie jest wymagane przekazywanie go bezpośrednio w wywołaniu funkcji do solvera.f
jako funkcję, więc nie musisz sprawdzać, czy jest to stała (funkcja).f
być cyfrowym .f = (function(x)-2)
działa dla pierwszego przykładu, więc nigdy nie ma takiej potrzebyrep
.x<-0:10/10;f<-function(x){-2};10^-2*sapply(x,f)
, jeśli f (x) nie jest quaranteed być wektorowy lub po prostu10^-2*f(x)
jeślif
jest wektorowy (laplace(Vectorize(function(x)2),0,0,10
)f
jako właściwą funkcję.Haskell,
195168 bajtówCzytelność spotkała się z dużym hitem. Nie golfowany:
DO ZROBIENIA: Drukowanie w
8371 bajtach.Daj mi zobaczyć:
Nie!
źródło
Axiom,
579460 bajtówrozkop go i przetestuj
funkcją pytania jest m (,,,) powyższy kod jest umieszczony w pliku „file.input” i załadowany do Axiom. Wynik zależy od funkcji digits ().
jeśli ktoś myśli, że to nie gra w golfa => on lub ona może pokazać, jak to zrobić ... dzięki
PS
wydaje się, że 6 liczb po. dla e ^ (x ^ 2) nie są tutaj ani w przykładach, ale tutaj zwiększam cyfry, ale liczby się nie zmieniają ... dla mnie oznacza to, że liczby w przykładzie są nieprawidłowe. Dlaczego wszyscy inni nie pokazali swoich liczb?
w przypadku sin (2 *% pi * x) występują również problemy
„Tutaj dokładne rozwiązanie to u = (sin (2 * π * x)) / (4 * π ^ 2) +1” skopiowałem dokładne rozwiązanie dla x = 1/19:
w WolframAlpha https://www.wolframalpha.com/input/?i=(sin(2% CF% 80% 2F19))% 2F (4 % CF% 80% 5E2)% 2B1 wynik
1.0083001 zaproponowany jako wynik różni się czwartą cyfrą od rzeczywistego wyniku 1.00822473 ... (a nie 6.)
źródło
f=-2
przykład ma pasujące rozwiązanie analityczne i numeryczne.