Let's start by looking at how we'll initialize this objective
function.
The complete source is available,
but since it's so big, let's look at it piece by piece again:
import org.coinor.opents.*;
public class MyObjectiveFunction implements ObjectiveFunction
{
public double[][] matrix;
public TSPObjectiveFunction( double[][] customers )
{ matrix = createMatrix( customers );
} // end constructor
public double[] evaluate( Solution solution, Move move)
{
...
} // end evaluate
...
} // end class MyObjectiveFunction
The constructor expects to be passed that nx2
matrix of customer locations that we generated in the main program.
We then create a matrix of distances among these customers in the
createMatrix(...) method. Let's look at that:
import org.coinor.opents.*;
public class MyObjectiveFunction implements ObjectiveFunction
{
...
/** Create symmetric matrix. */
private double[][] createMatrix( double[][] customers )
{
int len = customers.length;
double[][] matrix = new double[len][len];
for( int i = 0; i < len; i++ )
for( int j = i+1; j < len; j++ )
matrix[i][j] = matrix[j][i] = norm(
customers[i][0], customers[i][1],
customers[j][0], customers[j][1] );
return matrix;
} // end createMatrix
/** Calculate distance between two points. */
private double norm( double x1, double y1, double x2, double y2 )
{
double xDiff = x2 - x1;
double yDiff = y2 - y1;
return Math.sqrt( xDiff*xDiff + yDiff*yDiff );
} // end norm
} // end class MyObjectiveFunction
In fact we used two methods: createMatrix(...)
and norm(...). The second method simply applies
the Pythagorean theorem to the two sets of (x,y) coordinates.
The matrix is symmetric, so we could get away with creating
a double matrix that was not square, but then we'd have
to worry about making sure we called for [i][j] instead
of [j][i]: too confusing. The little extra memory needed
for a full, square matrix is worth the fewer headaches.
We still haven't seen how we're going to evaluate a solution,
so we'll look at that next.