From f25e1f589ba7c9984af4c77776f43d6746bf98b1 Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Mon, 24 Jul 2023 15:09:20 +0200 Subject: Enabled QueryTransactionTest --- .../java/tools/refinery/store/query/viatra/QueryTransactionTest.java | 3 --- 1 file changed, 3 deletions(-) (limited to 'subprojects/store-query-viatra') diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java index 66f043c6..32f51cf0 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java @@ -6,7 +6,6 @@ package tools.refinery.store.query.viatra; import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import tools.refinery.store.model.ModelStore; import tools.refinery.store.query.ModelQueryAdapter; @@ -283,7 +282,6 @@ class QueryTransactionTest { assertResults(Map.of(Tuple.of(0), false), queryResultSet); } - @Disabled("TODO Fix DiffCursor") @Test void commitAfterFlushTest() { var store = ModelStore.builder() @@ -332,7 +330,6 @@ class QueryTransactionTest { ), predicateResultSet); } - @Disabled("TODO Fix DiffCursor") @Test void commitWithoutFlushTest() { var store = ModelStore.builder() -- cgit v1.2.3-70-g09d2 From b34d844a40d0bc4095df6e4d7c4fad4eec2d919b Mon Sep 17 00:00:00 2001 From: nagilooh Date: Fri, 21 Jul 2023 16:49:53 +0200 Subject: Add Design space exploration and DFS strategy - Transformation rules - Design Space Exploration adapter - Depth First Strategy --- subprojects/store-query-viatra/build.gradle.kts | 1 + .../refinery/store/query/dse/ActionFactory.java | 9 + .../query/dse/DesignSpaceExplorationAdapter.java | 55 +++ .../query/dse/DesignSpaceExplorationBuilder.java | 55 +++ .../dse/DesignSpaceExplorationStoreAdapter.java | 6 + .../tools/refinery/store/query/dse/Strategy.java | 10 + .../store/query/dse/internal/Activation.java | 9 + .../DesignSpaceExplorationAdapterImpl.java | 256 +++++++++++++ .../DesignSpaceExplorationBuilderImpl.java | 77 ++++ .../DesignSpaceExplorationStoreAdapterImpl.java | 64 ++++ .../query/dse/internal/TransformationRule.java | 85 +++++ .../AlwaysSatisfiedDummyHardObjective.java | 51 +++ .../store/query/dse/objectives/BaseObjective.java | 147 ++++++++ .../store/query/dse/objectives/Comparators.java | 25 ++ .../store/query/dse/objectives/Fitness.java | 21 ++ .../dse/objectives/LeveledObjectivesHelper.java | 114 ++++++ .../store/query/dse/objectives/Objective.java | 110 ++++++ .../dse/objectives/ObjectiveComparatorHelper.java | 218 +++++++++++ .../query/dse/strategy/DepthFirstStrategy.java | 108 ++++++ .../query/dse/DesignSpaceExplorationTest.java | 117 ++++++ .../store/query/dse/TransformationRuleTest.java | 403 +++++++++++++++++++++ .../model/internal/ModelStoreBuilderImpl.java | 6 +- 22 files changed, 1944 insertions(+), 3 deletions(-) create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/ActionFactory.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationAdapter.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationBuilder.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationStoreAdapter.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/Strategy.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/Activation.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationBuilderImpl.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/TransformationRule.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/AlwaysSatisfiedDummyHardObjective.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/BaseObjective.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Comparators.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Fitness.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/LeveledObjectivesHelper.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Objective.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/ObjectiveComparatorHelper.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/strategy/DepthFirstStrategy.java create mode 100644 subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DesignSpaceExplorationTest.java create mode 100644 subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/TransformationRuleTest.java (limited to 'subprojects/store-query-viatra') diff --git a/subprojects/store-query-viatra/build.gradle.kts b/subprojects/store-query-viatra/build.gradle.kts index e3a22145..85ea7e2e 100644 --- a/subprojects/store-query-viatra/build.gradle.kts +++ b/subprojects/store-query-viatra/build.gradle.kts @@ -12,4 +12,5 @@ dependencies { implementation(libs.ecore) api(libs.viatra) api(project(":refinery-store-query")) + api(project(":refinery-store-reasoning")) } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/ActionFactory.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/ActionFactory.java new file mode 100644 index 00000000..e2f452c3 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/ActionFactory.java @@ -0,0 +1,9 @@ +package tools.refinery.store.query.dse; + +import org.eclipse.collections.api.block.procedure.Procedure; +import tools.refinery.store.model.Model; +import tools.refinery.store.tuple.Tuple; + +public interface ActionFactory { + Procedure prepare(Model model); +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationAdapter.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationAdapter.java new file mode 100644 index 00000000..e7ce7b2c --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationAdapter.java @@ -0,0 +1,55 @@ +package tools.refinery.store.query.dse; + +import tools.refinery.store.adapter.ModelAdapter; +import tools.refinery.store.query.dse.internal.Activation; +import tools.refinery.store.query.dse.internal.DesignSpaceExplorationBuilderImpl; +import tools.refinery.store.query.dse.objectives.Fitness; +import tools.refinery.store.query.dse.objectives.ObjectiveComparatorHelper; +import tools.refinery.store.tuple.Tuple; +import tools.refinery.store.tuple.Tuple1; + +import java.util.Collection; +import java.util.List; + +public interface DesignSpaceExplorationAdapter extends ModelAdapter { + @Override + DesignSpaceExplorationStoreAdapter getStoreAdapter(); + + static DesignSpaceExplorationBuilder builder() { + return new DesignSpaceExplorationBuilderImpl(); + } + + Collection explore(); + + public int getModelSize(); + + public Tuple1 createObject(); + + public Tuple deleteObject(Tuple tuple); + + public boolean checkGlobalConstraints(); + + public boolean backtrack(); + + public Fitness calculateFitness(); + + public void newSolution(); + + public int getDepth(); + + public Collection getUntraversedActivations(); + + public boolean fireActivation(Activation activation); + + public void fireRandomActivation(); + + public boolean isCurrentInTrajectory(); + + public List getTrajectory(); + + public boolean isCurrentStateAlreadyTraversed(); + + public ObjectiveComparatorHelper getObjectiveComparatorHelper(); + + public void restoreTrajectory(List trajectory); +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationBuilder.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationBuilder.java new file mode 100644 index 00000000..0ec6f599 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationBuilder.java @@ -0,0 +1,55 @@ +package tools.refinery.store.query.dse; + +import tools.refinery.store.adapter.ModelAdapterBuilder; +import tools.refinery.store.query.dnf.AnyQuery; +import tools.refinery.store.query.dnf.RelationalQuery; +import tools.refinery.store.query.dse.internal.TransformationRule; +import tools.refinery.store.query.dse.objectives.Objective; + +import java.util.Collection; +import java.util.List; + +public interface DesignSpaceExplorationBuilder extends ModelAdapterBuilder { + default DesignSpaceExplorationBuilder stopConditions(AnyQuery... stopConditions) { + return stopConditions(List.of(stopConditions)); + } + + default DesignSpaceExplorationBuilder stopConditions(Collection stopConditions) { + stopConditions.forEach(this::stopCondition); + return this; + } + + default DesignSpaceExplorationBuilder transformations(TransformationRule... transformationRules) { + return transformations(List.of(transformationRules)); + } + + default DesignSpaceExplorationBuilder transformations(Collection transformationRules) { + transformationRules.forEach(this::transformation); + return this; + } + + default DesignSpaceExplorationBuilder globalConstraints(RelationalQuery... globalConstraints) { + return globalConstraints(List.of(globalConstraints)); + } + + default DesignSpaceExplorationBuilder globalConstraints(Collection globalConstraints) { + globalConstraints.forEach(this::globalConstraint); + return this; + } + + default DesignSpaceExplorationBuilder objectives(Objective... objectives) { + return objectives(List.of(objectives)); + } + + default DesignSpaceExplorationBuilder objectives(Collection objectives) { + objectives.forEach(this::objective); + return this; + } + + DesignSpaceExplorationBuilder stopCondition(AnyQuery stopCondition); + + DesignSpaceExplorationBuilder transformation(TransformationRule transformationRule); + DesignSpaceExplorationBuilder globalConstraint(RelationalQuery globalConstraint); + DesignSpaceExplorationBuilder objective(Objective objective); + DesignSpaceExplorationBuilder strategy(Strategy strategy); +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationStoreAdapter.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationStoreAdapter.java new file mode 100644 index 00000000..21b10f0e --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationStoreAdapter.java @@ -0,0 +1,6 @@ +package tools.refinery.store.query.dse; + +import tools.refinery.store.adapter.ModelStoreAdapter; + +public interface DesignSpaceExplorationStoreAdapter extends ModelStoreAdapter { +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/Strategy.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/Strategy.java new file mode 100644 index 00000000..0aeea818 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/Strategy.java @@ -0,0 +1,10 @@ +package tools.refinery.store.query.dse; + +import tools.refinery.store.model.Model; + +public interface Strategy { + + public void initStrategy(DesignSpaceExplorationAdapter designSpaceExplorationAdapter); + + public void explore(); +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/Activation.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/Activation.java new file mode 100644 index 00000000..82a4c978 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/Activation.java @@ -0,0 +1,9 @@ +package tools.refinery.store.query.dse.internal; + +import tools.refinery.store.tuple.Tuple; + +public record Activation(TransformationRule transformationRule, Tuple activation) { + public boolean fire() { + return transformationRule.fireActivation(activation); + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java new file mode 100644 index 00000000..5adf8306 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java @@ -0,0 +1,256 @@ +package tools.refinery.store.query.dse.internal; + +import tools.refinery.store.model.Interpretation; +import tools.refinery.store.model.Model; +import tools.refinery.store.query.ModelQueryAdapter; +import tools.refinery.store.query.dnf.RelationalQuery; +import tools.refinery.store.query.dse.DesignSpaceExplorationAdapter; +import tools.refinery.store.query.dse.DesignSpaceExplorationStoreAdapter; +import tools.refinery.store.query.dse.Strategy; +import tools.refinery.store.query.dse.objectives.Fitness; +import tools.refinery.store.query.dse.objectives.LeveledObjectivesHelper; +import tools.refinery.store.query.dse.objectives.Objective; +import tools.refinery.store.query.dse.objectives.ObjectiveComparatorHelper; +import tools.refinery.store.query.resultset.ResultSet; +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.tuple.Tuple; +import tools.refinery.store.tuple.Tuple1; + +import java.util.*; + +public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExplorationAdapter { + static final Symbol NODE_COUNT_SYMBOL = Symbol.of("MODEL_SIZE", 0, Integer.class, 0); + private final Model model; + private final ModelQueryAdapter queryEngine; + private final DesignSpaceExplorationStoreAdapterImpl storeAdapter; + private final Set transformationRules; + private final Set globalConstraints; + private final List objectives; + private final Set> globalConstraintResultSets = new HashSet<>(); + private final Interpretation sizeInterpretation; + private final Strategy strategy; + + private ObjectiveComparatorHelper objectiveComparatorHelper; + private List trajectory = new LinkedList<>(); + private Fitness lastFitness; + private final Set solutions = new HashSet<>(); +// private Map> statesAndActivations; + private Map> statesAndUntraversedActivations; + private Map> statesAndTraversedActivations; + private Random random = new Random(); + private Objective[][] leveledObjectives; + private boolean isNewState = false; + + public List getTrajectory() { + return trajectory; + } + + public DesignSpaceExplorationAdapterImpl(Model model, DesignSpaceExplorationStoreAdapterImpl storeAdapter) { + this.model = model; + this.storeAdapter = storeAdapter; + this.sizeInterpretation = model.getInterpretation(NODE_COUNT_SYMBOL); + queryEngine = model.getAdapter(ModelQueryAdapter.class); + + globalConstraints = storeAdapter.getGlobalConstraints(); + for (var constraint : globalConstraints) { + globalConstraintResultSets.add(queryEngine.getResultSet(constraint)); + } + + transformationRules = storeAdapter.getTransformationSpecifications(); + for (var rule : transformationRules) { + rule.prepare(model, queryEngine); + } + + objectives = storeAdapter.getObjectives(); + leveledObjectives = new LeveledObjectivesHelper(objectives).initLeveledObjectives(); + statesAndUntraversedActivations = new HashMap<>(); + statesAndTraversedActivations = new HashMap<>(); + strategy = storeAdapter.getStrategy(); + + } + + @Override + public Model getModel() { + return model; + } + + @Override + public DesignSpaceExplorationStoreAdapter getStoreAdapter() { + return storeAdapter; + } + + @Override + public Collection explore() { + var state = model.commit(); + trajectory.add(state); + statesAndUntraversedActivations.put(state, getAllActivations()); + statesAndTraversedActivations.put(state, new HashSet<>()); + strategy.initStrategy(this); + strategy.explore(); + return solutions; + } + + @Override + public int getModelSize() { + return sizeInterpretation.get(Tuple.of()); + } + + @Override + public Tuple1 createObject() { + var newNodeId = getModelSize(); + sizeInterpretation.put(Tuple.of(), newNodeId + 1); + return Tuple.of(newNodeId); + } + + @Override + public Tuple deleteObject(Tuple tuple) { + if (tuple.getSize() != 1) { + throw new IllegalArgumentException("Tuple size must be 1"); + } +// TODO: implement more efficient deletion +// if (tuple.get(0) == getModelSize() - 1) { +// sizeInterpretation.put(Tuple.of(), getModelSize() - 1); +// } + return tuple; + } + + @Override + public boolean checkGlobalConstraints() { + for (var resultSet : globalConstraintResultSets) { + if (resultSet.size() > 0) { + return false; + } + } + return true; + } + + @Override + public boolean backtrack() { + if (trajectory.size() < 2) { + return false; + } + model.restore(trajectory.get(trajectory.size() - 2)); + trajectory.remove(trajectory.size() - 1); + return true; + } + + @Override + public void restoreTrajectory(List trajectory) { + model.restore(trajectory.get(trajectory.size() - 1)); + this.trajectory = trajectory; + + } + + @Override + public Fitness calculateFitness() { + Fitness result = new Fitness(); + boolean satisfiesHardObjectives = true; + for (Objective objective : objectives) { + var fitness = objective.getFitness(this); + result.put(objective.getName(), fitness); + if (objective.isHardObjective() && !objective.satisfiesHardObjective(fitness)) { + satisfiesHardObjectives = false; + } + } + result.setSatisfiesHardObjectives(satisfiesHardObjectives); + + lastFitness = result; + + return result; + } + + @Override + public void newSolution() { + var state = model.getState(); + solutions.add(state); + } + + @Override + public int getDepth() { + return trajectory.size() - 1; + } + + public Collection getUntraversedActivations() { +// return statesAndUntraversedActivations.get(model.getState()); + List untraversedActivations = new ArrayList<>(); + for (Activation activation : getAllActivations()) { + if (!statesAndTraversedActivations.get(model.getState()).contains(activation)) { + untraversedActivations.add(activation); + } + } + + return untraversedActivations; + } + + @Override + public boolean fireActivation(Activation activation) { + if (activation == null) { + return false; + } + long previousState = model.getState(); + if (!statesAndUntraversedActivations.get(previousState).contains(activation)) { +// TODO: throw exception? + return false; + } + if (!activation.fire()) { + return false; + } + statesAndUntraversedActivations.get(previousState).remove(activation); + statesAndTraversedActivations.get(previousState).add(activation); + long newState = model.commit(); + trajectory.add(newState); + isNewState = !statesAndUntraversedActivations.containsKey(newState); + statesAndUntraversedActivations.put(newState, getAllActivations()); + statesAndTraversedActivations.put(newState, new HashSet<>()); + return true; + } + + @Override + public void fireRandomActivation() { + var activations = getUntraversedActivations(); + if (activations.isEmpty()) { +// TODO: throw exception + return; + } + int index = random.nextInt(activations.size()); + var iterator = activations.iterator(); + while (index-- > 0) { + iterator.next(); + } + var activationId = iterator.next(); + fireActivation(activationId); + } + + @Override + public boolean isCurrentInTrajectory() { + return trajectory.contains(model.getState()); + } + + public Collection getAllActivations() { + Collection result = new HashSet<>(); + for (var rule : transformationRules) { + result.addAll(rule.getAllActivations()); + } + return result; + } + + public boolean isCurrentStateAlreadyTraversed() { +// TODO: check isomorphism? + return !isNewState; + } + + public Fitness getLastFitness() { + return lastFitness; + } + + public ObjectiveComparatorHelper getObjectiveComparatorHelper() { + if (objectiveComparatorHelper == null) { + objectiveComparatorHelper = new ObjectiveComparatorHelper(leveledObjectives); + } + return objectiveComparatorHelper; + } + + public Objective[][] getLeveledObjectives() { + return leveledObjectives; + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationBuilderImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationBuilderImpl.java new file mode 100644 index 00000000..79864de0 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationBuilderImpl.java @@ -0,0 +1,77 @@ +package tools.refinery.store.query.dse.internal; + +import tools.refinery.store.adapter.AbstractModelAdapterBuilder; +import tools.refinery.store.model.ModelStore; +import tools.refinery.store.model.ModelStoreBuilder; +import tools.refinery.store.query.dnf.AnyQuery; +import tools.refinery.store.query.dnf.RelationalQuery; +import tools.refinery.store.query.dse.DesignSpaceExplorationBuilder; +import tools.refinery.store.query.dse.Strategy; +import tools.refinery.store.query.dse.objectives.Objective; + +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +public class DesignSpaceExplorationBuilderImpl + extends AbstractModelAdapterBuilder + implements DesignSpaceExplorationBuilder { + + private final Set stopConditionSpecifications = new LinkedHashSet<>(); + private final Set transformationSpecifications = new LinkedHashSet<>(); + private final Set globalConstraints = new LinkedHashSet<>(); + private final List objectives = new LinkedList<>(); + private Strategy strategy; + + @Override + protected DesignSpaceExplorationStoreAdapterImpl doBuild(ModelStore store) { + return new DesignSpaceExplorationStoreAdapterImpl(store, stopConditionSpecifications, + transformationSpecifications, globalConstraints, objectives, strategy); + } + + @Override + public DesignSpaceExplorationBuilder stopCondition(AnyQuery stopCondition) { + checkNotConfigured(); + stopConditionSpecifications.add(stopCondition); + return this; + } + + @Override + public DesignSpaceExplorationBuilder transformation(TransformationRule transformationRule) { + checkNotConfigured(); + transformationSpecifications.add(transformationRule); + return this; + } + + @Override + public DesignSpaceExplorationBuilder globalConstraint(RelationalQuery globalConstraint) { + checkNotConfigured(); + globalConstraints.add(globalConstraint); + return this; + } + + @Override + public DesignSpaceExplorationBuilder objective(Objective objective) { + checkNotConfigured(); + objectives.add(objective); + return this; + } + + @Override + public DesignSpaceExplorationBuilder strategy(Strategy strategy) { + checkNotConfigured(); + this.strategy = strategy; + return this; + } + + public Set getStopConditionSpecifications() { + return stopConditionSpecifications; + } + + @Override + protected void doConfigure(ModelStoreBuilder storeBuilder) { + storeBuilder.symbols(DesignSpaceExplorationAdapterImpl.NODE_COUNT_SYMBOL); + super.doConfigure(storeBuilder); + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java new file mode 100644 index 00000000..9c2fa4d6 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java @@ -0,0 +1,64 @@ +package tools.refinery.store.query.dse.internal; + +import tools.refinery.store.adapter.ModelAdapter; +import tools.refinery.store.query.dnf.AnyQuery; +import tools.refinery.store.query.dnf.RelationalQuery; +import tools.refinery.store.query.dse.DesignSpaceExplorationStoreAdapter; +import tools.refinery.store.model.Model; +import tools.refinery.store.model.ModelStore; +import tools.refinery.store.query.dse.Strategy; +import tools.refinery.store.query.dse.objectives.Objective; + +import java.util.List; +import java.util.Set; + +public class DesignSpaceExplorationStoreAdapterImpl implements DesignSpaceExplorationStoreAdapter { + private final ModelStore store; + private final Set stopConditionSpecifications; + private final Set transformationSpecifications; + private final Set globalConstraints; + private final List objectives; + private final Strategy strategy; + + public DesignSpaceExplorationStoreAdapterImpl(ModelStore store, Set stopConditionSpecifications, + Set transformationSpecifications, + Set globalConstraints, List objectives, + Strategy strategy) { + this.store = store; + this.stopConditionSpecifications = stopConditionSpecifications; + this.transformationSpecifications = transformationSpecifications; + this.globalConstraints = globalConstraints; + this.objectives = objectives; + this.strategy = strategy; + } + + @Override + public ModelStore getStore() { + return store; + } + + @Override + public ModelAdapter createModelAdapter(Model model) { + return new DesignSpaceExplorationAdapterImpl(model, this); + } + + public Set getStopConditionSpecifications() { + return stopConditionSpecifications; + } + + public Set getTransformationSpecifications() { + return transformationSpecifications; + } + + public Set getGlobalConstraints() { + return globalConstraints; + } + + public List getObjectives() { + return objectives; + } + + public Strategy getStrategy() { + return strategy; + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/TransformationRule.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/TransformationRule.java new file mode 100644 index 00000000..c46ff712 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/TransformationRule.java @@ -0,0 +1,85 @@ +package tools.refinery.store.query.dse.internal; + +import org.eclipse.collections.api.block.procedure.Procedure; +import tools.refinery.store.model.Model; +import tools.refinery.store.query.ModelQueryAdapter; +import tools.refinery.store.query.dnf.RelationalQuery; +import tools.refinery.store.query.dse.ActionFactory; +import tools.refinery.store.query.resultset.OrderedResultSet; +import tools.refinery.store.query.resultset.ResultSet; +import tools.refinery.store.tuple.Tuple; + +import java.util.HashSet; +import java.util.Random; +import java.util.Set; + +public class TransformationRule { + + private final String name; + private final RelationalQuery precondition; + private final ActionFactory actionFactory; + private Procedure action; + private OrderedResultSet activations; + private Random random; + private ModelQueryAdapter queryEngine; + + public TransformationRule(String name, RelationalQuery precondition, ActionFactory actionFactory) { + this(name, precondition, actionFactory, new Random()); + } + + public TransformationRule(String name, RelationalQuery precondition, ActionFactory actionFactory, long seed) { + this(name, precondition, actionFactory, new Random(seed)); + } + + public TransformationRule(String name, RelationalQuery precondition, ActionFactory actionFactory, Random random) { + this.name = name; + this.precondition = precondition; + this.actionFactory = actionFactory; + this.random = random; + } + public boolean prepare(Model model, ModelQueryAdapter queryEngine) { + action = actionFactory.prepare(model); + this.queryEngine = queryEngine; + activations = new OrderedResultSet<>(queryEngine.getResultSet(precondition)); + return true; + } + + public boolean fireActivation(Tuple activation) { + action.accept(activation); + queryEngine.flushChanges(); + return true; + } + + public boolean fireRandomActivation() { + return getRandomActivation().fire(); + } + + public String getName() { + return name; + } + + public RelationalQuery getPrecondition() { + return precondition; + } + + public ResultSet getAllActivationsAsSets() { + return activations; + } + + public Set getAllActivations() { + var result = new HashSet(); + var cursor = activations.getAll(); + while (cursor.move()) { + result.add(new Activation(this, cursor.getKey())); + } + return result; + } + + public Activation getRandomActivation() { + return new Activation(this, activations.getKey(random.nextInt(activations.size()))); + } + + public Activation getActivation(int index) { + return new Activation(this, activations.getKey(index)); + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/AlwaysSatisfiedDummyHardObjective.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/AlwaysSatisfiedDummyHardObjective.java new file mode 100644 index 00000000..26744d94 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/AlwaysSatisfiedDummyHardObjective.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2010-2016, Andras Szabolcs Nagy, Zoltan Ujhelyi and Daniel Varro + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-v20.html. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package tools.refinery.store.query.dse.objectives; + +import tools.refinery.store.query.dse.DesignSpaceExplorationAdapter; + +/** + * This hard objective is fulfilled in any circumstances. Use it if all states should be regarded as a valid solution. + * + * @author Andras Szabolcs Nagy + * + */ +public class AlwaysSatisfiedDummyHardObjective extends BaseObjective { + + private static final String DEFAULT_NAME = "AlwaysSatisfiedDummyHardObjective"; + + public AlwaysSatisfiedDummyHardObjective() { + super(DEFAULT_NAME); + } + + public AlwaysSatisfiedDummyHardObjective(String name) { + super(name); + } + + @Override + public Double getFitness(DesignSpaceExplorationAdapter context) { + return 0d; + } + + @Override + public boolean isHardObjective() { + return true; + } + + @Override + public boolean satisfiesHardObjective(Double fitness) { + return true; + } + + @Override + public Objective createNew() { + return this; + } + +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/BaseObjective.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/BaseObjective.java new file mode 100644 index 00000000..fd8529f7 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/BaseObjective.java @@ -0,0 +1,147 @@ +/******************************************************************************* + * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-v20.html. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package tools.refinery.store.query.dse.objectives; + +import tools.refinery.store.query.dse.DesignSpaceExplorationAdapter; + +import java.util.Comparator; +import java.util.Objects; + +/** + * This abstract class implements the basic functionality of an objective ({@link Objective} namely its name, + * comparator, level and fitness hard constraint. + * + * @author Andras Szabolcs Nagy + * + */ +public abstract class BaseObjective implements Objective { + + protected final String name; + protected Comparator comparator = Comparators.HIGHER_IS_BETTER; + protected int level = 0; + + protected double fitnessConstraint; + protected boolean isThereFitnessConstraint = false; + protected Comparator fitnessConstraintComparator; + + public BaseObjective(String name) { + Objects.requireNonNull(name, "Name of the objective cannot be null."); + this.name = name; + } + + @Override + public String getName() { + return name; + } + + @Override + public void setComparator(Comparator comparator) { + this.comparator = comparator; + } + + @Override + public Comparator getComparator() { + return comparator; + } + + @Override + public void setLevel(int level) { + this.level = level; + } + + @Override + public int getLevel() { + return level; + } + + public BaseObjective withLevel(int level) { + setLevel(level); + return this; + } + + public BaseObjective withComparator(Comparator comparator) { + setComparator(comparator); + return this; + } + + /** + * Adds a hard constraint on the fitness value. For example, the fitness value must be better than 10 to accept the + * current state as a solution. + * + * @param fitnessConstraint + * Solutions should be better than this value. + * @param fitnessConstraintComparator + * {@link Comparator} to determine if the current state is better than the given value. + * @return The actual instance to enable builder pattern like usage. + */ + public BaseObjective withHardConstraintOnFitness(double fitnessConstraint, + Comparator fitnessConstraintComparator) { + this.fitnessConstraint = fitnessConstraint; + this.fitnessConstraintComparator = fitnessConstraintComparator; + this.isThereFitnessConstraint = true; + return this; + } + + /** + * Adds a hard constraint on the fitness value. For example, the fitness value must be better than 10 to accept the + * current state as a solution. The provided comparator will be used. + * + * @param fitnessConstraint + * Solutions should be better than this value. + * @return The actual instance to enable builder pattern like usage. + */ + public BaseObjective withHardConstraintOnFitness(double fitnessConstraint) { + return withHardConstraintOnFitness(fitnessConstraint, null); + } + + @Override + public void init(DesignSpaceExplorationAdapter context) { + if (fitnessConstraintComparator == null) { + fitnessConstraintComparator = comparator; + } + } + + @Override + public boolean isHardObjective() { + return isThereFitnessConstraint; + } + + @Override + public boolean satisfiesHardObjective(Double fitness) { + if (isThereFitnessConstraint) { + int compare = fitnessConstraintComparator.compare(fitness, fitnessConstraint); + if (compare < 0) { + return false; + } + } + return true; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof BaseObjective baseObjective) { + return name.equals(baseObjective.getName()); + } + return false; + } + + @Override + public String toString() { + return name; + } + +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Comparators.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Comparators.java new file mode 100644 index 00000000..7fba6736 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Comparators.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-v20.html. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package tools.refinery.store.query.dse.objectives; + +import java.util.Comparator; + +public class Comparators { + + private Comparators() { /*Utility class constructor*/ } + + public static final Comparator HIGHER_IS_BETTER = (o1, o2) -> o1.compareTo(o2); + + public static final Comparator LOWER_IS_BETTER = (o1, o2) -> o2.compareTo(o1); + + private static final Double ZERO = (double) 0; + + public static final Comparator DIFFERENCE_TO_ZERO_IS_BETTER = (o1, o2) -> ZERO.compareTo(Math.abs(o1)-Math.abs(o2)); + +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Fitness.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Fitness.java new file mode 100644 index 00000000..ea80ed55 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Fitness.java @@ -0,0 +1,21 @@ +package tools.refinery.store.query.dse.objectives; + +import java.util.HashMap; + +public class Fitness extends HashMap { + + private boolean satisfiesHardObjectives; + + public boolean isSatisfiesHardObjectives() { + return satisfiesHardObjectives; + } + + public void setSatisfiesHardObjectives(boolean satisfiesHardObjectives) { + this.satisfiesHardObjectives = satisfiesHardObjectives; + } + + @Override + public String toString() { + return super.toString() + " hardObjectives=" + satisfiesHardObjectives; + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/LeveledObjectivesHelper.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/LeveledObjectivesHelper.java new file mode 100644 index 00000000..6c4e7837 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/LeveledObjectivesHelper.java @@ -0,0 +1,114 @@ +/******************************************************************************* + * Copyright (c) 2010-2016, Andras Szabolcs Nagy and Daniel Varro + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-v20.html. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package tools.refinery.store.query.dse.objectives; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; + +public class LeveledObjectivesHelper { + + private List objectives = new ArrayList(); + private Objective[][] leveledObjectives; + + public LeveledObjectivesHelper(List objectives) { + this.objectives = objectives; + } + + public Objective[][] initLeveledObjectives() { + if (objectives.isEmpty()) { + leveledObjectives = new Objective[0][0]; + return leveledObjectives; + } + + int level = objectives.get(0).getLevel(); + boolean oneLevelOnly = true; + for (Objective objective : objectives) { + if (objective.getLevel() != level) { + oneLevelOnly = false; + break; + } + } + + if (oneLevelOnly) { + leveledObjectives = new Objective[1][objectives.size()]; + for (int i = 0; i < objectives.size(); i++) { + leveledObjectives[0][i] = objectives.get(i); + } + return leveledObjectives; + } + + Objective[] objectivesArray = getSortedByLevelObjectives(objectives); + + int numberOfLevels = getNumberOfObjectiveLevels(objectivesArray); + + leveledObjectives = new Objective[numberOfLevels][]; + + fillLeveledObjectives(objectivesArray); + + return leveledObjectives; + } + + private void fillLeveledObjectives(Objective[] objectivesArray) { + int actLevel = objectivesArray[0].getLevel(); + int levelIndex = 0; + int lastIndex = 0; + int corrigationForLastLevel = 0; + boolean oneObjectiveAtLastLevel = false; + for (int i = 0; i < objectivesArray.length; i++) { + if (i == objectivesArray.length - 1) { + corrigationForLastLevel = 1; + if (objectivesArray[i - 1].getLevel() != objectivesArray[i].getLevel()) { + oneObjectiveAtLastLevel = true; + corrigationForLastLevel = 0; + } + } + if (objectivesArray[i].getLevel() != actLevel || corrigationForLastLevel == 1 || oneObjectiveAtLastLevel) { + leveledObjectives[levelIndex] = new Objective[i - lastIndex + corrigationForLastLevel]; + for (int j = lastIndex; j < i + corrigationForLastLevel; j++) { + leveledObjectives[levelIndex][j - lastIndex] = objectivesArray[j]; + } + if (oneObjectiveAtLastLevel) { + leveledObjectives[levelIndex + 1] = new Objective[1]; + leveledObjectives[levelIndex + 1][0] = objectivesArray[i]; + } + actLevel = objectivesArray[i].getLevel(); + levelIndex++; + lastIndex = i; + } + } + } + + private int getNumberOfObjectiveLevels(Objective[] objectivesArray) { + + int actLevel = objectivesArray[0].getLevel(); + int numberOfLevels = 1; + + for (int i = 1; i < objectivesArray.length; i++) { + if (objectivesArray[i].getLevel() != actLevel) { + numberOfLevels++; + actLevel = objectivesArray[i].getLevel(); + } + } + + return numberOfLevels; + } + + private Objective[] getSortedByLevelObjectives(List objectives) { + Objective[] objectivesArray = objectives.toArray(new Objective[objectives.size()]); + Arrays.sort(objectivesArray, Comparator.comparingInt(Objective::getLevel)); + return objectivesArray; + } + + public Objective[][] getLeveledObjectives() { + return leveledObjectives; + } + +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Objective.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Objective.java new file mode 100644 index 00000000..b160b453 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Objective.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-v20.html. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package tools.refinery.store.query.dse.objectives; + +import tools.refinery.store.query.dse.DesignSpaceExplorationAdapter; + +import java.util.Comparator; + +/** + * + * Implementation of this interface represents a single objective of the DSE problem, which can assess a solution + * (trajectory) in a single number. It has a name and a comparator which orders two solution based on the calculated + * value. + *

+ * Objectives can be either hard or soft objectives. Hard objectives can be satisfied or unsatisfied. If all of the hard + * objectives are satisfied on a single solution, then it is considered to be a valid (or goal) solution. + *

+ * Certain objectives can have inner state for calculating the fitness value. In this case a new instance is necessary + * for every new thread, and the {@code createNew} method should not return the same instance more than once. + * + * @author Andras Szabolcs Nagy + * + */ +public interface Objective { + + /** + * Returns the name of the objective. + * + * @return The name of the objective. + */ + String getName(); + + /** + * Sets the {@link Comparator} which is used to compare fitness (doubles). It determines whether the objective is to + * minimize or maximize (or minimize or maximize a delta from a given number). + * + * @param comparator The comparator. + */ + void setComparator(Comparator comparator); + + /** + * Returns a {@link Comparator} which is used to compare fitness (doubles). It determines whether the objective is + * to minimize or maximize (or minimize or maximize a delta from a given number). + * + * @return The comparator. + */ + Comparator getComparator(); + + /** + * Calculates the value of the objective on a given solution (trajectory). + * + * @param context + * The {@link DesignSpaceExplorationAdapter} + * @return The objective value in double. + */ + Double getFitness(DesignSpaceExplorationAdapter context); + + /** + * Initializes the objective. It is called exactly once for every thread starts. + * + * @param context + * The {@link DesignSpaceExplorationAdapter}. + */ + void init(DesignSpaceExplorationAdapter context); + + /** + * Returns an instance of the {@link Objective}. If it returns the same instance, all the methods has to be thread + * save as they are called concurrently. + * + * @return An instance of the objective. + */ + Objective createNew(); + + /** + * Returns true if the objective is a hard objective. In such a case the method + * {@link Objective#satisfiesHardObjective(Double)} is called. + * + * @return True if the objective is a hard objective. + * @see Objective#satisfiesHardObjective(Double) + * @see Objective + */ + boolean isHardObjective(); + + /** + * Determines if the given fitness value satisfies the hard objective. + * + * @param fitness + * The fitness value of a solution. + * @return True if it satisfies the hard objective or it is a soft constraint. + * @see Objective + */ + boolean satisfiesHardObjective(Double fitness); + + /** + * Set the level of the objective. + */ + void setLevel(int level); + + /** + * Gets the level of the objective. + */ + int getLevel(); + +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/ObjectiveComparatorHelper.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/ObjectiveComparatorHelper.java new file mode 100644 index 00000000..23fb24ee --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/ObjectiveComparatorHelper.java @@ -0,0 +1,218 @@ +/******************************************************************************* + * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-v20.html. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package tools.refinery.store.query.dse.objectives; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import org.eclipse.viatra.query.runtime.matchers.util.Preconditions; + +/** + * This class is responsible to compare and sort fitness values. {@link TrajectoryFitness} instances can be added to an + * instance of this class, that it can sort them. + * + * @author András Szabolcs Nagy + */ +public class ObjectiveComparatorHelper { + + private Objective[][] leveledObjectives; + private List trajectoryFitnesses = new ArrayList(); + private Random random = new Random(); + private boolean computeCrowdingDistance = false; + + public ObjectiveComparatorHelper(Objective[][] leveledObjectives) { + this.leveledObjectives = leveledObjectives; + } + + public void setComputeCrowdingDistance(boolean computeCrowdingDistance) { + this.computeCrowdingDistance = computeCrowdingDistance; + } + + /** + * Compares two fitnesses based on hierarchical dominance. Returns -1 if the second parameter {@code o2} is a better + * solution ({@code o2} dominates {@code o1}), 1 if the first parameter {@code o1} is better ({@code o1} dominates + * {@code o2}) and returns 0 if they are non-dominating each other. + */ + public int compare(Fitness o1, Fitness o2) { + + levelsLoop: + for (Objective[] leveledObjective : leveledObjectives) { + + boolean o1HasBetterFitness = false; + boolean o2HasBetterFitness = false; + + for (Objective objective : leveledObjective) { + String objectiveName = objective.getName(); + int sgn = objective.getComparator().compare(o1.get(objectiveName), o2.get(objectiveName)); + + if (sgn < 0) { + o2HasBetterFitness = true; + } + if (sgn > 0) { + o1HasBetterFitness = true; + } + if (o1HasBetterFitness && o2HasBetterFitness) { + continue levelsLoop; + } + } + if (o2HasBetterFitness) { + return -1; + } else if (o1HasBetterFitness) { + return 1; + } + } + + return 0; + + } + + /** + * Adds a {@link TrajectoryFitness} to an inner list to compare later. + * + * @param trajectoryFitness + */ + public void addTrajectoryFitness(TrajectoryFitness trajectoryFitness) { + trajectoryFitnesses.add(trajectoryFitness); + } + + /** + * Clears the inner {@link TrajectoryFitness} list. + */ + public void clearTrajectoryFitnesses() { + trajectoryFitnesses.clear(); + } + + /** + * Returns the inner {@link TrajectoryFitness} list. + */ + public List getTrajectoryFitnesses() { + return trajectoryFitnesses; + } + + /** + * Returns a random {@link TrajectoryFitness} from the pareto front. + */ + public TrajectoryFitness getRandomBest() { + List paretoFront = getParetoFront(); + int randomIndex = random.nextInt(paretoFront.size()); + return paretoFront.get(randomIndex); + } + + /** + * Returns the pareto front of the previously added {@link TrajectoryFitness}. + */ + public List getParetoFront() { + return getFronts().get(0); + } + + /** + * Returns the previously added {@link TrajectoryFitness} instances in fronts. + */ + public List> getFronts() { + Preconditions.checkArgument(!trajectoryFitnesses.isEmpty(), "No trajectory fitnesses were added."); + List> fronts = new ArrayList>(); + + Map> dominatedInstances = new HashMap>(); + Map dominatingInstances = new HashMap(); + + // calculate dominations + for (TrajectoryFitness TrajectoryFitnessP : trajectoryFitnesses) { + dominatedInstances.put(TrajectoryFitnessP, new ArrayList()); + dominatingInstances.put(TrajectoryFitnessP, 0); + + for (TrajectoryFitness TrajectoryFitnessQ : trajectoryFitnesses) { + int dominates = compare(TrajectoryFitnessP.fitness, TrajectoryFitnessQ.fitness); + if (dominates > 0) { + dominatedInstances.get(TrajectoryFitnessP).add(TrajectoryFitnessQ); + } else if (dominates < 0) { + dominatingInstances.put(TrajectoryFitnessP, dominatingInstances.get(TrajectoryFitnessP) + 1); + } + } + + if (dominatingInstances.get(TrajectoryFitnessP) == 0) { + // p belongs to the first front + TrajectoryFitnessP.rank = 1; + if (fronts.isEmpty()) { + ArrayList firstDominationFront = new ArrayList(); + firstDominationFront.add(TrajectoryFitnessP); + fronts.add(firstDominationFront); + } else { + List firstDominationFront = fronts.get(0); + firstDominationFront.add(TrajectoryFitnessP); + } + } + } + + // create fronts + int i = 1; + while (fronts.size() == i) { + ArrayList nextDominationFront = new ArrayList(); + for (TrajectoryFitness TrajectoryFitnessP : fronts.get(i - 1)) { + for (TrajectoryFitness TrajectoryFitnessQ : dominatedInstances.get(TrajectoryFitnessP)) { + dominatingInstances.put(TrajectoryFitnessQ, dominatingInstances.get(TrajectoryFitnessQ) - 1); + if (dominatingInstances.get(TrajectoryFitnessQ) == 0) { + TrajectoryFitnessQ.rank = i + 1; + nextDominationFront.add(TrajectoryFitnessQ); + } + } + } + i++; + if (!nextDominationFront.isEmpty()) { + if (computeCrowdingDistance) { + crowdingDistanceAssignment(nextDominationFront, leveledObjectives); + } + fronts.add(nextDominationFront); + } + } + + return fronts; + } + + /** + * Executes the crowding distance assignment for the specified front. + * + * @param front + */ + public static void crowdingDistanceAssignment(List front, Objective[][] leveledObjectives) { + + for (TrajectoryFitness InstanceData : front) { + // initialize crowding distance + InstanceData.crowdingDistance = 0; + } + + for (final Objective[] objectives : leveledObjectives) { + for (final Objective objective : objectives) { + + final String m = objective.getName(); + TrajectoryFitness[] sortedFront = front.toArray(new TrajectoryFitness[0]); + // sort using m-th objective value + Arrays.sort(sortedFront, (o1, o2) -> objective.getComparator().compare(o1.fitness.get(m), o2.fitness.get(m))); + // so that boundary points are always selected + sortedFront[0].crowdingDistance = Double.POSITIVE_INFINITY; + sortedFront[sortedFront.length - 1].crowdingDistance = Double.POSITIVE_INFINITY; + // If minimal and maximal fitness value for this objective are + // equal, then do not change crowding distance + if (sortedFront[0].fitness.get(m) != sortedFront[sortedFront.length - 1].fitness.get(m)) { + for (int i = 1; i < sortedFront.length - 1; i++) { + double newCrowdingDistance = sortedFront[i].crowdingDistance; + newCrowdingDistance += (sortedFront[i + 1].fitness.get(m) - sortedFront[i - 1].fitness.get(m)) + / (sortedFront[sortedFront.length - 1].fitness.get(m) - sortedFront[0].fitness.get(m)); + + sortedFront[i].crowdingDistance = newCrowdingDistance; + } + } + } + } + } + +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/strategy/DepthFirstStrategy.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/strategy/DepthFirstStrategy.java new file mode 100644 index 00000000..8192048a --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/strategy/DepthFirstStrategy.java @@ -0,0 +1,108 @@ +package tools.refinery.store.query.dse.strategy; + +import tools.refinery.store.query.dse.DesignSpaceExplorationAdapter; +import tools.refinery.store.query.dse.Strategy; +import tools.refinery.store.query.dse.internal.Activation; +import tools.refinery.store.query.dse.objectives.Fitness; + +import java.util.Collection; + +public class DepthFirstStrategy implements Strategy { + + private DesignSpaceExplorationAdapter dseAdapter; + + private int maxDepth; + private boolean backTrackIfSolution = true; + + public DepthFirstStrategy() { + this(-1); + } + + public DepthFirstStrategy(int maxDepth) { + if (maxDepth < 0) { + this.maxDepth = Integer.MAX_VALUE; + } else { + this.maxDepth = maxDepth; + } + } + + public DepthFirstStrategy continueIfHardObjectivesFulfilled() { + backTrackIfSolution = false; + return this; + } + + @Override + public void initStrategy(DesignSpaceExplorationAdapter designSpaceExplorationAdapter) { + this.dseAdapter = designSpaceExplorationAdapter; + } + + @Override + public void explore() { + mainloop: while (true) { + var globalConstraintsAreSatisfied = dseAdapter.checkGlobalConstraints(); + if (!globalConstraintsAreSatisfied) { + var isSuccessfulUndo = dseAdapter.backtrack(); + if (!isSuccessfulUndo) { +// "Global constraint is not satisfied and cannot backtrack." + break; + } + else { +// "Global constraint is not satisfied, backtrack." + continue; + } + } + + Fitness fitness = dseAdapter.calculateFitness(); + if (fitness.isSatisfiesHardObjectives()) { + dseAdapter.newSolution(); + if (backTrackIfSolution) { + var isSuccessfulUndo = dseAdapter.backtrack(); + if (!isSuccessfulUndo) { +// "Found a solution but cannot backtrack." + break; + } else { +// "Found a solution, backtrack." + continue; + } + } + } + + var depth = dseAdapter.getDepth(); + if (dseAdapter.getDepth() >= maxDepth) { + var isSuccessfulUndo = dseAdapter.backtrack(); + if (!isSuccessfulUndo) { +// "Reached max depth but cannot backtrack." + break; + } + } + + Collection activations; + do { + activations = dseAdapter.getUntraversedActivations(); + if (activations.isEmpty()) { + if (!dseAdapter.backtrack()) { + // "No more transitions from current state and cannot backtrack." + break mainloop; + } + else { + // "No more transitions from current state, backtrack." + continue; + } + } + } while (activations.isEmpty()); + + dseAdapter.fireRandomActivation(); +// if (dseAdapter.isCurrentInTrajectory()) { +// if (!dseAdapter.backtrack()) { +//// TODO: throw exception +//// "The new state is present in the trajectory but cannot backtrack. Should never happen!" +// break; +// } +// else { +//// "The new state is already visited in the trajectory, backtrack." +// continue; +// } +// } + } + } +} diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DesignSpaceExplorationTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DesignSpaceExplorationTest.java new file mode 100644 index 00000000..06e2e076 --- /dev/null +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DesignSpaceExplorationTest.java @@ -0,0 +1,117 @@ +package tools.refinery.store.query.dse; + +import guru.nidi.graphviz.engine.Format; +import org.junit.jupiter.api.Test; +import tools.refinery.store.model.ModelStore; +import tools.refinery.store.query.ModelQueryAdapter; +import tools.refinery.store.query.dnf.Query; +import tools.refinery.store.query.dse.internal.TransformationRule; +import tools.refinery.store.query.dse.strategy.BestFirstStrategy; +import tools.refinery.store.query.dse.strategy.DepthFirstStrategy; +import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; +import tools.refinery.store.query.view.AnySymbolView; +import tools.refinery.store.query.view.KeyOnlyView; +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.tuple.Tuple; +import tools.refinery.visualization.ModelVisualizerAdapter; + +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static tools.refinery.store.query.literal.Literals.not; +import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertResults; + +public class DesignSpaceExplorationTest { +// private static final Symbol namedElement = Symbol.of("NamedElement", 1); +// private static final Symbol attribute = Symbol.of("Attribute", 1); +// private static final Symbol method = Symbol.of("Method", 1); +// private static final Symbol dataDependency = Symbol.of("DataDependency", 2); +// private static final Symbol functionalDependency = Symbol.of("FunctionalDependency", 2); + + private static final Symbol classModel = Symbol.of("ClassModel", 1); + private static final Symbol classElement = Symbol.of("ClassElement", 1); + private static final Symbol feature = Symbol.of("Feature", 1); + + private static final Symbol isEncapsulatedBy = Symbol.of("IsEncapsulatedBy", 2); + private static final Symbol encapsulates = Symbol.of("Encapsulates", 2); + + private static final Symbol features = Symbol.of("Features", 2); + private static final Symbol classes = Symbol.of("Classes", 2); + + private static final AnySymbolView classModelView = new KeyOnlyView<>(classModel); + private static final AnySymbolView classElementView = new KeyOnlyView<>(classElement); + private static final AnySymbolView featureView = new KeyOnlyView<>(feature); + private static final AnySymbolView isEncapsulatedByView = new KeyOnlyView<>(isEncapsulatedBy); + private static final AnySymbolView encapsulatesView = new KeyOnlyView<>(encapsulates); + private static final AnySymbolView featuresView = new KeyOnlyView<>(features); + private static final AnySymbolView classesView = new KeyOnlyView<>(classes); + + @Test + void createObjectTest() { + var store = ModelStore.builder() + .with(ViatraModelQueryAdapter.builder()) + .with(DesignSpaceExplorationAdapter.builder()) + .build(); + + var model = store.createEmptyModel(); + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + + assertEquals(0, dseAdapter.getModelSize()); + + var newModel = dseAdapter.createObject(); + var newModelId = newModel.get(0); + var newClass1 = dseAdapter.createObject(); + var newClass1Id = newClass1.get(0); + var newClass2 = dseAdapter.createObject(); + var newClass2Id = newClass2.get(0); + var newField = dseAdapter.createObject(); + var newFieldId = newField.get(0); + + assertEquals(0, newModelId); + assertEquals(1, newClass1Id); + assertEquals(2, newClass2Id); + assertEquals(3, newFieldId); + assertEquals(4, dseAdapter.getModelSize()); + } + + @Test + void deleteMiddleObjectTest() { + var store = ModelStore.builder() + .with(ViatraModelQueryAdapter.builder()) + .with(DesignSpaceExplorationAdapter.builder()) + .build(); + + var model = store.createEmptyModel(); + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + + assertEquals(0, dseAdapter.getModelSize()); + + var newObject0 = dseAdapter.createObject(); + var newObject0Id = newObject0.get(0); + var newObject1 = dseAdapter.createObject(); + var newObject1Id = newObject1.get(0); + var newObject2 = dseAdapter.createObject(); + var newObject2Id = newObject2.get(0); + var newObject3 = dseAdapter.createObject(); + var newObject3Id = newObject3.get(0); + + assertEquals(0, newObject0Id); + assertEquals(1, newObject1Id); + assertEquals(2, newObject2Id); + assertEquals(3, newObject3Id); + assertEquals(4, dseAdapter.getModelSize()); + + dseAdapter.deleteObject(newObject1); + assertEquals(4, dseAdapter.getModelSize()); + + var newObject4 = dseAdapter.createObject(); + var newObject4Id = newObject4.get(0); + assertEquals(4, newObject4Id); + assertEquals(5, dseAdapter.getModelSize()); + + dseAdapter.deleteObject(newObject4); + assertEquals(5, dseAdapter.getModelSize()); + } + +} diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/TransformationRuleTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/TransformationRuleTest.java new file mode 100644 index 00000000..1fb3421b --- /dev/null +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/TransformationRuleTest.java @@ -0,0 +1,403 @@ +package tools.refinery.store.query.dse; + +import org.junit.jupiter.api.Test; +import tools.refinery.store.model.ModelStore; +import tools.refinery.store.query.ModelQueryAdapter; +import tools.refinery.store.query.dnf.Query; +import tools.refinery.store.query.dse.internal.TransformationRule; +import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; +import tools.refinery.store.query.view.AnySymbolView; +import tools.refinery.store.query.view.KeyOnlyView; +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.tuple.Tuple; + +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static tools.refinery.store.query.literal.Literals.not; +import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertResults; + +public class TransformationRuleTest { + + private static final Symbol classModel = Symbol.of("ClassModel", 1); + private static final Symbol classElement = Symbol.of("ClassElement", 1); + private static final Symbol feature = Symbol.of("Feature", 1); + + private static final Symbol isEncapsulatedBy = Symbol.of("IsEncapsulatedBy", 2); + private static final Symbol encapsulates = Symbol.of("Encapsulates", 2); + + private static final Symbol features = Symbol.of("Features", 2); + private static final Symbol classes = Symbol.of("Classes", 2); + + private static final AnySymbolView classModelView = new KeyOnlyView<>(classModel); + private static final AnySymbolView classElementView = new KeyOnlyView<>(classElement); + private static final AnySymbolView featureView = new KeyOnlyView<>(feature); + private static final AnySymbolView isEncapsulatedByView = new KeyOnlyView<>(isEncapsulatedBy); + private static final AnySymbolView encapsulatesView = new KeyOnlyView<>(encapsulates); + private static final AnySymbolView featuresView = new KeyOnlyView<>(features); + private static final AnySymbolView classesView = new KeyOnlyView<>(classes); + + @Test + void activationsTest() { + var assignFeaturePreconditionHelper = Query.of("AssignFeaturePreconditionHelper", + (builder, model, c, f) -> builder.clause( + classElementView.call(c), + classesView.call(model, c), + encapsulatesView.call(c, f) + )); + + var assignFeaturePrecondition = Query.of("AssignFeaturePrecondition", (builder, c2, f) + -> builder.clause((model, c1) -> List.of( + classModelView.call(model), + featureView.call(f), + classElementView.call(c2), + featuresView.call(model, f), + classesView.call(model, c1), + not(assignFeaturePreconditionHelper.call(model, c2, f)), + not(encapsulatesView.call(c2, f)) + ))); + + var deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition", + (builder, model, c) -> builder.clause((f) -> List.of( + classModelView.call(model), + classElementView.call(c), + featuresView.call(model, f), + not(encapsulatesView.call(c, f)) + ))); + + TransformationRule assignFeatureRule = new TransformationRule("AssignFeature", + assignFeaturePrecondition, + (model) -> { + var isEncapsulatedByInterpretation = model.getInterpretation(isEncapsulatedBy); + return ((Tuple activation) -> { + var feature = activation.get(0); + var classElement = activation.get(1); + + isEncapsulatedByInterpretation.put(Tuple.of(feature, classElement), true); + }); + }); + + TransformationRule deleteEmptyClassRule = new TransformationRule("DeleteEmptyClass", + deleteEmptyClassPrecondition, + (model) -> { + var classesInterpretation = model.getInterpretation(classes); + var classElementInterpretation = model.getInterpretation(classElement); + return ((Tuple activation) -> { + var modelElement = activation.get(0); + var classElement = activation.get(1); + + classesInterpretation.put(Tuple.of(modelElement, classElement), false); + classElementInterpretation.put(Tuple.of(classElement), false); + }); + }); + + + var store = ModelStore.builder() + .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features) + .with(ViatraModelQueryAdapter.builder() + .queries(assignFeaturePrecondition, assignFeaturePreconditionHelper, + deleteEmptyClassPrecondition)) + .with(DesignSpaceExplorationAdapter.builder()) + .build(); + + var model = store.createEmptyModel(); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + assignFeatureRule.prepare(model, queryEngine); + deleteEmptyClassRule.prepare(model, queryEngine); + + var classModelInterpretation = model.getInterpretation(classModel); + var classElementInterpretation = model.getInterpretation(classElement); + var featureInterpretation = model.getInterpretation(feature); + var featuresInterpretation = model.getInterpretation(features); + var classesInterpretation = model.getInterpretation(classes); + + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var newModel = dseAdapter.createObject(); + var newModelId = newModel.get(0); + var newClass1 = dseAdapter.createObject(); + var newClass1Id = newClass1.get(0); + var newClass2 = dseAdapter.createObject(); + var newClass2Id = newClass2.get(0); + var newField = dseAdapter.createObject(); + var newFieldId = newField.get(0); + + classModelInterpretation.put(newModel, true); + classElementInterpretation.put(newClass1, true); + classElementInterpretation.put(newClass2, true); + featureInterpretation.put(newField, true); + classesInterpretation.put(Tuple.of(newModelId, newClass1Id), true); + classesInterpretation.put(Tuple.of(newModelId, newClass2Id), true); + featuresInterpretation.put(Tuple.of(newModelId, newFieldId), true); + + queryEngine.flushChanges(); + + var assignFeatureRuleActivations = assignFeatureRule.getAllActivationsAsSets(); + var deleteEmptyClassRuleActivations = deleteEmptyClassRule.getAllActivationsAsSets(); + + assertResults(Map.of( + Tuple.of(newClass1Id, newFieldId), true, + Tuple.of(newClass2Id, newFieldId), true + ), assignFeatureRuleActivations); + + assertResults(Map.of( + Tuple.of(newModelId, newClass1Id), true, + Tuple.of(newModelId, newClass2Id), true + ), deleteEmptyClassRuleActivations); + } + + @Test + void randomActivationTest() { + var deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition", + (builder, model, c) -> builder.clause((f) -> List.of( + classModelView.call(model), + classElementView.call(c), + featuresView.call(model, f), + not(encapsulatesView.call(c, f)) + ))); + + TransformationRule deleteEmptyClassRule0 = new TransformationRule("DeleteEmptyClass0", + deleteEmptyClassPrecondition, + (model) -> { + var classesInterpretation = model.getInterpretation(classes); + var classElementInterpretation = model.getInterpretation(classElement); + return ((Tuple activation) -> { + var modelElement = activation.get(0); + var classElement = activation.get(1); + + classesInterpretation.put(Tuple.of(modelElement, classElement), false); + classElementInterpretation.put(Tuple.of(classElement), false); + }); + }, + 0L); + + TransformationRule deleteEmptyClassRule1 = new TransformationRule("DeleteEmptyClass1", + deleteEmptyClassPrecondition, + (model) -> { + var classesInterpretation = model.getInterpretation(classes); + var classElementInterpretation = model.getInterpretation(classElement); + return ((Tuple activation) -> { + var modelElement = activation.get(0); + var classElement = activation.get(1); + + classesInterpretation.put(Tuple.of(modelElement, classElement), false); + classElementInterpretation.put(Tuple.of(classElement), false); + }); + }, + 78634L); + + var store = ModelStore.builder() + .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features) + .with(ViatraModelQueryAdapter.builder() + .queries(deleteEmptyClassPrecondition)) + .with(DesignSpaceExplorationAdapter.builder()) + .build(); + + var model = store.createEmptyModel(); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + deleteEmptyClassRule0.prepare(model, queryEngine); + deleteEmptyClassRule1.prepare(model, queryEngine); + + var classModelInterpretation = model.getInterpretation(classModel); + var classElementInterpretation = model.getInterpretation(classElement); + var featureInterpretation = model.getInterpretation(feature); + var featuresInterpretation = model.getInterpretation(features); + var classesInterpretation = model.getInterpretation(classes); + + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var newModel = dseAdapter.createObject(); + var newModelId = newModel.get(0); + var newClass1 = dseAdapter.createObject(); + var newClass1Id = newClass1.get(0); + var newClass2 = dseAdapter.createObject(); + var newClass2Id = newClass2.get(0); + var newField = dseAdapter.createObject(); + var newFieldId = newField.get(0); + + classModelInterpretation.put(newModel, true); + classElementInterpretation.put(newClass1, true); + classElementInterpretation.put(newClass2, true); + featureInterpretation.put(newField, true); + classesInterpretation.put(Tuple.of(newModelId, newClass1Id), true); + classesInterpretation.put(Tuple.of(newModelId, newClass2Id), true); + featuresInterpretation.put(Tuple.of(newModelId, newFieldId), true); + + queryEngine.flushChanges(); + + + var activation0 = deleteEmptyClassRule0.getRandomActivation().activation(); + var activation1 = deleteEmptyClassRule1.getRandomActivation().activation(); + + assertResults(Map.of( + Tuple.of(newModelId, newClass1Id), true, + Tuple.of(newModelId, newClass2Id), true + ), deleteEmptyClassRule0.getAllActivationsAsSets()); + + assertResults(Map.of( + Tuple.of(newModelId, newClass1Id), true, + Tuple.of(newModelId, newClass2Id), true + ), deleteEmptyClassRule1.getAllActivationsAsSets()); + + assertEquals(Tuple.of(newModelId, newClass2Id), activation0); + assertEquals(Tuple.of(newModelId, newClass1Id), activation1); + + } + + @Test + void fireTest() { + var deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition", + (builder, model, c) -> builder.clause((f) -> List.of( + classModelView.call(model), + classElementView.call(c), + featuresView.call(model, f), + not(encapsulatesView.call(c, f)) + ))); + + TransformationRule deleteEmptyClassRule = new TransformationRule("DeleteEmptyClass", + deleteEmptyClassPrecondition, + (model) -> { + var classesInterpretation = model.getInterpretation(classes); + var classElementInterpretation = model.getInterpretation(classElement); + return ((Tuple activation) -> { + var modelElement = activation.get(0); + var classElement = activation.get(1); + + classesInterpretation.put(Tuple.of(modelElement, classElement), false); + classElementInterpretation.put(Tuple.of(classElement), false); + }); + }); + + var store = ModelStore.builder() + .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features) + .with(ViatraModelQueryAdapter.builder() + .queries(deleteEmptyClassPrecondition)) + .with(DesignSpaceExplorationAdapter.builder()) + .build(); + + var model = store.createEmptyModel(); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + deleteEmptyClassRule.prepare(model, queryEngine); + + var classModelInterpretation = model.getInterpretation(classModel); + var classElementInterpretation = model.getInterpretation(classElement); + var featureInterpretation = model.getInterpretation(feature); + var featuresInterpretation = model.getInterpretation(features); + var classesInterpretation = model.getInterpretation(classes); + + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var newModel = dseAdapter.createObject(); + var newModelId = newModel.get(0); + var newClass1 = dseAdapter.createObject(); + var newClass1Id = newClass1.get(0); + var newClass2 = dseAdapter.createObject(); + var newClass2Id = newClass2.get(0); + var newField = dseAdapter.createObject(); + var newFieldId = newField.get(0); + + classModelInterpretation.put(newModel, true); + classElementInterpretation.put(newClass1, true); + classElementInterpretation.put(newClass2, true); + featureInterpretation.put(newField, true); + classesInterpretation.put(Tuple.of(newModelId, newClass1Id), true); + classesInterpretation.put(Tuple.of(newModelId, newClass2Id), true); + featuresInterpretation.put(Tuple.of(newModelId, newFieldId), true); + + queryEngine.flushChanges(); + + assertResults(Map.of( + Tuple.of(newModelId, newClass1Id), true, + Tuple.of(newModelId, newClass2Id), true + ), deleteEmptyClassRule.getAllActivationsAsSets()); + + + deleteEmptyClassRule.fireActivation(Tuple.of(0, 1)); + + assertResults(Map.of( + Tuple.of(newModelId, newClass1Id), false, + Tuple.of(newModelId, newClass2Id), true + ), deleteEmptyClassRule.getAllActivationsAsSets()); + } + + @Test + void randomFireTest() { + var deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition", + (builder, model, c) -> builder.clause((f) -> List.of( + classModelView.call(model), + classElementView.call(c), + featuresView.call(model, f), + not(encapsulatesView.call(c, f)) + ))); + + TransformationRule deleteEmptyClassRule = new TransformationRule("DeleteEmptyClass0", + deleteEmptyClassPrecondition, + (model) -> { + var classesInterpretation = model.getInterpretation(classes); + var classElementInterpretation = model.getInterpretation(classElement); + return ((Tuple activation) -> { + var modelElement = activation.get(0); + var classElement = activation.get(1); + + classesInterpretation.put(Tuple.of(modelElement, classElement), false); + classElementInterpretation.put(Tuple.of(classElement), false); + }); + }, + 0L); + + var store = ModelStore.builder() + .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features) + .with(ViatraModelQueryAdapter.builder() + .queries(deleteEmptyClassPrecondition)) + .with(DesignSpaceExplorationAdapter.builder()) + .build(); + + var model = store.createEmptyModel(); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + deleteEmptyClassRule.prepare(model, queryEngine); + + var classModelInterpretation = model.getInterpretation(classModel); + var classElementInterpretation = model.getInterpretation(classElement); + var featureInterpretation = model.getInterpretation(feature); + var featuresInterpretation = model.getInterpretation(features); + var classesInterpretation = model.getInterpretation(classes); + + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var newModel = dseAdapter.createObject(); + var newModelId = newModel.get(0); + var newClass1 = dseAdapter.createObject(); + var newClass1Id = newClass1.get(0); + var newClass2 = dseAdapter.createObject(); + var newClass2Id = newClass2.get(0); + var newField = dseAdapter.createObject(); + var newFieldId = newField.get(0); + + classModelInterpretation.put(newModel, true); + classElementInterpretation.put(newClass1, true); + classElementInterpretation.put(newClass2, true); + featureInterpretation.put(newField, true); + classesInterpretation.put(Tuple.of(newModelId, newClass1Id), true); + classesInterpretation.put(Tuple.of(newModelId, newClass2Id), true); + featuresInterpretation.put(Tuple.of(newModelId, newFieldId), true); + + queryEngine.flushChanges(); + + assertResults(Map.of( + Tuple.of(newModelId, newClass1Id), true, + Tuple.of(newModelId, newClass2Id), true + ), deleteEmptyClassRule.getAllActivationsAsSets()); + + deleteEmptyClassRule.fireRandomActivation(); + + assertResults(Map.of( + Tuple.of(newModelId, newClass1Id), true, + Tuple.of(newModelId, newClass2Id), false + ), deleteEmptyClassRule.getAllActivationsAsSets()); + + deleteEmptyClassRule.fireRandomActivation(); + + assertResults(Map.of( + Tuple.of(newModelId, newClass1Id), false, + Tuple.of(newModelId, newClass2Id), false + ), deleteEmptyClassRule.getAllActivationsAsSets()); + + } +} diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java index aafbe130..24d4088a 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java +++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java @@ -59,13 +59,13 @@ public class ModelStoreBuilderImpl implements ModelStoreBuilder { @Override public ModelStore build() { + for (int i = adapters.size() - 1; i >= 0; i--) { + adapters.get(i).configure(this); + } var stores = new HashMap>(allSymbols.size()); for (var entry : equivalenceClasses.entrySet()) { createStores(stores, entry.getKey(), entry.getValue()); } - for (int i = adapters.size() - 1; i >= 0; i--) { - adapters.get(i).configure(this); - } var modelStore = new ModelStoreImpl(stores, adapters.size()); for (var adapterBuilder : adapters) { var storeAdapter = adapterBuilder.build(modelStore); -- cgit v1.2.3-70-g09d2 From 4f307849e09477cfaa600b50837e999208d05ad6 Mon Sep 17 00:00:00 2001 From: nagilooh Date: Tue, 25 Jul 2023 21:48:55 +0200 Subject: Add best first strategy --- .../query/dse/objectives/TrajectoryFitness.java | 71 ++++++++ .../query/dse/strategy/BestFirstStrategy.java | 189 +++++++++++++++++++++ 2 files changed, 260 insertions(+) create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/TrajectoryFitness.java create mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/strategy/BestFirstStrategy.java (limited to 'subprojects/store-query-viatra') diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/TrajectoryFitness.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/TrajectoryFitness.java new file mode 100644 index 00000000..b9ff7067 --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/TrajectoryFitness.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-v20.html. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package tools.refinery.store.query.dse.objectives; + +import java.util.Arrays; + + +/** + * This class represents a trajectory and its fitness. + * @author Andras Szabolcs Nagy + * + */ +public class TrajectoryFitness { + + public Object[] trajectory; + public Fitness fitness; + + public int rank; + public double crowdingDistance; + + private int hash; + + public int survive; + + /** + * Creates a {@link TrajectoryFitness} with the full trajectory. + * @param trajectory The trajectory. + * @param fitness The fitness. + */ + public TrajectoryFitness(Object[] trajectory, Fitness fitness) { + this.fitness = fitness; + this.trajectory = trajectory; + } + + /** + * Creates a {@link TrajectoryFitness} with the given activation id} + * @param transition The transition. + * @param fitness The fitness. + */ + public TrajectoryFitness(Object transition, Fitness fitness) { + this.fitness = fitness; + trajectory = new Object[] {transition}; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof TrajectoryFitness) { + return Arrays.equals(trajectory, ((TrajectoryFitness) obj).trajectory); + } + return false; + } + + @Override + public int hashCode() { + if (hash == 0 && trajectory.length > 0) { + hash = Arrays.hashCode(trajectory); + } + return hash; + } + + @Override + public String toString() { + return Arrays.toString(trajectory) + fitness.toString(); + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/strategy/BestFirstStrategy.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/strategy/BestFirstStrategy.java new file mode 100644 index 00000000..62adb72f --- /dev/null +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/strategy/BestFirstStrategy.java @@ -0,0 +1,189 @@ +package tools.refinery.store.query.dse.strategy; + +import tools.refinery.store.query.dse.DesignSpaceExplorationAdapter; +import tools.refinery.store.query.dse.Strategy; +import tools.refinery.store.query.dse.internal.Activation; +import tools.refinery.store.query.dse.objectives.Fitness; +import tools.refinery.store.query.dse.objectives.ObjectiveComparatorHelper; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.PriorityQueue; + +public class BestFirstStrategy implements Strategy { + + private DesignSpaceExplorationAdapter dseAdapter; + + private int maxDepth; + private boolean backTrackIfSolution = true; + private boolean onlyBetterFirst = false; + + private PriorityQueue trajectoriesToExplore; + + private static class TrajectoryWithFitness { + + public List trajectory; + public Fitness fitness; + + public TrajectoryWithFitness(List trajectory, Fitness fitness) { + super(); + this.trajectory = trajectory; + this.fitness = fitness; + } + + @Override + public String toString() { + return trajectory.toString() + fitness.toString(); + } + + } + + public BestFirstStrategy() { + this(-1); + } + + public BestFirstStrategy(int maxDepth) { + if (maxDepth < 0) { + this.maxDepth = Integer.MAX_VALUE; + } else { + this.maxDepth = maxDepth; + } + } + + public BestFirstStrategy continueIfHardObjectivesFulfilled() { + backTrackIfSolution = false; + return this; + } + + public BestFirstStrategy goOnOnlyIfFitnessIsBetter() { + onlyBetterFirst = true; + return this; + } + + @Override + public void initStrategy(DesignSpaceExplorationAdapter designSpaceExplorationAdapter) { + this.dseAdapter = designSpaceExplorationAdapter; + final ObjectiveComparatorHelper objectiveComparatorHelper = dseAdapter.getObjectiveComparatorHelper(); + + trajectoriesToExplore = new PriorityQueue(11, + (o1, o2) -> objectiveComparatorHelper.compare(o2.fitness, o1.fitness)); + } + + @Override + public void explore() { + final ObjectiveComparatorHelper objectiveComparatorHelper = dseAdapter.getObjectiveComparatorHelper(); + + boolean globalConstraintsAreSatisfied = dseAdapter.checkGlobalConstraints(); + if (!globalConstraintsAreSatisfied) { + // "Global constraint is not satisfied in the first state. Terminate."); + return; + } + + final Fitness firstFitness = dseAdapter.calculateFitness(); + if (firstFitness.isSatisfiesHardObjectives()) { + dseAdapter.newSolution(); + // "First state is a solution. Terminate."); + if (backTrackIfSolution) { + return; + } + } + + if (maxDepth == 0) { + return; + } + + final List firstTrajectory = dseAdapter.getTrajectory(); + TrajectoryWithFitness currentTrajectoryWithFitness = new TrajectoryWithFitness(firstTrajectory, firstFitness); + trajectoriesToExplore.add(currentTrajectoryWithFitness); + + mainLoop: while (true) { + + if (currentTrajectoryWithFitness == null) { + if (trajectoriesToExplore.isEmpty()) { + // "State space is fully traversed."); + return; + } else { + currentTrajectoryWithFitness = trajectoriesToExplore.element(); +// if (logger.isDebugEnabled()) { +// "New trajectory is chosen: " + currentTrajectoryWithFitness); +// } + dseAdapter.restoreTrajectory(currentTrajectoryWithFitness.trajectory); + } + } + + Collection activations = dseAdapter.getUntraversedActivations(); + Iterator iterator = activations.iterator(); + + + + while (iterator.hasNext()) { + final Activation nextActivation = iterator.next(); + if (!iterator.hasNext()) { + // "Last untraversed activation of the state."); + trajectoriesToExplore.remove(currentTrajectoryWithFitness); + } + +// if (logger.isDebugEnabled()) { +// "Executing new activation: " + nextActivation); +// } + dseAdapter.fireActivation(nextActivation); + if (dseAdapter.isCurrentStateAlreadyTraversed()) { + // "The new state is already visited."); + dseAdapter.backtrack(); + } else if (!dseAdapter.checkGlobalConstraints()) { + // "Global constraint is not satisfied."); + dseAdapter.backtrack(); + } else { + final Fitness nextFitness = dseAdapter.calculateFitness(); + if (nextFitness.isSatisfiesHardObjectives()) { + dseAdapter.newSolution(); + // "Found a solution."); + if (backTrackIfSolution) { + dseAdapter.backtrack(); + continue; + } + } + if (dseAdapter.getDepth() >= maxDepth) { + // "Reached max depth."); + dseAdapter.backtrack(); + continue; + } + + TrajectoryWithFitness nextTrajectoryWithFitness = new TrajectoryWithFitness( + dseAdapter.getTrajectory(), nextFitness); + trajectoriesToExplore.add(nextTrajectoryWithFitness); + + int compare = objectiveComparatorHelper.compare(currentTrajectoryWithFitness.fitness, + nextTrajectoryWithFitness.fitness); + if (compare < 0) { + // "Better fitness, moving on: " + nextFitness); + currentTrajectoryWithFitness = nextTrajectoryWithFitness; + continue mainLoop; + } else if (compare == 0) { + if (onlyBetterFirst) { + // "Equally good fitness, backtrack: " + nextFitness); + dseAdapter.backtrack(); + continue; + } else { + // "Equally good fitness, moving on: " + nextFitness); + currentTrajectoryWithFitness = nextTrajectoryWithFitness; + continue mainLoop; + } + } else { + // "Worse fitness."); + currentTrajectoryWithFitness = null; + continue mainLoop; + } + } + } + + // "State is fully traversed."); + trajectoriesToExplore.remove(currentTrajectoryWithFitness); + currentTrajectoryWithFitness = null; + + } + // "Interrupted."); + + } +} -- cgit v1.2.3-70-g09d2 From 7dfa50ea739ce76b650fd3f957ae74619af69b85 Mon Sep 17 00:00:00 2001 From: nagilooh Date: Wed, 26 Jul 2023 12:04:09 +0200 Subject: Fix issue with storing trajectory --- .../store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'subprojects/store-query-viatra') diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java index 5adf8306..eb2fc063 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java @@ -42,7 +42,7 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration private boolean isNewState = false; public List getTrajectory() { - return trajectory; + return new LinkedList<>(trajectory); } public DesignSpaceExplorationAdapterImpl(Model model, DesignSpaceExplorationStoreAdapterImpl storeAdapter) { -- cgit v1.2.3-70-g09d2 From 4a528d6d5b5502c81a1cd094fcf9e706062b982c Mon Sep 17 00:00:00 2001 From: nagilooh Date: Tue, 25 Jul 2023 21:55:57 +0200 Subject: Add new test files --- subprojects/store-query-viatra/build.gradle.kts | 2 + .../refinery/store/query/dse/CRAExamplesTest.java | 135 +++++++++++++++++++++ .../tools/refinery/store/query/dse/DebugTest.java | 114 +++++++++++++++++ 3 files changed, 251 insertions(+) create mode 100644 subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/CRAExamplesTest.java create mode 100644 subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DebugTest.java (limited to 'subprojects/store-query-viatra') diff --git a/subprojects/store-query-viatra/build.gradle.kts b/subprojects/store-query-viatra/build.gradle.kts index 85ea7e2e..1f804247 100644 --- a/subprojects/store-query-viatra/build.gradle.kts +++ b/subprojects/store-query-viatra/build.gradle.kts @@ -10,7 +10,9 @@ plugins { dependencies { implementation(libs.ecore) + implementation ("guru.nidi:graphviz-java:0.18.1") api(libs.viatra) api(project(":refinery-store-query")) api(project(":refinery-store-reasoning")) + api(project(":refinery-visualization")) } diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/CRAExamplesTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/CRAExamplesTest.java new file mode 100644 index 00000000..8fe50a42 --- /dev/null +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/CRAExamplesTest.java @@ -0,0 +1,135 @@ +package tools.refinery.store.query.dse; + +import tools.refinery.store.query.dnf.Query; +import tools.refinery.store.query.dnf.RelationalQuery; +import tools.refinery.store.query.dse.internal.TransformationRule; +import tools.refinery.store.query.view.AnySymbolView; +import tools.refinery.store.query.view.KeyOnlyView; +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.tuple.Tuple; + +import java.util.List; + +import static tools.refinery.store.query.literal.Literals.not; + +public class CRAExamplesTest { + private static final Symbol classModel = Symbol.of("ClassModel", 1); + private static final Symbol classElement = Symbol.of("ClassElement", 1); + private static final Symbol feature = Symbol.of("Feature", 1); + + private static final Symbol isEncapsulatedBy = Symbol.of("IsEncapsulatedBy", 2); + private static final Symbol encapsulates = Symbol.of("Encapsulates", 2); + + private static final Symbol features = Symbol.of("Features", 2); + private static final Symbol classes = Symbol.of("Classes", 2); + + private static final AnySymbolView classModelView = new KeyOnlyView<>(classModel); + private static final AnySymbolView classElementView = new KeyOnlyView<>(classElement); + private static final AnySymbolView featureView = new KeyOnlyView<>(feature); + private static final AnySymbolView isEncapsulatedByView = new KeyOnlyView<>(isEncapsulatedBy); + private static final AnySymbolView encapsulatesView = new KeyOnlyView<>(encapsulates); + private static final AnySymbolView featuresView = new KeyOnlyView<>(features); + private static final AnySymbolView classesView = new KeyOnlyView<>(classes); + + /*Example Transformation rules*/ + private static final RelationalQuery assignFeaturePreconditionHelper = Query.of("AssignFeaturePreconditionHelper", + (builder, model, c, f) -> builder.clause( + classElementView.call(c), + classesView.call(model, c), + encapsulatesView.call(c, f) + )); + + private static final RelationalQuery assignFeaturePrecondition = Query.of("AssignFeaturePrecondition", (builder, c2, f) + -> builder.clause((model, c1) -> List.of( + classModelView.call(model), + featureView.call(f), + classElementView.call(c2), + featuresView.call(model, f), + classesView.call(model, c1), + not(assignFeaturePreconditionHelper.call(model, c2, f)), + not(encapsulatesView.call(c2, f)) + ))); + + private static final RelationalQuery deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition", + (builder, model, c) -> builder.clause((f) -> List.of( + classModelView.call(model), + classElementView.call(c), + featuresView.call(model, f), + not(encapsulatesView.call(c, f)) + ))); + + private static final RelationalQuery createClassPreconditionHelper = Query.of("CreateClassPreconditionHelper", + (builder, model, f, c) -> builder.clause( + classElementView.call(c), + classesView.call(model, c), + encapsulatesView.call(c, f) + )); + + private static final RelationalQuery createClassPrecondition = Query.of("CreateClassPrecondition", + (builder, model, f) -> builder.clause((c) -> List.of( + classModelView.call(model), + featureView.call(f), + not(createClassPreconditionHelper.call(model, f, c)) + ))); + + private static final RelationalQuery moveFeature = Query.of("MoveFeature", + (builder, c1, c2, f) -> builder.clause((model) -> List.of( + classModelView.call(model), + classElementView.call(c1), + classElementView.call(c2), + featureView.call(f), + classesView.call(model, c1), + classesView.call(model, c2), + featuresView.call(model, f), + encapsulatesView.call(c1, f) + ))); + + private static final TransformationRule assignFeatureRule = new TransformationRule("AssignFeature", + assignFeaturePrecondition, + (model) -> { + var isEncapsulatedByInterpretation = model.getInterpretation(isEncapsulatedBy); + return ((Tuple activation) -> { + var feature = activation.get(0); + var classElement = activation.get(1); + + isEncapsulatedByInterpretation.put(Tuple.of(feature, classElement), true); + }); + }); + + private static final TransformationRule deleteEmptyClassRule = new TransformationRule("DeleteEmptyClass", + deleteEmptyClassPrecondition, + (model) -> { + var classesInterpretation = model.getInterpretation(classes); + var classElementInterpretation = model.getInterpretation(classElement); + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + return ((Tuple activation) -> { + var modelElement = activation.get(0); + var classElement = activation.get(1); + + classesInterpretation.put(Tuple.of(modelElement, classElement), false); + classElementInterpretation.put(Tuple.of(classElement), false); + dseAdapter.deleteObject(Tuple.of(classElement)); + }); + }); + + private static final TransformationRule createClassRule = new TransformationRule("CreateClass", + createClassPrecondition, + (model) -> { + var adapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var classElementInterpretation = model.getInterpretation(classElement); + var classesInterpretation = model.getInterpretation(classes); + var encapsulatesInterpretation = model.getInterpretation(encapsulates); + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + return ((Tuple activation) -> { + var modelElement = activation.get(0); + var feature = activation.get(1); + + var newClassElement = dseAdapter.createObject(); + var newClassElementId = newClassElement.get(0); + classElementInterpretation.put(newClassElement, true); + classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); + encapsulatesInterpretation.put(Tuple.of(newClassElementId, feature), true); + }); + }); + +} diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DebugTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DebugTest.java new file mode 100644 index 00000000..969afbcb --- /dev/null +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DebugTest.java @@ -0,0 +1,114 @@ +package tools.refinery.store.query.dse; + +import org.junit.jupiter.api.Test; +import tools.refinery.store.model.ModelStore; +import tools.refinery.store.query.ModelQueryAdapter; +import tools.refinery.store.query.dnf.Query; +import tools.refinery.store.query.dse.internal.TransformationRule; +import tools.refinery.store.query.dse.strategy.DepthFirstStrategy; +import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; +import tools.refinery.store.query.view.AnySymbolView; +import tools.refinery.store.query.view.KeyOnlyView; +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.tuple.Tuple; +import tools.refinery.visualization.ModelVisualizerAdapter; + +public class DebugTest { + private static final Symbol classModel = Symbol.of("ClassModel", 1); + private static final Symbol classElement = Symbol.of("ClassElement", 1); + private static final Symbol feature = Symbol.of("Feature", 1); + + private static final Symbol isEncapsulatedBy = Symbol.of("IsEncapsulatedBy", 2); + private static final Symbol encapsulates = Symbol.of("Encapsulates", 2); + + private static final Symbol features = Symbol.of("Features", 2); + private static final Symbol classes = Symbol.of("Classes", 2); + + private static final AnySymbolView classModelView = new KeyOnlyView<>(classModel); + private static final AnySymbolView classElementView = new KeyOnlyView<>(classElement); + private static final AnySymbolView featureView = new KeyOnlyView<>(feature); + private static final AnySymbolView isEncapsulatedByView = new KeyOnlyView<>(isEncapsulatedBy); + private static final AnySymbolView encapsulatesView = new KeyOnlyView<>(encapsulates); + private static final AnySymbolView featuresView = new KeyOnlyView<>(features); + private static final AnySymbolView classesView = new KeyOnlyView<>(classes); + + + @Test + void BFSTest() { + var createClassPrecondition = Query.of("CreateClassPrecondition", + (builder, model) -> builder.clause( + classModelView.call(model) + )); + + var createClassRule = new TransformationRule("CreateClass", + createClassPrecondition, + (model) -> { + var classesInterpretation = model.getInterpretation(classes); + var classElementInterpretation = model.getInterpretation(classElement); + return ((Tuple activation) -> { + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var modelElement = activation.get(0); + + var newClassElement = dseAdapter.createObject(); + var newClassElementId = newClassElement.get(0); + + classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); + classElementInterpretation.put(Tuple.of(newClassElementId), true); + }); + }); + + var createFeaturePrecondition = Query.of("CreateFeaturePrecondition", + (builder, model) -> builder.clause( + classModelView.call(model) + )); + + var createFeatureRule = new TransformationRule("CreateFeature", + createFeaturePrecondition, + (model) -> { + var featuresInterpretation = model.getInterpretation(features); + var featureInterpretation = model.getInterpretation(feature); + return ((Tuple activation) -> { + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var modelElement = activation.get(0); + + var newClassElement = dseAdapter.createObject(); + var newClassElementId = newClassElement.get(0); + + featuresInterpretation.put(Tuple.of(modelElement, newClassElementId), true); + featureInterpretation.put(Tuple.of(newClassElementId), true); + }); + }); + + var store = ModelStore.builder() + .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features) + .with(ViatraModelQueryAdapter.builder() + .queries(createClassPrecondition, createFeaturePrecondition)) + .with(DesignSpaceExplorationAdapter.builder() + .transformations(createClassRule, createFeatureRule) + .strategy(new DepthFirstStrategy(4).continueIfHardObjectivesFulfilled() +// .strategy(new BestFirstStrategy(4).continueIfHardObjectivesFulfilled() +// .goOnOnlyIfFitnessIsBetter() + )) + .with(ModelVisualizerAdapter.builder()) + .build(); + + var model = store.createEmptyModel(); + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + + var modelElementInterpretation = model.getInterpretation(classModel); + modelElementInterpretation.put(dseAdapter.createObject(), true); + queryEngine.flushChanges(); + + + var states = dseAdapter.explore(); + var visualizer = model.getAdapter(ModelVisualizerAdapter.class); + for (var state : states) { + var visualization = visualizer.createVisualizationForModelState(state); + visualizer.saveVisualization(visualization, "test_output" + state.hashCode() + ".png"); + } + System.out.println("states size: " + states.size()); + System.out.println("states: " + states); + + } +} -- cgit v1.2.3-70-g09d2 From 261d7d1a5a60dc46dc243118e55adf6c4bb8c9f8 Mon Sep 17 00:00:00 2001 From: nagilooh Date: Thu, 27 Jul 2023 12:15:58 +0200 Subject: Add seed option for random --- .../store/query/dse/DesignSpaceExplorationAdapter.java | 5 +++++ .../query/dse/internal/DesignSpaceExplorationAdapterImpl.java | 10 ++++++++++ 2 files changed, 15 insertions(+) (limited to 'subprojects/store-query-viatra') diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationAdapter.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationAdapter.java index e7ce7b2c..4cfca210 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationAdapter.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationAdapter.java @@ -10,6 +10,7 @@ import tools.refinery.store.tuple.Tuple1; import java.util.Collection; import java.util.List; +import java.util.Random; public interface DesignSpaceExplorationAdapter extends ModelAdapter { @Override @@ -52,4 +53,8 @@ public interface DesignSpaceExplorationAdapter extends ModelAdapter { public ObjectiveComparatorHelper getObjectiveComparatorHelper(); public void restoreTrajectory(List trajectory); + + public void setRandom(Random random); + + public void setRandom(long seed); } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java index eb2fc063..c4c51e79 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java @@ -141,6 +141,16 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration } + @Override + public void setRandom(Random random) { + this.random = random; + } + + @Override + public void setRandom(long seed) { + this.random = new Random(seed); + } + @Override public Fitness calculateFitness() { Fitness result = new Fitness(); -- cgit v1.2.3-70-g09d2 From f5604eebaf63e4227f57cdc27644ac04db26caf4 Mon Sep 17 00:00:00 2001 From: nagilooh Date: Thu, 27 Jul 2023 12:17:23 +0200 Subject: Add trivial test cases for DSE Strategies --- .../query/dse/DesignSpaceExplorationTest.java | 382 ++++++++++++++++++++- 1 file changed, 376 insertions(+), 6 deletions(-) (limited to 'subprojects/store-query-viatra') diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DesignSpaceExplorationTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DesignSpaceExplorationTest.java index 06e2e076..59775b43 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DesignSpaceExplorationTest.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DesignSpaceExplorationTest.java @@ -1,6 +1,5 @@ package tools.refinery.store.query.dse; -import guru.nidi.graphviz.engine.Format; import org.junit.jupiter.api.Test; import tools.refinery.store.model.ModelStore; import tools.refinery.store.query.ModelQueryAdapter; @@ -15,12 +14,7 @@ import tools.refinery.store.representation.Symbol; import tools.refinery.store.tuple.Tuple; import tools.refinery.visualization.ModelVisualizerAdapter; -import java.util.List; -import java.util.Map; - import static org.junit.jupiter.api.Assertions.assertEquals; -import static tools.refinery.store.query.literal.Literals.not; -import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertResults; public class DesignSpaceExplorationTest { // private static final Symbol namedElement = Symbol.of("NamedElement", 1); @@ -114,4 +108,380 @@ public class DesignSpaceExplorationTest { assertEquals(5, dseAdapter.getModelSize()); } + @Test + void DFSTrivialTest() { + var store = ModelStore.builder() + .symbols(classModel) + .with(ViatraModelQueryAdapter.builder()) + .with(ModelVisualizerAdapter.builder()) + .with(DesignSpaceExplorationAdapter.builder() + .strategy(new DepthFirstStrategy(0))) + .build(); + + var model = store.createEmptyModel(); + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + + var states = dseAdapter.explore(); + assertEquals(1, states.size()); + assertEquals(0, states.iterator().next()); + } + + @Test + void DFSOneRuleTest() { + var createClassPrecondition = Query.of("CreateClassPrecondition", + (builder, model) -> builder.clause( + classModelView.call(model) + )); + + var createClassRule = new TransformationRule("CreateClass", + createClassPrecondition, + (model) -> { + var classesInterpretation = model.getInterpretation(classes); + var classElementInterpretation = model.getInterpretation(classElement); + return ((Tuple activation) -> { + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var modelElement = activation.get(0); + + var newClassElement = dseAdapter.createObject(); + var newClassElementId = newClassElement.get(0); + + classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); + classElementInterpretation.put(Tuple.of(newClassElementId), true); + }); + }); + + var store = ModelStore.builder() + .symbols(classModel, classElement, classes) + .with(ViatraModelQueryAdapter.builder() + .queries(createClassPrecondition)) + .with(ModelVisualizerAdapter.builder()) + .with(DesignSpaceExplorationAdapter.builder() + .transformations(createClassRule) + .strategy(new DepthFirstStrategy(4) + )) + .build(); + + var model = store.createEmptyModel(); + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + + var modelElementInterpretation = model.getInterpretation(classModel); + modelElementInterpretation.put(dseAdapter.createObject(), true); + queryEngine.flushChanges(); + + var states = dseAdapter.explore(); + assertEquals(1, states.size()); + assertEquals(0, states.iterator().next()); + } + + @Test + void DFSContinueTest() { + var createClassPrecondition = Query.of("CreateClassPrecondition", + (builder, model) -> builder.clause( + classModelView.call(model) + )); + + var createClassRule = new TransformationRule("CreateClass", + createClassPrecondition, + (model) -> { + var classesInterpretation = model.getInterpretation(classes); + var classElementInterpretation = model.getInterpretation(classElement); + return ((Tuple activation) -> { + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var modelElement = activation.get(0); + + var newClassElement = dseAdapter.createObject(); + var newClassElementId = newClassElement.get(0); + + classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); + classElementInterpretation.put(Tuple.of(newClassElementId), true); + }); + }); + + var store = ModelStore.builder() + .symbols(classModel, classElement, classes) + .with(ViatraModelQueryAdapter.builder() + .queries(createClassPrecondition)) + .with(ModelVisualizerAdapter.builder()) + .with(DesignSpaceExplorationAdapter.builder() + .transformations(createClassRule) + .strategy(new DepthFirstStrategy(4).continueIfHardObjectivesFulfilled() + )) + .build(); + + var model = store.createEmptyModel(); + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + + var modelElementInterpretation = model.getInterpretation(classModel); + modelElementInterpretation.put(dseAdapter.createObject(), true); + queryEngine.flushChanges(); + + var states = dseAdapter.explore(); + var iterator = states.iterator(); + assertEquals(5, states.size()); + assertEquals(0, iterator.next()); + assertEquals(1, iterator.next()); + assertEquals(2, iterator.next()); + assertEquals(3, iterator.next()); + assertEquals(4, iterator.next()); + } + + @Test + void DFSCompletenessTest() { + var createClassPrecondition = Query.of("CreateClassPrecondition", + (builder, model) -> builder.clause( + classModelView.call(model) + )); + + var createClassRule = new TransformationRule("CreateClass", + createClassPrecondition, + (model) -> { + var classesInterpretation = model.getInterpretation(classes); + var classElementInterpretation = model.getInterpretation(classElement); + return ((Tuple activation) -> { + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var modelElement = activation.get(0); + + var newClassElement = dseAdapter.createObject(); + var newClassElementId = newClassElement.get(0); + + classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); + classElementInterpretation.put(Tuple.of(newClassElementId), true); + }); + }); + + var createFeaturePrecondition = Query.of("CreateFeaturePrecondition", + (builder, model) -> builder.clause( + classModelView.call(model) + )); + + var createFeatureRule = new TransformationRule("CreateFeature", + createFeaturePrecondition, + (model) -> { + var featuresInterpretation = model.getInterpretation(features); + var featureInterpretation = model.getInterpretation(feature); + return ((Tuple activation) -> { + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var modelElement = activation.get(0); + + var newClassElement = dseAdapter.createObject(); + var newClassElementId = newClassElement.get(0); + + featuresInterpretation.put(Tuple.of(modelElement, newClassElementId), true); + featureInterpretation.put(Tuple.of(newClassElementId), true); + }); + }); + + var store = ModelStore.builder() + .symbols(classModel, classElement, classes, feature, features, isEncapsulatedBy, encapsulates) + .with(ViatraModelQueryAdapter.builder() + .queries(createClassPrecondition, createFeaturePrecondition)) + .with(ModelVisualizerAdapter.builder()) + .with(DesignSpaceExplorationAdapter.builder() + .transformations(createClassRule, createFeatureRule) + .strategy(new DepthFirstStrategy(10).continueIfHardObjectivesFulfilled() + )) + .build(); + + var model = store.createEmptyModel(); + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + + var modelElementInterpretation = model.getInterpretation(classModel); + modelElementInterpretation.put(dseAdapter.createObject(), true); + queryEngine.flushChanges(); + + var states = dseAdapter.explore(); + assertEquals(2047, states.size()); + } + + @Test + void BFSTrivialTest() { + var store = ModelStore.builder() + .symbols(classModel) + .with(ViatraModelQueryAdapter.builder()) + .with(ModelVisualizerAdapter.builder()) + .with(DesignSpaceExplorationAdapter.builder() + .strategy(new BestFirstStrategy(0))) + .build(); + + var model = store.createEmptyModel(); + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + + var states = dseAdapter.explore(); + assertEquals(1, states.size()); + assertEquals(0, states.iterator().next()); + } + + @Test + void BFSOneRuleTest() { + var createClassPrecondition = Query.of("CreateClassPrecondition", + (builder, model) -> builder.clause( + classModelView.call(model) + )); + + var createClassRule = new TransformationRule("CreateClass", + createClassPrecondition, + (model) -> { + var classesInterpretation = model.getInterpretation(classes); + var classElementInterpretation = model.getInterpretation(classElement); + return ((Tuple activation) -> { + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var modelElement = activation.get(0); + + var newClassElement = dseAdapter.createObject(); + var newClassElementId = newClassElement.get(0); + + classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); + classElementInterpretation.put(Tuple.of(newClassElementId), true); + }); + }); + + var store = ModelStore.builder() + .symbols(classModel, classElement, classes) + .with(ViatraModelQueryAdapter.builder() + .queries(createClassPrecondition)) + .with(ModelVisualizerAdapter.builder()) + .with(DesignSpaceExplorationAdapter.builder() + .transformations(createClassRule) + .strategy(new BestFirstStrategy(4) + )) + .build(); + + var model = store.createEmptyModel(); + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + + var modelElementInterpretation = model.getInterpretation(classModel); + modelElementInterpretation.put(dseAdapter.createObject(), true); + queryEngine.flushChanges(); + + var states = dseAdapter.explore(); + assertEquals(1, states.size()); + assertEquals(0, states.iterator().next()); + } + + @Test + void BFSContinueTest() { + var createClassPrecondition = Query.of("CreateClassPrecondition", + (builder, model) -> builder.clause( + classModelView.call(model) + )); + + var createClassRule = new TransformationRule("CreateClass", + createClassPrecondition, + (model) -> { + var classesInterpretation = model.getInterpretation(classes); + var classElementInterpretation = model.getInterpretation(classElement); + return ((Tuple activation) -> { + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var modelElement = activation.get(0); + + var newClassElement = dseAdapter.createObject(); + var newClassElementId = newClassElement.get(0); + + classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); + classElementInterpretation.put(Tuple.of(newClassElementId), true); + }); + }); + + var store = ModelStore.builder() + .symbols(classModel, classElement, classes) + .with(ViatraModelQueryAdapter.builder() + .queries(createClassPrecondition)) + .with(ModelVisualizerAdapter.builder()) + .with(DesignSpaceExplorationAdapter.builder() + .transformations(createClassRule) + .strategy(new BestFirstStrategy(4).continueIfHardObjectivesFulfilled() + )) + .build(); + + var model = store.createEmptyModel(); + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + + var modelElementInterpretation = model.getInterpretation(classModel); + modelElementInterpretation.put(dseAdapter.createObject(), true); + queryEngine.flushChanges(); + + var states = dseAdapter.explore(); + var iterator = states.iterator(); + assertEquals(5, states.size()); + assertEquals(0, iterator.next()); + assertEquals(1, iterator.next()); + assertEquals(2, iterator.next()); + assertEquals(3, iterator.next()); + assertEquals(4, iterator.next()); + } + + @Test + void BFSCompletenessTest() { + var createClassPrecondition = Query.of("CreateClassPrecondition", + (builder, model) -> builder.clause( + classModelView.call(model) + )); + + var createClassRule = new TransformationRule("CreateClass", + createClassPrecondition, + (model) -> { + var classesInterpretation = model.getInterpretation(classes); + var classElementInterpretation = model.getInterpretation(classElement); + return ((Tuple activation) -> { + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var modelElement = activation.get(0); + + var newClassElement = dseAdapter.createObject(); + var newClassElementId = newClassElement.get(0); + + classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); + classElementInterpretation.put(Tuple.of(newClassElementId), true); + }); + }); + + var createFeaturePrecondition = Query.of("CreateFeaturePrecondition", + (builder, model) -> builder.clause( + classModelView.call(model) + )); + + var createFeatureRule = new TransformationRule("CreateFeature", + createFeaturePrecondition, + (model) -> { + var featuresInterpretation = model.getInterpretation(features); + var featureInterpretation = model.getInterpretation(feature); + return ((Tuple activation) -> { + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var modelElement = activation.get(0); + + var newClassElement = dseAdapter.createObject(); + var newClassElementId = newClassElement.get(0); + + featuresInterpretation.put(Tuple.of(modelElement, newClassElementId), true); + featureInterpretation.put(Tuple.of(newClassElementId), true); + }); + }); + + var store = ModelStore.builder() + .symbols(classModel, classElement, classes, feature, features, isEncapsulatedBy, encapsulates) + .with(ViatraModelQueryAdapter.builder() + .queries(createClassPrecondition, createFeaturePrecondition)) + .with(ModelVisualizerAdapter.builder()) + .with(DesignSpaceExplorationAdapter.builder() + .transformations(createClassRule, createFeatureRule) + .strategy(new BestFirstStrategy(10).continueIfHardObjectivesFulfilled() + )) + .build(); + + var model = store.createEmptyModel(); + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + + var modelElementInterpretation = model.getInterpretation(classModel); + modelElementInterpretation.put(dseAdapter.createObject(), true); + queryEngine.flushChanges(); + + var states = dseAdapter.explore(); + assertEquals(2047, states.size()); + } + } -- cgit v1.2.3-70-g09d2 From 00c8fcf947d3f5c375d49a907bcefa5d8e1dd8ea Mon Sep 17 00:00:00 2001 From: nagilooh Date: Tue, 1 Aug 2023 12:41:45 +0200 Subject: Update visualization - Replace guru.nidi:graphviz-java with DOT based solution - Draws the design space as well as the model states - Design space nodes link to visualization of the sate --- subprojects/store-query-viatra/build.gradle.kts | 1 - .../DesignSpaceExplorationAdapterImpl.java | 21 ++++ .../tools/refinery/store/query/dse/DebugTest.java | 15 +-- subprojects/visualization/build.gradle.kts | 1 - .../visualization/ModelVisualizerAdapter.java | 23 ++-- .../internal/ModelVisualizerAdapterImpl.java | 120 +++++++++++---------- 6 files changed, 109 insertions(+), 72 deletions(-) (limited to 'subprojects/store-query-viatra') diff --git a/subprojects/store-query-viatra/build.gradle.kts b/subprojects/store-query-viatra/build.gradle.kts index 1f804247..ef73e10a 100644 --- a/subprojects/store-query-viatra/build.gradle.kts +++ b/subprojects/store-query-viatra/build.gradle.kts @@ -10,7 +10,6 @@ plugins { dependencies { implementation(libs.ecore) - implementation ("guru.nidi:graphviz-java:0.18.1") api(libs.viatra) api(project(":refinery-store-query")) api(project(":refinery-store-reasoning")) diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java index c4c51e79..0fcc719d 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java @@ -15,6 +15,7 @@ import tools.refinery.store.query.resultset.ResultSet; import tools.refinery.store.representation.Symbol; import tools.refinery.store.tuple.Tuple; import tools.refinery.store.tuple.Tuple1; +import tools.refinery.visualization.ModelVisualizerAdapter; import java.util.*; @@ -40,6 +41,8 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration private Random random = new Random(); private Objective[][] leveledObjectives; private boolean isNewState = false; + private final boolean isVisualizationEnabled; + private final ModelVisualizerAdapter modelVisualizerAdapter; public List getTrajectory() { return new LinkedList<>(trajectory); @@ -66,6 +69,8 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration statesAndUntraversedActivations = new HashMap<>(); statesAndTraversedActivations = new HashMap<>(); strategy = storeAdapter.getStrategy(); + modelVisualizerAdapter = model.tryGetAdapter(ModelVisualizerAdapter.class).orElse(null); + isVisualizationEnabled = modelVisualizerAdapter != null; } @@ -129,6 +134,10 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration if (trajectory.size() < 2) { return false; } + if (isVisualizationEnabled) { + modelVisualizerAdapter.addTransition(trajectory.get(trajectory.size() - 1), + trajectory.get(trajectory.size() - 2), "backtrack"); + } model.restore(trajectory.get(trajectory.size() - 2)); trajectory.remove(trajectory.size() - 1); return true; @@ -137,6 +146,10 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration @Override public void restoreTrajectory(List trajectory) { model.restore(trajectory.get(trajectory.size() - 1)); +// if (isVisualizationEnabled) { +// modelVisualizerAdapter.addTransition(this.trajectory.get(trajectory.size() - 1), +// trajectory.get(trajectory.size() - 1), "restore"); +// } this.trajectory = trajectory; } @@ -173,6 +186,9 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration public void newSolution() { var state = model.getState(); solutions.add(state); + if (isVisualizationEnabled) { + modelVisualizerAdapter.addSolution(state); + } } @Override @@ -212,6 +228,11 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration isNewState = !statesAndUntraversedActivations.containsKey(newState); statesAndUntraversedActivations.put(newState, getAllActivations()); statesAndTraversedActivations.put(newState, new HashSet<>()); + if (isVisualizationEnabled) { + modelVisualizerAdapter.addTransition(trajectory.get(trajectory.size() - 2), + trajectory.get(trajectory.size() - 1), activation.transformationRule().getName(), + activation.activation()); + } return true; } diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DebugTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DebugTest.java index 969afbcb..821be7e6 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DebugTest.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DebugTest.java @@ -5,6 +5,7 @@ import tools.refinery.store.model.ModelStore; import tools.refinery.store.query.ModelQueryAdapter; import tools.refinery.store.query.dnf.Query; import tools.refinery.store.query.dse.internal.TransformationRule; +import tools.refinery.store.query.dse.strategy.BestFirstStrategy; import tools.refinery.store.query.dse.strategy.DepthFirstStrategy; import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; import tools.refinery.store.query.view.AnySymbolView; @@ -12,6 +13,7 @@ import tools.refinery.store.query.view.KeyOnlyView; import tools.refinery.store.representation.Symbol; import tools.refinery.store.tuple.Tuple; import tools.refinery.visualization.ModelVisualizerAdapter; +import tools.refinery.visualization.internal.FileFormat; public class DebugTest { private static final Symbol classModel = Symbol.of("ClassModel", 1); @@ -83,30 +85,31 @@ public class DebugTest { .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features) .with(ViatraModelQueryAdapter.builder() .queries(createClassPrecondition, createFeaturePrecondition)) + .with(ModelVisualizerAdapter.builder()) .with(DesignSpaceExplorationAdapter.builder() .transformations(createClassRule, createFeatureRule) .strategy(new DepthFirstStrategy(4).continueIfHardObjectivesFulfilled() // .strategy(new BestFirstStrategy(4).continueIfHardObjectivesFulfilled() // .goOnOnlyIfFitnessIsBetter() )) - .with(ModelVisualizerAdapter.builder()) .build(); var model = store.createEmptyModel(); var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); +// dseAdapter.setRandom(1); var queryEngine = model.getAdapter(ModelQueryAdapter.class); var modelElementInterpretation = model.getInterpretation(classModel); - modelElementInterpretation.put(dseAdapter.createObject(), true); + var classElementInterpretation = model.getInterpretation(classElement); + var modelElement = dseAdapter.createObject(); + modelElementInterpretation.put(modelElement, true); + classElementInterpretation.put(modelElement, true); queryEngine.flushChanges(); var states = dseAdapter.explore(); var visualizer = model.getAdapter(ModelVisualizerAdapter.class); - for (var state : states) { - var visualization = visualizer.createVisualizationForModelState(state); - visualizer.saveVisualization(visualization, "test_output" + state.hashCode() + ".png"); - } + visualizer.renderDesignSpace("test_output", FileFormat.SVG); System.out.println("states size: " + states.size()); System.out.println("states: " + states); diff --git a/subprojects/visualization/build.gradle.kts b/subprojects/visualization/build.gradle.kts index 97b1688a..abad0491 100644 --- a/subprojects/visualization/build.gradle.kts +++ b/subprojects/visualization/build.gradle.kts @@ -9,6 +9,5 @@ plugins { } dependencies { - implementation ("guru.nidi:graphviz-java:0.18.1") api(project(":refinery-store-query")) } diff --git a/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerAdapter.java b/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerAdapter.java index 42f01242..2f71d4f3 100644 --- a/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerAdapter.java +++ b/subprojects/visualization/src/main/java/tools/refinery/visualization/ModelVisualizerAdapter.java @@ -1,8 +1,7 @@ package tools.refinery.visualization; -import guru.nidi.graphviz.engine.Format; -import guru.nidi.graphviz.model.MutableGraph; import tools.refinery.store.adapter.ModelAdapter; +import tools.refinery.store.tuple.Tuple; import tools.refinery.visualization.internal.FileFormat; import tools.refinery.visualization.internal.ModelVisualizerBuilderImpl; @@ -13,21 +12,25 @@ public interface ModelVisualizerAdapter extends ModelAdapter { return new ModelVisualizerBuilderImpl(); } - public MutableGraph createVisualizationForCurrentModelState(); - - public MutableGraph createVisualizationForModelState(Long version); - public String createDotForCurrentModelState(); public String createDotForModelState(Long version); - public boolean saveVisualization(MutableGraph graph, String path); - - public boolean saveVisualization(MutableGraph graph, Format format, String path); - public boolean saveDot(String dot, String filePath); public boolean renderDot(String dot, String filePath); public boolean renderDot(String dot, FileFormat format, String filePath); + + public void addTransition(Long from, Long to, String action); + + + public void addTransition(Long from, Long to, String action, Tuple activation); + public void addSolution(Long state); + + public boolean saveDesignSpace(String path); + + public boolean renderDesignSpace(String path); + + public boolean renderDesignSpace(String path, FileFormat format); } diff --git a/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerAdapterImpl.java b/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerAdapterImpl.java index 7456d913..9a284e24 100644 --- a/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerAdapterImpl.java +++ b/subprojects/visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerAdapterImpl.java @@ -1,14 +1,9 @@ package tools.refinery.visualization.internal; -import guru.nidi.graphviz.attribute.GraphAttr; -import guru.nidi.graphviz.attribute.Label; -import guru.nidi.graphviz.engine.Format; -import guru.nidi.graphviz.engine.Graphviz; -import guru.nidi.graphviz.model.MutableGraph; import tools.refinery.store.model.Interpretation; import tools.refinery.store.model.Model; import tools.refinery.store.representation.AnySymbol; -import tools.refinery.store.representation.TruthValue; +import tools.refinery.store.tuple.Tuple; import tools.refinery.visualization.ModelVisualizerAdapter; import tools.refinery.visualization.ModelVisualizerStoreAdapter; @@ -16,12 +11,13 @@ import java.io.*; import java.util.HashMap; import java.util.Map; -import static guru.nidi.graphviz.model.Factory.*; - public class ModelVisualizerAdapterImpl implements ModelVisualizerAdapter { private final Model model; private final ModelVisualizerStoreAdapter storeAdapter; private final Map> interpretations; + private final StringBuilder designSpaceBuilder = new StringBuilder(); + private int transitionCounter = 0; + public ModelVisualizerAdapterImpl(Model model, ModelVisualizerStoreAdapter storeAdapter) { this.model = model; this.storeAdapter = storeAdapter; @@ -46,6 +42,7 @@ public class ModelVisualizerAdapterImpl implements ModelVisualizerAdapter { } interpretations.put(symbol, castInterpretation); } + designSpaceBuilder.append("digraph designSpace {\n"); } @Override @@ -58,36 +55,6 @@ public class ModelVisualizerAdapterImpl implements ModelVisualizerAdapter { return storeAdapter; } - @Override - public MutableGraph createVisualizationForCurrentModelState() { - var graph = mutGraph("model").setDirected(true).graphAttrs().add(GraphAttr.dpi(100)); - for (var entry : interpretations.entrySet()) { - var key = entry.getKey(); - var arity = key.arity(); - var cursor = entry.getValue().getAll(); - while (cursor.move()) { - if (arity == 1) { - var id = cursor.getKey().get(0); - graph.add(mutNode(String.valueOf(id)).add("label", key.name() + ": " + id)); - } else { - var from = cursor.getKey().get(0); - var to = cursor.getKey().get(1); - graph.add(mutNode(String.valueOf(from)).addLink(to(mutNode(String.valueOf(to))).with(Label.of(key.name())))); - } - } - } - return graph; - } - - @Override - public MutableGraph createVisualizationForModelState(Long version) { - var currentVersion = model.getState(); - model.restore(version); - var graph = createVisualizationForCurrentModelState(); - model.restore(currentVersion); - return graph; - } - @Override public String createDotForCurrentModelState() { var sb = new StringBuilder(); @@ -122,22 +89,6 @@ public class ModelVisualizerAdapterImpl implements ModelVisualizerAdapter { return graph; } - @Override - public boolean saveVisualization(MutableGraph graph, String path) { - return saveVisualization(graph, Format.PNG, path); - } - - @Override - public boolean saveVisualization(MutableGraph graph, Format format, String path) { - try { - Graphviz.fromGraph(graph).render(format).toFile(new File(path)); - return true; - } catch (IOException e) { - e.printStackTrace(); - return false; - } - } - @Override public boolean saveDot(String dot, String filePath) { File file = new File(filePath); @@ -172,4 +123,65 @@ public class ModelVisualizerAdapterImpl implements ModelVisualizerAdapter { } return true; } + + @Override + public void addTransition(Long from, Long to, String action) { + designSpaceBuilder.append(from).append(" -> ").append(to).append(" [label=\"").append(transitionCounter++) + .append(": ").append(action).append("\"]\n"); + + } + + @Override + public void addTransition(Long from, Long to, String action, Tuple activation) { + designSpaceBuilder.append(from).append(" -> ").append(to).append(" [label=\"").append(transitionCounter++) + .append(": ").append(action).append(" / "); + + + for (int i = 0; i < activation.getSize(); i++) { + designSpaceBuilder.append(activation.get(i)); + if (i < activation.getSize() - 1) { + designSpaceBuilder.append(", "); + } + } + designSpaceBuilder.append("\"]\n"); + } + + @Override + public void addSolution(Long state) { + designSpaceBuilder.append(state).append(" [shape = doublecircle]\n"); + } + + private String buildDesignSpaceDot() { + for (var state : storeAdapter.getStore().getStates()) { + designSpaceBuilder.append(state).append(" [URL=\"./").append(state).append(".svg\"]\n"); + } + designSpaceBuilder.append("}"); + return designSpaceBuilder.toString(); + } + + @Override + public boolean saveDesignSpace(String path) { + saveDot(buildDesignSpaceDot(), path + "/designSpace.dot"); + for (var state : storeAdapter.getStore().getStates()) { + saveDot(createDotForModelState(state), path + "/" + state + ".dot"); + } + return true; + } + + @Override + public boolean renderDesignSpace(String path) { + return renderDesignSpace(path, FileFormat.SVG); + } + + @Override + public boolean renderDesignSpace(String path, FileFormat format) { + for (var state : storeAdapter.getStore().getStates()) { + var stateDot = createDotForModelState(state); + saveDot(stateDot, path + "/" + state + ".dot"); + renderDot(stateDot, path + "/" + state + "." + format.getFormat()); + } + var designSpaceDot = buildDesignSpaceDot(); + saveDot(designSpaceDot, path + "/designSpace.dot"); + return renderDot(designSpaceDot, format, path + "/designSpace." + format.getFormat()); + } } -- cgit v1.2.3-70-g09d2 From e21e289dd62d1499cb63811ba0a6da0c684b0d95 Mon Sep 17 00:00:00 2001 From: nagilooh Date: Tue, 1 Aug 2023 13:00:21 +0200 Subject: Change Set to LinkedHashSet, remove unused methods --- .../query/dse/DesignSpaceExplorationBuilder.java | 11 -------- .../DesignSpaceExplorationAdapterImpl.java | 27 ++++++++++---------- .../DesignSpaceExplorationBuilderImpl.java | 23 +++-------------- .../DesignSpaceExplorationStoreAdapterImpl.java | 29 ++++++++-------------- .../query/dse/internal/TransformationRule.java | 7 +++--- 5 files changed, 31 insertions(+), 66 deletions(-) (limited to 'subprojects/store-query-viatra') diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationBuilder.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationBuilder.java index 0ec6f599..58eac681 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationBuilder.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationBuilder.java @@ -10,15 +10,6 @@ import java.util.Collection; import java.util.List; public interface DesignSpaceExplorationBuilder extends ModelAdapterBuilder { - default DesignSpaceExplorationBuilder stopConditions(AnyQuery... stopConditions) { - return stopConditions(List.of(stopConditions)); - } - - default DesignSpaceExplorationBuilder stopConditions(Collection stopConditions) { - stopConditions.forEach(this::stopCondition); - return this; - } - default DesignSpaceExplorationBuilder transformations(TransformationRule... transformationRules) { return transformations(List.of(transformationRules)); } @@ -46,8 +37,6 @@ public interface DesignSpaceExplorationBuilder extends ModelAdapterBuilder { return this; } - DesignSpaceExplorationBuilder stopCondition(AnyQuery stopCondition); - DesignSpaceExplorationBuilder transformation(TransformationRule transformationRule); DesignSpaceExplorationBuilder globalConstraint(RelationalQuery globalConstraint); DesignSpaceExplorationBuilder objective(Objective objective); diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java index 0fcc719d..35f94dce 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java @@ -24,20 +24,19 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration private final Model model; private final ModelQueryAdapter queryEngine; private final DesignSpaceExplorationStoreAdapterImpl storeAdapter; - private final Set transformationRules; - private final Set globalConstraints; + private final LinkedHashSet transformationRules; + private final LinkedHashSet globalConstraints; private final List objectives; - private final Set> globalConstraintResultSets = new HashSet<>(); + private final LinkedHashSet> globalConstraintResultSets = new LinkedHashSet<>(); private final Interpretation sizeInterpretation; private final Strategy strategy; private ObjectiveComparatorHelper objectiveComparatorHelper; private List trajectory = new LinkedList<>(); private Fitness lastFitness; - private final Set solutions = new HashSet<>(); -// private Map> statesAndActivations; - private Map> statesAndUntraversedActivations; - private Map> statesAndTraversedActivations; + private final LinkedHashSet solutions = new LinkedHashSet<>(); + private Map> statesAndUntraversedActivations; + private Map> statesAndTraversedActivations; private Random random = new Random(); private Objective[][] leveledObjectives; private boolean isNewState = false; @@ -85,11 +84,11 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration } @Override - public Collection explore() { + public LinkedHashSet explore() { var state = model.commit(); trajectory.add(state); statesAndUntraversedActivations.put(state, getAllActivations()); - statesAndTraversedActivations.put(state, new HashSet<>()); + statesAndTraversedActivations.put(state, new LinkedHashSet<>()); strategy.initStrategy(this); strategy.explore(); return solutions; @@ -196,9 +195,9 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration return trajectory.size() - 1; } - public Collection getUntraversedActivations() { + public LinkedHashSet getUntraversedActivations() { // return statesAndUntraversedActivations.get(model.getState()); - List untraversedActivations = new ArrayList<>(); + LinkedHashSet untraversedActivations = new LinkedHashSet<>(); for (Activation activation : getAllActivations()) { if (!statesAndTraversedActivations.get(model.getState()).contains(activation)) { untraversedActivations.add(activation); @@ -227,7 +226,7 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration trajectory.add(newState); isNewState = !statesAndUntraversedActivations.containsKey(newState); statesAndUntraversedActivations.put(newState, getAllActivations()); - statesAndTraversedActivations.put(newState, new HashSet<>()); + statesAndTraversedActivations.put(newState, new LinkedHashSet<>()); if (isVisualizationEnabled) { modelVisualizerAdapter.addTransition(trajectory.get(trajectory.size() - 2), trajectory.get(trajectory.size() - 1), activation.transformationRule().getName(), @@ -257,8 +256,8 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration return trajectory.contains(model.getState()); } - public Collection getAllActivations() { - Collection result = new HashSet<>(); + public LinkedHashSet getAllActivations() { + LinkedHashSet result = new LinkedHashSet<>(); for (var rule : transformationRules) { result.addAll(rule.getAllActivations()); } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationBuilderImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationBuilderImpl.java index 79864de0..638ec641 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationBuilderImpl.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationBuilderImpl.java @@ -3,7 +3,6 @@ package tools.refinery.store.query.dse.internal; import tools.refinery.store.adapter.AbstractModelAdapterBuilder; import tools.refinery.store.model.ModelStore; import tools.refinery.store.model.ModelStoreBuilder; -import tools.refinery.store.query.dnf.AnyQuery; import tools.refinery.store.query.dnf.RelationalQuery; import tools.refinery.store.query.dse.DesignSpaceExplorationBuilder; import tools.refinery.store.query.dse.Strategy; @@ -12,29 +11,19 @@ import tools.refinery.store.query.dse.objectives.Objective; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; -import java.util.Set; public class DesignSpaceExplorationBuilderImpl extends AbstractModelAdapterBuilder implements DesignSpaceExplorationBuilder { - - private final Set stopConditionSpecifications = new LinkedHashSet<>(); - private final Set transformationSpecifications = new LinkedHashSet<>(); - private final Set globalConstraints = new LinkedHashSet<>(); + private final LinkedHashSet transformationSpecifications = new LinkedHashSet<>(); + private final LinkedHashSet globalConstraints = new LinkedHashSet<>(); private final List objectives = new LinkedList<>(); private Strategy strategy; @Override protected DesignSpaceExplorationStoreAdapterImpl doBuild(ModelStore store) { - return new DesignSpaceExplorationStoreAdapterImpl(store, stopConditionSpecifications, - transformationSpecifications, globalConstraints, objectives, strategy); - } - - @Override - public DesignSpaceExplorationBuilder stopCondition(AnyQuery stopCondition) { - checkNotConfigured(); - stopConditionSpecifications.add(stopCondition); - return this; + return new DesignSpaceExplorationStoreAdapterImpl(store, transformationSpecifications, globalConstraints, + objectives, strategy); } @Override @@ -65,10 +54,6 @@ public class DesignSpaceExplorationBuilderImpl return this; } - public Set getStopConditionSpecifications() { - return stopConditionSpecifications; - } - @Override protected void doConfigure(ModelStoreBuilder storeBuilder) { storeBuilder.symbols(DesignSpaceExplorationAdapterImpl.NODE_COUNT_SYMBOL); diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java index 9c2fa4d6..f58715b7 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java @@ -1,31 +1,28 @@ package tools.refinery.store.query.dse.internal; import tools.refinery.store.adapter.ModelAdapter; -import tools.refinery.store.query.dnf.AnyQuery; -import tools.refinery.store.query.dnf.RelationalQuery; -import tools.refinery.store.query.dse.DesignSpaceExplorationStoreAdapter; import tools.refinery.store.model.Model; import tools.refinery.store.model.ModelStore; +import tools.refinery.store.query.dnf.RelationalQuery; +import tools.refinery.store.query.dse.DesignSpaceExplorationStoreAdapter; import tools.refinery.store.query.dse.Strategy; import tools.refinery.store.query.dse.objectives.Objective; +import java.util.LinkedHashSet; import java.util.List; -import java.util.Set; public class DesignSpaceExplorationStoreAdapterImpl implements DesignSpaceExplorationStoreAdapter { private final ModelStore store; - private final Set stopConditionSpecifications; - private final Set transformationSpecifications; - private final Set globalConstraints; + private final LinkedHashSet transformationSpecifications; + private final LinkedHashSet globalConstraints; private final List objectives; private final Strategy strategy; - public DesignSpaceExplorationStoreAdapterImpl(ModelStore store, Set stopConditionSpecifications, - Set transformationSpecifications, - Set globalConstraints, List objectives, - Strategy strategy) { + public DesignSpaceExplorationStoreAdapterImpl(ModelStore store, + LinkedHashSet transformationSpecifications, + LinkedHashSet globalConstraints, + List objectives, Strategy strategy) { this.store = store; - this.stopConditionSpecifications = stopConditionSpecifications; this.transformationSpecifications = transformationSpecifications; this.globalConstraints = globalConstraints; this.objectives = objectives; @@ -42,15 +39,11 @@ public class DesignSpaceExplorationStoreAdapterImpl implements DesignSpaceExplor return new DesignSpaceExplorationAdapterImpl(model, this); } - public Set getStopConditionSpecifications() { - return stopConditionSpecifications; - } - - public Set getTransformationSpecifications() { + public LinkedHashSet getTransformationSpecifications() { return transformationSpecifications; } - public Set getGlobalConstraints() { + public LinkedHashSet getGlobalConstraints() { return globalConstraints; } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/TransformationRule.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/TransformationRule.java index c46ff712..950ca930 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/TransformationRule.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/TransformationRule.java @@ -9,9 +9,8 @@ import tools.refinery.store.query.resultset.OrderedResultSet; import tools.refinery.store.query.resultset.ResultSet; import tools.refinery.store.tuple.Tuple; -import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.Random; -import java.util.Set; public class TransformationRule { @@ -66,8 +65,8 @@ public class TransformationRule { return activations; } - public Set getAllActivations() { - var result = new HashSet(); + public LinkedHashSet getAllActivations() { + var result = new LinkedHashSet(); var cursor = activations.getAll(); while (cursor.move()) { result.add(new Activation(this, cursor.getKey())); -- cgit v1.2.3-70-g09d2 From f123b148f01982ee3068f4be91c44241e0812830 Mon Sep 17 00:00:00 2001 From: nagilooh Date: Wed, 2 Aug 2023 11:57:12 +0200 Subject: Remove objective levels --- .../DesignSpaceExplorationAdapterImpl.java | 9 +- .../store/query/dse/objectives/BaseObjective.java | 16 -- .../dse/objectives/LeveledObjectivesHelper.java | 114 --------- .../store/query/dse/objectives/Objective.java | 10 - .../dse/objectives/ObjectiveComparatorHelper.java | 276 +++++---------------- .../query/dse/objectives/TrajectoryFitness.java | 71 ------ 6 files changed, 59 insertions(+), 437 deletions(-) delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/LeveledObjectivesHelper.java delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/TrajectoryFitness.java (limited to 'subprojects/store-query-viatra') diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java index 35f94dce..fbed0465 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java @@ -8,7 +8,6 @@ import tools.refinery.store.query.dse.DesignSpaceExplorationAdapter; import tools.refinery.store.query.dse.DesignSpaceExplorationStoreAdapter; import tools.refinery.store.query.dse.Strategy; import tools.refinery.store.query.dse.objectives.Fitness; -import tools.refinery.store.query.dse.objectives.LeveledObjectivesHelper; import tools.refinery.store.query.dse.objectives.Objective; import tools.refinery.store.query.dse.objectives.ObjectiveComparatorHelper; import tools.refinery.store.query.resultset.ResultSet; @@ -38,7 +37,6 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration private Map> statesAndUntraversedActivations; private Map> statesAndTraversedActivations; private Random random = new Random(); - private Objective[][] leveledObjectives; private boolean isNewState = false; private final boolean isVisualizationEnabled; private final ModelVisualizerAdapter modelVisualizerAdapter; @@ -64,7 +62,6 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration } objectives = storeAdapter.getObjectives(); - leveledObjectives = new LeveledObjectivesHelper(objectives).initLeveledObjectives(); statesAndUntraversedActivations = new HashMap<>(); statesAndTraversedActivations = new HashMap<>(); strategy = storeAdapter.getStrategy(); @@ -275,12 +272,8 @@ public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExploration public ObjectiveComparatorHelper getObjectiveComparatorHelper() { if (objectiveComparatorHelper == null) { - objectiveComparatorHelper = new ObjectiveComparatorHelper(leveledObjectives); + objectiveComparatorHelper = new ObjectiveComparatorHelper(objectives); } return objectiveComparatorHelper; } - - public Objective[][] getLeveledObjectives() { - return leveledObjectives; - } } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/BaseObjective.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/BaseObjective.java index fd8529f7..db8d5d7e 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/BaseObjective.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/BaseObjective.java @@ -24,7 +24,6 @@ public abstract class BaseObjective implements Objective { protected final String name; protected Comparator comparator = Comparators.HIGHER_IS_BETTER; - protected int level = 0; protected double fitnessConstraint; protected boolean isThereFitnessConstraint = false; @@ -50,21 +49,6 @@ public abstract class BaseObjective implements Objective { return comparator; } - @Override - public void setLevel(int level) { - this.level = level; - } - - @Override - public int getLevel() { - return level; - } - - public BaseObjective withLevel(int level) { - setLevel(level); - return this; - } - public BaseObjective withComparator(Comparator comparator) { setComparator(comparator); return this; diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/LeveledObjectivesHelper.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/LeveledObjectivesHelper.java deleted file mode 100644 index 6c4e7837..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/LeveledObjectivesHelper.java +++ /dev/null @@ -1,114 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010-2016, Andras Szabolcs Nagy and Daniel Varro - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-v20.html. - * - * SPDX-License-Identifier: EPL-2.0 - *******************************************************************************/ -package tools.refinery.store.query.dse.objectives; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.List; - -public class LeveledObjectivesHelper { - - private List objectives = new ArrayList(); - private Objective[][] leveledObjectives; - - public LeveledObjectivesHelper(List objectives) { - this.objectives = objectives; - } - - public Objective[][] initLeveledObjectives() { - if (objectives.isEmpty()) { - leveledObjectives = new Objective[0][0]; - return leveledObjectives; - } - - int level = objectives.get(0).getLevel(); - boolean oneLevelOnly = true; - for (Objective objective : objectives) { - if (objective.getLevel() != level) { - oneLevelOnly = false; - break; - } - } - - if (oneLevelOnly) { - leveledObjectives = new Objective[1][objectives.size()]; - for (int i = 0; i < objectives.size(); i++) { - leveledObjectives[0][i] = objectives.get(i); - } - return leveledObjectives; - } - - Objective[] objectivesArray = getSortedByLevelObjectives(objectives); - - int numberOfLevels = getNumberOfObjectiveLevels(objectivesArray); - - leveledObjectives = new Objective[numberOfLevels][]; - - fillLeveledObjectives(objectivesArray); - - return leveledObjectives; - } - - private void fillLeveledObjectives(Objective[] objectivesArray) { - int actLevel = objectivesArray[0].getLevel(); - int levelIndex = 0; - int lastIndex = 0; - int corrigationForLastLevel = 0; - boolean oneObjectiveAtLastLevel = false; - for (int i = 0; i < objectivesArray.length; i++) { - if (i == objectivesArray.length - 1) { - corrigationForLastLevel = 1; - if (objectivesArray[i - 1].getLevel() != objectivesArray[i].getLevel()) { - oneObjectiveAtLastLevel = true; - corrigationForLastLevel = 0; - } - } - if (objectivesArray[i].getLevel() != actLevel || corrigationForLastLevel == 1 || oneObjectiveAtLastLevel) { - leveledObjectives[levelIndex] = new Objective[i - lastIndex + corrigationForLastLevel]; - for (int j = lastIndex; j < i + corrigationForLastLevel; j++) { - leveledObjectives[levelIndex][j - lastIndex] = objectivesArray[j]; - } - if (oneObjectiveAtLastLevel) { - leveledObjectives[levelIndex + 1] = new Objective[1]; - leveledObjectives[levelIndex + 1][0] = objectivesArray[i]; - } - actLevel = objectivesArray[i].getLevel(); - levelIndex++; - lastIndex = i; - } - } - } - - private int getNumberOfObjectiveLevels(Objective[] objectivesArray) { - - int actLevel = objectivesArray[0].getLevel(); - int numberOfLevels = 1; - - for (int i = 1; i < objectivesArray.length; i++) { - if (objectivesArray[i].getLevel() != actLevel) { - numberOfLevels++; - actLevel = objectivesArray[i].getLevel(); - } - } - - return numberOfLevels; - } - - private Objective[] getSortedByLevelObjectives(List objectives) { - Objective[] objectivesArray = objectives.toArray(new Objective[objectives.size()]); - Arrays.sort(objectivesArray, Comparator.comparingInt(Objective::getLevel)); - return objectivesArray; - } - - public Objective[][] getLeveledObjectives() { - return leveledObjectives; - } - -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Objective.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Objective.java index b160b453..df86f36a 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Objective.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Objective.java @@ -97,14 +97,4 @@ public interface Objective { */ boolean satisfiesHardObjective(Double fitness); - /** - * Set the level of the objective. - */ - void setLevel(int level); - - /** - * Gets the level of the objective. - */ - int getLevel(); - } diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/ObjectiveComparatorHelper.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/ObjectiveComparatorHelper.java index 23fb24ee..0c925096 100644 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/ObjectiveComparatorHelper.java +++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/ObjectiveComparatorHelper.java @@ -1,218 +1,58 @@ -/******************************************************************************* - * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-v20.html. - * - * SPDX-License-Identifier: EPL-2.0 - *******************************************************************************/ -package tools.refinery.store.query.dse.objectives; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; - -import org.eclipse.viatra.query.runtime.matchers.util.Preconditions; - -/** - * This class is responsible to compare and sort fitness values. {@link TrajectoryFitness} instances can be added to an - * instance of this class, that it can sort them. - * - * @author András Szabolcs Nagy - */ -public class ObjectiveComparatorHelper { - - private Objective[][] leveledObjectives; - private List trajectoryFitnesses = new ArrayList(); - private Random random = new Random(); - private boolean computeCrowdingDistance = false; - - public ObjectiveComparatorHelper(Objective[][] leveledObjectives) { - this.leveledObjectives = leveledObjectives; - } - - public void setComputeCrowdingDistance(boolean computeCrowdingDistance) { - this.computeCrowdingDistance = computeCrowdingDistance; - } - - /** - * Compares two fitnesses based on hierarchical dominance. Returns -1 if the second parameter {@code o2} is a better - * solution ({@code o2} dominates {@code o1}), 1 if the first parameter {@code o1} is better ({@code o1} dominates - * {@code o2}) and returns 0 if they are non-dominating each other. - */ - public int compare(Fitness o1, Fitness o2) { - - levelsLoop: - for (Objective[] leveledObjective : leveledObjectives) { - - boolean o1HasBetterFitness = false; - boolean o2HasBetterFitness = false; - - for (Objective objective : leveledObjective) { - String objectiveName = objective.getName(); - int sgn = objective.getComparator().compare(o1.get(objectiveName), o2.get(objectiveName)); - - if (sgn < 0) { - o2HasBetterFitness = true; - } - if (sgn > 0) { - o1HasBetterFitness = true; - } - if (o1HasBetterFitness && o2HasBetterFitness) { - continue levelsLoop; - } - } - if (o2HasBetterFitness) { - return -1; - } else if (o1HasBetterFitness) { - return 1; - } - } - - return 0; - - } - - /** - * Adds a {@link TrajectoryFitness} to an inner list to compare later. - * - * @param trajectoryFitness - */ - public void addTrajectoryFitness(TrajectoryFitness trajectoryFitness) { - trajectoryFitnesses.add(trajectoryFitness); - } - - /** - * Clears the inner {@link TrajectoryFitness} list. - */ - public void clearTrajectoryFitnesses() { - trajectoryFitnesses.clear(); - } - - /** - * Returns the inner {@link TrajectoryFitness} list. - */ - public List getTrajectoryFitnesses() { - return trajectoryFitnesses; - } - - /** - * Returns a random {@link TrajectoryFitness} from the pareto front. - */ - public TrajectoryFitness getRandomBest() { - List paretoFront = getParetoFront(); - int randomIndex = random.nextInt(paretoFront.size()); - return paretoFront.get(randomIndex); - } - - /** - * Returns the pareto front of the previously added {@link TrajectoryFitness}. - */ - public List getParetoFront() { - return getFronts().get(0); - } - - /** - * Returns the previously added {@link TrajectoryFitness} instances in fronts. - */ - public List> getFronts() { - Preconditions.checkArgument(!trajectoryFitnesses.isEmpty(), "No trajectory fitnesses were added."); - List> fronts = new ArrayList>(); - - Map> dominatedInstances = new HashMap>(); - Map dominatingInstances = new HashMap(); - - // calculate dominations - for (TrajectoryFitness TrajectoryFitnessP : trajectoryFitnesses) { - dominatedInstances.put(TrajectoryFitnessP, new ArrayList()); - dominatingInstances.put(TrajectoryFitnessP, 0); - - for (TrajectoryFitness TrajectoryFitnessQ : trajectoryFitnesses) { - int dominates = compare(TrajectoryFitnessP.fitness, TrajectoryFitnessQ.fitness); - if (dominates > 0) { - dominatedInstances.get(TrajectoryFitnessP).add(TrajectoryFitnessQ); - } else if (dominates < 0) { - dominatingInstances.put(TrajectoryFitnessP, dominatingInstances.get(TrajectoryFitnessP) + 1); - } - } - - if (dominatingInstances.get(TrajectoryFitnessP) == 0) { - // p belongs to the first front - TrajectoryFitnessP.rank = 1; - if (fronts.isEmpty()) { - ArrayList firstDominationFront = new ArrayList(); - firstDominationFront.add(TrajectoryFitnessP); - fronts.add(firstDominationFront); - } else { - List firstDominationFront = fronts.get(0); - firstDominationFront.add(TrajectoryFitnessP); - } - } - } - - // create fronts - int i = 1; - while (fronts.size() == i) { - ArrayList nextDominationFront = new ArrayList(); - for (TrajectoryFitness TrajectoryFitnessP : fronts.get(i - 1)) { - for (TrajectoryFitness TrajectoryFitnessQ : dominatedInstances.get(TrajectoryFitnessP)) { - dominatingInstances.put(TrajectoryFitnessQ, dominatingInstances.get(TrajectoryFitnessQ) - 1); - if (dominatingInstances.get(TrajectoryFitnessQ) == 0) { - TrajectoryFitnessQ.rank = i + 1; - nextDominationFront.add(TrajectoryFitnessQ); - } - } - } - i++; - if (!nextDominationFront.isEmpty()) { - if (computeCrowdingDistance) { - crowdingDistanceAssignment(nextDominationFront, leveledObjectives); - } - fronts.add(nextDominationFront); - } - } - - return fronts; - } - - /** - * Executes the crowding distance assignment for the specified front. - * - * @param front - */ - public static void crowdingDistanceAssignment(List front, Objective[][] leveledObjectives) { - - for (TrajectoryFitness InstanceData : front) { - // initialize crowding distance - InstanceData.crowdingDistance = 0; - } - - for (final Objective[] objectives : leveledObjectives) { - for (final Objective objective : objectives) { - - final String m = objective.getName(); - TrajectoryFitness[] sortedFront = front.toArray(new TrajectoryFitness[0]); - // sort using m-th objective value - Arrays.sort(sortedFront, (o1, o2) -> objective.getComparator().compare(o1.fitness.get(m), o2.fitness.get(m))); - // so that boundary points are always selected - sortedFront[0].crowdingDistance = Double.POSITIVE_INFINITY; - sortedFront[sortedFront.length - 1].crowdingDistance = Double.POSITIVE_INFINITY; - // If minimal and maximal fitness value for this objective are - // equal, then do not change crowding distance - if (sortedFront[0].fitness.get(m) != sortedFront[sortedFront.length - 1].fitness.get(m)) { - for (int i = 1; i < sortedFront.length - 1; i++) { - double newCrowdingDistance = sortedFront[i].crowdingDistance; - newCrowdingDistance += (sortedFront[i + 1].fitness.get(m) - sortedFront[i - 1].fitness.get(m)) - / (sortedFront[sortedFront.length - 1].fitness.get(m) - sortedFront[0].fitness.get(m)); - - sortedFront[i].crowdingDistance = newCrowdingDistance; - } - } - } - } - } - -} +/******************************************************************************* + * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-v20.html. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package tools.refinery.store.query.dse.objectives; + +import java.util.List; + +/** + * This class is responsible to compare and sort fitness values. + * + * @author András Szabolcs Nagy + */ +public class ObjectiveComparatorHelper { + + private final List objectives; + + public ObjectiveComparatorHelper(List objectives) { + this.objectives = objectives; + } + + /** + * Compares two fitnesses based on dominance. Returns -1 if the second parameter {@code o2} is a better + * solution ({@code o2} dominates {@code o1}), 1 if the first parameter {@code o1} is better ({@code o1} dominates + * {@code o2}) and returns 0 if they are non-dominating each other. + */ + public int compare(Fitness o1, Fitness o2) { + + boolean o1HasBetterFitness = false; + boolean o2HasBetterFitness = false; + + for (Objective objective : objectives) { + String objectiveName = objective.getName(); + int sgn = objective.getComparator().compare(o1.get(objectiveName), o2.get(objectiveName)); + + if (sgn < 0) { + o2HasBetterFitness = true; + } + if (sgn > 0) { + o1HasBetterFitness = true; + } + if (o1HasBetterFitness && o2HasBetterFitness) { + break; + } + } + if (o2HasBetterFitness) { + } else if (o1HasBetterFitness) { + return 1; + } + + return 0; + + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/TrajectoryFitness.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/TrajectoryFitness.java deleted file mode 100644 index b9ff7067..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/TrajectoryFitness.java +++ /dev/null @@ -1,71 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-v20.html. - * - * SPDX-License-Identifier: EPL-2.0 - *******************************************************************************/ -package tools.refinery.store.query.dse.objectives; - -import java.util.Arrays; - - -/** - * This class represents a trajectory and its fitness. - * @author Andras Szabolcs Nagy - * - */ -public class TrajectoryFitness { - - public Object[] trajectory; - public Fitness fitness; - - public int rank; - public double crowdingDistance; - - private int hash; - - public int survive; - - /** - * Creates a {@link TrajectoryFitness} with the full trajectory. - * @param trajectory The trajectory. - * @param fitness The fitness. - */ - public TrajectoryFitness(Object[] trajectory, Fitness fitness) { - this.fitness = fitness; - this.trajectory = trajectory; - } - - /** - * Creates a {@link TrajectoryFitness} with the given activation id} - * @param transition The transition. - * @param fitness The fitness. - */ - public TrajectoryFitness(Object transition, Fitness fitness) { - this.fitness = fitness; - trajectory = new Object[] {transition}; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof TrajectoryFitness) { - return Arrays.equals(trajectory, ((TrajectoryFitness) obj).trajectory); - } - return false; - } - - @Override - public int hashCode() { - if (hash == 0 && trajectory.length > 0) { - hash = Arrays.hashCode(trajectory); - } - return hash; - } - - @Override - public String toString() { - return Arrays.toString(trajectory) + fitness.toString(); - } -} -- cgit v1.2.3-70-g09d2 From 85347a15d62169b233b36754aacd654623f7770c Mon Sep 17 00:00:00 2001 From: nagilooh Date: Wed, 2 Aug 2023 12:07:30 +0200 Subject: Update CRA test case --- .../refinery/store/query/dse/CRAExamplesTest.java | 233 ++++++++++++++++----- 1 file changed, 186 insertions(+), 47 deletions(-) (limited to 'subprojects/store-query-viatra') diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/CRAExamplesTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/CRAExamplesTest.java index 8fe50a42..2effb353 100644 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/CRAExamplesTest.java +++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/CRAExamplesTest.java @@ -1,112 +1,140 @@ package tools.refinery.store.query.dse; +import org.junit.jupiter.api.Test; +import tools.refinery.store.model.ModelStore; +import tools.refinery.store.query.ModelQueryAdapter; import tools.refinery.store.query.dnf.Query; import tools.refinery.store.query.dnf.RelationalQuery; import tools.refinery.store.query.dse.internal.TransformationRule; +import tools.refinery.store.query.dse.strategy.BestFirstStrategy; +import tools.refinery.store.query.dse.strategy.DepthFirstStrategy; +import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; import tools.refinery.store.query.view.AnySymbolView; import tools.refinery.store.query.view.KeyOnlyView; import tools.refinery.store.representation.Symbol; import tools.refinery.store.tuple.Tuple; +import tools.refinery.visualization.ModelVisualizerAdapter; +import tools.refinery.visualization.internal.FileFormat; import java.util.List; import static tools.refinery.store.query.literal.Literals.not; public class CRAExamplesTest { - private static final Symbol classModel = Symbol.of("ClassModel", 1); + private static final Symbol name = Symbol.of("Name", 1, String.class); + +// private static final Symbol classModel = Symbol.of("ClassModel", 1); private static final Symbol classElement = Symbol.of("ClassElement", 1); - private static final Symbol feature = Symbol.of("Feature", 1); +// private static final Symbol feature = Symbol.of("Feature", 1); + private static final Symbol attribute = Symbol.of("Attribute", 1); + private static final Symbol method = Symbol.of("Method", 1); - private static final Symbol isEncapsulatedBy = Symbol.of("IsEncapsulatedBy", 2); +// private static final Symbol isEncapsulatedBy = Symbol.of("IsEncapsulatedBy", 2); private static final Symbol encapsulates = Symbol.of("Encapsulates", 2); + private static final Symbol dataDependency = Symbol.of("DataDependency", 2); + private static final Symbol functionalDependency = Symbol.of("FunctionalDependency", 2); private static final Symbol features = Symbol.of("Features", 2); private static final Symbol classes = Symbol.of("Classes", 2); - private static final AnySymbolView classModelView = new KeyOnlyView<>(classModel); +// private static final AnySymbolView classModelView = new KeyOnlyView<>(classModel); private static final AnySymbolView classElementView = new KeyOnlyView<>(classElement); - private static final AnySymbolView featureView = new KeyOnlyView<>(feature); - private static final AnySymbolView isEncapsulatedByView = new KeyOnlyView<>(isEncapsulatedBy); +// private static final AnySymbolView featureView = new KeyOnlyView<>(feature); + private static final AnySymbolView attributeView = new KeyOnlyView<>(attribute); + private static final AnySymbolView methodView = new KeyOnlyView<>(method); +// private static final AnySymbolView isEncapsulatedByView = new KeyOnlyView<>(isEncapsulatedBy); private static final AnySymbolView encapsulatesView = new KeyOnlyView<>(encapsulates); + private static final AnySymbolView dataDependencyView = new KeyOnlyView<>(dataDependency); + private static final AnySymbolView functionalDependencyView = new KeyOnlyView<>(functionalDependency); private static final AnySymbolView featuresView = new KeyOnlyView<>(features); private static final AnySymbolView classesView = new KeyOnlyView<>(classes); /*Example Transformation rules*/ + private static final RelationalQuery feature = Query.of("Feature", + (builder, f) -> builder.clause( + attributeView.call(f)) + .clause( + methodView.call(f)) + ); + private static final RelationalQuery assignFeaturePreconditionHelper = Query.of("AssignFeaturePreconditionHelper", - (builder, model, c, f) -> builder.clause( + (builder, c, f) -> builder.clause( classElementView.call(c), - classesView.call(model, c), +// classesView.call(model, c), encapsulatesView.call(c, f) )); - private static final RelationalQuery assignFeaturePrecondition = Query.of("AssignFeaturePrecondition", (builder, c2, f) - -> builder.clause((model, c1) -> List.of( - classModelView.call(model), - featureView.call(f), - classElementView.call(c2), - featuresView.call(model, f), - classesView.call(model, c1), - not(assignFeaturePreconditionHelper.call(model, c2, f)), - not(encapsulatesView.call(c2, f)) + private static final RelationalQuery assignFeaturePrecondition = Query.of("AssignFeaturePrecondition", + (builder, f, c1) -> builder.clause((c2) -> List.of( +// classModelView.call(model), + feature.call(f), + classElementView.call(c1), +// featuresView.call(model, f), + not(assignFeaturePreconditionHelper.call(c2, f)), + not(encapsulatesView.call(c1, f)) ))); private static final RelationalQuery deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition", - (builder, model, c) -> builder.clause((f) -> List.of( - classModelView.call(model), + (builder, c) -> builder.clause((f) -> List.of( +// classModelView.call(model), classElementView.call(c), - featuresView.call(model, f), +// featuresView.call(model, f), not(encapsulatesView.call(c, f)) ))); private static final RelationalQuery createClassPreconditionHelper = Query.of("CreateClassPreconditionHelper", - (builder, model, f, c) -> builder.clause( + (builder, f, c) -> builder.clause( classElementView.call(c), - classesView.call(model, c), +// classesView.call(model, c), encapsulatesView.call(c, f) )); private static final RelationalQuery createClassPrecondition = Query.of("CreateClassPrecondition", - (builder, model, f) -> builder.clause((c) -> List.of( - classModelView.call(model), - featureView.call(f), - not(createClassPreconditionHelper.call(model, f, c)) + (builder, f) -> builder.clause((c) -> List.of( +// classModelView.call(model), + feature.call(f), + not(createClassPreconditionHelper.call(f, c)) ))); - private static final RelationalQuery moveFeature = Query.of("MoveFeature", - (builder, c1, c2, f) -> builder.clause((model) -> List.of( - classModelView.call(model), + private static final RelationalQuery moveFeaturePrecondition = Query.of("MoveFeature", + (builder, c1, c2, f) -> builder.clause( +// classModelView.call(model), classElementView.call(c1), classElementView.call(c2), - featureView.call(f), - classesView.call(model, c1), - classesView.call(model, c2), - featuresView.call(model, f), + c1.notEquivalent(c2), + feature.call(f), +// classesView.call(model, c1), +// classesView.call(model, c2), +// featuresView.call(model, f), encapsulatesView.call(c1, f) - ))); + )); private static final TransformationRule assignFeatureRule = new TransformationRule("AssignFeature", assignFeaturePrecondition, (model) -> { - var isEncapsulatedByInterpretation = model.getInterpretation(isEncapsulatedBy); +// var isEncapsulatedByInterpretation = model.getInterpretation(isEncapsulatedBy); + var encapsulatesInterpretation = model.getInterpretation(encapsulates); return ((Tuple activation) -> { var feature = activation.get(0); var classElement = activation.get(1); - isEncapsulatedByInterpretation.put(Tuple.of(feature, classElement), true); +// isEncapsulatedByInterpretation.put(Tuple.of(feature, classElement), true); + encapsulatesInterpretation.put(Tuple.of(classElement, feature), true); }); }); private static final TransformationRule deleteEmptyClassRule = new TransformationRule("DeleteEmptyClass", deleteEmptyClassPrecondition, (model) -> { - var classesInterpretation = model.getInterpretation(classes); +// var classesInterpretation = model.getInterpretation(classes); var classElementInterpretation = model.getInterpretation(classElement); - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); return ((Tuple activation) -> { - var modelElement = activation.get(0); - var classElement = activation.get(1); + // TODO: can we move dseAdapter outside? + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); +// var modelElement = activation.get(0); + var classElement = activation.get(0); - classesInterpretation.put(Tuple.of(modelElement, classElement), false); +// classesInterpretation.put(Tuple.of(modelElement, classElement), false); classElementInterpretation.put(Tuple.of(classElement), false); dseAdapter.deleteObject(Tuple.of(classElement)); }); @@ -115,21 +143,132 @@ public class CRAExamplesTest { private static final TransformationRule createClassRule = new TransformationRule("CreateClass", createClassPrecondition, (model) -> { - var adapter = model.getAdapter(DesignSpaceExplorationAdapter.class); var classElementInterpretation = model.getInterpretation(classElement); - var classesInterpretation = model.getInterpretation(classes); +// var classesInterpretation = model.getInterpretation(classes); var encapsulatesInterpretation = model.getInterpretation(encapsulates); - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); return ((Tuple activation) -> { - var modelElement = activation.get(0); - var feature = activation.get(1); + // TODO: can we move dseAdapter outside? + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); +// var modelElement = activation.get(0); + var feature = activation.get(0); var newClassElement = dseAdapter.createObject(); var newClassElementId = newClassElement.get(0); classElementInterpretation.put(newClassElement, true); - classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); +// classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); encapsulatesInterpretation.put(Tuple.of(newClassElementId, feature), true); }); }); + private static final TransformationRule moveFeatureRule = new TransformationRule("MoveFeature", + moveFeaturePrecondition, + (model) -> { + var encapsulatesInterpretation = model.getInterpretation(encapsulates); + return ((Tuple activation) -> { + var classElement1 = activation.get(0); + var classElement2 = activation.get(1); + var feature = activation.get(2); + + encapsulatesInterpretation.put(Tuple.of(classElement1, feature), false); + encapsulatesInterpretation.put(Tuple.of(classElement2, feature), true); + }); + }); + + @Test + void craTest() { + var store = ModelStore.builder() + .symbols(classElement, encapsulates, classes, features, attribute, method, dataDependency, + functionalDependency, name) + .with(ViatraModelQueryAdapter.builder() + .queries(feature, assignFeaturePreconditionHelper, assignFeaturePrecondition, + deleteEmptyClassPrecondition, createClassPreconditionHelper, createClassPrecondition, + moveFeaturePrecondition)) + .with(ModelVisualizerAdapter.builder()) + .with(DesignSpaceExplorationAdapter.builder() + .transformations(assignFeatureRule, deleteEmptyClassRule, createClassRule, moveFeatureRule) +// .strategy(new DepthFirstStrategy(3).continueIfHardObjectivesFulfilled() + .strategy(new BestFirstStrategy(6).continueIfHardObjectivesFulfilled() +// .goOnOnlyIfFitnessIsBetter() + )) + .build(); + + var model = store.createEmptyModel(); + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); +// dseAdapter.setRandom(1); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + +// var modelInterpretation = model.getInterpretation(classModel); + var nameInterpretation = model.getInterpretation(name); + var methodInterpretation = model.getInterpretation(method); + var attributeInterpretation = model.getInterpretation(attribute); + var dataDependencyInterpretation = model.getInterpretation(dataDependency); + var functionalDependencyInterpretation = model.getInterpretation(functionalDependency); + +// var modelElement = dseAdapter.createObject(); + var method1 = dseAdapter.createObject(); + var method1Id = method1.get(0); + var method2 = dseAdapter.createObject(); + var method2Id = method2.get(0); + var method3 = dseAdapter.createObject(); + var method3Id = method3.get(0); + var method4 = dseAdapter.createObject(); + var method4Id = method4.get(0); + var attribute1 = dseAdapter.createObject(); + var attribute1Id = attribute1.get(0); + var attribute2 = dseAdapter.createObject(); + var attribute2Id = attribute2.get(0); + var attribute3 = dseAdapter.createObject(); + var attribute3Id = attribute3.get(0); + var attribute4 = dseAdapter.createObject(); + var attribute4Id = attribute4.get(0); + var attribute5 = dseAdapter.createObject(); + var attribute5Id = attribute5.get(0); + + nameInterpretation.put(method1, "M1"); + nameInterpretation.put(method2, "M2"); + nameInterpretation.put(method3, "M3"); + nameInterpretation.put(method4, "M4"); + nameInterpretation.put(attribute1, "A1"); + nameInterpretation.put(attribute2, "A2"); + nameInterpretation.put(attribute3, "A3"); + nameInterpretation.put(attribute4, "A4"); + nameInterpretation.put(attribute5, "A5"); + + + +// modelInterpretation.put(modelElement, true); + methodInterpretation.put(method1, true); + methodInterpretation.put(method2, true); + methodInterpretation.put(method3, true); + methodInterpretation.put(method4, true); + attributeInterpretation.put(attribute1, true); + attributeInterpretation.put(attribute2, true); + attributeInterpretation.put(attribute3, true); + attributeInterpretation.put(attribute4, true); + attributeInterpretation.put(attribute5, true); + + dataDependencyInterpretation.put(Tuple.of(method1Id, attribute1Id), true); + dataDependencyInterpretation.put(Tuple.of(method1Id, attribute3Id), true); + dataDependencyInterpretation.put(Tuple.of(method2Id, attribute2Id), true); + dataDependencyInterpretation.put(Tuple.of(method3Id, attribute3Id), true); + dataDependencyInterpretation.put(Tuple.of(method3Id, attribute4Id), true); + dataDependencyInterpretation.put(Tuple.of(method4Id, attribute3Id), true); + dataDependencyInterpretation.put(Tuple.of(method4Id, attribute5Id), true); + + functionalDependencyInterpretation.put(Tuple.of(method1Id, attribute3Id), true); + functionalDependencyInterpretation.put(Tuple.of(method1Id, attribute4Id), true); + functionalDependencyInterpretation.put(Tuple.of(method2Id, attribute1Id), true); + functionalDependencyInterpretation.put(Tuple.of(method3Id, attribute1Id), true); + functionalDependencyInterpretation.put(Tuple.of(method3Id, attribute4Id), true); + functionalDependencyInterpretation.put(Tuple.of(method4Id, attribute2Id), true); + + queryEngine.flushChanges(); + + var states = dseAdapter.explore(); + System.out.println("states size: " + states.size()); + System.out.println("states: " + states); + var visualizer = model.getAdapter(ModelVisualizerAdapter.class); + visualizer.renderDesignSpace("test_output", FileFormat.SVG); + } + } -- cgit v1.2.3-70-g09d2 From c93d455d2459c2fbe0cfce7693d592986f65d44c Mon Sep 17 00:00:00 2001 From: nagilooh Date: Wed, 2 Aug 2023 14:07:35 +0200 Subject: Move DSE to new subproject --- settings.gradle.kts | 1 + subprojects/store-dse/build.gradle.kts | 16 + .../tools/refinery/store/dse/ActionFactory.java | 9 + .../store/dse/DesignSpaceExplorationAdapter.java | 61 +++ .../store/dse/DesignSpaceExplorationBuilder.java | 43 ++ .../dse/DesignSpaceExplorationStoreAdapter.java | 6 + .../java/tools/refinery/store/dse/Strategy.java | 8 + .../refinery/store/dse/internal/Activation.java | 9 + .../DesignSpaceExplorationAdapterImpl.java | 283 ++++++++++++ .../DesignSpaceExplorationBuilderImpl.java | 62 +++ .../DesignSpaceExplorationStoreAdapterImpl.java | 57 +++ .../store/dse/internal/TransformationRule.java | 84 ++++ .../AlwaysSatisfiedDummyHardObjective.java | 51 +++ .../store/dse/objectives/BaseObjective.java | 131 ++++++ .../refinery/store/dse/objectives/Comparators.java | 25 ++ .../refinery/store/dse/objectives/Fitness.java | 21 + .../refinery/store/dse/objectives/Objective.java | 100 +++++ .../dse/objectives/ObjectiveComparatorHelper.java | 58 +++ .../store/dse/strategy/BestFirstStrategy.java | 190 ++++++++ .../store/dse/strategy/DepthFirstStrategy.java | 108 +++++ .../tools/refinery/store/dse/CRAExamplesTest.java | 274 ++++++++++++ .../java/tools/refinery/store/dse/DebugTest.java | 117 +++++ .../store/dse/DesignSpaceExplorationTest.java | 487 +++++++++++++++++++++ .../refinery/store/dse/TransformationRuleTest.java | 403 +++++++++++++++++ .../refinery/store/dse/tests/QueryAssertions.java | 57 +++ .../refinery/store/query/dse/ActionFactory.java | 9 - .../query/dse/DesignSpaceExplorationAdapter.java | 61 --- .../query/dse/DesignSpaceExplorationBuilder.java | 44 -- .../dse/DesignSpaceExplorationStoreAdapter.java | 6 - .../tools/refinery/store/query/dse/Strategy.java | 10 - .../store/query/dse/internal/Activation.java | 9 - .../DesignSpaceExplorationAdapterImpl.java | 283 ------------ .../DesignSpaceExplorationBuilderImpl.java | 62 --- .../DesignSpaceExplorationStoreAdapterImpl.java | 57 --- .../query/dse/internal/TransformationRule.java | 84 ---- .../AlwaysSatisfiedDummyHardObjective.java | 51 --- .../store/query/dse/objectives/BaseObjective.java | 131 ------ .../store/query/dse/objectives/Comparators.java | 25 -- .../store/query/dse/objectives/Fitness.java | 21 - .../store/query/dse/objectives/Objective.java | 100 ----- .../dse/objectives/ObjectiveComparatorHelper.java | 58 --- .../query/dse/strategy/BestFirstStrategy.java | 190 -------- .../query/dse/strategy/DepthFirstStrategy.java | 108 ----- .../refinery/store/query/dse/CRAExamplesTest.java | 274 ------------ .../tools/refinery/store/query/dse/DebugTest.java | 117 ----- .../query/dse/DesignSpaceExplorationTest.java | 487 --------------------- .../store/query/dse/TransformationRuleTest.java | 403 ----------------- 47 files changed, 2661 insertions(+), 2590 deletions(-) create mode 100644 subprojects/store-dse/build.gradle.kts create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/ActionFactory.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationAdapter.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationBuilder.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationStoreAdapter.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/Strategy.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/Activation.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationAdapterImpl.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationBuilderImpl.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/TransformationRule.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/AlwaysSatisfiedDummyHardObjective.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/BaseObjective.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Comparators.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Fitness.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Objective.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/ObjectiveComparatorHelper.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstStrategy.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/DepthFirstStrategy.java create mode 100644 subprojects/store-dse/src/test/java/tools/refinery/store/dse/CRAExamplesTest.java create mode 100644 subprojects/store-dse/src/test/java/tools/refinery/store/dse/DebugTest.java create mode 100644 subprojects/store-dse/src/test/java/tools/refinery/store/dse/DesignSpaceExplorationTest.java create mode 100644 subprojects/store-dse/src/test/java/tools/refinery/store/dse/TransformationRuleTest.java create mode 100644 subprojects/store-dse/src/test/java/tools/refinery/store/dse/tests/QueryAssertions.java delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/ActionFactory.java delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationAdapter.java delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationBuilder.java delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationStoreAdapter.java delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/Strategy.java delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/Activation.java delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationBuilderImpl.java delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/TransformationRule.java delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/AlwaysSatisfiedDummyHardObjective.java delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/BaseObjective.java delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Comparators.java delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Fitness.java delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Objective.java delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/ObjectiveComparatorHelper.java delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/strategy/BestFirstStrategy.java delete mode 100644 subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/strategy/DepthFirstStrategy.java delete mode 100644 subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/CRAExamplesTest.java delete mode 100644 subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DebugTest.java delete mode 100644 subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DesignSpaceExplorationTest.java delete mode 100644 subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/TransformationRuleTest.java (limited to 'subprojects/store-query-viatra') diff --git a/settings.gradle.kts b/settings.gradle.kts index 8b53e7f7..0eae2800 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -14,6 +14,7 @@ include( "language-semantics", "language-web", "store", + "store-dse", "store-query", "store-query-viatra", "store-reasoning", diff --git a/subprojects/store-dse/build.gradle.kts b/subprojects/store-dse/build.gradle.kts new file mode 100644 index 00000000..bb1dee7d --- /dev/null +++ b/subprojects/store-dse/build.gradle.kts @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ + +plugins { + id("tools.refinery.gradle.java-library") +} + +dependencies { + api(project(":refinery-store-query")) + api(project(":refinery-store-query-viatra")) + api(project(":refinery-store-reasoning")) + api(project(":refinery-visualization")) +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/ActionFactory.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/ActionFactory.java new file mode 100644 index 00000000..2af22963 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/ActionFactory.java @@ -0,0 +1,9 @@ +package tools.refinery.store.dse; + +import org.eclipse.collections.api.block.procedure.Procedure; +import tools.refinery.store.model.Model; +import tools.refinery.store.tuple.Tuple; + +public interface ActionFactory { + Procedure prepare(Model model); +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationAdapter.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationAdapter.java new file mode 100644 index 00000000..729a6fc9 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationAdapter.java @@ -0,0 +1,61 @@ +package tools.refinery.store.dse; + +import tools.refinery.store.adapter.ModelAdapter; +import tools.refinery.store.map.Version; +import tools.refinery.store.dse.internal.Activation; +import tools.refinery.store.dse.internal.DesignSpaceExplorationBuilderImpl; +import tools.refinery.store.dse.objectives.Fitness; +import tools.refinery.store.dse.objectives.ObjectiveComparatorHelper; +import tools.refinery.store.tuple.Tuple; +import tools.refinery.store.tuple.Tuple1; + +import java.util.Collection; +import java.util.List; +import java.util.Random; + +public interface DesignSpaceExplorationAdapter extends ModelAdapter { + @Override + DesignSpaceExplorationStoreAdapter getStoreAdapter(); + + static DesignSpaceExplorationBuilder builder() { + return new DesignSpaceExplorationBuilderImpl(); + } + + Collection explore(); + + public int getModelSize(); + + public Tuple1 createObject(); + + public Tuple deleteObject(Tuple tuple); + + public boolean checkGlobalConstraints(); + + public boolean backtrack(); + + public Fitness calculateFitness(); + + public void newSolution(); + + public int getDepth(); + + public Collection getUntraversedActivations(); + + public boolean fireActivation(Activation activation); + + public void fireRandomActivation(); + + public boolean isCurrentInTrajectory(); + + public List getTrajectory(); + + public boolean isCurrentStateAlreadyTraversed(); + + public ObjectiveComparatorHelper getObjectiveComparatorHelper(); + + public void restoreTrajectory(List trajectory); + + public void setRandom(Random random); + + public void setRandom(long seed); +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationBuilder.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationBuilder.java new file mode 100644 index 00000000..8ca0037d --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationBuilder.java @@ -0,0 +1,43 @@ +package tools.refinery.store.dse; + +import tools.refinery.store.adapter.ModelAdapterBuilder; +import tools.refinery.store.query.dnf.RelationalQuery; +import tools.refinery.store.dse.internal.TransformationRule; +import tools.refinery.store.dse.objectives.Objective; + +import java.util.Collection; +import java.util.List; + +public interface DesignSpaceExplorationBuilder extends ModelAdapterBuilder { + default DesignSpaceExplorationBuilder transformations(TransformationRule... transformationRules) { + return transformations(List.of(transformationRules)); + } + + default DesignSpaceExplorationBuilder transformations(Collection transformationRules) { + transformationRules.forEach(this::transformation); + return this; + } + + default DesignSpaceExplorationBuilder globalConstraints(RelationalQuery... globalConstraints) { + return globalConstraints(List.of(globalConstraints)); + } + + default DesignSpaceExplorationBuilder globalConstraints(Collection globalConstraints) { + globalConstraints.forEach(this::globalConstraint); + return this; + } + + default DesignSpaceExplorationBuilder objectives(Objective... objectives) { + return objectives(List.of(objectives)); + } + + default DesignSpaceExplorationBuilder objectives(Collection objectives) { + objectives.forEach(this::objective); + return this; + } + + DesignSpaceExplorationBuilder transformation(TransformationRule transformationRule); + DesignSpaceExplorationBuilder globalConstraint(RelationalQuery globalConstraint); + DesignSpaceExplorationBuilder objective(Objective objective); + DesignSpaceExplorationBuilder strategy(Strategy strategy); +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationStoreAdapter.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationStoreAdapter.java new file mode 100644 index 00000000..5964cd82 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationStoreAdapter.java @@ -0,0 +1,6 @@ +package tools.refinery.store.dse; + +import tools.refinery.store.adapter.ModelStoreAdapter; + +public interface DesignSpaceExplorationStoreAdapter extends ModelStoreAdapter { +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/Strategy.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/Strategy.java new file mode 100644 index 00000000..cef43386 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/Strategy.java @@ -0,0 +1,8 @@ +package tools.refinery.store.dse; + +public interface Strategy { + + public void initStrategy(DesignSpaceExplorationAdapter designSpaceExplorationAdapter); + + public void explore(); +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/Activation.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/Activation.java new file mode 100644 index 00000000..f1de00e6 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/Activation.java @@ -0,0 +1,9 @@ +package tools.refinery.store.dse.internal; + +import tools.refinery.store.tuple.Tuple; + +public record Activation(TransformationRule transformationRule, Tuple activation) { + public boolean fire() { + return transformationRule.fireActivation(activation); + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationAdapterImpl.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationAdapterImpl.java new file mode 100644 index 00000000..5fb54da9 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationAdapterImpl.java @@ -0,0 +1,283 @@ +package tools.refinery.store.dse.internal; + +import tools.refinery.store.map.Version; +import tools.refinery.store.model.Interpretation; +import tools.refinery.store.model.Model; +import tools.refinery.store.query.ModelQueryAdapter; +import tools.refinery.store.query.dnf.RelationalQuery; +import tools.refinery.store.dse.DesignSpaceExplorationAdapter; +import tools.refinery.store.dse.DesignSpaceExplorationStoreAdapter; +import tools.refinery.store.dse.Strategy; +import tools.refinery.store.dse.objectives.Fitness; +import tools.refinery.store.dse.objectives.Objective; +import tools.refinery.store.dse.objectives.ObjectiveComparatorHelper; +import tools.refinery.store.query.resultset.ResultSet; +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.tuple.Tuple; +import tools.refinery.store.tuple.Tuple1; +import tools.refinery.visualization.ModelVisualizerAdapter; + +import java.util.*; + +public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExplorationAdapter { + static final Symbol NODE_COUNT_SYMBOL = Symbol.of("MODEL_SIZE", 0, Integer.class, 0); + private final Model model; + private final ModelQueryAdapter queryEngine; + private final DesignSpaceExplorationStoreAdapterImpl storeAdapter; + private final LinkedHashSet transformationRules; + private final LinkedHashSet globalConstraints; + private final List objectives; + private final LinkedHashSet> globalConstraintResultSets = new LinkedHashSet<>(); + private final Interpretation sizeInterpretation; + private final Strategy strategy; + + private ObjectiveComparatorHelper objectiveComparatorHelper; + private List trajectory = new LinkedList<>(); + private Fitness lastFitness; + private final LinkedHashSet solutions = new LinkedHashSet<>(); + private Map> statesAndUntraversedActivations; + private Map> statesAndTraversedActivations; + private Random random = new Random(); + private boolean isNewState = false; + private final boolean isVisualizationEnabled; + private final ModelVisualizerAdapter modelVisualizerAdapter; + + public List getTrajectory() { + return new LinkedList<>(trajectory); + } + + public DesignSpaceExplorationAdapterImpl(Model model, DesignSpaceExplorationStoreAdapterImpl storeAdapter) { + this.model = model; + this.storeAdapter = storeAdapter; + this.sizeInterpretation = model.getInterpretation(NODE_COUNT_SYMBOL); + queryEngine = model.getAdapter(ModelQueryAdapter.class); + + globalConstraints = storeAdapter.getGlobalConstraints(); + for (var constraint : globalConstraints) { + globalConstraintResultSets.add(queryEngine.getResultSet(constraint)); + } + + transformationRules = storeAdapter.getTransformationSpecifications(); + for (var rule : transformationRules) { + rule.prepare(model, queryEngine); + } + + objectives = storeAdapter.getObjectives(); + statesAndUntraversedActivations = new HashMap<>(); + statesAndTraversedActivations = new HashMap<>(); + strategy = storeAdapter.getStrategy(); + modelVisualizerAdapter = model.tryGetAdapter(ModelVisualizerAdapter.class).orElse(null); + isVisualizationEnabled = modelVisualizerAdapter != null; + + } + + @Override + public Model getModel() { + return model; + } + + @Override + public DesignSpaceExplorationStoreAdapter getStoreAdapter() { + return storeAdapter; + } + + @Override + public LinkedHashSet explore() { + var state = model.commit(); + trajectory.add(state); + statesAndUntraversedActivations.put(state, getAllActivations()); + statesAndTraversedActivations.put(state, new LinkedHashSet<>()); + strategy.initStrategy(this); + strategy.explore(); + return solutions; + } + + @Override + public int getModelSize() { + return sizeInterpretation.get(Tuple.of()); + } + + @Override + public Tuple1 createObject() { + var newNodeId = getModelSize(); + sizeInterpretation.put(Tuple.of(), newNodeId + 1); + return Tuple.of(newNodeId); + } + + @Override + public Tuple deleteObject(Tuple tuple) { + if (tuple.getSize() != 1) { + throw new IllegalArgumentException("Tuple size must be 1"); + } +// TODO: implement more efficient deletion +// if (tuple.get(0) == getModelSize() - 1) { +// sizeInterpretation.put(Tuple.of(), getModelSize() - 1); +// } + return tuple; + } + + @Override + public boolean checkGlobalConstraints() { + for (var resultSet : globalConstraintResultSets) { + if (resultSet.size() > 0) { + return false; + } + } + return true; + } + + @Override + public boolean backtrack() { + if (trajectory.size() < 2) { + return false; + } + if (isVisualizationEnabled) { + modelVisualizerAdapter.addTransition(trajectory.get(trajectory.size() - 1), + trajectory.get(trajectory.size() - 2), "backtrack"); + } + model.restore(trajectory.get(trajectory.size() - 2)); + trajectory.remove(trajectory.size() - 1); + return true; + } + + @Override + public void restoreTrajectory(List trajectory) { + model.restore(trajectory.get(trajectory.size() - 1)); +// if (isVisualizationEnabled) { +// modelVisualizerAdapter.addTransition(this.trajectory.get(trajectory.size() - 1), +// trajectory.get(trajectory.size() - 1), "restore"); +// } + this.trajectory = trajectory; + + } + + @Override + public void setRandom(Random random) { + this.random = random; + } + + @Override + public void setRandom(long seed) { + this.random = new Random(seed); + } + + @Override + public Fitness calculateFitness() { + Fitness result = new Fitness(); + boolean satisfiesHardObjectives = true; + for (Objective objective : objectives) { + var fitness = objective.getFitness(this); + result.put(objective.getName(), fitness); + if (objective.isHardObjective() && !objective.satisfiesHardObjective(fitness)) { + satisfiesHardObjectives = false; + } + } + result.setSatisfiesHardObjectives(satisfiesHardObjectives); + + lastFitness = result; + + return result; + } + + @Override + public void newSolution() { + var state = model.getState(); + solutions.add(state); + if (isVisualizationEnabled) { + modelVisualizerAdapter.addSolution(state); + } + } + + @Override + public int getDepth() { + return trajectory.size() - 1; + } + + public LinkedHashSet getUntraversedActivations() { +// return statesAndUntraversedActivations.get(model.getState()); + LinkedHashSet untraversedActivations = new LinkedHashSet<>(); + for (Activation activation : getAllActivations()) { + if (!statesAndTraversedActivations.get(model.getState()).contains(activation)) { + untraversedActivations.add(activation); + } + } + + return untraversedActivations; + } + + @Override + public boolean fireActivation(Activation activation) { + if (activation == null) { + return false; + } + var previousState = model.getState(); + if (!statesAndUntraversedActivations.get(previousState).contains(activation)) { +// TODO: throw exception? + return false; + } + if (!activation.fire()) { + return false; + } + statesAndUntraversedActivations.get(previousState).remove(activation); + statesAndTraversedActivations.get(previousState).add(activation); + var newState = model.commit(); + trajectory.add(newState); + isNewState = !statesAndUntraversedActivations.containsKey(newState); + statesAndUntraversedActivations.put(newState, getAllActivations()); + statesAndTraversedActivations.put(newState, new LinkedHashSet<>()); + if (isVisualizationEnabled) { + if (isNewState) { + modelVisualizerAdapter.addState(newState); + } + modelVisualizerAdapter.addTransition(trajectory.get(trajectory.size() - 2), + trajectory.get(trajectory.size() - 1), activation.transformationRule().getName(), + activation.activation()); + } + return true; + } + + @Override + public void fireRandomActivation() { + var activations = getUntraversedActivations(); + if (activations.isEmpty()) { +// TODO: throw exception + return; + } + int index = random.nextInt(activations.size()); + var iterator = activations.iterator(); + while (index-- > 0) { + iterator.next(); + } + var activationId = iterator.next(); + fireActivation(activationId); + } + + @Override + public boolean isCurrentInTrajectory() { + return trajectory.contains(model.getState()); + } + + public LinkedHashSet getAllActivations() { + LinkedHashSet result = new LinkedHashSet<>(); + for (var rule : transformationRules) { + result.addAll(rule.getAllActivations()); + } + return result; + } + + public boolean isCurrentStateAlreadyTraversed() { +// TODO: check isomorphism? + return !isNewState; + } + + public Fitness getLastFitness() { + return lastFitness; + } + + public ObjectiveComparatorHelper getObjectiveComparatorHelper() { + if (objectiveComparatorHelper == null) { + objectiveComparatorHelper = new ObjectiveComparatorHelper(objectives); + } + return objectiveComparatorHelper; + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationBuilderImpl.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationBuilderImpl.java new file mode 100644 index 00000000..03508adc --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationBuilderImpl.java @@ -0,0 +1,62 @@ +package tools.refinery.store.dse.internal; + +import tools.refinery.store.adapter.AbstractModelAdapterBuilder; +import tools.refinery.store.model.ModelStore; +import tools.refinery.store.model.ModelStoreBuilder; +import tools.refinery.store.query.dnf.RelationalQuery; +import tools.refinery.store.dse.DesignSpaceExplorationBuilder; +import tools.refinery.store.dse.Strategy; +import tools.refinery.store.dse.objectives.Objective; + +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; + +public class DesignSpaceExplorationBuilderImpl + extends AbstractModelAdapterBuilder + implements DesignSpaceExplorationBuilder { + private final LinkedHashSet transformationSpecifications = new LinkedHashSet<>(); + private final LinkedHashSet globalConstraints = new LinkedHashSet<>(); + private final List objectives = new LinkedList<>(); + private Strategy strategy; + + @Override + protected DesignSpaceExplorationStoreAdapterImpl doBuild(ModelStore store) { + return new DesignSpaceExplorationStoreAdapterImpl(store, transformationSpecifications, globalConstraints, + objectives, strategy); + } + + @Override + public DesignSpaceExplorationBuilder transformation(TransformationRule transformationRule) { + checkNotConfigured(); + transformationSpecifications.add(transformationRule); + return this; + } + + @Override + public DesignSpaceExplorationBuilder globalConstraint(RelationalQuery globalConstraint) { + checkNotConfigured(); + globalConstraints.add(globalConstraint); + return this; + } + + @Override + public DesignSpaceExplorationBuilder objective(Objective objective) { + checkNotConfigured(); + objectives.add(objective); + return this; + } + + @Override + public DesignSpaceExplorationBuilder strategy(Strategy strategy) { + checkNotConfigured(); + this.strategy = strategy; + return this; + } + + @Override + protected void doConfigure(ModelStoreBuilder storeBuilder) { + storeBuilder.symbols(DesignSpaceExplorationAdapterImpl.NODE_COUNT_SYMBOL); + super.doConfigure(storeBuilder); + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java new file mode 100644 index 00000000..b06462ce --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java @@ -0,0 +1,57 @@ +package tools.refinery.store.dse.internal; + +import tools.refinery.store.adapter.ModelAdapter; +import tools.refinery.store.model.Model; +import tools.refinery.store.model.ModelStore; +import tools.refinery.store.query.dnf.RelationalQuery; +import tools.refinery.store.dse.DesignSpaceExplorationStoreAdapter; +import tools.refinery.store.dse.Strategy; +import tools.refinery.store.dse.objectives.Objective; + +import java.util.LinkedHashSet; +import java.util.List; + +public class DesignSpaceExplorationStoreAdapterImpl implements DesignSpaceExplorationStoreAdapter { + private final ModelStore store; + private final LinkedHashSet transformationSpecifications; + private final LinkedHashSet globalConstraints; + private final List objectives; + private final Strategy strategy; + + public DesignSpaceExplorationStoreAdapterImpl(ModelStore store, + LinkedHashSet transformationSpecifications, + LinkedHashSet globalConstraints, + List objectives, Strategy strategy) { + this.store = store; + this.transformationSpecifications = transformationSpecifications; + this.globalConstraints = globalConstraints; + this.objectives = objectives; + this.strategy = strategy; + } + + @Override + public ModelStore getStore() { + return store; + } + + @Override + public ModelAdapter createModelAdapter(Model model) { + return new DesignSpaceExplorationAdapterImpl(model, this); + } + + public LinkedHashSet getTransformationSpecifications() { + return transformationSpecifications; + } + + public LinkedHashSet getGlobalConstraints() { + return globalConstraints; + } + + public List getObjectives() { + return objectives; + } + + public Strategy getStrategy() { + return strategy; + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/TransformationRule.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/TransformationRule.java new file mode 100644 index 00000000..ed2e77f1 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/TransformationRule.java @@ -0,0 +1,84 @@ +package tools.refinery.store.dse.internal; + +import org.eclipse.collections.api.block.procedure.Procedure; +import tools.refinery.store.model.Model; +import tools.refinery.store.query.ModelQueryAdapter; +import tools.refinery.store.query.dnf.RelationalQuery; +import tools.refinery.store.dse.ActionFactory; +import tools.refinery.store.query.resultset.OrderedResultSet; +import tools.refinery.store.query.resultset.ResultSet; +import tools.refinery.store.tuple.Tuple; + +import java.util.LinkedHashSet; +import java.util.Random; + +public class TransformationRule { + + private final String name; + private final RelationalQuery precondition; + private final ActionFactory actionFactory; + private Procedure action; + private OrderedResultSet activations; + private Random random; + private ModelQueryAdapter queryEngine; + + public TransformationRule(String name, RelationalQuery precondition, ActionFactory actionFactory) { + this(name, precondition, actionFactory, new Random()); + } + + public TransformationRule(String name, RelationalQuery precondition, ActionFactory actionFactory, long seed) { + this(name, precondition, actionFactory, new Random(seed)); + } + + public TransformationRule(String name, RelationalQuery precondition, ActionFactory actionFactory, Random random) { + this.name = name; + this.precondition = precondition; + this.actionFactory = actionFactory; + this.random = random; + } + public boolean prepare(Model model, ModelQueryAdapter queryEngine) { + action = actionFactory.prepare(model); + this.queryEngine = queryEngine; + activations = new OrderedResultSet<>(queryEngine.getResultSet(precondition)); + return true; + } + + public boolean fireActivation(Tuple activation) { + action.accept(activation); + queryEngine.flushChanges(); + return true; + } + + public boolean fireRandomActivation() { + return getRandomActivation().fire(); + } + + public String getName() { + return name; + } + + public RelationalQuery getPrecondition() { + return precondition; + } + + public ResultSet getAllActivationsAsSets() { + return activations; + } + + public LinkedHashSet getAllActivations() { + var result = new LinkedHashSet(); + var cursor = activations.getAll(); + while (cursor.move()) { + result.add(new Activation(this, cursor.getKey())); + } + return result; + } + + public Activation getRandomActivation() { + return new Activation(this, activations.getKey(random.nextInt(activations.size()))); + } + + public Activation getActivation(int index) { + return new Activation(this, activations.getKey(index)); + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/AlwaysSatisfiedDummyHardObjective.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/AlwaysSatisfiedDummyHardObjective.java new file mode 100644 index 00000000..82695704 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/AlwaysSatisfiedDummyHardObjective.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2010-2016, Andras Szabolcs Nagy, Zoltan Ujhelyi and Daniel Varro + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-v20.html. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package tools.refinery.store.dse.objectives; + +import tools.refinery.store.dse.DesignSpaceExplorationAdapter; + +/** + * This hard objective is fulfilled in any circumstances. Use it if all states should be regarded as a valid solution. + * + * @author Andras Szabolcs Nagy + * + */ +public class AlwaysSatisfiedDummyHardObjective extends BaseObjective { + + private static final String DEFAULT_NAME = "AlwaysSatisfiedDummyHardObjective"; + + public AlwaysSatisfiedDummyHardObjective() { + super(DEFAULT_NAME); + } + + public AlwaysSatisfiedDummyHardObjective(String name) { + super(name); + } + + @Override + public Double getFitness(DesignSpaceExplorationAdapter context) { + return 0d; + } + + @Override + public boolean isHardObjective() { + return true; + } + + @Override + public boolean satisfiesHardObjective(Double fitness) { + return true; + } + + @Override + public Objective createNew() { + return this; + } + +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/BaseObjective.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/BaseObjective.java new file mode 100644 index 00000000..24e3280d --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/BaseObjective.java @@ -0,0 +1,131 @@ +/******************************************************************************* + * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-v20.html. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package tools.refinery.store.dse.objectives; + +import tools.refinery.store.dse.DesignSpaceExplorationAdapter; + +import java.util.Comparator; +import java.util.Objects; + +/** + * This abstract class implements the basic functionality of an objective ({@link Objective} namely its name, + * comparator, level and fitness hard constraint. + * + * @author Andras Szabolcs Nagy + * + */ +public abstract class BaseObjective implements Objective { + + protected final String name; + protected Comparator comparator = Comparators.HIGHER_IS_BETTER; + + protected double fitnessConstraint; + protected boolean isThereFitnessConstraint = false; + protected Comparator fitnessConstraintComparator; + + public BaseObjective(String name) { + Objects.requireNonNull(name, "Name of the objective cannot be null."); + this.name = name; + } + + @Override + public String getName() { + return name; + } + + @Override + public void setComparator(Comparator comparator) { + this.comparator = comparator; + } + + @Override + public Comparator getComparator() { + return comparator; + } + + public BaseObjective withComparator(Comparator comparator) { + setComparator(comparator); + return this; + } + + /** + * Adds a hard constraint on the fitness value. For example, the fitness value must be better than 10 to accept the + * current state as a solution. + * + * @param fitnessConstraint + * Solutions should be better than this value. + * @param fitnessConstraintComparator + * {@link Comparator} to determine if the current state is better than the given value. + * @return The actual instance to enable builder pattern like usage. + */ + public BaseObjective withHardConstraintOnFitness(double fitnessConstraint, + Comparator fitnessConstraintComparator) { + this.fitnessConstraint = fitnessConstraint; + this.fitnessConstraintComparator = fitnessConstraintComparator; + this.isThereFitnessConstraint = true; + return this; + } + + /** + * Adds a hard constraint on the fitness value. For example, the fitness value must be better than 10 to accept the + * current state as a solution. The provided comparator will be used. + * + * @param fitnessConstraint + * Solutions should be better than this value. + * @return The actual instance to enable builder pattern like usage. + */ + public BaseObjective withHardConstraintOnFitness(double fitnessConstraint) { + return withHardConstraintOnFitness(fitnessConstraint, null); + } + + @Override + public void init(DesignSpaceExplorationAdapter context) { + if (fitnessConstraintComparator == null) { + fitnessConstraintComparator = comparator; + } + } + + @Override + public boolean isHardObjective() { + return isThereFitnessConstraint; + } + + @Override + public boolean satisfiesHardObjective(Double fitness) { + if (isThereFitnessConstraint) { + int compare = fitnessConstraintComparator.compare(fitness, fitnessConstraint); + if (compare < 0) { + return false; + } + } + return true; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof BaseObjective baseObjective) { + return name.equals(baseObjective.getName()); + } + return false; + } + + @Override + public String toString() { + return name; + } + +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Comparators.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Comparators.java new file mode 100644 index 00000000..e64e04e8 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Comparators.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-v20.html. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package tools.refinery.store.dse.objectives; + +import java.util.Comparator; + +public class Comparators { + + private Comparators() { /*Utility class constructor*/ } + + public static final Comparator HIGHER_IS_BETTER = (o1, o2) -> o1.compareTo(o2); + + public static final Comparator LOWER_IS_BETTER = (o1, o2) -> o2.compareTo(o1); + + private static final Double ZERO = (double) 0; + + public static final Comparator DIFFERENCE_TO_ZERO_IS_BETTER = (o1, o2) -> ZERO.compareTo(Math.abs(o1)-Math.abs(o2)); + +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Fitness.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Fitness.java new file mode 100644 index 00000000..16caed85 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Fitness.java @@ -0,0 +1,21 @@ +package tools.refinery.store.dse.objectives; + +import java.util.HashMap; + +public class Fitness extends HashMap { + + private boolean satisfiesHardObjectives; + + public boolean isSatisfiesHardObjectives() { + return satisfiesHardObjectives; + } + + public void setSatisfiesHardObjectives(boolean satisfiesHardObjectives) { + this.satisfiesHardObjectives = satisfiesHardObjectives; + } + + @Override + public String toString() { + return super.toString() + " hardObjectives=" + satisfiesHardObjectives; + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Objective.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Objective.java new file mode 100644 index 00000000..4e14c9a3 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Objective.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-v20.html. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package tools.refinery.store.dse.objectives; + +import tools.refinery.store.dse.DesignSpaceExplorationAdapter; + +import java.util.Comparator; + +/** + * + * Implementation of this interface represents a single objective of the DSE problem, which can assess a solution + * (trajectory) in a single number. It has a name and a comparator which orders two solution based on the calculated + * value. + *

+ * Objectives can be either hard or soft objectives. Hard objectives can be satisfied or unsatisfied. If all of the hard + * objectives are satisfied on a single solution, then it is considered to be a valid (or goal) solution. + *

+ * Certain objectives can have inner state for calculating the fitness value. In this case a new instance is necessary + * for every new thread, and the {@code createNew} method should not return the same instance more than once. + * + * @author Andras Szabolcs Nagy + * + */ +public interface Objective { + + /** + * Returns the name of the objective. + * + * @return The name of the objective. + */ + String getName(); + + /** + * Sets the {@link Comparator} which is used to compare fitness (doubles). It determines whether the objective is to + * minimize or maximize (or minimize or maximize a delta from a given number). + * + * @param comparator The comparator. + */ + void setComparator(Comparator comparator); + + /** + * Returns a {@link Comparator} which is used to compare fitness (doubles). It determines whether the objective is + * to minimize or maximize (or minimize or maximize a delta from a given number). + * + * @return The comparator. + */ + Comparator getComparator(); + + /** + * Calculates the value of the objective on a given solution (trajectory). + * + * @param context + * The {@link DesignSpaceExplorationAdapter} + * @return The objective value in double. + */ + Double getFitness(DesignSpaceExplorationAdapter context); + + /** + * Initializes the objective. It is called exactly once for every thread starts. + * + * @param context + * The {@link DesignSpaceExplorationAdapter}. + */ + void init(DesignSpaceExplorationAdapter context); + + /** + * Returns an instance of the {@link Objective}. If it returns the same instance, all the methods has to be thread + * save as they are called concurrently. + * + * @return An instance of the objective. + */ + Objective createNew(); + + /** + * Returns true if the objective is a hard objective. In such a case the method + * {@link Objective#satisfiesHardObjective(Double)} is called. + * + * @return True if the objective is a hard objective. + * @see Objective#satisfiesHardObjective(Double) + * @see Objective + */ + boolean isHardObjective(); + + /** + * Determines if the given fitness value satisfies the hard objective. + * + * @param fitness + * The fitness value of a solution. + * @return True if it satisfies the hard objective or it is a soft constraint. + * @see Objective + */ + boolean satisfiesHardObjective(Double fitness); + +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/ObjectiveComparatorHelper.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/ObjectiveComparatorHelper.java new file mode 100644 index 00000000..3184b8c4 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/ObjectiveComparatorHelper.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-v20.html. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package tools.refinery.store.dse.objectives; + +import java.util.List; + +/** + * This class is responsible to compare and sort fitness values. + * + * @author András Szabolcs Nagy + */ +public class ObjectiveComparatorHelper { + + private final List objectives; + + public ObjectiveComparatorHelper(List objectives) { + this.objectives = objectives; + } + + /** + * Compares two fitnesses based on dominance. Returns -1 if the second parameter {@code o2} is a better + * solution ({@code o2} dominates {@code o1}), 1 if the first parameter {@code o1} is better ({@code o1} dominates + * {@code o2}) and returns 0 if they are non-dominating each other. + */ + public int compare(Fitness o1, Fitness o2) { + + boolean o1HasBetterFitness = false; + boolean o2HasBetterFitness = false; + + for (Objective objective : objectives) { + String objectiveName = objective.getName(); + int sgn = objective.getComparator().compare(o1.get(objectiveName), o2.get(objectiveName)); + + if (sgn < 0) { + o2HasBetterFitness = true; + } + if (sgn > 0) { + o1HasBetterFitness = true; + } + if (o1HasBetterFitness && o2HasBetterFitness) { + break; + } + } + if (o2HasBetterFitness) { + } else if (o1HasBetterFitness) { + return 1; + } + + return 0; + + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstStrategy.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstStrategy.java new file mode 100644 index 00000000..05cc5bac --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstStrategy.java @@ -0,0 +1,190 @@ +package tools.refinery.store.dse.strategy; + +import tools.refinery.store.map.Version; +import tools.refinery.store.dse.DesignSpaceExplorationAdapter; +import tools.refinery.store.dse.Strategy; +import tools.refinery.store.dse.internal.Activation; +import tools.refinery.store.dse.objectives.Fitness; +import tools.refinery.store.dse.objectives.ObjectiveComparatorHelper; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.PriorityQueue; + +public class BestFirstStrategy implements Strategy { + + private DesignSpaceExplorationAdapter dseAdapter; + + private int maxDepth; + private boolean backTrackIfSolution = true; + private boolean onlyBetterFirst = false; + + private PriorityQueue trajectoriesToExplore; + + private static class TrajectoryWithFitness { + + public List trajectory; + public Fitness fitness; + + public TrajectoryWithFitness(List trajectory, Fitness fitness) { + super(); + this.trajectory = trajectory; + this.fitness = fitness; + } + + @Override + public String toString() { + return trajectory.toString() + fitness.toString(); + } + + } + + public BestFirstStrategy() { + this(-1); + } + + public BestFirstStrategy(int maxDepth) { + if (maxDepth < 0) { + this.maxDepth = Integer.MAX_VALUE; + } else { + this.maxDepth = maxDepth; + } + } + + public BestFirstStrategy continueIfHardObjectivesFulfilled() { + backTrackIfSolution = false; + return this; + } + + public BestFirstStrategy goOnOnlyIfFitnessIsBetter() { + onlyBetterFirst = true; + return this; + } + + @Override + public void initStrategy(DesignSpaceExplorationAdapter designSpaceExplorationAdapter) { + this.dseAdapter = designSpaceExplorationAdapter; + final ObjectiveComparatorHelper objectiveComparatorHelper = dseAdapter.getObjectiveComparatorHelper(); + + trajectoriesToExplore = new PriorityQueue(11, + (o1, o2) -> objectiveComparatorHelper.compare(o2.fitness, o1.fitness)); + } + + @Override + public void explore() { + final ObjectiveComparatorHelper objectiveComparatorHelper = dseAdapter.getObjectiveComparatorHelper(); + + boolean globalConstraintsAreSatisfied = dseAdapter.checkGlobalConstraints(); + if (!globalConstraintsAreSatisfied) { + // "Global constraint is not satisfied in the first state. Terminate."); + return; + } + + final Fitness firstFitness = dseAdapter.calculateFitness(); + if (firstFitness.isSatisfiesHardObjectives()) { + dseAdapter.newSolution(); + // "First state is a solution. Terminate."); + if (backTrackIfSolution) { + return; + } + } + + if (maxDepth == 0) { + return; + } + + final List firstTrajectory = dseAdapter.getTrajectory(); + TrajectoryWithFitness currentTrajectoryWithFitness = new TrajectoryWithFitness(firstTrajectory, firstFitness); + trajectoriesToExplore.add(currentTrajectoryWithFitness); + + mainLoop: while (true) { + + if (currentTrajectoryWithFitness == null) { + if (trajectoriesToExplore.isEmpty()) { + // "State space is fully traversed."); + return; + } else { + currentTrajectoryWithFitness = trajectoriesToExplore.element(); +// if (logger.isDebugEnabled()) { +// "New trajectory is chosen: " + currentTrajectoryWithFitness); +// } + dseAdapter.restoreTrajectory(currentTrajectoryWithFitness.trajectory); + } + } + + Collection activations = dseAdapter.getUntraversedActivations(); + Iterator iterator = activations.iterator(); + + + + while (iterator.hasNext()) { + final Activation nextActivation = iterator.next(); + if (!iterator.hasNext()) { + // "Last untraversed activation of the state."); + trajectoriesToExplore.remove(currentTrajectoryWithFitness); + } + +// if (logger.isDebugEnabled()) { +// "Executing new activation: " + nextActivation); +// } + dseAdapter.fireActivation(nextActivation); + if (dseAdapter.isCurrentStateAlreadyTraversed()) { + // "The new state is already visited."); + dseAdapter.backtrack(); + } else if (!dseAdapter.checkGlobalConstraints()) { + // "Global constraint is not satisfied."); + dseAdapter.backtrack(); + } else { + final Fitness nextFitness = dseAdapter.calculateFitness(); + if (nextFitness.isSatisfiesHardObjectives()) { + dseAdapter.newSolution(); + // "Found a solution."); + if (backTrackIfSolution) { + dseAdapter.backtrack(); + continue; + } + } + if (dseAdapter.getDepth() >= maxDepth) { + // "Reached max depth."); + dseAdapter.backtrack(); + continue; + } + + TrajectoryWithFitness nextTrajectoryWithFitness = new TrajectoryWithFitness( + dseAdapter.getTrajectory(), nextFitness); + trajectoriesToExplore.add(nextTrajectoryWithFitness); + + int compare = objectiveComparatorHelper.compare(currentTrajectoryWithFitness.fitness, + nextTrajectoryWithFitness.fitness); + if (compare < 0) { + // "Better fitness, moving on: " + nextFitness); + currentTrajectoryWithFitness = nextTrajectoryWithFitness; + continue mainLoop; + } else if (compare == 0) { + if (onlyBetterFirst) { + // "Equally good fitness, backtrack: " + nextFitness); + dseAdapter.backtrack(); + continue; + } else { + // "Equally good fitness, moving on: " + nextFitness); + currentTrajectoryWithFitness = nextTrajectoryWithFitness; + continue mainLoop; + } + } else { + // "Worse fitness."); + currentTrajectoryWithFitness = null; + continue mainLoop; + } + } + } + + // "State is fully traversed."); + trajectoriesToExplore.remove(currentTrajectoryWithFitness); + currentTrajectoryWithFitness = null; + + } + // "Interrupted."); + + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/DepthFirstStrategy.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/DepthFirstStrategy.java new file mode 100644 index 00000000..42985013 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/DepthFirstStrategy.java @@ -0,0 +1,108 @@ +package tools.refinery.store.dse.strategy; + +import tools.refinery.store.dse.DesignSpaceExplorationAdapter; +import tools.refinery.store.dse.Strategy; +import tools.refinery.store.dse.internal.Activation; +import tools.refinery.store.dse.objectives.Fitness; + +import java.util.Collection; + +public class DepthFirstStrategy implements Strategy { + + private DesignSpaceExplorationAdapter dseAdapter; + + private int maxDepth; + private boolean backTrackIfSolution = true; + + public DepthFirstStrategy() { + this(-1); + } + + public DepthFirstStrategy(int maxDepth) { + if (maxDepth < 0) { + this.maxDepth = Integer.MAX_VALUE; + } else { + this.maxDepth = maxDepth; + } + } + + public DepthFirstStrategy continueIfHardObjectivesFulfilled() { + backTrackIfSolution = false; + return this; + } + + @Override + public void initStrategy(DesignSpaceExplorationAdapter designSpaceExplorationAdapter) { + this.dseAdapter = designSpaceExplorationAdapter; + } + + @Override + public void explore() { + mainloop: while (true) { + var globalConstraintsAreSatisfied = dseAdapter.checkGlobalConstraints(); + if (!globalConstraintsAreSatisfied) { + var isSuccessfulUndo = dseAdapter.backtrack(); + if (!isSuccessfulUndo) { +// "Global constraint is not satisfied and cannot backtrack." + break; + } + else { +// "Global constraint is not satisfied, backtrack." + continue; + } + } + + Fitness fitness = dseAdapter.calculateFitness(); + if (fitness.isSatisfiesHardObjectives()) { + dseAdapter.newSolution(); + if (backTrackIfSolution) { + var isSuccessfulUndo = dseAdapter.backtrack(); + if (!isSuccessfulUndo) { +// "Found a solution but cannot backtrack." + break; + } else { +// "Found a solution, backtrack." + continue; + } + } + } + + var depth = dseAdapter.getDepth(); + if (dseAdapter.getDepth() >= maxDepth) { + var isSuccessfulUndo = dseAdapter.backtrack(); + if (!isSuccessfulUndo) { +// "Reached max depth but cannot backtrack." + break; + } + } + + Collection activations; + do { + activations = dseAdapter.getUntraversedActivations(); + if (activations.isEmpty()) { + if (!dseAdapter.backtrack()) { + // "No more transitions from current state and cannot backtrack." + break mainloop; + } + else { + // "No more transitions from current state, backtrack." + continue; + } + } + } while (activations.isEmpty()); + + dseAdapter.fireRandomActivation(); +// if (dseAdapter.isCurrentInTrajectory()) { +// if (!dseAdapter.backtrack()) { +//// TODO: throw exception +//// "The new state is present in the trajectory but cannot backtrack. Should never happen!" +// break; +// } +// else { +//// "The new state is already visited in the trajectory, backtrack." +// continue; +// } +// } + } + } +} diff --git a/subprojects/store-dse/src/test/java/tools/refinery/store/dse/CRAExamplesTest.java b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/CRAExamplesTest.java new file mode 100644 index 00000000..e7cc60d6 --- /dev/null +++ b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/CRAExamplesTest.java @@ -0,0 +1,274 @@ +package tools.refinery.store.dse; + +import org.junit.jupiter.api.Test; +import tools.refinery.store.model.ModelStore; +import tools.refinery.store.query.ModelQueryAdapter; +import tools.refinery.store.query.dnf.Query; +import tools.refinery.store.query.dnf.RelationalQuery; +import tools.refinery.store.dse.internal.TransformationRule; +import tools.refinery.store.dse.strategy.BestFirstStrategy; +import tools.refinery.store.dse.strategy.DepthFirstStrategy; +import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; +import tools.refinery.store.query.view.AnySymbolView; +import tools.refinery.store.query.view.KeyOnlyView; +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.tuple.Tuple; +import tools.refinery.visualization.ModelVisualizerAdapter; +import tools.refinery.visualization.internal.FileFormat; + +import java.util.List; + +import static tools.refinery.store.query.literal.Literals.not; + +public class CRAExamplesTest { + private static final Symbol name = Symbol.of("Name", 1, String.class); + +// private static final Symbol classModel = Symbol.of("ClassModel", 1); + private static final Symbol classElement = Symbol.of("ClassElement", 1); +// private static final Symbol feature = Symbol.of("Feature", 1); + private static final Symbol attribute = Symbol.of("Attribute", 1); + private static final Symbol method = Symbol.of("Method", 1); + +// private static final Symbol isEncapsulatedBy = Symbol.of("IsEncapsulatedBy", 2); + private static final Symbol encapsulates = Symbol.of("Encapsulates", 2); + private static final Symbol dataDependency = Symbol.of("DataDependency", 2); + private static final Symbol functionalDependency = Symbol.of("FunctionalDependency", 2); + + private static final Symbol features = Symbol.of("Features", 2); + private static final Symbol classes = Symbol.of("Classes", 2); + +// private static final AnySymbolView classModelView = new KeyOnlyView<>(classModel); + private static final AnySymbolView classElementView = new KeyOnlyView<>(classElement); +// private static final AnySymbolView featureView = new KeyOnlyView<>(feature); + private static final AnySymbolView attributeView = new KeyOnlyView<>(attribute); + private static final AnySymbolView methodView = new KeyOnlyView<>(method); +// private static final AnySymbolView isEncapsulatedByView = new KeyOnlyView<>(isEncapsulatedBy); + private static final AnySymbolView encapsulatesView = new KeyOnlyView<>(encapsulates); + private static final AnySymbolView dataDependencyView = new KeyOnlyView<>(dataDependency); + private static final AnySymbolView functionalDependencyView = new KeyOnlyView<>(functionalDependency); + private static final AnySymbolView featuresView = new KeyOnlyView<>(features); + private static final AnySymbolView classesView = new KeyOnlyView<>(classes); + + /*Example Transformation rules*/ + private static final RelationalQuery feature = Query.of("Feature", + (builder, f) -> builder.clause( + attributeView.call(f)) + .clause( + methodView.call(f)) + ); + + private static final RelationalQuery assignFeaturePreconditionHelper = Query.of("AssignFeaturePreconditionHelper", + (builder, c, f) -> builder.clause( + classElementView.call(c), +// classesView.call(model, c), + encapsulatesView.call(c, f) + )); + + private static final RelationalQuery assignFeaturePrecondition = Query.of("AssignFeaturePrecondition", + (builder, f, c1) -> builder.clause((c2) -> List.of( +// classModelView.call(model), + feature.call(f), + classElementView.call(c1), +// featuresView.call(model, f), + not(assignFeaturePreconditionHelper.call(c2, f)), + not(encapsulatesView.call(c1, f)) + ))); + + private static final RelationalQuery deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition", + (builder, c) -> builder.clause((f) -> List.of( +// classModelView.call(model), + classElementView.call(c), +// featuresView.call(model, f), + not(encapsulatesView.call(c, f)) + ))); + + private static final RelationalQuery createClassPreconditionHelper = Query.of("CreateClassPreconditionHelper", + (builder, f, c) -> builder.clause( + classElementView.call(c), +// classesView.call(model, c), + encapsulatesView.call(c, f) + )); + + private static final RelationalQuery createClassPrecondition = Query.of("CreateClassPrecondition", + (builder, f) -> builder.clause((c) -> List.of( +// classModelView.call(model), + feature.call(f), + not(createClassPreconditionHelper.call(f, c)) + ))); + + private static final RelationalQuery moveFeaturePrecondition = Query.of("MoveFeature", + (builder, c1, c2, f) -> builder.clause( +// classModelView.call(model), + classElementView.call(c1), + classElementView.call(c2), + c1.notEquivalent(c2), + feature.call(f), +// classesView.call(model, c1), +// classesView.call(model, c2), +// featuresView.call(model, f), + encapsulatesView.call(c1, f) + )); + + private static final TransformationRule assignFeatureRule = new TransformationRule("AssignFeature", + assignFeaturePrecondition, + (model) -> { +// var isEncapsulatedByInterpretation = model.getInterpretation(isEncapsulatedBy); + var encapsulatesInterpretation = model.getInterpretation(encapsulates); + return ((Tuple activation) -> { + var feature = activation.get(0); + var classElement = activation.get(1); + +// isEncapsulatedByInterpretation.put(Tuple.of(feature, classElement), true); + encapsulatesInterpretation.put(Tuple.of(classElement, feature), true); + }); + }); + + private static final TransformationRule deleteEmptyClassRule = new TransformationRule("DeleteEmptyClass", + deleteEmptyClassPrecondition, + (model) -> { +// var classesInterpretation = model.getInterpretation(classes); + var classElementInterpretation = model.getInterpretation(classElement); + return ((Tuple activation) -> { + // TODO: can we move dseAdapter outside? + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); +// var modelElement = activation.get(0); + var classElement = activation.get(0); + +// classesInterpretation.put(Tuple.of(modelElement, classElement), false); + classElementInterpretation.put(Tuple.of(classElement), false); + dseAdapter.deleteObject(Tuple.of(classElement)); + }); + }); + + private static final TransformationRule createClassRule = new TransformationRule("CreateClass", + createClassPrecondition, + (model) -> { + var classElementInterpretation = model.getInterpretation(classElement); +// var classesInterpretation = model.getInterpretation(classes); + var encapsulatesInterpretation = model.getInterpretation(encapsulates); + return ((Tuple activation) -> { + // TODO: can we move dseAdapter outside? + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); +// var modelElement = activation.get(0); + var feature = activation.get(0); + + var newClassElement = dseAdapter.createObject(); + var newClassElementId = newClassElement.get(0); + classElementInterpretation.put(newClassElement, true); +// classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); + encapsulatesInterpretation.put(Tuple.of(newClassElementId, feature), true); + }); + }); + + private static final TransformationRule moveFeatureRule = new TransformationRule("MoveFeature", + moveFeaturePrecondition, + (model) -> { + var encapsulatesInterpretation = model.getInterpretation(encapsulates); + return ((Tuple activation) -> { + var classElement1 = activation.get(0); + var classElement2 = activation.get(1); + var feature = activation.get(2); + + encapsulatesInterpretation.put(Tuple.of(classElement1, feature), false); + encapsulatesInterpretation.put(Tuple.of(classElement2, feature), true); + }); + }); + + @Test + void craTest() { + var store = ModelStore.builder() + .symbols(classElement, encapsulates, classes, features, attribute, method, dataDependency, + functionalDependency, name) + .with(ViatraModelQueryAdapter.builder() + .queries(feature, assignFeaturePreconditionHelper, assignFeaturePrecondition, + deleteEmptyClassPrecondition, createClassPreconditionHelper, createClassPrecondition, + moveFeaturePrecondition)) + .with(ModelVisualizerAdapter.builder()) + .with(DesignSpaceExplorationAdapter.builder() + .transformations(assignFeatureRule, deleteEmptyClassRule, createClassRule, moveFeatureRule) +// .strategy(new DepthFirstStrategy(3).continueIfHardObjectivesFulfilled() + .strategy(new BestFirstStrategy(6).continueIfHardObjectivesFulfilled() +// .goOnOnlyIfFitnessIsBetter() + )) + .build(); + + var model = store.createEmptyModel(); + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); +// dseAdapter.setRandom(1); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + +// var modelInterpretation = model.getInterpretation(classModel); + var nameInterpretation = model.getInterpretation(name); + var methodInterpretation = model.getInterpretation(method); + var attributeInterpretation = model.getInterpretation(attribute); + var dataDependencyInterpretation = model.getInterpretation(dataDependency); + var functionalDependencyInterpretation = model.getInterpretation(functionalDependency); + +// var modelElement = dseAdapter.createObject(); + var method1 = dseAdapter.createObject(); + var method1Id = method1.get(0); + var method2 = dseAdapter.createObject(); + var method2Id = method2.get(0); + var method3 = dseAdapter.createObject(); + var method3Id = method3.get(0); + var method4 = dseAdapter.createObject(); + var method4Id = method4.get(0); + var attribute1 = dseAdapter.createObject(); + var attribute1Id = attribute1.get(0); + var attribute2 = dseAdapter.createObject(); + var attribute2Id = attribute2.get(0); + var attribute3 = dseAdapter.createObject(); + var attribute3Id = attribute3.get(0); + var attribute4 = dseAdapter.createObject(); + var attribute4Id = attribute4.get(0); + var attribute5 = dseAdapter.createObject(); + var attribute5Id = attribute5.get(0); + + nameInterpretation.put(method1, "M1"); + nameInterpretation.put(method2, "M2"); + nameInterpretation.put(method3, "M3"); + nameInterpretation.put(method4, "M4"); + nameInterpretation.put(attribute1, "A1"); + nameInterpretation.put(attribute2, "A2"); + nameInterpretation.put(attribute3, "A3"); + nameInterpretation.put(attribute4, "A4"); + nameInterpretation.put(attribute5, "A5"); + + + +// modelInterpretation.put(modelElement, true); + methodInterpretation.put(method1, true); + methodInterpretation.put(method2, true); + methodInterpretation.put(method3, true); + methodInterpretation.put(method4, true); + attributeInterpretation.put(attribute1, true); + attributeInterpretation.put(attribute2, true); + attributeInterpretation.put(attribute3, true); + attributeInterpretation.put(attribute4, true); + attributeInterpretation.put(attribute5, true); + + dataDependencyInterpretation.put(Tuple.of(method1Id, attribute1Id), true); + dataDependencyInterpretation.put(Tuple.of(method1Id, attribute3Id), true); + dataDependencyInterpretation.put(Tuple.of(method2Id, attribute2Id), true); + dataDependencyInterpretation.put(Tuple.of(method3Id, attribute3Id), true); + dataDependencyInterpretation.put(Tuple.of(method3Id, attribute4Id), true); + dataDependencyInterpretation.put(Tuple.of(method4Id, attribute3Id), true); + dataDependencyInterpretation.put(Tuple.of(method4Id, attribute5Id), true); + + functionalDependencyInterpretation.put(Tuple.of(method1Id, attribute3Id), true); + functionalDependencyInterpretation.put(Tuple.of(method1Id, attribute4Id), true); + functionalDependencyInterpretation.put(Tuple.of(method2Id, attribute1Id), true); + functionalDependencyInterpretation.put(Tuple.of(method3Id, attribute1Id), true); + functionalDependencyInterpretation.put(Tuple.of(method3Id, attribute4Id), true); + functionalDependencyInterpretation.put(Tuple.of(method4Id, attribute2Id), true); + + queryEngine.flushChanges(); + + var states = dseAdapter.explore(); + System.out.println("states size: " + states.size()); + System.out.println("states: " + states); + var visualizer = model.getAdapter(ModelVisualizerAdapter.class); + visualizer.renderDesignSpace("test_output", FileFormat.SVG); + } + +} diff --git a/subprojects/store-dse/src/test/java/tools/refinery/store/dse/DebugTest.java b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/DebugTest.java new file mode 100644 index 00000000..911c0661 --- /dev/null +++ b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/DebugTest.java @@ -0,0 +1,117 @@ +package tools.refinery.store.dse; + +import org.junit.jupiter.api.Test; +import tools.refinery.store.model.ModelStore; +import tools.refinery.store.query.ModelQueryAdapter; +import tools.refinery.store.query.dnf.Query; +import tools.refinery.store.dse.internal.TransformationRule; +import tools.refinery.store.dse.strategy.BestFirstStrategy; +import tools.refinery.store.dse.strategy.DepthFirstStrategy; +import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; +import tools.refinery.store.query.view.AnySymbolView; +import tools.refinery.store.query.view.KeyOnlyView; +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.tuple.Tuple; +import tools.refinery.visualization.ModelVisualizerAdapter; +import tools.refinery.visualization.internal.FileFormat; + +public class DebugTest { + private static final Symbol classModel = Symbol.of("ClassModel", 1); + private static final Symbol classElement = Symbol.of("ClassElement", 1); + private static final Symbol feature = Symbol.of("Feature", 1); + + private static final Symbol isEncapsulatedBy = Symbol.of("IsEncapsulatedBy", 2); + private static final Symbol encapsulates = Symbol.of("Encapsulates", 2); + + private static final Symbol features = Symbol.of("Features", 2); + private static final Symbol classes = Symbol.of("Classes", 2); + + private static final AnySymbolView classModelView = new KeyOnlyView<>(classModel); + private static final AnySymbolView classElementView = new KeyOnlyView<>(classElement); + private static final AnySymbolView featureView = new KeyOnlyView<>(feature); + private static final AnySymbolView isEncapsulatedByView = new KeyOnlyView<>(isEncapsulatedBy); + private static final AnySymbolView encapsulatesView = new KeyOnlyView<>(encapsulates); + private static final AnySymbolView featuresView = new KeyOnlyView<>(features); + private static final AnySymbolView classesView = new KeyOnlyView<>(classes); + + + @Test + void BFSTest() { + var createClassPrecondition = Query.of("CreateClassPrecondition", + (builder, model) -> builder.clause( + classModelView.call(model) + )); + + var createClassRule = new TransformationRule("CreateClass", + createClassPrecondition, + (model) -> { + var classesInterpretation = model.getInterpretation(classes); + var classElementInterpretation = model.getInterpretation(classElement); + return ((Tuple activation) -> { + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var modelElement = activation.get(0); + + var newClassElement = dseAdapter.createObject(); + var newClassElementId = newClassElement.get(0); + + classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); + classElementInterpretation.put(Tuple.of(newClassElementId), true); + }); + }); + + var createFeaturePrecondition = Query.of("CreateFeaturePrecondition", + (builder, model) -> builder.clause( + classModelView.call(model) + )); + + var createFeatureRule = new TransformationRule("CreateFeature", + createFeaturePrecondition, + (model) -> { + var featuresInterpretation = model.getInterpretation(features); + var featureInterpretation = model.getInterpretation(feature); + return ((Tuple activation) -> { + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var modelElement = activation.get(0); + + var newClassElement = dseAdapter.createObject(); + var newClassElementId = newClassElement.get(0); + + featuresInterpretation.put(Tuple.of(modelElement, newClassElementId), true); + featureInterpretation.put(Tuple.of(newClassElementId), true); + }); + }); + + var store = ModelStore.builder() + .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features) + .with(ViatraModelQueryAdapter.builder() + .queries(createClassPrecondition, createFeaturePrecondition)) + .with(ModelVisualizerAdapter.builder()) + .with(DesignSpaceExplorationAdapter.builder() + .transformations(createClassRule, createFeatureRule) + .strategy(new DepthFirstStrategy(4).continueIfHardObjectivesFulfilled() +// .strategy(new BestFirstStrategy(4).continueIfHardObjectivesFulfilled() +// .goOnOnlyIfFitnessIsBetter() + )) + .build(); + + var model = store.createEmptyModel(); + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); +// dseAdapter.setRandom(1); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + + var modelElementInterpretation = model.getInterpretation(classModel); + var classElementInterpretation = model.getInterpretation(classElement); + var modelElement = dseAdapter.createObject(); + modelElementInterpretation.put(modelElement, true); + classElementInterpretation.put(modelElement, true); + queryEngine.flushChanges(); + + + var states = dseAdapter.explore(); + var visualizer = model.getAdapter(ModelVisualizerAdapter.class); + visualizer.renderDesignSpace("test_output", FileFormat.SVG); + System.out.println("states size: " + states.size()); + System.out.println("states: " + states); + + } +} diff --git a/subprojects/store-dse/src/test/java/tools/refinery/store/dse/DesignSpaceExplorationTest.java b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/DesignSpaceExplorationTest.java new file mode 100644 index 00000000..c454f4ec --- /dev/null +++ b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/DesignSpaceExplorationTest.java @@ -0,0 +1,487 @@ +package tools.refinery.store.dse; + +import org.junit.jupiter.api.Test; +import tools.refinery.store.model.ModelStore; +import tools.refinery.store.query.ModelQueryAdapter; +import tools.refinery.store.query.dnf.Query; +import tools.refinery.store.dse.internal.TransformationRule; +import tools.refinery.store.dse.strategy.BestFirstStrategy; +import tools.refinery.store.dse.strategy.DepthFirstStrategy; +import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; +import tools.refinery.store.query.view.AnySymbolView; +import tools.refinery.store.query.view.KeyOnlyView; +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.tuple.Tuple; +import tools.refinery.visualization.ModelVisualizerAdapter; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class DesignSpaceExplorationTest { +// private static final Symbol namedElement = Symbol.of("NamedElement", 1); +// private static final Symbol attribute = Symbol.of("Attribute", 1); +// private static final Symbol method = Symbol.of("Method", 1); +// private static final Symbol dataDependency = Symbol.of("DataDependency", 2); +// private static final Symbol functionalDependency = Symbol.of("FunctionalDependency", 2); + + private static final Symbol classModel = Symbol.of("ClassModel", 1); + private static final Symbol classElement = Symbol.of("ClassElement", 1); + private static final Symbol feature = Symbol.of("Feature", 1); + + private static final Symbol isEncapsulatedBy = Symbol.of("IsEncapsulatedBy", 2); + private static final Symbol encapsulates = Symbol.of("Encapsulates", 2); + + private static final Symbol features = Symbol.of("Features", 2); + private static final Symbol classes = Symbol.of("Classes", 2); + + private static final AnySymbolView classModelView = new KeyOnlyView<>(classModel); + private static final AnySymbolView classElementView = new KeyOnlyView<>(classElement); + private static final AnySymbolView featureView = new KeyOnlyView<>(feature); + private static final AnySymbolView isEncapsulatedByView = new KeyOnlyView<>(isEncapsulatedBy); + private static final AnySymbolView encapsulatesView = new KeyOnlyView<>(encapsulates); + private static final AnySymbolView featuresView = new KeyOnlyView<>(features); + private static final AnySymbolView classesView = new KeyOnlyView<>(classes); + + @Test + void createObjectTest() { + var store = ModelStore.builder() + .with(ViatraModelQueryAdapter.builder()) + .with(DesignSpaceExplorationAdapter.builder()) + .build(); + + var model = store.createEmptyModel(); + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + + assertEquals(0, dseAdapter.getModelSize()); + + var newModel = dseAdapter.createObject(); + var newModelId = newModel.get(0); + var newClass1 = dseAdapter.createObject(); + var newClass1Id = newClass1.get(0); + var newClass2 = dseAdapter.createObject(); + var newClass2Id = newClass2.get(0); + var newField = dseAdapter.createObject(); + var newFieldId = newField.get(0); + + assertEquals(0, newModelId); + assertEquals(1, newClass1Id); + assertEquals(2, newClass2Id); + assertEquals(3, newFieldId); + assertEquals(4, dseAdapter.getModelSize()); + } + + @Test + void deleteMiddleObjectTest() { + var store = ModelStore.builder() + .with(ViatraModelQueryAdapter.builder()) + .with(DesignSpaceExplorationAdapter.builder()) + .build(); + + var model = store.createEmptyModel(); + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + + assertEquals(0, dseAdapter.getModelSize()); + + var newObject0 = dseAdapter.createObject(); + var newObject0Id = newObject0.get(0); + var newObject1 = dseAdapter.createObject(); + var newObject1Id = newObject1.get(0); + var newObject2 = dseAdapter.createObject(); + var newObject2Id = newObject2.get(0); + var newObject3 = dseAdapter.createObject(); + var newObject3Id = newObject3.get(0); + + assertEquals(0, newObject0Id); + assertEquals(1, newObject1Id); + assertEquals(2, newObject2Id); + assertEquals(3, newObject3Id); + assertEquals(4, dseAdapter.getModelSize()); + + dseAdapter.deleteObject(newObject1); + assertEquals(4, dseAdapter.getModelSize()); + + var newObject4 = dseAdapter.createObject(); + var newObject4Id = newObject4.get(0); + assertEquals(4, newObject4Id); + assertEquals(5, dseAdapter.getModelSize()); + + dseAdapter.deleteObject(newObject4); + assertEquals(5, dseAdapter.getModelSize()); + } + + @Test + void DFSTrivialTest() { + var store = ModelStore.builder() + .symbols(classModel) + .with(ViatraModelQueryAdapter.builder()) + .with(ModelVisualizerAdapter.builder()) + .with(DesignSpaceExplorationAdapter.builder() + .strategy(new DepthFirstStrategy(0))) + .build(); + + var model = store.createEmptyModel(); + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + + var states = dseAdapter.explore(); + assertEquals(1, states.size()); + assertEquals(0, states.iterator().next()); + } + + @Test + void DFSOneRuleTest() { + var createClassPrecondition = Query.of("CreateClassPrecondition", + (builder, model) -> builder.clause( + classModelView.call(model) + )); + + var createClassRule = new TransformationRule("CreateClass", + createClassPrecondition, + (model) -> { + var classesInterpretation = model.getInterpretation(classes); + var classElementInterpretation = model.getInterpretation(classElement); + return ((Tuple activation) -> { + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var modelElement = activation.get(0); + + var newClassElement = dseAdapter.createObject(); + var newClassElementId = newClassElement.get(0); + + classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); + classElementInterpretation.put(Tuple.of(newClassElementId), true); + }); + }); + + var store = ModelStore.builder() + .symbols(classModel, classElement, classes) + .with(ViatraModelQueryAdapter.builder() + .queries(createClassPrecondition)) + .with(ModelVisualizerAdapter.builder()) + .with(DesignSpaceExplorationAdapter.builder() + .transformations(createClassRule) + .strategy(new DepthFirstStrategy(4) + )) + .build(); + + var model = store.createEmptyModel(); + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + + var modelElementInterpretation = model.getInterpretation(classModel); + modelElementInterpretation.put(dseAdapter.createObject(), true); + queryEngine.flushChanges(); + + var states = dseAdapter.explore(); + assertEquals(1, states.size()); + assertEquals(0, states.iterator().next()); + } + + @Test + void DFSContinueTest() { + var createClassPrecondition = Query.of("CreateClassPrecondition", + (builder, model) -> builder.clause( + classModelView.call(model) + )); + + var createClassRule = new TransformationRule("CreateClass", + createClassPrecondition, + (model) -> { + var classesInterpretation = model.getInterpretation(classes); + var classElementInterpretation = model.getInterpretation(classElement); + return ((Tuple activation) -> { + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var modelElement = activation.get(0); + + var newClassElement = dseAdapter.createObject(); + var newClassElementId = newClassElement.get(0); + + classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); + classElementInterpretation.put(Tuple.of(newClassElementId), true); + }); + }); + + var store = ModelStore.builder() + .symbols(classModel, classElement, classes) + .with(ViatraModelQueryAdapter.builder() + .queries(createClassPrecondition)) + .with(ModelVisualizerAdapter.builder()) + .with(DesignSpaceExplorationAdapter.builder() + .transformations(createClassRule) + .strategy(new DepthFirstStrategy(4).continueIfHardObjectivesFulfilled() + )) + .build(); + + var model = store.createEmptyModel(); + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + + var modelElementInterpretation = model.getInterpretation(classModel); + modelElementInterpretation.put(dseAdapter.createObject(), true); + queryEngine.flushChanges(); + + var states = dseAdapter.explore(); + var iterator = states.iterator(); + assertEquals(5, states.size()); + assertEquals(0, iterator.next()); + assertEquals(1, iterator.next()); + assertEquals(2, iterator.next()); + assertEquals(3, iterator.next()); + assertEquals(4, iterator.next()); + } + + @Test + void DFSCompletenessTest() { + var createClassPrecondition = Query.of("CreateClassPrecondition", + (builder, model) -> builder.clause( + classModelView.call(model) + )); + + var createClassRule = new TransformationRule("CreateClass", + createClassPrecondition, + (model) -> { + var classesInterpretation = model.getInterpretation(classes); + var classElementInterpretation = model.getInterpretation(classElement); + return ((Tuple activation) -> { + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var modelElement = activation.get(0); + + var newClassElement = dseAdapter.createObject(); + var newClassElementId = newClassElement.get(0); + + classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); + classElementInterpretation.put(Tuple.of(newClassElementId), true); + }); + }); + + var createFeaturePrecondition = Query.of("CreateFeaturePrecondition", + (builder, model) -> builder.clause( + classModelView.call(model) + )); + + var createFeatureRule = new TransformationRule("CreateFeature", + createFeaturePrecondition, + (model) -> { + var featuresInterpretation = model.getInterpretation(features); + var featureInterpretation = model.getInterpretation(feature); + return ((Tuple activation) -> { + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var modelElement = activation.get(0); + + var newClassElement = dseAdapter.createObject(); + var newClassElementId = newClassElement.get(0); + + featuresInterpretation.put(Tuple.of(modelElement, newClassElementId), true); + featureInterpretation.put(Tuple.of(newClassElementId), true); + }); + }); + + var store = ModelStore.builder() + .symbols(classModel, classElement, classes, feature, features, isEncapsulatedBy, encapsulates) + .with(ViatraModelQueryAdapter.builder() + .queries(createClassPrecondition, createFeaturePrecondition)) + .with(ModelVisualizerAdapter.builder()) + .with(DesignSpaceExplorationAdapter.builder() + .transformations(createClassRule, createFeatureRule) + .strategy(new DepthFirstStrategy(10).continueIfHardObjectivesFulfilled() + )) + .build(); + + var model = store.createEmptyModel(); + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + + var modelElementInterpretation = model.getInterpretation(classModel); + modelElementInterpretation.put(dseAdapter.createObject(), true); + queryEngine.flushChanges(); + + var states = dseAdapter.explore(); + assertEquals(2047, states.size()); + } + + @Test + void BFSTrivialTest() { + var store = ModelStore.builder() + .symbols(classModel) + .with(ViatraModelQueryAdapter.builder()) + .with(ModelVisualizerAdapter.builder()) + .with(DesignSpaceExplorationAdapter.builder() + .strategy(new BestFirstStrategy(0))) + .build(); + + var model = store.createEmptyModel(); + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + + var states = dseAdapter.explore(); + assertEquals(1, states.size()); + assertEquals(0, states.iterator().next()); + } + + @Test + void BFSOneRuleTest() { + var createClassPrecondition = Query.of("CreateClassPrecondition", + (builder, model) -> builder.clause( + classModelView.call(model) + )); + + var createClassRule = new TransformationRule("CreateClass", + createClassPrecondition, + (model) -> { + var classesInterpretation = model.getInterpretation(classes); + var classElementInterpretation = model.getInterpretation(classElement); + return ((Tuple activation) -> { + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var modelElement = activation.get(0); + + var newClassElement = dseAdapter.createObject(); + var newClassElementId = newClassElement.get(0); + + classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); + classElementInterpretation.put(Tuple.of(newClassElementId), true); + }); + }); + + var store = ModelStore.builder() + .symbols(classModel, classElement, classes) + .with(ViatraModelQueryAdapter.builder() + .queries(createClassPrecondition)) + .with(ModelVisualizerAdapter.builder()) + .with(DesignSpaceExplorationAdapter.builder() + .transformations(createClassRule) + .strategy(new BestFirstStrategy(4) + )) + .build(); + + var model = store.createEmptyModel(); + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + + var modelElementInterpretation = model.getInterpretation(classModel); + modelElementInterpretation.put(dseAdapter.createObject(), true); + queryEngine.flushChanges(); + + var states = dseAdapter.explore(); + assertEquals(1, states.size()); + assertEquals(0, states.iterator().next()); + } + + @Test + void BFSContinueTest() { + var createClassPrecondition = Query.of("CreateClassPrecondition", + (builder, model) -> builder.clause( + classModelView.call(model) + )); + + var createClassRule = new TransformationRule("CreateClass", + createClassPrecondition, + (model) -> { + var classesInterpretation = model.getInterpretation(classes); + var classElementInterpretation = model.getInterpretation(classElement); + return ((Tuple activation) -> { + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var modelElement = activation.get(0); + + var newClassElement = dseAdapter.createObject(); + var newClassElementId = newClassElement.get(0); + + classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); + classElementInterpretation.put(Tuple.of(newClassElementId), true); + }); + }); + + var store = ModelStore.builder() + .symbols(classModel, classElement, classes) + .with(ViatraModelQueryAdapter.builder() + .queries(createClassPrecondition)) + .with(ModelVisualizerAdapter.builder()) + .with(DesignSpaceExplorationAdapter.builder() + .transformations(createClassRule) + .strategy(new BestFirstStrategy(4).continueIfHardObjectivesFulfilled() + )) + .build(); + + var model = store.createEmptyModel(); + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + + var modelElementInterpretation = model.getInterpretation(classModel); + modelElementInterpretation.put(dseAdapter.createObject(), true); + queryEngine.flushChanges(); + + var states = dseAdapter.explore(); + var iterator = states.iterator(); + assertEquals(5, states.size()); + assertEquals(0, iterator.next()); + assertEquals(1, iterator.next()); + assertEquals(2, iterator.next()); + assertEquals(3, iterator.next()); + assertEquals(4, iterator.next()); + } + + @Test + void BFSCompletenessTest() { + var createClassPrecondition = Query.of("CreateClassPrecondition", + (builder, model) -> builder.clause( + classModelView.call(model) + )); + + var createClassRule = new TransformationRule("CreateClass", + createClassPrecondition, + (model) -> { + var classesInterpretation = model.getInterpretation(classes); + var classElementInterpretation = model.getInterpretation(classElement); + return ((Tuple activation) -> { + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var modelElement = activation.get(0); + + var newClassElement = dseAdapter.createObject(); + var newClassElementId = newClassElement.get(0); + + classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); + classElementInterpretation.put(Tuple.of(newClassElementId), true); + }); + }); + + var createFeaturePrecondition = Query.of("CreateFeaturePrecondition", + (builder, model) -> builder.clause( + classModelView.call(model) + )); + + var createFeatureRule = new TransformationRule("CreateFeature", + createFeaturePrecondition, + (model) -> { + var featuresInterpretation = model.getInterpretation(features); + var featureInterpretation = model.getInterpretation(feature); + return ((Tuple activation) -> { + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var modelElement = activation.get(0); + + var newClassElement = dseAdapter.createObject(); + var newClassElementId = newClassElement.get(0); + + featuresInterpretation.put(Tuple.of(modelElement, newClassElementId), true); + featureInterpretation.put(Tuple.of(newClassElementId), true); + }); + }); + + var store = ModelStore.builder() + .symbols(classModel, classElement, classes, feature, features, isEncapsulatedBy, encapsulates) + .with(ViatraModelQueryAdapter.builder() + .queries(createClassPrecondition, createFeaturePrecondition)) + .with(ModelVisualizerAdapter.builder()) + .with(DesignSpaceExplorationAdapter.builder() + .transformations(createClassRule, createFeatureRule) + .strategy(new BestFirstStrategy(10).continueIfHardObjectivesFulfilled() + )) + .build(); + + var model = store.createEmptyModel(); + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + + var modelElementInterpretation = model.getInterpretation(classModel); + modelElementInterpretation.put(dseAdapter.createObject(), true); + queryEngine.flushChanges(); + + var states = dseAdapter.explore(); + assertEquals(2047, states.size()); + } + +} diff --git a/subprojects/store-dse/src/test/java/tools/refinery/store/dse/TransformationRuleTest.java b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/TransformationRuleTest.java new file mode 100644 index 00000000..a32d392b --- /dev/null +++ b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/TransformationRuleTest.java @@ -0,0 +1,403 @@ +package tools.refinery.store.dse; + +import org.junit.jupiter.api.Test; +import tools.refinery.store.model.ModelStore; +import tools.refinery.store.query.ModelQueryAdapter; +import tools.refinery.store.query.dnf.Query; +import tools.refinery.store.dse.internal.TransformationRule; +import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; +import tools.refinery.store.query.view.AnySymbolView; +import tools.refinery.store.query.view.KeyOnlyView; +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.tuple.Tuple; + +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static tools.refinery.store.query.literal.Literals.not; +import static tools.refinery.store.dse.tests.QueryAssertions.assertResults; + +public class TransformationRuleTest { + + private static final Symbol classModel = Symbol.of("ClassModel", 1); + private static final Symbol classElement = Symbol.of("ClassElement", 1); + private static final Symbol feature = Symbol.of("Feature", 1); + + private static final Symbol isEncapsulatedBy = Symbol.of("IsEncapsulatedBy", 2); + private static final Symbol encapsulates = Symbol.of("Encapsulates", 2); + + private static final Symbol features = Symbol.of("Features", 2); + private static final Symbol classes = Symbol.of("Classes", 2); + + private static final AnySymbolView classModelView = new KeyOnlyView<>(classModel); + private static final AnySymbolView classElementView = new KeyOnlyView<>(classElement); + private static final AnySymbolView featureView = new KeyOnlyView<>(feature); + private static final AnySymbolView isEncapsulatedByView = new KeyOnlyView<>(isEncapsulatedBy); + private static final AnySymbolView encapsulatesView = new KeyOnlyView<>(encapsulates); + private static final AnySymbolView featuresView = new KeyOnlyView<>(features); + private static final AnySymbolView classesView = new KeyOnlyView<>(classes); + + @Test + void activationsTest() { + var assignFeaturePreconditionHelper = Query.of("AssignFeaturePreconditionHelper", + (builder, model, c, f) -> builder.clause( + classElementView.call(c), + classesView.call(model, c), + encapsulatesView.call(c, f) + )); + + var assignFeaturePrecondition = Query.of("AssignFeaturePrecondition", (builder, c2, f) + -> builder.clause((model, c1) -> List.of( + classModelView.call(model), + featureView.call(f), + classElementView.call(c2), + featuresView.call(model, f), + classesView.call(model, c1), + not(assignFeaturePreconditionHelper.call(model, c2, f)), + not(encapsulatesView.call(c2, f)) + ))); + + var deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition", + (builder, model, c) -> builder.clause((f) -> List.of( + classModelView.call(model), + classElementView.call(c), + featuresView.call(model, f), + not(encapsulatesView.call(c, f)) + ))); + + TransformationRule assignFeatureRule = new TransformationRule("AssignFeature", + assignFeaturePrecondition, + (model) -> { + var isEncapsulatedByInterpretation = model.getInterpretation(isEncapsulatedBy); + return ((Tuple activation) -> { + var feature = activation.get(0); + var classElement = activation.get(1); + + isEncapsulatedByInterpretation.put(Tuple.of(feature, classElement), true); + }); + }); + + TransformationRule deleteEmptyClassRule = new TransformationRule("DeleteEmptyClass", + deleteEmptyClassPrecondition, + (model) -> { + var classesInterpretation = model.getInterpretation(classes); + var classElementInterpretation = model.getInterpretation(classElement); + return ((Tuple activation) -> { + var modelElement = activation.get(0); + var classElement = activation.get(1); + + classesInterpretation.put(Tuple.of(modelElement, classElement), false); + classElementInterpretation.put(Tuple.of(classElement), false); + }); + }); + + + var store = ModelStore.builder() + .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features) + .with(ViatraModelQueryAdapter.builder() + .queries(assignFeaturePrecondition, assignFeaturePreconditionHelper, + deleteEmptyClassPrecondition)) + .with(DesignSpaceExplorationAdapter.builder()) + .build(); + + var model = store.createEmptyModel(); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + assignFeatureRule.prepare(model, queryEngine); + deleteEmptyClassRule.prepare(model, queryEngine); + + var classModelInterpretation = model.getInterpretation(classModel); + var classElementInterpretation = model.getInterpretation(classElement); + var featureInterpretation = model.getInterpretation(feature); + var featuresInterpretation = model.getInterpretation(features); + var classesInterpretation = model.getInterpretation(classes); + + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var newModel = dseAdapter.createObject(); + var newModelId = newModel.get(0); + var newClass1 = dseAdapter.createObject(); + var newClass1Id = newClass1.get(0); + var newClass2 = dseAdapter.createObject(); + var newClass2Id = newClass2.get(0); + var newField = dseAdapter.createObject(); + var newFieldId = newField.get(0); + + classModelInterpretation.put(newModel, true); + classElementInterpretation.put(newClass1, true); + classElementInterpretation.put(newClass2, true); + featureInterpretation.put(newField, true); + classesInterpretation.put(Tuple.of(newModelId, newClass1Id), true); + classesInterpretation.put(Tuple.of(newModelId, newClass2Id), true); + featuresInterpretation.put(Tuple.of(newModelId, newFieldId), true); + + queryEngine.flushChanges(); + + var assignFeatureRuleActivations = assignFeatureRule.getAllActivationsAsSets(); + var deleteEmptyClassRuleActivations = deleteEmptyClassRule.getAllActivationsAsSets(); + + assertResults(Map.of( + Tuple.of(newClass1Id, newFieldId), true, + Tuple.of(newClass2Id, newFieldId), true + ), assignFeatureRuleActivations); + + assertResults(Map.of( + Tuple.of(newModelId, newClass1Id), true, + Tuple.of(newModelId, newClass2Id), true + ), deleteEmptyClassRuleActivations); + } + + @Test + void randomActivationTest() { + var deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition", + (builder, model, c) -> builder.clause((f) -> List.of( + classModelView.call(model), + classElementView.call(c), + featuresView.call(model, f), + not(encapsulatesView.call(c, f)) + ))); + + TransformationRule deleteEmptyClassRule0 = new TransformationRule("DeleteEmptyClass0", + deleteEmptyClassPrecondition, + (model) -> { + var classesInterpretation = model.getInterpretation(classes); + var classElementInterpretation = model.getInterpretation(classElement); + return ((Tuple activation) -> { + var modelElement = activation.get(0); + var classElement = activation.get(1); + + classesInterpretation.put(Tuple.of(modelElement, classElement), false); + classElementInterpretation.put(Tuple.of(classElement), false); + }); + }, + 0L); + + TransformationRule deleteEmptyClassRule1 = new TransformationRule("DeleteEmptyClass1", + deleteEmptyClassPrecondition, + (model) -> { + var classesInterpretation = model.getInterpretation(classes); + var classElementInterpretation = model.getInterpretation(classElement); + return ((Tuple activation) -> { + var modelElement = activation.get(0); + var classElement = activation.get(1); + + classesInterpretation.put(Tuple.of(modelElement, classElement), false); + classElementInterpretation.put(Tuple.of(classElement), false); + }); + }, + 78634L); + + var store = ModelStore.builder() + .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features) + .with(ViatraModelQueryAdapter.builder() + .queries(deleteEmptyClassPrecondition)) + .with(DesignSpaceExplorationAdapter.builder()) + .build(); + + var model = store.createEmptyModel(); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + deleteEmptyClassRule0.prepare(model, queryEngine); + deleteEmptyClassRule1.prepare(model, queryEngine); + + var classModelInterpretation = model.getInterpretation(classModel); + var classElementInterpretation = model.getInterpretation(classElement); + var featureInterpretation = model.getInterpretation(feature); + var featuresInterpretation = model.getInterpretation(features); + var classesInterpretation = model.getInterpretation(classes); + + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var newModel = dseAdapter.createObject(); + var newModelId = newModel.get(0); + var newClass1 = dseAdapter.createObject(); + var newClass1Id = newClass1.get(0); + var newClass2 = dseAdapter.createObject(); + var newClass2Id = newClass2.get(0); + var newField = dseAdapter.createObject(); + var newFieldId = newField.get(0); + + classModelInterpretation.put(newModel, true); + classElementInterpretation.put(newClass1, true); + classElementInterpretation.put(newClass2, true); + featureInterpretation.put(newField, true); + classesInterpretation.put(Tuple.of(newModelId, newClass1Id), true); + classesInterpretation.put(Tuple.of(newModelId, newClass2Id), true); + featuresInterpretation.put(Tuple.of(newModelId, newFieldId), true); + + queryEngine.flushChanges(); + + + var activation0 = deleteEmptyClassRule0.getRandomActivation().activation(); + var activation1 = deleteEmptyClassRule1.getRandomActivation().activation(); + + assertResults(Map.of( + Tuple.of(newModelId, newClass1Id), true, + Tuple.of(newModelId, newClass2Id), true + ), deleteEmptyClassRule0.getAllActivationsAsSets()); + + assertResults(Map.of( + Tuple.of(newModelId, newClass1Id), true, + Tuple.of(newModelId, newClass2Id), true + ), deleteEmptyClassRule1.getAllActivationsAsSets()); + + assertEquals(Tuple.of(newModelId, newClass2Id), activation0); + assertEquals(Tuple.of(newModelId, newClass1Id), activation1); + + } + + @Test + void fireTest() { + var deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition", + (builder, model, c) -> builder.clause((f) -> List.of( + classModelView.call(model), + classElementView.call(c), + featuresView.call(model, f), + not(encapsulatesView.call(c, f)) + ))); + + TransformationRule deleteEmptyClassRule = new TransformationRule("DeleteEmptyClass", + deleteEmptyClassPrecondition, + (model) -> { + var classesInterpretation = model.getInterpretation(classes); + var classElementInterpretation = model.getInterpretation(classElement); + return ((Tuple activation) -> { + var modelElement = activation.get(0); + var classElement = activation.get(1); + + classesInterpretation.put(Tuple.of(modelElement, classElement), false); + classElementInterpretation.put(Tuple.of(classElement), false); + }); + }); + + var store = ModelStore.builder() + .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features) + .with(ViatraModelQueryAdapter.builder() + .queries(deleteEmptyClassPrecondition)) + .with(DesignSpaceExplorationAdapter.builder()) + .build(); + + var model = store.createEmptyModel(); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + deleteEmptyClassRule.prepare(model, queryEngine); + + var classModelInterpretation = model.getInterpretation(classModel); + var classElementInterpretation = model.getInterpretation(classElement); + var featureInterpretation = model.getInterpretation(feature); + var featuresInterpretation = model.getInterpretation(features); + var classesInterpretation = model.getInterpretation(classes); + + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var newModel = dseAdapter.createObject(); + var newModelId = newModel.get(0); + var newClass1 = dseAdapter.createObject(); + var newClass1Id = newClass1.get(0); + var newClass2 = dseAdapter.createObject(); + var newClass2Id = newClass2.get(0); + var newField = dseAdapter.createObject(); + var newFieldId = newField.get(0); + + classModelInterpretation.put(newModel, true); + classElementInterpretation.put(newClass1, true); + classElementInterpretation.put(newClass2, true); + featureInterpretation.put(newField, true); + classesInterpretation.put(Tuple.of(newModelId, newClass1Id), true); + classesInterpretation.put(Tuple.of(newModelId, newClass2Id), true); + featuresInterpretation.put(Tuple.of(newModelId, newFieldId), true); + + queryEngine.flushChanges(); + + assertResults(Map.of( + Tuple.of(newModelId, newClass1Id), true, + Tuple.of(newModelId, newClass2Id), true + ), deleteEmptyClassRule.getAllActivationsAsSets()); + + + deleteEmptyClassRule.fireActivation(Tuple.of(0, 1)); + + assertResults(Map.of( + Tuple.of(newModelId, newClass1Id), false, + Tuple.of(newModelId, newClass2Id), true + ), deleteEmptyClassRule.getAllActivationsAsSets()); + } + + @Test + void randomFireTest() { + var deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition", + (builder, model, c) -> builder.clause((f) -> List.of( + classModelView.call(model), + classElementView.call(c), + featuresView.call(model, f), + not(encapsulatesView.call(c, f)) + ))); + + TransformationRule deleteEmptyClassRule = new TransformationRule("DeleteEmptyClass0", + deleteEmptyClassPrecondition, + (model) -> { + var classesInterpretation = model.getInterpretation(classes); + var classElementInterpretation = model.getInterpretation(classElement); + return ((Tuple activation) -> { + var modelElement = activation.get(0); + var classElement = activation.get(1); + + classesInterpretation.put(Tuple.of(modelElement, classElement), false); + classElementInterpretation.put(Tuple.of(classElement), false); + }); + }, + 0L); + + var store = ModelStore.builder() + .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features) + .with(ViatraModelQueryAdapter.builder() + .queries(deleteEmptyClassPrecondition)) + .with(DesignSpaceExplorationAdapter.builder()) + .build(); + + var model = store.createEmptyModel(); + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + deleteEmptyClassRule.prepare(model, queryEngine); + + var classModelInterpretation = model.getInterpretation(classModel); + var classElementInterpretation = model.getInterpretation(classElement); + var featureInterpretation = model.getInterpretation(feature); + var featuresInterpretation = model.getInterpretation(features); + var classesInterpretation = model.getInterpretation(classes); + + var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + var newModel = dseAdapter.createObject(); + var newModelId = newModel.get(0); + var newClass1 = dseAdapter.createObject(); + var newClass1Id = newClass1.get(0); + var newClass2 = dseAdapter.createObject(); + var newClass2Id = newClass2.get(0); + var newField = dseAdapter.createObject(); + var newFieldId = newField.get(0); + + classModelInterpretation.put(newModel, true); + classElementInterpretation.put(newClass1, true); + classElementInterpretation.put(newClass2, true); + featureInterpretation.put(newField, true); + classesInterpretation.put(Tuple.of(newModelId, newClass1Id), true); + classesInterpretation.put(Tuple.of(newModelId, newClass2Id), true); + featuresInterpretation.put(Tuple.of(newModelId, newFieldId), true); + + queryEngine.flushChanges(); + + assertResults(Map.of( + Tuple.of(newModelId, newClass1Id), true, + Tuple.of(newModelId, newClass2Id), true + ), deleteEmptyClassRule.getAllActivationsAsSets()); + + deleteEmptyClassRule.fireRandomActivation(); + + assertResults(Map.of( + Tuple.of(newModelId, newClass1Id), true, + Tuple.of(newModelId, newClass2Id), false + ), deleteEmptyClassRule.getAllActivationsAsSets()); + + deleteEmptyClassRule.fireRandomActivation(); + + assertResults(Map.of( + Tuple.of(newModelId, newClass1Id), false, + Tuple.of(newModelId, newClass2Id), false + ), deleteEmptyClassRule.getAllActivationsAsSets()); + + } +} diff --git a/subprojects/store-dse/src/test/java/tools/refinery/store/dse/tests/QueryAssertions.java b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/tests/QueryAssertions.java new file mode 100644 index 00000000..be514eaf --- /dev/null +++ b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/tests/QueryAssertions.java @@ -0,0 +1,57 @@ +/* + * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.tests; + +import org.junit.jupiter.api.function.Executable; +import tools.refinery.store.query.resultset.ResultSet; +import tools.refinery.store.tuple.Tuple; + +import java.util.*; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.jupiter.api.Assertions.assertAll; + +public final class QueryAssertions { + private QueryAssertions() { + throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); + } + + public static void assertNullableResults(Map> expected, ResultSet resultSet) { + var nullableValuesMap = new LinkedHashMap(expected.size()); + for (var entry : expected.entrySet()) { + nullableValuesMap.put(entry.getKey(), entry.getValue().orElse(null)); + } + assertResults(nullableValuesMap, resultSet); + } + + public static void assertResults(Map expected, ResultSet resultSet) { + var defaultValue = resultSet.getQuery().defaultValue(); + var filteredExpected = new LinkedHashMap(); + var executables = new ArrayList(); + for (var entry : expected.entrySet()) { + var key = entry.getKey(); + var value = entry.getValue(); + if (!Objects.equals(value, defaultValue)) { + filteredExpected.put(key, value); + } + executables.add(() -> assertThat("value for key " + key,resultSet.get(key), is(value))); + } + executables.add(() -> assertThat("results size", resultSet.size(), is(filteredExpected.size()))); + + var actual = new LinkedHashMap(); + var cursor = resultSet.getAll(); + while (cursor.move()) { + var key = cursor.getKey(); + var previous = actual.put(key, cursor.getValue()); + assertThat("duplicate value for key " + key, previous, nullValue()); + } + executables.add(() -> assertThat("results cursor", actual, is(filteredExpected))); + + assertAll(executables); + } +} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/ActionFactory.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/ActionFactory.java deleted file mode 100644 index e2f452c3..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/ActionFactory.java +++ /dev/null @@ -1,9 +0,0 @@ -package tools.refinery.store.query.dse; - -import org.eclipse.collections.api.block.procedure.Procedure; -import tools.refinery.store.model.Model; -import tools.refinery.store.tuple.Tuple; - -public interface ActionFactory { - Procedure prepare(Model model); -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationAdapter.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationAdapter.java deleted file mode 100644 index ca780855..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationAdapter.java +++ /dev/null @@ -1,61 +0,0 @@ -package tools.refinery.store.query.dse; - -import tools.refinery.store.adapter.ModelAdapter; -import tools.refinery.store.map.Version; -import tools.refinery.store.query.dse.internal.Activation; -import tools.refinery.store.query.dse.internal.DesignSpaceExplorationBuilderImpl; -import tools.refinery.store.query.dse.objectives.Fitness; -import tools.refinery.store.query.dse.objectives.ObjectiveComparatorHelper; -import tools.refinery.store.tuple.Tuple; -import tools.refinery.store.tuple.Tuple1; - -import java.util.Collection; -import java.util.List; -import java.util.Random; - -public interface DesignSpaceExplorationAdapter extends ModelAdapter { - @Override - DesignSpaceExplorationStoreAdapter getStoreAdapter(); - - static DesignSpaceExplorationBuilder builder() { - return new DesignSpaceExplorationBuilderImpl(); - } - - Collection explore(); - - public int getModelSize(); - - public Tuple1 createObject(); - - public Tuple deleteObject(Tuple tuple); - - public boolean checkGlobalConstraints(); - - public boolean backtrack(); - - public Fitness calculateFitness(); - - public void newSolution(); - - public int getDepth(); - - public Collection getUntraversedActivations(); - - public boolean fireActivation(Activation activation); - - public void fireRandomActivation(); - - public boolean isCurrentInTrajectory(); - - public List getTrajectory(); - - public boolean isCurrentStateAlreadyTraversed(); - - public ObjectiveComparatorHelper getObjectiveComparatorHelper(); - - public void restoreTrajectory(List trajectory); - - public void setRandom(Random random); - - public void setRandom(long seed); -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationBuilder.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationBuilder.java deleted file mode 100644 index 58eac681..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationBuilder.java +++ /dev/null @@ -1,44 +0,0 @@ -package tools.refinery.store.query.dse; - -import tools.refinery.store.adapter.ModelAdapterBuilder; -import tools.refinery.store.query.dnf.AnyQuery; -import tools.refinery.store.query.dnf.RelationalQuery; -import tools.refinery.store.query.dse.internal.TransformationRule; -import tools.refinery.store.query.dse.objectives.Objective; - -import java.util.Collection; -import java.util.List; - -public interface DesignSpaceExplorationBuilder extends ModelAdapterBuilder { - default DesignSpaceExplorationBuilder transformations(TransformationRule... transformationRules) { - return transformations(List.of(transformationRules)); - } - - default DesignSpaceExplorationBuilder transformations(Collection transformationRules) { - transformationRules.forEach(this::transformation); - return this; - } - - default DesignSpaceExplorationBuilder globalConstraints(RelationalQuery... globalConstraints) { - return globalConstraints(List.of(globalConstraints)); - } - - default DesignSpaceExplorationBuilder globalConstraints(Collection globalConstraints) { - globalConstraints.forEach(this::globalConstraint); - return this; - } - - default DesignSpaceExplorationBuilder objectives(Objective... objectives) { - return objectives(List.of(objectives)); - } - - default DesignSpaceExplorationBuilder objectives(Collection objectives) { - objectives.forEach(this::objective); - return this; - } - - DesignSpaceExplorationBuilder transformation(TransformationRule transformationRule); - DesignSpaceExplorationBuilder globalConstraint(RelationalQuery globalConstraint); - DesignSpaceExplorationBuilder objective(Objective objective); - DesignSpaceExplorationBuilder strategy(Strategy strategy); -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationStoreAdapter.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationStoreAdapter.java deleted file mode 100644 index 21b10f0e..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/DesignSpaceExplorationStoreAdapter.java +++ /dev/null @@ -1,6 +0,0 @@ -package tools.refinery.store.query.dse; - -import tools.refinery.store.adapter.ModelStoreAdapter; - -public interface DesignSpaceExplorationStoreAdapter extends ModelStoreAdapter { -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/Strategy.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/Strategy.java deleted file mode 100644 index 0aeea818..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/Strategy.java +++ /dev/null @@ -1,10 +0,0 @@ -package tools.refinery.store.query.dse; - -import tools.refinery.store.model.Model; - -public interface Strategy { - - public void initStrategy(DesignSpaceExplorationAdapter designSpaceExplorationAdapter); - - public void explore(); -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/Activation.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/Activation.java deleted file mode 100644 index 82a4c978..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/Activation.java +++ /dev/null @@ -1,9 +0,0 @@ -package tools.refinery.store.query.dse.internal; - -import tools.refinery.store.tuple.Tuple; - -public record Activation(TransformationRule transformationRule, Tuple activation) { - public boolean fire() { - return transformationRule.fireActivation(activation); - } -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java deleted file mode 100644 index d2a8e6fa..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationAdapterImpl.java +++ /dev/null @@ -1,283 +0,0 @@ -package tools.refinery.store.query.dse.internal; - -import tools.refinery.store.map.Version; -import tools.refinery.store.model.Interpretation; -import tools.refinery.store.model.Model; -import tools.refinery.store.query.ModelQueryAdapter; -import tools.refinery.store.query.dnf.RelationalQuery; -import tools.refinery.store.query.dse.DesignSpaceExplorationAdapter; -import tools.refinery.store.query.dse.DesignSpaceExplorationStoreAdapter; -import tools.refinery.store.query.dse.Strategy; -import tools.refinery.store.query.dse.objectives.Fitness; -import tools.refinery.store.query.dse.objectives.Objective; -import tools.refinery.store.query.dse.objectives.ObjectiveComparatorHelper; -import tools.refinery.store.query.resultset.ResultSet; -import tools.refinery.store.representation.Symbol; -import tools.refinery.store.tuple.Tuple; -import tools.refinery.store.tuple.Tuple1; -import tools.refinery.visualization.ModelVisualizerAdapter; - -import java.util.*; - -public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExplorationAdapter { - static final Symbol NODE_COUNT_SYMBOL = Symbol.of("MODEL_SIZE", 0, Integer.class, 0); - private final Model model; - private final ModelQueryAdapter queryEngine; - private final DesignSpaceExplorationStoreAdapterImpl storeAdapter; - private final LinkedHashSet transformationRules; - private final LinkedHashSet globalConstraints; - private final List objectives; - private final LinkedHashSet> globalConstraintResultSets = new LinkedHashSet<>(); - private final Interpretation sizeInterpretation; - private final Strategy strategy; - - private ObjectiveComparatorHelper objectiveComparatorHelper; - private List trajectory = new LinkedList<>(); - private Fitness lastFitness; - private final LinkedHashSet solutions = new LinkedHashSet<>(); - private Map> statesAndUntraversedActivations; - private Map> statesAndTraversedActivations; - private Random random = new Random(); - private boolean isNewState = false; - private final boolean isVisualizationEnabled; - private final ModelVisualizerAdapter modelVisualizerAdapter; - - public List getTrajectory() { - return new LinkedList<>(trajectory); - } - - public DesignSpaceExplorationAdapterImpl(Model model, DesignSpaceExplorationStoreAdapterImpl storeAdapter) { - this.model = model; - this.storeAdapter = storeAdapter; - this.sizeInterpretation = model.getInterpretation(NODE_COUNT_SYMBOL); - queryEngine = model.getAdapter(ModelQueryAdapter.class); - - globalConstraints = storeAdapter.getGlobalConstraints(); - for (var constraint : globalConstraints) { - globalConstraintResultSets.add(queryEngine.getResultSet(constraint)); - } - - transformationRules = storeAdapter.getTransformationSpecifications(); - for (var rule : transformationRules) { - rule.prepare(model, queryEngine); - } - - objectives = storeAdapter.getObjectives(); - statesAndUntraversedActivations = new HashMap<>(); - statesAndTraversedActivations = new HashMap<>(); - strategy = storeAdapter.getStrategy(); - modelVisualizerAdapter = model.tryGetAdapter(ModelVisualizerAdapter.class).orElse(null); - isVisualizationEnabled = modelVisualizerAdapter != null; - - } - - @Override - public Model getModel() { - return model; - } - - @Override - public DesignSpaceExplorationStoreAdapter getStoreAdapter() { - return storeAdapter; - } - - @Override - public LinkedHashSet explore() { - var state = model.commit(); - trajectory.add(state); - statesAndUntraversedActivations.put(state, getAllActivations()); - statesAndTraversedActivations.put(state, new LinkedHashSet<>()); - strategy.initStrategy(this); - strategy.explore(); - return solutions; - } - - @Override - public int getModelSize() { - return sizeInterpretation.get(Tuple.of()); - } - - @Override - public Tuple1 createObject() { - var newNodeId = getModelSize(); - sizeInterpretation.put(Tuple.of(), newNodeId + 1); - return Tuple.of(newNodeId); - } - - @Override - public Tuple deleteObject(Tuple tuple) { - if (tuple.getSize() != 1) { - throw new IllegalArgumentException("Tuple size must be 1"); - } -// TODO: implement more efficient deletion -// if (tuple.get(0) == getModelSize() - 1) { -// sizeInterpretation.put(Tuple.of(), getModelSize() - 1); -// } - return tuple; - } - - @Override - public boolean checkGlobalConstraints() { - for (var resultSet : globalConstraintResultSets) { - if (resultSet.size() > 0) { - return false; - } - } - return true; - } - - @Override - public boolean backtrack() { - if (trajectory.size() < 2) { - return false; - } - if (isVisualizationEnabled) { - modelVisualizerAdapter.addTransition(trajectory.get(trajectory.size() - 1), - trajectory.get(trajectory.size() - 2), "backtrack"); - } - model.restore(trajectory.get(trajectory.size() - 2)); - trajectory.remove(trajectory.size() - 1); - return true; - } - - @Override - public void restoreTrajectory(List trajectory) { - model.restore(trajectory.get(trajectory.size() - 1)); -// if (isVisualizationEnabled) { -// modelVisualizerAdapter.addTransition(this.trajectory.get(trajectory.size() - 1), -// trajectory.get(trajectory.size() - 1), "restore"); -// } - this.trajectory = trajectory; - - } - - @Override - public void setRandom(Random random) { - this.random = random; - } - - @Override - public void setRandom(long seed) { - this.random = new Random(seed); - } - - @Override - public Fitness calculateFitness() { - Fitness result = new Fitness(); - boolean satisfiesHardObjectives = true; - for (Objective objective : objectives) { - var fitness = objective.getFitness(this); - result.put(objective.getName(), fitness); - if (objective.isHardObjective() && !objective.satisfiesHardObjective(fitness)) { - satisfiesHardObjectives = false; - } - } - result.setSatisfiesHardObjectives(satisfiesHardObjectives); - - lastFitness = result; - - return result; - } - - @Override - public void newSolution() { - var state = model.getState(); - solutions.add(state); - if (isVisualizationEnabled) { - modelVisualizerAdapter.addSolution(state); - } - } - - @Override - public int getDepth() { - return trajectory.size() - 1; - } - - public LinkedHashSet getUntraversedActivations() { -// return statesAndUntraversedActivations.get(model.getState()); - LinkedHashSet untraversedActivations = new LinkedHashSet<>(); - for (Activation activation : getAllActivations()) { - if (!statesAndTraversedActivations.get(model.getState()).contains(activation)) { - untraversedActivations.add(activation); - } - } - - return untraversedActivations; - } - - @Override - public boolean fireActivation(Activation activation) { - if (activation == null) { - return false; - } - var previousState = model.getState(); - if (!statesAndUntraversedActivations.get(previousState).contains(activation)) { -// TODO: throw exception? - return false; - } - if (!activation.fire()) { - return false; - } - statesAndUntraversedActivations.get(previousState).remove(activation); - statesAndTraversedActivations.get(previousState).add(activation); - var newState = model.commit(); - trajectory.add(newState); - isNewState = !statesAndUntraversedActivations.containsKey(newState); - statesAndUntraversedActivations.put(newState, getAllActivations()); - statesAndTraversedActivations.put(newState, new LinkedHashSet<>()); - if (isVisualizationEnabled) { - if (isNewState) { - modelVisualizerAdapter.addState(newState); - } - modelVisualizerAdapter.addTransition(trajectory.get(trajectory.size() - 2), - trajectory.get(trajectory.size() - 1), activation.transformationRule().getName(), - activation.activation()); - } - return true; - } - - @Override - public void fireRandomActivation() { - var activations = getUntraversedActivations(); - if (activations.isEmpty()) { -// TODO: throw exception - return; - } - int index = random.nextInt(activations.size()); - var iterator = activations.iterator(); - while (index-- > 0) { - iterator.next(); - } - var activationId = iterator.next(); - fireActivation(activationId); - } - - @Override - public boolean isCurrentInTrajectory() { - return trajectory.contains(model.getState()); - } - - public LinkedHashSet getAllActivations() { - LinkedHashSet result = new LinkedHashSet<>(); - for (var rule : transformationRules) { - result.addAll(rule.getAllActivations()); - } - return result; - } - - public boolean isCurrentStateAlreadyTraversed() { -// TODO: check isomorphism? - return !isNewState; - } - - public Fitness getLastFitness() { - return lastFitness; - } - - public ObjectiveComparatorHelper getObjectiveComparatorHelper() { - if (objectiveComparatorHelper == null) { - objectiveComparatorHelper = new ObjectiveComparatorHelper(objectives); - } - return objectiveComparatorHelper; - } -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationBuilderImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationBuilderImpl.java deleted file mode 100644 index 638ec641..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationBuilderImpl.java +++ /dev/null @@ -1,62 +0,0 @@ -package tools.refinery.store.query.dse.internal; - -import tools.refinery.store.adapter.AbstractModelAdapterBuilder; -import tools.refinery.store.model.ModelStore; -import tools.refinery.store.model.ModelStoreBuilder; -import tools.refinery.store.query.dnf.RelationalQuery; -import tools.refinery.store.query.dse.DesignSpaceExplorationBuilder; -import tools.refinery.store.query.dse.Strategy; -import tools.refinery.store.query.dse.objectives.Objective; - -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.List; - -public class DesignSpaceExplorationBuilderImpl - extends AbstractModelAdapterBuilder - implements DesignSpaceExplorationBuilder { - private final LinkedHashSet transformationSpecifications = new LinkedHashSet<>(); - private final LinkedHashSet globalConstraints = new LinkedHashSet<>(); - private final List objectives = new LinkedList<>(); - private Strategy strategy; - - @Override - protected DesignSpaceExplorationStoreAdapterImpl doBuild(ModelStore store) { - return new DesignSpaceExplorationStoreAdapterImpl(store, transformationSpecifications, globalConstraints, - objectives, strategy); - } - - @Override - public DesignSpaceExplorationBuilder transformation(TransformationRule transformationRule) { - checkNotConfigured(); - transformationSpecifications.add(transformationRule); - return this; - } - - @Override - public DesignSpaceExplorationBuilder globalConstraint(RelationalQuery globalConstraint) { - checkNotConfigured(); - globalConstraints.add(globalConstraint); - return this; - } - - @Override - public DesignSpaceExplorationBuilder objective(Objective objective) { - checkNotConfigured(); - objectives.add(objective); - return this; - } - - @Override - public DesignSpaceExplorationBuilder strategy(Strategy strategy) { - checkNotConfigured(); - this.strategy = strategy; - return this; - } - - @Override - protected void doConfigure(ModelStoreBuilder storeBuilder) { - storeBuilder.symbols(DesignSpaceExplorationAdapterImpl.NODE_COUNT_SYMBOL); - super.doConfigure(storeBuilder); - } -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java deleted file mode 100644 index f58715b7..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java +++ /dev/null @@ -1,57 +0,0 @@ -package tools.refinery.store.query.dse.internal; - -import tools.refinery.store.adapter.ModelAdapter; -import tools.refinery.store.model.Model; -import tools.refinery.store.model.ModelStore; -import tools.refinery.store.query.dnf.RelationalQuery; -import tools.refinery.store.query.dse.DesignSpaceExplorationStoreAdapter; -import tools.refinery.store.query.dse.Strategy; -import tools.refinery.store.query.dse.objectives.Objective; - -import java.util.LinkedHashSet; -import java.util.List; - -public class DesignSpaceExplorationStoreAdapterImpl implements DesignSpaceExplorationStoreAdapter { - private final ModelStore store; - private final LinkedHashSet transformationSpecifications; - private final LinkedHashSet globalConstraints; - private final List objectives; - private final Strategy strategy; - - public DesignSpaceExplorationStoreAdapterImpl(ModelStore store, - LinkedHashSet transformationSpecifications, - LinkedHashSet globalConstraints, - List objectives, Strategy strategy) { - this.store = store; - this.transformationSpecifications = transformationSpecifications; - this.globalConstraints = globalConstraints; - this.objectives = objectives; - this.strategy = strategy; - } - - @Override - public ModelStore getStore() { - return store; - } - - @Override - public ModelAdapter createModelAdapter(Model model) { - return new DesignSpaceExplorationAdapterImpl(model, this); - } - - public LinkedHashSet getTransformationSpecifications() { - return transformationSpecifications; - } - - public LinkedHashSet getGlobalConstraints() { - return globalConstraints; - } - - public List getObjectives() { - return objectives; - } - - public Strategy getStrategy() { - return strategy; - } -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/TransformationRule.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/TransformationRule.java deleted file mode 100644 index 950ca930..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/internal/TransformationRule.java +++ /dev/null @@ -1,84 +0,0 @@ -package tools.refinery.store.query.dse.internal; - -import org.eclipse.collections.api.block.procedure.Procedure; -import tools.refinery.store.model.Model; -import tools.refinery.store.query.ModelQueryAdapter; -import tools.refinery.store.query.dnf.RelationalQuery; -import tools.refinery.store.query.dse.ActionFactory; -import tools.refinery.store.query.resultset.OrderedResultSet; -import tools.refinery.store.query.resultset.ResultSet; -import tools.refinery.store.tuple.Tuple; - -import java.util.LinkedHashSet; -import java.util.Random; - -public class TransformationRule { - - private final String name; - private final RelationalQuery precondition; - private final ActionFactory actionFactory; - private Procedure action; - private OrderedResultSet activations; - private Random random; - private ModelQueryAdapter queryEngine; - - public TransformationRule(String name, RelationalQuery precondition, ActionFactory actionFactory) { - this(name, precondition, actionFactory, new Random()); - } - - public TransformationRule(String name, RelationalQuery precondition, ActionFactory actionFactory, long seed) { - this(name, precondition, actionFactory, new Random(seed)); - } - - public TransformationRule(String name, RelationalQuery precondition, ActionFactory actionFactory, Random random) { - this.name = name; - this.precondition = precondition; - this.actionFactory = actionFactory; - this.random = random; - } - public boolean prepare(Model model, ModelQueryAdapter queryEngine) { - action = actionFactory.prepare(model); - this.queryEngine = queryEngine; - activations = new OrderedResultSet<>(queryEngine.getResultSet(precondition)); - return true; - } - - public boolean fireActivation(Tuple activation) { - action.accept(activation); - queryEngine.flushChanges(); - return true; - } - - public boolean fireRandomActivation() { - return getRandomActivation().fire(); - } - - public String getName() { - return name; - } - - public RelationalQuery getPrecondition() { - return precondition; - } - - public ResultSet getAllActivationsAsSets() { - return activations; - } - - public LinkedHashSet getAllActivations() { - var result = new LinkedHashSet(); - var cursor = activations.getAll(); - while (cursor.move()) { - result.add(new Activation(this, cursor.getKey())); - } - return result; - } - - public Activation getRandomActivation() { - return new Activation(this, activations.getKey(random.nextInt(activations.size()))); - } - - public Activation getActivation(int index) { - return new Activation(this, activations.getKey(index)); - } -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/AlwaysSatisfiedDummyHardObjective.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/AlwaysSatisfiedDummyHardObjective.java deleted file mode 100644 index 26744d94..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/AlwaysSatisfiedDummyHardObjective.java +++ /dev/null @@ -1,51 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010-2016, Andras Szabolcs Nagy, Zoltan Ujhelyi and Daniel Varro - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-v20.html. - * - * SPDX-License-Identifier: EPL-2.0 - *******************************************************************************/ -package tools.refinery.store.query.dse.objectives; - -import tools.refinery.store.query.dse.DesignSpaceExplorationAdapter; - -/** - * This hard objective is fulfilled in any circumstances. Use it if all states should be regarded as a valid solution. - * - * @author Andras Szabolcs Nagy - * - */ -public class AlwaysSatisfiedDummyHardObjective extends BaseObjective { - - private static final String DEFAULT_NAME = "AlwaysSatisfiedDummyHardObjective"; - - public AlwaysSatisfiedDummyHardObjective() { - super(DEFAULT_NAME); - } - - public AlwaysSatisfiedDummyHardObjective(String name) { - super(name); - } - - @Override - public Double getFitness(DesignSpaceExplorationAdapter context) { - return 0d; - } - - @Override - public boolean isHardObjective() { - return true; - } - - @Override - public boolean satisfiesHardObjective(Double fitness) { - return true; - } - - @Override - public Objective createNew() { - return this; - } - -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/BaseObjective.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/BaseObjective.java deleted file mode 100644 index db8d5d7e..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/BaseObjective.java +++ /dev/null @@ -1,131 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-v20.html. - * - * SPDX-License-Identifier: EPL-2.0 - *******************************************************************************/ -package tools.refinery.store.query.dse.objectives; - -import tools.refinery.store.query.dse.DesignSpaceExplorationAdapter; - -import java.util.Comparator; -import java.util.Objects; - -/** - * This abstract class implements the basic functionality of an objective ({@link Objective} namely its name, - * comparator, level and fitness hard constraint. - * - * @author Andras Szabolcs Nagy - * - */ -public abstract class BaseObjective implements Objective { - - protected final String name; - protected Comparator comparator = Comparators.HIGHER_IS_BETTER; - - protected double fitnessConstraint; - protected boolean isThereFitnessConstraint = false; - protected Comparator fitnessConstraintComparator; - - public BaseObjective(String name) { - Objects.requireNonNull(name, "Name of the objective cannot be null."); - this.name = name; - } - - @Override - public String getName() { - return name; - } - - @Override - public void setComparator(Comparator comparator) { - this.comparator = comparator; - } - - @Override - public Comparator getComparator() { - return comparator; - } - - public BaseObjective withComparator(Comparator comparator) { - setComparator(comparator); - return this; - } - - /** - * Adds a hard constraint on the fitness value. For example, the fitness value must be better than 10 to accept the - * current state as a solution. - * - * @param fitnessConstraint - * Solutions should be better than this value. - * @param fitnessConstraintComparator - * {@link Comparator} to determine if the current state is better than the given value. - * @return The actual instance to enable builder pattern like usage. - */ - public BaseObjective withHardConstraintOnFitness(double fitnessConstraint, - Comparator fitnessConstraintComparator) { - this.fitnessConstraint = fitnessConstraint; - this.fitnessConstraintComparator = fitnessConstraintComparator; - this.isThereFitnessConstraint = true; - return this; - } - - /** - * Adds a hard constraint on the fitness value. For example, the fitness value must be better than 10 to accept the - * current state as a solution. The provided comparator will be used. - * - * @param fitnessConstraint - * Solutions should be better than this value. - * @return The actual instance to enable builder pattern like usage. - */ - public BaseObjective withHardConstraintOnFitness(double fitnessConstraint) { - return withHardConstraintOnFitness(fitnessConstraint, null); - } - - @Override - public void init(DesignSpaceExplorationAdapter context) { - if (fitnessConstraintComparator == null) { - fitnessConstraintComparator = comparator; - } - } - - @Override - public boolean isHardObjective() { - return isThereFitnessConstraint; - } - - @Override - public boolean satisfiesHardObjective(Double fitness) { - if (isThereFitnessConstraint) { - int compare = fitnessConstraintComparator.compare(fitness, fitnessConstraint); - if (compare < 0) { - return false; - } - } - return true; - } - - @Override - public int hashCode() { - return name.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof BaseObjective baseObjective) { - return name.equals(baseObjective.getName()); - } - return false; - } - - @Override - public String toString() { - return name; - } - -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Comparators.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Comparators.java deleted file mode 100644 index 7fba6736..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Comparators.java +++ /dev/null @@ -1,25 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-v20.html. - * - * SPDX-License-Identifier: EPL-2.0 - *******************************************************************************/ -package tools.refinery.store.query.dse.objectives; - -import java.util.Comparator; - -public class Comparators { - - private Comparators() { /*Utility class constructor*/ } - - public static final Comparator HIGHER_IS_BETTER = (o1, o2) -> o1.compareTo(o2); - - public static final Comparator LOWER_IS_BETTER = (o1, o2) -> o2.compareTo(o1); - - private static final Double ZERO = (double) 0; - - public static final Comparator DIFFERENCE_TO_ZERO_IS_BETTER = (o1, o2) -> ZERO.compareTo(Math.abs(o1)-Math.abs(o2)); - -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Fitness.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Fitness.java deleted file mode 100644 index ea80ed55..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Fitness.java +++ /dev/null @@ -1,21 +0,0 @@ -package tools.refinery.store.query.dse.objectives; - -import java.util.HashMap; - -public class Fitness extends HashMap { - - private boolean satisfiesHardObjectives; - - public boolean isSatisfiesHardObjectives() { - return satisfiesHardObjectives; - } - - public void setSatisfiesHardObjectives(boolean satisfiesHardObjectives) { - this.satisfiesHardObjectives = satisfiesHardObjectives; - } - - @Override - public String toString() { - return super.toString() + " hardObjectives=" + satisfiesHardObjectives; - } -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Objective.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Objective.java deleted file mode 100644 index df86f36a..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/Objective.java +++ /dev/null @@ -1,100 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-v20.html. - * - * SPDX-License-Identifier: EPL-2.0 - *******************************************************************************/ -package tools.refinery.store.query.dse.objectives; - -import tools.refinery.store.query.dse.DesignSpaceExplorationAdapter; - -import java.util.Comparator; - -/** - * - * Implementation of this interface represents a single objective of the DSE problem, which can assess a solution - * (trajectory) in a single number. It has a name and a comparator which orders two solution based on the calculated - * value. - *

- * Objectives can be either hard or soft objectives. Hard objectives can be satisfied or unsatisfied. If all of the hard - * objectives are satisfied on a single solution, then it is considered to be a valid (or goal) solution. - *

- * Certain objectives can have inner state for calculating the fitness value. In this case a new instance is necessary - * for every new thread, and the {@code createNew} method should not return the same instance more than once. - * - * @author Andras Szabolcs Nagy - * - */ -public interface Objective { - - /** - * Returns the name of the objective. - * - * @return The name of the objective. - */ - String getName(); - - /** - * Sets the {@link Comparator} which is used to compare fitness (doubles). It determines whether the objective is to - * minimize or maximize (or minimize or maximize a delta from a given number). - * - * @param comparator The comparator. - */ - void setComparator(Comparator comparator); - - /** - * Returns a {@link Comparator} which is used to compare fitness (doubles). It determines whether the objective is - * to minimize or maximize (or minimize or maximize a delta from a given number). - * - * @return The comparator. - */ - Comparator getComparator(); - - /** - * Calculates the value of the objective on a given solution (trajectory). - * - * @param context - * The {@link DesignSpaceExplorationAdapter} - * @return The objective value in double. - */ - Double getFitness(DesignSpaceExplorationAdapter context); - - /** - * Initializes the objective. It is called exactly once for every thread starts. - * - * @param context - * The {@link DesignSpaceExplorationAdapter}. - */ - void init(DesignSpaceExplorationAdapter context); - - /** - * Returns an instance of the {@link Objective}. If it returns the same instance, all the methods has to be thread - * save as they are called concurrently. - * - * @return An instance of the objective. - */ - Objective createNew(); - - /** - * Returns true if the objective is a hard objective. In such a case the method - * {@link Objective#satisfiesHardObjective(Double)} is called. - * - * @return True if the objective is a hard objective. - * @see Objective#satisfiesHardObjective(Double) - * @see Objective - */ - boolean isHardObjective(); - - /** - * Determines if the given fitness value satisfies the hard objective. - * - * @param fitness - * The fitness value of a solution. - * @return True if it satisfies the hard objective or it is a soft constraint. - * @see Objective - */ - boolean satisfiesHardObjective(Double fitness); - -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/ObjectiveComparatorHelper.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/ObjectiveComparatorHelper.java deleted file mode 100644 index 0c925096..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/objectives/ObjectiveComparatorHelper.java +++ /dev/null @@ -1,58 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-v20.html. - * - * SPDX-License-Identifier: EPL-2.0 - *******************************************************************************/ -package tools.refinery.store.query.dse.objectives; - -import java.util.List; - -/** - * This class is responsible to compare and sort fitness values. - * - * @author András Szabolcs Nagy - */ -public class ObjectiveComparatorHelper { - - private final List objectives; - - public ObjectiveComparatorHelper(List objectives) { - this.objectives = objectives; - } - - /** - * Compares two fitnesses based on dominance. Returns -1 if the second parameter {@code o2} is a better - * solution ({@code o2} dominates {@code o1}), 1 if the first parameter {@code o1} is better ({@code o1} dominates - * {@code o2}) and returns 0 if they are non-dominating each other. - */ - public int compare(Fitness o1, Fitness o2) { - - boolean o1HasBetterFitness = false; - boolean o2HasBetterFitness = false; - - for (Objective objective : objectives) { - String objectiveName = objective.getName(); - int sgn = objective.getComparator().compare(o1.get(objectiveName), o2.get(objectiveName)); - - if (sgn < 0) { - o2HasBetterFitness = true; - } - if (sgn > 0) { - o1HasBetterFitness = true; - } - if (o1HasBetterFitness && o2HasBetterFitness) { - break; - } - } - if (o2HasBetterFitness) { - } else if (o1HasBetterFitness) { - return 1; - } - - return 0; - - } -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/strategy/BestFirstStrategy.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/strategy/BestFirstStrategy.java deleted file mode 100644 index 6264c502..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/strategy/BestFirstStrategy.java +++ /dev/null @@ -1,190 +0,0 @@ -package tools.refinery.store.query.dse.strategy; - -import tools.refinery.store.map.Version; -import tools.refinery.store.query.dse.DesignSpaceExplorationAdapter; -import tools.refinery.store.query.dse.Strategy; -import tools.refinery.store.query.dse.internal.Activation; -import tools.refinery.store.query.dse.objectives.Fitness; -import tools.refinery.store.query.dse.objectives.ObjectiveComparatorHelper; - -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.PriorityQueue; - -public class BestFirstStrategy implements Strategy { - - private DesignSpaceExplorationAdapter dseAdapter; - - private int maxDepth; - private boolean backTrackIfSolution = true; - private boolean onlyBetterFirst = false; - - private PriorityQueue trajectoriesToExplore; - - private static class TrajectoryWithFitness { - - public List trajectory; - public Fitness fitness; - - public TrajectoryWithFitness(List trajectory, Fitness fitness) { - super(); - this.trajectory = trajectory; - this.fitness = fitness; - } - - @Override - public String toString() { - return trajectory.toString() + fitness.toString(); - } - - } - - public BestFirstStrategy() { - this(-1); - } - - public BestFirstStrategy(int maxDepth) { - if (maxDepth < 0) { - this.maxDepth = Integer.MAX_VALUE; - } else { - this.maxDepth = maxDepth; - } - } - - public BestFirstStrategy continueIfHardObjectivesFulfilled() { - backTrackIfSolution = false; - return this; - } - - public BestFirstStrategy goOnOnlyIfFitnessIsBetter() { - onlyBetterFirst = true; - return this; - } - - @Override - public void initStrategy(DesignSpaceExplorationAdapter designSpaceExplorationAdapter) { - this.dseAdapter = designSpaceExplorationAdapter; - final ObjectiveComparatorHelper objectiveComparatorHelper = dseAdapter.getObjectiveComparatorHelper(); - - trajectoriesToExplore = new PriorityQueue(11, - (o1, o2) -> objectiveComparatorHelper.compare(o2.fitness, o1.fitness)); - } - - @Override - public void explore() { - final ObjectiveComparatorHelper objectiveComparatorHelper = dseAdapter.getObjectiveComparatorHelper(); - - boolean globalConstraintsAreSatisfied = dseAdapter.checkGlobalConstraints(); - if (!globalConstraintsAreSatisfied) { - // "Global constraint is not satisfied in the first state. Terminate."); - return; - } - - final Fitness firstFitness = dseAdapter.calculateFitness(); - if (firstFitness.isSatisfiesHardObjectives()) { - dseAdapter.newSolution(); - // "First state is a solution. Terminate."); - if (backTrackIfSolution) { - return; - } - } - - if (maxDepth == 0) { - return; - } - - final List firstTrajectory = dseAdapter.getTrajectory(); - TrajectoryWithFitness currentTrajectoryWithFitness = new TrajectoryWithFitness(firstTrajectory, firstFitness); - trajectoriesToExplore.add(currentTrajectoryWithFitness); - - mainLoop: while (true) { - - if (currentTrajectoryWithFitness == null) { - if (trajectoriesToExplore.isEmpty()) { - // "State space is fully traversed."); - return; - } else { - currentTrajectoryWithFitness = trajectoriesToExplore.element(); -// if (logger.isDebugEnabled()) { -// "New trajectory is chosen: " + currentTrajectoryWithFitness); -// } - dseAdapter.restoreTrajectory(currentTrajectoryWithFitness.trajectory); - } - } - - Collection activations = dseAdapter.getUntraversedActivations(); - Iterator iterator = activations.iterator(); - - - - while (iterator.hasNext()) { - final Activation nextActivation = iterator.next(); - if (!iterator.hasNext()) { - // "Last untraversed activation of the state."); - trajectoriesToExplore.remove(currentTrajectoryWithFitness); - } - -// if (logger.isDebugEnabled()) { -// "Executing new activation: " + nextActivation); -// } - dseAdapter.fireActivation(nextActivation); - if (dseAdapter.isCurrentStateAlreadyTraversed()) { - // "The new state is already visited."); - dseAdapter.backtrack(); - } else if (!dseAdapter.checkGlobalConstraints()) { - // "Global constraint is not satisfied."); - dseAdapter.backtrack(); - } else { - final Fitness nextFitness = dseAdapter.calculateFitness(); - if (nextFitness.isSatisfiesHardObjectives()) { - dseAdapter.newSolution(); - // "Found a solution."); - if (backTrackIfSolution) { - dseAdapter.backtrack(); - continue; - } - } - if (dseAdapter.getDepth() >= maxDepth) { - // "Reached max depth."); - dseAdapter.backtrack(); - continue; - } - - TrajectoryWithFitness nextTrajectoryWithFitness = new TrajectoryWithFitness( - dseAdapter.getTrajectory(), nextFitness); - trajectoriesToExplore.add(nextTrajectoryWithFitness); - - int compare = objectiveComparatorHelper.compare(currentTrajectoryWithFitness.fitness, - nextTrajectoryWithFitness.fitness); - if (compare < 0) { - // "Better fitness, moving on: " + nextFitness); - currentTrajectoryWithFitness = nextTrajectoryWithFitness; - continue mainLoop; - } else if (compare == 0) { - if (onlyBetterFirst) { - // "Equally good fitness, backtrack: " + nextFitness); - dseAdapter.backtrack(); - continue; - } else { - // "Equally good fitness, moving on: " + nextFitness); - currentTrajectoryWithFitness = nextTrajectoryWithFitness; - continue mainLoop; - } - } else { - // "Worse fitness."); - currentTrajectoryWithFitness = null; - continue mainLoop; - } - } - } - - // "State is fully traversed."); - trajectoriesToExplore.remove(currentTrajectoryWithFitness); - currentTrajectoryWithFitness = null; - - } - // "Interrupted."); - - } -} diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/strategy/DepthFirstStrategy.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/strategy/DepthFirstStrategy.java deleted file mode 100644 index 8192048a..00000000 --- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/dse/strategy/DepthFirstStrategy.java +++ /dev/null @@ -1,108 +0,0 @@ -package tools.refinery.store.query.dse.strategy; - -import tools.refinery.store.query.dse.DesignSpaceExplorationAdapter; -import tools.refinery.store.query.dse.Strategy; -import tools.refinery.store.query.dse.internal.Activation; -import tools.refinery.store.query.dse.objectives.Fitness; - -import java.util.Collection; - -public class DepthFirstStrategy implements Strategy { - - private DesignSpaceExplorationAdapter dseAdapter; - - private int maxDepth; - private boolean backTrackIfSolution = true; - - public DepthFirstStrategy() { - this(-1); - } - - public DepthFirstStrategy(int maxDepth) { - if (maxDepth < 0) { - this.maxDepth = Integer.MAX_VALUE; - } else { - this.maxDepth = maxDepth; - } - } - - public DepthFirstStrategy continueIfHardObjectivesFulfilled() { - backTrackIfSolution = false; - return this; - } - - @Override - public void initStrategy(DesignSpaceExplorationAdapter designSpaceExplorationAdapter) { - this.dseAdapter = designSpaceExplorationAdapter; - } - - @Override - public void explore() { - mainloop: while (true) { - var globalConstraintsAreSatisfied = dseAdapter.checkGlobalConstraints(); - if (!globalConstraintsAreSatisfied) { - var isSuccessfulUndo = dseAdapter.backtrack(); - if (!isSuccessfulUndo) { -// "Global constraint is not satisfied and cannot backtrack." - break; - } - else { -// "Global constraint is not satisfied, backtrack." - continue; - } - } - - Fitness fitness = dseAdapter.calculateFitness(); - if (fitness.isSatisfiesHardObjectives()) { - dseAdapter.newSolution(); - if (backTrackIfSolution) { - var isSuccessfulUndo = dseAdapter.backtrack(); - if (!isSuccessfulUndo) { -// "Found a solution but cannot backtrack." - break; - } else { -// "Found a solution, backtrack." - continue; - } - } - } - - var depth = dseAdapter.getDepth(); - if (dseAdapter.getDepth() >= maxDepth) { - var isSuccessfulUndo = dseAdapter.backtrack(); - if (!isSuccessfulUndo) { -// "Reached max depth but cannot backtrack." - break; - } - } - - Collection activations; - do { - activations = dseAdapter.getUntraversedActivations(); - if (activations.isEmpty()) { - if (!dseAdapter.backtrack()) { - // "No more transitions from current state and cannot backtrack." - break mainloop; - } - else { - // "No more transitions from current state, backtrack." - continue; - } - } - } while (activations.isEmpty()); - - dseAdapter.fireRandomActivation(); -// if (dseAdapter.isCurrentInTrajectory()) { -// if (!dseAdapter.backtrack()) { -//// TODO: throw exception -//// "The new state is present in the trajectory but cannot backtrack. Should never happen!" -// break; -// } -// else { -//// "The new state is already visited in the trajectory, backtrack." -// continue; -// } -// } - } - } -} diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/CRAExamplesTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/CRAExamplesTest.java deleted file mode 100644 index 2effb353..00000000 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/CRAExamplesTest.java +++ /dev/null @@ -1,274 +0,0 @@ -package tools.refinery.store.query.dse; - -import org.junit.jupiter.api.Test; -import tools.refinery.store.model.ModelStore; -import tools.refinery.store.query.ModelQueryAdapter; -import tools.refinery.store.query.dnf.Query; -import tools.refinery.store.query.dnf.RelationalQuery; -import tools.refinery.store.query.dse.internal.TransformationRule; -import tools.refinery.store.query.dse.strategy.BestFirstStrategy; -import tools.refinery.store.query.dse.strategy.DepthFirstStrategy; -import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; -import tools.refinery.store.query.view.AnySymbolView; -import tools.refinery.store.query.view.KeyOnlyView; -import tools.refinery.store.representation.Symbol; -import tools.refinery.store.tuple.Tuple; -import tools.refinery.visualization.ModelVisualizerAdapter; -import tools.refinery.visualization.internal.FileFormat; - -import java.util.List; - -import static tools.refinery.store.query.literal.Literals.not; - -public class CRAExamplesTest { - private static final Symbol name = Symbol.of("Name", 1, String.class); - -// private static final Symbol classModel = Symbol.of("ClassModel", 1); - private static final Symbol classElement = Symbol.of("ClassElement", 1); -// private static final Symbol feature = Symbol.of("Feature", 1); - private static final Symbol attribute = Symbol.of("Attribute", 1); - private static final Symbol method = Symbol.of("Method", 1); - -// private static final Symbol isEncapsulatedBy = Symbol.of("IsEncapsulatedBy", 2); - private static final Symbol encapsulates = Symbol.of("Encapsulates", 2); - private static final Symbol dataDependency = Symbol.of("DataDependency", 2); - private static final Symbol functionalDependency = Symbol.of("FunctionalDependency", 2); - - private static final Symbol features = Symbol.of("Features", 2); - private static final Symbol classes = Symbol.of("Classes", 2); - -// private static final AnySymbolView classModelView = new KeyOnlyView<>(classModel); - private static final AnySymbolView classElementView = new KeyOnlyView<>(classElement); -// private static final AnySymbolView featureView = new KeyOnlyView<>(feature); - private static final AnySymbolView attributeView = new KeyOnlyView<>(attribute); - private static final AnySymbolView methodView = new KeyOnlyView<>(method); -// private static final AnySymbolView isEncapsulatedByView = new KeyOnlyView<>(isEncapsulatedBy); - private static final AnySymbolView encapsulatesView = new KeyOnlyView<>(encapsulates); - private static final AnySymbolView dataDependencyView = new KeyOnlyView<>(dataDependency); - private static final AnySymbolView functionalDependencyView = new KeyOnlyView<>(functionalDependency); - private static final AnySymbolView featuresView = new KeyOnlyView<>(features); - private static final AnySymbolView classesView = new KeyOnlyView<>(classes); - - /*Example Transformation rules*/ - private static final RelationalQuery feature = Query.of("Feature", - (builder, f) -> builder.clause( - attributeView.call(f)) - .clause( - methodView.call(f)) - ); - - private static final RelationalQuery assignFeaturePreconditionHelper = Query.of("AssignFeaturePreconditionHelper", - (builder, c, f) -> builder.clause( - classElementView.call(c), -// classesView.call(model, c), - encapsulatesView.call(c, f) - )); - - private static final RelationalQuery assignFeaturePrecondition = Query.of("AssignFeaturePrecondition", - (builder, f, c1) -> builder.clause((c2) -> List.of( -// classModelView.call(model), - feature.call(f), - classElementView.call(c1), -// featuresView.call(model, f), - not(assignFeaturePreconditionHelper.call(c2, f)), - not(encapsulatesView.call(c1, f)) - ))); - - private static final RelationalQuery deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition", - (builder, c) -> builder.clause((f) -> List.of( -// classModelView.call(model), - classElementView.call(c), -// featuresView.call(model, f), - not(encapsulatesView.call(c, f)) - ))); - - private static final RelationalQuery createClassPreconditionHelper = Query.of("CreateClassPreconditionHelper", - (builder, f, c) -> builder.clause( - classElementView.call(c), -// classesView.call(model, c), - encapsulatesView.call(c, f) - )); - - private static final RelationalQuery createClassPrecondition = Query.of("CreateClassPrecondition", - (builder, f) -> builder.clause((c) -> List.of( -// classModelView.call(model), - feature.call(f), - not(createClassPreconditionHelper.call(f, c)) - ))); - - private static final RelationalQuery moveFeaturePrecondition = Query.of("MoveFeature", - (builder, c1, c2, f) -> builder.clause( -// classModelView.call(model), - classElementView.call(c1), - classElementView.call(c2), - c1.notEquivalent(c2), - feature.call(f), -// classesView.call(model, c1), -// classesView.call(model, c2), -// featuresView.call(model, f), - encapsulatesView.call(c1, f) - )); - - private static final TransformationRule assignFeatureRule = new TransformationRule("AssignFeature", - assignFeaturePrecondition, - (model) -> { -// var isEncapsulatedByInterpretation = model.getInterpretation(isEncapsulatedBy); - var encapsulatesInterpretation = model.getInterpretation(encapsulates); - return ((Tuple activation) -> { - var feature = activation.get(0); - var classElement = activation.get(1); - -// isEncapsulatedByInterpretation.put(Tuple.of(feature, classElement), true); - encapsulatesInterpretation.put(Tuple.of(classElement, feature), true); - }); - }); - - private static final TransformationRule deleteEmptyClassRule = new TransformationRule("DeleteEmptyClass", - deleteEmptyClassPrecondition, - (model) -> { -// var classesInterpretation = model.getInterpretation(classes); - var classElementInterpretation = model.getInterpretation(classElement); - return ((Tuple activation) -> { - // TODO: can we move dseAdapter outside? - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); -// var modelElement = activation.get(0); - var classElement = activation.get(0); - -// classesInterpretation.put(Tuple.of(modelElement, classElement), false); - classElementInterpretation.put(Tuple.of(classElement), false); - dseAdapter.deleteObject(Tuple.of(classElement)); - }); - }); - - private static final TransformationRule createClassRule = new TransformationRule("CreateClass", - createClassPrecondition, - (model) -> { - var classElementInterpretation = model.getInterpretation(classElement); -// var classesInterpretation = model.getInterpretation(classes); - var encapsulatesInterpretation = model.getInterpretation(encapsulates); - return ((Tuple activation) -> { - // TODO: can we move dseAdapter outside? - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); -// var modelElement = activation.get(0); - var feature = activation.get(0); - - var newClassElement = dseAdapter.createObject(); - var newClassElementId = newClassElement.get(0); - classElementInterpretation.put(newClassElement, true); -// classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); - encapsulatesInterpretation.put(Tuple.of(newClassElementId, feature), true); - }); - }); - - private static final TransformationRule moveFeatureRule = new TransformationRule("MoveFeature", - moveFeaturePrecondition, - (model) -> { - var encapsulatesInterpretation = model.getInterpretation(encapsulates); - return ((Tuple activation) -> { - var classElement1 = activation.get(0); - var classElement2 = activation.get(1); - var feature = activation.get(2); - - encapsulatesInterpretation.put(Tuple.of(classElement1, feature), false); - encapsulatesInterpretation.put(Tuple.of(classElement2, feature), true); - }); - }); - - @Test - void craTest() { - var store = ModelStore.builder() - .symbols(classElement, encapsulates, classes, features, attribute, method, dataDependency, - functionalDependency, name) - .with(ViatraModelQueryAdapter.builder() - .queries(feature, assignFeaturePreconditionHelper, assignFeaturePrecondition, - deleteEmptyClassPrecondition, createClassPreconditionHelper, createClassPrecondition, - moveFeaturePrecondition)) - .with(ModelVisualizerAdapter.builder()) - .with(DesignSpaceExplorationAdapter.builder() - .transformations(assignFeatureRule, deleteEmptyClassRule, createClassRule, moveFeatureRule) -// .strategy(new DepthFirstStrategy(3).continueIfHardObjectivesFulfilled() - .strategy(new BestFirstStrategy(6).continueIfHardObjectivesFulfilled() -// .goOnOnlyIfFitnessIsBetter() - )) - .build(); - - var model = store.createEmptyModel(); - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); -// dseAdapter.setRandom(1); - var queryEngine = model.getAdapter(ModelQueryAdapter.class); - -// var modelInterpretation = model.getInterpretation(classModel); - var nameInterpretation = model.getInterpretation(name); - var methodInterpretation = model.getInterpretation(method); - var attributeInterpretation = model.getInterpretation(attribute); - var dataDependencyInterpretation = model.getInterpretation(dataDependency); - var functionalDependencyInterpretation = model.getInterpretation(functionalDependency); - -// var modelElement = dseAdapter.createObject(); - var method1 = dseAdapter.createObject(); - var method1Id = method1.get(0); - var method2 = dseAdapter.createObject(); - var method2Id = method2.get(0); - var method3 = dseAdapter.createObject(); - var method3Id = method3.get(0); - var method4 = dseAdapter.createObject(); - var method4Id = method4.get(0); - var attribute1 = dseAdapter.createObject(); - var attribute1Id = attribute1.get(0); - var attribute2 = dseAdapter.createObject(); - var attribute2Id = attribute2.get(0); - var attribute3 = dseAdapter.createObject(); - var attribute3Id = attribute3.get(0); - var attribute4 = dseAdapter.createObject(); - var attribute4Id = attribute4.get(0); - var attribute5 = dseAdapter.createObject(); - var attribute5Id = attribute5.get(0); - - nameInterpretation.put(method1, "M1"); - nameInterpretation.put(method2, "M2"); - nameInterpretation.put(method3, "M3"); - nameInterpretation.put(method4, "M4"); - nameInterpretation.put(attribute1, "A1"); - nameInterpretation.put(attribute2, "A2"); - nameInterpretation.put(attribute3, "A3"); - nameInterpretation.put(attribute4, "A4"); - nameInterpretation.put(attribute5, "A5"); - - - -// modelInterpretation.put(modelElement, true); - methodInterpretation.put(method1, true); - methodInterpretation.put(method2, true); - methodInterpretation.put(method3, true); - methodInterpretation.put(method4, true); - attributeInterpretation.put(attribute1, true); - attributeInterpretation.put(attribute2, true); - attributeInterpretation.put(attribute3, true); - attributeInterpretation.put(attribute4, true); - attributeInterpretation.put(attribute5, true); - - dataDependencyInterpretation.put(Tuple.of(method1Id, attribute1Id), true); - dataDependencyInterpretation.put(Tuple.of(method1Id, attribute3Id), true); - dataDependencyInterpretation.put(Tuple.of(method2Id, attribute2Id), true); - dataDependencyInterpretation.put(Tuple.of(method3Id, attribute3Id), true); - dataDependencyInterpretation.put(Tuple.of(method3Id, attribute4Id), true); - dataDependencyInterpretation.put(Tuple.of(method4Id, attribute3Id), true); - dataDependencyInterpretation.put(Tuple.of(method4Id, attribute5Id), true); - - functionalDependencyInterpretation.put(Tuple.of(method1Id, attribute3Id), true); - functionalDependencyInterpretation.put(Tuple.of(method1Id, attribute4Id), true); - functionalDependencyInterpretation.put(Tuple.of(method2Id, attribute1Id), true); - functionalDependencyInterpretation.put(Tuple.of(method3Id, attribute1Id), true); - functionalDependencyInterpretation.put(Tuple.of(method3Id, attribute4Id), true); - functionalDependencyInterpretation.put(Tuple.of(method4Id, attribute2Id), true); - - queryEngine.flushChanges(); - - var states = dseAdapter.explore(); - System.out.println("states size: " + states.size()); - System.out.println("states: " + states); - var visualizer = model.getAdapter(ModelVisualizerAdapter.class); - visualizer.renderDesignSpace("test_output", FileFormat.SVG); - } - -} diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DebugTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DebugTest.java deleted file mode 100644 index 821be7e6..00000000 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DebugTest.java +++ /dev/null @@ -1,117 +0,0 @@ -package tools.refinery.store.query.dse; - -import org.junit.jupiter.api.Test; -import tools.refinery.store.model.ModelStore; -import tools.refinery.store.query.ModelQueryAdapter; -import tools.refinery.store.query.dnf.Query; -import tools.refinery.store.query.dse.internal.TransformationRule; -import tools.refinery.store.query.dse.strategy.BestFirstStrategy; -import tools.refinery.store.query.dse.strategy.DepthFirstStrategy; -import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; -import tools.refinery.store.query.view.AnySymbolView; -import tools.refinery.store.query.view.KeyOnlyView; -import tools.refinery.store.representation.Symbol; -import tools.refinery.store.tuple.Tuple; -import tools.refinery.visualization.ModelVisualizerAdapter; -import tools.refinery.visualization.internal.FileFormat; - -public class DebugTest { - private static final Symbol classModel = Symbol.of("ClassModel", 1); - private static final Symbol classElement = Symbol.of("ClassElement", 1); - private static final Symbol feature = Symbol.of("Feature", 1); - - private static final Symbol isEncapsulatedBy = Symbol.of("IsEncapsulatedBy", 2); - private static final Symbol encapsulates = Symbol.of("Encapsulates", 2); - - private static final Symbol features = Symbol.of("Features", 2); - private static final Symbol classes = Symbol.of("Classes", 2); - - private static final AnySymbolView classModelView = new KeyOnlyView<>(classModel); - private static final AnySymbolView classElementView = new KeyOnlyView<>(classElement); - private static final AnySymbolView featureView = new KeyOnlyView<>(feature); - private static final AnySymbolView isEncapsulatedByView = new KeyOnlyView<>(isEncapsulatedBy); - private static final AnySymbolView encapsulatesView = new KeyOnlyView<>(encapsulates); - private static final AnySymbolView featuresView = new KeyOnlyView<>(features); - private static final AnySymbolView classesView = new KeyOnlyView<>(classes); - - - @Test - void BFSTest() { - var createClassPrecondition = Query.of("CreateClassPrecondition", - (builder, model) -> builder.clause( - classModelView.call(model) - )); - - var createClassRule = new TransformationRule("CreateClass", - createClassPrecondition, - (model) -> { - var classesInterpretation = model.getInterpretation(classes); - var classElementInterpretation = model.getInterpretation(classElement); - return ((Tuple activation) -> { - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); - var modelElement = activation.get(0); - - var newClassElement = dseAdapter.createObject(); - var newClassElementId = newClassElement.get(0); - - classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); - classElementInterpretation.put(Tuple.of(newClassElementId), true); - }); - }); - - var createFeaturePrecondition = Query.of("CreateFeaturePrecondition", - (builder, model) -> builder.clause( - classModelView.call(model) - )); - - var createFeatureRule = new TransformationRule("CreateFeature", - createFeaturePrecondition, - (model) -> { - var featuresInterpretation = model.getInterpretation(features); - var featureInterpretation = model.getInterpretation(feature); - return ((Tuple activation) -> { - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); - var modelElement = activation.get(0); - - var newClassElement = dseAdapter.createObject(); - var newClassElementId = newClassElement.get(0); - - featuresInterpretation.put(Tuple.of(modelElement, newClassElementId), true); - featureInterpretation.put(Tuple.of(newClassElementId), true); - }); - }); - - var store = ModelStore.builder() - .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features) - .with(ViatraModelQueryAdapter.builder() - .queries(createClassPrecondition, createFeaturePrecondition)) - .with(ModelVisualizerAdapter.builder()) - .with(DesignSpaceExplorationAdapter.builder() - .transformations(createClassRule, createFeatureRule) - .strategy(new DepthFirstStrategy(4).continueIfHardObjectivesFulfilled() -// .strategy(new BestFirstStrategy(4).continueIfHardObjectivesFulfilled() -// .goOnOnlyIfFitnessIsBetter() - )) - .build(); - - var model = store.createEmptyModel(); - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); -// dseAdapter.setRandom(1); - var queryEngine = model.getAdapter(ModelQueryAdapter.class); - - var modelElementInterpretation = model.getInterpretation(classModel); - var classElementInterpretation = model.getInterpretation(classElement); - var modelElement = dseAdapter.createObject(); - modelElementInterpretation.put(modelElement, true); - classElementInterpretation.put(modelElement, true); - queryEngine.flushChanges(); - - - var states = dseAdapter.explore(); - var visualizer = model.getAdapter(ModelVisualizerAdapter.class); - visualizer.renderDesignSpace("test_output", FileFormat.SVG); - System.out.println("states size: " + states.size()); - System.out.println("states: " + states); - - } -} diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DesignSpaceExplorationTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DesignSpaceExplorationTest.java deleted file mode 100644 index 59775b43..00000000 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/DesignSpaceExplorationTest.java +++ /dev/null @@ -1,487 +0,0 @@ -package tools.refinery.store.query.dse; - -import org.junit.jupiter.api.Test; -import tools.refinery.store.model.ModelStore; -import tools.refinery.store.query.ModelQueryAdapter; -import tools.refinery.store.query.dnf.Query; -import tools.refinery.store.query.dse.internal.TransformationRule; -import tools.refinery.store.query.dse.strategy.BestFirstStrategy; -import tools.refinery.store.query.dse.strategy.DepthFirstStrategy; -import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; -import tools.refinery.store.query.view.AnySymbolView; -import tools.refinery.store.query.view.KeyOnlyView; -import tools.refinery.store.representation.Symbol; -import tools.refinery.store.tuple.Tuple; -import tools.refinery.visualization.ModelVisualizerAdapter; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class DesignSpaceExplorationTest { -// private static final Symbol namedElement = Symbol.of("NamedElement", 1); -// private static final Symbol attribute = Symbol.of("Attribute", 1); -// private static final Symbol method = Symbol.of("Method", 1); -// private static final Symbol dataDependency = Symbol.of("DataDependency", 2); -// private static final Symbol functionalDependency = Symbol.of("FunctionalDependency", 2); - - private static final Symbol classModel = Symbol.of("ClassModel", 1); - private static final Symbol classElement = Symbol.of("ClassElement", 1); - private static final Symbol feature = Symbol.of("Feature", 1); - - private static final Symbol isEncapsulatedBy = Symbol.of("IsEncapsulatedBy", 2); - private static final Symbol encapsulates = Symbol.of("Encapsulates", 2); - - private static final Symbol features = Symbol.of("Features", 2); - private static final Symbol classes = Symbol.of("Classes", 2); - - private static final AnySymbolView classModelView = new KeyOnlyView<>(classModel); - private static final AnySymbolView classElementView = new KeyOnlyView<>(classElement); - private static final AnySymbolView featureView = new KeyOnlyView<>(feature); - private static final AnySymbolView isEncapsulatedByView = new KeyOnlyView<>(isEncapsulatedBy); - private static final AnySymbolView encapsulatesView = new KeyOnlyView<>(encapsulates); - private static final AnySymbolView featuresView = new KeyOnlyView<>(features); - private static final AnySymbolView classesView = new KeyOnlyView<>(classes); - - @Test - void createObjectTest() { - var store = ModelStore.builder() - .with(ViatraModelQueryAdapter.builder()) - .with(DesignSpaceExplorationAdapter.builder()) - .build(); - - var model = store.createEmptyModel(); - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); - - assertEquals(0, dseAdapter.getModelSize()); - - var newModel = dseAdapter.createObject(); - var newModelId = newModel.get(0); - var newClass1 = dseAdapter.createObject(); - var newClass1Id = newClass1.get(0); - var newClass2 = dseAdapter.createObject(); - var newClass2Id = newClass2.get(0); - var newField = dseAdapter.createObject(); - var newFieldId = newField.get(0); - - assertEquals(0, newModelId); - assertEquals(1, newClass1Id); - assertEquals(2, newClass2Id); - assertEquals(3, newFieldId); - assertEquals(4, dseAdapter.getModelSize()); - } - - @Test - void deleteMiddleObjectTest() { - var store = ModelStore.builder() - .with(ViatraModelQueryAdapter.builder()) - .with(DesignSpaceExplorationAdapter.builder()) - .build(); - - var model = store.createEmptyModel(); - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); - - assertEquals(0, dseAdapter.getModelSize()); - - var newObject0 = dseAdapter.createObject(); - var newObject0Id = newObject0.get(0); - var newObject1 = dseAdapter.createObject(); - var newObject1Id = newObject1.get(0); - var newObject2 = dseAdapter.createObject(); - var newObject2Id = newObject2.get(0); - var newObject3 = dseAdapter.createObject(); - var newObject3Id = newObject3.get(0); - - assertEquals(0, newObject0Id); - assertEquals(1, newObject1Id); - assertEquals(2, newObject2Id); - assertEquals(3, newObject3Id); - assertEquals(4, dseAdapter.getModelSize()); - - dseAdapter.deleteObject(newObject1); - assertEquals(4, dseAdapter.getModelSize()); - - var newObject4 = dseAdapter.createObject(); - var newObject4Id = newObject4.get(0); - assertEquals(4, newObject4Id); - assertEquals(5, dseAdapter.getModelSize()); - - dseAdapter.deleteObject(newObject4); - assertEquals(5, dseAdapter.getModelSize()); - } - - @Test - void DFSTrivialTest() { - var store = ModelStore.builder() - .symbols(classModel) - .with(ViatraModelQueryAdapter.builder()) - .with(ModelVisualizerAdapter.builder()) - .with(DesignSpaceExplorationAdapter.builder() - .strategy(new DepthFirstStrategy(0))) - .build(); - - var model = store.createEmptyModel(); - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); - - var states = dseAdapter.explore(); - assertEquals(1, states.size()); - assertEquals(0, states.iterator().next()); - } - - @Test - void DFSOneRuleTest() { - var createClassPrecondition = Query.of("CreateClassPrecondition", - (builder, model) -> builder.clause( - classModelView.call(model) - )); - - var createClassRule = new TransformationRule("CreateClass", - createClassPrecondition, - (model) -> { - var classesInterpretation = model.getInterpretation(classes); - var classElementInterpretation = model.getInterpretation(classElement); - return ((Tuple activation) -> { - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); - var modelElement = activation.get(0); - - var newClassElement = dseAdapter.createObject(); - var newClassElementId = newClassElement.get(0); - - classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); - classElementInterpretation.put(Tuple.of(newClassElementId), true); - }); - }); - - var store = ModelStore.builder() - .symbols(classModel, classElement, classes) - .with(ViatraModelQueryAdapter.builder() - .queries(createClassPrecondition)) - .with(ModelVisualizerAdapter.builder()) - .with(DesignSpaceExplorationAdapter.builder() - .transformations(createClassRule) - .strategy(new DepthFirstStrategy(4) - )) - .build(); - - var model = store.createEmptyModel(); - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); - var queryEngine = model.getAdapter(ModelQueryAdapter.class); - - var modelElementInterpretation = model.getInterpretation(classModel); - modelElementInterpretation.put(dseAdapter.createObject(), true); - queryEngine.flushChanges(); - - var states = dseAdapter.explore(); - assertEquals(1, states.size()); - assertEquals(0, states.iterator().next()); - } - - @Test - void DFSContinueTest() { - var createClassPrecondition = Query.of("CreateClassPrecondition", - (builder, model) -> builder.clause( - classModelView.call(model) - )); - - var createClassRule = new TransformationRule("CreateClass", - createClassPrecondition, - (model) -> { - var classesInterpretation = model.getInterpretation(classes); - var classElementInterpretation = model.getInterpretation(classElement); - return ((Tuple activation) -> { - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); - var modelElement = activation.get(0); - - var newClassElement = dseAdapter.createObject(); - var newClassElementId = newClassElement.get(0); - - classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); - classElementInterpretation.put(Tuple.of(newClassElementId), true); - }); - }); - - var store = ModelStore.builder() - .symbols(classModel, classElement, classes) - .with(ViatraModelQueryAdapter.builder() - .queries(createClassPrecondition)) - .with(ModelVisualizerAdapter.builder()) - .with(DesignSpaceExplorationAdapter.builder() - .transformations(createClassRule) - .strategy(new DepthFirstStrategy(4).continueIfHardObjectivesFulfilled() - )) - .build(); - - var model = store.createEmptyModel(); - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); - var queryEngine = model.getAdapter(ModelQueryAdapter.class); - - var modelElementInterpretation = model.getInterpretation(classModel); - modelElementInterpretation.put(dseAdapter.createObject(), true); - queryEngine.flushChanges(); - - var states = dseAdapter.explore(); - var iterator = states.iterator(); - assertEquals(5, states.size()); - assertEquals(0, iterator.next()); - assertEquals(1, iterator.next()); - assertEquals(2, iterator.next()); - assertEquals(3, iterator.next()); - assertEquals(4, iterator.next()); - } - - @Test - void DFSCompletenessTest() { - var createClassPrecondition = Query.of("CreateClassPrecondition", - (builder, model) -> builder.clause( - classModelView.call(model) - )); - - var createClassRule = new TransformationRule("CreateClass", - createClassPrecondition, - (model) -> { - var classesInterpretation = model.getInterpretation(classes); - var classElementInterpretation = model.getInterpretation(classElement); - return ((Tuple activation) -> { - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); - var modelElement = activation.get(0); - - var newClassElement = dseAdapter.createObject(); - var newClassElementId = newClassElement.get(0); - - classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); - classElementInterpretation.put(Tuple.of(newClassElementId), true); - }); - }); - - var createFeaturePrecondition = Query.of("CreateFeaturePrecondition", - (builder, model) -> builder.clause( - classModelView.call(model) - )); - - var createFeatureRule = new TransformationRule("CreateFeature", - createFeaturePrecondition, - (model) -> { - var featuresInterpretation = model.getInterpretation(features); - var featureInterpretation = model.getInterpretation(feature); - return ((Tuple activation) -> { - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); - var modelElement = activation.get(0); - - var newClassElement = dseAdapter.createObject(); - var newClassElementId = newClassElement.get(0); - - featuresInterpretation.put(Tuple.of(modelElement, newClassElementId), true); - featureInterpretation.put(Tuple.of(newClassElementId), true); - }); - }); - - var store = ModelStore.builder() - .symbols(classModel, classElement, classes, feature, features, isEncapsulatedBy, encapsulates) - .with(ViatraModelQueryAdapter.builder() - .queries(createClassPrecondition, createFeaturePrecondition)) - .with(ModelVisualizerAdapter.builder()) - .with(DesignSpaceExplorationAdapter.builder() - .transformations(createClassRule, createFeatureRule) - .strategy(new DepthFirstStrategy(10).continueIfHardObjectivesFulfilled() - )) - .build(); - - var model = store.createEmptyModel(); - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); - var queryEngine = model.getAdapter(ModelQueryAdapter.class); - - var modelElementInterpretation = model.getInterpretation(classModel); - modelElementInterpretation.put(dseAdapter.createObject(), true); - queryEngine.flushChanges(); - - var states = dseAdapter.explore(); - assertEquals(2047, states.size()); - } - - @Test - void BFSTrivialTest() { - var store = ModelStore.builder() - .symbols(classModel) - .with(ViatraModelQueryAdapter.builder()) - .with(ModelVisualizerAdapter.builder()) - .with(DesignSpaceExplorationAdapter.builder() - .strategy(new BestFirstStrategy(0))) - .build(); - - var model = store.createEmptyModel(); - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); - - var states = dseAdapter.explore(); - assertEquals(1, states.size()); - assertEquals(0, states.iterator().next()); - } - - @Test - void BFSOneRuleTest() { - var createClassPrecondition = Query.of("CreateClassPrecondition", - (builder, model) -> builder.clause( - classModelView.call(model) - )); - - var createClassRule = new TransformationRule("CreateClass", - createClassPrecondition, - (model) -> { - var classesInterpretation = model.getInterpretation(classes); - var classElementInterpretation = model.getInterpretation(classElement); - return ((Tuple activation) -> { - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); - var modelElement = activation.get(0); - - var newClassElement = dseAdapter.createObject(); - var newClassElementId = newClassElement.get(0); - - classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); - classElementInterpretation.put(Tuple.of(newClassElementId), true); - }); - }); - - var store = ModelStore.builder() - .symbols(classModel, classElement, classes) - .with(ViatraModelQueryAdapter.builder() - .queries(createClassPrecondition)) - .with(ModelVisualizerAdapter.builder()) - .with(DesignSpaceExplorationAdapter.builder() - .transformations(createClassRule) - .strategy(new BestFirstStrategy(4) - )) - .build(); - - var model = store.createEmptyModel(); - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); - var queryEngine = model.getAdapter(ModelQueryAdapter.class); - - var modelElementInterpretation = model.getInterpretation(classModel); - modelElementInterpretation.put(dseAdapter.createObject(), true); - queryEngine.flushChanges(); - - var states = dseAdapter.explore(); - assertEquals(1, states.size()); - assertEquals(0, states.iterator().next()); - } - - @Test - void BFSContinueTest() { - var createClassPrecondition = Query.of("CreateClassPrecondition", - (builder, model) -> builder.clause( - classModelView.call(model) - )); - - var createClassRule = new TransformationRule("CreateClass", - createClassPrecondition, - (model) -> { - var classesInterpretation = model.getInterpretation(classes); - var classElementInterpretation = model.getInterpretation(classElement); - return ((Tuple activation) -> { - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); - var modelElement = activation.get(0); - - var newClassElement = dseAdapter.createObject(); - var newClassElementId = newClassElement.get(0); - - classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); - classElementInterpretation.put(Tuple.of(newClassElementId), true); - }); - }); - - var store = ModelStore.builder() - .symbols(classModel, classElement, classes) - .with(ViatraModelQueryAdapter.builder() - .queries(createClassPrecondition)) - .with(ModelVisualizerAdapter.builder()) - .with(DesignSpaceExplorationAdapter.builder() - .transformations(createClassRule) - .strategy(new BestFirstStrategy(4).continueIfHardObjectivesFulfilled() - )) - .build(); - - var model = store.createEmptyModel(); - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); - var queryEngine = model.getAdapter(ModelQueryAdapter.class); - - var modelElementInterpretation = model.getInterpretation(classModel); - modelElementInterpretation.put(dseAdapter.createObject(), true); - queryEngine.flushChanges(); - - var states = dseAdapter.explore(); - var iterator = states.iterator(); - assertEquals(5, states.size()); - assertEquals(0, iterator.next()); - assertEquals(1, iterator.next()); - assertEquals(2, iterator.next()); - assertEquals(3, iterator.next()); - assertEquals(4, iterator.next()); - } - - @Test - void BFSCompletenessTest() { - var createClassPrecondition = Query.of("CreateClassPrecondition", - (builder, model) -> builder.clause( - classModelView.call(model) - )); - - var createClassRule = new TransformationRule("CreateClass", - createClassPrecondition, - (model) -> { - var classesInterpretation = model.getInterpretation(classes); - var classElementInterpretation = model.getInterpretation(classElement); - return ((Tuple activation) -> { - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); - var modelElement = activation.get(0); - - var newClassElement = dseAdapter.createObject(); - var newClassElementId = newClassElement.get(0); - - classesInterpretation.put(Tuple.of(modelElement, newClassElementId), true); - classElementInterpretation.put(Tuple.of(newClassElementId), true); - }); - }); - - var createFeaturePrecondition = Query.of("CreateFeaturePrecondition", - (builder, model) -> builder.clause( - classModelView.call(model) - )); - - var createFeatureRule = new TransformationRule("CreateFeature", - createFeaturePrecondition, - (model) -> { - var featuresInterpretation = model.getInterpretation(features); - var featureInterpretation = model.getInterpretation(feature); - return ((Tuple activation) -> { - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); - var modelElement = activation.get(0); - - var newClassElement = dseAdapter.createObject(); - var newClassElementId = newClassElement.get(0); - - featuresInterpretation.put(Tuple.of(modelElement, newClassElementId), true); - featureInterpretation.put(Tuple.of(newClassElementId), true); - }); - }); - - var store = ModelStore.builder() - .symbols(classModel, classElement, classes, feature, features, isEncapsulatedBy, encapsulates) - .with(ViatraModelQueryAdapter.builder() - .queries(createClassPrecondition, createFeaturePrecondition)) - .with(ModelVisualizerAdapter.builder()) - .with(DesignSpaceExplorationAdapter.builder() - .transformations(createClassRule, createFeatureRule) - .strategy(new BestFirstStrategy(10).continueIfHardObjectivesFulfilled() - )) - .build(); - - var model = store.createEmptyModel(); - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); - var queryEngine = model.getAdapter(ModelQueryAdapter.class); - - var modelElementInterpretation = model.getInterpretation(classModel); - modelElementInterpretation.put(dseAdapter.createObject(), true); - queryEngine.flushChanges(); - - var states = dseAdapter.explore(); - assertEquals(2047, states.size()); - } - -} diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/TransformationRuleTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/TransformationRuleTest.java deleted file mode 100644 index 1fb3421b..00000000 --- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/dse/TransformationRuleTest.java +++ /dev/null @@ -1,403 +0,0 @@ -package tools.refinery.store.query.dse; - -import org.junit.jupiter.api.Test; -import tools.refinery.store.model.ModelStore; -import tools.refinery.store.query.ModelQueryAdapter; -import tools.refinery.store.query.dnf.Query; -import tools.refinery.store.query.dse.internal.TransformationRule; -import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; -import tools.refinery.store.query.view.AnySymbolView; -import tools.refinery.store.query.view.KeyOnlyView; -import tools.refinery.store.representation.Symbol; -import tools.refinery.store.tuple.Tuple; - -import java.util.List; -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static tools.refinery.store.query.literal.Literals.not; -import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertResults; - -public class TransformationRuleTest { - - private static final Symbol classModel = Symbol.of("ClassModel", 1); - private static final Symbol classElement = Symbol.of("ClassElement", 1); - private static final Symbol feature = Symbol.of("Feature", 1); - - private static final Symbol isEncapsulatedBy = Symbol.of("IsEncapsulatedBy", 2); - private static final Symbol encapsulates = Symbol.of("Encapsulates", 2); - - private static final Symbol features = Symbol.of("Features", 2); - private static final Symbol classes = Symbol.of("Classes", 2); - - private static final AnySymbolView classModelView = new KeyOnlyView<>(classModel); - private static final AnySymbolView classElementView = new KeyOnlyView<>(classElement); - private static final AnySymbolView featureView = new KeyOnlyView<>(feature); - private static final AnySymbolView isEncapsulatedByView = new KeyOnlyView<>(isEncapsulatedBy); - private static final AnySymbolView encapsulatesView = new KeyOnlyView<>(encapsulates); - private static final AnySymbolView featuresView = new KeyOnlyView<>(features); - private static final AnySymbolView classesView = new KeyOnlyView<>(classes); - - @Test - void activationsTest() { - var assignFeaturePreconditionHelper = Query.of("AssignFeaturePreconditionHelper", - (builder, model, c, f) -> builder.clause( - classElementView.call(c), - classesView.call(model, c), - encapsulatesView.call(c, f) - )); - - var assignFeaturePrecondition = Query.of("AssignFeaturePrecondition", (builder, c2, f) - -> builder.clause((model, c1) -> List.of( - classModelView.call(model), - featureView.call(f), - classElementView.call(c2), - featuresView.call(model, f), - classesView.call(model, c1), - not(assignFeaturePreconditionHelper.call(model, c2, f)), - not(encapsulatesView.call(c2, f)) - ))); - - var deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition", - (builder, model, c) -> builder.clause((f) -> List.of( - classModelView.call(model), - classElementView.call(c), - featuresView.call(model, f), - not(encapsulatesView.call(c, f)) - ))); - - TransformationRule assignFeatureRule = new TransformationRule("AssignFeature", - assignFeaturePrecondition, - (model) -> { - var isEncapsulatedByInterpretation = model.getInterpretation(isEncapsulatedBy); - return ((Tuple activation) -> { - var feature = activation.get(0); - var classElement = activation.get(1); - - isEncapsulatedByInterpretation.put(Tuple.of(feature, classElement), true); - }); - }); - - TransformationRule deleteEmptyClassRule = new TransformationRule("DeleteEmptyClass", - deleteEmptyClassPrecondition, - (model) -> { - var classesInterpretation = model.getInterpretation(classes); - var classElementInterpretation = model.getInterpretation(classElement); - return ((Tuple activation) -> { - var modelElement = activation.get(0); - var classElement = activation.get(1); - - classesInterpretation.put(Tuple.of(modelElement, classElement), false); - classElementInterpretation.put(Tuple.of(classElement), false); - }); - }); - - - var store = ModelStore.builder() - .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features) - .with(ViatraModelQueryAdapter.builder() - .queries(assignFeaturePrecondition, assignFeaturePreconditionHelper, - deleteEmptyClassPrecondition)) - .with(DesignSpaceExplorationAdapter.builder()) - .build(); - - var model = store.createEmptyModel(); - var queryEngine = model.getAdapter(ModelQueryAdapter.class); - assignFeatureRule.prepare(model, queryEngine); - deleteEmptyClassRule.prepare(model, queryEngine); - - var classModelInterpretation = model.getInterpretation(classModel); - var classElementInterpretation = model.getInterpretation(classElement); - var featureInterpretation = model.getInterpretation(feature); - var featuresInterpretation = model.getInterpretation(features); - var classesInterpretation = model.getInterpretation(classes); - - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); - var newModel = dseAdapter.createObject(); - var newModelId = newModel.get(0); - var newClass1 = dseAdapter.createObject(); - var newClass1Id = newClass1.get(0); - var newClass2 = dseAdapter.createObject(); - var newClass2Id = newClass2.get(0); - var newField = dseAdapter.createObject(); - var newFieldId = newField.get(0); - - classModelInterpretation.put(newModel, true); - classElementInterpretation.put(newClass1, true); - classElementInterpretation.put(newClass2, true); - featureInterpretation.put(newField, true); - classesInterpretation.put(Tuple.of(newModelId, newClass1Id), true); - classesInterpretation.put(Tuple.of(newModelId, newClass2Id), true); - featuresInterpretation.put(Tuple.of(newModelId, newFieldId), true); - - queryEngine.flushChanges(); - - var assignFeatureRuleActivations = assignFeatureRule.getAllActivationsAsSets(); - var deleteEmptyClassRuleActivations = deleteEmptyClassRule.getAllActivationsAsSets(); - - assertResults(Map.of( - Tuple.of(newClass1Id, newFieldId), true, - Tuple.of(newClass2Id, newFieldId), true - ), assignFeatureRuleActivations); - - assertResults(Map.of( - Tuple.of(newModelId, newClass1Id), true, - Tuple.of(newModelId, newClass2Id), true - ), deleteEmptyClassRuleActivations); - } - - @Test - void randomActivationTest() { - var deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition", - (builder, model, c) -> builder.clause((f) -> List.of( - classModelView.call(model), - classElementView.call(c), - featuresView.call(model, f), - not(encapsulatesView.call(c, f)) - ))); - - TransformationRule deleteEmptyClassRule0 = new TransformationRule("DeleteEmptyClass0", - deleteEmptyClassPrecondition, - (model) -> { - var classesInterpretation = model.getInterpretation(classes); - var classElementInterpretation = model.getInterpretation(classElement); - return ((Tuple activation) -> { - var modelElement = activation.get(0); - var classElement = activation.get(1); - - classesInterpretation.put(Tuple.of(modelElement, classElement), false); - classElementInterpretation.put(Tuple.of(classElement), false); - }); - }, - 0L); - - TransformationRule deleteEmptyClassRule1 = new TransformationRule("DeleteEmptyClass1", - deleteEmptyClassPrecondition, - (model) -> { - var classesInterpretation = model.getInterpretation(classes); - var classElementInterpretation = model.getInterpretation(classElement); - return ((Tuple activation) -> { - var modelElement = activation.get(0); - var classElement = activation.get(1); - - classesInterpretation.put(Tuple.of(modelElement, classElement), false); - classElementInterpretation.put(Tuple.of(classElement), false); - }); - }, - 78634L); - - var store = ModelStore.builder() - .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features) - .with(ViatraModelQueryAdapter.builder() - .queries(deleteEmptyClassPrecondition)) - .with(DesignSpaceExplorationAdapter.builder()) - .build(); - - var model = store.createEmptyModel(); - var queryEngine = model.getAdapter(ModelQueryAdapter.class); - deleteEmptyClassRule0.prepare(model, queryEngine); - deleteEmptyClassRule1.prepare(model, queryEngine); - - var classModelInterpretation = model.getInterpretation(classModel); - var classElementInterpretation = model.getInterpretation(classElement); - var featureInterpretation = model.getInterpretation(feature); - var featuresInterpretation = model.getInterpretation(features); - var classesInterpretation = model.getInterpretation(classes); - - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); - var newModel = dseAdapter.createObject(); - var newModelId = newModel.get(0); - var newClass1 = dseAdapter.createObject(); - var newClass1Id = newClass1.get(0); - var newClass2 = dseAdapter.createObject(); - var newClass2Id = newClass2.get(0); - var newField = dseAdapter.createObject(); - var newFieldId = newField.get(0); - - classModelInterpretation.put(newModel, true); - classElementInterpretation.put(newClass1, true); - classElementInterpretation.put(newClass2, true); - featureInterpretation.put(newField, true); - classesInterpretation.put(Tuple.of(newModelId, newClass1Id), true); - classesInterpretation.put(Tuple.of(newModelId, newClass2Id), true); - featuresInterpretation.put(Tuple.of(newModelId, newFieldId), true); - - queryEngine.flushChanges(); - - - var activation0 = deleteEmptyClassRule0.getRandomActivation().activation(); - var activation1 = deleteEmptyClassRule1.getRandomActivation().activation(); - - assertResults(Map.of( - Tuple.of(newModelId, newClass1Id), true, - Tuple.of(newModelId, newClass2Id), true - ), deleteEmptyClassRule0.getAllActivationsAsSets()); - - assertResults(Map.of( - Tuple.of(newModelId, newClass1Id), true, - Tuple.of(newModelId, newClass2Id), true - ), deleteEmptyClassRule1.getAllActivationsAsSets()); - - assertEquals(Tuple.of(newModelId, newClass2Id), activation0); - assertEquals(Tuple.of(newModelId, newClass1Id), activation1); - - } - - @Test - void fireTest() { - var deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition", - (builder, model, c) -> builder.clause((f) -> List.of( - classModelView.call(model), - classElementView.call(c), - featuresView.call(model, f), - not(encapsulatesView.call(c, f)) - ))); - - TransformationRule deleteEmptyClassRule = new TransformationRule("DeleteEmptyClass", - deleteEmptyClassPrecondition, - (model) -> { - var classesInterpretation = model.getInterpretation(classes); - var classElementInterpretation = model.getInterpretation(classElement); - return ((Tuple activation) -> { - var modelElement = activation.get(0); - var classElement = activation.get(1); - - classesInterpretation.put(Tuple.of(modelElement, classElement), false); - classElementInterpretation.put(Tuple.of(classElement), false); - }); - }); - - var store = ModelStore.builder() - .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features) - .with(ViatraModelQueryAdapter.builder() - .queries(deleteEmptyClassPrecondition)) - .with(DesignSpaceExplorationAdapter.builder()) - .build(); - - var model = store.createEmptyModel(); - var queryEngine = model.getAdapter(ModelQueryAdapter.class); - deleteEmptyClassRule.prepare(model, queryEngine); - - var classModelInterpretation = model.getInterpretation(classModel); - var classElementInterpretation = model.getInterpretation(classElement); - var featureInterpretation = model.getInterpretation(feature); - var featuresInterpretation = model.getInterpretation(features); - var classesInterpretation = model.getInterpretation(classes); - - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); - var newModel = dseAdapter.createObject(); - var newModelId = newModel.get(0); - var newClass1 = dseAdapter.createObject(); - var newClass1Id = newClass1.get(0); - var newClass2 = dseAdapter.createObject(); - var newClass2Id = newClass2.get(0); - var newField = dseAdapter.createObject(); - var newFieldId = newField.get(0); - - classModelInterpretation.put(newModel, true); - classElementInterpretation.put(newClass1, true); - classElementInterpretation.put(newClass2, true); - featureInterpretation.put(newField, true); - classesInterpretation.put(Tuple.of(newModelId, newClass1Id), true); - classesInterpretation.put(Tuple.of(newModelId, newClass2Id), true); - featuresInterpretation.put(Tuple.of(newModelId, newFieldId), true); - - queryEngine.flushChanges(); - - assertResults(Map.of( - Tuple.of(newModelId, newClass1Id), true, - Tuple.of(newModelId, newClass2Id), true - ), deleteEmptyClassRule.getAllActivationsAsSets()); - - - deleteEmptyClassRule.fireActivation(Tuple.of(0, 1)); - - assertResults(Map.of( - Tuple.of(newModelId, newClass1Id), false, - Tuple.of(newModelId, newClass2Id), true - ), deleteEmptyClassRule.getAllActivationsAsSets()); - } - - @Test - void randomFireTest() { - var deleteEmptyClassPrecondition = Query.of("DeleteEmptyClassPrecondition", - (builder, model, c) -> builder.clause((f) -> List.of( - classModelView.call(model), - classElementView.call(c), - featuresView.call(model, f), - not(encapsulatesView.call(c, f)) - ))); - - TransformationRule deleteEmptyClassRule = new TransformationRule("DeleteEmptyClass0", - deleteEmptyClassPrecondition, - (model) -> { - var classesInterpretation = model.getInterpretation(classes); - var classElementInterpretation = model.getInterpretation(classElement); - return ((Tuple activation) -> { - var modelElement = activation.get(0); - var classElement = activation.get(1); - - classesInterpretation.put(Tuple.of(modelElement, classElement), false); - classElementInterpretation.put(Tuple.of(classElement), false); - }); - }, - 0L); - - var store = ModelStore.builder() - .symbols(classModel, classElement, feature, isEncapsulatedBy, encapsulates, classes, features) - .with(ViatraModelQueryAdapter.builder() - .queries(deleteEmptyClassPrecondition)) - .with(DesignSpaceExplorationAdapter.builder()) - .build(); - - var model = store.createEmptyModel(); - var queryEngine = model.getAdapter(ModelQueryAdapter.class); - deleteEmptyClassRule.prepare(model, queryEngine); - - var classModelInterpretation = model.getInterpretation(classModel); - var classElementInterpretation = model.getInterpretation(classElement); - var featureInterpretation = model.getInterpretation(feature); - var featuresInterpretation = model.getInterpretation(features); - var classesInterpretation = model.getInterpretation(classes); - - var dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); - var newModel = dseAdapter.createObject(); - var newModelId = newModel.get(0); - var newClass1 = dseAdapter.createObject(); - var newClass1Id = newClass1.get(0); - var newClass2 = dseAdapter.createObject(); - var newClass2Id = newClass2.get(0); - var newField = dseAdapter.createObject(); - var newFieldId = newField.get(0); - - classModelInterpretation.put(newModel, true); - classElementInterpretation.put(newClass1, true); - classElementInterpretation.put(newClass2, true); - featureInterpretation.put(newField, true); - classesInterpretation.put(Tuple.of(newModelId, newClass1Id), true); - classesInterpretation.put(Tuple.of(newModelId, newClass2Id), true); - featuresInterpretation.put(Tuple.of(newModelId, newFieldId), true); - - queryEngine.flushChanges(); - - assertResults(Map.of( - Tuple.of(newModelId, newClass1Id), true, - Tuple.of(newModelId, newClass2Id), true - ), deleteEmptyClassRule.getAllActivationsAsSets()); - - deleteEmptyClassRule.fireRandomActivation(); - - assertResults(Map.of( - Tuple.of(newModelId, newClass1Id), true, - Tuple.of(newModelId, newClass2Id), false - ), deleteEmptyClassRule.getAllActivationsAsSets()); - - deleteEmptyClassRule.fireRandomActivation(); - - assertResults(Map.of( - Tuple.of(newModelId, newClass1Id), false, - Tuple.of(newModelId, newClass2Id), false - ), deleteEmptyClassRule.getAllActivationsAsSets()); - - } -} -- cgit v1.2.3-70-g09d2