Skip to content
Merged
Show file tree
Hide file tree
Changes from 63 commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
2a139a3
feat: print the feature model without cross tree constraints as pseud…
st-vi Sep 13, 2024
1a03d01
feat: worked on pseudo boolean encoding
st-vi Sep 13, 2024
3fdc06d
feat: added constraint to pbc translation
st-vi Sep 13, 2024
027596b
fix: constraint pbc encoding
st-vi Sep 14, 2024
87f81c9
fix: fixed wrong constraint encoding
st-vi Sep 19, 2024
dfca14c
fix: fixed wrong constraint encoding
st-vi Oct 16, 2024
5996092
fix: error in group cardinality conversion and multi or for larger po…
st-vi Oct 17, 2024
ac989be
feat: printing fm to z3 input format
st-vi Oct 17, 2024
df1afae
feat: uvl to opb and dimacs pipeline
st-vi Oct 17, 2024
4778f46
Merge branch 'Universal-Variability-Language:refactoring_metamodel' i…
st-vi Oct 21, 2024
3144252
fix: only include satisfying assignments for an ExpressionsConstraint…
st-vi Oct 22, 2024
1d9058f
fix: also include feature constraints for pseudo-boolean encoding
st-vi Oct 22, 2024
a21f1f3
feat: pseudo boolean encoding of feature attribute constraints withou…
st-vi Oct 22, 2024
073daa4
feat: pseudo boolean encoding of feature attribute constraints with d…
st-vi Oct 23, 2024
0822b6b
feat: pseudo boolean encoding of feature attribute constraints that c…
st-vi Oct 23, 2024
e88e6dc
refactor: renaming
st-vi Oct 23, 2024
3e8bb40
fix: check for division by 0 in smt conversion
st-vi Oct 24, 2024
3667150
fix: check for division by 0 in smt conversion
st-vi Oct 24, 2024
70f2e3e
fix: simplify and fix multiplication of number and literal (before ha…
st-vi Oct 24, 2024
b34d158
fix: wrong factor sign after denominator removal
st-vi Oct 24, 2024
bbc46be
fix: error during biimplicatino transformation
st-vi Oct 24, 2024
858b753
fix: fixed pseudo boolean encoding of division (now directly like all…
st-vi Oct 25, 2024
b241f8f
multiple changes
st-vi Oct 30, 2024
113fd47
feat: automated evaluation
st-vi Oct 30, 2024
dc4b12b
fix: wrong opb encoding for group cardinality
st-vi Oct 31, 2024
8fd6e48
fix: opb encoding for double negated literals
st-vi Oct 31, 2024
aa08603
feat: eval pipeline
st-vi Oct 31, 2024
4b89614
fix: error in feature cardinality conversion strategy
st-vi Nov 4, 2024
41ddad7
feat: encode feature cardinality in pseudo-boolean
st-vi Nov 4, 2024
5cbe351
feat: encode aggregate functions and string constraints in pseudo-boo…
st-vi Nov 4, 2024
a386ecc
fix: remove multi or in feature cardinality conversion
st-vi Nov 4, 2024
4b433a1
fix: biimplication of literal and pb constraint (because former assum…
st-vi Nov 4, 2024
8d8c578
fix: conversion strategy for feature attribute constraints only searc…
st-vi Nov 4, 2024
934a6e8
feat: changed or-group pseudo-boolean encoding to are more concise on…
st-vi Nov 5, 2024
40ae056
feat: removed unnecessary IO from dimacs encoding
st-vi Nov 11, 2024
7e42d96
fix: fixed and refactored pbc encoding
st-vi Nov 21, 2024
85929d5
fix: fixed pbc encoding for single negated literal constraints
st-vi Nov 21, 2024
3c4adc1
fix: simplified and fixed opb encoding
st-vi Nov 23, 2024
d983695
refactor: simplified PBConstraint
st-vi Nov 23, 2024
7c8397b
refactor: default value for literal sign
st-vi Nov 23, 2024
6fcf920
refactor: escape every feature name with " to avoid errors with solve…
st-vi Nov 23, 2024
2b1cfe1
refactor: escape every feature name with " to avoid errors with solve…
st-vi Nov 23, 2024
cadc16c
fix: feature cardinality conversion strategy (set right constraint re…
st-vi Nov 23, 2024
2eddf76
fix: several bugs and added new semantic for constraints containing c…
st-vi Nov 23, 2024
772a08f
fix: attribute cloning, remove unnecessary attributes for cloned feat…
st-vi Nov 28, 2024
89d1645
feat: added support for distributive cross-tree constraint encoding (…
st-vi Nov 30, 2024
e63866c
feat: added support for distributive opb encoding
st-vi Dec 5, 2024
f1b9c8f
fix: set quotes for feature name "false"
st-vi Dec 17, 2024
83b103f
refactor: moved all pseudo-boolean related code into another project
st-vi Dec 18, 2024
5f6c038
fix: use multior in smt conversion to prevent stack overflow
st-vi Dec 19, 2024
a606dc1
fix: drop typelevel conversion also considers constraints with type r…
st-vi Jan 19, 2025
44a90bb
Delete .idea/.gitignore
st-vi Jan 22, 2025
6b1dd66
Delete .idea directory
st-vi Jan 22, 2025
2f49f18
refactor: removed unnecessary files
st-vi Jan 22, 2025
69cec26
Merge remote-tracking branch 'origin/refactoring_metamodel' into refa…
st-vi Jan 22, 2025
7c9dcf6
refactor: applied code auto-formatting
st-vi Jan 23, 2025
997298e
refactor: changed back to maven dependencies
st-vi Jan 23, 2025
6cd2983
Merge pull request #8 from st-vi/refactoring_metamodel
SundermannC Jan 26, 2025
e5687e7
Added automatic bracket creation when printing UVL models
SundermannC Jan 28, 2025
b794dbc
Added unit tests for brackets; small fix
SundermannC Jan 28, 2025
5d73f92
Several changes to simplify changing identifiers programatically with…
SundermannC Feb 27, 2025
3f7c495
Merge branch 'main' into refactoring_metamodel
SundermannC Sep 1, 2025
50941df
Resolved issues following merge
SundermannC Sep 1, 2025
5edec1f
misc: updated changes according to Kevin's review
SundermannC Sep 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 130 additions & 20 deletions src/main/java/de/vill/conversion/ConvertFeatureCardinality.java
Original file line number Diff line number Diff line change
@@ -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.*;

Expand Down Expand Up @@ -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<Boolean>("abstract", true, feature));
newChildren.getFeatures().add(newChild);
newChild.setParentGroup(newChildren);
Expand All @@ -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<Boolean>("abstract", true, subTreeClone));
addPrefixToNamesRecursively(subTreeClone, "-" + i + "-" + j, featureModel);
mandatoryGroup.getFeatures().add(subTreeClone);
subTreeClone.setParentGroup(mandatoryGroup);

Expand All @@ -71,22 +73,77 @@ 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);
}
}
}
/*
additional constraint with all cloned versions ored
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a particular reason to leave the comments in?
Please remove these comments, otherwise.

Set<String> allFeatureNamesInSubTree = new HashSet<>();
getAllSubFeatureNamesRecursively(feature, allFeatureNamesInSubTree);
for (Constraint constraint : constraintsToClone) {
Constraint newConstraint = constraint.clone();
orAdaptedConstraint(newConstraint, allFeatureNamesInSubTree, min, max, featureModel);
featureModel.getOwnConstraints().add(newConstraint);
}

*/


feature.getChildren().removeAll(feature.getChildren());
feature.getChildren().add(newChildren);
newChildren.setParentFeature(feature);
}

private void addPrefixToNamesRecursively(Feature feature, String prefix) {
private void orAdaptedConstraint(Constraint constraint, Set<String> featuresToReplace, int min, int max, FeatureModel featureModel) {
for (Constraint subPart : constraint.getConstraintSubParts()) {
if (subPart instanceof LiteralConstraint) {
String toReplace = ((LiteralConstraint) subPart).getReference().getIdentifier();
if (featuresToReplace.contains(toReplace)) {
Feature f = featureModel.getFeatureMap().get(toReplace + "-" + (min == 0 ? 1 : min) + "-1");
Constraint newOr = new LiteralConstraint(f);
for (int i = min + 1; i <= max; i++) {
for (int j = 1; j <= i; j++) {
newOr = new OrConstraint(newOr, new LiteralConstraint(featureModel.getFeatureMap().get(toReplace + "-" + i + "-" + j)));
}
}
constraint.replaceConstraintSubPart(subPart, new ParenthesisConstraint(newOr));
}
} else {
orAdaptedConstraint(subPart, featuresToReplace, min, max, featureModel);
}
}
}

private void getAllSubFeatureNamesRecursively(Feature feature, Set<String> names) {
names.add(feature.getFeatureName());
for (Group child : feature.getChildren()) {
for (Feature childFeature : child.getFeatures()) {
getAllSubFeatureNamesRecursively(childFeature, names);
}
}
}

private void addPrefixToNamesRecursively(Feature feature, String prefix, FeatureModel featureModel) {
feature.setFeatureName(feature.getFeatureName() + prefix);
var attributes = feature.getAttributes();
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);
}
}
}
Expand Down Expand Up @@ -118,14 +175,46 @@ private List<Feature> getFeatureFromSubTree(Group group) {

private boolean constraintContains(Constraint constraint, List<Feature> subTreeFeatures) {
List<Constraint> 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);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This if-else statement is very specific.
Can we guarantee that there only will be these cases? If not, we may want to add some sort of log, error statement in an else branch of the cascade.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this makes sense. It should only be those three cases in this abstraction level:

  1. Found the atom to collect it
  2. Constraint is an expression, so we switch to "expression mode" for the traversal
  3. Traverse all subparts of the constraint


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<Feature> 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;
Expand All @@ -144,17 +233,38 @@ private void createFeatureReplacementMap(Feature oldSubTree, Feature newSubTree,
}

private void adaptConstraint(Feature subTreeRoot, Constraint constraint, Map<String, Feature> featureReplacementMap) {
List<Constraint> 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<Constraint> 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<String, Feature> 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);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ private void removeGroupCardinality(Group group, FeatureModel featureModel) {
Set<Feature> 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<Set<Feature>> featureCombinations = new HashSet<>();
for (int i = lowerBound; i <= upperBound; i++) {
featureCombinations.addAll(Sets.combinations(groupMembers, i));
Expand Down Expand Up @@ -81,6 +81,11 @@ private Constraint createConjunction(Set<Feature> selectedFeatures, Set<Feature>
}

private Constraint createDisjunction(Set<Constraint> constraints) {
MultiOrConstraint orConstraint = new MultiOrConstraint();
for (Constraint constraint : constraints) {
orConstraint.add_sub_part(constraint);
}
/*
Constraint orConstraint;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as before. Please remove code in comments.

if (constraints.size() == 1) {
Constraint constraint = constraints.iterator().next();
Expand All @@ -92,6 +97,8 @@ private Constraint createDisjunction(Set<Constraint> constraints) {
orConstraint = new OrConstraint(constraint, createDisjunction(constraints));
}

*/

return orConstraint;
}
}
57 changes: 44 additions & 13 deletions src/main/java/de/vill/conversion/ConvertSMTLevel.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,33 +19,53 @@ public Set<LanguageLevel> 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<Constraint> constraints = featureModel.getFeatureConstraints();
constraints.addAll(featureModel.getOwnConstraints());
constraints.stream().forEach(this::replaceEquationInConstraint);
for(Constraint constraint : constraints) {
replaceEquationInConstraint(constraint, featureModel);
}
List<Constraint> 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<Feature> featuresInEquation = getFeaturesInEquation(equation);
Set<Set<Feature>> featureCombinations = getFeatureCombinations(featuresInEquation);
Set<Constraint> disjunction = new HashSet<>();
Expand All @@ -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<Feature> getFeaturesInEquation(ExpressionConstraint equation) {
Expand Down Expand Up @@ -112,6 +136,11 @@ private Constraint createConjunction(Set<Feature> selectedFeatures, Set<Feature>
}

private Constraint createDisjunction(Set<Constraint> constraints) {
MultiOrConstraint orConstraint = new MultiOrConstraint();
for (Constraint constraint : constraints) {
orConstraint.add_sub_part(constraint);
}
/*
Constraint orConstraint;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove comments.

if (constraints.size() == 1) {
Constraint constraint = constraints.iterator().next();
Expand All @@ -123,23 +152,25 @@ private Constraint createDisjunction(Set<Constraint> constraints) {
orConstraint = new OrConstraint(constraint, createDisjunction(constraints));
}

*/

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));
}
}
if (attributeConstraintList != null && attributeConstraintList.getValue() instanceof List<?>) {
List<Object> 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);
Expand All @@ -149,11 +180,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);
}
}
}
Expand Down
Loading
Loading