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