// Dr. M. Turhan ÇOBAN
// EGE University School of Engineering, Mechanical Engineering Department
// package : Numerical analysis package
// subject : optimization
// group   : Genetic Algorithms 
// Gene Class
// 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	

import java.util.*;
import java.io.*;

public class Gene extends Object
{

int N;	//number of binary digits(number of bits in a byte)
         //N should be less than 64
double xN;//Limit value for integer(2^N-1)
double xmin,xmax;//maximum and minimum limits of double number
BitSet b; //binary array that stored the integer

public Gene(double ixmin,double ixmax,int iN)
{//randomly generate the gene
 N=iN;
 if(N>63) N=63; 
 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(double ixmin,double ixmax)
{//randomly generate the gene
 N=63;
 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)
 if(N>63) N=63;
 b=new BitSet(N);
 xN=1;
 for(int i=1;i<=N;i++) {xN*=2;}
 xN-=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=1;
 for(int i=1;i<=N;i++) {xN*=2;}
 xN-=1;
//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=1;
 for(int i=1;i<=N;i++) {xN*=2;}
 xN-=1;
 //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)
{setGene(Father,Mother,"double");}

public void  setGene(Gene Father,Gene Mother)
{setGene(Father,Mother,"double");}
	
public void  setGene(Gene Father,Gene Mother,String crossovertype)
{
xmin=Father.xmin;
xmax=Father.xmax; 
N=Father.N;
xN=Father.xN;
b=new BitSet(N);
int ir1,ir2,ir3;
if(crossovertype.equals("regular"))
{
for(int i=0;i<N;i++)
   {if(boolean_random()) { if(Father.b.get(i)) b.set(i);} 
    else { if(Mother.b.get(i)) b.set(i);}
   }
}
else if(crossovertype.equals("single"))
{
    ir1=int_random();
    if(boolean_random())
    {   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);}
    }
}
else if(crossovertype.equals("double"))
{
    ir1=int_random();
    ir2=int_random();
    int ix;
    if(ir1>ir2) {ix=ir2;ir2=ir1;ir1=ix;}
    if(boolean_random())
    {   for(int i=0;i<ir1;i++)
          { if(Father.b.get(i)) b.set(i);}
        for(int i=ir1;i<ir2;i++)
          { if(Mother.b.get(i)) b.set(i);}
        for(int i=ir2;i<N;i++)
          { if(Father.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<ir2;i++)
          { if(Father.b.get(i)) b.set(i);}
        for(int i=ir2;i<N;i++)
          { if(Mother.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 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; 
   }
 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;   	
}

public boolean boolean_random()
{
if(Math.random()<=0.5) return false;
else return true;
}

public int int_random()
{
  int x1=(int)(Math.random()*N);
  return x1;
}

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

public void setbits()
{
b.clear();
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();
  if(i1<0) i1=0;
  b.flip(i1);  
}
}