aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorB. Bogart <bbogart@users.sourceforge.net>2003-09-30 15:58:08 +0000
committerB. Bogart <bbogart@users.sourceforge.net>2003-09-30 15:58:08 +0000
commit8890d81285fc713353a00d7d149fb02e6b00b3b5 (patch)
tree61fe8dc9aafbadc481c80009aa7e1c29b96584df
parenta10c1491da756bd6af75a01c418e054cbd7b7c66 (diff)
This is the first Release of chaosII (internally versioned at 0.3)
The makefile has been updated, but I'm not sure if the vcproj requires an update. Should compile on all PD platforms. svn path=/trunk/externals/bbogart/chaos/; revision=1051
-rw-r--r--README.build.txt3
-rw-r--r--README.txt31
-rw-r--r--chaos.c74
-rw-r--r--henon.c318
-rw-r--r--ikeda.c383
-rw-r--r--lorenz.c396
-rw-r--r--makefile28
-rw-r--r--rossler.c394
8 files changed, 1245 insertions, 382 deletions
diff --git a/README.build.txt b/README.build.txt
index dc6b4e5..638cbcb 100644
--- a/README.build.txt
+++ b/README.build.txt
@@ -12,5 +12,4 @@ make pd_darwin
To Install:
-Copy the .pd* files where PD will seem them, like the "extra" folder.
-Precompiled binaries for OSX and Win32 are in the "Release" directory.
+Copy the .pd_* files where PD will seem them, like the "extra" folder.
diff --git a/README.txt b/README.txt
index ca2f2a0..face8a0 100644
--- a/README.txt
+++ b/README.txt
@@ -1,11 +1,15 @@
This is the readme for "Chaos PD Externals" a set of objects for PD which
-calculate various "Chaotic Attractors"; including, Lorenz, Rossler, Henon
-and Ikeda. Hopefully more will be on their way.
+calculate various "Chaotic Attractors"; including: lorenz, rossler, henon,
+ikeda, attract1, base, base3, dejong, gingerbreadman, hopalong, latoocarfian,
+latoomutalpha, latoomutbeta, latoomutgamma, logistic, lotka_volterra, martin,
+mlogistic, pickover, popcorn, quadruptwo, standardmap, strange1, tent, three_d, threeply, tinkerbell and unity.
-If you have any questions/comments you can reach me at ben@ekran.org
+If you have any questions/comments you can reach the co-authors at:
+Ben Bogart ben@ekran.org
+Michael McGonagle mjmogo@comcast.net
Please Note:
-These programs are Copyright Ben Bogart 2002
+These programs are Copyright Ben Bogart 2002, Ben Bogart and Michael McGonagle 2003.
These programs are distributed under the terms of the GNU General Public
License
@@ -26,24 +30,25 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
USAGE:
-The package only includes 2 and 3 dimentional attractors. There are
-outlets for each dimention. The scale of the values vary between the
-different attractors. To run pd with the chaos externals use:
+The package includes 1, 2 and 3 dimentional attractors. There are outlets for
+each dimention, starting from the left, followed by three outlets for attractor
+data (see the help patches for details). The scale of the values vary between
+the different attractors. To run pd with the chaos externals use:
pd -lib chaos
-The object methods are as follows:
+The basic object methods are as follows:
-bang: Calculate one interation of the attractor.
+bang: Calculate one iteration of the attractor.
reset: Reset to initial conditions defined by the two or three arguments.
[reset a b c] will reset the xyz values to abc respectively.
param: Modify the paramaters of the equation, the number of args depend
on the attractor. (Be careful with the parameters, an attractor
will go from stable to infinity in very few interations.)
-See the example patches for clarification.
+See the example patches for other methods (parameter searching etc.)
+The next release will include a script to generate your own attractor object
+for chaos from the attractor attributes.
-Have fun with them. I'd be happy to hear about any interesting uses you
-find for them. As well as any interesting attractor equations you come
-across.
+Have Fun.
diff --git a/chaos.c b/chaos.c
index 89d6fab..caf51e0 100644
--- a/chaos.c
+++ b/chaos.c
@@ -26,22 +26,46 @@
#include "m_pd.h"
-#ifndef __DATE__
+#ifndef __DATE__
#define __DATE__ "without using a gnu compiler"
#endif
typedef struct _chaos
{
- t_object x_obj;
+ t_object x_obj;
} t_chaos;
static t_class* chaos_class;
- /* objects */
-void henon_setup();
-void ikeda_setup();
-void lorenz_setup();
-void rossler_setup();
+/* objects */
+extern void attract1_setup();
+extern void base_setup();
+extern void base3_setup();
+extern void dejong_setup();
+extern void gingerbreadman_setup();
+extern void henon_setup();
+extern void hopalong_setup();
+extern void ikeda_setup();
+extern void lotkavolterra_setup();
+extern void latoocarfian_setup();
+extern void latoomutalpha_setup();
+extern void latoomutbeta_setup();
+extern void latoomutgamma_setup();
+extern void logistic_setup();
+extern void lorenz_setup();
+extern void martin_setup();
+extern void mlogistic_setup();
+extern void pickover_setup();
+extern void popcorn_setup();
+extern void quadruptwo_setup();
+extern void rossler_setup();
+extern void standardmap_setup();
+extern void strange1_setup();
+extern void tent_setup();
+extern void three_d_setup();
+extern void threeply_setup();
+extern void tinkerbell_setup();
+extern void unity_setup();
static void* chaos_new(t_symbol* s)
{
@@ -49,21 +73,43 @@ static void* chaos_new(t_symbol* s)
return (x);
}
-void chaos_setup(void)
+void chaos_setup(void)
{
- chaos_class = class_new(gensym("chaos"), (t_newmethod)chaos_new, 0,
- sizeof(t_chaos), 0,0);
+ chaos_class = class_new(gensym("chaos"), (t_newmethod)chaos_new, 0, sizeof(t_chaos), 0,0);
post("-------------------------"); /* Copyright info */
post("Chaos PD Externals");
- post("Copyright Ben Bogart 2002");
+ post("Copyright Ben Bogart 2002, Copyright Ben Bogart and Michael McGonagle 2003");
post("Win32 compilation by joge 2002");
+ attract1_setup();
+ base_setup();
+ base3_setup();
+ dejong_setup();
+ gingerbreadman_setup();
henon_setup();
+ hopalong_setup();
ikeda_setup();
+ lotkavolterra_setup();
+ latoocarfian_setup();
+ latoomutalpha_setup();
+ latoomutbeta_setup();
+ latoomutgamma_setup();
+ logistic_setup();
lorenz_setup();
+ martin_setup();
+ mlogistic_setup();
+ pickover_setup();
+ popcorn_setup();
+ quadruptwo_setup();
rossler_setup();
-
- post("-------------------------");
-}
+ standardmap_setup();
+ strange1_setup();
+ tent_setup();
+ three_d_setup();
+ threeply_setup();
+ tinkerbell_setup();
+ unity_setup();
+ post("-------------------------");
+}
diff --git a/henon.c b/henon.c
index a67addd..c921ded 100644
--- a/henon.c
+++ b/henon.c
@@ -1,8 +1,6 @@
-///////////////////////////////////////////////////////////////////////////////////
-/* Henon's Attractor PD External */
-/* Copyright Ben Bogart 2002 */
-/* This program is distributed under the terms of the GNU General Public License */
-///////////////////////////////////////////////////////////////////////////////////
+/* henon Attractor PD External */
+/* Copyright Ben Bogart, 2003 */
+/* This program is distributed under the params of the GNU Public License */
///////////////////////////////////////////////////////////////////////////////////
/* This file is part of Chaos PD Externals. */
@@ -22,88 +20,262 @@
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
///////////////////////////////////////////////////////////////////////////////////
-#include "m_pd.h"
+#include <stdio.h>
+#include <stdlib.h>
#include <math.h>
+#include <time.h>
+#include "lyapunov.h"
+
+#define M_a_lo -1
+#define M_a_hi 2
+#define M_b_lo -1
+#define M_b_hi 2
+
+#define M_a 0
+#define M_b 1
+
+#define M_x 0
+#define M_y 1
+
+#define M_param_count 2
+#define M_var_count 2
+#define M_search_count 3
+#define M_failure_limit 1000
+
+static char *version = "henon v0.0, by Ben Bogart, 2003";
t_class *henon_class;
-typedef struct henon_struct
-{
- t_object henon_obj;
- double a, b, lx0, ly0;
- t_outlet *y_outlet;
-} henon_struct;
-
-static void calculate(henon_struct *x)
-{
- double lx0, ly0, lx1, ly1;
- double a, b;
+typedef struct henon_struct {
+ t_object x_obj;
+
+ double vars[M_var_count];
+ double vars_init[M_var_count];
+ t_atom vars_out[M_var_count];
+ t_outlet *vars_outlet;
+
+ t_atom search_out[M_search_count];
+ t_outlet *search_outlet;
- a = x->a;
- b = x->b;
- lx0 = x->lx0;
- ly0 = x->ly0;
-
- lx1 = (ly0 + 1) - (a * pow(lx0,2));
- ly1 = b * lx0;
- x->lx0 = lx1;
- x->ly0 = ly1;
-
- outlet_float(x->henon_obj.ob_outlet, (t_float)lx1);
- outlet_float(x->y_outlet, (t_float)ly1);
+ double a, a_lo, a_hi, b, b_lo, b_hi;
+ t_atom params_out[M_param_count];
+ t_outlet *params_outlet;
+ double lyap_exp, lyap_lo, lyap_hi, lyap_limit, failure_ratio;
+
+ t_outlet *outlets[M_var_count - 1];
+} henon_struct;
+
+static void calc(henon_struct *henon, double *vars) {
+ double x_0, y_0;
+ x_0 =(vars[M_y]+1)-(henon -> a*pow(vars[M_x],2));
+ y_0 =henon -> b*vars[M_x];
+ vars[M_x] = x_0;
+ vars[M_y] = y_0;
+} // end calc
+
+static void calculate(henon_struct *henon) {
+ calc(henon, henon -> vars);
+ outlet_float(henon -> x_obj.ob_outlet, henon -> vars[M_x]);
+ outlet_float(henon -> outlets[M_y - 1], henon -> vars[M_y]);
+} // end calculate
+
+static void reset(henon_struct *henon, t_symbol *s, int argc, t_atom *argv) {
+ if (argc == M_var_count) {
+ henon -> vars[M_x] = (double) atom_getfloatarg(M_x, argc, argv);
+ henon -> vars[M_y] = (double) atom_getfloatarg(M_y, argc, argv);
+ } else {
+ henon -> vars[M_x] = henon -> vars_init[M_x];
+ henon -> vars[M_y] = henon -> vars_init[M_y];
+ } // end if
+} // end reset
+
+static char *classify(henon_struct *henon) {
+ static char buff[3];
+ char *c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ buff[0] = c[(int) (((henon -> a - M_a_lo) * (1.0 / (M_a_hi - M_a_lo))) * 26)];
+ buff[1] = c[(int) (((henon -> b - M_b_lo) * (1.0 / (M_b_hi - M_b_lo))) * 26)];
+ buff[2] = '\0';
+ return buff;
}
-static void reset(henon_struct *x, t_floatarg lx0, t_floatarg ly0)
-{
- x->lx0 = lx0;
- x->ly0 = ly0;
+static void make_results(henon_struct *henon) {
+ SETFLOAT(&henon -> search_out[0], henon -> lyap_exp);
+ SETSYMBOL(&henon -> search_out[1], gensym(classify(henon)));
+ SETFLOAT(&henon -> search_out[2], henon -> failure_ratio);
+ SETFLOAT(&henon -> vars_out[M_x], henon -> vars[M_x]);
+ SETFLOAT(&henon -> vars_out[M_y], henon -> vars[M_y]);
+ SETFLOAT(&henon -> params_out[M_a], henon -> a);
+ SETFLOAT(&henon -> params_out[M_b], henon -> b);
+ outlet_list(henon -> params_outlet, gensym("list"), M_param_count, henon -> params_out);
+ outlet_list(henon -> vars_outlet, gensym("list"), M_var_count, henon -> vars_out);
}
-static void param(henon_struct *x, t_floatarg a, t_floatarg b)
-{
- x->a = (double)a;
- x->b = (double)b;
+static void show(henon_struct *henon) {
+ make_results(henon);
+ outlet_anything(henon -> search_outlet, gensym("show"), M_search_count, henon -> search_out);
}
-void *henon_new(void)
-{
- henon_struct *x = (henon_struct *)pd_new(henon_class);
- x->a = 1.4;
- x->b = 0.3;
- x->lx0 = 1;
- x->ly0 = 1;
-
- outlet_new(&x->henon_obj, &s_float); /* Default float outlet */
- x->y_outlet = outlet_new(&x->henon_obj, &s_float); /* New Outlet */
-
- return (void *)x;
+static void param(henon_struct *henon, t_symbol *s, int argc, t_atom *argv) {
+ if (argc != 2) {
+ post("Incorrect number of arguments for henon fractal. Expecting 2 arguments.");
+ return;
+ }
+ henon -> a = (double) atom_getfloatarg(0, argc, argv);
+ henon -> b = (double) atom_getfloatarg(1, argc, argv);
}
+static void seed(henon_struct *henon, t_symbol *s, int argc, t_atom *argv) {
+ if (argc > 0) {
+ srand48(((unsigned int)time(0))|1);
+ } else {
+ srand48((unsigned int) atom_getfloatarg(0, argc, argv));
+ }
+}
-void henon_setup(void)
-{
- post("henon");
+static void lyap(henon_struct *henon, t_floatarg l, t_floatarg h, t_floatarg lim) {
+ henon -> lyap_lo = l;
+ henon -> lyap_hi = h;
+ henon -> lyap_limit = (double) ((int) lim);
+}
- henon_class = class_new(gensym("henon"), /* symname is the symbolic name */
- (t_newmethod)henon_new, /* Constructor Function */
- 0, /* Destructor Function */
- sizeof(henon_struct), /* Size of the structure */
- CLASS_DEFAULT, /* Graphical Representation */
- 0); /* 0 Terminates Argument List */
+static void elyap(henon_struct *henon) {
+ double results[M_var_count];
+ int i;
+ if (lyapunov_full((void *) henon, (t_gotfn) calc, M_var_count, henon -> vars, results) != NULL) {
+ post("elyapunov:");
+ for(i = 0; i < M_var_count; i++) { post("%d: %3.80f", i, results[i]); }
+ }
+}
- class_addbang(henon_class, (t_method)calculate);
-
- class_addmethod(henon_class,
- (t_method)reset,
- gensym("reset"),
- A_DEFFLOAT,
- A_DEFFLOAT,
- 0);
-
- class_addmethod(henon_class,
- (t_method)param,
- gensym("param"),
- A_DEFFLOAT,
- A_DEFFLOAT,
- 0);
+static void limiter(henon_struct *henon) {
+ if (henon -> a_lo < M_a_lo) { henon -> a_lo = M_a_lo; }
+ if (henon -> a_lo > M_a_hi) { henon -> a_lo = M_a_hi; }
+ if (henon -> a_hi < M_a_lo) { henon -> a_hi = M_a_lo; }
+ if (henon -> a_hi > M_a_hi) { henon -> a_hi = M_a_hi; }
+ if (henon -> b_lo < M_b_lo) { henon -> b_lo = M_b_lo; }
+ if (henon -> b_lo > M_b_hi) { henon -> b_lo = M_b_hi; }
+ if (henon -> b_hi < M_b_lo) { henon -> b_hi = M_b_lo; }
+ if (henon -> b_hi > M_b_hi) { henon -> b_hi = M_b_hi; }
+}
+
+static void constrain(henon_struct *henon, t_symbol *s, int argc, t_atom *argv) {
+ int i;
+ t_atom *arg = argv;
+ if (argc == 0) {
+ // reset to full limits of search ranges
+ henon -> a_lo = M_a_lo;
+ henon -> a_hi = M_a_hi;
+ henon -> b_lo = M_b_lo;
+ henon -> b_hi = M_b_hi;
+ return;
+ }
+ if (argc == 1) {
+ // set the ranges based on percentage of full range
+ double percent = atom_getfloat(arg);
+ double a_spread = ((M_a_hi - M_a_lo) * percent) / 2;
+ double b_spread = ((M_b_hi - M_b_lo) * percent) / 2;
+ henon -> a_lo = henon -> a - a_spread;
+ henon -> a_hi = henon -> a + a_spread;
+ henon -> b_lo = henon -> b - b_spread;
+ henon -> b_hi = henon -> b + b_spread;
+ limiter(henon);
+ return;
+ }
+ if (argc != M_param_count * 2) {
+ post("Invalid number of arguments for henon constraints, requires 4 values, got %d", argc);
+ return;
+ }
+ henon -> a_lo = atom_getfloat(arg++);
+ henon -> a_hi = atom_getfloat(arg++);
+ henon -> b_lo = atom_getfloat(arg++);
+ henon -> b_hi = atom_getfloat(arg++);
+ limiter(henon);
+}
+
+static void search(henon_struct *henon, t_symbol *s, int argc, t_atom *argv) {
+ int not_found, not_expired = henon -> lyap_limit;
+ int jump, i, iterations;
+ t_atom vars[M_var_count];
+ double temp_a = henon -> a;
+ double temp_b = henon -> b;
+ if (argc > 0) {
+ for (i = 0; i < M_var_count; i++) {
+ SETFLOAT(&vars[i], atom_getfloatarg(i, argc, argv));
+ }
+ } else {
+ for (i = 0; i < M_var_count; i++) {
+ SETFLOAT(&vars[i], henon -> vars_init[i]);
+ }
+ }
+ do {
+ jump = 500;
+ not_found = 0;
+ iterations = 10000;
+ bad_params:
+ henon -> a = (drand48() * (henon -> a_hi - henon -> a_lo)) + henon -> a_lo;
+ henon -> b = (drand48() * (henon -> b_hi - henon -> b_lo)) + henon -> b_lo;
+ // put any preliminary checks specific to this fractal to eliminate bad_params
+
+ reset(henon, NULL, argc, vars);
+ do { calc(henon, henon -> vars); } while(jump--);
+ henon -> lyap_exp = lyapunov((void *) henon, (t_gotfn) calc, M_var_count, (double *) henon -> vars);
+ if (isnan(henon -> lyap_exp)) { not_found = 1; }
+ if (henon -> lyap_exp < henon -> lyap_lo || henon -> lyap_exp > henon -> lyap_hi) { not_found = 1; }
+ not_expired--;
+ } while(not_found && not_expired);
+ reset(henon, NULL, argc, vars);
+ if (!not_expired) {
+ post("Could not find a fractal after %d attempts.", (int) henon -> lyap_limit);
+ post("Try using wider constraints.");
+ henon -> a = temp_a;
+ henon -> b = temp_b;
+ outlet_anything(henon -> search_outlet, gensym("invalid"), 0, NULL);
+ } else {
+ henon -> failure_ratio = (henon -> lyap_limit - not_expired) / henon -> lyap_limit;
+ make_results(henon);
+ outlet_anything(henon -> search_outlet, gensym("search"), M_search_count, henon -> search_out);
+ }
+}
+
+void *henon_new(t_symbol *s, int argc, t_atom *argv) {
+ henon_struct *henon = (henon_struct *) pd_new(henon_class);
+ if (henon != NULL) {
+ outlet_new(&henon -> x_obj, &s_float);
+ henon -> outlets[0] = outlet_new(&henon -> x_obj, &s_float);
+ henon -> search_outlet = outlet_new(&henon -> x_obj, &s_list);
+ henon -> vars_outlet = outlet_new(&henon -> x_obj, &s_list);
+ henon -> params_outlet = outlet_new(&henon -> x_obj, &s_list);
+ if (argc == M_param_count + M_var_count) {
+ henon -> vars_init[M_x] = henon -> vars[M_x] = (double) atom_getfloatarg(0, argc, argv);
+ henon -> vars_init[M_y] = henon -> vars[M_y] = (double) atom_getfloatarg(1, argc, argv);
+ henon -> a = (double) atom_getfloatarg(2, argc, argv);
+ henon -> b = (double) atom_getfloatarg(3, argc, argv);
+ } else {
+ if (argc != 0 && argc != M_param_count + M_var_count) {
+ post("Incorrect number of arguments for henon fractal. Expecting 4 arguments.");
+ }
+ henon -> vars_init[M_x] = 1;
+ henon -> vars_init[M_y] = 1;
+ henon -> a = 1.4;
+ henon -> b = 0.3;
+ }
+ constrain(henon, NULL, 0, NULL);
+ lyap(henon, -1000000.0, 1000000.0, M_failure_limit);
+ }
+ return (void *)henon;
}
+
+void henon_setup(void) {
+ henon_class = class_new(gensym("henon"), (t_newmethod) henon_new, 0, sizeof(henon_struct), 0, A_GIMME, 0);
+ class_addbang(henon_class, (t_method) calculate);
+ class_addmethod(henon_class, (t_method) reset, gensym("reset"), A_GIMME, 0);
+ class_addmethod(henon_class, (t_method) show, gensym("show"), 0);
+ class_addmethod(henon_class, (t_method) param, gensym("param"), A_GIMME, 0);
+ class_addmethod(henon_class, (t_method) seed, gensym("seed"), A_GIMME, 0);
+ class_addmethod(henon_class, (t_method) lyap, gensym("lyapunov"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(henon_class, (t_method) elyap, gensym("elyapunov"), 0);
+ class_addmethod(henon_class, (t_method) search, gensym("search"), A_GIMME, 0);
+ class_addmethod(henon_class, (t_method) constrain, gensym("constrain"), A_GIMME, 0);
+ class_sethelpsymbol(henon_class, gensym("help-henon.pd"));
+}
+
diff --git a/ikeda.c b/ikeda.c
index 0c2fa21..4299f46 100644
--- a/ikeda.c
+++ b/ikeda.c
@@ -1,8 +1,6 @@
-///////////////////////////////////////////////////////////////////////////////////
-/* Ikeda Attractor PD External */
-/* Copyright Ben Bogart 2002 */
-/* This program is distributed under the terms of the GNU General Public License */
-///////////////////////////////////////////////////////////////////////////////////
+/* ikeda Attractor PD External */
+/* Copyright Ben Bogart, 2002 */
+/* This program is distributed under the params of the GNU Public License */
///////////////////////////////////////////////////////////////////////////////////
/* This file is part of Chaos PD Externals. */
@@ -22,102 +20,309 @@
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
///////////////////////////////////////////////////////////////////////////////////
-#include "m_pd.h"
+#include <stdio.h>
+#include <stdlib.h>
#include <math.h>
+#include <time.h>
+#include "lyapunov.h"
+
+#define M_a_lo -350
+#define M_a_hi 350
+#define M_b_lo -2
+#define M_b_hi 2
+#define M_c_lo -350
+#define M_c_hi 350
+#define M_rho_lo -250
+#define M_rho_hi 250
+
+#define M_a 0
+#define M_b 1
+#define M_c 2
+#define M_rho 3
+#define M_x 0
+#define M_y 1
+
+#define M_param_count 4
+#define M_var_count 2
+#define M_search_count 3
+#define M_failure_limit 1000
+
+static char *version = "ikeda v0.0, by Ben Bogart, 2002";
t_class *ikeda_class;
-typedef struct ikeda_struct
-{
- t_object ikeda_obj;
- double a, b, c, rho, lx0, ly0;
- t_outlet *y_outlet;
-} ikeda_struct;
-
-static void calculate(ikeda_struct *x)
-{
- double lx0, ly0, lx1, ly1;
- double a, b, c, rho, tmp, cos_tmp, sin_tmp;
-
- a = x->a;
- b = x->b;
- c = x->c;
- rho = x->rho;
- lx0 = x->lx0;
- ly0 = x->ly0;
-
-
- tmp = a - c / ( 1.0 + lx0*lx0 + ly0*ly0);
- sin_tmp = sin(tmp);
- cos_tmp = cos(tmp);
-
- lx1 = rho + b * ( lx0 * cos_tmp - ly0 * sin_tmp);
- ly1 = b * ( lx0 * sin_tmp + ly0 * cos_tmp);
- x->lx0 = lx1;
- x->ly0 = ly1;
-
- outlet_float(x->ikeda_obj.ob_outlet, (t_float)lx1);
- outlet_float(x->y_outlet, (t_float)ly1);
+typedef struct ikeda_struct {
+ t_object x_obj;
+
+ double vars[M_var_count];
+ double vars_init[M_var_count];
+ t_atom vars_out[M_var_count];
+ t_outlet *vars_outlet;
+
+ t_atom search_out[M_search_count];
+ t_outlet *search_outlet;
+
+ double a, a_lo, a_hi, b, b_lo, b_hi, c, c_lo, c_hi, rho, rho_lo, rho_hi;
+ t_atom params_out[M_param_count];
+ t_outlet *params_outlet;
+ double lyap_exp, lyap_lo, lyap_hi, lyap_limit, failure_ratio;
+
+ t_outlet *outlets[M_var_count - 1];
+} ikeda_struct;
+
+static void calc(ikeda_struct *ikeda, double *vars) {
+ double t, s, d, x_0, y_0;
+ t=ikeda -> a-ikeda -> c/(1.0+vars[M_x]*vars[M_x]+vars[M_y]*vars[M_y]);
+ s=sin(t);
+ d=cos(t);
+ x_0 =ikeda -> rho+ikeda -> b*(vars[M_x]*d-vars[M_y]*s);
+ y_0 =ikeda -> b*(vars[M_x]*s+vars[M_y]*d);
+ vars[M_x] = x_0;
+ vars[M_y] = y_0;
+} // end calc
+
+static void calculate(ikeda_struct *ikeda) {
+ calc(ikeda, ikeda -> vars);
+ outlet_float(ikeda -> x_obj.ob_outlet, ikeda -> vars[M_x]);
+ outlet_float(ikeda -> outlets[M_y - 1], ikeda -> vars[M_y]);
+} // end calculate
+
+static void reset(ikeda_struct *ikeda, t_symbol *s, int argc, t_atom *argv) {
+ if (argc == M_var_count) {
+ ikeda -> vars[M_x] = (double) atom_getfloatarg(M_x, argc, argv);
+ ikeda -> vars[M_y] = (double) atom_getfloatarg(M_y, argc, argv);
+ } else {
+ ikeda -> vars[M_x] = ikeda -> vars_init[M_x];
+ ikeda -> vars[M_y] = ikeda -> vars_init[M_y];
+ } // end if
+} // end reset
+
+static char *classify(ikeda_struct *ikeda) {
+ static char buff[5];
+ char *c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ buff[0] = c[(int) (((ikeda -> a - M_a_lo) * (1.0 / (M_a_hi - M_a_lo))) * 26)];
+ buff[1] = c[(int) (((ikeda -> b - M_b_lo) * (1.0 / (M_b_hi - M_b_lo))) * 26)];
+ buff[2] = c[(int) (((ikeda -> c - M_c_lo) * (1.0 / (M_c_hi - M_c_lo))) * 26)];
+ buff[3] = c[(int) (((ikeda -> rho - M_rho_lo) * (1.0 / (M_rho_hi - M_rho_lo))) * 26)];
+ buff[4] = '\0';
+ return buff;
+}
+
+static void make_results(ikeda_struct *ikeda) {
+ SETFLOAT(&ikeda -> search_out[0], ikeda -> lyap_exp);
+ SETSYMBOL(&ikeda -> search_out[1], gensym(classify(ikeda)));
+ SETFLOAT(&ikeda -> search_out[2], ikeda -> failure_ratio);
+ SETFLOAT(&ikeda -> vars_out[M_x], ikeda -> vars[M_x]);
+ SETFLOAT(&ikeda -> vars_out[M_y], ikeda -> vars[M_y]);
+ SETFLOAT(&ikeda -> params_out[M_a], ikeda -> a);
+ SETFLOAT(&ikeda -> params_out[M_b], ikeda -> b);
+ SETFLOAT(&ikeda -> params_out[M_c], ikeda -> c);
+ SETFLOAT(&ikeda -> params_out[M_rho], ikeda -> rho);
+ outlet_list(ikeda -> params_outlet, gensym("list"), M_param_count, ikeda -> params_out);
+ outlet_list(ikeda -> vars_outlet, gensym("list"), M_var_count, ikeda -> vars_out);
}
-static void reset(ikeda_struct *x, t_floatarg lx0, t_floatarg ly0)
-{
- x->lx0 = lx0;
- x->ly0 = ly0;
+static void show(ikeda_struct *ikeda) {
+ make_results(ikeda);
+ outlet_anything(ikeda -> search_outlet, gensym("show"), M_search_count, ikeda -> search_out);
}
-static void param(ikeda_struct *x, t_floatarg a, t_floatarg b, t_floatarg c, t_floatarg rho)
-{
- x->a = (double)a;
- x->b = (double)b;
- x->c = (double)c;
- x->rho = (double)rho;
+static void param(ikeda_struct *ikeda, t_symbol *s, int argc, t_atom *argv) {
+ if (argc != 4) {
+ post("Incorrect number of arguments for ikeda fractal. Expecting 4 arguments.");
+ return;
+ }
+ ikeda -> a = (double) atom_getfloatarg(0, argc, argv);
+ ikeda -> b = (double) atom_getfloatarg(1, argc, argv);
+ ikeda -> c = (double) atom_getfloatarg(2, argc, argv);
+ ikeda -> rho = (double) atom_getfloatarg(3, argc, argv);
}
-void *ikeda_new(void)
-{
- ikeda_struct *x = (ikeda_struct *)pd_new(ikeda_class);
- x->a = 0.4;
- x->b = 0.9;
- x->c = 6.0;
- x->rho = 1.0;
- x->lx0 = 0.1;
- x->ly0 = 0.1;
-
- outlet_new(&x->ikeda_obj, &s_float); /* Default float outlet */
- x->y_outlet = outlet_new(&x->ikeda_obj, &s_float); /* New Outlet */
-
- return (void *)x;
+static void seed(ikeda_struct *ikeda, t_symbol *s, int argc, t_atom *argv) {
+ if (argc > 0) {
+ srand48(((unsigned int)time(0))|1);
+ } else {
+ srand48((unsigned int) atom_getfloatarg(0, argc, argv));
+ }
}
+static void lyap(ikeda_struct *ikeda, t_floatarg l, t_floatarg h, t_floatarg lim) {
+ ikeda -> lyap_lo = l;
+ ikeda -> lyap_hi = h;
+ ikeda -> lyap_limit = (double) ((int) lim);
+}
+
+static void elyap(ikeda_struct *ikeda) {
+ double results[M_var_count];
+ int i;
+ if (lyapunov_full((void *) ikeda, (t_gotfn) calc, M_var_count, ikeda -> vars, results) != NULL) {
+ post("elyapunov:");
+ for(i = 0; i < M_var_count; i++) { post("%d: %3.80f", i, results[i]); }
+ }
+}
-void ikeda_setup(void)
-{
- post("ikeda");
-
- ikeda_class = class_new(gensym("ikeda"), /* symname is the symbolic name */
- (t_newmethod)ikeda_new, /* Constructor Function */
- 0, /* Destructor Function */
- sizeof(ikeda_struct), /* Size of the structure */
- CLASS_DEFAULT, /* Graphical Representation */
- 0); /* 0 Terminates Argument List */
-
- class_addbang(ikeda_class, (t_method)calculate);
-
- class_addmethod(ikeda_class,
- (t_method)reset,
- gensym("reset"),
- A_DEFFLOAT,
- A_DEFFLOAT,
- 0);
-
- class_addmethod(ikeda_class,
- (t_method)param,
- gensym("param"),
- A_DEFFLOAT,
- A_DEFFLOAT,
- A_DEFFLOAT,
- A_DEFFLOAT,
- 0);
+static void limiter(ikeda_struct *ikeda) {
+ if (ikeda -> a_lo < M_a_lo) { ikeda -> a_lo = M_a_lo; }
+ if (ikeda -> a_lo > M_a_hi) { ikeda -> a_lo = M_a_hi; }
+ if (ikeda -> a_hi < M_a_lo) { ikeda -> a_hi = M_a_lo; }
+ if (ikeda -> a_hi > M_a_hi) { ikeda -> a_hi = M_a_hi; }
+ if (ikeda -> b_lo < M_b_lo) { ikeda -> b_lo = M_b_lo; }
+ if (ikeda -> b_lo > M_b_hi) { ikeda -> b_lo = M_b_hi; }
+ if (ikeda -> b_hi < M_b_lo) { ikeda -> b_hi = M_b_lo; }
+ if (ikeda -> b_hi > M_b_hi) { ikeda -> b_hi = M_b_hi; }
+ if (ikeda -> c_lo < M_c_lo) { ikeda -> c_lo = M_c_lo; }
+ if (ikeda -> c_lo > M_c_hi) { ikeda -> c_lo = M_c_hi; }
+ if (ikeda -> c_hi < M_c_lo) { ikeda -> c_hi = M_c_lo; }
+ if (ikeda -> c_hi > M_c_hi) { ikeda -> c_hi = M_c_hi; }
+ if (ikeda -> rho_lo < M_rho_lo) { ikeda -> rho_lo = M_rho_lo; }
+ if (ikeda -> rho_lo > M_rho_hi) { ikeda -> rho_lo = M_rho_hi; }
+ if (ikeda -> rho_hi < M_rho_lo) { ikeda -> rho_hi = M_rho_lo; }
+ if (ikeda -> rho_hi > M_rho_hi) { ikeda -> rho_hi = M_rho_hi; }
}
+
+static void constrain(ikeda_struct *ikeda, t_symbol *s, int argc, t_atom *argv) {
+ int i;
+ t_atom *arg = argv;
+ if (argc == 0) {
+ // reset to full limits of search ranges
+ ikeda -> a_lo = M_a_lo;
+ ikeda -> a_hi = M_a_hi;
+ ikeda -> b_lo = M_b_lo;
+ ikeda -> b_hi = M_b_hi;
+ ikeda -> c_lo = M_c_lo;
+ ikeda -> c_hi = M_c_hi;
+ ikeda -> rho_lo = M_rho_lo;
+ ikeda -> rho_hi = M_rho_hi;
+ return;
+ }
+ if (argc == 1) {
+ // set the ranges based on percentage of full range
+ double percent = atom_getfloat(arg);
+ double a_spread = ((M_a_hi - M_a_lo) * percent) / 2;
+ double b_spread = ((M_b_hi - M_b_lo) * percent) / 2;
+ double c_spread = ((M_c_hi - M_c_lo) * percent) / 2;
+ double rho_spread = ((M_rho_hi - M_rho_lo) * percent) / 2;
+ ikeda -> a_lo = ikeda -> a - a_spread;
+ ikeda -> a_hi = ikeda -> a + a_spread;
+ ikeda -> b_lo = ikeda -> b - b_spread;
+ ikeda -> b_hi = ikeda -> b + b_spread;
+ ikeda -> c_lo = ikeda -> c - c_spread;
+ ikeda -> c_hi = ikeda -> c + c_spread;
+ ikeda -> rho_lo = ikeda -> rho - rho_spread;
+ ikeda -> rho_hi = ikeda -> rho + rho_spread;
+ limiter(ikeda);
+ return;
+ }
+ if (argc != M_param_count * 2) {
+ post("Invalid number of arguments for ikeda constraints, requires 8 values, got %d", argc);
+ return;
+ }
+ ikeda -> a_lo = atom_getfloat(arg++);
+ ikeda -> a_hi = atom_getfloat(arg++);
+ ikeda -> b_lo = atom_getfloat(arg++);
+ ikeda -> b_hi = atom_getfloat(arg++);
+ ikeda -> c_lo = atom_getfloat(arg++);
+ ikeda -> c_hi = atom_getfloat(arg++);
+ ikeda -> rho_lo = atom_getfloat(arg++);
+ ikeda -> rho_hi = atom_getfloat(arg++);
+ limiter(ikeda);
+}
+
+static void search(ikeda_struct *ikeda, t_symbol *s, int argc, t_atom *argv) {
+ int not_found, not_expired = ikeda -> lyap_limit;
+ int jump, i, iterations;
+ t_atom vars[M_var_count];
+ double temp_a = ikeda -> a;
+ double temp_b = ikeda -> b;
+ double temp_c = ikeda -> c;
+ double temp_rho = ikeda -> rho;
+ if (argc > 0) {
+ for (i = 0; i < M_var_count; i++) {
+ SETFLOAT(&vars[i], atom_getfloatarg(i, argc, argv));
+ }
+ } else {
+ for (i = 0; i < M_var_count; i++) {
+ SETFLOAT(&vars[i], ikeda -> vars_init[i]);
+ }
+ }
+ do {
+ jump = 500;
+ not_found = 0;
+ iterations = 10000;
+ bad_params:
+ ikeda -> a = (drand48() * (ikeda -> a_hi - ikeda -> a_lo)) + ikeda -> a_lo;
+ ikeda -> b = (drand48() * (ikeda -> b_hi - ikeda -> b_lo)) + ikeda -> b_lo;
+ ikeda -> c = (drand48() * (ikeda -> c_hi - ikeda -> c_lo)) + ikeda -> c_lo;
+ ikeda -> rho = (drand48() * (ikeda -> rho_hi - ikeda -> rho_lo)) + ikeda -> rho_lo;
+ // put any preliminary checks specific to this fractal to eliminate bad_params
+
+ reset(ikeda, NULL, argc, vars);
+ do { calc(ikeda, ikeda -> vars); } while(jump--);
+ ikeda -> lyap_exp = lyapunov((void *) ikeda, (t_gotfn) calc, M_var_count, (double *) ikeda -> vars);
+ if (isnan(ikeda -> lyap_exp)) { not_found = 1; }
+ if (ikeda -> lyap_exp < ikeda -> lyap_lo || ikeda -> lyap_exp > ikeda -> lyap_hi) { not_found = 1; }
+ not_expired--;
+ } while(not_found && not_expired);
+ reset(ikeda, NULL, argc, vars);
+ if (!not_expired) {
+ post("Could not find a fractal after %d attempts.", (int) ikeda -> lyap_limit);
+ post("Try using wider constraints.");
+ ikeda -> a = temp_a;
+ ikeda -> b = temp_b;
+ ikeda -> c = temp_c;
+ ikeda -> rho = temp_rho;
+ outlet_anything(ikeda -> search_outlet, gensym("invalid"), 0, NULL);
+ } else {
+ ikeda -> failure_ratio = (ikeda -> lyap_limit - not_expired) / ikeda -> lyap_limit;
+ make_results(ikeda);
+ outlet_anything(ikeda -> search_outlet, gensym("search"), M_search_count, ikeda -> search_out);
+ }
+}
+
+void *ikeda_new(t_symbol *s, int argc, t_atom *argv) {
+ ikeda_struct *ikeda = (ikeda_struct *) pd_new(ikeda_class);
+ if (ikeda != NULL) {
+ outlet_new(&ikeda -> x_obj, &s_float);
+ ikeda -> outlets[0] = outlet_new(&ikeda -> x_obj, &s_float);
+ ikeda -> search_outlet = outlet_new(&ikeda -> x_obj, &s_list);
+ ikeda -> vars_outlet = outlet_new(&ikeda -> x_obj, &s_list);
+ ikeda -> params_outlet = outlet_new(&ikeda -> x_obj, &s_list);
+ if (argc == M_param_count + M_var_count) {
+ ikeda -> vars_init[M_x] = ikeda -> vars[M_x] = (double) atom_getfloatarg(0, argc, argv);
+ ikeda -> vars_init[M_y] = ikeda -> vars[M_y] = (double) atom_getfloatarg(1, argc, argv);
+ ikeda -> a = (double) atom_getfloatarg(2, argc, argv);
+ ikeda -> b = (double) atom_getfloatarg(3, argc, argv);
+ ikeda -> c = (double) atom_getfloatarg(4, argc, argv);
+ ikeda -> rho = (double) atom_getfloatarg(5, argc, argv);
+ } else {
+ if (argc != 0 && argc != M_param_count + M_var_count) {
+ post("Incorrect number of arguments for ikeda fractal. Expecting 6 arguments.");
+ }
+ ikeda -> vars_init[M_x] = 0.1;
+ ikeda -> vars_init[M_y] = 0.1;
+ ikeda -> a = 0.4;
+ ikeda -> b = 0.9;
+ ikeda -> c = 6;
+ ikeda -> rho = 1;
+ }
+ constrain(ikeda, NULL, 0, NULL);
+ lyap(ikeda, -1000000.0, 1000000.0, M_failure_limit);
+ }
+ return (void *)ikeda;
+}
+
+void ikeda_setup(void) {
+ ikeda_class = class_new(gensym("ikeda"), (t_newmethod) ikeda_new, 0, sizeof(ikeda_struct), 0, A_GIMME, 0);
+ class_addbang(ikeda_class, (t_method) calculate);
+ class_addmethod(ikeda_class, (t_method) reset, gensym("reset"), A_GIMME, 0);
+ class_addmethod(ikeda_class, (t_method) show, gensym("show"), 0);
+ class_addmethod(ikeda_class, (t_method) param, gensym("param"), A_GIMME, 0);
+ class_addmethod(ikeda_class, (t_method) seed, gensym("seed"), A_GIMME, 0);
+ class_addmethod(ikeda_class, (t_method) lyap, gensym("lyapunov"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(ikeda_class, (t_method) elyap, gensym("elyapunov"), 0);
+ class_addmethod(ikeda_class, (t_method) search, gensym("search"), A_GIMME, 0);
+ class_addmethod(ikeda_class, (t_method) constrain, gensym("constrain"), A_GIMME, 0);
+ class_sethelpsymbol(ikeda_class, gensym("help-ikeda.pd"));
+}
+
diff --git a/lorenz.c b/lorenz.c
index 95994c9..35853fb 100644
--- a/lorenz.c
+++ b/lorenz.c
@@ -1,8 +1,6 @@
-///////////////////////////////////////////////////////////////////////////////////
-/* Lorenz's Attractor PD External */
-/* Copyright Ben Bogart 2002 */
-/* This program is distributed under the terms of the GNU General Public License */
-///////////////////////////////////////////////////////////////////////////////////
+/* lorenz Attractor PD External */
+/* Copyright Ben Bogart, 2002 */
+/* This program is distributed under the params of the GNU Public License */
///////////////////////////////////////////////////////////////////////////////////
/* This file is part of Chaos PD Externals. */
@@ -22,106 +20,316 @@
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
///////////////////////////////////////////////////////////////////////////////////
-#include "m_pd.h"
+#include <stdio.h>
+#include <stdlib.h>
#include <math.h>
+#include <time.h>
+#include "lyapunov.h"
+
+#define M_h_lo -1000
+#define M_h_hi 1000
+#define M_a_lo -1000
+#define M_a_hi 1000
+#define M_b_lo -1000
+#define M_b_hi 1000
+#define M_c_lo -1000
+#define M_c_hi 1000
+
+#define M_h 0
+#define M_a 1
+#define M_b 2
+#define M_c 3
+
+#define M_x 0
+#define M_y 1
+#define M_z 2
+
+#define M_param_count 4
+#define M_var_count 3
+#define M_search_count 3
+#define M_failure_limit 1000
+
+static char *version = "lorenz v0.0, by Ben Bogart, 2002";
t_class *lorenz_class;
-typedef struct lorenz_struct
-{
- t_object lorenz_obj;
- double h, a, b, c, lx0, ly0, lz0;
- t_outlet *y_outlet;
- t_outlet *z_outlet;
-} lorenz_struct;
-
-static void calculate(lorenz_struct *x)
-{
- double lx0, ly0, lz0, lx1, ly1, lz1;
- double h, a, b, c;
-
- h = x->h;
- a = x->a;
- b = x->b;
- c = x->c;
- lx0 = x->lx0;
- ly0 = x->ly0;
- lz0 = x->lz0;
-
- lx1 = lx0 + h * a * (ly0 - lx0);
- ly1 = ly0 + h * (lx0 * (b - lz0) - ly0);
- lz1 = lz0 + h * (lx0 * ly0 - c * lz0);
- x->lx0 = lx1;
- x->ly0 = ly1;
- x->lz0 = lz1;
-
- outlet_float(x->lorenz_obj.ob_outlet, (t_float)lx1);
- outlet_float(x->y_outlet, (t_float)ly1);
- outlet_float(x->z_outlet, (t_float)lz1);
+typedef struct lorenz_struct {
+ t_object x_obj;
+
+ double vars[M_var_count];
+ double vars_init[M_var_count];
+ t_atom vars_out[M_var_count];
+ t_outlet *vars_outlet;
+
+ t_atom search_out[M_search_count];
+ t_outlet *search_outlet;
+
+ double h, h_lo, h_hi, a, a_lo, a_hi, b, b_lo, b_hi, c, c_lo, c_hi;
+ t_atom params_out[M_param_count];
+ t_outlet *params_outlet;
+ double lyap_exp, lyap_lo, lyap_hi, lyap_limit, failure_ratio;
+
+ t_outlet *outlets[M_var_count - 1];
+} lorenz_struct;
+
+static void calc(lorenz_struct *lorenz, double *vars) {
+ double x_0, y_0, z_0;
+ x_0 =vars[M_x]+lorenz -> h*lorenz -> a*(vars[M_y]-vars[M_x]);
+ y_0 =vars[M_y]+lorenz -> h*(vars[M_x]*(lorenz -> b-vars[M_z])-vars[M_y]);
+ z_0 =vars[M_z]+lorenz -> h*(vars[M_x]*vars[M_y]-lorenz -> c*vars[M_z]);
+ vars[M_x] = x_0;
+ vars[M_y] = y_0;
+ vars[M_z] = z_0;
+} // end calc
+
+static void calculate(lorenz_struct *lorenz) {
+ calc(lorenz, lorenz -> vars);
+ outlet_float(lorenz -> x_obj.ob_outlet, lorenz -> vars[M_x]);
+ outlet_float(lorenz -> outlets[M_y - 1], lorenz -> vars[M_y]);
+ outlet_float(lorenz -> outlets[M_z - 1], lorenz -> vars[M_z]);
+} // end calculate
+
+static void reset(lorenz_struct *lorenz, t_symbol *s, int argc, t_atom *argv) {
+ if (argc == M_var_count) {
+ lorenz -> vars[M_x] = (double) atom_getfloatarg(M_x, argc, argv);
+ lorenz -> vars[M_y] = (double) atom_getfloatarg(M_y, argc, argv);
+ lorenz -> vars[M_z] = (double) atom_getfloatarg(M_z, argc, argv);
+ } else {
+ lorenz -> vars[M_x] = lorenz -> vars_init[M_x];
+ lorenz -> vars[M_y] = lorenz -> vars_init[M_y];
+ lorenz -> vars[M_z] = lorenz -> vars_init[M_z];
+ } // end if
+} // end reset
+
+static char *classify(lorenz_struct *lorenz) {
+ static char buff[5];
+ char *c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ buff[0] = c[(int) (((lorenz -> h - M_h_lo) * (1.0 / (M_h_hi - M_h_lo))) * 26)];
+ buff[1] = c[(int) (((lorenz -> a - M_a_lo) * (1.0 / (M_a_hi - M_a_lo))) * 26)];
+ buff[2] = c[(int) (((lorenz -> b - M_b_lo) * (1.0 / (M_b_hi - M_b_lo))) * 26)];
+ buff[3] = c[(int) (((lorenz -> c - M_c_lo) * (1.0 / (M_c_hi - M_c_lo))) * 26)];
+ buff[4] = '\0';
+ return buff;
}
-static void reset(lorenz_struct *x, t_floatarg lx0, t_floatarg ly0, t_floatarg lz0)
-{
- x->lx0 = lx0;
- x->ly0 = ly0;
- x->lz0 = lz0;
-}
-
-static void param(lorenz_struct *x, t_floatarg h, t_floatarg a, t_floatarg b, t_floatarg c)
-{
- x->h = (double)h;
- x->a = (double)a;
- x->b = (double)b;
- x->c = (double)c;
+static void make_results(lorenz_struct *lorenz) {
+ SETFLOAT(&lorenz -> search_out[0], lorenz -> lyap_exp);
+ SETSYMBOL(&lorenz -> search_out[1], gensym(classify(lorenz)));
+ SETFLOAT(&lorenz -> search_out[2], lorenz -> failure_ratio);
+ SETFLOAT(&lorenz -> vars_out[M_x], lorenz -> vars[M_x]);
+ SETFLOAT(&lorenz -> vars_out[M_y], lorenz -> vars[M_y]);
+ SETFLOAT(&lorenz -> vars_out[M_z], lorenz -> vars[M_z]);
+ SETFLOAT(&lorenz -> params_out[M_h], lorenz -> h);
+ SETFLOAT(&lorenz -> params_out[M_a], lorenz -> a);
+ SETFLOAT(&lorenz -> params_out[M_b], lorenz -> b);
+ SETFLOAT(&lorenz -> params_out[M_c], lorenz -> c);
+ outlet_list(lorenz -> params_outlet, gensym("list"), M_param_count, lorenz -> params_out);
+ outlet_list(lorenz -> vars_outlet, gensym("list"), M_var_count, lorenz -> vars_out);
}
-void *lorenz_new(void)
-{
- lorenz_struct *x = (lorenz_struct *)pd_new(lorenz_class);
- x->h = 0.01;
- x->a = 10.0;
- x->b = 28.0;
- x->c = 8.0/3.0;
- x->lx0 = 0.1;
- x->ly0 = 0;
- x->lz0 = 0;
-
- outlet_new(&x->lorenz_obj, &s_float); /* Default float outlet */
- x->y_outlet = outlet_new(&x->lorenz_obj, &s_float); /* Two New Outlets */
- x->z_outlet = outlet_new(&x->lorenz_obj, &s_float);
-
- return (void *)x;
+static void show(lorenz_struct *lorenz) {
+ make_results(lorenz);
+ outlet_anything(lorenz -> search_outlet, gensym("show"), M_search_count, lorenz -> search_out);
}
+static void param(lorenz_struct *lorenz, t_symbol *s, int argc, t_atom *argv) {
+ if (argc != 4) {
+ post("Incorrect number of arguments for lorenz fractal. Expecting 4 arguments.");
+ return;
+ }
+ lorenz -> h = (double) atom_getfloatarg(0, argc, argv);
+ lorenz -> a = (double) atom_getfloatarg(1, argc, argv);
+ lorenz -> b = (double) atom_getfloatarg(2, argc, argv);
+ lorenz -> c = (double) atom_getfloatarg(3, argc, argv);
+}
-void lorenz_setup(void)
-{
-
- post("lorenz");
+static void seed(lorenz_struct *lorenz, t_symbol *s, int argc, t_atom *argv) {
+ if (argc > 0) {
+ srand48(((unsigned int)time(0))|1);
+ } else {
+ srand48((unsigned int) atom_getfloatarg(0, argc, argv));
+ }
+}
- lorenz_class = class_new(gensym("lorenz"), /* symname is the symbolic name */
- (t_newmethod)lorenz_new, /* Constructor Function */
- 0, /* Destructor Function */
- sizeof(lorenz_struct), /* Size of the structure */
- CLASS_DEFAULT, /* Graphical Representation */
- 0); /* 0 Terminates Argument List */
+static void lyap(lorenz_struct *lorenz, t_floatarg l, t_floatarg h, t_floatarg lim) {
+ lorenz -> lyap_lo = l;
+ lorenz -> lyap_hi = h;
+ lorenz -> lyap_limit = (double) ((int) lim);
+}
- class_addbang(lorenz_class, (t_method)calculate);
-
- class_addmethod(lorenz_class,
- (t_method)reset,
- gensym("reset"),
- A_DEFFLOAT,
- A_DEFFLOAT,
- A_DEFFLOAT,
- 0);
-
- class_addmethod(lorenz_class,
- (t_method)param,
- gensym("param"),
- A_DEFFLOAT,
- A_DEFFLOAT,
- A_DEFFLOAT,
- A_DEFFLOAT,
- 0);
+static void elyap(lorenz_struct *lorenz) {
+ double results[M_var_count];
+ int i;
+ if (lyapunov_full((void *) lorenz, (t_gotfn) calc, M_var_count, lorenz -> vars, results) != NULL) {
+ post("elyapunov:");
+ for(i = 0; i < M_var_count; i++) { post("%d: %3.80f", i, results[i]); }
+ }
+}
+
+static void limiter(lorenz_struct *lorenz) {
+ if (lorenz -> h_lo < M_h_lo) { lorenz -> h_lo = M_h_lo; }
+ if (lorenz -> h_lo > M_h_hi) { lorenz -> h_lo = M_h_hi; }
+ if (lorenz -> h_hi < M_h_lo) { lorenz -> h_hi = M_h_lo; }
+ if (lorenz -> h_hi > M_h_hi) { lorenz -> h_hi = M_h_hi; }
+ if (lorenz -> a_lo < M_a_lo) { lorenz -> a_lo = M_a_lo; }
+ if (lorenz -> a_lo > M_a_hi) { lorenz -> a_lo = M_a_hi; }
+ if (lorenz -> a_hi < M_a_lo) { lorenz -> a_hi = M_a_lo; }
+ if (lorenz -> a_hi > M_a_hi) { lorenz -> a_hi = M_a_hi; }
+ if (lorenz -> b_lo < M_b_lo) { lorenz -> b_lo = M_b_lo; }
+ if (lorenz -> b_lo > M_b_hi) { lorenz -> b_lo = M_b_hi; }
+ if (lorenz -> b_hi < M_b_lo) { lorenz -> b_hi = M_b_lo; }
+ if (lorenz -> b_hi > M_b_hi) { lorenz -> b_hi = M_b_hi; }
+ if (lorenz -> c_lo < M_c_lo) { lorenz -> c_lo = M_c_lo; }
+ if (lorenz -> c_lo > M_c_hi) { lorenz -> c_lo = M_c_hi; }
+ if (lorenz -> c_hi < M_c_lo) { lorenz -> c_hi = M_c_lo; }
+ if (lorenz -> c_hi > M_c_hi) { lorenz -> c_hi = M_c_hi; }
+}
+
+static void constrain(lorenz_struct *lorenz, t_symbol *s, int argc, t_atom *argv) {
+ int i;
+ t_atom *arg = argv;
+ if (argc == 0) {
+ // reset to full limits of search ranges
+ lorenz -> h_lo = M_h_lo;
+ lorenz -> h_hi = M_h_hi;
+ lorenz -> a_lo = M_a_lo;
+ lorenz -> a_hi = M_a_hi;
+ lorenz -> b_lo = M_b_lo;
+ lorenz -> b_hi = M_b_hi;
+ lorenz -> c_lo = M_c_lo;
+ lorenz -> c_hi = M_c_hi;
+ return;
+ }
+ if (argc == 1) {
+ // set the ranges based on percentage of full range
+ double percent = atom_getfloat(arg);
+ double h_spread = ((M_h_hi - M_h_lo) * percent) / 2;
+ double a_spread = ((M_a_hi - M_a_lo) * percent) / 2;
+ double b_spread = ((M_b_hi - M_b_lo) * percent) / 2;
+ double c_spread = ((M_c_hi - M_c_lo) * percent) / 2;
+ lorenz -> h_lo = lorenz -> h - h_spread;
+ lorenz -> h_hi = lorenz -> h + h_spread;
+ lorenz -> a_lo = lorenz -> a - a_spread;
+ lorenz -> a_hi = lorenz -> a + a_spread;
+ lorenz -> b_lo = lorenz -> b - b_spread;
+ lorenz -> b_hi = lorenz -> b + b_spread;
+ lorenz -> c_lo = lorenz -> c - c_spread;
+ lorenz -> c_hi = lorenz -> c + c_spread;
+ limiter(lorenz);
+ return;
+ }
+ if (argc != M_param_count * 2) {
+ post("Invalid number of arguments for lorenz constraints, requires 8 values, got %d", argc);
+ return;
+ }
+ lorenz -> h_lo = atom_getfloat(arg++);
+ lorenz -> h_hi = atom_getfloat(arg++);
+ lorenz -> a_lo = atom_getfloat(arg++);
+ lorenz -> a_hi = atom_getfloat(arg++);
+ lorenz -> b_lo = atom_getfloat(arg++);
+ lorenz -> b_hi = atom_getfloat(arg++);
+ lorenz -> c_lo = atom_getfloat(arg++);
+ lorenz -> c_hi = atom_getfloat(arg++);
+ limiter(lorenz);
}
+
+static void search(lorenz_struct *lorenz, t_symbol *s, int argc, t_atom *argv) {
+ int not_found, not_expired = lorenz -> lyap_limit;
+ int jump, i, iterations;
+ t_atom vars[M_var_count];
+ double temp_h = lorenz -> h;
+ double temp_a = lorenz -> a;
+ double temp_b = lorenz -> b;
+ double temp_c = lorenz -> c;
+ if (argc > 0) {
+ for (i = 0; i < M_var_count; i++) {
+ SETFLOAT(&vars[i], atom_getfloatarg(i, argc, argv));
+ }
+ } else {
+ for (i = 0; i < M_var_count; i++) {
+ SETFLOAT(&vars[i], lorenz -> vars_init[i]);
+ }
+ }
+ do {
+ jump = 500;
+ not_found = 0;
+ iterations = 10000;
+ bad_params:
+ lorenz -> h = (drand48() * (lorenz -> h_hi - lorenz -> h_lo)) + lorenz -> h_lo;
+ lorenz -> a = (drand48() * (lorenz -> a_hi - lorenz -> a_lo)) + lorenz -> a_lo;
+ lorenz -> b = (drand48() * (lorenz -> b_hi - lorenz -> b_lo)) + lorenz -> b_lo;
+ lorenz -> c = (drand48() * (lorenz -> c_hi - lorenz -> c_lo)) + lorenz -> c_lo;
+ // put any preliminary checks specific to this fractal to eliminate bad_params
+
+ reset(lorenz, NULL, argc, vars);
+ do { calc(lorenz, lorenz -> vars); } while(jump--);
+ lorenz -> lyap_exp = lyapunov((void *) lorenz, (t_gotfn) calc, M_var_count, (double *) lorenz -> vars);
+ if (isnan(lorenz -> lyap_exp)) { not_found = 1; }
+ if (lorenz -> lyap_exp < lorenz -> lyap_lo || lorenz -> lyap_exp > lorenz -> lyap_hi) { not_found = 1; }
+ not_expired--;
+ } while(not_found && not_expired);
+ reset(lorenz, NULL, argc, vars);
+ if (!not_expired) {
+ post("Could not find a fractal after %d attempts.", (int) lorenz -> lyap_limit);
+ post("Try using wider constraints.");
+ lorenz -> h = temp_h;
+ lorenz -> a = temp_a;
+ lorenz -> b = temp_b;
+ lorenz -> c = temp_c;
+ outlet_anything(lorenz -> search_outlet, gensym("invalid"), 0, NULL);
+ } else {
+ lorenz -> failure_ratio = (lorenz -> lyap_limit - not_expired) / lorenz -> lyap_limit;
+ make_results(lorenz);
+ outlet_anything(lorenz -> search_outlet, gensym("search"), M_search_count, lorenz -> search_out);
+ }
+}
+
+void *lorenz_new(t_symbol *s, int argc, t_atom *argv) {
+ lorenz_struct *lorenz = (lorenz_struct *) pd_new(lorenz_class);
+ if (lorenz != NULL) {
+ outlet_new(&lorenz -> x_obj, &s_float);
+ lorenz -> outlets[0] = outlet_new(&lorenz -> x_obj, &s_float);
+ lorenz -> outlets[1] = outlet_new(&lorenz -> x_obj, &s_float);
+ lorenz -> search_outlet = outlet_new(&lorenz -> x_obj, &s_list);
+ lorenz -> vars_outlet = outlet_new(&lorenz -> x_obj, &s_list);
+ lorenz -> params_outlet = outlet_new(&lorenz -> x_obj, &s_list);
+ if (argc == M_param_count + M_var_count) {
+ lorenz -> vars_init[M_x] = lorenz -> vars[M_x] = (double) atom_getfloatarg(0, argc, argv);
+ lorenz -> vars_init[M_y] = lorenz -> vars[M_y] = (double) atom_getfloatarg(1, argc, argv);
+ lorenz -> vars_init[M_z] = lorenz -> vars[M_z] = (double) atom_getfloatarg(2, argc, argv);
+ lorenz -> h = (double) atom_getfloatarg(3, argc, argv);
+ lorenz -> a = (double) atom_getfloatarg(4, argc, argv);
+ lorenz -> b = (double) atom_getfloatarg(5, argc, argv);
+ lorenz -> c = (double) atom_getfloatarg(6, argc, argv);
+ } else {
+ if (argc != 0 && argc != M_param_count + M_var_count) {
+ post("Incorrect number of arguments for lorenz fractal. Expecting 7 arguments.");
+ }
+ lorenz -> vars_init[M_x] = 0.1;
+ lorenz -> vars_init[M_y] = 0;
+ lorenz -> vars_init[M_z] = 0;
+ lorenz -> h = 0.01;
+ lorenz -> a = 10;
+ lorenz -> b = 28;
+ lorenz -> c = 2.66667;
+ }
+ constrain(lorenz, NULL, 0, NULL);
+ lyap(lorenz, -1000000.0, 1000000.0, M_failure_limit);
+ }
+ return (void *)lorenz;
+}
+
+void lorenz_setup(void) {
+ lorenz_class = class_new(gensym("lorenz"), (t_newmethod) lorenz_new, 0, sizeof(lorenz_struct), 0, A_GIMME, 0);
+ class_addbang(lorenz_class, (t_method) calculate);
+ class_addmethod(lorenz_class, (t_method) reset, gensym("reset"), A_GIMME, 0);
+ class_addmethod(lorenz_class, (t_method) show, gensym("show"), 0);
+ class_addmethod(lorenz_class, (t_method) param, gensym("param"), A_GIMME, 0);
+ class_addmethod(lorenz_class, (t_method) seed, gensym("seed"), A_GIMME, 0);
+ class_addmethod(lorenz_class, (t_method) lyap, gensym("lyapunov"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(lorenz_class, (t_method) elyap, gensym("elyapunov"), 0);
+ class_addmethod(lorenz_class, (t_method) search, gensym("search"), A_GIMME, 0);
+ class_addmethod(lorenz_class, (t_method) constrain, gensym("constrain"), A_GIMME, 0);
+ class_sethelpsymbol(lorenz_class, gensym("help-lorenz.pd"));
+}
+
diff --git a/makefile b/makefile
index 4633d68..24f1e79 100644
--- a/makefile
+++ b/makefile
@@ -24,7 +24,7 @@ PDNTLIB = $(PDNTLDIR)\msvcrt.lib \
$(PDNTLDIR)\pthreadVC.lib \
c:\pd\bin\pd.lib
-PDNTEXTERNALS = lorenz.obj rossler.obj henon.obj ikeda.obj
+PDNTEXTERNALS = lyapunov.obj henon.obj hopalong.obj ikeda.obj latoocarfian.obj latoomutalpha.obj latoomutbeta.obj latoomutgamma.obj logistic.obj lorenz.obj mlogistic.obj rossler.obj standardmap.obj tent.obj three_d.obj
.c.dll:
cl $(PDNTCFLAGS) $(PDNTINCLUDE) /c *.c
@@ -43,14 +43,30 @@ DARWINCFLAGS = -DPD -DMAXLIB -DUNIX -DMACOSX -O2 \
# where is your m_pd.h ???
DARWININCLUDE = -I../../src -I../../obj
-DARWINEXTERNALS = lorenz.o rossler.o henon.o ikeda.o
+DARWINEXTERNALS = lyapunov.o attract1.o base.o base3.o dejong.o gingerbreadman.o henon.o hopalong.o ikeda.o latoocarfian.o latoomutalpha.o \
+latoomutbeta.o latoomutgamma.o logistic.o lorenz.o martin.o mlogistic.o pickover.o popcorn.o quadruptwo.o rossler.o standardmap.o \
+strange1.o tent.o three_d.o threeply.o tinkerbell.o unity.o lotka_volterra.o
-.c.pd_darwin:
+PD_LOCAL_EXTERNALS = $(HOME)/Library/Pd/Externals
+PD_LOCAL_HELP = $(HOME)/Library/Pd/Help
+PD_BINARY = /usr/local/pd/bin/pd
+MTARGET = $(NAME).pd_darwin
+MDARWININCLUDE = -I/usr/local/pd/src
+
+.c.o:
cc $(DARWINCFLAGS) $(DARWININCLUDE) -c *.c
- cc -bundle -undefined suppress -flat_namespace -o $*.pd_darwin $*.o $(DARWINEXTERNALS)
+
+.o.pd_darwin:
+ cc -bundle -bundle_loader $(PD_BINARY) -flat_namespace -o $*.pd_darwin $*.o $(DARWINEXTERNALS)
+
+pd_darwin: $(DARWINEXTERNALS)
rm -f $*.o ../$*.pd_darwin
ln -s $*/$*.pd_darwin ..
+minstall: $(MTARGET) $(DARWINEXTERNALS)
+ mv -f $(MTARGET) $(PD_LOCAL_EXTERNALS)
+ cp -f help-*.pd $(PD_LOCAL_HELP)
+
# ----------------------- LINUX i386 -----------------------
pd_linux: $(NAME).pd_linux
@@ -64,7 +80,9 @@ LINUXCFLAGS = -DPD -DUNIX -O2 -funroll-loops -fomit-frame-pointer \
# where is your m_pd.h ???
LINUXINCLUDE = -I/usr/local/include
-LINUXEXTERNALS = lorenz.o rossler.o henon.o ikeda.o
+LINUXEXTERNALS = lyapunov.o attract1.o base.o base3.o dejong.o gingerbreadman.o henon.o hopalong.o ikeda.o latoocarfian.o latoomutalpha.o \
+latoomutbeta.o latoomutgamma.o logistic.o lorenz.o martin.o mlogistic.o pickover.o popcorn.o quadruptwo.o rossler.o standardmap.o \
+strange1.o tent.o three_d.o threeply.o tinkerbell.o unity.o lotka_volterra.o
.c.pd_linux:
cc -O2 -Wall -DPD -fPIC $(LINUXCFLAGS) $(LINUXINCLUDE) -c *.c
diff --git a/rossler.c b/rossler.c
index 867a9e0..38217b0 100644
--- a/rossler.c
+++ b/rossler.c
@@ -1,8 +1,6 @@
-///////////////////////////////////////////////////////////////////////////////////
-/* Rossler's Attractor PD External */
-/* Copyright Ben Bogart 2002 */
-/* This program is distributed under the terms of the GNU General Public License */
-///////////////////////////////////////////////////////////////////////////////////
+/* rossler Attractor PD External */
+/* Copyright Ben Bogart, 2002 */
+/* This program is distributed under the params of the GNU Public License */
///////////////////////////////////////////////////////////////////////////////////
/* This file is part of Chaos PD Externals. */
@@ -22,104 +20,316 @@
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
///////////////////////////////////////////////////////////////////////////////////
-#include "m_pd.h"
+#include <stdio.h>
+#include <stdlib.h>
#include <math.h>
+#include <time.h>
+#include "lyapunov.h"
+
+#define M_h_lo -1000
+#define M_h_hi 1000
+#define M_a_lo -1000
+#define M_a_hi 1000
+#define M_b_lo -1000
+#define M_b_hi 1000
+#define M_c_lo -1000
+#define M_c_hi 1000
+
+#define M_h 0
+#define M_a 1
+#define M_b 2
+#define M_c 3
+
+#define M_x 0
+#define M_y 1
+#define M_z 2
+
+#define M_param_count 4
+#define M_var_count 3
+#define M_search_count 3
+#define M_failure_limit 1000
+
+static char *version = "rossler v0.0, by Ben Bogart, 2002";
t_class *rossler_class;
-typedef struct rossler_struct
-{
- t_object myobj;
- double h,a,b,c,lx0,ly0,lz0;
- t_outlet *y_outlet;
- t_outlet *z_outlet;
-} rossler_struct;
-
-static void calculate(rossler_struct *x)
-{
- double lx0,ly0,lz0,lx1,ly1,lz1;
- double h,a,b,c;
-
- h = x->h;
- a = x->a;
- b = x->b;
- c = x->c;
- lx0 = x->lx0;
- ly0 = x->ly0;
- lz0 = x->lz0;
-
- lx1 = lx0 + h * (-ly0 - lz0);
- ly1 = ly0 + h * (lx0 + (a * ly0));
- lz1 = lz0 + h * (b + (lx0*lz0) - (c * lz0));;
- x->lx0 = lx1;
- x->ly0 = ly1;
- x->lz0 = lz1;
-
- outlet_float(x->myobj.ob_outlet, (t_float)lx1);
- outlet_float(x->y_outlet, (t_float)ly1);
- outlet_float(x->z_outlet, (t_float)lz1);
+typedef struct rossler_struct {
+ t_object x_obj;
+
+ double vars[M_var_count];
+ double vars_init[M_var_count];
+ t_atom vars_out[M_var_count];
+ t_outlet *vars_outlet;
+
+ t_atom search_out[M_search_count];
+ t_outlet *search_outlet;
+
+ double h, h_lo, h_hi, a, a_lo, a_hi, b, b_lo, b_hi, c, c_lo, c_hi;
+ t_atom params_out[M_param_count];
+ t_outlet *params_outlet;
+ double lyap_exp, lyap_lo, lyap_hi, lyap_limit, failure_ratio;
+
+ t_outlet *outlets[M_var_count - 1];
+} rossler_struct;
+
+static void calc(rossler_struct *rossler, double *vars) {
+ double x_0, y_0, z_0;
+ x_0 =vars[M_x]+rossler -> h*(-vars[M_y]-vars[M_z]);
+ y_0 =vars[M_y]+rossler -> h*(vars[M_x]+(rossler -> a*vars[M_y]));
+ z_0 =vars[M_z]+rossler -> h*(rossler -> b+(vars[M_x]*vars[M_z])-(rossler -> c*vars[M_z]));
+ vars[M_x] = x_0;
+ vars[M_y] = y_0;
+ vars[M_z] = z_0;
+} // end calc
+
+static void calculate(rossler_struct *rossler) {
+ calc(rossler, rossler -> vars);
+ outlet_float(rossler -> x_obj.ob_outlet, rossler -> vars[M_x]);
+ outlet_float(rossler -> outlets[M_y - 1], rossler -> vars[M_y]);
+ outlet_float(rossler -> outlets[M_z - 1], rossler -> vars[M_z]);
+} // end calculate
+
+static void reset(rossler_struct *rossler, t_symbol *s, int argc, t_atom *argv) {
+ if (argc == M_var_count) {
+ rossler -> vars[M_x] = (double) atom_getfloatarg(M_x, argc, argv);
+ rossler -> vars[M_y] = (double) atom_getfloatarg(M_y, argc, argv);
+ rossler -> vars[M_z] = (double) atom_getfloatarg(M_z, argc, argv);
+ } else {
+ rossler -> vars[M_x] = rossler -> vars_init[M_x];
+ rossler -> vars[M_y] = rossler -> vars_init[M_y];
+ rossler -> vars[M_z] = rossler -> vars_init[M_z];
+ } // end if
+} // end reset
+
+static char *classify(rossler_struct *rossler) {
+ static char buff[5];
+ char *c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ buff[0] = c[(int) (((rossler -> h - M_h_lo) * (1.0 / (M_h_hi - M_h_lo))) * 26)];
+ buff[1] = c[(int) (((rossler -> a - M_a_lo) * (1.0 / (M_a_hi - M_a_lo))) * 26)];
+ buff[2] = c[(int) (((rossler -> b - M_b_lo) * (1.0 / (M_b_hi - M_b_lo))) * 26)];
+ buff[3] = c[(int) (((rossler -> c - M_c_lo) * (1.0 / (M_c_hi - M_c_lo))) * 26)];
+ buff[4] = '\0';
+ return buff;
}
-static void reset(rossler_struct *x, t_floatarg lx0, t_floatarg ly0, t_floatarg lz0)
-{
- x->lx0 = lx0;
- x->ly0 = ly0;
- x->lz0 = lz0;
+static void make_results(rossler_struct *rossler) {
+ SETFLOAT(&rossler -> search_out[0], rossler -> lyap_exp);
+ SETSYMBOL(&rossler -> search_out[1], gensym(classify(rossler)));
+ SETFLOAT(&rossler -> search_out[2], rossler -> failure_ratio);
+ SETFLOAT(&rossler -> vars_out[M_x], rossler -> vars[M_x]);
+ SETFLOAT(&rossler -> vars_out[M_y], rossler -> vars[M_y]);
+ SETFLOAT(&rossler -> vars_out[M_z], rossler -> vars[M_z]);
+ SETFLOAT(&rossler -> params_out[M_h], rossler -> h);
+ SETFLOAT(&rossler -> params_out[M_a], rossler -> a);
+ SETFLOAT(&rossler -> params_out[M_b], rossler -> b);
+ SETFLOAT(&rossler -> params_out[M_c], rossler -> c);
+ outlet_list(rossler -> params_outlet, gensym("list"), M_param_count, rossler -> params_out);
+ outlet_list(rossler -> vars_outlet, gensym("list"), M_var_count, rossler -> vars_out);
}
-static void param(rossler_struct *x, t_floatarg h, t_floatarg a, t_floatarg b, t_floatarg c)
-{
- x->h = (double)h;
- x->a = (double)a;
- x->b = (double)b;
- x->c = (double)c;
+static void show(rossler_struct *rossler) {
+ make_results(rossler);
+ outlet_anything(rossler -> search_outlet, gensym("show"), M_search_count, rossler -> search_out);
}
-void *rossler_new(void)
-{
- rossler_struct *x = (rossler_struct *)pd_new(rossler_class);
- x->h = 0.01;
- x->a = 0.2;
- x->b = 0.2;
- x->c = 5.7;
- x->lx0 = 0.1;
- x->ly0 = 0;
- x->lz0 = 0;
-
- outlet_new(&x->myobj, &s_float); /* Default float outlet */
- x->y_outlet = outlet_new(&x->myobj, &s_float); /* Two new Outlets */
- x->z_outlet = outlet_new(&x->myobj, &s_float);
- return (void *)x;
+static void param(rossler_struct *rossler, t_symbol *s, int argc, t_atom *argv) {
+ if (argc != 4) {
+ post("Incorrect number of arguments for rossler fractal. Expecting 4 arguments.");
+ return;
+ }
+ rossler -> h = (double) atom_getfloatarg(0, argc, argv);
+ rossler -> a = (double) atom_getfloatarg(1, argc, argv);
+ rossler -> b = (double) atom_getfloatarg(2, argc, argv);
+ rossler -> c = (double) atom_getfloatarg(3, argc, argv);
}
+static void seed(rossler_struct *rossler, t_symbol *s, int argc, t_atom *argv) {
+ if (argc > 0) {
+ srand48(((unsigned int)time(0))|1);
+ } else {
+ srand48((unsigned int) atom_getfloatarg(0, argc, argv));
+ }
+}
-void rossler_setup(void)
-{
- post("rossler");
-
- rossler_class = class_new(gensym("rossler"), /* symname is the symbolic name */
- (t_newmethod)rossler_new, /* Constructor Function */
- 0, /* Destructor Function */
- sizeof(rossler_struct), /* Size of the structure */
- CLASS_DEFAULT, /* Graphical Representation */
- 0); /* 0 Terminates Argument List */
-
- class_addbang(rossler_class, (t_method)calculate);
-
- class_addmethod(rossler_class,
- (t_method)reset,
- gensym("reset"),
- A_DEFFLOAT,
- A_DEFFLOAT,
- A_DEFFLOAT,
- 0);
-
- class_addmethod(rossler_class,
- (t_method)param,
- gensym("param"),
- A_DEFFLOAT,
- A_DEFFLOAT,
- A_DEFFLOAT,
- A_DEFFLOAT,
- 0);
+static void lyap(rossler_struct *rossler, t_floatarg l, t_floatarg h, t_floatarg lim) {
+ rossler -> lyap_lo = l;
+ rossler -> lyap_hi = h;
+ rossler -> lyap_limit = (double) ((int) lim);
}
+
+static void elyap(rossler_struct *rossler) {
+ double results[M_var_count];
+ int i;
+ if (lyapunov_full((void *) rossler, (t_gotfn) calc, M_var_count, rossler -> vars, results) != NULL) {
+ post("elyapunov:");
+ for(i = 0; i < M_var_count; i++) { post("%d: %3.80f", i, results[i]); }
+ }
+}
+
+static void limiter(rossler_struct *rossler) {
+ if (rossler -> h_lo < M_h_lo) { rossler -> h_lo = M_h_lo; }
+ if (rossler -> h_lo > M_h_hi) { rossler -> h_lo = M_h_hi; }
+ if (rossler -> h_hi < M_h_lo) { rossler -> h_hi = M_h_lo; }
+ if (rossler -> h_hi > M_h_hi) { rossler -> h_hi = M_h_hi; }
+ if (rossler -> a_lo < M_a_lo) { rossler -> a_lo = M_a_lo; }
+ if (rossler -> a_lo > M_a_hi) { rossler -> a_lo = M_a_hi; }
+ if (rossler -> a_hi < M_a_lo) { rossler -> a_hi = M_a_lo; }
+ if (rossler -> a_hi > M_a_hi) { rossler -> a_hi = M_a_hi; }
+ if (rossler -> b_lo < M_b_lo) { rossler -> b_lo = M_b_lo; }
+ if (rossler -> b_lo > M_b_hi) { rossler -> b_lo = M_b_hi; }
+ if (rossler -> b_hi < M_b_lo) { rossler -> b_hi = M_b_lo; }
+ if (rossler -> b_hi > M_b_hi) { rossler -> b_hi = M_b_hi; }
+ if (rossler -> c_lo < M_c_lo) { rossler -> c_lo = M_c_lo; }
+ if (rossler -> c_lo > M_c_hi) { rossler -> c_lo = M_c_hi; }
+ if (rossler -> c_hi < M_c_lo) { rossler -> c_hi = M_c_lo; }
+ if (rossler -> c_hi > M_c_hi) { rossler -> c_hi = M_c_hi; }
+}
+
+static void constrain(rossler_struct *rossler, t_symbol *s, int argc, t_atom *argv) {
+ int i;
+ t_atom *arg = argv;
+ if (argc == 0) {
+ // reset to full limits of search ranges
+ rossler -> h_lo = M_h_lo;
+ rossler -> h_hi = M_h_hi;
+ rossler -> a_lo = M_a_lo;
+ rossler -> a_hi = M_a_hi;
+ rossler -> b_lo = M_b_lo;
+ rossler -> b_hi = M_b_hi;
+ rossler -> c_lo = M_c_lo;
+ rossler -> c_hi = M_c_hi;
+ return;
+ }
+ if (argc == 1) {
+ // set the ranges based on percentage of full range
+ double percent = atom_getfloat(arg);
+ double h_spread = ((M_h_hi - M_h_lo) * percent) / 2;
+ double a_spread = ((M_a_hi - M_a_lo) * percent) / 2;
+ double b_spread = ((M_b_hi - M_b_lo) * percent) / 2;
+ double c_spread = ((M_c_hi - M_c_lo) * percent) / 2;
+ rossler -> h_lo = rossler -> h - h_spread;
+ rossler -> h_hi = rossler -> h + h_spread;
+ rossler -> a_lo = rossler -> a - a_spread;
+ rossler -> a_hi = rossler -> a + a_spread;
+ rossler -> b_lo = rossler -> b - b_spread;
+ rossler -> b_hi = rossler -> b + b_spread;
+ rossler -> c_lo = rossler -> c - c_spread;
+ rossler -> c_hi = rossler -> c + c_spread;
+ limiter(rossler);
+ return;
+ }
+ if (argc != M_param_count * 2) {
+ post("Invalid number of arguments for rossler constraints, requires 8 values, got %d", argc);
+ return;
+ }
+ rossler -> h_lo = atom_getfloat(arg++);
+ rossler -> h_hi = atom_getfloat(arg++);
+ rossler -> a_lo = atom_getfloat(arg++);
+ rossler -> a_hi = atom_getfloat(arg++);
+ rossler -> b_lo = atom_getfloat(arg++);
+ rossler -> b_hi = atom_getfloat(arg++);
+ rossler -> c_lo = atom_getfloat(arg++);
+ rossler -> c_hi = atom_getfloat(arg++);
+ limiter(rossler);
+}
+
+static void search(rossler_struct *rossler, t_symbol *s, int argc, t_atom *argv) {
+ int not_found, not_expired = rossler -> lyap_limit;
+ int jump, i, iterations;
+ t_atom vars[M_var_count];
+ double temp_h = rossler -> h;
+ double temp_a = rossler -> a;
+ double temp_b = rossler -> b;
+ double temp_c = rossler -> c;
+ if (argc > 0) {
+ for (i = 0; i < M_var_count; i++) {
+ SETFLOAT(&vars[i], atom_getfloatarg(i, argc, argv));
+ }
+ } else {
+ for (i = 0; i < M_var_count; i++) {
+ SETFLOAT(&vars[i], rossler -> vars_init[i]);
+ }
+ }
+ do {
+ jump = 500;
+ not_found = 0;
+ iterations = 10000;
+ bad_params:
+ rossler -> h = (drand48() * (rossler -> h_hi - rossler -> h_lo)) + rossler -> h_lo;
+ rossler -> a = (drand48() * (rossler -> a_hi - rossler -> a_lo)) + rossler -> a_lo;
+ rossler -> b = (drand48() * (rossler -> b_hi - rossler -> b_lo)) + rossler -> b_lo;
+ rossler -> c = (drand48() * (rossler -> c_hi - rossler -> c_lo)) + rossler -> c_lo;
+ // put any preliminary checks specific to this fractal to eliminate bad_params
+
+ reset(rossler, NULL, argc, vars);
+ do { calc(rossler, rossler -> vars); } while(jump--);
+ rossler -> lyap_exp = lyapunov((void *) rossler, (t_gotfn) calc, M_var_count, (double *) rossler -> vars);
+ if (isnan(rossler -> lyap_exp)) { not_found = 1; }
+ if (rossler -> lyap_exp < rossler -> lyap_lo || rossler -> lyap_exp > rossler -> lyap_hi) { not_found = 1; }
+ not_expired--;
+ } while(not_found && not_expired);
+ reset(rossler, NULL, argc, vars);
+ if (!not_expired) {
+ post("Could not find a fractal after %d attempts.", (int) rossler -> lyap_limit);
+ post("Try using wider constraints.");
+ rossler -> h = temp_h;
+ rossler -> a = temp_a;
+ rossler -> b = temp_b;
+ rossler -> c = temp_c;
+ outlet_anything(rossler -> search_outlet, gensym("invalid"), 0, NULL);
+ } else {
+ rossler -> failure_ratio = (rossler -> lyap_limit - not_expired) / rossler -> lyap_limit;
+ make_results(rossler);
+ outlet_anything(rossler -> search_outlet, gensym("search"), M_search_count, rossler -> search_out);
+ }
+}
+
+void *rossler_new(t_symbol *s, int argc, t_atom *argv) {
+ rossler_struct *rossler = (rossler_struct *) pd_new(rossler_class);
+ if (rossler != NULL) {
+ outlet_new(&rossler -> x_obj, &s_float);
+ rossler -> outlets[0] = outlet_new(&rossler -> x_obj, &s_float);
+ rossler -> outlets[1] = outlet_new(&rossler -> x_obj, &s_float);
+ rossler -> search_outlet = outlet_new(&rossler -> x_obj, &s_list);
+ rossler -> vars_outlet = outlet_new(&rossler -> x_obj, &s_list);
+ rossler -> params_outlet = outlet_new(&rossler -> x_obj, &s_list);
+ if (argc == M_param_count + M_var_count) {
+ rossler -> vars_init[M_x] = rossler -> vars[M_x] = (double) atom_getfloatarg(0, argc, argv);
+ rossler -> vars_init[M_y] = rossler -> vars[M_y] = (double) atom_getfloatarg(1, argc, argv);
+ rossler -> vars_init[M_z] = rossler -> vars[M_z] = (double) atom_getfloatarg(2, argc, argv);
+ rossler -> h = (double) atom_getfloatarg(3, argc, argv);
+ rossler -> a = (double) atom_getfloatarg(4, argc, argv);
+ rossler -> b = (double) atom_getfloatarg(5, argc, argv);
+ rossler -> c = (double) atom_getfloatarg(6, argc, argv);
+ } else {
+ if (argc != 0 && argc != M_param_count + M_var_count) {
+ post("Incorrect number of arguments for rossler fractal. Expecting 7 arguments.");
+ }
+ rossler -> vars_init[M_x] = 0.1;
+ rossler -> vars_init[M_y] = 0;
+ rossler -> vars_init[M_z] = 0;
+ rossler -> h = 0.01;
+ rossler -> a = 0.2;
+ rossler -> b = 0.2;
+ rossler -> c = 5.7;
+ }
+ constrain(rossler, NULL, 0, NULL);
+ lyap(rossler, -1000000.0, 1000000.0, M_failure_limit);
+ }
+ return (void *)rossler;
+}
+
+void rossler_setup(void) {
+ rossler_class = class_new(gensym("rossler"), (t_newmethod) rossler_new, 0, sizeof(rossler_struct), 0, A_GIMME, 0);
+ class_addbang(rossler_class, (t_method) calculate);
+ class_addmethod(rossler_class, (t_method) reset, gensym("reset"), A_GIMME, 0);
+ class_addmethod(rossler_class, (t_method) show, gensym("show"), 0);
+ class_addmethod(rossler_class, (t_method) param, gensym("param"), A_GIMME, 0);
+ class_addmethod(rossler_class, (t_method) seed, gensym("seed"), A_GIMME, 0);
+ class_addmethod(rossler_class, (t_method) lyap, gensym("lyapunov"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(rossler_class, (t_method) elyap, gensym("elyapunov"), 0);
+ class_addmethod(rossler_class, (t_method) search, gensym("search"), A_GIMME, 0);
+ class_addmethod(rossler_class, (t_method) constrain, gensym("constrain"), A_GIMME, 0);
+ class_sethelpsymbol(rossler_class, gensym("help-rossler.pd"));
+}
+