/**
*
*/
package vroom.trsp.datamodel.costDelegates;
import vroom.common.utilities.Utilities;
import vroom.common.utilities.Utilities.Math.DeviationMeasure;
import vroom.common.utilities.optimization.IMove;
import vroom.trsp.datamodel.ITRSPTour;
import vroom.trsp.datamodel.TRSPSolution;
import vroom.trsp.datamodel.TRSPTour;
import vroom.trsp.optimization.InsertionMove;
import vroom.trsp.optimization.TRSPMove;
/**
* <code>TRSPTourBalance</code> is a specialization of {@link TRSPCostDelegate} that measures the balancing of tours
* depending on a given metric
* <p>
* Creation date: May 18, 2011 - 2:22:00 PM
*
* @author Victor Pillac, <a href="http://uniandes.edu.co">Universidad de Los Andes</a>-<a
* href="http://copa.uniandes.edu.co">Copa</a> <a href="http://www.emn.fr">Ecole des Mines de Nantes</a>-<a
* href="http://www.irccyn.ec-nantes.fr/irccyn/d/en/equipes/Slp">SLP</a>
* @version 1.0
*/
public class TRSPTourBalance extends TRSPCostDelegate {
public static boolean sPenaliseBalInInsertion = false;
private final double mPenaltyWeight;
/**
* Returns the weight of the disbalance penalty that will be added to the initial objective function.
* <p>
* A value of {@link Double#NaN} indicates that the final cost is equal to the disblance value
* </p>
*
* @return the weight of the disbalance penalty that will be added to the initial objective function.
*/
public double getPenaltyWeight() {
return mPenaltyWeight;
}
private final DeviationMeasure mMeasure;
private final TRSPCostDelegate mTourCostDelegate;
/**
* Returns the {@link TRSPCostDelegate cost delegate} used to evaluate each tour
*
* @return the {@link TRSPCostDelegate cost delegate} used to evaluate each tour
*/
public TRSPCostDelegate getTourCostDelegate() {
return mTourCostDelegate;
}
/**
* Creates a new <code>TRSPTourBalance</code> based on {@link TRSPWorkingTime}
*/
public TRSPTourBalance() {
this(new TRSPWorkingTime(), DeviationMeasure.MaxAbsDev);
}
/**
* Creates a new <code>TRSPTourBalance</code>
*
* @param baseCostDelegate
* the cost delegate that will be used to measure the cost of each tour
*/
public TRSPTourBalance(TRSPCostDelegate baseCostDelegate, DeviationMeasure measure) {
this(baseCostDelegate, measure, Double.NaN);
}
/**
* Creates a new <code>TRSPTourBalance</code>
*
* @param baseCostDelegate
* the cost delegate that will be used to measure the cost of each tour
* @param measure
* the DeviationMeasure to be used to measure the disbalance between tours
* @param penaltyWeight
* the weight given to the disbalance measure in the final cost, {@link Double#NaN} if the original
* objective function is to be ignored and replaced by the disbalance measure
*/
public TRSPTourBalance(TRSPCostDelegate baseCostDelegate, DeviationMeasure measure,
double penaltyWeight) {
mTourCostDelegate = baseCostDelegate;
mMeasure = measure;
mPenaltyWeight = penaltyWeight;
}
@Override
protected double evaluateTRSPTour(TRSPTour tour, int node, boolean updateTour) {
return mTourCostDelegate.evaluateTRSPTour(tour, node, updateTour);
}
@Override
protected double evaluateGenericTour(ITRSPTour tour) {
return mTourCostDelegate.evaluateGenericTour(tour);
}
/**
* Returns an array containing the costs of all tours in {@code solution}
*
* @param solution
* the studied solution
* @param evaluateTours
* {@code true} if tours are to be reevaluated, {@code false} to used the stored value
* @param updateTours
* {@code true} if the tours are to be updated when reevaluated
* @return an array containing the costs of all tours in {@code solution}
* @see #evaluateTour(ITRSPTour, boolean)
*/
private double[] evaluateTours(TRSPSolution solution, boolean evaluateTours, boolean updateTours) {
double[] costs = new double[solution.getTourCount()];
for (int t = 0; t < costs.length; t++)
costs[t] = evaluateTours ? evaluateTour(solution.getTour(t), updateTours) : solution
.getTour(t).getTotalCost();
return costs;
}
/**
* Returns the main objective value for the given {@code costs}, or {@code 0} if this component is ignored
*
* @param costs
* @return the main objective value for the given {@code costs}
*/
private double evaluateFinalCost(double[] costs) {
double mainObj = 0;
double disbalance = Utilities.Math.deviation(mMeasure, costs);
if (!Double.isNaN(getPenaltyWeight())) {
disbalance *= getPenaltyWeight();
for (double c : costs)
mainObj += c;
}
return mainObj + disbalance;
}
@Override
public double evaluateSolution(TRSPSolution solution, boolean evaluateTours, boolean updateTours) {
double[] costs = evaluateTours(solution, evaluateTours, updateTours);
return evaluateFinalCost(costs) + evaluatePenalty(solution);
}
@Override
public double evaluateDetour(ITRSPTour tour, int i, int n, int j, boolean isRemoval) {
double cost = mTourCostDelegate.evaluateDetour(tour, i, n, j, isRemoval);
if (!sPenaliseBalInInsertion)
return cost;
double[] costs = evaluateTours(tour.getSolution(), false, false);
costs[tour.getTechnicianId()] += cost;
return evaluateFinalCost(costs);
}
@Override
public double evaluateMove(IMove move) throws UnsupportedOperationException {
if (move instanceof TRSPMove) {
double cost = mTourCostDelegate.evaluateMove(move);
if (!InsertionMove.class.isAssignableFrom(move.getClass()) || sPenaliseBalInInsertion) {
double[] costs = evaluateTours(((TRSPMove) move).getTour().getSolution(), false,
false);
double prev = evaluateFinalCost(costs);
costs[((TRSPMove) move).getTour().getTechnicianId()] += cost;
double imp = prev - evaluateFinalCost(costs);
move.setImprovement(imp);
return imp;
} else {
return cost;
}
} else {
throw new IllegalArgumentException("Unsupported move: " + move);
}
}
@Override
public String toString() {
return String.format("%s (%s %s)", super.toString(), mMeasure, mTourCostDelegate.getClass()
.getSimpleName());
}
@Override
public boolean isInsertionSeqDependent() {
return mTourCostDelegate.isInsertionSeqDependent();
}
}