/**
*
*/
package vroom.trsp.datamodel;
import vroom.common.modeling.dataModel.DistanceMatrix;
import vroom.common.modeling.dataModel.Node;
import vroom.common.modeling.dataModel.attributes.ILocation;
import vroom.common.modeling.util.CostCalculationDelegate;
import vroom.common.utilities.GeoTools;
/**
* <code>TRSPDistanceMatrix</code> is an extension of {@link DistanceMatrix} for the special case of the TRSP
* <p>
* Creation date: Feb 23, 2011 - 12:09:42 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 TRSPDistanceMatrix extends CostCalculationDelegate {
/** The distance matrix between all nodes of the graph. */
private final double mDistances[][];
private final TRSPInstance mInstance;
public TRSPDistanceMatrix(TRSPInstance instance) {
mInstance = instance;
mDistances = new double[mInstance.getMaxId()][mInstance.getMaxId()];
for (int i = 0; i < mDistances.length; i++) {
for (int j = 0; j < mDistances.length; j++) {
if (i != j)
mDistances[i][j] = evaluateDistance(mInstance.getNode(i).getLocation(),
mInstance.getNode(j).getLocation());
}
}
}
/**
* Creates a new <code>TRSPDistanceMatrix</code> with the specified distance matrix
*
* @param instance
* @param ds
*/
protected TRSPDistanceMatrix(TRSPInstance instance, double[][] ds) {
mInstance = instance;
mDistances = new double[mInstance.getMaxId()][mInstance.getMaxId()];
for (int i = 0; i < mDistances.length; i++) {
for (int j = 0; j < mDistances.length; j++) {
if (i != j)
mDistances[i][j] = ds[i][j];
}
}
}
@Override
protected void precisionChanged() {
for (int i = 0; i < mDistances.length; i++) {
for (int j = 0; j < mDistances[i].length; j++) {
mDistances[i][j] = vroom.common.utilities.Utilities.Math.round(mDistances[i][j],
getPrecision(), getRoundingMethod());
}
}
}
/**
* @param a
* @param b
* @return
*/
private double evaluateDistance(ILocation a, ILocation b) {
if (a.getCoordinateSystem() != b.getCoordinateSystem())
throw new IllegalArgumentException(String.format(
"Both locations must be in the same coordinate system (%s/%s)",
a.getCoordinateSystem(), b.getCoordinateSystem()));
switch (a.getCoordinateSystem()) {
case CARTESIAN:
return GeoTools.distEuclidean(a.getX(), a.getY(), b.getX(), b.getY());
case LAT_LON_DEC_DEG:
return GeoTools.distVincenty(a.getX(), a.getY(), b.getX(), b.getY()) / 1000;
default:
throw new UnsupportedOperationException("Unsupported coordinate system: "
+ a.getCoordinateSystem());
}
}
@Override
public double getDistance(Node origin, Node destination) {
return getDistanceInternal(origin, destination);
}
@Override
protected double getDistanceInternal(Node origin, Node destination) {
return getDistance(origin.getID(), destination.getID());
}
/**
* Calculate the distance between to nodes.
*
* @param pred
* the first node id
* @param succ
* the second node id
* @return the distance separating <code>pred</code> and <code>succ</code>: <code>|(pred,succ)|</code>
*/
public double getDistance(int pred, int succ) {
return mDistances[pred][succ];
}
/**
* Calculate the cost of traveling an arc with a given technician.
* <p>
* Depending on the definition of the technician {@linkplain Technician#getVariableCost() variable cost} this can be
* a measure of time, monetary value or other.
* </p>
*
* @param o
* the first node id
* @param d
* the second node id
* @param technician
* the considered technician
* @return the cost of traveling from o to d, defined by <code>|(o,d)|*technician.getVariableCost()</code>
* @see Technician#getVariableCost()
*/
public double getCost(int o, int d, Technician technician) {
return getDistance(o, d) * technician.getVariableCost();
}
/**
* Calculation of the insertion detour.
*
* @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>
* @return the cost of inserting as given by
*/
public double getInsertionDetour(int node, int pred, int succ) {
return getDistance(pred, node) + getDistance(node, succ) - getDistance(pred, succ);
}
/**
* 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(int node, int pred, int succ, Technician technician) {
return getCost(pred, node, technician) + getCost(node, succ, technician)
- getCost(pred, succ, technician);
}
/**
* Calculate the traveling time over an arc with a given technician, depending on its traveling speed
* {@linkplain Technician#getSpeed() speed}.
*
* @param o
* the first node id
* @param d
* the second node id
* @param technician
* the considered technician
* @return the traveling time from o to d, defined by <code>|(o,d)|*technician.getSpeed()</code>
* @see Technician#getSpeed()
*/
public double getTravelTime(int o, int d, Technician technician) {
return getDistance(o, d) / technician.getSpeed();
}
/**
* Returns the maximum distance between two nodes in this matrix
*
* @return the maximum distance between two nodes in this matrix
*/
public double getMaxDistance() {
double max = Double.NEGATIVE_INFINITY;
for (int i = 0; i < mDistances.length; i++)
for (int j = 0; j < mDistances[i].length; j++)
if (mDistances[i][j] > max)
max = mDistances[i][j];
return max;
}
@Override
public String getDistanceType() {
return "EUCLIDIAN_2D";
}
}