Рассмотрим сценарий перехода к хаосу в логистическом отображении через последовательные удвоения периода цикла. Логистическое отображение (уравнение приведено в начале статьи) описывает изменение численности популяции с течением времени. В отображениях время задается дискретно, в приведенном уравнении время n = 0, 1, 2 , ... Значение x при n=0 называют начальным условием, его часто задают произвольно. В рассматриваемой здесь модели значение x при n=0 можно задавать произвольно, но в интервале от 0 до 1, поскольку вне этого интервала отображение "уходит на бесконечность". Во многих нелинейных моделях начальные условия влияют на то, какой в итоге установится в модели режим, но в этом простом отображении любые начальные условия из интервала от 0 до 1 приведут к одному и тому же режиму при фиксированном параметре r. Параметр r в этой модели меняют от 0 до 4. Рассмотрим поведение модели более подробно, в конце статьи привожу код программы logisctic на языке C++, который компилируется командой "g++ -o logistic logistic.cpp" и запускается командой "./logistic 2.5 0.5 1000 100". В последней команде после названия программы logistic перечисляются параметры (управляющий параметр отображения r; начальное условие отображения x при n=0; время переходного процесса transient_time; время рассмотрения динамики observation_time), которые пользователь может выбирать на свое усмотрение.
Режимы поведения логистического отображения
Установим параметр r=2.5, начальное состояния x(n=0) = 0.5 и рассмотрим поведение модели с самого начала, не отбрасывая переходный процесс. Для этого запустим команду "./logistic 2.5 0.5 0 50", после чего программа создает файл "time-series.dat" такого типа:
# r=2.5
1 0.625
2 0.585938
3 0.606537
4 0.596625
5 0.601659
6 0.599164
7 0.600416
...
По этому файлу можно построить график с помощью команды 'set lmargin screen 0.07; set bmargin screen 0.15; set rmargin screen 0.97; set xlabel "n" offset 0,-1.5 font "Helvetica, 30"; set ylabel "x_n" offset -6,0 font "Helvetica, 30"; set tics font "Helvetica, 30"; set xtics 5 offset 0,-0.5; set ytics 0.05; set key font "Helvetica, 30"; plot [][0.5:0.7] "time-series.dat" w lp lw 4 pt 5 ps 1 lc rgb "forest-green" title "Logistic map behaviour at r=2.5"' программе gnuplot.
На рисунке 1 видно, что, начиная с 10 итерации, поведение логистического отображения неизменно, это означает, что модель демонстрирует состояние равновесия, или, другими словами, цикл период 1. То есть, каждую итерацию переменная x возвращается в одно и то же состояние.
Установим значение параметра r=3.01 (запустим команду "./logistic 3.01 0.5 1000 50" в консоли и 'set lmargin screen 0.07; set bmargin screen 0.15; set rmargin screen 0.97; set xlabel "n" offset 0,-1.5 font "Helvetica, 30"; set ylabel "x_n" offset -6,0 font "Helvetica, 30"; set tics font "Helvetica, 30"; set xtics 5 offset 0,-0.5; set ytics 0.05; set key font "Helvetica, 30"; plot [][0.59:0.8] "time-series.dat" w lp lw 4 pt 5 ps 1 lc rgb "forest-green" title "Logistic map behaviour at r=3.01"' в гнуплоте).
В случае r=3.01 (рисунок 2) переходный процесс уже гораздо более долгий и показывать его на одном графике не будет презентабельным. После процесса установления отображение демонстрирует цикл периода 2, то есть x возвращается в одно и то же состояние через раз. Поскольку при r=2.5 наблюдался цикл периода 1, а при r=3.01 мы обнаружили цикл периода 2, надо ожидать, что в промежутке от 2.5 до 3.01 есть бифуркационное значение r, которое разделяет значения r, при которых наблюдается цикл периода 1, и значения r, при которых цикл удваивается.
На рисунках 3 и 4 приведены аналогичным образом полученные реализации для r=3.5 (цикл период 4) и для r=3.575 (цикл периода 8). То есть, цикл все чаще удваивается.
Если продолжить увеличивать параметр r, то, при превышении некоторого критического значения, о котором мы поговорим в следующих статьях, наблюдается переход к хаосу (рисунок 5). На рисунке 5 приведен пример хаотического режима, в котором поведение переменной x никогда не повторяет себя (непериодический процесс).
В этой статье мы рассмотрели поведение логистического отображение и разобрались как проводить исследование бифуркационных переходов вручную. Изменяя параметр r все более аккуратно можно довольно точно найти значение, при котором поведение логистического отображения качественно изменяется. Как раз качественное изменение и называют в теории колебаний бифуркационным переходом. Продолжение материала.
p. s. Чтобы сразу увидеть новый материал в моем блоге в своей ленте, подписывайтесь! Буду рад комментариям, вопросам, предложениям.
Программа logistic для моделирования поведения логистического отображения
#include <iostream>
#include <cstdlib>
#include <fstream>
/*
/*The program written by Andrei Bukh, to compile it run:
* $ g++ -o logistic logistic.cpp
*/
int logistic (double *in, double *out, double par_r) {
if (((*in) < 0.0) || ((*in) > 1.0)) return 1;
if ((par_r < 0.0) || (par_r > 4.0)) return 2;
(*out) = par_r * (*in) * (1.0 - (*in));
return 0;
}
int main (int argc, char* argv[]) {
double parameter_r = 0.0;
if (argc > 1) {
bool rightnumber = true;
try {
parameter_r = std::stod (argv[1]);
} catch (std::invalid_argument) {
rightnumber = false;
}
if (!rightnumber) {
std::cout << "Please, enter parameter r = ";
std::cin >> parameter_r;
}
}
else {
std::cout << "Please, enter parameter r = ";
std::cin >> parameter_r;
}
double x_odd = 0.0;
if (argc > 2) {
bool rightnumber = true;
try {
x_odd = std::stod (argv[2]);
} catch (std::invalid_argument) {
rightnumber = false;
}
if (!rightnumber) {
std::cout << "Please, enter x_0 = ";
std::cin >> x_odd;
}
}
else {
std::cout << "Please, enter x_0 = ";
std::cin >> x_odd;
}
int transient_time = 0;
if (argc > 3) {
bool rightnumber = true;
try {
transient_time = std::stoi (argv[3]);
} catch (std::invalid_argument) {
rightnumber = false;
}
if (!rightnumber) {
std::cout << "Please, enter transient_time = ";
std::cin >> transient_time;
}
}
else {
std::cout << "Please, enter transient_time = ";
std::cin >> transient_time;
}
int observation_time = 0;
if (argc > 4) {
bool rightnumber = true;
try {
observation_time = std::stoi (argv[4]);
} catch (std::invalid_argument) {
rightnumber = false;
}
if (!rightnumber) {
std::cout << "Please, enter observation_time = ";
std::cin >> observation_time;
}
}
else {
std::cout << "Please, enter observation_time = ";
std::cin >> observation_time;
}
std::cout << "parameter_r = " << parameter_r << "\n";
std::cout << "x_0 = " << x_odd << "\n";
std::cout << "transient_time = " << transient_time << "\n";
std::cout << "observation_time = " << observation_time << "\n";
double x_even; int counter = 0;
for (int i=0; i<transient_time; i++) {
int error = 0;
if ((counter%2) == 0)
error = logistic (&x_odd, &x_even, parameter_r);
else
error = logistic (&x_even, &x_odd, parameter_r);
counter++;
if (error == 1) {
std::cout << "Variable x has gone to infinity\n";
return error;
}
if (error == 2) {
std::cout << "Parameter r has to be in range [0:4]\n";
return error;
}
}
std::ofstream TS_file("time-series.dat");
TS_file << "# r=" << parameter_r << "\n";
for (int i=0; i<observation_time; i++) {
int error = 0;
if ((counter%2) == 0)
error = logistic (&x_odd, &x_even, parameter_r);
else
error = logistic (&x_even, &x_odd, parameter_r);
counter++;
if (error == 1) {
std::cout << "Variable x has gone to infinity\n";
return error;
}
if (error == 2) {
std::cout << "Parameter r has to be in range [0:4]\n";
return error;
}
if ((counter%2) == 0)
TS_file << counter << " " << x_odd << "\n";
else
TS_file << counter << " " << x_even << "\n";
}
TS_file.close();
return 0;
}
p. s. Чтобы сразу увидеть новый материал в моем блоге в своей ленте, подписывайтесь! Буду рад комментариям, вопросам, предложениям.