MultipleExperimenter.java
package progen.experimenter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import progen.ProGenException;
import progen.context.ProGenContext;
import progen.experimenter.property.Property;
import progen.experimenter.property.PropertyFactory;
import progen.kernel.error.Info;
/**
* Clase que implementa el comportamiento de los experimentos múltiples. Este
* comportamiento es tal que recupera el conjunto marcado con el nombre
* <code>progen.experimenter.*</code> e irá generando la propiedad, eliminando
* del nombre el literal <code>experimenter</code> para que vaya cambiando el
* contexto de ejecución de ProGen.
*
* @author jirsis
* @since 2.0
*/
public class MultipleExperimenter extends Experimenter {
private static final int DEFAULT_STRINGBUILDER_SIZE = 20;
/** Conjunto de propiedades que definen el experimento múltiple */
private List<Property> properties;
/** Indica el número de veces que se ejecutará el experimento */
private int totalRepetitions;
/** Indica qué repetición está ejecutando en un momento dado */
private int currentRepetition;
/**
* Indica si se ha terminado de ejecutar una repetición y falta por ejecutar
* más
*/
private boolean nextRepetition;
/** Indica que experimenter concreto se está ejecutando */
private int currentExperimenter;
/**
* Instancia de SimpleExperimenter que calculará los resultados de un
* experimento determinado.
*/
private SimpleExperimenter experimenter;
private boolean defined;
/**
* Constructor genérico de la clase. Recupera todas las propiedades definidas
* con el nombre <code>progen.experimenter.*</code> y las irá incluyendo en
* ProGenContext con un valor nuevo cada vez que se llame al método de
* actualización.
*/
public MultipleExperimenter() {
super();
currentRepetition = 0;
currentExperimenter = 0;
nextRepetition = false;
totalRepetitions = ProGenContext.getOptionalProperty("progen.repetitions.experimenter", 1);
properties = new ArrayList<Property>();
final List<String> propertiesLabels = ProGenContext.getFamilyOptions("progen.experimenter.");
for (String label : propertiesLabels) {
properties.add(PropertyFactory.makeInstance(label));
}
experimenter = new SimpleExperimenter();
defined = false;
}
@Override
public void updateValues() {
boolean actualizado = false;
if (!isDone()) {
defined = false;
if (nextRepetition) {
resetAllProperties();
nextRepetition = false;
currentExperimenter = 0;
} else {
// incremento de las propiedades
int propertyIndex = 0;
Property nextProp;
while (propertyIndex < properties.size() && !actualizado) {
nextProp = properties.get(propertyIndex);
if (nextProp.hasNext()) {
actualizado = incrementPropertyValue(nextProp);
} else {
propertyIndex++;
}
}
resetPreviousProperties(actualizado, propertyIndex);
}
}
}
private void resetPreviousProperties(boolean actualizado, int lastPropertyIndex) {
int currentProperty=lastPropertyIndex;
if (actualizado) {
while (--currentProperty>= 0) {
properties.get(currentProperty).reset();
}
}
}
private boolean incrementPropertyValue(Property nextProp) {
boolean actualizado;
nextProp.nextValue();
actualizado = true;
currentExperimenter++;
return actualizado;
}
private void resetAllProperties() {
for (Property property : properties) {
property.reset();
}
}
@Override
public boolean isDone() {
boolean done = true;
if (nextRepetition) {
currentRepetition++;
done = false;
} else {
for (Property property : properties) {
done &= !property.hasNext();
}
if (done && (currentRepetition + 1) < totalRepetitions) {
done = false;
nextRepetition = true;
}
}
return done && defined;
}
@Override
public void defineValues() {
defined = true;
// actualizacion de las variables
for (Property property : properties) {
ProGenContext.setProperty(property.getLabel(), property.getValue());
}
}
@Override
public void generateResults() {
dumpResults();
}
/**
* Genera la carpeta de volcado de un experimento y copia en ella, tanto el
* contexto actual de dicho experimento como los resultados asociados.
*
*/
private void dumpResults() {
PrintWriter context;
// se recupera el path de la carpeta de resultados del experimento
final File experimentDir = new File(ProGenContext.getMandatoryProperty("progen.output.dir") + ProGenContext.getMandatoryProperty("progen.output.experiment"));
try {
// creamos el fichero del contexto actual
final File file = new File(experimentDir.getAbsolutePath() + File.separator + "current context.txt");
context = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"));
for (Property property : properties) {
context.print(property.getLabel());
context.print("=");
context.println(property.getValue());
}
context.close();
experimenter.generateResults();
} catch (IOException e) {
throw new ProGenException(e.getLocalizedMessage(), e);
}
}
/**
* Devuelve la repetición actual.
*
* @return la repetición actual.
*/
public int getCurrentRepetition() {
int repetition = currentRepetition;
if (nextRepetition) {
repetition = currentRepetition - 1;
}
return repetition;
}
/**
* Devuelve el experimenter actual.
*
* @return el experimenter actual.
*/
public int getCurrentExperimenter() {
return currentExperimenter;
}
@Override
public String defineExperimentDir() {
final StringBuilder experimenterDir = new StringBuilder(DEFAULT_STRINGBUILDER_SIZE);
experimenterDir.append("exp-");
experimenterDir.append(currentRepetition);
experimenterDir.append("-");
experimenterDir.append(currentExperimenter);
return experimenterDir.toString();
}
@Override
public String finishMessage() {
final StringBuilder finishMessage = new StringBuilder(DEFAULT_STRINGBUILDER_SIZE);
finishMessage.append("---- ");
finishMessage.append(Info.get(2));
finishMessage.append(" ");
finishMessage.append(currentExperimenter);
finishMessage.append(" -----");
return finishMessage.toString();
}
}