import java.util.*;

public class Gene extends Object
{
//Gene class generates digital(binary) array to represent a double number
//actual binary defination changes depends on number of bits, xmin and xmax
//binary data stored in b BitSet array	
int N;	//number of binary digits(number of bits in a byte)
double xN;//Limit value for integer(2^N-1)
double xmin,xmax;//maximum and minimum limits of double number
BitSet b; //binary array that strore the integer

public Gene(double ixmin,double ixmax,int iN)
{//randomly generate the gene
 N=iN;
 b=new BitSet(N);
 xN=Math.pow(2.0,N)-1;
 xmin=ixmin;
 xmax=ixmax;
 //generate random numbers to fill binary array
 setbits();	
}

public Gene(String s,double ixmin,double ixmax)
{
//generate gene equal to a given string
 N=s.length();;
 b=new BitSet(N);
 xN=Math.pow(2.0,N)-1;
 xmin=ixmin;
 xmax=ixmax; 
 for(int i=N-1;i>=0;i--)
    if(s.charAt(i)=='1') b.set(N-1-i);
}

public Gene(double number,double ixmin,double ixmax,int iN)
{
//Generate a gene from a given double number	
 N=iN;//number of binary digits(number of bits in a byte)
 b=new BitSet(N);
 xN=StrictMath.pow(2.0,N)-1;
 xmin=ixmin;
 xmax=ixmax;
 //z : integer equivalent of the double number 	
long z=(long)((number-xmin)/(xmax-xmin)*xN);
//System.out.println("inside double"+z);
long y=(long)xN;
double r=z;
for(int i=0;i<N;i++)
   {    	   
   if((z-(z/2)*2)!=0) {b.set(i);}
   z/=2; 
   } 
}  

public Gene()
{
//empty Gene	
N=1;
b=new BitSet(N);
xN=StrictMath.pow(2.0,N)-1;
xmin=0;
xmax=1.0;
b.set(0);
}

public Gene(Gene g)
{
// copy a Gene from another one	
copyGene(g);
}

public void copyGene(Gene g)
{
 N=g.N;
 b=(BitSet)g.b.clone();
 xN=Math.pow(2.0,N)-1;
 xmin=g.xmin;
 xmax=g.xmax;
 
}

public Gene copyGene()
{
 Gene g=new Gene(this);
 return g;
}
	

public Gene(Gene Father,Gene Mother)
{// create gene from two parent genes
 // crossover process
//  Genes from Father and Mother should have the same limit values
xmin=Father.xmin;
xmax=Father.xmax; 
N=Father.N;
xN=Father.xN;
b=new BitSet(N);
int ir1=int_random();
if(Father.b.get(ir1))
{
for(int i=0;i<ir1;i++)
   { if(Father.b.get(i)) b.set(i);}
for(int i=ir1;i<N;i++)
   { if(Mother.b.get(i)) b.set(i);}
}
else
{
for(int i=0;i<ir1;i++)
   { if(Mother.b.get(i)) b.set(i);}
for(int i=ir1;i<N;i++)
   { if(Father.b.get(i)) b.set(i);}
}   
}


public void cross1(double crossratio,Gene Father,Gene Mother)
{// create gene from two parent genes
 // crossover process
//  Genes from Father and Mother should have the same limit values
xmin=Father.xmin;
xmax=Father.xmax; 
N=Father.N;
xN=Father.xN;
b=new BitSet(N);
int ir1=(int)(crossratio*N+0.5);
for(int i=0;i<ir1;i++)
   { if(Father.b.get(i)) b.set(i);}
for(int i=ir1;i<N;i++)
   { if(Mother.b.get(i)) b.set(i);}
}

public void cross2(double crossratio,Gene Father,Gene Mother)
{// create gene from two parent genes
 // crossover process
//  Genes from Father and Mother should have the same limit values
xmin=Father.xmin;
xmax=Father.xmax; 
N=Father.N;
xN=Father.xN;
b=new BitSet(N);
int ir1=(int)(crossratio*N+0.5);
for(int i=0;i<ir1;i++)
   { if(Mother.b.get(i)) b.set(i);}
for(int i=ir1;i<N;i++)
   { if(Father.b.get(i)) b.set(i);}
}


/*
public Gene(Gene Father,Gene Mother)
{
xmin=Father.xmin;
xmax=Father.xmax; 
N=Father.N;
xN=Father.xN;
b=new BitSet(N);
double x1=Father.getX();
double x2=Mother.getX();
double rand=Math.random();
double x=x1*rand+(1.0-rand)*x2;
long z=(long)((x-xmin)/(xmax-xmin)*xN);
//System.out.println("inside double"+z);
long y=(long)xN;
double r=z;
for(int i=0;i<N;i++)
   {    	   
   if((z-(z/2)*2)!=0) {b.set(i);}
   z/=2; 
   } 
}
*/

public long getXP()
{
//returns intermediate integer of double number equivalent	
long y=1;
double r=xN;
long z=0;
for(int i=0;i<N;i++)
   {
   if(b.get(i)) {z+=y;}
   y*=2; 
   }
 //System.out.println("z="+z);  
 return z;  
}  

public double getX()
{//return double number equivalent of bit set number   
 return (xmin+(xmax-xmin)/xN*getXP());  
}
  
public void clear()
{//fill the entire population with zero
b.clear(0,N);}

public void fill()
{//fill the entire population with ones
b.clear(0,N);b.flip(0,N);}

public String toBitSetString()
{//return bit set array values as defined in class BitSet 
return b.toString();
}

public String toString()
{
// return bit set array values as a binary number definition 
// plus double value of array	
 String s="(";	
 for(int i=N-1;i>=0;i--)
    if(b.get(i)) s+="1";
    else         s+="0";
    s+=") "+getX();
  return s;   	
 //return b.toString();
}

public boolean boolean_random()
{
if((int)(Math.round(Math.random()+0.01))==0) return false;
else     return true;
}

public int int_random()
{
  return (int)(Math.random()*N+1.0);
}

public double double_random()
{
  return (xmin+Math.random()*(xmax-xmin));
}

public void setbits()
{
for(int i=0;i<N;i++)
   {
   if(boolean_random()) b.set(i);
   }
}

public void flip(int i)
{
b.flip(i);
}

public void mutate()
{ 
  //fip one bit of data	
  int i1=int_random();
  b.flip(i1);  
}


}