Розв’яжіть рівняння Лапласа


13

Вступ до числової математики

Це "Привіт, світ!" PDE (часткових диференціальних рівнянь). Рівняння Лапласа або Дифузії часто з'являється у фізиці, наприклад, рівняння тепла, деформування, динаміка рідини тощо. Оскільки реальне життя є 3D, але ми хочемо сказати "Привіт, світ!" а не співати "99 пляшок пива, ..." це завдання дано в 1Д. Ви можете трактувати це як гумовий халат, прив'язаний до обох кінців до стіни з певною силою, прикладеної до нього.

У [0,1]домені знайдіть функцію uдля заданої функції джерела fта граничні значення, u_Lі u_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

Вихідні дані

  • Array, List, якийсь відокремлений рядок 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

Одна реалізація цього для демонстрації в 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)

Альтернативна реалізація без матричної алгебри (використовуючи метод Якобі )

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

Однак ви можете використовувати будь-який інший метод для розв’язання рівняння Лапласа. Якщо ви використовуєте ітеративний метод, слід повторити його до залишкового значення |b-Au|<1e-6, bбудучи вектором правого бокуu_L,f_1h²,f_2h²,...

Примітки

Залежно від способу рішення, ви не можете вирішувати приклади саме до заданих рішень. Принаймні, щоб N->infinityпомилка повинна наближатися до нуля.

Стандартні лазівки заборонені , дозволено вбудовувати PDE.

Бонус

Бонус -30% за показ рішення, графічного або ASCII-art.

Перемога

Це codegolf, тому найкоротший код у байтах виграє!


Я рекомендую додати приклад, який не вирішується аналітично, наприклад, з f(x) = exp(x^2).
flawr

@flawr Звичайно, у нього є рішення, однак функція помилки задіяна.
Карл Напф

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)він не є точно обчислюваним.
Карл Напф

Чому ітерація до 1е-6, а не ітерація до 1е-30?
RosLuP

Відповіді:


4

Математика, 52,5 байт (= 75 * (1 - 30%))

+0,7 байт за коментар @flawr.

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 інтервал [0,1] на N (четвертий вхід) частин.

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

Карта uна вихід Subdivide.

ListPlot[ ... ]

Накресліть кінцевий результат.

Не графічне рішення: 58 байт

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

Це не спрацьовуєf(x) = exp(x^2)
помилка

Можливо, ви можете використовувати 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є лівою / правою стороною Діріхле протипоказання.

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!

Якщо хтось хоче редагувати фотографії, сміливо робіть це. Це в основному R-адаптація як розміщених версій matlab, так і python.

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 
}

Приклад та тестові приклади:

Іменовану функцію та функцію, що не має волі, можна викликати, використовуючи:

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функцію, не потрібно передавати його безпосередньо у виклику функції до вирішувача.
Карл Напф

Ах бачу, я не знав, що між цими двома є різниця. Добре, якщо він коротший, ви можете змінити вирішувач, щоб прийняти його fяк функцію, так що вам не доведеться перевіряти, чи справа це константа (функція).
Карл Напф

1
@Billywob не потрібно fніколи бути числовим. f = (function(x)-2)працює для першого прикладу, тому ніколи в цьому не потрібно rep.
Ангс

Ви можете використовувати, x<-0:10/10;f<-function(x){-2};10^-2*sapply(x,f)якщо f (x) не має 10^-2*f(x)flaplace(Vectorize(function(x)2),0,0,10
гарантії на векторність

Не використовуйте eval, надайте fяк належну функцію.
Ангс

2

Haskell, 195 168 байт

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 байт.

Лемма див .:

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

D'oh!


Я не знаю багато про Haskell, але, можливо, рішення без матричної алгебри може бути коротшим, я додав другу реалізацію вибірки.
Карл Напф

@KarlNapf не дуже близький Це лише напівгольф, але він повинен використовувати багато вбудованих функцій. З алгебри матриці більша частина коду будує матрицю (64 байти) та імпорт (29 байт). Залишки і джакобі займають досить багато місця.
Ангс

Ну, дуже погано, але варто було спробувати.
Карл Напф

1

Аксіома, 579 460 байт

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 це і тест

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. Результат залежить від функції digits ().

якщо хтось думає, що це не гольф => він чи вона можуть показати, як це зробити ... дякую

PS

здається, 6 цифр після цього. для e ^ (x ^ 2) не нормально тут чи в прикладах, але тут я збільшую цифри, але цифри не змінюються ... для мене це означає, що числа в прикладі неправильні. Чому всі інші не показали своїх номерів?

для гріха (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.0083001 відрізняється в 4-й цифрі від реального результату 1.00822473 ... (а не 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 можуть бути точно представлені. Тож лише f=-2приклад має відповідне аналітичне та числове рішення.
Карл Напф

тут числове рішення здається нормальним, якщо я зміню цифри на 80 або 70 -> g (sin (2 *% pi * x), 1,1,1 / 19) 7044082938 1577926 ...
RosLuP
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.