Построение фрактальных фигур в Matlab

в 16:49, , рубрики: Matlab, математика, фрактал, хаос, метки: , ,

«Итерация от человека. Рекурсия — от Бога.» Л. Питер Дойч

Введение

Многие из нас слышали про фракталы, я думаю, что многие даже имеют довольно четкое представление об этих удивительных математических объектах и их тесной взаимосвязи с физическими природными структурами. Тем не менее, в этой статье я хотел бы затронуть исследовательский и философский аспекты данного вопроса. Сама по себе возможность генерировать сложнейшие узоры на комплексной плоскости с помощью простых математических выражений весьма заманчива, собственно это и натолкнуло на написание статьи. Написав пару строчек кода мы сможем упасть на самое дно разрядной сетки нашего ПК, изучая масштабируемые фрактальные узоры.

Про фракталы

В одной из передач цикла BBC (Тайная жизнь хаоса) позиционировалась интересная мысль, позиционировалась она конечно не авторами этого видео, а Аланом Тьюрингом и отцом теории хаоса Эдвардом Лоренцем. Как оказалось, сложные системы, с большим числом связей и элементов (пусть даже однообразных) имеют порог предсказуемости. Что это значит? Совокупность простейших структур с детерминированной логикой может на выходе давать весьма и весьма сложное поведение. Почти так и получается в нашем случае: взяв простое рекуррентное соотношение Z[i+1] = Z[i]^(n) + C, i = 1, 2,… inf где С — комплексное число, Z[0] = 0, увидим, что некоторые суммы будут конечны, а некоторые будут убегать в бесконечность (в зависимости от выбранной С). Ниже будет код, будет понятнее. Большой интерес вызывает поведение точек на границе расходимости. Они формируют сложные, порой самоповторяющиеся узоры, которые могут меняться при увеличении степени масштабирования, генерируя бесконечный динамический рисунок. Порой наблюдать за этими рисунками бывает интересно, изменяя степень полинома, или ставя в рекурсивную формулу новые функции, можно получить очень интересные картинки.

Написание кода

Начнем с написания скрипта fractal.m: Зададим размер картинки 500x500 пикселей, для нас будет интересна область [-2, 1]; по действительной оси и [-1.5, 1.5]; по мнимой оси, в ней мы и будем наблюдать фрактал. Если сумма ряда выходит за границы этого квадрата, то мы считаем, что ряд расходится.

image_size = 500;

bound_re = [-2, 1];
bound_im = [-1.5, 1.5];

Далее мы рисуем фрактал с помощью функции draw_fractal, её мы рассмотрим далее. Она принимает ограничивающий прямоугольник и размер картинки на вход. Данная функция возвращает пересчитанные размеры пикселя на увеличенном участке т.е. pb_re pb_im — математический размер пикселя по мнимой и действительной оси. Далее мы выбираем область для приближения через getrect , current_point, — левая верхняя точка прямоугольника зумирования, получаем ширину и высоту ограничивающего прямоугольника, заданного мышью. bound_re и bound_im новые границы рассматриваемой области (аналогично начальным). Далее все повторяется.

while(1)
    [pb_re pb_im] = draw_fractal(bound_re, bound_im, image_size);
    
    rect = getrect;
    current_point = complex(bound_re(1) + rect(1) * pb_re - 0.5 * pb_re , ...
        bound_im(1) + rect(2) * pb_im - 0.5 * pb_im);
    
    current_width = rect(3) * pb_re;
    current_height = rect(4) * pb_im;
    
    bound_re = [real(current_point), real(current_point) + current_width];
    bound_im = [imag(current_point), imag(current_point) + current_height];
    
end

Функция draw_fractal.m вычисляет какому математическому размеру соответствует пиксель pixel_bounds_re и pixel_bounds_im, далее мы идем по матрице изображения и рассматриваем математическое множество точек, лежащих в центре наших коробочек-пикселей, для каждой точки с помощью функции [color] = is_a_m_point(current_point) вычисляем убегает ли она в бесконечность или нет.

function [pixel_bounds_re, pixel_bounds_im]=draw_fractal( bound_re,  bound_im, image_size)

    pixel_bounds_re = (bound_re(2) - bound_re(1) ) / image_size;
    pixel_bounds_im = (bound_im(2) - bound_im(1) ) / image_size;
    
    frac = zeros([image_size, image_size]);
    
    parfor re = 1 : image_size
        for im = 1 : image_size
            current_point = complex(bound_re(1) + re * pixel_bounds_re - 0.5 * pixel_bounds_re , bound_im(1) + ...
            im * pixel_bounds_im - 0.5 * pixel_bounds_im);
        
            [color] = is_a_m_point(current_point);
            
            frac(im,re) = color;

        end
    end
    frac = mat2gray(frac);
    imshow(frac);
end

Причем чем быстрее точка будет убегать в бесконечность, тем светлее она будет, это видно из функции is_a_m_point.m Она принимает на вход нашу константу С из рекурсивной формулы Z[i + 1] = Z[i] ^ (n) + C, задача функции состоит в том, чтобы вернуть цвет color, — чем быстрее ряд расходится тем ярче цвет, если точка убегает за границы [-2 1] (реал ось) [-1.5 1.5] (мнимая ось), то мы считаем, что ряд расходится. Мы считаем, что Z[0] = 0, а в ряде суммируем 50 чисел (как правило этого достаточно, чтобы понять разойдется ряд или нет).

function [ color] = is_a_m_point( constant )
    color = 0;
    z = 0; % это Z[0]
    
    for i = 1 : 50
         z = z^(2) / (1 + z + z^(4)) + constant; % используемая рекурсивная зависимость

        if real(z) < -2 || real(z) > 1 || imag(z) > 1.5 || imag(z) < -1.5
                color = 255 - 5.5 * (i - 1);
                return;
        end
    end
end

Вот и всё. Написав пару скриптов можно расслабиться и попытаться исследовать, что получилось в результате. Так как бедное множество Мондельброта уже где только не светилось, попробуем исследовать что-нибудь поинтереснее, например функцию z = z^(2) / (1 + z + z^(4)) + constant;

Визуализация

Указанная зависимость порождает на комплексной плоскости следующий рисунок:
image
Левая центральная часть этой картины интересна тем, что приближая её мы будем падать в бесконечный обновляющийся паттерн самоподобных фигур. Прекрасная аллегория к тому, что многообразие может быть порождено группой конечных примитивов.
image
Используя представленные матлабовские скрипты легко получить и динамику изменения фрактальных узоров на плоскости, например меняя степень полинома n в рекурсивной формуле Z[i] = Z[i-1] ^ (n) + C, n = 1, 2… 200 можно получить следующее

Заключение

В данной статье я попытался представить простейшие вариант реализации скриптов в среде Matlab, создающих фрактальные узоры от произвольной рекурсивной зависимости с возможностью масштабирования. Легко заметить, что каждая зависимость рождает по-своему уникальный мир на комплексной плоскости, со своими «законами формирования узоров», со своей симметрией. Из всего этого можно сделать много интуитивных умозаключений, некоторые из которых я уже приводил в тексте статьи. В цикле своих лекций Франклин Меррелл-Вольф (Математика, философия йога) ставит вопрос о двойственности человеческого мышления и стремлении человека к дескретизации реальности, а так же ставит вопрос «А правда ли, что мир из чего-то состоит?». Так состоит ли он, или во главе всего стоит одна рекурсивная формула, которая и порождает необъятное многообразие действительности?

Автор: alexhoppus

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js