import ChaosDemos.*;
import java.awt.*;
import java.util.*;

//********************************************************************
/**                    
* Diagnostics for Map1D <br>
* Plots the "bifurcation diagram" i.e. the values of x in the attractor
* for different values of the map parameter a.<br>
* Portions of the plot can be enlarged by outlining with a mouse drag.
* Points on the running plot can be read out with a mouse click.
* @version 10 October 1997
* @author Michael Cross
*/
//********************************************************************     

public class Map1DLyapunov extends Map1DDiagnostics {
 
/** maximum number of attempts to iterate from initial condition to fond point */       
      private static int MAX_TRY=1024;                             
/** cumulative slope */
      double slope;
/** number of points for averaging Lyapunov exponent */
      private int dataLength ;      
/** Minimum value of a in scan */      
      private double amin;
/** Maximum value of a in scan */      
      private double amax;         
/** increment of a */
      private double dela;   
/** true if axes range contains first point **/
      private boolean validRange;
      private static final double FLOOR=.0000454;
      private double yScaleMin=Math.log(FLOOR); 
      private double yScaleMax=-0.5*yScaleMin;                      
          

//******************************************************************
/**
* @param inParent parent class
* @see Map1D
*/
//******************************************************************
      public Map1DLyapunov(Map1D inParent) {
            super(inParent);
            hideab=true;                                                                                          
      }
      
//********************************************************************
/**
* Updates parameters from the text controls in parent class 
*/ 
//********************************************************************
      public void updateParameters() {
            int i;           

          if(parent.mapFunction.enforceBRange) {
                double bMaxLimit=parent.mapFunction.bMaximum;
                double bMinLimit=parent.mapFunction.bMinimum;
                b=parent.variables.parseTextField(1, 0.5*(bMinLimit+bMaxLimit),
                            bMinLimit, bMaxLimit);
          }                  
          else  b=parent.variables.parseTextField(1, b);
          aMaxLimit=parent.mapFunction.getAMaximum(b);             
          aMinLimit=parent.mapFunction.getAMinimum(b);
          if(parent.mapFunction.enforceARange) {
            amin=parent.variables.parseTextField(5, aMinLimit, aMinLimit, aMaxLimit);
            amax=parent.variables.parseTextField(6, aMaxLimit, aMinLimit, aMaxLimit);
          }  
          else {
            amin=parent.variables.parseTextField(5, amin);
            amax=parent.variables.parseTextField(6, amax);
          }  

          if(!setAxesRange) {                               
                xmin=amin;
                xmax=amax;
                ymin=yScaleMin;
                ymax=yScaleMax;
          }      

          dataLength=parent.variables.parseTextField(4,256,true);          
          a=xmin;
          slope=0.;
          nParameters=parent.nParameters;
          parameters = new double[nParameters];
          parameters[0]=a;
          if(nParameters>1) parameters[1]=parent.parameters[1];
          parent.mapFunction.setParameters(parameters);                                   

          x=Math.random();
          ntrans=parent.variables.parseTextField(3,ntrans);
          if(ntrans>0) runTrans=true;                                                

          nf=parent.variables.parseTextField(2,nf,true);
          parent.mapFunction.setCompose(nf);                             
      }      
                
//*********************************************************************
/**
* Restarts
*/
//*********************************************************************
      
      public void restart() {

            double data1[] = new double[4];
            int i,j;

            double f;
            int ip=0;
            
            a=xmin;
            parameters[0]=xmin;
            parent.mapFunction.setParameters(parameters);              
            
            // Reset graph
            ncurve=parent.resetGraph();
                        
           data1[0]=xmin;
           data1[1]=ymin;
           data1[2]=xmax;
           data1[3]=ymax; 

           ncurve = parent.graph.addCurve(data1,2,Color.black,0,7,1.); 
           if(ymin<0. && ymax >0.)  {
                  data1[1]=0.;
                  data1[3]=0.;
                  ncurve = parent.graph.addCurve(data1,2,Color.black); 
           } 
           dela=(xmax-xmin)/256.;     
           boolean foundInitialPoint=false;
           while(a<xmax && !foundInitialPoint) {
                 x=Math.random();
                 // Eliminate transient
                 if(runTrans) {
                     for(i=0;i<ntrans;i++) 
                         x=parent.mapFunction.iterate(x);                         
                 }
                      
                 slope=0.;
                 for(i=0,j=0;i<dataLength;i++) {
                       x=parent.mapFunction.evaluateSlope(x);
                       slope+=Math.log(Math.abs(parent.mapFunction.slope)+FLOOR);  
                 }                 
                 data1[0]=a;
                 data1[1]=slope/dataLength;
                 if(data1[1] >= ymin && data1[1] <= ymax) {
                        ncurve = parent.graph.addCurve(data1,1,Color.red,0,7,1.);
                        ncurve1=ncurve;
                        foundInitialPoint=true;
                 }
                 else a=a+dela;
           }  
           if(!foundInitialPoint) {
                  alertDialog alert = new alertDialog
                  (parent,"No points found in plot region: please reset");
           }           
           iterations=0;
           parent.graph.paintAll=true;
           parent.graph.clearAll=true;
           parent.graph.repaint();        
            if(parent.showTime) parent.status.setText("No. of Iterations "+ iterations);            
      }

//*********************************************************************
/**
* Iterates Map equations and updates graph
*/
//*********************************************************************      
      public boolean iterate() {
            int i,j;
            double[] moredata = new double[6];
            slope=0.;
            for(i=0,j=0;i<dataLength;i++) {
                  x=parent.mapFunction.evaluateSlope(x);
                  slope+=Math.log(Math.abs(parent.mapFunction.slope)+FLOOR);  
            }
            moredata[0]=a;
            moredata[1]=slope/dataLength;
            if(checkRange(a, moredata[1])) {
                  parent.graph.clearAll=false;                         
                  parent.graph.paintAll=false;     
                  parent.graph.appendToCurve(moredata,1,ncurve1);
                  parent.graph.paintAll=true;                        
                  parent.graph.repaint();
            }                                          
            a=a+dela;
            if(a>xmax) a=xmin+Math.random()*dela;
            parameters[0]=a;
            parent.mapFunction.setParameters(parameters);
            x=Math.random();
            if (runTrans) for(i=0;i<ntrans;i++) x=parent.mapFunction.iterate(x);            
            return true;
      }
      
//**********************************************************************
/**
* Sets default values of parameters
*/
//**********************************************************************          
      public void setPlotDefaults() {
               String[] label={"Transient","Points","  a_min  ","  a_max  "};
               String[] text={"256","256",String.valueOf(parent.mapFunction.aMinimum),
                            String.valueOf(parent.mapFunction.aMaximum)};
               parent.setPlotTextBoxes(label,text);                               
               parent.choices.setState(0,false);
               parent.showTime=false;
               parent.status.setText("");
               parent.choices.disable(0);  
      }                 
            
           
//**********************************************************************
/**
* Checks if point within plot range
* @param x x-coordinate of point
* @param y y-coordinate of point
* @return true if within range
*/
//**********************************************************************              
      private boolean checkRange(double x,double y) {
            if(x>=xmin && x<=xmax && y>=ymin && y<=ymax) return true;
            else return false;
      }
      
//**********************************************************************
/**
* Resets x-range to 0 < x < 1
*/
//**********************************************************************            
      public void resetRange() {
            xmin=amin;
            xmax=amax;
            ymin=yScaleMin;
            ymax=yScaleMax;
            setAxesRange=false;
      } 
      
//**********************************************************************                     
}      
