Привет!

Очередной очерк. На этот раз поиграемся с комплексными числами, с формулами и их визуализацией.



Идея


Комплексное число — это некоторое расширение вещественного числа, по сути вектор, для которого определено целое множество аксиом. Любое комплексное (а значит и вещественное) число можно записать в виде $z=a+bi$, где a — вещественная часть, b — мнимая, i — корень уравнения $x^{2}=-1$. Для него определено много операций, которые определены для вещественного числа, к примеру, $z_1 + z_2 = a_1 + a_2 + (b_1 + b_2)i$. Интересно, что если проделывать различные операции с ними, возводить в степень, умножать и т. д. а затем брать $Re(z)$ (вещественную часть) для оси Ox, а $Im(z)$ (мнимую часть) для оси Oy, можно получать забавные картинки.

Кстати все следующие формулы я сам придумал.

Функция визуализации


Рутина. Функция, которая по данной итеративной функции рисует все на поле:

import random
import numpy as np
def vis(A, f, step=1.0, c=None):
    x = []
    y = []
    for B in np.arange(0, A, step):
        v = f(A, B)
        x.append(v.real)
        y.append(v.imag)
    plt.figure(figsize=[8, 8])
    mxabs = max([i[0] ** 2 + i[1] ** 2 for i in zip(x, y)]) ** 0.5
    x = np.array(x) / mxabs
    y = np.array(y) / mxabs
    if c is None:
        plt.scatter(x, y)
    else:
        plt.scatter(x, y, color=[c(x[i], y[i]) for i in range(len(x))])
    plt.show()

Все наши функции зависят от двух параметров A и B. Причем по B мы итерируемся внутри vis(), а A — глобальный параметр функции.

Функция «Завитушки»


$f(A, B) = Bsin(B)*e^{iBcos(A)}$



Ее объявление в python:

def func_1(A, B):
    return math.sin(B) * B * math.e ** (1j * (B * math.cos(A)))

И запустим

A = 121.5
vis(A, func_1, step=0.1)

И результат для A=121.5:



И для A=221.5:



Заметьте, эти числа вовсе не следуют из расчета какого-нибудь определенного интеграла на гладком многообразии и других умных бессмысленных в этом контексте слов. Это действительно рандомные числа, и существует еще ровно бесконечность разных A, в результате которых получается красота.

Надо покрасить


Объявим функцию цвета (такую функцию, которая по координатам возвращает tuple из трех чисел):

def sigm(x):  # Эта функция позволяет нормализировать все что угодно от 0 до 1
    return (1 / (1 + 1.2 ** (-x*50)) - 0.5) * 2

color_1 = lambda x, y: (0.2, sigm(x ** 2 + y ** 2) / 1.4, 1 - sigm(x ** 2 + y ** 2))
color_2 = lambda x, y: (sigm(x ** 2 + y ** 2), 0.5, 0.5)

Выберем рандомный параметр A, пусть будет 149:

vis(149, func_1, step=0.1, c=color_1)



Функция «Гуси»


Гуси описываются так:

$f(A, B) = cos(B)sin(B) * B * e^{iBcos(A)}$


Объявление на python:

def func_2(A, B):
    return math.cos(B) * math.sin(B) * B * math.e ** (1j * (B * math.cos(A)))

Ее результат для A=106:



Функция «Фокачча»


$f(A, B) = cos(B(A + 1)) * e^{iBcos(A)}$



def func_3(A, B):
    return math.cos((A + 1) * B) * math.e ** (1j * (B * math.cos(A)))

vis(246, func_3, step=0.1, c=color_2)



vis(246, func_3, step=0.1, c=color_2)



Функция «Без названия»


$f(A, B) = Bsin(A + B) * e^{iBsin(A)}$


color_3 = lambda x, y: (0.5, 0.5, sigm(x ** 2 + y ** 2))
vis(162, func_4, step=0.1, c=color_3)



vis(179, func_4, step=0.1, c=color_3)



Формула красоты


$f(A, B) = cos(B(A+1))^{\frac{3}{2}} * e^{iBcos(A)}$



def func_5(A, B):
    return math.cos((A + 1) * B) ** 1.5 * math.e ** (1j * (B * math.cos(A)))

color_4 = lambda x, y: (sigm(x ** 2 + y ** 2) / 2, 0.5, 1 - sigm(x ** 2 + y ** 2))
vis(345, func_5, step=0.1, c=color_4)



vis(350, func_5, step=0.1, c=color_4)



Пока все.

Весь код

import numpy as np
import random
import matplotlib.pyplot as plt
import math

def vis(A, f, step=1.0, c=None):
    x = []
    y = []
    for B in np.arange(0, A, step):
        v = f(A, B)
        x.append(v.real)
        y.append(v.imag)
    plt.figure(figsize=[7, 7])
    mxabs = max([i[0] ** 2 + i[1] ** 2 for i in zip(x, y)]) ** 0.5
    x = np.array(x) / mxabs
    y = np.array(y) / mxabs
    if c is None:
        plt.scatter(x, y)
    else:
        plt.scatter(x, y, color=[c(x[i], y[i]) for i in range(len(x))])
    plt.show()

def func_1(A, B):
    return math.sin(B) * B * math.e ** (1j * (B * math.cos(A)))

def func_2(A, B):
    return math.cos(B) * math.sin(B) * B * math.e ** (1j * (B * math.cos(A)))

def func_3(A, B):
    return math.cos((A + 1) * B) * math.e ** (1j * (B * math.cos(A)))

def func_4(A, B):
    return math.sin(A + B) * B * math.e ** (1j * B * math.sin(A))

def func_5(A, B):
    return math.cos((A + 1) * B) ** 1.5 * math.e ** (1j * (B * math.cos(A)))

def sigm(x):
    return (1 / (1 + 1.2 ** (-x*50)) - 0.5) * 2

color_1 = lambda x, y: (0.2, sigm(x ** 2 + y ** 2) / 1.4, 1 - sigm(x ** 2 + y ** 2))
color_2 = lambda x, y: (sigm(x ** 2 + y ** 2), 0.5, 0.5)
color_3 = lambda x, y: (0.5, 0.5, sigm(x ** 2 + y ** 2))
color_4 = lambda x, y: (sigm(x ** 2 + y ** 2) / 2, 0.5, 1 - sigm(x ** 2 + y ** 2))
colors = [color_1, color_2, color_3, color_4]
funcs = [func_1, func_2, func_3, func_4, func_5]
while True:
    col = random.choice(colors)
    func = random.choice(funcs)
    vis(random.random() * 200 + 100, func, step=0.1, c=col)
    if input() == "exit":
        break



Еще скриншоты


















Комментарии (8)


  1. Sychuan
    25.09.2019 12:20
    +1

    Я с комплексными числами много играюсь
    image


    1. Bookvarenko
      25.09.2019 14:00

      Красиво, пёстренько! Код есть?


      1. Sychuan
        27.09.2019 18:43

        Конкретно эту функцию я не помню. Но идея очень простая, называется domain coloring:
        1. Покрасить комплексную плоскость в какие-нибудь цвета. В данном случае (я точно не помню, но скорее всего) фаза комплексного числа превращается в HUE, а модуль в Lightness.
        2. Подействовать на плоскость какой-нибудь функцией.
        3. Покрасить в зависимости от значения
        В википедии все объяснено очень хорошо


  1. vin2809
    26.09.2019 08:36

    Большое спасибо. Красотища то какая!


  1. qpy
    26.09.2019 16:16

    а интересно, как часто используется matplotlib в data science, в аналитике? И какие альтернативы vs matplotlib, которые наиболее популярны для этих целей?

    Насчет статьи, на мой взгляд, крупные изображения в ней мешают восприятию кода. Хотелось бы, чтобы Вы спрятали все изображения в виде спойлеров.


  1. Drammm
    26.09.2019 20:54

    А можно ли построить график функции Вейерштрасса? https://ibb.co/bdh2mcw, где: k_n= k^n; k и ? – произвольные числа; z – комплексная переменная.


    1. Sychuan
      27.09.2019 23:39

      Я попробовал сделать в лоб, но после нескольких суммирований большинство значений получились NaN. Вряд ли у этой функции какой-то интересный график на комплексной плоскости получится.Есть много очень интересных функций, но эта вряд ли из их числа. (но может я ошибся, от программирования я далек). И я взял формулу из википедии. Мне там показалось понятнее


  1. onground
    27.09.2019 14:58
    +1

    Наверное имеет смысл добавить в первый листинг две строчки

    import math
    import matplotlib.pyplot as plt