Java tutorial
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package edu.gsgp.experiment.config; import edu.gsgp.experiment.data.ExperimentalData; import edu.gsgp.experiment.data.HoldoutHandler; import edu.gsgp.experiment.data.DataProducer; import edu.gsgp.experiment.data.CrossvalidationHandler; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.Properties; import edu.gsgp.utils.Statistics; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.MissingOptionException; import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import edu.gsgp.utils.MersenneTwister; import edu.gsgp.utils.Utils.DatasetType; import edu.gsgp.population.Population; import edu.gsgp.nodes.Node; import edu.gsgp.nodes.functions.Function; import edu.gsgp.nodes.terminals.Input; import edu.gsgp.nodes.terminals.Terminal; import edu.gsgp.population.treebuilder.FullBuilder; import edu.gsgp.population.treebuilder.GrowBuilder; import edu.gsgp.population.treebuilder.HalfBuilder; import edu.gsgp.population.Individual; import edu.gsgp.population.populator.Populator; import edu.gsgp.population.treebuilder.TreeBuilder; import edu.gsgp.population.fitness.Fitness; import edu.gsgp.population.operator.Breeder; import edu.gsgp.population.pipeline.Pipeline; import edu.gsgp.population.selector.BetweennessSelector; import edu.gsgp.population.selector.IndividualSelector; import edu.gsgp.population.selector.TournamentSelector; import edu.gsgp.utils.StatisticsDimension; import edu.gsgp.utils.Utils; import java.io.FileNotFoundException; import java.lang.reflect.Constructor; import java.util.Arrays; /** * @author Luiz Otavio Vilas Boas Oliveira * http://homepages.dcc.ufmg.br/~luizvbo/ luiz.vbo@gmail.com * * Copyright (C) 20014, Federal University of Minas Gerais, Belo Horizonte, * Brazil * * This class load the parameters from the file and instantiate the objects used * in the GSGP */ public class PropertiesManager { public enum paramType { STRING, INT, DOUBLE, CLASS, CLASS_LIST, FILE } protected boolean parameterLoaded; protected Properties fileParameters; protected CommandLine cliParameters; protected Options cliOptions; private DataProducer dataProducer; private MersenneTwister mersennePRNG; private ExperimentalData data; private boolean mutStepFromSD; private int numExperiments; private int numGenerations; private int numThreads; private int populationSize; private int rtPoolSize; private int maxInitAttempts; private double minError; private double mutationStep; private double spreaderInitProb; private double spreaderAlpha; private Populator populationInitializer; private Pipeline pipeline; private Breeder[] breederList; private Fitness fitnessFunction; private Terminal[] terminalSet; private Function[] functionSet; private ExperimentalData experimentalData; private IndividualSelector individualSelectorTournament; private IndividualSelector individualSelectorDimension; private TreeBuilder individualBuilder; private TreeBuilder randomTreeBuilder; private String outputDir; private String filePrefix; private String individualSelector; private double probability; // Used do double check the parameters loaded/used by the experiment private StringBuilder loadedParametersLog; public PropertiesManager(String args[]) throws Exception { loadedParametersLog = new StringBuilder(); setOptions(); parameterLoaded = loadParameterFile(args); if (parameterLoaded) { loadParameters(); } } private void loadParameters() throws Exception { dataProducer = getDataProducer(); mersennePRNG = new MersenneTwister(getLongProperty(ParameterList.SEED, System.currentTimeMillis())); terminalSet = getTerminalObjects(); functionSet = getFunctionObjects(); fitnessFunction = getFitnessObject(); numExperiments = getIntegerProperty(ParameterList.NUM_REPETITIONS, 1); numGenerations = getIntegerProperty(ParameterList.NUM_GENERATION, 200); numThreads = getIntegerProperty(ParameterList.NUMBER_THREADS, -1); if (numThreads == -1) { numThreads = Runtime.getRuntime().availableProcessors(); } populationSize = getIntegerProperty(ParameterList.POP_SIZE, 1000); rtPoolSize = getIntegerProperty(ParameterList.RT_POOL_SIZE, 200); maxInitAttempts = getIntegerProperty(ParameterList.POP_INIT_ATTEMPTS, 10); minError = getDoubleProperty(ParameterList.MIN_ERROR, 0); mutationStep = getDoubleProperty(ParameterList.MUT_STEP, 0.1); mutStepFromSD = getBooleanProperty(ParameterList.MUT_STEP_SD, true); spreaderInitProb = getDoubleProperty(ParameterList.SPREADER_PROB, 0.5); spreaderAlpha = getDoubleProperty(ParameterList.SPREADER_ALPHA, 2); outputDir = getStringProperty(ParameterList.PATH_OUTPUT_DIR, true); filePrefix = getStringProperty(ParameterList.FILE_PREFIX, false); individualBuilder = getIndividualBuilder(false); randomTreeBuilder = getIndividualBuilder(true); pipeline = getPipelineObject(); populationInitializer = getPopInitObject(); breederList = getBreederObjects(); this.probability = getDoubleProperty(ParameterList.BETWEENESS_PROB, 0.01); //pode tirar esse mtodo. Instancia como seletor de torneio normal. getIndividualSelector(); } public enum ParameterList { PARENT_FILE("parent", "Path to the parent parameter file. The child parameters overwrite the parent", false), PATH_DATA_FILE("experiment.data", "Path for the training/test files. See experiment.design option for more details", true), PATH_TEST_FILE("experiment.data.test", "Path for the test files. See experiment.design option for more details", false), PATH_OUTPUT_DIR("experiment.output.dir", "Output directory", false), SEED( "experiment.seed", "Seed (long int) used by the pseudo-random number generator", false), FILE_PREFIX("experiment.file.prefix", "Identifier prefix for files", false), TERMINAL_LIST("tree.build.terminals", "List of terminals used to build new trees (separeted by commas)", true), FUNCTION_LIST("tree.build.functions", "List of functions used to build new trees (separeted by commas)", true), FITNESS_FUNCTION("pop.fitness", "Fitness function adopted during the evolution", true), INDIVIDUAL_BUILDER_POP( "tree.build.builder", "Builder used to generate trees for the initial population", true), INDIVIDUAL_BUILDER_RAND_TREE( "tree.build.builder.random.tree", "Builder used to generate random trees for the semantic operators", true), INDIVIDUAL_SELECTOR( "pop.ind.selector", "Type of selector used to select individuals for next generations", true), EXPERIMENT_DESIGN( "experiment.design", "Type of experiment (cross-validation or holdout):" + "\n# - If crossvalidation, uses splited data from a list of files. Use paths to the" + "\n# files in the form /pathToFile/repeatedName#repeatedName, where # indicates " + "\n# where the fold index is placed (a number from 0 to k-1). E.g. /home/iris-#.dat," + "\n# with 3 folds in the path will look for iris-0.dat, iris-1.dat and iris-2.dat" + "\n# - If holdout, we have two cases: " + "\n# 1) Use paths to the files in the form /pathToFile/repeatedName#repeatedName," + "\n# where # is composed by the pattern (train|test)-i with i=0,1,...,n-1, where n is" + "\n# the number of experiment files. E.g. /home/iris-#.dat, with 4 files (2x(train+test))" + "\n# in the path will look for iris-train-0.dat, iris-test-0.dat, iris-train-1.dat and iris-test-1.dat" + "\n# 2) Use the path in 'experiment.data' to read the training files in the format " + "\n# /pathToFile/repeatedName#repeatedName and the path in 'experiment.data.test'" + "\n# to read the test data, replacing # by i=0,1,...,n-1. This option is used when" + "\n# 'experiment.data.test' is provided", true), MAX_TREE_DEPTH( "tree.build.max.depth", "Max depth allowed when building trees", false), MIN_TREE_DEPTH( "tree.min.depth", "Min depth allowed when building trees", false), NUM_GENERATION( "evol.num.generation", "Number of generations", false), NUM_REPETITIONS( "experiment.num.repetition", "Number of experiment repetitions (per fold) - default = 1", false), POP_SIZE( "pop.size", "Population size", false), RT_POOL_SIZE( "rt.pool.size", "Size of the pool of random trees used by GSX/GSM", false), NUMBER_THREADS( "evol.num.threads", "Number of threads (for parallel execution)", false), TOURNAMENT_SIZE( "pop.ind.selector.tourn.size", "Tournament size, when using tournament as selector", false), MIN_ERROR( "evol.min.error", "Minimum error to consider a hit", false), MUT_STEP( "breed.mut.step", "Mutation step", false), MUT_STEP_SD( "breed.mut.step.sd", "Indicate if the mutation step is absolute (false) or relative to the stardard deviation" + "\n# of the outputs of the training set.", false), BREEDERS_LIST( "breed.list", "List of breeders classes used during the evolution. The list items must be comma separated and the propability" + "\n# must follow the breeder class separated by a *. E.g.: " + "\n# edu.gsgp.population.builder.individual.BreederA*0.1, edu.gsgp.population.builder.individual.BreederB*0.9", true), POP_INITIALIZER( "pop.initializer", "Population Initializer class. Default: edu.gsgp.population.builder.individual.SimplePopulator", true), POP_PIPELINE( "pop.pipeline", "Class responsible for evolve a new population from a previous one", false), POP_INIT_ATTEMPTS( "pop.initializer.attempts", "Number of attemtps before adding an individual in the population", false), SPREADER_PROB( "breed.spread.prob", "Probability of applying the spreader operator (in standalone mode)", false), SPREADER_ALPHA( "breed.spread.alpha", "Alpha used to compute the effective probability of applying the spreader", false), BETWEENESS_PROB( "pop.ind.selector.betweeness.prob", "Probability of applying the betweeness operator", false), TOURNAMENT_POOL( "pop.ind.selector.tourn.pool.size", "Pool of individuals generated by tournament, when using betweeneess as selector", false); // MUT_PROB("breed.mut.prob", "Probability of applying the mutation operator", false), // XOVER_PROB("breed.xover.prob", "Probability of applying the crossover operator", false), // SEMANTIC_SIMILARITY_THRESHOLD("sem.gp.epsilon", "Threshold used to determine if two semantics are similar", false); public final String name; public final String description; public final boolean mandatory; private ParameterList(String name, String description, boolean mandatory) { this.name = name; this.description = description; this.mandatory = mandatory; } } /** * Load the parameters from the CLI and file * * @param args CLI parameters * @return True if and only if parameters are loaded both from CLI and file * @throws Exception */ private boolean loadParameterFile(String[] args) throws Exception { try { CommandLineParser parser = new DefaultParser(); CommandLine parametersCLI = parser.parse(cliOptions, args); if (parametersCLI.hasOption("H")) { writeParameterModel(); return false; } if (!parametersCLI.hasOption("p")) { throw new Exception("The parameter file was not specified."); } String path = parametersCLI.getOptionValue("p"); fileParameters = loadProperties(path); return true; } catch (MissingOptionException ex) { throw new Exception("Required parameter not found."); } catch (ParseException ex) { throw new Exception("Error while parsing the command line."); } } private String preProcessPath(String path) { if (path.startsWith("~")) { String osName = System.getProperty("os.name").toLowerCase(); String homePath = System.getProperty("user.home"); if (osName.startsWith("windows")) { homePath = homePath.replace("\\", "/"); } path = path.replaceFirst("^~", homePath); } else if (path.startsWith(".") && !path.startsWith("..")) { String osName = System.getProperty("os.name").toLowerCase(); String currPath = System.getProperty("user.dir"); if (osName.startsWith("windows")) { currPath = currPath.replace("\\", "/"); } path = path.replaceFirst("^\\.", currPath); } return path; } private Properties loadProperties(String path) throws Exception { path = this.preProcessPath(path); File parameterFile = new File(path); if (!parameterFile.canRead()) { throw new FileNotFoundException("Parameter file can not be read: " + parameterFile.getCanonicalPath()); } FileInputStream fileInput = new FileInputStream(parameterFile); Properties property = new Properties(); property.load(fileInput); if (property.containsKey(ParameterList.PARENT_FILE.name)) { Properties propertyParent = loadProperties(property.getProperty("parent").trim()); propertyParent.putAll(property); property = propertyParent; } return property; } private void writeParameterModel() { try { File file = new File("model.param"); // if file doesnt exists, then create it if (!file.exists()) { file.createNewFile(); } FileWriter fw = new FileWriter(file); BufferedWriter bw = new BufferedWriter(fw); StringBuilder textToPrint = new StringBuilder(); for (ParameterList p : ParameterList.values()) { textToPrint.append("# " + p.description + "\n"); textToPrint.append(p.name + " = \n"); } bw.write(textToPrint.toString()); bw.close(); } catch (IOException e) { e.printStackTrace(); } } private void getIndividualSelector() throws Exception { this.individualSelector = getStringProperty(ParameterList.INDIVIDUAL_SELECTOR, false).toLowerCase(); switch (this.individualSelector) { case "tournament": this.individualSelectorTournament = new TournamentSelector( getIntegerProperty(ParameterList.TOURNAMENT_SIZE, 7), getIntegerProperty(ParameterList.TOURNAMENT_POOL, 100)); break; case "betweeness": this.individualSelectorTournament = new TournamentSelector( getIntegerProperty(ParameterList.TOURNAMENT_SIZE, 7), getIntegerProperty(ParameterList.TOURNAMENT_POOL, 100)); //definir parmetros do seletor. this.individualSelectorDimension = new BetweennessSelector(); break; default: throw new Exception("The inidividual selector must be defined."); } } private DataProducer getDataProducer() throws Exception { String value = getStringProperty(ParameterList.EXPERIMENT_DESIGN, false).toLowerCase(); DataProducer dataProducer; switch (value) { case "crossvalidation": dataProducer = new CrossvalidationHandler(); break; case "holdout": dataProducer = new HoldoutHandler(); break; default: throw new Exception( "Experiment design (experiment.design) must be \"crossvalidation\" or \"holdout\"."); } dataProducer.setDataset(getStringProperty(ParameterList.PATH_DATA_FILE, true), getStringProperty(ParameterList.PATH_TEST_FILE, true)); return dataProducer; } /** * Load a boolean property from the file. * * @param key The name of the property * @param defaultValue The default value for this property * @return The value loaded from the file or the default value, if it is not * specified in the file. * @throws NumberFormatException The loaded value can not be converted to * boolean * @throws NullPointerException The parameter file was not initialized * @throws MissingOptionException The parameter is mandatory and it was not * found in the parameter file. */ private boolean getBooleanProperty(ParameterList key, boolean defaultValue) throws NumberFormatException, NullPointerException, MissingOptionException { try { boolean keyPresent = fileParameters.containsKey(key.name); String strValue = keyPresent ? fileParameters.getProperty(key.name).replaceAll("\\s", "") : null; if (!keyPresent && key.mandatory) { throw new MissingOptionException("The input parameter (" + key.name + ") was not found"); } else if (!keyPresent || strValue.equals("")) { loadedParametersLog.append(key.name).append("=").append(defaultValue).append(" (DEFAULT)\n"); return defaultValue; } loadedParametersLog.append(key.name).append("=").append(strValue).append("\n"); return Boolean.parseBoolean(strValue); } catch (NumberFormatException e) { throw new NumberFormatException( e.getMessage() + "\nThe input parameter (" + key.name + ") could not be converted to boolean."); } catch (NullPointerException e) { throw new NullPointerException(e.getMessage() + "\nThe parameter file was not initialized."); } } /** * Load an int property from the file. * * @param key The name of the property * @param defaultValue The default value for this property * @return The value loaded from the file or the default value, if it is not * specified in the file. * @throws NumberFormatException The loaded value can not be converted to * int * @throws NullPointerException The parameter file was not initialized * @throws MissingOptionException The parameter is mandatory and it was not * found in the parameter file. */ private int getIntegerProperty(ParameterList key, int defaultValue) throws NumberFormatException, NullPointerException, MissingOptionException { try { boolean keyPresent = fileParameters.containsKey(key.name); String strValue = keyPresent ? fileParameters.getProperty(key.name).replaceAll("\\s", "") : null; if (!keyPresent && key.mandatory) { throw new MissingOptionException("The input parameter (" + key.name + ") was not found"); } else if (!keyPresent || strValue.equals("")) { loadedParametersLog.append(key.name).append("=").append(defaultValue).append(" (DEFAULT)\n"); return defaultValue; } loadedParametersLog.append(key.name).append("=").append(strValue).append("\n"); return Integer.parseInt(strValue); } catch (NumberFormatException e) { throw new NumberFormatException( e.getMessage() + "\nThe input parameter (" + key.name + ") could not be converted to int."); } catch (NullPointerException e) { throw new NullPointerException(e.getMessage() + "\nThe parameter file was not initialized."); } } /** * Load a long property from the file. * * @param key The name of the property * @param defaultValue The default value for this property * @return The value loaded from the file or the default value, if it is not * specified in the file. * @throws NumberFormatException The loaded value can not be converted to * long * @throws NullPointerException The parameter file was not initialized * @throws MissingOptionException The parameter is mandatory and it was not * found in the parameter file. */ private long getLongProperty(ParameterList key, long defaultValue) throws NumberFormatException, NullPointerException, MissingOptionException { try { boolean keyPresent = fileParameters.containsKey(key.name); String strValue = keyPresent ? fileParameters.getProperty(key.name).replaceAll("\\s", "") : null; if (!keyPresent && key.mandatory) { throw new MissingOptionException("The input parameter (" + key.name + ") was not found"); } else if (!keyPresent || strValue.equals("")) { loadedParametersLog.append(key.name).append("=").append(defaultValue).append(" (DEFAULT)\n"); return defaultValue; } loadedParametersLog.append(key.name).append("=").append(strValue).append("\n"); return Integer.parseInt(strValue); } catch (NumberFormatException e) { throw new NumberFormatException( e.getMessage() + "\nThe input parameter (" + key.name + ") could not be converted to long."); } catch (NullPointerException e) { throw new NullPointerException(e.getMessage() + "\nThe parameter file was not initialized."); } } /** * Load a double property from the file. * * @param key The name of the property * @param defaultValue The default value for this property * @return The value loaded from the file or the default value, if it is not * specified in the file. * @throws NumberFormatException The loaded value can not be converted to * double * @throws NullPointerException The parameter file was not initialized * @throws MissingOptionException The parameter is mandatory and it was not * found in the parameter file. */ private double getDoubleProperty(ParameterList key, double defaultValue) throws NumberFormatException, NullPointerException, MissingOptionException { try { boolean keyPresent = fileParameters.containsKey(key.name); String strValue = keyPresent ? fileParameters.getProperty(key.name).replaceAll("\\s", "") : null; if (!keyPresent && key.mandatory) { throw new MissingOptionException("The input parameter (" + key.name + ") was not found"); } else if (!keyPresent || strValue.equals("")) { loadedParametersLog.append(key.name).append("=").append(defaultValue).append(" (DEFAULT)\n"); return defaultValue; } loadedParametersLog.append(key.name).append("=").append(strValue).append("\n"); return Double.parseDouble(strValue); } catch (NumberFormatException e) { throw new NumberFormatException( e.getMessage() + "\nThe input parameter (" + key.name + ") could not be converted to double."); } catch (NullPointerException e) { throw new NullPointerException(e.getMessage() + "\nThe parameter file was not initialized."); } } /** * Load a string property from the file. * * @param key The name of the property * @param isFile Specifies whether the property relates to a file * @return The value loaded from the file or the default value, if it is not * specified in the file. * @throws NumberFormatException The loaded value can not be converted to * string * @throws NullPointerException The parameter file was not initialized * @throws MissingOptionException The parameter is mandatory and it was not * found in the parameter file. */ private String getStringProperty(ParameterList key, boolean isFile) throws NumberFormatException, NullPointerException, MissingOptionException { try { boolean keyPresent = fileParameters.containsKey(key.name); String strValue = keyPresent ? fileParameters.getProperty(key.name).replaceAll("\\s", "") : null; if (!keyPresent && key.mandatory) { throw new MissingOptionException("Input parameter not found: " + key.name); } else if (!keyPresent) { return null; } if (isFile) { strValue = this.preProcessPath(strValue); } loadedParametersLog.append(key.name).append("=").append(strValue).append("\n"); return strValue; } catch (NullPointerException e) { throw new NullPointerException(e.getMessage() + "\nThe parameter file was not initialized."); } } private TreeBuilder getIndividualBuilder(boolean isForRandomTrees) throws Exception { String builderType; if (isForRandomTrees) { builderType = getStringProperty(ParameterList.INDIVIDUAL_BUILDER_RAND_TREE, false).toLowerCase(); } else { builderType = getStringProperty(ParameterList.INDIVIDUAL_BUILDER_POP, false).toLowerCase(); } int maxDepth = getIntegerProperty(ParameterList.MAX_TREE_DEPTH, 6); int minDepth = getIntegerProperty(ParameterList.MIN_TREE_DEPTH, 2); switch (builderType) { case "grow": return new GrowBuilder(maxDepth, minDepth, functionSet, terminalSet); case "full": return new FullBuilder(maxDepth, minDepth, functionSet, terminalSet); case "rhh": return new HalfBuilder(maxDepth, minDepth, functionSet, terminalSet); default: String msg = isForRandomTrees ? "Error loading the random trees builder. " : "Error loading the individuals' trees builder. "; if (builderType.isEmpty()) { msg += "No builder was specified."; } else { msg += "There is no builder called " + builderType + "."; } throw new Exception(msg); } } public boolean isParameterLoaded() { return parameterLoaded; } private Breeder[] getBreederObjects() throws Exception { String[] strBreeders = getStringProperty(ParameterList.BREEDERS_LIST, false).split(","); ArrayList<Breeder> breeders = new ArrayList<Breeder>(); for (String sBreeder : strBreeders) { try { sBreeder = sBreeder.trim(); String[] strBreedersSplitted = sBreeder.split("\\*"); Class<?> breederClass = Class.forName(strBreedersSplitted[0].trim()); Constructor<?> breederConstructor = breederClass.getConstructor(PropertiesManager.class, Double.class); Breeder newBreeder = (Breeder) breederConstructor.newInstance(this, Double.parseDouble(strBreedersSplitted[1].trim())); breeders.add(newBreeder); } catch (ClassNotFoundException e) { String msg = "Error loading the breeder list. "; if (sBreeder.isEmpty()) { msg += "No breeder was specified."; } else { msg += "It was not possible to parse the input \"" + sBreeder + "\"."; } throw new ClassNotFoundException(msg, e); } } return breeders.toArray(new Breeder[breeders.size()]); } /** * * @return @throws Exception */ private Terminal[] getTerminalObjects() throws Exception { String[] sTerminals = getStringProperty(ParameterList.TERMINAL_LIST, false).split(","); boolean useAllInputs = true; for (String str : sTerminals) { str = str.trim(); if (str.toLowerCase().matches("x\\d+")) { useAllInputs = false; break; } } ArrayList<Terminal> terminals = new ArrayList<Terminal>(); if (useAllInputs) { for (int i = 0; i < dataProducer.getNumInputs(); i++) { terminals.add(new Input(i)); } for (String str : sTerminals) { try { str = str.trim(); Class<?> terminal = Class.forName(str); Terminal newTerminal = (Terminal) terminal.newInstance(); terminals.add(newTerminal); } catch (ClassNotFoundException e) { throw new ClassNotFoundException("Error loading the terminal set. Class " + str + " not found", e); } } } else { // ************************ TO IMPLEMENT ************************ } return terminals.toArray(new Terminal[terminals.size()]); } /** * Get the list of functions from the String read from the file * * @return An array of functions * @throws Exception Parameter not found, error while parsing the function * type */ private Function[] getFunctionObjects() throws Exception { String[] sFunctions = getStringProperty(ParameterList.FUNCTION_LIST, false).split(","); ArrayList<Function> functionArray = new ArrayList<Function>(); for (String str : sFunctions) { try { str = str.trim(); Class<?> function = Class.forName(str); functionArray.add((Function) function.newInstance()); } catch (ClassNotFoundException e) { throw new ClassNotFoundException("Error loading the function set. Class " + str + " not found", e); } } return functionArray.toArray(new Function[functionArray.size()]); } /** * Get the population initializer from the file * * @return A new population initializer object * @throws Exception Parameter not found, error while parsing the Populator * type */ private Populator getPopInitObject() throws Exception { String populatorClassname = ""; try { populatorClassname = getStringProperty(ParameterList.POP_INITIALIZER, false).replaceAll("\\s", ""); Class<?> populatorClass = Class.forName(populatorClassname); Constructor<?> populatorConstructor = populatorClass.getConstructor(PropertiesManager.class); return (Populator) populatorConstructor.newInstance(this); } catch (ClassNotFoundException e) { String msg = "Error loading the population initializer. "; if (populatorClassname.isEmpty()) { msg += "No population initializer was specified."; } else { msg += "Class " + populatorClassname + " not found"; } throw new ClassNotFoundException(msg, e); } } /** * Get the pipeline object from the file * * @return A new pipeline object * @throws Exception Parameter not found, error while parsing the Pipeline * type */ private Pipeline getPipelineObject() throws Exception { String populatorClassname = ""; try { populatorClassname = getStringProperty(ParameterList.POP_PIPELINE, false).replaceAll("\\s", ""); Class<?> populatorClass = Class.forName(populatorClassname); Constructor<?> populatorConstructor = populatorClass.getConstructor(); return (Pipeline) populatorConstructor.newInstance(); } catch (ClassNotFoundException e) { String msg = "Error loading the pipeline. "; if (populatorClassname.isEmpty()) { msg += "No pipeline was specified."; } else { msg += "Class " + populatorClassname + " not found"; } throw new ClassNotFoundException(msg, e); } } /** * Get the fitness object from the file * * @return A new fintess function * @throws Exception Parameter not found, error while parsing the Fitness * type */ private Fitness getFitnessObject() throws Exception { String fitnessClassname = ""; try { fitnessClassname = getStringProperty(ParameterList.FITNESS_FUNCTION, false).replaceAll("\\s", ""); Class<?> fitnessClass = Class.forName(fitnessClassname); return (Fitness) fitnessClass.newInstance(); } catch (ClassNotFoundException e) { throw new ClassNotFoundException( "Error loading the fitness function. Class " + fitnessClassname + " not found", e); } } /** * Update the experimental data from the dataProducer */ public void updateExperimentalData() { experimentalData = dataProducer.getExperimentDataset(); } /** * There are tree input options from the CLI: - The path for the parameter * file - One or more parameters to overwrite parameters from the file - The * option of creating a parameter file model on the classpath */ private void setOptions() { cliOptions = new Options(); cliOptions.addOption( Option.builder("p").required(false).hasArg().desc("Paramaters file").type(String.class).build()); cliOptions.addOption(Option.builder("P").required(false).hasArg() .desc("Overwrite of one or more parameters provided by file.").type(String.class).hasArgs() .build()); cliOptions.addOption(Option.builder("H").required(false) .desc("Create a parameter file model on the classpath.").type(String.class).build()); } //********************************** Public getters ********************************** public MersenneTwister getRandomGenerator() { long newSeed = mersennePRNG.nextLong(); return new MersenneTwister(newSeed); } public int getPopulationSize() { return populationSize; } public int getNumExperiments() { return numExperiments; } /** * Return the number of generations to be performed during the evolution * * @return The number of generations */ public int getNumGenerations() { return numGenerations; } public int getNumThreads() { return numThreads; } public int getRTPoolSize() { return rtPoolSize; } public int getMaxInitAttempts() { return maxInitAttempts; } public double getMinError() { return minError; } public double getSpreaderAlpha() { return spreaderAlpha; } public double getSpreaderInitProb() { return spreaderInitProb; } /** * Return the mutation step. If the mutation step is defined w.r.t. the * standard deviation of the training set outputs, we compute the value * before returning it. Otherwise, we return the value obtained from the * parameter file. * * @return The mutation step. */ public double getMutationStep() { // The variable mutationStep is obtained from the parameter file if (!mutStepFromSD) { return mutationStep; } else { return mutationStep * experimentalData.getDataset(DatasetType.TRAINING).getOutputSD(); } } // public double getMutProb() { // return mutProb; // } // // public double getXoverProb() { // return xoverProb; // } // // public double getSemSimThreshold() { // return semSimThres; // } public String getOutputDir() { return outputDir; } public String getFilePrefix() { return filePrefix; } public Fitness geFitnessFunction() { return fitnessFunction.softClone(); } public Node getRandomTree(MersenneTwister rnd) { return randomTreeBuilder.newRootedTree(0, rnd); } public Node getNewIndividualTree(MersenneTwister rnd) { return individualBuilder.newRootedTree(0, rnd); } public Individual[] selectIndividuals(Population population, MersenneTwister rndGenerator, ExperimentalData expData, Statistics stats) { try { Individual[] individuals = new Individual[2]; switch (this.individualSelector) { case "tournament": individuals = doTournament(population, rndGenerator, expData, stats); break; case "betweeness": individuals = doBetweenness(population, rndGenerator, expData, stats); break; } return individuals; } catch (NumberFormatException | NullPointerException ex) { System.err.println("The inidividual selector must be defined."); } return null; } // public Individual[] selectIndividuals(Population population, MersenneTwister rndGenerator, ExperimentalData expData, Statistics stats) { // try { // Individual[] individuals = new Individual[2]; // individuals[0] = selectIndividual(population, rndGenerator, stats); // Population pop = new Population(); // pop.addAll(population); // pop.remove(individuals[0]); //// StatisticsDimension statistics = StatisticsDimension.getInstance(); //// String value = getStringProperty(ParameterList.INDIVIDUAL_SELECTOR, false).toLowerCase(); // switch (this.individualSelector) { // case "tournament": //// statistics.addGeneration(StatisticsDimension.StatsTypeDimension.DIM_TOURNAMENT); //// statistics.addInfoTournament(String.valueOf(-1)); // individuals[1] = selectIndividual(population, rndGenerator, stats); // countDimension(stats, individuals, expData); // break; // case "betweeness": // double chance = Math.random(); // if (chance < this.probability) { // individuals[1] = selectIndividual(pop, individuals[0], expData, stats); // } else { //// statistics.addGeneration(StatisticsDimension.StatsTypeDimension.DIM_TOURNAMENT); //// statistics.addInfoTournament(String.valueOf(-1)); // individuals[1] = selectIndividual(population, rndGenerator, stats); // countDimension(stats, individuals, expData); // } // break; // } // return individuals; // } catch (NumberFormatException | NullPointerException ex) { // System.err.println("The inidividual selector must be defined."); // } // return null; // } private Individual[] doTournament(Population population, MersenneTwister rndGenerator, ExperimentalData expData, Statistics stats) { try { Individual[] individuals = new Individual[2]; individuals[0] = selectIndividual(population, rndGenerator, stats); Population pop = new Population(); pop.addAll(population); pop.remove(individuals[0]); individuals[1] = selectIndividual(pop, rndGenerator, stats); countDimension(stats, individuals, expData); return individuals; } catch (NumberFormatException | NullPointerException ex) { System.err.println("The inidividual selector must be defined."); } return null; } private Individual[] doBetweenness(Population population, MersenneTwister rndGenerator, ExperimentalData expData, Statistics stats) { try { double chance = rndGenerator.nextDouble(); if (chance < this.probability) { Individual[] individuals = new Individual[2]; // individuals[0] = selectIndividual(population, rndGenerator, stats); Individual[] individualsPool = ((TournamentSelector) individualSelectorTournament) .selectIndividuals(population, null, rndGenerator, null, stats); Arrays.sort(individualsPool); individuals[0] = individualsPool[0]; Population pop = new Population(); pop.addAll(individualsPool); pop.remove(individualsPool[0]); // pop.addAll(population); // pop.remove(individuals[0]); individuals[1] = selectIndividual(pop, individuals[0], expData, stats); return individuals; } else { return doTournament(population, rndGenerator, expData, stats); } } catch (NumberFormatException | NullPointerException ex) { System.err.println("The inidividual selector must be defined."); } return null; } private void countDimension(Statistics statistic, Individual[] individuals, ExperimentalData expData) { // Must be expData because this.experimentalData points to the last experimental data loaded and // not to the current execution. double[] outputs = expData.getDataset(Utils.DatasetType.TRAINING).getOutputs(); int numDim = 0; for (int i = 0; i < outputs.length; i++) { double fitnessSemantic1 = individuals[0].getFitnessFunction() .getSemantics(Utils.DatasetType.TRAINING)[i]; double fitnessSemantic2 = individuals[1].getFitnessFunction() .getSemantics(Utils.DatasetType.TRAINING)[i]; if (((fitnessSemantic1 < outputs[i]) && (outputs[i] < fitnessSemantic2)) || ((fitnessSemantic2 < outputs[i]) && (outputs[i] < fitnessSemantic1))) { numDim++; // statistic.addInfoTournament(String.valueOf(i)); } } // statistic.updateInfoTournament(String.valueOf(numDim), 1); statistic.addInfoTournament(String.valueOf(numDim)); // statistic.asWritableString(StatisticsDimension.StatsTypeDimension.DIM_TOURNAMENT); } public Individual selectIndividual(Population population, MersenneTwister rndGenerator, Statistics stats) { return individualSelectorTournament.selectIndividual(population, null, rndGenerator, null, stats); } public Individual selectIndividual(Population population, Individual individual, ExperimentalData expData, Statistics stats) { return individualSelectorDimension.selectIndividual(population, individual, null, expData, stats); } public Function getRandomFunction(MersenneTwister rnd) { return functionSet[rnd.nextInt(functionSet.length)].softClone(); } public Terminal getRandomTerminal(MersenneTwister rnd) { return terminalSet[rnd.nextInt(terminalSet.length)].softClone(rnd); } public ExperimentalData getExperimentalData() { return experimentalData; } /** * Return a copy of the function set, to avoid modifications in the original * set. * * @return A copy of the terminal set */ public Function[] getFunctionSet() { Function[] copyFunctionSet = new Function[functionSet.length]; for (int i = 0; i < functionSet.length; i++) { copyFunctionSet[i] = functionSet[i].softClone(); } return copyFunctionSet; } /** * Return a copy of the terminal set, to avoid modifications in the original * set. * * @param rnd Random number generator used during terminal cloning * @return A copy of the terminal set */ public Terminal[] getTerminalSet(MersenneTwister rnd) { Terminal[] copyTerminalSet = new Terminal[terminalSet.length]; for (int i = 0; i < terminalSet.length; i++) { copyTerminalSet[i] = terminalSet[i].softClone(rnd); } return copyTerminalSet; } /** * Generate an array of pseudorandom number generators, used in * multithreaded environments. * * @param size Number of pseudorandom number generators to be generated * @return The array of PRNG's */ public MersenneTwister[] getMersennePRGNArray(int size) { MersenneTwister[] generators = new MersenneTwister[size]; for (int i = 0; i < size; i++) { long seed = mersennePRNG.nextLong(); generators[i] = new MersenneTwister(seed); } return generators; } public Pipeline getPipeline() { return pipeline.softClone(); } public Populator getPopulationInitializer() { return populationInitializer.softClone(); } /** * Return a list of sof clones of the breeders list recovered from the * parameter file * * @return The list of soft clones of the breeders */ public Breeder[] getBreederList() { Breeder[] copyBreeders = new Breeder[breederList.length]; for (int i = 0; i < breederList.length; i++) { copyBreeders[i] = breederList[i].softClone(this); } return copyBreeders; } public String getLoadedParametersString() { return loadedParametersLog.toString(); } }