/*
* Copyright (c) 2010 Mathew Hall.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* Neither the name of the University of Sheffield nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package main;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Queue;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jgap.InvalidConfigurationException;
import primitives.cluster.ClusterHead;
import primitives.graph.Graph;
import search.fitnessfunctions.TreeFitnessFunction;
import search.searchtechniques.GeneticAlgorithmSearch;
import search.searchtechniques.RandomMutationHillClimbingSearch;
import search.searchtechniques.Search;
import search.util.*;
/**
* Runs a list of Experiments over as many threads as there are cores.
* Usage: instantiate, then use instance.runExperiments()
* @author Mathew Hall
*/
public class ExperimentRunner implements Runnable {
private ThreadCount semaphore;
private Experiment td;
private ProgressStatus monitor;
public void setRunnerMonitor(ProgressStatus mon){
monitor = mon;
}
public ArrayList<Experiment> runExperiments(Queue<Experiment> expts) {
ArrayList<Experiment> results = new ArrayList<Experiment>();
ThreadCount sem = null;
boolean set = false;
StatusMonitor sm = new StatusMonitor();
new Thread(sm, "StatusMonitor").start();
int startSize = expts.size();
int iter = 0;
while (!expts.isEmpty()) {
Experiment current = expts.remove();
if(!set){
set = true;
sem = new ThreadCount(current.getNumThreads());
}
sem.inc();
ExperimentRunner inst = new ExperimentRunner(current, sem);
ProgressStatus ps = new ProgressStatus(sm);
ps.id = "["+current.getExperimentName() + " #" + this.hashCode() + "] " + current.getInputname().getName();
double prog = 1.0 - (expts.size() / (1.0* startSize));
iter++;
ps.id += " (" + iter + "/" + startSize + "%)";
Logger.getLogger(ExperimentRunner.class.getName()).log(Level.FINE, current.getExperimentName() + ": Progress: " + (prog * 100) + "%");
inst.setRunnerMonitor(ps);
Thread t = new Thread(inst, "ExperimentRunner Slave Thread " + iter);
t.start();
results.add(current);
}
sem.waitForZero();
sm.pushEvent(new ProgressEvent(ProgressEvent.TYPE_SHUTDOWN, -1, "",""));
return results;
}
private ExperimentRunner(Experiment toDo, ThreadCount semaphore) {
this.semaphore = semaphore;
this.td = toDo;
}
public ExperimentRunner() {
}
public void run() {
try {
Class<?> ffClass = Object.class;
try {
ffClass = Class.forName(td.getFitnessFunction(), true, this.getClass().getClassLoader());
} catch (ClassNotFoundException ex) {
Logger.getLogger(ExperimentRunner.class.getName()).log(Level.SEVERE, "Failed to load fitness function " + td.getFitnessFunction(), ex);
} //TODO: add support for Bunch adapted FFs (these require constructors)
TreeFitnessFunction fitnessFunction = null;
try {
fitnessFunction = (TreeFitnessFunction) ffClass.newInstance();
} catch (InstantiationException ex) {
Logger.getLogger(ExperimentRunner.class.getName()).log(Level.SEVERE, "Failed to instantiate fitness function " + td.getFitnessFunction(), ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(ExperimentRunner.class.getName()).log(Level.SEVERE, "IllegalAccessException when instantiating " + td.getFitnessFunction(), ex);
}
ClusterHead toCluster = TreeLoader2.loadTreeFromDot(td.getInputname());
Logger.getLogger(ExperimentRunner.class.getName()).log(Level.FINE, String.format("Starting clustering of file: %s [%d nodes, %d edges]"
, td.getInputname().getName()
,toCluster.getSize()
,new Graph(toCluster.getNodes()).countTransitions()
));
Search gs = null;
if(td.getSearchType().equals("GA")){
gs = new GeneticAlgorithmSearch();
}else if(td.getSearchType().equals("RMHC")){
gs = new RandomMutationHillClimbingSearch();
}else{
throw new RuntimeException(String.format("Chosen search type %s is not a valid option", td.getSearchType()));
}
gs.setPopulationSize(td.getPopsize());
gs.setChromosomeSize(td.getChromesize());
gs.setGenerations(td.getNumgens());
gs.setFitnessFunction(fitnessFunction);
gs.setInput(toCluster);
gs.setGeneType(td.getGeneType());
gs.setExperimentName(td.getExperimentName());
gs.setFitnessBudget(td.getFitnessBudget());
SearchResult sr = null;
gs.setProgressStatus(monitor);
gs.setName(td.getInputname().toString());
sr = gs.start();
td.setResult(sr);
try {
td.storeAll();
} catch (IOException ex) {
Logger.getLogger(ExperimentRunner.class.getName()).log(Level.SEVERE, null, ex);
} catch (ExperimentNotRunException ex) {
Logger.getLogger(ExperimentRunner.class.getName()).log(Level.SEVERE, null, ex);
}
semaphore.dec();
} catch (InvalidConfigurationException ex) {
Logger.getLogger(ExperimentRunner.class.getName()).log(Level.SEVERE, String.format("Invalid JGAP configuration %s","for file " + td.getInputname().toString()), ex);
semaphore.dec();
} catch (IOException ex) {
Logger.getLogger(ExperimentRunner.class.getName()).log(Level.SEVERE, "IOException when saving results", ex);
semaphore.dec();
}catch(IllegalStateException ex){
Logger.getLogger(ExperimentRunner.class.getName()).log(Level.SEVERE, String.format("Illegal State Exception: %s",td.getInputname()), ex);
semaphore.dec();
}catch(Exception e){
Logger.getLogger(ExperimentRunner.class.getName()).log(Level.SEVERE, String.format("Exception raised in GA, this result will be invalid: %s: %s",e.getMessage(),e.toString()), e) ;
semaphore.dec();
}
}
}