Giải phương trình Laplace


13

Giới thiệu về Toán số

Đây là "Xin chào, Thế giới!" của PDEs (Phương trình vi phân từng phần). Phương trình Laplace hoặc Diffusion xuất hiện thường xuyên trong Vật lý, ví dụ Phương trình nhiệt, Biến dạng, Động lực học, v.v ... Vì cuộc sống thực là 3D nhưng chúng tôi muốn nói "Xin chào, Thế giới!" và không hát "99 chai bia, ..." nhiệm vụ này được đưa ra trong 1D. Bạn có thể giải thích điều này như một chiếc áo choàng cao su được buộc vào một bức tường ở cả hai đầu với một lực tác dụng lên nó.

Trên một [0,1]miền, tìm một hàm ucho hàm nguồn đã cho fvà các giá trị biên u_Lu_Rnhư vậy:

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

u'' biểu thị đạo hàm thứ hai của u

Điều này có thể được giải quyết hoàn toàn trên lý thuyết nhưng nhiệm vụ của bạn là giải quyết nó bằng số trên một miền x rời rạc cho Ncác điểm:

  • x = {i/(N-1) | i=0..N-1}hoặc 1 dựa trên:{(i-1)/(N-1) | i=1..N}
  • h = 1/(N-1) là khoảng cách

Đầu vào

  • f như hàm hoặc biểu thức hoặc chuỗi
  • u_L, u_Rnhư các giá trị dấu phẩy động
  • N là số nguyên> = 2

Đầu ra

  • Mảng, Danh sách, một số loại chuỗi tách biệt unhư vậyu_i == u(x_i)

Ví dụ

ví dụ 1

Input: f = -2, u_L = u_R = 0, N = 10(không dùng f=-2sai, nó không phải là một giá trị nhưng một hàm liên tục mà lợi nhuận -2cho tất cả xNó giống như một trọng lực liên tục trên dây của chúng tôi..)

Đầu ra: [-0.0, -0.09876543209876543, -0.1728395061728395, -0.22222222222222224, -0.24691358024691357, -0.24691358024691357, -0.22222222222222224, -0.1728395061728395, -0.09876543209876547, -0.0]

Có một giải pháp chính xác dễ dàng: u = -x*(1-x)

Ví dụ 2

Input: f = 10*x, u_L = 0 u_R = 1, N = 15(Ở đây có rất nhiều hướng gió ở phía bên phải)

Đầu ra: [ 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.]

Giải pháp chính xác cho trạng thái này: u = 1/3*(8*x-5*x^3)

Ví dụ 3

Input: f = sin(2*pi*x), u_L = u_R = 1, N = 20(người đã phá vỡ nghiêm trọng hoặc có một loại cập nhật mới và hướng gió)

Đầu ra: [ 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.]

Đây là giải pháp chính xác u = (sin(2*π*x))/(4*π^2)+1

Ví dụ 4

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

Đầu ra: [ 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. ]

Lưu ý sự không đối xứng nhẹ

FDM

Một phương pháp khả thi để giải quyết điều này là Phương pháp khác biệt hữu hạn :

  • viết lại -u_i'' = f_inhư
  • (-u_{i-1} + 2u_i - u{i+1})/h² = f_i bằng
  • -u_{i-1} + 2u_i - u{i+1} = h²f_i
  • Thiết lập các phương trình:

  • Bằng với phương trình vectơ ma trận:

  • Giải phương trình này và xuất ra u_i

Một triển khai này để trình diễn trong 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)

Thực hiện thay thế mà không cần Đại số ma trận (sử dụng phương pháp 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

Tuy nhiên, bạn có thể sử dụng bất kỳ phương pháp nào khác để giải phương trình Laplace. Nếu bạn sử dụng phương pháp lặp, bạn nên lặp lại cho đến khi dư |b-Au|<1e-6, với bvectơ bên phảiu_L,f_1h²,f_2h²,...

Ghi chú

Tùy thuộc vào phương pháp giải pháp của bạn, bạn có thể không giải quyết chính xác các ví dụ cho các giải pháp đã cho. Ít nhất là cho N->infinitylỗi nên gần bằng không.

Các lỗ hổng tiêu chuẩn không được phép , tích hợp sẵn cho các PDE được cho phép.

Tặng kem

Phần thưởng -30% khi hiển thị giải pháp, theo đồ họa hoặc nghệ thuật ASCII.

Chiến thắng

Đây là codegolf, vì vậy mã ngắn nhất trong byte thắng!


Tôi khuyên bạn nên thêm một ví dụ không thể phân tích được, ví dụ như với f(x) = exp(x^2).
flawr

@flawr Chắc chắn, nó có một giải pháp tuy nhiên chức năng lỗi có liên quan.
Karl Napf 7/11/2016

1
Xin lỗi, đó có lẽ là biểu hiện sai, có thể "chống phản xạ không tiểu học" phù hợp hơn? Tôi có nghĩa là các chức năng như log(log(x))hoặc sqrt(1-x^4)có một tích phân, tuy nhiên không thể biểu thị trong các chức năng cơ bản.
flawr

@flawr Không ổn, chức năng lỗi không phải là sơ cấp, tôi chỉ muốn nói có một cách để thể hiện giải pháp một cách phân tích nhưng u(x) = 1/2 (-sqrt(π) x erfi(x)+sqrt(π) erfi(1) x+e^(x^2)-e x+x-1)không thể tính toán chính xác.
Karl Napf 7/11/2016

Tại sao lặp lại cho đến 1e-6 và không lặp lại cho đến 1e-30?
RosLuP

Câu trả lời:


4

Toán học, 52,5 byte (= 75 * (1 - 30%))

+ 0,7 byte cho mỗi bình luận của @flawr.

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

Điều này âm mưu đầu ra.

ví dụ

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

nhập mô tả hình ảnh ở đây

Giải trình

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

Giải các hàm u.

Subdivide@#4

Subdivide khoảng [0,1] thành các phần N (đầu vào thứ 4).

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

Bản đồ uđến đầu ra của Subdivide.

ListPlot[ ... ]

Vẽ kết quả cuối cùng.

Giải pháp không vẽ đồ thị: 58 byte

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

Điều này không hoạt động chof(x) = exp(x^2)
flawr 7/11/2016

Có lẽ bạn có thể muốn sử dụng NDSolvecho trường hợp chung của các giải pháp không cơ bản.
flawr

6

Matlab, 84, 81,2 79,1 byte = 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)

Lưu ý rằng trong ví dụ này, tôi sử dụng các vectơ hàng, điều này có nghĩa là ma trận Ađược hoán vị. fđược thực hiện như một hàm xử lý, a,blà các mâu thuẫn Dirichlet bên trái / bên phải.

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

Đối với ví dụ f = 10*x, u_L = 0 u_R = 1, N = 15này, kết quả là:


3

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

Chỉnh sửa: Đã lưu một số byte nhờ @Angs!

Nếu ai đó muốn chỉnh sửa hình ảnh, hãy làm như vậy. Về cơ bản, đây là bản chuyển thể R của cả phiên bản matlab và python được đăng.

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

Ungolfed & giải thích:

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 
}

Ví dụ & trường hợp thử nghiệm:

Hàm được đặt tên và không được phép có thể được gọi bằng cách sử dụng:

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)

Lưu ý rằng fđối số là hàm R.

Để chạy phiên bản golf, chỉ cần sử dụng (function(...){...})(args)

nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây


Tôi nghĩ bạn có thể bỏ is.numeric(f)kiểm tra nếu bạn khai báo flà hàm, không có yêu cầu chuyển trực tiếp nó trong lệnh gọi hàm đến bộ giải.
Karl Napf

À tôi hiểu rồi, tôi không biết có sự khác biệt giữa hai thứ đó. Chà, nếu nó ngắn hơn, bạn có thể sửa đổi bộ giải của mình để chấp nhận flà một hàm để bạn không phải kiểm tra trường hợp đó là hằng số (hàm).
Karl Napf 7/11/2016

1
@Billywob không cần phải flà số. f = (function(x)-2)làm việc cho ví dụ đầu tiên, vì vậy không bao giờ cần phải làm vậy rep.
Angs

Bạn có thể sử dụng x<-0:10/10;f<-function(x){-2};10^-2*sapply(x,f)nếu f (x) không được cách ly để được vector hóa hoặc chỉ 10^-2*f(x)khi fđược vector hóa ( laplace(Vectorize(function(x)2),0,0,10)
Angs

Đừng sử dụng eval, cung cấp fnhư là một chức năng thích hợp.
Angs

2

Haskell, 195 168 byte

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

Khả năng đọc mất khá nhiều. Ung dung:

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: In bằng 83 71 byte.

Để tớ xem nào:

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

Ôi!


Tôi không biết nhiều về Haskell, nhưng có lẽ giải pháp không có đại số ma trận có thể ngắn hơn, tôi đã thêm một triển khai mẫu thứ hai.
Karl Napf 7/11/2016

@KarlNapf không đến rất gần Đây chỉ là bán gôn nhưng nó phải sử dụng rất nhiều chức năng tích hợp dài dòng. Với đại số ma trận, hầu hết các mã đang xây dựng ma trận (64 byte) và nhập (29 byte). Phần còn lại và jacobi chiếm khá nhiều không gian.
Angs

Chà, quá tệ nhưng nó đáng để thử.
Karl Napf 7/11/2016

1

Tiên đề, 579 460 byte

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 nó và kiểm tra

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)

hàm cho câu hỏi là m (,,,) đoạn mã trên được đặt trong tệp "file.input" và tải trong Axiom. Kết quả phụ thuộc vào hàm chữ số ().

nếu ai đó nghĩ rằng nó không được đánh gôn => người đó có thể chỉ cho bạn cách làm ... cảm ơn

PS

Có vẻ như 6 số phía sau. đối với e ^ (x ^ 2) không ổn ở đây hoặc trong các ví dụ nhưng ở đây tôi tăng các chữ số nhưng số không thay đổi ... đối với tôi, điều đó có nghĩa là các số trong ví dụ là sai. Tại sao tất cả những người khác đã không hiển thị số của họ?

đối với sin (2 *% pi * x) cũng có vấn đề

"Ở đây, giải pháp chính xác là u = (sin (2 * π * x)) / (4 * π ^ 2) +1" tôi đã sao chép giải pháp chính xác cho x = 1/19:

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

trong WolframAlpha https://www.wolframalpha.com/input/?i=(sin(2% CF% 80% 2F19))% 2F (4 % CF% 80% 5E2)% 2B1 kết quả

1.008224733636964333380661957738992274267070440829381577926...
1.0083001
  1234
1.00822473

1,0083001 được đề xuất là kết quả khác với chữ số thứ 4 so với kết quả thực 1.00822473 ... (chứ không phải thứ 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

Giải pháp số khác với giải pháp chính xác vì FDM ở đây chỉ là bậc hai, điều đó có nghĩa là chỉ các đa thức cho đến bậc 2 mới có thể được biểu diễn chính xác. Vì vậy, chỉ có f=-2ví dụ có một giải pháp phân tích và số phù hợp.
Karl Napf

Ở đây, giải pháp số có vẻ ổn nếu tôi thay đổi chữ số thành 80 hoặc 70 -> g (sin (2 *% pi * x), 1,1,1 / 19) 1.0082247336 3696433338 0661957738 9922742670 7044082938 1577926908 950765832 số khác 1.0082247333333 7044082938 1577926 ...
RosLuP
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.