Uvod¶
V okviru tega poglavja bomo za dano funkcijo izračunali določen integral:
kjer sta in meji integriranja, pa so vrednosti funkcije, ki jih pridobimo iz tabele vrednosti ali s pomočjo analitične funkcije.
Numerični integral bomo računali na podlagi diskretne vsote:
kjer so uteži, pa vozlišča na intervalu in je število vozlišč.
Ogledali si bomo dva različna pristopa k numerični integraciji:
Newton-Cotesov pristop, ki temelji na ekvidistantnih vozliščih (konstanten korak integracije) in
Gaussov integracijski pristop, kjer so vozlišča postavljena tako, da se doseže natančnost za polinome.
Motivacijski primer¶
Pri numeričnem integriranju si bomo pomagali s konkretnim primerom:
Pripravimo si vozlišča. Osnovni korak naj bo , v tem primeru imamo štiri podintervale in pet vozlišč, pri koraku so tri vozliščne točke in pri koraku samo dve (skrajni):
import numpy as np
xg, hg = np.linspace(1, 2, 100, retstep=True) # goste točke (za prikaz)
x2v, h2v = np.linspace(1, 2, 2, retstep=True) # korak h2v = 1 (2 vozlišči)
x3v, h3v = np.linspace(1, 2, 3, retstep=True) # korak h3v = 0.5 (3 vozlišča)
x4v, h4v = np.linspace(1, 2, 4, retstep=True) # korak h4v = 0.33.. (4 vozlišča)
x5v, h5v = np.linspace(1, 2, 5, retstep=True) # korak h5v = 0.25 (5 vozlišč)Pripravimo še funkcijske vrednosti:
yg = xg * np.sin(xg)
y2v = x2v * np.sin(x2v)
y3v = x3v * np.sin(x3v)
y4v = x4v * np.sin(x4v)
y5v = x5v * np.sin(x5v)Pripravimo prikaz podatkov:
import matplotlib.pyplot as plt
%matplotlib inline
def fig_motivacija():
plt.fill_between(xg, yg, alpha=0.25, facecolor='r')
plt.annotate(r'$\int_1^2\,x\,\sin(x)\,\mathrm{d}x$', (1.3, 0.5), fontsize=22)
plt.plot(xg, yg, lw=3, alpha=0.5, label=r'$x\,\sin(x)$')
plt.plot(x2v, y2v, 's', alpha=0.5, label=f'$h={h2v}$', markersize=14)
plt.plot(x3v, y3v, 'o', alpha=0.5, label=f'$h={h3v}$', markersize=10)
plt.legend(loc=(1.01, 0))
plt.ylim(0, 2)
plt.show()Prikažimo podatke:
fig_motivacija()
Analitično izračunajmo točen rezultat:
import sympy as sym
sym.init_printing()
x = sym.symbols('x')
I_točno = float(sym.integrate(x*sym.sin(x), (x, 1, 2)).evalf())
I_točnoNewton-Cotesov pristop¶
Na sliki je prikazan splošen primer, kjer je razdalja med vozlišči enaka (gre za ekvidistantno delitev).

V okviru tega poglavja si bomo najprej pogledali trapezno ter sestavljeno trapezno pravilo, pozneje pa bosta sledili še Simpsonova ter Rombergova metoda.
Trapezno pravilo¶
Trapezno pravilo vrednosti podintegralske funkcije na (pod)intervalu interpolira z linearno funkcijo. Za dve vozliščni točki to pomeni, da površino pod grafom funkcije približno izračunamo kot:
In so uteži:
Numerična implementacija¶
Numerična implementacija je:
def trapezno(y, h):
"""
Trapezno pravilo integriranja.
:param y: funkcijske vrednosti
:param h: korak integriranja
"""
return (y[0] + y[-1])*h/2Numerični zgled¶
V konkretnem primeru to pomeni, da prvo in zadnjo funkcijsko vrednost utežimo s . V našem primeru je :
I_trapezno = trapezno(y2v, h=h2v)
I_trapeznoPripravimo sliko:
def fig_trapezno():
plt.fill_between(x2v, y2v, alpha=0.25, facecolor='r')
plt.vlines(x2v, 0, y2v, color='r', linestyles='dashed', lw=1)
plt.annotate('$I_{\\mathrm{trapezno}}$', (1.4, 0.5), fontsize=22)
plt.annotate('Napaka', fontsize=20, xy=(1.5, 1.4), xytext=(1.6, 1.8),
arrowprops=dict(facecolor='gray', shrink=0.05))
plt.plot(xg, yg, lw=3, alpha=0.5, label='$x\\,\\sin(x)$')
plt.plot(x2v, y2v, 'o', alpha=0.5, label=f'$h={h2v}$')
plt.legend(loc=(1.01, 0))
plt.ylim(0, 2)
plt.show()Prikažemo:
fig_trapezno()
Napaka trapeznega pravila¶
Razlika med analitično vrednostjo integrala in numeričnim približkom je napaka metode:
Če je funkcija vsaj dvakrat odvedljiva, se lahko (glejte npr. vir: Burden, Faires, Burden: Numerical Analysis 10th Ed) izpelje ocena napake, ki velja samo za trapezni približek prek celega integracijskega intervala:
kjer je in neznana vrednost na intervalu .
Sestavljeno trapezno pravilo¶
Če razdelimo interval na podintervalov in na vsakem uporabimo trapezno pravilo integriranja, govorimo o sestavljenem trapeznem pravilu (angl. composite trapezoidal rule).
V tem primeru za vsak podinterval uporabimo trapezno pravilo in torej za meje podinterval in uporabimo uteži . Ker so notranja vozlišča podvojena, sledi:
Pri tem smo predpostavili podintervale enake širine:
Sledi torej:
Numerična implementacija¶
Numerična implementacija je:
def trapezno_sest(y, h):
"""
Sestavljeno trapezno pravilo integriranja.
:param y: funkcijske vrednosti
:param h: korak integriranja
"""
return (np.sum(y) - 0.5*y[0] - 0.5*y[-1])*hNumerični zgled¶
Zgoraj smo že pripravili podatke za dva podintervala (tri vozlišča):
x3varray([1. , 1.5, 2. ])h3vIzračunajmo oceno integrala s sestavljenim trapeznim pravilom:
I_trapezno_sest = trapezno_sest(y3v, h=h3v)
I_trapezno_sestPripravimo sliko:
def fig_trapezno_sest():
plt.fill_between(x3v, y3v, alpha=0.25, facecolor='r')
plt.vlines(x3v, 0, y3v, color='r', linestyles='dashed', lw=1)
plt.annotate('$I_{\\mathrm{trapezno\\;sestavljeno}}$', (1.2, 0.5), fontsize=22)
plt.annotate('Napaka', fontsize=20, xy=(1.75, 1.68), xytext=(1.4, 1.8),
arrowprops=dict(facecolor='gray', shrink=0.05))
plt.annotate('Napaka', fontsize=20, xy=(1.2, 1.1), xytext=(1., 1.4),
arrowprops=dict(facecolor='gray', shrink=0.05))
plt.plot(xg, yg, lw=3, alpha=0.5, label='$x\\,\\sin(x)$')
plt.plot(x3v, y3v, 'o', alpha=0.5, label=f'$h={h3v}$')
plt.legend(loc=(1.01, 0))
plt.ylim(0, 2)
plt.show()Prikažemo:
fig_trapezno_sest()
Napaka sestavljenega trapeznega pravila¶
Napaka sestavljenega trapeznega pravila izhaja iz napake trapeznega pravila; pri tem tako napako naredimo -krat.
Ker velja , izpeljemo napako sestavljenega trapeznega pravila kot:
je vrednost na intervalu . Napaka je drugega reda .
Boljši približek integrala¶
V nadaljevanju si bomo pogledali t. i. Richardsonovo ekstrapolacijo, pri kateri na podlagi ocene integrala s korakom in izračunamo boljši približek.
V kolikor integral numerično izračunamo pri dveh različnih korakih in , velja:
kjer sta in približka integrala s korakom in ter in oceni napake pri koraku in . Izpeljemo
Naprej zapišemo:
Ob predpostavki, da je pri koraku in enak ( je pri koraku in dejansko različen), zapišemo:
Numerični zgled¶
Predhodno smo s trapeznim pravilom že izračunali integral pri koraku in pri koraku , rezultata sta bila:
[I_trapezno, I_trapezno_sest]S pomočjo zgornje formule izračunamo boljši približek:
I_trapezno_boljši = 4/3*I_trapezno_sest - 1/3*I_trapezno
print(f'Točen rezultat: {I_točno}\nBoljši približek: {I_trapezno_boljši}')Točen rezultat: 1.4404224209802097
Boljši približek: 1.4408392930139313
Sestavljeno trapezno pravilo je implementirano tudi v paketu numpy, s funkcijo numpy.trapezoid (v starejših različicah numpy.trapz):
trapezoid(y, x=None, dx=1.0, axis=-1)ypredstavlja tabelo funkcijskih vrednosti,xje opcijski parameter in definira vozlišča; če parameter ni definiran, se privzame ekvidistančna vozlišča na razdaljidx,dxdefinira (konstanten) korak integracije, ima privzeto vrednost 1,axisdefinira os po kateri se integrira (v primeru, da jeyvečdimenzijsko numerično polje).
Funkcija vrne izračunani integral po sestavljenem trapeznem pravilu. Več informacij lahko najdete v dokumentaciji.
numpy implementacija sestavljenega trapeznega pravila¶
Poglejmo si primer:
#%%timeit
I_trapezno_np = np.trapezoid(y3v, dx=h3v)
I_trapezno_npSimpsonova in druge metode¶
Zgoraj smo si pogledali trapezno pravilo, ki temelji na linearni interpolacijski funkciji na posameznem podintervalu. Z interpolacijo višjega reda lahko izpeljemo še druge integracijske metode.
Izračunati moramo:
Tabeliramo podintegralsko funkcijo in tabelo interpoliramo z Lagrangevim interpolacijskim polinomom stopnje :
kjer so funkcijske vrednosti v vozliščih in je Lagrangev polinom definiran kot:
Za numerični izračun integrala (meje so: , ) namesto funkcije vstavimo v integral interpolacijski polinom :
Ker je integriranje linearna operacija, lahko zamenjamo integriranje in vsoto:
Lagrangev polinom integriramo in dobimo uteži :
Izpeljava trapeznega pravila z uporabo Lagrangevih polinomov¶
Poglejmo si kako z Lagrangevim interpolacijskim polinomom prve stopnje strojno izpeljemo uteži v primeru trapeznega pravila.
Najprej v simbolni obliki definirajmo spremenljivko x, vozlišči x0 in x1 ter korak h:
x, x0, x1, h = sym.symbols('x x0, x1, h')Pripravimo Python funkcijo, ki v simbolni obliki vrne seznam koeficientov Lagrangevih polinomov stopnje :
def lagrange(n, x, vozlišča_predpona='x'):
if isinstance(vozlišča_predpona, str):
vozlišča = sym.symbols(f'{vozlišča_predpona}:{n}')
coeffs = []
for i in range(0, n):
numer = []
denom = []
for j in range(0, n):
if i == j:
continue
numer.append(x - vozlišča[j])
denom.append(vozlišča[i] - vozlišča[j])
numer = sym.Mul(*numer)
denom = sym.Mul(*denom)
coeffs.append(numer/denom)
return coeffs Najprej poglejmo Lagrangeva polinoma za linearno interpolacijo ():
lag = lagrange(2, x)
lagSedaj Lagrangev polinom integriramo čez celotni interval:
int0 = sym.integrate(lag[0], (x, x0, x1))
int0Izraz poenostavimo in dobimo:
int1 = int0.factor()
int1Ker je širina podintervala konstantna je , izvedemo zamenjavo:
zamenjave = {x1: x0+h}
int1.subs(zamenjave)Zgornje korake za Lagrangev polinom lahko posplošimo za seznam Lagrangevih polinomov:
x, x0, x1, h = sym.symbols('x, x0, x1, h')
zamenjave = {x1: x0+h}
A_trapez = [sym.integrate(li, (x, x0, x1)).factor().subs(zamenjave)
for li in lagrange(2, x)] # za vsak lagrangev polimom `li` v seznamu lagrange(2,x)
A_trapezIzpeljali smo uteži, ki smo jih uporabili pri trapezni metodi:
Trapezno pravilo je:
Ocena napake je (vir: Burden, Faires, Burden: Numerical Analysis 10th Ed):
Izračun uteži za Simpsonovo pravilo¶
Potem ko smo zgoraj pokazali strnjen izračun za trapezno pravilo, lahko podobno izvedemo za kvadratno interpolacijo čez tri točke ().
Izračun uteži je analogen zgornjemu:
x, x0, x1, x2, h = sym.symbols('x, x0, x1, x2, h')
zamenjave = {x1: x0+h, x2: x0+2*h}
A_Simpson1_3 = [sym.integrate(li, (x, x0, x2)).factor().subs(zamenjave).factor()
for li in lagrange(3, x)]
A_Simpson1_3Simpsonovo pravilo (to pravilo se imenuje tudi Simpsonovo 1/3 pravilo) je:
Ocena napake je (vir: Burden, Faires, Burden: Numerical Analysis 10th Ed):
Pri tem je treba izpostaviti, da je napaka lokalno 5. reda in definirana z neznano vrednostjo četrtega odvoda , posledično je to pravilo točno za polinome stopnje 3 ali manj.
Primer uporabe:
I_Simps = h3v/3 * np.sum(y3v * [1, 4, 1])
I_SimpsPripravimo sliko. Ker Simpsonovo pravilo temelji na kvadratni interpolaciji, moramo najprej pripraviti interpolacijski polinom (pomagamo si z numpy.polynomial.Polynomial):
from numpy.polynomial import Polynomial # interpolacijski polinom skozi vozliščadef fig_Simpsonovo():
y_interpolate = Polynomial.fit(x3v, y3v, deg=len(x3v)-1)
plt.fill_between(xg, y_interpolate(xg), alpha=0.25, facecolor='r')
plt.vlines(x3v, 0, y3v, color='r', linestyles='dashed', lw=1)
plt.annotate('$I_{\\mathrm{Simpsonovo}}$', (1.2, 0.5), fontsize=22)
plt.annotate('Napaka', fontsize=20, xy=(1.75, 1.7), xytext=(1.4, 1.8),
arrowprops=dict(facecolor='gray', shrink=0.05))
plt.annotate('Napaka', fontsize=20, xy=(1.2, 1.1), xytext=(1., 1.4),
arrowprops=dict(facecolor='gray', shrink=0.05))
plt.plot(xg, yg, lw=3, alpha=0.5, label='$x\\,\\sin(x)$')
plt.plot(x3v, y3v, 'o', alpha=0.5, label=f'$h={h3v}$')
plt.legend(loc=(1.01, 0))
plt.ylim(0, 2)
plt.show()Prikažemo:
fig_Simpsonovo()
scipy.integrate.newton_cotes¶
Koeficiente integracijskega pristopa Newton-Cotes pridobimo tudi s pomočjo scipy.integrate.newton_cotes() dokumentacija:
newton_cotes(rn, equal=0)kjer sta parametra:
rn, ki definira število podintervalov (mogoč je tudi nekonstanten korak, glejte dokumentacijo),equal, ki definira ali se zahteva konstantno široke podintervale.
Funkcija vrne terko, pri čemer prvi element predstavlja numerično polje uteži in drugi člen oceno napake.
Poglejmo si primer:
from scipy import integrate
integrate.newton_cotes(2)(array([0.33333333, 1.33333333, 0.33333333]), -0.011111111111111112)Izračun uteži za Simpsonovo 3/8 pravilo¶
Nadaljujemo lahko s kubično interpolacijo čez štiri točke ():
x, x0, x1, x2, x3, h = sym.symbols('x, x0, x1, x2, x3, h')
zamenjave = {x1: x0+h, x2: x0+2*h, x3: x0+3*h}
A_Simpson3_8 = [sym.integrate(li, (x, x0, x3)).factor().subs(zamenjave).factor()
for li in lagrange(4, x)]
A_Simpson3_8Simpsonovo 3/8 pravilo je:
Ocena napake je (vir: Burden, Faires, Burden: Numerical Analysis 10th Ed):
Poglejmo si primer uporabe. Uporabimo pripravljeno tabelo vrednosti funkcije v štirih točkah:
y4varray([0.84147098, 1.2959172 , 1.65901326, 1.81859485])I_Simps38 = 3*h4v/8 * np.sum(y4v * [1, 3, 3, 1])
I_Simps38Pripravimo še prikaz:
def fig_Simpsonovo38():
y_interpolate = Polynomial.fit(x4v, y4v, deg=len(x4v)-1)
plt.fill_between(xg, y_interpolate(xg), alpha=0.25, facecolor='r')
plt.vlines(x4v, 0, y4v, color='r', linestyles='dashed', lw=1)
plt.annotate('$I_{\\mathrm{Simpsonovo\\;3/8}}$', (1.2, 0.5), fontsize=22)
plt.annotate('Napaka', fontsize=20, xy=(1.75, 1.7), xytext=(1.4, 1.8),
arrowprops=dict(facecolor='gray', shrink=0.05))
plt.annotate('Napaka', fontsize=20, xy=(1.5, 1.47), xytext=(1.1, 1.6),
arrowprops=dict(facecolor='gray', shrink=0.05))
plt.annotate('Napaka', fontsize=20, xy=(1.2, 1.1), xytext=(1., 1.4),
arrowprops=dict(facecolor='gray', shrink=0.05))
plt.plot(xg, yg, lw=3, alpha=0.5, label='$x\\,\\sin(x)$')
plt.plot(x4v, y4v, 'o', alpha=0.5, label=f'$h={h4v:.6f}$')
plt.legend(loc=(1.01, 0))
plt.ylim(0, 2)
plt.show()Prikažemo:
fig_Simpsonovo38() 
Sestavljeno Simpsonovo pravilo¶
Interval razdelimo na sodo število podintervalov enake širine , s čimer so definirana vozlišča za . V tem primeru zapišemo sestavljeno Simpsonovo pravilo:
kjer je neznana vrednost na intervalu . Napaka je četrtega reda .
Numerična implementacija:
def simpsonovo_sest(y, h):
"""
Sestavljeno Simpsonovo pravilo integriranja.
:param y: funkcijske vrednosti
:param h: korak integriranja
"""
return h/3 * (y[0] + 4*np.sum(y[1:-1:2]) + 2*np.sum(y[2:-1:2]) + y[-1])I_Simps_sest = simpsonovo_sest(y5v, h=h5v)
I_Simps_sestPripravimo sliko:
def fig_Simpsonovo_sest():
y_interpolate = Polynomial.fit(x5v, y5v, deg=len(x5v)-1)
plt.fill_between(xg, y_interpolate(xg), alpha=0.25, facecolor='r')
plt.vlines(x5v, 0, y5v, color='r', linestyles='dashed', lw=1)
plt.annotate('$I_{\\mathrm{Simpsonovo\\;sestavljeno}}$', (1.2, 0.5), fontsize=22)
plt.annotate('Napaka', fontsize=20, xy=(1.70, 1.68), xytext=(1.4, 1.8),
arrowprops=dict(facecolor='gray', shrink=0.05))
plt.plot(xg, yg, lw=3, alpha=0.5, label='$x\\,\\sin(x)$')
plt.plot(x5v, y5v, 'o', alpha=0.5, label=f'$h={h5v}$')
plt.legend(loc=(1.01, 0))
plt.ylim(0, 2)
plt.show()Prikažemo:
fig_Simpsonovo_sest()
Boljša ocena integrala¶
Izboljšano oceno integrala določimo na podoben način kakor pri sestavljeni trapezni metodi; integral ocenjujemo pri dveh različnih korakih in , velja natančno:
kjer je približek integrala s korakom in ocena napake pri koraku ; analogno velja za in .
Če predpostavimo, da je v obeh primerih enak, lahko določimo razliko .
Naprej zapišemo:
Ob predpostavki, da je pri koraku in enak ( je pri koraku in dejansko različen), zapišemo:
Numerični zgled¶
Predhodno smo s Simpsonovim pravilom že izračunali integral pri koraku in pri koraku , rezultata sta bila:
[I_Simps, I_Simps_sest]S pomočjo zgornje formule izračunamo boljši približek:
I_Simps_boljši = 16/15*I_Simps_sest - 1/15*I_Simps
print(f'Točen rezultat: {I_točno}\nBoljši približek: {I_Simps_boljši}')Točen rezultat: 1.4404224209802097
Boljši približek: 1.4404218714139077
Pridobimo boljši numerični približek, izgubimo pa oceno napake!
Simpsonova metoda v scipy.integrate.simpson¶
V scipy je implementirano sestavljeno Simpsonovo pravilo v scipy.integrate.simpson() (dokumentacija):
simpson(y, x=None, *, dx=1.0, axis=-1)kjer so parametri:
ytabela funkcijskih vrednosti, ki jih integriramo,xvozlišča, gre za opcijski parameter, če jex=None, se predpostavi ekvidistantne podintervale širinedx,dxširina ekvidistantnih podintervalov oz korak integriranja,axisos integriranja (pomembno v primeru večdimenzijskega numeričnega polja).
V starejših različicah SciPy se je funkcija imenovala simps in je imela še parameter even; oboje je bilo odstranjeno v SciPy 1.14.
Poglejmo si primer, najprej uvozimo funkcijo simpson:
from scipy.integrate import simpson#%%timeit
simpson(y5v, dx=h5v)Rombergova metoda¶
Rombergova metoda temelji na Richardsonovi ekstrapolaciji. Predpostavimo, da integral integriramo na intervalu , ki ga razdelimo na podintervalov ().
Rezultat trapeznega pravila pri označimo z , pri čemer označuje natančnost pridobljenega rezultata .
Če uporabimo trapezno integracijsko pravilo pri podintervalih, izračunamo:
, korak , red natančnosti ,
, korak , red natančnosti ,
, korak , red natančnosti ,
, korak , red natančnosti ,
, korak , red natančnosti .
Na podlagi Richardsonove ekstrapolacije izračunamo boljši približek
, korak , red natančnosti ,
, korak , red natančnosti ,
, korak , red natančnosti .
Nato nadaljujemo z Richardsonovo ekstrapolacijo:
, korak , red natančnosti ,
, korak , red natančnosti .
Richardsonovo extrapolacijo lahko posplošimo:
, korak , red natančnosti
Pri tem je boljši približek pri koraku enak rezultatu, ki ga dobimo po Simpsonovi metodi pri koraku . Podobno je boljši približek pri koraku enak numeričnemu integralu Simpsonove metode pri koraku . In je dalje enak popravljenemu približku Simpsonove metode pri koraku .
Pripravimo numerične podatke:
x9v, h9v = np.linspace(1, 2, 9, retstep=True) # korak h9v = 0.125 (9 vozlišč)
y9v = x9v * np.sin(x9v)Poglejmo si primer od zgoraj. Najprej s sestavljeno trapezno metodo izračunamo integral pri različnih korakih (drugi red napake):
## O(h^2)
R1_1 = trapezno_sest(y9v[::8], 8*h9v) # h=1.0
R2_1 = trapezno_sest(y9v[::4], 4*h9v) # h=0.5
R3_1 = trapezno_sest(y9v[::2], 2*h9v) # h=0.25
R4_1 = trapezno_sest(y9v, h9v) # h=0.125
[R1_1, R2_1, R3_1, R4_1]Nato izračunamo boljše približke (dobimo četrti red napake):
## O(h^4)
R2_2 = R2_1 + 1/3 * (R2_1 - R1_1)
R3_2 = R3_1 + 1/3 * (R3_1 - R2_1)
R4_2 = R4_1 + 1/3 * (R4_1 - R3_1)
[R2_2, R3_2, R4_2]Rezultati predstavljajo rezultat Simpsonove metode pri koraku , in :
[simpsonovo_sest(y9v[::4], 4*h9v), simpsonovo_sest(y9v[::2], 2*h9v), simpsonovo_sest(y9v, h9v)]Ponovno izračunamo boljše približke (dobimo šesti red napake):
## O(h6)
R3_3 = R3_2 + 1/15 * (R3_2 - R2_2)
R4_3 = R4_2 + 1/15 * (R4_2 - R3_2)
[R3_3, R4_3]Rezultat predstavlja boljši rezultat Simpsonove pri koraku in :
a4h, a2h, ah = [simpsonovo_sest(y9v[::4], 4*h9v), simpsonovo_sest(y9v[::2], 2*h9v), simpsonovo_sest(y9v, h9v)]
[16/15*a2h-1/15*a4h, 16/15*ah-1/15*a2h]Ponovno izračunamo boljše približke (dobimo osmi red napake):
## O(h8)
R4_4 = R4_3 + 1/63 * (R4_3 - R3_3)
R4_4Rombergova metoda nam torej ponuja visoko natančnost rezultata za relativno majhno numerično ceno. Napako pa ocenimo:
Rombergova metoda v scipy.integrate.romb¶
V scipy je implementirana Rombergova metoda v scipy.integrate.romb() (dokumentacija):
romb(y, dx=1.0, axis=-1, show=False)kjer so parametri:
ytabela funkcijskih vrednosti, ki jih integriramo,dxširina ekvidistantnih podintervalov oz korak integriranja,axisos integriranja (pomembno v primeru večdimenzijskega numeričnega polja),showče jeTrueprikaže elemente Richardsonove ekstrapolacije.
Poglejmo si primer od zgoraj:
from scipy.integrate import romby9varray([0.84147098, 1.01505104, 1.18623077, 1.34872795, 1.49624248,
1.62261343, 1.72197541, 1.78891084, 1.81859485])romb(y9v, dx=h9v, show=True)Richardson Extrapolation Table for Romberg Integration
======================================================
1.33003
1.41314 1.44084
1.43362 1.44045 1.44042
1.43872 1.44042 1.44042 1.44042
======================================================
Gaussov integracijski pristop¶
Newton-Cotesov pristop temelji na polinomu -te stopnje in napaka je stopnje. To pomeni, da integracija daje točen rezultat, če je integrirana funkcija polinom stopnje ali manj; pri sodem zaradi simetrije celo stopnje (Simpsonovo pravilo, , je npr. točno tudi za kubične polinome).
Gaussov integracijski pristop je v principu drugačen: cilj je integral funkcije nadomestiti z uteženo vsoto vrednosti funkcije pri diskretnih vrednostih :
Pri tem je neznana utež in tudi lega vozlišča . Za stopnje polinoma bomo potrebovali tudi več točk .
V nadaljevanju bomo spoznali, da lahko zelo učinkovito izračunamo numerično točen integral. Prednost Gaussove integracije je tudi, da lahko izračuna integral funkcij s singularnostmi (npr: ).
Gaussova kvadratura z enim vozliščem¶
Predpostavimo, da želimo integrirati polinom stopnje (linearna funkcija):
Izračunajmo:
Po drugi strani pa želimo integral izračunati glede na ustrezno uteženo vrednost funkcije v neznanem vozlišču (samo eno vozlišče!):
Z enačenjem zgornjih izrazov izpeljemo:
in sta koeficienta linearne funkcije, ki lahko zavzame poljubne vrednosti, zato velja:
Gre za sistem linearnih enačb z rešitvijo:
Če je integrirana funkcija linearna, bomo samo na podlagi vrednosti v eni točki izračunali pravo vrednost!
Da je Gaussov integracijski pristop neodvisen od mej integriranja , , pa uvedemo standardne meje.
V primeru standardnih mej, je pri eni Gaussovi točki utež in vrednost, pri kateri moramo izračunati funkcijo .
Strojno izpeljevanje uteži in Gaussove točke¶
Definirajmo simbole in nastavimo enačbo:
a_0, a_1, x, x_L, x_D, A_0, x_0 = sym.symbols('a_0, a_1, x, x_L, x_D, A_0, x_0') # simboli
P1 = a_0 + a_1*x # linearni polinom
eq = sym.Eq(P1.integrate((x, x_L, x_D)).expand(), A_0*P1.subs(x, x_0)) # teoretični integral = ocen z utežmi
eqPripravimo dve enačbi (za prvo predpostavimo , za drugo predpostavimo ) ter rešimo sistem za A_0 in x_0:
sym.solve([eq.subs(a_0, 0).subs(a_1, 1), eq.subs(a_1, 0).subs(a_0, 1)], [A_0, x_0])Za dodatno razlago priporočam video posnetek.
Gaussova integracijska metoda z več vozlišči¶
Izpeljati želimo Gaussovo integracijsko metodo, ki bo upoštevala na intervalu vozlišč in bo točno izračunala integral polinomov do stopnje . Veljati mora:
Pri izpeljavi se bomo omejili na standardne meje , ,
kjer je polinom stopnje definiran kot:
Z dvema Gaussovima točkama/vozliščema točno izračunamo integral polinoma do tretjega reda, s tremi Gaussovimi vozlišči pa točno izračunamo integral polinoma do petega reda!
Strojno izpeljevanje¶
Pripravimo si najprej simbolni zapis polinoma in ustreznih spremenljivk:
def P_etc(n=1, a='a', x='x'): # n je stopnja polinoma
ai = sym.symbols(f'{a}:{n+1}') # seznam a_i
x = sym.symbols(x) # spremenljivka x
return ai, x, sum([ai[i]*x**i for i in range(n+1)])Sedaj pa poiščimo uteži in vozlišča za primer dveh Gaussovih vozlišč; polinom je torej tretje stopnje.
v = 2 # število vozlišč
ai, x, P = P_etc(n=2*v-1)
xi = sym.symbols(f'x:{v}') # seznam x_i
Ai = sym.symbols(f'A:{v}') # seznam A_i
print(f'Vozlišča: {xi}\nUteži: {Ai}')Vozlišča: (x0, x1)
Uteži: (A0, A1)
Polinom:
PPodobno kakor zgoraj za eno vozlišče, tukaj definirajmo enačbe:
eqs = [sym.Eq(P.integrate((x, -1, 1)).coeff(a_),\
sum([Ai[i]*P.subs(x, xi[i]) \
for i in range(v)]).expand().coeff(a_)) \
for a_ in ai]
eqsRešimo jih za neznane in :
sol = sym.solve(eqs, sym.flatten((xi, Ai)))
solDoločili smo seznam dveh (enakih) rešitev.
Najprej sta definirani vozlišči: in , katerima pripadata uteži .
Koda zgoraj je izpeljana v splošnem - število vozlišč v lahko povečate ter izračunate vozlišča ter pripadajoče uteži.
Spodaj je podana tabela vozlišč in uteži za eno, dve in tri vozlišča (za meje , ):
Število točk 1:
| Vozlišče | Utež | |
|---|---|---|
| 0 | 0 | 2 |
Število točk 2:
| Vozlišče | Utež | |
|---|---|---|
| 0 | 1 | |
| 1 | 1 |
Število točk 3:
| Vozlišče | Utež | |
|---|---|---|
| 0 | ||
| 1 | 0 | |
| 2 |
Za več vozlišč in tudi oceno napake, glejte Mathworld Legendre-Gauss Quadrature.
Za primer treh Gaussovih točk numerični integral izračunamo (standardne meje):
Numerična implementacija¶
Numerična implementacija (vključno s transformacijo mej) za eno, dve ali tri vozlišča:
def Gaussova(fun, a, b, vozlišč=1):
"""
Gaussova integracijska metoda.
:param fun: objekt funkcije, ki jo integriramo
:param a: spodnja meja
:param b: zgornja meja
:param vozlišč: število vozlišč (1, 2 ali 3)
"""
def g(xi): # funkcija za transformacijo mej
return (b-a)/2 * fun((b+a +xi * (b-a))/2)
if vozlišč == 1:
return 2*g(0.)
elif vozlišč == 2:
return 1. * g(-np.sqrt(3)/3) + 1. * g(np.sqrt(3)/3)
elif vozlišč == 3:
return 5/9 * g(-np.sqrt(15)/5) +8/9 * g(0.) + 5/9 * g(np.sqrt(15)/5)Poglejmo si zgled. Najprej definirajmo funkcijo, ki jo želimo integrirati:
def f(x):
return x*np.sin(x)Sedaj pa funkcijo (v konkretnem primeru f) in ne vrednosti (npr. f(0.)) posredujemo funkciji Gaussova. Najprej za eno vozlišče, nato dve in tri:
Gaussova(fun=f, a=1., b=2., vozlišč=1)Gaussova(fun=f, a=1., b=2., vozlišč=2)Gaussova(fun=f, a=1., b=2., vozlišč=3)scipy.integrate.fixed_quad¶
Znotraj scipy je Gaussova integracijska metoda implementirana v okviru funkcije scipy.integrate.fixed_quad() (dokumentacija):
fixed_quad(func, a, b, args=(), n=5)kjer so parametri:
funcje ime funkcije, ki jo kličemo,aje spodnja meja,bje zgornja meja,argsje terka morebitnih dodatnih argumentov funkcijefunc,nje število vozlišč Gaussove integracije, privzeton=5.
Funkcija vrne terko z rezultatom integriranja val in vrednost None: (val, None)
Poglejmo primer od zgoraj:
from scipy.integrate import fixed_quad
fixed_quad(f, a=1, b=2, n=3)[0]Rezultat je enak predhodnemu:
Gaussova(fun=f, a=1., b=2., vozlišč=3)scipy.integrate¶
scipy.integrate je močno orodje za numerično integriranje (glejte dokumentacijo). V nadaljevanju si bomo pogledali nekatere funkcije.
Integracijske funkcije, ki zahtevajo definicijsko funkcijo:¶
quad(func, a, b[, args, full_output, ...])izračuna določeni integralfunc(x)v mejah [a,b],dblquad(func, a, b, gfun, hfun[, args, ...])izračuna določeni integralfunc(x,y),tplquad(func, a, b, gfun, hfun, qfun, rfun)izračuna določeni integralfunc(x,y,z),nquad(func, ranges[, args, opts, full_output])izračuna določeni integral dimenzijske funkcijefunc( ...),
scipy.integrate.quad¶
Poglejmo si zelo uporabno funkcijo za integriranje, scipy.integrate.quad() (dokumentacija):
quad(func, a, b, args=(), full_output=0, epsabs=1.49e-08, epsrel=1.49e-08, limit=50,
points=None, weight=None, wvar=None, wopts=None, maxp1=50, limlst=50)Izbrani parametri so:
funcPython funkcija, ki jo integriramo,aspodnja meja integriranja (lahko se uporabinp.infza mejo v neskončnosti),bzgornja meja integriranja (lahko se uporabinp.infza mejo v neskončnosti),full_outputza prikaz vseh rezultatov, privzeto 0,epsabsdovoljena absolutna napaka,epsreldovoljena relativna napaka.
Poglejmo primer od zgoraj:
from scipy import integrateintegrate.quad(f, a=1, b=2)scipy.integrate.dblquad¶
Gre za podobno funkcijo kot quad, vendar za integriranje po dveh spremenljivkah (dokumentacija).
Funkcija scipy.integrate.dblquad() izračuna dvojni integral func(y, x) v mejah od x = [a, b] in y = [gfun(x), hfun(x)].
dblquad(func, a, b, gfun, hfun, args=(), epsabs=1.49e-08, epsrel=1.49e-08)Izbrani parametri so:
funcje Python funkcija, ki jo integriramo,aje spodnja meja integriranjax(lahko se uporabinp.infza mejo v neskončnosti),bje zgornja meja integriranjax(lahko se uporabinp.infza mejo v neskončnosti),gfunje Python funkcija, ki definira spodnjo mejoyv odvisnosti odx,hfunje Python funkcija, ki definira zgornjo mejoyv odvisnosti odx.
Poglejmo primer izračuna površine polkroga s polmerom 1:
Definirajmo ustrezne Python funkcije in izračunajmo rezultat:
def func(y, x): # integracijska funkcija je enostavna, konstanta = 1!
return 1.
def gfun(x): # spodnja meja = 0
return 0.
def hfun(x): # zgornja meja
return np.sqrt(1-x**2)
integrate.dblquad(func=func, a=-1, b=1, gfun=gfun, hfun=hfun)Integracijske funkcije, ki zahtevajo tabelo vrednosti:¶
trapezoid(y[, x, dx, axis])sestavljeno trapezno pravilo,cumulative_trapezoid(y[, x, dx, axis, initial])kumulativni integral podintegralske funkcije (vrne rezultat v vsakem vozlišču),simpson(y[, x, dx, axis])Simpsonova metoda,romb(y[, dx, axis, show])Rombergova metoda.
Tukaj si bomo na primeru ogledali funkcijo cumulative_trapezoid. Oglejmo si primer, ko na maso (enote izpustimo) deluje sila . Iz 2. Newtonovega zakona sledi: . Pospešek integriramo, da izračunamo hitrost; nato integriramo še enkrat za pomik. Definirajmo najprej funkcijo za pospešek:
def pospešek(t):
F = np.sin(t)
m = 1
return F/mZanima nas dogajanje v času 3 sekund:
t, h = np.linspace(0, 3, 100, retstep=True)Izračunajmo tabelo pospeškov ter nato integrirajmo za hitrost (pri tem je pomembno, da definiramo začetno vrednost):
a = pospešek(t)
v = integrate.cumulative_trapezoid(y=a, dx=h, initial=0)Hitrost sedaj še enkrat integrirajmo, da izračunamo pot:
s = integrate.cumulative_trapezoid(y=v, dx=h, initial=0)Prikažimo rezultat:
plt.plot(t, a, label='Pospešek')
plt.plot(t, v, label='Hitrost')
plt.plot(t, s, label='Pot')
plt.xlabel('$t$ [s]')
plt.legend();
Vprašanje 1: Z uporabo orodij paketa sympy simbolno določite vrednost statičnega momenta prereza v obliki četrtine kroga na sliki:

Pripravite tudi numerično funkcijo odvisnosti integranda pri podani vrednosti polmera .
Podatki:
mm
Vprašanje 2: Uporabite numerično funkcijo, pripravljeno pri prejšnji nalogi, in izračunajte ter grafično prikažite vrednosti integranda iz prve naloge pri 100 diskretnih točkah na intervalu .
Izračunajte vrednost določenega integrala še numerično, s pomočjo trapezne in Simpsonove 1/3 metode iz paketov numpy oziroma scipy.
Trapezno pravilo¶
Vprašanje 3: Z uporabo lastne implementacije trapeznega pravila (osnovnega, ne sestavljenega) izračunajte določeni integral
Dobljeno vrednost primerjajte z rezultatom funkcije numpy.trapezoid (ali scipy.integrate.trapezoid), kjer opazovan interval razdelite na 10 ekvidistantnih odsekov.
Vprašanje 4 : Uporabite Richardsonovo ekstrapolacijo in določite natančnejšo vrednost integrala iz prejšnje naloge tako, da opazovan interval najprej razdelite na 2, nato še na 4 ekvidistantne segmente in uporabite sestavljeno trapezno metodo iz paketa numpy.
Simpsonovo 1/3 pravilo¶
Vprašanje 5: Določen integral iz prejšnje naloge izračunajte z lastno kodo Simpsonove 1/3 metode (osnovne, ne sestavljene).
Dobljeno vrednost primerjajte z rezultatom funkcije scipy.integrate.simpson, kjer opazovan interval razdelite na 7 ekvidistantnih točk.
Vprašanje 6: Podane so izmerjene vrednosti pospeška avtomobila v smeri vožnje v času. Z uporabo kumulativne trapezne metode (scipy.integrate.cumulative_trapezoid) določite vrednosti hitrosti in opravljene poti avtomobila v opazovanem časovnem intervalu.
Avto pri času miruje (namig: argument initial).
#Podatki
t = np.linspace(0, 7, 10) # s
a = np.array([ 3.47, 4.03, 4.36, 4.48, 4.27, 3.78, 3.19, 2.73, 2.54, 2.53]) # m/s^2Gaussova integracijska metoda (Gaussova kvadratura)¶
Vprašanje 7: Z uporabo sestavljene trapezne metode iz scipy in metode Gaussove integracije (scipy.integrate.quad) izračunajte vrednosti integralov:
Pri uporabi trapezne metode razdelite opazovan interval na 10 točk.
Vprašanje 8: Integral:
izračunajte še z uporabo funkcije scipy.integrate.fixed_quad, ki ji lahko podamo tudi parameter števila vozlišč pri integraciji, n. Najprej uporabite integracijo z enim vozliščem, nato z dvema in nazadnje še s tremi vozlišči.