aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorB. Bogart <bbogart@users.sourceforge.net>2003-09-30 16:04:40 +0000
committerB. Bogart <bbogart@users.sourceforge.net>2003-09-30 16:04:40 +0000
commit705f8dee50e2073a3aba60b03e5c9b86672abd4c (patch)
treeb3ec18787ac0687df3f2de109eff4d840a679996
parent8890d81285fc713353a00d7d149fb02e6b00b3b5 (diff)
Opps - forgot to add the files that did not exist in chaosI!
svn path=/trunk/externals/bbogart/chaos/; revision=1052
-rw-r--r--attract1.c369
-rw-r--r--base.c269
-rw-r--r--base3.c269
-rw-r--r--dejong.c325
-rw-r--r--gingerbreadman.c101
-rw-r--r--hopalong.c303
-rw-r--r--latoocarfian.c325
-rw-r--r--latoomutalpha.c325
-rw-r--r--latoomutbeta.c325
-rw-r--r--latoomutgamma.c325
-rw-r--r--mlogistic.c247
-rw-r--r--pickover.c335
-rw-r--r--popcorn.c259
-rw-r--r--quadruptwo.c303
-rw-r--r--standardmap.c259
-rw-r--r--strange1.c501
-rw-r--r--tent.c247
-rw-r--r--three_d.c357
-rw-r--r--threeply.c303
-rw-r--r--tinkerbell.c325
-rw-r--r--tools/fractal-tools.pd27
-rw-r--r--tools/help-attract1.pd35
-rw-r--r--tools/help-base.pd28
-rw-r--r--tools/help-gingerbreadman.pd31
-rw-r--r--tools/help-henon.pd30
-rw-r--r--tools/help-hopalong.pd32
-rw-r--r--tools/help-ikeda.pd33
-rw-r--r--tools/help-latoocarfian.pd35
-rw-r--r--tools/help-latoomutalpha.pd35
-rw-r--r--tools/help-latoomutbeta.pd35
-rw-r--r--tools/help-latoomutgamma.pd35
-rw-r--r--tools/help-lorenz.pd32
-rw-r--r--tools/help-martin-test.pd92
-rw-r--r--tools/help-martin.pd38
-rw-r--r--tools/help-popcorn-test.pd62
-rw-r--r--tools/help-popcorn.pd35
-rw-r--r--tools/help-quaruptwo-test.pd69
-rw-r--r--tools/help-quaruptwo.pd32
-rw-r--r--tools/help-standardmap.pd32
-rw-r--r--tools/loop.pd43
-rw-r--r--tools/readme-frac-format.pd22
-rw-r--r--tools/readme-fractals.pd54
-rw-r--r--tools/readme-gen-fractal.pd6
-rw-r--r--tools/readme-lyapunov.pd16
-rw-r--r--tools/readme-operation.pd34
-rw-r--r--tools/readme-parameter-ranges.pd23
-rw-r--r--tools/readme-searching.pd101
-rw-r--r--tools/search-tools.pd186
-rw-r--r--unity.c102
49 files changed, 7407 insertions, 0 deletions
diff --git a/attract1.c b/attract1.c
new file mode 100644
index 0000000..dc1f4c1
--- /dev/null
+++ b/attract1.c
@@ -0,0 +1,369 @@
+/* attract1 Attractor PD External */
+/* Copyright Michael McGonagle, from 'attract.java' by Julian Sprott, 2003 */
+/* This program is distributed under the params of the GNU Public License */
+
+///////////////////////////////////////////////////////////////////////////////////
+/* This file is part of Chaos PD Externals. */
+/* */
+/* Chaos PD Externals are free software; you can redistribute them and/or modify */
+/* them under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* Chaos PD Externals are distributed in the hope that they will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with the Chaos PD Externals; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+///////////////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#include "lyapunov.h"
+
+#define M_a0_lo -3
+#define M_a0_hi 3
+#define M_a1_lo -3
+#define M_a1_hi 3
+#define M_a2_lo -3
+#define M_a2_hi 3
+#define M_a3_lo -3
+#define M_a3_hi 3
+#define M_a4_lo -3
+#define M_a4_hi 3
+#define M_a5_lo -3
+#define M_a5_hi 3
+
+#define M_a0 0
+#define M_a1 1
+#define M_a2 2
+#define M_a3 3
+#define M_a4 4
+#define M_a5 5
+
+#define M_x 0
+#define M_y 1
+
+#define M_param_count 6
+#define M_var_count 2
+#define M_search_count 3
+#define M_failure_limit 1000
+
+static char *version = "attract1 v0.0, by Michael McGonagle, from 'attract.java' by Julian Sprott, 2003";
+
+t_class *attract1_class;
+
+typedef struct attract1_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 a0, a0_lo, a0_hi, a1, a1_lo, a1_hi, a2, a2_lo, a2_hi, a3, a3_lo, a3_hi, a4, a4_lo, a4_hi, a5, a5_lo, a5_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];
+} attract1_struct;
+
+static void calc(attract1_struct *attract1, double *vars) {
+ double x_0, y_0;
+ x_0 =attract1 -> a0+vars[M_x]*(attract1 -> a1+attract1 -> a2*vars[M_x]+attract1 -> a3*vars[M_y])+vars[M_y]*(attract1 -> a4+attract1 -> a5*vars[M_y]);
+ y_0 =vars[M_x];
+ vars[M_x] = x_0;
+ vars[M_y] = y_0;
+} // end calc
+
+static void calculate(attract1_struct *attract1) {
+ calc(attract1, attract1 -> vars);
+ outlet_float(attract1 -> x_obj.ob_outlet, attract1 -> vars[M_x]);
+ outlet_float(attract1 -> outlets[M_y - 1], attract1 -> vars[M_y]);
+} // end calculate
+
+static void reset(attract1_struct *attract1, t_symbol *s, int argc, t_atom *argv) {
+ if (argc == M_var_count) {
+ attract1 -> vars[M_x] = (double) atom_getfloatarg(M_x, argc, argv);
+ attract1 -> vars[M_y] = (double) atom_getfloatarg(M_y, argc, argv);
+ } else {
+ attract1 -> vars[M_x] = attract1 -> vars_init[M_x];
+ attract1 -> vars[M_y] = attract1 -> vars_init[M_y];
+ } // end if
+} // end reset
+
+static char *classify(attract1_struct *attract1) {
+ static char buff[7];
+ char *c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ buff[0] = c[(int) (((attract1 -> a0 - M_a0_lo) * (1.0 / (M_a0_hi - M_a0_lo))) * 26)];
+ buff[1] = c[(int) (((attract1 -> a1 - M_a1_lo) * (1.0 / (M_a1_hi - M_a1_lo))) * 26)];
+ buff[2] = c[(int) (((attract1 -> a2 - M_a2_lo) * (1.0 / (M_a2_hi - M_a2_lo))) * 26)];
+ buff[3] = c[(int) (((attract1 -> a3 - M_a3_lo) * (1.0 / (M_a3_hi - M_a3_lo))) * 26)];
+ buff[4] = c[(int) (((attract1 -> a4 - M_a4_lo) * (1.0 / (M_a4_hi - M_a4_lo))) * 26)];
+ buff[5] = c[(int) (((attract1 -> a5 - M_a5_lo) * (1.0 / (M_a5_hi - M_a5_lo))) * 26)];
+ buff[6] = '\0';
+ return buff;
+}
+
+static void make_results(attract1_struct *attract1) {
+ SETFLOAT(&attract1 -> search_out[0], attract1 -> lyap_exp);
+ SETSYMBOL(&attract1 -> search_out[1], gensym(classify(attract1)));
+ SETFLOAT(&attract1 -> search_out[2], attract1 -> failure_ratio);
+ SETFLOAT(&attract1 -> vars_out[M_x], attract1 -> vars[M_x]);
+ SETFLOAT(&attract1 -> vars_out[M_y], attract1 -> vars[M_y]);
+ SETFLOAT(&attract1 -> params_out[M_a0], attract1 -> a0);
+ SETFLOAT(&attract1 -> params_out[M_a1], attract1 -> a1);
+ SETFLOAT(&attract1 -> params_out[M_a2], attract1 -> a2);
+ SETFLOAT(&attract1 -> params_out[M_a3], attract1 -> a3);
+ SETFLOAT(&attract1 -> params_out[M_a4], attract1 -> a4);
+ SETFLOAT(&attract1 -> params_out[M_a5], attract1 -> a5);
+ outlet_list(attract1 -> params_outlet, gensym("list"), M_param_count, attract1 -> params_out);
+ outlet_list(attract1 -> vars_outlet, gensym("list"), M_var_count, attract1 -> vars_out);
+}
+
+static void show(attract1_struct *attract1) {
+ make_results(attract1);
+ outlet_anything(attract1 -> search_outlet, gensym("show"), M_search_count, attract1 -> search_out);
+}
+
+static void param(attract1_struct *attract1, t_symbol *s, int argc, t_atom *argv) {
+ if (argc != 6) {
+ post("Incorrect number of arguments for attract1 fractal. Expecting 6 arguments.");
+ return;
+ }
+ attract1 -> a0 = (double) atom_getfloatarg(0, argc, argv);
+ attract1 -> a1 = (double) atom_getfloatarg(1, argc, argv);
+ attract1 -> a2 = (double) atom_getfloatarg(2, argc, argv);
+ attract1 -> a3 = (double) atom_getfloatarg(3, argc, argv);
+ attract1 -> a4 = (double) atom_getfloatarg(4, argc, argv);
+ attract1 -> a5 = (double) atom_getfloatarg(5, argc, argv);
+}
+
+static void seed(attract1_struct *attract1, 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(attract1_struct *attract1, t_floatarg l, t_floatarg h, t_floatarg lim) {
+ attract1 -> lyap_lo = l;
+ attract1 -> lyap_hi = h;
+ attract1 -> lyap_limit = (double) ((int) lim);
+}
+
+static void elyap(attract1_struct *attract1) {
+ double results[M_var_count];
+ int i;
+ if (lyapunov_full((void *) attract1, (t_gotfn) calc, M_var_count, attract1 -> vars, results) != NULL) {
+ post("elyapunov:");
+ for(i = 0; i < M_var_count; i++) { post("%d: %3.80f", i, results[i]); }
+ }
+}
+
+static void limiter(attract1_struct *attract1) {
+ if (attract1 -> a0_lo < M_a0_lo) { attract1 -> a0_lo = M_a0_lo; }
+ if (attract1 -> a0_lo > M_a0_hi) { attract1 -> a0_lo = M_a0_hi; }
+ if (attract1 -> a0_hi < M_a0_lo) { attract1 -> a0_hi = M_a0_lo; }
+ if (attract1 -> a0_hi > M_a0_hi) { attract1 -> a0_hi = M_a0_hi; }
+ if (attract1 -> a1_lo < M_a1_lo) { attract1 -> a1_lo = M_a1_lo; }
+ if (attract1 -> a1_lo > M_a1_hi) { attract1 -> a1_lo = M_a1_hi; }
+ if (attract1 -> a1_hi < M_a1_lo) { attract1 -> a1_hi = M_a1_lo; }
+ if (attract1 -> a1_hi > M_a1_hi) { attract1 -> a1_hi = M_a1_hi; }
+ if (attract1 -> a2_lo < M_a2_lo) { attract1 -> a2_lo = M_a2_lo; }
+ if (attract1 -> a2_lo > M_a2_hi) { attract1 -> a2_lo = M_a2_hi; }
+ if (attract1 -> a2_hi < M_a2_lo) { attract1 -> a2_hi = M_a2_lo; }
+ if (attract1 -> a2_hi > M_a2_hi) { attract1 -> a2_hi = M_a2_hi; }
+ if (attract1 -> a3_lo < M_a3_lo) { attract1 -> a3_lo = M_a3_lo; }
+ if (attract1 -> a3_lo > M_a3_hi) { attract1 -> a3_lo = M_a3_hi; }
+ if (attract1 -> a3_hi < M_a3_lo) { attract1 -> a3_hi = M_a3_lo; }
+ if (attract1 -> a3_hi > M_a3_hi) { attract1 -> a3_hi = M_a3_hi; }
+ if (attract1 -> a4_lo < M_a4_lo) { attract1 -> a4_lo = M_a4_lo; }
+ if (attract1 -> a4_lo > M_a4_hi) { attract1 -> a4_lo = M_a4_hi; }
+ if (attract1 -> a4_hi < M_a4_lo) { attract1 -> a4_hi = M_a4_lo; }
+ if (attract1 -> a4_hi > M_a4_hi) { attract1 -> a4_hi = M_a4_hi; }
+ if (attract1 -> a5_lo < M_a5_lo) { attract1 -> a5_lo = M_a5_lo; }
+ if (attract1 -> a5_lo > M_a5_hi) { attract1 -> a5_lo = M_a5_hi; }
+ if (attract1 -> a5_hi < M_a5_lo) { attract1 -> a5_hi = M_a5_lo; }
+ if (attract1 -> a5_hi > M_a5_hi) { attract1 -> a5_hi = M_a5_hi; }
+}
+
+static void constrain(attract1_struct *attract1, t_symbol *s, int argc, t_atom *argv) {
+ int i;
+ t_atom *arg = argv;
+ if (argc == 0) {
+ // reset to full limits of search ranges
+ attract1 -> a0_lo = M_a0_lo;
+ attract1 -> a0_hi = M_a0_hi;
+ attract1 -> a1_lo = M_a1_lo;
+ attract1 -> a1_hi = M_a1_hi;
+ attract1 -> a2_lo = M_a2_lo;
+ attract1 -> a2_hi = M_a2_hi;
+ attract1 -> a3_lo = M_a3_lo;
+ attract1 -> a3_hi = M_a3_hi;
+ attract1 -> a4_lo = M_a4_lo;
+ attract1 -> a4_hi = M_a4_hi;
+ attract1 -> a5_lo = M_a5_lo;
+ attract1 -> a5_hi = M_a5_hi;
+ return;
+ }
+ if (argc == 1) {
+ // set the ranges based on percentage of full range
+ double percent = atom_getfloat(arg);
+ double a0_spread = ((M_a0_hi - M_a0_lo) * percent) / 2;
+ double a1_spread = ((M_a1_hi - M_a1_lo) * percent) / 2;
+ double a2_spread = ((M_a2_hi - M_a2_lo) * percent) / 2;
+ double a3_spread = ((M_a3_hi - M_a3_lo) * percent) / 2;
+ double a4_spread = ((M_a4_hi - M_a4_lo) * percent) / 2;
+ double a5_spread = ((M_a5_hi - M_a5_lo) * percent) / 2;
+ attract1 -> a0_lo = attract1 -> a0 - a0_spread;
+ attract1 -> a0_hi = attract1 -> a0 + a0_spread;
+ attract1 -> a1_lo = attract1 -> a1 - a1_spread;
+ attract1 -> a1_hi = attract1 -> a1 + a1_spread;
+ attract1 -> a2_lo = attract1 -> a2 - a2_spread;
+ attract1 -> a2_hi = attract1 -> a2 + a2_spread;
+ attract1 -> a3_lo = attract1 -> a3 - a3_spread;
+ attract1 -> a3_hi = attract1 -> a3 + a3_spread;
+ attract1 -> a4_lo = attract1 -> a4 - a4_spread;
+ attract1 -> a4_hi = attract1 -> a4 + a4_spread;
+ attract1 -> a5_lo = attract1 -> a5 - a5_spread;
+ attract1 -> a5_hi = attract1 -> a5 + a5_spread;
+ limiter(attract1);
+ return;
+ }
+ if (argc != M_param_count * 2) {
+ post("Invalid number of arguments for attract1 constraints, requires 12 values, got %d", argc);
+ return;
+ }
+ attract1 -> a0_lo = atom_getfloat(arg++);
+ attract1 -> a0_hi = atom_getfloat(arg++);
+ attract1 -> a1_lo = atom_getfloat(arg++);
+ attract1 -> a1_hi = atom_getfloat(arg++);
+ attract1 -> a2_lo = atom_getfloat(arg++);
+ attract1 -> a2_hi = atom_getfloat(arg++);
+ attract1 -> a3_lo = atom_getfloat(arg++);
+ attract1 -> a3_hi = atom_getfloat(arg++);
+ attract1 -> a4_lo = atom_getfloat(arg++);
+ attract1 -> a4_hi = atom_getfloat(arg++);
+ attract1 -> a5_lo = atom_getfloat(arg++);
+ attract1 -> a5_hi = atom_getfloat(arg++);
+ limiter(attract1);
+}
+
+static void search(attract1_struct *attract1, t_symbol *s, int argc, t_atom *argv) {
+ int not_found, not_expired = attract1 -> lyap_limit;
+ int jump, i, iterations;
+ t_atom vars[M_var_count];
+ double temp_a0 = attract1 -> a0;
+ double temp_a1 = attract1 -> a1;
+ double temp_a2 = attract1 -> a2;
+ double temp_a3 = attract1 -> a3;
+ double temp_a4 = attract1 -> a4;
+ double temp_a5 = attract1 -> a5;
+ 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], attract1 -> vars_init[i]);
+ }
+ }
+ do {
+ jump = 500;
+ not_found = 0;
+ iterations = 10000;
+ bad_params:
+ attract1 -> a0 = (drand48() * (attract1 -> a0_hi - attract1 -> a0_lo)) + attract1 -> a0_lo;
+ attract1 -> a1 = (drand48() * (attract1 -> a1_hi - attract1 -> a1_lo)) + attract1 -> a1_lo;
+ attract1 -> a2 = (drand48() * (attract1 -> a2_hi - attract1 -> a2_lo)) + attract1 -> a2_lo;
+ attract1 -> a3 = (drand48() * (attract1 -> a3_hi - attract1 -> a3_lo)) + attract1 -> a3_lo;
+ attract1 -> a4 = (drand48() * (attract1 -> a4_hi - attract1 -> a4_lo)) + attract1 -> a4_lo;
+ attract1 -> a5 = (drand48() * (attract1 -> a5_hi - attract1 -> a5_lo)) + attract1 -> a5_lo;
+ // put any preliminary checks specific to this fractal to eliminate bad_params
+
+ reset(attract1, NULL, argc, vars);
+ do { calc(attract1, attract1 -> vars); } while(jump--);
+ attract1 -> lyap_exp = lyapunov((void *) attract1, (t_gotfn) calc, M_var_count, (double *) attract1 -> vars);
+ if (isnan(attract1 -> lyap_exp)) { not_found = 1; }
+ if (attract1 -> lyap_exp < attract1 -> lyap_lo || attract1 -> lyap_exp > attract1 -> lyap_hi) { not_found = 1; }
+ not_expired--;
+ } while(not_found && not_expired);
+ reset(attract1, NULL, argc, vars);
+ if (!not_expired) {
+ post("Could not find a fractal after %d attempts.", (int) attract1 -> lyap_limit);
+ post("Try using wider constraints.");
+ attract1 -> a0 = temp_a0;
+ attract1 -> a1 = temp_a1;
+ attract1 -> a2 = temp_a2;
+ attract1 -> a3 = temp_a3;
+ attract1 -> a4 = temp_a4;
+ attract1 -> a5 = temp_a5;
+ outlet_anything(attract1 -> search_outlet, gensym("invalid"), 0, NULL);
+ } else {
+ attract1 -> failure_ratio = (attract1 -> lyap_limit - not_expired) / attract1 -> lyap_limit;
+ make_results(attract1);
+ outlet_anything(attract1 -> search_outlet, gensym("search"), M_search_count, attract1 -> search_out);
+ }
+}
+
+void *attract1_new(t_symbol *s, int argc, t_atom *argv) {
+ attract1_struct *attract1 = (attract1_struct *) pd_new(attract1_class);
+ if (attract1 != NULL) {
+ outlet_new(&attract1 -> x_obj, &s_float);
+ attract1 -> outlets[0] = outlet_new(&attract1 -> x_obj, &s_float);
+ attract1 -> search_outlet = outlet_new(&attract1 -> x_obj, &s_list);
+ attract1 -> vars_outlet = outlet_new(&attract1 -> x_obj, &s_list);
+ attract1 -> params_outlet = outlet_new(&attract1 -> x_obj, &s_list);
+ if (argc == M_param_count + M_var_count) {
+ attract1 -> vars_init[M_x] = attract1 -> vars[M_x] = (double) atom_getfloatarg(0, argc, argv);
+ attract1 -> vars_init[M_y] = attract1 -> vars[M_y] = (double) atom_getfloatarg(1, argc, argv);
+ attract1 -> a0 = (double) atom_getfloatarg(2, argc, argv);
+ attract1 -> a1 = (double) atom_getfloatarg(3, argc, argv);
+ attract1 -> a2 = (double) atom_getfloatarg(4, argc, argv);
+ attract1 -> a3 = (double) atom_getfloatarg(5, argc, argv);
+ attract1 -> a4 = (double) atom_getfloatarg(6, argc, argv);
+ attract1 -> a5 = (double) atom_getfloatarg(7, argc, argv);
+ } else {
+ if (argc != 0 && argc != M_param_count + M_var_count) {
+ post("Incorrect number of arguments for attract1 fractal. Expecting 8 arguments.");
+ }
+ attract1 -> vars_init[M_x] = 0;
+ attract1 -> vars_init[M_y] = 0;
+ attract1 -> a0 = 1;
+ attract1 -> a1 = 1;
+ attract1 -> a2 = 1;
+ attract1 -> a3 = 1;
+ attract1 -> a4 = 1;
+ attract1 -> a5 = 1;
+ }
+ constrain(attract1, NULL, 0, NULL);
+ lyap(attract1, -1000000.0, 1000000.0, M_failure_limit);
+ }
+ return (void *)attract1;
+}
+
+void attract1_setup(void) {
+ attract1_class = class_new(gensym("attract1"), (t_newmethod) attract1_new, 0, sizeof(attract1_struct), 0, A_GIMME, 0);
+ class_addbang(attract1_class, (t_method) calculate);
+ class_addmethod(attract1_class, (t_method) reset, gensym("reset"), A_GIMME, 0);
+ class_addmethod(attract1_class, (t_method) show, gensym("show"), 0);
+ class_addmethod(attract1_class, (t_method) param, gensym("param"), A_GIMME, 0);
+ class_addmethod(attract1_class, (t_method) seed, gensym("seed"), A_GIMME, 0);
+ class_addmethod(attract1_class, (t_method) lyap, gensym("lyapunov"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(attract1_class, (t_method) elyap, gensym("elyapunov"), 0);
+ class_addmethod(attract1_class, (t_method) search, gensym("search"), A_GIMME, 0);
+ class_addmethod(attract1_class, (t_method) constrain, gensym("constrain"), A_GIMME, 0);
+ class_sethelpsymbol(attract1_class, gensym("help-attract1.pd"));
+}
+
diff --git a/base.c b/base.c
new file mode 100644
index 0000000..ffdcb9f
--- /dev/null
+++ b/base.c
@@ -0,0 +1,269 @@
+/* base Attractor PD External */
+/* Copyright Michael McGonagle, 2003 */
+/* This program is distributed under the params of the GNU Public License */
+
+///////////////////////////////////////////////////////////////////////////////////
+/* This file is part of Chaos PD Externals. */
+/* */
+/* Chaos PD Externals are free software; you can redistribute them and/or modify */
+/* them under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* Chaos PD Externals are distributed in the hope that they will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with the Chaos PD Externals; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+///////////////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#include "lyapunov.h"
+
+#define M_a_lo 0
+#define M_a_hi 3
+#define M_b_lo 0.001
+#define M_b_hi 2.6667
+
+#define M_a 0
+#define M_b 1
+
+#define M_x 0
+
+#define M_param_count 2
+#define M_var_count 1
+#define M_search_count 3
+#define M_failure_limit 1000
+
+static char *version = "base v0.0, by Michael McGonagle, 2003";
+
+t_class *base_class;
+
+typedef struct base_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;
+ t_atom params_out[M_param_count];
+ t_outlet *params_outlet;
+ double lyap_exp, lyap_lo, lyap_hi, lyap_limit, failure_ratio;
+} base_struct;
+
+static void calc(base_struct *base, double *vars) {
+ double x_0;
+ x_0 =vars[M_x]+(base -> a*sin(pow(vars[M_x],base -> b)));
+ vars[M_x] = x_0;
+} // end calc
+
+static void calculate(base_struct *base) {
+ calc(base, base -> vars);
+ outlet_float(base -> x_obj.ob_outlet, base -> vars[M_x]);
+} // end calculate
+
+static void reset(base_struct *base, t_symbol *s, int argc, t_atom *argv) {
+ if (argc == M_var_count) {
+ base -> vars[M_x] = (double) atom_getfloatarg(M_x, argc, argv);
+ } else {
+ base -> vars[M_x] = base -> vars_init[M_x];
+ } // end if
+} // end reset
+
+static char *classify(base_struct *base) {
+ static char buff[3];
+ char *c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ buff[0] = c[(int) (((base -> a - M_a_lo) * (1.0 / (M_a_hi - M_a_lo))) * 26)];
+ buff[1] = c[(int) (((base -> b - M_b_lo) * (1.0 / (M_b_hi - M_b_lo))) * 26)];
+ buff[2] = '\0';
+ return buff;
+}
+
+static void make_results(base_struct *base) {
+ SETFLOAT(&base -> search_out[0], base -> lyap_exp);
+ SETSYMBOL(&base -> search_out[1], gensym(classify(base)));
+ SETFLOAT(&base -> search_out[2], base -> failure_ratio);
+ SETFLOAT(&base -> vars_out[M_x], base -> vars[M_x]);
+ SETFLOAT(&base -> params_out[M_a], base -> a);
+ SETFLOAT(&base -> params_out[M_b], base -> b);
+ outlet_list(base -> params_outlet, gensym("list"), M_param_count, base -> params_out);
+ outlet_list(base -> vars_outlet, gensym("list"), M_var_count, base -> vars_out);
+}
+
+static void show(base_struct *base) {
+ make_results(base);
+ outlet_anything(base -> search_outlet, gensym("show"), M_search_count, base -> search_out);
+}
+
+static void param(base_struct *base, t_symbol *s, int argc, t_atom *argv) {
+ if (argc != 2) {
+ post("Incorrect number of arguments for base fractal. Expecting 2 arguments.");
+ return;
+ }
+ base -> a = (double) atom_getfloatarg(0, argc, argv);
+ base -> b = (double) atom_getfloatarg(1, argc, argv);
+}
+
+static void seed(base_struct *base, 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(base_struct *base, t_floatarg l, t_floatarg h, t_floatarg lim) {
+ base -> lyap_lo = l;
+ base -> lyap_hi = h;
+ base -> lyap_limit = (double) ((int) lim);
+}
+
+static void elyap(base_struct *base) {
+ double results[M_var_count];
+ int i;
+ if (lyapunov_full((void *) base, (t_gotfn) calc, M_var_count, base -> vars, results) != NULL) {
+ post("elyapunov:");
+ for(i = 0; i < M_var_count; i++) { post("%d: %3.80f", i, results[i]); }
+ }
+}
+
+static void limiter(base_struct *base) {
+ if (base -> a_lo < M_a_lo) { base -> a_lo = M_a_lo; }
+ if (base -> a_lo > M_a_hi) { base -> a_lo = M_a_hi; }
+ if (base -> a_hi < M_a_lo) { base -> a_hi = M_a_lo; }
+ if (base -> a_hi > M_a_hi) { base -> a_hi = M_a_hi; }
+ if (base -> b_lo < M_b_lo) { base -> b_lo = M_b_lo; }
+ if (base -> b_lo > M_b_hi) { base -> b_lo = M_b_hi; }
+ if (base -> b_hi < M_b_lo) { base -> b_hi = M_b_lo; }
+ if (base -> b_hi > M_b_hi) { base -> b_hi = M_b_hi; }
+}
+
+static void constrain(base_struct *base, t_symbol *s, int argc, t_atom *argv) {
+ int i;
+ t_atom *arg = argv;
+ if (argc == 0) {
+ // reset to full limits of search ranges
+ base -> a_lo = M_a_lo;
+ base -> a_hi = M_a_hi;
+ base -> b_lo = M_b_lo;
+ base -> 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;
+ base -> a_lo = base -> a - a_spread;
+ base -> a_hi = base -> a + a_spread;
+ base -> b_lo = base -> b - b_spread;
+ base -> b_hi = base -> b + b_spread;
+ limiter(base);
+ return;
+ }
+ if (argc != M_param_count * 2) {
+ post("Invalid number of arguments for base constraints, requires 4 values, got %d", argc);
+ return;
+ }
+ base -> a_lo = atom_getfloat(arg++);
+ base -> a_hi = atom_getfloat(arg++);
+ base -> b_lo = atom_getfloat(arg++);
+ base -> b_hi = atom_getfloat(arg++);
+ limiter(base);
+}
+
+static void search(base_struct *base, t_symbol *s, int argc, t_atom *argv) {
+ int not_found, not_expired = base -> lyap_limit;
+ int jump, i, iterations;
+ t_atom vars[M_var_count];
+ double temp_a = base -> a;
+ double temp_b = base -> 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], base -> vars_init[i]);
+ }
+ }
+ do {
+ jump = 500;
+ not_found = 0;
+ iterations = 10000;
+ bad_params:
+ base -> a = (drand48() * (base -> a_hi - base -> a_lo)) + base -> a_lo;
+ base -> b = (drand48() * (base -> b_hi - base -> b_lo)) + base -> b_lo;
+ // put any preliminary checks specific to this fractal to eliminate bad_params
+
+ reset(base, NULL, argc, vars);
+ do { calc(base, base -> vars); } while(jump--);
+ base -> lyap_exp = lyapunov((void *) base, (t_gotfn) calc, M_var_count, (double *) base -> vars);
+ if (isnan(base -> lyap_exp)) { not_found = 1; }
+ if (base -> lyap_exp < base -> lyap_lo || base -> lyap_exp > base -> lyap_hi) { not_found = 1; }
+ not_expired--;
+ } while(not_found && not_expired);
+ reset(base, NULL, argc, vars);
+ if (!not_expired) {
+ post("Could not find a fractal after %d attempts.", (int) base -> lyap_limit);
+ post("Try using wider constraints.");
+ base -> a = temp_a;
+ base -> b = temp_b;
+ outlet_anything(base -> search_outlet, gensym("invalid"), 0, NULL);
+ } else {
+ base -> failure_ratio = (base -> lyap_limit - not_expired) / base -> lyap_limit;
+ make_results(base);
+ outlet_anything(base -> search_outlet, gensym("search"), M_search_count, base -> search_out);
+ }
+}
+
+void *base_new(t_symbol *s, int argc, t_atom *argv) {
+ base_struct *base = (base_struct *) pd_new(base_class);
+ if (base != NULL) {
+ outlet_new(&base -> x_obj, &s_float);
+ base -> search_outlet = outlet_new(&base -> x_obj, &s_list);
+ base -> vars_outlet = outlet_new(&base -> x_obj, &s_list);
+ base -> params_outlet = outlet_new(&base -> x_obj, &s_list);
+ if (argc == M_param_count + M_var_count) {
+ base -> vars_init[M_x] = base -> vars[M_x] = (double) atom_getfloatarg(0, argc, argv);
+ base -> a = (double) atom_getfloatarg(1, argc, argv);
+ base -> b = (double) atom_getfloatarg(2, argc, argv);
+ } else {
+ if (argc != 0 && argc != M_param_count + M_var_count) {
+ post("Incorrect number of arguments for base fractal. Expecting 3 arguments.");
+ }
+ base -> vars_init[M_x] = 0.1;
+ base -> a = 1;
+ base -> b = 1;
+ }
+ constrain(base, NULL, 0, NULL);
+ lyap(base, -1000000.0, 1000000.0, M_failure_limit);
+ }
+ return (void *)base;
+}
+
+void base_setup(void) {
+ base_class = class_new(gensym("base"), (t_newmethod) base_new, 0, sizeof(base_struct), 0, A_GIMME, 0);
+ class_addbang(base_class, (t_method) calculate);
+ class_addmethod(base_class, (t_method) reset, gensym("reset"), A_GIMME, 0);
+ class_addmethod(base_class, (t_method) show, gensym("show"), 0);
+ class_addmethod(base_class, (t_method) param, gensym("param"), A_GIMME, 0);
+ class_addmethod(base_class, (t_method) seed, gensym("seed"), A_GIMME, 0);
+ class_addmethod(base_class, (t_method) lyap, gensym("lyapunov"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(base_class, (t_method) elyap, gensym("elyapunov"), 0);
+ class_addmethod(base_class, (t_method) search, gensym("search"), A_GIMME, 0);
+ class_addmethod(base_class, (t_method) constrain, gensym("constrain"), A_GIMME, 0);
+ class_sethelpsymbol(base_class, gensym("help-base.pd"));
+}
+
diff --git a/base3.c b/base3.c
new file mode 100644
index 0000000..24f5a5e
--- /dev/null
+++ b/base3.c
@@ -0,0 +1,269 @@
+/* base3 Attractor PD External */
+/* Copyright Michael McGonagle, 2003 */
+/* This program is distributed under the params of the GNU Public License */
+
+///////////////////////////////////////////////////////////////////////////////////
+/* This file is part of Chaos PD Externals. */
+/* */
+/* Chaos PD Externals are free software; you can redistribute them and/or modify */
+/* them under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* Chaos PD Externals are distributed in the hope that they will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with the Chaos PD Externals; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+///////////////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#include "lyapunov.h"
+
+#define M_a_lo 0
+#define M_a_hi 3
+#define M_b_lo 0.001
+#define M_b_hi 2.6667
+
+#define M_a 0
+#define M_b 1
+
+#define M_x 0
+
+#define M_param_count 2
+#define M_var_count 1
+#define M_search_count 3
+#define M_failure_limit 1000
+
+static char *version = "base3 v0.0, by Michael McGonagle, 2003";
+
+t_class *base3_class;
+
+typedef struct base3_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;
+ t_atom params_out[M_param_count];
+ t_outlet *params_outlet;
+ double lyap_exp, lyap_lo, lyap_hi, lyap_limit, failure_ratio;
+} base3_struct;
+
+static void calc(base3_struct *base3, double *vars) {
+ double x_0;
+ x_0 =base3 -> a*sin(pow(vars[M_x],base3 -> b));
+ vars[M_x] = x_0;
+} // end calc
+
+static void calculate(base3_struct *base3) {
+ calc(base3, base3 -> vars);
+ outlet_float(base3 -> x_obj.ob_outlet, base3 -> vars[M_x]);
+} // end calculate
+
+static void reset(base3_struct *base3, t_symbol *s, int argc, t_atom *argv) {
+ if (argc == M_var_count) {
+ base3 -> vars[M_x] = (double) atom_getfloatarg(M_x, argc, argv);
+ } else {
+ base3 -> vars[M_x] = base3 -> vars_init[M_x];
+ } // end if
+} // end reset
+
+static char *classify(base3_struct *base3) {
+ static char buff[3];
+ char *c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ buff[0] = c[(int) (((base3 -> a - M_a_lo) * (1.0 / (M_a_hi - M_a_lo))) * 26)];
+ buff[1] = c[(int) (((base3 -> b - M_b_lo) * (1.0 / (M_b_hi - M_b_lo))) * 26)];
+ buff[2] = '\0';
+ return buff;
+}
+
+static void make_results(base3_struct *base3) {
+ SETFLOAT(&base3 -> search_out[0], base3 -> lyap_exp);
+ SETSYMBOL(&base3 -> search_out[1], gensym(classify(base3)));
+ SETFLOAT(&base3 -> search_out[2], base3 -> failure_ratio);
+ SETFLOAT(&base3 -> vars_out[M_x], base3 -> vars[M_x]);
+ SETFLOAT(&base3 -> params_out[M_a], base3 -> a);
+ SETFLOAT(&base3 -> params_out[M_b], base3 -> b);
+ outlet_list(base3 -> params_outlet, gensym("list"), M_param_count, base3 -> params_out);
+ outlet_list(base3 -> vars_outlet, gensym("list"), M_var_count, base3 -> vars_out);
+}
+
+static void show(base3_struct *base3) {
+ make_results(base3);
+ outlet_anything(base3 -> search_outlet, gensym("show"), M_search_count, base3 -> search_out);
+}
+
+static void param(base3_struct *base3, t_symbol *s, int argc, t_atom *argv) {
+ if (argc != 2) {
+ post("Incorrect number of arguments for base3 fractal. Expecting 2 arguments.");
+ return;
+ }
+ base3 -> a = (double) atom_getfloatarg(0, argc, argv);
+ base3 -> b = (double) atom_getfloatarg(1, argc, argv);
+}
+
+static void seed(base3_struct *base3, 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(base3_struct *base3, t_floatarg l, t_floatarg h, t_floatarg lim) {
+ base3 -> lyap_lo = l;
+ base3 -> lyap_hi = h;
+ base3 -> lyap_limit = (double) ((int) lim);
+}
+
+static void elyap(base3_struct *base3) {
+ double results[M_var_count];
+ int i;
+ if (lyapunov_full((void *) base3, (t_gotfn) calc, M_var_count, base3 -> vars, results) != NULL) {
+ post("elyapunov:");
+ for(i = 0; i < M_var_count; i++) { post("%d: %3.80f", i, results[i]); }
+ }
+}
+
+static void limiter(base3_struct *base3) {
+ if (base3 -> a_lo < M_a_lo) { base3 -> a_lo = M_a_lo; }
+ if (base3 -> a_lo > M_a_hi) { base3 -> a_lo = M_a_hi; }
+ if (base3 -> a_hi < M_a_lo) { base3 -> a_hi = M_a_lo; }
+ if (base3 -> a_hi > M_a_hi) { base3 -> a_hi = M_a_hi; }
+ if (base3 -> b_lo < M_b_lo) { base3 -> b_lo = M_b_lo; }
+ if (base3 -> b_lo > M_b_hi) { base3 -> b_lo = M_b_hi; }
+ if (base3 -> b_hi < M_b_lo) { base3 -> b_hi = M_b_lo; }
+ if (base3 -> b_hi > M_b_hi) { base3 -> b_hi = M_b_hi; }
+}
+
+static void constrain(base3_struct *base3, t_symbol *s, int argc, t_atom *argv) {
+ int i;
+ t_atom *arg = argv;
+ if (argc == 0) {
+ // reset to full limits of search ranges
+ base3 -> a_lo = M_a_lo;
+ base3 -> a_hi = M_a_hi;
+ base3 -> b_lo = M_b_lo;
+ base3 -> 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;
+ base3 -> a_lo = base3 -> a - a_spread;
+ base3 -> a_hi = base3 -> a + a_spread;
+ base3 -> b_lo = base3 -> b - b_spread;
+ base3 -> b_hi = base3 -> b + b_spread;
+ limiter(base3);
+ return;
+ }
+ if (argc != M_param_count * 2) {
+ post("Invalid number of arguments for base3 constraints, requires 4 values, got %d", argc);
+ return;
+ }
+ base3 -> a_lo = atom_getfloat(arg++);
+ base3 -> a_hi = atom_getfloat(arg++);
+ base3 -> b_lo = atom_getfloat(arg++);
+ base3 -> b_hi = atom_getfloat(arg++);
+ limiter(base3);
+}
+
+static void search(base3_struct *base3, t_symbol *s, int argc, t_atom *argv) {
+ int not_found, not_expired = base3 -> lyap_limit;
+ int jump, i, iterations;
+ t_atom vars[M_var_count];
+ double temp_a = base3 -> a;
+ double temp_b = base3 -> 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], base3 -> vars_init[i]);
+ }
+ }
+ do {
+ jump = 500;
+ not_found = 0;
+ iterations = 10000;
+ bad_params:
+ base3 -> a = (drand48() * (base3 -> a_hi - base3 -> a_lo)) + base3 -> a_lo;
+ base3 -> b = (drand48() * (base3 -> b_hi - base3 -> b_lo)) + base3 -> b_lo;
+ // put any preliminary checks specific to this fractal to eliminate bad_params
+
+ reset(base3, NULL, argc, vars);
+ do { calc(base3, base3 -> vars); } while(jump--);
+ base3 -> lyap_exp = lyapunov((void *) base3, (t_gotfn) calc, M_var_count, (double *) base3 -> vars);
+ if (isnan(base3 -> lyap_exp)) { not_found = 1; }
+ if (base3 -> lyap_exp < base3 -> lyap_lo || base3 -> lyap_exp > base3 -> lyap_hi) { not_found = 1; }
+ not_expired--;
+ } while(not_found && not_expired);
+ reset(base3, NULL, argc, vars);
+ if (!not_expired) {
+ post("Could not find a fractal after %d attempts.", (int) base3 -> lyap_limit);
+ post("Try using wider constraints.");
+ base3 -> a = temp_a;
+ base3 -> b = temp_b;
+ outlet_anything(base3 -> search_outlet, gensym("invalid"), 0, NULL);
+ } else {
+ base3 -> failure_ratio = (base3 -> lyap_limit - not_expired) / base3 -> lyap_limit;
+ make_results(base3);
+ outlet_anything(base3 -> search_outlet, gensym("search"), M_search_count, base3 -> search_out);
+ }
+}
+
+void *base3_new(t_symbol *s, int argc, t_atom *argv) {
+ base3_struct *base3 = (base3_struct *) pd_new(base3_class);
+ if (base3 != NULL) {
+ outlet_new(&base3 -> x_obj, &s_float);
+ base3 -> search_outlet = outlet_new(&base3 -> x_obj, &s_list);
+ base3 -> vars_outlet = outlet_new(&base3 -> x_obj, &s_list);
+ base3 -> params_outlet = outlet_new(&base3 -> x_obj, &s_list);
+ if (argc == M_param_count + M_var_count) {
+ base3 -> vars_init[M_x] = base3 -> vars[M_x] = (double) atom_getfloatarg(0, argc, argv);
+ base3 -> a = (double) atom_getfloatarg(1, argc, argv);
+ base3 -> b = (double) atom_getfloatarg(2, argc, argv);
+ } else {
+ if (argc != 0 && argc != M_param_count + M_var_count) {
+ post("Incorrect number of arguments for base3 fractal. Expecting 3 arguments.");
+ }
+ base3 -> vars_init[M_x] = 0.1;
+ base3 -> a = 1;
+ base3 -> b = 1;
+ }
+ constrain(base3, NULL, 0, NULL);
+ lyap(base3, -1000000.0, 1000000.0, M_failure_limit);
+ }
+ return (void *)base3;
+}
+
+void base3_setup(void) {
+ base3_class = class_new(gensym("base3"), (t_newmethod) base3_new, 0, sizeof(base3_struct), 0, A_GIMME, 0);
+ class_addbang(base3_class, (t_method) calculate);
+ class_addmethod(base3_class, (t_method) reset, gensym("reset"), A_GIMME, 0);
+ class_addmethod(base3_class, (t_method) show, gensym("show"), 0);
+ class_addmethod(base3_class, (t_method) param, gensym("param"), A_GIMME, 0);
+ class_addmethod(base3_class, (t_method) seed, gensym("seed"), A_GIMME, 0);
+ class_addmethod(base3_class, (t_method) lyap, gensym("lyapunov"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(base3_class, (t_method) elyap, gensym("elyapunov"), 0);
+ class_addmethod(base3_class, (t_method) search, gensym("search"), A_GIMME, 0);
+ class_addmethod(base3_class, (t_method) constrain, gensym("constrain"), A_GIMME, 0);
+ class_sethelpsymbol(base3_class, gensym("help-base3.pd"));
+}
+
diff --git a/dejong.c b/dejong.c
new file mode 100644
index 0000000..8cd806f
--- /dev/null
+++ b/dejong.c
@@ -0,0 +1,325 @@
+/* dejong Attractor PD External */
+/* Copyright Michael McGonagle, from ???pbourke???, 2003 */
+/* This program is distributed under the params of the GNU Public License */
+
+///////////////////////////////////////////////////////////////////////////////////
+/* This file is part of Chaos PD Externals. */
+/* */
+/* Chaos PD Externals are free software; you can redistribute them and/or modify */
+/* them under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* Chaos PD Externals are distributed in the hope that they will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with the Chaos PD Externals; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+///////////////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#include "lyapunov.h"
+
+#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_d_lo -1000
+#define M_d_hi 1000
+
+#define M_a 0
+#define M_b 1
+#define M_c 2
+#define M_d 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 = "dejong v0.0, by Michael McGonagle, from ???pbourke???, 2003";
+
+t_class *dejong_class;
+
+typedef struct dejong_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, d, d_lo, d_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];
+} dejong_struct;
+
+static void calc(dejong_struct *dejong, double *vars) {
+ double x_0, y_0;
+ x_0 =sin(dejong -> a*vars[M_y])-cos(dejong -> b*vars[M_x]);
+ y_0 =sin(dejong -> c*vars[M_x])-cos(dejong -> d*vars[M_y]);
+ vars[M_x] = x_0;
+ vars[M_y] = y_0;
+} // end calc
+
+static void calculate(dejong_struct *dejong) {
+ calc(dejong, dejong -> vars);
+ outlet_float(dejong -> x_obj.ob_outlet, dejong -> vars[M_x]);
+ outlet_float(dejong -> outlets[M_y - 1], dejong -> vars[M_y]);
+} // end calculate
+
+static void reset(dejong_struct *dejong, t_symbol *s, int argc, t_atom *argv) {
+ if (argc == M_var_count) {
+ dejong -> vars[M_x] = (double) atom_getfloatarg(M_x, argc, argv);
+ dejong -> vars[M_y] = (double) atom_getfloatarg(M_y, argc, argv);
+ } else {
+ dejong -> vars[M_x] = dejong -> vars_init[M_x];
+ dejong -> vars[M_y] = dejong -> vars_init[M_y];
+ } // end if
+} // end reset
+
+static char *classify(dejong_struct *dejong) {
+ static char buff[5];
+ char *c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ buff[0] = c[(int) (((dejong -> a - M_a_lo) * (1.0 / (M_a_hi - M_a_lo))) * 26)];
+ buff[1] = c[(int) (((dejong -> b - M_b_lo) * (1.0 / (M_b_hi - M_b_lo))) * 26)];
+ buff[2] = c[(int) (((dejong -> c - M_c_lo) * (1.0 / (M_c_hi - M_c_lo))) * 26)];
+ buff[3] = c[(int) (((dejong -> d - M_d_lo) * (1.0 / (M_d_hi - M_d_lo))) * 26)];
+ buff[4] = '\0';
+ return buff;
+}
+
+static void make_results(dejong_struct *dejong) {
+ SETFLOAT(&dejong -> search_out[0], dejong -> lyap_exp);
+ SETSYMBOL(&dejong -> search_out[1], gensym(classify(dejong)));
+ SETFLOAT(&dejong -> search_out[2], dejong -> failure_ratio);
+ SETFLOAT(&dejong -> vars_out[M_x], dejong -> vars[M_x]);
+ SETFLOAT(&dejong -> vars_out[M_y], dejong -> vars[M_y]);
+ SETFLOAT(&dejong -> params_out[M_a], dejong -> a);
+ SETFLOAT(&dejong -> params_out[M_b], dejong -> b);
+ SETFLOAT(&dejong -> params_out[M_c], dejong -> c);
+ SETFLOAT(&dejong -> params_out[M_d], dejong -> d);
+ outlet_list(dejong -> params_outlet, gensym("list"), M_param_count, dejong -> params_out);
+ outlet_list(dejong -> vars_outlet, gensym("list"), M_var_count, dejong -> vars_out);
+}
+
+static void show(dejong_struct *dejong) {
+ make_results(dejong);
+ outlet_anything(dejong -> search_outlet, gensym("show"), M_search_count, dejong -> search_out);
+}
+
+static void param(dejong_struct *dejong, t_symbol *s, int argc, t_atom *argv) {
+ if (argc != 4) {
+ post("Incorrect number of arguments for dejong fractal. Expecting 4 arguments.");
+ return;
+ }
+ dejong -> a = (double) atom_getfloatarg(0, argc, argv);
+ dejong -> b = (double) atom_getfloatarg(1, argc, argv);
+ dejong -> c = (double) atom_getfloatarg(2, argc, argv);
+ dejong -> d = (double) atom_getfloatarg(3, argc, argv);
+}
+
+static void seed(dejong_struct *dejong, 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(dejong_struct *dejong, t_floatarg l, t_floatarg h, t_floatarg lim) {
+ dejong -> lyap_lo = l;
+ dejong -> lyap_hi = h;
+ dejong -> lyap_limit = (double) ((int) lim);
+}
+
+static void elyap(dejong_struct *dejong) {
+ double results[M_var_count];
+ int i;
+ if (lyapunov_full((void *) dejong, (t_gotfn) calc, M_var_count, dejong -> vars, results) != NULL) {
+ post("elyapunov:");
+ for(i = 0; i < M_var_count; i++) { post("%d: %3.80f", i, results[i]); }
+ }
+}
+
+static void limiter(dejong_struct *dejong) {
+ if (dejong -> a_lo < M_a_lo) { dejong -> a_lo = M_a_lo; }
+ if (dejong -> a_lo > M_a_hi) { dejong -> a_lo = M_a_hi; }
+ if (dejong -> a_hi < M_a_lo) { dejong -> a_hi = M_a_lo; }
+ if (dejong -> a_hi > M_a_hi) { dejong -> a_hi = M_a_hi; }
+ if (dejong -> b_lo < M_b_lo) { dejong -> b_lo = M_b_lo; }
+ if (dejong -> b_lo > M_b_hi) { dejong -> b_lo = M_b_hi; }
+ if (dejong -> b_hi < M_b_lo) { dejong -> b_hi = M_b_lo; }
+ if (dejong -> b_hi > M_b_hi) { dejong -> b_hi = M_b_hi; }
+ if (dejong -> c_lo < M_c_lo) { dejong -> c_lo = M_c_lo; }
+ if (dejong -> c_lo > M_c_hi) { dejong -> c_lo = M_c_hi; }
+ if (dejong -> c_hi < M_c_lo) { dejong -> c_hi = M_c_lo; }
+ if (dejong -> c_hi > M_c_hi) { dejong -> c_hi = M_c_hi; }
+ if (dejong -> d_lo < M_d_lo) { dejong -> d_lo = M_d_lo; }
+ if (dejong -> d_lo > M_d_hi) { dejong -> d_lo = M_d_hi; }
+ if (dejong -> d_hi < M_d_lo) { dejong -> d_hi = M_d_lo; }
+ if (dejong -> d_hi > M_d_hi) { dejong -> d_hi = M_d_hi; }
+}
+
+static void constrain(dejong_struct *dejong, t_symbol *s, int argc, t_atom *argv) {
+ int i;
+ t_atom *arg = argv;
+ if (argc == 0) {
+ // reset to full limits of search ranges
+ dejong -> a_lo = M_a_lo;
+ dejong -> a_hi = M_a_hi;
+ dejong -> b_lo = M_b_lo;
+ dejong -> b_hi = M_b_hi;
+ dejong -> c_lo = M_c_lo;
+ dejong -> c_hi = M_c_hi;
+ dejong -> d_lo = M_d_lo;
+ dejong -> d_hi = M_d_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 d_spread = ((M_d_hi - M_d_lo) * percent) / 2;
+ dejong -> a_lo = dejong -> a - a_spread;
+ dejong -> a_hi = dejong -> a + a_spread;
+ dejong -> b_lo = dejong -> b - b_spread;
+ dejong -> b_hi = dejong -> b + b_spread;
+ dejong -> c_lo = dejong -> c - c_spread;
+ dejong -> c_hi = dejong -> c + c_spread;
+ dejong -> d_lo = dejong -> d - d_spread;
+ dejong -> d_hi = dejong -> d + d_spread;
+ limiter(dejong);
+ return;
+ }
+ if (argc != M_param_count * 2) {
+ post("Invalid number of arguments for dejong constraints, requires 8 values, got %d", argc);
+ return;
+ }
+ dejong -> a_lo = atom_getfloat(arg++);
+ dejong -> a_hi = atom_getfloat(arg++);
+ dejong -> b_lo = atom_getfloat(arg++);
+ dejong -> b_hi = atom_getfloat(arg++);
+ dejong -> c_lo = atom_getfloat(arg++);
+ dejong -> c_hi = atom_getfloat(arg++);
+ dejong -> d_lo = atom_getfloat(arg++);
+ dejong -> d_hi = atom_getfloat(arg++);
+ limiter(dejong);
+}
+
+static void search(dejong_struct *dejong, t_symbol *s, int argc, t_atom *argv) {
+ int not_found, not_expired = dejong -> lyap_limit;
+ int jump, i, iterations;
+ t_atom vars[M_var_count];
+ double temp_a = dejong -> a;
+ double temp_b = dejong -> b;
+ double temp_c = dejong -> c;
+ double temp_d = dejong -> d;
+ 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], dejong -> vars_init[i]);
+ }
+ }
+ do {
+ jump = 500;
+ not_found = 0;
+ iterations = 10000;
+ bad_params:
+ dejong -> a = (drand48() * (dejong -> a_hi - dejong -> a_lo)) + dejong -> a_lo;
+ dejong -> b = (drand48() * (dejong -> b_hi - dejong -> b_lo)) + dejong -> b_lo;
+ dejong -> c = (drand48() * (dejong -> c_hi - dejong -> c_lo)) + dejong -> c_lo;
+ dejong -> d = (drand48() * (dejong -> d_hi - dejong -> d_lo)) + dejong -> d_lo;
+ // put any preliminary checks specific to this fractal to eliminate bad_params
+
+ reset(dejong, NULL, argc, vars);
+ do { calc(dejong, dejong -> vars); } while(jump--);
+ dejong -> lyap_exp = lyapunov((void *) dejong, (t_gotfn) calc, M_var_count, (double *) dejong -> vars);
+ if (isnan(dejong -> lyap_exp)) { not_found = 1; }
+ if (dejong -> lyap_exp < dejong -> lyap_lo || dejong -> lyap_exp > dejong -> lyap_hi) { not_found = 1; }
+ not_expired--;
+ } while(not_found && not_expired);
+ reset(dejong, NULL, argc, vars);
+ if (!not_expired) {
+ post("Could not find a fractal after %d attempts.", (int) dejong -> lyap_limit);
+ post("Try using wider constraints.");
+ dejong -> a = temp_a;
+ dejong -> b = temp_b;
+ dejong -> c = temp_c;
+ dejong -> d = temp_d;
+ outlet_anything(dejong -> search_outlet, gensym("invalid"), 0, NULL);
+ } else {
+ dejong -> failure_ratio = (dejong -> lyap_limit - not_expired) / dejong -> lyap_limit;
+ make_results(dejong);
+ outlet_anything(dejong -> search_outlet, gensym("search"), M_search_count, dejong -> search_out);
+ }
+}
+
+void *dejong_new(t_symbol *s, int argc, t_atom *argv) {
+ dejong_struct *dejong = (dejong_struct *) pd_new(dejong_class);
+ if (dejong != NULL) {
+ outlet_new(&dejong -> x_obj, &s_float);
+ dejong -> outlets[0] = outlet_new(&dejong -> x_obj, &s_float);
+ dejong -> search_outlet = outlet_new(&dejong -> x_obj, &s_list);
+ dejong -> vars_outlet = outlet_new(&dejong -> x_obj, &s_list);
+ dejong -> params_outlet = outlet_new(&dejong -> x_obj, &s_list);
+ if (argc == M_param_count + M_var_count) {
+ dejong -> vars_init[M_x] = dejong -> vars[M_x] = (double) atom_getfloatarg(0, argc, argv);
+ dejong -> vars_init[M_y] = dejong -> vars[M_y] = (double) atom_getfloatarg(1, argc, argv);
+ dejong -> a = (double) atom_getfloatarg(2, argc, argv);
+ dejong -> b = (double) atom_getfloatarg(3, argc, argv);
+ dejong -> c = (double) atom_getfloatarg(4, argc, argv);
+ dejong -> d = (double) atom_getfloatarg(5, argc, argv);
+ } else {
+ if (argc != 0 && argc != M_param_count + M_var_count) {
+ post("Incorrect number of arguments for dejong fractal. Expecting 6 arguments.");
+ }
+ dejong -> vars_init[M_x] = 0.01;
+ dejong -> vars_init[M_y] = 0;
+ dejong -> a = -2.24;
+ dejong -> b = -0.65;
+ dejong -> c = 0.43;
+ dejong -> d = -2.43;
+ }
+ constrain(dejong, NULL, 0, NULL);
+ lyap(dejong, -1000000.0, 1000000.0, M_failure_limit);
+ }
+ return (void *)dejong;
+}
+
+void dejong_setup(void) {
+ dejong_class = class_new(gensym("dejong"), (t_newmethod) dejong_new, 0, sizeof(dejong_struct), 0, A_GIMME, 0);
+ class_addbang(dejong_class, (t_method) calculate);
+ class_addmethod(dejong_class, (t_method) reset, gensym("reset"), A_GIMME, 0);
+ class_addmethod(dejong_class, (t_method) show, gensym("show"), 0);
+ class_addmethod(dejong_class, (t_method) param, gensym("param"), A_GIMME, 0);
+ class_addmethod(dejong_class, (t_method) seed, gensym("seed"), A_GIMME, 0);
+ class_addmethod(dejong_class, (t_method) lyap, gensym("lyapunov"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(dejong_class, (t_method) elyap, gensym("elyapunov"), 0);
+ class_addmethod(dejong_class, (t_method) search, gensym("search"), A_GIMME, 0);
+ class_addmethod(dejong_class, (t_method) constrain, gensym("constrain"), A_GIMME, 0);
+ class_sethelpsymbol(dejong_class, gensym("help-dejong.pd"));
+}
+
diff --git a/gingerbreadman.c b/gingerbreadman.c
new file mode 100644
index 0000000..51218a1
--- /dev/null
+++ b/gingerbreadman.c
@@ -0,0 +1,101 @@
+/* gingerbreadman Attractor PD External */
+/* Copyright Michael McGonagle, from ??????, 2003 */
+/* This program is distributed under the params of the GNU Public License */
+
+///////////////////////////////////////////////////////////////////////////////////
+/* This file is part of Chaos PD Externals. */
+/* */
+/* Chaos PD Externals are free software; you can redistribute them and/or modify */
+/* them under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* Chaos PD Externals are distributed in the hope that they will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with the Chaos PD Externals; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+///////////////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#include "m_pd.h"
+
+
+
+#define M_x 0
+#define M_y 1
+
+#define M_param_count 0
+#define M_var_count 2
+#define M_search_count 0
+#define M_failure_limit 1000
+
+static char *version = "gingerbreadman v0.0, by Michael McGonagle, from ??????, 2003";
+
+t_class *gingerbreadman_class;
+
+typedef struct gingerbreadman_struct {
+ t_object x_obj;
+
+ double vars[M_var_count];
+ double vars_init[M_var_count];
+
+ t_outlet *outlets[M_var_count - 1];
+} gingerbreadman_struct;
+
+static void calc(gingerbreadman_struct *gingerbreadman, double *vars) {
+ double x_0, y_0;
+ x_0 =1-vars[M_y]+abs(vars[M_x]);
+ y_0 =vars[M_x];
+ vars[M_x] = x_0;
+ vars[M_y] = y_0;
+} // end calc
+
+static void calculate(gingerbreadman_struct *gingerbreadman) {
+ calc(gingerbreadman, gingerbreadman -> vars);
+ outlet_float(gingerbreadman -> x_obj.ob_outlet, gingerbreadman -> vars[M_x]);
+ outlet_float(gingerbreadman -> outlets[M_y - 1], gingerbreadman -> vars[M_y]);
+} // end calculate
+
+static void reset(gingerbreadman_struct *gingerbreadman, t_symbol *s, int argc, t_atom *argv) {
+ if (argc == M_var_count) {
+ gingerbreadman -> vars[M_x] = (double) atom_getfloatarg(M_x, argc, argv);
+ gingerbreadman -> vars[M_y] = (double) atom_getfloatarg(M_y, argc, argv);
+ } else {
+ gingerbreadman -> vars[M_x] = gingerbreadman -> vars_init[M_x];
+ gingerbreadman -> vars[M_y] = gingerbreadman -> vars_init[M_y];
+ } // end if
+} // end reset
+
+void *gingerbreadman_new(t_symbol *s, int argc, t_atom *argv) {
+ gingerbreadman_struct *gingerbreadman = (gingerbreadman_struct *) pd_new(gingerbreadman_class);
+ if (gingerbreadman != NULL) {
+ outlet_new(&gingerbreadman -> x_obj, &s_float);
+ gingerbreadman -> outlets[0] = outlet_new(&gingerbreadman -> x_obj, &s_float);
+ if (argc == M_param_count + M_var_count) {
+ gingerbreadman -> vars_init[M_x] = gingerbreadman -> vars[M_x] = (double) atom_getfloatarg(0, argc, argv);
+ gingerbreadman -> vars_init[M_y] = gingerbreadman -> vars[M_y] = (double) atom_getfloatarg(1, argc, argv);
+ } else {
+ if (argc != 0 && argc != M_param_count + M_var_count) {
+ post("Incorrect number of arguments for gingerbreadman fractal. Expecting 2 arguments.");
+ }
+ gingerbreadman -> vars_init[M_x] = -0.1;
+ gingerbreadman -> vars_init[M_y] = 0;
+ }
+ }
+ return (void *)gingerbreadman;
+}
+
+void gingerbreadman_setup(void) {
+ gingerbreadman_class = class_new(gensym("gingerbreadman"), (t_newmethod) gingerbreadman_new, 0, sizeof(gingerbreadman_struct), 0, A_GIMME, 0);
+ class_addbang(gingerbreadman_class, (t_method) calculate);
+ class_addmethod(gingerbreadman_class, (t_method) reset, gensym("reset"), A_GIMME, 0);
+ class_sethelpsymbol(gingerbreadman_class, gensym("help-gingerbreadman.pd"));
+}
+
diff --git a/hopalong.c b/hopalong.c
new file mode 100644
index 0000000..01f6d13
--- /dev/null
+++ b/hopalong.c
@@ -0,0 +1,303 @@
+/* hopalong Attractor PD External */
+/* Copyright Michael McGonagle, from ??????, 2003 */
+/* This program is distributed under the params of the GNU Public License */
+
+///////////////////////////////////////////////////////////////////////////////////
+/* This file is part of Chaos PD Externals. */
+/* */
+/* Chaos PD Externals are free software; you can redistribute them and/or modify */
+/* them under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* Chaos PD Externals are distributed in the hope that they will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with the Chaos PD Externals; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+///////////////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#include "lyapunov.h"
+
+#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_a 0
+#define M_b 1
+#define M_c 2
+
+#define M_x 0
+#define M_y 1
+
+#define M_param_count 3
+#define M_var_count 2
+#define M_search_count 3
+#define M_failure_limit 1000
+
+static char *version = "hopalong v0.0, by Michael McGonagle, from ??????, 2003";
+
+t_class *hopalong_class;
+
+typedef struct hopalong_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;
+ 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];
+} hopalong_struct;
+
+static void calc(hopalong_struct *hopalong, double *vars) {
+ double x_0, y_0;
+ x_0 =vars[M_y]-((vars[M_x]<0)?-1:1)*sqrt(abs(hopalong -> b*vars[M_x]-hopalong -> c));
+ y_0 =hopalong -> a-vars[M_x];
+ vars[M_x] = x_0;
+ vars[M_y] = y_0;
+} // end calc
+
+static void calculate(hopalong_struct *hopalong) {
+ calc(hopalong, hopalong -> vars);
+ outlet_float(hopalong -> x_obj.ob_outlet, hopalong -> vars[M_x]);
+ outlet_float(hopalong -> outlets[M_y - 1], hopalong -> vars[M_y]);
+} // end calculate
+
+static void reset(hopalong_struct *hopalong, t_symbol *s, int argc, t_atom *argv) {
+ if (argc == M_var_count) {
+ hopalong -> vars[M_x] = (double) atom_getfloatarg(M_x, argc, argv);
+ hopalong -> vars[M_y] = (double) atom_getfloatarg(M_y, argc, argv);
+ } else {
+ hopalong -> vars[M_x] = hopalong -> vars_init[M_x];
+ hopalong -> vars[M_y] = hopalong -> vars_init[M_y];
+ } // end if
+} // end reset
+
+static char *classify(hopalong_struct *hopalong) {
+ static char buff[4];
+ char *c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ buff[0] = c[(int) (((hopalong -> a - M_a_lo) * (1.0 / (M_a_hi - M_a_lo))) * 26)];
+ buff[1] = c[(int) (((hopalong -> b - M_b_lo) * (1.0 / (M_b_hi - M_b_lo))) * 26)];
+ buff[2] = c[(int) (((hopalong -> c - M_c_lo) * (1.0 / (M_c_hi - M_c_lo))) * 26)];
+ buff[3] = '\0';
+ return buff;
+}
+
+static void make_results(hopalong_struct *hopalong) {
+ SETFLOAT(&hopalong -> search_out[0], hopalong -> lyap_exp);
+ SETSYMBOL(&hopalong -> search_out[1], gensym(classify(hopalong)));
+ SETFLOAT(&hopalong -> search_out[2], hopalong -> failure_ratio);
+ SETFLOAT(&hopalong -> vars_out[M_x], hopalong -> vars[M_x]);
+ SETFLOAT(&hopalong -> vars_out[M_y], hopalong -> vars[M_y]);
+ SETFLOAT(&hopalong -> params_out[M_a], hopalong -> a);
+ SETFLOAT(&hopalong -> params_out[M_b], hopalong -> b);
+ SETFLOAT(&hopalong -> params_out[M_c], hopalong -> c);
+ outlet_list(hopalong -> params_outlet, gensym("list"), M_param_count, hopalong -> params_out);
+ outlet_list(hopalong -> vars_outlet, gensym("list"), M_var_count, hopalong -> vars_out);
+}
+
+static void show(hopalong_struct *hopalong) {
+ make_results(hopalong);
+ outlet_anything(hopalong -> search_outlet, gensym("show"), M_search_count, hopalong -> search_out);
+}
+
+static void param(hopalong_struct *hopalong, t_symbol *s, int argc, t_atom *argv) {
+ if (argc != 3) {
+ post("Incorrect number of arguments for hopalong fractal. Expecting 3 arguments.");
+ return;
+ }
+ hopalong -> a = (double) atom_getfloatarg(0, argc, argv);
+ hopalong -> b = (double) atom_getfloatarg(1, argc, argv);
+ hopalong -> c = (double) atom_getfloatarg(2, argc, argv);
+}
+
+static void seed(hopalong_struct *hopalong, 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(hopalong_struct *hopalong, t_floatarg l, t_floatarg h, t_floatarg lim) {
+ hopalong -> lyap_lo = l;
+ hopalong -> lyap_hi = h;
+ hopalong -> lyap_limit = (double) ((int) lim);
+}
+
+static void elyap(hopalong_struct *hopalong) {
+ double results[M_var_count];
+ int i;
+ if (lyapunov_full((void *) hopalong, (t_gotfn) calc, M_var_count, hopalong -> vars, results) != NULL) {
+ post("elyapunov:");
+ for(i = 0; i < M_var_count; i++) { post("%d: %3.80f", i, results[i]); }
+ }
+}
+
+static void limiter(hopalong_struct *hopalong) {
+ if (hopalong -> a_lo < M_a_lo) { hopalong -> a_lo = M_a_lo; }
+ if (hopalong -> a_lo > M_a_hi) { hopalong -> a_lo = M_a_hi; }
+ if (hopalong -> a_hi < M_a_lo) { hopalong -> a_hi = M_a_lo; }
+ if (hopalong -> a_hi > M_a_hi) { hopalong -> a_hi = M_a_hi; }
+ if (hopalong -> b_lo < M_b_lo) { hopalong -> b_lo = M_b_lo; }
+ if (hopalong -> b_lo > M_b_hi) { hopalong -> b_lo = M_b_hi; }
+ if (hopalong -> b_hi < M_b_lo) { hopalong -> b_hi = M_b_lo; }
+ if (hopalong -> b_hi > M_b_hi) { hopalong -> b_hi = M_b_hi; }
+ if (hopalong -> c_lo < M_c_lo) { hopalong -> c_lo = M_c_lo; }
+ if (hopalong -> c_lo > M_c_hi) { hopalong -> c_lo = M_c_hi; }
+ if (hopalong -> c_hi < M_c_lo) { hopalong -> c_hi = M_c_lo; }
+ if (hopalong -> c_hi > M_c_hi) { hopalong -> c_hi = M_c_hi; }
+}
+
+static void constrain(hopalong_struct *hopalong, t_symbol *s, int argc, t_atom *argv) {
+ int i;
+ t_atom *arg = argv;
+ if (argc == 0) {
+ // reset to full limits of search ranges
+ hopalong -> a_lo = M_a_lo;
+ hopalong -> a_hi = M_a_hi;
+ hopalong -> b_lo = M_b_lo;
+ hopalong -> b_hi = M_b_hi;
+ hopalong -> c_lo = M_c_lo;
+ hopalong -> c_hi = M_c_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;
+ hopalong -> a_lo = hopalong -> a - a_spread;
+ hopalong -> a_hi = hopalong -> a + a_spread;
+ hopalong -> b_lo = hopalong -> b - b_spread;
+ hopalong -> b_hi = hopalong -> b + b_spread;
+ hopalong -> c_lo = hopalong -> c - c_spread;
+ hopalong -> c_hi = hopalong -> c + c_spread;
+ limiter(hopalong);
+ return;
+ }
+ if (argc != M_param_count * 2) {
+ post("Invalid number of arguments for hopalong constraints, requires 6 values, got %d", argc);
+ return;
+ }
+ hopalong -> a_lo = atom_getfloat(arg++);
+ hopalong -> a_hi = atom_getfloat(arg++);
+ hopalong -> b_lo = atom_getfloat(arg++);
+ hopalong -> b_hi = atom_getfloat(arg++);
+ hopalong -> c_lo = atom_getfloat(arg++);
+ hopalong -> c_hi = atom_getfloat(arg++);
+ limiter(hopalong);
+}
+
+static void search(hopalong_struct *hopalong, t_symbol *s, int argc, t_atom *argv) {
+ int not_found, not_expired = hopalong -> lyap_limit;
+ int jump, i, iterations;
+ t_atom vars[M_var_count];
+ double temp_a = hopalong -> a;
+ double temp_b = hopalong -> b;
+ double temp_c = hopalong -> 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], hopalong -> vars_init[i]);
+ }
+ }
+ do {
+ jump = 500;
+ not_found = 0;
+ iterations = 10000;
+ bad_params:
+ hopalong -> a = (drand48() * (hopalong -> a_hi - hopalong -> a_lo)) + hopalong -> a_lo;
+ hopalong -> b = (drand48() * (hopalong -> b_hi - hopalong -> b_lo)) + hopalong -> b_lo;
+ hopalong -> c = (drand48() * (hopalong -> c_hi - hopalong -> c_lo)) + hopalong -> c_lo;
+ // put any preliminary checks specific to this fractal to eliminate bad_params
+
+ reset(hopalong, NULL, argc, vars);
+ do { calc(hopalong, hopalong -> vars); } while(jump--);
+ hopalong -> lyap_exp = lyapunov((void *) hopalong, (t_gotfn) calc, M_var_count, (double *) hopalong -> vars);
+ if (isnan(hopalong -> lyap_exp)) { not_found = 1; }
+ if (hopalong -> lyap_exp < hopalong -> lyap_lo || hopalong -> lyap_exp > hopalong -> lyap_hi) { not_found = 1; }
+ not_expired--;
+ } while(not_found && not_expired);
+ reset(hopalong, NULL, argc, vars);
+ if (!not_expired) {
+ post("Could not find a fractal after %d attempts.", (int) hopalong -> lyap_limit);
+ post("Try using wider constraints.");
+ hopalong -> a = temp_a;
+ hopalong -> b = temp_b;
+ hopalong -> c = temp_c;
+ outlet_anything(hopalong -> search_outlet, gensym("invalid"), 0, NULL);
+ } else {
+ hopalong -> failure_ratio = (hopalong -> lyap_limit - not_expired) / hopalong -> lyap_limit;
+ make_results(hopalong);
+ outlet_anything(hopalong -> search_outlet, gensym("search"), M_search_count, hopalong -> search_out);
+ }
+}
+
+void *hopalong_new(t_symbol *s, int argc, t_atom *argv) {
+ hopalong_struct *hopalong = (hopalong_struct *) pd_new(hopalong_class);
+ if (hopalong != NULL) {
+ outlet_new(&hopalong -> x_obj, &s_float);
+ hopalong -> outlets[0] = outlet_new(&hopalong -> x_obj, &s_float);
+ hopalong -> search_outlet = outlet_new(&hopalong -> x_obj, &s_list);
+ hopalong -> vars_outlet = outlet_new(&hopalong -> x_obj, &s_list);
+ hopalong -> params_outlet = outlet_new(&hopalong -> x_obj, &s_list);
+ if (argc == M_param_count + M_var_count) {
+ hopalong -> vars_init[M_x] = hopalong -> vars[M_x] = (double) atom_getfloatarg(0, argc, argv);
+ hopalong -> vars_init[M_y] = hopalong -> vars[M_y] = (double) atom_getfloatarg(1, argc, argv);
+ hopalong -> a = (double) atom_getfloatarg(2, argc, argv);
+ hopalong -> b = (double) atom_getfloatarg(3, argc, argv);
+ hopalong -> c = (double) atom_getfloatarg(4, argc, argv);
+ } else {
+ if (argc != 0 && argc != M_param_count + M_var_count) {
+ post("Incorrect number of arguments for hopalong fractal. Expecting 5 arguments.");
+ }
+ hopalong -> vars_init[M_x] = 0.1;
+ hopalong -> vars_init[M_y] = 0.1;
+ hopalong -> a = 1;
+ hopalong -> b = 1;
+ hopalong -> c = 0;
+ }
+ constrain(hopalong, NULL, 0, NULL);
+ lyap(hopalong, -1000000.0, 1000000.0, M_failure_limit);
+ }
+ return (void *)hopalong;
+}
+
+void hopalong_setup(void) {
+ hopalong_class = class_new(gensym("hopalong"), (t_newmethod) hopalong_new, 0, sizeof(hopalong_struct), 0, A_GIMME, 0);
+ class_addbang(hopalong_class, (t_method) calculate);
+ class_addmethod(hopalong_class, (t_method) reset, gensym("reset"), A_GIMME, 0);
+ class_addmethod(hopalong_class, (t_method) show, gensym("show"), 0);
+ class_addmethod(hopalong_class, (t_method) param, gensym("param"), A_GIMME, 0);
+ class_addmethod(hopalong_class, (t_method) seed, gensym("seed"), A_GIMME, 0);
+ class_addmethod(hopalong_class, (t_method) lyap, gensym("lyapunov"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(hopalong_class, (t_method) elyap, gensym("elyapunov"), 0);
+ class_addmethod(hopalong_class, (t_method) search, gensym("search"), A_GIMME, 0);
+ class_addmethod(hopalong_class, (t_method) constrain, gensym("constrain"), A_GIMME, 0);
+ class_sethelpsymbol(hopalong_class, gensym("help-hopalong.pd"));
+}
+
diff --git a/latoocarfian.c b/latoocarfian.c
new file mode 100644
index 0000000..996d987
--- /dev/null
+++ b/latoocarfian.c
@@ -0,0 +1,325 @@
+/* latoocarfian Attractor PD External */
+/* Copyright Michael McGonagle, from Cliff Pickover, 2003 */
+/* This program is distributed under the params of the GNU Public License */
+
+///////////////////////////////////////////////////////////////////////////////////
+/* This file is part of Chaos PD Externals. */
+/* */
+/* Chaos PD Externals are free software; you can redistribute them and/or modify */
+/* them under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* Chaos PD Externals are distributed in the hope that they will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with the Chaos PD Externals; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+///////////////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#include "lyapunov.h"
+
+#define M_a_lo -3
+#define M_a_hi 3
+#define M_b_lo -3
+#define M_b_hi 3
+#define M_c_lo 0.5
+#define M_c_hi 1.5
+#define M_d_lo 0.5
+#define M_d_hi 1.5
+
+#define M_a 0
+#define M_b 1
+#define M_c 2
+#define M_d 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 = "latoocarfian v0.0, by Michael McGonagle, from Cliff Pickover, 2003";
+
+t_class *latoocarfian_class;
+
+typedef struct latoocarfian_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, d, d_lo, d_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];
+} latoocarfian_struct;
+
+static void calc(latoocarfian_struct *latoocarfian, double *vars) {
+ double x_0, y_0;
+ x_0 =sin(vars[M_y]*latoocarfian -> b)+(latoocarfian -> c*sin(vars[M_x]*latoocarfian -> b));
+ y_0 =sin(vars[M_x]*latoocarfian -> a)+(latoocarfian -> d*sin(vars[M_y]*latoocarfian -> a));
+ vars[M_x] = x_0;
+ vars[M_y] = y_0;
+} // end calc
+
+static void calculate(latoocarfian_struct *latoocarfian) {
+ calc(latoocarfian, latoocarfian -> vars);
+ outlet_float(latoocarfian -> x_obj.ob_outlet, latoocarfian -> vars[M_x]);
+ outlet_float(latoocarfian -> outlets[M_y - 1], latoocarfian -> vars[M_y]);
+} // end calculate
+
+static void reset(latoocarfian_struct *latoocarfian, t_symbol *s, int argc, t_atom *argv) {
+ if (argc == M_var_count) {
+ latoocarfian -> vars[M_x] = (double) atom_getfloatarg(M_x, argc, argv);
+ latoocarfian -> vars[M_y] = (double) atom_getfloatarg(M_y, argc, argv);
+ } else {
+ latoocarfian -> vars[M_x] = latoocarfian -> vars_init[M_x];
+ latoocarfian -> vars[M_y] = latoocarfian -> vars_init[M_y];
+ } // end if
+} // end reset
+
+static char *classify(latoocarfian_struct *latoocarfian) {
+ static char buff[5];
+ char *c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ buff[0] = c[(int) (((latoocarfian -> a - M_a_lo) * (1.0 / (M_a_hi - M_a_lo))) * 26)];
+ buff[1] = c[(int) (((latoocarfian -> b - M_b_lo) * (1.0 / (M_b_hi - M_b_lo))) * 26)];
+ buff[2] = c[(int) (((latoocarfian -> c - M_c_lo) * (1.0 / (M_c_hi - M_c_lo))) * 26)];
+ buff[3] = c[(int) (((latoocarfian -> d - M_d_lo) * (1.0 / (M_d_hi - M_d_lo))) * 26)];
+ buff[4] = '\0';
+ return buff;
+}
+
+static void make_results(latoocarfian_struct *latoocarfian) {
+ SETFLOAT(&latoocarfian -> search_out[0], latoocarfian -> lyap_exp);
+ SETSYMBOL(&latoocarfian -> search_out[1], gensym(classify(latoocarfian)));
+ SETFLOAT(&latoocarfian -> search_out[2], latoocarfian -> failure_ratio);
+ SETFLOAT(&latoocarfian -> vars_out[M_x], latoocarfian -> vars[M_x]);
+ SETFLOAT(&latoocarfian -> vars_out[M_y], latoocarfian -> vars[M_y]);
+ SETFLOAT(&latoocarfian -> params_out[M_a], latoocarfian -> a);
+ SETFLOAT(&latoocarfian -> params_out[M_b], latoocarfian -> b);
+ SETFLOAT(&latoocarfian -> params_out[M_c], latoocarfian -> c);
+ SETFLOAT(&latoocarfian -> params_out[M_d], latoocarfian -> d);
+ outlet_list(latoocarfian -> params_outlet, gensym("list"), M_param_count, latoocarfian -> params_out);
+ outlet_list(latoocarfian -> vars_outlet, gensym("list"), M_var_count, latoocarfian -> vars_out);
+}
+
+static void show(latoocarfian_struct *latoocarfian) {
+ make_results(latoocarfian);
+ outlet_anything(latoocarfian -> search_outlet, gensym("show"), M_search_count, latoocarfian -> search_out);
+}
+
+static void param(latoocarfian_struct *latoocarfian, t_symbol *s, int argc, t_atom *argv) {
+ if (argc != 4) {
+ post("Incorrect number of arguments for latoocarfian fractal. Expecting 4 arguments.");
+ return;
+ }
+ latoocarfian -> a = (double) atom_getfloatarg(0, argc, argv);
+ latoocarfian -> b = (double) atom_getfloatarg(1, argc, argv);
+ latoocarfian -> c = (double) atom_getfloatarg(2, argc, argv);
+ latoocarfian -> d = (double) atom_getfloatarg(3, argc, argv);
+}
+
+static void seed(latoocarfian_struct *latoocarfian, 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(latoocarfian_struct *latoocarfian, t_floatarg l, t_floatarg h, t_floatarg lim) {
+ latoocarfian -> lyap_lo = l;
+ latoocarfian -> lyap_hi = h;
+ latoocarfian -> lyap_limit = (double) ((int) lim);
+}
+
+static void elyap(latoocarfian_struct *latoocarfian) {
+ double results[M_var_count];
+ int i;
+ if (lyapunov_full((void *) latoocarfian, (t_gotfn) calc, M_var_count, latoocarfian -> vars, results) != NULL) {
+ post("elyapunov:");
+ for(i = 0; i < M_var_count; i++) { post("%d: %3.80f", i, results[i]); }
+ }
+}
+
+static void limiter(latoocarfian_struct *latoocarfian) {
+ if (latoocarfian -> a_lo < M_a_lo) { latoocarfian -> a_lo = M_a_lo; }
+ if (latoocarfian -> a_lo > M_a_hi) { latoocarfian -> a_lo = M_a_hi; }
+ if (latoocarfian -> a_hi < M_a_lo) { latoocarfian -> a_hi = M_a_lo; }
+ if (latoocarfian -> a_hi > M_a_hi) { latoocarfian -> a_hi = M_a_hi; }
+ if (latoocarfian -> b_lo < M_b_lo) { latoocarfian -> b_lo = M_b_lo; }
+ if (latoocarfian -> b_lo > M_b_hi) { latoocarfian -> b_lo = M_b_hi; }
+ if (latoocarfian -> b_hi < M_b_lo) { latoocarfian -> b_hi = M_b_lo; }
+ if (latoocarfian -> b_hi > M_b_hi) { latoocarfian -> b_hi = M_b_hi; }
+ if (latoocarfian -> c_lo < M_c_lo) { latoocarfian -> c_lo = M_c_lo; }
+ if (latoocarfian -> c_lo > M_c_hi) { latoocarfian -> c_lo = M_c_hi; }
+ if (latoocarfian -> c_hi < M_c_lo) { latoocarfian -> c_hi = M_c_lo; }
+ if (latoocarfian -> c_hi > M_c_hi) { latoocarfian -> c_hi = M_c_hi; }
+ if (latoocarfian -> d_lo < M_d_lo) { latoocarfian -> d_lo = M_d_lo; }
+ if (latoocarfian -> d_lo > M_d_hi) { latoocarfian -> d_lo = M_d_hi; }
+ if (latoocarfian -> d_hi < M_d_lo) { latoocarfian -> d_hi = M_d_lo; }
+ if (latoocarfian -> d_hi > M_d_hi) { latoocarfian -> d_hi = M_d_hi; }
+}
+
+static void constrain(latoocarfian_struct *latoocarfian, t_symbol *s, int argc, t_atom *argv) {
+ int i;
+ t_atom *arg = argv;
+ if (argc == 0) {
+ // reset to full limits of search ranges
+ latoocarfian -> a_lo = M_a_lo;
+ latoocarfian -> a_hi = M_a_hi;
+ latoocarfian -> b_lo = M_b_lo;
+ latoocarfian -> b_hi = M_b_hi;
+ latoocarfian -> c_lo = M_c_lo;
+ latoocarfian -> c_hi = M_c_hi;
+ latoocarfian -> d_lo = M_d_lo;
+ latoocarfian -> d_hi = M_d_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 d_spread = ((M_d_hi - M_d_lo) * percent) / 2;
+ latoocarfian -> a_lo = latoocarfian -> a - a_spread;
+ latoocarfian -> a_hi = latoocarfian -> a + a_spread;
+ latoocarfian -> b_lo = latoocarfian -> b - b_spread;
+ latoocarfian -> b_hi = latoocarfian -> b + b_spread;
+ latoocarfian -> c_lo = latoocarfian -> c - c_spread;
+ latoocarfian -> c_hi = latoocarfian -> c + c_spread;
+ latoocarfian -> d_lo = latoocarfian -> d - d_spread;
+ latoocarfian -> d_hi = latoocarfian -> d + d_spread;
+ limiter(latoocarfian);
+ return;
+ }
+ if (argc != M_param_count * 2) {
+ post("Invalid number of arguments for latoocarfian constraints, requires 8 values, got %d", argc);
+ return;
+ }
+ latoocarfian -> a_lo = atom_getfloat(arg++);
+ latoocarfian -> a_hi = atom_getfloat(arg++);
+ latoocarfian -> b_lo = atom_getfloat(arg++);
+ latoocarfian -> b_hi = atom_getfloat(arg++);
+ latoocarfian -> c_lo = atom_getfloat(arg++);
+ latoocarfian -> c_hi = atom_getfloat(arg++);
+ latoocarfian -> d_lo = atom_getfloat(arg++);
+ latoocarfian -> d_hi = atom_getfloat(arg++);
+ limiter(latoocarfian);
+}
+
+static void search(latoocarfian_struct *latoocarfian, t_symbol *s, int argc, t_atom *argv) {
+ int not_found, not_expired = latoocarfian -> lyap_limit;
+ int jump, i, iterations;
+ t_atom vars[M_var_count];
+ double temp_a = latoocarfian -> a;
+ double temp_b = latoocarfian -> b;
+ double temp_c = latoocarfian -> c;
+ double temp_d = latoocarfian -> d;
+ 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], latoocarfian -> vars_init[i]);
+ }
+ }
+ do {
+ jump = 500;
+ not_found = 0;
+ iterations = 10000;
+ bad_params:
+ latoocarfian -> a = (drand48() * (latoocarfian -> a_hi - latoocarfian -> a_lo)) + latoocarfian -> a_lo;
+ latoocarfian -> b = (drand48() * (latoocarfian -> b_hi - latoocarfian -> b_lo)) + latoocarfian -> b_lo;
+ latoocarfian -> c = (drand48() * (latoocarfian -> c_hi - latoocarfian -> c_lo)) + latoocarfian -> c_lo;
+ latoocarfian -> d = (drand48() * (latoocarfian -> d_hi - latoocarfian -> d_lo)) + latoocarfian -> d_lo;
+ // put any preliminary checks specific to this fractal to eliminate bad_params
+
+ reset(latoocarfian, NULL, argc, vars);
+ do { calc(latoocarfian, latoocarfian -> vars); } while(jump--);
+ latoocarfian -> lyap_exp = lyapunov((void *) latoocarfian, (t_gotfn) calc, M_var_count, (double *) latoocarfian -> vars);
+ if (isnan(latoocarfian -> lyap_exp)) { not_found = 1; }
+ if (latoocarfian -> lyap_exp < latoocarfian -> lyap_lo || latoocarfian -> lyap_exp > latoocarfian -> lyap_hi) { not_found = 1; }
+ not_expired--;
+ } while(not_found && not_expired);
+ reset(latoocarfian, NULL, argc, vars);
+ if (!not_expired) {
+ post("Could not find a fractal after %d attempts.", (int) latoocarfian -> lyap_limit);
+ post("Try using wider constraints.");
+ latoocarfian -> a = temp_a;
+ latoocarfian -> b = temp_b;
+ latoocarfian -> c = temp_c;
+ latoocarfian -> d = temp_d;
+ outlet_anything(latoocarfian -> search_outlet, gensym("invalid"), 0, NULL);
+ } else {
+ latoocarfian -> failure_ratio = (latoocarfian -> lyap_limit - not_expired) / latoocarfian -> lyap_limit;
+ make_results(latoocarfian);
+ outlet_anything(latoocarfian -> search_outlet, gensym("search"), M_search_count, latoocarfian -> search_out);
+ }
+}
+
+void *latoocarfian_new(t_symbol *s, int argc, t_atom *argv) {
+ latoocarfian_struct *latoocarfian = (latoocarfian_struct *) pd_new(latoocarfian_class);
+ if (latoocarfian != NULL) {
+ outlet_new(&latoocarfian -> x_obj, &s_float);
+ latoocarfian -> outlets[0] = outlet_new(&latoocarfian -> x_obj, &s_float);
+ latoocarfian -> search_outlet = outlet_new(&latoocarfian -> x_obj, &s_list);
+ latoocarfian -> vars_outlet = outlet_new(&latoocarfian -> x_obj, &s_list);
+ latoocarfian -> params_outlet = outlet_new(&latoocarfian -> x_obj, &s_list);
+ if (argc == M_param_count + M_var_count) {
+ latoocarfian -> vars_init[M_x] = latoocarfian -> vars[M_x] = (double) atom_getfloatarg(0, argc, argv);
+ latoocarfian -> vars_init[M_y] = latoocarfian -> vars[M_y] = (double) atom_getfloatarg(1, argc, argv);
+ latoocarfian -> a = (double) atom_getfloatarg(2, argc, argv);
+ latoocarfian -> b = (double) atom_getfloatarg(3, argc, argv);
+ latoocarfian -> c = (double) atom_getfloatarg(4, argc, argv);
+ latoocarfian -> d = (double) atom_getfloatarg(5, argc, argv);
+ } else {
+ if (argc != 0 && argc != M_param_count + M_var_count) {
+ post("Incorrect number of arguments for latoocarfian fractal. Expecting 6 arguments.");
+ }
+ latoocarfian -> vars_init[M_x] = 0.1;
+ latoocarfian -> vars_init[M_y] = 0.1;
+ latoocarfian -> a = -0.966918;
+ latoocarfian -> b = 2.87988;
+ latoocarfian -> c = 0.756145;
+ latoocarfian -> d = 0.744728;
+ }
+ constrain(latoocarfian, NULL, 0, NULL);
+ lyap(latoocarfian, -1000000.0, 1000000.0, M_failure_limit);
+ }
+ return (void *)latoocarfian;
+}
+
+void latoocarfian_setup(void) {
+ latoocarfian_class = class_new(gensym("latoocarfian"), (t_newmethod) latoocarfian_new, 0, sizeof(latoocarfian_struct), 0, A_GIMME, 0);
+ class_addbang(latoocarfian_class, (t_method) calculate);
+ class_addmethod(latoocarfian_class, (t_method) reset, gensym("reset"), A_GIMME, 0);
+ class_addmethod(latoocarfian_class, (t_method) show, gensym("show"), 0);
+ class_addmethod(latoocarfian_class, (t_method) param, gensym("param"), A_GIMME, 0);
+ class_addmethod(latoocarfian_class, (t_method) seed, gensym("seed"), A_GIMME, 0);
+ class_addmethod(latoocarfian_class, (t_method) lyap, gensym("lyapunov"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(latoocarfian_class, (t_method) elyap, gensym("elyapunov"), 0);
+ class_addmethod(latoocarfian_class, (t_method) search, gensym("search"), A_GIMME, 0);
+ class_addmethod(latoocarfian_class, (t_method) constrain, gensym("constrain"), A_GIMME, 0);
+ class_sethelpsymbol(latoocarfian_class, gensym("help-latoocarfian.pd"));
+}
+
diff --git a/latoomutalpha.c b/latoomutalpha.c
new file mode 100644
index 0000000..3648d8c
--- /dev/null
+++ b/latoomutalpha.c
@@ -0,0 +1,325 @@
+/* latoomutalpha Attractor PD External */
+/* Copyright Michael McGonagle, from Cliff Pickover, 2003 */
+/* This program is distributed under the params of the GNU Public License */
+
+///////////////////////////////////////////////////////////////////////////////////
+/* This file is part of Chaos PD Externals. */
+/* */
+/* Chaos PD Externals are free software; you can redistribute them and/or modify */
+/* them under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* Chaos PD Externals are distributed in the hope that they will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with the Chaos PD Externals; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+///////////////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#include "lyapunov.h"
+
+#define M_a_lo -3
+#define M_a_hi 3
+#define M_b_lo -3
+#define M_b_hi 3
+#define M_c_lo 0.5
+#define M_c_hi 1.5
+#define M_d_lo 0.5
+#define M_d_hi 1.5
+
+#define M_a 0
+#define M_b 1
+#define M_c 2
+#define M_d 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 = "latoomutalpha v0.0, by Michael McGonagle, from Cliff Pickover, 2003";
+
+t_class *latoomutalpha_class;
+
+typedef struct latoomutalpha_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, d, d_lo, d_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];
+} latoomutalpha_struct;
+
+static void calc(latoomutalpha_struct *latoomutalpha, double *vars) {
+ double x_0, y_0;
+ x_0 =sin(vars[M_y]*latoomutalpha -> b)+pow(sin(vars[M_x]*latoomutalpha -> b),2)+pow(sin(vars[M_x]*latoomutalpha -> b),3);
+ y_0 =sin(vars[M_x]*latoomutalpha -> a)+pow(sin(vars[M_y]*latoomutalpha -> a),2)+pow(sin(vars[M_y]*latoomutalpha -> c),3);
+ vars[M_x] = x_0;
+ vars[M_y] = y_0;
+} // end calc
+
+static void calculate(latoomutalpha_struct *latoomutalpha) {
+ calc(latoomutalpha, latoomutalpha -> vars);
+ outlet_float(latoomutalpha -> x_obj.ob_outlet, latoomutalpha -> vars[M_x]);
+ outlet_float(latoomutalpha -> outlets[M_y - 1], latoomutalpha -> vars[M_y]);
+} // end calculate
+
+static void reset(latoomutalpha_struct *latoomutalpha, t_symbol *s, int argc, t_atom *argv) {
+ if (argc == M_var_count) {
+ latoomutalpha -> vars[M_x] = (double) atom_getfloatarg(M_x, argc, argv);
+ latoomutalpha -> vars[M_y] = (double) atom_getfloatarg(M_y, argc, argv);
+ } else {
+ latoomutalpha -> vars[M_x] = latoomutalpha -> vars_init[M_x];
+ latoomutalpha -> vars[M_y] = latoomutalpha -> vars_init[M_y];
+ } // end if
+} // end reset
+
+static char *classify(latoomutalpha_struct *latoomutalpha) {
+ static char buff[5];
+ char *c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ buff[0] = c[(int) (((latoomutalpha -> a - M_a_lo) * (1.0 / (M_a_hi - M_a_lo))) * 26)];
+ buff[1] = c[(int) (((latoomutalpha -> b - M_b_lo) * (1.0 / (M_b_hi - M_b_lo))) * 26)];
+ buff[2] = c[(int) (((latoomutalpha -> c - M_c_lo) * (1.0 / (M_c_hi - M_c_lo))) * 26)];
+ buff[3] = c[(int) (((latoomutalpha -> d - M_d_lo) * (1.0 / (M_d_hi - M_d_lo))) * 26)];
+ buff[4] = '\0';
+ return buff;
+}
+
+static void make_results(latoomutalpha_struct *latoomutalpha) {
+ SETFLOAT(&latoomutalpha -> search_out[0], latoomutalpha -> lyap_exp);
+ SETSYMBOL(&latoomutalpha -> search_out[1], gensym(classify(latoomutalpha)));
+ SETFLOAT(&latoomutalpha -> search_out[2], latoomutalpha -> failure_ratio);
+ SETFLOAT(&latoomutalpha -> vars_out[M_x], latoomutalpha -> vars[M_x]);
+ SETFLOAT(&latoomutalpha -> vars_out[M_y], latoomutalpha -> vars[M_y]);
+ SETFLOAT(&latoomutalpha -> params_out[M_a], latoomutalpha -> a);
+ SETFLOAT(&latoomutalpha -> params_out[M_b], latoomutalpha -> b);
+ SETFLOAT(&latoomutalpha -> params_out[M_c], latoomutalpha -> c);
+ SETFLOAT(&latoomutalpha -> params_out[M_d], latoomutalpha -> d);
+ outlet_list(latoomutalpha -> params_outlet, gensym("list"), M_param_count, latoomutalpha -> params_out);
+ outlet_list(latoomutalpha -> vars_outlet, gensym("list"), M_var_count, latoomutalpha -> vars_out);
+}
+
+static void show(latoomutalpha_struct *latoomutalpha) {
+ make_results(latoomutalpha);
+ outlet_anything(latoomutalpha -> search_outlet, gensym("show"), M_search_count, latoomutalpha -> search_out);
+}
+
+static void param(latoomutalpha_struct *latoomutalpha, t_symbol *s, int argc, t_atom *argv) {
+ if (argc != 4) {
+ post("Incorrect number of arguments for latoomutalpha fractal. Expecting 4 arguments.");
+ return;
+ }
+ latoomutalpha -> a = (double) atom_getfloatarg(0, argc, argv);
+ latoomutalpha -> b = (double) atom_getfloatarg(1, argc, argv);
+ latoomutalpha -> c = (double) atom_getfloatarg(2, argc, argv);
+ latoomutalpha -> d = (double) atom_getfloatarg(3, argc, argv);
+}
+
+static void seed(latoomutalpha_struct *latoomutalpha, 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(latoomutalpha_struct *latoomutalpha, t_floatarg l, t_floatarg h, t_floatarg lim) {
+ latoomutalpha -> lyap_lo = l;
+ latoomutalpha -> lyap_hi = h;
+ latoomutalpha -> lyap_limit = (double) ((int) lim);
+}
+
+static void elyap(latoomutalpha_struct *latoomutalpha) {
+ double results[M_var_count];
+ int i;
+ if (lyapunov_full((void *) latoomutalpha, (t_gotfn) calc, M_var_count, latoomutalpha -> vars, results) != NULL) {
+ post("elyapunov:");
+ for(i = 0; i < M_var_count; i++) { post("%d: %3.80f", i, results[i]); }
+ }
+}
+
+static void limiter(latoomutalpha_struct *latoomutalpha) {
+ if (latoomutalpha -> a_lo < M_a_lo) { latoomutalpha -> a_lo = M_a_lo; }
+ if (latoomutalpha -> a_lo > M_a_hi) { latoomutalpha -> a_lo = M_a_hi; }
+ if (latoomutalpha -> a_hi < M_a_lo) { latoomutalpha -> a_hi = M_a_lo; }
+ if (latoomutalpha -> a_hi > M_a_hi) { latoomutalpha -> a_hi = M_a_hi; }
+ if (latoomutalpha -> b_lo < M_b_lo) { latoomutalpha -> b_lo = M_b_lo; }
+ if (latoomutalpha -> b_lo > M_b_hi) { latoomutalpha -> b_lo = M_b_hi; }
+ if (latoomutalpha -> b_hi < M_b_lo) { latoomutalpha -> b_hi = M_b_lo; }
+ if (latoomutalpha -> b_hi > M_b_hi) { latoomutalpha -> b_hi = M_b_hi; }
+ if (latoomutalpha -> c_lo < M_c_lo) { latoomutalpha -> c_lo = M_c_lo; }
+ if (latoomutalpha -> c_lo > M_c_hi) { latoomutalpha -> c_lo = M_c_hi; }
+ if (latoomutalpha -> c_hi < M_c_lo) { latoomutalpha -> c_hi = M_c_lo; }
+ if (latoomutalpha -> c_hi > M_c_hi) { latoomutalpha -> c_hi = M_c_hi; }
+ if (latoomutalpha -> d_lo < M_d_lo) { latoomutalpha -> d_lo = M_d_lo; }
+ if (latoomutalpha -> d_lo > M_d_hi) { latoomutalpha -> d_lo = M_d_hi; }
+ if (latoomutalpha -> d_hi < M_d_lo) { latoomutalpha -> d_hi = M_d_lo; }
+ if (latoomutalpha -> d_hi > M_d_hi) { latoomutalpha -> d_hi = M_d_hi; }
+}
+
+static void constrain(latoomutalpha_struct *latoomutalpha, t_symbol *s, int argc, t_atom *argv) {
+ int i;
+ t_atom *arg = argv;
+ if (argc == 0) {
+ // reset to full limits of search ranges
+ latoomutalpha -> a_lo = M_a_lo;
+ latoomutalpha -> a_hi = M_a_hi;
+ latoomutalpha -> b_lo = M_b_lo;
+ latoomutalpha -> b_hi = M_b_hi;
+ latoomutalpha -> c_lo = M_c_lo;
+ latoomutalpha -> c_hi = M_c_hi;
+ latoomutalpha -> d_lo = M_d_lo;
+ latoomutalpha -> d_hi = M_d_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 d_spread = ((M_d_hi - M_d_lo) * percent) / 2;
+ latoomutalpha -> a_lo = latoomutalpha -> a - a_spread;
+ latoomutalpha -> a_hi = latoomutalpha -> a + a_spread;
+ latoomutalpha -> b_lo = latoomutalpha -> b - b_spread;
+ latoomutalpha -> b_hi = latoomutalpha -> b + b_spread;
+ latoomutalpha -> c_lo = latoomutalpha -> c - c_spread;
+ latoomutalpha -> c_hi = latoomutalpha -> c + c_spread;
+ latoomutalpha -> d_lo = latoomutalpha -> d - d_spread;
+ latoomutalpha -> d_hi = latoomutalpha -> d + d_spread;
+ limiter(latoomutalpha);
+ return;
+ }
+ if (argc != M_param_count * 2) {
+ post("Invalid number of arguments for latoomutalpha constraints, requires 8 values, got %d", argc);
+ return;
+ }
+ latoomutalpha -> a_lo = atom_getfloat(arg++);
+ latoomutalpha -> a_hi = atom_getfloat(arg++);
+ latoomutalpha -> b_lo = atom_getfloat(arg++);
+ latoomutalpha -> b_hi = atom_getfloat(arg++);
+ latoomutalpha -> c_lo = atom_getfloat(arg++);
+ latoomutalpha -> c_hi = atom_getfloat(arg++);
+ latoomutalpha -> d_lo = atom_getfloat(arg++);
+ latoomutalpha -> d_hi = atom_getfloat(arg++);
+ limiter(latoomutalpha);
+}
+
+static void search(latoomutalpha_struct *latoomutalpha, t_symbol *s, int argc, t_atom *argv) {
+ int not_found, not_expired = latoomutalpha -> lyap_limit;
+ int jump, i, iterations;
+ t_atom vars[M_var_count];
+ double temp_a = latoomutalpha -> a;
+ double temp_b = latoomutalpha -> b;
+ double temp_c = latoomutalpha -> c;
+ double temp_d = latoomutalpha -> d;
+ 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], latoomutalpha -> vars_init[i]);
+ }
+ }
+ do {
+ jump = 500;
+ not_found = 0;
+ iterations = 10000;
+ bad_params:
+ latoomutalpha -> a = (drand48() * (latoomutalpha -> a_hi - latoomutalpha -> a_lo)) + latoomutalpha -> a_lo;
+ latoomutalpha -> b = (drand48() * (latoomutalpha -> b_hi - latoomutalpha -> b_lo)) + latoomutalpha -> b_lo;
+ latoomutalpha -> c = (drand48() * (latoomutalpha -> c_hi - latoomutalpha -> c_lo)) + latoomutalpha -> c_lo;
+ latoomutalpha -> d = (drand48() * (latoomutalpha -> d_hi - latoomutalpha -> d_lo)) + latoomutalpha -> d_lo;
+ // put any preliminary checks specific to this fractal to eliminate bad_params
+
+ reset(latoomutalpha, NULL, argc, vars);
+ do { calc(latoomutalpha, latoomutalpha -> vars); } while(jump--);
+ latoomutalpha -> lyap_exp = lyapunov((void *) latoomutalpha, (t_gotfn) calc, M_var_count, (double *) latoomutalpha -> vars);
+ if (isnan(latoomutalpha -> lyap_exp)) { not_found = 1; }
+ if (latoomutalpha -> lyap_exp < latoomutalpha -> lyap_lo || latoomutalpha -> lyap_exp > latoomutalpha -> lyap_hi) { not_found = 1; }
+ not_expired--;
+ } while(not_found && not_expired);
+ reset(latoomutalpha, NULL, argc, vars);
+ if (!not_expired) {
+ post("Could not find a fractal after %d attempts.", (int) latoomutalpha -> lyap_limit);
+ post("Try using wider constraints.");
+ latoomutalpha -> a = temp_a;
+ latoomutalpha -> b = temp_b;
+ latoomutalpha -> c = temp_c;
+ latoomutalpha -> d = temp_d;
+ outlet_anything(latoomutalpha -> search_outlet, gensym("invalid"), 0, NULL);
+ } else {
+ latoomutalpha -> failure_ratio = (latoomutalpha -> lyap_limit - not_expired) / latoomutalpha -> lyap_limit;
+ make_results(latoomutalpha);
+ outlet_anything(latoomutalpha -> search_outlet, gensym("search"), M_search_count, latoomutalpha -> search_out);
+ }
+}
+
+void *latoomutalpha_new(t_symbol *s, int argc, t_atom *argv) {
+ latoomutalpha_struct *latoomutalpha = (latoomutalpha_struct *) pd_new(latoomutalpha_class);
+ if (latoomutalpha != NULL) {
+ outlet_new(&latoomutalpha -> x_obj, &s_float);
+ latoomutalpha -> outlets[0] = outlet_new(&latoomutalpha -> x_obj, &s_float);
+ latoomutalpha -> search_outlet = outlet_new(&latoomutalpha -> x_obj, &s_list);
+ latoomutalpha -> vars_outlet = outlet_new(&latoomutalpha -> x_obj, &s_list);
+ latoomutalpha -> params_outlet = outlet_new(&latoomutalpha -> x_obj, &s_list);
+ if (argc == M_param_count + M_var_count) {
+ latoomutalpha -> vars_init[M_x] = latoomutalpha -> vars[M_x] = (double) atom_getfloatarg(0, argc, argv);
+ latoomutalpha -> vars_init[M_y] = latoomutalpha -> vars[M_y] = (double) atom_getfloatarg(1, argc, argv);
+ latoomutalpha -> a = (double) atom_getfloatarg(2, argc, argv);
+ latoomutalpha -> b = (double) atom_getfloatarg(3, argc, argv);
+ latoomutalpha -> c = (double) atom_getfloatarg(4, argc, argv);
+ latoomutalpha -> d = (double) atom_getfloatarg(5, argc, argv);
+ } else {
+ if (argc != 0 && argc != M_param_count + M_var_count) {
+ post("Incorrect number of arguments for latoomutalpha fractal. Expecting 6 arguments.");
+ }
+ latoomutalpha -> vars_init[M_x] = 0.1;
+ latoomutalpha -> vars_init[M_y] = 0.1;
+ latoomutalpha -> a = 1;
+ latoomutalpha -> b = 1;
+ latoomutalpha -> c = 1;
+ latoomutalpha -> d = 1;
+ }
+ constrain(latoomutalpha, NULL, 0, NULL);
+ lyap(latoomutalpha, -1000000.0, 1000000.0, M_failure_limit);
+ }
+ return (void *)latoomutalpha;
+}
+
+void latoomutalpha_setup(void) {
+ latoomutalpha_class = class_new(gensym("latoomutalpha"), (t_newmethod) latoomutalpha_new, 0, sizeof(latoomutalpha_struct), 0, A_GIMME, 0);
+ class_addbang(latoomutalpha_class, (t_method) calculate);
+ class_addmethod(latoomutalpha_class, (t_method) reset, gensym("reset"), A_GIMME, 0);
+ class_addmethod(latoomutalpha_class, (t_method) show, gensym("show"), 0);
+ class_addmethod(latoomutalpha_class, (t_method) param, gensym("param"), A_GIMME, 0);
+ class_addmethod(latoomutalpha_class, (t_method) seed, gensym("seed"), A_GIMME, 0);
+ class_addmethod(latoomutalpha_class, (t_method) lyap, gensym("lyapunov"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(latoomutalpha_class, (t_method) elyap, gensym("elyapunov"), 0);
+ class_addmethod(latoomutalpha_class, (t_method) search, gensym("search"), A_GIMME, 0);
+ class_addmethod(latoomutalpha_class, (t_method) constrain, gensym("constrain"), A_GIMME, 0);
+ class_sethelpsymbol(latoomutalpha_class, gensym("help-latoomutalpha.pd"));
+}
+
diff --git a/latoomutbeta.c b/latoomutbeta.c
new file mode 100644
index 0000000..759cddd
--- /dev/null
+++ b/latoomutbeta.c
@@ -0,0 +1,325 @@
+/* latoomutbeta Attractor PD External */
+/* Copyright Michael McGonagle, from Cliff Pickover, 2003 */
+/* This program is distributed under the params of the GNU Public License */
+
+///////////////////////////////////////////////////////////////////////////////////
+/* This file is part of Chaos PD Externals. */
+/* */
+/* Chaos PD Externals are free software; you can redistribute them and/or modify */
+/* them under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* Chaos PD Externals are distributed in the hope that they will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with the Chaos PD Externals; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+///////////////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#include "lyapunov.h"
+
+#define M_a_lo -3
+#define M_a_hi 3
+#define M_b_lo -3
+#define M_b_hi 3
+#define M_c_lo 0.5
+#define M_c_hi 1.5
+#define M_d_lo 0.5
+#define M_d_hi 1.5
+
+#define M_a 0
+#define M_b 1
+#define M_c 2
+#define M_d 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 = "latoomutbeta v0.0, by Michael McGonagle, from Cliff Pickover, 2003";
+
+t_class *latoomutbeta_class;
+
+typedef struct latoomutbeta_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, d, d_lo, d_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];
+} latoomutbeta_struct;
+
+static void calc(latoomutbeta_struct *latoomutbeta, double *vars) {
+ double x_0, y_0;
+ x_0 =sin(vars[M_y]*latoomutbeta -> b)+pow(sin(vars[M_x]*latoomutbeta -> b),2);
+ y_0 =sin(vars[M_x]*latoomutbeta -> a)+pow(sin(vars[M_y]*latoomutbeta -> a),2);
+ vars[M_x] = x_0;
+ vars[M_y] = y_0;
+} // end calc
+
+static void calculate(latoomutbeta_struct *latoomutbeta) {
+ calc(latoomutbeta, latoomutbeta -> vars);
+ outlet_float(latoomutbeta -> x_obj.ob_outlet, latoomutbeta -> vars[M_x]);
+ outlet_float(latoomutbeta -> outlets[M_y - 1], latoomutbeta -> vars[M_y]);
+} // end calculate
+
+static void reset(latoomutbeta_struct *latoomutbeta, t_symbol *s, int argc, t_atom *argv) {
+ if (argc == M_var_count) {
+ latoomutbeta -> vars[M_x] = (double) atom_getfloatarg(M_x, argc, argv);
+ latoomutbeta -> vars[M_y] = (double) atom_getfloatarg(M_y, argc, argv);
+ } else {
+ latoomutbeta -> vars[M_x] = latoomutbeta -> vars_init[M_x];
+ latoomutbeta -> vars[M_y] = latoomutbeta -> vars_init[M_y];
+ } // end if
+} // end reset
+
+static char *classify(latoomutbeta_struct *latoomutbeta) {
+ static char buff[5];
+ char *c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ buff[0] = c[(int) (((latoomutbeta -> a - M_a_lo) * (1.0 / (M_a_hi - M_a_lo))) * 26)];
+ buff[1] = c[(int) (((latoomutbeta -> b - M_b_lo) * (1.0 / (M_b_hi - M_b_lo))) * 26)];
+ buff[2] = c[(int) (((latoomutbeta -> c - M_c_lo) * (1.0 / (M_c_hi - M_c_lo))) * 26)];
+ buff[3] = c[(int) (((latoomutbeta -> d - M_d_lo) * (1.0 / (M_d_hi - M_d_lo))) * 26)];
+ buff[4] = '\0';
+ return buff;
+}
+
+static void make_results(latoomutbeta_struct *latoomutbeta) {
+ SETFLOAT(&latoomutbeta -> search_out[0], latoomutbeta -> lyap_exp);
+ SETSYMBOL(&latoomutbeta -> search_out[1], gensym(classify(latoomutbeta)));
+ SETFLOAT(&latoomutbeta -> search_out[2], latoomutbeta -> failure_ratio);
+ SETFLOAT(&latoomutbeta -> vars_out[M_x], latoomutbeta -> vars[M_x]);
+ SETFLOAT(&latoomutbeta -> vars_out[M_y], latoomutbeta -> vars[M_y]);
+ SETFLOAT(&latoomutbeta -> params_out[M_a], latoomutbeta -> a);
+ SETFLOAT(&latoomutbeta -> params_out[M_b], latoomutbeta -> b);
+ SETFLOAT(&latoomutbeta -> params_out[M_c], latoomutbeta -> c);
+ SETFLOAT(&latoomutbeta -> params_out[M_d], latoomutbeta -> d);
+ outlet_list(latoomutbeta -> params_outlet, gensym("list"), M_param_count, latoomutbeta -> params_out);
+ outlet_list(latoomutbeta -> vars_outlet, gensym("list"), M_var_count, latoomutbeta -> vars_out);
+}
+
+static void show(latoomutbeta_struct *latoomutbeta) {
+ make_results(latoomutbeta);
+ outlet_anything(latoomutbeta -> search_outlet, gensym("show"), M_search_count, latoomutbeta -> search_out);
+}
+
+static void param(latoomutbeta_struct *latoomutbeta, t_symbol *s, int argc, t_atom *argv) {
+ if (argc != 4) {
+ post("Incorrect number of arguments for latoomutbeta fractal. Expecting 4 arguments.");
+ return;
+ }
+ latoomutbeta -> a = (double) atom_getfloatarg(0, argc, argv);
+ latoomutbeta -> b = (double) atom_getfloatarg(1, argc, argv);
+ latoomutbeta -> c = (double) atom_getfloatarg(2, argc, argv);
+ latoomutbeta -> d = (double) atom_getfloatarg(3, argc, argv);
+}
+
+static void seed(latoomutbeta_struct *latoomutbeta, 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(latoomutbeta_struct *latoomutbeta, t_floatarg l, t_floatarg h, t_floatarg lim) {
+ latoomutbeta -> lyap_lo = l;
+ latoomutbeta -> lyap_hi = h;
+ latoomutbeta -> lyap_limit = (double) ((int) lim);
+}
+
+static void elyap(latoomutbeta_struct *latoomutbeta) {
+ double results[M_var_count];
+ int i;
+ if (lyapunov_full((void *) latoomutbeta, (t_gotfn) calc, M_var_count, latoomutbeta -> vars, results) != NULL) {
+ post("elyapunov:");
+ for(i = 0; i < M_var_count; i++) { post("%d: %3.80f", i, results[i]); }
+ }
+}
+
+static void limiter(latoomutbeta_struct *latoomutbeta) {
+ if (latoomutbeta -> a_lo < M_a_lo) { latoomutbeta -> a_lo = M_a_lo; }
+ if (latoomutbeta -> a_lo > M_a_hi) { latoomutbeta -> a_lo = M_a_hi; }
+ if (latoomutbeta -> a_hi < M_a_lo) { latoomutbeta -> a_hi = M_a_lo; }
+ if (latoomutbeta -> a_hi > M_a_hi) { latoomutbeta -> a_hi = M_a_hi; }
+ if (latoomutbeta -> b_lo < M_b_lo) { latoomutbeta -> b_lo = M_b_lo; }
+ if (latoomutbeta -> b_lo > M_b_hi) { latoomutbeta -> b_lo = M_b_hi; }
+ if (latoomutbeta -> b_hi < M_b_lo) { latoomutbeta -> b_hi = M_b_lo; }
+ if (latoomutbeta -> b_hi > M_b_hi) { latoomutbeta -> b_hi = M_b_hi; }
+ if (latoomutbeta -> c_lo < M_c_lo) { latoomutbeta -> c_lo = M_c_lo; }
+ if (latoomutbeta -> c_lo > M_c_hi) { latoomutbeta -> c_lo = M_c_hi; }
+ if (latoomutbeta -> c_hi < M_c_lo) { latoomutbeta -> c_hi = M_c_lo; }
+ if (latoomutbeta -> c_hi > M_c_hi) { latoomutbeta -> c_hi = M_c_hi; }
+ if (latoomutbeta -> d_lo < M_d_lo) { latoomutbeta -> d_lo = M_d_lo; }
+ if (latoomutbeta -> d_lo > M_d_hi) { latoomutbeta -> d_lo = M_d_hi; }
+ if (latoomutbeta -> d_hi < M_d_lo) { latoomutbeta -> d_hi = M_d_lo; }
+ if (latoomutbeta -> d_hi > M_d_hi) { latoomutbeta -> d_hi = M_d_hi; }
+}
+
+static void constrain(latoomutbeta_struct *latoomutbeta, t_symbol *s, int argc, t_atom *argv) {
+ int i;
+ t_atom *arg = argv;
+ if (argc == 0) {
+ // reset to full limits of search ranges
+ latoomutbeta -> a_lo = M_a_lo;
+ latoomutbeta -> a_hi = M_a_hi;
+ latoomutbeta -> b_lo = M_b_lo;
+ latoomutbeta -> b_hi = M_b_hi;
+ latoomutbeta -> c_lo = M_c_lo;
+ latoomutbeta -> c_hi = M_c_hi;
+ latoomutbeta -> d_lo = M_d_lo;
+ latoomutbeta -> d_hi = M_d_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 d_spread = ((M_d_hi - M_d_lo) * percent) / 2;
+ latoomutbeta -> a_lo = latoomutbeta -> a - a_spread;
+ latoomutbeta -> a_hi = latoomutbeta -> a + a_spread;
+ latoomutbeta -> b_lo = latoomutbeta -> b - b_spread;
+ latoomutbeta -> b_hi = latoomutbeta -> b + b_spread;
+ latoomutbeta -> c_lo = latoomutbeta -> c - c_spread;
+ latoomutbeta -> c_hi = latoomutbeta -> c + c_spread;
+ latoomutbeta -> d_lo = latoomutbeta -> d - d_spread;
+ latoomutbeta -> d_hi = latoomutbeta -> d + d_spread;
+ limiter(latoomutbeta);
+ return;
+ }
+ if (argc != M_param_count * 2) {
+ post("Invalid number of arguments for latoomutbeta constraints, requires 8 values, got %d", argc);
+ return;
+ }
+ latoomutbeta -> a_lo = atom_getfloat(arg++);
+ latoomutbeta -> a_hi = atom_getfloat(arg++);
+ latoomutbeta -> b_lo = atom_getfloat(arg++);
+ latoomutbeta -> b_hi = atom_getfloat(arg++);
+ latoomutbeta -> c_lo = atom_getfloat(arg++);
+ latoomutbeta -> c_hi = atom_getfloat(arg++);
+ latoomutbeta -> d_lo = atom_getfloat(arg++);
+ latoomutbeta -> d_hi = atom_getfloat(arg++);
+ limiter(latoomutbeta);
+}
+
+static void search(latoomutbeta_struct *latoomutbeta, t_symbol *s, int argc, t_atom *argv) {
+ int not_found, not_expired = latoomutbeta -> lyap_limit;
+ int jump, i, iterations;
+ t_atom vars[M_var_count];
+ double temp_a = latoomutbeta -> a;
+ double temp_b = latoomutbeta -> b;
+ double temp_c = latoomutbeta -> c;
+ double temp_d = latoomutbeta -> d;
+ 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], latoomutbeta -> vars_init[i]);
+ }
+ }
+ do {
+ jump = 500;
+ not_found = 0;
+ iterations = 10000;
+ bad_params:
+ latoomutbeta -> a = (drand48() * (latoomutbeta -> a_hi - latoomutbeta -> a_lo)) + latoomutbeta -> a_lo;
+ latoomutbeta -> b = (drand48() * (latoomutbeta -> b_hi - latoomutbeta -> b_lo)) + latoomutbeta -> b_lo;
+ latoomutbeta -> c = (drand48() * (latoomutbeta -> c_hi - latoomutbeta -> c_lo)) + latoomutbeta -> c_lo;
+ latoomutbeta -> d = (drand48() * (latoomutbeta -> d_hi - latoomutbeta -> d_lo)) + latoomutbeta -> d_lo;
+ // put any preliminary checks specific to this fractal to eliminate bad_params
+
+ reset(latoomutbeta, NULL, argc, vars);
+ do { calc(latoomutbeta, latoomutbeta -> vars); } while(jump--);
+ latoomutbeta -> lyap_exp = lyapunov((void *) latoomutbeta, (t_gotfn) calc, M_var_count, (double *) latoomutbeta -> vars);
+ if (isnan(latoomutbeta -> lyap_exp)) { not_found = 1; }
+ if (latoomutbeta -> lyap_exp < latoomutbeta -> lyap_lo || latoomutbeta -> lyap_exp > latoomutbeta -> lyap_hi) { not_found = 1; }
+ not_expired--;
+ } while(not_found && not_expired);
+ reset(latoomutbeta, NULL, argc, vars);
+ if (!not_expired) {
+ post("Could not find a fractal after %d attempts.", (int) latoomutbeta -> lyap_limit);
+ post("Try using wider constraints.");
+ latoomutbeta -> a = temp_a;
+ latoomutbeta -> b = temp_b;
+ latoomutbeta -> c = temp_c;
+ latoomutbeta -> d = temp_d;
+ outlet_anything(latoomutbeta -> search_outlet, gensym("invalid"), 0, NULL);
+ } else {
+ latoomutbeta -> failure_ratio = (latoomutbeta -> lyap_limit - not_expired) / latoomutbeta -> lyap_limit;
+ make_results(latoomutbeta);
+ outlet_anything(latoomutbeta -> search_outlet, gensym("search"), M_search_count, latoomutbeta -> search_out);
+ }
+}
+
+void *latoomutbeta_new(t_symbol *s, int argc, t_atom *argv) {
+ latoomutbeta_struct *latoomutbeta = (latoomutbeta_struct *) pd_new(latoomutbeta_class);
+ if (latoomutbeta != NULL) {
+ outlet_new(&latoomutbeta -> x_obj, &s_float);
+ latoomutbeta -> outlets[0] = outlet_new(&latoomutbeta -> x_obj, &s_float);
+ latoomutbeta -> search_outlet = outlet_new(&latoomutbeta -> x_obj, &s_list);
+ latoomutbeta -> vars_outlet = outlet_new(&latoomutbeta -> x_obj, &s_list);
+ latoomutbeta -> params_outlet = outlet_new(&latoomutbeta -> x_obj, &s_list);
+ if (argc == M_param_count + M_var_count) {
+ latoomutbeta -> vars_init[M_x] = latoomutbeta -> vars[M_x] = (double) atom_getfloatarg(0, argc, argv);
+ latoomutbeta -> vars_init[M_y] = latoomutbeta -> vars[M_y] = (double) atom_getfloatarg(1, argc, argv);
+ latoomutbeta -> a = (double) atom_getfloatarg(2, argc, argv);
+ latoomutbeta -> b = (double) atom_getfloatarg(3, argc, argv);
+ latoomutbeta -> c = (double) atom_getfloatarg(4, argc, argv);
+ latoomutbeta -> d = (double) atom_getfloatarg(5, argc, argv);
+ } else {
+ if (argc != 0 && argc != M_param_count + M_var_count) {
+ post("Incorrect number of arguments for latoomutbeta fractal. Expecting 6 arguments.");
+ }
+ latoomutbeta -> vars_init[M_x] = 0.1;
+ latoomutbeta -> vars_init[M_y] = 0.1;
+ latoomutbeta -> a = 1;
+ latoomutbeta -> b = 1;
+ latoomutbeta -> c = 1;
+ latoomutbeta -> d = 1;
+ }
+ constrain(latoomutbeta, NULL, 0, NULL);
+ lyap(latoomutbeta, -1000000.0, 1000000.0, M_failure_limit);
+ }
+ return (void *)latoomutbeta;
+}
+
+void latoomutbeta_setup(void) {
+ latoomutbeta_class = class_new(gensym("latoomutbeta"), (t_newmethod) latoomutbeta_new, 0, sizeof(latoomutbeta_struct), 0, A_GIMME, 0);
+ class_addbang(latoomutbeta_class, (t_method) calculate);
+ class_addmethod(latoomutbeta_class, (t_method) reset, gensym("reset"), A_GIMME, 0);
+ class_addmethod(latoomutbeta_class, (t_method) show, gensym("show"), 0);
+ class_addmethod(latoomutbeta_class, (t_method) param, gensym("param"), A_GIMME, 0);
+ class_addmethod(latoomutbeta_class, (t_method) seed, gensym("seed"), A_GIMME, 0);
+ class_addmethod(latoomutbeta_class, (t_method) lyap, gensym("lyapunov"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(latoomutbeta_class, (t_method) elyap, gensym("elyapunov"), 0);
+ class_addmethod(latoomutbeta_class, (t_method) search, gensym("search"), A_GIMME, 0);
+ class_addmethod(latoomutbeta_class, (t_method) constrain, gensym("constrain"), A_GIMME, 0);
+ class_sethelpsymbol(latoomutbeta_class, gensym("help-latoomutbeta.pd"));
+}
+
diff --git a/latoomutgamma.c b/latoomutgamma.c
new file mode 100644
index 0000000..ea9f717
--- /dev/null
+++ b/latoomutgamma.c
@@ -0,0 +1,325 @@
+/* latoomutgamma Attractor PD External */
+/* Copyright Michael McGonagle, from Cliff Pickover, 2003 */
+/* This program is distributed under the params of the GNU Public License */
+
+///////////////////////////////////////////////////////////////////////////////////
+/* This file is part of Chaos PD Externals. */
+/* */
+/* Chaos PD Externals are free software; you can redistribute them and/or modify */
+/* them under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* Chaos PD Externals are distributed in the hope that they will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with the Chaos PD Externals; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+///////////////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#include "lyapunov.h"
+
+#define M_a_lo -3
+#define M_a_hi 3
+#define M_b_lo -3
+#define M_b_hi 3
+#define M_c_lo 0.5
+#define M_c_hi 1.5
+#define M_d_lo 0.5
+#define M_d_hi 1.5
+
+#define M_a 0
+#define M_b 1
+#define M_c 2
+#define M_d 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 = "latoomutgamma v0.0, by Michael McGonagle, from Cliff Pickover, 2003";
+
+t_class *latoomutgamma_class;
+
+typedef struct latoomutgamma_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, d, d_lo, d_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];
+} latoomutgamma_struct;
+
+static void calc(latoomutgamma_struct *latoomutgamma, double *vars) {
+ double x_0, y_0;
+ x_0 =abs(sin(vars[M_y]*latoomutgamma -> b))+pow(sin(vars[M_x]*latoomutgamma -> b),2);
+ y_0 =abs(sin(vars[M_x]*latoomutgamma -> a))+pow(sin(vars[M_y]*latoomutgamma -> b),2);
+ vars[M_x] = x_0;
+ vars[M_y] = y_0;
+} // end calc
+
+static void calculate(latoomutgamma_struct *latoomutgamma) {
+ calc(latoomutgamma, latoomutgamma -> vars);
+ outlet_float(latoomutgamma -> x_obj.ob_outlet, latoomutgamma -> vars[M_x]);
+ outlet_float(latoomutgamma -> outlets[M_y - 1], latoomutgamma -> vars[M_y]);
+} // end calculate
+
+static void reset(latoomutgamma_struct *latoomutgamma, t_symbol *s, int argc, t_atom *argv) {
+ if (argc == M_var_count) {
+ latoomutgamma -> vars[M_x] = (double) atom_getfloatarg(M_x, argc, argv);
+ latoomutgamma -> vars[M_y] = (double) atom_getfloatarg(M_y, argc, argv);
+ } else {
+ latoomutgamma -> vars[M_x] = latoomutgamma -> vars_init[M_x];
+ latoomutgamma -> vars[M_y] = latoomutgamma -> vars_init[M_y];
+ } // end if
+} // end reset
+
+static char *classify(latoomutgamma_struct *latoomutgamma) {
+ static char buff[5];
+ char *c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ buff[0] = c[(int) (((latoomutgamma -> a - M_a_lo) * (1.0 / (M_a_hi - M_a_lo))) * 26)];
+ buff[1] = c[(int) (((latoomutgamma -> b - M_b_lo) * (1.0 / (M_b_hi - M_b_lo))) * 26)];
+ buff[2] = c[(int) (((latoomutgamma -> c - M_c_lo) * (1.0 / (M_c_hi - M_c_lo))) * 26)];
+ buff[3] = c[(int) (((latoomutgamma -> d - M_d_lo) * (1.0 / (M_d_hi - M_d_lo))) * 26)];
+ buff[4] = '\0';
+ return buff;
+}
+
+static void make_results(latoomutgamma_struct *latoomutgamma) {
+ SETFLOAT(&latoomutgamma -> search_out[0], latoomutgamma -> lyap_exp);
+ SETSYMBOL(&latoomutgamma -> search_out[1], gensym(classify(latoomutgamma)));
+ SETFLOAT(&latoomutgamma -> search_out[2], latoomutgamma -> failure_ratio);
+ SETFLOAT(&latoomutgamma -> vars_out[M_x], latoomutgamma -> vars[M_x]);
+ SETFLOAT(&latoomutgamma -> vars_out[M_y], latoomutgamma -> vars[M_y]);
+ SETFLOAT(&latoomutgamma -> params_out[M_a], latoomutgamma -> a);
+ SETFLOAT(&latoomutgamma -> params_out[M_b], latoomutgamma -> b);
+ SETFLOAT(&latoomutgamma -> params_out[M_c], latoomutgamma -> c);
+ SETFLOAT(&latoomutgamma -> params_out[M_d], latoomutgamma -> d);
+ outlet_list(latoomutgamma -> params_outlet, gensym("list"), M_param_count, latoomutgamma -> params_out);
+ outlet_list(latoomutgamma -> vars_outlet, gensym("list"), M_var_count, latoomutgamma -> vars_out);
+}
+
+static void show(latoomutgamma_struct *latoomutgamma) {
+ make_results(latoomutgamma);
+ outlet_anything(latoomutgamma -> search_outlet, gensym("show"), M_search_count, latoomutgamma -> search_out);
+}
+
+static void param(latoomutgamma_struct *latoomutgamma, t_symbol *s, int argc, t_atom *argv) {
+ if (argc != 4) {
+ post("Incorrect number of arguments for latoomutgamma fractal. Expecting 4 arguments.");
+ return;
+ }
+ latoomutgamma -> a = (double) atom_getfloatarg(0, argc, argv);
+ latoomutgamma -> b = (double) atom_getfloatarg(1, argc, argv);
+ latoomutgamma -> c = (double) atom_getfloatarg(2, argc, argv);
+ latoomutgamma -> d = (double) atom_getfloatarg(3, argc, argv);
+}
+
+static void seed(latoomutgamma_struct *latoomutgamma, 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(latoomutgamma_struct *latoomutgamma, t_floatarg l, t_floatarg h, t_floatarg lim) {
+ latoomutgamma -> lyap_lo = l;
+ latoomutgamma -> lyap_hi = h;
+ latoomutgamma -> lyap_limit = (double) ((int) lim);
+}
+
+static void elyap(latoomutgamma_struct *latoomutgamma) {
+ double results[M_var_count];
+ int i;
+ if (lyapunov_full((void *) latoomutgamma, (t_gotfn) calc, M_var_count, latoomutgamma -> vars, results) != NULL) {
+ post("elyapunov:");
+ for(i = 0; i < M_var_count; i++) { post("%d: %3.80f", i, results[i]); }
+ }
+}
+
+static void limiter(latoomutgamma_struct *latoomutgamma) {
+ if (latoomutgamma -> a_lo < M_a_lo) { latoomutgamma -> a_lo = M_a_lo; }
+ if (latoomutgamma -> a_lo > M_a_hi) { latoomutgamma -> a_lo = M_a_hi; }
+ if (latoomutgamma -> a_hi < M_a_lo) { latoomutgamma -> a_hi = M_a_lo; }
+ if (latoomutgamma -> a_hi > M_a_hi) { latoomutgamma -> a_hi = M_a_hi; }
+ if (latoomutgamma -> b_lo < M_b_lo) { latoomutgamma -> b_lo = M_b_lo; }
+ if (latoomutgamma -> b_lo > M_b_hi) { latoomutgamma -> b_lo = M_b_hi; }
+ if (latoomutgamma -> b_hi < M_b_lo) { latoomutgamma -> b_hi = M_b_lo; }
+ if (latoomutgamma -> b_hi > M_b_hi) { latoomutgamma -> b_hi = M_b_hi; }
+ if (latoomutgamma -> c_lo < M_c_lo) { latoomutgamma -> c_lo = M_c_lo; }
+ if (latoomutgamma -> c_lo > M_c_hi) { latoomutgamma -> c_lo = M_c_hi; }
+ if (latoomutgamma -> c_hi < M_c_lo) { latoomutgamma -> c_hi = M_c_lo; }
+ if (latoomutgamma -> c_hi > M_c_hi) { latoomutgamma -> c_hi = M_c_hi; }
+ if (latoomutgamma -> d_lo < M_d_lo) { latoomutgamma -> d_lo = M_d_lo; }
+ if (latoomutgamma -> d_lo > M_d_hi) { latoomutgamma -> d_lo = M_d_hi; }
+ if (latoomutgamma -> d_hi < M_d_lo) { latoomutgamma -> d_hi = M_d_lo; }
+ if (latoomutgamma -> d_hi > M_d_hi) { latoomutgamma -> d_hi = M_d_hi; }
+}
+
+static void constrain(latoomutgamma_struct *latoomutgamma, t_symbol *s, int argc, t_atom *argv) {
+ int i;
+ t_atom *arg = argv;
+ if (argc == 0) {
+ // reset to full limits of search ranges
+ latoomutgamma -> a_lo = M_a_lo;
+ latoomutgamma -> a_hi = M_a_hi;
+ latoomutgamma -> b_lo = M_b_lo;
+ latoomutgamma -> b_hi = M_b_hi;
+ latoomutgamma -> c_lo = M_c_lo;
+ latoomutgamma -> c_hi = M_c_hi;
+ latoomutgamma -> d_lo = M_d_lo;
+ latoomutgamma -> d_hi = M_d_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 d_spread = ((M_d_hi - M_d_lo) * percent) / 2;
+ latoomutgamma -> a_lo = latoomutgamma -> a - a_spread;
+ latoomutgamma -> a_hi = latoomutgamma -> a + a_spread;
+ latoomutgamma -> b_lo = latoomutgamma -> b - b_spread;
+ latoomutgamma -> b_hi = latoomutgamma -> b + b_spread;
+ latoomutgamma -> c_lo = latoomutgamma -> c - c_spread;
+ latoomutgamma -> c_hi = latoomutgamma -> c + c_spread;
+ latoomutgamma -> d_lo = latoomutgamma -> d - d_spread;
+ latoomutgamma -> d_hi = latoomutgamma -> d + d_spread;
+ limiter(latoomutgamma);
+ return;
+ }
+ if (argc != M_param_count * 2) {
+ post("Invalid number of arguments for latoomutgamma constraints, requires 8 values, got %d", argc);
+ return;
+ }
+ latoomutgamma -> a_lo = atom_getfloat(arg++);
+ latoomutgamma -> a_hi = atom_getfloat(arg++);
+ latoomutgamma -> b_lo = atom_getfloat(arg++);
+ latoomutgamma -> b_hi = atom_getfloat(arg++);
+ latoomutgamma -> c_lo = atom_getfloat(arg++);
+ latoomutgamma -> c_hi = atom_getfloat(arg++);
+ latoomutgamma -> d_lo = atom_getfloat(arg++);
+ latoomutgamma -> d_hi = atom_getfloat(arg++);
+ limiter(latoomutgamma);
+}
+
+static void search(latoomutgamma_struct *latoomutgamma, t_symbol *s, int argc, t_atom *argv) {
+ int not_found, not_expired = latoomutgamma -> lyap_limit;
+ int jump, i, iterations;
+ t_atom vars[M_var_count];
+ double temp_a = latoomutgamma -> a;
+ double temp_b = latoomutgamma -> b;
+ double temp_c = latoomutgamma -> c;
+ double temp_d = latoomutgamma -> d;
+ 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], latoomutgamma -> vars_init[i]);
+ }
+ }
+ do {
+ jump = 500;
+ not_found = 0;
+ iterations = 10000;
+ bad_params:
+ latoomutgamma -> a = (drand48() * (latoomutgamma -> a_hi - latoomutgamma -> a_lo)) + latoomutgamma -> a_lo;
+ latoomutgamma -> b = (drand48() * (latoomutgamma -> b_hi - latoomutgamma -> b_lo)) + latoomutgamma -> b_lo;
+ latoomutgamma -> c = (drand48() * (latoomutgamma -> c_hi - latoomutgamma -> c_lo)) + latoomutgamma -> c_lo;
+ latoomutgamma -> d = (drand48() * (latoomutgamma -> d_hi - latoomutgamma -> d_lo)) + latoomutgamma -> d_lo;
+ // put any preliminary checks specific to this fractal to eliminate bad_params
+
+ reset(latoomutgamma, NULL, argc, vars);
+ do { calc(latoomutgamma, latoomutgamma -> vars); } while(jump--);
+ latoomutgamma -> lyap_exp = lyapunov((void *) latoomutgamma, (t_gotfn) calc, M_var_count, (double *) latoomutgamma -> vars);
+ if (isnan(latoomutgamma -> lyap_exp)) { not_found = 1; }
+ if (latoomutgamma -> lyap_exp < latoomutgamma -> lyap_lo || latoomutgamma -> lyap_exp > latoomutgamma -> lyap_hi) { not_found = 1; }
+ not_expired--;
+ } while(not_found && not_expired);
+ reset(latoomutgamma, NULL, argc, vars);
+ if (!not_expired) {
+ post("Could not find a fractal after %d attempts.", (int) latoomutgamma -> lyap_limit);
+ post("Try using wider constraints.");
+ latoomutgamma -> a = temp_a;
+ latoomutgamma -> b = temp_b;
+ latoomutgamma -> c = temp_c;
+ latoomutgamma -> d = temp_d;
+ outlet_anything(latoomutgamma -> search_outlet, gensym("invalid"), 0, NULL);
+ } else {
+ latoomutgamma -> failure_ratio = (latoomutgamma -> lyap_limit - not_expired) / latoomutgamma -> lyap_limit;
+ make_results(latoomutgamma);
+ outlet_anything(latoomutgamma -> search_outlet, gensym("search"), M_search_count, latoomutgamma -> search_out);
+ }
+}
+
+void *latoomutgamma_new(t_symbol *s, int argc, t_atom *argv) {
+ latoomutgamma_struct *latoomutgamma = (latoomutgamma_struct *) pd_new(latoomutgamma_class);
+ if (latoomutgamma != NULL) {
+ outlet_new(&latoomutgamma -> x_obj, &s_float);
+ latoomutgamma -> outlets[0] = outlet_new(&latoomutgamma -> x_obj, &s_float);
+ latoomutgamma -> search_outlet = outlet_new(&latoomutgamma -> x_obj, &s_list);
+ latoomutgamma -> vars_outlet = outlet_new(&latoomutgamma -> x_obj, &s_list);
+ latoomutgamma -> params_outlet = outlet_new(&latoomutgamma -> x_obj, &s_list);
+ if (argc == M_param_count + M_var_count) {
+ latoomutgamma -> vars_init[M_x] = latoomutgamma -> vars[M_x] = (double) atom_getfloatarg(0, argc, argv);
+ latoomutgamma -> vars_init[M_y] = latoomutgamma -> vars[M_y] = (double) atom_getfloatarg(1, argc, argv);
+ latoomutgamma -> a = (double) atom_getfloatarg(2, argc, argv);
+ latoomutgamma -> b = (double) atom_getfloatarg(3, argc, argv);
+ latoomutgamma -> c = (double) atom_getfloatarg(4, argc, argv);
+ latoomutgamma -> d = (double) atom_getfloatarg(5, argc, argv);
+ } else {
+ if (argc != 0 && argc != M_param_count + M_var_count) {
+ post("Incorrect number of arguments for latoomutgamma fractal. Expecting 6 arguments.");
+ }
+ latoomutgamma -> vars_init[M_x] = 0.1;
+ latoomutgamma -> vars_init[M_y] = 0.1;
+ latoomutgamma -> a = 1;
+ latoomutgamma -> b = 1;
+ latoomutgamma -> c = 1;
+ latoomutgamma -> d = 1;
+ }
+ constrain(latoomutgamma, NULL, 0, NULL);
+ lyap(latoomutgamma, -1000000.0, 1000000.0, M_failure_limit);
+ }
+ return (void *)latoomutgamma;
+}
+
+void latoomutgamma_setup(void) {
+ latoomutgamma_class = class_new(gensym("latoomutgamma"), (t_newmethod) latoomutgamma_new, 0, sizeof(latoomutgamma_struct), 0, A_GIMME, 0);
+ class_addbang(latoomutgamma_class, (t_method) calculate);
+ class_addmethod(latoomutgamma_class, (t_method) reset, gensym("reset"), A_GIMME, 0);
+ class_addmethod(latoomutgamma_class, (t_method) show, gensym("show"), 0);
+ class_addmethod(latoomutgamma_class, (t_method) param, gensym("param"), A_GIMME, 0);
+ class_addmethod(latoomutgamma_class, (t_method) seed, gensym("seed"), A_GIMME, 0);
+ class_addmethod(latoomutgamma_class, (t_method) lyap, gensym("lyapunov"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(latoomutgamma_class, (t_method) elyap, gensym("elyapunov"), 0);
+ class_addmethod(latoomutgamma_class, (t_method) search, gensym("search"), A_GIMME, 0);
+ class_addmethod(latoomutgamma_class, (t_method) constrain, gensym("constrain"), A_GIMME, 0);
+ class_sethelpsymbol(latoomutgamma_class, gensym("help-latoomutgamma.pd"));
+}
+
diff --git a/mlogistic.c b/mlogistic.c
new file mode 100644
index 0000000..def932b
--- /dev/null
+++ b/mlogistic.c
@@ -0,0 +1,247 @@
+/* mlogistic Attractor PD External */
+/* Copyright Michael McGonagle, from ??????, 2003 */
+/* This program is distributed under the params of the GNU Public License */
+
+///////////////////////////////////////////////////////////////////////////////////
+/* This file is part of Chaos PD Externals. */
+/* */
+/* Chaos PD Externals are free software; you can redistribute them and/or modify */
+/* them under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* Chaos PD Externals are distributed in the hope that they will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with the Chaos PD Externals; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+///////////////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#include "lyapunov.h"
+
+#define M_c_lo 0
+#define M_c_hi 4
+
+#define M_c 0
+
+#define M_x 0
+
+#define M_param_count 1
+#define M_var_count 1
+#define M_search_count 3
+#define M_failure_limit 1000
+
+static char *version = "mlogistic v0.0, by Michael McGonagle, from ??????, 2003";
+
+t_class *mlogistic_class;
+
+typedef struct mlogistic_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 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;
+} mlogistic_struct;
+
+static void calc(mlogistic_struct *mlogistic, double *vars) {
+ double x_0;
+ x_0 =(vars[M_x]*vars[M_x])+mlogistic -> c;
+ vars[M_x] = x_0;
+} // end calc
+
+static void calculate(mlogistic_struct *mlogistic) {
+ calc(mlogistic, mlogistic -> vars);
+ outlet_float(mlogistic -> x_obj.ob_outlet, mlogistic -> vars[M_x]);
+} // end calculate
+
+static void reset(mlogistic_struct *mlogistic, t_symbol *s, int argc, t_atom *argv) {
+ if (argc == M_var_count) {
+ mlogistic -> vars[M_x] = (double) atom_getfloatarg(M_x, argc, argv);
+ } else {
+ mlogistic -> vars[M_x] = mlogistic -> vars_init[M_x];
+ } // end if
+} // end reset
+
+static char *classify(mlogistic_struct *mlogistic) {
+ static char buff[2];
+ char *c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ buff[0] = c[(int) (((mlogistic -> c - M_c_lo) * (1.0 / (M_c_hi - M_c_lo))) * 26)];
+ buff[1] = '\0';
+ return buff;
+}
+
+static void make_results(mlogistic_struct *mlogistic) {
+ SETFLOAT(&mlogistic -> search_out[0], mlogistic -> lyap_exp);
+ SETSYMBOL(&mlogistic -> search_out[1], gensym(classify(mlogistic)));
+ SETFLOAT(&mlogistic -> search_out[2], mlogistic -> failure_ratio);
+ SETFLOAT(&mlogistic -> vars_out[M_x], mlogistic -> vars[M_x]);
+ SETFLOAT(&mlogistic -> params_out[M_c], mlogistic -> c);
+ outlet_list(mlogistic -> params_outlet, gensym("list"), M_param_count, mlogistic -> params_out);
+ outlet_list(mlogistic -> vars_outlet, gensym("list"), M_var_count, mlogistic -> vars_out);
+}
+
+static void show(mlogistic_struct *mlogistic) {
+ make_results(mlogistic);
+ outlet_anything(mlogistic -> search_outlet, gensym("show"), M_search_count, mlogistic -> search_out);
+}
+
+static void param(mlogistic_struct *mlogistic, t_symbol *s, int argc, t_atom *argv) {
+ if (argc != 1) {
+ post("Incorrect number of arguments for mlogistic fractal. Expecting 1 arguments.");
+ return;
+ }
+ mlogistic -> c = (double) atom_getfloatarg(0, argc, argv);
+}
+
+static void seed(mlogistic_struct *mlogistic, 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(mlogistic_struct *mlogistic, t_floatarg l, t_floatarg h, t_floatarg lim) {
+ mlogistic -> lyap_lo = l;
+ mlogistic -> lyap_hi = h;
+ mlogistic -> lyap_limit = (double) ((int) lim);
+}
+
+static void elyap(mlogistic_struct *mlogistic) {
+ double results[M_var_count];
+ int i;
+ if (lyapunov_full((void *) mlogistic, (t_gotfn) calc, M_var_count, mlogistic -> vars, results) != NULL) {
+ post("elyapunov:");
+ for(i = 0; i < M_var_count; i++) { post("%d: %3.80f", i, results[i]); }
+ }
+}
+
+static void limiter(mlogistic_struct *mlogistic) {
+ if (mlogistic -> c_lo < M_c_lo) { mlogistic -> c_lo = M_c_lo; }
+ if (mlogistic -> c_lo > M_c_hi) { mlogistic -> c_lo = M_c_hi; }
+ if (mlogistic -> c_hi < M_c_lo) { mlogistic -> c_hi = M_c_lo; }
+ if (mlogistic -> c_hi > M_c_hi) { mlogistic -> c_hi = M_c_hi; }
+}
+
+static void constrain(mlogistic_struct *mlogistic, t_symbol *s, int argc, t_atom *argv) {
+ int i;
+ t_atom *arg = argv;
+ if (argc == 0) {
+ // reset to full limits of search ranges
+ mlogistic -> c_lo = M_c_lo;
+ mlogistic -> c_hi = M_c_hi;
+ return;
+ }
+ if (argc == 1) {
+ // set the ranges based on percentage of full range
+ double percent = atom_getfloat(arg);
+ double c_spread = ((M_c_hi - M_c_lo) * percent) / 2;
+ mlogistic -> c_lo = mlogistic -> c - c_spread;
+ mlogistic -> c_hi = mlogistic -> c + c_spread;
+ limiter(mlogistic);
+ return;
+ }
+ if (argc != M_param_count * 2) {
+ post("Invalid number of arguments for mlogistic constraints, requires 2 values, got %d", argc);
+ return;
+ }
+ mlogistic -> c_lo = atom_getfloat(arg++);
+ mlogistic -> c_hi = atom_getfloat(arg++);
+ limiter(mlogistic);
+}
+
+static void search(mlogistic_struct *mlogistic, t_symbol *s, int argc, t_atom *argv) {
+ int not_found, not_expired = mlogistic -> lyap_limit;
+ int jump, i, iterations;
+ t_atom vars[M_var_count];
+ double temp_c = mlogistic -> 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], mlogistic -> vars_init[i]);
+ }
+ }
+ do {
+ jump = 500;
+ not_found = 0;
+ iterations = 10000;
+ bad_params:
+ mlogistic -> c = (drand48() * (mlogistic -> c_hi - mlogistic -> c_lo)) + mlogistic -> c_lo;
+ // put any preliminary checks specific to this fractal to eliminate bad_params
+
+ reset(mlogistic, NULL, argc, vars);
+ do { calc(mlogistic, mlogistic -> vars); } while(jump--);
+ mlogistic -> lyap_exp = lyapunov((void *) mlogistic, (t_gotfn) calc, M_var_count, (double *) mlogistic -> vars);
+ if (isnan(mlogistic -> lyap_exp)) { not_found = 1; }
+ if (mlogistic -> lyap_exp < mlogistic -> lyap_lo || mlogistic -> lyap_exp > mlogistic -> lyap_hi) { not_found = 1; }
+ not_expired--;
+ } while(not_found && not_expired);
+ reset(mlogistic, NULL, argc, vars);
+ if (!not_expired) {
+ post("Could not find a fractal after %d attempts.", (int) mlogistic -> lyap_limit);
+ post("Try using wider constraints.");
+ mlogistic -> c = temp_c;
+ outlet_anything(mlogistic -> search_outlet, gensym("invalid"), 0, NULL);
+ } else {
+ mlogistic -> failure_ratio = (mlogistic -> lyap_limit - not_expired) / mlogistic -> lyap_limit;
+ make_results(mlogistic);
+ outlet_anything(mlogistic -> search_outlet, gensym("search"), M_search_count, mlogistic -> search_out);
+ }
+}
+
+void *mlogistic_new(t_symbol *s, int argc, t_atom *argv) {
+ mlogistic_struct *mlogistic = (mlogistic_struct *) pd_new(mlogistic_class);
+ if (mlogistic != NULL) {
+ outlet_new(&mlogistic -> x_obj, &s_float);
+ mlogistic -> search_outlet = outlet_new(&mlogistic -> x_obj, &s_list);
+ mlogistic -> vars_outlet = outlet_new(&mlogistic -> x_obj, &s_list);
+ mlogistic -> params_outlet = outlet_new(&mlogistic -> x_obj, &s_list);
+ if (argc == M_param_count + M_var_count) {
+ mlogistic -> vars_init[M_x] = mlogistic -> vars[M_x] = (double) atom_getfloatarg(0, argc, argv);
+ mlogistic -> c = (double) atom_getfloatarg(1, argc, argv);
+ } else {
+ if (argc != 0 && argc != M_param_count + M_var_count) {
+ post("Incorrect number of arguments for mlogistic fractal. Expecting 2 arguments.");
+ }
+ mlogistic -> vars_init[M_x] = 0.1;
+ mlogistic -> c = 4;
+ }
+ constrain(mlogistic, NULL, 0, NULL);
+ lyap(mlogistic, -1000000.0, 1000000.0, M_failure_limit);
+ }
+ return (void *)mlogistic;
+}
+
+void mlogistic_setup(void) {
+ mlogistic_class = class_new(gensym("mlogistic"), (t_newmethod) mlogistic_new, 0, sizeof(mlogistic_struct), 0, A_GIMME, 0);
+ class_addbang(mlogistic_class, (t_method) calculate);
+ class_addmethod(mlogistic_class, (t_method) reset, gensym("reset"), A_GIMME, 0);
+ class_addmethod(mlogistic_class, (t_method) show, gensym("show"), 0);
+ class_addmethod(mlogistic_class, (t_method) param, gensym("param"), A_GIMME, 0);
+ class_addmethod(mlogistic_class, (t_method) seed, gensym("seed"), A_GIMME, 0);
+ class_addmethod(mlogistic_class, (t_method) lyap, gensym("lyapunov"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(mlogistic_class, (t_method) elyap, gensym("elyapunov"), 0);
+ class_addmethod(mlogistic_class, (t_method) search, gensym("search"), A_GIMME, 0);
+ class_addmethod(mlogistic_class, (t_method) constrain, gensym("constrain"), A_GIMME, 0);
+ class_sethelpsymbol(mlogistic_class, gensym("help-mlogistic.pd"));
+}
+
diff --git a/pickover.c b/pickover.c
new file mode 100644
index 0000000..73a46e5
--- /dev/null
+++ b/pickover.c
@@ -0,0 +1,335 @@
+/* pickover Attractor PD External */
+/* Copyright Michael McGonagle, from Cliff Pickover, 2003 */
+/* This program is distributed under the params of the GNU Public License */
+
+///////////////////////////////////////////////////////////////////////////////////
+/* This file is part of Chaos PD Externals. */
+/* */
+/* Chaos PD Externals are free software; you can redistribute them and/or modify */
+/* them under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* Chaos PD Externals are distributed in the hope that they will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with the Chaos PD Externals; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+///////////////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#include "lyapunov.h"
+
+#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_d_lo -1000
+#define M_d_hi 1000
+
+#define M_a 0
+#define M_b 1
+#define M_c 2
+#define M_d 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 = "pickover v0.0, by Michael McGonagle, from Cliff Pickover, 2003";
+
+t_class *pickover_class;
+
+typedef struct pickover_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, d, d_lo, d_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];
+} pickover_struct;
+
+static void calc(pickover_struct *pickover, double *vars) {
+ double x_0, y_0, z_0;
+ x_0 =sin(pickover -> a*vars[M_y])-vars[M_z]*cos(pickover -> b*vars[M_x]);
+ y_0 =vars[M_z]*sin(pickover -> c*vars[M_x])-cos(pickover -> d*vars[M_y]);
+ z_0 =sin(vars[M_x]);
+ vars[M_x] = x_0;
+ vars[M_y] = y_0;
+ vars[M_z] = z_0;
+} // end calc
+
+static void calculate(pickover_struct *pickover) {
+ calc(pickover, pickover -> vars);
+ outlet_float(pickover -> x_obj.ob_outlet, pickover -> vars[M_x]);
+ outlet_float(pickover -> outlets[M_y - 1], pickover -> vars[M_y]);
+ outlet_float(pickover -> outlets[M_z - 1], pickover -> vars[M_z]);
+} // end calculate
+
+static void reset(pickover_struct *pickover, t_symbol *s, int argc, t_atom *argv) {
+ if (argc == M_var_count) {
+ pickover -> vars[M_x] = (double) atom_getfloatarg(M_x, argc, argv);
+ pickover -> vars[M_y] = (double) atom_getfloatarg(M_y, argc, argv);
+ pickover -> vars[M_z] = (double) atom_getfloatarg(M_z, argc, argv);
+ } else {
+ pickover -> vars[M_x] = pickover -> vars_init[M_x];
+ pickover -> vars[M_y] = pickover -> vars_init[M_y];
+ pickover -> vars[M_z] = pickover -> vars_init[M_z];
+ } // end if
+} // end reset
+
+static char *classify(pickover_struct *pickover) {
+ static char buff[5];
+ char *c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ buff[0] = c[(int) (((pickover -> a - M_a_lo) * (1.0 / (M_a_hi - M_a_lo))) * 26)];
+ buff[1] = c[(int) (((pickover -> b - M_b_lo) * (1.0 / (M_b_hi - M_b_lo))) * 26)];
+ buff[2] = c[(int) (((pickover -> c - M_c_lo) * (1.0 / (M_c_hi - M_c_lo))) * 26)];
+ buff[3] = c[(int) (((pickover -> d - M_d_lo) * (1.0 / (M_d_hi - M_d_lo))) * 26)];
+ buff[4] = '\0';
+ return buff;
+}
+
+static void make_results(pickover_struct *pickover) {
+ SETFLOAT(&pickover -> search_out[0], pickover -> lyap_exp);
+ SETSYMBOL(&pickover -> search_out[1], gensym(classify(pickover)));
+ SETFLOAT(&pickover -> search_out[2], pickover -> failure_ratio);
+ SETFLOAT(&pickover -> vars_out[M_x], pickover -> vars[M_x]);
+ SETFLOAT(&pickover -> vars_out[M_y], pickover -> vars[M_y]);
+ SETFLOAT(&pickover -> vars_out[M_z], pickover -> vars[M_z]);
+ SETFLOAT(&pickover -> params_out[M_a], pickover -> a);
+ SETFLOAT(&pickover -> params_out[M_b], pickover -> b);
+ SETFLOAT(&pickover -> params_out[M_c], pickover -> c);
+ SETFLOAT(&pickover -> params_out[M_d], pickover -> d);
+ outlet_list(pickover -> params_outlet, gensym("list"), M_param_count, pickover -> params_out);
+ outlet_list(pickover -> vars_outlet, gensym("list"), M_var_count, pickover -> vars_out);
+}
+
+static void show(pickover_struct *pickover) {
+ make_results(pickover);
+ outlet_anything(pickover -> search_outlet, gensym("show"), M_search_count, pickover -> search_out);
+}
+
+static void param(pickover_struct *pickover, t_symbol *s, int argc, t_atom *argv) {
+ if (argc != 4) {
+ post("Incorrect number of arguments for pickover fractal. Expecting 4 arguments.");
+ return;
+ }
+ pickover -> a = (double) atom_getfloatarg(0, argc, argv);
+ pickover -> b = (double) atom_getfloatarg(1, argc, argv);
+ pickover -> c = (double) atom_getfloatarg(2, argc, argv);
+ pickover -> d = (double) atom_getfloatarg(3, argc, argv);
+}
+
+static void seed(pickover_struct *pickover, 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(pickover_struct *pickover, t_floatarg l, t_floatarg h, t_floatarg lim) {
+ pickover -> lyap_lo = l;
+ pickover -> lyap_hi = h;
+ pickover -> lyap_limit = (double) ((int) lim);
+}
+
+static void elyap(pickover_struct *pickover) {
+ double results[M_var_count];
+ int i;
+ if (lyapunov_full((void *) pickover, (t_gotfn) calc, M_var_count, pickover -> vars, results) != NULL) {
+ post("elyapunov:");
+ for(i = 0; i < M_var_count; i++) { post("%d: %3.80f", i, results[i]); }
+ }
+}
+
+static void limiter(pickover_struct *pickover) {
+ if (pickover -> a_lo < M_a_lo) { pickover -> a_lo = M_a_lo; }
+ if (pickover -> a_lo > M_a_hi) { pickover -> a_lo = M_a_hi; }
+ if (pickover -> a_hi < M_a_lo) { pickover -> a_hi = M_a_lo; }
+ if (pickover -> a_hi > M_a_hi) { pickover -> a_hi = M_a_hi; }
+ if (pickover -> b_lo < M_b_lo) { pickover -> b_lo = M_b_lo; }
+ if (pickover -> b_lo > M_b_hi) { pickover -> b_lo = M_b_hi; }
+ if (pickover -> b_hi < M_b_lo) { pickover -> b_hi = M_b_lo; }
+ if (pickover -> b_hi > M_b_hi) { pickover -> b_hi = M_b_hi; }
+ if (pickover -> c_lo < M_c_lo) { pickover -> c_lo = M_c_lo; }
+ if (pickover -> c_lo > M_c_hi) { pickover -> c_lo = M_c_hi; }
+ if (pickover -> c_hi < M_c_lo) { pickover -> c_hi = M_c_lo; }
+ if (pickover -> c_hi > M_c_hi) { pickover -> c_hi = M_c_hi; }
+ if (pickover -> d_lo < M_d_lo) { pickover -> d_lo = M_d_lo; }
+ if (pickover -> d_lo > M_d_hi) { pickover -> d_lo = M_d_hi; }
+ if (pickover -> d_hi < M_d_lo) { pickover -> d_hi = M_d_lo; }
+ if (pickover -> d_hi > M_d_hi) { pickover -> d_hi = M_d_hi; }
+}
+
+static void constrain(pickover_struct *pickover, t_symbol *s, int argc, t_atom *argv) {
+ int i;
+ t_atom *arg = argv;
+ if (argc == 0) {
+ // reset to full limits of search ranges
+ pickover -> a_lo = M_a_lo;
+ pickover -> a_hi = M_a_hi;
+ pickover -> b_lo = M_b_lo;
+ pickover -> b_hi = M_b_hi;
+ pickover -> c_lo = M_c_lo;
+ pickover -> c_hi = M_c_hi;
+ pickover -> d_lo = M_d_lo;
+ pickover -> d_hi = M_d_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 d_spread = ((M_d_hi - M_d_lo) * percent) / 2;
+ pickover -> a_lo = pickover -> a - a_spread;
+ pickover -> a_hi = pickover -> a + a_spread;
+ pickover -> b_lo = pickover -> b - b_spread;
+ pickover -> b_hi = pickover -> b + b_spread;
+ pickover -> c_lo = pickover -> c - c_spread;
+ pickover -> c_hi = pickover -> c + c_spread;
+ pickover -> d_lo = pickover -> d - d_spread;
+ pickover -> d_hi = pickover -> d + d_spread;
+ limiter(pickover);
+ return;
+ }
+ if (argc != M_param_count * 2) {
+ post("Invalid number of arguments for pickover constraints, requires 8 values, got %d", argc);
+ return;
+ }
+ pickover -> a_lo = atom_getfloat(arg++);
+ pickover -> a_hi = atom_getfloat(arg++);
+ pickover -> b_lo = atom_getfloat(arg++);
+ pickover -> b_hi = atom_getfloat(arg++);
+ pickover -> c_lo = atom_getfloat(arg++);
+ pickover -> c_hi = atom_getfloat(arg++);
+ pickover -> d_lo = atom_getfloat(arg++);
+ pickover -> d_hi = atom_getfloat(arg++);
+ limiter(pickover);
+}
+
+static void search(pickover_struct *pickover, t_symbol *s, int argc, t_atom *argv) {
+ int not_found, not_expired = pickover -> lyap_limit;
+ int jump, i, iterations;
+ t_atom vars[M_var_count];
+ double temp_a = pickover -> a;
+ double temp_b = pickover -> b;
+ double temp_c = pickover -> c;
+ double temp_d = pickover -> d;
+ 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], pickover -> vars_init[i]);
+ }
+ }
+ do {
+ jump = 500;
+ not_found = 0;
+ iterations = 10000;
+ bad_params:
+ pickover -> a = (drand48() * (pickover -> a_hi - pickover -> a_lo)) + pickover -> a_lo;
+ pickover -> b = (drand48() * (pickover -> b_hi - pickover -> b_lo)) + pickover -> b_lo;
+ pickover -> c = (drand48() * (pickover -> c_hi - pickover -> c_lo)) + pickover -> c_lo;
+ pickover -> d = (drand48() * (pickover -> d_hi - pickover -> d_lo)) + pickover -> d_lo;
+ // put any preliminary checks specific to this fractal to eliminate bad_params
+
+ reset(pickover, NULL, argc, vars);
+ do { calc(pickover, pickover -> vars); } while(jump--);
+ pickover -> lyap_exp = lyapunov((void *) pickover, (t_gotfn) calc, M_var_count, (double *) pickover -> vars);
+ if (isnan(pickover -> lyap_exp)) { not_found = 1; }
+ if (pickover -> lyap_exp < pickover -> lyap_lo || pickover -> lyap_exp > pickover -> lyap_hi) { not_found = 1; }
+ not_expired--;
+ } while(not_found && not_expired);
+ reset(pickover, NULL, argc, vars);
+ if (!not_expired) {
+ post("Could not find a fractal after %d attempts.", (int) pickover -> lyap_limit);
+ post("Try using wider constraints.");
+ pickover -> a = temp_a;
+ pickover -> b = temp_b;
+ pickover -> c = temp_c;
+ pickover -> d = temp_d;
+ outlet_anything(pickover -> search_outlet, gensym("invalid"), 0, NULL);
+ } else {
+ pickover -> failure_ratio = (pickover -> lyap_limit - not_expired) / pickover -> lyap_limit;
+ make_results(pickover);
+ outlet_anything(pickover -> search_outlet, gensym("search"), M_search_count, pickover -> search_out);
+ }
+}
+
+void *pickover_new(t_symbol *s, int argc, t_atom *argv) {
+ pickover_struct *pickover = (pickover_struct *) pd_new(pickover_class);
+ if (pickover != NULL) {
+ outlet_new(&pickover -> x_obj, &s_float);
+ pickover -> outlets[0] = outlet_new(&pickover -> x_obj, &s_float);
+ pickover -> outlets[1] = outlet_new(&pickover -> x_obj, &s_float);
+ pickover -> search_outlet = outlet_new(&pickover -> x_obj, &s_list);
+ pickover -> vars_outlet = outlet_new(&pickover -> x_obj, &s_list);
+ pickover -> params_outlet = outlet_new(&pickover -> x_obj, &s_list);
+ if (argc == M_param_count + M_var_count) {
+ pickover -> vars_init[M_x] = pickover -> vars[M_x] = (double) atom_getfloatarg(0, argc, argv);
+ pickover -> vars_init[M_y] = pickover -> vars[M_y] = (double) atom_getfloatarg(1, argc, argv);
+ pickover -> vars_init[M_z] = pickover -> vars[M_z] = (double) atom_getfloatarg(2, argc, argv);
+ pickover -> a = (double) atom_getfloatarg(3, argc, argv);
+ pickover -> b = (double) atom_getfloatarg(4, argc, argv);
+ pickover -> c = (double) atom_getfloatarg(5, argc, argv);
+ pickover -> d = (double) atom_getfloatarg(6, argc, argv);
+ } else {
+ if (argc != 0 && argc != M_param_count + M_var_count) {
+ post("Incorrect number of arguments for pickover fractal. Expecting 7 arguments.");
+ }
+ pickover -> vars_init[M_x] = 0.01;
+ pickover -> vars_init[M_y] = 0;
+ pickover -> vars_init[M_z] = 0;
+ pickover -> a = 2.24;
+ pickover -> b = 0.43;
+ pickover -> c = -0.65;
+ pickover -> d = -2.43;
+ }
+ constrain(pickover, NULL, 0, NULL);
+ lyap(pickover, -1000000.0, 1000000.0, M_failure_limit);
+ }
+ return (void *)pickover;
+}
+
+void pickover_setup(void) {
+ pickover_class = class_new(gensym("pickover"), (t_newmethod) pickover_new, 0, sizeof(pickover_struct), 0, A_GIMME, 0);
+ class_addbang(pickover_class, (t_method) calculate);
+ class_addmethod(pickover_class, (t_method) reset, gensym("reset"), A_GIMME, 0);
+ class_addmethod(pickover_class, (t_method) show, gensym("show"), 0);
+ class_addmethod(pickover_class, (t_method) param, gensym("param"), A_GIMME, 0);
+ class_addmethod(pickover_class, (t_method) seed, gensym("seed"), A_GIMME, 0);
+ class_addmethod(pickover_class, (t_method) lyap, gensym("lyapunov"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(pickover_class, (t_method) elyap, gensym("elyapunov"), 0);
+ class_addmethod(pickover_class, (t_method) search, gensym("search"), A_GIMME, 0);
+ class_addmethod(pickover_class, (t_method) constrain, gensym("constrain"), A_GIMME, 0);
+ class_sethelpsymbol(pickover_class, gensym("help-pickover.pd"));
+}
+
diff --git a/popcorn.c b/popcorn.c
new file mode 100644
index 0000000..8b46857
--- /dev/null
+++ b/popcorn.c
@@ -0,0 +1,259 @@
+/* popcorn Attractor PD External */
+/* Copyright Michael McGonagle, from Cliff Pickover, 2003 */
+/* This program is distributed under the params of the GNU Public License */
+
+///////////////////////////////////////////////////////////////////////////////////
+/* This file is part of Chaos PD Externals. */
+/* */
+/* Chaos PD Externals are free software; you can redistribute them and/or modify */
+/* them under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* Chaos PD Externals are distributed in the hope that they will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with the Chaos PD Externals; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+///////////////////////////////////////////////////////////////////////////////////
+
+#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_h 0
+
+#define M_x 0
+#define M_y 1
+
+#define M_param_count 1
+#define M_var_count 2
+#define M_search_count 3
+#define M_failure_limit 1000
+
+static char *version = "popcorn v0.0, by Michael McGonagle, from Cliff Pickover, 2003";
+
+t_class *popcorn_class;
+
+typedef struct popcorn_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;
+ 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];
+} popcorn_struct;
+
+static void calc(popcorn_struct *popcorn, double *vars) {
+ double x_0, y_0;
+ x_0 =vars[M_x]-popcorn -> h*sin(vars[M_y]+tan(3*vars[M_y]));
+ y_0 =vars[M_y]-popcorn -> h*sin(vars[M_x]+tan(3*vars[M_x]));
+ vars[M_x] = x_0;
+ vars[M_y] = y_0;
+} // end calc
+
+static void calculate(popcorn_struct *popcorn) {
+ calc(popcorn, popcorn -> vars);
+ outlet_float(popcorn -> x_obj.ob_outlet, popcorn -> vars[M_x]);
+ outlet_float(popcorn -> outlets[M_y - 1], popcorn -> vars[M_y]);
+} // end calculate
+
+static void reset(popcorn_struct *popcorn, t_symbol *s, int argc, t_atom *argv) {
+ if (argc == M_var_count) {
+ popcorn -> vars[M_x] = (double) atom_getfloatarg(M_x, argc, argv);
+ popcorn -> vars[M_y] = (double) atom_getfloatarg(M_y, argc, argv);
+ } else {
+ popcorn -> vars[M_x] = popcorn -> vars_init[M_x];
+ popcorn -> vars[M_y] = popcorn -> vars_init[M_y];
+ } // end if
+} // end reset
+
+static char *classify(popcorn_struct *popcorn) {
+ static char buff[2];
+ char *c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ buff[0] = c[(int) (((popcorn -> h - M_h_lo) * (1.0 / (M_h_hi - M_h_lo))) * 26)];
+ buff[1] = '\0';
+ return buff;
+}
+
+static void make_results(popcorn_struct *popcorn) {
+ SETFLOAT(&popcorn -> search_out[0], popcorn -> lyap_exp);
+ SETSYMBOL(&popcorn -> search_out[1], gensym(classify(popcorn)));
+ SETFLOAT(&popcorn -> search_out[2], popcorn -> failure_ratio);
+ SETFLOAT(&popcorn -> vars_out[M_x], popcorn -> vars[M_x]);
+ SETFLOAT(&popcorn -> vars_out[M_y], popcorn -> vars[M_y]);
+ SETFLOAT(&popcorn -> params_out[M_h], popcorn -> h);
+ outlet_list(popcorn -> params_outlet, gensym("list"), M_param_count, popcorn -> params_out);
+ outlet_list(popcorn -> vars_outlet, gensym("list"), M_var_count, popcorn -> vars_out);
+}
+
+static void show(popcorn_struct *popcorn) {
+ make_results(popcorn);
+ outlet_anything(popcorn -> search_outlet, gensym("show"), M_search_count, popcorn -> search_out);
+}
+
+static void param(popcorn_struct *popcorn, t_symbol *s, int argc, t_atom *argv) {
+ if (argc != 1) {
+ post("Incorrect number of arguments for popcorn fractal. Expecting 1 arguments.");
+ return;
+ }
+ popcorn -> h = (double) atom_getfloatarg(0, argc, argv);
+}
+
+static void seed(popcorn_struct *popcorn, 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(popcorn_struct *popcorn, t_floatarg l, t_floatarg h, t_floatarg lim) {
+ popcorn -> lyap_lo = l;
+ popcorn -> lyap_hi = h;
+ popcorn -> lyap_limit = (double) ((int) lim);
+}
+
+static void elyap(popcorn_struct *popcorn) {
+ double results[M_var_count];
+ int i;
+ if (lyapunov_full((void *) popcorn, (t_gotfn) calc, M_var_count, popcorn -> vars, results) != NULL) {
+ post("elyapunov:");
+ for(i = 0; i < M_var_count; i++) { post("%d: %3.80f", i, results[i]); }
+ }
+}
+
+static void limiter(popcorn_struct *popcorn) {
+ if (popcorn -> h_lo < M_h_lo) { popcorn -> h_lo = M_h_lo; }
+ if (popcorn -> h_lo > M_h_hi) { popcorn -> h_lo = M_h_hi; }
+ if (popcorn -> h_hi < M_h_lo) { popcorn -> h_hi = M_h_lo; }
+ if (popcorn -> h_hi > M_h_hi) { popcorn -> h_hi = M_h_hi; }
+}
+
+static void constrain(popcorn_struct *popcorn, t_symbol *s, int argc, t_atom *argv) {
+ int i;
+ t_atom *arg = argv;
+ if (argc == 0) {
+ // reset to full limits of search ranges
+ popcorn -> h_lo = M_h_lo;
+ popcorn -> h_hi = M_h_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;
+ popcorn -> h_lo = popcorn -> h - h_spread;
+ popcorn -> h_hi = popcorn -> h + h_spread;
+ limiter(popcorn);
+ return;
+ }
+ if (argc != M_param_count * 2) {
+ post("Invalid number of arguments for popcorn constraints, requires 2 values, got %d", argc);
+ return;
+ }
+ popcorn -> h_lo = atom_getfloat(arg++);
+ popcorn -> h_hi = atom_getfloat(arg++);
+ limiter(popcorn);
+}
+
+static void search(popcorn_struct *popcorn, t_symbol *s, int argc, t_atom *argv) {
+ int not_found, not_expired = popcorn -> lyap_limit;
+ int jump, i, iterations;
+ t_atom vars[M_var_count];
+ double temp_h = popcorn -> h;
+ 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], popcorn -> vars_init[i]);
+ }
+ }
+ do {
+ jump = 500;
+ not_found = 0;
+ iterations = 10000;
+ bad_params:
+ popcorn -> h = (drand48() * (popcorn -> h_hi - popcorn -> h_lo)) + popcorn -> h_lo;
+ // put any preliminary checks specific to this fractal to eliminate bad_params
+
+ reset(popcorn, NULL, argc, vars);
+ do { calc(popcorn, popcorn -> vars); } while(jump--);
+ popcorn -> lyap_exp = lyapunov((void *) popcorn, (t_gotfn) calc, M_var_count, (double *) popcorn -> vars);
+ if (isnan(popcorn -> lyap_exp)) { not_found = 1; }
+ if (popcorn -> lyap_exp < popcorn -> lyap_lo || popcorn -> lyap_exp > popcorn -> lyap_hi) { not_found = 1; }
+ not_expired--;
+ } while(not_found && not_expired);
+ reset(popcorn, NULL, argc, vars);
+ if (!not_expired) {
+ post("Could not find a fractal after %d attempts.", (int) popcorn -> lyap_limit);
+ post("Try using wider constraints.");
+ popcorn -> h = temp_h;
+ outlet_anything(popcorn -> search_outlet, gensym("invalid"), 0, NULL);
+ } else {
+ popcorn -> failure_ratio = (popcorn -> lyap_limit - not_expired) / popcorn -> lyap_limit;
+ make_results(popcorn);
+ outlet_anything(popcorn -> search_outlet, gensym("search"), M_search_count, popcorn -> search_out);
+ }
+}
+
+void *popcorn_new(t_symbol *s, int argc, t_atom *argv) {
+ popcorn_struct *popcorn = (popcorn_struct *) pd_new(popcorn_class);
+ if (popcorn != NULL) {
+ outlet_new(&popcorn -> x_obj, &s_float);
+ popcorn -> outlets[0] = outlet_new(&popcorn -> x_obj, &s_float);
+ popcorn -> search_outlet = outlet_new(&popcorn -> x_obj, &s_list);
+ popcorn -> vars_outlet = outlet_new(&popcorn -> x_obj, &s_list);
+ popcorn -> params_outlet = outlet_new(&popcorn -> x_obj, &s_list);
+ if (argc == M_param_count + M_var_count) {
+ popcorn -> vars_init[M_x] = popcorn -> vars[M_x] = (double) atom_getfloatarg(0, argc, argv);
+ popcorn -> vars_init[M_y] = popcorn -> vars[M_y] = (double) atom_getfloatarg(1, argc, argv);
+ popcorn -> h = (double) atom_getfloatarg(2, argc, argv);
+ } else {
+ if (argc != 0 && argc != M_param_count + M_var_count) {
+ post("Incorrect number of arguments for popcorn fractal. Expecting 3 arguments.");
+ }
+ popcorn -> vars_init[M_x] = 0;
+ popcorn -> vars_init[M_y] = 0;
+ popcorn -> h = 0.05;
+ }
+ constrain(popcorn, NULL, 0, NULL);
+ lyap(popcorn, -1000000.0, 1000000.0, M_failure_limit);
+ }
+ return (void *)popcorn;
+}
+
+void popcorn_setup(void) {
+ popcorn_class = class_new(gensym("popcorn"), (t_newmethod) popcorn_new, 0, sizeof(popcorn_struct), 0, A_GIMME, 0);
+ class_addbang(popcorn_class, (t_method) calculate);
+ class_addmethod(popcorn_class, (t_method) reset, gensym("reset"), A_GIMME, 0);
+ class_addmethod(popcorn_class, (t_method) show, gensym("show"), 0);
+ class_addmethod(popcorn_class, (t_method) param, gensym("param"), A_GIMME, 0);
+ class_addmethod(popcorn_class, (t_method) seed, gensym("seed"), A_GIMME, 0);
+ class_addmethod(popcorn_class, (t_method) lyap, gensym("lyapunov"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(popcorn_class, (t_method) elyap, gensym("elyapunov"), 0);
+ class_addmethod(popcorn_class, (t_method) search, gensym("search"), A_GIMME, 0);
+ class_addmethod(popcorn_class, (t_method) constrain, gensym("constrain"), A_GIMME, 0);
+ class_sethelpsymbol(popcorn_class, gensym("help-popcorn.pd"));
+}
+
diff --git a/quadruptwo.c b/quadruptwo.c
new file mode 100644
index 0000000..4869731
--- /dev/null
+++ b/quadruptwo.c
@@ -0,0 +1,303 @@
+/* quadruptwo Attractor PD External */
+/* Copyright Michael McGonagle, from ??????, 2003 */
+/* This program is distributed under the params of the GNU Public License */
+
+///////////////////////////////////////////////////////////////////////////////////
+/* This file is part of Chaos PD Externals. */
+/* */
+/* Chaos PD Externals are free software; you can redistribute them and/or modify */
+/* them under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* Chaos PD Externals are distributed in the hope that they will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with the Chaos PD Externals; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+///////////////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#include "lyapunov.h"
+
+#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_a 0
+#define M_b 1
+#define M_c 2
+
+#define M_x 0
+#define M_y 1
+
+#define M_param_count 3
+#define M_var_count 2
+#define M_search_count 3
+#define M_failure_limit 1000
+
+static char *version = "quadruptwo v0.0, by Michael McGonagle, from ??????, 2003";
+
+t_class *quadruptwo_class;
+
+typedef struct quadruptwo_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;
+ 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];
+} quadruptwo_struct;
+
+static void calc(quadruptwo_struct *quadruptwo, double *vars) {
+ double x_0, y_0;
+ x_0 =vars[M_y]-((vars[M_x]<0)?-1:1)*sin(log(abs(quadruptwo -> b*vars[M_x]-quadruptwo -> c)))*atan(pow(abs(quadruptwo -> c*vars[M_x]-quadruptwo -> b),2));
+ y_0 =quadruptwo -> a-vars[M_x];
+ vars[M_x] = x_0;
+ vars[M_y] = y_0;
+} // end calc
+
+static void calculate(quadruptwo_struct *quadruptwo) {
+ calc(quadruptwo, quadruptwo -> vars);
+ outlet_float(quadruptwo -> x_obj.ob_outlet, quadruptwo -> vars[M_x]);
+ outlet_float(quadruptwo -> outlets[M_y - 1], quadruptwo -> vars[M_y]);
+} // end calculate
+
+static void reset(quadruptwo_struct *quadruptwo, t_symbol *s, int argc, t_atom *argv) {
+ if (argc == M_var_count) {
+ quadruptwo -> vars[M_x] = (double) atom_getfloatarg(M_x, argc, argv);
+ quadruptwo -> vars[M_y] = (double) atom_getfloatarg(M_y, argc, argv);
+ } else {
+ quadruptwo -> vars[M_x] = quadruptwo -> vars_init[M_x];
+ quadruptwo -> vars[M_y] = quadruptwo -> vars_init[M_y];
+ } // end if
+} // end reset
+
+static char *classify(quadruptwo_struct *quadruptwo) {
+ static char buff[4];
+ char *c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ buff[0] = c[(int) (((quadruptwo -> a - M_a_lo) * (1.0 / (M_a_hi - M_a_lo))) * 26)];
+ buff[1] = c[(int) (((quadruptwo -> b - M_b_lo) * (1.0 / (M_b_hi - M_b_lo))) * 26)];
+ buff[2] = c[(int) (((quadruptwo -> c - M_c_lo) * (1.0 / (M_c_hi - M_c_lo))) * 26)];
+ buff[3] = '\0';
+ return buff;
+}
+
+static void make_results(quadruptwo_struct *quadruptwo) {
+ SETFLOAT(&quadruptwo -> search_out[0], quadruptwo -> lyap_exp);
+ SETSYMBOL(&quadruptwo -> search_out[1], gensym(classify(quadruptwo)));
+ SETFLOAT(&quadruptwo -> search_out[2], quadruptwo -> failure_ratio);
+ SETFLOAT(&quadruptwo -> vars_out[M_x], quadruptwo -> vars[M_x]);
+ SETFLOAT(&quadruptwo -> vars_out[M_y], quadruptwo -> vars[M_y]);
+ SETFLOAT(&quadruptwo -> params_out[M_a], quadruptwo -> a);
+ SETFLOAT(&quadruptwo -> params_out[M_b], quadruptwo -> b);
+ SETFLOAT(&quadruptwo -> params_out[M_c], quadruptwo -> c);
+ outlet_list(quadruptwo -> params_outlet, gensym("list"), M_param_count, quadruptwo -> params_out);
+ outlet_list(quadruptwo -> vars_outlet, gensym("list"), M_var_count, quadruptwo -> vars_out);
+}
+
+static void show(quadruptwo_struct *quadruptwo) {
+ make_results(quadruptwo);
+ outlet_anything(quadruptwo -> search_outlet, gensym("show"), M_search_count, quadruptwo -> search_out);
+}
+
+static void param(quadruptwo_struct *quadruptwo, t_symbol *s, int argc, t_atom *argv) {
+ if (argc != 3) {
+ post("Incorrect number of arguments for quadruptwo fractal. Expecting 3 arguments.");
+ return;
+ }
+ quadruptwo -> a = (double) atom_getfloatarg(0, argc, argv);
+ quadruptwo -> b = (double) atom_getfloatarg(1, argc, argv);
+ quadruptwo -> c = (double) atom_getfloatarg(2, argc, argv);
+}
+
+static void seed(quadruptwo_struct *quadruptwo, 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(quadruptwo_struct *quadruptwo, t_floatarg l, t_floatarg h, t_floatarg lim) {
+ quadruptwo -> lyap_lo = l;
+ quadruptwo -> lyap_hi = h;
+ quadruptwo -> lyap_limit = (double) ((int) lim);
+}
+
+static void elyap(quadruptwo_struct *quadruptwo) {
+ double results[M_var_count];
+ int i;
+ if (lyapunov_full((void *) quadruptwo, (t_gotfn) calc, M_var_count, quadruptwo -> vars, results) != NULL) {
+ post("elyapunov:");
+ for(i = 0; i < M_var_count; i++) { post("%d: %3.80f", i, results[i]); }
+ }
+}
+
+static void limiter(quadruptwo_struct *quadruptwo) {
+ if (quadruptwo -> a_lo < M_a_lo) { quadruptwo -> a_lo = M_a_lo; }
+ if (quadruptwo -> a_lo > M_a_hi) { quadruptwo -> a_lo = M_a_hi; }
+ if (quadruptwo -> a_hi < M_a_lo) { quadruptwo -> a_hi = M_a_lo; }
+ if (quadruptwo -> a_hi > M_a_hi) { quadruptwo -> a_hi = M_a_hi; }
+ if (quadruptwo -> b_lo < M_b_lo) { quadruptwo -> b_lo = M_b_lo; }
+ if (quadruptwo -> b_lo > M_b_hi) { quadruptwo -> b_lo = M_b_hi; }
+ if (quadruptwo -> b_hi < M_b_lo) { quadruptwo -> b_hi = M_b_lo; }
+ if (quadruptwo -> b_hi > M_b_hi) { quadruptwo -> b_hi = M_b_hi; }
+ if (quadruptwo -> c_lo < M_c_lo) { quadruptwo -> c_lo = M_c_lo; }
+ if (quadruptwo -> c_lo > M_c_hi) { quadruptwo -> c_lo = M_c_hi; }
+ if (quadruptwo -> c_hi < M_c_lo) { quadruptwo -> c_hi = M_c_lo; }
+ if (quadruptwo -> c_hi > M_c_hi) { quadruptwo -> c_hi = M_c_hi; }
+}
+
+static void constrain(quadruptwo_struct *quadruptwo, t_symbol *s, int argc, t_atom *argv) {
+ int i;
+ t_atom *arg = argv;
+ if (argc == 0) {
+ // reset to full limits of search ranges
+ quadruptwo -> a_lo = M_a_lo;
+ quadruptwo -> a_hi = M_a_hi;
+ quadruptwo -> b_lo = M_b_lo;
+ quadruptwo -> b_hi = M_b_hi;
+ quadruptwo -> c_lo = M_c_lo;
+ quadruptwo -> c_hi = M_c_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;
+ quadruptwo -> a_lo = quadruptwo -> a - a_spread;
+ quadruptwo -> a_hi = quadruptwo -> a + a_spread;
+ quadruptwo -> b_lo = quadruptwo -> b - b_spread;
+ quadruptwo -> b_hi = quadruptwo -> b + b_spread;
+ quadruptwo -> c_lo = quadruptwo -> c - c_spread;
+ quadruptwo -> c_hi = quadruptwo -> c + c_spread;
+ limiter(quadruptwo);
+ return;
+ }
+ if (argc != M_param_count * 2) {
+ post("Invalid number of arguments for quadruptwo constraints, requires 6 values, got %d", argc);
+ return;
+ }
+ quadruptwo -> a_lo = atom_getfloat(arg++);
+ quadruptwo -> a_hi = atom_getfloat(arg++);
+ quadruptwo -> b_lo = atom_getfloat(arg++);
+ quadruptwo -> b_hi = atom_getfloat(arg++);
+ quadruptwo -> c_lo = atom_getfloat(arg++);
+ quadruptwo -> c_hi = atom_getfloat(arg++);
+ limiter(quadruptwo);
+}
+
+static void search(quadruptwo_struct *quadruptwo, t_symbol *s, int argc, t_atom *argv) {
+ int not_found, not_expired = quadruptwo -> lyap_limit;
+ int jump, i, iterations;
+ t_atom vars[M_var_count];
+ double temp_a = quadruptwo -> a;
+ double temp_b = quadruptwo -> b;
+ double temp_c = quadruptwo -> 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], quadruptwo -> vars_init[i]);
+ }
+ }
+ do {
+ jump = 500;
+ not_found = 0;
+ iterations = 10000;
+ bad_params:
+ quadruptwo -> a = (drand48() * (quadruptwo -> a_hi - quadruptwo -> a_lo)) + quadruptwo -> a_lo;
+ quadruptwo -> b = (drand48() * (quadruptwo -> b_hi - quadruptwo -> b_lo)) + quadruptwo -> b_lo;
+ quadruptwo -> c = (drand48() * (quadruptwo -> c_hi - quadruptwo -> c_lo)) + quadruptwo -> c_lo;
+ // put any preliminary checks specific to this fractal to eliminate bad_params
+
+ reset(quadruptwo, NULL, argc, vars);
+ do { calc(quadruptwo, quadruptwo -> vars); } while(jump--);
+ quadruptwo -> lyap_exp = lyapunov((void *) quadruptwo, (t_gotfn) calc, M_var_count, (double *) quadruptwo -> vars);
+ if (isnan(quadruptwo -> lyap_exp)) { not_found = 1; }
+ if (quadruptwo -> lyap_exp < quadruptwo -> lyap_lo || quadruptwo -> lyap_exp > quadruptwo -> lyap_hi) { not_found = 1; }
+ not_expired--;
+ } while(not_found && not_expired);
+ reset(quadruptwo, NULL, argc, vars);
+ if (!not_expired) {
+ post("Could not find a fractal after %d attempts.", (int) quadruptwo -> lyap_limit);
+ post("Try using wider constraints.");
+ quadruptwo -> a = temp_a;
+ quadruptwo -> b = temp_b;
+ quadruptwo -> c = temp_c;
+ outlet_anything(quadruptwo -> search_outlet, gensym("invalid"), 0, NULL);
+ } else {
+ quadruptwo -> failure_ratio = (quadruptwo -> lyap_limit - not_expired) / quadruptwo -> lyap_limit;
+ make_results(quadruptwo);
+ outlet_anything(quadruptwo -> search_outlet, gensym("search"), M_search_count, quadruptwo -> search_out);
+ }
+}
+
+void *quadruptwo_new(t_symbol *s, int argc, t_atom *argv) {
+ quadruptwo_struct *quadruptwo = (quadruptwo_struct *) pd_new(quadruptwo_class);
+ if (quadruptwo != NULL) {
+ outlet_new(&quadruptwo -> x_obj, &s_float);
+ quadruptwo -> outlets[0] = outlet_new(&quadruptwo -> x_obj, &s_float);
+ quadruptwo -> search_outlet = outlet_new(&quadruptwo -> x_obj, &s_list);
+ quadruptwo -> vars_outlet = outlet_new(&quadruptwo -> x_obj, &s_list);
+ quadruptwo -> params_outlet = outlet_new(&quadruptwo -> x_obj, &s_list);
+ if (argc == M_param_count + M_var_count) {
+ quadruptwo -> vars_init[M_x] = quadruptwo -> vars[M_x] = (double) atom_getfloatarg(0, argc, argv);
+ quadruptwo -> vars_init[M_y] = quadruptwo -> vars[M_y] = (double) atom_getfloatarg(1, argc, argv);
+ quadruptwo -> a = (double) atom_getfloatarg(2, argc, argv);
+ quadruptwo -> b = (double) atom_getfloatarg(3, argc, argv);
+ quadruptwo -> c = (double) atom_getfloatarg(4, argc, argv);
+ } else {
+ if (argc != 0 && argc != M_param_count + M_var_count) {
+ post("Incorrect number of arguments for quadruptwo fractal. Expecting 5 arguments.");
+ }
+ quadruptwo -> vars_init[M_x] = 0;
+ quadruptwo -> vars_init[M_y] = 0;
+ quadruptwo -> a = 34;
+ quadruptwo -> b = 1;
+ quadruptwo -> c = 5;
+ }
+ constrain(quadruptwo, NULL, 0, NULL);
+ lyap(quadruptwo, -1000000.0, 1000000.0, M_failure_limit);
+ }
+ return (void *)quadruptwo;
+}
+
+void quadruptwo_setup(void) {
+ quadruptwo_class = class_new(gensym("quadruptwo"), (t_newmethod) quadruptwo_new, 0, sizeof(quadruptwo_struct), 0, A_GIMME, 0);
+ class_addbang(quadruptwo_class, (t_method) calculate);
+ class_addmethod(quadruptwo_class, (t_method) reset, gensym("reset"), A_GIMME, 0);
+ class_addmethod(quadruptwo_class, (t_method) show, gensym("show"), 0);
+ class_addmethod(quadruptwo_class, (t_method) param, gensym("param"), A_GIMME, 0);
+ class_addmethod(quadruptwo_class, (t_method) seed, gensym("seed"), A_GIMME, 0);
+ class_addmethod(quadruptwo_class, (t_method) lyap, gensym("lyapunov"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(quadruptwo_class, (t_method) elyap, gensym("elyapunov"), 0);
+ class_addmethod(quadruptwo_class, (t_method) search, gensym("search"), A_GIMME, 0);
+ class_addmethod(quadruptwo_class, (t_method) constrain, gensym("constrain"), A_GIMME, 0);
+ class_sethelpsymbol(quadruptwo_class, gensym("help-quadruptwo.pd"));
+}
+
diff --git a/standardmap.c b/standardmap.c
new file mode 100644
index 0000000..efb099c
--- /dev/null
+++ b/standardmap.c
@@ -0,0 +1,259 @@
+/* standardmap Attractor PD External */
+/* Copyright Michael McGonagle, from ??????, 2003 */
+/* This program is distributed under the params of the GNU Public License */
+
+///////////////////////////////////////////////////////////////////////////////////
+/* This file is part of Chaos PD Externals. */
+/* */
+/* Chaos PD Externals are free software; you can redistribute them and/or modify */
+/* them under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* Chaos PD Externals are distributed in the hope that they will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with the Chaos PD Externals; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+///////////////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#include "lyapunov.h"
+
+#define M_k_lo -1000
+#define M_k_hi 1000
+
+#define M_k 0
+
+#define M_p 0
+#define M_q 1
+
+#define M_param_count 1
+#define M_var_count 2
+#define M_search_count 3
+#define M_failure_limit 1000
+
+static char *version = "standardmap v0.0, by Michael McGonagle, from ??????, 2003";
+
+t_class *standardmap_class;
+
+typedef struct standardmap_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 k, k_lo, k_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];
+} standardmap_struct;
+
+static void calc(standardmap_struct *standardmap, double *vars) {
+ double p_0, q_0;
+ p_0 =vars[M_p]+standardmap -> k*sin(vars[M_q]+vars[M_p]);
+ q_0 =vars[M_q]+vars[M_p];
+ vars[M_p] = p_0;
+ vars[M_q] = q_0;
+} // end calc
+
+static void calculate(standardmap_struct *standardmap) {
+ calc(standardmap, standardmap -> vars);
+ outlet_float(standardmap -> x_obj.ob_outlet, standardmap -> vars[M_p]);
+ outlet_float(standardmap -> outlets[M_q - 1], standardmap -> vars[M_q]);
+} // end calculate
+
+static void reset(standardmap_struct *standardmap, t_symbol *s, int argc, t_atom *argv) {
+ if (argc == M_var_count) {
+ standardmap -> vars[M_p] = (double) atom_getfloatarg(M_p, argc, argv);
+ standardmap -> vars[M_q] = (double) atom_getfloatarg(M_q, argc, argv);
+ } else {
+ standardmap -> vars[M_p] = standardmap -> vars_init[M_p];
+ standardmap -> vars[M_q] = standardmap -> vars_init[M_q];
+ } // end if
+} // end reset
+
+static char *classify(standardmap_struct *standardmap) {
+ static char buff[2];
+ char *c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ buff[0] = c[(int) (((standardmap -> k - M_k_lo) * (1.0 / (M_k_hi - M_k_lo))) * 26)];
+ buff[1] = '\0';
+ return buff;
+}
+
+static void make_results(standardmap_struct *standardmap) {
+ SETFLOAT(&standardmap -> search_out[0], standardmap -> lyap_exp);
+ SETSYMBOL(&standardmap -> search_out[1], gensym(classify(standardmap)));
+ SETFLOAT(&standardmap -> search_out[2], standardmap -> failure_ratio);
+ SETFLOAT(&standardmap -> vars_out[M_p], standardmap -> vars[M_p]);
+ SETFLOAT(&standardmap -> vars_out[M_q], standardmap -> vars[M_q]);
+ SETFLOAT(&standardmap -> params_out[M_k], standardmap -> k);
+ outlet_list(standardmap -> params_outlet, gensym("list"), M_param_count, standardmap -> params_out);
+ outlet_list(standardmap -> vars_outlet, gensym("list"), M_var_count, standardmap -> vars_out);
+}
+
+static void show(standardmap_struct *standardmap) {
+ make_results(standardmap);
+ outlet_anything(standardmap -> search_outlet, gensym("show"), M_search_count, standardmap -> search_out);
+}
+
+static void param(standardmap_struct *standardmap, t_symbol *s, int argc, t_atom *argv) {
+ if (argc != 1) {
+ post("Incorrect number of arguments for standardmap fractal. Expecting 1 arguments.");
+ return;
+ }
+ standardmap -> k = (double) atom_getfloatarg(0, argc, argv);
+}
+
+static void seed(standardmap_struct *standardmap, 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(standardmap_struct *standardmap, t_floatarg l, t_floatarg h, t_floatarg lim) {
+ standardmap -> lyap_lo = l;
+ standardmap -> lyap_hi = h;
+ standardmap -> lyap_limit = (double) ((int) lim);
+}
+
+static void elyap(standardmap_struct *standardmap) {
+ double results[M_var_count];
+ int i;
+ if (lyapunov_full((void *) standardmap, (t_gotfn) calc, M_var_count, standardmap -> vars, results) != NULL) {
+ post("elyapunov:");
+ for(i = 0; i < M_var_count; i++) { post("%d: %3.80f", i, results[i]); }
+ }
+}
+
+static void limiter(standardmap_struct *standardmap) {
+ if (standardmap -> k_lo < M_k_lo) { standardmap -> k_lo = M_k_lo; }
+ if (standardmap -> k_lo > M_k_hi) { standardmap -> k_lo = M_k_hi; }
+ if (standardmap -> k_hi < M_k_lo) { standardmap -> k_hi = M_k_lo; }
+ if (standardmap -> k_hi > M_k_hi) { standardmap -> k_hi = M_k_hi; }
+}
+
+static void constrain(standardmap_struct *standardmap, t_symbol *s, int argc, t_atom *argv) {
+ int i;
+ t_atom *arg = argv;
+ if (argc == 0) {
+ // reset to full limits of search ranges
+ standardmap -> k_lo = M_k_lo;
+ standardmap -> k_hi = M_k_hi;
+ return;
+ }
+ if (argc == 1) {
+ // set the ranges based on percentage of full range
+ double percent = atom_getfloat(arg);
+ double k_spread = ((M_k_hi - M_k_lo) * percent) / 2;
+ standardmap -> k_lo = standardmap -> k - k_spread;
+ standardmap -> k_hi = standardmap -> k + k_spread;
+ limiter(standardmap);
+ return;
+ }
+ if (argc != M_param_count * 2) {
+ post("Invalid number of arguments for standardmap constraints, requires 2 values, got %d", argc);
+ return;
+ }
+ standardmap -> k_lo = atom_getfloat(arg++);
+ standardmap -> k_hi = atom_getfloat(arg++);
+ limiter(standardmap);
+}
+
+static void search(standardmap_struct *standardmap, t_symbol *s, int argc, t_atom *argv) {
+ int not_found, not_expired = standardmap -> lyap_limit;
+ int jump, i, iterations;
+ t_atom vars[M_var_count];
+ double temp_k = standardmap -> k;
+ 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], standardmap -> vars_init[i]);
+ }
+ }
+ do {
+ jump = 500;
+ not_found = 0;
+ iterations = 10000;
+ bad_params:
+ standardmap -> k = (drand48() * (standardmap -> k_hi - standardmap -> k_lo)) + standardmap -> k_lo;
+ // put any preliminary checks specific to this fractal to eliminate bad_params
+
+ reset(standardmap, NULL, argc, vars);
+ do { calc(standardmap, standardmap -> vars); } while(jump--);
+ standardmap -> lyap_exp = lyapunov((void *) standardmap, (t_gotfn) calc, M_var_count, (double *) standardmap -> vars);
+ if (isnan(standardmap -> lyap_exp)) { not_found = 1; }
+ if (standardmap -> lyap_exp < standardmap -> lyap_lo || standardmap -> lyap_exp > standardmap -> lyap_hi) { not_found = 1; }
+ not_expired--;
+ } while(not_found && not_expired);
+ reset(standardmap, NULL, argc, vars);
+ if (!not_expired) {
+ post("Could not find a fractal after %d attempts.", (int) standardmap -> lyap_limit);
+ post("Try using wider constraints.");
+ standardmap -> k = temp_k;
+ outlet_anything(standardmap -> search_outlet, gensym("invalid"), 0, NULL);
+ } else {
+ standardmap -> failure_ratio = (standardmap -> lyap_limit - not_expired) / standardmap -> lyap_limit;
+ make_results(standardmap);
+ outlet_anything(standardmap -> search_outlet, gensym("search"), M_search_count, standardmap -> search_out);
+ }
+}
+
+void *standardmap_new(t_symbol *s, int argc, t_atom *argv) {
+ standardmap_struct *standardmap = (standardmap_struct *) pd_new(standardmap_class);
+ if (standardmap != NULL) {
+ outlet_new(&standardmap -> x_obj, &s_float);
+ standardmap -> outlets[0] = outlet_new(&standardmap -> x_obj, &s_float);
+ standardmap -> search_outlet = outlet_new(&standardmap -> x_obj, &s_list);
+ standardmap -> vars_outlet = outlet_new(&standardmap -> x_obj, &s_list);
+ standardmap -> params_outlet = outlet_new(&standardmap -> x_obj, &s_list);
+ if (argc == M_param_count + M_var_count) {
+ standardmap -> vars_init[M_p] = standardmap -> vars[M_p] = (double) atom_getfloatarg(0, argc, argv);
+ standardmap -> vars_init[M_q] = standardmap -> vars[M_q] = (double) atom_getfloatarg(1, argc, argv);
+ standardmap -> k = (double) atom_getfloatarg(2, argc, argv);
+ } else {
+ if (argc != 0 && argc != M_param_count + M_var_count) {
+ post("Incorrect number of arguments for standardmap fractal. Expecting 3 arguments.");
+ }
+ standardmap -> vars_init[M_p] = 0.1;
+ standardmap -> vars_init[M_q] = 0.1;
+ standardmap -> k = 1;
+ }
+ constrain(standardmap, NULL, 0, NULL);
+ lyap(standardmap, -1000000.0, 1000000.0, M_failure_limit);
+ }
+ return (void *)standardmap;
+}
+
+void standardmap_setup(void) {
+ standardmap_class = class_new(gensym("standardmap"), (t_newmethod) standardmap_new, 0, sizeof(standardmap_struct), 0, A_GIMME, 0);
+ class_addbang(standardmap_class, (t_method) calculate);
+ class_addmethod(standardmap_class, (t_method) reset, gensym("reset"), A_GIMME, 0);
+ class_addmethod(standardmap_class, (t_method) show, gensym("show"), 0);
+ class_addmethod(standardmap_class, (t_method) param, gensym("param"), A_GIMME, 0);
+ class_addmethod(standardmap_class, (t_method) seed, gensym("seed"), A_GIMME, 0);
+ class_addmethod(standardmap_class, (t_method) lyap, gensym("lyapunov"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(standardmap_class, (t_method) elyap, gensym("elyapunov"), 0);
+ class_addmethod(standardmap_class, (t_method) search, gensym("search"), A_GIMME, 0);
+ class_addmethod(standardmap_class, (t_method) constrain, gensym("constrain"), A_GIMME, 0);
+ class_sethelpsymbol(standardmap_class, gensym("help-standardmap.pd"));
+}
+
diff --git a/strange1.c b/strange1.c
new file mode 100644
index 0000000..2a4f500
--- /dev/null
+++ b/strange1.c
@@ -0,0 +1,501 @@
+/* strange1 Attractor PD External */
+/* Copyright Michael McGonagle, from ???pbourke???, 2003 */
+/* This program is distributed under the params of the GNU Public License */
+
+///////////////////////////////////////////////////////////////////////////////////
+/* This file is part of Chaos PD Externals. */
+/* */
+/* Chaos PD Externals are free software; you can redistribute them and/or modify */
+/* them under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* Chaos PD Externals are distributed in the hope that they will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with the Chaos PD Externals; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+///////////////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#include "lyapunov.h"
+
+#define M_a0_lo -2
+#define M_a0_hi 2
+#define M_a1_lo -2
+#define M_a1_hi 2
+#define M_a2_lo -2
+#define M_a2_hi 2
+#define M_a3_lo -2
+#define M_a3_hi 2
+#define M_a4_lo -2
+#define M_a4_hi 2
+#define M_a5_lo -2
+#define M_a5_hi 2
+#define M_b0_lo -2
+#define M_b0_hi 2
+#define M_b1_lo -2
+#define M_b1_hi 2
+#define M_b2_lo -2
+#define M_b2_hi 2
+#define M_b3_lo -2
+#define M_b3_hi 2
+#define M_b4_lo -2
+#define M_b4_hi 2
+#define M_b5_lo -2
+#define M_b5_hi 2
+
+#define M_a0 0
+#define M_a1 1
+#define M_a2 2
+#define M_a3 3
+#define M_a4 4
+#define M_a5 5
+#define M_b0 6
+#define M_b1 7
+#define M_b2 8
+#define M_b3 9
+#define M_b4 10
+#define M_b5 11
+
+#define M_x 0
+#define M_y 1
+
+#define M_param_count 12
+#define M_var_count 2
+#define M_search_count 3
+#define M_failure_limit 1000
+
+static char *version = "strange1 v0.0, by Michael McGonagle, from ???pbourke???, 2003";
+
+t_class *strange1_class;
+
+typedef struct strange1_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 a0, a0_lo, a0_hi, a1, a1_lo, a1_hi, a2, a2_lo, a2_hi, a3, a3_lo, a3_hi, a4, a4_lo, a4_hi, a5, a5_lo, a5_hi, b0, b0_lo, b0_hi, b1, b1_lo, b1_hi, b2, b2_lo, b2_hi, b3, b3_lo, b3_hi, b4, b4_lo, b4_hi, b5, b5_lo, b5_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];
+} strange1_struct;
+
+static void calc(strange1_struct *strange1, double *vars) {
+ double x_0, y_0;
+ x_0 =strange1 -> a0+strange1 -> a1*vars[M_x]+strange1 -> a2*vars[M_x]*vars[M_x]+strange1 -> a3*vars[M_x]*vars[M_y]+strange1 -> a4*vars[M_y]+strange1 -> a5*vars[M_y]*vars[M_y];
+ y_0 =strange1 -> b0+strange1 -> b1*vars[M_x]+strange1 -> b2*vars[M_x]*vars[M_x]+strange1 -> b3*vars[M_x]*vars[M_y]+strange1 -> b4*vars[M_y]+strange1 -> b5*vars[M_y]*vars[M_y];
+ vars[M_x] = x_0;
+ vars[M_y] = y_0;
+} // end calc
+
+static void calculate(strange1_struct *strange1) {
+ calc(strange1, strange1 -> vars);
+ outlet_float(strange1 -> x_obj.ob_outlet, strange1 -> vars[M_x]);
+ outlet_float(strange1 -> outlets[M_y - 1], strange1 -> vars[M_y]);
+} // end calculate
+
+static void reset(strange1_struct *strange1, t_symbol *s, int argc, t_atom *argv) {
+ if (argc == M_var_count) {
+ strange1 -> vars[M_x] = (double) atom_getfloatarg(M_x, argc, argv);
+ strange1 -> vars[M_y] = (double) atom_getfloatarg(M_y, argc, argv);
+ } else {
+ strange1 -> vars[M_x] = strange1 -> vars_init[M_x];
+ strange1 -> vars[M_y] = strange1 -> vars_init[M_y];
+ } // end if
+} // end reset
+
+static char *classify(strange1_struct *strange1) {
+ static char buff[13];
+ char *c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ buff[0] = c[(int) (((strange1 -> a0 - M_a0_lo) * (1.0 / (M_a0_hi - M_a0_lo))) * 26)];
+ buff[1] = c[(int) (((strange1 -> a1 - M_a1_lo) * (1.0 / (M_a1_hi - M_a1_lo))) * 26)];
+ buff[2] = c[(int) (((strange1 -> a2 - M_a2_lo) * (1.0 / (M_a2_hi - M_a2_lo))) * 26)];
+ buff[3] = c[(int) (((strange1 -> a3 - M_a3_lo) * (1.0 / (M_a3_hi - M_a3_lo))) * 26)];
+ buff[4] = c[(int) (((strange1 -> a4 - M_a4_lo) * (1.0 / (M_a4_hi - M_a4_lo))) * 26)];
+ buff[5] = c[(int) (((strange1 -> a5 - M_a5_lo) * (1.0 / (M_a5_hi - M_a5_lo))) * 26)];
+ buff[6] = c[(int) (((strange1 -> b0 - M_b0_lo) * (1.0 / (M_b0_hi - M_b0_lo))) * 26)];
+ buff[7] = c[(int) (((strange1 -> b1 - M_b1_lo) * (1.0 / (M_b1_hi - M_b1_lo))) * 26)];
+ buff[8] = c[(int) (((strange1 -> b2 - M_b2_lo) * (1.0 / (M_b2_hi - M_b2_lo))) * 26)];
+ buff[9] = c[(int) (((strange1 -> b3 - M_b3_lo) * (1.0 / (M_b3_hi - M_b3_lo))) * 26)];
+ buff[10] = c[(int) (((strange1 -> b4 - M_b4_lo) * (1.0 / (M_b4_hi - M_b4_lo))) * 26)];
+ buff[11] = c[(int) (((strange1 -> b5 - M_b5_lo) * (1.0 / (M_b5_hi - M_b5_lo))) * 26)];
+ buff[12] = '\0';
+ return buff;
+}
+
+static void make_results(strange1_struct *strange1) {
+ SETFLOAT(&strange1 -> search_out[0], strange1 -> lyap_exp);
+ SETSYMBOL(&strange1 -> search_out[1], gensym(classify(strange1)));
+ SETFLOAT(&strange1 -> search_out[2], strange1 -> failure_ratio);
+ SETFLOAT(&strange1 -> vars_out[M_x], strange1 -> vars[M_x]);
+ SETFLOAT(&strange1 -> vars_out[M_y], strange1 -> vars[M_y]);
+ SETFLOAT(&strange1 -> params_out[M_a0], strange1 -> a0);
+ SETFLOAT(&strange1 -> params_out[M_a1], strange1 -> a1);
+ SETFLOAT(&strange1 -> params_out[M_a2], strange1 -> a2);
+ SETFLOAT(&strange1 -> params_out[M_a3], strange1 -> a3);
+ SETFLOAT(&strange1 -> params_out[M_a4], strange1 -> a4);
+ SETFLOAT(&strange1 -> params_out[M_a5], strange1 -> a5);
+ SETFLOAT(&strange1 -> params_out[M_b0], strange1 -> b0);
+ SETFLOAT(&strange1 -> params_out[M_b1], strange1 -> b1);
+ SETFLOAT(&strange1 -> params_out[M_b2], strange1 -> b2);
+ SETFLOAT(&strange1 -> params_out[M_b3], strange1 -> b3);
+ SETFLOAT(&strange1 -> params_out[M_b4], strange1 -> b4);
+ SETFLOAT(&strange1 -> params_out[M_b5], strange1 -> b5);
+ outlet_list(strange1 -> params_outlet, gensym("list"), M_param_count, strange1 -> params_out);
+ outlet_list(strange1 -> vars_outlet, gensym("list"), M_var_count, strange1 -> vars_out);
+}
+
+static void show(strange1_struct *strange1) {
+ make_results(strange1);
+ outlet_anything(strange1 -> search_outlet, gensym("show"), M_search_count, strange1 -> search_out);
+}
+
+static void param(strange1_struct *strange1, t_symbol *s, int argc, t_atom *argv) {
+ if (argc != 12) {
+ post("Incorrect number of arguments for strange1 fractal. Expecting 12 arguments.");
+ return;
+ }
+ strange1 -> a0 = (double) atom_getfloatarg(0, argc, argv);
+ strange1 -> a1 = (double) atom_getfloatarg(1, argc, argv);
+ strange1 -> a2 = (double) atom_getfloatarg(2, argc, argv);
+ strange1 -> a3 = (double) atom_getfloatarg(3, argc, argv);
+ strange1 -> a4 = (double) atom_getfloatarg(4, argc, argv);
+ strange1 -> a5 = (double) atom_getfloatarg(5, argc, argv);
+ strange1 -> b0 = (double) atom_getfloatarg(6, argc, argv);
+ strange1 -> b1 = (double) atom_getfloatarg(7, argc, argv);
+ strange1 -> b2 = (double) atom_getfloatarg(8, argc, argv);
+ strange1 -> b3 = (double) atom_getfloatarg(9, argc, argv);
+ strange1 -> b4 = (double) atom_getfloatarg(10, argc, argv);
+ strange1 -> b5 = (double) atom_getfloatarg(11, argc, argv);
+}
+
+static void seed(strange1_struct *strange1, 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(strange1_struct *strange1, t_floatarg l, t_floatarg h, t_floatarg lim) {
+ strange1 -> lyap_lo = l;
+ strange1 -> lyap_hi = h;
+ strange1 -> lyap_limit = (double) ((int) lim);
+}
+
+static void elyap(strange1_struct *strange1) {
+ double results[M_var_count];
+ int i;
+ if (lyapunov_full((void *) strange1, (t_gotfn) calc, M_var_count, strange1 -> vars, results) != NULL) {
+ post("elyapunov:");
+ for(i = 0; i < M_var_count; i++) { post("%d: %3.80f", i, results[i]); }
+ }
+}
+
+static void limiter(strange1_struct *strange1) {
+ if (strange1 -> a0_lo < M_a0_lo) { strange1 -> a0_lo = M_a0_lo; }
+ if (strange1 -> a0_lo > M_a0_hi) { strange1 -> a0_lo = M_a0_hi; }
+ if (strange1 -> a0_hi < M_a0_lo) { strange1 -> a0_hi = M_a0_lo; }
+ if (strange1 -> a0_hi > M_a0_hi) { strange1 -> a0_hi = M_a0_hi; }
+ if (strange1 -> a1_lo < M_a1_lo) { strange1 -> a1_lo = M_a1_lo; }
+ if (strange1 -> a1_lo > M_a1_hi) { strange1 -> a1_lo = M_a1_hi; }
+ if (strange1 -> a1_hi < M_a1_lo) { strange1 -> a1_hi = M_a1_lo; }
+ if (strange1 -> a1_hi > M_a1_hi) { strange1 -> a1_hi = M_a1_hi; }
+ if (strange1 -> a2_lo < M_a2_lo) { strange1 -> a2_lo = M_a2_lo; }
+ if (strange1 -> a2_lo > M_a2_hi) { strange1 -> a2_lo = M_a2_hi; }
+ if (strange1 -> a2_hi < M_a2_lo) { strange1 -> a2_hi = M_a2_lo; }
+ if (strange1 -> a2_hi > M_a2_hi) { strange1 -> a2_hi = M_a2_hi; }
+ if (strange1 -> a3_lo < M_a3_lo) { strange1 -> a3_lo = M_a3_lo; }
+ if (strange1 -> a3_lo > M_a3_hi) { strange1 -> a3_lo = M_a3_hi; }
+ if (strange1 -> a3_hi < M_a3_lo) { strange1 -> a3_hi = M_a3_lo; }
+ if (strange1 -> a3_hi > M_a3_hi) { strange1 -> a3_hi = M_a3_hi; }
+ if (strange1 -> a4_lo < M_a4_lo) { strange1 -> a4_lo = M_a4_lo; }
+ if (strange1 -> a4_lo > M_a4_hi) { strange1 -> a4_lo = M_a4_hi; }
+ if (strange1 -> a4_hi < M_a4_lo) { strange1 -> a4_hi = M_a4_lo; }
+ if (strange1 -> a4_hi > M_a4_hi) { strange1 -> a4_hi = M_a4_hi; }
+ if (strange1 -> a5_lo < M_a5_lo) { strange1 -> a5_lo = M_a5_lo; }
+ if (strange1 -> a5_lo > M_a5_hi) { strange1 -> a5_lo = M_a5_hi; }
+ if (strange1 -> a5_hi < M_a5_lo) { strange1 -> a5_hi = M_a5_lo; }
+ if (strange1 -> a5_hi > M_a5_hi) { strange1 -> a5_hi = M_a5_hi; }
+ if (strange1 -> b0_lo < M_b0_lo) { strange1 -> b0_lo = M_b0_lo; }
+ if (strange1 -> b0_lo > M_b0_hi) { strange1 -> b0_lo = M_b0_hi; }
+ if (strange1 -> b0_hi < M_b0_lo) { strange1 -> b0_hi = M_b0_lo; }
+ if (strange1 -> b0_hi > M_b0_hi) { strange1 -> b0_hi = M_b0_hi; }
+ if (strange1 -> b1_lo < M_b1_lo) { strange1 -> b1_lo = M_b1_lo; }
+ if (strange1 -> b1_lo > M_b1_hi) { strange1 -> b1_lo = M_b1_hi; }
+ if (strange1 -> b1_hi < M_b1_lo) { strange1 -> b1_hi = M_b1_lo; }
+ if (strange1 -> b1_hi > M_b1_hi) { strange1 -> b1_hi = M_b1_hi; }
+ if (strange1 -> b2_lo < M_b2_lo) { strange1 -> b2_lo = M_b2_lo; }
+ if (strange1 -> b2_lo > M_b2_hi) { strange1 -> b2_lo = M_b2_hi; }
+ if (strange1 -> b2_hi < M_b2_lo) { strange1 -> b2_hi = M_b2_lo; }
+ if (strange1 -> b2_hi > M_b2_hi) { strange1 -> b2_hi = M_b2_hi; }
+ if (strange1 -> b3_lo < M_b3_lo) { strange1 -> b3_lo = M_b3_lo; }
+ if (strange1 -> b3_lo > M_b3_hi) { strange1 -> b3_lo = M_b3_hi; }
+ if (strange1 -> b3_hi < M_b3_lo) { strange1 -> b3_hi = M_b3_lo; }
+ if (strange1 -> b3_hi > M_b3_hi) { strange1 -> b3_hi = M_b3_hi; }
+ if (strange1 -> b4_lo < M_b4_lo) { strange1 -> b4_lo = M_b4_lo; }
+ if (strange1 -> b4_lo > M_b4_hi) { strange1 -> b4_lo = M_b4_hi; }
+ if (strange1 -> b4_hi < M_b4_lo) { strange1 -> b4_hi = M_b4_lo; }
+ if (strange1 -> b4_hi > M_b4_hi) { strange1 -> b4_hi = M_b4_hi; }
+ if (strange1 -> b5_lo < M_b5_lo) { strange1 -> b5_lo = M_b5_lo; }
+ if (strange1 -> b5_lo > M_b5_hi) { strange1 -> b5_lo = M_b5_hi; }
+ if (strange1 -> b5_hi < M_b5_lo) { strange1 -> b5_hi = M_b5_lo; }
+ if (strange1 -> b5_hi > M_b5_hi) { strange1 -> b5_hi = M_b5_hi; }
+}
+
+static void constrain(strange1_struct *strange1, t_symbol *s, int argc, t_atom *argv) {
+ int i;
+ t_atom *arg = argv;
+ if (argc == 0) {
+ // reset to full limits of search ranges
+ strange1 -> a0_lo = M_a0_lo;
+ strange1 -> a0_hi = M_a0_hi;
+ strange1 -> a1_lo = M_a1_lo;
+ strange1 -> a1_hi = M_a1_hi;
+ strange1 -> a2_lo = M_a2_lo;
+ strange1 -> a2_hi = M_a2_hi;
+ strange1 -> a3_lo = M_a3_lo;
+ strange1 -> a3_hi = M_a3_hi;
+ strange1 -> a4_lo = M_a4_lo;
+ strange1 -> a4_hi = M_a4_hi;
+ strange1 -> a5_lo = M_a5_lo;
+ strange1 -> a5_hi = M_a5_hi;
+ strange1 -> b0_lo = M_b0_lo;
+ strange1 -> b0_hi = M_b0_hi;
+ strange1 -> b1_lo = M_b1_lo;
+ strange1 -> b1_hi = M_b1_hi;
+ strange1 -> b2_lo = M_b2_lo;
+ strange1 -> b2_hi = M_b2_hi;
+ strange1 -> b3_lo = M_b3_lo;
+ strange1 -> b3_hi = M_b3_hi;
+ strange1 -> b4_lo = M_b4_lo;
+ strange1 -> b4_hi = M_b4_hi;
+ strange1 -> b5_lo = M_b5_lo;
+ strange1 -> b5_hi = M_b5_hi;
+ return;
+ }
+ if (argc == 1) {
+ // set the ranges based on percentage of full range
+ double percent = atom_getfloat(arg);
+ double a0_spread = ((M_a0_hi - M_a0_lo) * percent) / 2;
+ double a1_spread = ((M_a1_hi - M_a1_lo) * percent) / 2;
+ double a2_spread = ((M_a2_hi - M_a2_lo) * percent) / 2;
+ double a3_spread = ((M_a3_hi - M_a3_lo) * percent) / 2;
+ double a4_spread = ((M_a4_hi - M_a4_lo) * percent) / 2;
+ double a5_spread = ((M_a5_hi - M_a5_lo) * percent) / 2;
+ double b0_spread = ((M_b0_hi - M_b0_lo) * percent) / 2;
+ double b1_spread = ((M_b1_hi - M_b1_lo) * percent) / 2;
+ double b2_spread = ((M_b2_hi - M_b2_lo) * percent) / 2;
+ double b3_spread = ((M_b3_hi - M_b3_lo) * percent) / 2;
+ double b4_spread = ((M_b4_hi - M_b4_lo) * percent) / 2;
+ double b5_spread = ((M_b5_hi - M_b5_lo) * percent) / 2;
+ strange1 -> a0_lo = strange1 -> a0 - a0_spread;
+ strange1 -> a0_hi = strange1 -> a0 + a0_spread;
+ strange1 -> a1_lo = strange1 -> a1 - a1_spread;
+ strange1 -> a1_hi = strange1 -> a1 + a1_spread;
+ strange1 -> a2_lo = strange1 -> a2 - a2_spread;
+ strange1 -> a2_hi = strange1 -> a2 + a2_spread;
+ strange1 -> a3_lo = strange1 -> a3 - a3_spread;
+ strange1 -> a3_hi = strange1 -> a3 + a3_spread;
+ strange1 -> a4_lo = strange1 -> a4 - a4_spread;
+ strange1 -> a4_hi = strange1 -> a4 + a4_spread;
+ strange1 -> a5_lo = strange1 -> a5 - a5_spread;
+ strange1 -> a5_hi = strange1 -> a5 + a5_spread;
+ strange1 -> b0_lo = strange1 -> b0 - b0_spread;
+ strange1 -> b0_hi = strange1 -> b0 + b0_spread;
+ strange1 -> b1_lo = strange1 -> b1 - b1_spread;
+ strange1 -> b1_hi = strange1 -> b1 + b1_spread;
+ strange1 -> b2_lo = strange1 -> b2 - b2_spread;
+ strange1 -> b2_hi = strange1 -> b2 + b2_spread;
+ strange1 -> b3_lo = strange1 -> b3 - b3_spread;
+ strange1 -> b3_hi = strange1 -> b3 + b3_spread;
+ strange1 -> b4_lo = strange1 -> b4 - b4_spread;
+ strange1 -> b4_hi = strange1 -> b4 + b4_spread;
+ strange1 -> b5_lo = strange1 -> b5 - b5_spread;
+ strange1 -> b5_hi = strange1 -> b5 + b5_spread;
+ limiter(strange1);
+ return;
+ }
+ if (argc != M_param_count * 2) {
+ post("Invalid number of arguments for strange1 constraints, requires 24 values, got %d", argc);
+ return;
+ }
+ strange1 -> a0_lo = atom_getfloat(arg++);
+ strange1 -> a0_hi = atom_getfloat(arg++);
+ strange1 -> a1_lo = atom_getfloat(arg++);
+ strange1 -> a1_hi = atom_getfloat(arg++);
+ strange1 -> a2_lo = atom_getfloat(arg++);
+ strange1 -> a2_hi = atom_getfloat(arg++);
+ strange1 -> a3_lo = atom_getfloat(arg++);
+ strange1 -> a3_hi = atom_getfloat(arg++);
+ strange1 -> a4_lo = atom_getfloat(arg++);
+ strange1 -> a4_hi = atom_getfloat(arg++);
+ strange1 -> a5_lo = atom_getfloat(arg++);
+ strange1 -> a5_hi = atom_getfloat(arg++);
+ strange1 -> b0_lo = atom_getfloat(arg++);
+ strange1 -> b0_hi = atom_getfloat(arg++);
+ strange1 -> b1_lo = atom_getfloat(arg++);
+ strange1 -> b1_hi = atom_getfloat(arg++);
+ strange1 -> b2_lo = atom_getfloat(arg++);
+ strange1 -> b2_hi = atom_getfloat(arg++);
+ strange1 -> b3_lo = atom_getfloat(arg++);
+ strange1 -> b3_hi = atom_getfloat(arg++);
+ strange1 -> b4_lo = atom_getfloat(arg++);
+ strange1 -> b4_hi = atom_getfloat(arg++);
+ strange1 -> b5_lo = atom_getfloat(arg++);
+ strange1 -> b5_hi = atom_getfloat(arg++);
+ limiter(strange1);
+}
+
+static void search(strange1_struct *strange1, t_symbol *s, int argc, t_atom *argv) {
+ int not_found, not_expired = strange1 -> lyap_limit;
+ int jump, i, iterations;
+ t_atom vars[M_var_count];
+ double temp_a0 = strange1 -> a0;
+ double temp_a1 = strange1 -> a1;
+ double temp_a2 = strange1 -> a2;
+ double temp_a3 = strange1 -> a3;
+ double temp_a4 = strange1 -> a4;
+ double temp_a5 = strange1 -> a5;
+ double temp_b0 = strange1 -> b0;
+ double temp_b1 = strange1 -> b1;
+ double temp_b2 = strange1 -> b2;
+ double temp_b3 = strange1 -> b3;
+ double temp_b4 = strange1 -> b4;
+ double temp_b5 = strange1 -> b5;
+ 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], strange1 -> vars_init[i]);
+ }
+ }
+ do {
+ jump = 500;
+ not_found = 0;
+ iterations = 10000;
+ bad_params:
+ strange1 -> a0 = (drand48() * (strange1 -> a0_hi - strange1 -> a0_lo)) + strange1 -> a0_lo;
+ strange1 -> a1 = (drand48() * (strange1 -> a1_hi - strange1 -> a1_lo)) + strange1 -> a1_lo;
+ strange1 -> a2 = (drand48() * (strange1 -> a2_hi - strange1 -> a2_lo)) + strange1 -> a2_lo;
+ strange1 -> a3 = (drand48() * (strange1 -> a3_hi - strange1 -> a3_lo)) + strange1 -> a3_lo;
+ strange1 -> a4 = (drand48() * (strange1 -> a4_hi - strange1 -> a4_lo)) + strange1 -> a4_lo;
+ strange1 -> a5 = (drand48() * (strange1 -> a5_hi - strange1 -> a5_lo)) + strange1 -> a5_lo;
+ strange1 -> b0 = (drand48() * (strange1 -> b0_hi - strange1 -> b0_lo)) + strange1 -> b0_lo;
+ strange1 -> b1 = (drand48() * (strange1 -> b1_hi - strange1 -> b1_lo)) + strange1 -> b1_lo;
+ strange1 -> b2 = (drand48() * (strange1 -> b2_hi - strange1 -> b2_lo)) + strange1 -> b2_lo;
+ strange1 -> b3 = (drand48() * (strange1 -> b3_hi - strange1 -> b3_lo)) + strange1 -> b3_lo;
+ strange1 -> b4 = (drand48() * (strange1 -> b4_hi - strange1 -> b4_lo)) + strange1 -> b4_lo;
+ strange1 -> b5 = (drand48() * (strange1 -> b5_hi - strange1 -> b5_lo)) + strange1 -> b5_lo;
+ // put any preliminary checks specific to this fractal to eliminate bad_params
+
+ reset(strange1, NULL, argc, vars);
+ do { calc(strange1, strange1 -> vars); } while(jump--);
+ strange1 -> lyap_exp = lyapunov((void *) strange1, (t_gotfn) calc, M_var_count, (double *) strange1 -> vars);
+ if (isnan(strange1 -> lyap_exp)) { not_found = 1; }
+ if (strange1 -> lyap_exp < strange1 -> lyap_lo || strange1 -> lyap_exp > strange1 -> lyap_hi) { not_found = 1; }
+ not_expired--;
+ } while(not_found && not_expired);
+ reset(strange1, NULL, argc, vars);
+ if (!not_expired) {
+ post("Could not find a fractal after %d attempts.", (int) strange1 -> lyap_limit);
+ post("Try using wider constraints.");
+ strange1 -> a0 = temp_a0;
+ strange1 -> a1 = temp_a1;
+ strange1 -> a2 = temp_a2;
+ strange1 -> a3 = temp_a3;
+ strange1 -> a4 = temp_a4;
+ strange1 -> a5 = temp_a5;
+ strange1 -> b0 = temp_b0;
+ strange1 -> b1 = temp_b1;
+ strange1 -> b2 = temp_b2;
+ strange1 -> b3 = temp_b3;
+ strange1 -> b4 = temp_b4;
+ strange1 -> b5 = temp_b5;
+ outlet_anything(strange1 -> search_outlet, gensym("invalid"), 0, NULL);
+ } else {
+ strange1 -> failure_ratio = (strange1 -> lyap_limit - not_expired) / strange1 -> lyap_limit;
+ make_results(strange1);
+ outlet_anything(strange1 -> search_outlet, gensym("search"), M_search_count, strange1 -> search_out);
+ }
+}
+
+void *strange1_new(t_symbol *s, int argc, t_atom *argv) {
+ strange1_struct *strange1 = (strange1_struct *) pd_new(strange1_class);
+ if (strange1 != NULL) {
+ outlet_new(&strange1 -> x_obj, &s_float);
+ strange1 -> outlets[0] = outlet_new(&strange1 -> x_obj, &s_float);
+ strange1 -> search_outlet = outlet_new(&strange1 -> x_obj, &s_list);
+ strange1 -> vars_outlet = outlet_new(&strange1 -> x_obj, &s_list);
+ strange1 -> params_outlet = outlet_new(&strange1 -> x_obj, &s_list);
+ if (argc == M_param_count + M_var_count) {
+ strange1 -> vars_init[M_x] = strange1 -> vars[M_x] = (double) atom_getfloatarg(0, argc, argv);
+ strange1 -> vars_init[M_y] = strange1 -> vars[M_y] = (double) atom_getfloatarg(1, argc, argv);
+ strange1 -> a0 = (double) atom_getfloatarg(2, argc, argv);
+ strange1 -> a1 = (double) atom_getfloatarg(3, argc, argv);
+ strange1 -> a2 = (double) atom_getfloatarg(4, argc, argv);
+ strange1 -> a3 = (double) atom_getfloatarg(5, argc, argv);
+ strange1 -> a4 = (double) atom_getfloatarg(6, argc, argv);
+ strange1 -> a5 = (double) atom_getfloatarg(7, argc, argv);
+ strange1 -> b0 = (double) atom_getfloatarg(8, argc, argv);
+ strange1 -> b1 = (double) atom_getfloatarg(9, argc, argv);
+ strange1 -> b2 = (double) atom_getfloatarg(10, argc, argv);
+ strange1 -> b3 = (double) atom_getfloatarg(11, argc, argv);
+ strange1 -> b4 = (double) atom_getfloatarg(12, argc, argv);
+ strange1 -> b5 = (double) atom_getfloatarg(13, argc, argv);
+ } else {
+ if (argc != 0 && argc != M_param_count + M_var_count) {
+ post("Incorrect number of arguments for strange1 fractal. Expecting 14 arguments.");
+ }
+ strange1 -> vars_init[M_x] = 0;
+ strange1 -> vars_init[M_y] = 0;
+ strange1 -> a0 = 1;
+ strange1 -> a1 = 1;
+ strange1 -> a2 = 1;
+ strange1 -> a3 = 1;
+ strange1 -> a4 = 1;
+ strange1 -> a5 = 1;
+ strange1 -> b0 = 1;
+ strange1 -> b1 = 1;
+ strange1 -> b2 = 1;
+ strange1 -> b3 = 1;
+ strange1 -> b4 = 1;
+ strange1 -> b5 = 1;
+ }
+ constrain(strange1, NULL, 0, NULL);
+ lyap(strange1, -1000000.0, 1000000.0, M_failure_limit);
+ }
+ return (void *)strange1;
+}
+
+void strange1_setup(void) {
+ strange1_class = class_new(gensym("strange1"), (t_newmethod) strange1_new, 0, sizeof(strange1_struct), 0, A_GIMME, 0);
+ class_addbang(strange1_class, (t_method) calculate);
+ class_addmethod(strange1_class, (t_method) reset, gensym("reset"), A_GIMME, 0);
+ class_addmethod(strange1_class, (t_method) show, gensym("show"), 0);
+ class_addmethod(strange1_class, (t_method) param, gensym("param"), A_GIMME, 0);
+ class_addmethod(strange1_class, (t_method) seed, gensym("seed"), A_GIMME, 0);
+ class_addmethod(strange1_class, (t_method) lyap, gensym("lyapunov"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(strange1_class, (t_method) elyap, gensym("elyapunov"), 0);
+ class_addmethod(strange1_class, (t_method) search, gensym("search"), A_GIMME, 0);
+ class_addmethod(strange1_class, (t_method) constrain, gensym("constrain"), A_GIMME, 0);
+ class_sethelpsymbol(strange1_class, gensym("help-strange1.pd"));
+}
+
diff --git a/tent.c b/tent.c
new file mode 100644
index 0000000..baf7302
--- /dev/null
+++ b/tent.c
@@ -0,0 +1,247 @@
+/* tent Attractor PD External */
+/* Copyright Michael McGonagle, from Cliff Pickover, 2003 */
+/* This program is distributed under the params of the GNU Public License */
+
+///////////////////////////////////////////////////////////////////////////////////
+/* This file is part of Chaos PD Externals. */
+/* */
+/* Chaos PD Externals are free software; you can redistribute them and/or modify */
+/* them under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* Chaos PD Externals are distributed in the hope that they will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with the Chaos PD Externals; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+///////////////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#include "lyapunov.h"
+
+#define M_r_lo -1000
+#define M_r_hi 1000
+
+#define M_r 0
+
+#define M_x 0
+
+#define M_param_count 1
+#define M_var_count 1
+#define M_search_count 3
+#define M_failure_limit 1000
+
+static char *version = "tent v0.0, by Michael McGonagle, from Cliff Pickover, 2003";
+
+t_class *tent_class;
+
+typedef struct tent_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 r, r_lo, r_hi;
+ t_atom params_out[M_param_count];
+ t_outlet *params_outlet;
+ double lyap_exp, lyap_lo, lyap_hi, lyap_limit, failure_ratio;
+} tent_struct;
+
+static void calc(tent_struct *tent, double *vars) {
+ double x_0;
+ x_0 =(vars[M_x]<=0.5)?2*tent -> r*vars[M_x]:2*tent -> r*(1.0-vars[M_x]);
+ vars[M_x] = x_0;
+} // end calc
+
+static void calculate(tent_struct *tent) {
+ calc(tent, tent -> vars);
+ outlet_float(tent -> x_obj.ob_outlet, tent -> vars[M_x]);
+} // end calculate
+
+static void reset(tent_struct *tent, t_symbol *s, int argc, t_atom *argv) {
+ if (argc == M_var_count) {
+ tent -> vars[M_x] = (double) atom_getfloatarg(M_x, argc, argv);
+ } else {
+ tent -> vars[M_x] = tent -> vars_init[M_x];
+ } // end if
+} // end reset
+
+static char *classify(tent_struct *tent) {
+ static char buff[2];
+ char *c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ buff[0] = c[(int) (((tent -> r - M_r_lo) * (1.0 / (M_r_hi - M_r_lo))) * 26)];
+ buff[1] = '\0';
+ return buff;
+}
+
+static void make_results(tent_struct *tent) {
+ SETFLOAT(&tent -> search_out[0], tent -> lyap_exp);
+ SETSYMBOL(&tent -> search_out[1], gensym(classify(tent)));
+ SETFLOAT(&tent -> search_out[2], tent -> failure_ratio);
+ SETFLOAT(&tent -> vars_out[M_x], tent -> vars[M_x]);
+ SETFLOAT(&tent -> params_out[M_r], tent -> r);
+ outlet_list(tent -> params_outlet, gensym("list"), M_param_count, tent -> params_out);
+ outlet_list(tent -> vars_outlet, gensym("list"), M_var_count, tent -> vars_out);
+}
+
+static void show(tent_struct *tent) {
+ make_results(tent);
+ outlet_anything(tent -> search_outlet, gensym("show"), M_search_count, tent -> search_out);
+}
+
+static void param(tent_struct *tent, t_symbol *s, int argc, t_atom *argv) {
+ if (argc != 1) {
+ post("Incorrect number of arguments for tent fractal. Expecting 1 arguments.");
+ return;
+ }
+ tent -> r = (double) atom_getfloatarg(0, argc, argv);
+}
+
+static void seed(tent_struct *tent, 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(tent_struct *tent, t_floatarg l, t_floatarg h, t_floatarg lim) {
+ tent -> lyap_lo = l;
+ tent -> lyap_hi = h;
+ tent -> lyap_limit = (double) ((int) lim);
+}
+
+static void elyap(tent_struct *tent) {
+ double results[M_var_count];
+ int i;
+ if (lyapunov_full((void *) tent, (t_gotfn) calc, M_var_count, tent -> vars, results) != NULL) {
+ post("elyapunov:");
+ for(i = 0; i < M_var_count; i++) { post("%d: %3.80f", i, results[i]); }
+ }
+}
+
+static void limiter(tent_struct *tent) {
+ if (tent -> r_lo < M_r_lo) { tent -> r_lo = M_r_lo; }
+ if (tent -> r_lo > M_r_hi) { tent -> r_lo = M_r_hi; }
+ if (tent -> r_hi < M_r_lo) { tent -> r_hi = M_r_lo; }
+ if (tent -> r_hi > M_r_hi) { tent -> r_hi = M_r_hi; }
+}
+
+static void constrain(tent_struct *tent, t_symbol *s, int argc, t_atom *argv) {
+ int i;
+ t_atom *arg = argv;
+ if (argc == 0) {
+ // reset to full limits of search ranges
+ tent -> r_lo = M_r_lo;
+ tent -> r_hi = M_r_hi;
+ return;
+ }
+ if (argc == 1) {
+ // set the ranges based on percentage of full range
+ double percent = atom_getfloat(arg);
+ double r_spread = ((M_r_hi - M_r_lo) * percent) / 2;
+ tent -> r_lo = tent -> r - r_spread;
+ tent -> r_hi = tent -> r + r_spread;
+ limiter(tent);
+ return;
+ }
+ if (argc != M_param_count * 2) {
+ post("Invalid number of arguments for tent constraints, requires 2 values, got %d", argc);
+ return;
+ }
+ tent -> r_lo = atom_getfloat(arg++);
+ tent -> r_hi = atom_getfloat(arg++);
+ limiter(tent);
+}
+
+static void search(tent_struct *tent, t_symbol *s, int argc, t_atom *argv) {
+ int not_found, not_expired = tent -> lyap_limit;
+ int jump, i, iterations;
+ t_atom vars[M_var_count];
+ double temp_r = tent -> r;
+ 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], tent -> vars_init[i]);
+ }
+ }
+ do {
+ jump = 500;
+ not_found = 0;
+ iterations = 10000;
+ bad_params:
+ tent -> r = (drand48() * (tent -> r_hi - tent -> r_lo)) + tent -> r_lo;
+ // put any preliminary checks specific to this fractal to eliminate bad_params
+
+ reset(tent, NULL, argc, vars);
+ do { calc(tent, tent -> vars); } while(jump--);
+ tent -> lyap_exp = lyapunov((void *) tent, (t_gotfn) calc, M_var_count, (double *) tent -> vars);
+ if (isnan(tent -> lyap_exp)) { not_found = 1; }
+ if (tent -> lyap_exp < tent -> lyap_lo || tent -> lyap_exp > tent -> lyap_hi) { not_found = 1; }
+ not_expired--;
+ } while(not_found && not_expired);
+ reset(tent, NULL, argc, vars);
+ if (!not_expired) {
+ post("Could not find a fractal after %d attempts.", (int) tent -> lyap_limit);
+ post("Try using wider constraints.");
+ tent -> r = temp_r;
+ outlet_anything(tent -> search_outlet, gensym("invalid"), 0, NULL);
+ } else {
+ tent -> failure_ratio = (tent -> lyap_limit - not_expired) / tent -> lyap_limit;
+ make_results(tent);
+ outlet_anything(tent -> search_outlet, gensym("search"), M_search_count, tent -> search_out);
+ }
+}
+
+void *tent_new(t_symbol *s, int argc, t_atom *argv) {
+ tent_struct *tent = (tent_struct *) pd_new(tent_class);
+ if (tent != NULL) {
+ outlet_new(&tent -> x_obj, &s_float);
+ tent -> search_outlet = outlet_new(&tent -> x_obj, &s_list);
+ tent -> vars_outlet = outlet_new(&tent -> x_obj, &s_list);
+ tent -> params_outlet = outlet_new(&tent -> x_obj, &s_list);
+ if (argc == M_param_count + M_var_count) {
+ tent -> vars_init[M_x] = tent -> vars[M_x] = (double) atom_getfloatarg(0, argc, argv);
+ tent -> r = (double) atom_getfloatarg(1, argc, argv);
+ } else {
+ if (argc != 0 && argc != M_param_count + M_var_count) {
+ post("Incorrect number of arguments for tent fractal. Expecting 2 arguments.");
+ }
+ tent -> vars_init[M_x] = 0.1;
+ tent -> r = 1;
+ }
+ constrain(tent, NULL, 0, NULL);
+ lyap(tent, -1000000.0, 1000000.0, M_failure_limit);
+ }
+ return (void *)tent;
+}
+
+void tent_setup(void) {
+ tent_class = class_new(gensym("tent"), (t_newmethod) tent_new, 0, sizeof(tent_struct), 0, A_GIMME, 0);
+ class_addbang(tent_class, (t_method) calculate);
+ class_addmethod(tent_class, (t_method) reset, gensym("reset"), A_GIMME, 0);
+ class_addmethod(tent_class, (t_method) show, gensym("show"), 0);
+ class_addmethod(tent_class, (t_method) param, gensym("param"), A_GIMME, 0);
+ class_addmethod(tent_class, (t_method) seed, gensym("seed"), A_GIMME, 0);
+ class_addmethod(tent_class, (t_method) lyap, gensym("lyapunov"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(tent_class, (t_method) elyap, gensym("elyapunov"), 0);
+ class_addmethod(tent_class, (t_method) search, gensym("search"), A_GIMME, 0);
+ class_addmethod(tent_class, (t_method) constrain, gensym("constrain"), A_GIMME, 0);
+ class_sethelpsymbol(tent_class, gensym("help-tent.pd"));
+}
+
diff --git a/three_d.c b/three_d.c
new file mode 100644
index 0000000..3ba4e7f
--- /dev/null
+++ b/three_d.c
@@ -0,0 +1,357 @@
+/* three_d Attractor PD External */
+/* Copyright Michael McGonagle, from Cliff Pickover, 2003 */
+/* This program is distributed under the params of the GNU Public License */
+
+///////////////////////////////////////////////////////////////////////////////////
+/* This file is part of Chaos PD Externals. */
+/* */
+/* Chaos PD Externals are free software; you can redistribute them and/or modify */
+/* them under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* Chaos PD Externals are distributed in the hope that they will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with the Chaos PD Externals; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+///////////////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#include "lyapunov.h"
+
+#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_d_lo -1000
+#define M_d_hi 1000
+#define M_e_lo -1000
+#define M_e_hi 1000
+
+#define M_a 0
+#define M_b 1
+#define M_c 2
+#define M_d 3
+#define M_e 4
+
+#define M_x 0
+#define M_y 1
+#define M_z 2
+
+#define M_param_count 5
+#define M_var_count 3
+#define M_search_count 3
+#define M_failure_limit 1000
+
+static char *version = "three_d v0.0, by Michael McGonagle, from Cliff Pickover, 2003";
+
+t_class *three_d_class;
+
+typedef struct three_d_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, d, d_lo, d_hi, e, e_lo, e_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];
+} three_d_struct;
+
+static void calc(three_d_struct *three_d, double *vars) {
+ double x_0, y_0, z_0;
+ x_0 =sin(three_d -> a*vars[M_y])-vars[M_z]*cos(three_d -> b*vars[M_x]);
+ y_0 =vars[M_z]*sin(three_d -> c*vars[M_x])-cos(three_d -> d*vars[M_y]);
+ z_0 =three_d -> e*sin(vars[M_x]);
+ vars[M_x] = x_0;
+ vars[M_y] = y_0;
+ vars[M_z] = z_0;
+} // end calc
+
+static void calculate(three_d_struct *three_d) {
+ calc(three_d, three_d -> vars);
+ outlet_float(three_d -> x_obj.ob_outlet, three_d -> vars[M_x]);
+ outlet_float(three_d -> outlets[M_y - 1], three_d -> vars[M_y]);
+ outlet_float(three_d -> outlets[M_z - 1], three_d -> vars[M_z]);
+} // end calculate
+
+static void reset(three_d_struct *three_d, t_symbol *s, int argc, t_atom *argv) {
+ if (argc == M_var_count) {
+ three_d -> vars[M_x] = (double) atom_getfloatarg(M_x, argc, argv);
+ three_d -> vars[M_y] = (double) atom_getfloatarg(M_y, argc, argv);
+ three_d -> vars[M_z] = (double) atom_getfloatarg(M_z, argc, argv);
+ } else {
+ three_d -> vars[M_x] = three_d -> vars_init[M_x];
+ three_d -> vars[M_y] = three_d -> vars_init[M_y];
+ three_d -> vars[M_z] = three_d -> vars_init[M_z];
+ } // end if
+} // end reset
+
+static char *classify(three_d_struct *three_d) {
+ static char buff[6];
+ char *c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ buff[0] = c[(int) (((three_d -> a - M_a_lo) * (1.0 / (M_a_hi - M_a_lo))) * 26)];
+ buff[1] = c[(int) (((three_d -> b - M_b_lo) * (1.0 / (M_b_hi - M_b_lo))) * 26)];
+ buff[2] = c[(int) (((three_d -> c - M_c_lo) * (1.0 / (M_c_hi - M_c_lo))) * 26)];
+ buff[3] = c[(int) (((three_d -> d - M_d_lo) * (1.0 / (M_d_hi - M_d_lo))) * 26)];
+ buff[4] = c[(int) (((three_d -> e - M_e_lo) * (1.0 / (M_e_hi - M_e_lo))) * 26)];
+ buff[5] = '\0';
+ return buff;
+}
+
+static void make_results(three_d_struct *three_d) {
+ SETFLOAT(&three_d -> search_out[0], three_d -> lyap_exp);
+ SETSYMBOL(&three_d -> search_out[1], gensym(classify(three_d)));
+ SETFLOAT(&three_d -> search_out[2], three_d -> failure_ratio);
+ SETFLOAT(&three_d -> vars_out[M_x], three_d -> vars[M_x]);
+ SETFLOAT(&three_d -> vars_out[M_y], three_d -> vars[M_y]);
+ SETFLOAT(&three_d -> vars_out[M_z], three_d -> vars[M_z]);
+ SETFLOAT(&three_d -> params_out[M_a], three_d -> a);
+ SETFLOAT(&three_d -> params_out[M_b], three_d -> b);
+ SETFLOAT(&three_d -> params_out[M_c], three_d -> c);
+ SETFLOAT(&three_d -> params_out[M_d], three_d -> d);
+ SETFLOAT(&three_d -> params_out[M_e], three_d -> e);
+ outlet_list(three_d -> params_outlet, gensym("list"), M_param_count, three_d -> params_out);
+ outlet_list(three_d -> vars_outlet, gensym("list"), M_var_count, three_d -> vars_out);
+}
+
+static void show(three_d_struct *three_d) {
+ make_results(three_d);
+ outlet_anything(three_d -> search_outlet, gensym("show"), M_search_count, three_d -> search_out);
+}
+
+static void param(three_d_struct *three_d, t_symbol *s, int argc, t_atom *argv) {
+ if (argc != 5) {
+ post("Incorrect number of arguments for three_d fractal. Expecting 5 arguments.");
+ return;
+ }
+ three_d -> a = (double) atom_getfloatarg(0, argc, argv);
+ three_d -> b = (double) atom_getfloatarg(1, argc, argv);
+ three_d -> c = (double) atom_getfloatarg(2, argc, argv);
+ three_d -> d = (double) atom_getfloatarg(3, argc, argv);
+ three_d -> e = (double) atom_getfloatarg(4, argc, argv);
+}
+
+static void seed(three_d_struct *three_d, 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(three_d_struct *three_d, t_floatarg l, t_floatarg h, t_floatarg lim) {
+ three_d -> lyap_lo = l;
+ three_d -> lyap_hi = h;
+ three_d -> lyap_limit = (double) ((int) lim);
+}
+
+static void elyap(three_d_struct *three_d) {
+ double results[M_var_count];
+ int i;
+ if (lyapunov_full((void *) three_d, (t_gotfn) calc, M_var_count, three_d -> vars, results) != NULL) {
+ post("elyapunov:");
+ for(i = 0; i < M_var_count; i++) { post("%d: %3.80f", i, results[i]); }
+ }
+}
+
+static void limiter(three_d_struct *three_d) {
+ if (three_d -> a_lo < M_a_lo) { three_d -> a_lo = M_a_lo; }
+ if (three_d -> a_lo > M_a_hi) { three_d -> a_lo = M_a_hi; }
+ if (three_d -> a_hi < M_a_lo) { three_d -> a_hi = M_a_lo; }
+ if (three_d -> a_hi > M_a_hi) { three_d -> a_hi = M_a_hi; }
+ if (three_d -> b_lo < M_b_lo) { three_d -> b_lo = M_b_lo; }
+ if (three_d -> b_lo > M_b_hi) { three_d -> b_lo = M_b_hi; }
+ if (three_d -> b_hi < M_b_lo) { three_d -> b_hi = M_b_lo; }
+ if (three_d -> b_hi > M_b_hi) { three_d -> b_hi = M_b_hi; }
+ if (three_d -> c_lo < M_c_lo) { three_d -> c_lo = M_c_lo; }
+ if (three_d -> c_lo > M_c_hi) { three_d -> c_lo = M_c_hi; }
+ if (three_d -> c_hi < M_c_lo) { three_d -> c_hi = M_c_lo; }
+ if (three_d -> c_hi > M_c_hi) { three_d -> c_hi = M_c_hi; }
+ if (three_d -> d_lo < M_d_lo) { three_d -> d_lo = M_d_lo; }
+ if (three_d -> d_lo > M_d_hi) { three_d -> d_lo = M_d_hi; }
+ if (three_d -> d_hi < M_d_lo) { three_d -> d_hi = M_d_lo; }
+ if (three_d -> d_hi > M_d_hi) { three_d -> d_hi = M_d_hi; }
+ if (three_d -> e_lo < M_e_lo) { three_d -> e_lo = M_e_lo; }
+ if (three_d -> e_lo > M_e_hi) { three_d -> e_lo = M_e_hi; }
+ if (three_d -> e_hi < M_e_lo) { three_d -> e_hi = M_e_lo; }
+ if (three_d -> e_hi > M_e_hi) { three_d -> e_hi = M_e_hi; }
+}
+
+static void constrain(three_d_struct *three_d, t_symbol *s, int argc, t_atom *argv) {
+ int i;
+ t_atom *arg = argv;
+ if (argc == 0) {
+ // reset to full limits of search ranges
+ three_d -> a_lo = M_a_lo;
+ three_d -> a_hi = M_a_hi;
+ three_d -> b_lo = M_b_lo;
+ three_d -> b_hi = M_b_hi;
+ three_d -> c_lo = M_c_lo;
+ three_d -> c_hi = M_c_hi;
+ three_d -> d_lo = M_d_lo;
+ three_d -> d_hi = M_d_hi;
+ three_d -> e_lo = M_e_lo;
+ three_d -> e_hi = M_e_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 d_spread = ((M_d_hi - M_d_lo) * percent) / 2;
+ double e_spread = ((M_e_hi - M_e_lo) * percent) / 2;
+ three_d -> a_lo = three_d -> a - a_spread;
+ three_d -> a_hi = three_d -> a + a_spread;
+ three_d -> b_lo = three_d -> b - b_spread;
+ three_d -> b_hi = three_d -> b + b_spread;
+ three_d -> c_lo = three_d -> c - c_spread;
+ three_d -> c_hi = three_d -> c + c_spread;
+ three_d -> d_lo = three_d -> d - d_spread;
+ three_d -> d_hi = three_d -> d + d_spread;
+ three_d -> e_lo = three_d -> e - e_spread;
+ three_d -> e_hi = three_d -> e + e_spread;
+ limiter(three_d);
+ return;
+ }
+ if (argc != M_param_count * 2) {
+ post("Invalid number of arguments for three_d constraints, requires 10 values, got %d", argc);
+ return;
+ }
+ three_d -> a_lo = atom_getfloat(arg++);
+ three_d -> a_hi = atom_getfloat(arg++);
+ three_d -> b_lo = atom_getfloat(arg++);
+ three_d -> b_hi = atom_getfloat(arg++);
+ three_d -> c_lo = atom_getfloat(arg++);
+ three_d -> c_hi = atom_getfloat(arg++);
+ three_d -> d_lo = atom_getfloat(arg++);
+ three_d -> d_hi = atom_getfloat(arg++);
+ three_d -> e_lo = atom_getfloat(arg++);
+ three_d -> e_hi = atom_getfloat(arg++);
+ limiter(three_d);
+}
+
+static void search(three_d_struct *three_d, t_symbol *s, int argc, t_atom *argv) {
+ int not_found, not_expired = three_d -> lyap_limit;
+ int jump, i, iterations;
+ t_atom vars[M_var_count];
+ double temp_a = three_d -> a;
+ double temp_b = three_d -> b;
+ double temp_c = three_d -> c;
+ double temp_d = three_d -> d;
+ double temp_e = three_d -> e;
+ 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], three_d -> vars_init[i]);
+ }
+ }
+ do {
+ jump = 500;
+ not_found = 0;
+ iterations = 10000;
+ bad_params:
+ three_d -> a = (drand48() * (three_d -> a_hi - three_d -> a_lo)) + three_d -> a_lo;
+ three_d -> b = (drand48() * (three_d -> b_hi - three_d -> b_lo)) + three_d -> b_lo;
+ three_d -> c = (drand48() * (three_d -> c_hi - three_d -> c_lo)) + three_d -> c_lo;
+ three_d -> d = (drand48() * (three_d -> d_hi - three_d -> d_lo)) + three_d -> d_lo;
+ three_d -> e = (drand48() * (three_d -> e_hi - three_d -> e_lo)) + three_d -> e_lo;
+ // put any preliminary checks specific to this fractal to eliminate bad_params
+
+ reset(three_d, NULL, argc, vars);
+ do { calc(three_d, three_d -> vars); } while(jump--);
+ three_d -> lyap_exp = lyapunov((void *) three_d, (t_gotfn) calc, M_var_count, (double *) three_d -> vars);
+ if (isnan(three_d -> lyap_exp)) { not_found = 1; }
+ if (three_d -> lyap_exp < three_d -> lyap_lo || three_d -> lyap_exp > three_d -> lyap_hi) { not_found = 1; }
+ not_expired--;
+ } while(not_found && not_expired);
+ reset(three_d, NULL, argc, vars);
+ if (!not_expired) {
+ post("Could not find a fractal after %d attempts.", (int) three_d -> lyap_limit);
+ post("Try using wider constraints.");
+ three_d -> a = temp_a;
+ three_d -> b = temp_b;
+ three_d -> c = temp_c;
+ three_d -> d = temp_d;
+ three_d -> e = temp_e;
+ outlet_anything(three_d -> search_outlet, gensym("invalid"), 0, NULL);
+ } else {
+ three_d -> failure_ratio = (three_d -> lyap_limit - not_expired) / three_d -> lyap_limit;
+ make_results(three_d);
+ outlet_anything(three_d -> search_outlet, gensym("search"), M_search_count, three_d -> search_out);
+ }
+}
+
+void *three_d_new(t_symbol *s, int argc, t_atom *argv) {
+ three_d_struct *three_d = (three_d_struct *) pd_new(three_d_class);
+ if (three_d != NULL) {
+ outlet_new(&three_d -> x_obj, &s_float);
+ three_d -> outlets[0] = outlet_new(&three_d -> x_obj, &s_float);
+ three_d -> outlets[1] = outlet_new(&three_d -> x_obj, &s_float);
+ three_d -> search_outlet = outlet_new(&three_d -> x_obj, &s_list);
+ three_d -> vars_outlet = outlet_new(&three_d -> x_obj, &s_list);
+ three_d -> params_outlet = outlet_new(&three_d -> x_obj, &s_list);
+ if (argc == M_param_count + M_var_count) {
+ three_d -> vars_init[M_x] = three_d -> vars[M_x] = (double) atom_getfloatarg(0, argc, argv);
+ three_d -> vars_init[M_y] = three_d -> vars[M_y] = (double) atom_getfloatarg(1, argc, argv);
+ three_d -> vars_init[M_z] = three_d -> vars[M_z] = (double) atom_getfloatarg(2, argc, argv);
+ three_d -> a = (double) atom_getfloatarg(3, argc, argv);
+ three_d -> b = (double) atom_getfloatarg(4, argc, argv);
+ three_d -> c = (double) atom_getfloatarg(5, argc, argv);
+ three_d -> d = (double) atom_getfloatarg(6, argc, argv);
+ three_d -> e = (double) atom_getfloatarg(7, argc, argv);
+ } else {
+ if (argc != 0 && argc != M_param_count + M_var_count) {
+ post("Incorrect number of arguments for three_d fractal. Expecting 8 arguments.");
+ }
+ three_d -> vars_init[M_x] = 0;
+ three_d -> vars_init[M_y] = 0;
+ three_d -> vars_init[M_z] = 0;
+ three_d -> a = 2.24;
+ three_d -> b = 0.43;
+ three_d -> c = -0.65;
+ three_d -> d = -2.43;
+ three_d -> e = 1;
+ }
+ constrain(three_d, NULL, 0, NULL);
+ lyap(three_d, -1000000.0, 1000000.0, M_failure_limit);
+ }
+ return (void *)three_d;
+}
+
+void three_d_setup(void) {
+ three_d_class = class_new(gensym("three_d"), (t_newmethod) three_d_new, 0, sizeof(three_d_struct), 0, A_GIMME, 0);
+ class_addbang(three_d_class, (t_method) calculate);
+ class_addmethod(three_d_class, (t_method) reset, gensym("reset"), A_GIMME, 0);
+ class_addmethod(three_d_class, (t_method) show, gensym("show"), 0);
+ class_addmethod(three_d_class, (t_method) param, gensym("param"), A_GIMME, 0);
+ class_addmethod(three_d_class, (t_method) seed, gensym("seed"), A_GIMME, 0);
+ class_addmethod(three_d_class, (t_method) lyap, gensym("lyapunov"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(three_d_class, (t_method) elyap, gensym("elyapunov"), 0);
+ class_addmethod(three_d_class, (t_method) search, gensym("search"), A_GIMME, 0);
+ class_addmethod(three_d_class, (t_method) constrain, gensym("constrain"), A_GIMME, 0);
+ class_sethelpsymbol(three_d_class, gensym("help-three_d.pd"));
+}
+
diff --git a/threeply.c b/threeply.c
new file mode 100644
index 0000000..7618772
--- /dev/null
+++ b/threeply.c
@@ -0,0 +1,303 @@
+/* threeply Attractor PD External */
+/* Copyright Michael McGonagle, from ??????, 2003 */
+/* This program is distributed under the params of the GNU Public License */
+
+///////////////////////////////////////////////////////////////////////////////////
+/* This file is part of Chaos PD Externals. */
+/* */
+/* Chaos PD Externals are free software; you can redistribute them and/or modify */
+/* them under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* Chaos PD Externals are distributed in the hope that they will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with the Chaos PD Externals; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+///////////////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#include "lyapunov.h"
+
+#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_a 0
+#define M_b 1
+#define M_c 2
+
+#define M_x 0
+#define M_y 1
+
+#define M_param_count 3
+#define M_var_count 2
+#define M_search_count 3
+#define M_failure_limit 1000
+
+static char *version = "threeply v0.0, by Michael McGonagle, from ??????, 2003";
+
+t_class *threeply_class;
+
+typedef struct threeply_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;
+ 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];
+} threeply_struct;
+
+static void calc(threeply_struct *threeply, double *vars) {
+ double x_0, y_0;
+ x_0 =vars[M_y]-((vars[M_x]<0)?-1:1)*abs(sin(vars[M_x])*cos(threeply -> b)+threeply -> c-vars[M_x]*sin(threeply -> a+threeply -> b+threeply -> c));
+ y_0 =threeply -> a-vars[M_x];
+ vars[M_x] = x_0;
+ vars[M_y] = y_0;
+} // end calc
+
+static void calculate(threeply_struct *threeply) {
+ calc(threeply, threeply -> vars);
+ outlet_float(threeply -> x_obj.ob_outlet, threeply -> vars[M_x]);
+ outlet_float(threeply -> outlets[M_y - 1], threeply -> vars[M_y]);
+} // end calculate
+
+static void reset(threeply_struct *threeply, t_symbol *s, int argc, t_atom *argv) {
+ if (argc == M_var_count) {
+ threeply -> vars[M_x] = (double) atom_getfloatarg(M_x, argc, argv);
+ threeply -> vars[M_y] = (double) atom_getfloatarg(M_y, argc, argv);
+ } else {
+ threeply -> vars[M_x] = threeply -> vars_init[M_x];
+ threeply -> vars[M_y] = threeply -> vars_init[M_y];
+ } // end if
+} // end reset
+
+static char *classify(threeply_struct *threeply) {
+ static char buff[4];
+ char *c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ buff[0] = c[(int) (((threeply -> a - M_a_lo) * (1.0 / (M_a_hi - M_a_lo))) * 26)];
+ buff[1] = c[(int) (((threeply -> b - M_b_lo) * (1.0 / (M_b_hi - M_b_lo))) * 26)];
+ buff[2] = c[(int) (((threeply -> c - M_c_lo) * (1.0 / (M_c_hi - M_c_lo))) * 26)];
+ buff[3] = '\0';
+ return buff;
+}
+
+static void make_results(threeply_struct *threeply) {
+ SETFLOAT(&threeply -> search_out[0], threeply -> lyap_exp);
+ SETSYMBOL(&threeply -> search_out[1], gensym(classify(threeply)));
+ SETFLOAT(&threeply -> search_out[2], threeply -> failure_ratio);
+ SETFLOAT(&threeply -> vars_out[M_x], threeply -> vars[M_x]);
+ SETFLOAT(&threeply -> vars_out[M_y], threeply -> vars[M_y]);
+ SETFLOAT(&threeply -> params_out[M_a], threeply -> a);
+ SETFLOAT(&threeply -> params_out[M_b], threeply -> b);
+ SETFLOAT(&threeply -> params_out[M_c], threeply -> c);
+ outlet_list(threeply -> params_outlet, gensym("list"), M_param_count, threeply -> params_out);
+ outlet_list(threeply -> vars_outlet, gensym("list"), M_var_count, threeply -> vars_out);
+}
+
+static void show(threeply_struct *threeply) {
+ make_results(threeply);
+ outlet_anything(threeply -> search_outlet, gensym("show"), M_search_count, threeply -> search_out);
+}
+
+static void param(threeply_struct *threeply, t_symbol *s, int argc, t_atom *argv) {
+ if (argc != 3) {
+ post("Incorrect number of arguments for threeply fractal. Expecting 3 arguments.");
+ return;
+ }
+ threeply -> a = (double) atom_getfloatarg(0, argc, argv);
+ threeply -> b = (double) atom_getfloatarg(1, argc, argv);
+ threeply -> c = (double) atom_getfloatarg(2, argc, argv);
+}
+
+static void seed(threeply_struct *threeply, 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(threeply_struct *threeply, t_floatarg l, t_floatarg h, t_floatarg lim) {
+ threeply -> lyap_lo = l;
+ threeply -> lyap_hi = h;
+ threeply -> lyap_limit = (double) ((int) lim);
+}
+
+static void elyap(threeply_struct *threeply) {
+ double results[M_var_count];
+ int i;
+ if (lyapunov_full((void *) threeply, (t_gotfn) calc, M_var_count, threeply -> vars, results) != NULL) {
+ post("elyapunov:");
+ for(i = 0; i < M_var_count; i++) { post("%d: %3.80f", i, results[i]); }
+ }
+}
+
+static void limiter(threeply_struct *threeply) {
+ if (threeply -> a_lo < M_a_lo) { threeply -> a_lo = M_a_lo; }
+ if (threeply -> a_lo > M_a_hi) { threeply -> a_lo = M_a_hi; }
+ if (threeply -> a_hi < M_a_lo) { threeply -> a_hi = M_a_lo; }
+ if (threeply -> a_hi > M_a_hi) { threeply -> a_hi = M_a_hi; }
+ if (threeply -> b_lo < M_b_lo) { threeply -> b_lo = M_b_lo; }
+ if (threeply -> b_lo > M_b_hi) { threeply -> b_lo = M_b_hi; }
+ if (threeply -> b_hi < M_b_lo) { threeply -> b_hi = M_b_lo; }
+ if (threeply -> b_hi > M_b_hi) { threeply -> b_hi = M_b_hi; }
+ if (threeply -> c_lo < M_c_lo) { threeply -> c_lo = M_c_lo; }
+ if (threeply -> c_lo > M_c_hi) { threeply -> c_lo = M_c_hi; }
+ if (threeply -> c_hi < M_c_lo) { threeply -> c_hi = M_c_lo; }
+ if (threeply -> c_hi > M_c_hi) { threeply -> c_hi = M_c_hi; }
+}
+
+static void constrain(threeply_struct *threeply, t_symbol *s, int argc, t_atom *argv) {
+ int i;
+ t_atom *arg = argv;
+ if (argc == 0) {
+ // reset to full limits of search ranges
+ threeply -> a_lo = M_a_lo;
+ threeply -> a_hi = M_a_hi;
+ threeply -> b_lo = M_b_lo;
+ threeply -> b_hi = M_b_hi;
+ threeply -> c_lo = M_c_lo;
+ threeply -> c_hi = M_c_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;
+ threeply -> a_lo = threeply -> a - a_spread;
+ threeply -> a_hi = threeply -> a + a_spread;
+ threeply -> b_lo = threeply -> b - b_spread;
+ threeply -> b_hi = threeply -> b + b_spread;
+ threeply -> c_lo = threeply -> c - c_spread;
+ threeply -> c_hi = threeply -> c + c_spread;
+ limiter(threeply);
+ return;
+ }
+ if (argc != M_param_count * 2) {
+ post("Invalid number of arguments for threeply constraints, requires 6 values, got %d", argc);
+ return;
+ }
+ threeply -> a_lo = atom_getfloat(arg++);
+ threeply -> a_hi = atom_getfloat(arg++);
+ threeply -> b_lo = atom_getfloat(arg++);
+ threeply -> b_hi = atom_getfloat(arg++);
+ threeply -> c_lo = atom_getfloat(arg++);
+ threeply -> c_hi = atom_getfloat(arg++);
+ limiter(threeply);
+}
+
+static void search(threeply_struct *threeply, t_symbol *s, int argc, t_atom *argv) {
+ int not_found, not_expired = threeply -> lyap_limit;
+ int jump, i, iterations;
+ t_atom vars[M_var_count];
+ double temp_a = threeply -> a;
+ double temp_b = threeply -> b;
+ double temp_c = threeply -> 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], threeply -> vars_init[i]);
+ }
+ }
+ do {
+ jump = 500;
+ not_found = 0;
+ iterations = 10000;
+ bad_params:
+ threeply -> a = (drand48() * (threeply -> a_hi - threeply -> a_lo)) + threeply -> a_lo;
+ threeply -> b = (drand48() * (threeply -> b_hi - threeply -> b_lo)) + threeply -> b_lo;
+ threeply -> c = (drand48() * (threeply -> c_hi - threeply -> c_lo)) + threeply -> c_lo;
+ // put any preliminary checks specific to this fractal to eliminate bad_params
+
+ reset(threeply, NULL, argc, vars);
+ do { calc(threeply, threeply -> vars); } while(jump--);
+ threeply -> lyap_exp = lyapunov((void *) threeply, (t_gotfn) calc, M_var_count, (double *) threeply -> vars);
+ if (isnan(threeply -> lyap_exp)) { not_found = 1; }
+ if (threeply -> lyap_exp < threeply -> lyap_lo || threeply -> lyap_exp > threeply -> lyap_hi) { not_found = 1; }
+ not_expired--;
+ } while(not_found && not_expired);
+ reset(threeply, NULL, argc, vars);
+ if (!not_expired) {
+ post("Could not find a fractal after %d attempts.", (int) threeply -> lyap_limit);
+ post("Try using wider constraints.");
+ threeply -> a = temp_a;
+ threeply -> b = temp_b;
+ threeply -> c = temp_c;
+ outlet_anything(threeply -> search_outlet, gensym("invalid"), 0, NULL);
+ } else {
+ threeply -> failure_ratio = (threeply -> lyap_limit - not_expired) / threeply -> lyap_limit;
+ make_results(threeply);
+ outlet_anything(threeply -> search_outlet, gensym("search"), M_search_count, threeply -> search_out);
+ }
+}
+
+void *threeply_new(t_symbol *s, int argc, t_atom *argv) {
+ threeply_struct *threeply = (threeply_struct *) pd_new(threeply_class);
+ if (threeply != NULL) {
+ outlet_new(&threeply -> x_obj, &s_float);
+ threeply -> outlets[0] = outlet_new(&threeply -> x_obj, &s_float);
+ threeply -> search_outlet = outlet_new(&threeply -> x_obj, &s_list);
+ threeply -> vars_outlet = outlet_new(&threeply -> x_obj, &s_list);
+ threeply -> params_outlet = outlet_new(&threeply -> x_obj, &s_list);
+ if (argc == M_param_count + M_var_count) {
+ threeply -> vars_init[M_x] = threeply -> vars[M_x] = (double) atom_getfloatarg(0, argc, argv);
+ threeply -> vars_init[M_y] = threeply -> vars[M_y] = (double) atom_getfloatarg(1, argc, argv);
+ threeply -> a = (double) atom_getfloatarg(2, argc, argv);
+ threeply -> b = (double) atom_getfloatarg(3, argc, argv);
+ threeply -> c = (double) atom_getfloatarg(4, argc, argv);
+ } else {
+ if (argc != 0 && argc != M_param_count + M_var_count) {
+ post("Incorrect number of arguments for threeply fractal. Expecting 5 arguments.");
+ }
+ threeply -> vars_init[M_x] = 0;
+ threeply -> vars_init[M_y] = 0;
+ threeply -> a = -55;
+ threeply -> b = -1;
+ threeply -> c = -42;
+ }
+ constrain(threeply, NULL, 0, NULL);
+ lyap(threeply, -1000000.0, 1000000.0, M_failure_limit);
+ }
+ return (void *)threeply;
+}
+
+void threeply_setup(void) {
+ threeply_class = class_new(gensym("threeply"), (t_newmethod) threeply_new, 0, sizeof(threeply_struct), 0, A_GIMME, 0);
+ class_addbang(threeply_class, (t_method) calculate);
+ class_addmethod(threeply_class, (t_method) reset, gensym("reset"), A_GIMME, 0);
+ class_addmethod(threeply_class, (t_method) show, gensym("show"), 0);
+ class_addmethod(threeply_class, (t_method) param, gensym("param"), A_GIMME, 0);
+ class_addmethod(threeply_class, (t_method) seed, gensym("seed"), A_GIMME, 0);
+ class_addmethod(threeply_class, (t_method) lyap, gensym("lyapunov"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(threeply_class, (t_method) elyap, gensym("elyapunov"), 0);
+ class_addmethod(threeply_class, (t_method) search, gensym("search"), A_GIMME, 0);
+ class_addmethod(threeply_class, (t_method) constrain, gensym("constrain"), A_GIMME, 0);
+ class_sethelpsymbol(threeply_class, gensym("help-threeply.pd"));
+}
+
diff --git a/tinkerbell.c b/tinkerbell.c
new file mode 100644
index 0000000..b934bd9
--- /dev/null
+++ b/tinkerbell.c
@@ -0,0 +1,325 @@
+/* tinkerbell Attractor PD External */
+/* Copyright Michael McGonagle, from ??????, 2003 */
+/* This program is distributed under the params of the GNU Public License */
+
+///////////////////////////////////////////////////////////////////////////////////
+/* This file is part of Chaos PD Externals. */
+/* */
+/* Chaos PD Externals are free software; you can redistribute them and/or modify */
+/* them under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* Chaos PD Externals are distributed in the hope that they will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with the Chaos PD Externals; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+///////////////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#include "lyapunov.h"
+
+#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_d_lo -1000
+#define M_d_hi 1000
+
+#define M_a 0
+#define M_b 1
+#define M_c 2
+#define M_d 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 = "tinkerbell v0.0, by Michael McGonagle, from ??????, 2003";
+
+t_class *tinkerbell_class;
+
+typedef struct tinkerbell_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, d, d_lo, d_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];
+} tinkerbell_struct;
+
+static void calc(tinkerbell_struct *tinkerbell, double *vars) {
+ double x_0, y_0;
+ x_0 =vars[M_x]*vars[M_x]-vars[M_y]*vars[M_y]+tinkerbell -> a*vars[M_x]+tinkerbell -> b*vars[M_y];
+ y_0 =2*vars[M_x]*vars[M_y]-tinkerbell -> c*vars[M_x]+tinkerbell -> d*vars[M_y];
+ vars[M_x] = x_0;
+ vars[M_y] = y_0;
+} // end calc
+
+static void calculate(tinkerbell_struct *tinkerbell) {
+ calc(tinkerbell, tinkerbell -> vars);
+ outlet_float(tinkerbell -> x_obj.ob_outlet, tinkerbell -> vars[M_x]);
+ outlet_float(tinkerbell -> outlets[M_y - 1], tinkerbell -> vars[M_y]);
+} // end calculate
+
+static void reset(tinkerbell_struct *tinkerbell, t_symbol *s, int argc, t_atom *argv) {
+ if (argc == M_var_count) {
+ tinkerbell -> vars[M_x] = (double) atom_getfloatarg(M_x, argc, argv);
+ tinkerbell -> vars[M_y] = (double) atom_getfloatarg(M_y, argc, argv);
+ } else {
+ tinkerbell -> vars[M_x] = tinkerbell -> vars_init[M_x];
+ tinkerbell -> vars[M_y] = tinkerbell -> vars_init[M_y];
+ } // end if
+} // end reset
+
+static char *classify(tinkerbell_struct *tinkerbell) {
+ static char buff[5];
+ char *c = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ buff[0] = c[(int) (((tinkerbell -> a - M_a_lo) * (1.0 / (M_a_hi - M_a_lo))) * 26)];
+ buff[1] = c[(int) (((tinkerbell -> b - M_b_lo) * (1.0 / (M_b_hi - M_b_lo))) * 26)];
+ buff[2] = c[(int) (((tinkerbell -> c - M_c_lo) * (1.0 / (M_c_hi - M_c_lo))) * 26)];
+ buff[3] = c[(int) (((tinkerbell -> d - M_d_lo) * (1.0 / (M_d_hi - M_d_lo))) * 26)];
+ buff[4] = '\0';
+ return buff;
+}
+
+static void make_results(tinkerbell_struct *tinkerbell) {
+ SETFLOAT(&tinkerbell -> search_out[0], tinkerbell -> lyap_exp);
+ SETSYMBOL(&tinkerbell -> search_out[1], gensym(classify(tinkerbell)));
+ SETFLOAT(&tinkerbell -> search_out[2], tinkerbell -> failure_ratio);
+ SETFLOAT(&tinkerbell -> vars_out[M_x], tinkerbell -> vars[M_x]);
+ SETFLOAT(&tinkerbell -> vars_out[M_y], tinkerbell -> vars[M_y]);
+ SETFLOAT(&tinkerbell -> params_out[M_a], tinkerbell -> a);
+ SETFLOAT(&tinkerbell -> params_out[M_b], tinkerbell -> b);
+ SETFLOAT(&tinkerbell -> params_out[M_c], tinkerbell -> c);
+ SETFLOAT(&tinkerbell -> params_out[M_d], tinkerbell -> d);
+ outlet_list(tinkerbell -> params_outlet, gensym("list"), M_param_count, tinkerbell -> params_out);
+ outlet_list(tinkerbell -> vars_outlet, gensym("list"), M_var_count, tinkerbell -> vars_out);
+}
+
+static void show(tinkerbell_struct *tinkerbell) {
+ make_results(tinkerbell);
+ outlet_anything(tinkerbell -> search_outlet, gensym("show"), M_search_count, tinkerbell -> search_out);
+}
+
+static void param(tinkerbell_struct *tinkerbell, t_symbol *s, int argc, t_atom *argv) {
+ if (argc != 4) {
+ post("Incorrect number of arguments for tinkerbell fractal. Expecting 4 arguments.");
+ return;
+ }
+ tinkerbell -> a = (double) atom_getfloatarg(0, argc, argv);
+ tinkerbell -> b = (double) atom_getfloatarg(1, argc, argv);
+ tinkerbell -> c = (double) atom_getfloatarg(2, argc, argv);
+ tinkerbell -> d = (double) atom_getfloatarg(3, argc, argv);
+}
+
+static void seed(tinkerbell_struct *tinkerbell, 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(tinkerbell_struct *tinkerbell, t_floatarg l, t_floatarg h, t_floatarg lim) {
+ tinkerbell -> lyap_lo = l;
+ tinkerbell -> lyap_hi = h;
+ tinkerbell -> lyap_limit = (double) ((int) lim);
+}
+
+static void elyap(tinkerbell_struct *tinkerbell) {
+ double results[M_var_count];
+ int i;
+ if (lyapunov_full((void *) tinkerbell, (t_gotfn) calc, M_var_count, tinkerbell -> vars, results) != NULL) {
+ post("elyapunov:");
+ for(i = 0; i < M_var_count; i++) { post("%d: %3.80f", i, results[i]); }
+ }
+}
+
+static void limiter(tinkerbell_struct *tinkerbell) {
+ if (tinkerbell -> a_lo < M_a_lo) { tinkerbell -> a_lo = M_a_lo; }
+ if (tinkerbell -> a_lo > M_a_hi) { tinkerbell -> a_lo = M_a_hi; }
+ if (tinkerbell -> a_hi < M_a_lo) { tinkerbell -> a_hi = M_a_lo; }
+ if (tinkerbell -> a_hi > M_a_hi) { tinkerbell -> a_hi = M_a_hi; }
+ if (tinkerbell -> b_lo < M_b_lo) { tinkerbell -> b_lo = M_b_lo; }
+ if (tinkerbell -> b_lo > M_b_hi) { tinkerbell -> b_lo = M_b_hi; }
+ if (tinkerbell -> b_hi < M_b_lo) { tinkerbell -> b_hi = M_b_lo; }
+ if (tinkerbell -> b_hi > M_b_hi) { tinkerbell -> b_hi = M_b_hi; }
+ if (tinkerbell -> c_lo < M_c_lo) { tinkerbell -> c_lo = M_c_lo; }
+ if (tinkerbell -> c_lo > M_c_hi) { tinkerbell -> c_lo = M_c_hi; }
+ if (tinkerbell -> c_hi < M_c_lo) { tinkerbell -> c_hi = M_c_lo; }
+ if (tinkerbell -> c_hi > M_c_hi) { tinkerbell -> c_hi = M_c_hi; }
+ if (tinkerbell -> d_lo < M_d_lo) { tinkerbell -> d_lo = M_d_lo; }
+ if (tinkerbell -> d_lo > M_d_hi) { tinkerbell -> d_lo = M_d_hi; }
+ if (tinkerbell -> d_hi < M_d_lo) { tinkerbell -> d_hi = M_d_lo; }
+ if (tinkerbell -> d_hi > M_d_hi) { tinkerbell -> d_hi = M_d_hi; }
+}
+
+static void constrain(tinkerbell_struct *tinkerbell, t_symbol *s, int argc, t_atom *argv) {
+ int i;
+ t_atom *arg = argv;
+ if (argc == 0) {
+ // reset to full limits of search ranges
+ tinkerbell -> a_lo = M_a_lo;
+ tinkerbell -> a_hi = M_a_hi;
+ tinkerbell -> b_lo = M_b_lo;
+ tinkerbell -> b_hi = M_b_hi;
+ tinkerbell -> c_lo = M_c_lo;
+ tinkerbell -> c_hi = M_c_hi;
+ tinkerbell -> d_lo = M_d_lo;
+ tinkerbell -> d_hi = M_d_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 d_spread = ((M_d_hi - M_d_lo) * percent) / 2;
+ tinkerbell -> a_lo = tinkerbell -> a - a_spread;
+ tinkerbell -> a_hi = tinkerbell -> a + a_spread;
+ tinkerbell -> b_lo = tinkerbell -> b - b_spread;
+ tinkerbell -> b_hi = tinkerbell -> b + b_spread;
+ tinkerbell -> c_lo = tinkerbell -> c - c_spread;
+ tinkerbell -> c_hi = tinkerbell -> c + c_spread;
+ tinkerbell -> d_lo = tinkerbell -> d - d_spread;
+ tinkerbell -> d_hi = tinkerbell -> d + d_spread;
+ limiter(tinkerbell);
+ return;
+ }
+ if (argc != M_param_count * 2) {
+ post("Invalid number of arguments for tinkerbell constraints, requires 8 values, got %d", argc);
+ return;
+ }
+ tinkerbell -> a_lo = atom_getfloat(arg++);
+ tinkerbell -> a_hi = atom_getfloat(arg++);
+ tinkerbell -> b_lo = atom_getfloat(arg++);
+ tinkerbell -> b_hi = atom_getfloat(arg++);
+ tinkerbell -> c_lo = atom_getfloat(arg++);
+ tinkerbell -> c_hi = atom_getfloat(arg++);
+ tinkerbell -> d_lo = atom_getfloat(arg++);
+ tinkerbell -> d_hi = atom_getfloat(arg++);
+ limiter(tinkerbell);
+}
+
+static void search(tinkerbell_struct *tinkerbell, t_symbol *s, int argc, t_atom *argv) {
+ int not_found, not_expired = tinkerbell -> lyap_limit;
+ int jump, i, iterations;
+ t_atom vars[M_var_count];
+ double temp_a = tinkerbell -> a;
+ double temp_b = tinkerbell -> b;
+ double temp_c = tinkerbell -> c;
+ double temp_d = tinkerbell -> d;
+ 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], tinkerbell -> vars_init[i]);
+ }
+ }
+ do {
+ jump = 500;
+ not_found = 0;
+ iterations = 10000;
+ bad_params:
+ tinkerbell -> a = (drand48() * (tinkerbell -> a_hi - tinkerbell -> a_lo)) + tinkerbell -> a_lo;
+ tinkerbell -> b = (drand48() * (tinkerbell -> b_hi - tinkerbell -> b_lo)) + tinkerbell -> b_lo;
+ tinkerbell -> c = (drand48() * (tinkerbell -> c_hi - tinkerbell -> c_lo)) + tinkerbell -> c_lo;
+ tinkerbell -> d = (drand48() * (tinkerbell -> d_hi - tinkerbell -> d_lo)) + tinkerbell -> d_lo;
+ // put any preliminary checks specific to this fractal to eliminate bad_params
+
+ reset(tinkerbell, NULL, argc, vars);
+ do { calc(tinkerbell, tinkerbell -> vars); } while(jump--);
+ tinkerbell -> lyap_exp = lyapunov((void *) tinkerbell, (t_gotfn) calc, M_var_count, (double *) tinkerbell -> vars);
+ if (isnan(tinkerbell -> lyap_exp)) { not_found = 1; }
+ if (tinkerbell -> lyap_exp < tinkerbell -> lyap_lo || tinkerbell -> lyap_exp > tinkerbell -> lyap_hi) { not_found = 1; }
+ not_expired--;
+ } while(not_found && not_expired);
+ reset(tinkerbell, NULL, argc, vars);
+ if (!not_expired) {
+ post("Could not find a fractal after %d attempts.", (int) tinkerbell -> lyap_limit);
+ post("Try using wider constraints.");
+ tinkerbell -> a = temp_a;
+ tinkerbell -> b = temp_b;
+ tinkerbell -> c = temp_c;
+ tinkerbell -> d = temp_d;
+ outlet_anything(tinkerbell -> search_outlet, gensym("invalid"), 0, NULL);
+ } else {
+ tinkerbell -> failure_ratio = (tinkerbell -> lyap_limit - not_expired) / tinkerbell -> lyap_limit;
+ make_results(tinkerbell);
+ outlet_anything(tinkerbell -> search_outlet, gensym("search"), M_search_count, tinkerbell -> search_out);
+ }
+}
+
+void *tinkerbell_new(t_symbol *s, int argc, t_atom *argv) {
+ tinkerbell_struct *tinkerbell = (tinkerbell_struct *) pd_new(tinkerbell_class);
+ if (tinkerbell != NULL) {
+ outlet_new(&tinkerbell -> x_obj, &s_float);
+ tinkerbell -> outlets[0] = outlet_new(&tinkerbell -> x_obj, &s_float);
+ tinkerbell -> search_outlet = outlet_new(&tinkerbell -> x_obj, &s_list);
+ tinkerbell -> vars_outlet = outlet_new(&tinkerbell -> x_obj, &s_list);
+ tinkerbell -> params_outlet = outlet_new(&tinkerbell -> x_obj, &s_list);
+ if (argc == M_param_count + M_var_count) {
+ tinkerbell -> vars_init[M_x] = tinkerbell -> vars[M_x] = (double) atom_getfloatarg(0, argc, argv);
+ tinkerbell -> vars_init[M_y] = tinkerbell -> vars[M_y] = (double) atom_getfloatarg(1, argc, argv);
+ tinkerbell -> a = (double) atom_getfloatarg(2, argc, argv);
+ tinkerbell -> b = (double) atom_getfloatarg(3, argc, argv);
+ tinkerbell -> c = (double) atom_getfloatarg(4, argc, argv);
+ tinkerbell -> d = (double) atom_getfloatarg(5, argc, argv);
+ } else {
+ if (argc != 0 && argc != M_param_count + M_var_count) {
+ post("Incorrect number of arguments for tinkerbell fractal. Expecting 6 arguments.");
+ }
+ tinkerbell -> vars_init[M_x] = 0.1;
+ tinkerbell -> vars_init[M_y] = 0.1;
+ tinkerbell -> a = 0.9;
+ tinkerbell -> b = 0.6;
+ tinkerbell -> c = 2;
+ tinkerbell -> d = 0.5;
+ }
+ constrain(tinkerbell, NULL, 0, NULL);
+ lyap(tinkerbell, -1000000.0, 1000000.0, M_failure_limit);
+ }
+ return (void *)tinkerbell;
+}
+
+void tinkerbell_setup(void) {
+ tinkerbell_class = class_new(gensym("tinkerbell"), (t_newmethod) tinkerbell_new, 0, sizeof(tinkerbell_struct), 0, A_GIMME, 0);
+ class_addbang(tinkerbell_class, (t_method) calculate);
+ class_addmethod(tinkerbell_class, (t_method) reset, gensym("reset"), A_GIMME, 0);
+ class_addmethod(tinkerbell_class, (t_method) show, gensym("show"), 0);
+ class_addmethod(tinkerbell_class, (t_method) param, gensym("param"), A_GIMME, 0);
+ class_addmethod(tinkerbell_class, (t_method) seed, gensym("seed"), A_GIMME, 0);
+ class_addmethod(tinkerbell_class, (t_method) lyap, gensym("lyapunov"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(tinkerbell_class, (t_method) elyap, gensym("elyapunov"), 0);
+ class_addmethod(tinkerbell_class, (t_method) search, gensym("search"), A_GIMME, 0);
+ class_addmethod(tinkerbell_class, (t_method) constrain, gensym("constrain"), A_GIMME, 0);
+ class_sethelpsymbol(tinkerbell_class, gensym("help-tinkerbell.pd"));
+}
+
diff --git a/tools/fractal-tools.pd b/tools/fractal-tools.pd
new file mode 100644
index 0000000..2170d6a
--- /dev/null
+++ b/tools/fractal-tools.pd
@@ -0,0 +1,27 @@
+#N canvas 0 22 454 304 10;
+#X obj 27 252 outlet;
+#X msg 149 80 reset;
+#X msg 158 101 show;
+#X msg 167 122 param;
+#X msg 175 143 lyapunov -100 100 1000;
+#X msg 183 164 elyapunov;
+#X msg 192 186 constrain;
+#X msg 198 208 search;
+#X obj 27 23 inlet;
+#N canvas 0 22 454 304 iterator-tools 0;
+#X obj 17 264 outlet;
+#X text 17 19 This abstraction is intended to be used to iterate over
+the parameter space. Repeatedly performs the following:;
+#X text 46 65 1 'param' to set a centerpoint around which to search
+;
+#X text 46 80 2 'constrain <percent>' to limit the search area;
+#X text 46 95 3 'search' to find a fractal within the area;
+#X restore 48 53 pd iterator-tools;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 5 0 0 0;
+#X connect 6 0 0 0;
+#X connect 7 0 0 0;
+#X connect 8 0 0 0;
diff --git a/tools/help-attract1.pd b/tools/help-attract1.pd
new file mode 100644
index 0000000..cb737b9
--- /dev/null
+++ b/tools/help-attract1.pd
@@ -0,0 +1,35 @@
+#N canvas 426 137 573 476 10;
+#X obj 44 115 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 95 116 5 0 0 0 - - -;
+#X floatatom 132 393 10 0 0 0 Y - -;
+#X floatatom 44 393 10 0 0 0 X - -;
+#X text 18 49 (This attractor is not continuous);
+#X obj 44 132 metro 50;
+#X obj 19 131 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 242 104 readme-fractals;
+#X msg 87 245 search;
+#X text 138 246 Find a random attractor set;
+#X msg 98 266 show;
+#X obj 44 316 attract1 0 0 -0.0239362 -0.67834 2.50703 -0.0138538 -1.44072
+2.47917;
+#X msg 78 195 param -0.0239362 -0.67834 2.50703 -0.0138538 -1.44072
+2.47917;
+#X text 20 18 Attract1 Attractor;
+#X text 18 33 Chaos PD Externals - Copyright Michael McGonagle \, 2003
+;
+#X obj 278 367 search-tools;
+#X connect 0 0 5 0;
+#X connect 1 0 5 1;
+#X connect 5 0 11 0;
+#X connect 6 0 11 0;
+#X connect 8 0 11 0;
+#X connect 10 0 11 0;
+#X connect 11 0 3 0;
+#X connect 11 1 2 0;
+#X connect 11 2 15 0;
+#X connect 11 3 15 1;
+#X connect 11 4 15 2;
+#X connect 12 0 11 0;
+#X connect 15 0 11 0;
diff --git a/tools/help-base.pd b/tools/help-base.pd
new file mode 100644
index 0000000..bc0fd83
--- /dev/null
+++ b/tools/help-base.pd
@@ -0,0 +1,28 @@
+#N canvas 680 295 589 492 10;
+#X obj 43 134 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 94 135 5 0 0 0 - - -;
+#X floatatom 43 332 10 0 0 0 X - -;
+#X text 19 50 (This attractor is not continuous);
+#X text 20 34 Chaos PD Externals - Copyright Michael McGonagle 2003
+;
+#X obj 43 151 metro 50;
+#X obj 20 154 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 436 18 readme-fractals;
+#X text 21 19 Base Attractor;
+#X obj 53 262 fractal-tools;
+#X obj 43 285 base3 0.1 1.18939 2.24148;
+#X msg 61 240 lyapunov 0 100 1000;
+#X obj 126 320 search-tools;
+#X connect 0 0 5 0;
+#X connect 1 0 5 1;
+#X connect 5 0 10 0;
+#X connect 6 0 10 0;
+#X connect 9 0 10 0;
+#X connect 10 0 2 0;
+#X connect 10 1 12 0;
+#X connect 10 2 12 1;
+#X connect 10 3 12 2;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
diff --git a/tools/help-gingerbreadman.pd b/tools/help-gingerbreadman.pd
new file mode 100644
index 0000000..701b33e
--- /dev/null
+++ b/tools/help-gingerbreadman.pd
@@ -0,0 +1,31 @@
+#N canvas 615 23 577 480 10;
+#X obj 44 115 tgl 15 0 empty empty empty 0 -6 32 8 -262144 -1 -1 0
+1;
+#X floatatom 95 116 5 0 0 0 - - -;
+#X floatatom 131 348 10 0 0 0 Y - -;
+#X floatatom 44 348 10 0 0 0 X - -;
+#X text 17 48 (This attractor is not continuous);
+#X obj 44 132 metro 50;
+#X obj 19 131 bng 15 250 50 0 empty empty empty 0 -6 32 8 -262144 -1
+-1;
+#X obj 242 104 readme-fractals;
+#X msg 113 272 show;
+#X msg 76 156 reset;
+#X text 120 156 Reset to initial state from creation arguments;
+#X text 19 33 Chaos PD Externals - Copyright Michael McGonagle \, 2003
+;
+#X text 20 18 Gingerbreadman Attractor;
+#X obj 44 316 gingerbreadman;
+#X text 91 193 This fractal equation does not have any parameters \,
+and thus does not allow the messages 'param' or any of the searching
+functions.;
+#X msg 96 235 param;
+#X connect 0 0 5 0;
+#X connect 1 0 5 1;
+#X connect 5 0 13 0;
+#X connect 6 0 13 0;
+#X connect 8 0 13 0;
+#X connect 9 0 13 0;
+#X connect 13 0 3 0;
+#X connect 13 1 2 0;
+#X connect 15 0 13 0;
diff --git a/tools/help-henon.pd b/tools/help-henon.pd
new file mode 100644
index 0000000..87b06ce
--- /dev/null
+++ b/tools/help-henon.pd
@@ -0,0 +1,30 @@
+#N canvas 473 208 581 484 10;
+#X obj 43 81 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 94 82 5 0 0 0 - - -;
+#X floatatom 71 372 10 0 0 0 Y - -;
+#X floatatom 43 348 10 0 0 0 X - -;
+#X text 18 49 (This attractor is not continuous);
+#X obj 43 98 metro 50;
+#X obj 18 97 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 88 209 param 1.4 0.3;
+#X text 19 33 Chaos PD Externals - Copyright Ben Bogart 2002;
+#X text 20 17 Henon Attractor;
+#X obj 43 294 henon 1 1 1.4 0.3;
+#X msg 75 176 reset;
+#X text 120 176 Reset to initial state from creation arguments;
+#X text 192 209 Modify parameters;
+#X obj 90 318 search-tools;
+#X connect 0 0 5 0;
+#X connect 1 0 5 1;
+#X connect 5 0 10 0;
+#X connect 6 0 10 0;
+#X connect 7 0 10 0;
+#X connect 10 0 3 0;
+#X connect 10 1 2 0;
+#X connect 10 2 14 0;
+#X connect 10 3 14 1;
+#X connect 10 4 14 2;
+#X connect 11 0 10 0;
+#X connect 14 0 10 0;
diff --git a/tools/help-hopalong.pd b/tools/help-hopalong.pd
new file mode 100644
index 0000000..4b6433b
--- /dev/null
+++ b/tools/help-hopalong.pd
@@ -0,0 +1,32 @@
+#N canvas 473 208 581 484 10;
+#X obj 43 134 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 94 135 5 0 0 0 - - -;
+#X text 91 208 Reset To Initial Conditions;
+#X text 102 251 Modify Parameters;
+#X msg 88 191 reset 0.1 0.1;
+#X floatatom 115 419 10 0 0 0 Y - -;
+#X floatatom 43 388 10 0 0 0 X - -;
+#X text 19 50 (This attractor is not continuous);
+#X text 20 34 Chaos PD Externals - Copyright Michael McGonagle 2003
+;
+#X obj 43 151 metro 50;
+#X obj 18 150 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 25 83 readme-fractals;
+#X text 21 19 Hopalong Attractor;
+#X msg 99 234 param -639.064 886.792 -150.226;
+#X obj 43 348 hopalong 0.1 0.1 -639.064 886.792 -150.226;
+#X obj 220 378 search-tools;
+#X connect 0 0 9 0;
+#X connect 1 0 9 1;
+#X connect 4 0 14 0;
+#X connect 9 0 14 0;
+#X connect 10 0 14 0;
+#X connect 13 0 14 0;
+#X connect 14 0 6 0;
+#X connect 14 1 5 0;
+#X connect 14 2 15 0;
+#X connect 14 3 15 1;
+#X connect 14 4 15 2;
+#X connect 15 0 14 0;
diff --git a/tools/help-ikeda.pd b/tools/help-ikeda.pd
new file mode 100644
index 0000000..b9d009c
--- /dev/null
+++ b/tools/help-ikeda.pd
@@ -0,0 +1,33 @@
+#N canvas 23 245 569 472 10;
+#X obj 44 115 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 95 116 5 0 0 0 - - -;
+#X floatatom 86 379 10 0 0 0 Y - -;
+#X floatatom 44 352 10 0 0 0 X - -;
+#X text 18 49 (This attractor is not continuous);
+#X obj 44 132 metro 50;
+#X obj 19 131 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 92 215 param 0.4 0.9 6 1;
+#X msg 92 193 param 0.4 0.8 20 1;
+#X text 20 18 Ikeda Attractor;
+#X text 19 33 Chaos PD Externals - Copyright Ben Bogart 2002;
+#X obj 242 104 readme-fractals;
+#X obj 44 316 ikeda 0.1 0.1 0.4 0.9 6 1;
+#X msg 76 156 reset;
+#X text 120 156 Reset to initial state from creation arguments;
+#X text 226 193 Modify parameters;
+#X obj 156 349 search-tools;
+#X connect 0 0 5 0;
+#X connect 1 0 5 1;
+#X connect 5 0 12 0;
+#X connect 6 0 12 0;
+#X connect 7 0 12 0;
+#X connect 8 0 12 0;
+#X connect 12 0 3 0;
+#X connect 12 1 2 0;
+#X connect 12 2 16 0;
+#X connect 12 3 16 1;
+#X connect 12 4 16 2;
+#X connect 13 0 12 0;
+#X connect 16 0 12 0;
diff --git a/tools/help-latoocarfian.pd b/tools/help-latoocarfian.pd
new file mode 100644
index 0000000..ee592be
--- /dev/null
+++ b/tools/help-latoocarfian.pd
@@ -0,0 +1,35 @@
+#N canvas 527 258 589 492 10;
+#X obj 43 134 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 94 135 5 0 0 0 - - -;
+#X text 91 208 Reset To Initial Conditions;
+#X text 114 281 Modify Parameters;
+#X msg 88 191 reset 0.1 0.1;
+#X msg 111 243 param -0.966918 2.87988 0.756145 0.744728;
+#X msg 111 264 param -2.90515 -2.03043 1.44055 0.70307;
+#X floatatom 136 407 10 0 0 0 Y - -;
+#X floatatom 43 367 10 0 0 0 X - -;
+#X text 19 50 (This attractor is not continuous);
+#X text 21 19 Latoocarfian Attractor (from Cliff Pickover);
+#X text 20 34 Chaos PD Externals - Copyright Michael McGonagle 2003
+;
+#X obj 43 151 metro 50;
+#X obj 18 150 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 25 83 readme-fractals;
+#X obj 43 347 latoocarfian 0.1 0.1 -2.90515 -2.03043 1.44055 0.70307
+;
+#X obj 283 376 search-tools;
+#X connect 0 0 12 0;
+#X connect 1 0 12 1;
+#X connect 4 0 15 0;
+#X connect 5 0 15 0;
+#X connect 6 0 15 0;
+#X connect 12 0 15 0;
+#X connect 13 0 15 0;
+#X connect 15 0 8 0;
+#X connect 15 1 7 0;
+#X connect 15 2 16 0;
+#X connect 15 3 16 1;
+#X connect 15 4 16 2;
+#X connect 16 0 15 0;
diff --git a/tools/help-latoomutalpha.pd b/tools/help-latoomutalpha.pd
new file mode 100644
index 0000000..dda50f5
--- /dev/null
+++ b/tools/help-latoomutalpha.pd
@@ -0,0 +1,35 @@
+#N canvas 487 49 585 488 10;
+#X obj 43 134 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 94 135 5 0 0 0 - - -;
+#X text 91 208 Reset To Initial Conditions;
+#X text 114 281 Modify Parameters;
+#X msg 88 191 reset 0.1 0.1;
+#X msg 111 243 param -0.966918 2.87988 0.756145 0.744728;
+#X msg 111 264 param -2.90515 -2.03043 1.44055 0.70307;
+#X floatatom 138 404 10 0 0 0 Y - -;
+#X floatatom 43 367 10 0 0 0 X - -;
+#X text 19 50 (This attractor is not continuous);
+#X text 21 19 Latoocarfian Attractor (from Cliff Pickover);
+#X text 20 34 Chaos PD Externals - Copyright Michael McGonagle 2003
+;
+#X obj 43 151 metro 50;
+#X obj 18 150 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 25 83 readme-fractals;
+#X obj 43 347 latoomutalpha 0.1 0.1 -2.90515 -2.03043 1.44055 0.70307
+;
+#X obj 289 374 search-tools;
+#X connect 0 0 12 0;
+#X connect 1 0 12 1;
+#X connect 4 0 15 0;
+#X connect 5 0 15 0;
+#X connect 6 0 15 0;
+#X connect 12 0 15 0;
+#X connect 13 0 15 0;
+#X connect 15 0 8 0;
+#X connect 15 1 7 0;
+#X connect 15 2 16 0;
+#X connect 15 3 16 1;
+#X connect 15 4 16 2;
+#X connect 16 0 15 0;
diff --git a/tools/help-latoomutbeta.pd b/tools/help-latoomutbeta.pd
new file mode 100644
index 0000000..775b542
--- /dev/null
+++ b/tools/help-latoomutbeta.pd
@@ -0,0 +1,35 @@
+#N canvas 527 258 585 488 10;
+#X obj 43 134 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 94 135 5 0 0 0 - - -;
+#X text 91 208 Reset To Initial Conditions;
+#X text 114 281 Modify Parameters;
+#X msg 88 191 reset 0.1 0.1;
+#X msg 111 243 param -0.966918 2.87988 0.756145 0.744728;
+#X msg 111 264 param -2.90515 -2.03043 1.44055 0.70307;
+#X floatatom 136 399 10 0 0 0 Y - -;
+#X floatatom 43 367 10 0 0 0 X - -;
+#X text 19 50 (This attractor is not continuous);
+#X text 21 19 Latoocarfian Attractor (from Cliff Pickover);
+#X text 20 34 Chaos PD Externals - Copyright Michael McGonagle 2003
+;
+#X obj 43 151 metro 50;
+#X obj 18 150 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 25 83 readme-fractals;
+#X obj 43 347 latoomutbeta 0.1 0.1 -2.90515 -2.03043 1.44055 0.70307
+;
+#X obj 283 373 search-tools;
+#X connect 0 0 12 0;
+#X connect 1 0 12 1;
+#X connect 4 0 15 0;
+#X connect 5 0 15 0;
+#X connect 6 0 15 0;
+#X connect 12 0 15 0;
+#X connect 13 0 15 0;
+#X connect 15 0 8 0;
+#X connect 15 1 7 0;
+#X connect 15 2 16 0;
+#X connect 15 3 16 1;
+#X connect 15 4 16 2;
+#X connect 16 0 15 0;
diff --git a/tools/help-latoomutgamma.pd b/tools/help-latoomutgamma.pd
new file mode 100644
index 0000000..256b795
--- /dev/null
+++ b/tools/help-latoomutgamma.pd
@@ -0,0 +1,35 @@
+#N canvas 527 258 581 484 10;
+#X obj 43 134 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 94 135 5 0 0 0 - - -;
+#X text 91 208 Reset To Initial Conditions;
+#X text 114 281 Modify Parameters;
+#X msg 88 191 reset 0.1 0.1;
+#X msg 111 243 param -0.966918 2.87988 0.756145 0.744728;
+#X msg 111 264 param -2.90515 -2.03043 1.44055 0.70307;
+#X floatatom 138 406 10 0 0 0 Y - -;
+#X floatatom 43 367 10 0 0 0 X - -;
+#X text 19 50 (This attractor is not continuous);
+#X text 21 19 Latoocarfian Attractor (from Cliff Pickover);
+#X text 20 34 Chaos PD Externals - Copyright Michael McGonagle 2003
+;
+#X obj 43 151 metro 50;
+#X obj 18 150 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 25 83 readme-fractals;
+#X obj 43 347 latoomutgamma 0.1 0.1 -2.90515 -2.03043 1.44055 0.70307
+;
+#X obj 289 374 search-tools;
+#X connect 0 0 12 0;
+#X connect 1 0 12 1;
+#X connect 4 0 15 0;
+#X connect 5 0 15 0;
+#X connect 6 0 15 0;
+#X connect 12 0 15 0;
+#X connect 13 0 15 0;
+#X connect 15 0 8 0;
+#X connect 15 1 7 0;
+#X connect 15 2 16 0;
+#X connect 15 3 16 1;
+#X connect 15 4 16 2;
+#X connect 16 0 15 0;
diff --git a/tools/help-lorenz.pd b/tools/help-lorenz.pd
new file mode 100644
index 0000000..0dc9b56
--- /dev/null
+++ b/tools/help-lorenz.pd
@@ -0,0 +1,32 @@
+#N canvas 683 22 577 480 10;
+#X obj 43 105 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 94 106 5 0 0 0 - - -;
+#X text 132 162 Reset To Initial Conditions;
+#X floatatom 88 372 10 0 0 0 Y - -;
+#X floatatom 43 350 10 0 0 0 X - -;
+#X obj 43 122 metro 50;
+#X obj 18 121 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 98 192 param 0.02 10 28 2.66667;
+#X floatatom 133 399 10 0 0 0 Z - -;
+#X text 20 18 Lorenz Attractor;
+#X text 19 33 Chaos PD Externals - Copyright Ben Bogart 2002;
+#X obj 20 62 readme-fractals;
+#X obj 43 318 lorenz 0.1 0 0 0.02 10 28 2.66667;
+#X text 275 194 Modify parameters;
+#X msg 88 162 reset;
+#X obj 184 345 search-tools;
+#X connect 0 0 5 0;
+#X connect 1 0 5 1;
+#X connect 5 0 12 0;
+#X connect 6 0 12 0;
+#X connect 7 0 12 0;
+#X connect 12 0 4 0;
+#X connect 12 1 3 0;
+#X connect 12 2 8 0;
+#X connect 12 3 15 0;
+#X connect 12 4 15 1;
+#X connect 12 5 15 2;
+#X connect 14 0 12 0;
+#X connect 15 0 12 0;
diff --git a/tools/help-martin-test.pd b/tools/help-martin-test.pd
new file mode 100644
index 0000000..b8f294a
--- /dev/null
+++ b/tools/help-martin-test.pd
@@ -0,0 +1,92 @@
+#N canvas 437 54 668 669 10;
+#X obj 35 179 tgl 15 0 empty empty empty 0 -6 32 8 -262144 -1 -1 0
+1;
+#X floatatom 86 180 5 0 0 0 - - -;
+#X text 81 219 Reset To Initial Conditions;
+#X text 94 261 Modify Parameters;
+#X msg 80 236 reset 0.1 0.1;
+#X floatatom 59 444 10 0 0 0 Y - -;
+#X floatatom 32 464 10 0 0 0 X - -;
+#X text 19 50 (This attractor is not continuous);
+#X text 21 19 Latoocarfian Attractor (from Cliff Pickover);
+#X text 20 34 Chaos PD Externals - Copyright Michael McGonagle 2003
+;
+#X obj 35 196 metro 50;
+#X obj 14 197 bng 15 250 50 0 empty empty empty 0 -6 32 8 -262144 -1
+-1;
+#X obj 25 83 readme-fractals;
+#X msg 98 307 search;
+#X obj 34 392 martin;
+#X msg 89 282 param 1;
+#X msg 113 330 show;
+#X msg 380 144 1000;
+#X obj 336 202 until;
+#X obj 279 384 route show search invalid;
+#X obj 335 441 print search;
+#X obj 279 460 print show;
+#X obj 392 422 print invalid;
+#X obj 449 403 print somethingelse;
+#X msg 346 115 100;
+#X msg 311 141 10;
+#X msg 309 169 1;
+#X obj 474 625 qlist;
+#X msg 491 567 print;
+#X msg 484 547 clear;
+#X msg 474 527 rewind;
+#N canvas 0 22 458 308 search 1;
+#X floatatom 187 89 5 0 0 0 - - -;
+#X obj 142 50 bng 15 250 50 0 empty empty empty 0 -6 32 8 -262144 -1
+-1;
+#X obj 147 73 loop;
+#X floatatom 186 15 5 0 0 0 - - -;
+#X floatatom 192 31 5 0 0 0 - - -;
+#X floatatom 198 47 5 0 0 0 - - -;
+#X obj 31 259 outlet;
+#X msg 48 167 param \$1;
+#X msg 65 192 constrain 0.01;
+#X obj 77 121 t b b f;
+#X msg 82 218 search;
+#X connect 1 0 2 0;
+#X connect 2 0 9 0;
+#X connect 2 1 0 0;
+#X connect 3 0 2 0;
+#X connect 4 0 2 1;
+#X connect 5 0 2 2;
+#X connect 7 0 6 0;
+#X connect 8 0 6 0;
+#X connect 9 0 10 0;
+#X connect 9 1 8 0;
+#X connect 9 2 7 0;
+#X connect 10 0 6 0;
+#X restore 45 119 pd search;
+#X obj 52 146 print sit;
+#X msg 136 357 lyapunov 0 10 100;
+#X msg 465 504 add martin \$1 \$3 \$6;
+#X connect 0 0 10 0;
+#X connect 1 0 10 1;
+#X connect 4 0 14 0;
+#X connect 10 0 14 0;
+#X connect 11 0 14 0;
+#X connect 13 0 14 0;
+#X connect 14 0 6 0;
+#X connect 14 1 5 0;
+#X connect 14 2 19 0;
+#X connect 15 0 14 0;
+#X connect 16 0 14 0;
+#X connect 17 0 18 0;
+#X connect 18 0 13 0;
+#X connect 19 0 21 0;
+#X connect 19 1 20 0;
+#X connect 19 1 34 0;
+#X connect 19 2 22 0;
+#X connect 19 3 23 0;
+#X connect 24 0 18 0;
+#X connect 25 0 18 0;
+#X connect 26 0 18 0;
+#X connect 28 0 27 0;
+#X connect 29 0 27 0;
+#X connect 30 0 27 0;
+#X connect 31 0 32 0;
+#X connect 31 0 14 0;
+#X connect 33 0 14 0;
+#X connect 34 0 27 0;
diff --git a/tools/help-martin.pd b/tools/help-martin.pd
new file mode 100644
index 0000000..ef12d0d
--- /dev/null
+++ b/tools/help-martin.pd
@@ -0,0 +1,38 @@
+#N canvas 203 283 593 496 10;
+#X obj 43 134 tgl 15 0 empty empty empty 0 -6 32 8 -262144 -1 -1 0
+1;
+#X floatatom 94 135 5 0 0 0 - - -;
+#X text 89 174 Reset To Initial Conditions;
+#X text 102 216 Modify Parameters;
+#X msg 88 191 reset 0.1 0.1;
+#X floatatom 51 451 10 0 0 0 Y - -;
+#X floatatom 42 427 10 0 0 0 X - -;
+#X text 19 50 (This attractor is not continuous);
+#X text 20 34 Chaos PD Externals - Copyright Michael McGonagle 2003
+;
+#X obj 43 151 metro 50;
+#X obj 18 150 bng 15 250 50 0 empty empty empty 0 -6 32 8 -262144 -1
+-1;
+#X obj 25 83 readme-fractals;
+#X obj 42 347 martin;
+#X text 143 429 This fractal exhibits chaotic tendencies when A (param)
+is in the vicinity of an odd multiple of PI.;
+#X msg 97 237 param 3.14159;
+#X text 21 19 Martin Attractor;
+#X obj 68 379 search-tools;
+#X obj 204 344 print vars;
+#X obj 239 317 print param;
+#X connect 0 0 9 0;
+#X connect 1 0 9 1;
+#X connect 4 0 12 0;
+#X connect 9 0 12 0;
+#X connect 10 0 12 0;
+#X connect 12 0 6 0;
+#X connect 12 1 5 0;
+#X connect 12 2 16 0;
+#X connect 12 3 16 1;
+#X connect 12 3 17 0;
+#X connect 12 4 16 2;
+#X connect 12 4 18 0;
+#X connect 14 0 12 0;
+#X connect 16 0 12 0;
diff --git a/tools/help-popcorn-test.pd b/tools/help-popcorn-test.pd
new file mode 100644
index 0000000..cbfdc4b
--- /dev/null
+++ b/tools/help-popcorn-test.pd
@@ -0,0 +1,62 @@
+#N canvas 575 260 589 492 10;
+#X obj 43 134 tgl 15 0 empty empty empty 0 -6 160 8 -262144 -1 -1 0
+1;
+#X floatatom 94 135 5 0 0 0 - - -;
+#X text 79 201 Reset To Initial Conditions;
+#X text 99 246 Modify Parameters;
+#X msg 76 184 reset 0.1 0.1;
+#X floatatom 131 384 10 0 0 0 Y - -;
+#X floatatom 43 384 10 0 0 0 X - -;
+#X text 19 50 (This attractor is not continuous);
+#X text 21 19 Latoocarfian Attractor (from Cliff Pickover);
+#X text 20 34 Chaos PD Externals - Copyright Michael McGonagle 2003
+;
+#X obj 43 151 metro 50;
+#X obj 13 150 bng 15 250 50 0 empty empty empty 0 -6 32 8 -262144 -1
+-1;
+#X obj 25 83 readme-fractals;
+#X msg 101 266 search;
+#X obj 212 381 print;
+#X msg 113 294 show;
+#X msg 95 226 param 2.35155;
+#X obj 43 347 popcorn 0.1 0 2.35155;
+#N canvas 83 103 466 316 search 1;
+#X floatatom 187 89 5 0 0 0 - - -;
+#X obj 142 50 bng 15 250 50 0 empty empty empty 0 -6 32 8 -262144 -1
+-1;
+#X obj 147 73 loop;
+#X floatatom 186 15 5 0 0 0 - - -;
+#X floatatom 192 31 5 0 0 0 - - -;
+#X floatatom 198 47 5 0 0 0 - - -;
+#X obj 31 259 outlet;
+#X msg 48 167 param \$1;
+#X obj 77 121 t b b f;
+#X msg 82 218 search;
+#X msg 65 192 constrain 0.001;
+#X connect 1 0 2 0;
+#X connect 2 0 8 0;
+#X connect 2 1 0 0;
+#X connect 3 0 2 0;
+#X connect 4 0 2 1;
+#X connect 5 0 2 2;
+#X connect 7 0 6 0;
+#X connect 8 0 9 0;
+#X connect 8 1 10 0;
+#X connect 8 2 7 0;
+#X connect 9 0 6 0;
+#X connect 10 0 6 0;
+#X restore 229 286 pd search;
+#X obj 236 313 print sit;
+#X connect 0 0 10 0;
+#X connect 1 0 10 1;
+#X connect 4 0 17 0;
+#X connect 10 0 17 0;
+#X connect 11 0 17 0;
+#X connect 13 0 17 0;
+#X connect 15 0 17 0;
+#X connect 16 0 17 0;
+#X connect 17 0 6 0;
+#X connect 17 1 5 0;
+#X connect 17 2 14 0;
+#X connect 18 0 19 0;
+#X connect 18 0 17 0;
diff --git a/tools/help-popcorn.pd b/tools/help-popcorn.pd
new file mode 100644
index 0000000..119edea
--- /dev/null
+++ b/tools/help-popcorn.pd
@@ -0,0 +1,35 @@
+#N canvas 492 119 593 496 10;
+#X obj 43 134 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 94 135 5 0 0 0 - - -;
+#X text 79 201 Reset To Initial Conditions;
+#X text 99 246 Modify Parameters;
+#X msg 76 184 reset 0.1 0.1;
+#X floatatom 78 398 10 0 0 0 Y - -;
+#X floatatom 43 373 10 0 0 0 X - -;
+#X text 19 50 (This attractor is not continuous);
+#X text 20 34 Chaos PD Externals - Copyright Michael McGonagle 2003
+;
+#X obj 43 151 metro 50;
+#X obj 13 150 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 25 83 readme-fractals;
+#X msg 95 226 param 2.35155;
+#X obj 43 347 popcorn 0.1 0 2.35155;
+#X text 98 441 This fractal seems to allow is sole parameter to range
+over a large range. As the value of the parameter rises \, so does
+the Lyapunov Exponent \, but it does not appear to be linear.;
+#X text 21 19 Popcorn Attractor (from Cliff Pickover);
+#X obj 126 373 search-tools;
+#X connect 0 0 9 0;
+#X connect 1 0 9 1;
+#X connect 4 0 13 0;
+#X connect 9 0 13 0;
+#X connect 10 0 13 0;
+#X connect 12 0 13 0;
+#X connect 13 0 6 0;
+#X connect 13 1 5 0;
+#X connect 13 2 16 0;
+#X connect 13 3 16 1;
+#X connect 13 4 16 2;
+#X connect 16 0 13 0;
diff --git a/tools/help-quaruptwo-test.pd b/tools/help-quaruptwo-test.pd
new file mode 100644
index 0000000..4fcc159
--- /dev/null
+++ b/tools/help-quaruptwo-test.pd
@@ -0,0 +1,69 @@
+#N canvas 559 82 589 492 10;
+#X obj 43 134 tgl 15 0 empty empty empty 0 -6 160 8 -262144 -1 -1 0
+1;
+#X floatatom 94 135 5 0 0 0 - - -;
+#X text 91 208 Reset To Initial Conditions;
+#X text 114 281 Modify Parameters;
+#X floatatom 197 399 10 0 0 0 Y - -;
+#X floatatom 43 399 10 0 0 0 X - -;
+#X text 19 50 (This attractor is not continuous);
+#X text 20 34 Chaos PD Externals - Copyright Michael McGonagle 2003
+;
+#X obj 43 151 metro 50;
+#X obj 18 150 bng 15 250 50 0 empty empty empty 0 -6 160 8 -262144
+-1 -1;
+#X obj 25 83 readme-fractals;
+#X msg 117 303 search;
+#X obj 327 394 print;
+#X text 21 19 QuadrupTwo Attractor;
+#X msg 111 243 param 0 1 2;
+#X msg 177 335 show;
+#X msg 88 191 reset;
+#N canvas 0 22 470 320 search 0;
+#X floatatom 187 89 5 0 0 0 - - -;
+#X obj 142 50 bng 15 250 50 0 empty empty empty 0 -6 32 8 -262144 -1
+-1;
+#X obj 147 73 loop;
+#X floatatom 186 15 5 0 0 0 - - -;
+#X floatatom 192 31 5 0 0 0 - - -;
+#X floatatom 198 47 5 0 0 0 - - -;
+#X obj 31 259 outlet;
+#X obj 77 121 t b b f;
+#X msg 82 218 search;
+#X msg 48 167 param 34 1 \$1;
+#X msg 65 192 constrain 0.05;
+#X msg 190 149 constrain;
+#X msg 238 268 elyapunov;
+#X msg 198 198 constrain 0 100 0 2 0 100;
+#X msg 218 228 lyapunov 0 10 1000;
+#X connect 1 0 2 0;
+#X connect 2 0 7 0;
+#X connect 2 1 0 0;
+#X connect 3 0 2 0;
+#X connect 4 0 2 1;
+#X connect 5 0 2 2;
+#X connect 7 0 8 0;
+#X connect 7 2 9 0;
+#X connect 8 0 6 0;
+#X connect 9 0 6 0;
+#X connect 10 0 6 0;
+#X connect 11 0 6 0;
+#X connect 12 0 6 0;
+#X connect 13 0 6 0;
+#X connect 14 0 6 0;
+#X restore 165 96 pd search;
+#X obj 172 123 print sit;
+#X obj 43 363 quadruptwo 0.1 0.1 34 1 5;
+#X connect 0 0 8 0;
+#X connect 1 0 8 1;
+#X connect 8 0 19 0;
+#X connect 9 0 19 0;
+#X connect 11 0 19 0;
+#X connect 14 0 19 0;
+#X connect 15 0 19 0;
+#X connect 16 0 19 0;
+#X connect 17 0 18 0;
+#X connect 17 0 19 0;
+#X connect 19 0 5 0;
+#X connect 19 1 4 0;
+#X connect 19 2 12 0;
diff --git a/tools/help-quaruptwo.pd b/tools/help-quaruptwo.pd
new file mode 100644
index 0000000..292b46e
--- /dev/null
+++ b/tools/help-quaruptwo.pd
@@ -0,0 +1,32 @@
+#N canvas 527 258 585 488 10;
+#X obj 43 134 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 94 135 5 0 0 0 - - -;
+#X text 91 208 Reset To Initial Conditions;
+#X text 114 263 Modify Parameters;
+#X floatatom 78 414 10 0 0 0 Y - -;
+#X floatatom 43 392 10 0 0 0 X - -;
+#X text 19 50 (This attractor is not continuous);
+#X text 20 34 Chaos PD Externals - Copyright Michael McGonagle 2003
+;
+#X obj 43 151 metro 50;
+#X obj 18 150 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 25 83 readme-fractals;
+#X text 21 19 QuadrupTwo Attractor;
+#X msg 111 243 param 0 1 2;
+#X msg 88 191 reset;
+#X obj 43 363 quadruptwo 0 0 34 1 5;
+#X obj 126 390 search-tools;
+#X connect 0 0 8 0;
+#X connect 1 0 8 1;
+#X connect 8 0 14 0;
+#X connect 9 0 14 0;
+#X connect 12 0 14 0;
+#X connect 13 0 14 0;
+#X connect 14 0 5 0;
+#X connect 14 1 4 0;
+#X connect 14 2 15 0;
+#X connect 14 3 15 1;
+#X connect 14 4 15 2;
+#X connect 15 0 14 0;
diff --git a/tools/help-standardmap.pd b/tools/help-standardmap.pd
new file mode 100644
index 0000000..02fb992
--- /dev/null
+++ b/tools/help-standardmap.pd
@@ -0,0 +1,32 @@
+#N canvas 527 258 585 488 10;
+#X obj 43 134 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 94 135 5 0 0 0 - - -;
+#X text 91 208 Reset To Initial Conditions;
+#X text 112 265 Modify Parameters;
+#X msg 88 191 reset 0.1 0.1;
+#X floatatom 61 452 10 0 0 0 Y - -;
+#X floatatom 43 427 10 0 0 0 X - -;
+#X text 19 50 (This attractor is not continuous);
+#X text 20 34 Chaos PD Externals - Copyright Michael McGonagle 2003
+;
+#X obj 43 151 metro 50;
+#X obj 18 150 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 25 83 readme-fractals;
+#X text 21 19 Standard Map;
+#X obj 43 369 standardmap;
+#X msg 110 242 param 0.89;
+#X obj 70 398 search-tools;
+#X connect 0 0 9 0;
+#X connect 1 0 9 1;
+#X connect 4 0 13 0;
+#X connect 9 0 13 0;
+#X connect 10 0 13 0;
+#X connect 13 0 6 0;
+#X connect 13 1 5 0;
+#X connect 13 2 15 0;
+#X connect 13 3 15 1;
+#X connect 13 4 15 2;
+#X connect 14 0 13 0;
+#X connect 15 0 13 0;
diff --git a/tools/loop.pd b/tools/loop.pd
new file mode 100644
index 0000000..19896ab
--- /dev/null
+++ b/tools/loop.pd
@@ -0,0 +1,43 @@
+#N canvas 640 438 490 340 10;
+#X obj 52 26 inlet;
+#X obj 93 26 inlet;
+#X obj 134 26 inlet;
+#X obj 52 262 outlet;
+#X obj 52 44 route bang float;
+#X obj 74 118 f;
+#X obj 74 136 -;
+#X obj 74 154 /;
+#X obj 74 172 i;
+#X obj 74 190 + 1;
+#X obj 52 208 f;
+#X obj 52 226 until;
+#X obj 52 244 f;
+#X obj 79 244 +;
+#X obj 96 99 f;
+#X obj 52 62 t b b b;
+#X obj 130 262 outlet;
+#X obj 74 81 t b f;
+#X connect 0 0 4 0;
+#X connect 1 0 5 1;
+#X connect 2 0 13 1;
+#X connect 2 0 7 1;
+#X connect 4 0 15 0;
+#X connect 4 1 17 0;
+#X connect 5 0 6 0;
+#X connect 6 0 7 0;
+#X connect 7 0 8 0;
+#X connect 8 0 9 0;
+#X connect 9 0 10 1;
+#X connect 9 0 16 0;
+#X connect 10 0 11 0;
+#X connect 11 0 12 0;
+#X connect 12 0 13 0;
+#X connect 12 0 3 0;
+#X connect 13 0 12 1;
+#X connect 14 0 12 1;
+#X connect 15 0 10 0;
+#X connect 15 1 5 0;
+#X connect 15 2 14 0;
+#X connect 17 0 5 0;
+#X connect 17 1 14 1;
+#X connect 17 1 6 1;
diff --git a/tools/readme-frac-format.pd b/tools/readme-frac-format.pd
new file mode 100644
index 0000000..950f56c
--- /dev/null
+++ b/tools/readme-frac-format.pd
@@ -0,0 +1,22 @@
+#N canvas 171 208 685 432 10;
+#X text 31 36 The format of this file is pretty simple (or tries to
+be).;
+#X text 55 69 Line 1: name - this is used as the 'c' identifier;
+#X text 55 81 Line 2: <var_count> <param_count> - integer for each
+;
+#X text 55 93 Line 3-x: <name> <init> - var name and start state;
+#X text 55 105 Line y-z: <name> <low> <high> <init> - param data;
+#X text 55 131 Line c: '.' - file must end with a single period '.'
+;
+#X text 33 180 This file is used by 'gen_fractal_framework' to produce
+the 'C' source for the external.;
+#X text 62 225 ** - The pseudo-code must not have any spaces. Each
+line in the pseudo-code is considered to be a single "assignment" statement.
+There is no need to worry about creating storage for any intermediate
+(calculated) variables \, as that is done by the translation program.
+The pseudo-code represents variables and parameters with a '$' before
+the variable name. Locals are allowed \, but are preceded with a '#'.
+(Locals are used as 'intermediate' \, computed values that are not
+retained from iteration to iteration.);
+#X text 55 118 Line a-b: <code_fragment> - line(s) of frac 'pseudo-code'
+**;
diff --git a/tools/readme-fractals.pd b/tools/readme-fractals.pd
new file mode 100644
index 0000000..2281c6a
--- /dev/null
+++ b/tools/readme-fractals.pd
@@ -0,0 +1,54 @@
+#N canvas 495 74 487 362 10;
+#X obj 56 202 readme-frac-format;
+#X obj 56 221 readme-gen-fractal;
+#X text 37 183 if you want to add new fractals:;
+#X obj 56 144 readme-operation;
+#X obj 56 164 readme-searching;
+#X text 22 107 Additional Reading \,;
+#X text 41 126 if you want to us existing fractals:;
+#X obj 56 240 readme-parameter-ranges;
+#X text 270 269 Developed using PD 0.36;
+#X text 93 295 Copyright 2003 \, Ben Bogart and Michael McGonagle;
+#X text 276 282 Released under GNU GPL;
+#N canvas 302 96 575 579 available_fractals 0;
+#X obj 157 264 henon;
+#X obj 157 302 ikeda;
+#X obj 157 321 latoocarfian;
+#X obj 157 340 latoomutalpha;
+#X obj 157 359 latoomutbeta;
+#X obj 157 378 latoomutgamma;
+#X obj 69 208 logistic;
+#X obj 277 208 lorenz;
+#X obj 69 227 mlogistic;
+#X obj 277 246 rossler;
+#X obj 157 473 standardmap;
+#X obj 69 246 tent;
+#X obj 277 265 three_d;
+#X text 57 187 1 variable;
+#X text 157 187 2 variables;
+#X text 273 187 3 variables;
+#X text 24 136 The remaining outputs represent the variables \, corresponding
+from left to right as the variables from the '*.frac' data file.;
+#X text 24 16 Below \, there is an object for each of the fractals
+currently available in the ChaosII collection.;
+#X text 23 55 All fractals share the same common structure \, in that
+the right-most outlet is used as the "results" outlet. This is used
+during the "Searching" operations to return the results of the search
+to the user. see 'readme-searching' file for more info on the results
+of a search.;
+#X obj 157 207 attract1;
+#X obj 157 226 dejong;
+#X obj 157 245 gingerbreadman;
+#X obj 157 283 hopalong;
+#X obj 157 416 martin;
+#X obj 277 227 pickover;
+#X obj 157 435 popcorn;
+#X obj 157 454 quadruptwo;
+#X obj 157 492 strange1;
+#X obj 157 511 tinkerbell;
+#X obj 157 530 unity;
+#X obj 157 397 lotkavolterra;
+#X restore 43 78 pd available_fractals;
+#X text 27 28 The Chaos Library provides a means to generate multiple
+chaotic datastreams \, as well as the ability to search for new attractor
+sets that produce other chaotic datastreams.;
diff --git a/tools/readme-gen-fractal.pd b/tools/readme-gen-fractal.pd
new file mode 100644
index 0000000..2af4657
--- /dev/null
+++ b/tools/readme-gen-fractal.pd
@@ -0,0 +1,6 @@
+#N canvas 0 22 478 328 10;
+#X text 25 23 This will explain the usage of 'gen_fractal_framework'
+\, once the program has become more "stable" and generates what would
+be unique to each fractal. Currently \, there is still some redundancy
+in the code.;
+#X text 282 136 more later...;
diff --git a/tools/readme-lyapunov.pd b/tools/readme-lyapunov.pd
new file mode 100644
index 0000000..056e6bd
--- /dev/null
+++ b/tools/readme-lyapunov.pd
@@ -0,0 +1,16 @@
+#N canvas 0 22 565 389 10;
+#X text 74 61 Lyapunov Exponent;
+#X text 25 82 This value is an estimate of the attractors potential
+for chaos. It will not necessarily be the same for any given run using
+any arbitrary fractal. The description below attempts to put "attractors"
+into three catagories.;
+#X text 48 262 Don't forget \, just because an "attractor" is not chaotic
+\, it does not mean that it will not generate an interesting stream
+of number \, if only until they converge.;
+#X text 40 151 < 0;
+#X text 78 151 These are not chaotic \, may produce a "short-term"
+stream of intrest;
+#X text 39 179 == 0;
+#X text 80 179 Attractors converge to one or more points;
+#X text 40 197 > 0;
+#X text 80 198 Chaos begins. Higher values indicate "more" chaos.;
diff --git a/tools/readme-operation.pd b/tools/readme-operation.pd
new file mode 100644
index 0000000..be93969
--- /dev/null
+++ b/tools/readme-operation.pd
@@ -0,0 +1,34 @@
+#N canvas 159 133 675 651 10;
+#X msg 56 219 reset <var-init>;
+#X msg 56 240 param <param-data>;
+#X text 36 280 As to the exact variable and parameter ranges to use
+\, you will have to consult each fractals help file. You can also use
+the "Searching" functions to randomly find a new attractor set \, and
+then use those values in either a set of messages to the fractal \,
+or in its creation arguments.;
+#X msg 56 198 reset;
+#X text 98 199 sets the variables back to their initial state **;
+#X text 181 221 sets the variables to an explicit state ***;
+#X text 195 242 sets parameters to explicit state ****;
+#X text 34 26 Create a fractal with or without a set of variables and
+parameters \, passed as creation arguments. Without the creation arguments
+\, the class defaults will be used for the fractal. With the arguments
+\, a new fractal is created using the arguments as the defaults.;
+#X text 35 104 To use a fractal \, create the instance \, and optionally
+pass it an initial state of variables and a set of parameters. Then
+repeatedly 'bang' on the input to iterate thru the fractals variable
+states. Using a 'reset' message will return the variables to their
+initial state \, or to the explicit values passed.;
+#X text 38 369 ** - The initial state can be explicitly set by passing
+the arguments at creation time for the fractal \, or (without creation
+arguments) the class default value will be used.;
+#X text 37 414 *** - When setting the variables to an arbitrary state
+\, the stream may not be in a "stable" state. You may need to iterate
+the fractal several hundred (or thousand) times to obtain a "stable"
+state. If you pass a set of variables that were taken from the 'search'
+(or 'show') results \, the values most likely will be in a "stable"
+condition.;
+#X text 38 500 **** - Do remember that not all combinations of parameters
+result in an attractor set.;
+#X text 234 577 chaos \, version 2 by Ben Bogart and Michael McGonagle.
+Copyright 2003;
diff --git a/tools/readme-parameter-ranges.pd b/tools/readme-parameter-ranges.pd
new file mode 100644
index 0000000..27fe5f0
--- /dev/null
+++ b/tools/readme-parameter-ranges.pd
@@ -0,0 +1,23 @@
+#N canvas 0 22 499 399 10;
+#X text 33 275 The "classification" of an attractor set uses the full
+range of the fractals acceptable parameter ranges. As this method of
+"classification" is relative \, it will not describe each fractal uniquely
+\, but rather can be used to compare attractor sets that have similar
+(closely related) parameter values. NOTE: there needs to be a way to
+increase the granularity of the classification system...;
+#X text 35 21 Parameter Ranges - Once you have an operational fractal
+external \, it is important to make sure that the assigned ranges for
+each of the parameters are "optimized" to limit the random number generator
+to those ranges. This is important when a variable can only range between
+(-1 .. 1) and you have declared that it can range from (-100 .. 100).
+Because of the much wider search space \, there is less likelyhood
+of finding anything useful \, or at least make the search times longer
+due to higher failure rates.;
+#X text 35 147 If you are unsure of what the ranges are \, you can
+either figure them out mathematically \, or use the "brute-force" method
+and iterate over ranges of the defined parameters. The points that
+return a fractal (even ones that converge) will give an indication
+as to the acceptable ranges for each param. Once you have determined
+those ranges \, adjust them in your '*.frac' file and re-make the external
+for your fractal. (Or you can just edit the Macros in the C code \,
+if you are comfortable with that.);
diff --git a/tools/readme-searching.pd b/tools/readme-searching.pd
new file mode 100644
index 0000000..0135779
--- /dev/null
+++ b/tools/readme-searching.pd
@@ -0,0 +1,101 @@
+#N canvas 39 41 1031 669 10;
+#X msg 471 344 show;
+#X msg 470 295 seed;
+#X msg 470 314 seed number;
+#X msg 469 234 elyapunov;
+#X msg 467 118 constrain;
+#X text 601 76 random search for an attractor;
+#X text 508 345 displays info on attractor to console;
+#X text 543 119 restores full param search area;
+#X text 632 138 based on current params \, limits to percentage of
+range;
+#X msg 465 76 search <var-inits>;
+#X msg 467 137 constrain <percentage>;
+#X msg 467 156 constrain <param-limits>;
+#X msg 468 200 lyapunov <low> <high> <failure>;
+#X msg 465 57 search;
+#X text 516 57 random search for an attractor \, variables use defaults
+;
+#X text 17 403 The search method implemented performs the following:
+;
+#X text 41 418 1 Set the params randomly based on allowed ranges;
+#X text 41 432 2 Calculate the Lyapunov Exponent;
+#X text 41 447 3 If the Lyapunov Exponent is within allowed range \,
+return the attractor set;
+#X text 19 39 Searching for an attractor set can be as simple as sending
+a 'search' message to a fractal. This will search the fractals allowable
+parameter limits for an attractor set.;
+#X text 39 183 arg[1] = Lyapunov Exponent;
+#X msg 469 265 classify <units>;
+#X text 591 266 Used to set the "granularity" of the classification
+;
+#X text 17 323 The Lyapunov Exponent for the attractor set will indicates
+one of three states \, (1) Convergence [a negative value] \, (2) Stability
+[0 \, of values close to 0] \, and (3) Chaos [a positive value]. Each
+class will have different ranges of Lyapunov Exponent.;
+#X text 39 196 arg[2] = Classification String ****;
+#X text 16 513 **** - The classification method was adopted from Julian
+Sprott's method of classification. While it is an arbitrary system
+\, and does not "uniquely" identify an attractor set \, it is used
+to show a relationship with other attractor sets with similar values.
+;
+#X text 558 313 seeds search random number generator with number *
+;
+#X text 507 296 seeds search random number generator with time *;
+#X text 543 235 calculates an extended Lyapunov Exponent **;
+#X text 648 157 params are limited to explicit ranges ***;
+#X text 473 419 * - all fractals of all classes currently share the
+same random number generator.;
+#X text 473 452 ** - this performs a Lyapunov Exponent calculation
+for each variable in the attractor. Ideally \, all results should be
+approximately the same. This is an experimental function.;
+#X text 473 502 *** - expects there to be a low and high range limit
+for each param in the fractal equation.;
+#X text 483 217 sets search limits and failure count for Lyapunov Exponent
+;
+#X text 37 15 Searching - the art of chaos.;
+#N canvas 0 22 464 316 simple_example 0;
+#X obj 166 106 latoocarfian;
+#X msg 173 38 search;
+#X text 32 238 This example creates a 'latoocarfian' fractal with the
+class defaults. When a search is performed \, the initial state for
+the variables are set to the class defaults.;
+#X obj 131 14 bng 15 250 50 0 empty empty empty 0 -6 32 8 -262144 -1
+-1;
+#X floatatom 166 211 10 0 0 0 X - -;
+#X floatatom 185 194 10 0 0 1 Y - -;
+#X msg 166 16 reset;
+#X msg 183 61 show;
+#X obj 205 173 print results;
+#X obj 225 152 print vars;
+#X obj 245 132 print params;
+#X connect 0 0 4 0;
+#X connect 0 1 5 0;
+#X connect 0 2 8 0;
+#X connect 0 3 9 0;
+#X connect 0 4 10 0;
+#X connect 1 0 0 0;
+#X connect 3 0 0 0;
+#X connect 6 0 0 0;
+#X connect 7 0 0 0;
+#X restore 286 18 pd simple_example;
+#X text 39 210 arg[3] = failure rate before solution *****;
+#X text 16 581 ***** - the failure rate is a percentage of the actual
+number of failures until a solution is found over the total number
+of times the search algorithm will be executed before giving up. This
+limit is set via the 'lyapunov' message. This number will also be influenced
+by the 'low' and 'high' ranges set.;
+#X text 19 93 The values returned from a 'search' message use the 'search'
+outlets. These three outlets encapsulate that three pieces of data
+of interest. The first of the 'search' outlets holds a list of the
+results. This includes:;
+#X text 39 170 arg[0] = 'show' \, 'search' \, or 'invalid';
+#X text 18 269 Most likely \, you won't see any failures ('invalid')
+\, unless you mess with the 'constrain' or 'lyapunov' messages. 'show'
+is returned when you use the 'show' message.;
+#X obj 153 376 readme-lyapunov;
+#X text 43 475 4 If the Limit Count has been exceeded \, return 'invalid'
+\, else goto 1;
+#X text 18 154 Search Outlet 0:;
+#X text 18 227 Search Outlet 1: list of current variables;
+#X text 18 243 Search Outlet 2: list of parameter set;
diff --git a/tools/search-tools.pd b/tools/search-tools.pd
new file mode 100644
index 0000000..f00a011
--- /dev/null
+++ b/tools/search-tools.pd
@@ -0,0 +1,186 @@
+#N canvas 619 310 464 533 10;
+#X obj -97 556 outlet;
+#X obj -97 2 cnv 15 450 220 empty empty Searching_Commands 2 9 1 10
+-233017 -66577 0;
+#X msg 104 83 constrain;
+#X msg 104 104 constrain \$1;
+#X text -77 104 % Constraint;
+#X text -77 82 No Constraint;
+#X msg 104 30 search;
+#X obj 221 52 nbx 5 17 -1e+37 1e+37 0 0 \$0-search_v2 empty empty 0
+-6 1153 10 -262144 -1 -1 0 256;
+#X obj 172 52 nbx 5 17 -1e+37 1e+37 0 0 \$0-search_v1 empty empty 0
+-6 1153 10 -262144 -1 -1 0 256;
+#X text -78 48 Search w/ inits;
+#X text -78 29 Search w/ default inits;
+#X obj 86 143 bng 17 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text -76 142 Set Lyapunov Limits;
+#X obj 287 143 nbx 5 17 -1e+37 1e+37 0 0 \$0-lyapunov_v3 empty failure
+0 -6 1153 10 -262144 -1 -1 0 256;
+#X obj 238 143 nbx 5 17 -1e+37 1e+37 0 0 \$0-lyapunov_v2 empty high
+0 -6 1153 10 -262144 -1 -1 0 256;
+#X obj 189 143 nbx 5 17 -1e+37 1e+37 0 0 \$0-lyapunov_v1 empty low
+0 -6 1153 10 -262144 -1 -1 0 256;
+#N canvas 0 22 509 236 lyapunov 0;
+#X obj 42 26 inlet;
+#X obj 83 26 r \$0-lyapunov_v1;
+#X obj 101 61 pack f f f;
+#X obj 203 27 r \$0-lyapunov_v2;
+#X obj 320 27 r \$0-lyapunov_v3;
+#X msg 101 84 lyapunov \$1 \$2 \$3;
+#X obj 101 108 s \$0-outlet;
+#X connect 0 0 2 0;
+#X connect 1 0 2 0;
+#X connect 2 0 5 0;
+#X connect 3 0 2 1;
+#X connect 4 0 2 2;
+#X connect 5 0 6 0;
+#X restore 106 143 pd lyapunov;
+#X obj 86 52 bng 17 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#N canvas 0 22 374 205 search 0;
+#X obj 104 104 pack f f;
+#X msg 104 127 search \$1 \$2;
+#X obj 83 26 r \$0-search_v1;
+#X obj 186 26 r \$0-search_v2;
+#X obj 94 63 f;
+#X obj 104 151 s \$0-outlet;
+#X obj 18 26 inlet;
+#X connect 0 0 1 0;
+#X connect 1 0 5 0;
+#X connect 2 0 4 1;
+#X connect 3 0 0 1;
+#X connect 4 0 0 0;
+#X connect 6 0 4 0;
+#X restore 104 52 pd search;
+#X text -76 164 Extended Lyapunov;
+#X msg 104 165 elyapunov;
+#X msg 104 186 show;
+#X text -75 198 Get Attractor Info;
+#X obj 104 226 s \$0-outlet;
+#X obj -97 535 r \$0-outlet;
+#X obj -14 535 inlet;
+#X obj -14 556 s \$0-inlet;
+#X obj -97 226 cnv 15 450 300 empty empty Search_Results 2 9 1 10 -233017
+-66577 0;
+#N canvas 48 644 700 296 get_results 0;
+#X msg 5 39 set \$1;
+#X obj 5 17 symbol;
+#X obj 5 61 outlet;
+#X obj 150 38 s \$0-lyapunov;
+#X obj 190 89 s \$0-failure_rate;
+#X obj 319 32 s \$0-v1;
+#X obj 343 53 s \$0-v2;
+#X obj 367 75 s \$0-v3;
+#X obj 473 31 s \$0-p1;
+#X obj 497 52 s \$0-p2;
+#X obj 521 74 s \$0-p3;
+#X obj 170 62 s \$0-classification;
+#X obj 44 222 r \$0-classification;
+#X msg 44 243 set \$1;
+#X obj 44 264 outlet;
+#X obj 5 -6 r \$0-inlet;
+#X obj 80 117 print debug;
+#X obj 131 11 unpack s 0 s 0;
+#X obj 319 9 unpack 0 0 0 0 0 0;
+#X obj 391 96 s \$0-v4;
+#X obj 415 117 s \$0-v5;
+#X obj 440 138 s \$0-v6;
+#X obj 473 9 unpack 0 0 0 0 0 0;
+#X obj 545 96 s \$0-p4;
+#X obj 569 117 s \$0-p5;
+#X obj 594 137 s \$0-p6;
+#X obj 318 -12 r \$0-inlet_var;
+#X obj 473 -11 r \$0-inlet_param;
+#X connect 0 0 2 0;
+#X connect 1 0 0 0;
+#X connect 12 0 13 0;
+#X connect 13 0 14 0;
+#X connect 15 0 1 0;
+#X connect 15 0 17 0;
+#X connect 17 1 3 0;
+#X connect 17 2 11 0;
+#X connect 17 3 4 0;
+#X connect 18 0 5 0;
+#X connect 18 1 6 0;
+#X connect 18 2 7 0;
+#X connect 18 3 19 0;
+#X connect 18 4 20 0;
+#X connect 18 5 21 0;
+#X connect 22 0 8 0;
+#X connect 22 1 9 0;
+#X connect 22 2 10 0;
+#X connect 22 3 23 0;
+#X connect 22 4 24 0;
+#X connect 22 5 25 0;
+#X connect 26 0 18 0;
+#X connect 27 0 22 0;
+#X restore -14 267 pd get_results;
+#X msg -14 288 search;
+#X msg 79 288 NOCBNS;
+#X text 184 290 Classification;
+#X obj 79 309 nbx 10 17 -1e+37 1e+37 0 0 empty \$0-lyapunov empty 0
+-6 577 10 -262144 -1 -1 -0.482697 256;
+#X obj 79 330 nbx 10 17 -1e+37 1e+37 0 0 empty \$0-failure_rate empty
+0 -6 577 10 -262144 -1 -1 0.005 256;
+#X obj -14 371 nbx 5 17 -1e+37 1e+37 0 0 empty \$0-v1 empty 0 -6 577
+10 -262144 -1 -1 0 256;
+#X obj -14 391 nbx 5 17 -1e+37 1e+37 0 0 empty \$0-v2 empty 0 -6 577
+10 -262144 -1 -1 0 256;
+#X obj -14 411 nbx 5 17 -1e+37 1e+37 0 0 empty \$0-v3 empty 0 -6 577
+10 -262144 -1 -1 0 256;
+#X obj 111 371 nbx 5 17 -1e+37 1e+37 0 0 empty \$0-p1 empty 0 -6 577
+10 -262144 -1 -1 0.17869 256;
+#X obj 111 391 nbx 5 17 -1e+37 1e+37 0 0 empty \$0-p2 empty 0 -6 577
+10 -262144 -1 -1 0.437724 256;
+#X obj 111 411 nbx 5 17 -1e+37 1e+37 0 0 empty \$0-p3 empty 0 -6 577
+10 -262144 -1 -1 -2.31304 256;
+#X text 183 331 Failure Rate;
+#X text 184 309 Lyapunov Exponent;
+#X text 48 372 Var 1;
+#X text 48 392 Var 2;
+#X text 48 412 Var 3;
+#X text 174 373 Param 1;
+#X text 174 393 Param 2;
+#X text 174 413 Param 3;
+#X obj 188 164 readme-lyapunov;
+#X obj 171 29 readme-searching;
+#X obj -14 431 nbx 5 17 -1e+37 1e+37 0 0 empty \$0-v4 empty 0 -6 577
+10 -262144 -1 -1 0 256;
+#X obj -14 451 nbx 5 17 -1e+37 1e+37 0 0 empty \$0-v5 empty 0 -6 577
+10 -262144 -1 -1 0 256;
+#X obj -14 471 nbx 5 17 -1e+37 1e+37 0 0 empty \$0-v6 empty 0 -6 577
+10 -262144 -1 -1 0 256;
+#X obj 111 431 nbx 5 17 -1e+37 1e+37 0 0 empty \$0-p4 empty 0 -6 577
+10 -262144 -1 -1 -2.74459 256;
+#X obj 111 451 nbx 5 17 -1e+37 1e+37 0 0 empty \$0-p5 empty 0 -6 577
+10 -262144 -1 -1 0.00541449 256;
+#X obj 111 471 nbx 5 17 -1e+37 1e+37 0 0 empty \$0-p6 empty 0 -6 577
+10 -262144 -1 -1 1.3485 256;
+#X text 48 432 Var 4;
+#X text 48 452 Var 5;
+#X text 48 472 Var 6;
+#X text 174 433 Param 4;
+#X text 174 453 Param 5;
+#X text 174 473 Param 6;
+#X obj 62 535 inlet;
+#X obj 166 535 inlet;
+#X obj 62 556 s \$0-inlet_var;
+#X obj 166 556 s \$0-inlet_param;
+#X obj 198 104 nbx 5 17 -1e+37 1e+37 0 0 empty empty % 0 -6 1 10 -262144
+-1 -1 0 256;
+#X connect 2 0 23 0;
+#X connect 3 0 23 0;
+#X connect 6 0 23 0;
+#X connect 11 0 16 0;
+#X connect 17 0 18 0;
+#X connect 20 0 23 0;
+#X connect 21 0 23 0;
+#X connect 24 0 0 0;
+#X connect 25 0 26 0;
+#X connect 28 0 29 0;
+#X connect 28 1 30 0;
+#X connect 62 0 64 0;
+#X connect 63 0 65 0;
+#X connect 66 0 3 0;
diff --git a/unity.c b/unity.c
new file mode 100644
index 0000000..21ecc6f
--- /dev/null
+++ b/unity.c
@@ -0,0 +1,102 @@
+/* unity Attractor PD External */
+/* Copyright Michael McGonagle, from ??????, 2003 */
+/* This program is distributed under the params of the GNU Public License */
+
+///////////////////////////////////////////////////////////////////////////////////
+/* This file is part of Chaos PD Externals. */
+/* */
+/* Chaos PD Externals are free software; you can redistribute them and/or modify */
+/* them under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* Chaos PD Externals are distributed in the hope that they will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with the Chaos PD Externals; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+///////////////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#include "m_pd.h"
+
+
+
+#define M_x 0
+#define M_y 1
+
+#define M_param_count 0
+#define M_var_count 2
+#define M_search_count 0
+#define M_failure_limit 1000
+
+static char *version = "unity v0.0, by Michael McGonagle, from ??????, 2003";
+
+t_class *unity_class;
+
+typedef struct unity_struct {
+ t_object x_obj;
+
+ double vars[M_var_count];
+ double vars_init[M_var_count];
+
+ t_outlet *outlets[M_var_count - 1];
+} unity_struct;
+
+static void calc(unity_struct *unity, double *vars) {
+ double k, x_0, y_0;
+ k=(vars[M_x]*vars[M_x])+(vars[M_y]*vars[M_y]);
+ x_0 =(2-k)*vars[M_y];
+ y_0 =(2-k)*vars[M_x];
+ vars[M_x] = x_0;
+ vars[M_y] = y_0;
+} // end calc
+
+static void calculate(unity_struct *unity) {
+ calc(unity, unity -> vars);
+ outlet_float(unity -> x_obj.ob_outlet, unity -> vars[M_x]);
+ outlet_float(unity -> outlets[M_y - 1], unity -> vars[M_y]);
+} // end calculate
+
+static void reset(unity_struct *unity, t_symbol *s, int argc, t_atom *argv) {
+ if (argc == M_var_count) {
+ unity -> vars[M_x] = (double) atom_getfloatarg(M_x, argc, argv);
+ unity -> vars[M_y] = (double) atom_getfloatarg(M_y, argc, argv);
+ } else {
+ unity -> vars[M_x] = unity -> vars_init[M_x];
+ unity -> vars[M_y] = unity -> vars_init[M_y];
+ } // end if
+} // end reset
+
+void *unity_new(t_symbol *s, int argc, t_atom *argv) {
+ unity_struct *unity = (unity_struct *) pd_new(unity_class);
+ if (unity != NULL) {
+ outlet_new(&unity -> x_obj, &s_float);
+ unity -> outlets[0] = outlet_new(&unity -> x_obj, &s_float);
+ if (argc == M_param_count + M_var_count) {
+ unity -> vars_init[M_x] = unity -> vars[M_x] = (double) atom_getfloatarg(0, argc, argv);
+ unity -> vars_init[M_y] = unity -> vars[M_y] = (double) atom_getfloatarg(1, argc, argv);
+ } else {
+ if (argc != 0 && argc != M_param_count + M_var_count) {
+ post("Incorrect number of arguments for unity fractal. Expecting 2 arguments.");
+ }
+ unity -> vars_init[M_x] = 0;
+ unity -> vars_init[M_y] = 0;
+ }
+ }
+ return (void *)unity;
+}
+
+void unity_setup(void) {
+ unity_class = class_new(gensym("unity"), (t_newmethod) unity_new, 0, sizeof(unity_struct), 0, A_GIMME, 0);
+ class_addbang(unity_class, (t_method) calculate);
+ class_addmethod(unity_class, (t_method) reset, gensym("reset"), A_GIMME, 0);
+ class_sethelpsymbol(unity_class, gensym("help-unity.pd"));
+}
+