Skip to content
Snippets Groups Projects
Commit 2cc4086f authored by Bernhard Johannes Berger's avatar Bernhard Johannes Berger
Browse files

Resolve "Integrate model-driven optimisation"

parent 7b644a69
No related branches found
No related tags found
2 merge requests!26Merge current develop into release,!13Resolve "Integrate model-driven optimisation"
Pipeline #343157 canceled
Showing
with 1553 additions and 4 deletions
package de.evoal.core.api.languages;
import de.evoal.languages.model.base.*;
import de.evoal.languages.model.ddl.DataDescription;
import de.evoal.languages.model.interpreter.ConstantExpressionEvaluator;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.emf.ecore.EObject;
......@@ -54,6 +55,26 @@ public class ExpressionEvaluator {
.toArray();
}
public DataDescription[] attributeToDataDescriptionArray(final Instance instance, final String attributeName) {
final Object result = attributeToObject(instance, attributeName);
if(!(result instanceof List<?> resultList)) {
log.error("Expression did not evaluate to a list for attribute {} which was expected.", attributeName);
throw new IllegalStateException("Expression evaluation error. Please check your configuration.");
}
final boolean allDataDescriptions = resultList.stream()
.allMatch(DataDescription.class::isInstance);
if(!allDataDescriptions) {
log.error("Expression did not evaluate to a list of numbers for attribute {} which was expected.", attributeName);
throw new IllegalStateException("Expression evaluation error. Please check your configuration.");
}
return resultList.stream()
.map(DataDescription.class::cast)
.toArray(DataDescription[]::new);
}
public double[][] attributeToDoubleArrayArray(final Instance instance, final String attributeName) {
final Object result = attributeToObject(instance, attributeName);
......
......@@ -6,6 +6,7 @@ import de.evoal.languages.model.ol.AlgorithmInstance;
import de.evoal.languages.model.ol.OptimisationModule;
import de.evoal.languages.model.ol.ProblemInstance;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.emf.ecore.EObject;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
......@@ -197,6 +198,11 @@ public class LanguageHelper {
if((type instanceof InstanceType || type instanceof DataType) && current instanceof OrExpression) {
return evaluator.evaluate(current);
} else if(type instanceof LiteralType) {
if(!(current instanceof EObject)) {
log.info("Current is not an EObject, returning value.");
return current;
}
return readExpression(current, type);
} else if(type instanceof ArrayType) {
return readArray(current, type);
......
package de.evoal.core.main.comparator;
import de.evoal.core.api.languages.ExpressionEvaluator;
import de.evoal.core.api.optimisation.OptimisationValueComparator;
import de.evoal.core.api.properties.PropertiesSpecification;
import de.evoal.languages.model.base.Instance;
import de.evoal.languages.model.ddl.DataDescription;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
import javax.inject.Named;
@Dependent
@Named("de.evoal.core.optimisation.hierarchical-comparator")
public class HierarchicalComparator implements OptimisationValueComparator {
private int[] orderIndices;
@Inject @Named("optimisation-space-specification")
private PropertiesSpecification optimisationSpecification;
@Inject
private ExpressionEvaluator evaluator;
@Override
public HierarchicalValue toValue(final double[] fitnessValues) {
return HierarchicalValue.of(orderIndices, fitnessValues);
}
@Override
public HierarchicalComparator init(final Instance config) {
final DataDescription[] order = evaluator.attributeToDataDescriptionArray(config, "order");
orderIndices = new int[order.length];
for(int i = 0; i < order.length; i++) {
orderIndices[i] = optimisationSpecification.indexOf(order[i].getName());
}
return this;
}
}
package de.evoal.core.main.comparator;
import de.evoal.core.api.optimisation.OptimisationValue;
import lombok.Getter;
import lombok.NonNull;
import java.util.Arrays;
public class HierarchicalValue implements OptimisationValue {
@Getter
private final @NonNull double[] fitnessValues;
private final @NonNull int[] orderIndices;
private HierarchicalValue(final @NonNull int[] orderIndices, final @NonNull double[] fitnessValues) {
this.orderIndices = Arrays.copyOf(orderIndices, orderIndices.length);
this.fitnessValues = fitnessValues;
}
public static HierarchicalValue of(final int[] orderIndices, final double [] fitnessValues) {
return new HierarchicalValue(orderIndices, fitnessValues);
}
@Override
public int compareTo(final @NonNull OptimisationValue other) {
if(other instanceof HierarchicalValue hv) {
for(int index : orderIndices) {
if(fitnessValues[index] != hv.fitnessValues[index]) {
return Double.compare(fitnessValues[index], hv.fitnessValues[index]);
}
}
return 0;
} else{
throw new IllegalArgumentException("Only allowed to compare HierarchicalValue");
}
}
@Override
public String toString() {
return "HierarchicalValue [fit=" + Arrays.toString(fitnessValues) + ", order=" + Arrays.toString(orderIndices) + "]";
}
@Override
public Object[] toStatistics() {
final Object [] result = new Object[fitnessValues.length];
for(int i = 0; i < result.length; ++i) {
result[i] = fitnessValues[i];
}
return result;
}
}
......@@ -156,6 +156,18 @@ module de.evoal.core.optimisation {
*/
weights : array real;
}
/**
* Compares the data in the specified order. First, the first data entry is compared.
* If the values differ, the comparison result is returned. If the values are equal,
* the next entry is taken into account.
*/
type 'hierarchical-comparator' extends comparator {
/**
* Comparison order of the fitness data.
*/
order : array data;
}
/**
* Comparator for a single number-based fitness value (such as a double).
......
package de.evoal.core.ea.api.alterer;
import io.jenetics.*;
import io.jenetics.util.RandomRegistry;
import io.jenetics.util.Seq;
public abstract class EvoAlMutator<
G extends Gene<?, G>,
C extends Comparable<? super C>
>
extends Mutator<G, C>
{
public EvoAlMutator(final double probability) {
super(probability);
}
@Override
public AltererResult<G, C> alter(
final Seq<Phenotype<G, C>> population,
final long generation
) {
assert population != null : "Not null is guaranteed from base class.";
final var random = RandomRegistry.random();
final double p = StrictMath.pow(_probability, 1.0/3.0);
final int P = EvoAlMutator.toInt(p);
final Seq<MutatorResult<Phenotype<G, C>>> result = population
.map(pt -> mutate(pt, generation, p, random));
return new AltererResult<>(
result.map(MutatorResult::result).asISeq(),
result.stream().mapToInt(MutatorResult::mutations).sum()
);
}
private static final long INT_RANGE = pow(2, 32) - 1;
protected static int toInt(final double probability) {
return (int)(Math.round(INT_RANGE*probability) + Integer.MIN_VALUE);
}
protected static long pow(final long b, final long e) {
long base = b;
long exp = e;
long result = 1;
while (exp != 0) {
if ((exp & 1) != 0) {
result *= base;
}
exp >>>= 1;
base *= base;
}
return result;
}
}
package de.evoal.core.ea.api.codec.model;
import de.evoal.core.ea.main.codec.model.ModelBuilder;
import de.evoal.languages.model.base.Instance;
import io.jenetics.AbstractChromosome;
import io.jenetics.Chromosome;
import io.jenetics.util.ISeq;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.emf.ecore.util.EcoreUtil;
@Slf4j
public class ModelChromosome extends AbstractChromosome<ModelGene> {
private final ModelBuilder builder;
public ModelBuilder builder() {
return builder;
}
/**
* Create a new {@code AbstractChromosome} from the given {@code genes}
* array.
*
* @param genes the genes that form the chromosome.
* @throws NullPointerException if the given gene array is {@code null}.
* @throws IllegalArgumentException if the length of the gene sequence is
* empty.
*/
protected ModelChromosome(ISeq<? extends ModelGene> genes, final ModelBuilder builder) {
super(genes);
this.builder = builder;
}
public static ModelChromosome of(final ModelBuilder memento) {
return create(memento);
}
public static ModelChromosome of(final ModelBuilder memento, final Instance model) {
return new ModelChromosome(ISeq.of(memento.toIterable(model)), memento);
}
private static ModelChromosome create(final ModelBuilder builder) {
return ModelChromosome.of(builder, builder.random());
}
@Override
public Chromosome<ModelGene> newInstance(final ISeq<ModelGene> genes) {
return new ModelChromosome(genes, builder);
}
@Override
public Chromosome<ModelGene> newInstance() {
log.info("Creating new instance of model chromosome");
return ModelChromosome.of(builder, builder.random());
}
public Instance getModel() {
return ((ModelGene)gene()).allele();
}
public ModelChromosome copy() {
return ModelChromosome.of(builder, EcoreUtil.copy(getModel()));
}
}
package de.evoal.core.ea.api.codec.model;
import de.evoal.core.ea.main.codec.model.ModelBuilder;
import de.evoal.languages.model.base.*;
import io.jenetics.Gene;
import org.eclipse.emf.ecore.util.EcoreUtil;
/**
* A model gene represents an instance of the model space.
*/
public class ModelGene implements Gene<Instance, ModelGene> {
/**
* The model builder for generating new random instances.
*/
private final ModelBuilder builder;
/**
* The instance the gene corresponds to
*/
private final Instance allele;
private ModelGene(final ModelBuilder builder, final Instance allele) {
this.builder = builder;
this.allele = allele;
}
@Override
public Instance allele() {
return allele;
}
@Override
public boolean isValid() {
return true;
}
@Override
public ModelGene newInstance() {
final Instance copy = EcoreUtil.copy(allele);
for(final Attribute attribute : copy.getAttributes()) {
final Type attributeType = attribute.getDefinition().getType();
if(attributeType instanceof IntType || attributeType instanceof BooleanType) {
// regenerate attribute and set value to newly generated value
final Attribute attr = builder.random(attribute.getDefinition());
attribute.setValue(attr.getValue());
}
}
return new ModelGene(builder, copy);
}
@Override
public ModelGene newInstance(final Instance value) {
return new ModelGene(builder, value);
}
public static ModelGene of(final ModelBuilder builder, final Instance allele) {
return new ModelGene(builder, allele);
}
public int size() {
return builder.size(allele);
}
}
package de.evoal.core.ea.main.alterer;
import java.util.Arrays;
import java.util.function.BiFunction;
import de.evoal.core.api.cdi.BeanFactory;
......@@ -11,6 +12,7 @@ import de.evoal.core.ea.main.alterer.internal.MeanCorrelationAlterer;
import de.evoal.core.ea.main.alterer.mutator.SingleBitFlipMutator;
import de.evoal.core.ea.main.alterer.crossover.*;
import de.evoal.core.ea.main.alterer.mutator.SingleBitFlipCorrelationMutator;
import de.evoal.core.ea.main.alterer.mutator.SingleChoiceMutator;
import de.evoal.core.ea.main.alterer.mutator.SwapCorrelationMutator;
import de.evoal.core.api.correlations.Correlations;
import de.evoal.core.ea.main.codec.program.rewriters.*;
......@@ -22,10 +24,13 @@ import io.jenetics.ext.TreeGene;
import io.jenetics.ext.rewriting.TreeRewriter;
import io.jenetics.prog.MathRewriteAlterer;
import io.jenetics.prog.op.Op;
import io.jenetics.util.ISeq;
import io.jenetics.util.Mean;
import javax.enterprise.context.ApplicationScoped;
import lombok.extern.slf4j.Slf4j;
import javax.enterprise.context.Dependent;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;
import javax.inject.Named;
......@@ -58,8 +63,7 @@ public class AltererFactory {
log.info("Creating alterer with name '{}'.", name);
switch(name) {
//case "CompositeAlterer": return createCompositeAlterer(config);
switch (name) {
case "mean-alterer": return createMeanAlterer(config);
case "correlation-mean-alterer": return (Alterer<G, OptimisationValue>) createCorrelationMeanAlterer(config);
case "partial-matched-alterer": return createPartiallyMatchedAlterer(config);
......@@ -72,9 +76,8 @@ public class AltererFactory {
case "correlation-swap-mutator": return createCorrelationSwapMutator(config);
case "bit-flip-mutator": return createBitFlipMutator(config);
case "correlation-bit-flip-mutator": return createCorrelationBitFlipMutator(config);
case "mathematical-expression-rewriter": return (Alterer<G, OptimisationValue>)createRewriteMutator(config);
case "mathematical-expression-rewriter": return (Alterer<G, OptimisationValue>) createRewriteMutator(config);
// case "IntermediateCrossover": return createIntermediateCrossover(config);
case "line-crossover": return createLineCrossover(config);
case "correlation-line-crossover": return createCorrelationLineCrossover(config);
case "multi-point-crossover": return createMultiPointCrossover(config);
......@@ -84,11 +87,24 @@ public class AltererFactory {
case "uniform-crossover": return createUniformCrossover(config);
case "correlation-uniform-crossover": return createCorrelationUniformCrossover(config);
case "single-node-crossover": return (Alterer<G, OptimisationValue>) createSingleNodeCrossover(config);
case "single-choice-mutator": return createSingleChoiceMutator(config);
}
return BeanFactory.createComponent(AltererComponent.class, AltererComponentProvider.class, config);
}
private <G extends Gene<?, G>> Alterer<G, OptimisationValue> createSingleChoiceMutator(final Instance config) {
final Object[] alterers = helper.lookup(config, "alterers");
final ISeq<Alterer> components =
Arrays.stream(alterers)
.map(Instance.class::cast)
.map(a -> create(a))
.collect(ISeq.toISeq());
return new SingleChoiceMutator(components);
}
private <G extends TreeGene<?, G>> Alterer<G, OptimisationValue> createSingleNodeCrossover(Instance config) {
final Double probability = helper.lookup(config, "probability");
......
package de.evoal.core.ea.main.alterer.model;
import de.evoal.core.api.cdi.BeanFactory;
import de.evoal.core.api.utils.LanguageHelper;
import de.evoal.core.ea.api.operators.AltererComponentProvider;
import de.evoal.core.ea.main.alterer.model.crossover.FeatureSwapCrossover;
import de.evoal.core.ea.main.alterer.model.mutator.ArrayReorderMutator;
import de.evoal.core.ea.main.alterer.model.mutator.ArraySizeMutator;
import de.evoal.core.ea.main.alterer.model.mutator.LiteralMutator;
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;
@ApplicationScoped
public class MutatorProducer {
@Inject
private LanguageHelper helper;
private double probability(final Instance instance) {
return helper.lookup(instance, "probability");
}
@Produces
@Dependent
@Named("de.evoal.core.ea.mdo.feature-swap-crossover")
public AltererComponentProvider createFeatureSwapCrossover() {
return instance -> FeatureSwapCrossover.of(probability(instance));
}
@Produces
@Dependent
@Named("de.evoal.core.ea.mdo.array-size-mutator")
public AltererComponentProvider createArraySizeMutator() {
return instance -> new ArraySizeMutator<>(probability(instance));
}
@Produces
@Dependent
@Named("de.evoal.core.ea.mdo.array-reorder-mutator")
public AltererComponentProvider createArrayReorderMutator() {
return instance -> new ArrayReorderMutator<>(probability(instance));
}
@Produces
@Dependent
@Named("de.evoal.core.ea.mdo.literal-mutator")
public AltererComponentProvider createLiteralMutator() {
return instance -> {
final LiteralMutator<?> mutator = new LiteralMutator<>(probability(instance));
BeanFactory.injectFields(mutator);
mutator.init(instance);
return mutator;
};
}
}
package de.evoal.core.ea.main.alterer.model.crossover;
import de.evoal.core.ea.api.operators.AltererComponent;
import de.evoal.languages.model.base.*;
import io.jenetics.util.RandomRegistry;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import java.util.*;
import java.util.random.RandomGenerator;
import java.util.stream.Collectors;
@Slf4j
public class FeatureSwapCrossover extends TreeCrossover implements AltererComponent {
private RandomGenerator random = RandomRegistry.random();
/**
* Constructs an alterer with a given recombination probability.
*
* @param probability The recombination probability.
* @throws IllegalArgumentException if the {@code probability} is not in the
* valid range of {@code [0, 1]} or the given {@code order} is
* smaller than two.
*/
protected FeatureSwapCrossover(double probability) {
super(probability);
}
@Override
protected void crossover(final Instance tree1, final Instance tree2) {
final List<Instance> instances1 = collectInstances(tree1);
final List<Instance> instances2 = collectInstances(tree2);
final Map<AttributeDefinition, List<Instance>> categories1 = calculateCategories(instances1);
final Map<AttributeDefinition, List<Instance>> categories2 = calculateCategories(instances2);
while(true) {
final AttributeDefinition definition = chooseAttributeRandomly(categories1.keySet(), categories2.keySet());
// check if we have an instance in both trees
if(!categories1.containsKey(definition) || !categories2.containsKey(definition)) {
continue;
}
// select instances
final Instance instance1 = chooseInstanceWithAttributeRandomly(instances1, definition);
final Instance instance2 = chooseInstanceWithAttributeRandomly(instances2, definition);
if(definition.getType() instanceof ArrayType && swapArrayMember()) {
log.info("Swapping attribute elements in '{}' between '{}' and '{}'.", definition.getName(), instance1.getDefinition().getName(), instance2.getDefinition().getName());
final Attribute attribute1 = instance1.findAttribute(definition.getName());
final Attribute attribute2 = instance2.findAttribute(definition.getName());
final Array array1 = findArray(attribute1.getValue());
final Array array2 = findArray(attribute2.getValue());
final int index1 = random.nextInt(0, array1.getValues().size());
final int index2 = random.nextInt(0, array2.getValues().size());
final Value temporary = array1.getValues().get(index1);
array1.getValues().set(index1, EcoreUtil.copy(array2.getValues().get(index2)));
array2.getValues().set(index2, temporary);
} else {
log.info("Swapping attribute '{}' between '{}' and '{}'.", definition.getName(), instance1.getDefinition().getName(), instance2.getDefinition().getName());
final Attribute attribute1 = instance1.findAttribute(definition.getName());
final Attribute attribute2 = instance2.findAttribute(definition.getName());
final Expression temporary = attribute1.getValue();
attribute1.setValue(attribute2.getValue());
attribute2.setValue(temporary);
}
break;
}
}
/**
* @return <code>true</code> iff an element of an array should be swapped or the complete array.
*/
private boolean swapArrayMember() {
return random.nextInt(100) < 98;
}
private Instance chooseInstanceWithAttributeRandomly(final List<Instance> instances, final AttributeDefinition definition) {
final List<Instance> possible = instances.stream()
.filter(i -> i.getAttributes().stream().anyMatch(a -> definition.equals(a.getDefinition())))
.collect(Collectors.toUnmodifiableList());
int index = random.nextInt(possible.size());
return possible.get(index);
}
private AttributeDefinition chooseAttributeRandomly(final Set<AttributeDefinition> definitions1, final Set<AttributeDefinition> definitions2) {
final Set<AttributeDefinition> combined = new HashSet<>(definitions1);
combined.retainAll(definitions2);
final List<AttributeDefinition> combinedList = new ArrayList<>(combined);
int index = random.nextInt(combined.size());
return combinedList.get(index);
}
private Map<AttributeDefinition, List<Instance>> calculateCategories(final List<Instance> instances) {
final Map<AttributeDefinition, List<Instance>> categories = new HashMap<>();
instances.forEach(instance -> {
instance.getDefinition().getAttributes().forEach(attribute -> {
if (!categories.containsKey(attribute)) {
final List<Instance> sublist = new ArrayList<>();
sublist.add(instance);
categories.put(attribute, sublist);
} else {
categories.get(attribute).add(instance);
}
});
});
return categories;
}
private List<Instance> collectInstances(final Instance tree) {
final List<Instance> instances = new ArrayList<>();
final TreeIterator<EObject> iterator = tree.eAllContents();
while (iterator.hasNext()) {
final EObject object = iterator.next();
if (object instanceof Instance instance) {
instances.add(instance);
}
}
return instances;
}
private Array findArray(final Expression value) {
return (Array) ((OrExpression)value)
.getSubExpressions().get(0)
.getSubExpressions().get(0)
.getSubExpressions().get(0)
.getOperand()
.getLeftOperand()
.getLeftOperand()
.getLeftOperand()
.getLeftOperand()
.getSubExpression();
}
public static FeatureSwapCrossover of(final double probability) {
return new FeatureSwapCrossover(probability);
}
}
package de.evoal.core.ea.main.alterer.model.crossover;
import de.evoal.core.api.utils.Requirements;
import de.evoal.core.ea.api.codec.model.ModelChromosome;
import de.evoal.core.ea.api.codec.model.ModelGene;
import de.evoal.languages.model.base.Instance;
import io.jenetics.Genotype;
import io.jenetics.Phenotype;
import io.jenetics.Recombinator;
import io.jenetics.util.MSeq;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.emf.ecore.util.EcoreUtil;
@Slf4j
public abstract class TreeCrossover<A extends Comparable<? super A>> extends Recombinator<ModelGene, A> {
/**
* Constructs an alterer with a given recombination probability.
*
* @param probability The recombination probability.
* @throws IllegalArgumentException if the {@code probability} is not in the
* valid range of {@code [0, 1]} or the given {@code order} is
* smaller than two.
*/
protected TreeCrossover(double probability) {
super(probability, 2);
}
protected abstract void crossover(final Instance tree1, final Instance tree2);
@Override
protected int recombine(final MSeq<Phenotype<ModelGene, A>> population, int[] individuals, long generation) {
Requirements.requireEqual(2, individuals.length);
log.info("Recombining {} and {}.", individuals[0], individuals[1]);
final Phenotype<ModelGene, A> phenotype1 = population.get(individuals[0]);
final Phenotype<ModelGene, A> phenotype2 = population.get(individuals[1]);
final Genotype<ModelGene> genotype1 = phenotype1.genotype();
final Genotype<ModelGene> genotype2 = phenotype2.genotype();
final Instance tree1 = EcoreUtil.copy(genotype1.gene().allele());
final Instance tree2 = EcoreUtil.copy(genotype2.gene().allele());
crossover(tree1, tree2);
final ModelChromosome chromosome1 = ModelChromosome.of(((ModelChromosome)genotype1.chromosome()).builder(), tree1);
final ModelChromosome chromosome2 = ModelChromosome.of(((ModelChromosome)genotype2.chromosome()).builder(), tree2);
//Creating two new Phenotypes and exchanging it with the old.
population.set(
individuals[0],
Phenotype.of(Genotype.of(chromosome1), generation)
);
population.set(
individuals[1],
Phenotype.of(Genotype.of(chromosome2), generation)
);
return order();
}
}
package de.evoal.core.ea.main.alterer.model.mutator;
import de.evoal.core.ea.api.alterer.EvoAlMutator;
import de.evoal.core.ea.api.operators.AltererComponent;
import de.evoal.core.ea.api.codec.model.ModelChromosome;
import de.evoal.core.ea.api.codec.model.ModelGene;
import de.evoal.languages.model.base.*;
import io.jenetics.Chromosome;
import io.jenetics.MutatorResult;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import java.util.*;
import java.util.random.RandomGenerator;
import java.util.stream.StreamSupport;
@Slf4j
public class ArrayReorderMutator<A extends Comparable<? super A>> extends EvoAlMutator implements AltererComponent {
public ArrayReorderMutator(double probability) {
super(probability);
}
protected MutatorResult<Chromosome<ModelGene>> mutate(
final Chromosome chromosome,
final double p,
final RandomGenerator random
) {
final int P = toInt(p);
final ModelChromosome mc = (ModelChromosome) chromosome;
final Instance copy = EcoreUtil.copy(mc.getModel());
final TreeIterator<EObject> iterator = copy.eAllContents();
final List<Attribute> attributes = StreamSupport.stream(
Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED),
false)
.filter(Instance.class::isInstance)
.map(Instance.class::cast)
.flatMap(i -> i.getAttributes().stream().filter(a -> a.getDefinition().getType() instanceof ArrayType))
.toList();
int numberOfChanges = 0;
final Set<Integer> indices = new HashSet<>();
do {
final int index = random.nextInt(0, attributes.size());
if(!indices.add(index) ) {
break;
}
final Array array = findArray(attributes.get(index).getValue());
numberOfChanges += 1;
if(array.getValues().size() == 1) {
continue;
} else {
int index1 = random.nextInt(0, array.getValues().size());
int index2 = random.nextInt(0, array.getValues().size());
log.info("Swapping children {} and {}.", index1, index2);
final Value value1 = EcoreUtil.copy(array.getValues().get(index1));
final Value value2 = EcoreUtil.copy(array.getValues().get(index2));
array.getValues().set(index1, value2);
array.getValues().set(index2, value1);
}
} while (random.nextInt() < P);
log.info("Number of changes are {}.", numberOfChanges);
return new MutatorResult<>(
ModelChromosome.of(mc.builder(), copy),
numberOfChanges
);
}
private Array findArray(final Expression value) {
return (Array) ((OrExpression)value)
.getSubExpressions().get(0)
.getSubExpressions().get(0)
.getSubExpressions().get(0)
.getOperand()
.getLeftOperand()
.getLeftOperand()
.getLeftOperand()
.getLeftOperand()
.getSubExpression();
}
}
package de.evoal.core.ea.main.alterer.model.mutator;
import de.evoal.core.ea.api.alterer.EvoAlMutator;
import de.evoal.core.ea.api.operators.AltererComponent;
import de.evoal.core.ea.api.codec.model.ModelChromosome;
import de.evoal.core.ea.api.codec.model.ModelGene;
import de.evoal.languages.model.base.*;
import io.jenetics.Chromosome;
import io.jenetics.MutatorResult;
import io.jenetics.util.RandomRegistry;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import java.util.*;
import java.util.random.RandomGenerator;
import java.util.stream.StreamSupport;
@Slf4j
public class ArraySizeMutator<A extends Comparable<? super A>> extends EvoAlMutator implements AltererComponent {
private RandomGenerator generator = RandomRegistry.random();
public ArraySizeMutator(double probability) {
super(probability);
}
protected MutatorResult<Chromosome<ModelGene>> mutate(
final Chromosome chromosome,
final double p,
final RandomGenerator random
) {
final int P = EvoAlMutator.toInt(p);
final ModelChromosome mc = (ModelChromosome) chromosome;
final Instance copy = EcoreUtil.copy(mc.getModel());
final TreeIterator<EObject> iterator = copy.eAllContents();
final List<Attribute> attributes = StreamSupport.stream(
Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED),
false)
.filter(Instance.class::isInstance)
.map(Instance.class::cast)
.flatMap(i -> i.getAttributes().stream().filter(a -> a.getDefinition().getType() instanceof ArrayType))
.toList();
int numberOfChanges = 0;
final Set<Integer> indices = new HashSet<>();
do {
final int index = generator.nextInt(0, attributes.size());
if(!indices.add(index) ) {
break;
}
final Attribute attribute = attributes.get(index);
final Array array = findArray(attribute.getValue());
numberOfChanges += 1;
if(array.getValues().size() == 1 || shouldAdd(random)) {
final int elementIndex = generator.nextInt(0, array.getValues().size() + 1);
log.info("Adding a new child to array at position {}", elementIndex);
final Value newChild = mc.builder().random("", ((ArrayType)attribute.getDefinition().getType()).getElements());
if(elementIndex == array.getValues().size()) {
array.getValues().add(newChild);
} else {
array.getValues().add(elementIndex, newChild);
}
} else {
final int elementIndex = generator.nextInt(0, array.getValues().size());
log.info("Removing child {} from array", elementIndex);
array.getValues().remove(elementIndex);
}
} while (random.nextInt() < P);
log.info("Number of changes are {}.", numberOfChanges);
return new MutatorResult<>(
ModelChromosome.of(mc.builder(), copy),
numberOfChanges
);
}
private Array findArray(final Expression value) {
return (Array) ((OrExpression)value)
.getSubExpressions().get(0)
.getSubExpressions().get(0)
.getSubExpressions().get(0)
.getOperand()
.getLeftOperand()
.getLeftOperand()
.getLeftOperand()
.getLeftOperand()
.getSubExpression();
}
boolean shouldAdd(final RandomGenerator random) {
return random.nextDouble() < 0.50;
}
}
package de.evoal.core.ea.main.alterer.model.mutator;
import de.evoal.core.ea.api.alterer.EvoAlMutator;
import de.evoal.core.ea.api.operators.AltererComponent;
import de.evoal.core.ea.api.codec.model.ModelChromosome;
import de.evoal.core.ea.api.codec.model.ModelGene;
import de.evoal.languages.model.base.*;
import io.jenetics.Chromosome;
import io.jenetics.MutatorResult;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import java.util.*;
import java.util.random.RandomGenerator;
import java.util.stream.StreamSupport;
@Slf4j
public class LiteralMutator<A extends Comparable<? super A>> extends EvoAlMutator implements AltererComponent {
public LiteralMutator(double probability) {
super(probability);
}
protected MutatorResult<Chromosome<ModelGene>> mutate(
final Chromosome chromosome,
final double p,
final RandomGenerator random
) {
final int P = toInt(p);
final ModelChromosome mc = (ModelChromosome) chromosome;
final Instance copy = EcoreUtil.copy(mc.getModel());
final TreeIterator<EObject> iterator = copy.eAllContents();
final List<Attribute> attributes = StreamSupport.stream(
Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED),
false)
.filter(Instance.class::isInstance)
.map(Instance.class::cast)
.flatMap(i -> i.getAttributes().stream().filter(a -> a.getDefinition().getType() instanceof LiteralType))
.toList();
int numberOfChanges = 0;
final Set<Integer> indices = new HashSet<>();
do {
final int index = random.nextInt(0, attributes.size());
if(!indices.add(index) ) {
break;
}
final Attribute attribute = attributes.get(index);
final Literal literal = findLiteral(attribute.getValue());
numberOfChanges += 1;
if(literal instanceof IntegerLiteral iLiteral) {
int value = random.nextInt(0, 4);
log.info("Replacing {} by {}.", iLiteral.getLiteral(), value);
iLiteral.setLiteral(value);
} else if(literal instanceof BooleanLiteral bLiteral) {
boolean value = random.nextBoolean();
log.info("Replacing {} by {}.", bLiteral.isValue(), value);
bLiteral.setValue(value);
} else {
throw new IllegalStateException("");
}
} while (random.nextInt() < P);
log.info("Number of changes are {}.", numberOfChanges);
return new MutatorResult<>(
ModelChromosome.of(mc.builder(), copy),
numberOfChanges
);
}
private Literal findLiteral(final Expression value) {
return (Literal) ((OrExpression)value)
.getSubExpressions().get(0)
.getSubExpressions().get(0)
.getSubExpressions().get(0)
.getOperand()
.getLeftOperand()
.getLeftOperand()
.getLeftOperand()
.getLeftOperand()
.getSubExpression();
}
}
/*
* Java Genetic Algorithm Library (jenetics-7.1.0).
* Copyright (c) 2007-2022 Franz Wilhelmstötter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author:
* Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
*/
package de.evoal.core.ea.main.alterer.mutator;
import de.evoal.core.ea.api.operators.AltererComponent;
import io.jenetics.Alterer;
import io.jenetics.AltererResult;
import io.jenetics.Gene;
import io.jenetics.Phenotype;
import io.jenetics.util.ISeq;
import io.jenetics.util.RandomRegistry;
import io.jenetics.util.Seq;
import lombok.extern.slf4j.Slf4j;
import java.util.random.RandomGenerator;
import java.util.stream.Collectors;
import static java.lang.String.format;
/**
* Combines several alterers to one.
*
* @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
* @since 1.0
* @version 5.0
*/
@Slf4j
public final class SingleChoiceMutator<
G extends Gene<?, G>,
C extends Comparable<? super C>
>
implements AltererComponent
{
private final ISeq<Alterer<G, C>> _alterers;
private final RandomGenerator random = RandomRegistry.random();
/**
* Combine the given alterers.
*
* @param alterers the alterers to combine.
* @throws NullPointerException if one of the alterers is {@code null}.
*/
public SingleChoiceMutator(final Seq<Alterer<G, C>> alterers) {
_alterers = ISeq.of(alterers);
}
@Override
public AltererResult alter(
final Seq population,
final long generation
) {
final ISeq<Phenotype> results =
(ISeq<Phenotype>) population.stream()
.map(Phenotype.class::cast)
.map(p -> {
final int aIndex = random.nextInt(0, _alterers.size());
final Alterer alterer = _alterers.get(aIndex);
log.debug("Calling alterer {}", alterer.getClass().getSimpleName());
return alterer.alter(ISeq.of((Phenotype)p), generation);
})
.map(r -> ((AltererResult)r).population().get(0))
.map(Phenotype.class::cast)
.collect(ISeq.toISeq());
return new AltererResult(
results, (int)generation
);
}
@Override
public String toString() {
return format(
"%s:\n%s", getClass().getSimpleName(),
_alterers.stream()
.map(a -> " - " + a)
.collect(Collectors.joining("\n"))
);
}
}
package de.evoal.core.ea.main.codec.model;
import de.evoal.core.api.properties.PropertySpecification;
import de.evoal.core.ea.api.codec.model.ModelChromosome;
public record GenotypeInformation(PropertySpecification searchSpaceProperty,
ModelBuilder memento,
ModelChromosome chromosome) {
}
package de.evoal.core.ea.main.codec.model;
import de.evoal.core.ea.api.codec.model.ModelGene;
import de.evoal.languages.model.base.*;
import io.jenetics.util.RandomRegistry;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
@Slf4j
public record ModelBuilder(TypeDefinition root, Map<TypeDefinition, Set<TypeDefinition>> subtypes, Map<AttributeDefinition, Set<TypeDefinition>> attributes) {
private static final BaseFactory FACTORY = BaseFactory.eINSTANCE;
public Instance random() {
return random(root);
}
public @NonNull Iterable<ModelGene> toIterable(final @NonNull Instance tree) {
final List<ModelGene> genes = new ArrayList<>();
toIterable(genes, tree);
return genes;
}
private void toIterable(final @NonNull List<ModelGene> genes, @NonNull final Instance tree) {
genes.add(ModelGene.of(this, tree));
for(final Attribute attr : tree.getAttributes()) {
final Type type = attr.getDefinition().getType();
if(type instanceof InstanceType) {
toIterable(genes, findInstance(attr.getValue()));
} else if(type instanceof ArrayType arrayType && arrayType.getElements() instanceof InstanceType instanceType) {
final Array array = findArray(attr.getValue());
array.getValues()
.stream()
.map(Instance.class::cast)
.forEach(i -> toIterable(genes, i));
}
}
}
private Array findArray(Expression value) {
return (Array) ((OrExpression)value)
.getSubExpressions().get(0)
.getSubExpressions().get(0)
.getSubExpressions().get(0)
.getOperand()
.getLeftOperand()
.getLeftOperand()
.getLeftOperand()
.getLeftOperand()
.getSubExpression();
}
private Instance findInstance(final Expression value) {
return (Instance) ((OrExpression)value)
.getSubExpressions().get(0)
.getSubExpressions().get(0)
.getSubExpressions().get(0)
.getOperand()
.getLeftOperand()
.getLeftOperand()
.getLeftOperand()
.getLeftOperand()
.getSubExpression();
}
/**
* Creates an instance of the given type and sets the attributes randomly.
*
* @param definition Instance type.
* @return A valid instance.
*/
private @NonNull Instance random(final TypeDefinition definition) {
log.info("Creating instance of type {}", definition.getName());
final Instance instance = FACTORY.createInstance();
instance.setDefinition(definition);
for(AttributeDefinition attributeDef : definition.getAttributes()) {
instance.getAttributes().add(random(attributeDef));
}
return instance;
}
/**
* Creates an attribute for the given {@code definition} and initialises the
* value randomly.
*
* @param definition The attribute to generate.
* @return A valid attribute.
*/
public @NonNull Attribute random(final AttributeDefinition definition) {
final Attribute attribute = FACTORY.createAttribute();
attribute.setDefinition(definition);
attribute.setValue(toExpression(random(definition.getName(), definition.getType())));
return attribute;
}
private @NonNull Expression toExpression(@NonNull Value value) {
final OrExpression or = FACTORY.createOrExpression();
final XorExpression xor = FACTORY.createXorExpression();
or.getSubExpressions().add(xor);
final AndExpression and = FACTORY.createAndExpression();
xor.getSubExpressions().add(and);
final NotExpression not = FACTORY.createNotExpression();
and.getSubExpressions().add(not);
final ComparisonExpression comparison = FACTORY.createComparisonExpression();
not.setOperand(comparison);
not.setNegated(false);
final AddOrSubtractExpression add = FACTORY.createAddOrSubtractExpression();
comparison.setLeftOperand(add);
final MultiplyDivideModuloExpression multiply = FACTORY.createMultiplyDivideModuloExpression();
add.setLeftOperand(multiply);
final PowerOfExpression power = FACTORY.createPowerOfExpression();
multiply.setLeftOperand(power);
final UnaryAddOrSubtractExpression unary = FACTORY.createUnaryAddOrSubtractExpression();
power.setLeftOperand(unary);
unary.setSubExpression(value);
return or;
}
public @NonNull Value random(final @NonNull String name, final @NonNull Type type) {
if(type instanceof ArrayType arrayType) {
return random(name, arrayType);
} else if(type instanceof InstanceType instanceType) {
final Set<TypeDefinition> definitions = subtypes.get((TypeDefinition)instanceType.getDefinition());
final List<TypeDefinition> types = new ArrayList<>(definitions);
int index = RandomRegistry.random().nextInt(definitions.size());
return random(types.get(index));
} else if(type instanceof IntType) {
return random(name, (IntType) type);
} else if(type instanceof BooleanType) {
return random((BooleanType) type);
} else {
throw new IllegalArgumentException("Unsupported type: " + type.eClass().getName());
}
}
private @NonNull Value random(final String name, final IntType type) {
final IntegerLiteral literal = FACTORY.createIntegerLiteral();
int value = RandomRegistry.random().nextInt(0, 4);
if("value".equals(name)) {
value = RandomRegistry.random().nextInt(0, 16);
value = (int)Math.pow(2, value);
}
literal.setLiteral(value);
return literal;
}
private @NonNull Value random(final BooleanType type) {
final BooleanLiteral literal = FACTORY.createBooleanLiteral();
literal.setValue(RandomRegistry.random().nextInt(0, 2) == 1);
return literal;
}
private @NonNull Value random(@NonNull final String name, final @NonNull ArrayType type) {
int count = "entries".equals(name) ? RandomRegistry.random().nextInt(1,5) : 1; // ; // TODO What about a gaussian distribution?
final Array array = FACTORY.createArray();
for(int i = 0; i < count; i++) {
final Value child = random(name, type.getElements());
array.getValues().add(child);
}
return array;
}
public int size(final Instance instance) {
return 1 + instance.getAttributes()
.stream()
.filter(a -> {
Type t = a.getDefinition().getType();
if(t instanceof ArrayType) {
t = ((ArrayType)t).getElements();
}
return t instanceof InstanceType;
})
.flatMap(a -> {
Type t = a.getDefinition().getType();
if(t instanceof ArrayType) {
return findArray(a.getValue()).getValues().stream().map(Instance.class::cast);
}
return Stream.of(findInstance(a.getValue()));
})
.mapToInt(this::size)
.sum();
}
}
package de.evoal.core.ea.main.codec.model;
import de.evoal.core.api.cdi.BeanFactory;
import de.evoal.core.api.properties.Properties;
import de.evoal.core.api.properties.PropertiesSpecification;
import de.evoal.core.api.properties.PropertySpecification;
import de.evoal.core.api.utils.LanguageHelper;
import de.evoal.core.api.utils.Requirements;
import de.evoal.core.ea.api.codec.CustomCodec;
import de.evoal.core.ea.api.codec.model.ModelChromosome;
import de.evoal.core.ea.api.codec.model.ModelGene;
import de.evoal.languages.model.base.*;
import de.evoal.languages.model.ddl.DataDescription;
import de.evoal.languages.model.ddl.StructuredDataDescription;
import de.evoal.languages.model.dl.DefinitionModule;
import de.evoal.languages.model.dl.util.FQNProvider;
import io.jenetics.Genotype;
import io.jenetics.util.Factory;
import lombok.extern.slf4j.Slf4j;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;
import javax.inject.Named;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@Slf4j
@ApplicationScoped
public class ModelGenotypeCodec implements CustomCodec<ModelGene> {
private static final String CHROMOSOME_NAME = "de.evoal.core.ea.mdo.model-chromosome";
static final String GENOTYPE_NAME = "de.evoal.core.ea.mdo.model-genotype";
private static final String MODEL_DATA_NAME = "de.evoal.core.ea.mdo.model";
@Inject
private LanguageHelper helper;
@Inject
private @Named("genotype-specification") PropertiesSpecification specification;
@Inject
private @Named("optimisation-space-specification") PropertiesSpecification optimisationSpace;
private List<DataDescription> genotypeSpec = Collections.emptyList();
private PropertiesSpecification mapping;
private PropertiesSpecification variablesSpecification;
private List<GenotypeInformation> information;
@Override
public ModelGenotypeCodec init(final Instance config) {
log.info("Initialising model genotype codec");
final Object[] chromosomeConfigurations = helper.lookup(config, "chromosomes");
final FQNProvider provider = new FQNProvider();
Requirements.requireFalse(Arrays.stream(chromosomeConfigurations)
.map(Instance.class::cast)
.anyMatch(i -> !CHROMOSOME_NAME.equals(provider.get(i))),
"Non model-chromosome are not allowed.");
genotypeSpec = Arrays.stream(chromosomeConfigurations)
.map(Instance.class::cast)
.filter(i -> CHROMOSOME_NAME.equals(provider.get(i)))
.map(i -> helper.<DataDescription>lookup(i, "root"))
.collect(Collectors.toList());
Requirements.requireTrue(
genotypeSpec.stream()
.allMatch(StructuredDataDescription.class::isInstance),
"A model chromosome can only use structured data: data <name> of instance program;"
);
Requirements.requireTrue(
genotypeSpec.stream()
.map(StructuredDataDescription.class::cast)
.map(StructuredDataDescription::getType)
.allMatch(ModelGenotypeCodec::isSubclassOfModel),
"A model chromosome can only use structured data: data <name> of instance model;"
);
mapping = PropertiesSpecification.builder()
.addDescriptions(genotypeSpec.stream())
.build();
Requirements.requireTrue(mapping.size() == chromosomeConfigurations.length, "Required to be of same size.");
information = IntStream.range(0, mapping.size())
.mapToObj(i -> {
final Instance configuration = (Instance) chromosomeConfigurations[i];
return toChromosome(configuration, i);
})
.collect(Collectors.toList());
return this;
}
private static boolean isSubclassOfModel(final TypeDefinition definition) {
final FQNProvider provider = new FQNProvider();
if(MODEL_DATA_NAME.equals(provider.get(definition))) {
return true;
}
if(definition.getSuperType() == null) {
return false;
}
return isSubclassOfModel(definition.getSuperType());
}
private GenotypeInformation toChromosome(final Instance configuration, int genotypeIndex) {
final StructuredDataDescription type = (StructuredDataDescription)genotypeSpec.get(genotypeIndex);
log.info("Converting configuration with base {} to chromosome.", type.getName());
final Map<TypeDefinition, Set<TypeDefinition>> subtypes = createSubtypeTable(type);
final Map<AttributeDefinition, Set<TypeDefinition>> attributes = createAttributeTable(type, subtypes);
final Set<AttributeDefinition> arrays = collectArrays(type);
/*
Object [] validatorConfiguration = helper.lookup(configuration, "validators");
List<TreeValidator> validators = Arrays.stream(validatorConfiguration)
.map(Instance.class::cast)
.map(i -> BeanFactory.createComponent(TreeValidator.class, i))
.collect(Collectors.toList());
Predicate<? super ModelChromosome> validator = c -> validators.stream().allMatch(v -> v.validate(c));
*/
final ModelBuilder memento = new ModelBuilder(type.getType(),
subtypes,
attributes);
final ModelChromosome chromosome = ModelChromosome.of(memento);
return new GenotypeInformation(mapping.get(genotypeIndex), memento, chromosome);
}
private Set<AttributeDefinition> collectArrays(StructuredDataDescription type) {
final Set<AttributeDefinition> arrays = new HashSet<>();
final Set<TypeDefinition> working = new HashSet<>();
final Set<TypeDefinition> visited = new HashSet<>();
working.add(type.getType());
while(!working.isEmpty()) {
final TypeDefinition currentType = working.iterator().next();
if(visited.contains(currentType)) {
continue;
}
working.remove(currentType);
visited.add(currentType);
for(final AttributeDefinition attr : currentType.getAttributes()) {
Type attrType = attr.getType();
if(attrType instanceof ArrayType arrayType) {
arrays.add(attr);
attrType = arrayType.getElements();
}
if(attrType instanceof InstanceType instanceType) {
working.add(instanceType.getDefinition());
}
}
}
return arrays;
}
private Map<AttributeDefinition, Set<TypeDefinition>> createAttributeTable(final StructuredDataDescription type, final Map<TypeDefinition, Set<TypeDefinition>> subtypes) {
final Map<AttributeDefinition, Set<TypeDefinition>> attributes = new HashMap<>();
final Set<TypeDefinition> working = new HashSet<>();
final Set<TypeDefinition> visited = new HashSet<>();
working.add(type.getType());
while(!working.isEmpty()) {
final TypeDefinition currentType = working.iterator().next();
if(visited.contains(currentType)) {
continue;
}
working.remove(currentType);
visited.add(currentType);
for(final AttributeDefinition attr : currentType.getAttributes()) {
Type attrType = attr.getType();
if(attrType instanceof ArrayType) {
attrType = ((ArrayType)attrType).getElements();
}
if(attrType instanceof InstanceType instanceType) {
final Set<TypeDefinition> types = subtypes.get(instanceType.getDefinition());
attributes.put(attr, types);
working.add(instanceType.getDefinition());
}
}
}
return attributes;
}
private Map<TypeDefinition, Set<TypeDefinition>> createSubtypeTable(final StructuredDataDescription root) {
final DefinitionModule module = (DefinitionModule) root.getType().eContainer();
final Map<TypeDefinition, Set<TypeDefinition>> subtypes = new HashMap<>();
for(final TypeDefinition type : module.getTypes()) {
subtypes.put(type, new HashSet<>());
}
for(final TypeDefinition type : module.getTypes()) {
if(type.isAbstract()) {
continue;
}
TypeDefinition parent = type;
while(parent != null) {
if(subtypes.containsKey(parent)) {
subtypes.get(parent).add(type);
}
parent = parent.getSuperType();
}
}
return subtypes;
}
@Override
public Genotype<ModelGene> encode(final Properties p) {
return Genotype.of(
information.stream()
.map(info -> {
PropertySpecification spec = info.searchSpaceProperty();
final Instance model = (Instance)p.get(spec);
return ModelChromosome.of(info.memento(), model);
})
.collect(Collectors.toList())
);
}
@Override
public Factory<Genotype<ModelGene>> encoding() {
return Genotype.of(
information.stream()
.map(GenotypeInformation::chromosome)
.collect(Collectors.toList())
);
}
@Override
public Function<Genotype<ModelGene>, Properties> decoder() {
return this::decodeGenotype;
}
private Properties decodeGenotype(final Genotype<ModelGene> genotype) {
final Properties result = new Properties(specification);
IntStream.range(0, genotype.length())
.forEach(i -> {
final ModelChromosome chromosome = (ModelChromosome)genotype.get(i);
final Instance model = chromosome.getModel();
final GenotypeInformation info = information.get(i);
result.put(info.searchSpaceProperty(), model);
});
return result;
}
@Produces
@Named(GENOTYPE_NAME)
@ApplicationScoped
public static CustomCodec create() {
log.info("Creating model-based codec for optimisation problem.");
return BeanFactory.injectFields(new ModelGenotypeCodec());
}
}
package de.evoal.core.ea.main.codec.model;
import de.evoal.core.api.languages.ExpressionEvaluator;
import de.evoal.core.api.utils.InitializationException;
import de.evoal.core.api.utils.LanguageHelper;
import de.evoal.core.ea.api.codec.CustomCodecDescriber;
import de.evoal.languages.model.base.Definition;
import de.evoal.languages.model.base.Instance;
import lombok.extern.slf4j.Slf4j;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
import javax.inject.Named;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@Dependent
@Named(ModelGenotypeCodec.GENOTYPE_NAME + "-describer")
@Slf4j
public class ModelGenotypeDescriber implements CustomCodecDescriber {
private Instance configuration;
@Inject
private LanguageHelper helper;
@Inject
private ExpressionEvaluator evaluator;
@Override
public CustomCodecDescriber init(final Instance configuration) throws InitializationException {
log.info("Setting up describer");
this.configuration = configuration;
return CustomCodecDescriber.super.init(configuration);
}
@Override
public List<Definition> describe() {
log.info("Describing Genotype.");
final Object [] genes = helper.lookup(configuration, "chromosomes");
return Arrays.stream(genes)
.map(Instance.class::cast)
.map(i -> evaluator.attributeToObject(i, "root"))
.map(Definition.class::cast)
.collect(Collectors.toList());
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment