2.1 複素微分とコーシー・リーマンの方程式
複素関数 $f(z)$ が点 $z_0$ で微分可能であるとは、極限 $\lim_{h \to 0} \frac{f(z_0+h) - f(z_0)}{h}$ が $h$ の近づき方によらず存在することです。
📐 定理: コーシー・リーマンの方程式
$f(z) = u(x,y) + iv(x,y)$ が正則であるための必要十分条件: $$\frac{\partial u}{\partial x} = \frac{\partial v}{\partial y}, \quad \frac{\partial u}{\partial y} = -\frac{\partial v}{\partial x}$$ 複素微分の計算: $$f'(z) = \frac{\partial u}{\partial x} + i\frac{\partial v}{\partial x} = \frac{\partial v}{\partial y} - i\frac{\partial u}{\partial y}$$
$f(z) = u(x,y) + iv(x,y)$ が正則であるための必要十分条件: $$\frac{\partial u}{\partial x} = \frac{\partial v}{\partial y}, \quad \frac{\partial u}{\partial y} = -\frac{\partial v}{\partial x}$$ 複素微分の計算: $$f'(z) = \frac{\partial u}{\partial x} + i\frac{\partial v}{\partial x} = \frac{\partial v}{\partial y} - i\frac{\partial u}{\partial y}$$
💻 コード例1: コーシー・リーマンの方程式の検証
Python実装: コーシー・リーマンの方程式の検証
import numpy as np
import matplotlib.pyplot as plt
from scipy.misc import derivative
def f_analytic(z):
"""正則関数: f(z) = z^2"""
return z**2
def f_not_analytic(z):
"""非正則関数: f(z) = z̄ (複素共役)"""
return np.conj(z)
# 実部と虚部を分離
def extract_uv(f, x, y):
z = x + 1j*y
w = f(z)
return w.real, w.imag
# 偏微分の数値計算
def check_cauchy_riemann(f, x0, y0, h=1e-5):
u, v = extract_uv(f, x0, y0)
# ∂u/∂x
u_xp, _ = extract_uv(f, x0+h, y0)
u_xm, _ = extract_uv(f, x0-h, y0)
du_dx = (u_xp - u_xm) / (2*h)
# ∂u/∂y
u_yp, _ = extract_uv(f, x0, y0+h)
u_ym, _ = extract_uv(f, x0, y0-h)
du_dy = (u_yp - u_ym) / (2*h)
# ∂v/∂x
_, v_xp = extract_uv(f, x0+h, y0)
_, v_xm = extract_uv(f, x0-h, y0)
dv_dx = (v_xp - v_xm) / (2*h)
# ∂v/∂y
_, v_yp = extract_uv(f, x0, y0+h)
_, v_ym = extract_uv(f, x0, y0-h)
dv_dy = (v_yp - v_ym) / (2*h)
return du_dx, du_dy, dv_dx, dv_dy
# テスト点
x0, y0 = 1.5, 2.0
print("=== 正則関数: f(z) = z^2 ===")
du_dx, du_dy, dv_dx, dv_dy = check_cauchy_riemann(f_analytic, x0, y0)
print(f"∂u/∂x = {du_dx:.6f}")
print(f"∂v/∂y = {dv_dy:.6f}")
print(f"∂u/∂x - ∂v/∂y = {du_dx - dv_dy:.6e} (should be ~0)")
print(f"\n∂u/∂y = {du_dy:.6f}")
print(f"-∂v/∂x = {-dv_dx:.6f}")
print(f"∂u/∂y - (-∂v/∂x) = {du_dy - (-dv_dx):.6e} (should be ~0)")
print("\n\n=== 非正則関数: f(z) = z̄ ===")
du_dx, du_dy, dv_dx, dv_dy = check_cauchy_riemann(f_not_analytic, x0, y0)
print(f"∂u/∂x = {du_dx:.6f}")
print(f"∂v/∂y = {dv_dy:.6f}")
print(f"∂u/∂x - ∂v/∂y = {du_dx - dv_dy:.6f} (NOT ~0)")
print(f"\n∂u/∂y = {du_dy:.6f}")
print(f"-∂v/∂x = {-dv_dx:.6f}")
print(f"∂u/∂y - (-∂v/∂x) = {du_dy - (-dv_dx):.6f} (NOT ~0)")
# 可視化
x = np.linspace(-2, 2, 100)
y = np.linspace(-2, 2, 100)
X, Y = np.meshgrid(x, y)
Z = X + 1j*Y
# 正則関数
W_analytic = f_analytic(Z)
U_analytic = W_analytic.real
V_analytic = W_analytic.imag
# 非正則関数
W_not = f_not_analytic(Z)
U_not = W_not.real
V_not = W_not.imag
fig, axes = plt.subplots(2, 2, figsize=(14, 12))
# 正則関数: 実部
im = axes[0, 0].contourf(X, Y, U_analytic, levels=20, cmap='RdBu_r')
axes[0, 0].contour(X, Y, V_analytic, levels=10, colors='green', linewidths=1, alpha=0.5)
axes[0, 0].plot(x0, y0, 'ko', markersize=10)
axes[0, 0].set_xlabel('x', fontsize=12)
axes[0, 0].set_ylabel('y', fontsize=12)
axes[0, 0].set_title('正則関数 $f(z)=z^2$: 実部(色), 虚部(緑線)', fontsize=12)
plt.colorbar(im, ax=axes[0, 0])
# 正則関数: 虚部
im = axes[0, 1].contourf(X, Y, V_analytic, levels=20, cmap='RdBu_r')
axes[0, 1].contour(X, Y, U_analytic, levels=10, colors='red', linewidths=1, alpha=0.5)
axes[0, 1].plot(x0, y0, 'ko', markersize=10)
axes[0, 1].set_xlabel('x', fontsize=12)
axes[0, 1].set_ylabel('y', fontsize=12)
axes[0, 1].set_title('正則関数 $f(z)=z^2$: 虚部(色), 実部(赤線)', fontsize=12)
plt.colorbar(im, ax=axes[0, 1])
# 非正則関数: 実部
im = axes[1, 0].contourf(X, Y, U_not, levels=20, cmap='RdBu_r')
axes[1, 0].contour(X, Y, V_not, levels=10, colors='green', linewidths=1, alpha=0.5)
axes[1, 0].plot(x0, y0, 'ko', markersize=10)
axes[1, 0].set_xlabel('x', fontsize=12)
axes[1, 0].set_ylabel('y', fontsize=12)
axes[1, 0].set_title('非正則関数 $f(z)=\\bar{z}$: 実部(色), 虚部(緑線)', fontsize=12)
plt.colorbar(im, ax=axes[1, 0])
# 非正則関数: 虚部
im = axes[1, 1].contourf(X, Y, V_not, levels=20, cmap='RdBu_r')
axes[1, 1].contour(X, Y, U_not, levels=10, colors='red', linewidths=1, alpha=0.5)
axes[1, 1].plot(x0, y0, 'ko', markersize=10)
axes[1, 1].set_xlabel('x', fontsize=12)
axes[1, 1].set_ylabel('y', fontsize=12)
axes[1, 1].set_title('非正則関数 $f(z)=\\bar{z}$: 虚部(色), 実部(赤線)', fontsize=12)
plt.colorbar(im, ax=axes[1, 1])
plt.suptitle('正則関数と非正則関数の等高線 (直交性の検証)', fontsize=14)
plt.tight_layout()
plt.show()
📌 注意: 正則関数では実部と虚部の等高線が直交します(コーシー・リーマンの方程式の幾何学的意味)。
2.2 正則関数の例と性質
多くの複素関数は正則ですが、複素共役や絶対値を含む関数は正則ではありません。
📐 定理: 正則関数
正則関数の例:
正則関数の例:
- 多項式: $z^n$, $a_n z^n + \cdots + a_1 z + a_0$
- 指数関数: $e^z$
- 三角関数: $\sin z$, $\cos z$
- 有理関数: $\frac{P(z)}{Q(z)}$ ($Q(z) \neq 0$ の領域)
- 複素共役: $\bar{z}$
- 実部/虚部: $\mathrm{Re}(z)$, $\mathrm{Im}(z)$
- 絶対値: $|z|$
💻 コード例2: 様々な正則関数の微分
Python実装: 正則関数の微分
import numpy as np
import matplotlib.pyplot as plt
# 複素微分の数値計算
def complex_derivative(f, z, h=1e-7):
return (f(z + h) - f(z - h)) / (2*h)
# テスト関数
functions = {
'z^2': lambda z: z**2,
'z^3': lambda z: z**3,
'e^z': lambda z: np.exp(z),
'sin(z)': lambda z: np.sin(z),
'1/z': lambda z: 1/z,
}
# 理論的な導関数
derivatives_theory = {
'z^2': lambda z: 2*z,
'z^3': lambda z: 3*z**2,
'e^z': lambda z: np.exp(z),
'sin(z)': lambda z: np.cos(z),
'1/z': lambda z: -1/z**2,
}
# テスト点
z0 = 1.5 + 2.0j
print("複素微分の計算と検証:")
print("=" * 60)
for name, f in functions.items():
f_prime_numerical = complex_derivative(f, z0)
f_prime_theoretical = derivatives_theory[name](z0)
error = np.abs(f_prime_numerical - f_prime_theoretical)
print(f"\nf(z) = {name}")
print(f" z = {z0}")
print(f" 数値微分: f'(z) = {f_prime_numerical:.6f}")
print(f" 理論値: f'(z) = {f_prime_theoretical:.6f}")
print(f" 誤差: {error:.2e}")
# 可視化: ベクトル場としての導関数
x = np.linspace(-2, 2, 15)
y = np.linspace(-2, 2, 15)
X, Y = np.meshgrid(x, y)
Z = X + 1j*Y
fig, axes = plt.subplots(2, 3, figsize=(16, 10))
axes = axes.flatten()
for idx, (name, f) in enumerate(functions.items()):
if idx >= len(axes):
break
ax = axes[idx]
# 関数値
W = f(Z)
# 導関数(ベクトル場)
F_prime = np.array([[complex_derivative(f, z) for z in row] for row in Z])
# ベクトル場の可視化
U = F_prime.real
V = F_prime.imag
magnitude = np.sqrt(U**2 + V**2)
# 色で大きさを表示
im = ax.contourf(X, Y, magnitude, levels=20, cmap='viridis', alpha=0.6)
# ベクトル場
skip = 2
ax.quiver(X[::skip, ::skip], Y[::skip, ::skip],
U[::skip, ::skip], V[::skip, ::skip],
magnitude[::skip, ::skip], cmap='hot', scale=50, width=0.003)
ax.set_xlabel('Re(z)', fontsize=10)
ax.set_ylabel('Im(z)', fontsize=10)
ax.set_title(f"$f'(z)$ for $f(z) = {name}$", fontsize=12)
ax.axis('equal')
ax.grid(True, alpha=0.3)
plt.colorbar(im, ax=ax, label="$|f'(z)|$")
# 最後のサブプロットを削除(5つしか関数がないので)
fig.delaxes(axes[5])
plt.suptitle('正則関数の導関数(ベクトル場表示)', fontsize=14)
plt.tight_layout()
plt.show()
2.3 複素積分の計算
複素積分は経路積分として定義されます: $\int_C f(z) dz = \int_a^b f(z(t)) z'(t) dt$
📐 定理: 複素線積分
$$\int_C f(z) dz = \int_a^b f(z(t)) \frac{dz}{dt} dt$$ ここで $z(t)$ は経路 $C$ のパラメータ表示 $(a \leq t \leq b)$
$$\int_C f(z) dz = \int_a^b f(z(t)) \frac{dz}{dt} dt$$ ここで $z(t)$ は経路 $C$ のパラメータ表示 $(a \leq t \leq b)$
💻 コード例3: 複素積分の数値計算
Python実装: 複素積分の数値計算
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import quad
def complex_line_integral(f, z_t, t_range, n_points=1000):
"""
複素線積分の数値計算
f: 被積分関数
z_t: 経路のパラメータ表示 z(t)
t_range: (t_start, t_end)
"""
t = np.linspace(t_range[0], t_range[1], n_points)
dt = t[1] - t[0]
# 経路上の点
z = z_t(t)
# 導関数 dz/dt (数値微分)
dz_dt = np.gradient(z, dt)
# 被積分関数の値
f_z = f(z)
# 積分 (台形則)
integral = np.trapz(f_z * dz_dt, dx=dt)
return integral, z
# テスト関数
f1 = lambda z: z
f2 = lambda z: z**2
f3 = lambda z: 1/z
# 経路1: 原点から1+iへの直線
path1 = lambda t: t * (1 + 1j)
t_range1 = (0, 1)
print("=== 経路1: 直線 (0 → 1+i) ===")
integral1_f1, z1 = complex_line_integral(f1, path1, t_range1)
print(f"∫ z dz = {integral1_f1:.6f}")
print(f"理論値: (1+i)^2 / 2 = {(1+1j)**2 / 2:.6f}")
integral1_f2, _ = complex_line_integral(f2, path1, t_range1)
print(f"\n∫ z^2 dz = {integral1_f2:.6f}")
print(f"理論値: (1+i)^3 / 3 = {(1+1j)**3 / 3:.6f}")
# 経路2: 単位円(反時計回り)
path2 = lambda t: np.exp(1j * t)
t_range2 = (0, 2*np.pi)
print("\n\n=== 経路2: 単位円(反時計回り) ===")
integral2_f1, z2 = complex_line_integral(f1, path2, t_range2)
print(f"∫ z dz = {integral2_f1:.6f}")
print(f"理論値: 0 (正則関数の閉曲線積分)")
integral2_f3, _ = complex_line_integral(f3, path2, t_range2)
print(f"\n∫ (1/z) dz = {integral2_f3:.6f}")
print(f"理論値: 2πi = {2*np.pi*1j:.6f}")
# 経路3: 原点から1+iへの折れ線 (0→1→1+i)
path3a = lambda t: t # 0 → 1 (実軸)
path3b = lambda t: 1 + 1j*t # 1 → 1+i (虚軸)
integral3_f1a, z3a = complex_line_integral(f1, path3a, (0, 1))
integral3_f1b, z3b = complex_line_integral(f1, path3b, (0, 1))
integral3_f1_total = integral3_f1a + integral3_f1b
print("\n\n=== 経路3: 折れ線 (0→1→1+i) ===")
print(f"∫ z dz = {integral3_f1_total:.6f}")
print(f"理論値: (1+i)^2 / 2 = {(1+1j)**2 / 2:.6f}")
print(f"(経路によらない = 正則関数)")
# 可視化
fig, axes = plt.subplots(1, 3, figsize=(16, 5))
# 経路1
ax = axes[0]
ax.plot(z1.real, z1.imag, 'b-', linewidth=2, label='経路')
ax.plot(0, 0, 'go', markersize=10, label='始点')
ax.plot(1, 1, 'ro', markersize=10, label='終点')
ax.arrow(0, 0, 0.4, 0.4, head_width=0.05, head_length=0.05, fc='blue', ec='blue')
ax.grid(True, alpha=0.3)
ax.set_xlabel('Re(z)', fontsize=12)
ax.set_ylabel('Im(z)', fontsize=12)
ax.set_title('経路1: 直線 $(0 \\to 1+i)$', fontsize=12)
ax.axis('equal')
ax.legend()
# 経路2
ax = axes[1]
ax.plot(z2.real, z2.imag, 'b-', linewidth=2, label='経路')
ax.plot(1, 0, 'go', markersize=10, label='始点/終点')
# 矢印(反時計回り)
angles_arrow = [0, np.pi/2, np.pi, 3*np.pi/2]
for angle in angles_arrow:
z_arr = np.exp(1j * angle)
dz = 0.3 * np.exp(1j * (angle + np.pi/2))
ax.arrow(z_arr.real, z_arr.imag, dz.real, dz.imag,
head_width=0.1, head_length=0.08, fc='blue', ec='blue', alpha=0.6)
ax.grid(True, alpha=0.3)
ax.set_xlabel('Re(z)', fontsize=12)
ax.set_ylabel('Im(z)', fontsize=12)
ax.set_title('経路2: 単位円(反時計回り)', fontsize=12)
ax.axis('equal')
ax.legend()
# 経路3
ax = axes[2]
ax.plot(z3a.real, z3a.imag, 'b-', linewidth=2, label='経路')
ax.plot(z3b.real, z3b.imag, 'b-', linewidth=2)
ax.plot(0, 0, 'go', markersize=10, label='始点')
ax.plot(1, 1, 'ro', markersize=10, label='終点')
ax.plot(1, 0, 'ko', markersize=8, label='中間点')
ax.arrow(0, 0, 0.4, 0, head_width=0.05, head_length=0.05, fc='blue', ec='blue')
ax.arrow(1, 0, 0, 0.4, head_width=0.05, head_length=0.05, fc='blue', ec='blue')
ax.grid(True, alpha=0.3)
ax.set_xlabel('Re(z)', fontsize=12)
ax.set_ylabel('Im(z)', fontsize=12)
ax.set_title('経路3: 折れ線 $(0 \\to 1 \\to 1+i)$', fontsize=12)
ax.axis('equal')
ax.legend()
plt.suptitle('複素積分の経路', fontsize=14)
plt.tight_layout()
plt.show()
2.4 コーシーの積分定理
正則関数の閉曲線に沿った積分は0になります。これはコーシーの積分定理として知られています。
📐 定理: コーシーの積分定理
$$\oint_C f(z) dz = 0$$ ただし $f(z)$ は閉曲線 $C$ の内部で正則
$$\oint_C f(z) dz = 0$$ ただし $f(z)$ は閉曲線 $C$ の内部で正則
💻 コード例4: コーシーの積分定理の検証
Python実装: コーシーの積分定理の検証
import numpy as np
import matplotlib.pyplot as plt
def complex_contour_integral(f, path, t_range, n_points=1000):
"""閉曲線に沿った複素積分"""
t = np.linspace(t_range[0], t_range[1], n_points)
dt = t[1] - t[0]
z = path(t)
dz_dt = np.gradient(z, dt)
f_z = f(z)
integral = np.trapz(f_z * dz_dt, dx=dt)
return integral, z
# 正則関数
f_analytic = [
('z', lambda z: z),
('z^2', lambda z: z**2),
('e^z', lambda z: np.exp(z)),
('sin(z)', lambda z: np.sin(z)),
]
# 非正則関数
f_not_analytic = [
('z̄', lambda z: np.conj(z)),
('|z|^2', lambda z: np.abs(z)**2),
]
# 特異点を含む関数
f_singular = [
('1/z', lambda z: 1/z), # z=0 で特異点
('1/(z-1)', lambda z: 1/(z-1)), # z=1 で特異点
]
# 閉曲線: 単位円
unit_circle = lambda t: np.exp(1j * t)
t_range = (0, 2*np.pi)
print("=== コーシーの積分定理の検証 ===\n")
print("閉曲線: 単位円(反時計回り)\n")
print("【正則関数(特異点なし)】")
print("コーシーの積分定理により ∮f(z)dz = 0 のはず:")
for name, f in f_analytic:
integral, _ = complex_contour_integral(f, unit_circle, t_range)
print(f" ∮ {name:8s} dz = {integral.real:10.6f} + {integral.imag:10.6f}i")
print("\n【非正則関数】")
print("一般に ∮f(z)dz ≠ 0:")
for name, f in f_not_analytic:
integral, _ = complex_contour_integral(f, unit_circle, t_range)
print(f" ∮ {name:8s} dz = {integral.real:10.6f} + {integral.imag:10.6f}i")
print("\n【特異点を含む関数】")
print("単位円内に特異点 → ∮f(z)dz ≠ 0:")
for name, f in f_singular:
integral, _ = complex_contour_integral(f, unit_circle, t_range)
print(f" ∮ {name:12s} dz = {integral.real:10.6f} + {integral.imag:10.6f}i")
# 可視化: 様々な閉曲線での検証
contours = {
'単位円': (lambda t: np.exp(1j * t), (0, 2*np.pi)),
'正方形': (lambda t: np.where(t < 0.25, 4*t,
np.where(t < 0.5, 1 + 4j*(t-0.25),
np.where(t < 0.75, 1 - 4*(t-0.5) + 1j,
4j*(1 - (t-0.75))))), (0, 1)),
'楕円': (lambda t: 2*np.cos(t) + 1j*np.sin(t), (0, 2*np.pi)),
}
f_test = lambda z: z**2 # 正則関数
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
for ax, (name, (path, t_range)) in zip(axes, contours.items()):
integral, z_path = complex_contour_integral(f_test, path, t_range)
ax.plot(z_path.real, z_path.imag, 'b-', linewidth=2, label=f'経路: {name}')
ax.plot(z_path.real[0], z_path.imag[0], 'go', markersize=10, label='始点')
ax.grid(True, alpha=0.3)
ax.axhline(0, color='gray', linewidth=0.5)
ax.axvline(0, color='gray', linewidth=0.5)
ax.set_xlabel('Re(z)', fontsize=12)
ax.set_ylabel('Im(z)', fontsize=12)
ax.set_title(f'{name}\n∮ $z^2$ dz = {integral:.6f}', fontsize=12)
ax.axis('equal')
ax.legend()
plt.suptitle('コーシーの積分定理: 正則関数の閉曲線積分 = 0', fontsize=14)
plt.tight_layout()
plt.show()
2.5 コーシーの積分公式
正則関数の値は、その周囲の閉曲線上の値から求められます。
📐 定理: コーシーの積分公式
コーシーの積分公式: $$f(z_0) = \frac{1}{2\pi i} \oint_C \frac{f(z)}{z - z_0} dz$$ 導関数の公式: $$f^{(n)}(z_0) = \frac{n!}{2\pi i} \oint_C \frac{f(z)}{(z - z_0)^{n+1}} dz$$
コーシーの積分公式: $$f(z_0) = \frac{1}{2\pi i} \oint_C \frac{f(z)}{z - z_0} dz$$ 導関数の公式: $$f^{(n)}(z_0) = \frac{n!}{2\pi i} \oint_C \frac{f(z)}{(z - z_0)^{n+1}} dz$$
💻 コード例5: コーシーの積分公式の検証
Python実装: コーシーの積分公式の検証
import numpy as np
import matplotlib.pyplot as plt
def cauchy_integral_formula(f, z0, radius=1.0, n_points=1000):
"""
コーシーの積分公式を使ってf(z0)を計算
f: 正則関数
z0: 評価点
radius: z0を中心とする円の半径
"""
t = np.linspace(0, 2*np.pi, n_points)
dt = t[1] - t[0]
# 経路: z0を中心とする円
z = z0 + radius * np.exp(1j * t)
dz_dt = 1j * radius * np.exp(1j * t)
# 被積分関数
integrand = f(z) / (z - z0)
# 積分
integral = np.trapz(integrand * dz_dt, dx=dt)
f_z0_from_integral = integral / (2 * np.pi * 1j)
return f_z0_from_integral, z
# テスト関数
functions = {
'z^2': lambda z: z**2,
'z^3': lambda z: z**3,
'e^z': lambda z: np.exp(z),
'sin(z)': lambda z: np.sin(z),
}
# 評価点
z0 = 0.5 + 0.8j
print("=== コーシーの積分公式の検証 ===")
print(f"評価点: z0 = {z0}\n")
results = []
for name, f in functions.items():
# 直接計算
f_z0_direct = f(z0)
# コーシーの積分公式で計算
f_z0_integral, path = cauchy_integral_formula(f, z0, radius=1.0)
error = np.abs(f_z0_direct - f_z0_integral)
print(f"f(z) = {name}")
print(f" 直接計算: f(z0) = {f_z0_direct:.8f}")
print(f" 積分公式から: f(z0) = {f_z0_integral:.8f}")
print(f" 誤差: {error:.2e}\n")
results.append((name, f, path))
# 可視化
fig, axes = plt.subplots(2, 2, figsize=(12, 12))
axes = axes.flatten()
for idx, (name, f, path) in enumerate(results):
if idx >= len(axes):
break
ax = axes[idx]
# 関数の等高線
x = np.linspace(-2, 2, 100)
y = np.linspace(-2, 2, 100)
X, Y = np.meshgrid(x, y)
Z = X + 1j*Y
W = f(Z)
im = ax.contourf(X, Y, np.abs(W), levels=20, cmap='viridis', alpha=0.6)
plt.colorbar(im, ax=ax, label='|f(z)|')
# 積分経路
ax.plot(path.real, path.imag, 'r-', linewidth=2, label='積分経路')
ax.plot(z0.real, z0.imag, 'ko', markersize=10, label=f'z0 = {z0:.2f}')
ax.grid(True, alpha=0.3)
ax.set_xlabel('Re(z)', fontsize=12)
ax.set_ylabel('Im(z)', fontsize=12)
ax.set_title(f'$f(z) = {name}$', fontsize=12)
ax.axis('equal')
ax.legend()
ax.set_xlim(-1.5, 2)
ax.set_ylim(-1, 2)
plt.suptitle('コーシーの積分公式: 円周上の値から中心の値を計算', fontsize=14)
plt.tight_layout()
plt.show()
2.6 導関数の積分公式
コーシーの積分公式を拡張すると、高階導関数も積分で表現できます。
💻 コード例6: 高階導関数の積分公式
Python実装: 高階導関数の積分公式
import numpy as np
import matplotlib.pyplot as plt
from scipy.special import factorial
def cauchy_derivative_formula(f, z0, n, radius=1.0, n_points=1000):
"""
コーシーの導関数公式を使ってf^(n)(z0)を計算
f: 正則関数
z0: 評価点
n: 導関数の階数
"""
t = np.linspace(0, 2*np.pi, n_points)
dt = t[1] - t[0]
# 経路: z0を中心とする円
z = z0 + radius * np.exp(1j * t)
dz_dt = 1j * radius * np.exp(1j * t)
# 被積分関数
integrand = f(z) / (z - z0)**(n + 1)
# 積分
integral = np.trapz(integrand * dz_dt, dx=dt)
f_n_z0 = factorial(n) * integral / (2 * np.pi * 1j)
return f_n_z0
# 複素微分の数値計算(検証用)
def numerical_derivative(f, z, n=1, h=1e-5):
"""n階微分の数値計算"""
if n == 0:
return f(z)
elif n == 1:
return (f(z + h) - f(z - h)) / (2*h)
else:
# 再帰的に計算
f_n_minus_1 = lambda w: numerical_derivative(f, w, n-1, h)
return (f_n_minus_1(z + h) - f_n_minus_1(z - h)) / (2*h)
# テスト関数
f = lambda z: np.exp(z)
z0 = 1.0 + 0.5j
print("=== 高階導関数の積分公式 ===")
print(f"f(z) = e^z, z0 = {z0}\n")
print("理論値: すべての導関数が e^z0\n")
for n in range(5):
# 積分公式
f_n_integral = cauchy_derivative_formula(f, z0, n, radius=0.5)
# 数値微分
f_n_numerical = numerical_derivative(f, z0, n)
# 理論値 (e^z の n 階導関数は e^z)
f_n_theory = np.exp(z0)
error_integral = np.abs(f_n_integral - f_n_theory)
error_numerical = np.abs(f_n_numerical - f_n_theory)
print(f"f^({n})(z0):")
print(f" 積分公式: {f_n_integral:.8f}")
print(f" 数値微分: {f_n_numerical:.8f}")
print(f" 理論値: {f_n_theory:.8f}")
print(f" 誤差(積分): {error_integral:.2e}")
print(f" 誤差(数値): {error_numerical:.2e}\n")
# 別のテスト: f(z) = z^4
print("\n=== f(z) = z^4 ===")
f2 = lambda z: z**4
z0_2 = 2.0 + 1.0j
derivatives_theory = [
z0_2**4, # f
4 * z0_2**3, # f'
12 * z0_2**2, # f''
24 * z0_2, # f'''
24, # f''''
]
for n in range(5):
f_n_integral = cauchy_derivative_formula(f2, z0_2, n, radius=1.0)
f_n_theory = derivatives_theory[n]
error = np.abs(f_n_integral - f_n_theory)
print(f"f^({n})(z0) = {f_n_integral:.6f}, 理論値 = {f_n_theory:.6f}, 誤差 = {error:.2e}")
# 可視化: 異なる半径での精度
radii = np.linspace(0.1, 2.0, 20)
errors = []
for radius in radii:
f_2_integral = cauchy_derivative_formula(f2, z0_2, 2, radius=radius)
error = np.abs(f_2_integral - derivatives_theory[2])
errors.append(error)
plt.figure(figsize=(10, 6))
plt.semilogy(radii, errors, 'b-o', linewidth=2, markersize=6)
plt.grid(True, alpha=0.3)
plt.xlabel('積分経路の半径', fontsize=12)
plt.ylabel('誤差', fontsize=12)
plt.title("コーシーの導関数公式の精度 vs 積分経路の半径\n$f''(z_0)$ for $f(z) = z^4$", fontsize=14)
plt.axhline(1e-10, color='red', linestyle='--', label='数値誤差の限界')
plt.legend()
plt.tight_layout()
plt.show()
2.7 等角写像と調和関数
正則関数は角度を保つ写像(等角写像)です。また、正則関数の実部と虚部は調和関数(ラプラス方程式の解)です。
📐 定理: 等角写像と調和関数
等角写像: 正則関数 $w = f(z)$ は角度を保つ
調和関数: $f(z) = u + iv$ が正則なら $$\nabla^2 u = \frac{\partial^2 u}{\partial x^2} + \frac{\partial^2 u}{\partial y^2} = 0$$ $$\nabla^2 v = \frac{\partial^2 v}{\partial x^2} + \frac{\partial^2 v}{\partial y^2} = 0$$
等角写像: 正則関数 $w = f(z)$ は角度を保つ
調和関数: $f(z) = u + iv$ が正則なら $$\nabla^2 u = \frac{\partial^2 u}{\partial x^2} + \frac{\partial^2 u}{\partial y^2} = 0$$ $$\nabla^2 v = \frac{\partial^2 v}{\partial x^2} + \frac{\partial^2 v}{\partial y^2} = 0$$
💻 コード例7: 等角写像の可視化
Python実装: 等角写像の可視化
import numpy as np
import matplotlib.pyplot as plt
def plot_conformal_map(f, title):
"""等角写像の可視化"""
# 元の領域: 格子
x = np.linspace(-1.5, 1.5, 15)
y = np.linspace(-1.5, 1.5, 15)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))
# 左図: 元の領域
for xi in x:
y_line = y
z_line = xi + 1j*y_line
ax1.plot(z_line.real, z_line.imag, 'b-', linewidth=1, alpha=0.5)
for yi in y:
x_line = x
z_line = x_line + 1j*yi
ax1.plot(z_line.real, z_line.imag, 'b-', linewidth=1, alpha=0.5)
ax1.axhline(0, color='gray', linewidth=0.5)
ax1.axvline(0, color='gray', linewidth=0.5)
ax1.grid(True, alpha=0.3)
ax1.set_xlabel('Re(z)', fontsize=12)
ax1.set_ylabel('Im(z)', fontsize=12)
ax1.set_title('元の領域 (z平面)', fontsize=12)
ax1.axis('equal')
ax1.set_xlim(-2, 2)
ax1.set_ylim(-2, 2)
# 右図: 写像後の領域
for xi in x:
y_line = y
z_line = xi + 1j*y_line
w_line = f(z_line)
ax2.plot(w_line.real, w_line.imag, 'r-', linewidth=1, alpha=0.5)
for yi in y:
x_line = x
z_line = x_line + 1j*yi
w_line = f(z_line)
ax2.plot(w_line.real, w_line.imag, 'r-', linewidth=1, alpha=0.5)
ax2.axhline(0, color='gray', linewidth=0.5)
ax2.axvline(0, color='gray', linewidth=0.5)
ax2.grid(True, alpha=0.3)
ax2.set_xlabel('Re(w)', fontsize=12)
ax2.set_ylabel('Im(w)', fontsize=12)
ax2.set_title(f'写像後の領域 (w平面): {title}', fontsize=12)
ax2.axis('equal')
plt.tight_layout()
return fig
# 様々な等角写像
maps = {
'w = z^2': lambda z: z**2,
'w = e^z': lambda z: np.exp(z),
'w = 1/z': lambda z: 1/z,
'w = (z-1)/(z+1) (Möbius)': lambda z: (z-1)/(z+1),
}
for name, f in maps.items():
fig = plot_conformal_map(f, name)
plt.show()
print("等角写像の性質:")
print("- 格子の交点での角度が保たれる")
print("- 正則関数は局所的に回転と拡大の合成")
💻 コード例8: 調和関数の検証
Python実装: 調和関数の検証
import numpy as np
import matplotlib.pyplot as plt
def laplacian_2d(u, x, y, h=0.01):
"""2次元ラプラシアンの数値計算"""
u_xx = (u(x+h, y) - 2*u(x, y) + u(x-h, y)) / h**2
u_yy = (u(x, y+h) - 2*u(x, y) + u(x, y-h)) / h**2
return u_xx + u_yy
# 正則関数 f(z) = z^2 = (x+iy)^2 = (x^2-y^2) + i(2xy)
def u(x, y):
"""実部: u = x^2 - y^2"""
return x**2 - y**2
def v(x, y):
"""虚部: v = 2xy"""
return 2*x*y
# グリッド
x = np.linspace(-2, 2, 100)
y = np.linspace(-2, 2, 100)
X, Y = np.meshgrid(x, y)
U = u(X, Y)
V = v(X, Y)
# ラプラシアンの計算(数値微分)
dx = x[1] - x[0]
dy = y[1] - y[0]
Laplacian_U = (np.roll(U, -1, axis=1) - 2*U + np.roll(U, 1, axis=1)) / dx**2 + \
(np.roll(U, -1, axis=0) - 2*U + np.roll(U, 1, axis=0)) / dy**2
Laplacian_V = (np.roll(V, -1, axis=1) - 2*V + np.roll(V, 1, axis=1)) / dx**2 + \
(np.roll(V, -1, axis=0) - 2*V + np.roll(V, 1, axis=0)) / dy**2
# テスト点でのラプラシアン
x0, y0 = 1.0, 1.5
lap_u = laplacian_2d(u, x0, y0)
lap_v = laplacian_2d(v, x0, y0)
print("=== 調和関数の検証 ===")
print(f"正則関数: f(z) = z^2")
print(f"実部: u(x,y) = x^2 - y^2")
print(f"虚部: v(x,y) = 2xy")
print(f"\nテスト点: ({x0}, {y0})")
print(f"∇²u = {lap_u:.6e} (should be ~0)")
print(f"∇²v = {lap_v:.6e} (should be ~0)")
# 可視化
fig, axes = plt.subplots(2, 3, figsize=(16, 10))
# 実部
im = axes[0, 0].contourf(X, Y, U, levels=20, cmap='RdBu_r')
axes[0, 0].contour(X, Y, U, levels=10, colors='black', linewidths=0.5, alpha=0.4)
axes[0, 0].set_xlabel('x', fontsize=12)
axes[0, 0].set_ylabel('y', fontsize=12)
axes[0, 0].set_title('実部: $u = x^2 - y^2$', fontsize=12)
axes[0, 0].axis('equal')
plt.colorbar(im, ax=axes[0, 0])
# 虚部
im = axes[0, 1].contourf(X, Y, V, levels=20, cmap='RdBu_r')
axes[0, 1].contour(X, Y, V, levels=10, colors='black', linewidths=0.5, alpha=0.4)
axes[0, 1].set_xlabel('x', fontsize=12)
axes[0, 1].set_ylabel('y', fontsize=12)
axes[0, 1].set_title('虚部: $v = 2xy$', fontsize=12)
axes[0, 1].axis('equal')
plt.colorbar(im, ax=axes[0, 1])
# 実部と虚部の等高線(直交性)
axes[0, 2].contour(X, Y, U, levels=15, colors='blue', linewidths=1.5, alpha=0.7)
axes[0, 2].contour(X, Y, V, levels=15, colors='red', linewidths=1.5, alpha=0.7)
axes[0, 2].set_xlabel('x', fontsize=12)
axes[0, 2].set_ylabel('y', fontsize=12)
axes[0, 2].set_title('等高線の直交性(青:u, 赤:v)', fontsize=12)
axes[0, 2].axis('equal')
axes[0, 2].grid(True, alpha=0.3)
# ラプラシアン(実部)
im = axes[1, 0].contourf(X, Y, Laplacian_U, levels=20, cmap='seismic', vmin=-0.1, vmax=0.1)
axes[1, 0].set_xlabel('x', fontsize=12)
axes[1, 0].set_ylabel('y', fontsize=12)
axes[1, 0].set_title('$\\nabla^2 u$ (should be ~0)', fontsize=12)
axes[1, 0].axis('equal')
plt.colorbar(im, ax=axes[1, 0])
# ラプラシアン(虚部)
im = axes[1, 1].contourf(X, Y, Laplacian_V, levels=20, cmap='seismic', vmin=-0.1, vmax=0.1)
axes[1, 1].set_xlabel('x', fontsize=12)
axes[1, 1].set_ylabel('y', fontsize=12)
axes[1, 1].set_title('$\\nabla^2 v$ (should be ~0)', fontsize=12)
axes[1, 1].axis('equal')
plt.colorbar(im, ax=axes[1, 1])
# ラプラシアンの大きさ
Lap_magnitude = np.sqrt(Laplacian_U**2 + Laplacian_V**2)
im = axes[1, 2].contourf(X, Y, Lap_magnitude, levels=20, cmap='viridis')
axes[1, 2].set_xlabel('x', fontsize=12)
axes[1, 2].set_ylabel('y', fontsize=12)
axes[1, 2].set_title('$|\\nabla^2 u|^2 + |\\nabla^2 v|^2$', fontsize=12)
axes[1, 2].axis('equal')
plt.colorbar(im, ax=axes[1, 2])
plt.suptitle('調和関数: 正則関数の実部・虚部はラプラス方程式を満たす', fontsize=14)
plt.tight_layout()
plt.show()
print("\n調和関数の性質:")
print("- 正則関数の実部と虚部は調和関数")
print("- 調和関数の等高線は直交する(コーシー・リーマンの方程式)")
print("- 調和関数は極大値・極小値を持たない(最大値原理)")
📝 章末問題
✏️ 演習問題
- $f(z) = z^3$ について、点 $z_0 = 1+i$ でコーシー・リーマンの方程式を検証せよ。
- $\oint_C z^n dz$ を計算せよ。ただし $C$ は原点中心の単位円、$n$ は整数。
- $f(z) = \frac{1}{z-2}$ について、単位円に沿った積分 $\oint_C f(z) dz$ を計算し、コーシーの積分定理との関係を考察せよ。
- 等角写像 $w = z^2$ によって、直線 $x=1$ がどのような曲線に写されるか求めよ。
🔗 参考文献
- Ahlfors, L. V. (1979). Complex Analysis. McGraw-Hill.
- Stein, E. M., & Shakarchi, R. (2003). Complex Analysis. Princeton University Press.