package vroom.optimization.online.jmsa;
import static vroom.optimization.online.jmsa.events.MSACallbackEvent.EventTypes.MSA_EVENT_HANDLING_END;
import static vroom.optimization.online.jmsa.events.MSACallbackEvent.EventTypes.MSA_EVENT_HANDLING_START;
import static vroom.optimization.online.jmsa.events.MSACallbackEvent.EventTypes.MSA_NEW_EVENT;
import java.util.Arrays;
import vroom.common.heuristics.ProcedureStatus;
import vroom.common.utilities.ExtendedReentrantLock;
import vroom.common.utilities.Stopwatch;
import vroom.common.utilities.events.EventHandlingException;
import vroom.common.utilities.events.IEventHandler;
import vroom.optimization.online.jmsa.components.RequestSamplerParam;
import vroom.optimization.online.jmsa.components.ScenarioGeneratorParam;
import vroom.optimization.online.jmsa.events.GenerateEvent;
import vroom.optimization.online.jmsa.events.MSAEvent;
import vroom.optimization.online.jmsa.events.OptimizeEvent;
import vroom.optimization.online.jmsa.utils.MSALogging;
/**
* <code>MSASequential</code> is the class responsible for running a multiple scenario approach procedure.
*
* @param <S>
* the type of scenario that will be handled in by the MSA algorithm
* @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 #updated 16-Feb-2010 10:06:45 a.m.
*/
public class MSASequential<S extends IScenario, I extends IInstance> extends MSABase<S, I> {
/**
* Constructor for a new MSA procedure
*
* @param parameters
* the global parameters that will be used for this MSA procedure
* @param instance
* the instance on which this msa procedure will be based
* @see MSAGlobalParameters
*/
public MSASequential(I instance, MSAGlobalParameters parameters) {
super(instance, parameters);
}
/**
* Utility method used to log a message if the procedure has to be aborted
*
* @return <code>true</code> if the procedure is to be continued, <code>false</code> if it has to be aborted
*/
private boolean checkRunningState() {
// Abort if the the procedure is no longer running
if (!isRunning()) {
MSALogging.getProcedureLogger().info(
"MSA procedure is not running - aborting running:%s paused:%s", isRunning(),
isPaused());
return false;
} else {
return true;
}
}
/**
* The main method for the MSA procedure
*/
@Override
protected void msaProcedure() {
Stopwatch procTimer = new Stopwatch();
setStatus(ProcedureStatus.INITIALIZATION);
setInitialized(false);
int poolSize = getParameter(MSAGlobalParameters.POOL_SIZE);
double initialProp = getParameter(MSAGlobalParameters.POOL_INITIAL_PROPORTION);
int sampledReqCount = getParameter(MSAGlobalParameters.SAMPLED_REQUEST_COUNT);
ScenarioGeneratorParam params = new ScenarioGeneratorParam((int) (poolSize * initialProp),
getParameter(MSAGlobalParameters.GEN_MAX_SCEN_OPT_TIME), new RequestSamplerParam(
sampledReqCount));
procTimer.start();
MSALogging.getProcedureLogger().info("Scenario pool initialization started: %s", params);
mComponentManager.generateScenarios(params);
setStatus(ProcedureStatus.INITIALIZED);
setInitialized(true);
procTimer.stop();
MSALogging.getProcedureLogger().info(
"Scenario pool initialization terminated in %ss (%s scenarios in the pool)",
procTimer.readTimeS(), mPool.size());
MSALogging.getProcedureLogger().debug("Current state: %ss", this);
mEventFactory.raiseOptimizeEvent();
setStatus(ProcedureStatus.RUNNING);
while (isRunning()) {
// TODO add periodic cleaning of the pool
MSALogging.getProcedureLogger().lowDebug("Processing of the next event");
try {
waitUntilUnpaused();
} catch (InterruptedException e) {
// The waiting has been interrupted
// - Log the error
MSALogging
.getProcedureLogger()
.exception(
"MSASequential.msaProcedure while waiting for the next event, aborting the MSA procedure",
e);
// - Terminate the MSA procedure
setStatus(ProcedureStatus.EXCEPTION);
stop();
}
// Get the next event
setCurrentEvent(null);
try {
setCurrentEvent(this.takeNextEvent());
} catch (InterruptedException e) {
MSALogging
.getProcedureLogger()
.exception(
"MSASequential.msaProcedure while retrieving the next event, aborting the MSA procedure",
e);
// - Terminate the MSA procedure
setStatus(ProcedureStatus.EXCEPTION);
stop();
}
// Abort if the the procedure is no longer running
if (!checkRunningState()) {
break;
}
// If the event is null, then this iteration should be
// aborted
if (getCurrentEvent() == null) {
break;
}
MSALogging.getProcedureLogger().lowDebug("Next event successfully retreived: %s",
getCurrentEvent());
MSALogging.getProcedureLogger().lowDebug("Event queue: %s)",
Arrays.toString(mEventQueue.getPendingEvents()));
// Get the associated event handler
IEventHandler<MSAEvent> handler = mEventHandlerManager
.getEventHandler(getCurrentEvent());
// Check if the handler exists
if (handler == null) {
// Log the error
MSALogging
.getProcedureLogger()
.error("MSA procedure was not able to handle the event : there is no hanlder associated with this event (%s)",
getCurrentEvent());
} else {
MSALogging.getProcedureLogger().lowDebug(
"Event handler successfully retreived (%s)", handler);
// Abort if the the procedure is no longer running
if (!checkRunningState()) {
break;
}
// Execute callbacks
callbacks(MSA_NEW_EVENT, getCurrentEvent(), handler);
// Abort if the the procedure is no longer running
if (!checkRunningState()) {
break;
}
// Check if the handler can handle the event
if (handler.canHandleEvent(getCurrentEvent())) {
try {
waitUntilUnpaused();
} catch (InterruptedException e) {
// The waiting has been interrupted
// - Log the error
MSALogging
.getProcedureLogger()
.exception(
"MSASequential.msaProcedure while waiting for the next event, aborting the MSA procedure",
e);
// - Terminate the MSA procedure
stop();
}
// Handle the event
// Add parameters when relevant
if (getCurrentEvent() instanceof GenerateEvent) {
((GenerateEvent) getCurrentEvent()).setParameters(getGenerateParameters());
} else if (getCurrentEvent() instanceof OptimizeEvent) {
((OptimizeEvent) getCurrentEvent())
.setParameters(getOptimizeParameters(getCurrentEvent()));
}
MSALogging.getProcedureLogger().lowDebug(
"Handling of the event %s by handler %s", getCurrentEvent(), handler);
// Execute callbacks
callbacks(MSA_EVENT_HANDLING_START, getCurrentEvent(), handler);
// Abort if the the procedure is no longer running
if (!checkRunningState()) {
break;
}
// Handle the event
try {
handler.handleEvent(getCurrentEvent());
} catch (EventHandlingException e) {
// Log the exception
MSALogging.getProcedureLogger().error(
"MSA procedure was not able to handle the event %s",
getCurrentEvent(), e);
}
} else {
// The handler cannot handle the event: log the error
MSALogging
.getProcedureLogger()
.warn("MSA procedure was not able to handle the next event: the associated handler %s cannot handle the event %s, current state: %s",
handler, getCurrentEvent(), this);
}
}
MSALogging.getProcedureLogger().lowDebug("Event handling finished");
// Abort if the the procedure is no longer running
if (!checkRunningState()) {
break;
}
// Execute the callbacks
callbacks(MSA_EVENT_HANDLING_END, getCurrentEvent(), handler);
}
setStatus(ProcedureStatus.TERMINATED);
}
/**
* Waits for an event to become available
*
* @return the next event from the event manager
* @throws InterruptedException
*/
synchronized MSAEvent takeNextEvent() throws InterruptedException {
// if (this.mEventQueue.isEmpty())
// Logging
// .getProcedureLogger()
// .debug(
// "No event is currently available, will wait untill a new event becomes available");
final ExtendedReentrantLock lock = mLock;
lock.lockInterruptibly();
try {
while (mEventQueue.isEmpty() && isRunning()) {
// Checks the paused state
while (isPaused() && isRunning()) {
// Wait for the procedure to be unpaused
mPausedCondition.await();
}
if (isRunning() && mEventQueue.isEmpty()) {
// Waits 100ms if no event is available
// We wait only 100ms in case the procedure is paused in
// the meantime
// Logging.getProcedureLogger().lowDebug(
// "No event available, waiting 100ms");
mEventQueue.awaitForNewEvent(100);
}
}
if (!isRunning()) {
return null;
} else {
// Logging.getProcedureLogger().lowDebug(
// "A event is available, returning it");
return mEventQueue.pollNextEvent();
}
} catch (InterruptedException ie) {
mPausedCondition.signal(); // propagate to non-interrupted
// thread
throw ie;
} finally {
lock.unlock();
}
}
}