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

Fixed a bunch of bugs.

parent a1c84814
No related branches found
No related tags found
No related merge requests found
Pipeline #240510 passed
Showing
with 426 additions and 279 deletions
......@@ -322,6 +322,8 @@
<arg>io.jenetics.base/io.jenetics.internal.util=de.evoal.core</arg>
<arg>--add-exports</arg>
<arg>io.jenetics.base/io.jenetics.internal.collection=de.evoal.core</arg>
<arg>--add-exports</arg>
<arg>org.eclipse.xtext.util/org.eclipse.xtext.util=de.evoal.core</arg>
</compilerArgs>
<forceJavacCompilerUse>true</forceJavacCompilerUse>
</configuration>
......
......@@ -6,28 +6,39 @@ import de.evoal.core.api.cdi.ConfigurationValue;
import javax.enterprise.context.ApplicationScoped;
import de.evoal.core.api.utils.LanguageHelper;
import de.evoal.languages.model.instance.Array;
import de.evoal.languages.model.instance.Instance;
import de.evoal.languages.model.instance.LiteralValue;
import org.apache.deltaspike.core.api.provider.BeanProvider;
import javax.inject.Inject;
import java.util.HashMap;
import java.util.Map;
@ApplicationScoped
public class CalculationFactory {
private final Instance handlerConfigurations;
private final Map<String, Instance> calculationConfigurationByCategory = new HashMap<>();
@Inject
public CalculationFactory(final @ConfigurationValue(entry = BlackboardEntry.EA_CONFIGURATION, access = "algorithm.constraint_handling") Instance handlerConfiguration) {
handlerConfigurations = handlerConfiguration;
public CalculationFactory(final @ConfigurationValue(entry = BlackboardEntry.EA_CONFIGURATION, access = "algorithm.handlers") Array handlerConfigurations) {
handlerConfigurations.getValues()
.stream()
.map(Instance.class::cast)
.filter(LanguageHelper.filterInstanceByType("constraint-handler"))
.forEach(i -> {
final String category = LanguageHelper.lookup(i, "category");
final Instance config = LanguageHelper.lookup(i, "calculation");
calculationConfigurationByCategory.put(category, config);
});
}
public CalculationStrategy create(final Constraint constraint) {
final Instance handlerConfig = LanguageHelper.lookup(handlerConfigurations, constraint.getGroup());
final Instance calculationConfig = LanguageHelper.lookup(handlerConfigurations, "calculation");
final String calculationName = LanguageHelper.lookup(calculationConfig, "name");
final Instance config = calculationConfigurationByCategory.get(constraint.getGroup());
final String calculationName = LanguageHelper.lookup(config, "name");
final CalculationStrategy strategy = BeanProvider.getContextualReference(calculationName, false, CalculationStrategy.class);
strategy.init(constraint, calculationConfig);
strategy.init(constraint, config);
return strategy;
}
......
......@@ -17,7 +17,7 @@ public interface CalculationStrategy {
* @param properties Properties of an individual to check.
* @return A non-null non-empty list of constraint handling results.
*/
public @NonNull CalculationResult calculate(final Properties properties);
public @NonNull CalculationResult calculate(final Properties genotype, final Properties fitness);
/**
* Initialises the strategy with the constraint and the calculation configuration.
......
......@@ -5,7 +5,7 @@ import de.evoal.core.api.properties.PropertySpecification;
import lombok.Data;
import java.util.List;
import java.util.function.Function;
import java.util.function.BiFunction;
/**
* A single evaluable constraint. A constraint ca be applied to an individual
......@@ -26,7 +26,7 @@ public class Constraint {
/**
* The applicable constraint function.
*/
private Function<Properties, Object> function;
private BiFunction<Properties, Properties, Object> function;
/**
* List of used properties.
......@@ -39,11 +39,11 @@ public class Constraint {
* @param properties The individual to check.
* @return The result of the constraint's evaluation.
*/
public ConstraintResult apply(final Properties properties) {
public ConstraintResult apply(final Properties genotypeProps, final Properties fitnessProps) {
final ConstraintResult result = new ConstraintResult();
result.setConstraint(this);
result.setComparisonDifference(((Number)function.apply(properties)).doubleValue());
result.setComparisonDifference(((Number)function.apply(genotypeProps, fitnessProps)).doubleValue());
result.getUsedProperties().addAll(usedProperties);
result.setType(getConstraintType());
......
......@@ -25,9 +25,9 @@ public class Constraints {
* @param properties Properties to use
* @return A non-null list of constraint results.
*/
public List<ConstraintResult> apply(final Properties properties) {
public List<ConstraintResult> apply(final Properties genotype, final Properties fitness) {
return constraints.stream()
.map(c -> c.apply(properties))
.map(c -> c.apply(genotype, fitness))
.collect(Collectors.toList());
}
}
......@@ -5,6 +5,8 @@ import de.evoal.languages.model.instance.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.function.Predicate;
/**
* Helper class for processing eal files.
*/
......@@ -77,4 +79,7 @@ public final class LanguageHelper {
return (T) current;
}
public static Predicate<? super Value> filterInstanceByType(final String instanceTypeName) {
return i -> instanceTypeName.equals(((Instance)i).getName().getName());
}
}
package de.evoal.core.main.ea.constraints.constraint;
import de.evoal.core.api.board.BlackboardEntry;
import de.evoal.core.api.cdi.ConfigurationValue;
import de.evoal.core.api.ea.constraints.model.Constraint;
import de.evoal.core.api.ea.constraints.model.Constraints;
import de.evoal.core.api.ea.codec.CustomCodec;
......@@ -7,12 +9,18 @@ import de.evoal.core.api.ea.constraints.model.DataConstraints;
import de.evoal.core.api.properties.PropertiesSpecification;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import javax.inject.Named;
import de.evoal.core.main.ea.constraints.el.ElHelper;
import de.evoal.core.main.ea.fitness.JeneticsFitnessFunction;
import de.evoal.languages.model.ddl.DataDescription;
import de.evoal.languages.model.ddl.FunctionName;
import de.evoal.languages.model.el.Call;
import de.evoal.core.main.ea.constraints.constraint.ast.ConditionConverter;
import de.evoal.languages.model.instance.Array;
import de.evoal.languages.model.instance.Attribute;
import de.evoal.languages.model.instance.DataReference;
import de.evoal.languages.model.instance.Instance;
import lombok.extern.slf4j.Slf4j;
import java.util.Objects;
......@@ -21,13 +29,16 @@ import java.util.Optional;
@ApplicationScoped
@Slf4j
public class ConstraintProducer {
private PropertiesSpecification specification;
private PropertiesSpecification fitnessSpec;
private PropertiesSpecification genoSpec;
@Produces
@ApplicationScoped
public Constraints create(final DataConstraints constraints,
final CustomCodec codec) {
this.specification = specification;
@Named("genotype-specification") final PropertiesSpecification genoSpec,
@ConfigurationValue(entry = BlackboardEntry.EA_CONFIGURATION, access = "algorithm.fitness") final Instance fitnessConfig) {
this.genoSpec = genoSpec;
this.fitnessSpec = toInnerSpecification(fitnessConfig);
final Constraints result = new Constraints();
......@@ -51,6 +62,25 @@ public class ConstraintProducer {
return result;
}
private PropertiesSpecification toInnerSpecification(final Instance fitnessConfig) {
final Attribute subFunction = fitnessConfig.findAttribute("function");
if(subFunction != null) {
return toInnerSpecification((Instance)subFunction.getValue());
}
final Attribute mapping = fitnessConfig.findAttribute("maps-to");
return PropertiesSpecification.builder()
.add(((Array)mapping.getValue())
.getValues()
.stream()
.map(DataReference.class::cast)
.map(DataReference::getDefinition)
)
.build();
}
private Optional<Constraint> convert(final Call constraint, DataDescription context) {
if(constraint.getParameters().size() != 2) {
log.error("Constraint has more than two parameters. Skipping.");
......@@ -60,7 +90,7 @@ public class ConstraintProducer {
final Constraint result = new Constraint();
result.setGroup(ElHelper.findString(constraint.getParameters().get(1)));
final ConditionConverter converter = new ConditionConverter(specification, context);
final ConditionConverter converter = new ConditionConverter(genoSpec, fitnessSpec, context);
converter.doSwitch(constraint.getParameters().get(0));
result.setFunction(converter.getFunction());
......
......@@ -15,13 +15,7 @@ import lombok.extern.slf4j.Slf4j;
import java.util.*;
@Slf4j
public class BoundaryIdentifier extends ELSwitch<Object> {
private final DataDescription context;
public BoundaryIdentifier(final DataDescription context) {
this.context = context;
}
public class BoundaryIdentifier {
public static PropertiesBoundaries run(final DataConstraints constraints) {
final Map<DataDescription, Number> lowerBounds = new HashMap<>();
......@@ -41,7 +35,7 @@ public class BoundaryIdentifier extends ELSwitch<Object> {
}
private static void processConstraint(final Expression constraint, final DataDescription context, final Map<DataDescription, Number> lowerBounds, final Map<DataDescription, Number> upperBounds) {
final BoundaryIdentifier identifier = new BoundaryIdentifier(context);
final UnaryBoundaryIdentifier identifier = new UnaryBoundaryIdentifier(context);
Object result = identifier.doSwitch(constraint);
if(result == null) {
......@@ -89,170 +83,4 @@ public class BoundaryIdentifier extends ELSwitch<Object> {
}
}
}
@Override
public Object caseOrExpression(OrExpression object) {
Requirements.requireSize(object.getSubExpressions(), 1);
return doSwitch(object.getSubExpressions().get(0));
}
@Override
public Object caseXorExpression(XorExpression object) {
Requirements.requireSize(object.getSubExpressions(), 1);
return doSwitch(object.getSubExpressions().get(0));
}
@Override
public Object caseAndExpression(final AndExpression object) {
Requirements.requireSize(object.getSubExpressions(), 1);
return doSwitch(object.getSubExpressions().get(0));
}
@Override
public Object caseNotExpression(NotExpression object) {
Requirements.requireFalse(object.isNegated());
return doSwitch(object.getOperand());
}
@Override
public Object caseComparisonExpression(final ComparisonExpression object) {
Requirements.requireSize(object.getComparison(), 1);
final Object leftValue = doSwitch(object.getLeftOperand());
final Object rightValue = doSwitch(object.getComparison().get(0).getSubExpression());
if(!((leftValue instanceof DataDescription && rightValue instanceof Number) ||
(rightValue instanceof DataDescription && leftValue instanceof Number))) {
// not a supported relation
return null;
}
switch (object.getComparison().get(0).getOperator()) {
case GREATER_EQUAL:
case GREATER_THAN: {
if(leftValue instanceof DataDescription) {
// lower
return new Object[] {rightValue, leftValue};
} else {
// upper
return new Object[] {leftValue, rightValue};
}
}
case LESS_EQUAL:
case LESS_THAN:
{
if(leftValue instanceof DataDescription) {
// upper
return new Object[] {leftValue, rightValue};
} else {
// lower
return new Object[] {rightValue, leftValue};
}
}
case EQUAL:
case UNEQUAL: {
throw new IllegalArgumentException("(Un)equal is not allowed");
}
}
return null;
}
@Override
public Object caseAddOrSubtractExpression(final AddOrSubtractExpression object) {
Requirements.requireEmpty(object.getOperators());
return doSwitch(object.getLeftOperand());
}
@Override
public Object caseMultiplyDivideModuloExpression(final MultiplyDivideModuloExpression object) {
Requirements.requireEmpty(object.getOperators());
return doSwitch(object.getLeftOperand());
}
@Override
public Object casePowerOfExpression(final PowerOfExpression object) {
Requirements.requireNull(object.getRightOperand());
return doSwitch(object.getLeftOperand());
}
@Override
public Object caseUnaryAddOrSubtractExpression(UnaryAddOrSubtractExpression object) {
Object value = doSwitch(object.getSubExpression());
for(final AddOrSubtractOperator operator : object.getOperators()) {
switch (operator) {
case ADD: {
value = value;
break;
}
case SUBTRACT: {
if(value instanceof Double) {
value = -(Double)value;
} else if(value instanceof Integer) {
value = -(Integer)value;
} else {
throw new IllegalStateException("Unsupported");
}
break;
}
}
}
return value;
}
@Override
public Object caseIntegerLiteral(final IntegerLiteral object) {
return object.getValue();
}
@Override
public Object caseDoubleLiteral(final DoubleLiteral object) {
return object.getValue();
}
@Override
public Object caseStringLiteral(final StringLiteral object) {
return null;
}
@Override
public Object caseValueReference(final ValueReference object) {
if(object instanceof SelfReference) {
Requirements.requireNotNull(context);
return context;
}
if(!(object instanceof DataReference)) {
throw new IllegalStateException("Value reference is not a data reference: " + object.eClass());
}
final DataReference reference = (DataReference)object;
return reference.getDefinition();
}
@Override
public Object caseBooleanLiteral(final BooleanLiteral object) {
return null;
}
@Override
public Object caseCall(Call object) {
return null;
}
@Override
public Object caseParantheses(final Parantheses object) {
return doSwitch(object.getSubExpression());
}
}
......@@ -16,17 +16,19 @@ import de.evoal.languages.model.el.util.ELSwitch;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.function.BiFunction;
public class ConditionConverter extends ELSwitch<Object> {
private Function<Properties, Object> function;
private BiFunction<Properties, Properties, Object> function;
private final List<PropertySpecification> usedProperties = new ArrayList<>();
private final PropertiesSpecification specification;
private final PropertiesSpecification genoSpec;
private final PropertiesSpecification fitnessSpec;
private final DataDescription context;
private ConstraintType type;
public ConditionConverter(final PropertiesSpecification specification, final DataDescription context) {
this.specification = specification;
public ConditionConverter(final PropertiesSpecification genoSpec, final PropertiesSpecification fitnessSpec, final DataDescription context) {
this.genoSpec = genoSpec;
this.fitnessSpec = fitnessSpec;
this.context = context;
}
......@@ -70,20 +72,20 @@ public class ConditionConverter extends ELSwitch<Object> {
public Object caseComparisonExpression(ComparisonExpression object) {
Requirements.requireSize(object.getComparison(), 1);
final Function<Properties, Object> leftValue = (Function<Properties, Object>) doSwitch(object.getLeftOperand());
final Function<Properties, Object> rightValue = (Function<Properties, Object>) doSwitch(object.getComparison().get(0).getSubExpression());
final BiFunction<Properties, Properties, Object> leftValue = (BiFunction<Properties, Properties, Object>) doSwitch(object.getLeftOperand());
final BiFunction<Properties, Properties, Object> rightValue = (BiFunction<Properties, Properties, Object>) doSwitch(object.getComparison().get(0).getSubExpression());
switch (object.getComparison().get(0).getOperator()) {
case EQUAL:
case GREATER_EQUAL:
case GREATER_THAN: {
function = properties -> minus(leftValue.apply(properties), rightValue.apply(properties));
function = (gen, fit) -> minus(leftValue.apply(gen, fit), rightValue.apply(gen, fit));
break;
}
case LESS_EQUAL:
case LESS_THAN:
{
function = properties -> minus(rightValue.apply(properties), leftValue.apply(properties));
function = (gen, fit) -> minus(rightValue.apply(gen, fit), leftValue.apply(gen, fit));
break;
}
case UNEQUAL: {
......@@ -114,22 +116,22 @@ public class ConditionConverter extends ELSwitch<Object> {
@Override
public Object caseAddOrSubtractExpression(final AddOrSubtractExpression object) {
Function<Properties, Object> value = (Function<Properties, Object>) doSwitch(object.getLeftOperand());
BiFunction<Properties, Properties, Object> value = (BiFunction<Properties, Properties, Object>) doSwitch(object.getLeftOperand());
for(int i = 0; i < object.getOperators().size(); ++i) {
final AddOrSubtractOperator operator = object.getOperators().get(i);
final Function<Properties, Object> rOp = (Function<Properties, Object>) doSwitch(object.getOperands().get(i));
final BiFunction<Properties, Properties, Object> rOp = (BiFunction<Properties, Properties, Object>) doSwitch(object.getOperands().get(i));
switch (operator) {
case ADD: {
final Function<Properties, Object> lOp = value;
value = properties -> add(lOp.apply(properties), rOp.apply(properties));
final BiFunction<Properties, Properties, Object> lOp = value;
value = (gen, fit) -> add(lOp.apply(gen, fit), rOp.apply(gen, fit));
break;
}
case SUBTRACT: {
final Function<Properties, Object> lOp = value;
value = properties -> minus(lOp.apply(properties), rOp.apply(properties));
final BiFunction<Properties, Properties, Object> lOp = value;
value = (gen, fit) -> minus(lOp.apply(gen, fit), rOp.apply(gen, fit));
break;
}
}
......@@ -139,28 +141,28 @@ public class ConditionConverter extends ELSwitch<Object> {
@Override
public Object caseMultiplyDivideModuloExpression(MultiplyDivideModuloExpression object) {
Function<Properties, Object> value = (Function<Properties, Object>) doSwitch(object.getLeftOperand());
BiFunction<Properties, Properties, Object> value = (BiFunction<Properties, Properties, Object>) doSwitch(object.getLeftOperand());
for(int i = 0; i < object.getOperators().size(); ++i) {
final MultiplyDivideModuloOperator operator = object.getOperators().get(i);
final Function<Properties, Object> rOp = (Function<Properties, Object>) doSwitch(object.getOperands().get(i));
final BiFunction<Properties, Properties, Object> rOp = (BiFunction<Properties, Properties, Object>) doSwitch(object.getOperands().get(i));
switch (operator) {
case DIVIDE: {
final Function<Properties, Object> lOp = value;
value = properties -> divide(lOp.apply(properties), rOp.apply(properties));
final BiFunction<Properties, Properties, Object> lOp = value;
value = (gen, fit) -> divide(lOp.apply(gen, fit), rOp.apply(gen, fit));
break;
}
case MODULO: {
final Function<Properties, Object> lOp = value;
value = properties -> modulo(lOp.apply(properties), rOp.apply(properties));
final BiFunction<Properties, Properties, Object> lOp = value;
value = (gen, fit) -> modulo(lOp.apply(gen, fit), rOp.apply(gen, fit));
break;
}
case MULTIPLY: {
final Function<Properties, Object> lOp = value;
value = properties -> multiply(lOp.apply(properties), rOp.apply(properties));
final BiFunction<Properties, Properties, Object> lOp = value;
value = (gen, fit) -> multiply(lOp.apply(gen, fit), rOp.apply(gen, fit));
break;
}
}
......@@ -170,20 +172,20 @@ public class ConditionConverter extends ELSwitch<Object> {
@Override
public Object casePowerOfExpression(PowerOfExpression object) {
Function<Properties, Object> value = (Function<Properties, Object>) doSwitch(object.getLeftOperand());
BiFunction<Properties, Properties, Object> value = (BiFunction<Properties, Properties, Object>) doSwitch(object.getLeftOperand());
if(object.getRightOperand() != null) {
final Function<Properties, Object> lOp = value;
final Function<Properties, Object> rOp = (Function<Properties, Object>) doSwitch(object.getRightOperand());
final BiFunction<Properties, Properties, Object> lOp = value;
final BiFunction<Properties, Properties, Object> rOp = (BiFunction<Properties, Properties, Object>) doSwitch(object.getRightOperand());
value = properties -> pow(lOp.apply(properties), rOp.apply(properties));
value = (gen, fit) -> pow(lOp.apply(gen, fit), rOp.apply(gen, fit));
}
return value;
}
@Override
public Object caseUnaryAddOrSubtractExpression(UnaryAddOrSubtractExpression object) {
Function<Properties, Object> value = (Function<Properties, Object>) doSwitch(object.getSubExpression());
BiFunction<Properties, Properties, Object> value = (BiFunction<Properties, Properties, Object>) doSwitch(object.getSubExpression());
for(final AddOrSubtractOperator operator : object.getOperators()) {
switch (operator) {
......@@ -193,8 +195,8 @@ public class ConditionConverter extends ELSwitch<Object> {
}
case SUBTRACT: {
final Function<Properties, Object> lOp = value;
value = properties -> minus(0, lOp.apply(properties));
final BiFunction<Properties, Properties, Object> lOp = value;
value = (gen, fit) -> minus(0, lOp.apply(gen, fit));
break;
}
}
......@@ -203,17 +205,17 @@ public class ConditionConverter extends ELSwitch<Object> {
@Override
public Object caseIntegerLiteral(final IntegerLiteral object) {
return (Function<Properties, Object>) properties -> (double)object.getValue();
return (BiFunction<Properties, Properties, Object>) (gen, fit) -> (double)object.getValue();
}
@Override
public Object caseDoubleLiteral(final DoubleLiteral object) {
return (Function<Properties, Object>) properties -> object.getValue();
return (BiFunction<Properties, Properties, Object>) (gen, fit) -> object.getValue();
}
@Override
public Object caseStringLiteral(final StringLiteral object) {
return (Function<Properties, Object>) properties -> Double.parseDouble(object.getValue());
return (BiFunction<Properties, Properties, Object>) (gen, fit) -> Double.parseDouble(object.getValue());
}
@Override
......@@ -221,24 +223,45 @@ public class ConditionConverter extends ELSwitch<Object> {
if(object instanceof SelfReference) {
Requirements.requireNotNull(context);
final String propertyName = context.getName();
final int propertyIndex = specification.indexOf(propertyName);
if(fitnessSpec.contains(new PropertySpecification(context.getName(), context))) {
final int propertyIndex = fitnessSpec.indexOf(propertyName);
usedProperties.add(specification.getProperties().get(propertyIndex));
usedProperties.add(fitnessSpec.getProperties().get(propertyIndex));
return (Function<Properties, Object>) properties -> properties.get(propertyIndex);
return (BiFunction<Properties, Properties, Object>) (gen, fit) -> fit.get(propertyIndex);
} else {
final int propertyIndex = genoSpec.indexOf(propertyName);
usedProperties.add(genoSpec.getProperties().get(propertyIndex));
return (BiFunction<Properties, Properties, Object>) (gen, fit) -> gen.get(propertyIndex);
}
}
if(!(object instanceof DataReference)) {
throw new IllegalStateException("Value reference is not a data reference.");
}
final DataReference reference = (DataReference)object;
final String propertyName = reference.getDefinition().getName();
final int propertyIndex = specification.indexOf(propertyName);
final DataReference reference = (DataReference) object;
final DataDescription description = reference.getDefinition();
if(fitnessSpec.contains(new PropertySpecification(description.getName(), description))) {
final String propertyName = description.getName();
final int propertyIndex = fitnessSpec.indexOf(propertyName);
usedProperties.add(specification.getProperties().get(propertyIndex));
usedProperties.add(fitnessSpec.getProperties().get(propertyIndex));
return (Function<Properties, Object>) properties -> properties.get(propertyIndex);
return (BiFunction<Properties, Properties, Object>) (gen, fit) -> fit.get(propertyIndex);
} else {
final String propertyName = description.getName();
final int propertyIndex = genoSpec.indexOf(propertyName);
usedProperties.add(genoSpec.getProperties().get(propertyIndex));
return (BiFunction<Properties, Properties, Object>) (gen, fit) -> gen.get(propertyIndex);
}
}
@Override
......@@ -256,7 +279,7 @@ public class ConditionConverter extends ELSwitch<Object> {
return doSwitch(object.getSubExpression());
}
public Function<Properties, Object> getFunction() {
public BiFunction<Properties, Properties, Object> getFunction() {
return function;
}
......
package de.evoal.core.main.ea.constraints.constraint.ast;
import de.evoal.core.api.ea.constraints.model.DataConstraints;
import de.evoal.core.api.properties.PropertySpecification;
import de.evoal.core.api.properties.info.PropertiesBoundaries;
import de.evoal.core.api.utils.Requirements;
import de.evoal.languages.model.ddl.DataDescription;
import de.evoal.languages.model.ddl.DataReference;
import de.evoal.languages.model.ddl.RepresentationType;
import de.evoal.languages.model.ddl.SelfReference;
import de.evoal.languages.model.el.*;
import de.evoal.languages.model.el.util.ELSwitch;
import lombok.extern.slf4j.Slf4j;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class UnaryBoundaryIdentifier extends ELSwitch<Object> {
private final DataDescription context;
public UnaryBoundaryIdentifier(final DataDescription context) {
this.context = context;
}
@Override
public Object caseOrExpression(OrExpression object) {
Requirements.requireSize(object.getSubExpressions(), 1);
return doSwitch(object.getSubExpressions().get(0));
}
@Override
public Object caseXorExpression(XorExpression object) {
Requirements.requireSize(object.getSubExpressions(), 1);
return doSwitch(object.getSubExpressions().get(0));
}
@Override
public Object caseAndExpression(final AndExpression object) {
Requirements.requireSize(object.getSubExpressions(), 1);
return doSwitch(object.getSubExpressions().get(0));
}
@Override
public Object caseNotExpression(NotExpression object) {
Requirements.requireFalse(object.isNegated());
return doSwitch(object.getOperand());
}
@Override
public Object caseComparisonExpression(final ComparisonExpression object) {
if(object.getComparison().isEmpty()) {
return null;
}
Requirements.requireSize(object.getComparison(), 1);
final Object leftValue = doSwitch(object.getLeftOperand());
final Object rightValue = doSwitch(object.getComparison().get(0).getSubExpression());
if(!((leftValue instanceof DataDescription && rightValue instanceof Number) ||
(rightValue instanceof DataDescription && leftValue instanceof Number))) {
// not a supported relation
return null;
}
switch (object.getComparison().get(0).getOperator()) {
case GREATER_EQUAL:
case GREATER_THAN: {
if(leftValue instanceof DataDescription) {
// lower
return new Object[] {rightValue, leftValue};
} else {
// upper
return new Object[] {leftValue, rightValue};
}
}
case LESS_EQUAL:
case LESS_THAN:
{
if(leftValue instanceof DataDescription) {
// upper
return new Object[] {leftValue, rightValue};
} else {
// lower
return new Object[] {rightValue, leftValue};
}
}
case EQUAL:
case UNEQUAL: {
throw new IllegalArgumentException("(Un)equal is not allowed");
}
}
return null;
}
@Override
public Object caseAddOrSubtractExpression(final AddOrSubtractExpression object) {
Requirements.requireEmpty(object.getOperators());
return doSwitch(object.getLeftOperand());
}
@Override
public Object caseMultiplyDivideModuloExpression(final MultiplyDivideModuloExpression object) {
Requirements.requireEmpty(object.getOperators());
return doSwitch(object.getLeftOperand());
}
@Override
public Object casePowerOfExpression(final PowerOfExpression object) {
Requirements.requireNull(object.getRightOperand());
return doSwitch(object.getLeftOperand());
}
@Override
public Object caseUnaryAddOrSubtractExpression(UnaryAddOrSubtractExpression object) {
Object value = doSwitch(object.getSubExpression());
for(final AddOrSubtractOperator operator : object.getOperators()) {
switch (operator) {
case ADD: {
value = value;
break;
}
case SUBTRACT: {
if(value instanceof Double) {
value = -(Double)value;
} else if(value instanceof Integer) {
value = -(Integer)value;
} else {
throw new IllegalStateException("Unsupported");
}
break;
}
}
}
return value;
}
@Override
public Object caseIntegerLiteral(final IntegerLiteral object) {
return object.getValue();
}
@Override
public Object caseDoubleLiteral(final DoubleLiteral object) {
return object.getValue();
}
@Override
public Object caseStringLiteral(final StringLiteral object) {
return null;
}
@Override
public Object caseValueReference(final ValueReference object) {
if(object instanceof SelfReference) {
Requirements.requireNotNull(context);
return context;
}
if(!(object instanceof DataReference)) {
throw new IllegalStateException("Value reference is not a data reference: " + object.eClass());
}
final DataReference reference = (DataReference)object;
return reference.getDefinition();
}
@Override
public Object caseBooleanLiteral(final BooleanLiteral object) {
return null;
}
@Override
public Object caseCall(Call object) {
return null;
}
@Override
public Object caseParantheses(final Parantheses object) {
return doSwitch(object.getSubExpression());
}
}
......@@ -18,8 +18,8 @@ public class NormalCalculation implements CalculationStrategy {
private Constraint constraint;
@Override
public @NonNull CalculationResult calculate(final Properties properties) {
return new CalculationResult(constraint.apply(properties));
public @NonNull CalculationResult calculate(final Properties genotype, final Properties fitness) {
return new CalculationResult(constraint.apply(genotype, fitness));
}
@Override
......
......@@ -39,13 +39,14 @@ public class StandardDeviationCalculation implements CalculationStrategy {
private List<Pair<Integer, Double>> allowedDeviations;
@Override
public @NonNull CalculationResult calculate(final Properties properties) {
return new CalculationResult(calculateMinimalDifference(0, new HashMap<>(), properties));
public @NonNull CalculationResult calculate(final Properties genotype, final Properties fitness) {
return new CalculationResult(calculateMinimalDifference(0, new HashMap<>(), genotype, fitness));
}
private ConstraintResult calculateMinimalDifference(final int index, final Map<Integer, Double> differences, final Properties properties) {
// TODO Adapt fitness
private ConstraintResult calculateMinimalDifference(final int index, final Map<Integer, Double> differences, final Properties genotype, final Properties fitness) {
if(index == allowedDeviations.size()) {
final Properties adaptedProperties = new Properties(properties);
final Properties adaptedProperties = new Properties(genotype);
for(final Map.Entry<Integer, Double> entry : differences.entrySet()) {
final Integer propIndex = entry.getKey();
......@@ -53,14 +54,14 @@ public class StandardDeviationCalculation implements CalculationStrategy {
adaptedProperties.put(propIndex, value);
}
return constraint.apply(adaptedProperties);
return constraint.apply(adaptedProperties, fitness);
}
final Pair<Integer, Double> deviation = allowedDeviations.get(index);
// no deviation
differences.put(deviation.getFirst(), 0.0);
ConstraintResult minimalResult = calculateMinimalDifference(index + 1, differences, properties);
ConstraintResult minimalResult = calculateMinimalDifference(index + 1, differences, genotype, fitness);
if(CalculationResult.isSuccessful(minimalResult) || deviation.getSecond() == 0.0) {
return minimalResult;
......@@ -69,7 +70,7 @@ public class StandardDeviationCalculation implements CalculationStrategy {
// - deviation
{
differences.put(deviation.getFirst(), -deviation.getSecond() * factor);
ConstraintResult result = calculateMinimalDifference(index + 1, differences, properties);
ConstraintResult result = calculateMinimalDifference(index + 1, differences, genotype, fitness);
if(CalculationResult.isSuccessful(result)) {
return result;
......@@ -81,7 +82,7 @@ public class StandardDeviationCalculation implements CalculationStrategy {
// + deviation
{
differences.put(deviation.getFirst(), deviation.getSecond() * factor);
ConstraintResult result = calculateMinimalDifference(index + 1, differences, properties);
ConstraintResult result = calculateMinimalDifference(index + 1, differences, genotype, fitness);
if(CalculationResult.isSuccessful(result)) {
return result;
......
package de.evoal.core.main.ea.constraints.constraint.strategies.constraint;
import de.evoal.core.api.cdi.BeanFactory;
import de.evoal.core.api.ea.constraints.model.Constraint;
import de.evoal.core.api.ea.constraints.model.Constraints;
import de.evoal.core.api.ea.constraints.calculation.CalculationFactory;
import de.evoal.core.api.board.BlackboardEntry;
import de.evoal.core.api.cdi.ConfigurationValue;
import de.evoal.core.api.ea.codec.CustomCodec;
import de.evoal.core.api.ea.fitness.FitnessFunction;
import de.evoal.core.api.properties.PropertiesSpecification;
import de.evoal.core.main.ea.constraints.constraint.utils.ConfigurationUtils;
import de.evoal.languages.model.instance.Attribute;
import de.evoal.languages.model.instance.Instance;
import de.evoal.languages.model.instance.Misc;
import de.evoal.languages.model.instance.*;
import org.apache.deltaspike.core.api.provider.BeanProvider;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
......@@ -21,22 +23,56 @@ import java.util.stream.Collectors;
public class JeneticsConstraintProducer {
@Produces
public List<io.jenetics.engine.Constraint> create(
final @ConfigurationValue(entry = BlackboardEntry.EA_CONFIGURATION, access = "algorithm.handling") Instance handlerConfiguration,
final @ConfigurationValue(entry = BlackboardEntry.EA_CONFIGURATION, access = "algorithm.handlers") Array handlerConfigurations,
final @ConfigurationValue(entry = BlackboardEntry.EA_CONFIGURATION, access = "algorithm.fitness") Instance fitnessConfiguration,
final Constraints constraints,
final CustomCodec codec,
final CalculationFactory factory) {
// collect group information to handle
final List<Attribute> groups = ConfigurationUtils.findByHandlerName(handlerConfiguration, "killAtBirth");
final Set<String> allGroups = groups.stream().map(e -> ((Misc)e.getName()).getName()).collect(Collectors.toSet());
final List<Instance> groups = ConfigurationUtils.findConstraintHandlerByHandlingStrategy(handlerConfigurations, "kill-at-birth");
final Set<String> allGroups = groups.stream().map(i -> (String)((LiteralValue)i.findAttribute("category").getValue()).getLiteral().getValue()).collect(Collectors.toSet());
final List<Constraint> listOfConstraints = constraints.getConstraints();
final FitnessFunction function = create(fitnessConfiguration);
final PropertiesSpecification fitnessSpec = toSpecification(fitnessConfiguration);
final List<io.jenetics.engine.Constraint> result = listOfConstraints
.stream()
.filter(c -> allGroups.contains(c.getGroup()))
.map(factory::create)
.map(s -> new JeneticsConstraintStrategy(s, codec, new RandomGenotypeStrategy()))
.map(s -> new JeneticsConstraintStrategy(s, codec, function, fitnessSpec, new RandomGenotypeStrategy()))
.collect(Collectors.toList());
return result;
}
private PropertiesSpecification toSpecification(final Instance fitnessConfiguration) {
return PropertiesSpecification.builder()
.add(((Array)findInner(fitnessConfiguration).findAttribute("maps-to").getValue())
.getValues()
.stream()
.map(DataReference.class::cast)
.map(DataReference::getDefinition)
)
.build();
}
private FitnessFunction create(Instance fitnessConfig) {
fitnessConfig = findInner(fitnessConfig);
final String fitnessName = fitnessConfig.getName().getName();
return BeanProvider.getContextualReference(fitnessName, false, FitnessFunction.class)
.init(fitnessConfig);
}
private Instance findInner(final Instance fitnessConfig) {
final Attribute subFunction = fitnessConfig.findAttribute("function");
if(subFunction != null) {
return findInner((Instance)subFunction.getValue());
}
return fitnessConfig;
}
}
......@@ -3,7 +3,9 @@ package de.evoal.core.main.ea.constraints.constraint.strategies.constraint;
import de.evoal.core.api.ea.constraints.calculation.CalculationStrategy;
import de.evoal.core.api.ea.constraints.strategies.HandlingStrategy;
import de.evoal.core.api.ea.codec.CustomCodec;
import de.evoal.core.api.ea.fitness.FitnessFunction;
import de.evoal.core.api.properties.Properties;
import de.evoal.core.api.properties.PropertiesSpecification;
import io.jenetics.Gene;
import io.jenetics.Phenotype;
......@@ -14,19 +16,25 @@ public class JeneticsConstraintStrategy<
private final CalculationStrategy calculation;
private final CustomCodec<G> codec;
private final FitnessFunction function;
private final PropertiesSpecification fitnessSpec;
private final RepairStrategy repair;
public JeneticsConstraintStrategy(final CalculationStrategy calculation, final CustomCodec<G> codec, final RepairStrategy repair) {
public JeneticsConstraintStrategy(final CalculationStrategy calculation, final CustomCodec<G> codec, final FitnessFunction function, final PropertiesSpecification fitnessSpec, final RepairStrategy repair) {
this.calculation = calculation;
this.codec = codec;
this.function = function;
this.fitnessSpec = fitnessSpec;
this.repair = repair;
}
@Override
public boolean test(final Phenotype<G, C> individual) {
final Properties properties = codec.decode(individual.genotype());
final Properties genotype = codec.decode(individual.genotype());
final double [] calculated = function.evaluate(genotype);
final Properties fitness = new Properties(fitnessSpec, calculated);
return calculation.calculate(properties).isSuccessful();
return calculation.calculate(genotype, fitness).isSuccessful();
}
@Override
......
......@@ -17,6 +17,7 @@ import javax.enterprise.inject.Produces;
import de.evoal.core.main.ea.constraints.constraint.strategies.fitness.internal.MalusForFitnessFunction;
import de.evoal.core.main.ea.constraints.constraint.utils.ConfigurationUtils;
import de.evoal.languages.model.instance.Array;
import de.evoal.languages.model.instance.Attribute;
import de.evoal.languages.model.instance.Instance;
import de.evoal.languages.model.instance.Misc;
......@@ -29,7 +30,7 @@ import java.util.*;
public class MalusFunctionProducer {
@ApplicationScoped @Produces
public MalusForFitnessStrategy create(
final @ConfigurationValue(entry = BlackboardEntry.EA_CONFIGURATION, access = "algorithm.constraint_handling") Instance handlerConfiguration,
final @ConfigurationValue(entry = BlackboardEntry.EA_CONFIGURATION, access = "algorithm.handlers") Array handlers,
final Constraints constraints,
final @Named("genotype-specification") PropertiesSpecification source,
final @Named("output-dependencies") PropertiesDependencies dependencies,
......@@ -38,10 +39,10 @@ public class MalusFunctionProducer {
final MalusForFitnessStrategy resultingFunction = new MalusForFitnessStrategy(target.size());
// collect group information to handle
final List<Attribute> groups = ConfigurationUtils.findByHandlerName(handlerConfiguration, "malusForFitness");
final List<Instance> groups = ConfigurationUtils.findConstraintHandlerByHandlingStrategy(handlers, "malus-for-fitness");
// collect all constraints for each index (of the appropriate groups)
final List<List<Pair<Constraint, Attribute>>> constraintsForIndex = new ArrayList<>(source.size());
final List<List<Pair<Constraint, Instance>>> constraintsForIndex = new ArrayList<>(source.size());
for(int index = 0; index < source.size(); ++index) {
constraintsForIndex.add(new ArrayList<>());
}
......@@ -49,7 +50,7 @@ public class MalusFunctionProducer {
for(final Constraint constraint : constraints.getConstraints()) {
final String group = constraint.getGroup();
for(final Attribute info : groups) {
for(final Instance info : groups) {
if(((Misc)info.getName()).getName().equals(group)) {
for(final PropertySpecification ps : constraint.getUsedProperties()) {
final int index = source.indexOf(ps);
......@@ -66,9 +67,9 @@ public class MalusFunctionProducer {
for(final PropertySpecification ips : dependencies.get(target.getProperties().get(index))) {
final int ipsIndex = source.indexOf(ips);
for(final Pair<Constraint, Attribute> pair : constraintsForIndex.get(ipsIndex)) {
for(final Pair<Constraint, Instance> pair : constraintsForIndex.get(ipsIndex)) {
final Constraint constraint = pair.getFirst();
final Attribute configuration = pair.getSecond();
final Instance configuration = pair.getSecond();
// prevent constraints from being applied multiple times per fitness value
if(applied.contains(constraint)) {
......@@ -78,9 +79,9 @@ public class MalusFunctionProducer {
final CalculationStrategy calculation = factory.create(constraint);
final String handlerName = LanguageHelper.lookup((Instance) configuration.getValue(), "name");
final String handlerName = LanguageHelper.lookup(configuration, "name");
final MalusFunction strategy = new MalusForFitnessFunction(constraint, LanguageHelper.lookup((Instance)configuration.getValue(), "handling"), index) ;
final MalusFunction strategy = new MalusForFitnessFunction(constraint, LanguageHelper.lookup(configuration, "handling"), index) ;
resultingFunction.add(index, strategy);
}
}
......
......@@ -18,8 +18,9 @@ public class MalusForFitnessFunction implements MalusFunction {
@Override
public double apply(final Properties properties, double fitnessValue) {
final ConstraintResult result = constraint.apply(properties);
// final ConstraintResult result = constraint.apply(properties);
return fitnessValue - smoothing * Math.abs(result.getComparisonDifference());
throw new IllegalStateException("Not yet implemented");
// return fitnessValue - smoothing * Math.abs(result.getComparisonDifference());
}
}
package de.evoal.core.main.ea.constraints.constraint.utils;
import de.evoal.core.api.utils.LanguageHelper;
import de.evoal.languages.model.instance.Array;
import de.evoal.languages.model.instance.Attribute;
import de.evoal.languages.model.instance.Instance;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public final class ConfigurationUtils {
private ConfigurationUtils() {
}
public static List<Attribute> findByHandlerName(final Instance configuration, final String name) {
final List<Attribute> result = new ArrayList<>();
for(final Attribute attribute : configuration.getAttributes()) {
final Instance handlerConfiguration = LanguageHelper.lookup((Instance)attribute.getValue(), "handling");
final String handlerName = LanguageHelper.lookup(handlerConfiguration, "name");
if(name.equals(handlerName)) {
result.add(attribute);
}
}
return result;
public static List<Instance> findConstraintHandlerByHandlingStrategy(final Array handlers, final String name) {
return handlers.getValues()
.stream()
.map(Instance.class::cast)
.filter(i -> "constraint-handler".equals(i.getName().getName()))
.filter(i -> name.equals(((Instance)i.findAttribute("constraint-handling").getValue()).getName().getName()))
.collect(Collectors.toList());
}
}
......@@ -16,6 +16,7 @@ import de.evoal.languages.model.eal.impl.EALPackageImpl;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.resource.XtextResourceSet;
......@@ -61,6 +62,9 @@ public class EvolutionaryAlgorithmModelLoader {
final Resource resource = resourceSet.getResource(modelURI, true);
resource.load(resourceSet.getLoadOptions());
resourceSet.getResources()
.forEach(EcoreUtil::resolveAll);
if(!resource.getErrors().isEmpty()) {
for(Resource.Diagnostic diagnostic : resource.getErrors()) {
log.error("Error while processing rule '{}': {}", configurationFile, diagnostic);
......@@ -72,6 +76,10 @@ public class EvolutionaryAlgorithmModelLoader {
}
}
if(!resource.getErrors().isEmpty()) {
throw new IllegalArgumentException("EAL file contains errors. Please fix the file.");
}
model = (EAModel) resource.getContents().get(0);
board.bind(BlackboardEntry.EA_CONFIGURATION, model);
} catch (final Exception e) {
......
......@@ -94,7 +94,8 @@ public class ConstraintStatistics implements StatisticsWriter {
population.stream()
.map(Phenotype::genotype)
.map(g -> (Properties)codec.decode(g))
.map(strategy::calculate)
// TODO .map(strategy::calculate)
.map(CalculationResult.class::cast)
.collect(Collectors.toList());
final long invalid = calculationResults
......
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