見出し画像

Pythonは虚数を扱えるらしい

たとえば変数「$${c}$$」に複素数「$${3 + 4i}$$」を入れるとする。

$$
c = 3 + 4i
$$

Pythonではこう書くらしい。

c = complex(3, 4)
print(c)

結果。

(3+4j)

なぜか虚数が「$${j}$$」になっているけれど、電気工学の慣習では電流の「$${i}$$」と区別するために「$${j}$$」と書くらしい。「complex」は複素数「complex number」から。

たとえば先ほどの「$${c}$$」を2乗してみる。手計算だとこうなるけれど、

$$
\begin{align*}
\\
c^2 &= (3 + 4i)^2 \\
&= 3^2 + 2 \times 3 \times 4i + (4i)^2 \\
&= 9 + 24i - 16 \\ &= -7 + 24i
\end{align*}
$$

Pythonはこれだけ。

c = complex(3, 4)
print(c**2)

結果。

(-7+24j)

ちゃんと計算してくれてる!

逆に「$${c}$$」から「実部」や「虚部」を取り出すこともできる。

c = complex(3, 4)
print(c.real)
print(c.imag)

結果。

3
4

ちなみに英語で実部を「real part」、虚部を「imaginary part」と言うらしい。

マンデルブロ集合を描いてみる

こうなると描きたくなるのが「マンデルブロ集合」。これを描くには素数の計算が必要になるけれど、Pythonならすごく簡単に書けるのでは!?

# マンデルブロ集合の画像をPNG形式で保存する

# モジュールをインポート
import numpy as np  # 科学計算
from PIL import Image  # 画像の読み書きなど
import time  # 時間計算

# 開始時刻を記録
start = time.time()

# 画像の解像度、描画する範囲、を設定
width, height = 2000, 2000  # 画像の解像度(px)
a_min, a_max = -2, 1  # 複素数のaの範囲(画像の横軸)
b_min, b_max = -1.5, 1.5  # 複素数のbの範囲(画像の縦軸)
loop_max = 4096  # 再帰回数の最大(256の倍数を推奨)

# マンデルブロ集合の内側なら黒(0)、外側なら再帰回数(n)、を返す
def mandelbrot(c, loop_max):
    z = 0  # zの初期値=0
    n = 0  # 再帰回数の初期値=0
    while abs(z) <= 2 and n < loop_max:  # zが距離2を脱出するまで
        z = z ** 2 + c  # z = z² + c
        n = n + 1
    if n == loop_max:
        return 0  # 集合の内側
    else:
        return n  # 集合の外側

# 画像データ配列(NumPy配列)を作成
image_data = np.zeros((height, width), dtype=np.uint8)  # データ型:8bitの符号なし整数(0〜255)

# 全ピクセルについて、マンデルブロ集合の内側か外側かを調べる
for b_index, b in enumerate(np.linspace(b_min, b_max, height)):
    for a_index, a in enumerate(np.linspace(a_min, a_max, width)):
        c = complex(a, b)   # 複素数に変換(c=a+bi)
        n = mandelbrot(c, loop_max)  # マンデルブロ集合の計算(n=再帰回数)
        image_data[b_index, a_index] = 255 - n % 256  # nを画像データ配列に格納(nを0〜255の繰り返しにして、明るさを反転)

# NumPy配列をPillow画像オブジェクトに変換
image = Image.fromarray(image_data)  # NumPy→Pillow
image = image.convert('RGB')  # RGB形式に変換

# 画像を保存
image.save('mandelbrot.png')

# 終了時刻を記録
end = time.time()

# 実行にかかった時間を表示
print('実行時間 :', format(end - start, '.2f'), '秒')

うん、思ったより短く書けなかったね。😑

描画にかかった時間は7分54秒。

2000 × 2000ピクセルなので拡大すると粗い。

20000 × 20000ピクセルで描画してみた。

12時間44分もかかってしまったけれど、中央の粒がマンデルブロ集合の形になっているのがよくわかる。✨

余談だけど、「マンデルブロ集合」は「グレー」の「256階調」で描くのがいいと思う。色は後から付けた方が楽だから。

Photoshopで色を付ける手順

まず、開くときに「カラープロファイル」を埋め込む。これで「カラーモード」になる。

「レイヤー」パレットの「調整レイヤー」アイコンをタップし、

出てきたメニューから「グラデーションマップ」を選ぶ。

「グラデーションマップ」が追加された。

たぶん「プロパティ」が表示されていると思う。これが現在のグラデーション。右の「∨」を押すと、色々なグラデーションが表示される。

選ぶと色が変わる。

自作することもできる。

ちなみにこのグラデーションは、Pythonの「cubehelix」というカラーマップに似せて作ったもの。

「逆方向」や「方法」というオプションも調子が変わって面白かった。

フリー素材

20000ピクセルの画像はこちら。ご自由にお使いください。(需要あるかな?)


Python 3
macOS Sonoma 14.1.2
Photoshop 2024 25.3.1 

とりにえさをあたえるぼたん