라플라스 방정식 풀기


13

수치 수학 소개

이것이 "Hello, World!"입니다. PDE (부분 미분 방정식) 라플라스 또는 확산 방정식은 열 방정식, 변형, 유체 역학 등과 같은 물리학에서 자주 나타납니다. 실제는 3D이므로 "Hello, World!"라고 말하고 싶습니다. "99 병의 맥주"를 부르지 말고이 작업은 1D로 진행됩니다. 이를 힘이 가해져 양쪽 끝에 벽에 묶인 고무 로브로 해석 할 수 있습니다.

A의 [0,1]도메인 기능 찾을 u지정된 소스 기능 f및 경계 값 u_Lu_R같은 것을 :

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

u'' 의 이차 미분을 나타냄 u

이것은 순전히 이론적으로 해결할 수 있지만 당신의 임무는 점을 위해 이산 도메인 x 에서 숫자로 해결하는 것입니다 N.

  • x = {i/(N-1) | i=0..N-1}또는 1 기반 :{(i-1)/(N-1) | i=1..N}
  • h = 1/(N-1) 간격입니다

입력

  • f 함수 또는 표현식 또는 문자열로
  • u_L, u_R부동 소수점 값으로
  • N 정수> = 2

산출

  • 배열, 목록의 구분 문자열의 일종 u이되도록u_i == u(x_i)

실시 예 1

입력 : f = -2, u_L = u_R = 0, N = 10(하지 마십시오 f=-2잘못, 그것은 값 만 반환하는 일정한 기능을하지 않습니다 -2모든 x. 그것은 우리의 로프에 일정한 중력의 힘과 같다.)

산출: [-0.0, -0.09876543209876543, -0.1728395061728395, -0.22222222222222224, -0.24691358024691357, -0.24691358024691357, -0.22222222222222224, -0.1728395061728395, -0.09876543209876547, -0.0]

쉬운 정확한 해결책이 있습니다. u = -x*(1-x)

실시 예 2

입력 : f = 10*x, u_L = 0 u_R = 1, N = 15(여기서 우측 맞바람이 많을)

산출: [ 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.]

이 상태에 대한 정확한 해결책 : u = 1/3*(8*x-5*x^3)

실시 예 3

입력 : f = sin(2*pi*x), u_L = u_R = 1, N = 20(누군가가 중력을 위반하거나 위쪽 및 풍하의 종류가있다)

산출: [ 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.]

정확한 해결책은 다음과 같습니다. u = (sin(2*π*x))/(4*π^2)+1

실시 예 4

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

산출: [ 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. ]

약간의 비대칭 성을 유의하십시오

FDM

이를 해결하는 한 가지 가능한 방법은 유한 차분 법입니다 .

  • 다시 -u_i'' = f_i
  • (-u_{i-1} + 2u_i - u{i+1})/h² = f_i 어느 것이
  • -u_{i-1} + 2u_i - u{i+1} = h²f_i
  • 방정식을 설정하십시오.

  • 다음은 행렬-벡터 방정식과 같습니다.

  • 이 방정식을 풀고 u_i

파이썬 시연을위한 이것의 하나의 구현 :

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)

행렬 대수를 사용하지 않는 대체 구현 ( 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

그러나 Laplace 방정식을 풀기 위해 다른 방법을 사용할 수도 있습니다. 당신이 반복적 인 방법을 사용하는 경우 잔류 될 때까지 반복한다 |b-Au|<1e-6으로, b오른쪽 벡터 인u_L,f_1h²,f_2h²,...

노트

솔루션 방법에 따라 주어진 솔루션으로 예제를 정확하게 해결하지 못할 수 있습니다. 적어도 N->infinity오류의 경우 0에 접근해야합니다.

표준 허점은 허용되지 않으며 PDE 용 내장 기능이 허용됩니다.

보너스

솔루션을 그래픽 또는 ASCII로 표시하면 -30 %의 보너스.

승리

이것은 codegolf이므로 바이트 단위의 가장 짧은 코드가 승리합니다!


분석적으로 해결할 수없는 예를 추가하는 것이 좋습니다 (예 :) f(x) = exp(x^2).
flawr

@flawr 물론, 해결책이 있지만 오류 기능이 관련됩니다.
Karl Napf

1
죄송합니다. 어쩌면 잘못된 표현 일 것입니다. 나는 기본 기능으로는 표현할 수없는 것과 같은 기능 log(log(x))이나 sqrt(1-x^4)통합 기능이있는 기능을 의미 합니다.
flawr

@flawr 아니요 괜찮습니다. 오류 함수는 기본이 아니며 솔루션을 분석적으로 표현하는 방법이 있지만 u(x) = 1/2 (-sqrt(π) x erfi(x)+sqrt(π) erfi(1) x+e^(x^2)-e x+x-1)정확히 계산할 수는 없다고 말하고 싶었습니다 .
Karl Napf

1e-6까지 반복하고 1e-30까지 반복하지 않는 이유는 무엇입니까?
RosLuP

답변:


4

수학, 52.5 바이트 (= 75 * (1-30 %))

@flawr의 댓글 당 +0.7 바이트

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

출력을 플로팅합니다.

예 :

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

여기에 이미지 설명을 입력하십시오

설명

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

함수를 해결합니다 u.

Subdivide@#4

Subdivide N (4 번째 입력) 파트로의 간격 [0,1].

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

u의 출력에 매핑 하십시오 Subdivide.

ListPlot[ ... ]

최종 결과를 플로팅합니다.

비 그래프 솔루션 : 58 바이트

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

이것은 작동하지 않습니다f(x) = exp(x^2)
flawr

아마도 NDSolve기본이 아닌 솔루션의 일반적인 경우에 사용할 수 있습니다 .
flawr

6

Matlab, 84, 81.2 79.1 바이트 = 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)

이 예제에서 행 벡터를 사용한다는 것은 행렬 A이 바뀐 것을 의미합니다 . f함수 핸들로 사용 a,b되며, 왼쪽 / 오른쪽 Dirichlet 제약입니다.

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

예를 들면 f = 10*x, u_L = 0 u_R = 1, N = 15다음과 같습니다.


3

R, 123.2 102.9 98.7 바이트 (141-30 %)

편집 : @Angs 덕분에 몇 바이트를 절약했습니다!

누군가 그림을 편집하고 싶다면 자유롭게 편집하십시오. 이것은 기본적으로 게시 된 matlab 및 python 버전의 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))}

언 골프 드 & 설명 :

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 
}

예 및 테스트 사례 :

명명 된 및 ungolfed 함수는 다음을 사용하여 호출 할 수 있습니다.

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)

점을 유의 f인수가 R-기능입니다.

골프 버전을 실행하려면 (function(...){...})(args)

여기에 이미지 설명을 입력하십시오 여기에 이미지 설명을 입력하십시오 여기에 이미지 설명을 입력하십시오 여기에 이미지 설명을 입력하십시오


함수로 is.numeric(f)선언 하면 검사 를 취소 할 수 있다고 생각합니다 f. 솔버에 대한 함수 호출에서 직접 전달할 필요는 없습니다.
Karl Napf

아, 나는 그 둘 사이에 차이가 있다는 것을 몰랐다. 글쎄, 그것이 더 짧으면 f함수 로 받아 들여 지도록 솔버를 수정할 수 있으므로 사건을 확인할 필요가 없습니다 (함수).
Karl Napf

1
@Billywob는 f숫자가 될 필요가 없습니다 . f = (function(x)-2)첫 번째 예제에서 작동하므로 rep.

당신이 사용할 수있는 x<-0:10/10;f<-function(x){-2};10^-2*sapply(x,f)F (X)는 벡터화 할 quaranteed하거나하지 않은 경우 10^-2*f(x)경우 f벡터화 ( laplace(Vectorize(function(x)2),0,0,10)
Angs

eval을 사용하지 말고 f적절한 기능을 제공하십시오.
Angs

2

하스켈, 195168 바이트

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])

가독성이 대단했습니다. 언 골프 드 :

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]

TODO : 83 71 바이트로 인쇄 .

Lemme 참조 :

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

도!


나는 Haskell에 대해 많이 알지 못하지만 아마도 행렬 대수가없는 솔루션이 더 짧을 수도 있습니다. 두 번째 샘플 구현을 추가했습니다.
Karl Napf

@KarlNapf 는 매우 가까이에 오지 않습니다. 이것은 단지 반 골프이지만 많은 내장 함수를 사용해야합니다. 행렬 대수를 사용하면 대부분의 코드에서 행렬 (64 바이트)과 가져 오기 (29 바이트)를 작성합니다. 잔차와 jacobi는 많은 공간을 차지합니다.
Angs

글쎄, 너무 나쁘지만 시도해 볼 가치가 있었다.
Karl Napf

1

공리, 579460 바이트

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)

그것을 풀고 테스트

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)

질문에 대한 함수는 m (,,,)입니다. 위 코드는 "file.input"파일에 넣고 Axiom에로드합니다. 결과는 numeric () 함수에 따라 다릅니다.

골프를 치지 않았다고 생각하는 사람이 있다면 => 그 방법을 보여줄 수 있습니다 ... 감사합니다

추신

6 자리 숫자가 더 많을 것 같습니다. e ^ (x ^ 2)에 대해서는 여기 또는 예제에서 확인되지 않지만 여기에서는 숫자를 늘리지 만 숫자는 변경되지 않습니다 ... 나에게 그것은 예제의 숫자가 잘못되었음을 의미합니다. 왜 다른 사람들은 모두 숫자를 보여주지 않았습니까?

sin (2 * % pi * x)의 경우 문제도 있습니다

"여기서 정확한 해결책은 u = (sin (2 * π * x)) / (4 * π ^ 2) +1"입니다. x = 1 / 19에 대한 정확한 해결책을 복사했습니다.

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

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

1.008224733636964333380661957738992274267070440829381577926...
1.0083001
  1234
1.00822473

결과가 실제 결과 1.00822473과 4 번째 숫자가 다르므로 1.0083001이 제안되었습니다 (6 번째가 아님).

-- 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

여기에서 FDM이 2 차에 불과하기 때문에 수치 솔루션은 정확한 솔루션과 다릅니다. 즉, 2 차까지의 다항식 만 정확하게 표현할 수 있습니다. 따라서 f=-2예제 에만 일치하는 분석 및 수치 솔루션이 있습니다.
Karl Napf

여기에서 숫자를 80 또는 70으로 변경하면 숫자 솔루션은 괜찮은 것 같습니다. 7044082938 1577926 ...
RosLuP
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.