/** * */ package vroom.trsp.optimization.mpa; import java.util.Collections; import java.util.Date; import java.util.List; import vroom.common.utilities.Utilities; import vroom.optimization.online.jmsa.IActualRequest; import vroom.optimization.online.jmsa.IDistinguishedSolution; import vroom.optimization.online.jmsa.ISampledRequest; import vroom.optimization.online.jmsa.IScenario; import vroom.trsp.datamodel.ITRSPNode; import vroom.trsp.datamodel.ITRSPTour; import vroom.trsp.datamodel.TRSPInstance; import vroom.trsp.datamodel.TRSPSolution; import vroom.trsp.datamodel.TRSPTour; import vroom.trsp.datamodel.Technician; import vroom.trsp.datamodel.costDelegates.TRSPCostDelegate; /** * <code>DTRSPSolution</code> is an implementation of {@link IScenario} wrapping a {@link TRSPSolution} * <p> * Creation date: Feb 7, 2012 - 10:39:21 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 DTRSPSolution extends TRSPSolution implements IScenario, IDistinguishedSolution { private final long mTimeStamp; /** * Returns the time at which this scenario was created * * @return the time at which this scenario was created */ public long getTimeStamp() { return mTimeStamp; } /** * Returns the time at which this scenario was created as a string * * @return the time at which this scenario was created as a string */ public String getTimeStampString() { return Utilities.Time.TIME_STAMP_FORMAT.format(new Date(mTimeStamp)); } /** * Creates a new <code>DTRSPSolution</code> * * @param parent */ public DTRSPSolution(TRSPSolution parent) { super(parent); mTimeStamp = System.currentTimeMillis(); } @Override protected GiantPermutation clonePermutation(GiantPermutation perm) { DynGiantPermutation clone = new DynGiantPermutation(this); clone.importPermutation(perm); return clone; } @Override protected TRSPTour cloneTour(TRSPTour tour) { return new DTRSPTour(this, tour); } /** * Creates a new <code>DTRSPSolution</code> * * @param instance * the parent instance * @param costDelegate * the cost delegate used to evaluate tours */ public DTRSPSolution(TRSPInstance instance, TRSPCostDelegate costDelegate) { super(instance, costDelegate); mTimeStamp = System.currentTimeMillis(); } @Override protected GiantPermutation newGiantPermutation() { return new DynGiantPermutation(this); } @Override protected TRSPTour newTour(Technician t) { return new DTRSPTour(this, t); } @Override public DTRSPSolution clone() { return new DTRSPSolution(this); } /* * (non-Javadoc) * @see vroom.optimization.online.jmsa.IScenario#getActualRequests() */ @Override public List<? extends IActualRequest> getActualRequests() { // FIXME Implement getActualRequests throw new UnsupportedOperationException(); } @Override public List<? extends ISampledRequest> getSampledRequests() { return Collections.emptyList(); } @Override public IActualRequest getFirstActualRequest(int resource) { // return getInstance().getTRSPNode(getTour(resource).getFirstNode()); TRSPTour t = getTour(resource); ITRSPNode current = getInstance().getSimulator().getCurrentNode(resource); int succ = t.getSucc(current.getID()); return succ != ITRSPTour.UNDEFINED ? getInstance().getTRSPNode(succ) : null; } @Override public IActualRequest fixFirstActualRequest(int resource) { // This is implemented at the instance.simulator/constraint handler level throw new UnsupportedOperationException("Not implemented"); } /* * (non-Javadoc) * @see vroom.optimization.online.jmsa.IScenario#markLastVisitAsServed(int) */ @Override public boolean markLastVisitAsServed(int resource) { // This is implemented at the instance.simulator/constraint handler level throw new UnsupportedOperationException("Not implemented"); } /* * (non-Javadoc) * @see vroom.optimization.online.jmsa.IScenario#getOrderedActualRequests(int) */ @Override public List<? extends IActualRequest> getOrderedActualRequests(int resource) { // This is implemented at the instance.simulator/constraint handler level throw new UnsupportedOperationException("Not implemented"); } @Override public List<? extends ISampledRequest> getOrderedSampledRequests(int resource) { return Collections.emptyList(); } @Override public int getResourceCount() { return getTourCount(); } private int mNonImproving = 0; @Override public void incrementNonImprovingCount() { mNonImproving++; } @Override public void resetNonImprovingCount() { mNonImproving = 0; } @Override public int getNonImprovingCount() { return mNonImproving; } @Override public void dereference() { } @Override public IActualRequest getNextRequest() { throw new UnsupportedOperationException("Must specify a resource"); } @Override public IActualRequest getNextRequest(int resource) { ITRSPNode current = getInstance().getSimulator().getCurrentNode(resource); if (current != null) { int next = getTour(resource).getSucc(current.getID()); return next != ITRSPTour.UNDEFINED ? getInstance().getTRSPNode(next) : null; } else { return getInstance().getTRSPNode(getTour(resource).getFirstNode()); } } @Override protected DTRSPSolution.DynGiantPermutation getGiantPermutation() { return (DynGiantPermutation) super.getGiantPermutation(); } @Override public int hashCode() { return super.defaultHashCode(); } @Override public DTRSPTour getTour(int techId) { return (DTRSPTour) super.getTour(techId); } /** * Freeze this solution to prevent any changes */ public void freeze() { getGiantPermutation().freeze(); } /** * Freeze a specific node to prevent any changes * * @param node * the node to be frozen * @param arrivalTime * the arrival time at the frozen node * @param departureTime * the departure time at the frozen node */ public void freeze(int node, double arrivalTime, double departureTime) { getGiantPermutation().freeze(node, arrivalTime, departureTime); getVisitingTour(node).propagateTime(node); // FIXME this does not propagate slack time properly (25/06/14: // confirmed) getCostDelegate().nodeFrozen(getVisitingTour(node), node); } /** * Unfreeze this solution to allow changes */ public void unfreeze() { getGiantPermutation().unfreeze(); } /** * Return {@code true} if {@code node} is frozen * * @param node * @return {@code true} if {@code node} is frozen */ public boolean isFrozen(int node) { return getGiantPermutation().isFrozen(node); } /** * <code>TRSPDynTour</code> is an extension of {@link TRSPTour} with adjustments for dynamic contexts * <p> * Creation date: Apr 30, 2012 - 10:37:11 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 static class DTRSPTour extends TRSPTour { public DTRSPTour(DTRSPSolution solution, Technician technician) { super(solution, technician); } public DTRSPTour(DTRSPSolution solution, TRSPTour tour) { super(solution, tour.getTechnician()); setAutoUpdated(tour.isAutoUpdated()); setFirst(tour.getFirstNode()); setLast(tour.getLastNode()); setLength(tour.length()); setTotalCost(this.getTotalCost()); } @Override protected DTRSPTour cloneInternal(TRSPSolution solution) { return new DTRSPTour((DTRSPSolution) solution, getTechnician()); } @Override public DTRSPSolution getSolution() { return (DTRSPSolution) super.getSolution(); } @Override protected DTRSPSolution.DynGiantPermutation getPermutation() { return (DTRSPSolution.DynGiantPermutation) super.getPermutation(); } /** * Returns the latest time at which the tour can be started so that it ends at the earliest date possible and no * time window is violated * * @return the latest time at which the tour can be started */ @Override public double getLatestStartTime() { int secondNode = getSucc(getFirstNode()); if (length() < 2) return getEarliestStartTime(); if (getSolution().isFrozen(secondNode)) return getEarliestArrivalTime(secondNode) - getTravelTime(getFirstNode(), secondNode); else if (getPermutation().isFwdSlackTimeDefined()) return getEarliestStartTime() + Math.min(getFwdSlackTime(getFirstNode()), getWaitingTime(getFirstNode(), getLastNode())); else return getEarliestStartTime(); } @Override public double getEarliestDepartureTime(int node) { if (getPermutation().isFrozen(node)) return getPermutation().getEarliestDeparture(node); else return super.getEarliestDepartureTime(node); } /** * Sets the earliest departure time for a node * * @param node * @param time */ public void setEarliestDepartureTime(int node, double time) { if (getPermutation().isFrozen(node)) { getPermutation().setEarliestDeparture(node, time); propagateTime(node); } else throw new IllegalStateException( "Cannot set the earliest departure time of an unfrozen node"); } @Override protected boolean isUpdateAllowed(int node) { return !getSolution().isFrozen(node); } } /** * <code>DynGiantPermutation</code> is an extension of {@link GiantPermutation} that is used in dynamic context * <p> * Creation date: Apr 26, 2012 - 4:56:25 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 static class DynGiantPermutation extends GiantPermutation { private final boolean[] mFrozenNodes; /** the frozen flag, if {@code true} no changes will be permitted **/ private boolean mFrozen; /** the earliest departure time for frozen nodes */ private final double[] mDeparture; /** * Returns {@code true} if this permutation is frozen, {@code false} otherwise * * @return {@code true} if this permutation is frozen, {@code false} otherwise */ public boolean isFrozen() { return this.mFrozen; } /** * Returns {@code true} if the specified {@code node} is frozen, {@code false} otherwise * * @param node * the node to be checked * @return {@code true} if the specified {@code node} is frozen, {@code false} otherwise */ @Override public boolean isFrozen(int node) { return this.mFrozenNodes[node]; } /** * Freeze this permutation to prevent any changes */ public void freeze() { this.mFrozen = true; } /** * Freeze a node to prevent further changes * * @param node * the node to freeze * @param arrivalTime * the arrival time at {@code node} * @param departureTime * the departure time at {@code node} */ public void freeze(int node, double arrivalTime, double departureTime) { super.setEarliestArrivalTime(node, arrivalTime); this.mDeparture[node] = departureTime; this.mFrozenNodes[node] = true; } /** * Unfreeze this permutation to allow changes */ public void unfreeze() { this.mFrozen = false; } /** * Creates a new <code>FreezableGiantPermutation</code> * * @param solution */ public DynGiantPermutation(TRSPSolution solution) { super(solution); mFrozenNodes = new boolean[solution.getInstance().getMaxId()]; mDeparture = new double[solution.getInstance().getMaxId()]; } private void checkState() { if (isFrozen()) throw new IllegalStateException("Attempting to modify a frozen solution"); } @Override public void setAvailableSpareParts(int node, int type, int num) { checkState(); super.setAvailableSpareParts(node, type, num); } @Override public void setCumulativeCost(int node, double value) { checkState(); super.setCumulativeCost(node, value); } @Override public void setEarliestArrivalTime(int node, double time) { checkState(); if (isFrozen(node)) throw new IllegalStateException("Attempting to set a value for a frozen node: " + node); super.setEarliestArrivalTime(node, time); } @Override public void setFwdSlackTime(int i, int j, double slack) { checkState(); super.setFwdSlackTime(i, j, slack); } @Override public void setLatestFeasibleTime(int node, double time) { checkState(); super.setLatestFeasibleTime(node, time); } @Override public void setMainDepotVisited(int node, boolean visited) { checkState(); super.setMainDepotVisited(node, visited); } @Override public void setPred(int node, int pred) { checkState(); super.setPred(node, pred); } @Override public void setRequiredSpareParts(int node, int type, int num) { checkState(); super.setRequiredSpareParts(node, type, num); } @Override public void setSucc(int node, int succ) { checkState(); super.setSucc(node, succ); } @Override public void setToolAvailability(int node, int tool, boolean available) { checkState(); super.setToolAvailability(node, tool, available); } @Override public void setVisitingTechnician(int node, int techId) { checkState(); super.setVisitingTechnician(node, techId); } @Override public void setWaitingTime(int i, int j, double time) { checkState(); super.setWaitingTime(i, j, time); } @Override public void setWaitingTime(int node, double time) { checkState(); super.setWaitingTime(node, time); } @Override protected GiantPermutation cloneInternal(TRSPSolution solution) { DynGiantPermutation clone = new DynGiantPermutation(solution); for (int i = 0; i < mFrozenNodes.length; i++) { clone.mFrozenNodes[i] = this.mFrozenNodes[i]; clone.mDeparture[i] = this.mDeparture[i]; } clone.mFrozen = this.mFrozen; return clone; } @Override protected void importPermutationInternal(GiantPermutation giantPermutation) { DynGiantPermutation perm = (DynGiantPermutation) giantPermutation; for (int i = 0; i < mFrozenNodes.length; i++) { this.mFrozenNodes[i] = perm.mFrozenNodes[i]; this.mDeparture[i] = perm.mDeparture[i]; } this.mFrozen = perm.mFrozen; } @Override protected void resetNodeData(int node) { this.mFrozenNodes[node] = false; this.mDeparture[node] = NA; super.resetNodeData(node); } /** * Sets the earliest departure for a given node * * @param node * @param time */ public void setEarliestDeparture(int node, double time) { if (isFrozen(node)) throw new IllegalStateException("Attempting to set a value for a frozen node " + node); mDeparture[node] = time; } /** * Returns the stored earliest departure for the given node * * @param node * @return the earliest departure time from node */ public double getEarliestDeparture(int node) { return mDeparture[node]; } } }