Дифференцирование и интегрирование функций#

from matplotlib import pyplot as plt


def configure_matplotlib():
    plt.rc('text', usetex=True)
    plt.rcParams["axes.titlesize"] = 28
    plt.rcParams["axes.labelsize"] = 24
    plt.rcParams["legend.fontsize"] = 24
    plt.rcParams["xtick.labelsize"] = plt.rcParams["ytick.labelsize"] = 18
    plt.rcParams["text.latex.preamble"] = r"""
    \usepackage[utf8]{inputenc}
    \usepackage[english,russian]{babel}
    \usepackage{amsmath}
    """

configure_matplotlib()

Дифференцирование функций#

Разностная производная#

Одно из возможных определений первой производной дифференцируемой функции \(f(x)\) имеет вид

\[ \dfrac{\mathrm{d} f(x)}{\mathrm{d}x} = \lim_{h \to 0} \dfrac{f(x + h) - f(x)}{h}. \]

В рамказ компьютерной арифметики предельный переход осуществить невозможно, поэтому в целях аппроксимации производной нередко вместо предела при \(h \to 0\) подставляют очень малое \(h\):

\[ \dfrac{\mathrm{d} f(x)}{\mathrm{d}x} \approx \dfrac{f(x + h) - f(x)}{h}. \]

Такая аппроксимация производной называется правой разностной производной. Можно показать, что асимптотическая погрешность вычисления производной таким способом имеет вид \(o(h)\), т.е. уменьшая шаг \(h\) можно добиться любой точности вычисления производной. Более распространенна центральная разнастная производная, определяемая выражением

\[ \dfrac{\mathrm{d} f(x)}{\mathrm{d}x} \approx \dfrac{f(x + h) - f(x - h)}{2h}. \]

Её асимптотическая погрешность имеет вид \(o(h^2)\), а значит уменьшая шаг \(h\) в 2 раза, можно ожидать уменьшение погрешности вычисления производной в 4 раза.

Аналогичным образом можно определить аппроксимацию производной любого порядка. Метод scipy.misc.derivative в SciPy вычисляет разностную производную произвольного порядка (опциональный параметр n).

Продемонстрируем его применение на примере функции \(f(x) = e^{2x}\).

from scipy.misc import derivative
import numpy as np

def f(x):
    return np.exp(2. * x)

fig, ax = plt.subplots(figsize=(6, 6), layout="tight")
x = np.linspace(-1, 0, 100)
labels = ("$f(x)$", "$f'(x)$", "$f''(x)$")


for n, label in enumerate(labels):
    y = derivative(f, x, n=n, dx=1e-3, order=2*n+1) if order > 0 else f(x)
    ax.plot(x, y, label=label)
    
ax.set_xlabel("$x$")
ax.set_ylabel("$y$")
ax.legend()
ax.grid()   
../../_images/integration_3_0.png

Аналитическое дифференцирование#

Ряд современных библиотек умеет вычислять производные от своих методов. Например, библиотека autograd.

Note

Обратите внимание, что для аналитического вычисления производной средствами библиотеки autograd, необходимо вместо библиотеки NumPy использовать модуль autograd.numpy.

from autograd import numpy as np
from autograd import elementwise_grad 

fig, ax = plt.subplots(figsize=(6, 6), layout="tight")
x = np.linspace(-1, 0, 100)
labels = ("$f(x)$", "$f'(x)$", "$f''(x)$")
funcs = (f, elementwise_grad(f), elementwise_grad(elementwise_grad(f)))

for order, (label, func) in enumerate(zip(labels, funcs)):
    ax.plot(x, func(x), label=label)
    
ax.set_xlabel("$x$")
ax.set_ylabel("$y$")
ax.legend()
ax.grid()   
../../_images/integration_5_0.png

Интегрирование функций#

Подмодуль scipy.integrate позволяет приближенно вычислять значение определенных интегралов.

Однократные интегралы#

Функция scipy.integrate.quad позволяет проинтегрировать функцию \(f\colon \mathbb{R} \to \mathbb{R}\). Вызов функции quad(f, a, b) приближенно находит значение интеграла

\[ \int\limits_a^b f(x) \, dx. \]

В качестве примера найдем численно значение интеграла

\[ I = \int\limits_0^\pi \sin x \, dx = -\cos x\Big|_0^\pi = 2. \]
import numpy as np
from scipy import integrate
from matplotlib import pyplot as plt


f = np.sin
a, b = 0, np.pi
I, _ = integrate.quad(f, 0, np.pi)
x = np.linspace(0, np.pi, 100)
y = f(x)


fig, ax = plt.subplots(figsize=(10, 6), layout="tight")
ax.plot(x, y, label=r"$f(x)=\sin x$")
ax.set_xlabel("$x$")
ax.set_ylabel("$y$")
ax.fill_between(x, np.zeros_like(x), y, where=(y>0), facecolor='green', alpha=0.30)
ax.set_xticks(np.linspace(0, np.pi, 7))
ax.text(np.pi/2, 0.5, fr"$S = {I}$", fontdict={"size": 24, "ha": "center"})
ax.legend()
ax.grid()
../../_images/integration_7_0.png

Параметры \(a\) и \(b\) могут принимать значения -inf и +inf, чтобы брать несобственные интегралы. Продемонстрируем это на примере интеграла

\[ I = \int\limits_1^\infty \dfrac{1}{x^2}\,dx = 1. \]
def f(x):
    return 1. / np.square(x)


a, b = 1, np.inf
I, _ = integrate.quad(f, a, b)

x = np.linspace(a, 7, 100)
y = f(x)


fig, ax = plt.subplots(figsize=(10, 6), layout="tight")
ax.plot(x, y, label=r"$f(x)=\dfrac{1}{x^2}$")
ax.set_xlabel("$x$")
ax.set_ylabel("$y$")
ax.fill_between(x, np.zeros_like(x), y, where=(y>0), facecolor='green', alpha=0.30)
ax.set_xticks(np.linspace(1, 7, 7))
ax.text(1.5, 0.1, fr"$S = {I}$", fontdict={"size": 24, "ha": "center"})
ax.legend()
ax.grid()
../../_images/integration_9_0.png

Однако численное взятие несобственных интегралов отнюдь не тривиальная задача. Например, интеграл Френеля $\( \int\limits_0^\infty \sin x^2 \, dx = \sqrt{\dfrac{\pi}{8}} \)$

просто так вычислить не удастся.

def f(t):
    return np.sin(t**2)

I, _ = integrate.quad(f, 0, np.inf)
print(I)
-2395.5826175299862
C:\Users\fadeev\AppData\Local\Temp/ipykernel_8252/3166585030.py:4: IntegrationWarning: The integral is probably divergent, or slowly convergent.
  I, _ = integrate.quad(f, 0, np.inf)

Интегралы большей кратности#

Функция scipy.integrate.dblquad позволяет вычислять интегралы вида

\[ \int\limits_a^b \!\! \int\limits_{g(x)}^{h(x)} f(x, y) \, dx dy. \]

В качестве примера возьмём интеграл функции \(f = \sqrt{x^2 + y^2}\) в области \(D\) совпадающей с кругом единичного радиуса с центром в начале:

\[ \int\limits_{-1}^{1} \!\!\! \int\limits_{-\sqrt{1 - x^2}}^{\sqrt{1-x^2}} \sqrt{x^2 + y^2} \, dx dy = 2 \pi \int\limits_{0}^1 r^2 \, dr = \frac{2 \pi}{3}. \]
import numpy as np
from scipy import integrate
from matplotlib import pyplot as plt


def h(x):
    return np.sqrt(1 - x**2)

def g(x):
    return -h(x)

def f(x, y):
    return np.sqrt(x**2 + y**2)

a, b = -1, 1
I, _ = integrate.dblquad(f, -1, 1, g, h)

x = np.linspace(a, b, 100)
y = np.linspace(a, b, 100)
x, y = np.meshgrid(x, y)
z = f(x, y)

fig, ax = plt.subplots(figsize=(8, 8), layout="tight", subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z, cmap="coolwarm")
ax.set_xlabel("$x$")
ax.set_ylabel("$y$")
ax.set_zlabel("$z$")
ax.set_xticks([-1, 0, 1])
ax.set_yticks([-1, 0, 1])
ax.set_zticks([0, 1])
ax.set_title(r"$\sqrt{x^2 + y^2}$")



print(f"Вычисленное значение интеграла: {I}, точное значение: {2*np.pi/3}.")
Вычисленное значение интеграла: 2.0943951023924106, точное значение: 2.0943951023931953.
../../_images/integration_13_1.png

Трехкратные интегралы вида

\[ \int\limits_a^b \!\! \int\limits_{g(x)}^{h(x)} \!\! \int\limits_{q(x, y)}^{r(x, y)} f(x, y, z) \, dx dy dz. \]

можно вычислить методом integrate.tplquad. Интеграл произвольной кратности можно вычислить методом integrate.tplquad.