You are on page 1of 11

Проект 3: Предиктор-коректор

ü Персонална информация

Име Светлин Анков


Ф.№ 31 082
ад. гр. 2
вариант 14

ü Условие на задачата

„ Начални данни

u' HxL = , x ∈ H0, 1L


u2 − x + 0.5
(1)
x2 + u + 1
u H0L = 0 (2)

„ Брой стъпки

N = 40

„ Формула предиктор

H0L
I55 y'i − 59 yi−1 M
h ' ' '
yi+1 = yi + + 37 yi−2 − 9 yi−3 (3)
24

„ Формула коректор

K9 Jyi+1 N + 19 y'i − 5 yi−1 O


Hj+1L h HjL ' ' '
yi+1 = yi + + yi−2 (4)
24

ü Встъпителни думи

ü Коментар върху условието

метод, а (4) е 3-стъпков интерполационен метод, то и двата метода имат локална грешка OIh4 M. Този факт за (4) е показан
Видно е, че формулите (3) и (4) са валидни формули на Адамс. При това, предвид че (3) е 4-стъпков екстраполационен

y1 , y2 и y3 ще ползваме следните четириетапни формули на Рунге-Кута с локална грешка OIh4 M


по-долу. Следователно предвид условията на задачата (а и по естествени съображения), за намиране на началните данни

Hk1 + 2 k2 + 2 k3 + k4L
1
yi+1 = yi +
6

k1 = h f Hxi , yi L
h k1 (5)
k2 = h f xi + , yi +
2 2
h k2
k3 = h f xi + , yi +

k4 = h f Hxi + h, yi + k3 L
2 2
2 Предиктор-коректор

ü Изчисляване на локалната грешка на формулата коректор

„ Изчисляване на локална грешка на диференчен метод

Локална грешка се изчислява, като запишем първо формулата във вида:


HLh yh Li − HL yLi

Което за методите на Адамс означава:

‚ ai ym+i − ‚ bi ym+i
1 k k
'
h i=0 i=0

След това около xm развиваме в ред на Тейлър y j и y'j , където j ∫ m. Както ще видим по-долу, от голямо значение е до кой
член ще развием, тъй като развитие, където броят на членовете е по-малък от реда на търсената грешка няма да даде
коректни резултати. Затова и важността на експериментите не е за пренебрегване.

Последно, групираме множителите по h (като същевременно някои от тях се унищожават) и виждаме коя е най-ниската
степен на h (след като сме изпосъкратили), т.е. от кое h нататък имаме разлика с оригинала.

„ Изчисляване на грешката посредством Mathematica

Нека сметнем локалната грешка на (4), използвайки Mathematica. Тук ползваме постфиксен запис (//) – често стрещана

можем да запишем x êê G êê F. Чрез TraditionalForm получаваме резултатите в по-математически вид (например огражда
практика. За удобство, при записването на композиция от едноаргументни функции, вместо F@G@xDD, в Mathematica

аргументите не в квадратни скоби, а в кръгли и т.н.).

H9 y '@i + 1D + 19 y '@iD − 5 y '@i − 1D + y '@i − 2DL êê TraditionalForm


y@i + 1D − y@iD 1

h 24

H-y£ Hi - 2L + 5 y£ Hi - 1L - 19 y£ HiL - 9 y£ Hi + 1LL


yHi + 1L - yHiL 1
+
h 24

За да продължим, трябва да запишем израза по-коректно – в досегашния запис y@iD отговаряше (само) логически на yi .
Сега ще го заместим с y@x@iDD. За тази цел се обръщаме към последния изход с % и ползваме ReplaceAll (/.), Rule (Ø) и
patterns.
% ê. 8y@w_D → y@x@wDD, y '@w_D → y '@x@wDD< êê Expand êê TraditionalForm

y£ HxHi - 2LL + y£ HxHi - 1LL - y£ HxHiLL - y£ HxHi + 1LL


yHxHiLL yHxHi + 1LL 1 5 19 3
- + -
h h 24 24 24 8

Нека зададем променлива terms за брой членове в редовете на Тейлър.

terms = 7;
Светлин Анков 3

Сега да заместим y@i + нещоD и y '@i + нещоD със съответните им представяния в редове на Тайлър.

%% ê. 8y@x@i + w_DD → Series@y@x@i + wDD, 8x@i + wD, x@iD, terms<D,


y '@x@i + w_DD → Series@y '@x@i + wDD, 8x@i + wD, x@iD, terms<D< êê TraditionalForm

y£ HxHiLL y££ HxHiLL


-y£ HxHiLL + HxHi + 1L - xHiLL y££ HxHiLL + HxHi + 1L - xHiLL2 yH3L HxHiLL + HxHi + 1L - xHiLL3
3 3
- -
h 8 2h 16
yH3L HxHiLL yH4L HxHiLL yH5L HxHiLL
yH4L HxHiLL + HxHi + 1L - xHiLL4 yH5L HxHiLL + HxHi + 1L - xHiLL5 yH6L HxHiLL +
1 1 1
- - -
6h 16 24 h 64 120 h 320
yH6L HxHiLL yH7L HxHiLL yH7L HxHiLL yH8L HxHiLL
HxHi + 1L - xHiLL6 - + HxHi + 1L - xHiLL7 - + OIHxHi + 1L - xHiLL8 M +
720 h 1920 5040 h 13 440

HxHi - 1L - xHiLL y££ HxHiLL + HxHi - 1L - xHiLL2 yH3L HxHiLL + HxHi - 1L - xHiLL3 yH4L HxHiLL +
5 5 5
24 48 144

HxHi - 1L - xHiLL4 yH5L HxHiLL + HxHi - 1L - xHiLL5 yH6L HxHiLL +


5 1
576 576
HxHi - 1L - xHiLL6 yH7L HxHiLL HxHi - 1L - xHiLL7 yH8L HxHiLL
+ + OIHxHi - 1L - xHiLL8 M -
3456 24 192

HxHi - 2L - xHiLL y££ HxHiLL - HxHi - 2L - xHiLL2 yH3L HxHiLL -


1 1
24 48

HxHi - 2L - xHiLL3 yH4L HxHiLL -


1
144

HxHi - 2L - xHiLL4 yH5L HxHiLL -


1
576
HxHi - 2L - xHiLL5 yH6L HxHiLL
-
2880
HxHi - 2L - xHiLL6 yH7L HxHiLL
-
17 280
HxHi - 2L - xHiLL7 yH8L HxHiLL
+ OIHxHi - 2L - xHiLL8 M
120 960

Сега изразяваме x@iD чрез x0 и h.

% ê. x@i_D → x0 + i h êê TraditionalForm

SeriesData::sdatv : First argument h H1 + iL + x0 is not a valid variable. à

SeriesData::sdatv : First argument h H-1 + iL + x0 is not a valid variable. à

SeriesData::sdatv : First argument h H-2 + iL + x0 is not a valid variable. à

General::stop : Further output of SeriesData::sdatv will be suppressed during this calculation. à


4 Предиктор-коректор

Не стана. Тъй като при работа с редове Mathematica има "едно наум", то нагледно неочудващият резултат от Series
всъщност не представлява обичаен израз, а символ от тип SeriesData. Използвайки Normal ще "култивираме" израза.
H%% êê NormalL ê. x@i_D → x0 + i h êê TraditionalForm

Hh Hi - 2L - h iL7 yH8L Hh i + x0L Hh Hi - 2L - h iL6 yH7L Hh i + x0L Hh Hi - 2L - h iL5 yH6L Hh i + x0L


- - - -
120 960 17 280 2880

Hh Hi - 2L - h iL4 yH5L Hh i + x0L - Hh Hi - 2L - h iL3 yH4L Hh i + x0L - Hh Hi - 2L - h iL2 yH3L Hh i + x0L +


1 1 1
576 144 48
yH3L Hh i + x0L
Hh Hi - 1L - h iL2 yH3L Hh i + x0L + Hh Hi + 1L - h iL3 yH4L Hh i + x0L + Hh Hi - 1L - h iL3 yH4L Hh i + x0L +
5 1 5
-
48 6h 16 144
yH4L Hh i + x0L
Hh Hi + 1L - h iL4 yH5L Hh i + x0L + Hh Hi - 1L - h iL4 yH5L Hh i + x0L +
1 5
-
24 h 64 576
yH5L Hh i + x0L
Hh Hi + 1L - h iL5 yH6L Hh i + x0L + Hh Hi - 1L - h iL5 yH6L Hh i + x0L +
1 1
-
120 h 320 576
yH6L Hh i + x0L yH7L Hh i + x0L Hh Hi - 1L - h iL6 yH7L Hh i + x0L yH7L Hh i + x0L yH8L Hh i + x0L
Hh Hi + 1L - h iL6 - + + Hh Hi + 1L - h iL7 - +
720 h 1920 3456 5040 h 13 440
Hh Hi - 1L - h iL7 yH8L Hh i + x0L
Hh Hi - 2L - h iL y££ Hh i + x0L + Hh Hi - 1L - h iL y££ Hh i + x0L -
1 5
-
24 192 24 24
y££ Hh i + x0L y£ Hh i + x0L
y£ Hh i + x0L + Hh Hi + 1L - h iL2 yH3L Hh i + x0L + Hh Hi + 1L - h iL y££ Hh i + x0L
3 3
- -
2h 16 h 8

Разкриваме скобите.

% êê Expand êê TraditionalForm

19 h7 yH8L Hh i + x0L 113 h6 yH7L Hh i + x0L 11 h5 yH6L Hh i + x0L


h4 yH5L Hh i + x0L
19
- + -
20 160 30 240 1440 720

Ето, че получихме търсения резултат. Грешката е OAh4 E.


Светлин Анков 5

„ Програма за изчисляване на локалната грешка

За да покажем важността на броя членове в редовете на Тейлър, нека съберем горния алгоритъм в програмка с име
estimateError. Тук съм направил програмата да работи при всякакви производни yHkL . При това в последната стъпка
представям x0 + i h отново във вида xi . Необходимо е променливите да са y и i, при това символи (т.е. с незададени
числени стойности).
estimateError@expr_, terms_D :=
ModuleA
8exp = expr<,
exp = Iexp ê. 8y@w_D → y@x@wDD, Derivative@z_D@yD@w_D → Derivative@zD@yD@x@wDD<M;
exp = Iexp ê. 8Derivative@z_D@yD@x@i + k_DD → Series@Derivative@zD@yD@x@i + kDD,
8x@i + kD, x@iD, terms<D, y@x@i + k_DD −> Series@y@x@i + kDD, 8x@i + kD, x@iD, terms<D<M;
exp = IIHexp êê NormalL ê. x@i_D → x0 + i hM êê ExpandM;
exp = exp ê. Ix0 + i_ hM → x@iD; H∗ Връщаме пак в x@iD ∗L
exp êê TraditionalForm
E

За (4) тогава получаваме същия резултат при 7 члена.

H9 y '@i + 1D + 19 y '@iD − 5 y '@i − 1D + y '@i − 2DL, 7F


y@i + 1D − y@iD 1
estimateErrorB −
h 24
19 h7 yH8L HxHiLL 113 h6 yH7L HxHiLL 11 h5 yH6L HxHiLL
h4 yH5L HxHiLL
19
- + -
20 160 30 240 1440 720

При 4 члена методът все още е с грешка OIh4 M

H9 y '@i + 1D + 19 y '@iD − 5 y '@i − 1D + y '@i − 2DL, 4F


y@i + 1D − y@iD 1
estimateErrorB −
h 24

h4 yH5L HxHiLL
5
-
144

При 3 члена обаче, грешката вече е OIh3 M, а не задължително нула, както някой биха очаквали.

H9 y '@i + 1D + 19 y '@iD − 5 y '@i − 1D + y '@i − 2DL, 3F


y@i + 1D − y@iD 1
estimateErrorB −
h 24

h3 yH4L HxHiLL
1
-
24

При 2 също не дава нула.

H9 y '@i + 1D + 19 y '@iD − 5 y '@i − 1D + y '@i − 2DL, 2F


y@i + 1D − y@iD 1
estimateErrorB −
h 24

- h2 yH3L HxHiLL
1
6

Това показва значението на броя членове за експерименталното пресмятане на локалната грешка на апроксимация.

Още да изтъкнем, че estimateError може да даде грешката и за друг диференчен метод. Наприм, на метода на Ойлер.

y@i + 1D − y@iD
estimateErrorB − y '@iD, 2F
h

h y££ HxHiLL
1
2
6 Предиктор-коректор

Последно, можем да доизпипаме програмата да връща резултата във вида OHhn L. Забележете, че в Mathematica коректния
начин на записване на остатъчния член е не O@hn D, а O@hDn . Въпреки това в TraditonalForm Mathematica ще ползва
познатото ни означение.
estimateErrorO@expr_, terms_D :=
Module@
8exp = HestimateError@expr, termsDL@@1DD<,
H∗ P1T защото имаме TraditionalForm@...D ∗L
exp = exp ê. 8h → h@1D, hx_ → h@xD<;
exp = Cases@exp, h@x_D, ∞D;
exp = Min @ exp@@All, 1DD;
If@exp ∞,
Print@"Грешката е по−голяма от OHhL!"D;
Return@D;
D;
O@hDexp êê TraditionalForm
D;

Ето например как се ползва методът за формула (4):

H9 y '@i + 1D + 19 y '@iD − 5 y '@i − 1D + y '@i − 2DL, 8F


y@i + 1D − y@iD 1
estimateErrorOB −
h 24
OIh4 M
Светлин Анков 7

ü Реализация на програмата

ü Реализация на метода на Рунге-Кута

Функцията rungekutta4 е пълнофункционален метод за намиране на приближено решение по формулите (5). По-нататък
ще я използваме за намирането на началните стойности, необходими, за да "тръгне" Адамс.

В реализацията използваме SetDelayed (:=), тъй като въвеждаме функция. Използваме долна черта (Blank: _ ) след
имената на аргументите, за да укажем, че не става дума за конкретни x и u, а за първи и втори аргумент на функция (т.е.
използваме patterns). Още използваме Module, за да ограничим променливите да имат локална природа (нещо обичайно в
смисъла на функция, но неавтоматизирано при писането на Mathematica. Този факт не е недостатък, а по-скоро резултат
на обобщения характер на езика). Също така ползваме и NestList, който е и един от начините във функционалното
програмиране за реализиране на итерация.
rungekutta4@f_, x0_, X_, u0_, n_D :=
ModuleB8h, rg4it<,
H∗ Забележка: Естесвено y0 === u0 ∗L

H∗ смятаме h ∗L
X − x0
h= ;

H∗
n

Задаваме локална функция rg4it, правеща итерацията. Забележете,


че h е локално за rungekutta4, но е глобално за rg4it. По този начин не се налага всеки
път да предаваме h като параметър, h не е регистрирана в контекста на ноутбука,
а и така функцията е "безвредна" Hт.е. неупотребимаL в чужди ръце.
∗L

rg4it@8xold_, yold_<D :=
ModuleB8k1, k2, k3, k4<,
k1 = h f@xold, yoldD;

F;
h k1
k2 = h fBxold + , yold +
2 2

F;
h k2
k3 = h fBxold + , yold +
2 2
k4 = h f@xold + h, yold + k3D;

:xold + h, yold + Hk1 + 2 k2 + 2 k3 + k4L>


1
6
F;

H∗ Итерираме n пъти ∗L
NestList@rg4it, 8x0, u0<, nD
F

Нека пробваме функцията с произволни данни. Сравнявайки например с резултати от ODE, ще се убедим, че работи
правилно. В долния пример ползвам анонимна функция, която може да се чете като u + 1 (т.е. втория параметър за f
(който е u) плюс единица).
rungekutta4@H 2 + 1L &, 0, 1, 1, 10D êê N êê Transpose êê Grid

0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.


1. 1.21034 1.44281 1.69972 1.98365 2.29744 2.64424 3.0275 3.45108 3.9192 4.43656

Използваме N, за да получим числен отговор (в противен случай Mathematica връща едни страшни дроби). Последно
ползваме Transpose, за да завъртим таблицата от числа и Grid, за да получим по четлив резултат (иначе ще получим
списъци, заградени във фугирни скоби – не много удобно за четене).
8 Предиктор-коректор

Реализация на предиктор-коректор метода

Вече сме готови да напишем основния метод за проекта – predcorr. Още в сигнатурата на функцията чрез оператора за
условие, задаваме тя да е валидна само за целочислени n ¥ 0, а също задаваме и стойности по подразбиране за x и maxit.
predcorr@f_, x0_, X_, u0_, n_Integer ê; 0 ≤ n < ∞, ξ_: 0.00001, maxit_Integer: 3D :=
ModuleB
8x, y, iterations, g, h, predcorrit<,
H∗ списък с локалните променливи ∗L

H∗
Забележка
Естесвено y0 = u00
Също така y'i = fHxi ,yi L
∗L

H∗ Тъй като по логически съображения не можем да зададем стойност по подразбиране


за опционален аргумент и едновременно да го ограничим с условие чрез ê;,
необходимо е да зададем стандартни стойности за ξ и max_it,
при въведени некоректни данни. ∗L

If @ξ ≤ 0, ξ = 0.00001D;
If@maxit ≤ 0, maxit = 3D;

H∗ Смятаме h ∗L
X − x0
h= ;
n

H∗ Заделяме памет за резултата,


който е във вида 8xi ,yi ,iti <, като още от сега си попълваме мрежата за xi ∗L
8x, y, iterations< = Transpose @ Table@8x0 + i h, 0, 0<, 8i, 0, n<D;

H∗ Да проверим дали n < 4 и следователно няма да можем да приложим Адамс,


а само Рунге−Кута ∗L
If@n < 4,
Return@
rungekutta4@f, x0, X, u0, nD
D
D;

H∗ Използваме rungekutta4, за да сметнем четирите начални стойности. За


да имаме достъп до елемента i на списъка m, се използва израз от вида:
m@@iDD Hдве поредни средни скоби от всяка страна на индексаL. За да покажем интервал,
ползваме Span H;;L – идентичен Hне напълно – виж още и Range на оператора : в MatlabL ∗L
y@@1 ;; 4DD = rungekutta4@f, x0, x0 + 3 h, u0, 3D@@All, 2DD;

H∗ За по−удобно дефинираме функция g@iD, равняваща се на y'i . ∗L


Светлин Анков 9

g@i_D := f@x@@iDD, y@@iDDD;

H∗ Пишем итериращата част на метода – тази,


която се извиква за всяка Hбез началните точки, разбира сеL точка от
мрежата. Първата стойност на приближението се получава по формулата предиктор. ∗L
predcorrit@i_D :=
ModuleB

:lastApprox = y@@iDD + H55 g@iD − 59 g@i − 1D + 37 g@i − 2D − 9 g@i − 3DL,


h
24
approx, diff = ∞, it = 0>,
H∗ В началото diff е ∞,
тъй като е нужна поне една итерация, за да е определена разликата. ∗L

WhileBdiff > ξ && it ≤ maxit,

H9 f@x@@i + 1DD, lastApproxD + 19 g@iD − 5 g@i − 1D + g@i − 2DL;


h
approx = y@@iDD +
24
diff = Abs@approx − lastApproxD;
lastApprox = approx;
it ++;
F;
y@@i + 1DD = lastApprox;
iterations@@i + 1DD = it;
F;

H∗ За да се реализира цикъл,
разбира се можем да ползваме For, но функционалният начин е чрез Table ∗L
Table@
predcorrit@iD, 8i, 4, n<
H∗ Присвояването на новите стойности на y и iterations,
става директно в predcorrit от съображения за ефективност,
тъй като пак по същите съображения predcorrit има директен достъп до тях ∗L
D;
8x, y, iterations< H∗ връщаме резултата ∗L
F
10 Предиктор-коректор

ü Output функция

Нека за улеснение и прегледност напишем и функция, печатаща резултата в приличен вид.

predcorrprint@f_, x0_, X_, u0_, n_Integer ê; 0 ≤ n < ∞, ξ_ ê; ξ > 0, it_Integer ê; it > 0D :=


Module@8<,
Style@"\nOutput за предиктор−коректор, формули 14\n", "Subsubtitle"D êê Print;
Print@"u'HxL = ", TraditionalForm@f@x, uDD,
", x ∈ H", TraditionalForm@x0D, ", ", TraditionalForm@XD, "D"D;
Print@"uH", TraditionalForm@x0D, "L = ", TraditionalForm@u0DD;
Style@
88"Параметри"<, 8
Grid@
88"ξ HточностL", "N HинтервалиL", "максимум\nитерации"<, 8ξ, n, it<<,
Frame → 8All, False<
D
<<
êê Grid
, "Text"D êê Print;
Print@D;
NumberForm@
TableForm@
predcorr@f, 0, 1, 0, 40D êê N êê Transpose,
TableHeadings → 88<, 8"x", "y", "it"<<
D,
88, 8<
D
D;

ü Резултати

Да запишем f конкретно за нашата задача.

u2 − x + 0.5
f@x_, u_D :=
x2 + u + 1

Сега, използвайки нашите данни, да извикаме метода за принтене. Сигнатурата беше: f , x0 , X , u0 , N, x, iterations

predcorrprint@f, 0, 1, 0, 40, 0.00001, 3D


Светлин Анков 11

Output за предиктор-коректор, формули 14

, x ∈ H0, 1D
u2 − x + 0.5
u'HxL =
u + x2 + 1
uH0L = 0

Параметри
ξ HточностL N HинтервалиL максимум
итерации
0.00001 40 3

x y it
0.00000000 0.00000000 0.00000000
0.02500000 0.01211290 0.00000000
0.05000000 0.02346525 0.00000000
0.07500000 0.03407665 0.00000000
0.10000000 0.04396569 1.00000000
0.12500000 0.05315009 1.00000000
0.15000000 0.06164688 1.00000000
0.17500000 0.06947249 1.00000000
0.20000000 0.07664292 1.00000000
0.22500000 0.08317380 1.00000000
0.25000000 0.08908045 1.00000000
0.27500000 0.09437800 1.00000000
0.30000000 0.09908143 1.00000000
0.32500000 0.10320560 1.00000000
0.35000000 0.10676533 1.00000000
0.37500000 0.10977538 1.00000000
0.40000000 0.11225052 1.00000000
0.42500000 0.11420555 1.00000000
0.45000000 0.11565525 1.00000000
0.47500000 0.11661447 1.00000000
0.50000000 0.11709806 1.00000000
0.52500000 0.11712093 1.00000000
0.55000000 0.11669798 1.00000000
0.57500000 0.11584414 1.00000000
0.60000000 0.11457432 1.00000000
0.62500000 0.11290341 1.00000000
0.65000000 0.11084628 1.00000000
0.67500000 0.10841772 1.00000000
0.70000000 0.10563246 1.00000000
0.72500000 0.10250512 1.00000000
0.75000000 0.09905019 1.00000000
0.77500000 0.09528201 1.00000000
0.80000000 0.09121479 1.00000000
0.82500000 0.08686251 1.00000000
0.85000000 0.08223895 1.00000000
0.87500000 0.07735766 1.00000000
0.90000000 0.07223196 1.00000000
0.92500000 0.06687488 1.00000000
0.95000000 0.06129916 1.00000000
0.97500000 0.05551726 1.00000000
1.00000000 0.04954133 1.00000000

You might also like