2

I am working on an optimization engine based on the Jenetics framework (link to jenetics.io). I have a evolution engine definition as follows:

final Thread engineStream = new Thread(() -> {
final MinMax<EvolutionResult<DoubleGene, Double>> best = MinMax.of();

_scannerEngine.stream()
    .limit(byPopulationConvergence(convergenceCriterion))
    .limit(result -> !Thread.currentThread().isInterrupted())                              
    .limit(maxGenerations)
    .peek(best).forEach(evolutionResult -> {
        waiting();
        if (callback != null) {
            callback.accept(evolutionResult, best.getMax());
        }
        final String generationCounter = String.valueOf(evolutionResult.getGeneration());
       _callingInstance.doOnAlgorithmCallback(new String("****** finished generation: " + generationCounter + " ****"));
    });
}

engineStream.start();

Currently, I am pushing at the end of one evolution cycle (one iteration through the population) a message to my UI via

peek(best).forEach(
    ...
    _callingInstance.doOnAlgorithmCallback(...)
)

What I would like to do is to push the current state of the evolution (ideally some statistics containing current fitness average, min, max, etc.) after having executed each fitness step, so the user can see the current state of the optimization process.

Any idea?


Final implementation based on Franz Wilhelmstötter's suggestions:

final Thread engineStream = new Thread(() -> {
    final MinMax<EvolutionResult<DoubleGene, Double>> best = MinMax.of();

    try {
        _scannerEngine.stream() //
        // stop stream if fitness average across the population is smaller than % of best fitness
        .limit(byFitnessConvergence(5, 20, convergence%)) //
        .limit(interrupted -> !Thread.currentThread().isInterrupted()) //
        .limit(_geneticScanParameters.getMaxGenerationsLimit()) // maximum number of generations
        .peek(best) //
        .peek(_statistics) //
        .forEach(evolutionResult -> {
            waiting();
            if (callback != null) {
                MessageLogger.logError(getClass(), best.getMax().toString());
                if (_geneticScanParameters.getOptimizationStrategy() == Optimize.MAXIMUM) {
                    callback.accept(evolutionResult, best.getMax());
                } else if (_geneticScanParameters.getOptimizationStrategy() == Optimize.MINIMUM) {
                    callback.accept(evolutionResult, best.getMin());
                }
            }
            MessageLogger.log(getClass(), _statistics.toString());
            final String generationCounter = String.valueOf(evolutionResult.getGeneration());
            _callingInstance.doOnAlgorithmCallback(new String("****** finished generation: " + generationCounter + " ****"));
        });

        MessageLogger.log(getClass(), "\n" + _statistics.toString());
    } catch (final Exception ex) {
    MessageLogger.logError(getClass(), Thread.currentThread(), ex);
    }
    _callingInstance.doOnAlgorithmFinished();
});
engineStream.start();
_engineStream = engineStream;

Please note that I use a convention where "_variable" are class attributes.

beatngu13
  • 7,201
  • 6
  • 37
  • 66
WolfiG
  • 1,059
  • 14
  • 31

1 Answers1

3

You can use the EvolutionStatistics class for this purpose.

final Engine<DoubleGene, Double> engine = ...
final EvolutionStatistics<Double, DoubleMomentStatistics> statistics =
    EvolutionStatistics.ofNumber();

final Phenotype<DoubleGene, Double> result = engine.stream()
    .limit(bySteadyFitness(7))
    .limit(100)
    .peek(statistics)
    .collect(toBestPhenotype());

System.println(statistics);

If you update the class in the peek method you will get some additional statistics.

  • Hi Franz, thanks for the help, but this is not what I intended. The code snipped you provided gives the evolution statistics at the _end_ of the optimization. I want to monitor the process at _each step_, ideally at each single setting of values of an individual. Maybe I should mention that I run the engine single threaded, between each call of the ftness function there are a couple of seconds. – WolfiG Mar 23 '18 at 05:44
  • 1
    Sorry, I mean you can do the same with the `EvolutionStatistics` as with the `MinMax` object: Update it in the `peek` method and call the `doOnAlgorithmCallback` method in the `Stream.forEach`. – Franz Wilhelmstötter Mar 23 '18 at 07:53