My old project for strange attractors
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.
 
 
 

345 lines
7.6 KiB

#include <cmath>
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <iomanip>
#include <cassert>
#include <string>
using namespace std;
#include "Attractor.hpp"
/*
Constructors & initialisers
*/
Attractor::Attractor():
dim(3), par(4), formula(LORENZ), param(NULL), point(NULL), new_point(NULL) {
// Default attractor: 3D Lorenz attrractor
init_vector();
init_param();
param[0] = 0.001; //dt
param[1] = 10; //sigma
param[2] = 28; //rho
param[3] = 8.0/3.0; //beta
}
Attractor::Attractor(unsigned int dimensions, FormulaChoice formula, unsigned int orde):
dim(dimensions), formula(formula), orde(orde), param(NULL), point(NULL), new_point(NULL) {
init(dimensions, formula, orde);
}
Attractor::Attractor(const char* const filename) {
ifstream file(filename);
cout << "Reading file " << filename << "..." << endl;
if ( !file ) {
cout << " Error reading file '" << filename << "' dying now..." << endl;
exit(2);
}
/*
file.attr:
lorenz
3
0
3.24454
1.25
....
*/
string fileFormula;
file >> fileFormula;
for ( unsigned int i = 0; fileFormula[i] != '\0'; i++ ) {
fileFormula[i] = tolower(fileFormula[i]);
}
unsigned int fileDim;
file >> fileDim;
unsigned int fileOrde;
file >> fileOrde;
cout << " Formula: " << fileFormula << endl;
cout << " Dimensions: " << fileDim << endl;
cout << " Orde: " << fileOrde << endl;
if ( fileFormula == "lorenz" )
init(fileDim, LORENZ, fileOrde);
else if ( fileFormula == "poly_n" )
init(fileDim, POLY_N, fileOrde);
else if ( fileFormula == "poly_a" )
init(fileDim, POLY_A, fileOrde);
else if ( fileFormula == "logistic" )
init(fileDim, LOGISTIC, fileOrde);
else if ( fileFormula == "unravel" )
init(fileDim, UNRAVEL, fileOrde);
else {
cout << " Formula not (yet) supported" << endl;
exit(3);
}
for ( unsigned int i = 0; i < par; i++ ) {
file >> param[i];
cout << " Parameter " << i << " set to " << param[i] << ", ";
}
cout << endl << " Reading file complete" << endl;
}
void Attractor::init(unsigned int dim_in, FormulaChoice formula_in, unsigned int orde_in) {
dim = dim_in;
formula = formula_in;
orde = orde_in;
switch (formula) {
case POLY_N: {
double n_coef = orde + 1;
for (unsigned int i = 2; i <= dim; i++) {
n_coef = n_coef*(orde + i)/(i - 1);
}
par = (unsigned int) n_coef;
break;
}
case LORENZ: {
assert(dim == 3 || dim == 4);
par = dim + 1;
break;
}
case POLY_A: {
par = dim;
break;
}
case LOGISTIC: {
par = dim;
break;
}
case UNRAVEL: {
assert(dim == 3);
par = 7;
break;
}
default: {
cout << "Formula not recognized" << endl;
exit(1);
break;
}
}
init_vector();
init_param();
}
void Attractor::init_vector() {
point = new double[dim];
new_point = new double[dim];
assert(point != NULL);
assert(new_point != NULL);
for ( unsigned int i = 0; i < dim; i++ ) {
point[i] = new_point[i] = 0.9;
}
}
void Attractor::init_param() {
param = new double[par];
assert(param != NULL);
for ( unsigned int i = 0; i < dim; i++ ) {
param[i] = 0.0;
}
}
void Attractor::init_range() {
// stabilize attractor
for ( unsigned int i = 0; i < 100000; i++ ) {
iterate();
if ( !is_chaos() ) {
cout << "Attractor died after " << i << " iterations" << endl;
exit(0);
}
}
// initialize ranges
for ( vector<Projector*>::iterator it = projectors.begin(); it != projectors.end(); it++ ) {
(*it)->extern_dim = dim;
(*it)->intern_dim = 2;
(*it)->init(point);
}
// update ranges
for ( unsigned int i = 0; i < 100000; i++ ) {
iterate();
if ( !is_chaos() ) {
cout << "Attractor died after " << i << " iterations" << endl;
exit(0);
}
for ( vector<Projector*>::iterator it = projectors.begin(); it != projectors.end(); it++ ) {
(*it)->update_range(point);
}
}
for ( vector<Projector*>::iterator it = projectors.begin(); it != projectors.end(); it++ ) {
(*it)->finish_range();
}
}
bool Attractor::is_chaos() {
/*
check existence of attractor:
Escaping
Single point attractor
Lyapunov exponent
*/
double sum = 0;
for ( unsigned int i = 0; i < dim; i++ ) {
const double dist = new_point[i] - point[i];
sum += dist*dist;
}
if ( sum >= 1.0e7 ) {
// big change => Escaping
return false;
}
if ( sum <= 1.0e-7 ) {
// small change => singularity
return false;
}
return true;
}
/*
Iteration & Math
*/
void Attractor::iterate() {
// pointer swap
double * temp = point;
point = new_point;
new_point = temp;
// calculations
switch (formula) {
case POLY_N:
polynome();
break;
case POLY_A:
poly_A();
break;
case POLY_2:
poly_2();
break;
case LOGISTIC:
logistic();
break;
default:
cout << "Formula not recognized" << endl;
exit(1);
break;
}
#ifdef HARDDEBUG
cout << "Formula " << formula << " is done" << endl;
cout << "Old Vector: ";
for ( unsigned int i = 0; i < dim; i++ ) {
cout << point[i] << " ";
}
cout << endl << "Fresh Vector: ";
for ( unsigned int i = 0; i < dim; i++ ) {
cout << new_point[i] << " ";
}
cout << endl;
#endif
}
void Attractor::polynome() {
unsigned int m = 0;
for ( unsigned int i = 0; i < dim; i++ ) {
#ifdef HARDDEBUG
cout << "Entering new dimension: " << i << " With m = " << m << endl;
#endif
new_point[i] = param[m];
m++;
recur(i, 0, 1, m);
}
}
void Attractor::recur(unsigned int curr_dimension, unsigned int prev_i, unsigned int n, unsigned int& m, double prev_product) {
double product;
for (unsigned int i = prev_i; i < dim; i++) {
#ifdef HARDDEBUG
for ( unsigned int j = 0; j < n; j++ )
cout << " ";
cout << "Calculation in dimension: " << i << " With m = " << m << " And depth = " << n << endl;
#endif
product = prev_product * point[i];
new_point[curr_dimension] += param[m] * product;
m++;
if (n < orde) {
recur(curr_dimension, i, n+1, m, product);
}
}
}
void Attractor::poly_A() {
switch (dim) {
case 3:
new_point[0] = param[0] + point[1] - point[1]*point[2];
new_point[1] = param[1] + point[2] - point[2]*point[0];
new_point[2] = param[2] + point[0] - point[0]*point[1];
break;
default:
for ( unsigned int i = 0; i < dim; i++ ) {
new_point[i] = param[i] + point[(i+1) % dim] - point[(i+1) % dim]*point[(i+2) % dim];
}
break;
}
}
void Attractor::poly_2() {
exit(2);
}
void Attractor::logistic() {
for ( unsigned int i = 0; i < dim; i++ ) {
new_point[i] = param[i]*point[i]*(1.0 - point[i]);
}
}
void Attractor::plot() {
for ( vector<Projector *>::iterator it = projectors.begin(); it != projectors.end(); it++ ) {
(*it)->plot(point);
}
}
/*
IO & control
*/
void Attractor::output() {
for ( unsigned int i = 0; i < dim; i++ ) {
cout << point[i] << " ";
}
cout << endl;
}