package es_problems;
import evolution.*;
import java.awt.*;
import java.lang.Math;
import java.util.Random;
/** solve NxN magic squares using evolution strategy with a
** problem specific mutation operator
** @version 0.1
** @author hthadler
**/
public class MagicSquare extends ESgui implements ESproblem
{
static protected Random randgen = new Random(); //random-number generator
static protected Double optimal = new Double(0); //optimum
static protected Font nfont = new Font("TimesRoman",Font.PLAIN,7); //number font
int big_n=4; //default 4x4 magic square
/**
**/
public ESpopulation startpopulation()
{
double [] opars = new double [big_n*big_n];
double [] spars = new double [big_n*big_n];
for(int i=1; i<= big_n*big_n; i++)
{
opars[i-1]=i;
spars[i-1]=3;
}
int num_parents=10;
ESchromosome [] s = new ESchromosome[num_parents];
for(int i=0; i<num_parents; i++)
s[i]=new ESchromosome( opars, spars, big_n*big_n );
return new ESpopulation(s, num_parents, 40, ESchromosome.recombinate_id_discrete,
1, 1.3, ESpopulation.children_only, this, true);
}
/**
**/
public Dimension dimension_of_drawing_area()
{
int num_digits=0;
double how_many_digits = (big_n*(big_n*big_n+1))/2;
for(int i=0; how_many_digits >= 1; i++)
{
how_many_digits/=10;
num_digits++;
}
if( num_digits < 3 )
num_digits = 3;
int box_dim = (num_digits+1)*nfont.getSize();
return new Dimension((big_n+2)*box_dim,(big_n+2)*box_dim);
}
/** MagicSquare specific mutation operator
**/
public ESchromosome specific_mutation(ESchromosome c)
{
double [] cd = c.get_object_parameters();
double [] sd = c.get_strategy_parameters();
int i,p1,p2;
double dlen,px;
double [] op = new double [c.length];
double [] sp = new double [c.length];
// get a copy of the Chromosome
dlen = (double)c.length;
for(i=0; i<c.length; i++)
{
op[i]=cd[i];
sp[i]=sd[i];
}
// swap n numbers where n is value of sp[0]
for( int j=0; j<sp[0]; j++)
{
//indices of numbers to be swapped
p1 = (int)(dlen*randgen.nextDouble());
// search for a number within op[p1]-sp[p1] and op[p1]+sp[p1];
double range = sd[p1];
do
{
p2 = (int)(dlen*randgen.nextDouble());
}while( !((op[p1]-range) <= op[p2] && op[p2] <= (op[p1]+range)) );
//swap two numbers
if( p1 != p2 && p1 >= 0 && p1<c.length && p2 >= 0 && p2<c.length)
{
px=op[p1]; op[p1]=op[p2]; op[p2]=px;
}
}
//adapt strategy-parameters
double r=randgen.nextDouble();
if( r > 0.66 )
sp[0]+=1;
else if( r > 0.33 )
sp[0]-=1;
if(sp[0] < 1)
sp[0]=1;
for(i=1; i<big_n*big_n; i++)
sp[i]=sp[0];
return new ESchromosome( op, sp, c.length );
}
/** magicSquare optimum
**/
public Double optimum()
{
return optimal;
}
/** this method returns the fitness measure for a given chromosome
** @return fitness of chromosome
**/
public double calc_quality(ESchromosome c)
{
double [] cd = c.get_object_parameters();
double S = 0.5*big_n*(big_n*big_n+1);
double quality = 0.0;
double s;
//rows
for(int i=0; i<big_n; i++)
{
s=0;
for(int j=0; j<big_n; j++)
{
s+=cd[i*big_n+j];
}
quality += (S-s)*(S-s);
}
//columns
for(int i=0; i<big_n; i++)
{
s=0;
for(int j=0; j<big_n; j++)
{
s+=cd[j*big_n+i];
}
quality += (S-s)*(S-s);
}
//diagonal top,left - bottom,right
s=0;
for(int i=0; i<big_n; i++)
s+=cd[i*big_n+i];
quality += (S-s)*(S-s);
//diagonal bottom,left - top,right
s=0;
for(int i=0; i<big_n; i++)
s+=cd[(big_n-i-1)*big_n+i];
quality += (S-s)*(S-s);
return(quality);
}
/** draw a given chromosome using Graphics object g
** @param g Graphics object @see java.awt.Graphics
** @param c chromosome to be drawn
**/
public void draw_single(Graphics g, ESchromosome c)
{
int [] colors = new int [big_n*big_n];
int [] rows = new int [big_n];
int [] cols = new int [big_n];
int [] diag = new int [2];
int magic_sum = (big_n*(big_n*big_n+1))/2;
double [] cd = c.get_object_parameters();
// get row sums
int s=0;
for(int i=0; i<big_n; i++)
{
s=0;
for(int j=0; j<big_n; j++)
s+=(int)cd[i*big_n+j];
rows[i]=s;
}
// get column sums
for(int i=0; i<big_n; i++)
{
s=0;
for(int j=0; j<big_n;j++)
s+=(int)cd[j*big_n+i];
cols[i]=s;
}
// get diagonal sums
s=0;
for(int i=0; i<big_n; i++)
s+=(int)cd[i*big_n+i];
diag[0]=s;
s=0;
for(int i=0; i<big_n; i++)
s+=(int)cd[i*big_n+(big_n-i-1)];
diag[1]=s;
// get colors
// cols: 1 (blue), rows: 2(green), diag: 4(red)
for(int i=0; i<big_n; i++)
{
if( rows[i] == magic_sum )
{
for(int j=0; j<big_n; j++)
colors[i*big_n+j]+=2;
}
if( cols[i] == magic_sum )
{
for(int j=0; j<big_n; j++)
colors[j*big_n+i]+=1;
}
}
if(diag[0]==magic_sum)
for(int i=0; i<big_n; i++)
colors[i*big_n+i]+=4;
if(diag[1]==magic_sum)
for(int i=0; i<big_n; i++)
colors[i*big_n+(big_n-i-1)]+=4;
// get dimension for a single number-box
int num_digits=0;
double how_many_digits = (double)(magic_sum);
for(int i=0; how_many_digits >= 1; i++)
{
how_many_digits/=10;
num_digits++;
}
if( num_digits < 3 )
num_digits = 3;
int box_dim = (num_digits+1)*nfont.getSize();
int y_off = 4;
int x_off = 4;
g.drawRect(0,0,
dimension_of_drawing_area().width-1,
dimension_of_drawing_area().height-1);
// draw colored boxes
for(int i=0; i<big_n; i++)
{
for(int j=0; j<big_n; j++)
{
switch(colors[i*big_n+j])
{
case 0: g.setColor(Color.white);
break;
case 1: g.setColor(Color.blue);
break;
case 2: g.setColor(Color.blue);
break;
case 3: g.setColor(Color.green);
break;
case 4:
case 5:
case 6:
case 7: g.setColor(Color.red);
break;
default: g.setColor(Color.red);
break;
}
g.fillRect(box_dim+i*box_dim, box_dim+j*box_dim,
box_dim, box_dim);
g.setColor(this.getBackground());
g.fillRect(box_dim+i*box_dim+4, box_dim+j*box_dim+4,
box_dim-7,box_dim-7);
g.setColor(this.getForeground());
g.drawRect(box_dim+i*box_dim, box_dim+j*box_dim,
box_dim, box_dim);
g.drawString(""+((int)cd[i*big_n+j]),
box_dim+i*box_dim + x_off,
box_dim+(j+1)*box_dim-y_off);
}
}
// draw column sums
for(int i=0; i<big_n; i++)
g.drawString(""+cols[i], (big_n+1)*box_dim+x_off, (i+2)*box_dim-y_off);
// draw row sums
for(int i=0; i<big_n; i++)
g.drawString(""+rows[i], (i+1)*box_dim+x_off, (big_n+2)*box_dim-y_off);
//draw diagonal sums
g.drawString(""+diag[0], (big_n+1)*box_dim+x_off, (big_n+2)*box_dim-y_off);
g.drawString(""+diag[1], x_off , (big_n+2)*box_dim-y_off);
}
public void init()
{
try { big_n = (int)Integer.parseInt(getParameter("n")); }
catch ( NumberFormatException e) { big_n = 4; }
super.init();
}
public boolean handleEvent(Event e)
{
//handle problem-specific events here
return super.handleEvent(e);
}
/**
**/
public String[][] getParameterInfo()
{
String[][]info=
{ // name, type, description
{"n", "integer", "n × n magic square"}
};
return info;
}
}