Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

Python NumPy 외적(outer) 활용법 — Mandelbrot 집합 계산용 복소수 그리드 만들기

두 벡터 a = [a0, a1, ..., aM]와 b = [b0, b1, ..., bN]가 주어졌을 때, 외적(outer product)은 다음과 같이 정의됩니다.

[[a0*b0  a0*b1 ... a0*bN ]
[a1*b0   .      .
[ ...    .      .
[aM*b0          aM*bN ]]

Python에서 두 배열의 외적을 구하려면 numpy.outer() 메서드를 사용합니다. 이 메서드는 첫 번째 벡터의 각 요소와 두 번째 벡터의 모든 요소를 곱한 결과를 행렬 형태로 반환합니다.

이번 예제에서는 추가로 다음 두 함수도 함께 사용합니다.

  • numpy.ones() : 지정된 shape과 데이터 타입을 가지며, 모든 요소가 1로 채워진 새로운 배열을 반환합니다.
  • numpy.linspace() : 지정된 구간(start, stop) 사이에서 균일한 간격의 숫자들을 반환합니다.

복소평면 위에 격자(grid)를 만들려면 실수부(real part)와 허수부(imaginary part)를 각각 외적으로 계산한 뒤 더해주면 됩니다. 이렇게 만든 그리드는 Mandelbrot 집합처럼 복소수 평면 전체를 대상으로 연산할 때 유용하게 쓰입니다.

단계별 진행

먼저 필요한 라이브러리를 임포트합니다.

import numpy as np

1) 실수부 계산 — np.ones()와 np.outer()를 이용해 -2부터 2까지의 값을 가진 5x5 배열을 만듭니다.

rl = np.outer(np.ones((5,)), np.linspace(-2, 2, 5))
print("복소수의 실수부...\n", rl)

2) 허수부 계산 — linspace 결과에 허수 단위 j를 곱한 뒤 외적합니다.

im = np.outer(1j*np.linspace(2, -2, 5), np.ones((5,)))
print("\n복소수의 허수부...\n", im)

3) 그리드 생성 — 실수부와 허수부를 더해 복소수 그리드를 완성합니다.

grid = rl + im

전체 예제 코드

import numpy as np

# 두 배열의 외적을 구하려면 Python의 numpy.outer() 메서드를 사용합니다.
# numpy.ones()는 지정된 shape과 타입으로, 모든 값이 1인 새 배열을 반환합니다.
# numpy.linspace()는 지정된 구간에서 균일하게 떨어진 숫자들을 반환합니다.

# 실수부
rl = np.outer(np.ones((5,)), np.linspace(-2, 2, 5))
print("복소수의 실수부...\n", rl)

# 허수부
im = np.outer(1j*np.linspace(2, -2, 5), np.ones((5,)))
print("\n복소수의 허수부...\n", im)

# 그리드 생성
grid = rl + im
print("\n그리드 출력...\n", grid)

실행 결과

복소수의 실수부...
[[-2. -1.  0.  1.  2.]
 [-2. -1.  0.  1.  2.]
 [-2. -1.  0.  1.  2.]
 [-2. -1.  0.  1.  2.]
 [-2. -1.  0.  1.  2.]]

복소수의 허수부...
[[0.+2.j 0.+2.j 0.+2.j 0.+2.j 0.+2.j]
 [0.+1.j 0.+1.j 0.+1.j 0.+1.j 0.+1.j]
 [0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]
 [0.-1.j 0.-1.j 0.-1.j 0.-1.j 0.-1.j]
 [0.-2.j 0.-2.j 0.-2.j 0.-2.j 0.-2.j]]

그리드 출력...
[[-2.+2.j -1.+2.j  0.+2.j  1.+2.j  2.+2.j]
 [-2.+1.j -1.+1.j  0.+1.j  1.+1.j  2.+1.j]
 [-2.+0.j -1.+0.j  0.+0.j  1.+0.j  2.+0.j]
 [-2.-1.j -1.-1.j  0.-1.j  1.-1.j  2.-1.j]
 [-2.-2.j -1.-2.j  0.-2.j  1.-2.j  2.-2.j]]

마무리

이렇게 np.outer(), np.ones(), np.linspace() 세 함수만으로 복소평면 위의 좌표 그리드를 손쉽게 생성할 수 있습니다. 완성된 그리드의 각 원소 c에 대해 반복 수식 z = z² + c를 적용하고 발산 여부를 검사하면, 바로 Mandelbrot 집합을 계산할 수 있습니다. 해상도를 높이고 싶다면 linspace의 샘플 개수를 늘리거나 범위를 조정하면 됩니다.