How I get real time statistics in MOEA Framework?

224 views Asked by At

I know there is the Instrumenter class, however this method outputs the data after the run finish. I would like to get (near) real-time data, like in the Symbolic Regression in the Demos. Looking at its code, it seems I need to use the step method and try to imitate the runSingleSeed in Executor. Is there a better way? Some other class like Instrumenter but asynchronous. I cannot really find something similar online.

2

There are 2 answers

0
Black Arrow On BEST ANSWER

Just build a wrapper around the cycle (similar to the next one) and make it also a subject in an observer pattern.

observer pattern diagram

import java.util.Properties;
import java.util.Arrays;
import java.text.DecimalFormat;
import org.moeaframework.core.Algorithm;
import org.moeaframework.core.Solution;
import org.moeaframework.core.Problem;
import org.moeaframework.core.Population;
import org.moeaframework.core.NondominatedPopulation;
import org.moeaframework.core.variable.EncodingUtils;
import org.moeaframework.core.spi.AlgorithmFactory;

import org.moeaframework.problem.misc.Kursawe;

public class Main{
    public static void main(String[] args){
    String algorithmName = "NSGAII";

    Properties properties = new Properties();
    properties.setProperty("populationSize", "100"); // to change properties

        Problem problem = new Kursawe();

    Algorithm algorithm = AlgorithmFactory.getInstance()
        .getAlgorithm(algorithmName, properties, problem);

    int maxGenerations = 100;
    int generation = 0;
    while( generation < maxGenerations ){
        if( generation % 10 == 1 ){
        System.out.println("Generation " + generation);
        NondominatedPopulation paretoFront = algorithm.getResult();
        // metrics 
        System.out.print("One of the pareto front: ");
        System.out.println(toString(paretoFront.get(0)));       
        }
        algorithm.step();       
        generation++;
    }
    algorithm.terminate();

    System.out.println("Parento Front:");
    for(Solution solution: algorithm.getResult()){
        System.out.println(toString(solution));
    }
    export(algorithm.getResult());
    }
    private static String toString(Solution solution){
    StringBuilder out = new StringBuilder();
    double[] variables = EncodingUtils.getReal(solution);
    double[] objectives = solution.getObjectives();

    out.append("f");
    out.append(doubleArrayToString(variables));
    out.append(" = ");
    out.append(doubleArrayToString(objectives));

    return out.toString();
    }

    private static String doubleArrayToString(double[] array){
    DecimalFormat format = new DecimalFormat("+#,##0.00;-#");
    StringBuilder out = new StringBuilder();     

    out.append("[");
    for(int i = 0; i < array.length-1; i++){
        out.append(format.format(array[i]));
        out.append(", ");
    }
    out.append(format.format(array[array.length-1]));
    out.append("]");

    return out.toString();
    }

    private static void export(Population population){
    System.out.println();
    for(Solution solution: population){
        double[] objectives = solution.getObjectives();
        System.out.println(String.format("%.3f,%.3f", objectives[0], objectives[1]));
    }
    }
}

pareto front

0
Klaifer Garcia On

Another option for the one indicated by Black Arrow, if you are using multithread, is to extentend AlgorithmFactory. For example:

public class MyAlgorithmFactory extends AlgorithmFactory {  
     private static Algorithm algorithm;

     public Algorithm getGeneratedAlgorithm() {
         return this.algorithm;
     }

     @Override
     public Algorithm getAlgorithm(String name, Properties properties, Problem problem){
         this.algorithm = super.getAlgorithm(name, properties, problem);
         return algorithm;
     }
 }

Then you use this Factory on your Executor, for example:

    MyAlgorithmFactory af = new MyAlgorithmFactory();

    Executor executor = new Executor()
            .usingAlgorithmFactory(af)
            .withAlgorithm("NSGAII") //
            .withProblem(yourProblemHere) //
            .withMaxEvaluations(10000);

After this you can start the Executor on a separated thread, and call af.getGeneratedAlgorithm() to get the instance of Algorithm initialized by the Executor. From this Algorithm you can get, while the Executor is still running, the actual NondominatedPopulation to calc statistics.