/*
* To change this template, choose Tools | Templates and open the template in the editor.
*/
package vroom.optimization.online.jmsa.components;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.locks.ReentrantLock;
import vroom.common.utilities.BatchThreadPoolExecutor;
import vroom.common.utilities.Stopwatch;
import vroom.optimization.online.jmsa.IActualRequest;
import vroom.optimization.online.jmsa.IDistinguishedSolution;
import vroom.optimization.online.jmsa.IInstance;
import vroom.optimization.online.jmsa.IMSARequest;
import vroom.optimization.online.jmsa.ISampledRequest;
import vroom.optimization.online.jmsa.IScenario;
import vroom.optimization.online.jmsa.MSABase;
import vroom.optimization.online.jmsa.MSABase.MSAProxy;
import vroom.optimization.online.jmsa.MSAGlobalParameters;
import vroom.optimization.online.jmsa.utils.MSALogging;
/**
* The Class <code>DefaultComponentManager</code> is an implementation of {@link ComponentManager} that will use a
* {@link ThreadPoolExecutor} to execute the following tasks:
* <ul>
* <li>{@linkplain #optimizePool(ScenarioOptimizerParam) Scenario optimization}</li>
* <li>{@linkplain #generateScenarios(ScenarioGeneratorParam) Scenario generation}</li>
* <li>{@linkplain #enforceDecision(int, IActualRequest) Decision enforcement}</li>
* </ul>
* The number of {@link Thread Threads} used will depend on the {@link MSAGlobalParameters#MAX_THREADS} parameter.
* <p>
* Creation date: Nov 30, 2010 - 10:05:55 AM.
*
* @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 class DefaultComponentManager<S extends IScenario, I extends IInstance> extends ComponentManager<S, I> {
private final BatchThreadPoolExecutor mGenerateExecutor;
/**
* Creates a new component manager that will use a {@link ThreadPoolExecutor} to execute the time consuming tasks.
*
* @param msa
* the parent MSA
* @param msaProxy
* the msa proxy
*/
public DefaultComponentManager(MSABase<S, I> msa, MSAProxy<S, I> msaProxy) {
super(msa, msaProxy);
mOptimizerPool = new LinkedList<ScenarioOptimizerBase<S>>();
mGenerateExecutor = new BatchThreadPoolExecutor(getParentMSAProxy().getParameters().get(
MSAGlobalParameters.MAX_THREADS), "msa-gen");
mOptimizeExecutor = new BatchThreadPoolExecutor(getParentMSAProxy().getParameters().get(
MSAGlobalParameters.MAX_THREADS), "msa-opt");
}
private final ReentrantLock mOptimizerPoolLock = new ReentrantLock();
/** A pool of {@linkplain ScenarioOptimizerBase scenario optimizers}. */
private final LinkedList<ScenarioOptimizerBase<S>> mOptimizerPool;
private final BatchThreadPoolExecutor mOptimizeExecutor;
/**
* Take an optimizer from the pool.
*
* @return an optimizer
*/
protected ScenarioOptimizerBase<S> takeOptimizer() {
if (mOptimizerPool.isEmpty()) {
return getParentMSAProxy().getParameters().<ScenarioOptimizerBase<S>> newInstance(
MSAGlobalParameters.SCENARIO_OPTIMIZER_CLASS, this);
} else {
ScenarioOptimizerBase<S> opt = null;
try {
mOptimizerPoolLock.lockInterruptibly();
opt = mOptimizerPool.pop();
return opt;
} catch (Exception e) {
opt = getParentMSAProxy().getParameters().<ScenarioOptimizerBase<S>> newInstance(
MSAGlobalParameters.SCENARIO_OPTIMIZER_CLASS, this);
} finally {
if (mOptimizerPoolLock.isHeldByCurrentThread()) {
mOptimizerPoolLock.unlock();
}
}
return opt;
}
}
/**
* Release an optimizer (return it to the pool).
*
* @param optimizer
* the optimizer to be released
*/
protected void releaseOptimizer(ScenarioOptimizerBase<S> optimizer) {
try {
mOptimizerPoolLock.lockInterruptibly();
mOptimizerPool.push(optimizer);
mOptimizerPoolLock.unlock();
} catch (Exception e) {
// Do nothing
} finally {
if (mOptimizerPoolLock.isHeldByCurrentThread()) {
mOptimizerPoolLock.unlock();
}
}
}
/*
* (non-Javadoc)
* @see vroom.optimization.online.jmsa.components.ComponentManager# buildDistinguishedPlan
* (vroom.optimization.online.jmsa.components.ISolutionBuilderParam )
*/
@Override
public IDistinguishedSolution buildDistinguishedPlan(ISolutionBuilderParam params) {
return getSolutionBuilder().buildDistinguishedPlan(params);
}
/*
* (non-Javadoc)
* @see vroom.optimization.online.jmsa.components.ComponentManager#canBeServiced
* (vroom.optimization.online.jmsa.IActualRequest)
*/
@Override
public boolean canBeServiced(IActualRequest request) {
return getRequestValidator().canBeServiced(request);
}
/*
* (non-Javadoc)
* @see vroom.optimization.online.jmsa.components.ComponentManager#enforceDecision (int,
* vroom.optimization.online.jmsa.IActualRequest)
*/
@Override
public Collection<S> enforceDecision(int resourceId, IActualRequest committedRequest) {
List<S> removedScenarios = new LinkedList<S>();
Iterator<S> it = getParentMSAProxy().getScenarioPool().iterator();
while (it.hasNext()) {
S s = it.next();
if (!getScenarioUpdater().enforceDecision(s, committedRequest, resourceId)) {
removedScenarios.add(s);
it.remove();
}
}
if (removedScenarios.size() > 0) {
MSALogging.getComponentsLogger().debug(
"DefaultComponentManager.enforceDecision: removing %s incompatible scenarios",
removedScenarios.size());
}
return removedScenarios;
}
/*
* (non-Javadoc)
* @see vroom.optimization.online.jmsa.components.ComponentManager#cleanPool()
*/
@Override
public Collection<IScenario> cleanPool() {
return getPoolCleaner().cleanPool();
}
/*
* (non-Javadoc)
* @see vroom.optimization.online.jmsa.components.ComponentManager# generateSampledRequest
* (vroom.optimization.online.jmsa.components.RequestSamplerParam )
*/
@Override
public List<ISampledRequest> generateSampledRequest(RequestSamplerParam params) {
return getRequestSampler().generateSampledRequest(params);
}
/*
* (non-Javadoc)
* @see vroom.optimization.online.jmsa.components.ComponentManager#generateScenarios
* (vroom.optimization.online.jmsa.components.ScenarioGeneratorParam)
*/
@Override
public void generateScenarios(ScenarioGeneratorParam params) {
if (mMSAProxy.getScenarioPool().isFull()) {
MSALogging.getComponentsLogger().lowDebug("DefaultComponentManager.generateScenarios: Pool is full");
} else {
MSALogging.getComponentsLogger().debug(
"DefaultComponentManager.generateScenarios: Generating new scenarios: %s", params);
int count = 0;
Stopwatch timer = new Stopwatch(params.getMaxInitTime() * params.getMaxScen());
timer.start();
int targetCount = Math.min(params.getMaxScen(), getParentMSAProxy().getScenarioPool()
.getRemainingCapacity());
ArrayList<ScenarioGeneratorTask> batch = new ArrayList<>();
for (int i = 0; i < targetCount; i++)
batch.add(new ScenarioGeneratorTask(params));
// Launch all the tasks and wait for the executor termination
// tasks are responsible for checking the arrival of a preemptive event
Map<ScenarioGeneratorTask, Future<S>> results;
try {
results = mGenerateExecutor.submitBatch(batch, true);
for (Future<S> f : results.values()) {
try {
S s = f.get();
if (s != null)
getParentMSAProxy().getScenarioPool().addScenario(s);
} catch (Exception e) {
MSALogging.getComponentsLogger().exception("DefaultComponentManager.generateScenarios", e);
}
}
} catch (InterruptedException e) {
MSALogging.getComponentsLogger().exception("DefaultComponentManager.generateScenarios", e);
}
timer.stop();
MSALogging.getComponentsLogger().lowDebug("DefaultComponentManager.generateScenarios: New pool: %s",
mMSAProxy.getScenarioPool());
}
}
/*
* (non-Javadoc)
* @see vroom.optimization.online.jmsa.components.ComponentManager#insertRequest
* (vroom.optimization.online.jmsa.IMSARequest[])
*/
@Override
public Collection<S> insertRequest(IMSARequest... requests) {
LinkedList<S> removedScenarios = new LinkedList<S>();
for (S s : mMSAProxy.getScenarioPool()) {
if (!getScenarioUpdater().insertRequests(s, requests)) {
// The scenario cannot accommodate all requests
removedScenarios.add(s);
}
}
if (removedScenarios.size() > 0) {
MSALogging.getComponentsLogger().debug(
"DefaultComponentManager.insertRequest: removing %s incompatible scenarios",
removedScenarios.size());
}
mMSAProxy.getScenarioPool().removeScenarios(removedScenarios);
return removedScenarios;
}
/*
* (non-Javadoc)
* @see vroom.optimization.online.jmsa.components.ComponentManager# startOfServiceUpdate(int,
* vroom.optimization.online.jmsa.IActualRequest)
*/
@Override
public Collection<S> startOfServiceUpdate(int resourceId, IActualRequest request) {
LinkedList<S> removedScenarios = new LinkedList<S>();
for (S s : mMSAProxy.getScenarioPool()) {
if (!getScenarioUpdater().startOfServiceUpdate(s, resourceId, request)) {
// The scenario is not coherent with the current state
removedScenarios.add(s);
}
}
if (removedScenarios.size() > 0) {
MSALogging.getComponentsLogger().debug(
"DefaultComponentManager.startOfServiceUpdate: removing %s incompatible scenarios",
removedScenarios.size());
}
mMSAProxy.getScenarioPool().removeScenarios(removedScenarios);
return removedScenarios;
}
/*
* (non-Javadoc)
* @see vroom.optimization.online.jmsa.components.ComponentManager#endOfServiceUpdate (int,
* vroom.optimization.online.jmsa.IActualRequest)
*/
@Override
public Collection<S> endOfServiceUpdate(int resourceId, IActualRequest servedRequest) {
LinkedList<S> removedScenarios = new LinkedList<S>();
for (S s : mMSAProxy.getScenarioPool()) {
if (!getScenarioUpdater().endOfServiceUpdate(s, resourceId, servedRequest)) {
// The scenario is not coherent with the current state
removedScenarios.add(s);
}
}
if (removedScenarios.size() > 0) {
MSALogging.getComponentsLogger().debug(
"DefaultComponentManager.endOfServiceUpdate: removing %s incompatible scenarios",
removedScenarios.size());
}
mMSAProxy.getScenarioPool().removeScenarios(removedScenarios);
return removedScenarios;
}
/*
* (non-Javadoc)
* @see vroom.optimization.online.jmsa.components.ComponentManager# startServicingUpdate(int)
*/
@Override
public Collection<S> startServicingUpdate(int resourceId) {
LinkedList<S> removedScenarios = new LinkedList<S>();
for (S s : mMSAProxy.getScenarioPool()) {
if (!getScenarioUpdater().startServicingUpdate(s, resourceId)) {
// The scenario is not coherent with the current state
removedScenarios.add(s);
}
}
if (removedScenarios.size() > 0) {
MSALogging.getComponentsLogger().debug(
"DefaultComponentManager.startServicingUpdate: removing %s incompatible scenarios",
removedScenarios.size());
}
mMSAProxy.getScenarioPool().removeScenarios(removedScenarios);
return removedScenarios;
}
/*
* (non-Javadoc)
* @see vroom.optimization.online.jmsa.components.ComponentManager# stopServicingUpdate(int)
*/
@Override
public Collection<S> stopServicingUpdate(int resourceId) {
LinkedList<S> removedScenarios = new LinkedList<S>();
for (S s : mMSAProxy.getScenarioPool()) {
if (!getScenarioUpdater().stopServicingUpdate(s, resourceId)) {
// The scenario is not coherent with the current state
removedScenarios.add(s);
}
}
if (removedScenarios.size() > 0) {
MSALogging.getComponentsLogger().debug(
"DefaultComponentManager.stopServicingUpdate: removing %s incompatible scenarios",
removedScenarios.size());
}
mMSAProxy.getScenarioPool().removeScenarios(removedScenarios);
return removedScenarios;
}
/*
* (non-Javadoc)
* @see vroom.optimization.online.jmsa.components.ComponentManager#optimizePool
* (vroom.optimization.online.jmsa.components.ScenarioOptimizerParam)
*/
@Override
public void optimizePool(ScenarioOptimizerParam params) {
// Prevent log flooding
if (System.currentTimeMillis() - mLastOptTime > 1000) {
MSALogging.getComponentsLogger().debug("DefaultComponentManager.optimizePool: Optimizing the pool (%s)",
params);
} else {
MSALogging.getComponentsLogger().lowDebug("DefaultComponentManager.optimizePool: Optimizing the pool (%s)",
params);
}
LinkedList<S> scen = new LinkedList<S>(mMSAProxy.getScenarioPool().getScenarios());
Collections.sort(scen, new Comparator<IScenario>() {
@Override
public int compare(IScenario o1, IScenario o2) {
return o1.getNonImprovingCount() - o2.getNonImprovingCount();
}
});
Iterator<S> scenarios = scen.iterator();
Stopwatch timer = new Stopwatch(params.getMaxTime());
timer.start();
// while (!getParentMSA().hasPendingEvents() && scenarios.hasNext() &&
// !timer.hasTimedOut()) {
// optimize(scenarios.next(), params);
// }
while (!getParentMSAProxy().isNextEventPreemptive() && scenarios.hasNext() && !timer.hasTimedOut()) {
mOptimizeExecutor.execute(new ScenarioOptimizerTask(scenarios.next(), params));
}
// Wait for the executor termination
// tasks are responsible for checking the arrival of a preemptive event
try {
mOptimizeExecutor.awaitBatchCompletion();
} catch (InterruptedException e) {
MSALogging.getComponentsLogger().exception("DefaultComponentManager.generateScenarios", e);
}
timer.stop();
MSALogging.getComponentsLogger().lowDebug("DefaultComponentManager.optimizePool: Pool optimized in %sms%s",
timer.readTimeMS(), getParentMSAProxy().isNextEventPreemptive() ? " (interrupted)" : "");
mLastOptTime = System.currentTimeMillis();
}
/*
* (non-Javadoc)
* @see vroom.optimization.online.jmsa.components.ComponentManager#optimize(vroom
* .optimization.online.jmsa.IScenario, vroom.optimization.online.jmsa.components.ScenarioOptimizerParam)
*/
@Override
public boolean optimize(S scenario, ScenarioOptimizerParam params) {
return getScenarioOptimizer().optimize(scenario, params);
}
/**
* The Class <code>ScenarioOptimizerTask</code> is responsible for the execution of the optimization procedure on a
* given scenario.
* <p>
* Creation date: Nov 30, 2010 - 10:11:51 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
*/
protected class ScenarioOptimizerTask implements Runnable {
/** The Scenario. */
private final S mScenario;
/** The Params. */
private final ScenarioOptimizerParam mParams;
/**
* Creates a new <code>ScenarioOptimizerTask</code>.
*
* @param scenario
* the scenario
* @param params
* the params
*/
protected ScenarioOptimizerTask(S scenario, ScenarioOptimizerParam params) {
mScenario = scenario;
mParams = params;
}
/*
* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
// Check if there is a preemptive event
if (!getParentMSAProxy().isNextEventPreemptive()) {
ScenarioOptimizerBase<S> opt = takeOptimizer();
opt.optimize(mScenario, mParams);
releaseOptimizer(opt);
}
}
}
/**
* The Class <code>ScenarioGeneratorTask</code> is responsible for the generation of a single scenario.
* <p>
* Creation date: Dec 3, 2010 - 8:54:48 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
*/
protected class ScenarioGeneratorTask implements Callable<S> {
/** The Params. */
private final ScenarioGeneratorParam mParams;
/**
* Creates a new <code>ScenarioGeneratorTask</code>.
*
* @param params
* the params
*/
public ScenarioGeneratorTask(ScenarioGeneratorParam params) {
mParams = params;
}
/*
* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public S call() {
S scenario = null;
// Check if there is a preemptive event
if (!getParentMSAProxy().isNextEventPreemptive()) {
Stopwatch t = new Stopwatch();
t.start();
// ScenarioGeneratorBase<S> gen =
// getParentMSA().getParameters().<ScenarioGeneratorBase<S>>
// newInstance(
// MSAGlobalParameters.SCENARIO_GENERATOR_CLASS,
// DefaultComponentManager.this);
scenario = getScenarioGenerator().generateScenario(mParams);
ScenarioOptimizerBase<S> opt = takeOptimizer();
boolean feas = opt.initialize(scenario,
new ScenarioOptimizerParam(Integer.MAX_VALUE,
(int) (mParams.getMaxInitTime() - t.readTimeMS()), false));
releaseOptimizer(opt);
// The generated scenario is feasible
if (feas) {
// Add it to the pool
// mMSAProxy.getScenarioPool().addScenario(scenario);
// Log a message
MSALogging.getComponentsLogger()
.lowDebug("DefaultComponentManager.generateScenarios: New scenario generated in %s (%s)",
t, scenario);
} else {
// Log a message
MSALogging.getComponentsLogger().warn(
"DefaultComponentManager.generateScenarios: Infeasible generated, will be discarded (%s)",
scenario);
scenario = null;
}
}
return scenario;
}
}
}