eu.crisis_economics.abm.dashboard.GASearchHandler.java Source code

Java tutorial

Introduction

Here is the source code for eu.crisis_economics.abm.dashboard.GASearchHandler.java

Source

/*
 * This file is part of CRISIS, an economics simulator.
 * 
 * Copyright (C) 2015 AITIA International, Inc.
 * Copyright (C) 2015 Ross Richardson
 * Copyright (C) 2015 John Kieran Phillips
 *
 * CRISIS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * CRISIS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with CRISIS.  If not, see <http://www.gnu.org/licenses/>.
 */
package eu.crisis_economics.abm.dashboard;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.swing.JPanel;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;

import org.apache.commons.math3.random.MersenneTwister;
import org.jgap.Chromosome;
import org.jgap.Configuration;
import org.jgap.FitnessEvaluator;
import org.jgap.FitnessFunction;
import org.jgap.Gene;
import org.jgap.Genotype;
import org.jgap.IChromosome;
import org.jgap.InvalidConfigurationException;
import org.jgap.Population;
import org.jgap.RandomGenerator;
import org.jgap.impl.DefaultConfiguration;
import org.reflections.Reflections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import ai.aitia.meme.paramsweep.batch.IModelInformation.ModelInformationException;
import ai.aitia.meme.paramsweep.batch.IParameterSweepResultReader;
import ai.aitia.meme.paramsweep.batch.ReadingException;
import ai.aitia.meme.paramsweep.batch.ResultValueInfo;
import ai.aitia.meme.paramsweep.batch.output.RecordableInfo;
import ai.aitia.meme.paramsweep.batch.param.ParameterTree;
import ai.aitia.meme.paramsweep.colt.DoubleArrayList;
import ai.aitia.meme.paramsweep.generator.IStatisticInfoGenerator;
import ai.aitia.meme.paramsweep.generator.OperatorsInfoGenerator;
import ai.aitia.meme.paramsweep.generator.StatisticsInfoGenerator;
import ai.aitia.meme.paramsweep.gui.info.ISubmodelGUIInfo;
import ai.aitia.meme.paramsweep.gui.info.MemberInfo;
import ai.aitia.meme.paramsweep.gui.info.OperatorGeneratedMemberInfo;
import ai.aitia.meme.paramsweep.gui.info.ParameterInfo;
import ai.aitia.meme.paramsweep.gui.info.RecordableElement;
import ai.aitia.meme.paramsweep.gui.info.SimpleGeneratedMemberInfo;
import ai.aitia.meme.paramsweep.gui.info.SubmodelInfo;
import ai.aitia.meme.paramsweep.intellisweepPlugin.utils.ga.GeneInfo;
import ai.aitia.meme.paramsweep.internal.platform.InfoConverter;
import ai.aitia.meme.paramsweep.operatorPlugin.Operator_TimeSeries;
import ai.aitia.meme.paramsweep.plugin.IIntelliContext;
import ai.aitia.meme.paramsweep.plugin.IIntelliDynamicMethodPlugin;
import ai.aitia.meme.paramsweep.plugin.IStatisticsPlugin;
import ai.aitia.meme.paramsweep.utils.WizardLoadingException;
import ai.aitia.meme.utils.Utils;
import eu.crisis_economics.abm.dashboard.ga.BestChromosomeSelectorConfigurator;
import eu.crisis_economics.abm.dashboard.ga.CrossoverOperatorConfigurator;
import eu.crisis_economics.abm.dashboard.ga.DashboardBreeder;
import eu.crisis_economics.abm.dashboard.ga.GeneAveragingCrossoverOperatorConfigurator;
import eu.crisis_economics.abm.dashboard.ga.IGAOperatorConfigurator;
import eu.crisis_economics.abm.dashboard.ga.IGASelectorConfigurator;
import eu.crisis_economics.abm.dashboard.ga.IIdentifiableGene;
import eu.crisis_economics.abm.dashboard.ga.IWorkspaceAware;
import eu.crisis_economics.abm.dashboard.ga.IdentifiableDoubleGene;
import eu.crisis_economics.abm.dashboard.ga.IdentifiableListGene;
import eu.crisis_economics.abm.dashboard.ga.IdentifiableLongGene;
import eu.crisis_economics.abm.dashboard.ga.MutationOperatorConfigurator;
import eu.crisis_economics.abm.dashboard.ga.TournamentSelectorConfigurator;
import eu.crisis_economics.abm.dashboard.ga.WeightedRouletteSelectorConfigurator;
import eu.crisis_economics.abm.dashboard.ga.operators.StandardPostSelectorFixed;
import eu.crisis_economics.abm.dashboard.generated.GeneralParameter;
import eu.crisis_economics.abm.dashboard.generated.Model;
import eu.crisis_economics.abm.dashboard.generated.ObjectFactory;
import eu.crisis_economics.abm.dashboard.generated.Operator;
import eu.crisis_economics.abm.dashboard.generated.Parameter;
import eu.crisis_economics.abm.dashboard.generated.ParameterType;
import eu.crisis_economics.abm.dashboard.generated.Property;
import eu.crisis_economics.abm.dashboard.generated.Selector;
import eu.crisis_economics.abm.dashboard.generated.SubmodelParameter;
import eu.crisis_economics.abm.dashboard.jaxb.util.ParameterUtil;

@SuppressWarnings("unchecked")
public class GASearchHandler implements GASearchPanelModel, IIntelliDynamicMethodPlugin, IWorkspaceAware {

    //====================================================================================================
    // members

    private static final int DEFAULT_TIMESERIES_LENGTH = 20;
    private static final long serialVersionUID = 45791730954138881L;
    private static final Logger log = LoggerFactory.getLogger(GASearchHandler.class);

    private static final String POPULATION_SIZE = "Population size";
    private static final String POPULATION_RANDOM_SEED = "Population random seed";
    private static final String FIX_NUMBER_OF_GENERATIONS = "Fix number of generations";
    private static final String NUMBER_OF_GENERATIONS = "Number of generations";
    private static final String FITNESS_LIMIT_CRITERION = "Fitness limit";
    private static final String OPTIMIZATION_DIRECTION = "Optimization direction";
    private static final String FITNESS_FUNCTION = "Fitness function";
    private static final String FITNESS_STATISTICS = "Fitness statistics";
    private static final String FITNESS_TIMESERIES_LENGTH = "Fitness time-series length";

    protected static final String ext = ".txt";
    protected static final String bckExt = ".bak";

    private static final List<Class<?>> acceptableReturnTypesForFitnessFunction;
    private static final List<IStatisticsPlugin> fitnessStatistics;

    public static final IStatisticsPlugin noStatistics = new IStatisticsPlugin() {

        @Override
        public String getLocalizedName() {
            return null;
        }

        @Override
        public int getNumberOfParameters() {
            return 0;
        }

        @Override
        public String getName() {
            return "none";
        }

        @Override
        public String getDescription() {
            return "no statistics selected";
        }

        @SuppressWarnings("rawtypes")
        @Override
        public Class getReturnType() {
            return null;
        }

        @SuppressWarnings("rawtypes")
        @Override
        public List<Class> getParameterTypes() {
            return null;
        }

        @Override
        public List<String> getParameterNames() {
            return null;
        }

        @Override
        public List<String> getParameterDescriptions() {
            return null;
        }

        @Override
        public String getFullyQualifiedName() {
            return null;
        }
    };

    static {
        Class<?>[] array = { Byte.TYPE, Byte.class, Short.TYPE, Short.class, Integer.TYPE, Integer.class, Long.TYPE,
                Long.class, Float.TYPE, Float.class, Double.TYPE, Double.class };
        acceptableReturnTypesForFitnessFunction = Arrays.asList(array);

        Reflections reflections = new Reflections("ai.aitia.meme.paramsweep.coltPlugin");
        Set<Class<? extends IStatisticsPlugin>> subTypesOf = reflections.getSubTypesOf(IStatisticsPlugin.class);
        fitnessStatistics = new ArrayList<IStatisticsPlugin>();

        fitnessStatistics.add(noStatistics);

        for (Class<? extends IStatisticsPlugin> pluginClass : subTypesOf) {
            try {
                final IStatisticsPlugin plugin = pluginClass.newInstance();
                @SuppressWarnings("rawtypes")
                List<Class> parameterTypes = plugin.getParameterTypes();
                if (parameterTypes.size() == 1 && parameterTypes.get(0).isAssignableFrom(DoubleArrayList.class)) {
                    fitnessStatistics.add(plugin);
                }
            } catch (InstantiationException e) {
                log.error("Could not instantiate " + pluginClass.getName(), e);
            } catch (IllegalAccessException e) {
                log.error("Could not instantiate " + pluginClass.getName(), e);
            }
        }
    }

    private double numberOfTurns = Dashboard.NUMBER_OF_TURNS;
    private int populationSize = 12;
    private int populationGenerationSeed = 1;
    private int numberOfGenerations = 12;
    private double fitnessLimitCriterion = 0;
    private boolean fixNumberOfGenerations = true;
    private FitnessFunctionDirection optimizationDirection = FitnessFunctionDirection.MINIMIZE;
    private RecordableInfo selectedFunction;

    private IStatisticsPlugin selectedFitnessStatistics;

    private final List<IGASelectorConfigurator> selectedSelectionOperators = new ArrayList<IGASelectorConfigurator>();

    private final List<IGAOperatorConfigurator> selectedGeneticOperators = new ArrayList<IGAOperatorConfigurator>();

    private DefaultConfiguration gaConfiguration;

    /**
     * The available selection operators.
     */
    private List<IGASelectorConfigurator> selectors;

    /**
     * The available genetic operators.
     */
    private List<IGAOperatorConfigurator> geneticOperators;

    /**
     * The list of fitness functions.
     */
    private final List<RecordableInfo> fitnessFunctions = new ArrayList<RecordableInfo>();

    private int fitnessTimeSeriesLength = DEFAULT_TIMESERIES_LENGTH;

    private final String populationFileName = "population";

    private DefaultTreeModel chromosomeTree;
    private List<GeneInfo> genes = null;
    private int iterationCounter = 1;
    private boolean reachFitnessLimit = false;

    private Genotype genotype;
    private List<ParameterInfo> paramList;

    private final List<ModelListener> listeners = new ArrayList<GASearchPanelModel.ModelListener>();

    private File workspace = new File(".");
    private IModelHandler currentModelHandler = null;

    //====================================================================================================
    // methods

    //----------------------------------------------------------------------------------------------------
    public GASearchHandler(final IModelHandler currentModelHandler) {
        selectors = Arrays.asList(new TournamentSelectorConfigurator(), new WeightedRouletteSelectorConfigurator(),
                new BestChromosomeSelectorConfigurator());
        geneticOperators = Arrays.asList(new GeneAveragingCrossoverOperatorConfigurator(),
                new CrossoverOperatorConfigurator(), new MutationOperatorConfigurator());

        init(currentModelHandler);
    }

    //----------------------------------------------------------------------------------------------------
    public void init(final IModelHandler modelHandler) {
        this.currentModelHandler = modelHandler;
        numberOfTurns = Dashboard.NUMBER_OF_TURNS;
        populationSize = 12;
        populationGenerationSeed = 1;
        numberOfGenerations = 12;
        fitnessLimitCriterion = 0;
        fixNumberOfGenerations = true;
        optimizationDirection = FitnessFunctionDirection.MINIMIZE;
        selectedFunction = new RecordableInfo("Please select a function!", Object.class,
                "Please select a function!");

        selectedFitnessStatistics = fitnessStatistics.get(0);
        fitnessTimeSeriesLength = DEFAULT_TIMESERIES_LENGTH;

        selectedSelectionOperators.clear();
        selectedGeneticOperators.clear();

        gaConfiguration = null;
        fitnessFunctions.clear();

        iterationCounter = 1;
        reachFitnessLimit = false;

        genotype = null;
        paramList = null;

        workspace = new File(".");

        fitnessFunctions.add(selectedFunction);

        selectedSelectionOperators.add(selectors.get(2));

        selectedGeneticOperators.add(geneticOperators.get(0));
        selectedGeneticOperators.add(geneticOperators.get(2));
    }

    //----------------------------------------------------------------------------------------------------
    public void saveConfiguration(final ObjectFactory factory, final Model config) {
        saveGeneralParameters(factory, config);
        saveSelectors(factory, config);
        saveOperators(factory, config);
        saveChromosome(factory, config);
    }

    //----------------------------------------------------------------------------------------------------
    private void saveGeneralParameters(final ObjectFactory factory, final Model config) {
        final List<GeneralParameter> generalParameters = config.getGeneralParameterList();

        GeneralParameter gp = factory.createGeneralParameter();
        gp.setName(ParameterTreeUtils.NUMBER_OF_TURNS_XML_NAME);
        gp.setValue(String.valueOf(numberOfTurns));
        generalParameters.add(gp);

        gp = factory.createGeneralParameter();
        gp.setName(POPULATION_SIZE);
        gp.setValue(String.valueOf(populationSize));
        generalParameters.add(gp);

        gp = factory.createGeneralParameter();
        gp.setName(POPULATION_RANDOM_SEED);
        gp.setValue(String.valueOf(populationGenerationSeed));
        generalParameters.add(gp);

        gp = factory.createGeneralParameter();
        gp.setName(FIX_NUMBER_OF_GENERATIONS);
        gp.setValue(String.valueOf(fixNumberOfGenerations));
        generalParameters.add(gp);

        gp = factory.createGeneralParameter();
        gp.setName(NUMBER_OF_GENERATIONS);
        gp.setValue(String.valueOf(numberOfGenerations));
        generalParameters.add(gp);

        gp = factory.createGeneralParameter();
        gp.setName(FITNESS_LIMIT_CRITERION);
        gp.setValue(String.valueOf(fitnessLimitCriterion));
        generalParameters.add(gp);

        gp = factory.createGeneralParameter();
        gp.setName(OPTIMIZATION_DIRECTION);
        gp.setValue(optimizationDirection.name());
        generalParameters.add(gp);

        gp = factory.createGeneralParameter();
        gp.setName(FITNESS_FUNCTION);
        gp.setValue(createUniqueName(selectedFunction));
        generalParameters.add(gp);

        gp = factory.createGeneralParameter();
        gp.setName(FITNESS_STATISTICS);
        gp.setValue(selectedFitnessStatistics.getName());
        generalParameters.add(gp);

        gp = factory.createGeneralParameter();
        gp.setName(FITNESS_TIMESERIES_LENGTH);
        gp.setValue(String.valueOf(fitnessTimeSeriesLength));
        generalParameters.add(gp);
    }

    //----------------------------------------------------------------------------------------------------
    private String createUniqueName(final RecordableInfo fitnessFunction) {
        //TODO: support 'the fitness function is part of a submodel parameter' case too
        return fitnessFunction.getName();
    }

    //----------------------------------------------------------------------------------------------------
    private void saveSelectors(final ObjectFactory factory, final Model config) {
        final List<Selector> selectors = config.getSelectorList();

        for (final IGASelectorConfigurator selectorOperator : selectedSelectionOperators) {
            final Selector selector = factory.createSelector();
            selector.setType(selectorOperator.getName());
            final List<Property> selectorProperties = selector.getSelectorProperties();

            for (final Entry<String, String> entry : selectorOperator.getConfiguration().entrySet()) {
                final Property property = factory.createProperty();
                property.setKey(entry.getKey());
                property.setValue(entry.getValue());
                selectorProperties.add(property);
            }

            selectors.add(selector);
        }
    }

    //----------------------------------------------------------------------------------------------------
    private void saveOperators(final ObjectFactory factory, final Model config) {
        final List<Operator> operators = config.getOperatorList();

        for (final IGAOperatorConfigurator geneticOperator : selectedGeneticOperators) {
            final Operator operator = factory.createOperator();
            operator.setType(geneticOperator.getName());
            final List<Property> operatorProperties = operator.getOperatorProperties();

            for (final Entry<String, String> entry : geneticOperator.getConfiguration().entrySet()) {
                final Property property = factory.createProperty();
                property.setKey(entry.getKey());
                property.setValue(entry.getValue());
                operatorProperties.add(property);
            }

            operators.add(operator);
        }
    }

    //----------------------------------------------------------------------------------------------------
    private void saveChromosome(final ObjectFactory factory, final Model config) {
        final eu.crisis_economics.abm.dashboard.generated.Chromosome chromosome = factory.createChromosome();

        @SuppressWarnings("rawtypes")
        final Enumeration nodes = ((DefaultMutableTreeNode) chromosomeTree.getRoot()).children();
        while (nodes.hasMoreElements()) {
            final DefaultMutableTreeNode node = (DefaultMutableTreeNode) nodes.nextElement();
            saveParameterOrGene(node, factory, chromosome);
        }

        config.setChromosome(chromosome);
    }

    //----------------------------------------------------------------------------------------------------
    private void saveParameterOrGene(final DefaultMutableTreeNode node, final ObjectFactory factory,
            final Object parent) {
        final ParameterOrGene userObj = (ParameterOrGene) node.getUserObject();
        final ParameterInfo info = userObj.getInfo();

        if (userObj.isGene()) {
            final GeneInfo geneInfo = userObj.getGeneInfo();

            final eu.crisis_economics.abm.dashboard.generated.Gene gene = factory.createGene();
            gene.setName(info.getName());
            gene.setGeneType(geneInfo.getValueType());

            if (GeneInfo.INTERVAL.equals(geneInfo.getValueType())) {
                gene.setInteger(geneInfo.isIntegerVals());
                gene.setMin(geneInfo.isIntegerVals() ? new BigDecimal(geneInfo.getMinValue().longValue())
                        : new BigDecimal(geneInfo.getMinValue().doubleValue()));
                gene.setMax(geneInfo.isIntegerVals() ? new BigDecimal(geneInfo.getMaxValue().longValue())
                        : new BigDecimal(geneInfo.getMaxValue().doubleValue()));
            } else {
                final List<String> geneValues = gene.getGeneValueList();
                for (final Object value : geneInfo.getValueRange())
                    geneValues.add(String.valueOf(value));
            }

            if (parent instanceof eu.crisis_economics.abm.dashboard.generated.Chromosome) {
                final eu.crisis_economics.abm.dashboard.generated.Chromosome chromosome = (eu.crisis_economics.abm.dashboard.generated.Chromosome) parent;
                chromosome.getGeneList().add(gene);
            } else if (parent instanceof SubmodelParameter) {
                final SubmodelParameter submodelParameter = (SubmodelParameter) parent;
                submodelParameter.getGeneList().add(gene);
            }

        } else if (info instanceof SubmodelInfo) {
            final SubmodelInfo sInfo = (SubmodelInfo) info;

            final SubmodelParameter parameter = factory.createSubmodelParameter();
            parameter.setName(info.getName());
            parameter.setType(sInfo.getActualType() == null ? "null" : sInfo.getActualType().getName());

            if (parent instanceof eu.crisis_economics.abm.dashboard.generated.Chromosome) {
                final eu.crisis_economics.abm.dashboard.generated.Chromosome chromosome = (eu.crisis_economics.abm.dashboard.generated.Chromosome) parent;
                chromosome.getSubmodelParameterList().add(parameter);
            } else if (parent instanceof SubmodelParameter) {
                final SubmodelParameter submodelParameter = (SubmodelParameter) parent;
                submodelParameter.getSubmodelParameterList().add(parameter);
            }

            if (node.getChildCount() > 0) {
                @SuppressWarnings("rawtypes")
                final Enumeration childNodes = node.children();
                while (childNodes.hasMoreElements()) {
                    final DefaultMutableTreeNode childNode = (DefaultMutableTreeNode) childNodes.nextElement();
                    saveParameterOrGene(childNode, factory, parameter);
                }
            }
        } else {
            final Parameter parameter = factory.createParameter();
            parameter.setName(info.getName());
            parameter.setParameterType(ParameterType.CONSTANT);
            parameter.getContent().add(info.getValue().toString());

            if (parent instanceof eu.crisis_economics.abm.dashboard.generated.Chromosome) {
                final eu.crisis_economics.abm.dashboard.generated.Chromosome chromosome = (eu.crisis_economics.abm.dashboard.generated.Chromosome) parent;
                chromosome.getParameterList().add(parameter);
            } else if (parent instanceof SubmodelParameter) {
                final SubmodelParameter submodelParameter = (SubmodelParameter) parent;
                submodelParameter.getParameterList().add(parameter);
            }
        }
    }

    //----------------------------------------------------------------------------------------------------
    /**
     * This method creates a list of {@link ParameterInfo} instances for the {@link #loadConfiguration(Model, List)} method. How the list of {@link ai.aitia.meme.paramsweep.batch.param.ParameterInfo} is converted 
     * to {@link ParameterInfo} is copied from {@link Page_Parameters#createAndDisplayAParameterPanel} method.
     * 
     * @param config the object representing the XML file
     * @param parameters the list of model parameters
     * @throws ModelInformationException if {@link #loadConfiguration(Model, List)} throws an exception
     */
    public void loadConfigurationFromBatchInfo(final Model config,
            final List<ai.aitia.meme.paramsweep.batch.param.ParameterInfo<?>> parameters)
            throws ModelInformationException {
        final List<ParameterInfo> info = new ArrayList<ParameterInfo>();
        for (ai.aitia.meme.paramsweep.batch.param.ParameterInfo<?> batchParameterInfo : parameters) {
            final ParameterInfo parameterInfo = InfoConverter.parameterInfo2ParameterInfo(batchParameterInfo);
            // prepare the parameterInfo for the param sweeps
            parameterInfo.setRuns(0);
            parameterInfo.setDefinitionType(ParameterInfo.CONST_DEF);
            parameterInfo.setValue(batchParameterInfo.getDefaultValue());
            info.add(parameterInfo);
        }

        loadConfiguration(config, info);
    }

    //----------------------------------------------------------------------------------------------------
    @Override
    public void loadConfiguration(final Model config, final List<ParameterInfo> parameters)
            throws ModelInformationException {
        final List<GeneralParameter> generalParameters = config.getGeneralParameterList();
        loadGeneralParameters(generalParameters);

        final List<Selector> selectors = config.getSelectorList();
        loadSelectors(selectors);

        final List<Operator> operators = config.getOperatorList();
        loadOperators(operators);

        loadChromosome(config.getChromosome(), parameters);
    }

    //----------------------------------------------------------------------------------------------------
    private void loadGeneralParameters(final List<GeneralParameter> generalParameters) {
        for (final GeneralParameter generalParameter : generalParameters) {
            if (ParameterTreeUtils.NUMBER_OF_TURNS_XML_NAME.equals(generalParameter.getName()))
                numberOfTurns = Double.parseDouble(generalParameter.getValue());
            else if (POPULATION_SIZE.equals(generalParameter.getName()))
                populationSize = Integer.parseInt(generalParameter.getValue());
            else if (POPULATION_RANDOM_SEED.equals(generalParameter.getName()))
                populationGenerationSeed = Integer.parseInt(generalParameter.getValue());
            else if (FIX_NUMBER_OF_GENERATIONS.equals(generalParameter.getName()))
                fixNumberOfGenerations = Boolean.parseBoolean(generalParameter.getValue());
            else if (NUMBER_OF_GENERATIONS.equals(generalParameter.getName()))
                numberOfGenerations = Integer.parseInt(generalParameter.getValue());
            else if (FITNESS_LIMIT_CRITERION.equals(generalParameter.getName()))
                fitnessLimitCriterion = Double.parseDouble(generalParameter.getValue());
            else if (OPTIMIZATION_DIRECTION.equals(generalParameter.getName()))
                optimizationDirection = FitnessFunctionDirection.valueOf(generalParameter.getValue());
            else if (FITNESS_FUNCTION.equals(generalParameter.getName()))
                loadSelectedFitnessFunction(generalParameter.getValue());
            else if (FITNESS_STATISTICS.equals(generalParameter.getName())) {
                loadSelectedFitnessStatistics(generalParameter.getValue());
            } else if (FITNESS_TIMESERIES_LENGTH.equals(generalParameter.getName())) {
                fitnessTimeSeriesLength = Integer.parseInt(generalParameter.getValue());
            }
        }
    }

    private void loadSelectedFitnessStatistics(final String fitnessStatisticsName) {
        for (IStatisticsPlugin statistics : fitnessStatistics) {
            if (statistics.getName().equals(fitnessStatisticsName)) {
                selectedFitnessStatistics = statistics;
                break;
            }
        }
    }

    //----------------------------------------------------------------------------------------------------
    private void loadSelectedFitnessFunction(final String identifier) {
        for (final RecordableInfo function : fitnessFunctions) {
            //TODO: support 'the fitness function is part of a submodel parameter' case too
            if (identifier.equals(function.getName())) {
                selectedFunction = function;
                break;
            }
        }
    }

    //----------------------------------------------------------------------------------------------------
    private void loadSelectors(final List<Selector> selectorList) throws ModelInformationException {
        selectedSelectionOperators.clear();

        for (final Selector selector : selectorList) {
            final String selectorType = selector.getType();
            final IGASelectorConfigurator matchedConfigurator = findSelectorConfigurator(selectorType);
            final Map<String, String> config = convertPropertiesToMap(selector.getSelectorProperties());
            matchedConfigurator.setConfiguration(config);
            selectedSelectionOperators.add(matchedConfigurator);
        }
    }

    //----------------------------------------------------------------------------------------------------
    private IGASelectorConfigurator findSelectorConfigurator(final String selectorType)
            throws ModelInformationException {
        for (final IGASelectorConfigurator configurator : selectors) {
            if (configurator.getName().equals(selectorType))
                return configurator;
        }

        throw new ModelInformationException("Unrecognized selector: " + selectorType + ".");
    }

    //----------------------------------------------------------------------------------------------------
    private void loadOperators(final List<Operator> operatorList) throws ModelInformationException {
        selectedGeneticOperators.clear();

        for (final Operator operator : operatorList) {
            final String operatorType = operator.getType();
            final IGAOperatorConfigurator matchedConfigurator = findOperatorConfigurator(operatorType);
            final Map<String, String> config = convertPropertiesToMap(operator.getOperatorProperties());
            matchedConfigurator.setConfiguration(config);
            selectedGeneticOperators.add(matchedConfigurator);
        }
    }

    //----------------------------------------------------------------------------------------------------
    private IGAOperatorConfigurator findOperatorConfigurator(final String operatorType)
            throws ModelInformationException {
        for (final IGAOperatorConfigurator configurator : geneticOperators) {
            if (configurator.getName().equals(operatorType))
                return configurator;
        }

        throw new ModelInformationException("Unrecognized genetic operator: " + operatorType + ".");
    }

    //----------------------------------------------------------------------------------------------------
    private void loadChromosome(final eu.crisis_economics.abm.dashboard.generated.Chromosome chromosome,
            final List<ParameterInfo> parameters) throws ModelInformationException {
        final int childCount = getChromosomeTree().getChildCount(getChromosomeTree().getRoot());
        if (childCount > 0) {
            final DefaultMutableTreeNode root = (DefaultMutableTreeNode) getChromosomeTree().getRoot();
            for (int i = childCount - 1; i >= 0; --i) {
                final MutableTreeNode node = (MutableTreeNode) root.getChildAt(i);
                getChromosomeTree().removeNodeFromParent(node);
            }
            genes = null;
        }

        final DefaultMutableTreeNode root = (DefaultMutableTreeNode) getChromosomeTree().getRoot();
        loadChromosomeTreeLevel(root, parameters, chromosome.getParameterList(),
                chromosome.getSubmodelParameterList(), chromosome.getGeneList());
    }

    //----------------------------------------------------------------------------------------------------
    private void loadChromosomeTreeLevel(final DefaultMutableTreeNode parent, final List<ParameterInfo> infos,
            final List<Parameter> parameters, final List<SubmodelParameter> submodelParameters,
            final List<eu.crisis_economics.abm.dashboard.generated.Gene> genes) throws ModelInformationException {

        for (final eu.crisis_economics.abm.dashboard.generated.Gene gene : genes) {
            final ParameterInfo info = findParameterInfo(infos, gene.getName());
            if (info == null)
                throw new ModelInformationException("Unrecognized parameter: " + gene.getName() + ".");

            //initializeParent(info,parent);
            final ParameterOrGene userObj = initializeUserObjectFromGene(gene, info);
            final DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(userObj);
            getChromosomeTree().insertNodeInto(newNode, parent, parent.getChildCount());

        }

        for (final SubmodelParameter parameter : submodelParameters) {
            final ParameterInfo info = findParameterInfo(infos, parameter.getName());
            if (info == null)
                throw new ModelInformationException("Unrecognized parameter: " + parameter.getName() + ".");

            //initializeParent(info,parent);
            final SubmodelInfo submodelInfo = (SubmodelInfo) info;
            final String strType = parameter.getType();
            try {
                final Class<?> clazz = Class.forName(strType, true, currentModelHandler.getCustomClassLoader());
                if (submodelInfo.getActualType() == null
                        || !strType.equals(submodelInfo.getActualType().getName())) {
                    submodelInfo.setActualType(clazz, null);
                }

                final ParameterOrGene userObj = new ParameterOrGene(info);
                final DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(userObj);
                getChromosomeTree().insertNodeInto(newNode, parent, parent.getChildCount());

                final List<ai.aitia.meme.paramsweep.batch.param.ParameterInfo<?>> batchSubparameters = ParameterTreeUtils
                        .fetchSubparameters(currentModelHandler, submodelInfo);
                final List<ParameterInfo> subparameters = new ArrayList<ParameterInfo>(batchSubparameters.size());
                for (final ai.aitia.meme.paramsweep.batch.param.ParameterInfo<?> parameterInfo : batchSubparameters)
                    subparameters.add(InfoConverter.parameterInfo2ParameterInfo(parameterInfo));

                loadChromosomeTreeLevel(newNode, subparameters, parameter.getParameterList(),
                        parameter.getSubmodelParameterList(), parameter.getGeneList());
            } catch (final ClassNotFoundException e) {
                throw new ModelInformationException(
                        "Invalid actual type " + strType + " for submodel parameter: " + submodelInfo.getName(), e);
            }
        }

        for (final Parameter parameter : parameters) {
            final ParameterInfo info = findParameterInfo(infos, parameter.getName());
            if (info == null)
                throw new ModelInformationException("Unrecognized parameter: " + parameter.getName() + ".");

            //initializeParent(info,parent);
            info.setDefinitionType(ParameterInfo.CONST_DEF);
            String parameterValue = ParameterUtil.getParameterValue(parameter);
            Object value;
            if (info.getType().equals("File") && parameterValue == null) {
                value = new File("");
            } else {
                value = ParameterInfo.getValue(parameterValue, info.getJavaType());
            }
            info.setValue(value);

            final ParameterOrGene userObj = new ParameterOrGene(info);
            final DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(userObj);
            getChromosomeTree().insertNodeInto(newNode, parent, parent.getChildCount());
        }

    }

    //----------------------------------------------------------------------------------------------------
    private ParameterInfo findParameterInfo(final List<ParameterInfo> parameters, final String name) {
        for (final ParameterInfo info : parameters) {
            if (name.equals(info.getName()))
                return info;
        }

        return null;
    }

    //----------------------------------------------------------------------------------------------------
    //   private void initializeParent(final ParameterInfo parameterInfo, final DefaultMutableTreeNode parent) {
    //      if (parent.getUserObject() != null && parameterInfo instanceof ISubmodelGUIInfo) {
    //         final ISubmodelGUIInfo sgi = (ISubmodelGUIInfo) parameterInfo;
    //         final ParameterOrGene parentUserObject = (ParameterOrGene) parent.getUserObject();
    //         final SubmodelInfo parentInfo = (SubmodelInfo) parentUserObject.getInfo();
    //         sgi.setParentValue(parentInfo.getActualType());
    //      }
    //   }

    //----------------------------------------------------------------------------------------------------
    private ParameterOrGene initializeUserObjectFromGene(
            final eu.crisis_economics.abm.dashboard.generated.Gene gene, final ParameterInfo info) {
        if (GeneInfo.INTERVAL.equals(gene.getGeneType())) {
            final boolean integerInterval = gene.isInteger();
            return integerInterval ? new ParameterOrGene(info, gene.getMin().longValue(), gene.getMax().longValue())
                    : new ParameterOrGene(info, gene.getMin().doubleValue(), gene.getMax().doubleValue());
        } else {
            final List<Object> valueList = new ArrayList<Object>(gene.getGeneValueList().size());

            for (final String geneValue : gene.getGeneValueList())
                valueList.add(parseListElement(info.getJavaType(), geneValue));
            return new ParameterOrGene(info, valueList);
        }
    }

    //----------------------------------------------------------------------------------------------------
    private Map<String, String> convertPropertiesToMap(final List<Property> properties) {
        final Map<String, String> result = new HashMap<String, String>();
        for (final Property property : properties)
            result.put(property.getKey(), property.getValue());

        return result;
    }

    //----------------------------------------------------------------------------------------------------
    private Object parseListElement(final Class<?> type, final String strValue) {
        if (type.equals(Double.class) || type.equals(Float.class) || type.equals(Double.TYPE)
                || type.equals(Float.TYPE))
            return Double.parseDouble(strValue);

        return Long.parseLong(strValue);
    }

    //----------------------------------------------------------------------------------------------------
    public void addFitnessFunction(final RecordableInfo fitnessFunction) {
        fitnessFunctions.add((RecordableInfo) fitnessFunction);

        for (final ModelListener listener : listeners)
            listener.fitnessFunctionAdded();
    }

    //----------------------------------------------------------------------------------------------------
    public void removeAllFitnessFunctions() {
        fitnessFunctions.clear();
        fitnessFunctions
                .add(new RecordableInfo("Please select a function!", Object.class, "Please select a function!"));

        for (final ModelListener listener : listeners)
            listener.fitnessFunctionsRemoved();
    }

    //----------------------------------------------------------------------------------------------------
    public List<IGASelectorConfigurator> getSelectionOperators() {
        return selectors;
    }

    public List<RecordableInfo> getFitnessFunctions() {
        return fitnessFunctions;
    }

    @Override
    public List<IStatisticsPlugin> getFitnessStatistics() {
        return fitnessStatistics;
    }

    public List<IGAOperatorConfigurator> getGeneticOperators() {
        return geneticOperators;
    }

    public double getNumberOfTurns() {
        return numberOfTurns;
    }

    public int getPopulationSize() {
        return populationSize;
    }

    public int getPopulationRandomSeed() {
        return populationGenerationSeed;
    }

    public int getNumberOfGenerations() {
        return numberOfGenerations;
    }

    public double getFitnessLimitCriterion() {
        return fitnessLimitCriterion;
    }

    public FitnessFunctionDirection getFitnessFunctionDirection() {
        return optimizationDirection;
    }

    public RecordableInfo getSelectedFitnessFunction() {
        return selectedFunction;
    }

    @Override
    public IStatisticsPlugin getSelectedFitnessStatistics() {
        return selectedFitnessStatistics;
    }

    @Override
    public int getFitnessTimeSeriesLength() {
        return fitnessTimeSeriesLength;
    }

    public List<IGAOperatorConfigurator> getSelectedGeneticOperators() {
        return selectedGeneticOperators;
    }

    public List<IGASelectorConfigurator> getSelectedSelectionOperators() {
        return selectedSelectionOperators;
    }

    public boolean isFixNumberOfGenerations() {
        return fixNumberOfGenerations;
    }

    public File getWorkspace() {
        return workspace;
    }

    //----------------------------------------------------------------------------------------------------
    public void setNumberOfTurns(final double numberOfTurns) {
        this.numberOfTurns = numberOfTurns;
    }

    public void setPopulationSize(final int populationSize) {
        this.populationSize = populationSize;
    }

    public void setPopulationRandomSeed(final int seed) {
        this.populationGenerationSeed = seed;
    }

    public void setNumberOfGenerations(final int numberOfGenerations) {
        this.numberOfGenerations = numberOfGenerations;
    }

    public void setFitnessLimitCriterion(final double fitnessLimit) {
        this.fitnessLimitCriterion = fitnessLimit;
    }

    public void setFitnessFunctionDirection(final FitnessFunctionDirection direction) {
        this.optimizationDirection = direction;
    }

    @Override
    public void setSelectedFitnessFunction(final RecordableInfo fitnessFunction) {
        this.selectedFunction = (RecordableInfo) fitnessFunction;
    }

    public void setSelectedFitnessFunction(final String fitnessFunctionName) {
        loadSelectedFitnessFunction(fitnessFunctionName);
    }

    @Override
    public void setSelectedFitnessStatistics(IStatisticsPlugin fitnessStatistics) {
        this.selectedFitnessStatistics = fitnessStatistics;
    }

    public void setSelectedFitnessStatistics(final String fitnessStatisticsName) {
        loadSelectedFitnessStatistics(fitnessStatisticsName);
    }

    @Override
    public void setFitnessTimeSeriesLength(int fitnessTimeSeriesLength) {
        this.fitnessTimeSeriesLength = fitnessTimeSeriesLength;
    }

    public void setFixNumberOfGenerations(final boolean fixNumberOfGenerations) {
        this.fixNumberOfGenerations = fixNumberOfGenerations;
    }

    public void setWorkspace(final File workspace) {
        this.workspace = workspace;
    }

    //----------------------------------------------------------------------------------------------------
    public DefaultTreeModel getChromosomeTree() {
        if (chromosomeTree == null)
            chromosomeTree = new DefaultTreeModel(new DefaultMutableTreeNode());
        return chromosomeTree;
    }

    //----------------------------------------------------------------------------------------------------
    public void setSelectedSelectionOperator(final IGASelectorConfigurator operator) {
        if (operator != null && !selectedSelectionOperators.contains(operator))
            selectedSelectionOperators.add(operator);
    }

    //----------------------------------------------------------------------------------------------------
    public boolean unsetSelectedSelectionOperator(final IGASelectorConfigurator operator) {
        return selectedSelectionOperators.remove(operator);
    }

    //----------------------------------------------------------------------------------------------------
    public void setSelectedGeneticOperator(final IGAOperatorConfigurator operator) {
        if (operator != null && !selectedGeneticOperators.contains(operator))
            selectedGeneticOperators.add(operator);
    }

    //----------------------------------------------------------------------------------------------------
    public boolean unsetSelectedGeneticOperator(final IGAOperatorConfigurator operator) {
        return selectedGeneticOperators.remove(operator);
    }

    //----------------------------------------------------------------------------------------------------
    public boolean addModelListener(final ModelListener listener) {
        return listeners.add(listener);
    }

    //----------------------------------------------------------------------------------------------------
    public boolean removeModelListener(final ModelListener listener) {
        return listeners.remove(listener);
    }

    public void addSubmodelParameter(final SubmodelInfo sInfo, final DefaultMutableTreeNode node)
            throws ModelInformationException {
        if (sInfo.getActualType() == null) {
            if (node.getChildCount() > 0) {
                node.removeAllChildren();
                chromosomeTree.nodeStructureChanged(node);
            }

            return;
        }

        final List<ai.aitia.meme.paramsweep.batch.param.ParameterInfo<?>> subparameters = ParameterTreeUtils
                .fetchSubparameters(currentModelHandler, sInfo);

        final List<ParameterInfo> convertedSubparameters = new ArrayList<ParameterInfo>(subparameters.size());
        for (ai.aitia.meme.paramsweep.batch.param.ParameterInfo<?> parameterInfo : subparameters) {
            final ParameterInfo converted = InfoConverter.parameterInfo2ParameterInfo(parameterInfo);
            converted.setRuns(0);
            convertedSubparameters.add(converted);
        }
        Collections.sort(convertedSubparameters);

        if (node.getChildCount() > 0) {
            node.removeAllChildren();
            chromosomeTree.nodeStructureChanged(node);
        }

        for (final ParameterInfo pInfo : convertedSubparameters) {
            final DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(new ParameterOrGene(pInfo));
            chromosomeTree.insertNodeInto(newNode, node, node.getChildCount());

            if (pInfo instanceof SubmodelInfo) {
                final SubmodelInfo ssInfo = (SubmodelInfo) pInfo;
                if (ssInfo.getActualType() != null)
                    addSubmodelParameter(ssInfo, newNode);
            }

        }
    }

    //----------------------------------------------------------------------------------------------------
    public void addParameter(final ParameterOrGene parameterOrGene) throws ModelInformationException {
        if (chromosomeTree == null) {
            chromosomeTree = new DefaultTreeModel(new DefaultMutableTreeNode());
            genes = null;
        }

        final DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(parameterOrGene);
        final DefaultMutableTreeNode root = (DefaultMutableTreeNode) chromosomeTree.getRoot();
        chromosomeTree.insertNodeInto(newNode, root, root.getChildCount());

        if (parameterOrGene.info instanceof SubmodelInfo) {
            final SubmodelInfo ssInfo = (SubmodelInfo) parameterOrGene.info;
            if (ssInfo.getActualType() != null)
                addSubmodelParameter(ssInfo, newNode);
        }

        for (final ModelListener listener : listeners)
            listener.parameterAdded();
    }

    //----------------------------------------------------------------------------------------------------
    public void removeAllParameters() {
        if (chromosomeTree == null)
            chromosomeTree = new DefaultTreeModel(new DefaultMutableTreeNode());
        else
            chromosomeTree.setRoot(new DefaultMutableTreeNode());

        genes = null;

        for (final ModelListener listener : listeners)
            listener.parametersRemoved();
    }

    //----------------------------------------------------------------------------------------------------
    public String[] checkGAModel() {
        final List<String> errors = new ArrayList<String>();

        final RecordableInfo invalid = new RecordableInfo("Please select a function!", Object.class,
                "Please select a function!");
        if (selectedFunction.equals(invalid))
            errors.add("Please select a valid fitness function!");

        if (selectedSelectionOperators.isEmpty())
            errors.add("Please select at least one selector!");

        if (selectedGeneticOperators.isEmpty())
            errors.add("Please select at least one genetic operator!");

        if (calculateNumberOfGenes() == 0)
            errors.add("Please specify at least one gene!");

        return errors.size() == 0 ? null : errors.toArray(new String[0]);
    }

    //----------------------------------------------------------------------------------------------------
    public boolean canBeFitnessFunction(final RecordableInfo candidate) {
        return acceptableReturnTypesForFitnessFunction.contains(candidate.getType());
    }

    //----------------------------------------------------------------------------------------------------
    public int getNumberOfIterations() {
        if (fixNumberOfGenerations)
            return numberOfGenerations - 1;
        else
            return Integer.MAX_VALUE;
    }

    //----------------------------------------------------------------------------------------------------
    public int getCurrentIteration() {
        return iterationCounter;
    }

    //----------------------------------------------------------------------------------------------------
    public boolean noMoreIteration() {
        if (fixNumberOfGenerations)
            return iterationCounter > getNumberOfGenerations();
        else
            return reachFitnessLimit;
    }

    //----------------------------------------------------------------------------------------------------
    public ParameterTree getNextParameterTree(final IParameterSweepResultReader reader) {
        if (iterationCounter == 1) // first time
            initPopFile();

        iterationCounter++;

        ((ResultFileFitnessFunction) gaConfiguration.getFitnessFunction()).setCurrentReader(reader);

        printPopulation(iterationCounter - 1);

        if (!fixNumberOfGenerations) {
            final IChromosome fittestChromosome = genotype.getFittestChromosome();
            final double fitnessValue = gaConfiguration.getFitnessFunction().getFitnessValue(fittestChromosome);
            reachFitnessLimit = optimizationDirection == FitnessFunctionDirection.MINIMIZE
                    ? fitnessValue <= fitnessLimitCriterion
                    : fitnessValue >= fitnessLimitCriterion;

            if (reachFitnessLimit)
                return null;
        }

        if (iterationCounter > getNumberOfGenerations())
            return null;

        genotype.evolve();

        final ParameterTree nextTree = new ParameterTree();
        final Population descendants = genotype.getPopulation();

        for (int i = 0; i < paramList.size(); ++i) {
            final ParameterInfo paramInfo = paramList.get(i);
            paramInfo.setRuns(1); // Run is always 1

            final List<Object> values = new ArrayList<Object>();

            final int genIdx = whichGene(calculateName(paramInfo));
            for (int j = 0; j < descendants.size(); ++j) {
                IChromosome chromosome = descendants.getChromosome(j);
                if (chromosome.getFitnessValueDirectly() > -1.0D) {
                    if (genIdx >= 0) {
                        final String strValue = String.valueOf(chromosome.getGene(genIdx).getAllele());
                        values.add(ParameterInfo.getValue(strValue, paramInfo.getType()));
                        paramInfo.setDefinitionType(ParameterInfo.LIST_DEF);
                    } else {
                        values.add(paramInfo.getValue());
                        paramInfo.setDefinitionType(ParameterInfo.CONST_DEF);
                    }
                }
            }

            paramInfo.setValues(values);

            nextTree.addNode(InfoConverter.parameterInfo2ParameterInfo(paramInfo));
        }

        return nextTree;
    }

    //----------------------------------------------------------------------------------------------------
    public boolean alterParameterTree(final IIntelliContext ctx) {

        // create initial population
        final DefaultMutableTreeNode root = ctx.getParameterTreeRootNode();
        final DefaultMutableTreeNode newRoot = getAlteredParameterTreeRootNode(ctx);
        root.removeAllChildren();
        final int count = newRoot.getChildCount();

        for (int i = 0; i < count; ++i)
            root.add((DefaultMutableTreeNode) newRoot.getChildAt(0));

        return true;
    }

    //----------------------------------------------------------------------------------------------------
    protected DefaultMutableTreeNode getAlteredParameterTreeRootNode(final IIntelliContext ctx) {
        genotype = generateInitialPopulation(ctx);

        final Population descendants = genotype.getPopulation();
        final DefaultMutableTreeNode root = new DefaultMutableTreeNode("Parameter file");

        paramList = ctx.getParameters();
        for (int i = 0; i < paramList.size(); ++i) {
            final ParameterInfo paramInfo = paramList.get(i);
            paramInfo.setRuns(1); // Run is always 1

            final List<Object> values = new ArrayList<Object>();

            final int genIdx = whichGene(calculateName(paramInfo));
            for (int j = 0; j < populationSize; ++j) {
                if (genIdx >= 0) {
                    final String strValue = String
                            .valueOf(descendants.getChromosome(j).getGene(genIdx).getAllele());
                    values.add(ParameterInfo.getValue(strValue, paramInfo.getType()));
                    paramInfo.setDefinitionType(ParameterInfo.LIST_DEF);
                } else {
                    values.add(paramInfo.getValue());
                    paramInfo.setDefinitionType(ParameterInfo.CONST_DEF);
                }
            }

            paramInfo.setValues(values);

            // add and save the node
            root.add(new DefaultMutableTreeNode(paramInfo));
        }

        return root;
    }

    //----------------------------------------------------------------------------------------------------
    /**
     * Searches the selected genes list for the specified parameter, and returns
     * its index.
     * 
     * @param name
     *            the parameter's name that is searched in the selected genes list
     * @return the index of the gene that represents the given parameter, or -1
     *         if the parameter is not selected as a gene
     */
    private int whichGene(final String name) {
        for (int i = 0; i < genes.size(); i++) {
            final GeneInfo geneInfo = genes.get(i);
            if (geneInfo.getName().equals(name))
                return i;
        }

        return -1;
    }

    //----------------------------------------------------------------------------------------------------
    private List<GeneInfo> getSelectedGenes() {
        if (genes == null) {
            genes = new ArrayList<GeneInfo>();

            final DefaultMutableTreeNode root = (DefaultMutableTreeNode) chromosomeTree.getRoot();
            @SuppressWarnings("rawtypes")
            final Enumeration nodes = root.preorderEnumeration();
            nodes.nextElement();
            while (nodes.hasMoreElements()) {
                final DefaultMutableTreeNode node = (DefaultMutableTreeNode) nodes.nextElement();
                final ParameterOrGene userObj = (ParameterOrGene) node.getUserObject();
                if (userObj.isGene()) {
                    convertGeneName(userObj);
                    genes.add(userObj.getGeneInfo());
                }
            }
        }

        return genes;
    }

    //----------------------------------------------------------------------------------------------------
    private void convertGeneName(final ParameterOrGene param) {
        ParameterInfo info = param.getInfo();
        final String newName = calculateName(info);
        param.getGeneInfo().setName(newName);
    }

    //----------------------------------------------------------------------------------------------------
    private String calculateName(final ParameterInfo info) {
        ParameterInfo _info = info;

        if (_info != null) {
            String resultName = _info.getName();
            while ((_info instanceof ISubmodelGUIInfo) && ((ISubmodelGUIInfo) _info).getParent() != null) {
                _info = ((ISubmodelGUIInfo) _info).getParent();
                resultName = _info.getName() + "#" + resultName;
            }

            return resultName;
        }

        return null;
    }

    //----------------------------------------------------------------------------------------------------
    @SuppressWarnings("serial")
    protected Genotype generateInitialPopulation(final IIntelliContext context) {
        try {
            iterationCounter = 1;
            genes = null;

            Configuration.reset();
            gaConfiguration = new DefaultConfiguration();
            Configuration.reset();
            gaConfiguration.removeNaturalSelectors(true);
            gaConfiguration.removeNaturalSelectors(false);
            gaConfiguration.getGeneticOperators().clear();
            gaConfiguration.setAlwaysCaculateFitness(false);
            gaConfiguration.setPreservFittestIndividual(true);
            gaConfiguration.setKeepPopulationSizeConstant(false);
            gaConfiguration.setFitnessEvaluator(new FitnessEvaluator() {
                public boolean isFitter(IChromosome a_chrom1, IChromosome a_chrom2) {
                    return isFitter(a_chrom1.getFitnessValue(), a_chrom2.getFitnessValue());
                }

                public boolean isFitter(double a_fitness_value1, double a_fitness_value2) {
                    return optimizationDirection == FitnessFunctionDirection.MINIMIZE
                            ? a_fitness_value1 < a_fitness_value2
                            : a_fitness_value1 > a_fitness_value2;
                }
            });
            gaConfiguration.setFitnessFunction(new ResultFileFitnessFunction());
            gaConfiguration.setRandomGenerator(new RandomGenerator() {
                private static final long serialVersionUID = 1L;

                final MersenneTwister randomGenerator = new MersenneTwister(populationGenerationSeed);

                public long nextLong() {
                    return randomGenerator.nextLong();
                }

                public int nextInt(final int a_ceiling) {
                    return randomGenerator.nextInt(a_ceiling);
                }

                public int nextInt() {
                    return randomGenerator.nextInt();
                }

                public float nextFloat() {
                    return randomGenerator.nextFloat();
                }

                public double nextDouble() {
                    return randomGenerator.nextDouble();
                }

                public boolean nextBoolean() {
                    return randomGenerator.nextBoolean();
                }
            });

            final Gene[] initialGenes = new Gene[getSelectedGenes().size()];
            int i = 0;
            for (final GeneInfo geneInfo : getSelectedGenes()) {
                if (GeneInfo.INTERVAL.equals(geneInfo.getValueType())) {
                    if (geneInfo.isIntegerVals()) {
                        initialGenes[i] = new IdentifiableLongGene(geneInfo.getName(), gaConfiguration,
                                geneInfo.getMinValue().longValue(), geneInfo.getMaxValue().longValue());
                    } else {
                        initialGenes[i] = new IdentifiableDoubleGene(geneInfo.getName(), gaConfiguration,
                                geneInfo.getMinValue().doubleValue(), geneInfo.getMaxValue().doubleValue());
                    }
                } else {
                    final IdentifiableListGene listGene = new IdentifiableListGene(geneInfo.getName(),
                            gaConfiguration);
                    final List<Object> values = geneInfo.getValueRange();
                    for (final Object value : values) {
                        listGene.addAllele(value);
                    }
                    listGene.setAllele(values.get(0));
                    initialGenes[i] = listGene;
                }

                i++;
            }
            gaConfiguration.setMinimumPopSizePercent(100);
            gaConfiguration.setBreeder(new DashboardBreeder());

            final Chromosome sampleChromosome = new Chromosome(gaConfiguration, initialGenes);
            gaConfiguration.setSampleChromosome(sampleChromosome);
            gaConfiguration.setPopulationSize(populationSize);

            for (final IGAOperatorConfigurator operator : selectedGeneticOperators)
                gaConfiguration.addGeneticOperator(operator.getConfiguredOperator(gaConfiguration));

            for (IGASelectorConfigurator selectorConfig : selectedSelectionOperators)
                gaConfiguration.addNaturalSelector(selectorConfig.getSelector(gaConfiguration), true);

            gaConfiguration.addNaturalSelector(new StandardPostSelectorFixed(gaConfiguration), false);

            final Genotype initialGenotype = Genotype.randomInitialGenotype(gaConfiguration);

            return initialGenotype;
        } catch (final InvalidConfigurationException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    //----------------------------------------------------------------------------------------------------
    /**
     * Prints the header of the population file.
     */
    protected void initPopFile() {
        // create backup file when file already exists
        final File file = new File(workspace, populationFileName + ext);
        if (file.exists()) {
            for (int i = 1; i <= 1000; ++i) {
                final File newFile = new File(workspace, populationFileName + bckExt + i + ext);
                if (!newFile.exists() || i == 1000) {
                    file.renameTo(newFile);
                    break;
                }
            }
        }

        try {
            final PrintWriter popWriter = new PrintWriter(new FileWriter(file, true));

            popWriter.print("#pop");
            for (int i = 0; i < genes.size(); ++i)
                popWriter.print(";" + genes.get(i).getName());

            popWriter.print(";fitness");
            popWriter.println();
            popWriter.close();
        } catch (final IOException e) {
            log.error("Cannot print population to file:\n", e);
        }
    }

    //----------------------------------------------------------------------------------------------------
    protected void printPopulation(final int iteration) {
        try {
            final PrintWriter popWriter = new PrintWriter(
                    new FileWriter(new File(workspace, populationFileName + ext), true));

            Population population = genotype.getPopulation();
            for (int i = 0; i < population.size(); ++i) {
                popWriter.print(iteration);
                for (int j = 0; j < population.getChromosome(i).size(); ++j)
                    popWriter.print(";" + population.getChromosome(i).getGene(j).getAllele().toString());

                popWriter.print(";" + population.getChromosome(i).getFitnessValue());
                popWriter.println();
            }
            popWriter.close();
        } catch (final IOException e) {
            log.error("Cannot print population to file.", e);
        }
    }

    //----------------------------------------------------------------------------------------------------
    private int calculateNumberOfGenes() {
        int count = 0;

        final DefaultMutableTreeNode root = (DefaultMutableTreeNode) chromosomeTree.getRoot();
        @SuppressWarnings("rawtypes")
        final Enumeration nodes = root.breadthFirstEnumeration();
        nodes.nextElement();

        while (nodes.hasMoreElements()) {
            final DefaultMutableTreeNode node = (DefaultMutableTreeNode) nodes.nextElement();
            final ParameterOrGene userObj = (ParameterOrGene) node.getUserObject();
            if (userObj.isGene())
                count++;
        }

        return count;
    }

    //====================================================================================================
    // not implemented methods

    //----------------------------------------------------------------------------------------------------
    public void setRecordableVariables(final DefaultMutableTreeNode root) {
        throw new UnsupportedOperationException(); // intentionally not implemented
    }

    //----------------------------------------------------------------------------------------------------
    public String settingsOK(final DefaultMutableTreeNode recorders) {
        throw new UnsupportedOperationException(); // intentionally not implemented
    }

    //----------------------------------------------------------------------------------------------------
    public void setParameterTreeRoot(final DefaultMutableTreeNode root) {
        throw new UnsupportedOperationException(); // intentionally not implemented
    }

    //----------------------------------------------------------------------------------------------------
    public boolean getReadyStatus() {
        throw new UnsupportedOperationException(); // intentionally not implemented
    }

    //----------------------------------------------------------------------------------------------------
    public String getReadyStatusDetail() {
        throw new UnsupportedOperationException(); // intentionally not implemented
    }

    //----------------------------------------------------------------------------------------------------
    public JPanel getSettingsPanel(final IIntelliContext ctx) {
        throw new UnsupportedOperationException(); // intentionally not implemented
    }

    //----------------------------------------------------------------------------------------------------
    public void save(final Node node) {
        throw new UnsupportedOperationException(); // intentionally not implemented
    }

    //----------------------------------------------------------------------------------------------------
    public void load(final IIntelliContext context, final Element element) throws WizardLoadingException {
        throw new UnsupportedOperationException(); // intentionally not implemented
    }

    //----------------------------------------------------------------------------------------------------
    public void invalidatePlugin() {
        throw new UnsupportedOperationException(); // intentionally not implemented
    }

    //----------------------------------------------------------------------------------------------------
    public String getDescription() {
        throw new UnsupportedOperationException(); // intentionally not implemented
    }

    //----------------------------------------------------------------------------------------------------
    public int getMethodType() {
        throw new UnsupportedOperationException(); // intentionally not implemented
    }

    //----------------------------------------------------------------------------------------------------
    public boolean isImplemented() {
        throw new UnsupportedOperationException(); // intentionally not implemented
    }

    //----------------------------------------------------------------------------------------------------
    public String getLocalizedName() {
        throw new UnsupportedOperationException(); // intentionally not implemented
    }

    @Override
    public RecordableInfo getSelectedFitnessStatisticsInfo() {
        final RecordableInfo selectedFitnessFunction = getSelectedFitnessFunction();
        IStatisticsPlugin selectedFitnessStatistics = getSelectedFitnessStatistics();
        int fitnessTimeSeriesLength = getFitnessTimeSeriesLength();
        // this seems to be useless, as the GASearchPanelModel can directly return the selected fitness function
        //      final List<RecordableInfo> recordables = recorder.getRecordables();
        //      for (final RecordableInfo recordableInfo : recordables) {
        //         if (recordableInfo.equals(selectedFitnessFunction))
        //            return recordableInfo;
        //      }

        if (selectedFitnessStatistics.equals(GASearchHandler.noStatistics)) {
            return selectedFitnessFunction;
        }

        // create a time series of the specified length using the selected fitness function
        Operator_TimeSeries timeSeriesOperator = new Operator_TimeSeries();
        OperatorsInfoGenerator timeSeriesInfoGenerator = new OperatorsInfoGenerator(timeSeriesOperator);

        List<Object> parameters = new ArrayList<Object>();

        MemberInfo fitnessMemberInfo = new MemberInfo(selectedFitnessFunction.getAccessibleName(),
                selectedFitnessFunction.getType().getSimpleName(), selectedFitnessFunction.getType());

        parameters.add(fitnessMemberInfo);
        parameters.add(fitnessTimeSeriesLength);

        OperatorGeneratedMemberInfo timeSeriesMemberInfo = timeSeriesInfoGenerator.generateInfoObject("timeseries",
                parameters.toArray());
        List<String> errors = timeSeriesInfoGenerator.getError();
        if (errors != null && errors.size() > 0) {
            throw new IllegalStateException("Could not create the timeseries of the last '"
                    + selectedFitnessFunction.getName() + "' values!\n" + Utils.join(errors, "\n"));
        }
        timeSeriesMemberInfo.setGeneratorName(timeSeriesOperator.getClass().getName());
        timeSeriesMemberInfo.setBuildingBlock(parameters);

        // apply the selected statistics on the timeseries
        IStatisticInfoGenerator statisticsInfoGenerator = new StatisticsInfoGenerator(selectedFitnessStatistics);
        parameters = new ArrayList<Object>(selectedFitnessStatistics.getNumberOfParameters());
        List<Object> collectionParameter = new ArrayList<Object>();
        collectionParameter.add(timeSeriesMemberInfo);
        parameters.add(collectionParameter);
        SimpleGeneratedMemberInfo statMemberInfo = statisticsInfoGenerator
                .generateInfoObject(selectedFitnessStatistics.getName() + "_last" + fitnessTimeSeriesLength + "_"
                        + selectedFitnessFunction.getName(), parameters.toArray());
        errors = statisticsInfoGenerator.getError();
        if (errors != null && errors.size() > 0) {
            throw new IllegalStateException(
                    "Could not create the specified statistics (" + selectedFitnessStatistics.getName() + ") of '"
                            + selectedFitnessFunction.getName() + "'!\n" + Utils.join(errors, "\n"));
        }
        statMemberInfo.clearBuildingBlocks();
        statMemberInfo.setGeneratorName(selectedFitnessStatistics.getClass().getName());

        List<MemberInfo> l = new ArrayList<MemberInfo>(1);
        l.add(timeSeriesMemberInfo);
        statMemberInfo.addBuildingBlock(l);

        String alias = statMemberInfo.getName().endsWith("()")
                ? statMemberInfo.getName().substring(0, statMemberInfo.getName().length() - 2)
                : statMemberInfo.getName();
        RecordableElement stdRecordableElement = new RecordableElement(statMemberInfo, alias);

        return InfoConverter.convertRecordableElement2RecordableInfo(stdRecordableElement);
    }

    //====================================================================================================
    // nested classes

    //----------------------------------------------------------------------------------------------------
    @SuppressWarnings("serial")
    private class ResultFileFitnessFunction extends FitnessFunction {

        //====================================================================================================
        // members

        private IParameterSweepResultReader currentReader;

        //====================================================================================================
        // methods

        //----------------------------------------------------------------------------------------------------
        public void setCurrentReader(final IParameterSweepResultReader currentReader) {
            this.currentReader = currentReader;
        }

        //----------------------------------------------------------------------------------------------------
        protected double evaluate(final IChromosome a_subject) {
            if (currentReader == null)
                throw new IllegalStateException("Fitness function evaluation cannot access the results.");

            final List<ai.aitia.meme.paramsweep.batch.param.ParameterInfo<?>> combination = createCombinationFromChromosome(
                    a_subject);
            try {
                final List<ResultValueInfo> infos = currentReader
                        .getResultValueInfos(getSelectedFitnessStatisticsInfo(), combination);
                if (infos == null || infos.size() == 0) {
                    return 1e19; // dirty hack to make Ross going; 
                }

                if (Double.isInfinite(getFitnessValue(infos).doubleValue())) {
                    return Double.MAX_VALUE;
                }
                if (Double.isNaN(getFitnessValue(infos).doubleValue())) {
                    return 1e19;
                }
                return getFitnessValue(infos).doubleValue();
            } catch (final ReadingException e) {
                throw new RuntimeException(e);
            }
        }

        //----------------------------------------------------------------------------------------------------
        private List<ai.aitia.meme.paramsweep.batch.param.ParameterInfo<?>> createCombinationFromChromosome(
                final IChromosome a_subject) {
            final List<ai.aitia.meme.paramsweep.batch.param.ParameterInfo<?>> combination = new ArrayList<ai.aitia.meme.paramsweep.batch.param.ParameterInfo<?>>(
                    a_subject.getGenes().length);

            for (int i = 0; i < a_subject.getGenes().length; ++i) {
                final IIdentifiableGene geneWithId = (IIdentifiableGene) a_subject.getGene(i);
                final GeneInfo geneInfo = genes.get(whichGene(geneWithId.getId()));
                final ParameterInfo info = new ParameterInfo(geneInfo.getName(), geneInfo.getType(),
                        geneInfo.getJavaType());

                final String strValue = String.valueOf(geneWithId.getAllele());
                info.setValue(ParameterInfo.getValue(strValue, info.getType()));

                combination.add((ai.aitia.meme.paramsweep.batch.param.ParameterInfo<?>) InfoConverter
                        .parameterInfo2ParameterInfo(info));
            }

            return combination;
        }

        //----------------------------------------------------------------------------------------------------
        private Number getFitnessValue(final List<ResultValueInfo> candidates) {
            if (candidates == null || candidates.isEmpty())
                return new Double(FitnessFunction.NO_FITNESS_VALUE);
            //            return new Double(optimizationDirection == FitnessFunctionDirection.MAXIMIZE ? 0. :  Double.MAX_VALUE);

            Collections.sort(candidates, new Comparator<ResultValueInfo>() {
                public int compare(final ResultValueInfo info1, final ResultValueInfo info2) {
                    final double tick1 = (Double) info1.getLabel();
                    final double tick2 = (Double) info2.getLabel();

                    return Double.compare(tick1, tick2);
                }
            });

            final Object value = candidates.get(candidates.size() - 1).getValue();
            return (Number) value;
        }
    }
}