/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.hawaii.jmotif.sampler;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* A simple solver encapsulation running the optimization calculation in
* a separate thread and terminating it after a given time to prevent infinite
* looping or locks. (Decorator pattern)
*
* @author ytoh
*/
//@Component(name="Timeout solver")
public class TimeoutSolver implements Solver {
// static final Logger logger = Logger.getLogger(TimeoutSolver.class);
private ScheduledExecutorService scheduler;
private Solver solver;
private TimeoutStopCondition stopCondition;
// @Property(name="Maximum solving time [s]")
// @Range(from=1, to=Double.MAX_VALUE)
private double timeout;
public double getTimeout() {
return timeout;
}
public void setTimeout(double timeout) {
this.timeout = timeout;
}
/**
* Constructs an instance of <code>TimeoutSolver</code> wrapping the given
* solver and initializing the mechanism to terminate the optimization
* calculation if it runs longer then the specified timeout period.
*
* @param solver worker solver to be wrapped
* @param timeout maximum calculation period
*/
TimeoutSolver(Solver solver, long timeout) {
this.solver = solver;
this.timeout = timeout;
}
public void init(Function function, OptimizationMethod method) throws Exception {
// logger.debug("initialization of timeout solver");
this.scheduler = Executors.newSingleThreadScheduledExecutor();
this.stopCondition = new TimeoutStopCondition((long)timeout);
solver.init(function, method);
solver.addSystemStopCondition(stopCondition);
}
@SuppressWarnings("unchecked")
public void solve() throws Exception {
final Callable innerSolver = new Callable() {
public Object call() throws Exception {
stopCondition.start();
solver.solve();
return null;
}
};
final ScheduledFuture<?> solverHandle = scheduler.schedule(innerSolver, 0L, TimeUnit.SECONDS);
try {
solverHandle.get((long)timeout, TimeUnit.MILLISECONDS);
} catch (InterruptedException ex) {
// logger.error("Optimization stopped: User interrupt.", ex);
} catch (ExecutionException ex) {
// logger.error("Error occurred while optimizing", ex);
} catch (TimeoutException ex) {
// logger.warn("Optimization stopped: Time limit reached. (" + timeout + "ms)");
solverHandle.cancel(true);
} finally {
scheduler.shutdown();
}
}
public OptimizationResults getResults() {
if(stopCondition.isConditionMet()) { // optimization process reached its max running time
OptimizationResults innerResults = solver.getResults();
// we need to add the timeout stop conditions to the list of met stop conditions
List<StopCondition> conditions = new ArrayList<StopCondition>(innerResults.getMetConditions());
conditions.add(stopCondition);
return new OptimizationResults(innerResults.getSolution(), innerResults.getStatistics(), innerResults.getNumberOfIterations(), conditions);
} else { // optimization process stopped before the specified timeout
return solver.getResults();
}
}
public void addSystemStopCondition(StopCondition condition) {
solver.addSystemStopCondition(condition);
}
public void addConsumer(Consumer<? super Synchronization> consumer) {
solver.addConsumer(consumer);
}
public Synchronization getValue() {
return solver.getValue();
}
}