/**
*
*/
package vroom.trsp.optimization.rch;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import vroom.common.utilities.DoublyLinkedIntList;
import vroom.common.utilities.DoublyLinkedIntSet;
import vroom.trsp.datamodel.ITRSPTour;
import vroom.trsp.datamodel.TRSPInstance;
import vroom.trsp.datamodel.TRSPSimpleTour;
import vroom.trsp.datamodel.Technician;
import vroom.trsp.datamodel.costDelegates.TRSPCostDelegate;
import vroom.trsp.optimization.constraints.TourConstraintHandler;
import vroom.trsp.util.TRSPGlobalParameters;
import vroom.trsp.util.TRSPLogging;
/**
* <code>RndNearestFurthestIns</code> is an implementation of the random best insertion.
* <p>
* Creation date: Oct 4, 2011 - 1:44:48 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 RndBestIns extends TRSPRndConstructiveHeuristic {
private final NeighborComparator mComparator;
private final Neighbor[] mNearestTourNode;
private final DoublyLinkedIntSet mUnserved;
// private final LimitedSortedList<Neighbor> mBestNeighbors;
private final ArrayList<Neighbor> mBestNeighbors;
/**
* Creates a new <code>TRSPRndNearestFarthestInsOld</code>
*
* @param instance
* @param parameters
* @param constraintHandler
* @param costDelegate
* @param kMax
* the K<sub>max</sub> value
* @param rfi
* <code>true</code> if the farthest insertion should be selected (RFI), <code>false</code> if the
* nearest insertion should be selected (RNI)
*/
public RndBestIns(TRSPInstance instance, TRSPGlobalParameters parameters, TourConstraintHandler constraintHandler,
TRSPCostDelegate costDelegate, int kMax) {
super(instance, parameters, constraintHandler, costDelegate, kMax);
mNearestTourNode = new Neighbor[getInstance().getMaxId()];
mUnserved = new DoublyLinkedIntSet(getInstance().getMaxId());
mComparator = new NeighborComparator();
// mBestNeighbors = new LimitedSortedList<Neighbor>(getKmax(), mComparator);
mBestNeighbors = new ArrayList<Neighbor>(mUnserved.size());
}
@Override
protected Collection<ITRSPTour> generateGiantTour(Technician technician) {
Arrays.fill(mNearestTourNode, null);
mUnserved.clear();
// Initialize the nearest tour node array
for (ObservableNode node : getCompatibleRequests(technician.getID())) {
double dist = getInstance().getCostDelegate()
.getDistance(getHome(technician.getID()).getId(), node.getId());
Neighbor neighbor = new Neighbor(node, getHome(technician.getID()), 2 * dist);
mNearestTourNode[node.getId()] = neighbor;
mBestNeighbors.add(neighbor);
mUnserved.add(node.getId());
}
Collections.sort(mBestNeighbors, mComparator);
Collection<ITRSPTour> tours = new LinkedList<ITRSPTour>();
boolean abort = false;
while (!mUnserved.isEmpty() && !abort) {
abort = true;
// Initialize the tour
DoublyLinkedIntList tour = initTour(technician);
// Until all compatible requests have been visited
while (!mUnserved.isEmpty()) {
// ObservableNode node = selectNextNode(tour, tech, isUnserved, unserved);
Neighbor neigh = selectNextNode(tour, technician);
if (neigh == null)
break;
insertNextNode(tour, neigh, technician);
nodeInserted(tour, neigh, technician);
// System.out.println("ins: " + neigh + " tour: " + tour + " bi:" + mBestNeighbors);
abort = false;
}
tours.add(new TRSPSimpleTour(technician.getID(), getInstance(), tour));
}
if (!mUnserved.isEmpty())
TRSPLogging.getOptimizationLogger().info(
"RndNearestFurthestIns.generateGiantTour: %s request(s) left unserved: %s", mUnserved.size(),
mUnserved);
return tours;
}
@Override
protected ITRSPTour generateFeasibleTour(Technician tech) {
throw new UnsupportedOperationException("Not implemented yet");
}
protected DoublyLinkedIntList initTour(Technician tech) {
DoublyLinkedIntList tour = new DoublyLinkedIntList(getInstance().getMaxId());
// Add the technician home
tour.add(tech.getHome().getID());
// Add a random node
int rnd = getParameters().getRCHRndStream().nextInt(0, mBestNeighbors.size() - 1);
Neighbor seed = mBestNeighbors.remove(rnd);
tour.add(seed.getNode().getId());
nodeInserted(tour, seed, tech);
// Return the list
return tour;
}
protected Neighbor selectNextNode(List<Integer> tour, Technician tech) {
if (mBestNeighbors.isEmpty())
return null;
else
return mBestNeighbors.remove(nextIdx(mBestNeighbors.size()));
}
protected void insertNextNode(DoublyLinkedIntList tour, Neighbor neigh, Technician tech) {
if (tour.isEmpty())
tour.add(neigh.getNode().getId());
if (tour.getLast() == neigh.getNeighbor().getId())
tour.add(neigh.getNode().getId());
else
tour.insert(neigh.getNode().getId(), tour.getSucc(neigh.getNeighbor().getId()));
}
/**
* Update the array of nearest tour node after a new node is inserted in the current tour
*
* @param neigh
* the neighbor representing the node insertion
*/
protected void nodeInserted(DoublyLinkedIntList tour, Neighbor neigh, Technician technician) {
mNearestTourNode[neigh.getNode().getId()] = null;
mUnserved.remove(neigh.getNode().getId());
neigh.getNode().markAsServed();
boolean changed = false;
for (Integer u : mUnserved) {
if (mNearestTourNode[u].getNeighbor() == neigh.getNeighbor()) {
// The best insertion predecessor of u is the predecessor of the inserted node
// Reevaluate the best insertion of node u over the whole tour
Neighbor n = bestInsertion(tour, u, technician);
mNearestTourNode[u].update(n.getNeighbor(), n.getDistance());
} else {
// Evaluate the new insertion positions
// Insert between the predecessor and the inserted node
double distPred = getInstance().getCostDelegate().getInsertionDetour(u, neigh.getNeighbor().getId(),
neigh.getNode().getId());
// Insert after the inserted node
Integer succ = tour.getSucc(neigh.getNode().getId());
if (succ == DoublyLinkedIntList.UNDEFINED)
succ = tour.getFirst();
double distNode = getInstance().getCostDelegate().getInsertionDetour(u, neigh.getNode().getId(), succ);
ObservableNode best = null;
double dist;
if (mComparator.compare(distPred, distNode) < 0) {
best = neigh.getNeighbor();
dist = distPred;
} else {
best = neigh.getNode();
dist = distNode;
}
// getInstance().getCostDelegate().getDistance(neigh.getNode().getId(), u);
if (mComparator.compare(dist, mNearestTourNode[u].getDistance()) < 0) {
mNearestTourNode[u].update(best, dist);
changed = true;
}
}
}
if (changed)
Collections.sort(mBestNeighbors, mComparator);
}
protected Neighbor bestInsertion(DoublyLinkedIntList tour, Integer node, Technician technician) {
double bestInsCost = Double.POSITIVE_INFINITY;
Integer bestInsPred = null;
// Check for all possible insertions
ListIterator<Integer> it = tour.listIterator();
Integer pred = it.next();
while (it.hasNext()) {
Integer succ = it.next();
double insCost = evaluateInsertionCost(node, pred, succ, technician, true);
if (insCost < bestInsCost) {
bestInsCost = insCost;
bestInsPred = pred;
}
pred = succ;
}
// Insertion in the last position before the return to the depot
double insCost = evaluateInsertionCost(node, tour.getLast(), tour.getFirst(), technician, true);
if (insCost < bestInsCost) {
bestInsPred = tour.getLast();
bestInsCost = insCost;
}
return new Neighbor(getObsNode(node), getObsNode(bestInsPred), bestInsCost);
}
@Override
public String toString() {
return "RBI";
}
/**
* <code>InvNeighborComparator</code> is used to sort neighbors in the RNI variant
*/
protected class NeighborComparator implements Comparator<Neighbor> {
@Override
public int compare(Neighbor o1, Neighbor o2) {
return compare(o1.getDistance(), o2.getDistance());
}
public int compare(double d1, double d2) {
return Double.compare(d1, d2);
}
}
/**
* <code>InvNeighborComparator</code> is used to sort neighbors in the RFI variant
*/
protected class InvNeighborComparator extends NeighborComparator {
@Override
public int compare(double d1, double d2) {
return -Double.compare(d1, d2);
}
}
}