diff --git a/src/main/java/de/vill/conversion/ConvertFeatureCardinality.java b/src/main/java/de/vill/conversion/ConvertFeatureCardinality.java index dae088e..d89d062 100644 --- a/src/main/java/de/vill/conversion/ConvertFeatureCardinality.java +++ b/src/main/java/de/vill/conversion/ConvertFeatureCardinality.java @@ -1,10 +1,9 @@ package de.vill.conversion; import de.vill.model.*; -import de.vill.model.constraint.Constraint; -import de.vill.model.constraint.ImplicationConstraint; -import de.vill.model.constraint.LiteralConstraint; -import de.vill.model.constraint.ParenthesisConstraint; +import de.vill.model.constraint.*; +import de.vill.model.expression.Expression; +import de.vill.model.expression.LiteralExpression; import java.util.*; @@ -52,6 +51,7 @@ private void removeFeatureCardinality(Feature feature, FeatureModel featureModel for (int i = min; i <= max; i++) { Feature newChild = new Feature(feature.getFeatureName() + "-" + i); + featureModel.getFeatureMap().put(newChild.getFeatureName(), newChild); newChild.getAttributes().put("abstract", new Attribute("abstract", true, feature)); newChildren.getFeatures().add(newChild); newChild.setParentGroup(newChildren); @@ -62,7 +62,9 @@ private void removeFeatureCardinality(Feature feature, FeatureModel featureModel } for (int j = 1; j <= i; j++) { Feature subTreeClone = feature.clone(); - addPrefixToNamesRecursively(subTreeClone, "-" + i + "-" + j); + subTreeClone.getAttributes().clear(); + subTreeClone.getAttributes().put("abstract", new Attribute("abstract", true, subTreeClone)); + addPrefixToNamesRecursively(subTreeClone, "-" + i + "-" + j, featureModel); mandatoryGroup.getFeatures().add(subTreeClone); subTreeClone.setParentGroup(mandatoryGroup); @@ -71,22 +73,35 @@ private void removeFeatureCardinality(Feature feature, FeatureModel featureModel constraintReplacementMap.remove(feature.getFeatureName()); for (Constraint constraint : constraintsToClone) { Constraint newConstraint = constraint.clone(); + if (newConstraint instanceof LiteralConstraint) { + String toReplace = ((LiteralConstraint) newConstraint).getReference().getIdentifier(); + if (constraintReplacementMap.containsKey(toReplace)) { + LiteralConstraint newLiteral = new LiteralConstraint(constraintReplacementMap.get(toReplace)); + LiteralConstraint subTreeRootConstraint = new LiteralConstraint(newChild); + newConstraint = new ImplicationConstraint(subTreeRootConstraint, new ParenthesisConstraint(newLiteral)); + } + } else { + adaptConstraint(subTreeClone, newConstraint, constraintReplacementMap); + LiteralConstraint subTreeRootConstraint = new LiteralConstraint(newChild); + newConstraint = new ImplicationConstraint(subTreeRootConstraint, new ParenthesisConstraint(newConstraint)); + } featureModel.getOwnConstraints().add(newConstraint); - adaptConstraint(subTreeClone, newConstraint, constraintReplacementMap); } } } + feature.getChildren().removeAll(feature.getChildren()); feature.getChildren().add(newChildren); newChildren.setParentFeature(feature); } - private void addPrefixToNamesRecursively(Feature feature, String prefix) { + private void addPrefixToNamesRecursively(Feature feature, String prefix, FeatureModel featureModel) { feature.setFeatureName(feature.getFeatureName() + prefix); + featureModel.getFeatureMap().put(feature.getFeatureName(), feature); if (!feature.isSubmodelRoot()) { for (Group group : feature.getChildren()) { for (Feature subFeature : group.getFeatures()) { - addPrefixToNamesRecursively(subFeature, prefix); + addPrefixToNamesRecursively(subFeature, prefix, featureModel); } } } @@ -118,14 +133,46 @@ private List getFeatureFromSubTree(Group group) { private boolean constraintContains(Constraint constraint, List subTreeFeatures) { List subParts = constraint.getConstraintSubParts(); + if (constraint instanceof LiteralConstraint && ((LiteralConstraint) constraint).getReference() instanceof Feature) { + Feature feature = (Feature) ((LiteralConstraint) constraint).getReference(); + if (subTreeFeatures.contains(feature)) { + return true; + } + } else if (constraint instanceof ExpressionConstraint) { + Expression left = ((ExpressionConstraint) constraint).getLeft(); + Expression right = ((ExpressionConstraint) constraint).getRight(); + return expressionContains(left, subTreeFeatures) || expressionContains(right, subTreeFeatures); + } + for (Constraint subPart : subParts) { if (subPart instanceof LiteralConstraint && ((LiteralConstraint) subPart).getReference() instanceof Feature) { Feature feature = (Feature) ((LiteralConstraint) subPart).getReference(); if (subTreeFeatures.contains(feature)) { return true; } - } else { - constraintContains(subPart, subTreeFeatures); + } else if (constraintContains(subPart, subTreeFeatures)) { + return true; + } + } + return false; + } + + private boolean expressionContains(Expression expression, List subTreeFeatures) { + if (expression instanceof LiteralExpression) { + Feature feature = (Feature) ((Attribute) ((LiteralExpression) expression).getContent()).getFeature(); + if (subTreeFeatures.contains(feature)) { + return true; + } + } + + for (Expression subExpression : expression.getExpressionSubParts()) { + if (expression instanceof LiteralExpression) { + Feature feature = (Feature) ((LiteralExpression) expression).getContent(); + if (subTreeFeatures.contains(feature)) { + return true; + } + } else if (expressionContains(subExpression, subTreeFeatures)) { + return true; } } return false; @@ -144,17 +191,38 @@ private void createFeatureReplacementMap(Feature oldSubTree, Feature newSubTree, } private void adaptConstraint(Feature subTreeRoot, Constraint constraint, Map featureReplacementMap) { - List subParts = constraint.getConstraintSubParts(); - for (Constraint subPart : subParts) { - if (subPart instanceof LiteralConstraint) { - String toReplace = ((LiteralConstraint) subPart).getReference().getIdentifier(); - if (featureReplacementMap.containsKey(toReplace)) { - LiteralConstraint subTreeRootConstraint = new LiteralConstraint(subTreeRoot); - LiteralConstraint newLiteral = new LiteralConstraint(featureReplacementMap.get(toReplace)); - constraint.replaceConstraintSubPart(subPart, new ParenthesisConstraint(new ImplicationConstraint(subTreeRootConstraint, newLiteral))); + if (constraint instanceof ExpressionConstraint) { + adaptExpression(((ExpressionConstraint) constraint).getLeft(), featureReplacementMap); + adaptExpression(((ExpressionConstraint) constraint).getRight(), featureReplacementMap); + } else { + List subParts = constraint.getConstraintSubParts(); + for (Constraint subPart : subParts) { + if (subPart instanceof LiteralConstraint) { + String toReplace = ((LiteralConstraint) subPart).getReference().getIdentifier(); + if (featureReplacementMap.containsKey(toReplace)) { + LiteralConstraint newLiteral = new LiteralConstraint(featureReplacementMap.get(toReplace)); + constraint.replaceConstraintSubPart(subPart, newLiteral); + } + } else { + adaptConstraint(subTreeRoot, subPart, featureReplacementMap); } - } else { - adaptConstraint(subTreeRoot, subPart, featureReplacementMap); + } + } + } + + private void adaptExpression(Expression expression, Map featureReplacementMap) { + if (expression instanceof LiteralExpression) { + LiteralExpression literalExpression = (LiteralExpression) expression; + Attribute attribute = (Attribute) literalExpression.getContent(); + if (featureReplacementMap.containsKey(attribute.getFeature().getFeatureName())) { + var newAttribute = attribute.clone(); + newAttribute.setFeature(featureReplacementMap.get(attribute.getFeature().getFeatureName())); + literalExpression.setContent(newAttribute); + } + + } else { + for (Expression subExpression : expression.getExpressionSubParts()) { + adaptExpression(subExpression, featureReplacementMap); } } } diff --git a/src/main/java/de/vill/conversion/ConvertGroupCardinality.java b/src/main/java/de/vill/conversion/ConvertGroupCardinality.java index a431b12..89f051e 100644 --- a/src/main/java/de/vill/conversion/ConvertGroupCardinality.java +++ b/src/main/java/de/vill/conversion/ConvertGroupCardinality.java @@ -47,7 +47,7 @@ private void removeGroupCardinality(Group group, FeatureModel featureModel) { Set groupMembers = new HashSet<>(group.getFeatures()); int lowerBound = group.getCardinality().lower; - int upperBound = Math.max(group.getCardinality().upper, groupMembers.size()); + int upperBound = Math.min(group.getCardinality().upper, groupMembers.size()); Set> featureCombinations = new HashSet<>(); for (int i = lowerBound; i <= upperBound; i++) { featureCombinations.addAll(Sets.combinations(groupMembers, i)); @@ -81,17 +81,10 @@ private Constraint createConjunction(Set selectedFeatures, Set } private Constraint createDisjunction(Set constraints) { - Constraint orConstraint; - if (constraints.size() == 1) { - Constraint constraint = constraints.iterator().next(); - constraints.remove(constraint); - orConstraint = constraint; - } else { - Constraint constraint = constraints.iterator().next(); - constraints.remove(constraint); - orConstraint = new OrConstraint(constraint, createDisjunction(constraints)); + MultiOrConstraint orConstraint = new MultiOrConstraint(); + for (Constraint constraint : constraints) { + orConstraint.add_sub_part(constraint); } - return orConstraint; } } diff --git a/src/main/java/de/vill/conversion/ConvertSMTLevel.java b/src/main/java/de/vill/conversion/ConvertSMTLevel.java index af0052f..b45b99f 100644 --- a/src/main/java/de/vill/conversion/ConvertSMTLevel.java +++ b/src/main/java/de/vill/conversion/ConvertSMTLevel.java @@ -19,33 +19,53 @@ public Set getTargetLevelsOfConversion() { return new HashSet<>(Arrays.asList(LanguageLevel.BOOLEAN_LEVEL)); } + private Constraint getFalseConstraint(FeatureModel featureModel){ + return new NotConstraint(new LiteralConstraint(featureModel.getRootFeature())); + } + @Override public void convertFeatureModel(FeatureModel rootFeatureModel, FeatureModel featureModel) { List constraints = featureModel.getFeatureConstraints(); constraints.addAll(featureModel.getOwnConstraints()); - constraints.stream().forEach(this::replaceEquationInConstraint); + for(Constraint constraint : constraints) { + replaceEquationInConstraint(constraint, featureModel); + } List replacements = new LinkedList<>(); for (Constraint constraint : featureModel.getOwnConstraints()) { if (constraint instanceof ExpressionConstraint) { - Constraint equationReplacement = convertEquationToConstraint((ExpressionConstraint) constraint); + Constraint equationReplacement = convertEquationToConstraint((ExpressionConstraint) constraint, getFalseConstraint(featureModel)); replacements.add(equationReplacement); } } featureModel.getOwnConstraints().removeIf(x -> x instanceof ExpressionConstraint); featureModel.getOwnConstraints().addAll(replacements); - traverseFeatures(featureModel.getRootFeature()); + for (Constraint constraint : featureModel.getOwnConstraints()) { + convertConstraint(constraint, featureModel); + } + traverseFeatures(featureModel.getRootFeature(), featureModel); } - private void replaceEquationInConstraint(Constraint constraint) { + private void convertConstraint(Constraint constraint, FeatureModel featureModel) { for (Constraint subConstraint : constraint.getConstraintSubParts()) { if (subConstraint instanceof ExpressionConstraint) { - Constraint equationReplacement = convertEquationToConstraint((ExpressionConstraint) subConstraint); + Constraint equationReplacement = convertEquationToConstraint((ExpressionConstraint) subConstraint, getFalseConstraint(featureModel)); constraint.replaceConstraintSubPart(subConstraint, equationReplacement); + }else{ + convertConstraint(subConstraint, featureModel); } } } - private Constraint convertEquationToConstraint(ExpressionConstraint equation) { + private void replaceEquationInConstraint(Constraint constraint, FeatureModel featureModel) { + for (Constraint subConstraint : constraint.getConstraintSubParts()) { + if (subConstraint instanceof ExpressionConstraint) { + Constraint equationReplacement = convertEquationToConstraint((ExpressionConstraint) subConstraint, getFalseConstraint(featureModel)); + constraint.replaceConstraintSubPart(subConstraint, equationReplacement); + } + } + } + + private Constraint convertEquationToConstraint(ExpressionConstraint equation, Constraint falseConstraint) { Set featuresInEquation = getFeaturesInEquation(equation); Set> featureCombinations = getFeatureCombinations(featuresInEquation); Set disjunction = new HashSet<>(); @@ -55,7 +75,11 @@ private Constraint convertEquationToConstraint(ExpressionConstraint equation) { disjunction.add(createConjunction(configuration, new HashSet<>(featuresInEquation))); } } - return new ParenthesisConstraint(createDisjunction(disjunction)); + if (disjunction.isEmpty()) { + return falseConstraint; + }else{ + return new ParenthesisConstraint(createDisjunction(disjunction)); + } } private Set getFeaturesInEquation(ExpressionConstraint equation) { @@ -112,26 +136,19 @@ private Constraint createConjunction(Set selectedFeatures, Set } private Constraint createDisjunction(Set constraints) { - Constraint orConstraint; - if (constraints.size() == 1) { - Constraint constraint = constraints.iterator().next(); - constraints.remove(constraint); - orConstraint = constraint; - } else { - Constraint constraint = constraints.iterator().next(); - constraints.remove(constraint); - orConstraint = new OrConstraint(constraint, createDisjunction(constraints)); + MultiOrConstraint orConstraint = new MultiOrConstraint(); + for (Constraint constraint : constraints) { + orConstraint.add_sub_part(constraint); } - return orConstraint; } - private void removeEquationFromAttributes(Feature feature) { + private void removeEquationFromAttributes(Feature feature, FeatureModel featureModel) { Attribute attributeConstraint = feature.getAttributes().get("constraint"); Attribute attributeConstraintList = feature.getAttributes().get("constraints"); if (attributeConstraint != null) { if (attributeConstraint.getValue() instanceof ExpressionConstraint) { - Constraint equationReplacement = convertEquationToConstraint((ExpressionConstraint) attributeConstraint.getValue()); + Constraint equationReplacement = convertEquationToConstraint((ExpressionConstraint) attributeConstraint.getValue(), getFalseConstraint(featureModel)); feature.getAttributes().put("constraint", new Attribute<>("constraint", equationReplacement, feature)); } } @@ -139,7 +156,7 @@ private void removeEquationFromAttributes(Feature feature) { List newConstraintList = new LinkedList<>(); for (Object constraint : (List) attributeConstraintList.getValue()) { if (constraint instanceof ExpressionConstraint) { - Constraint equationReplacement = convertEquationToConstraint((ExpressionConstraint) constraint); + Constraint equationReplacement = convertEquationToConstraint((ExpressionConstraint) constraint, getFalseConstraint(featureModel)); newConstraintList.add(equationReplacement); } else { newConstraintList.add(constraint); @@ -149,11 +166,11 @@ private void removeEquationFromAttributes(Feature feature) { } } - private void traverseFeatures(Feature feature) { - removeEquationFromAttributes(feature); + private void traverseFeatures(Feature feature, FeatureModel featureModel) { + removeEquationFromAttributes(feature, featureModel); for (Group group : feature.getChildren()) { for (Feature subFeature : group.getFeatures()) { - traverseFeatures(subFeature); + traverseFeatures(subFeature, featureModel); } } } diff --git a/src/main/java/de/vill/conversion/DropTypeLevel.java b/src/main/java/de/vill/conversion/DropTypeLevel.java index 95a24d6..c00a15c 100644 --- a/src/main/java/de/vill/conversion/DropTypeLevel.java +++ b/src/main/java/de/vill/conversion/DropTypeLevel.java @@ -1,9 +1,15 @@ package de.vill.conversion; +import de.vill.main.Example; import de.vill.model.Feature; import de.vill.model.FeatureModel; import de.vill.model.Group; import de.vill.model.LanguageLevel; +import de.vill.model.constraint.Constraint; +import de.vill.model.constraint.ExpressionConstraint; +import de.vill.model.expression.Expression; +import de.vill.model.expression.LengthAggregateFunctionExpression; +import de.vill.model.expression.StringExpression; import de.vill.util.Constants; import java.util.Collections; @@ -24,6 +30,7 @@ public Set getTargetLevelsOfConversion() { @Override public void convertFeatureModel(final FeatureModel rootFeatureModel, final FeatureModel featureModel) { this.traverseFeatures(featureModel.getRootFeature()); + traverseConstraints(featureModel); } private void traverseFeatures(final Feature feature) { @@ -37,4 +44,44 @@ private void traverseFeatures(final Feature feature) { } } } + + private void traverseConstraints(FeatureModel featureModel) { + for(Constraint constraint : featureModel.getConstraints()){ + if (containsTypeConcept(constraint)){ + featureModel.getOwnConstraints().remove(constraint); + } + } + } + + private boolean containsTypeConcept(Constraint constraint) { + if (constraint instanceof ExpressionConstraint){ + for(Expression subExpression : ((ExpressionConstraint) constraint).getExpressionSubParts()){ + if (containsTypeConcept(subExpression)){ + return true; + } + } + + } + for(Constraint subConstraints : constraint.getConstraintSubParts()){ + if (containsTypeConcept(subConstraints)){ + return true; + } + } + return false; + } + + private boolean containsTypeConcept(Expression expression) { + if (expression instanceof LengthAggregateFunctionExpression){ + return true; + } + if (expression instanceof StringExpression){ + return true; + } + for(Expression subExpressions : expression.getExpressionSubParts()){ + if (containsTypeConcept(subExpressions)){ + return true; + } + } + return false; + } } diff --git a/src/main/java/de/vill/main/UVLModelFactory.java b/src/main/java/de/vill/main/UVLModelFactory.java index 321da6b..c6dd819 100644 --- a/src/main/java/de/vill/main/UVLModelFactory.java +++ b/src/main/java/de/vill/main/UVLModelFactory.java @@ -259,23 +259,12 @@ private List getActualLanguageLevelsToRemoveInOrder(FeatureModel List completeOrderedLevelsToRemove = new LinkedList<>(); while (!levelsToRemoveClone.isEmpty()) { LanguageLevel highestLevel = getMaxLanguageLevel(levelsToRemoveClone); - if (LanguageLevel.isMajorLevel(highestLevel)) { - //highestLevel is major level - int numberCorrespondingMinorLevels = highestLevel.getValue() + 1; - List correspondingMinorLevels = LanguageLevel.valueOf(numberCorrespondingMinorLevels); - if (correspondingMinorLevels != null) { - correspondingMinorLevels.retainAll(featureModel.getUsedLanguageLevelsRecursively()); - completeOrderedLevelsToRemove.addAll(correspondingMinorLevels); - } + + if (featureModel.getUsedLanguageLevelsRecursively().contains(highestLevel)) { completeOrderedLevelsToRemove.add(highestLevel); - levelsToRemoveClone.remove(highestLevel); - } else { - //highestLevel is minor level - if (featureModel.getUsedLanguageLevelsRecursively().contains(highestLevel)) { - completeOrderedLevelsToRemove.add(highestLevel); - } - levelsToRemoveClone.remove(highestLevel); } + levelsToRemoveClone.remove(highestLevel); + } //SAT-level can not be removed completeOrderedLevelsToRemove.remove(LanguageLevel.BOOLEAN_LEVEL); diff --git a/src/main/java/de/vill/model/Attribute.java b/src/main/java/de/vill/model/Attribute.java index b86666a..a997edd 100644 --- a/src/main/java/de/vill/model/Attribute.java +++ b/src/main/java/de/vill/model/Attribute.java @@ -8,6 +8,8 @@ import de.vill.model.building.VariableReference; import de.vill.model.constraint.Constraint; +import de.vill.model.expression.AddExpression; +import de.vill.model.expression.Expression; import de.vill.util.Constants; /** @@ -20,9 +22,9 @@ public class Attribute implements VariableReference { private int line; - private final String name; - private final T value; - private final Feature feature; + private String name; + private T value; + private Feature feature; /** * The constructor of the attribute class takes an attribute name (does not contain the feature name) and a value of type T @@ -53,6 +55,8 @@ public T getValue() { return value; } + public void setValue(T value) { this.value = value; } + /** * Returns the name of the attribute. * @@ -62,6 +66,9 @@ public String getName() { return name; } + public void setName(String name) { this.name = name; } + + /** * Returns the type of the attribute * @return Name of the attribute (never null) @@ -86,6 +93,10 @@ public String getType() { */ public Feature getFeature() {return feature;} + public void setFeature(Feature feature) { + this.feature = feature; + } + /** * Returns a uvl representation of the attribute as string (different for the possible types of the value) * @@ -167,4 +178,13 @@ public boolean equals(Object obj) { public String getIdentifier() { return feature.getIdentifier() + "." + name; } + + @Override + public Attribute clone(){ + return new Attribute(name, value, feature); + } + + public Attribute cloneWithFeature(Feature feature){ + return new Attribute(name, value, feature); + } } diff --git a/src/main/java/de/vill/model/Feature.java b/src/main/java/de/vill/model/Feature.java index 2aa7666..adba0c4 100644 --- a/src/main/java/de/vill/model/Feature.java +++ b/src/main/java/de/vill/model/Feature.java @@ -1,19 +1,13 @@ package de.vill.model; -import static de.vill.util.Util.addNecessaryQuotes; - -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import java.util.Objects; - import de.vill.config.Configuration; import de.vill.model.building.VariableReference; import de.vill.util.Util; +import java.util.*; + +import static de.vill.util.Util.addNecessaryQuotes; + /** * This class represents a feature of any kind (normal, numeric, abstract, ...). */ @@ -369,6 +363,10 @@ public String toString() { return toString(true, ""); } + public String getQuotedFeatureName(){ + return "\"" + getFeatureName() + "\""; + } + /** * This method is necessary because the uvl string representation differs * between the feature as imported feature another feature model or as the root @@ -521,11 +519,15 @@ private String attributesToString(boolean withSubmodels, String currentAlias) { public Feature clone() { Feature feature = new Feature(getFeatureName()); feature.setNameSpace(getNameSpace()); - feature.setCardinality(cardinality.clone()); + if (cardinality != null){ + feature.setCardinality(cardinality.clone()); + } feature.setSubmodelRoot(isSubmodelRoot); feature.setRelatedImport(getRelatedImport()); feature.setFeatureType(this.getFeatureType()); - feature.getAttributes().putAll(getAttributes()); + for (Map.Entry> entry : getAttributes().entrySet()){ + feature.getAttributes().put(entry.getKey(),entry.getValue().cloneWithFeature(feature)); + } for (Group group : getChildren()) { feature.getChildren().add(group.clone()); } diff --git a/src/main/java/de/vill/model/FeatureModel.java b/src/main/java/de/vill/model/FeatureModel.java index 8965ed5..b018fd2 100644 --- a/src/main/java/de/vill/model/FeatureModel.java +++ b/src/main/java/de/vill/model/FeatureModel.java @@ -1,16 +1,5 @@ package de.vill.model; -import static de.vill.util.Util.addNecessaryQuotes; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - import de.vill.config.Configuration; import de.vill.model.constraint.Constraint; import de.vill.model.constraint.LiteralConstraint; @@ -19,6 +8,10 @@ import de.vill.model.expression.LiteralExpression; import de.vill.util.Util; +import java.util.*; + +import static de.vill.util.Util.addNecessaryQuotes; + /** * This class represents a feature model and all its sub feature models if the * model is composed. @@ -254,6 +247,8 @@ public String toString() { return toString(false, ""); } + + /** * Returns a single uvl feature model composed out of all submodels. To avoid * naming conflicts all feature names are changed and a unique id is added. If diff --git a/src/main/java/de/vill/model/GlobalAttribute.java b/src/main/java/de/vill/model/GlobalAttribute.java index e9930bd..ff91e46 100644 --- a/src/main/java/de/vill/model/GlobalAttribute.java +++ b/src/main/java/de/vill/model/GlobalAttribute.java @@ -32,7 +32,7 @@ public static AttributeType fromString(String name) { } } - private final String identifier; + private String identifier; private AttributeType type; private final Set featuresContainingAttribute; @@ -53,6 +53,8 @@ public GlobalAttribute(String identifier, AttributeType type) { featuresContainingAttribute = new HashSet<>(); } + public void renameGlobalAttribute(String newIdentifier) { this.identifier = newIdentifier;} + public void addFeature(Feature feature) { featuresContainingAttribute.add(feature); } diff --git a/src/main/java/de/vill/model/Group.java b/src/main/java/de/vill/model/Group.java index 1597f27..00dc966 100644 --- a/src/main/java/de/vill/model/Group.java +++ b/src/main/java/de/vill/model/Group.java @@ -1,12 +1,9 @@ package de.vill.model; -import java.util.Collection; -import java.util.LinkedList; -import java.util.List; -import java.util.ListIterator; -import java.util.Objects; +import java.util.*; import de.vill.config.Configuration; +import de.vill.model.constraint.Constraint; import de.vill.util.Util; /** diff --git a/src/main/java/de/vill/model/LanguageLevel.java b/src/main/java/de/vill/model/LanguageLevel.java index 43b8d94..e9a6b3a 100644 --- a/src/main/java/de/vill/model/LanguageLevel.java +++ b/src/main/java/de/vill/model/LanguageLevel.java @@ -13,14 +13,14 @@ public enum LanguageLevel { // MAJOR LEVELS (logic: val % 2 != 0) BOOLEAN_LEVEL(1, Constants.BOOLEAN_LEVEL), ARITHMETIC_LEVEL(3, Constants.ARITHMETIC_LEVEL), - TYPE_LEVEL(5, Constants.TYPE_LEVEL), + TYPE_LEVEL(7, Constants.TYPE_LEVEL), // MINOR LEVELS (logic: val % 2 == 0) GROUP_CARDINALITY(2, "group-cardinality"), - FEATURE_CARDINALITY(4, "feature-cardinality"), + FEATURE_CARDINALITY(6, "feature-cardinality"), AGGREGATE_FUNCTION(4, "aggregate-function"), - STRING_CONSTRAINTS(6, "string-constraints"), - NUMERIC_CONSTRAINTS(6, "numeric-constraints"), + STRING_CONSTRAINTS(8, "string-constraints"), + NUMERIC_CONSTRAINTS(8, "numeric-constraints"), ; private final int value; diff --git a/src/main/java/de/vill/model/building/AutomaticBrackets.java b/src/main/java/de/vill/model/building/AutomaticBrackets.java new file mode 100644 index 0000000..fa9a80e --- /dev/null +++ b/src/main/java/de/vill/model/building/AutomaticBrackets.java @@ -0,0 +1,118 @@ +package de.vill.model.building; + +import de.vill.model.constraint.*; +import de.vill.model.expression.*; + +import java.util.HashMap; +import java.util.Map; + +/** + * This class automatically creates brackets for nested constraints to ensure semantic equivalence when printing out the UVL model. + * Precedences are ordered according to ... and ... + * A higher score indicates a higher precedence (i.e., a stronger binding) + * @author Chico Sundermann + */ +public class AutomaticBrackets { + + private AutomaticBrackets() {} + + static Map constraintprecedenceLookup; + + static Map expressionPrecedenceLookup; + + public final static int IFF_PRECEDENCE = 0; + public final static int IMPLY_PRECEDENCE = 1; + public final static int OR_PRECEDENCE = 2; + public final static int AND_PRECEDENCE = 3; + public final static int GEQ_LEQ_PRECEDENCE = 4; + public final static int EQUATION_PRECEDENCE = 5; + public final static int CONSTRAINT_UNARY_PRECEDENCE = 6; + + public final static int ADD_SUB_PRECEDENCE = 0; + public final static int MULT_DIV_PRECEDENCE = 1; + public final static int UNARY_EXPRESSION_PRECEDENCE = 2; + + + static { + constraintprecedenceLookup = new HashMap<>(); + + // n-ary + constraintprecedenceLookup.put(EquivalenceConstraint.class, IFF_PRECEDENCE); + constraintprecedenceLookup.put(ImplicationConstraint.class, IMPLY_PRECEDENCE); + constraintprecedenceLookup.put(OrConstraint.class, OR_PRECEDENCE); + constraintprecedenceLookup.put(MultiOrConstraint.class, OR_PRECEDENCE); + constraintprecedenceLookup.put(AndConstraint.class, AND_PRECEDENCE); + constraintprecedenceLookup.put(GreaterEquationConstraint.class, GEQ_LEQ_PRECEDENCE); + constraintprecedenceLookup.put(LowerEquationConstraint.class, GEQ_LEQ_PRECEDENCE); + constraintprecedenceLookup.put(GreaterEqualsEquationConstraint.class, GEQ_LEQ_PRECEDENCE); + constraintprecedenceLookup.put(LowerEqualsEquationConstraint.class, GEQ_LEQ_PRECEDENCE); + constraintprecedenceLookup.put(NotEqualsEquationConstraint.class, EQUATION_PRECEDENCE); + constraintprecedenceLookup.put(EqualEquationConstraint.class, EQUATION_PRECEDENCE); + + // Unary + constraintprecedenceLookup.put(LiteralConstraint.class, CONSTRAINT_UNARY_PRECEDENCE); + constraintprecedenceLookup.put(NotConstraint.class, CONSTRAINT_UNARY_PRECEDENCE); + constraintprecedenceLookup.put(ParenthesisConstraint.class, CONSTRAINT_UNARY_PRECEDENCE); + + expressionPrecedenceLookup = new HashMap<>(); + + // n-ary + expressionPrecedenceLookup.put(AddExpression.class, ADD_SUB_PRECEDENCE); + expressionPrecedenceLookup.put(SubExpression.class, ADD_SUB_PRECEDENCE); + expressionPrecedenceLookup.put(MulExpression.class, MULT_DIV_PRECEDENCE); + expressionPrecedenceLookup.put(DivExpression.class, MULT_DIV_PRECEDENCE); + + // unary + expressionPrecedenceLookup.put(AvgAggregateFunctionExpression.class, UNARY_EXPRESSION_PRECEDENCE); + expressionPrecedenceLookup.put(MaxAggregateFunctionExpression.class, UNARY_EXPRESSION_PRECEDENCE); + expressionPrecedenceLookup.put(MinAggregateFunctionExpression.class, UNARY_EXPRESSION_PRECEDENCE); + expressionPrecedenceLookup.put(SumAggregateFunctionExpression.class, UNARY_EXPRESSION_PRECEDENCE); + expressionPrecedenceLookup.put(ParenthesisExpression.class, UNARY_EXPRESSION_PRECEDENCE); + + expressionPrecedenceLookup.put(LiteralExpression.class, UNARY_EXPRESSION_PRECEDENCE); + expressionPrecedenceLookup.put(NumberExpression.class, UNARY_EXPRESSION_PRECEDENCE); + expressionPrecedenceLookup.put(StringExpression.class, UNARY_EXPRESSION_PRECEDENCE); + } + + /** + * + * @param parent + * @param child + * @return + */ + private static boolean requiresBracketsInConstraint(Constraint parent, Constraint child) { + return constraintprecedenceLookup.get(parent.getClass()) >= constraintprecedenceLookup.get(child.getClass()); + } + + private static boolean requiresBracketsInExpression(Expression parent, Expression child) { + return expressionPrecedenceLookup.get(parent.getClass()) >= expressionPrecedenceLookup.get(child.getClass()); + } + + /** + * Method can be used so that the printed versions of constraints are semantically equivalent to the internal object representation + * @see de.vill.model.building.AutomaticBrackets for the precendences + * @param parent + * @param child + * @param withSubmodels Consider imported submodels + * @param currentAlias Check alias of submodel at hand + * @return + */ + public static String enforceConstraintBracketsIfNecessary(Constraint parent, Constraint child, boolean withSubmodels, String currentAlias) { + if (requiresBracketsInConstraint(parent, child)) { + return "(" + child.toString(withSubmodels, currentAlias) + ")"; + } else { + return child.toString(withSubmodels, currentAlias); + } + } + + public static String enforceExpressionBracketsIfNecessary(Expression parent, Expression child, boolean withSubmodels, String currentAlias) { + if (requiresBracketsInExpression(parent, child)) { + return "(" + child.toString(withSubmodels, currentAlias) + ")"; + } else { + return child.toString(withSubmodels, currentAlias); + } + } + + + +} diff --git a/src/main/java/de/vill/model/building/FeatureModelBuilder.java b/src/main/java/de/vill/model/building/FeatureModelBuilder.java index 19f178e..bb998a6 100644 --- a/src/main/java/de/vill/model/building/FeatureModelBuilder.java +++ b/src/main/java/de/vill/model/building/FeatureModelBuilder.java @@ -3,7 +3,10 @@ import de.vill.exception.ParseError; import de.vill.model.*; import de.vill.model.constraint.Constraint; +import de.vill.model.constraint.ExpressionConstraint; import de.vill.model.constraint.LiteralConstraint; +import de.vill.model.expression.AggregateFunctionExpression; +import de.vill.model.expression.Expression; import java.util.List; import java.util.Map; @@ -102,7 +105,7 @@ public void addAttribute(Feature feature, Attribute attribute) { */ public boolean renameFeature(String oldName, String newName) { Map featureMap = fmInConstruction.getFeatureMap(); - if (featureMap.containsKey(oldName)) { + if (!featureMap.containsKey(oldName)) { return false; } Feature featureToUpdate = featureMap.get(oldName); @@ -116,6 +119,49 @@ public boolean renameFeature(String oldName, String newName) { return true; } + public void renameAttribute(Attribute attribute, String newName) { + String oldName = attribute.getName(); + attribute.setName(newName); + attribute.getFeature().getAttributes().remove(oldName); + attribute.getFeature().getAttributes().put(newName, attribute); + } + + public void renameAttributeGlobally(String oldName, String newName) { + for (Feature feature : fmInConstruction.getFeatureMap().values()) { + if (feature.getAttributes().containsKey(oldName)) { + Attribute attribute = feature.getAttributes().get(oldName); + renameAttribute(attribute, newName); + } + } + for (Constraint constraint : fmInConstruction.getConstraints()) { + crawlConstraintsToRenameGlobalAttribute(constraint, oldName, newName); + } + } + private void crawlConstraintsToRenameGlobalAttribute(Constraint constraint, String attributeName, String replace) { + if (constraint instanceof ExpressionConstraint) { + for (Expression exp : ((ExpressionConstraint) constraint).getExpressionSubParts()) { + crawlExpressionsToRenameGlobalAttribute(exp, attributeName, replace); + } + } else { + for (Constraint child : constraint.getConstraintSubParts()) { + crawlConstraintsToRenameGlobalAttribute(child, attributeName, replace); + } + } + } + + private void crawlExpressionsToRenameGlobalAttribute(Expression expression, String attributeName, String replace) { + if (expression instanceof AggregateFunctionExpression) { + AggregateFunctionExpression aggregateFunctionExpression = (AggregateFunctionExpression) expression; + if (aggregateFunctionExpression.getAttribute().getIdentifier().equals(attributeName)) { + aggregateFunctionExpression.getAttribute().renameGlobalAttribute(replace); + }; + } else { + for (Expression exp : expression.getExpressionSubParts()) { + crawlExpressionsToRenameGlobalAttribute(exp, attributeName, replace); + } + } + } + public void addConstraint(Constraint constraint) { fmInConstruction.getOwnConstraints().add(0,constraint); } diff --git a/src/main/java/de/vill/model/constraint/AndConstraint.java b/src/main/java/de/vill/model/constraint/AndConstraint.java index 1eea5f4..7587150 100644 --- a/src/main/java/de/vill/model/constraint/AndConstraint.java +++ b/src/main/java/de/vill/model/constraint/AndConstraint.java @@ -1,5 +1,6 @@ package de.vill.model.constraint; +import de.vill.model.building.AutomaticBrackets; import de.vill.model.building.VariableReference; import java.util.ArrayList; @@ -24,11 +25,19 @@ public Constraint getRight() { return right; } + public void setLeft(Constraint left) { + this.left = left; + } + + public void setRight(Constraint right){ + this.right = right; + } + @Override public String toString(boolean withSubmodels, String currentAlias) { - return left.toString(withSubmodels, currentAlias) + + return AutomaticBrackets.enforceConstraintBracketsIfNecessary(this, left, withSubmodels, currentAlias) + " & " + - right.toString(withSubmodels, currentAlias); + AutomaticBrackets.enforceConstraintBracketsIfNecessary(this, right, withSubmodels, currentAlias); } @Override diff --git a/src/main/java/de/vill/model/constraint/Constraint.java b/src/main/java/de/vill/model/constraint/Constraint.java index a10a567..0aa3edc 100644 --- a/src/main/java/de/vill/model/constraint/Constraint.java +++ b/src/main/java/de/vill/model/constraint/Constraint.java @@ -41,3 +41,4 @@ public int hashCode() { public abstract List getReferences(); } + diff --git a/src/main/java/de/vill/model/constraint/EqualEquationConstraint.java b/src/main/java/de/vill/model/constraint/EqualEquationConstraint.java index b8368cb..796c64e 100644 --- a/src/main/java/de/vill/model/constraint/EqualEquationConstraint.java +++ b/src/main/java/de/vill/model/constraint/EqualEquationConstraint.java @@ -7,25 +7,21 @@ import java.util.List; public class EqualEquationConstraint extends ExpressionConstraint { - private final Expression left; - private final Expression right; public EqualEquationConstraint(final Expression left, final Expression right) { super(left, right, "=="); - this.left = left; - this.right = right; } @Override public Constraint clone() { - return new EqualEquationConstraint(this.left, this.right); + return new EqualEquationConstraint(getLeft().clone(), getRight().clone()); } @Override public List getReferences() { List references = new ArrayList<>(); - references.addAll(left.getReferences()); - references.addAll(right.getReferences()); + references.addAll(getLeft().getReferences()); + references.addAll(getRight().getReferences()); return references; } } diff --git a/src/main/java/de/vill/model/constraint/EquivalenceConstraint.java b/src/main/java/de/vill/model/constraint/EquivalenceConstraint.java index 024a291..6a07fee 100644 --- a/src/main/java/de/vill/model/constraint/EquivalenceConstraint.java +++ b/src/main/java/de/vill/model/constraint/EquivalenceConstraint.java @@ -1,5 +1,6 @@ package de.vill.model.constraint; +import de.vill.model.building.AutomaticBrackets; import de.vill.model.building.VariableReference; import java.util.ArrayList; @@ -26,11 +27,9 @@ public Constraint getRight() { @Override public String toString(boolean withSubmodels, String currentAlias) { - StringBuilder result = new StringBuilder(); - result.append(left.toString(withSubmodels, currentAlias)); - result.append(" <=> "); - result.append(right.toString(withSubmodels, currentAlias)); - return result.toString(); + return AutomaticBrackets.enforceConstraintBracketsIfNecessary(this, left, withSubmodels, currentAlias) + + " <=> " + + AutomaticBrackets.enforceConstraintBracketsIfNecessary(this, right, withSubmodels, currentAlias); } @Override @@ -79,5 +78,4 @@ public List getReferences() { references.addAll(right.getReferences()); return references; } - } diff --git a/src/main/java/de/vill/model/constraint/ExpressionConstraint.java b/src/main/java/de/vill/model/constraint/ExpressionConstraint.java index f8213be..056dede 100644 --- a/src/main/java/de/vill/model/constraint/ExpressionConstraint.java +++ b/src/main/java/de/vill/model/constraint/ExpressionConstraint.java @@ -2,9 +2,7 @@ import de.vill.model.Feature; import de.vill.model.building.VariableReference; -import de.vill.model.expression.AggregateFunctionExpression; import de.vill.model.expression.Expression; -import de.vill.model.expression.LiteralExpression; import java.util.*; @@ -27,6 +25,14 @@ public Expression getRight() { return right; } + public void setLeft(Expression expression) { + left = expression; + } + + public void setRight(Expression expression) { + right = expression; + } + public String getExpressionSymbol() { return expressionSymbol; } @@ -65,6 +71,9 @@ public void replaceConstraintSubPart(Constraint oldSubConstraint, Constraint new public boolean evaluate(Set selectedFeatures) { double leftResult = left.evaluate(selectedFeatures); double rightResult = right.evaluate(selectedFeatures); + if (Double.isNaN(leftResult) || Double.isNaN(rightResult) || Double.isInfinite(leftResult) || Double.isInfinite(rightResult)){ + return false; + } if ("==".equals(expressionSymbol)) { return leftResult == rightResult; diff --git a/src/main/java/de/vill/model/constraint/GreaterEqualsEquationConstraint.java b/src/main/java/de/vill/model/constraint/GreaterEqualsEquationConstraint.java index 130c6fd..4aca930 100644 --- a/src/main/java/de/vill/model/constraint/GreaterEqualsEquationConstraint.java +++ b/src/main/java/de/vill/model/constraint/GreaterEqualsEquationConstraint.java @@ -8,13 +8,8 @@ import java.util.List; public class GreaterEqualsEquationConstraint extends ExpressionConstraint { - private final Expression left; - private final Expression right; - public GreaterEqualsEquationConstraint(final Expression left, final Expression right) { super(left, right, ">="); - this.left = left; - this.right = right; } @Override @@ -24,14 +19,14 @@ public List getConstraintSubParts() { @Override public Constraint clone() { - return new GreaterEqualsEquationConstraint(this.left, this.right); + return new GreaterEqualsEquationConstraint(getLeft().clone(), getRight().clone()); } @Override public List getReferences() { List references = new ArrayList<>(); - references.addAll(left.getReferences()); - references.addAll(right.getReferences()); + references.addAll(getLeft().getReferences()); + references.addAll(getRight().getReferences()); return references; } } diff --git a/src/main/java/de/vill/model/constraint/GreaterEquationConstraint.java b/src/main/java/de/vill/model/constraint/GreaterEquationConstraint.java index 6074f44..e323cd8 100644 --- a/src/main/java/de/vill/model/constraint/GreaterEquationConstraint.java +++ b/src/main/java/de/vill/model/constraint/GreaterEquationConstraint.java @@ -8,13 +8,8 @@ import java.util.List; public class GreaterEquationConstraint extends ExpressionConstraint { - private final Expression left; - private final Expression right; - public GreaterEquationConstraint(final Expression left, final Expression right) { super(left, right, ">"); - this.left = left; - this.right = right; } @Override @@ -24,14 +19,14 @@ public List getConstraintSubParts() { @Override public Constraint clone() { - return new GreaterEquationConstraint(this.left, this.right); + return new GreaterEquationConstraint(getLeft().clone(), getRight().clone()); } @Override public List getReferences() { List references = new ArrayList<>(); - references.addAll(left.getReferences()); - references.addAll(right.getReferences()); + references.addAll(getLeft().getReferences()); + references.addAll(getRight().getReferences()); return references; } } diff --git a/src/main/java/de/vill/model/constraint/ImplicationConstraint.java b/src/main/java/de/vill/model/constraint/ImplicationConstraint.java index d85bba0..854baf3 100644 --- a/src/main/java/de/vill/model/constraint/ImplicationConstraint.java +++ b/src/main/java/de/vill/model/constraint/ImplicationConstraint.java @@ -1,5 +1,6 @@ package de.vill.model.constraint; +import de.vill.model.building.AutomaticBrackets; import de.vill.model.building.VariableReference; import java.util.ArrayList; @@ -26,11 +27,9 @@ public Constraint getRight() { @Override public String toString(boolean withSubmodels, String currentAlias) { - StringBuilder result = new StringBuilder(); - result.append(left.toString(withSubmodels, currentAlias)); - result.append(" => "); - result.append(right.toString(withSubmodels, currentAlias)); - return result.toString(); + return AutomaticBrackets.enforceConstraintBracketsIfNecessary(this, left, withSubmodels, currentAlias) + + " => " + + AutomaticBrackets.enforceConstraintBracketsIfNecessary(this, right, withSubmodels, currentAlias); } @Override @@ -79,4 +78,5 @@ public List getReferences() { references.addAll(right.getReferences()); return references; } + } diff --git a/src/main/java/de/vill/model/constraint/LowerEqualsEquationConstraint.java b/src/main/java/de/vill/model/constraint/LowerEqualsEquationConstraint.java index a0e0dc4..ab03bcb 100644 --- a/src/main/java/de/vill/model/constraint/LowerEqualsEquationConstraint.java +++ b/src/main/java/de/vill/model/constraint/LowerEqualsEquationConstraint.java @@ -5,13 +5,8 @@ import java.util.List; public class LowerEqualsEquationConstraint extends ExpressionConstraint { - private final Expression left; - private final Expression right; - public LowerEqualsEquationConstraint(final Expression left, final Expression right) { super(left, right, "<="); - this.left = left; - this.right = right; } @Override @@ -21,6 +16,6 @@ public List getConstraintSubParts() { @Override public Constraint clone() { - return new LowerEqualsEquationConstraint(this.left, this.right); + return new LowerEqualsEquationConstraint(getLeft().clone(), getRight().clone()); } } diff --git a/src/main/java/de/vill/model/constraint/LowerEquationConstraint.java b/src/main/java/de/vill/model/constraint/LowerEquationConstraint.java index bec7314..4f6f991 100644 --- a/src/main/java/de/vill/model/constraint/LowerEquationConstraint.java +++ b/src/main/java/de/vill/model/constraint/LowerEquationConstraint.java @@ -5,13 +5,8 @@ import java.util.List; public class LowerEquationConstraint extends ExpressionConstraint { - private final Expression left; - private final Expression right; - public LowerEquationConstraint(final Expression left, final Expression right) { super(left, right, "<"); - this.left = left; - this.right = right; } @Override @@ -21,6 +16,6 @@ public List getConstraintSubParts() { @Override public Constraint clone() { - return new LowerEquationConstraint(this.left, this.right); + return new LowerEquationConstraint(getLeft().clone(), getRight().clone()); } } diff --git a/src/main/java/de/vill/model/constraint/MultiOrConstraint.java b/src/main/java/de/vill/model/constraint/MultiOrConstraint.java new file mode 100644 index 0000000..bb31d49 --- /dev/null +++ b/src/main/java/de/vill/model/constraint/MultiOrConstraint.java @@ -0,0 +1,98 @@ +package de.vill.model.constraint; + +import de.vill.model.building.AutomaticBrackets; +import de.vill.model.building.VariableReference; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +public class MultiOrConstraint extends Constraint{ + + private List sub_parts; + + public MultiOrConstraint() { + sub_parts = new LinkedList<>(); + } + + @Override + public String toString(boolean withSubmodels, String currentAlias) { + StringBuilder result = new StringBuilder(); + for (Constraint part : sub_parts) { + result.append(AutomaticBrackets.enforceConstraintBracketsIfNecessary(this, part, withSubmodels, currentAlias)); + result.append(" | "); + } + result.delete(result.length() -3, result.length()); + return result.toString(); + } + + @Override + public List getConstraintSubParts() { + return sub_parts; + } + + public void add_sub_part(Constraint constraint) { + sub_parts.add(constraint); + } + + @Override + public void replaceConstraintSubPart(Constraint oldSubConstraint, Constraint newSubConstraint) { + for (int i=0;i getReferences() { + List references = new ArrayList<>(); + for (int i=0;i getReferences() { return content.getReferences(); } + + + } diff --git a/src/main/java/de/vill/model/constraint/NotEqualsEquationConstraint.java b/src/main/java/de/vill/model/constraint/NotEqualsEquationConstraint.java index 852d1d4..35470f4 100644 --- a/src/main/java/de/vill/model/constraint/NotEqualsEquationConstraint.java +++ b/src/main/java/de/vill/model/constraint/NotEqualsEquationConstraint.java @@ -5,13 +5,8 @@ import java.util.List; public class NotEqualsEquationConstraint extends ExpressionConstraint { - private final Expression left; - private final Expression right; - public NotEqualsEquationConstraint(final Expression left, final Expression right) { super(left, right, "!="); - this.left = left; - this.right = right; } @Override @@ -21,6 +16,6 @@ public List getConstraintSubParts() { @Override public Constraint clone() { - return new NotEqualsEquationConstraint(this.left, this.right); + return new NotEqualsEquationConstraint(getLeft().clone(), getRight().clone()); } } diff --git a/src/main/java/de/vill/model/constraint/OrConstraint.java b/src/main/java/de/vill/model/constraint/OrConstraint.java index f770df8..b29aba1 100644 --- a/src/main/java/de/vill/model/constraint/OrConstraint.java +++ b/src/main/java/de/vill/model/constraint/OrConstraint.java @@ -1,5 +1,6 @@ package de.vill.model.constraint; +import de.vill.model.building.AutomaticBrackets; import de.vill.model.building.VariableReference; import java.util.ArrayList; @@ -25,11 +26,19 @@ public Constraint getRight() { return right; } + public void setLeft(Constraint left) { + this.left = left; + } + + public void setRight(Constraint right){ + this.right = right; + } + @Override public String toString(boolean withSubmodels, String currentAlias) { - return left.toString(withSubmodels, currentAlias) + + return AutomaticBrackets.enforceConstraintBracketsIfNecessary(this, left, withSubmodels, currentAlias) + " | " + - right.toString(withSubmodels, currentAlias); + AutomaticBrackets.enforceConstraintBracketsIfNecessary(this, right, withSubmodels, currentAlias); } @Override diff --git a/src/main/java/de/vill/model/expression/AddExpression.java b/src/main/java/de/vill/model/expression/AddExpression.java index 82dee3f..5bcd88b 100644 --- a/src/main/java/de/vill/model/expression/AddExpression.java +++ b/src/main/java/de/vill/model/expression/AddExpression.java @@ -1,6 +1,7 @@ package de.vill.model.expression; import de.vill.model.Feature; +import de.vill.model.building.AutomaticBrackets; import de.vill.model.building.VariableReference; import de.vill.util.Constants; @@ -27,9 +28,9 @@ public Expression getRight() { @Override public String toString(boolean withSubmodels, String currentAlias) { - return left.toString(withSubmodels, currentAlias) + + return AutomaticBrackets.enforceExpressionBracketsIfNecessary(this, left, withSubmodels, currentAlias) + " + " + - right.toString(withSubmodels, currentAlias); + AutomaticBrackets.enforceExpressionBracketsIfNecessary(this, right, withSubmodels, currentAlias); } @Override @@ -83,4 +84,10 @@ public List getReferences() { references.addAll(right.getReferences()); return references; } + + @Override + public Expression clone(){ + return new AddExpression(left.clone(), right.clone()); + } + } diff --git a/src/main/java/de/vill/model/expression/AggregateFunctionExpression.java b/src/main/java/de/vill/model/expression/AggregateFunctionExpression.java index 6822b03..b60efdf 100644 --- a/src/main/java/de/vill/model/expression/AggregateFunctionExpression.java +++ b/src/main/java/de/vill/model/expression/AggregateFunctionExpression.java @@ -1,5 +1,6 @@ package de.vill.model.expression; +import de.vill.util.Constants; import static de.vill.util.Util.addNecessaryQuotes; import de.vill.model.Feature; @@ -15,6 +16,7 @@ public abstract class AggregateFunctionExpression extends Expression { protected GlobalAttribute attribute; protected Feature rootFeature; + public AggregateFunctionExpression(GlobalAttribute attribute) { this.attribute = attribute; } @@ -23,7 +25,7 @@ public AggregateFunctionExpression(GlobalAttribute attribute, Feature rootFeatur this(attribute); this.rootFeature = rootFeature; } - + @Override public String toString(boolean withSubmodels, String currentAlias) { return toString(withSubmodels, "aggregateFunction", currentAlias); diff --git a/src/main/java/de/vill/model/expression/AvgAggregateFunctionExpression.java b/src/main/java/de/vill/model/expression/AvgAggregateFunctionExpression.java index d3bdb2a..68e04d1 100644 --- a/src/main/java/de/vill/model/expression/AvgAggregateFunctionExpression.java +++ b/src/main/java/de/vill/model/expression/AvgAggregateFunctionExpression.java @@ -51,4 +51,9 @@ public List getExpressionSubParts() { public String getReturnType() { return Constants.NUMBER; } + + @Override + public Expression clone() { + return new AvgAggregateFunctionExpression(attribute, rootFeature); + } } diff --git a/src/main/java/de/vill/model/expression/DivExpression.java b/src/main/java/de/vill/model/expression/DivExpression.java index 1449e02..0af62cb 100644 --- a/src/main/java/de/vill/model/expression/DivExpression.java +++ b/src/main/java/de/vill/model/expression/DivExpression.java @@ -1,6 +1,7 @@ package de.vill.model.expression; import de.vill.model.Feature; +import de.vill.model.building.AutomaticBrackets; import de.vill.model.building.VariableReference; import de.vill.util.Constants; @@ -27,9 +28,9 @@ public Expression getRight() { @Override public String toString(boolean withSubmodels, String currentAlias) { - return left.toString(withSubmodels, currentAlias) + + return AutomaticBrackets.enforceExpressionBracketsIfNecessary(this, left, withSubmodels, currentAlias) + " / " + - right.toString(withSubmodels, currentAlias); + AutomaticBrackets.enforceExpressionBracketsIfNecessary(this, right, withSubmodels, currentAlias); } @Override @@ -83,4 +84,9 @@ public List getReferences() { references.addAll(right.getReferences()); return references; } + + @Override + public Expression clone(){ + return new DivExpression(left.clone(), right.clone()); + } } diff --git a/src/main/java/de/vill/model/expression/Expression.java b/src/main/java/de/vill/model/expression/Expression.java index 382e506..510f19c 100644 --- a/src/main/java/de/vill/model/expression/Expression.java +++ b/src/main/java/de/vill/model/expression/Expression.java @@ -42,5 +42,8 @@ public int hashCode() { @Override public abstract boolean equals(Object obj); + @Override + public abstract Expression clone(); + public abstract List getReferences(); } diff --git a/src/main/java/de/vill/model/expression/LengthAggregateFunctionExpression.java b/src/main/java/de/vill/model/expression/LengthAggregateFunctionExpression.java index 17634b6..a50ebbd 100644 --- a/src/main/java/de/vill/model/expression/LengthAggregateFunctionExpression.java +++ b/src/main/java/de/vill/model/expression/LengthAggregateFunctionExpression.java @@ -86,4 +86,9 @@ public boolean equals(Object obj) { public List getReferences() { return List.of(); } + + @Override + public Expression clone(){ + return new LengthAggregateFunctionExpression(getReference()); + } } diff --git a/src/main/java/de/vill/model/expression/LiteralExpression.java b/src/main/java/de/vill/model/expression/LiteralExpression.java index a20a372..835f036 100644 --- a/src/main/java/de/vill/model/expression/LiteralExpression.java +++ b/src/main/java/de/vill/model/expression/LiteralExpression.java @@ -79,14 +79,18 @@ public double evaluate(final Set selectedFeatures) { return 0d; } else { Attribute attribute = (Attribute) content; - final Object attributeValue = attribute.getValue(); - if (attributeValue instanceof Integer) { - return ((Integer) attributeValue).doubleValue(); + if (selectedFeatures.contains(attribute.getFeature())) { + final Object attributeValue = attribute.getValue(); + if (attributeValue instanceof Integer) { + return ((Integer) attributeValue).doubleValue(); + } + if (attributeValue instanceof Long) { + return ((Long) attributeValue).doubleValue(); + } + return (double) attributeValue; + }else { + return 0; } - if (attributeValue instanceof Long) { - return ((Long) attributeValue).doubleValue(); - } - return (double) attributeValue; } } @@ -121,4 +125,9 @@ public List getReferences() { return List.of(content); } + @Override + public Expression clone(){ + return new LiteralExpression(content); + } + } diff --git a/src/main/java/de/vill/model/expression/MaxAggregateFunctionExpression.java b/src/main/java/de/vill/model/expression/MaxAggregateFunctionExpression.java index ccd0766..4bd9cb5 100644 --- a/src/main/java/de/vill/model/expression/MaxAggregateFunctionExpression.java +++ b/src/main/java/de/vill/model/expression/MaxAggregateFunctionExpression.java @@ -51,4 +51,9 @@ public String getReturnType() { public List getExpressionSubParts() { return Arrays.asList(); } + + @Override + public Expression clone() { + return new MaxAggregateFunctionExpression(attribute, rootFeature); + } } diff --git a/src/main/java/de/vill/model/expression/MinAggregateFunctionExpression.java b/src/main/java/de/vill/model/expression/MinAggregateFunctionExpression.java index c7d1421..b61ec32 100644 --- a/src/main/java/de/vill/model/expression/MinAggregateFunctionExpression.java +++ b/src/main/java/de/vill/model/expression/MinAggregateFunctionExpression.java @@ -52,4 +52,9 @@ public String getReturnType() { public List getExpressionSubParts() { return Arrays.asList(); } + + @Override + public Expression clone() { + return new MinAggregateFunctionExpression(attribute, rootFeature); + } } diff --git a/src/main/java/de/vill/model/expression/MulExpression.java b/src/main/java/de/vill/model/expression/MulExpression.java index e390382..830b5b7 100644 --- a/src/main/java/de/vill/model/expression/MulExpression.java +++ b/src/main/java/de/vill/model/expression/MulExpression.java @@ -1,6 +1,7 @@ package de.vill.model.expression; import de.vill.model.Feature; +import de.vill.model.building.AutomaticBrackets; import de.vill.model.building.VariableReference; import de.vill.util.Constants; @@ -27,9 +28,9 @@ public Expression getRight() { @Override public String toString(boolean withSubmodels, String currentAlias) { - return left.toString(withSubmodels, currentAlias) + + return AutomaticBrackets.enforceExpressionBracketsIfNecessary(this, left, withSubmodels, currentAlias) + " * " + - right.toString(withSubmodels, currentAlias); + AutomaticBrackets.enforceExpressionBracketsIfNecessary(this, right, withSubmodels, currentAlias); } @Override @@ -97,4 +98,9 @@ public List getReferences() { public String getReturnType() { return Constants.NUMBER; } + + @Override + public Expression clone(){ + return new MulExpression(left.clone(), right.clone()); + } } diff --git a/src/main/java/de/vill/model/expression/NumberExpression.java b/src/main/java/de/vill/model/expression/NumberExpression.java index fddc60c..33799f0 100644 --- a/src/main/java/de/vill/model/expression/NumberExpression.java +++ b/src/main/java/de/vill/model/expression/NumberExpression.java @@ -86,4 +86,9 @@ public List getReferences() { public String getReturnType() { return Constants.NUMBER; } + + @Override + public Expression clone(){ + return new NumberExpression(getNumber()); + } } diff --git a/src/main/java/de/vill/model/expression/ParenthesisExpression.java b/src/main/java/de/vill/model/expression/ParenthesisExpression.java index 1a78757..2cc6fa3 100644 --- a/src/main/java/de/vill/model/expression/ParenthesisExpression.java +++ b/src/main/java/de/vill/model/expression/ParenthesisExpression.java @@ -77,4 +77,9 @@ public List getReferences() { public String getReturnType() { return content.getReturnType(); } + + @Override + public Expression clone(){ + return new ParenthesisExpression(content.clone()); + } } diff --git a/src/main/java/de/vill/model/expression/StringExpression.java b/src/main/java/de/vill/model/expression/StringExpression.java index cf4b6cd..2ffcad2 100644 --- a/src/main/java/de/vill/model/expression/StringExpression.java +++ b/src/main/java/de/vill/model/expression/StringExpression.java @@ -83,4 +83,9 @@ public List getReferences() { public String getReturnType() { return Constants.STRING; } + + @Override + public Expression clone(){ + return new StringExpression(getString()); + } } diff --git a/src/main/java/de/vill/model/expression/SubExpression.java b/src/main/java/de/vill/model/expression/SubExpression.java index cdcb298..448c755 100644 --- a/src/main/java/de/vill/model/expression/SubExpression.java +++ b/src/main/java/de/vill/model/expression/SubExpression.java @@ -1,6 +1,7 @@ package de.vill.model.expression; import de.vill.model.Feature; +import de.vill.model.building.AutomaticBrackets; import de.vill.model.building.VariableReference; import de.vill.util.Constants; @@ -25,9 +26,9 @@ public Expression getRight() { @Override public String toString(boolean withSubmodels, String currentAlias) { - return left.toString(withSubmodels, currentAlias) + + return AutomaticBrackets.enforceExpressionBracketsIfNecessary(this, left, withSubmodels, currentAlias) + " - " + - right.toString(withSubmodels, currentAlias); + AutomaticBrackets.enforceExpressionBracketsIfNecessary(this, right, withSubmodels, currentAlias); } @Override @@ -80,4 +81,9 @@ public List getReferences() { public String getReturnType() { return Constants.NUMBER; } + + @Override + public Expression clone(){ + return new SubExpression(left.clone(), right.clone()); + } } diff --git a/src/main/java/de/vill/model/expression/SumAggregateFunctionExpression.java b/src/main/java/de/vill/model/expression/SumAggregateFunctionExpression.java index 4e1863a..cca56e3 100644 --- a/src/main/java/de/vill/model/expression/SumAggregateFunctionExpression.java +++ b/src/main/java/de/vill/model/expression/SumAggregateFunctionExpression.java @@ -49,4 +49,8 @@ public List getExpressionSubParts() { public String getReturnType() { return Constants.NUMBER; } + @Override + public Expression clone() { + return new SumAggregateFunctionExpression(attribute, rootFeature); + } } diff --git a/src/main/java/de/vill/util/Util.java b/src/main/java/de/vill/util/Util.java index 1ae573c..759ffda 100644 --- a/src/main/java/de/vill/util/Util.java +++ b/src/main/java/de/vill/util/Util.java @@ -26,6 +26,10 @@ public static String addNecessaryQuotes(String reference) { result.append("\""); result.append(part); result.append("\""); + } else if(part.equals("false")) { + result.append("\""); + result.append(part); + result.append("\""); } else { result.append(part); } diff --git a/src/test/java/de/vill/model/BracketsTest.java b/src/test/java/de/vill/model/BracketsTest.java new file mode 100644 index 0000000..2b06131 --- /dev/null +++ b/src/test/java/de/vill/model/BracketsTest.java @@ -0,0 +1,64 @@ +package de.vill.model; + +import de.vill.model.constraint.*; +import de.vill.model.expression.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class BracketsTest { + + + private static LiteralConstraint A; + private static LiteralConstraint B; + + private static LiteralExpression C; + private static LiteralExpression D; + + @BeforeAll + static void setUpBeforeClass() throws Exception { + A = new LiteralConstraint(new Feature("A")); + B = new LiteralConstraint(new Feature("B")); + C = new LiteralExpression(new Feature("C")); + D = new LiteralExpression(new Feature("D")); + } + + @Test + void testSimpleBooleanLogic() { + Constraint simpleOr = new OrConstraint(A,B); + Constraint simpleAnd = new AndConstraint(A,B); + Constraint simpleImply = new ImplicationConstraint(A,B); + Constraint simpleEquivalence = new EquivalenceConstraint(A,B); + + // and-or + assert new AndConstraint(simpleOr, simpleOr).toString().equals("(A | B) & (A | B)"); + assert new OrConstraint(simpleAnd, simpleAnd).toString().equals("A & B | A & B"); + + // and-imply + assert new AndConstraint(simpleImply, simpleImply).toString().equals("(A => B) & (A => B)"); + assert new ImplicationConstraint(simpleAnd, simpleAnd).toString().equals("A & B => A & B"); + + // imply-equiv + assert new ImplicationConstraint(simpleEquivalence, simpleEquivalence).toString().equals("(A <=> B) => (A <=> B)"); + assert new EquivalenceConstraint(simpleImply, simpleImply).toString().equals("A => B <=> A => B"); + } + + @Test + void testSimpleExpressions() { + Expression simpleSub = new SubExpression(C,D); + Expression simpleAdd = new AddExpression(C,D); + Expression simpleMult = new MulExpression(C,D); + Expression simpleDiv = new DivExpression(C,D); + + // add-sub + assert new AddExpression(simpleSub, simpleSub).toString().equals("(C - D) + (C - D)"); + assert new SubExpression(simpleAdd, simpleAdd).toString().equals("(C + D) - (C + D)"); + + // add-mult + assert new AddExpression(simpleMult, simpleMult).toString().equals("C * D + C * D"); + assert new MulExpression(simpleAdd, simpleAdd).toString().equals("(C + D) * (C + D)"); + + // mult-div + assert new MulExpression(simpleDiv, simpleDiv).toString().equals("(C / D) * (C / D)"); + } + +}