OpenTS Tutorial
MyObjectiveFunction
Evaluation

The OpenTS Tabu Search expects that our objective function be able to either evaluate an entire solution from scratch or evaluate a possible solution that would result from the application of a Move object. We determine what the Tabu Search expects in the evaluate(...) object by testing for whether or not the Move object is null. Either way, you must return the complete value, not the incremental, value of the solution.

import org.coinor.opents.*;

public class MyObjectiveFunction implements ObjectiveFunction
{
    ...

public double[] evaluate( Solution solution, Move move ) { int[] tour = ((MySolution)solution).tour; int len = tour.length; // If move is null, calculate distance from scratch if( move == null ) { double dist = 0; for( int i = 0; i < len; i++ ) dist += matrix[ tour[i] ][ i+1 >= len ? 0 : tour[i+1] ]; return new double[]{ dist }; } // end if: move == null // Else calculate incrementally else { MySwapMove mv = (MySwapMove)move; int pos1 = -1; int pos2 = -1; // Find positions for( int i = 0; i < tour.length; i++ ) if( tour[i] == mv.customer ) { pos1 = i; break; } pos2 = pos1 + mv.movement; // Logic below requires pos1 < pos2 if( pos1 > pos2 ) { int temp = pos2; pos2 = pos1; pos1 = temp; } // end if // Prior objective value double dist = solution.getObjectiveValue()[0]; // Treat a pair swap move differently if( pos1 + 1 == pos2 ) { ... return new double[]{ dist }; } // end if: pair swap // Else the swap is separated by at least one customer else { ... return new double[]{ dist }; } // end else: not a pair swap } // end else: calculate incremental } // end evaluate
... } // end class MyObjectiveFunction

So just how do we evaluate the incremental change? We'll take a look at that next.

If we didn't know any better, or if our objective function was more complex, we could always manipulate the solution, evaluate from scratch, and then un-manipulate the solution to put it back to the way it was.