/**
*
*/
package vroom.trsp.optimization.rch;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
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;
/**
* <code>RndClarkeWright</code> is a randomized implementation of the Clarke and
* Wright heuristic to generate TRSP tours
* <p>
* Creation date: Oct 27, 2011 - 10:23:13 AM.
*
* @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 RndClarkeWright extends TRSPRndConstructiveHeuristic {
private ArrayList<?>[] mArcs;
private ListIterator<CWArc> mArcIterator;
private LinkedList<?>[] mCurrentTours;
/**
* Instantiates a new rnd clarke wright.
*
* @param instance
* the instance
* @param parameters
* the parameters
* @param constraintHandler
* the constraint handler
* @param costDelegate
* the cost delegate
* @param kMax
* the k max
*/
public RndClarkeWright(TRSPInstance instance,
TRSPGlobalParameters parameters,
TourConstraintHandler constraintHandler,
TRSPCostDelegate costDelegate, int kMax) {
super(instance, parameters, constraintHandler, costDelegate, kMax);
}
@Override
protected void initialize(List<ObservableNode> requests) {
super.initialize(requests);
mArcs = new ArrayList<?>[getInstance().getFleet().size()];
generateArcs(requests);
}
/**
* Generate the saving arcs for each technician
*
* @param requests
*/
private void generateArcs(List<ObservableNode> requests) {
int tid = -1;
for (Technician t : getInstance().getFleet()) {
tid = t.getID();
mArcs[tid] = new ArrayList<CWArc>(getInstance().getRequestCount()
* getInstance().getRequestCount());
for (ObservableNode i : requests) {
for (ObservableNode j : requests) {
if (i.getId() != j.getId()
&& (!isCheckTWFeas() || getInstance()
.isArcTWFeasible(i.getId(), j.getId()))) {
getArcs(t.getID()).add(
new CWArc(i.getId(), j.getId(), -getInstance()
.getCostDelegate().getInsertionCost(
t.getHome().getID(), i.getId(),
j.getId(), t)));
}
}
}
Collections.sort(getArcs(t.getID()));
// Speed up when the fleet is homogeneous
if (getInstance().getFleet().isHomogeneous())
break;
}
// Copy the reference for all technicians
if (getInstance().getFleet().isHomogeneous()) {
for (Technician t2 : getInstance().getFleet()) {
mArcs[t2.getID()] = mArcs[tid];
}
}
}
/**
* Returns the list of the saving arcs for a given technician. This is a
* precalculated list that should not be modified.
*
* @param techId
* @return the list of the saving arcs for a given technician
*/
@SuppressWarnings("unchecked")
ArrayList<CWArc> getArcs(int techId) {
return (ArrayList<CWArc>) mArcs[techId];
}
@SuppressWarnings("unchecked")
@Override
protected Collection<ITRSPTour> generateGiantTour(Technician tech) {
// A copy of the saving arcs
LinkedList<CWArc> mergeArcs = new LinkedList<RndClarkeWright.CWArc>(
getArcs(tech.getID()));
// Reset the observable nodes (the served flag is not used in this
// implem)
// resetNodes(tech.getID());
mCurrentTours = new LinkedList<?>[getInstance().getMaxId()];
// Add each request to a tour
for (ObservableNode req : getCompatibleRequests(tech.getID())) {
LinkedList<Integer> tour = new LinkedList<Integer>();
tour.add(req.getId());
mCurrentTours[req.getId()] = tour;
}
mArcIterator = mergeArcs.listIterator();
while (!mergeArcs.isEmpty()) {
int k = nextIdx(mergeArcs.size());
// Select the k-th merge arc
CWArc arc = popKthArc(k);
if (arc != null) {
executeMerge(arc);
}
}
LinkedList<ITRSPTour> tours = new LinkedList<ITRSPTour>();
for (LinkedList<?> tour : mCurrentTours) {
if (tour != null) {
LinkedList<Integer> ltour = (LinkedList<Integer>) tour;
mCurrentTours[ltour.getFirst()] = null;
mCurrentTours[ltour.getLast()] = null;
ltour.addFirst(tech.getHome().getID());
tours.add(new TRSPSimpleTour(tech.getID(), getInstance(), ltour));
}
}
return tours;
}
/**
* Returns the k-th feasible arc
*
* @param k
* @return the k-th feasible arc
*/
protected final CWArc popKthArc(int k) {
CWArc kthArc = null;
CWArc tmpArc = null;
while (mArcIterator.nextIndex() < k && mArcIterator.hasNext()) {
tmpArc = mArcIterator.next();
if (!isArcFeasible(tmpArc)) // We remove infeasible arcs
mArcIterator.remove();
else
kthArc = tmpArc;
}
while (mArcIterator.nextIndex() > k && mArcIterator.hasPrevious()) {
tmpArc = mArcIterator.previous();
if (!isArcFeasible(tmpArc)) // We remove infeasible arcs
mArcIterator.remove();
else
kthArc = tmpArc;
}
tmpArc = null;
if (mArcIterator.hasNext()) {
tmpArc = mArcIterator.next();
mArcIterator.remove();
boolean feasible = isArcFeasible(tmpArc);
while (!feasible && mArcIterator.hasNext()) {
tmpArc = mArcIterator.next();
mArcIterator.remove();
feasible = isArcFeasible(tmpArc);
}
if (feasible) {
kthArc = tmpArc;
}
}
return kthArc;
}
/**
* Check if an arc represents a feasible merge
*
* @param arc
* @return
*/
private boolean isArcFeasible(CWArc arc) {
return isExterior(arc.getHead())
&& isExterior(arc.getTail()) //
&& isLast(arc.getTail()) && isFirst(arc.getHead())
&& mCurrentTours[arc.getHead()] != mCurrentTours[arc.getTail()];
}
/**
* Execute the merge represented by {@code arc}
*
* @param arc
*/
private void executeMerge(CWArc arc) {
LinkedList<Integer> tailTour = getCurrentTour(arc.getTail());
LinkedList<Integer> headTour = getCurrentTour(arc.getHead());
// Mark both head and tail as interior : set their current tour to null
mCurrentTours[arc.getHead()] = null;
if (tailTour.size() > 1)
mCurrentTours[arc.getTail()] = null;
// Append the head tour to the tail tour
tailTour.addAll(headTour);
// Update the current tour of the head last node
mCurrentTours[headTour.getLast()] = tailTour;
}
/**
* Returns the current tour of {@code node}
*
* @param node
* @return the current tour of {@code node}
*/
@SuppressWarnings("unchecked")
protected LinkedList<Integer> getCurrentTour(int node) {
return (LinkedList<Integer>) mCurrentTours[node];
}
private boolean isExterior(int node) {
return mCurrentTours[node] != null;
}
/**
* Returns {@code true} iif {@code node} is the first node of its tour
*
* @param node
* @return {@code true} iif {@code node} is the first node of its tour
*/
private boolean isFirst(int node) {
return getCurrentTour(node).getFirst() == node;
}
/**
* Returns {@code true} iif {@code node} is the last node of its tour
*
* @param node
* @return {@code true} iif {@code node} is the last node of its tour
*/
private boolean isLast(int node) {
return getCurrentTour(node).getLast() == node;
}
@Override
protected ITRSPTour generateFeasibleTour(Technician tech) {
throw new UnsupportedOperationException("Not implemented");
}
@Override
public String toString() {
return "RCW";
}
/**
* The Class <code>CWArc</code> wraps a saving arc for the CW algorithm
* <p>
* Creation date: Oct 27, 2011 - 10:48:26 AM.
*
* @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
*/
protected static class CWArc implements Comparable<CWArc> {
/** The Head. */
private final Integer mHead;
/** The Tail. */
private final Integer mTail;
/** The Savings. */
private final double mSavings;
/**
* Creates a new <code>CWArc</code>.
*
* @param head
* the head
* @param tail
* the tail
* @param savings
* the savings
*/
private CWArc(Integer head, Integer tail, double savings) {
mHead = head;
mTail = tail;
mSavings = savings;
}
/**
* Gets the head.
*
* @return the head
*/
public Integer getHead() {
return mHead;
}
/**
* Gets the tail.
*
* @return the tail
*/
public Integer getTail() {
return mTail;
}
/**
* Gets the savings.
*
* @return the savings
*/
public double getSavings() {
return mSavings;
}
@Override
public int compareTo(CWArc o) {
return Double.compare(this.getSavings(), o.getSavings());
}
@Override
public String toString() {
return String.format("(%s,%s,%.3f)", getHead(), getTail(),
getSavings());
}
}
}