import ChaosDemos.*;
import java.awt.*;
import java.util.*;
import java.net.URL;
import graph.*;
/**
* Iterates and plots various 2D maps
* Uses the "Java Graph Class Library" by Leigh Brookshaw
* @version 3 August, 1997
* @author Michael Cross
*/
public class Map2D extends dynamicGraph {
/** number of curves */
private int ncurve=-1;
/** index of first data curve */
private int ncurve1;
/** number of iterations to eliminate transient */
private int ntrans =10;
/** accumulated number of iterations */
private int iterations;
/** accumulated number of points plotted */
private int plotted;
/** number of iterations to do before plotting */
private int jump=1;
/** function chosen: 0=HENON 1=CIRCLE 2=DUFFING 3=BAKERS 4=YORKE 5=STANDARD
6=GOY 7=SINAI 8=MYFUNCTION */
private int function=0;
/** Number of subdivisions for box counting */
private int nDiv=4;
/** box size in dimesnion algorithm */
private double boxSize;
/** number of boxes across each dimension */
private int nBoxes;
/** nuber of subdivisions of boxes done */
private int divided=-1;
/** number of variabels controlled by sliders */
private int numSliders;
/** number of data points accumulated in plotData */
private int nData=0;
/** Order of dimension calculation */
private int q;
/** Index for variable plotted on x-axis */
private int index0;
/** Index for variable plotted on y-axis */
private int index1;
/** true if box-counting thread running */
private boolean running=false;
/** true after first mouse click */
private boolean clicked=false;
/** true if boxes should be painted on graph */
private boolean paintBoxes=false;
/** true on new run */
private boolean newRun;
/** true for return map */
private boolean returnMap;
/** true to calculate Lyapunov exponents */
private boolean lyapunov=false;
/** iteration variable */
private double[] x={0.,0.,0.,0.};
/** tangent vectors */
private double[] t1={1,0};
private double[] t2={0,1};
/** Cumulative Lyapunov totals */
private double[] cum={0,0};
/** mouse position */
private double[] xmouse={0.,0.};
/** map parameter */
private double a;
/** map parameter */
private double b;
/** map parameter */
private double c;
/** plot ranges */
private double xRange,yRange;
/** reciprocal of plot ranges */
private double xReduce,yReduce;
/** map parameters a,b,c */
private double[] params={1.4,0.3,0.};
/** starting value of x */
private double[] x0={0.,0.};
/** bottom-left corner */
private double[] cmin={-1.,-1.};
/** top-right corner */
private double[] cmax={1.,1.};
/** size of marker to be plotted */
private double marker=0.5;
/** data for pltting */
private double[] plotData;
/** axis labesl */
private String[] axisLabel={" X "," Y "};
/** GUI elements */
private textControls variables;
private sliderControls parameters;
private buttonControls buttons;
private Button dimButton;
private Choice functionChoice;
private CheckboxGroup cbg ;
private Checkbox cbYes;
private Checkbox cbNo ;
private CheckboxGroup mapCbg ;
private Checkbox cb2d;
private Checkbox cb1x;
private Checkbox cb1y;
private Checkbox cbl;
/** classes used */
private boxCalculate myBox;
private superGraph2D graph;
private movie theMovie;
private linearFitPlot win=null;
private Map2DFunction mapFunction;
/** parent */
private startMap2D outerparent;
/** animation thread */
private Thread aThread=null;
/** box counting thread */
private Thread bThread=null;
/** for location of marker.txt */
private URL markerURL;
/** location of marker.txt */
URL documentBase;
/** functions */
private static final int HENON=0;
private static final int CIRCLE=1;
private static final int DUFFING=2;
private static final int BAKERS=3;
private static final int YORKE=4;
private static final int STANDARD=5;
private static final int GOY=6;
private static final int SINAI=7;
private static final int MYFUNCTION=8;
/* log e -> log 10 */
private static final double le=0.43429;
/* log e -> log 2 */
private static final double l2=1.4427;
/** maximum number of points to be appended to plot */
private static int MAX_APPEND=1024;
/** maximum number of attempts to find good initial condition */
private static int MAX_TRY=1024;
/** value for testing divergence of iteration */
private static double MAX_VALUE = 100.;
/* arrays for setting parameters based on function choice */
int nParameters;
/**
* @param target starting class
* @see startMap2D
*/
public Map2D(startMap2D target, URL in_documentBase) {
documentBase=in_documentBase;
graph = new superGraph2D(this);
/*
** Load a file containing Marker definitions
*/
try {
markerURL = new URL(documentBase,"marker.txt");
graph.setMarkers(new Markers(markerURL));
} catch(Exception e) {
System.out.println("Failed to create Marker URL!");
}
theMovie = new movie(this);
this.outerparent = target;
addNotify();
setBackground(Color.lightGray);
GridBagLayout gridbag = new GridBagLayout();
GridBagConstraints constraints = new GridBagConstraints();
constraints.fill=GridBagConstraints.BOTH;
setLayout(gridbag);
graph.borderRight=35;
graph.borderTop=80; // MCC 8-10
Panel leftPanel = new Panel();
leftPanel.setLayout(new BorderLayout());
constraints.gridheight = 1;
constraints.gridwidth=1;
constraints.weightx=0.75;
constraints.weighty = 1.0;
constraints.insets = new Insets(10,0,10,0);
gridbag.setConstraints(leftPanel, constraints);
add(leftPanel);
leftPanel.add("Center",graph);
Panel bottomLeftPanel = new Panel();
bottomLeftPanel.setLayout( new GridLayout(2,1));
bottomLeftPanel.add(theMovie);
theMovie.borderBottom=0;
String[] buttonLabels={" Reset "," Clear ",
" Start "," Stop "};
buttons = new buttonControls((dynamicGraph) this,
buttonLabels,buttonLabels.length, true);
buttons.b_init[0] = true;
buttons.b_stopped[3] = false;
buttons.b_started[1] = true;
buttons.b_started[3] = true;
buttons.setup();
bottomLeftPanel.add(buttons);
leftPanel.add("South",bottomLeftPanel);
Panel rightPanel = new Panel();
rightPanel.setLayout(new BorderLayout());
Panel topRightPanel = new Panel();
topRightPanel.setLayout(gridbag);
rightPanel.add("Center",topRightPanel);
numSliders = params.length;
String[] textboxes = new String[numSliders];
for (int i=0;i0) {
for(int i=0;i xmouse[0]) {
variables.setText(0,String.valueOf(xmouse[0]));
variables.setText(2,String.valueOf(xcoord));
}
else if(xcoord < xmouse[0]) {
variables.setText(2,String.valueOf(xmouse[0]));
variables.setText(0,String.valueOf(xcoord));
}
if(ycoord > xmouse[1]) {
variables.setText(1,String.valueOf(xmouse[1]));
variables.setText(3,String.valueOf(ycoord));
}
else if (ycoord < xmouse[1]){
variables.setText(3,String.valueOf(xmouse[1]));
variables.setText(1,String.valueOf(ycoord));
}
// updateParameters();
updateVariables();
if(randomInitialCondition()) {
restart();
buttons.enableGo();
}
}
// if(checkBounds(x) > -1)
// restart();
// else iterationBox.setText("Invalid i.c.!");
}
else {
if(aThread==null) {
clicked=false;
function=functionChoice.getSelectedIndex();
setAxesDefaults();
updateParameters();
updateVariables();
if(randomInitialCondition()) {
restart();
buttons.enableGo();
}
}
}
}
//**********************************************************************
public Insets insets() {
return new Insets(10,0,20,10);
}
//************************************************************************
/**
* Stop movie thread
*/
//************************************************************************
public void movieStop() {
if(aThread!=null) {
theMovie.stopIterate();
// aThread.stop();
aThread=null;
}
}
//************************************************************************
/**
* Start movie thread
*/
//************************************************************************
public void movieStart() {
if(aThread==null) {
aThread = new Thread(theMovie);
// aThread.setPriority(Thread.MIN_PRIORITY);
aThread.start();
}
}
//************************************************************************
/**
* Event handler:
* Stops iteration on minimising and handles close window event
* (May fail under Windows95)
*/
//************************************************************************
public boolean handleEvent(Event evt) {
switch (evt.id) {
case Event.WINDOW_DESTROY:
movieStop();
if(win!=null) win.dispose();
outerparent.hideWindow();
return super.handleEvent(evt);
case Event.WINDOW_ICONIFY:
movieStop();
buttons.enableGo();
enableAll();
return super.handleEvent(evt);
case Event.ACTION_EVENT:
if(evt.target == functionChoice) {
function = functionChoice.getSelectedIndex();
setDefaults();
updateParameters();
updateVariables();
if(randomInitialCondition()) restart();
return super.handleEvent(evt);
}
else if( evt.target==cb2d || evt.target==cb1x || evt.target==cb1y
|| evt.target==cbl) {
setAxesDefaults();
updateVariables();
if(randomInitialCondition()) restart();
return super.handleEvent(evt);
}
// if (randomInitialCondition()) {
// restart();
// buttons.enableGo();
// }
// if(evt.target == xFunctionBox || evt.target == yFunctionBox) {
// updateParameters();
// updateVariables();
// }
else if(evt.target == dimButton) {
if(divided<0 ) {
nDiv = myBox.getNDiv();
q=myBox.getQ();
plotData = new double[2*nDiv];
nData=0;
running=true;
int np=graph.nPoints(ncurve1);
myBox.setText("Finding dimension for "+np+" points");
double[] xdata=graph.getData(ncurve1,np);
int ixdata[]= new int[2*np];
nBoxes=(int) (Math.pow(2.,(double)nDiv));
for(int i=0;i<2*np;i++) {
ixdata[i]=(int) (nBoxes*xdata[i]);
}
buttons.disableAll();
dimButton.enable();
disableAll();
myBox.setup(ixdata);
// myBox.setQ(q);
if(bThread!=null) {
// bThread.stop();
myBox.stopRequest();
bThread=null;
}
bThread = new Thread(myBox);
bThread.start();
boxSize=1.0;
nBoxes=1;
divided++;
dimButton.setLabel("Continue");
myBox.textBoxDisable();
}
else if(divided < nDiv) {
if(bThread.isAlive()) {
myBox.setText("Push Stop to end calculation");
}
else {
if(!myBox.completed) {
myBox.stopRequest();
dimButton.disable();
myBox.setText("");
buttons.enableGo();
enableAll();
paintBoxes=false;
graph.repaint();
divided=-1;
running=false;
}
else{
dimButton.disable();
divided++;
boxSize=boxSize/2.;
nBoxes=nBoxes*2;
calculateDimensionPoint();
// dimButton.enable();
if(divided0) {
win = new linearFitPlot(plotData, documentBase);
win.setTitle("Dimension Plot");
win.setShowIntercept(false);
if(q==0)
win.setAxisStrings("log(1/box size)","log(number of boxes)");
else if(q==1)
win.setAxisStrings("log(1/box size)","Information");
else if(q==2)
win.setAxisStrings("log(1/box size)","-log(P{^"+q+"})");
else
win.setAxisStrings("log(1/box size)","-log(P{^"+q+"})/"+(q-1));
win.setSlopeString("Dimension=");
win.resize(400,400);
win.show();
dimButton.enable();
}
else myBox.setText("No points to plot");
dimButton.setLabel("Dimension");
myBox.textBoxEnable();
dimButton.enable();
myBox.setText("");
buttons.enableGo();
enableAll();
paintBoxes=false;
graph.repaint();
divided=-1;
running=false;
}
return super.handleEvent(evt);
}
default:
return super.handleEvent(evt);
}
}
//************************************************************************
/**
* Disables text input in variables
*/
//************************************************************************
public void disableAll() {
int i;
for(i=0;i=0) ncurve = graph.deleteAllCurves();
clicked=false;
newRun=true;
if(cb2d.getState() || cbl.getState() ) {
returnMap=false;
index0=0;
index1=1;
}
else {
returnMap=true;
if(cb1x.getState()) {
index0=2;
index1=0;
}
else if(cb1y.getState()) {
index0=3;
index1=1;
}
}
if(cbl.getState() ) {
lyapunov=true;
cum[0]=0;
cum[1]=0;
}
else lyapunov=false;
iterations=0;
plotted=0;
mapFunction.winding=0;
mapFunction.total=0;
divided=-1;
paintBoxes=false;
data1[0]=0;
data1[1]=0;
data1[2]=1;
data1[3]=1;
ncurve = graph.addCurve(data1,2,Color.lightGray,0,7,0.5);
data2[0]=(x[index0]-cmin[0])*xReduce;
data2[1]=(x[index1]-cmin[1])*yReduce;
if(marker<=0.01){
markerType=7;
markerScale=1.;
}
else {
markerType=1;
markerScale=marker;
}
ncurve = graph.addCurve(data2,1,Color.blue,0,markerType,markerScale);
ncurve1=ncurve;
// graph.clearAll= false ;
graph.paintAll=true;
graph.repaint();
// iterations=0;
myBox.setText("");
}
//*********************************************************************
/**
* Iterates map and updates graph
*/
//*********************************************************************
public boolean iterate() {
int inBounds;
int i,n,nplot;
double[] moredata = new double[2*jump];
n=0;
nplot=0;
for(i=0; i<2*jump; i=i+2) {
if(lyapunov) {
mapFunction.iterateTangent(x,t1);
mapFunction.iterateTangent(x,t2);
renormalize(t1,t2,cum);
iterations++;
}
mapFunction.iterate(x);
inBounds = checkBounds(x);
if(inBounds == 1) {
moredata[nplot++]=(x[index0]-cmin[0])*xReduce;
moredata[nplot++]=(x[index1]-cmin[1])*yReduce;
n=n+1;
}
else if (inBounds == -1) {
alertDialog alert = new alertDialog(this, "Value diverged: stop and restart");
return false;
}
if(n > MAX_APPEND) break;
}
if(n==0) return true;
graph.paintAll=false; // Don't paint while updating data
// if(graph.nPoints(ncurve)>200) {
// graph.deleteFromCurve(100,ncurve);
// }
graph.appendToCurve(moredata,n,ncurve1);
graph.paintAll=true;
graph.clearAll=false;
graph.repaint();
plotted=plotted+n;
if(theMovie.iterate) {
if(mapFunction.showWinding && plotted > 0)
myBox.setText("Winding number "+
String.valueOf((float) mapFunction.winding/(float) mapFunction.total));
else
myBox.setText("Iteration number "+String.valueOf(plotted));
}
if (checkBounds(x) <0 ) {
return false;
}
else
return true;
}
//**********************************************************************
/**
* Stop thread and close fit window
*/
//**********************************************************************
public void stop() {
movieStop();
if(win!=null) win.dispose();
enableAll();
buttons.enableGo();
}
//**********************************************************************
/**
* Respond to buttonControls
* @see buttonControls
* @param buttonIndex index of button pushed
*/
//**********************************************************************
public void respondToButtons(int buttonIndex) {
if(buttonIndex==0) {
// setDefaults();
updateParameters();
updateVariables();
if(randomInitialCondition()) {
restart();
buttons.enableGo();
}
}
else if(buttonIndex==1) {
/* updateParameters();
updateVariables();
if(randomInitialCondition()) {
restart();
buttons.enableGo();
} */
graph.clearAll=false; //6/27/96
if(aThread != null) {
movieStop();
if(initialCondition(x)) {
restart();
newRun=false;
movieStart();
}
}
else {
// updateParameters();
updateVariables();
boolean dummy=randomInitialCondition();
restart();
}
}
else if(buttonIndex==2) {
if(clicked) {
clicked=false;
x[0]=xmouse[0];
x[1]=xmouse[1];
x[2]=x[0];
x[3]=x[1];
if (!initialCondition(x)) return;
}
else {
if(!newRun) {
if (!randomInitialCondition()) return;
}
else newRun=false;
}
buttons.disableGo();
disableAll();
mapFunction.windingAdd=1;
graph.allowDrag=false;
movieStart();
}
else if(buttonIndex==3) {
mapFunction.windingAdd=0;
buttons.enableGo();
movieStop();
graph.allowDrag=true;
enableAll();
dimButton.enable();
if(lyapunov && iterations > 0) {
myBox.setText("Exp: "+(float)(cum[0]/((double) iterations))+", "+
(float)(cum[1]/((double) iterations)));
}
}
}
//*********************************************
/**
* Checks that x is within bounds cmin, cmax
* @param input value
* @return -1 if "diverges" set by MAX_VALUE, 0 if within bounds,
* 1 if outside bounds
*/
//*********************************************
private int checkBounds(double[] x) {
if(Math.abs(x[index0]) > MAX_VALUE || Math.abs(x[index1]) > MAX_VALUE) {
return -1;
}
if(x[index0] < cmin[0] || x[index0] > cmax[0] ||
x[index1] < cmin[1] || x[index1] > cmax[1])
return 0;
else return 1;
}
//**********************************************************************
/**
* Picks random intial condition, eliminates transient and test for
* divergences. Returns true if valid, false if cannot find a valid i.c.
* in MAX_TRY attempts.
* @return true if valid starting point found
*/
//**********************************************************************
private boolean randomInitialCondition() {
boolean diverged=true;
double cump[] = new double[2];
int nTry=0;
while(diverged && nTry < MAX_TRY) {
nTry++;
diverged = false;
x[0]=cmin[0]+Math.random()*(cmax[0]-cmin[0]);
x[1]=cmin[1]+Math.random()*(cmax[1]-cmin[1]);
if(lyapunov) {
t1[0]=Math.random();
t1[1]=Math.sqrt(1-t1[0]*t1[0]);
t2[0]=-t1[1];
t2[1]=t1[0];
cump[0]=0;
cump[1]=0;
// iterations=0;
}
if(ntrans>0) {
for(int i=0;i0) {
for(int i=0;i1) {
parameters.enable(1);
parameters.setText(1,String.valueOf(mapFunction.aDefault[1]));
}
else {
parameters.setText(1,"");
parameters.disable(1);
}
if(nParameters>2) {
parameters.enable(2);
parameters.setText(2,String.valueOf(mapFunction.aDefault[2]));
}
else {
parameters.setText(2,"");
parameters.disable(2);
}
}
//**********************************************************************
/**
* Adds boxes to graph
* @param g Graphics context
* @param r data rectangle of graph
*/
//**********************************************************************
public void addToGraph( Graphics g, Rectangle r) {
double xBoxSize, yBoxSize;
if (paintBoxes) {
g.setColor(Color.red);
int start = 2*myBox.divIndex[divided];
int end = 2*myBox.divIndex[divided-1];
xBoxSize = r.width*boxSize;
yBoxSize = r.height*boxSize;
if(cbYes.getState())
for (int i=start;i< end;i=i+2)
g.drawRect(r.x+(int)(xBoxSize*myBox.output[i]),
r.y+r.height-(int) (yBoxSize*(myBox.output[i+1]+1)),
(int)xBoxSize,(int)yBoxSize);
// myBox.setText((end-start)/2+" boxes size "+(float)boxSize);
}
}
//**********************************************************************
/**
* Sets axes defaults based on type of plot
*/
//**********************************************************************
public void setAxesDefaults() {
if( cb2d.getState() || cbl.getState() ) {
variables.setText(0,String.valueOf(mapFunction.xminDefault));
variables.setText(1,String.valueOf(mapFunction.yminDefault));
variables.setText(2,String.valueOf(mapFunction.xmaxDefault));
variables.setText(3,String.valueOf(mapFunction.ymaxDefault));
graph.setXAxisTitle("X");
graph.setYAxisTitle("Y");
}
else if(cb1x.getState()) {
variables.setText(0,String.valueOf(mapFunction.xminDefault));
variables.setText(1,String.valueOf(mapFunction.xminDefault));
variables.setText(2,String.valueOf(mapFunction.xmaxDefault));
variables.setText(3,String.valueOf(mapFunction.xmaxDefault));
graph.setXAxisTitle("X_n");
graph.setYAxisTitle("X_n+1");
}
else if(cb1y.getState()) {
variables.setText(0,String.valueOf(mapFunction.yminDefault));
variables.setText(1,String.valueOf(mapFunction.yminDefault));
variables.setText(2,String.valueOf(mapFunction.ymaxDefault));
variables.setText(3,String.valueOf(mapFunction.ymaxDefault));
graph.setXAxisTitle("Y_n");
graph.setYAxisTitle("Y_n+1");
}
}
//**********************************************************************
/**
* Performs Gramm-Schmidt orthogonalization and calculates increase in norm of
* the vectors
* @param t1 Tangent vector of larger eigenvalue
* @param t2 Tangent vector of smaller eigenvalue
* @param c cumulated log of growth of vector norms
*/
//**********************************************************************
private void renormalize(double[] t1, double[] t2, double[] c) {
double norm1, norm2, dot;
norm1=Math.sqrt(t1[0]*t1[0]+t1[1]*t1[1]);
t1[0]=t1[0]/norm1;
t1[1]=t1[1]/norm1;
dot=t2[0]*t1[0]+t2[1]*t1[1];
t2[0]=t2[0]-dot*t1[0];
t2[1]=t2[1]-dot*t1[1];
norm2=Math.sqrt(t2[0]*t2[0]+t2[1]*t2[1]);
t2[0]=t2[0]/norm2;
t2[1]=t2[1]/norm2;
c[0]=c[0]+Math.log(norm1);
c[1]=c[1]+Math.log(norm2);
}
//**********************************************************************
/**
* Calculates point for generalized dimension plot
*/
//**********************************************************************
private void calculateDimensionPoint() {
int range= (myBox.divIndex[divided-1]-myBox.divIndex[divided]);
if(range>0) {
plotData[nData++]=l2*Math.log((double)nBoxes);
if(q==0) {
plotData[nData++]=l2*Math.log((double)range);
myBox.setText(range+" boxes size "+(float)boxSize);
}
else if(q==1) {
double probability=0;
for(int i=myBox.divIndex[divided];i