From e36ff3c8510e7cc947075ce1b53677a006b8fc72 Mon Sep 17 00:00:00 2001 From: "Bernhard J. Berger" <bernhard.berger@uni-bremen.de> Date: Thu, 11 May 2023 12:55:35 +0200 Subject: [PATCH] Example is working now. --- .../alterer/mutator/SingleBitFlipMutator.java | 2 +- .../codec/chromosome/DynamicChromosome.java | 20 ++++----- .../chromosome/DynamicScaledChromosome.java | 8 +++- .../ea/main/producer/SelectorFactory.java | 34 +++++++++++---- .../search/EvolutionaryAlgorithmSearch.java | 12 ++++-- .../api/languages/ExpressionEvaluator.java | 26 ++++++++++++ .../constraint/RandomGenotypeStrategy.java | 2 +- .../core/main/initial/RandomProducer.java | 2 +- .../OptimisationFunctionProducer.java | 2 +- .../main/producer/SpecificationProducer.java | 18 ++++---- .../main/statistics/StatisticsFactory.java | 41 ++++++++++++++----- .../GenerationStatisticsWriter.java | 2 +- 12 files changed, 123 insertions(+), 46 deletions(-) diff --git a/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/alterer/mutator/SingleBitFlipMutator.java b/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/alterer/mutator/SingleBitFlipMutator.java index 44bfaa47..082dc8d8 100644 --- a/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/alterer/mutator/SingleBitFlipMutator.java +++ b/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/alterer/mutator/SingleBitFlipMutator.java @@ -41,7 +41,7 @@ public class SingleBitFlipMutator< ) { final MSeq<BitGene> genes = MSeq.of(chromosome); - final int index = random.nextInt(); + final int index = random.nextInt(0, genes.size()); final BitGene gene = genes.get(index); genes.set(index, BitGene.of(!gene.bit())); diff --git a/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/codec/chromosome/DynamicChromosome.java b/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/codec/chromosome/DynamicChromosome.java index 9233373c..0e7879fb 100644 --- a/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/codec/chromosome/DynamicChromosome.java +++ b/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/codec/chromosome/DynamicChromosome.java @@ -1,5 +1,6 @@ package de.evoal.core.ea.main.codec.chromosome; +import de.evoal.core.api.languages.ExpressionEvaluator; import de.evoal.core.api.properties.Properties; import de.evoal.core.api.properties.PropertiesSpecification; import de.evoal.core.api.properties.PropertySpecification; @@ -11,25 +12,24 @@ import de.evoal.languages.model.base.Instance; import io.jenetics.Chromosome; import org.apache.commons.math3.util.Pair; +import javax.inject.Inject; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; public abstract class DynamicChromosome { + @Inject + private ExpressionEvaluator evaluator; + protected List<DataDescription> dataRepresented; protected PropertiesSpecification specification; public void init(final Instance specification) { - final Array genes = (Array)specification.findAttribute("genes") - .getValue(); - - this.dataRepresented = genes.getValues() - .stream() - .map(Instance.class::cast) - .map(i -> i.findAttribute("content")) - .map(Attribute::getValue) - .map(DataReference.class::cast) - .map(DataReference::getDefinition) + final List<Instance> genes = (List<Instance>) evaluator.attributeToObject(specification, "genes"); + + this.dataRepresented = genes.stream() + .map(i -> evaluator.attributeToObject(i, "content")) + .map(DataDescription.class::cast) .collect(Collectors.toList()); this.dataRepresented = Collections.unmodifiableList(dataRepresented); diff --git a/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/codec/chromosome/DynamicScaledChromosome.java b/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/codec/chromosome/DynamicScaledChromosome.java index fbf96650..5fd41174 100644 --- a/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/codec/chromosome/DynamicScaledChromosome.java +++ b/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/codec/chromosome/DynamicScaledChromosome.java @@ -1,5 +1,6 @@ package de.evoal.core.ea.main.codec.chromosome; +import de.evoal.core.api.languages.ExpressionEvaluator; import de.evoal.core.api.utils.Requirements; import de.evoal.languages.model.ddl.DataDescription; import de.evoal.languages.model.base.IntegerLiteral; @@ -7,7 +8,12 @@ import de.evoal.languages.model.base.Instance; import de.evoal.languages.model.base.Literal; import io.jenetics.util.DoubleRange; +import javax.inject.Inject; + public abstract class DynamicScaledChromosome extends DynamicBoundedDoubleChromosome { + @Inject + private ExpressionEvaluator evaluator; + protected int scale; @Override @@ -16,7 +22,7 @@ public abstract class DynamicScaledChromosome extends DynamicBoundedDoubleChromo Requirements.requireSize(dataRepresented, 1); Requirements.requireSize(ranges, 1); - scale = ((IntegerLiteral)specification.findAttribute("scale")).getValue(); + scale = evaluator.attributeToInteger(specification, "scale"); } protected DoubleRange toRange(final DataDescription dataDescription) { diff --git a/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/producer/SelectorFactory.java b/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/producer/SelectorFactory.java index 4f91bebd..69d9fe1d 100644 --- a/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/producer/SelectorFactory.java +++ b/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/producer/SelectorFactory.java @@ -5,6 +5,7 @@ import de.evoal.core.api.cdi.ConfigurationValue; import de.evoal.core.api.utils.LanguageHelper; import de.evoal.languages.model.base.Instance; import io.jenetics.*; +import lombok.extern.slf4j.Slf4j; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.inject.Produces; @@ -12,10 +13,11 @@ import javax.inject.Inject; import javax.inject.Named; @ApplicationScoped +@Slf4j public class SelectorFactory { @Inject private LanguageHelper helper; - + @Inject @ConfigurationValue(entry = CoreBlackboardEntries.OPTIMISATION_CONFIGURATION, access = "algorithm.size-of-population") private int sizeOfPopulation; @@ -39,19 +41,35 @@ public class SelectorFactory { switch(name) { case "elite-selector": return createEliteSelector(config); case "monte-carlo-selector": return createMonteCarloSelector(config); - case "exponential-rank-selector": return createExponentialRankSelector(config); - case "linear-rank-selector": return createLinearRankSelector(config); - case "boltzmann-selector": return createBoltzmannSelector(config); case "stochastic-universal-selector": return createStochasticUniversalSelector(config); case "tournament-selector": return createTournamentSelector(config); case "truncation-selector": return createTruncationSelector(config); - + + /* probability-based selectors */ + case "boltzmann-selector": return createBoltzmannSelector(config); + case "exponential-rank-selector": return createExponentialRankSelector(config); + case "linear-rank-selector": return createLinearRankSelector(config); + case "roulette-wheel-selector": return createRouletteWheelSelector(config); } + log.error("Configured selector with name '{}' is not supported. Available selectors are:\n" + + " elite-selector,\n" + + " monte-carlo-selector,\n" + + " stochastic-universal-selector,\n" + + " tournament-selector,\n" + + " truncation-selector,\n" + + " boltzmann-selector,\n" + + " exponential-rank-selector,\n" + + " linear-rank-selector,\n" + + " roulette-wheel-selector", name); throw new IllegalStateException("Selector '" + name + "' is unknown."); } - + + private <G extends Gene<?, G>, C extends Comparable<? super C>> Selector<G,C> createRouletteWheelSelector(final Instance config) { + return (Selector<G,C>) new RouletteWheelSelector<>(); + } + private <G extends Gene<?,G>, C extends Comparable<? super C>> Selector<G, C> createBoltzmannSelector(final Instance config) { - double beta = helper.lookup(config, "beta"); + final Double beta = helper.lookup(config, "beta"); return (Selector<G,C>) new BoltzmannSelector<>(beta); } @@ -91,7 +109,7 @@ public class SelectorFactory { private <G extends Gene<?,G>, C extends Comparable<? super C>> EliteSelector<G,C> createEliteSelector(final Instance config) { int count = (int)(helper.<Double>lookup(config, "size-factor") * sizeOfPopulation); final Instance nonEliteSelectorConfig = helper.lookup(config, "non-elite-selector"); - + if(nonEliteSelectorConfig == null) { return new EliteSelector<>(count); } diff --git a/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/search/EvolutionaryAlgorithmSearch.java b/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/search/EvolutionaryAlgorithmSearch.java index 4b8cdc16..e17224c1 100644 --- a/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/search/EvolutionaryAlgorithmSearch.java +++ b/src/core/de.evoal.core.ea/src/main/java/de/evoal/core/ea/main/search/EvolutionaryAlgorithmSearch.java @@ -11,6 +11,7 @@ import de.evoal.core.api.board.Blackboard; import de.evoal.core.api.cdi.BeanFactory; import de.evoal.core.api.cdi.BlackboardValue; import de.evoal.core.api.cdi.ConfigurationValue; +import de.evoal.core.api.languages.ExpressionEvaluator; import de.evoal.core.api.optimisation.InitialCandidatesProvider; import de.evoal.core.api.optimisation.OptimisationAlgorithm; import de.evoal.core.api.utils.LanguageHelper; @@ -45,6 +46,9 @@ public class EvolutionaryAlgorithmSearch implements OptimisationAlgorithm { @Inject private Blackboard board; + @Inject + private ExpressionEvaluator evaluator; + @Inject private LanguageHelper helper; @@ -71,7 +75,7 @@ public class EvolutionaryAlgorithmSearch implements OptimisationAlgorithm { private int sizeOfPopulation; @Inject - @ConfigurationValue(entry = CoreBlackboardEntries.OPTIMISATION_CONFIGURATION, access = "algorithm.maximise") + @ConfigurationValue(entry = CoreBlackboardEntries.OPTIMISATION_CONFIGURATION, access = "problem.maximise") private Boolean maximize; @Inject @@ -155,12 +159,12 @@ public class EvolutionaryAlgorithmSearch implements OptimisationAlgorithm { final String name = category.getDefinition().getName(); log.info("Processing alterer category '{}'.", name); - final Array array = (Array) category.getValue(); + final List<de.evoal.languages.model.base.Instance> listOfAltererConfigurations = (List<de.evoal.languages.model.base.Instance>)evaluator.evaluate(category.getValue()); - for(final Value alterer : array.getValues()) { + for(final de.evoal.languages.model.base.Instance alterer : listOfAltererConfigurations) { this.alterers .computeIfAbsent(name, k -> new ArrayList<>()) - .add(factory.create((de.evoal.languages.model.base.Instance)alterer)); + .add(factory.create(alterer)); } } } diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/api/languages/ExpressionEvaluator.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/api/languages/ExpressionEvaluator.java index 11cb6987..8d32e363 100644 --- a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/api/languages/ExpressionEvaluator.java +++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/api/languages/ExpressionEvaluator.java @@ -63,4 +63,30 @@ public class ExpressionEvaluator { public Object evaluate(final Object current) { return evaluator.doSwitch((EObject) current); } + + public int attributeToInteger(final Instance instance, final String attributeName) { + final Attribute attribute = instance.findAttribute(attributeName); + + Object result = null; + + if(attribute == null) { + log.info("Attribute binding not found. Using default value."); + final AttributeDefinition definition = instance.getDefinition().findAttribute(attributeName); + + if(defaultValueCache.containsKey(definition)) { + result = defaultValueCache.get(definition); + } else { + result = evaluator.doSwitch(definition.getInitialisation()); + } + } else { + result = evaluator.doSwitch(attribute.getValue()); + } + + if(!(result instanceof Number)) { + log.error("Expression did not evaluate to a number value for attribute {} which was expected.", attributeName); + throw new IllegalStateException("Expression evaluation error. Please check your configuration."); + } + + return ((Number)result).intValue(); + } } diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/constraints/constraint/strategies/constraint/RandomGenotypeStrategy.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/constraints/constraint/strategies/constraint/RandomGenotypeStrategy.java index 47d01377..f7aaf38e 100644 --- a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/constraints/constraint/strategies/constraint/RandomGenotypeStrategy.java +++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/constraints/constraint/strategies/constraint/RandomGenotypeStrategy.java @@ -14,7 +14,7 @@ import javax.inject.Named; @Named("repair-with-random") public class RandomGenotypeStrategy implements RepairStrategy { - @Inject @Named("random") + @Inject @Named("random-population") private InitialCandidatesProvider generator; @Override diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/initial/RandomProducer.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/initial/RandomProducer.java index dd304d40..7e04c969 100644 --- a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/initial/RandomProducer.java +++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/initial/RandomProducer.java @@ -19,7 +19,7 @@ public class RandomProducer { @Produces @Dependent - @Named("random") + @Named("random-population") public InitialCandidatesProvider create(@ConfigurationValue(entry = CoreBlackboardEntries.OPTIMISATION_CONFIGURATION, access = "algorithm.initialisation") Instance initialization) { final InitialCandidatesProvider population = new RandomInitialCandidates(); BeanFactory.injectFields(population); diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/producer/OptimisationFunctionProducer.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/producer/OptimisationFunctionProducer.java index dbc052e0..05420942 100644 --- a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/producer/OptimisationFunctionProducer.java +++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/producer/OptimisationFunctionProducer.java @@ -24,7 +24,7 @@ public class OptimisationFunctionProducer { @Produces @Dependent @Named("optimisation-function") - public OptimisationFunction createOptimisationFunction(final @ConfigurationValue(entry = CoreBlackboardEntries.OPTIMISATION_CONFIGURATION, access = "algorithm.optimisation-function.function") Instance configuration) { + public OptimisationFunction createOptimisationFunction(final @ConfigurationValue(entry = CoreBlackboardEntries.OPTIMISATION_CONFIGURATION, access = "algorithm.optimisation-function") Instance configuration) { return BeanFactory.create(configuration.getDefinition().getName(), OptimisationFunction.class) .init(configuration); } diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/producer/SpecificationProducer.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/producer/SpecificationProducer.java index f41e3afc..cb745869 100644 --- a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/producer/SpecificationProducer.java +++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/producer/SpecificationProducer.java @@ -2,6 +2,7 @@ package de.evoal.core.main.producer; import de.evoal.core.api.board.CoreBlackboardEntries; import de.evoal.core.api.cdi.ConfigurationValue; +import de.evoal.core.api.languages.ExpressionEvaluator; import de.evoal.core.api.properties.PropertiesSpecification; import de.evoal.languages.model.ddl.DataDescription; import de.evoal.languages.model.base.Array; @@ -12,6 +13,7 @@ import de.evoal.languages.model.base.Instance; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.Dependent; import javax.enterprise.inject.Produces; +import javax.inject.Inject; import javax.inject.Named; import java.util.Arrays; import java.util.List; @@ -19,6 +21,10 @@ import java.util.stream.Collectors; @ApplicationScoped public class SpecificationProducer { + + @Inject + private ExpressionEvaluator evaluator; + @Produces @Dependent @Named("genotype-description") @@ -27,14 +33,10 @@ public class SpecificationProducer { .map(Instance.class::cast) .map(i -> i.findAttribute("genes")) .map(Attribute::getValue) - .map(Array.class::cast) - .map(Array::getValues) - .flatMap(List::stream) - .map(Instance.class::cast) - .map(i -> i.findAttribute("content")) - .map(Attribute::getValue) - .map(DataReference.class::cast) - .map(DataReference::getDefinition) + .map(evaluator::evaluate) + .flatMap(l -> ((List<Instance>)(List)l).stream()) + .map(i -> evaluator.attributeToObject(i, "content")) + .map(DataDescription.class::cast) .collect(Collectors.toList()); return descriptors; diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/StatisticsFactory.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/StatisticsFactory.java index d57a0e31..ced05c76 100644 --- a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/StatisticsFactory.java +++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/StatisticsFactory.java @@ -3,7 +3,9 @@ package de.evoal.core.main.statistics; import de.evoal.core.api.board.CoreBlackboardEntries; import de.evoal.core.api.cdi.BeanFactory; import de.evoal.core.api.cdi.ConfigurationValue; +import de.evoal.core.api.languages.ExpressionEvaluator; import de.evoal.core.api.statistics.writer.StatisticsWriter; +import de.evoal.core.api.utils.LanguageHelper; import de.evoal.core.api.utils.Requirements; import de.evoal.core.main.statistics.internal.MultipleStatisticsWriter; import de.evoal.languages.model.base.Array; @@ -13,26 +15,45 @@ import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.Dependent; import javax.enterprise.inject.Produces; +import de.evoal.languages.model.base.Value; +import de.evoal.languages.model.interpreter.ConstantExpressionEvaluator; import org.apache.commons.math3.util.Pair; import org.apache.deltaspike.core.api.provider.BeanProvider; +import javax.inject.Inject; import javax.inject.Named; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; @ApplicationScoped public class StatisticsFactory { + @Inject + private ExpressionEvaluator evaluator; + @Produces @Dependent @Named("statistics") - public StatisticsWriter create(final @ConfigurationValue(entry = CoreBlackboardEntries.OPTIMISATION_CONFIGURATION, access = "statistics") Instance instance) { - Requirements.requireSize(instance.getAttributes(), 1); - final Array array = (Array)instance.getAttributes().get(0).getValue(); - - final StatisticsWriter [] writers = array.getValues() - .stream() - .map(Instance.class::cast) - .map(i -> new Pair<>(BeanFactory.create(i.getDefinition().getName(), StatisticsWriter.class), i)) - .map(p -> p.getFirst().init(p.getSecond())) - .toArray(i -> new StatisticsWriter[i]); + public StatisticsWriter create( + final @ConfigurationValue(entry = CoreBlackboardEntries.OPTIMISATION_CONFIGURATION, access = "problem.documentation") Array problemWriter, + final @ConfigurationValue(entry = CoreBlackboardEntries.OPTIMISATION_CONFIGURATION, access = "algorithm.documentation") Array algorithmWriter) { + + Stream<Value> problemStream = Stream.empty(); + Stream<Value> algorithmStream = Stream.empty(); + + if(problemWriter != null) { + problemStream = problemWriter.getValues().stream(); + } + + if(algorithmWriter != null) { + algorithmStream = algorithmWriter.getValues().stream(); + } + + final StatisticsWriter [] writers = Stream.concat(problemStream, algorithmStream) + .map(evaluator::evaluate) + .map(Instance.class::cast) + .map(i -> new Pair<>(BeanFactory.create(i.getDefinition().getName(), StatisticsWriter.class), i)) + .map(p -> p.getFirst().init(p.getSecond())) + .toArray(i -> new StatisticsWriter[i]); return new MultipleStatisticsWriter(writers); } diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/statistics/correlated/GenerationStatisticsWriter.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/statistics/correlated/GenerationStatisticsWriter.java index f9981c69..3f265a06 100644 --- a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/statistics/correlated/GenerationStatisticsWriter.java +++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/statistics/correlated/GenerationStatisticsWriter.java @@ -61,7 +61,7 @@ public class GenerationStatisticsWriter implements StatisticsWriter { @Inject private Provider<Function<Properties, Properties>> fitnessFactory; - @Inject @ConfigurationValue(entry = CoreBlackboardEntries.OPTIMISATION_CONFIGURATION, access = "algorithm.optimisation-function.function") + @Inject @ConfigurationValue(entry = CoreBlackboardEntries.OPTIMISATION_CONFIGURATION, access = "algorithm.optimisation-function") private Instance config; @Inject -- GitLab