/** * */ package vroom.trsp.bench.mpa; import vroom.common.utilities.Utilities; import vroom.optimization.online.jmsa.IDistinguishedSolution; import vroom.optimization.online.jmsa.events.MSACallbackBase; import vroom.optimization.online.jmsa.events.MSACallbackEvent; import vroom.optimization.online.jmsa.events.NewRequestEvent; import vroom.optimization.online.jmsa.events.ResourceEvent; import vroom.optimization.online.jmsa.utils.MSASimulationCallback; import vroom.optimization.online.jmsa.utils.MSASimulator.ResourceState; import vroom.optimization.online.jmsa.utils.MSASimulator.ResourceStates; import vroom.trsp.datamodel.ITRSPNode; import vroom.trsp.datamodel.ITRSPNode.NodeType; import vroom.trsp.datamodel.TRSPInstance; import vroom.trsp.datamodel.Technician; import vroom.trsp.util.TRSPLogging; /** * <code>TRSPSimulationCallback</code> is an extension of {@link MSACallbackBase} that is used to control the simulation * process. It listens to MSA and schedules resource events depending on the decisions that are taken. * <p> * Creation date: Mar 15, 2012 - 4:29:05 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 TRSPSimulationCallbackNoWaiting extends MSASimulationCallback { private final DTRSPRunMPA mRun; private boolean mAllResourcesStopped = false; /** * Returns the parent TRSP run * * @return the parent TRSP run */ private DTRSPRunMPA getRun() { return mRun; } /** * Returns the instance being solved * * @return the instance being solved */ private TRSPInstance getInstance() { return getRun().getInstance(); } public TRSPSimulationCallbackNoWaiting(DTRSPRunMPA run) { super(run.getMSASimulator()); mRun = run; } @Override protected void msaStarted(MSACallbackEvent event) { super.msaStarted(event); for (Technician t : getInstance().getFleet()) { // Set the current location as the home of the technician ITRSPNode home = getInstance().getTRSPNode(t.getHome().getID()); getInstance().getSimulator().assignNodeToTechnician(t.getID(), home, getSimulator().simulationTime()); getInstance().getSimulator().setAssignedNodeAsCurrent(t.getID()); } } @Override protected void msaEnded(MSACallbackEvent event) { super.msaEnded(event); // Do nothing } @Override protected void newDistinguishedSolution(MSACallbackEvent event, IDistinguishedSolution oldSol, IDistinguishedSolution newSol) { super.newDistinguishedSolution(event, oldSol, newSol); TRSPLogging .getSimulationLogger() .info("TRSPSimulationCallback.newDistinguishedSolution: new distinguished solution, assigning requests to idle technicians (%s)", newSol); if (newSol == null) { if (mAllResourcesStopped) return; // return; throw new IllegalStateException("Distinguished solution should not be null"); } boolean oneAssign = false; boolean allIdle = true; boolean oneIdle = false; for (Technician t : getInstance().getFleet()) { ResourceState state = getSimulator().getState(t.getID()); if (state.getState() == ResourceStates.IDLE) { ITRSPNode n = (ITRSPNode) newSol.getNextRequest(t.getID()); oneIdle = true; if (n != null) { if (n.getType() != NodeType.HOME || getInstance().getUnservedReleasedRequests().isEmpty()) { // The next node is the technician home: wait until all requests are served // TODO add max tour duration? TRSPLogging .getSimulationLogger() .info("TRSPSimulationCallback.newDistinguishedSolution: assigning %s to technician %s (%s)", n.getDescription(), t.getID(), state); // getInstance().assignRequestToResource((TRSPRequest) r, t.getID()); getRun().getMPA().getEventFactory().raiseRequestAssignedEvent(t.getID(), n); oneAssign = true; } } } else { allIdle = false; } } if (allIdle && !oneAssign && !getInstance().getUnservedReleasedRequests().isEmpty()) throw new IllegalStateException( "All technicicans are idle but no assignment was made, unserved requests: " + Utilities.toShortString(getInstance().getUnservedReleasedRequests())); } @Override protected void resourceStarted(MSACallbackEvent cbEvent, ResourceEvent e) { super.resourceStarted(cbEvent, e); // Schedule a decision event TRSPLogging .getSimulationLogger() .info("TRSPSimulationCallback.resourceStarted: technicians %s available, raising decision event", e.getResourceId()); // getInstance().getSimulator().appendToCurrentSolution( // getInstance().getTechnician(e.getResourceId()).getHome().getID(), e.getResourceId()); getInstance().markRequestAsServed( getInstance().getTRSPNode( getInstance().getFleet().getVehicle(e.getResourceId()).getHome().getID()), e.getResourceId()); getRun().getMPA().getEventFactory().raiseDecisionEvent(); } @Override protected void resourceStopped(MSACallbackEvent cbEvent, ResourceEvent e) { super.resourceStopped(cbEvent, e); // getInstance().getSimulator().assignNodeToTechnician( // e.getResourceId(), // getInstance().getTRSPNode( // getInstance() // .getHomeDuplicate(getInstance().getTechnician(e.getResourceId()).getHome().getID()))); boolean finished = true; // Check if all technicians are back to their home for (Technician t : getRun().getInstance().getFleet()) if (!getRun().getMPA().getInstance().isResourceStopped(t.getID())) { finished = false; break; } mAllResourcesStopped = finished; if (finished) { getSimulator().stop(); TRSPLogging .getSimulationLogger() .info("TRSPSimulationCallback.resourceStopped: all technicians are back to their home, stopping"); getRun().getMPA().stop(); } } @Override protected void requestAssigned(MSACallbackEvent cbEvent, ResourceEvent e) { super.requestAssigned(cbEvent, e); ITRSPNode n = (ITRSPNode) e.getRequest(); int next = n.getID(); int current = getRun().getSimulator().getCurrentNode(e.getResourceId()).getID(); double travelTime = getRun() .getInstance() .getCostDelegate() .getTravelTime(current, next, getRun().getInstance().getTechnician(e.getResourceId())); // Schedule the start of service double startTime = Math.max(getSimulator().simulationTime() + travelTime, n.getTimeWindow() .startAsDouble()); TRSPLogging .getSimulationLogger() .info("TRSPSimulationCallback.requestAssigned: %s assigned to %s, simulating travel time and scheduling start of service at %.2f", n.getDescription(), e.getResourceId(), startTime); getSimulator().scheduleEvent( ResourceEvent.newStartOfServiceEvent(startTime, getRun().getMPA().getEventFactory(), e.getResourceId(), getRun() .getInstance().getTRSPNode(next), null)); } @Override protected void startOfService(MSACallbackEvent cbEvent, ResourceEvent e) { super.startOfService(cbEvent, e); ITRSPNode n = (ITRSPNode) e.getRequest(); getRun().getSimulator().setAssignedNodeAsCurrent(e.getResourceId()); TRSPLogging .getSimulationLogger() .info("TRSPSimulationCallback.startOfService: %s being served by %s, simulating service time and scheduling end of service", n.getDescription(), e.getResourceId()); double time = e.getSimulationTimeStamp() + n.getServiceTime(); if (time < getSimulator().simulationTime()) time = getSimulator().simulationTime(); getSimulator().scheduleEvent( ResourceEvent.newEndOfServiceEvent(time, getRun().getMPA().getEventFactory(), e.getResourceId(), n, null)); } @Override protected void endOfService(MSACallbackEvent cbEvent, ResourceEvent e) { super.endOfService(cbEvent, e); ITRSPNode n = (ITRSPNode) e.getRequest(); if (n.getID() == getInstance().getHomeDuplicate( getInstance().getTechnician(e.getResourceId()).getHome().getID())) { // The served request is the technician home, schedule resource stop TRSPLogging .getSimulationLogger() .info("TRSPSimulationCallback.endOfService: %s served by %s, raising resource stop event (technician returned to home)", n.getDescription(), e.getResourceId()); getSimulator().scheduleEvent( ResourceEvent.newStopServiceEvent(getSimulator().simulationTime(), getRun() .getMPA().getEventFactory(), e.getResourceId(), null)); } else { TRSPLogging.getSimulationLogger().info( "TRSPSimulationCallback.endOfService: %s served by %s, raising decision event", n.getDescription(), e.getResourceId()); getRun().getMPA().getEventFactory().raiseDecisionEvent(); } } @Override protected void newRequest(MSACallbackEvent event, NewRequestEvent e) { super.newRequest(event, e); } @Override protected void beforeExecute(MSACallbackEvent event) { super.beforeExecute(event); getSimulator().pause(); } @Override protected void afterExecture(MSACallbackEvent event) { super.afterExecture(event); getSimulator().resume(); } }