Laplace denklemini çözme


13

Sayısal Matematiğe Giriş

Bu "Merhaba Dünya!" PDE'ler (Kısmi Diferansiyel Denklemler). Laplace veya Difüzyon Denklemi Fizikte sıklıkla görülür, örneğin Isı Denklemi, Deforme, Akışkanlar Dinamiği, vb ... Gerçek hayat 3D olduğundan, "Merhaba Dünya!" "99 şişe bira, ..." şarkı söylemeyin, bu görev 1D'de verilir. Bunu, her iki ucunda bir duvara bağlı, üzerine kuvvet uygulanmış bir kauçuk elbise olarak yorumlayabilirsiniz.

Bir [0,1]etki alanında ubelirli kaynak işlevi fve sınır değerleri için bir işlev bulun u_Lve u_Rbu şekilde:

  • -u'' = f
  • u(0) = u_L
  • u(1) = u_R

u'' "" nin ikinci türevini belirtir. u

Bu tamamen teorik olarak çözülebilir, ancak göreviniz, puan için ayrı bir x alanında sayısal olarak çözmektir N:

  • x = {i/(N-1) | i=0..N-1}veya 1 tabanlı:{(i-1)/(N-1) | i=1..N}
  • h = 1/(N-1) aralık mı

Giriş

  • f işlev veya ifade veya dize olarak
  • u_L, u_Rkayan nokta değerleri olarak
  • N tamsayı olarak> = 2

Çıktı

  • Dizi, Liste, bir Ayrılmış dize çeşit uöyle kiu_i == u(x_i)

Örnekler

örnek 1

Girdi: f = -2, u_L = u_R = 0, N = 10(alamaz Do f=-2yanlış, bir değer ancak döner bir sabit fonksiyon değildir -2herkes için x. Bu bizim ipe sabit yerçekimi kuvvetinin gibidir.)

Çıktı: [-0.0, -0.09876543209876543, -0.1728395061728395, -0.22222222222222224, -0.24691358024691357, -0.24691358024691357, -0.22222222222222224, -0.1728395061728395, -0.09876543209876547, -0.0]

Kolay ve kesin bir çözüm var: u = -x*(1-x)

ÖRNEK 2

Girdi: f = 10*x, u_L = 0 u_R = 1, N = 15(Burada sağ tarafta rüzgâra karşı bir sürü vardır)

Çıktı: [ 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.]

Bu durumlar için kesin çözüm: u = 1/3*(8*x-5*x^3)

ÖRNEK 3

Girdi: f = sin(2*pi*x), u_L = u_R = 1, N = 20(Birisi yerçekimi kırdı veya yukarı ve rüzgar altı bir tür vardır)

Çıktı: [ 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.]

İşte kesin çözüm u = (sin(2*π*x))/(4*π^2)+1

Örnek 4

Girdi: f = exp(x^2), u_L = u_R = 0,N=30

Çıktı: [ 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. ]

Hafif simetriye dikkat edin

FDM

Bunu çözmek için olası bir yöntem Sonlu Farklar Yöntemi'dir :

  • yeniden yazmak -u_i'' = f_iolarak
  • (-u_{i-1} + 2u_i - u{i+1})/h² = f_i hangisine eşit
  • -u_{i-1} + 2u_i - u{i+1} = h²f_i
  • Denklemleri kurun:

  • Bir matris-vektör denklemine eşit olan:

  • Bu denklemi çözün ve u_i

Python'da gösteri için bunun bir uygulaması:

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)

Matris Cebiri olmadan alternatif uygulama ( Jacobi yöntemini kullanarak )

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

Ancak Laplace denklemini çözmek için başka bir yöntem kullanabilirsiniz. Eğer iteratif yöntemi kullanırsanız, artık dek yineleme gerektiğini |b-Au|<1e-6ile, bsağ taraf vektörü olmaku_L,f_1h²,f_2h²,...

notlar

Çözüm yönteminize bağlı olarak, verilen çözümlerle ilgili örnekleri tam olarak çözemeyebilirsiniz. En azından N->infinityhata sıfıra yaklaşmalıdır.

Standart boşluklara izin verilmez , PDE'ler için yerleşik girişlere izin verilir.

Bonus

Grafik veya ASCII-art çözümünü görüntülemek için% -30'luk bir bonus.

Kazanan

Bu codegolf, baytlardaki en kısa kod kazanıyor!


Analitik olarak çözülemeyen bir örnek eklemenizi öneririm, örn f(x) = exp(x^2).
Kusur

@flawr Elbette, bir çözüm var ancak hata fonksiyonu dahil.
Karl Napf

1
Maalesef, bu yanlış bir ifadeydi, "temel olmayan antiderivatif" daha uygun olabilir mi? Yani , temel fonksiyonlarda ifade edilemeyen bir integrale sahip olan log(log(x))veya sqrt(1-x^4)olmayan fonksiyonlar.
Kusur

@flawr Hayır, iyi değil, hata fonksiyonu temel değildir, sadece çözümü analitik olarak ifade etmenin bir yolu olduğunu söylemek istedim ama u(x) = 1/2 (-sqrt(π) x erfi(x)+sqrt(π) erfi(1) x+e^(x^2)-e x+x-1)tam olarak hesaplanamaz.
Karl Napf

Neden 1e-6'ya kadar yineleniyor ve 1e-30'a kadar yinelenmiyor?
RosLuP

Yanıtlar:


4

Mathematica, 52.5 bayt (= 75 * (% 1-30))

@Flawr'ın yorumu başına +0,7 bayt.

ListPlot[{#,u@#}&/@Subdivide@#4/.NDSolve[-u''@x==#&&u@0==#2&&u@1==#3,u,x]]&

Bu çıktıyı çizer.

Örneğin

ListPlot[ ... ]&[10 x, 0, 1, 15]

resim açıklamasını buraya girin

açıklama

NDSolve[-u''@x==#&&u@0==#2&&u@1==#3,u,x]

İşlev için çözün u.

Subdivide@#4

Subdivide [0,1] değerini N (4. giriş) parçalarına ayırın.

{#,u@#}&/@ ...

Harita uçıktısı Subdivide.

ListPlot[ ... ]

Nihai sonucu çizin.

Grafik içermeyen çözüm: 58 bayt

u/@Subdivide@#4/.NDSolve[-u''@x==#&&u@0==#2&&u@1==#3,u,x]&

Bu işe yaramazf(x) = exp(x^2)
flawr

Belki de NDSolvetemel olmayan çözümlerin genel durumu için kullanmak isteyebilirsiniz .
flawr

6

Matlab, 84, 81.2 79.1 bayt = 113 -% 30

function u=l(f,N,a,b);A=toeplitz([2,-1,(3:N)*0]);A([1,2,end-[1,0]])=eye(2);u=[a,f((1:N-2)/N)*(N-1)^2,b]/A;plot(u)

Bu örnekte satır vektörleri kullandığımı, matrisin Atranspoze edildiği anlamına gelir . ffonksiyon tutamacı olarak alınır a,b, sol / sağ taraf Dirichlet kontrendikedir.

function u=l(f,N,a,b);
A=toeplitz([2,-1,(3:N)*0]);       % use the "toeplitz" builtin to generate the matrix
A([1,2,end-[1,0]])=eye(2);        % adjust first and last column of matrix
u=[a,f((1:N-2)/N)*(N-1)^2,b]/A;   % build right hand side (as row vector) and right mu
plot(u)                           % plot the solution

Örnek olarak f = 10*x, u_L = 0 u_R = 1, N = 15bunun sonucu:


3

R, 123,2 102,9 98,7 bayt (% 141-30)

Edit: @Angs sayesinde bir avuç bayt kurtardı!

Birisi resimleri düzenlemek istiyorsa, bunu yapmaktan çekinmeyin. Bu temel olarak hem matlab hem de python sürümlerinin bir R uyarlamasıdır.

function(f,a,b,N){n=N-1;x=1:N/n;A=toeplitz(c(2,-1,rep(0,N-2)));A[1,1:2]=1:0;A[N,n:N]=0:1;y=n^-2*sapply(x,f);y[1]=a;y[N]=b;plot(x,solve(A,y))}

Açık ve açık:

u=function(f,a,b,N){
    n=N-1;                                              # Alias for N-1
    x=0:n/n;                                            # Generate the x-axis
    A=toeplitz(c(2,-1,rep(0,N-2)));                     # Generate the A-matrix
    A[1,1:2]=1:0;                                       # Replace first row--
    A[N,n:N]=0:1;                                       # Replace last row
    y=n^-2*sapply(x,f)                                  # Generate h^2*f(x)
    y[1]=a;y[N]=b;                                      # Replace first and last elements with uL(a) and uR(b)
    plot(x,solve(A,y))                                  # Solve the matrix system A*x=y for x and plot against x 
}

Örnek ve test örnekleri:

Adlandırılmış ve çözülmemiş işlev şu şekilde çağrılabilir:

u(function(x)-2,0,0,10)
u(function(x)x*10,0,1,15)
u(function(x)sin(2*pi*x),1,1,20)
u(function(x)x^2,0,0,30)

Not fbağımsız değişken bir R-fonksiyondur.

Golfçü versiyonunu çalıştırmak için (function(...){...})(args)

resim açıklamasını buraya girin resim açıklamasını buraya girin resim açıklamasını buraya girin resim açıklamasını buraya girin


Fonksiyon olarak is.numeric(f)bildirirseniz kontrolü bırakabileceğinizi düşünüyorum f, çözücüye doğrudan işlev çağrısında geçirmeniz gerekmez.
Karl Napf

Ah, görüyorum, bu ikisi arasında bir fark olduğunu bilmiyordum. Daha kısa olursa, çözücünüzü fbir işlev olarak kabul edecek şekilde değiştirebilirsiniz, böylece durumun sabit (işlev) olup olmadığını kontrol etmeniz gerekmez.
Karl Napf

1
@Billywob fhiç sayısal olmanıza gerek yok . f = (function(x)-2)ilk örnek için çalışır, bu yüzden asla buna ihtiyaç yoktur rep.
Angs

Sen kullanabilirsiniz x<-0:10/10;f<-function(x){-2};10^-2*sapply(x,f)f (x) vectorized edilecek quaranteed ya da sadece değilse 10^-2*f(x)eğer fvectorized edilir ( laplace(Vectorize(function(x)2),0,0,10)
ANG'ler

Eval kullanmayın, fuygun bir işlev olarak verin .
Angs

2

Haskell, 195168 bayt

import Numeric.LinearAlgebra
p f s e n|m<-[0..]!!n=((n><n)(([1,0]:([3..n]>>[[-1,2,-1]])++[[0,1]])>>=(++(0<$[3..n]))))<\>(col$s:map((/(m-1)^2).f.(/(m-1)))[1..m-2]++[e])

Okunabilirlik oldukça etkilendi. Ungolfed:

laplace f start end _N = linearSolveLS _M y
  where
  n = fromIntegral _N
  _M = (_N><_N) --construct n×n matrix from list
        ( ( [1,0]           --make a list of [1,0]
          : ([3.._N]>>[[-1,2,-1]]) --         (n-2)×[-1,2,-1]
          ++ [[0,1]])       --               [0,1]
        >>= (++(0<$[3.._N])) --append (n-2) zeroes and concat
        )                   --(m><n) discards the extra zeroes at the end
  h  = 1/(n-1) :: Double
  y  = asColumn . fromList $ start : map ((*h^2).f.(*h)) [1..n-2] ++ [end]

YAPILACAKLAR: 83 71 baytta yazdırma .

Lemme bkz:

import Graphics.Rendering.Chart.Easy
import Graphics.Rendering.Chart.Backend.Cairo

D'oh!


Haskell hakkında çok şey bilmiyorum, ama belki matris cebri olmayan çözüm daha kısa olabilir, ikinci bir örnek uygulama ekledim.
Karl Napf

@KarlNapf çok yaklaşmıyor Bu sadece yarı golf oynamakla birlikte, çok sayıda yerleşik işlev kullanmak zorunda. Matris cebiri ile kodun çoğu matrisi (64 bayt) ve içe aktarmayı (29 bayt) oluşturur. Kalıntı ve jacobi oldukça fazla yer kaplar.
Angs

Eh, çok kötü ama denemeye değerdi.
Karl Napf

1

Axiom, 579 460 bayt

l(w,y)==(r:=0;for i in 1..y|index?(i,w)repeat r:=i;r)
g(z:EQ EXPR INT,y:BasicOperator,a0:Float,a1:Float,a2:Float):Float==(r:=digits();digits(r+30);q:=seriesSolve(z,y,x=0,[a,b])::UTS(EXPR INT,x,0);w:=eval(q,0);s:=l(w,r+30);o:=solve([w.s=a0,eval(q,1).s=a1]::List(EQ POLY Float),[a,b]);v:=eval(eval(eval(q,a2).s,o.1.1),o.1.2);digits(r);v)
m(z:EXPR INT,a0:Float,a1:Float,n:INT):List Float==(n:=n-1;y:=operator 'y;r:=[g(D(y x,x,2)=-z,y,a0,a1,i/n)for i in 0..n];r)

ungolf ve test

Len(w,y)==(r:=0;for i in 1..y|index?(i,w)repeat r:=i;r)

-- g(z,a0,a1,a2)
-- Numeric solve z as f(y''(x),y'(x),y(x))=g(x) with ini conditions y(0)=a0   y(1)=a1 in x=a2
NSolve2order(z:EQ EXPR INT,y:BasicOperator,a0:Float,a1:Float,a2:Float):Float==
      r:=digits();digits(r+30)
      q:=seriesSolve(z,y,x=0,[a,b])::UTS(EXPR INT,x,0)
      w:=eval(q,0);s:=Len(w,r+30)
      o:=solve([w.s=a0,eval(q,1).s=a1]::List(EQ POLY Float),[a,b])
      v:=eval(eval(eval(q,a2).s,o.1.1),o.1.2);digits(r)
      v

InNpoints(z:EXPR INT,a0:Float,a1:Float,n:INT):List Float==(n:=n-1;y:=operator 'y;r:=[NSolve2order(D(y x,x,2)=-z,y,a0,a1,i/n)for i in 0..n];r)

sorunun işlevi m (,,,) 'dir yukarıdaki kod "file.input" dosyasına konur ve Axiom'a yüklenir. Sonuç, digits () işlevine bağlıdır.

Bazıları golf olmadığını düşünüyorsa => nasıl yapacağını gösterebilir ... teşekkürler

PS

Görünüşe göre 6 numaradan sonra. e ^ (x ^ 2) için burada veya örneklerde tamam değil ama burada basamakları artırıyorum ama sayılar değişmiyor ... benim için bu sayıların yanlış olduğu anlamına geliyor. Neden diğer herkes numaralarını göstermedi?

günah için (2 *% pi * x) de problem var

"Burada kesin çözüm u = (sin (2 * π * x)) / (4 * π ^ 2) +1" i x = 1/19 için kesin çözümü kopyaladım:

              (sin(2*π/19))/(4*π^2)+1

WolframAlpha https://www.wolframalpha.com/input/?i=(sin(2% CF% 80% 2F19))% 2F ( % 4 CF% 80% 5E2)% 2B1 sonuç

1.008224733636964333380661957738992274267070440829381577926...
1.0083001
  1234
1.00822473

Sonuç olarak önerilen 1.0083001, 4. basamakta gerçek sonuçtan farklıdır 1.00822473 ... (6. değil)

-- in interactive mode
(?) -> )read  file
(10) -> digits(9)
   (10)  10
                                                        Type: PositiveInteger
(11) -> m(-2,0,0,10)
   (11)
   [0.0, - 0.0987654321, - 0.172839506, - 0.222222222, - 0.24691358,
    - 0.24691358, - 0.222222222, - 0.172839506, - 0.098765432, 0.0]
                                                             Type: List Float
(12) -> m(10*x,0,1,15)
   (12)
   [0.0, 0.189868805, 0.376093294, 0.555029155, 0.72303207, 0.876457726,
    1.01166181, 1.125, 1.21282799, 1.27150146, 1.29737609, 1.28680758,
    1.2361516, 1.14176385, 1.0]
                                                             Type: List Float
(13) -> m(sin(2*%pi*x),1,1,20)
   (13)
   [1.0, 1.00822473, 1.01555819, 1.02120567, 1.0245552, 1.02524378, 1.02319681,
    1.0186361, 1.01205589, 1.00416923, 0.99583077, 0.987944112, 0.981363896,
    0.976803191, 0.97475622, 0.975444804, 0.978794326, 0.98444181, 0.991775266,
    1.0]
                                                         Type: List Float
(14) -> m(exp(x^2),0,0,30)
   (14)
   [0.0, 0.0202160702, 0.0392414284, 0.0570718181, 0.0737001105, 0.0891162547,
    0.103307204, 0.116256821, 0.127945761, 0.138351328, 0.147447305,
    0.155203757, 0.161586801, 0.166558343, 0.170075777, 0.172091643,
    0.172553238, 0.171402177, 0.168573899, 0.163997099, 0.157593103,
    0.149275146, 0.13894757, 0.126504908, 0.111830857, 0.0947971117,
    0.0752620441, 0.0530692118, 0.0280456602, - 0.293873588 E -38]
                                                             Type: List Float

Sayısal çözüm tam çözümden farklıdır, çünkü buradaki FDM sadece ikinci derecedir, yani sadece 2. sıraya kadar olan polinomlar tam olarak temsil edilebilir. Bu yüzden sadece f=-2örnekte eşleşen bir analitik ve sayısal çözüm vardır.
Karl Napf

burada rakamları 80 veya 70 -> g (günah (2 *% pi * x), 1,1,1 / 19) olarak değiştirirsem sayısal çözüm iyi görünüyor 1.0082247336 3696433338 0661957738 9922742670 7044082938 1577926908 950765832 diğer sayı 1.0082247336 3696433338 06619577 7044082938 1577926 ...
RosLuP
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.