package vroom.common.modeling.dataModel;
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.List;
import java.util.ListIterator;
import java.util.concurrent.TimeUnit;
import vroom.common.utilities.ExtendedReentrantLock;
/**
* <code>VRPSolution</code> is the base class used to store a solution to a VRP problem <br>
* In particular, it contains a set of {@link RouteBase} of type <code>R</code>, that can be iterated over by the
* {@link Iterable} interface.
*
* @param <R>
* the type of {@link RouteBase} used to represent the routes
* @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 #created 15-Feb-2010 11:29:51 a.m.
*/
public class Solution<R extends IRoute<?>> implements IVRPSolution<R> {
/** The parent instance for this solution *. */
private final IVRPInstance mParentInstance;
/** The m routes. */
private List<R> mRoutes;
/**
* Creates a new <code>VRPSolution</code> associated with the given.
*
* @param parentInstance
* the parent instance {@link InstanceBase}
*/
public Solution(IVRPInstance parentInstance) {
this.mParentInstance = parentInstance;
this.mLock = new ExtendedReentrantLock();
if (this.mParentInstance.getFleet().isUnlimited()) {
this.mRoutes = new ArrayList<R>();
} else {
this.mRoutes = new ArrayList<R>(this.mParentInstance.getFleet().size());
}
}
/*
* (non-Javadoc)
*
* @see vroom.common.modeling.dataModel.ISolution#addRoute(R)
*/
@Override
public void addRoute(R route) {
this.mRoutes.add(route);
}
/*
* (non-Javadoc)
*
* @see vroom.common.modeling.dataModel.ISolution#addRoute(int,R)
*/
@Override
public void addRoute(R route, int index) {
this.mRoutes.add(index, route);
}
/*
* (non-Javadoc)
*
* @see
* vroom.common.modeling.dataModel.ISolution#removeRoute(vroom.modelling.
* VroomModelling.dataModel.IRoute)
*/
@Override
public void removeRoute(IRoute<?> route) {
this.mRoutes.remove(route);
};
/*
* (non-Javadoc)
*
* @see vroom.common.modeling.dataModel.ISolution#getCost()
*/
@Override
public double getCost() {
double cost = 0;
for (R route : this.mRoutes) {
cost += route.getCost();
}
return cost;
}
/*
* (non-Javadoc)
*
* @see vroom.common.utilities.optimization.ISolution#getObjectiveValue()
*/
@Override
public double getObjectiveValue() {
return getCost();
}
/*
* (non-Javadoc)
*
* @see vroom.common.modeling.dataModel.ISolution#getParentInstance()
*/
@Override
public IVRPInstance getParentInstance() {
return this.mParentInstance;
}
/*
* (non-Javadoc)
*
* @see vroom.common.modeling.dataModel.ISolution#getRoute(int)
*/
@Override
public R getRoute(int index) {
return this.mRoutes.get(index);
}
/*
* (non-Javadoc)
*
* @see vroom.common.modeling.dataModel.ISolution#getRouteCount()
*/
@Override
public int getRouteCount() {
return this.mRoutes.size();
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
/*
* (non-Javadoc)
*
* @see vroom.common.modeling.dataModel.ISolution#toString()
*/
@Override
public String toString() {
StringBuilder b = new StringBuilder(mRoutes.size() * 50);
b.append(String.format("Cost:%.2f, %s Routes: {", getCost(), this.getRouteCount()));
for (IRoute<?> r : this) {
b.append(r.toString());
b.append(',');
}
if (mRoutes.size() > 0) {
b.setCharAt(b.length() - 1, '}');
} else {
b.append('}');
}
return b.toString();
}
/*
* (non-Javadoc)
*
* @see java.lang.Iterable#iterator()
*/
/*
* (non-Javadoc)
*
* @see vroom.common.modeling.dataModel.ISolution#iterator()
*/
@Override
public ListIterator<R> iterator() {
return mRoutes.listIterator();
}
@SuppressWarnings("unchecked")
@Override
public Solution<R> clone() {
Solution<R> clone = new Solution<R>(getParentInstance());
for (R route : this) {
clone.addRoute((R) route.clone());
}
return clone;
}
/*
* (non-Javadoc)
*
* @see vroom.common.modeling.dataModel.ISolution#clear()
*/
@Override
public void clear() {
this.mRoutes.clear();
}
/*
* (non-Javadoc)
*
* @see vroom.common.utilities.optimization.ISolution#getFitnessValue()
*/
@Override
public Comparable<?> getObjective() {
return getCost();
}
// ------------------------------------
// ILockable interface implementation
// ------------------------------------
/** A lock to be used by this instance */
private final ExtendedReentrantLock mLock;
private boolean mSelfLock = false;
@Override
public boolean tryLock(long timeout) {
try {
return getLockInstance().tryLock(timeout, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
return false;
}
}
@Override
public void acquireLock() {
try {
if (!getLockInstance().tryLock(TRY_LOCK_TIMOUT, TRY_LOCK_TIMOUT_UNIT)) {
throw new IllegalStateException(
String.format(
"Unable to acquire lock on this instance of %s (%s) after %s %s, owner: %s",
this.getClass().getSimpleName(), hashCode(), TRY_LOCK_TIMOUT,
TRY_LOCK_TIMOUT_UNIT, getLockInstance().getOwnerName()));
}
} catch (InterruptedException e) {
throw new IllegalStateException(String.format(
"Unable to acquire lock on this instance of %s (%s)", this.getClass()
.getSimpleName(), hashCode()), e);
}
;
}
@Override
public void releaseLock() {
if (mLock.isLocked()) {
this.mLock.unlock();
}
}
public void internalReleaseLock() {
if (mSelfLock) {
releaseLock();
mSelfLock = false;
}
}
@Override
public boolean isLockOwnedByCurrentThread() {
return this.mLock.isHeldByCurrentThread();
}
@Override
public ExtendedReentrantLock getLockInstance() {
return this.mLock;
}
/**
* Check the lock state of this object
*
* @return <code>true</code> if there was no previous lock and lock was acquired, <code>false</code> if the lock was
* already owned by the current thread
* @throws ConcurrentModificationException
*/
public boolean checkLock() throws ConcurrentModificationException {
if (!isLockOwnedByCurrentThread() && mLock.isLocked()) {
throw new ConcurrentModificationException(
String.format(
"The current thread (%s) does not have the lock on this instance of %s, owner: %s",
Thread.currentThread(), this.getClass().getSimpleName(),
getLockInstance().getOwnerName()));
} else if (!mLock.isLocked()) {
acquireLock();
mSelfLock = true;
return true;
} else {
mSelfLock = false;
return false;
}
}
// ------------------------------------
@Override
public int hashSolution() {
return hashCode();
}
}// end VRPSolution