今回は Python (NumPy) の複素数について簡単にまとめてみました。
complex(a, b)
>>> import numpy as np >>> import cmath >>> a = complex(1, 2) >>> a (1+2j) >>> b = 3 + 4j >>> b (3+4j) >>> c = np.array([a, b]) >>> c array([ 1.+2.j, 3.+4.j]) >>> type(a) <class 'complex'> >>> np.iscomplex(a) True >>> np.iscomplex(c) array([ True, True], dtype=bool) >>> np.iscomplex(1.234) False >>> np.isreal(a) False >>> np.isreal(c) array([False, False], dtype=bool) >>> np.isreal(1.2345) True >>> a + b (4+6j) >>> a - b (-2-2j) >>> a * b (-5+10j) >>> a / b (0.44+0.08j) >>> a ** 2 (-3+4j) >>> a ** 3 (-11-2j) >>> a == a True >>> a != a False >>> a != b True >>> a.real 1.0 >>> a.imag 2.0 >>> np.real(a) 1.0 >>> np.real(c) array([ 1., 3.]) >>> np.imag(a) 2.0 >>> np.imag(c) array([ 2., 4.]) >>> abs(a) 2.23606797749979 >>> abs(b) 5.0 >>> np.abs(c) array([ 2.23606798, 5. ]) >>> cmath.phase(a) 1.1071487177940904 >>> np.angle(a) 1.1071487177940904 >>> cmath.phase(b) 0.9272952180016122 >>> np.angle(b) 0.92729521800161219 >>> np.angle(c) array([ 1.10714872, 0.92729522]) >>> cmath.polar(a) (2.23606797749979, 1.1071487177940904) >>> cmath.polar(b) (5.0, 0.9272952180016122) >>> cmath.rect(2.23606797749979, 1.1071487177940904) (1.0000000000000002+2j) >>> cmath.rect(5.0, 0.9272952180016122) (3.0000000000000004+3.9999999999999996j) >>> a.conjugate() (1-2j) >>> b.conjugate() (3-4j) >>> np.conj(a) (1-2j) >>> np.conj(b) (3-4j) >>> np.conj(c) array([ 1.-2.j, 3.-4.j]) >>> cmath.sqrt(-1) 1j >>> cmath.sqrt(-2) 1.4142135623730951j >>> np.sqrt(-1+0j) 1j >>> np.sqrt(-2+0j) 1.4142135623730951j >>> np.sqrt(c) array([ 1.27201965+0.78615138j, 2.00000000+1.j ]) >>> cmath.exp(complex(0,cmath.pi/4)) (0.7071067811865476+0.7071067811865475j) >>> cmath.exp(complex(0,cmath.pi)) + 1 1.2246467991473532e-16j >>> np.exp(a) (-1.1312043837568135+2.4717266720048188j) >>> np.exp(b) (-13.128783081462158-15.200784463067954j) >>> np.exp(c) array([ -1.13120438 +2.47172667j, -13.12878308-15.20078446j])
>>> import numpy as np >>> a = np.array([1+2j,3+4j]) >>> a array([ 1.+2.j, 3.+4.j]) >>> b = np.array([5+6j, 7+8j]) >>> b array([ 5.+6.j, 7.+8.j]) >>> np.conjugate(a) array([ 1.-2.j, 3.-4.j]) >>> np.conj(b) array([ 5.-6.j, 7.-8.j]) >>> a + b array([ 6. +8.j, 10.+12.j]) >>> a - b array([-4.-4.j, -4.-4.j]) >>> a * b array([ -7.+16.j, -11.+52.j]) >>> a / b array([ 0.27868852+0.06557377j, 0.46902655+0.03539823j]) >>> c = 1 - 1j >>> a + c array([ 2.+1.j, 4.+3.j]) >>> a - c array([ 0.+3.j, 2.+5.j]) >>> a * c array([ 3.+1.j, 7.+1.j]) >>> a / c array([-0.5+1.5j, -0.5+3.5j]) >>> np.vdot(a, b) (70-8j) >>> np.vdot(b, a) (70+8j) >>> np.conj(a) @ b (70-8j) >>> a @ np.conj(b) (70+8j) >>> a @ b (-18+68j) >>> np.vdot(a, a) (30+0j) >>> np.vdot(b, b) (174+0j) >>> np.linalg.norm(a) 5.4772255750516612 >>> np.linalg.norm(b) 13.19090595827292
>>> a = np.array([[1+1j, 1-1j], [2+3j, 2+1j]]) >>> a array([[ 1.+1.j, 1.-1.j], [ 2.+3.j, 2.+1.j]]) >>> a.T array([[ 1.+1.j, 2.+3.j], [ 1.-1.j, 2.+1.j]]) >>> def htr(a): return np.conj(a.T) ... >>> htr(a) array([[ 1.-1.j, 2.-3.j], [ 1.+1.j, 2.-1.j]]) >>> htr(htr(a)) array([[ 1.+1.j, 1.-1.j], [ 2.+3.j, 2.+1.j]]) >>> b = np.array([[1+0j, 1+1j],[1-1j, 0+1j]]) >>> b array([[ 1.+0.j, 1.+1.j], [ 1.-1.j, 0.+1.j]]) >>> htr(a + b) array([[ 2.-1.j, 3.-2.j], [ 2.-0.j, 2.-2.j]]) >>> htr(a) + htr(b) array([[ 2.-1.j, 3.-2.j], [ 2.+0.j, 2.-2.j]]) >>> c (1-1j) >>> htr(c * a) array([[ 2.-0.j, 5.-1.j], [ 0.+2.j, 3.+1.j]]) >>> np.conj(c) * htr(a) array([[ 2.+0.j, 5.-1.j], [ 0.+2.j, 3.+1.j]]) >>> htr(a @ b) array([[ 1.+1.j, 5.-2.j], [ 1.-3.j, -2.-7.j]]) >>> htr(b) @ htr(a) array([[ 1.+1.j, 5.-2.j], [ 1.-3.j, -2.-7.j]]) >>> np.linalg.det(a) (-4.0000000000000009+2.0000000000000009j) >>> np.linalg.det(htr(a)) (-4-2j) >>> np.conj(np.linalg.det(a)) (-4.0000000000000009-2.0000000000000009j) >>> np.linalg.inv(a) array([[-0.3-0.4j, 0.3-0.1j], [ 0.1+0.8j, -0.1-0.3j]]) >>> htr(np.linalg.inv(a)) array([[-0.3+0.4j, 0.1-0.8j], [ 0.3+0.1j, -0.1+0.3j]]) >>> np.linalg.inv(htr(a)) array([[-0.3+0.4j, 0.1-0.8j], [ 0.3+0.1j, -0.1+0.3j]]) >>> u = np.array([1+2j, 3+4j]) >>> u array([ 1.+2.j, 3.+4.j]) >>> v = np.array([5+6j, 7+8j]) >>> v array([ 5.+6.j, 7.+8.j]) >>> a @ u array([ 6. +4.j, -2.+18.j]) >>> np.vdot(a @ u, v) (184-126j) >>> np.vdot(u, htr(a) @ v) (184-126j)
参考文献『COMMON LISP 第 2 版』と参考 URL『複素関数で遊ぼう』を参考にして、複素関数 w = f(z) の値域 (w) をグラフにしてみました。下図に示す複素平面を考えます。
複素平面は横軸が実軸で、縦軸が虚軸となります。実軸と虚軸は黒 (black) で描画します。横線を青 (blue と darkblue) で、縦線を緑 (lime と green) で、原点を中心とした円を赤 (red と darkred) で描画しています。これを複素関数 sqrt, exp, log, sin, arcsin, cos, arccos, tan, arctan, sinh, arcsinh, cosh, arccosh, tanh, arctanh に渡して、評価結果を複素平面に描画します。
リスト : 複素関数の描画 import math import numpy as np import matplotlib.pyplot as plt plt.figure(figsize=(6, 6)) plt.subplots_adjust(left=0.1, right=0.95, bottom=0.1, top=0.95) plt.xlim(-4.1, 4.1) plt.ylim(-4.1, 4.1) # 描画する複素関数をセットする cfunc = np.sqrt for i in np.linspace(-4.0, 4.0, 9): # 横線 x = np.linspace(-10.0, 10.0, 1600) y = np.full(1600, i) z = np.array([complex(a, b) for a in x for b in y]) w = cfunc(z) if i > 0.0: c = 'blue' elif i < 0.0: c = 'darkblue' else: c = 'black' plt.plot(np.real(w), np.imag(w), ',', color = c) # 縦線 y = np.linspace(-10.0, 10.0, 1600) x = np.full(1600, i) z = np.array([complex(a, b) for a in x for b in y]) w = cfunc(z) if i > 0.0: c = 'lime' elif i < 0.0: c = 'green' else: c = 'black' plt.plot(np.real(w), np.imag(w), ',', color= c) # 円 for r, n in [(0.25, 800), (0.5, 800), (1.0, 800), (2.0, 1600), (4.0, 1600), (8.0, 3200)]: theta = np.linspace(-math.pi, math.pi, n) z = np.array([complex(r * math.cos(x), r * math.sin(x)) for x in theta]) w = cfunc(z) if r > 1.0: c = 'darkred' else: c = 'red' plt.plot(np.real(w), np.imag(w), ',', color = c) plt.gca().set_aspect('equal') plt.show()