Some Java code for a 2D neighbourhood representation scheme. Definitions can be found in our 2012 GECCO paper. Permission to use and modify the code or image (SVG, PNG, PDF) is granted, but please include a reference to our paper or link to this page.
/** Accepts an index and returns an Int2D location in the VN neighbourhood*/
public Int2D VNify(int n) {
Int2D result = new Int2D(0,0);
if (n == 0) return result;
int k = (int) Math.ceil( -1.0/2.0 + Math.sqrt(1 + 2.0*(n))/2.0 );
int nprime = n - (int) (2.0*k*(k-1)) - 1;
int positivey = nprime - k;
int negativey = 3*k - nprime;
int firstx = nprime;
int secondx = 2*k - nprime;
int lastx = nprime - 4*k;
if (nprime <= k) result.setLocation(positivey, firstx);
else if (nprime <= 2*k) result.setLocation(positivey, secondx);
else if (nprime <= 3*k) result.setLocation(negativey, secondx);
else result.setLocation(negativey, lastx);
return result;
}
/** Accepts an (x,y) location in the VN neighbourhood and returns the corresponding index. */
public int unVNify(int x, int y) {
double nx = Math.abs(x);
double ny = Math.abs(y);
if (nx + ny == 0) return 0;
double quartWidth = Math.abs(x) + Math.abs(y);
double tempResult = 0.0;
if ( y >= 0) tempResult = x + quartWidth;
else tempResult = 2.0*quartWidth + (quartWidth - x);
tempResult += 1.0 + 4.0*( (quartWidth)*(quartWidth-1)/2.0 );
return (int) Math.round(tempResult);
}
/** Accepts an index and returns an Int2D location in the cross neighbourhood*/
public Int2D crucify(int i) {
Int2D result = new Int2D(0,0);
double sign = Math.pow(-1.0, Math.floor((i%4)/2.0));
double mag = Math.ceil(i/4.0);
int val = (int) Math.round(sign*mag);
if (i%4 ==0 || i%4 == 2) result.setLocation(0, val);
else result.setLocation(val, 0);
return result;
}
/** Accepts an (x,y) location in the cross neighbourhood and returns the corresponding index. (Note: garbage in, garbage out :) */
public int resurrect(int x, int y) {
int result = 0;
double tempResult = 4.0*Math.max(Math.abs(x),Math.abs(y));
if (x > 0) tempResult -= 3;
if (y < 0) tempResult -= 2;
if (x < 0) tempResult -= 1;
result = (int) Math.round(tempResult);
return result;
}
/** Accepts an index and returns an Int2D location in the Moore neighbourhood*/
public Int2D Moorify(int n) {
Int2D result = new Int2D(0,0);
if (n == 0) return result;
int k = 0;
for (int i=1; i<n+1; i++)
if ( (2*i+1)*(2*i+1) <= n ) k = i;
int S = (2*k+1)*(2*k+1);
int nprime = n - S;
int diam = 2*(k+1) + 1;
int m = k + 1;
if (nprime < diam) result.setLocation(-m + nprime, m);
else if (nprime < 2*diam-1) result.setLocation(m, m - (nprime - diam + 1));
else if (nprime < 3*diam-2) result.setLocation(m - (nprime - 2*diam + 2), -m);
else result.setLocation(-m, -m + (nprime -3*diam +3));
return result;
}
This relies on my simple 2D integer class, Int2D:
public class Int2D {
int x;
int y;
public int getX() { return x; }
public int getY() { return y; }
public void setX(int v) { x = v; }
public void setY(int v) { y = v; }
public void setLocation(int xT, int yT) { x = xT; y = yT; }
public Int2D() {;}
public Int2D(int x, int y) {
this.x = x; this.y = y;
}
public Int2D clone() {
return new Int2D(x,y);
}
public String toString() {
return "("+x+","+y+")";
}
public boolean equals(Int2D p) {
return (this.getX() == p.getX() && this.getY() == p.getY());
}
public double distance(Int2D that) {
return Math.sqrt((this.getX() - that.getX())*(this.getX() - that.getX()) + (this.getY() - that.getY())*(this.getY() - that.getY()));
}
}