package vroom.common.modeling.util;
import java.math.RoundingMode;
import vroom.common.modeling.dataModel.INodeVisit;
import vroom.common.modeling.dataModel.Node;
import vroom.common.modeling.dataModel.Vehicle;
import vroom.common.utilities.Utilities.Math;
/**
* <code>CostHelperBase</code> is the base type for classes responsible for the calculation of distances between two
* {@link Node}.<br/>
* Subclasses must implement {@link CostCalculationDelegate#getDistance(Node, Node)}
*
* @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 #updated 16-Feb-2010 10:07:12 a.m.
*/
public abstract class CostCalculationDelegate {
/**
* The precision (number of digits) used in the distance calculations, {@code double} precision is represented by
* {@link Integer#MAX_VALUE}
*/
private int mPrecision = Integer.MAX_VALUE;
/**
* Returns the precision (number of digits) used in the distance calculations, {@code double} precision is
* represented by {@link Integer#MAX_VALUE}
*
* @return the precision used in the distance calculations
*/
public int getPrecision() {
return mPrecision;
}
/**
* Set the precision (number of digits) used in the distance calculations, {@code double} precision is represented
* by {@link Integer#MAX_VALUE}
*
* @param precision
* the precision used in the distance calculations
* @throws IllegalArgumentException
* if the precision is increased (may be overriden by subclasses)
*/
public void setPrecision(int precision, RoundingMode method) {
if (precision > mPrecision)
throw new IllegalArgumentException("Cannot increase the precision");
this.mPrecision = precision;
this.mRoundingMethod = method;
precisionChanged();
}
/**
* Method called when the precision is changed
*
* @see #setPrecision(int)
*/
protected abstract void precisionChanged();
/** the rounding method used **/
private RoundingMode mRoundingMethod = RoundingMode.UNNECESSARY;
/**
* Getter for the rounding method used
*
* @return the rounding method used
*/
public RoundingMode getRoundingMethod() {
return this.mRoundingMethod;
}
/**
* Calculation of a base cost - or distance.
*
* @param origin
* the origin node
* @param destination
* the destination node
* @return the cost (distance) between the specified and
*/
public final double getCost(Node origin, Node destination) {
return getCost(origin, destination, 1);
}
/**
* Calculation of a base cost - or distance.
*
* @param origin
* the origin node
* @param destination
* the destination node
* @return the cost (distance) between the specified and
*/
public double getCost(INodeVisit origin, INodeVisit destination) {
return getCost(origin.getNode(), destination.getNode());
}
/**
* Calculation of a travel cost.
*
* @param origin
* the origin node (<code>s</code>)
* @param destination
* the destination node (<code>t</code>)
* @param variableCost
* a variable cost per distance unit (<code>cv</code>)
* @return the cost for the origin-destination trip:
*/
final double getCost(Node origin, Node destination, double variableCost) {
return getDistance(origin, destination) * variableCost;
}
/**
* Calculation of a vehicle-dependent cost.
*
* @param origin
* the origin
* @param destination
* the destination
* @param vehicle
* the vehicle that will be used to calculate vehicle-dependant traveling costs between the
* <code>origin</code> and <code>destination</code>
* @return the cost between the specified and
*/
public final double getCost(Node origin, Node destination, Vehicle vehicle) {
return getCost(origin, destination, vehicle.getVariableCost());
}
/**
* Calculation of a vehicle-dependent cost.
*
* @param origin
* the origin
* @param destination
* the destination
* @param vehicle
* the vehicle that will be used to calculate vehicle-dependant traveling costs between the
* <code>origin</code> and <code>destination</code>
* @return the cost between the specified {@code origin} and {@code destination}
*/
public double getCost(INodeVisit origin, INodeVisit destination, Vehicle vehicle) {
return getCost(origin.getNode(), destination.getNode(), vehicle);
}
/**
* Calculation of a vehicle-dependent traveling time.
*
* @param origin
* the origin
* @param destination
* the destination
* @param vehicle
* the vehicle that will be used to calculate vehicle-dependant traveling time between the
* <code>origin</code> and <code>destination</code>
* @return the traveling time between the specified {@code origin} and {@code destination}
*/
public double getTravelTime(Node origin, Node destination, Vehicle vehicle) {
return getDistance(origin, destination) / vehicle.getSpeed();
}
/**
* Calculation of a vehicle-dependent traveling time.
*
* @param origin
* the origin
* @param destination
* the destination
* @param vehicle
* the vehicle that will be used to calculate vehicle-dependant traveling time between the
* <code>origin</code> and <code>destination</code>
* @return the traveling time between the specified {@code origin} and {@code destination}
*/
public double getTravelTime(INodeVisit origin, INodeVisit destination, Vehicle vehicle) {
return getDistance(origin, destination) / vehicle.getSpeed();
}
/**
* Calculation of the insertion cost.
*
* @param node
* the node to be inserted
* @param pred
* the candidate predecessor of <code>node</code>
* @param succ
* the candidate successor of <code>node</code>
* @param vehicle
* the considered vehicle
* @return the cost of inserting as given by
*/
public double getInsertionCost(Node node, Node pred, Node succ, Vehicle vehicle) {
return getCost(pred, node, vehicle) + getCost(node, succ, vehicle)
- getCost(pred, succ, vehicle);
}
/**
* Calculation of the insertion cost.
*
* @param node
* the node to be inserted
* @param pred
* the candidate predecessor of <code>node</code>
* @param succ
* the candidate successor of <code>node</code>
* @param vehicle
* the considered vehicle
* @return the cost of inserting as given by
*/
public double getInsertionCost(INodeVisit node, INodeVisit pred, INodeVisit succ,
Vehicle vehicle) {
return (pred != null ? getCost(pred, node, vehicle) : 0)
+ (succ != null ? getCost(node, succ, vehicle) : 0)
- (pred != null && succ != null ? getCost(pred, succ, vehicle) : 0);
}
/**
* Gets the distance.
*
* @param origin
* the origin
* @param destination
* the destination
* @return the distance
*/
public double getDistance(Node origin, Node destination) {
return Math.round(getDistanceInternal(origin, destination), getPrecision(),
getRoundingMethod());
}
/**
* Gets the distance.
*
* @param origin
* the origin
* @param destination
* the destination
* @return the distance
*/
protected abstract double getDistanceInternal(Node origin, Node destination);
/**
* Gets the distance.
*
* @param origin
* the origin
* @param destination
* the destination
* @return the distance
*/
public double getDistance(INodeVisit origin, INodeVisit destination) {
return getDistance(origin.getNode(), destination.getNode());
}
/**
* Cost type as defined in the TSPLib
*
* @return a string describing the cost calculation
*/
public abstract String getDistanceType();
}