Cvičení z Numerické matematiky 2

  1. Metoda konečných diferencí
  2. Cauchyho úloha a Rungovy-Kuttovy metody
    1. Rungova-Kuttova metoda pro n=1
    2. Rungova-Kuttova metoda pro n=2
    3. Cauchyho úloha vyššího řádu
  3. Objektově orientované programování
  4. Řešení okrajových úloh

Materiály

Metoda konečných diferencí

Oberhuberova prezentace

Definice. Nechť x0, Hx0 je jeho okolí a f,g:Hx0. f aproximuje g s přesností řádu r, pokud existuje C+ takové, že limxx0|f(x)g(x)||xx0|r=C
Definice. Nechť x0, Hx0 je jeho okolí, f:Hx0, h+ a l1,l2. Potom budeme značit
Věta. Nechť f𝒞2((x0,x1)). Potom f1f0h=f(x0)+𝒪(h)
Věta. Nechť f𝒞2((x1,x0)). Potom f0f1h=f(x0)+𝒪(h)
Věta. Nechť f𝒞2((x1,x1)). Potom f1f12h=f(x0)+𝒪(h)
Věta. Nechť f𝒞3((x1,x1)). Potom f1f12h=f(x0)+𝒪(h2)
Věta. Nechť f𝒞4((x1,x1)). Potom f12f0+f1h2=f(x0)+𝒪(h2)
Věta. Nechť f𝒞(n+1)((xl1,xl2)). Potom pro každé kn^ lze k-tou derivaci aproximovat pomocí konečných diferencí s přesností řádu n+1k.

Cauchyho úloha a Rungovy-Kuttovy metody

Oberhuberova prezentace

Mějme obyčejnou diferenciální rovnici s počáteční podmínkou:

x(t)=f(t,x(t)),t(0,T) x(0)=x0

Zkusíme ji vyřešit „simulací“ s diskrétními časovými intervaly. Zvolíme si časový krok τ, tedy budeme mít NTτ kroků. Budeme počítat:

xi+1xi+Δx(iτ,τ)

Otázkou je, jak zvolit vhodné Δx. Chtěli bychom, aby platilo:

Δx(t,τ)=x(t+τ)x(t)=Taylorτx(t)+τ22x(t)+

První derivaci si můžeme spočítat přímo ze zadání. S druhou už to bude horší:

x(t)=1f(t,x(t))+2f(t,x(t))x(t)=1f(t,x(t))+2f(t,x(t))f(t,x(t))

K tomu už potřebujeme znát derivace f. A s dalšími derivacemi by to bylo ještě horší. Pokud se vykašleme na všechny derivace kromě první, dostaneme známou Eulerovu metodu. Ale tento postup je obecně dost numericky nestabilní. Radši použijeme Rungovu-Kuttovu metodu. Ta funguje tak, že přírůstky budeme hledat ve tvaru:

Δx(t,τ)=i=1npiki(t,τ) k1(t,τ)τf(t,x(t)) ki(t,τ)τf(t+αiτ,x(t)+j=1i1βi,jkj(t,τ)),i>1

Teď je samozřejmě otázkou, jak vhodně zvolit koeficienty pi,ai,βi,j. Obecně je chceme zvolit tak, aby se přírůstek shodoval s Taylorem do co nejvyššího stupně. Detaily viz prezentace.

Rungova-Kuttova metoda pro n=1

Δx(t,τ)=p1k1(t,τ)=p1τf(t,x(t)) φ1(τ)=x(t+τ)x(t)p1τf(t,x(t))=τx(t)+τ22x(s)p1τf(t,x(t))=(1p1)τf(t,x(t))+τ22x(s) φ1(τ)=(1p1)f(t,x(t))+τx(s) φ1(0)=(1p1)f(t,x(t))=0p1=1 Δx(t,τ)=τf(t,x(t))

Tím jsme opět dostali známou Eulerovu metodu.

Rungova-Kuttova metoda pro n=2

Δx(t,τ)=p1k1(t,τ)+p2k2(t,τ)=p1τf(t,x(t))+p2τf(t+α2τ,x(t)+β2,1k1(t,τ)) φ2(τ)=τx(τ)+τ22x(t)+τ36x(s)zp1τf(t,x(t))p2τf(t,x(t)+β2,1k1(t,τ))=τf(t,x(t))+τ22(tf(t,x(t))+xf(t,x(t))f(t,x(t)))+zp1τf(r,x(t))p2τf(t,x(t)+β2,1τf(t,x(t))) φ2(τ)=f(t,x(t))+τ(tf(t,x(t))+xf(t,x(t))f(t,x(t)))p1f(t,x(t))p2f(t,x(t)+β2,1τf(t,x(t)))p2τ(tf()α2+xf()β2,1f(t,x(t))) φ2(τ)=τf(t,x(t))+xf(t,x(t))f(t,x(t))2p2(tf()α2+xf()β2,1f(t,x(t)))p2τt() φ2(0)==01p1p2=0 φ2(0)==012α2p2=12β2,1p2=0 První možnost: p1=p2=12,α2=β2,1=1 Druhá možnost: p1=0,p2=1,α2=β2,1=12 Vidíme, že pro každý řád se to počítá výrazně pracněji.

Cauchyho úloha vyššího řádu

x(n)(t)=f(t,x(t),,x(n1)t)

Použijeme substituci, čímž to převedeme na soustavu:

ui(t)x(i)(t) un(t)=f(t,u0(t),,un1(t)) ui1(t)=ui(t)

Musíme znát počáteční podmínky pro každé u, tedy počáteční derivace až do řádu n1.

Runge-Kuttovy metody můžeme přepsat do vektorového tvaru:

Δu(t,τ)=i=1npiki(t,τ) ki(t,τ)=τF(t+j=2iαjτ,u(t)+j=1i1βi,jkj(t,τ))

Objektově orientované programování

Oberhuberova prezentace

Když chceme v C++ vykreslit graf funkce, normální člověk by napsal něco takového:

void drawFunction(std::function<double(double)> f, double left, double right, double step) {
  for (double x = left; x <= right; x += step) {
    std::cout << x << " " << f(x) << "\n";
  }
}

int main() {
  drawFunction([](double x) { return (2 * x + 3) * x + 1; }, 0.0, 1.0, 0.1);
  drawFunction([](double x) { return 2 * sin(5 * x + 1); }, 0.0, 1.0, 0.1);
}

Ale Oberhuber radši napíše tohle:

struct Function
{
    virtual double getFx( double x );
}

struct Quadratic : public Function    // !!!!
{
    double a, b, c;

    double getFx ( double x )
    {
        return ( a * x + b ) * x + c;
    }
}

struct Sinus : public Function    // !!!!
{
    double A, f, p;

    double getFx ( double x )
    {
        fx = A * sin ( f * x + p );
    }
}

void drawFunction( Function * function ,
                   double left , double right , double step )
{
    for ( double x = left ; x <= right ; x += step )
    {
        printf( " %f %f \n", x, function−>getFx( x ) );
    }
}

int main ( int argc , char * argv[] )
{
        /****
         * Evaluate f (x) = 2 x^2 + 3 x + 1 on <0,1>
         */
         Quadratic f1;
         f1.a = 2.0;
         f1.b = 3.0;
         f1.c = 1.0;
         drawFunction ( &f1, // WE DO NOT NEED TO CARE ABOUT FUNCTION TYPE
                        0.0, 1.0,     // on interval <0, 1>
                        0.1,          // we draw it with resolution 0.1
                                      //    −> 11 points on the interval
                         );

        /****
         * Evaluate f(x) = 2 sin( 5 *x + 1 ) on <0,1>
         */
         Sinus f2;
         f2.A = 2.0;
         f2.f = 5.0;
         f2.p = 1.0;
         drawFunction ( &f2, // WE DO NOT NEED TO CARE ABOUT FUNCTION TYPE
                        0.0, 1.0,     // on interval <0, 1>
                        0.1,          // we draw it with resolution 0.1
                                      //    −> 11 points on the interval
                         );

}

Řešení okrajových úloh

Oberhuberova prezentace

Mame-li úlohu se dvěma stupni volnosti, potřebujeme dvě počáteční podmínky. Místo toho ale často máme zadané okrajové podmínky. Z přednášky známe metodu střelby, ale ta nejde zobecnit do více dimenzí (parciální diferenciální rovnice). Místo toho použijeme metodu sítí: provedeme diskretizaci a vyřešíme soustavu lineárních rovnic. Detaily viz prezentace a přednáška.