ec.vector.BitVectorIndividual Maven / Gradle / Ivy
Show all versions of ecj Show documentation
/*
Copyright 2006 by Sean Luke
Licensed under the Academic Free License version 3.0
See the file "LICENSE" for more information
*/
package ec.vector;
import ec.*;
import ec.util.*;
import java.io.*;
import java.util.*;
/*
* BitVectorIndividual.java
* Created: Tue Mar 13 15:03:12 EST 2001
*/
/**
* BitVectorIndividual is a VectorIndividual whose genome is an array of booleans.
* The default mutation method simply flips bits with mutationProbability.
*
* From ec.Individual:
*
*
In addition to serialization for checkpointing, Individuals may read and write themselves to streams in three ways.
*
*
* - writeIndividual(...,DataOutput)/readIndividual(...,DataInput) This method
* transmits or receives an individual in binary. It is the most efficient approach to sending
* individuals over networks, etc. These methods write the evaluated flag and the fitness, then
* call readGenotype/writeGenotype, which you must implement to write those parts of your
* Individual special to your functions-- the default versions of readGenotype/writeGenotype throw errors.
* You don't need to implement them if you don't plan on using read/writeIndividual.
*
*
- printIndividual(...,PrintWriter)/readIndividual(...,LineNumberReader) This
* approach transmits or receives an indivdual in text encoded such that the individual is largely readable
* by humans but can be read back in 100% by ECJ as well. To do this, these methods will encode numbers
* using the ec.util.Code class. These methods are mostly used to write out populations to
* files for inspection, slight modification, then reading back in later on. readIndividual reads
* in the fitness and the evaluation flag, then calls parseGenotype to read in the remaining individual.
* You are responsible for implementing parseGenotype: the Code class is there to help you.
* printIndividual writes out the fitness and evaluation flag, then calls genotypeToString
* and printlns the resultant string. You are responsible for implementing the genotypeToString method in such
* a way that parseGenotype can read back in the individual println'd with genotypeToString. The default form
* of genotypeToString simply calls toString, which you may override instead if you like. The default
* form of parseGenotype throws an error. You are not required to implement these methods, but without
* them you will not be able to write individuals to files in a simultaneously computer- and human-readable fashion.
*
*
- printIndividualForHumans(...,PrintWriter) This
* approach prints an individual in a fashion intended for human consumption only.
* printIndividualForHumans writes out the fitness and evaluation flag, then calls genotypeToStringForHumans
* and printlns the resultant string. You are responsible for implementing the genotypeToStringForHumans method.
* The default form of genotypeToStringForHumans simply calls toString, which you may override instead if you like
* (though note that genotypeToString's default also calls toString). You should handle one of these methods properly
* to ensure individuals can be printed by ECJ.
*
* In general, the various readers and writers do three things: they tell the Fitness to read/write itself,
* they read/write the evaluated flag, and they read/write the gene array. If you add instance variables to
* a VectorIndividual or subclass, you'll need to read/write those variables as well.
Default Base
vector.bit-vect-ind
* @author Sean Luke
* @version 1.0
*/
public class BitVectorIndividual extends VectorIndividual
{
public static final String P_BITVECTORINDIVIDUAL = "bit-vect-ind";
public boolean[] genome;
public Parameter defaultBase()
{
return VectorDefaults.base().push(P_BITVECTORINDIVIDUAL);
}
public Object clone()
{
BitVectorIndividual myobj = (BitVectorIndividual) (super.clone());
// must clone the genome
myobj.genome = (boolean[])(genome.clone());
return myobj;
}
public void setup(final EvolutionState state, final Parameter base)
{
super.setup(state,base); // actually unnecessary (Individual.setup() is empty)
BitVectorSpecies s = (BitVectorSpecies)species; // where my default info is stored
genome = new boolean[s.genomeSize];
}
public void defaultCrossover(EvolutionState state, int thread, VectorIndividual ind)
{
BitVectorSpecies s = (BitVectorSpecies)species; // where my default info is stored
BitVectorIndividual i = (BitVectorIndividual) ind;
boolean tmp;
int point;
int len = Math.min(genome.length, i.genome.length);
if (len != genome.length || len != i.genome.length)
state.output.warnOnce("Genome lengths are not the same. Vector crossover will only be done in overlapping region.");
switch(s.crossoverType)
{
case VectorSpecies.C_ONE_POINT:
// point = state.random[thread].nextInt((len / s.chunksize)+1);
// we want to go from 0 ... len-1
// so that there is only ONE case of NO-OP crossover, not TWO
point = state.random[thread].nextInt((len / s.chunksize));
for(int x=0;x point) { int p = point0; point0 = point; point = p; }
for(int x=point0*s.chunksize;x point) { int p = point0; point0 = point; point = p; }
for(int x=point0*s.chunksize;x=pieces.length-2)
point1 = genome.length;
else point1 = points[x+1];
}
}
/** Joins the n pieces and sets the genome to their concatenation.*/
public void join(Object[] pieces)
{
int sum=0;
for(int x=0;x>> 31 ) ^ Arrays.hashCode(genome);
return hash;
}
public String genotypeToStringForHumans()
{
StringBuilder s = new StringBuilder();
for( int i = 0 ; i < genome.length ; i++ )
{
if( genome[i] )
s.append("1");
else
s.append("0");
}
return s.toString();
}
public String genotypeToString()
{
StringBuilder s = new StringBuilder();
s.append( Code.encode( genome.length ) );
for( int i = 0 ; i < genome.length ; i++ )
s.append( Code.encode( genome[i] ) );
return s.toString();
}
protected void parseGenotype(final EvolutionState state,
final LineNumberReader reader) throws IOException
{
// read in the next line. The first item is the number of genes
String s = reader.readLine();
DecodeReturn d = new DecodeReturn(s);
Code.decode( d );
if (d.type != DecodeReturn.T_INTEGER) // uh oh
state.output.fatal("Individual with genome:\n" + s + "\n... does not have an integer at the beginning indicating the genome count.");
int lll = (int)(d.l);
genome = new boolean[ lll ];
// read in the genes
for( int i = 0 ; i < genome.length ; i++ )
{
Code.decode( d );
genome[i] = (boolean)(d.l!=0);
}
}
public boolean equals(Object ind)
{
if (ind==null) return false;
if (!(this.getClass().equals(ind.getClass()))) return false; // SimpleRuleIndividuals are special.
BitVectorIndividual i = (BitVectorIndividual)ind;
if( genome.length != i.genome.length )
return false;
for( int j = 0 ; j < genome.length ; j++ )
if( genome[j] != i.genome[j] )
return false;
return true;
}
public Object getGenome()
{ return genome; }
public void setGenome(Object gen)
{ genome = (boolean[]) gen; }
public int genomeLength()
{ return genome.length; }
public void setGenomeLength(int len)
{
boolean[] newGenome = new boolean[len];
System.arraycopy(genome, 0, newGenome, 0,
genome.length < newGenome.length ? genome.length : newGenome.length);
genome = newGenome;
}
public void writeGenotype(final EvolutionState state,
final DataOutput dataOutput) throws IOException
{
dataOutput.writeInt(genome.length);
for(int x=0;x