package vroom.optimization.online.jmsa;
import static vroom.common.utilities.ILockable.TRY_LOCK_TIMOUT;
import static vroom.common.utilities.ILockable.TRY_LOCK_TIMOUT_UNIT;
import static vroom.optimization.online.jmsa.events.MSACallbackEvent.EventTypes.MSA_END;
import static vroom.optimization.online.jmsa.events.MSACallbackEvent.EventTypes.MSA_NEW_DISTINGUISHED_SOLUTION;
import static vroom.optimization.online.jmsa.events.MSACallbackEvent.EventTypes.MSA_START;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.Observable;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.log4j.Level;
import umontreal.iro.lecuyer.rng.MRG32k3a;
import umontreal.iro.lecuyer.rng.RandomStream;
import vroom.common.heuristics.ProcedureStatus;
import vroom.common.utilities.ExtendedReentrantLock;
import vroom.common.utilities.Stopwatch;
import vroom.common.utilities.Stopwatch.ReadOnlyStopwatch;
import vroom.common.utilities.callbacks.CallbackManagerDelegate;
import vroom.common.utilities.callbacks.ICallback;
import vroom.common.utilities.events.EventHandlerManager;
import vroom.common.utilities.events.IEvent;
import vroom.common.utilities.logging.LoggerHelper;
import vroom.common.utilities.logging.Logging;
import vroom.common.utilities.optimization.IStoppingCriterion;
import vroom.common.utilities.params.ParameterKey;
import vroom.common.utilities.ssj.IRandomSource;
import vroom.optimization.online.jmsa.components.ComponentManager;
import vroom.optimization.online.jmsa.components.RequestSamplerParam;
import vroom.optimization.online.jmsa.components.ScenarioGeneratorParam;
import vroom.optimization.online.jmsa.components.ScenarioOptimizerParam;
import vroom.optimization.online.jmsa.events.DecisionEvent;
import vroom.optimization.online.jmsa.events.DecisionHandler;
import vroom.optimization.online.jmsa.events.GenerateEvent;
import vroom.optimization.online.jmsa.events.GenerateHandler;
import vroom.optimization.online.jmsa.events.IMSAEventFactory;
import vroom.optimization.online.jmsa.events.MSACallbackBase;
import vroom.optimization.online.jmsa.events.MSACallbackEvent;
import vroom.optimization.online.jmsa.events.MSACallbackEvent.EventTypes;
import vroom.optimization.online.jmsa.events.MSAEvent;
import vroom.optimization.online.jmsa.events.MSAEventHandler;
import vroom.optimization.online.jmsa.events.MSAEventQueue;
import vroom.optimization.online.jmsa.events.NewRequestEvent;
import vroom.optimization.online.jmsa.events.NewRequestHandler;
import vroom.optimization.online.jmsa.events.OptimizeEvent;
import vroom.optimization.online.jmsa.events.OptimizeHandler;
import vroom.optimization.online.jmsa.events.PoolUpdateEvent;
import vroom.optimization.online.jmsa.events.PoolUpdateHandler;
import vroom.optimization.online.jmsa.events.ResourceEvent;
import vroom.optimization.online.jmsa.events.ResourceHandler;
import vroom.optimization.online.jmsa.utils.MSALogging;
/**
* The Class <code>MSABase</code> is a base implementation of the MSA procedure
* <p>
* Creation date: Sep 21, 2010 - 3:21:21 PM.
*
* @param <S>
* the generic type
* @param <I>
* the generic type
* @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 abstract class MSABase<S extends IScenario, I extends IInstance> extends Observable
implements Runnable, IRandomSource {
public static final long MAX_FIRST_SEEDS = 4294967087l;
public static final long MAX_LAST_SEEDS = 4294944443l;
/**
* <code>MSAProxy</code> is a proxy class to restrict access to MSA fields to the authorized classes.
*
* @param <SS>
* the generic type
* @param <II>
* the generic type
* @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
* Nanntes</a>-<a href= "http://www.irccyn.ec-nantes.fr/irccyn/d/en/equipes/Slp">SLP</a>
*/
public static class MSAProxy<SS extends IScenario, II extends IInstance> {
/** The parent. */
private final MSABase<SS, II> parent;
/**
* Instantiates a new mSA proxy.
*
* @param msaBase
* the msa base
*/
MSAProxy(MSABase<SS, II> msaBase) {
this.parent = msaBase;
}
/**
* Execute the callbacks associated with <code>event</code>.
*
* @param eventType
* the event type that has occurred and for which the associated callbacks will be run
* @param params
* an optional parameter that will be transmitted to the callback
*/
public void callbacks(MSACallbackEvent.EventTypes eventType, Object... params) {
this.parent.callbacks(eventType, params);
}
/**
* Getter for the component manager.
*
* @return the component manager of the associated MSA instance
*/
public ComponentManager<SS, II> getComponentManager() {
return this.parent.mComponentManager;
}
/**
* Getter proy for the distinguished solution.
*
* @return The current distinguished solution
* @see MSASequential#getDistinguishedSolution()
*/
public IDistinguishedSolution getDistinguishedSolution() {
return this.parent.getDistinguishedSolution();
}
/**
* Getter for the instance.
*
* @return the instance associated with this msa procedure
*/
public II getInstance() {
return this.parent.mInstance;
}
/**
* Getter for the global parameters.
*
* @return the global parameters associated with this msa procedure
*/
public MSAGlobalParameters getParameters() {
return this.parent.getParameters();
}
/**
* Getter for the scenario pool.
*
* @return the scenario pool of this msa procedure
*/
public ScenarioPool<SS> getScenarioPool() {
return this.parent.mPool;
}
/**
* Setter for the distinguished solution, should only be called by instances of {@link DecisionHandler}.
*
* @param distinguishedSolution
* The new distinguished solution
*/
public void setDistinguishedSolution(IDistinguishedSolution distinguishedSolution) {
IDistinguishedSolution oldValue = this.parent.mDistinguishedSolution;
this.parent.mDistinguishedSolution = distinguishedSolution;
this.parent.callbacks(MSA_NEW_DISTINGUISHED_SOLUTION, oldValue,
this.parent.mDistinguishedSolution);
}
/**
* Getter for the main {@link RandomStream}
*
* @return the main {@link RandomStream} used in this msa instance
*/
public RandomStream getRandomStream() {
return this.parent.getRandomStream();
}
/**
* Getter for the {@link RandomStream} used in scenario optimization
*
* @return the {@link RandomStream} used to optimize scenarios
*/
public RandomStream getOptimizationRandomStream() {
return this.parent.getOptimizationRandomStream();
}
/**
* Getter for the {@link RandomStream} used in decisions
*
* @return the {@link RandomStream} used to take decisions
*/
public RandomStream getDecisionRandomStream() {
return this.parent.getDecisionRandomStream();
}
/**
* Getter for the {@link RandomStream} used in scenario generation
*
* @return the {@link RandomStream} used to generate new scenarios
*/
public RandomStream getGenerationRandomStream() {
return this.parent.getGenerationRandomStream();
}
/**
* Checks if a preemptive event was received
*
* @return <code>true</code> if the next event in the queue is preemptive
*/
public boolean isNextEventPreemptive() {
return !this.parent.isRunning() || this.parent.mEventQueue.isNextEventPreemptive();
}
/**
* Factory method for a {@link MSABaseStoppingCriterion}
*
* @param stoppingCriterion
* the base stopping criterion
* @param interruptible
* <code>true</code> if the process is interruptible
* @return an instance of {@link MSABaseStoppingCriterion} wrapping the provided <code>stoppingCriterion</code>
*/
@SuppressWarnings("unchecked")
public IStoppingCriterion newStoppingCriterion(IStoppingCriterion stoppingCriterion,
boolean interruptible) {
if (stoppingCriterion instanceof MSABase.MSAProxy.MSABaseStoppingCriterion) {
return new MSABaseStoppingCriterion(
((MSABaseStoppingCriterion) stoppingCriterion).getParentCriterion(),
interruptible);
} else {
return new MSABaseStoppingCriterion(stoppingCriterion, interruptible);
}
}
/**
* The Class <code>MSABaseStoppingCriterion</code> is an implementation of {@link IStoppingCriterion} that wraps
* an instance of {@link IStoppingCriterion} and additionally checks if there are
* {@linkplain IEvent#isPreemptive() preemptive} events in the event queue.
* <p>
* {@link #isStopCriterionMet()} will return <code>true</code> if this criterion is interruptible and a
* preemptive event is present. This is useful to terminate subroutines.
* </p>
* <p>
* Creation date: Nov 30, 2010 - 4:12:44 PM.
* </p>
*
* @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 MSABaseStoppingCriterion implements IStoppingCriterion {
private final IStoppingCriterion mCriterion;
private final boolean mInterruptible;
/**
* Creates a new <code>MSABaseStoppingCriterion</code>
*
* @param criterion
*/
private MSABaseStoppingCriterion(IStoppingCriterion criterion, boolean interruptible) {
mCriterion = criterion;
mInterruptible = interruptible;
}
@Override
public boolean isStopCriterionMet() {
return mCriterion.isStopCriterionMet()
|| (mInterruptible && isNextEventPreemptive());
}
@Override
public void update(int iterations, Object... args) {
mCriterion.update(iterations, args);
}
@Override
public void update(Object... args) {
mCriterion.update(args);
}
@Override
public void reset() {
mCriterion.reset();
}
@Override
public void init() {
mCriterion.init();
}
/**
* Returns the wrapped criterion
*
* @return the wrapped criterion
*/
public IStoppingCriterion getParentCriterion() {
return mCriterion;
}
/**
* Returns <code>true</code> if the criterion is used for an interruptible process
*
* @return<code>true</code> if the criterion is used for an interruptible process
*/
public boolean isInterruptible() {
return mInterruptible;
}
@Override
public int getIterationCount() {
return mCriterion.getIterationCount();
}
@Override
public int getMaxIterations() {
return mCriterion.getMaxIterations();
}
@Override
public double getCurrentTime() {
return mCriterion.getCurrentTime();
}
@Override
public long getMaxTime() {
return mCriterion.getMaxTime();
}
@Override
public MSABaseStoppingCriterion clone() {
return new MSABaseStoppingCriterion(mCriterion.clone(), mInterruptible);
}
}
}
private ProcedureStatus mState;
/**
* Returns the current state of the procedure
* <p>
* Possible values are:
* <ul>
* <li>{@link ProcedureStatus#INSTANTIATED}</li>
* <li>{@link ProcedureStatus#INITIALIZATION}</li>
* <li>{@link ProcedureStatus#INITIALIZED}</li>
* <li>{@link ProcedureStatus#RUNNING}</li>
* <li>{@link ProcedureStatus#PAUSED}</li>
* <li>{@link ProcedureStatus#TERMINATED}</li>
* <li>{@link ProcedureStatus#EXCEPTION}</li>
* </ul>
* </p>
*
* @return the current state of the procedure
*/
public ProcedureStatus getStatus() {
return mState;
}
/**
* Set the current state of the procedure
* <p>
* Possible values are:
* <ul>
* <li>{@link ProcedureStatus#INSTANTIATED}</li>
* <li>{@link ProcedureStatus#INITIALIZATION}</li>
* <li>{@link ProcedureStatus#INITIALIZED}</li>
* <li>{@link ProcedureStatus#RUNNING}</li>
* <li>{@link ProcedureStatus#PAUSED}</li>
* <li>{@link ProcedureStatus#TERMINATED}</li>
* <li>{@link ProcedureStatus#EXCEPTION}</li>
* </ul>
* </p>
*
* @param state
*/
protected void setStatus(ProcedureStatus state) {
if (mState != ProcedureStatus.EXCEPTION) {
acquireLock();
mState = state;
getStatusCond().signalAll();
releaseLock();
}
}
/**
* Returns a condition on the current state of the procedure
*
* @return a condition on the current state of the procedure
*/
public Condition getStatusCond() {
return mStatusCond;
}
/**
* Pause the main MSA procedure</br> This will cause the main procedure to be suspended before the retrieval of the
* next event or before the handling of the current event.
*/
public void pause() {
setPaused(true);
setStatus(ProcedureStatus.PAUSED);
}
/**
* Msa procedure.
*/
protected abstract void msaProcedure();
/** The name of the distinguished solution property. */
public static final String PROP_DISTINGUISHED_SOL = "DistinguishedSolution";
/** The name of the paused property. */
private static final String PROP_PAUSED = "Paused";
/** The number of initialized MSA procedures. */
protected static int sMSACount = 0;
/**
* The callback manager delegate used to register, unregister and call callback procedures.
*/
protected final CallbackManagerDelegate<MSABase<?, ?>, EventTypes> mCallbackManagerDelegate;
/** The object responsible for the management of MSA components. */
protected final ComponentManager<S, I> mComponentManager;
/** The current distinguished solution. */
private IDistinguishedSolution mDistinguishedSolution;
/**
* The event factory associated with this MSA procedure. All events should be created by this instance
*/
protected final IMSAEventFactory mEventFactory;
/**
* The event handler manager for this MSA procedure. It is responsible of the association of handlers to events for
* their handling
*/
protected final EventHandlerManager mEventHandlerManager;
/**
* The event manager for this MSA procedure. It is responsible of the reception and handling of incoming events.
*/
protected final MSAEventQueue mEventQueue;
/**
* The event being currently handled
*/
private MSAEvent mCurrentEvent;
/**
* Returns the event being currently handled
*
* @return the event being currently handled
*/
public MSAEvent getCurrentEvent() {
return mCurrentEvent;
}
/**
* Setter for the event being currently handled
*
* @param currentEvent
* the currentEvent to set
*/
void setCurrentEvent(MSAEvent currentEvent) {
mCurrentEvent = currentEvent;
}
/** <code>true</code> if the scenario pool has been initialized *. */
private boolean mInitialized;
/** The instance on which thiw MSA is based. */
protected final I mInstance;
private final ExtendedReentrantLock mPublicLock = new ExtendedReentrantLock(
true);
/** A private lock for this object. */
protected final ExtendedReentrantLock mLock = new ExtendedReentrantLock(
true);
/** A condition on the initialized state. */
private final Condition mInitializedCond = this.mPublicLock
.newCondition();
/** The Paused condition. */
protected final Condition mPausedCondition = this.mLock.newCondition();
/**
* The running status of this MSA procedure: <code>true</code> if started, <code>false</code> if not started yet or
* stopped.
*/
private boolean mRunning = false;
/** A condition on the running state. */
private final Condition mRunningCond = this.mPublicLock
.newCondition();
/** A condition on the current state of the procedure. */
private final Condition mStatusCond = this.mPublicLock
.newCondition();
/** An id for this procedure. */
protected final int mMSAId;
/** The global parameters used by this instance of the MSA procedure. */
protected final MSAGlobalParameters mParameters;
/**
* The paused status of this MSA procedure: <code>true</code> if it is currently paused, <code>false</code> if not.
*/
private boolean mPaused = true;
/** The pool of scenario used by this procedure. */
protected final ScenarioPool<S> mPool;
/** A proxy to restrict access to instance properties. */
protected final MSAProxy<S, I> mProxy;
/** A public lock for observable properties. */
/** A timer for this msa instance *. */
protected final Stopwatch mTimer;
/** The key to which the main random stream is associated */
public static final String MAIN_RANDOM_STREAM = "MSARndStream";
/** The key to which the optimization random stream is associated */
public static final String OPTIMIZATION_RANDOM_STREAM = "MSAOptRndStream";
/** The key to which the decision random stream is associated */
public static final String DECISION_RANDOM_STREAM = "MSADecRndStream";
/** The key to which the generation random stream is associated */
public static final String GENERATION_RANDOM_STREAM = "MSAGenRndStream";
private RandomStream mMainRndStream;
private RandomStream mOptRndStream;
private RandomStream mDecRndStream;
private RandomStream mGenRndStream;
/**
* Instantiates a new mSA base.
*
* @param instance
* the instance
* @param parameters
* the parameters
*/
public MSABase(I instance, MSAGlobalParameters parameters) {
super();
// Sets the id of this MSA instance
this.mMSAId = sMSACount;
sMSACount++;
this.mProxy = new MSAProxy<S, I>(this);
Collection<ParameterKey<?>> missingParams = parameters.checkRequiredParameters();
if (!missingParams.isEmpty()) {
MSALogging.getSetupLogger().warn(
"The following required global parameters have not been defined: "
+ missingParams.toString());
}
this.mInstance = instance;
this.mParameters = parameters;
long[] seeds = this.mParameters.get(MSAGlobalParameters.RANDOM_SEEDS);
Long paramSeeds = this.mParameters.get(MSAGlobalParameters.RANDOM_SEED);
Long seed = seeds != null ? seeds[0] : paramSeeds != null ? paramSeeds : System
.currentTimeMillis();
long[] seedsMain = new long[6];
if (seed != null) {
Random r = new Random(seed);
for (int i = 0; i < seedsMain.length; i++) {
seedsMain[i] = seeds != null && i < seeds.length ? seeds[i] : (long) Math.floor(r
.nextDouble() * 4294944443l);
}
}
MRG32k3a rnd = new MRG32k3a(MAIN_RANDOM_STREAM);
rnd.setSeed(seedsMain);
setRandomStream(rnd);
this.mPool = new ScenarioPool<S>(getParameter(MSAGlobalParameters.POOL_SIZE));
this.mCallbackManagerDelegate = new CallbackManagerDelegate<MSABase<?, ?>, EventTypes>(
"msa");
this.mEventQueue = new MSAEventQueue();
this.mComponentManager = getParameters().newInstance(
MSAGlobalParameters.COMPONENT_MANAGER_CLASS, this, this.mProxy);
this.mEventFactory = getParameters().<IMSAEventFactory> newInstance(
MSAGlobalParameters.EVENT_FACTORY_CLASS, this, this.mEventQueue);
this.mEventHandlerManager = new EventHandlerManager();
setDefaultEventHandlers();
this.mTimer = new Stopwatch();
mState = ProcedureStatus.INSTANTIATED;
}
/**
* Acquire lock.
*/
public void acquireLock() {
try {
if (!mPublicLock.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, mPublicLock.getOwnerName()));
}
} catch (InterruptedException e) {
throw new IllegalStateException(String.format(
"Unable to acquire lock on this instance of %s (%s)", this.getClass()
.getSimpleName(), hashCode()), e);
}
;
}
/**
* Execute the callbacks associated with <code>event</code>.
*
* @param eventType
* the event type that has occurred and for which the associated callbacks will be run
* @param params
* an optional parameter that will be transmitted to the callback
*/
public void callbacks(MSACallbackEvent.EventTypes eventType, Object... params) {
this.mCallbackManagerDelegate.callbacks(new MSACallbackEvent(eventType, this, params));
}
/**
* Check lock.
*
* @throws ConcurrentModificationException
* the concurrent modification exception
*/
public void checkLock() throws ConcurrentModificationException {
if (!isLockOwnedByCurrentThread()) {
throw new ConcurrentModificationException(String.format(
"The current thread (%s) does not have the lock on this object",
Thread.currentThread()));
}
}
// ------------------------------------
/*
* (non-Javadoc)
* @see java.lang.Object#finalize()
*/
@Override
protected void finalize() throws Throwable {
stopChildThreads();
super.finalize();
}
/**
* Stop child threads.
*/
protected void stopChildThreads() {
this.mCallbackManagerDelegate.stop();
}
/**
* Gets the components description.
*
* @return the components description
*/
public String getComponentsDescription() {
return mComponentManager.toString();
}
/**
* Getter for the current solution.
* <p/>
* This method will return an object representing the current (or final is the MSA procedure is terminated) request
* sequence that have been served by each resource.
*
* @return the current solution
* @see IInstance#getCurrentSolution()
*/
public Object getCurrentSolution() {
return getInstance().getCurrentSolution();
}
/**
* Getter for the distinguished solution.
*
* @return The current distinguished solution
*/
public IDistinguishedSolution getDistinguishedSolution() {
return this.mDistinguishedSolution;
}
/**
* Gets the event factory.
*
* @return the eventFactory associated with this MSA procedure. All events should be created by this instance
*/
public IMSAEventFactory getEventFactory() {
return this.mEventFactory;
}
/**
* Scenario generation parameters.
*
* @return the parameters to be used for scenario generation
*/
public ScenarioGeneratorParam getGenerateParameters() {
// TODO find a way to dynamically define these parameters
return new ScenarioGeneratorParam(
// getParameter(MSAGlobalParameters.POOL_SIZE),
(int) (getParameter(MSAGlobalParameters.POOL_SIZE) * 0.2),
getParameter(MSAGlobalParameters.GEN_MAX_SCEN_OPT_TIME), new RequestSamplerParam(
getParameter(MSAGlobalParameters.SAMPLED_REQUEST_COUNT)));
}
/**
* A {@link Condition} on the {@linkplain #isInitialized() initialized state} for external monitoring of the MSA
* running state.
*
* @return the {@link Condition} associated with the initialized state of this procedure
*/
public Condition getInitializedCondition() {
return this.mInitializedCond;
}
/**
* Getter for the underlying instance.
*
* @return the instance on which this MSA procedure is based
*/
public I getInstance() {
return this.mInstance;
}
/**
* Gets the lock instance.
*
* @return the lock instance
*/
public ReentrantLock getLockInstance() {
return this.mPublicLock;
}
/**
* Scenario optimization parameters.
*
* @return the parameters to be used for scenario generation
*/
public ScenarioOptimizerParam getOptimizeParameters(MSAEvent event) {
return new ScenarioOptimizerParam(
(int) (getParameter(MSAGlobalParameters.OPT_MAX_SCEN_OPT_TIME) * mPool.size() * 0.5),
getParameter(MSAGlobalParameters.OPT_MAX_SCEN_OPT_TIME), !event.isPreemptive());
}
/**
* Utility class to read parameters.
*
* @param <T>
* the generic type
* @param key
* the key for the desired parameter
* @return the value associated with the given <code>key</code>, <code>null</code> if there is no value associated
* with <code>key</code>
* @throws IllegalArgumentException
* if no value is associated with <code>key</code>
*/
protected <T> T getParameter(ParameterKey<T> key) throws IllegalArgumentException {
return getParameters().get(key);
}
/**
* Getter for the msa parameters.
*
* @return the global parameters used by this instance of the MSA procedure
*/
public final MSAGlobalParameters getParameters() {
return this.mParameters;
}
/**
* Getter for the MSA proxy.
*
* @return a proxy for some properties of this procedure
*/
public MSAProxy<S, I> getProxy() {
return this.mProxy;
}
@Override
public RandomStream getRandomStream() {
return mMainRndStream;
}
@Override
public void setRandomStream(RandomStream stream) {
mMainRndStream = stream;
// Generate the other random streams
long[] seedsOpt = new long[6];
long[] seedsGen = new long[6];
long[] seedsDec = new long[6];
for (int i = 0; i < seedsDec.length; i++) {
long max = i < 3 ? MAX_FIRST_SEEDS : MAX_LAST_SEEDS;
seedsOpt[i] = (long) Math.floor(stream.nextDouble() * max);
seedsGen[i] = (long) Math.floor(stream.nextDouble() * max);
seedsDec[i] = (long) Math.floor(stream.nextDouble() * max);
}
mGenRndStream = new MRG32k3a(GENERATION_RANDOM_STREAM);
((MRG32k3a) mGenRndStream).setSeed(seedsGen);
mDecRndStream = new MRG32k3a(DECISION_RANDOM_STREAM);
((MRG32k3a) mDecRndStream).setSeed(seedsDec);
mOptRndStream = new MRG32k3a(OPTIMIZATION_RANDOM_STREAM);
((MRG32k3a) mOptRndStream).setSeed(seedsOpt);
}
/**
* Getter for the {@link RandomStream} used in scenario optimization
*
* @return the {@link RandomStream} used to optimize scenarios
*/
public RandomStream getOptimizationRandomStream() {
return mOptRndStream;
}
/**
* Getter for the {@link RandomStream} used in decisions
*
* @return the {@link RandomStream} used to take decisions
*/
public RandomStream getDecisionRandomStream() {
return mDecRndStream;
}
/**
* Getter for the {@link RandomStream} used in scenario generation
*
* @return the {@link RandomStream} used to generate new scenarios
*/
public RandomStream getGenerationRandomStream() {
return mGenRndStream;
}
/**
* Getter for timer : A timer for this msa instance.
*
* @return the timer used in this instance
*/
public ReadOnlyStopwatch getTimer() {
return this.mTimer.getReadOnlyStopwatch();
}
/**
* Getter for initialized : <code>true</code> if the scenario pool has been initialized.
*
* @return the value of initialized
*/
public boolean isInitialized() {
return this.mInitialized;
}
/**
* Checks if is lock owned by current thread.
*
* @return true, if is lock owned by current thread
*/
public boolean isLockOwnedByCurrentThread() {
return this.mPublicLock.isHeldByCurrentThread();
}
/**
* Getter for paused : The paused status of this MSA procedure: <code>true</code> if it is currently paused,
* <code>false</code> if not.
*
* @return the value of paused
*/
public boolean isPaused() {
return this.mPaused;
}
/**
* Getter for running : The running status of this MSA procedure: <code>true</code> if started, <code>false</code>
* if not started yet or stopped. Note that the actual status of the procedure should be queried with
* {@link #getStatus()}
*
* @return the value of running
*/
public boolean isRunning() {
return this.mRunning;
}
/**
* A {@link Condition} on the {@linkplain #isRunning() running state} for external monitoring of the MSA running
* state.
*
* @return the {@link Condition} associated with the running state of this procedure
*/
public Condition getRunningCondition() {
return this.mRunningCond;
}
/**
* Check if there are pending events.
*
* @return <code>true</code> if there are pending events waiting to ve handled
*/
public boolean hasPendingEvents() {
return !mEventQueue.isEmpty();
}
/**
* Association of a callback to a specific event.
*
* @param eventType
* the event that will cause the execution of <code>callback</code>
* @param callback
* the callback object that will be associated with <code>event</code>
*/
public void registerCallback(MSACallbackEvent.EventTypes eventType,
ICallback<MSABase<?, ?>, EventTypes> callback) {
this.mCallbackManagerDelegate.registerCallback(callback, eventType);
}
/**
* Release lock.
*/
public void releaseLock() {
this.mPublicLock.unlock();
}
/**
* Calling this method will start the MSA procedure.
*
* @see MSASequential#start()
*/
@Override
public void run() {
try {
start();
} catch (Exception e) {
stop();
setStatus(ProcedureStatus.EXCEPTION);
throw new IllegalStateException("Exception thrown in the MSA procedure", e);
}
}
/**
* This method is called during initialization to set the default values for each event handled in the MSA
* procedure.<br/>
* It can be used to restore default values during the MSA execution
*/
protected final void setDefaultEventHandlers() {
setEventHanlder(DecisionEvent.class, new DecisionHandler<S, I>(this.mProxy));
setEventHanlder(ResourceEvent.class, new ResourceHandler<S, I>(this.mProxy));
setEventHanlder(GenerateEvent.class, new GenerateHandler<S, I>(this.mProxy));
setEventHanlder(NewRequestEvent.class, new NewRequestHandler<S, I>(this.mProxy));
setEventHanlder(OptimizeEvent.class, new OptimizeHandler<S, I>(this.mProxy));
setEventHanlder(PoolUpdateEvent.class, new PoolUpdateHandler<S, I>(this.mProxy));
}
/**
* Sets the event hanlder.
*
* @param <E>
* the element type
* @param eventClass
* the event class
* @param handler
* the handler
*/
public <E extends MSAEvent> void setEventHanlder(Class<E> eventClass,
MSAEventHandler<E, S, I> handler) {
this.mEventHandlerManager.setEventHandler(eventClass, handler);
}
/**
* Setter for initialized : <code>true</code> if the scenario pool has been initialized.
*
* @param initialized
* the value to be set for initialized
*/
protected void setInitialized(boolean initialized) {
this.mInitialized = initialized;
acquireLock();
getInitializedCondition().signalAll();
releaseLock();
}
/**
* Sets the paused status.
*
* @param paused
* the new paused
*/
protected void setPaused(boolean paused) {
boolean old = isPaused();
this.mPaused = paused;
if (old != isPaused()) {
notifyObservers(PROP_PAUSED);
try {
this.mLock.lockInterruptibly();
this.mPausedCondition.signalAll();
this.mLock.unlock();
} catch (InterruptedException e) {
MSALogging.getProcedureLogger().warn(
"Exception catched while setting the paused flag", e);
}
}
}
/**
* Sets the running state.
*
* @param running
* the new running
*/
private void setRunning(boolean running) {
this.mRunning = running;
acquireLock();
getRunningCondition().signalAll();
releaseLock();
}
/**
* Sets the level for the {@link org.apache.log4j.Logger} with the given <code>loggerName</code>
*
* @param loggerName
* the name of the logger for which the <code>level</code> will be set. <br/>
* Loggers names are defined in the {@link MSALogging} class. Note that all loggers loggers inherit by
* default from
* @param level
* the desired level of logging for logger <code>loggerName</code> <br/>
* Logging levels are defined in the {@link LoggerHelper} class. {@link MSALogging#BASE_LOGGER}
* @see MSALogging#BASE_LOGGER
* @see MSALogging#MSA_PROCEDURE_LOGGER
* @see MSALogging#MSA_SETUP_LOGGER
* @see MSALogging#MSA_COMPONENTS_LOGGER
* @see MSALogging#MSA_EVENTS_LOGGER
* @see LoggerHelper#LEVEL_LOW_DEBUG
* @see LoggerHelper#LEVEL_DEBUG
* @see LoggerHelper#LEVEL_INFO
* @see LoggerHelper#LEVEL_WARN
* @see LoggerHelper#LEVEL_ERROR
* @see LoggerHelper#LEVEL_FATAL
*/
public void setVerbose(String loggerName, Level level) {
Logging.setLoggerLevel(loggerName, level);
}
/**
* Starts the MSA procedure.<br/>
* The MSA procedure can be paused by calling {@link MSASequential#pause()} and unpaused with
* {@link MSASequential#resume()}. When the procedure is paused, it will finish the handling of the current event
* (if any) and then wait until unpaused to retreive and handle the next event.<br/>
* On the other hand, the procedure can be terminated by calling calling {@link MSASequential#stop()} in which case
* it will first finish the handling of the current event (id any) and then terminate.
*/
public void start() {
if (isRunning()) {
throw new IllegalStateException("This MSA procedure has already been started");
}
if (!checkState()) {
MSALogging.getProcedureLogger().warn("Aborting the MSA procedure, current state: %s",
this);
return;
}
setRunning(true);
resume();
mTimer.start();
MSALogging.getProcedureLogger().info("MSA procedure #%s started in thread %s [%s] ",
this.mMSAId, Thread.currentThread().getName(), Thread.currentThread().getId());
callbacks(MSA_START);
msaProcedure();
setStatus(ProcedureStatus.TERMINATED);
mTimer.stop();
MSALogging.getProcedureLogger().info("MSA procedure #%s finished in thread %s [%s] ",
this.mMSAId, Thread.currentThread().getName(), Thread.currentThread().getId());
callbacks(MSA_END);
stopChildThreads();
}
/**
* @return true if all components of the MSA are correctly defined
*/
protected boolean checkState() {
Collection<ParameterKey<?>> missingParams = getParameters().checkRequiredParameters();
if (!missingParams.isEmpty()) {
MSALogging.getProcedureLogger().warn(
"The following required global parameters have not been defined: "
+ missingParams.toString());
return false;
}
return true;
}
/**
* Permanently stop the MSA procedure (Cannot be resumed)<br/>
* For thread safety reasons, the procedure will be aborted after the handling of the current event if any.
*/
public void stop() {
if (!isRunning())
MSALogging.getProcedureLogger().info(
"MSABase.stop: The MSA procedure is already stopped, ignoring");
else {
MSALogging
.getProcedureLogger()
.info("MSABase.stop: Stopping the MSA procedure at the end of the current iteration if any");
resume();
setRunning(false);
this.mEventQueue.clear();
}
}
/**
* Permanently stop the MSA procedure (Cannot be resumed) after an exception<br/>
* For thread safety reasons, the procedure will be aborted after the handling of the current event if any.
*/
public void exception() {
stop();
setStatus(ProcedureStatus.EXCEPTION);
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
String state = "";
if (isInitialized()) {
state += "Initialized";
}
if (isRunning()) {
state += ",Running";
} else {
state += ",Stopped";
}
if (isPaused()) {
state += ",Paused";
}
return String.format("State: %s\n" + "Running Time: %s\n" + "Pool:%s\n"
+ "Current Solution:\n%s", state, this.mTimer, this.mPool.toString(),
getCurrentSolution());
}
/**
* Try lock.
*
* @param timeout
* the timeout
* @return true, if successful
*/
public boolean tryLock(long timeout) {
try {
return getLockInstance().tryLock(timeout, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
return false;
}
}
/**
* Unpause the main MSA procedure.
*/
public void resume() {
setPaused(false);
}
/**
* Removal of a callback for a specific event.
*
* @param eventType
* the considered event
* @param callback
* the callback object that will no longer be associated with <code>event</code>
*/
public void unregisterCallback(MSACallbackEvent.EventTypes eventType, MSACallbackBase callback) {
this.mCallbackManagerDelegate.unregisterCallback(callback, eventType);
}
/**
* This method will wait until the paused flag is set to <code>false</code>.
*
* @throws InterruptedException
* the interrupted exception
*/
protected synchronized void waitUntilUnpaused() throws InterruptedException {
while (isPaused()) {
// Logging.getProcedureLogger().lowDebug(
// "MSA Procedure paused, waiting untill it is unpaused");
acquireLock();
try {
try {
this.mPausedCondition.await();
} catch (InterruptedException ie) {
throw ie;
}
} finally {
releaseLock();
}
}
}
/**
* Getter for the component manager
*
* @return the component manager used in this instance
*/
public ComponentManager<S, I> getComponentManager() {
return mComponentManager;
}
}