From 9de7ead9602c2e51448c3b6710d13eb5dd2f3b1f Mon Sep 17 00:00:00 2001 From: OszkarSemerath Date: Tue, 5 Sep 2023 07:59:17 +0200 Subject: restructured DSE framework, failing build --- .../store/dse/DesignSpaceExplorationAdapter.java | 68 ----- .../store/dse/DesignSpaceExplorationBuilder.java | 48 ---- .../dse/DesignSpaceExplorationStoreAdapter.java | 29 -- .../java/tools/refinery/store/dse/Strategy.java | 13 - .../refinery/store/dse/internal/Activation.java | 14 - .../DesignSpaceExplorationAdapterImpl.java | 294 --------------------- .../DesignSpaceExplorationBuilderImpl.java | 67 ----- .../DesignSpaceExplorationStoreAdapterImpl.java | 65 ----- .../store/dse/internal/TransformationRule.java | 97 ------- .../dse/modification/ModificationAdapter.java | 24 ++ .../dse/modification/ModificationBuilder.java | 11 + .../dse/modification/ModificationStoreAdapter.java | 11 + .../internal/ModificationAdapterImpl.java | 62 +++++ .../internal/ModificationBuilderImpl.java | 29 ++ .../internal/ModificationStoreAdapterImpl.java | 29 ++ .../AlwaysSatisfiedDummyHardObjective.java | 52 ---- .../AlwaysSatisfiedRandomHardObjective.java | 56 ---- .../store/dse/objectives/BaseObjective.java | 132 --------- .../refinery/store/dse/objectives/Comparators.java | 26 -- .../refinery/store/dse/objectives/Fitness.java | 46 ---- .../refinery/store/dse/objectives/Objective.java | 101 ------- .../dse/objectives/ObjectiveComparatorHelper.java | 60 ----- .../store/dse/strategy/BestFirstExplorer.java | 164 ++++++++++++ .../store/dse/strategy/BestFirstStoreManager.java | 71 +++++ .../store/dse/strategy/BestFirstStrategy.java | 203 -------------- .../store/dse/strategy/BestFirstWorker.java | 113 ++++++++ .../store/dse/strategy/DepthFirstStrategy.java | 92 ------- .../refinery/store/dse/strategy/SubmitResult.java | 14 + .../transition/DesignSpaceExplorationAdapter.java | 31 +++ .../transition/DesignSpaceExplorationBuilder.java | 59 +++++ .../DesignSpaceExplorationStoreAdapter.java | 27 ++ .../store/dse/transition/ObjectiveValue.java | 24 ++ .../store/dse/transition/ObjectiveValues.java | 69 +++++ .../store/dse/transition/Transformation.java | 43 +++ .../store/dse/transition/TransformationRule.java | 63 +++++ .../dse/transition/VersionWithObjectiveValue.java | 11 + .../DesignSpaceExplorationAdapterImpl.java | 90 +++++++ .../DesignSpaceExplorationBuilderImpl.java | 75 ++++++ .../DesignSpaceExplorationStoreAdapterImpl.java | 70 +++++ .../store/dse/transition/objectives/Criterion.java | 15 ++ .../transition/objectives/CriterionCalculator.java | 10 + .../store/dse/transition/objectives/Objective.java | 15 ++ .../transition/objectives/ObjectiveCalculator.java | 10 + .../dse/transition/objectives/QueryCriteria.java | 44 +++ .../dse/transition/objectives/QueryObjective.java | 44 +++ .../dse/transition/statespace/ActivationStore.java | 18 ++ .../statespace/EquivalenceClassStore.java | 16 ++ .../statespace/ObjectivePriorityQueue.java | 21 ++ .../dse/transition/statespace/SolutionStore.java | 17 ++ .../internal/AbstractEquivalenceClassStore.java | 47 ++++ .../internal/ActivationStoreBitVectorEntry.java | 46 ++++ .../statespace/internal/ActivationStoreEntry.java | 32 +++ .../statespace/internal/ActivationStoreImpl.java | 131 +++++++++ .../internal/ActivationStoreListEntry.java | 95 +++++++ .../statespace/internal/ActivationStoreWorker.java | 56 ++++ .../internal/CompleteEquivalenceClassStore.java | 107 ++++++++ .../internal/FastEquivalenceClassStore.java | 32 +++ .../internal/ObjectivePriorityQueueImpl.java | 74 ++++++ .../statespace/internal/SolutionStoreImpl.java | 53 ++++ .../tools/refinery/store/dse/CRAExamplesTest.java | 6 +- .../java/tools/refinery/store/dse/DebugTest.java | 4 +- .../store/dse/DesignSpaceExplorationTest.java | 3 +- .../refinery/store/dse/TransformationRuleTest.java | 3 +- .../statespace/internal/ActivationUnitTest.java | 72 +++++ 64 files changed, 2054 insertions(+), 1470 deletions(-) delete mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationAdapter.java delete mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationBuilder.java delete mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationStoreAdapter.java delete mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/Strategy.java delete mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/Activation.java delete mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationAdapterImpl.java delete mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationBuilderImpl.java delete mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java delete 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/modification/ModificationAdapter.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/ModificationBuilder.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/ModificationStoreAdapter.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/internal/ModificationAdapterImpl.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/internal/ModificationBuilderImpl.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/internal/ModificationStoreAdapterImpl.java delete mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/AlwaysSatisfiedDummyHardObjective.java delete mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/AlwaysSatisfiedRandomHardObjective.java delete mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/BaseObjective.java delete mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Comparators.java delete mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Fitness.java delete mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Objective.java delete 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/BestFirstExplorer.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstStoreManager.java delete 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/BestFirstWorker.java delete mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/DepthFirstStrategy.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/SubmitResult.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/DesignSpaceExplorationAdapter.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/DesignSpaceExplorationBuilder.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/DesignSpaceExplorationStoreAdapter.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/ObjectiveValue.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/ObjectiveValues.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/Transformation.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/TransformationRule.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/VersionWithObjectiveValue.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/internal/DesignSpaceExplorationAdapterImpl.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/internal/DesignSpaceExplorationBuilderImpl.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/internal/DesignSpaceExplorationStoreAdapterImpl.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/Criterion.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/CriterionCalculator.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/Objective.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/ObjectiveCalculator.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/QueryCriteria.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/QueryObjective.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/ActivationStore.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/EquivalenceClassStore.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/ObjectivePriorityQueue.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/SolutionStore.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/AbstractEquivalenceClassStore.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreBitVectorEntry.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreEntry.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreImpl.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreListEntry.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreWorker.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/CompleteEquivalenceClassStore.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/FastEquivalenceClassStore.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ObjectivePriorityQueueImpl.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/SolutionStoreImpl.java create mode 100644 subprojects/store-dse/src/test/java/tools/refinery/store/dse/transition/statespace/internal/ActivationUnitTest.java (limited to 'subprojects/store-dse/src') 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 deleted file mode 100644 index 5aed5298..00000000 --- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationAdapter.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -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 boolean backtrack(String reason); - - public Fitness getFitness(); - - public void newSolution(); - - public int getDepth(); - - public Collection getUntraversedActivations(); - - public boolean fireActivation(Activation activation); - - public boolean fireRandomActivation(); - - public List getTrajectory(); - - public boolean isCurrentStateAlreadyTraversed(); - - public ObjectiveComparatorHelper getObjectiveComparatorHelper(); - - public void restoreTrajectory(List trajectory); - - public void setRandom(Random random); - - public void setRandom(long seed); - - public List getSolutions(); -} 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 deleted file mode 100644 index 4def5cb2..00000000 --- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationBuilder.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -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 deleted file mode 100644 index 0252748d..00000000 --- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationStoreAdapter.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.dse; - -import tools.refinery.store.adapter.ModelStoreAdapter; -import tools.refinery.store.dse.internal.TransformationRule; -import tools.refinery.store.dse.objectives.Objective; -import tools.refinery.store.model.Model; -import tools.refinery.store.query.dnf.RelationalQuery; - -import java.util.List; -import java.util.Set; - -public interface DesignSpaceExplorationStoreAdapter extends ModelStoreAdapter { - - @Override - DesignSpaceExplorationAdapter createModelAdapter(Model model); - - Set getTransformationSpecifications(); - - Set getGlobalConstraints(); - - List getObjectives(); - - Strategy getStrategy(); -} 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 deleted file mode 100644 index c60a4410..00000000 --- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/Strategy.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.dse; - -public interface Strategy { - - void initialize(DesignSpaceExplorationAdapter designSpaceExplorationAdapter); - - 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 deleted file mode 100644 index 1893ce2e..00000000 --- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/Activation.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -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 deleted file mode 100644 index 220f0b2d..00000000 --- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationAdapterImpl.java +++ /dev/null @@ -1,294 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro - * Copyright (c) 2023 The Refinery Authors - * 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.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 Set transformationRules; - private final Set 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 ArrayList<>(); - private Map parents = new HashMap<>(); - private final List solutions = new ArrayList<>(); - private Map> statesAndTraversedActivations; - private Random random = new Random(); - private boolean isNewState = false; - private final boolean isVisualizationEnabled; - private final ModelVisualizerAdapter modelVisualizerAdapter; - - private final Map fitnessCache = new HashMap<>(); - - 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(); - statesAndTraversedActivations = new HashMap<>(); - strategy = storeAdapter.getStrategy(); - strategy.initialize(this); - modelVisualizerAdapter = model.tryGetAdapter(ModelVisualizerAdapter.class).orElse(null); - isVisualizationEnabled = modelVisualizerAdapter != null; - - } - - public List getTrajectory() { - return new ArrayList<>(trajectory); - } - - @Override - public Model getModel() { - return model; - } - - @Override - public DesignSpaceExplorationStoreAdapter getStoreAdapter() { - return storeAdapter; - } - - @Override - public List explore() { - var state = model.commit(); - trajectory.add(state); - strategy.explore(); - if (isVisualizationEnabled) { - modelVisualizerAdapter.visualize(); - } - 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() { - return backtrack(""); - } - @Override - public boolean backtrack(String reason) { - if (trajectory.size() < 2) { - return false; - } - var currentState = model.getState(); - if (!parents.containsKey(currentState)) { - return false; - } - if (isVisualizationEnabled) { - modelVisualizerAdapter.addTransition(trajectory.get(trajectory.size() - 1), - trajectory.get(trajectory.size() - 2), "backtrack(" + reason + ")"); - } - model.restore(parents.get(model.getState())); - 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 = new ArrayList<>(trajectory); - - } - - @Override - public void setRandom(Random random) { - this.random = random; - } - - @Override - public void setRandom(long seed) { - this.random = new Random(seed); - } - - @Override - public List getSolutions() { - return solutions; - } - - @Override - public Fitness getFitness() { - return fitnessCache.computeIfAbsent(model.getState(), s -> calculateFitness()); - } - - private 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); - - 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() { - var traversedActivations = statesAndTraversedActivations.get(model.getState()); - if (traversedActivations == null) { - return new LinkedHashSet<>(getAllActivations()); - } - else { - LinkedHashSet untraversedActivations = new LinkedHashSet<>(); - for (Activation activation : getAllActivations()) { - if (!traversedActivations.contains(activation)) { - untraversedActivations.add(activation); - } - } - return untraversedActivations; - } - } - - @Override - public boolean fireActivation(Activation activation) { - if (activation == null) { - return false; - } - var previousState = model.getState(); - if (!activation.fire()) { - return false; - } - statesAndTraversedActivations.computeIfAbsent(previousState, s -> new ArrayList<>()).add(activation); - var newState = model.commit(); - trajectory.add(newState); - parents.put(newState, previousState); - isNewState = !statesAndTraversedActivations.containsKey(newState); - if (isVisualizationEnabled) { - if (isNewState) { - modelVisualizerAdapter.addState(newState, getFitness().values()); - } - modelVisualizerAdapter.addTransition(previousState, newState, activation.transformationRule().getName(), - activation.activation()); - } - return true; - } - - @Override - public boolean fireRandomActivation() { - var activations = getUntraversedActivations(); - if (activations.isEmpty()) { - return false; - } - int index = random.nextInt(activations.size()); - var iterator = activations.iterator(); - while (index-- > 0) { - iterator.next(); - } - var activationId = iterator.next(); - return fireActivation(activationId); - } - - public List getAllActivations() { - List result = new LinkedList<>(); - for (var rule : transformationRules) { - result.addAll(rule.getAllActivationsAsList()); - } - return result; - } - - public boolean isCurrentStateAlreadyTraversed() { - return !isNewState; - } - - 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 deleted file mode 100644 index 8f7056f2..00000000 --- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationBuilderImpl.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -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 deleted file mode 100644 index fea39886..00000000 --- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.dse.internal; - -import tools.refinery.store.dse.DesignSpaceExplorationStoreAdapter; -import tools.refinery.store.dse.Strategy; -import tools.refinery.store.dse.objectives.Objective; -import tools.refinery.store.model.Model; -import tools.refinery.store.model.ModelStore; -import tools.refinery.store.query.dnf.RelationalQuery; - -import java.util.List; -import java.util.Set; - -public class DesignSpaceExplorationStoreAdapterImpl implements DesignSpaceExplorationStoreAdapter { - private final ModelStore store; - private final Set transformationSpecifications; - private final Set globalConstraints; - private final List objectives; - private final Strategy strategy; - - public DesignSpaceExplorationStoreAdapterImpl(ModelStore store, - Set transformationSpecifications, - Set 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 DesignSpaceExplorationAdapterImpl createModelAdapter(Model model) { - return new DesignSpaceExplorationAdapterImpl(model, this); - } - - @Override - public Set getTransformationSpecifications() { - return transformationSpecifications; - } - - @Override - public Set getGlobalConstraints() { - return globalConstraints; - } - - @Override - public List getObjectives() { - return objectives; - } - - @Override - 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 deleted file mode 100644 index 8123c0d6..00000000 --- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/TransformationRule.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -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.*; - -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 getAllActivationsAsResultSet() { - return activations; - } - - public Set getAllActivations() { - var result = new LinkedHashSet(); - var cursor = activations.getAll(); - while (cursor.move()) { - result.add(new Activation(this, cursor.getKey())); - } - return result; - } - - public List getAllActivationsAsList() { - var result = new ArrayList(); - 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/modification/ModificationAdapter.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/ModificationAdapter.java new file mode 100644 index 00000000..f15c16e0 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/ModificationAdapter.java @@ -0,0 +1,24 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.modification; + +import tools.refinery.store.adapter.ModelAdapter; +import tools.refinery.store.dse.modification.internal.ModificationBuilderImpl; +import tools.refinery.store.tuple.Tuple; +import tools.refinery.store.tuple.Tuple1; + +public interface ModificationAdapter extends ModelAdapter { + + int getModelSize(); + + Tuple1 createObject(); + + Tuple deleteObject(Tuple tuple); + + static ModificationBuilder builder() { + return new ModificationBuilderImpl(); + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/ModificationBuilder.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/ModificationBuilder.java new file mode 100644 index 00000000..48c22bdf --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/ModificationBuilder.java @@ -0,0 +1,11 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.modification; + +import tools.refinery.store.adapter.ModelAdapterBuilder; + +public interface ModificationBuilder extends ModelAdapterBuilder { +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/ModificationStoreAdapter.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/ModificationStoreAdapter.java new file mode 100644 index 00000000..144c4d05 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/ModificationStoreAdapter.java @@ -0,0 +1,11 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.modification; + +import tools.refinery.store.adapter.ModelStoreAdapter; + +public interface ModificationStoreAdapter extends ModelStoreAdapter { +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/internal/ModificationAdapterImpl.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/internal/ModificationAdapterImpl.java new file mode 100644 index 00000000..b2a80d71 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/internal/ModificationAdapterImpl.java @@ -0,0 +1,62 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.modification.internal; + +import tools.refinery.store.adapter.ModelStoreAdapter; +import tools.refinery.store.dse.modification.ModificationAdapter; +import tools.refinery.store.model.Interpretation; +import tools.refinery.store.model.Model; +import tools.refinery.store.representation.Symbol; +import tools.refinery.store.tuple.Tuple; +import tools.refinery.store.tuple.Tuple1; + +public class ModificationAdapterImpl implements ModificationAdapter { + static final Symbol NEXT_ID = Symbol.of("NEXT_ID", 0, Integer.class, 0); + + final ModelStoreAdapter storeAdapter; + final Model model; + Interpretation nodeCountInterpretation; + + ModificationAdapterImpl(ModelStoreAdapter storeAdapter, Model model) { + this.storeAdapter = storeAdapter; + this.model = model; + this.nodeCountInterpretation = model.getInterpretation(NEXT_ID); + } + + @Override + public Model getModel() { + return model; + } + + @Override + public ModelStoreAdapter getStoreAdapter() { + return storeAdapter; + } + + @Override + public int getModelSize() { + return nodeCountInterpretation.get(Tuple.of()); + } + + @Override + public Tuple1 createObject() { + var newNodeId = getModelSize(); + nodeCountInterpretation.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) { + nodeCountInterpretation.put(Tuple.of(), getModelSize() - 1); + } + return tuple; + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/internal/ModificationBuilderImpl.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/internal/ModificationBuilderImpl.java new file mode 100644 index 00000000..c4d38d22 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/internal/ModificationBuilderImpl.java @@ -0,0 +1,29 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.modification.internal; + +import tools.refinery.store.adapter.AbstractModelAdapterBuilder; +import tools.refinery.store.dse.modification.ModificationBuilder; +import tools.refinery.store.dse.modification.ModificationStoreAdapter; +import tools.refinery.store.model.ModelStore; +import tools.refinery.store.model.ModelStoreBuilder; +import tools.refinery.store.statecoding.StateCoderBuilder; + +public class ModificationBuilderImpl extends AbstractModelAdapterBuilder implements ModificationBuilder { + + @Override + protected void doConfigure(ModelStoreBuilder storeBuilder) { + storeBuilder.symbols(ModificationAdapterImpl.NEXT_ID); + storeBuilder.tryGetAdapter(StateCoderBuilder.class).ifPresent( + coderBuilder -> coderBuilder.exclude(ModificationAdapterImpl.NEXT_ID)); + super.doConfigure(storeBuilder); + } + + @Override + protected ModificationStoreAdapter doBuild(ModelStore store) { + return new ModificationStoreAdapterImpl(store); + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/internal/ModificationStoreAdapterImpl.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/internal/ModificationStoreAdapterImpl.java new file mode 100644 index 00000000..913cb33f --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/internal/ModificationStoreAdapterImpl.java @@ -0,0 +1,29 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.modification.internal; + +import tools.refinery.store.adapter.ModelAdapter; +import tools.refinery.store.dse.modification.ModificationStoreAdapter; +import tools.refinery.store.model.Model; +import tools.refinery.store.model.ModelStore; + +public class ModificationStoreAdapterImpl implements ModificationStoreAdapter { + ModelStore store; + + ModificationStoreAdapterImpl(ModelStore store) { + this.store = store; + } + + @Override + public ModelStore getStore() { + return store; + } + + @Override + public ModelAdapter createModelAdapter(Model model) { + return null; + } +} 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 deleted file mode 100644 index afed75fd..00000000 --- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/AlwaysSatisfiedDummyHardObjective.java +++ /dev/null @@ -1,52 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010-2016, Andras Szabolcs Nagy, Zoltan Ujhelyi and Daniel Varro - * Copyright (c) 2023 The Refinery Authors - * 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/AlwaysSatisfiedRandomHardObjective.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/AlwaysSatisfiedRandomHardObjective.java deleted file mode 100644 index 327d5e2f..00000000 --- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/AlwaysSatisfiedRandomHardObjective.java +++ /dev/null @@ -1,56 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010-2016, Andras Szabolcs Nagy, Zoltan Ujhelyi and Daniel Varro - * Copyright (c) 2023 The Refinery Authors - * 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.Random; - -/** - * 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 AlwaysSatisfiedRandomHardObjective extends BaseObjective { - - private static final String DEFAULT_NAME = "AlwaysSatisfiedDummyHardObjective"; - private static final Random random = new Random(0); - - public AlwaysSatisfiedRandomHardObjective() { - super(DEFAULT_NAME); - } - - public AlwaysSatisfiedRandomHardObjective(String name) { - super(name); - } - - @Override - public Double getFitness(DesignSpaceExplorationAdapter context) { -// return 0d; - return random.nextDouble(); - } - - @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 deleted file mode 100644 index b76598fb..00000000 --- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/BaseObjective.java +++ /dev/null @@ -1,132 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro - * Copyright (c) 2023 The Refinery Authors - * 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; - - protected 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 deleted file mode 100644 index 181397b3..00000000 --- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Comparators.java +++ /dev/null @@ -1,26 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro - * Copyright (c) 2023 The Refinery Authors - * 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 = Double::compareTo; - - 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 deleted file mode 100644 index b1dc4442..00000000 --- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Fitness.java +++ /dev/null @@ -1,46 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro - * Copyright (c) 2023 The Refinery Authors - * 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.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; - } - - @Override - public boolean equals(Object other) { - if (other == null) return false; - if (getClass() != other.getClass()) return false; - if (!super.equals(other)) return false; - return satisfiesHardObjectives == ((Fitness) other).satisfiesHardObjectives; - } - - @Override - public int hashCode() { - int h = super.hashCode(); - h = h * 31 + (satisfiesHardObjectives ? 1 : 0); - return h; - } - -} 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 deleted file mode 100644 index c7313622..00000000 --- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Objective.java +++ /dev/null @@ -1,101 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro - * Copyright (c) 2023 The Refinery Authors - * 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 deleted file mode 100644 index eb03eeaf..00000000 --- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/ObjectiveComparatorHelper.java +++ /dev/null @@ -1,60 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro - * Copyright (c) 2023 The Refinery Authors - * 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) { - return -1; - } else if (o1HasBetterFitness) { - return 1; - } - - return 0; - - } -} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstExplorer.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstExplorer.java new file mode 100644 index 00000000..72bbbc55 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstExplorer.java @@ -0,0 +1,164 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.strategy; + +import tools.refinery.store.dse.transition.ObjectiveValue; +import tools.refinery.store.dse.transition.VersionWithObjectiveValue; +import tools.refinery.store.model.Model; + +import java.util.Random; + +public class BestFirstExplorer extends BestFirstWorker { + final int id; + Random random; + public BestFirstExplorer(BestFirstStoreManager storeManager, Model model, int id) { + super(storeManager, model); + this.id = id; + this.random = new Random(id); + } + + private boolean interrupted = false; + public void interrupt() { + this.interrupted = true; + } + + private boolean shouldRun() { + return !interrupted && !hasEnoughSolution(); + } + + public void explore() { + VersionWithObjectiveValue lastVisited = submit().newVersion(); + + mainLoop: while (shouldRun()) { + + if (lastVisited == null) { + var restored = this.restoreToBest(); + if(restored != null) { + lastVisited = restored; + } else { + return; + } + } + + boolean tryActivation = true; + while(tryActivation && shouldRun()) { + RandomVisitResult randomVisitResult = this.visitRandomUnvisited(random); + + tryActivation &= randomVisitResult.shouldRetry(); + var newSubmit = randomVisitResult.submitResult(); + if(newSubmit != null) { + if(!newSubmit.include()) { + restoreToLast(); + } else { + var newVisit = newSubmit.newVersion(); + int compareResult = compare(lastVisited,newVisit); + if(compareResult >= 0) { + lastVisited = newVisit; + continue mainLoop; + } + } + } + } + + //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.getFitness(); + if (firstFitness.isSatisfiesHardObjectives()) { + dseAdapter.newSolution(); + // First state is a solution. Terminate. + if (backTrackIfSolution) { + return; + } + } + + if (maxDepth == 0) { + return; + }*/ + + /* + var firstTrajectoryWithFitness = new TrajectoryWithFitness(dseAdapter.getTrajectory(), firstFitness); + trajectoriesToExplore.add(firstTrajectoryWithFitness); + TrajectoryWithFitness currentTrajectoryWithFitness = null; + */ +/* + 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); + } + + // Executing new activation + 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.getFitness(); + if (nextFitness.isSatisfiesHardObjectives()) { + dseAdapter.newSolution(); + var solutions = dseAdapter.getSolutions().size(); + if (solutions >= maxSolutions) { + return; + } + // 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 + currentTrajectoryWithFitness = nextTrajectoryWithFitness; + continue mainLoop; + } else if (compare == 0) { + if (onlyBetterFirst) { + // Equally good fitness, backtrack + dseAdapter.backtrack(); + } else { + // Equally good fitness, moving on + currentTrajectoryWithFitness = nextTrajectoryWithFitness; + continue mainLoop; + } + } else { + //"Worse fitness + currentTrajectoryWithFitness = null; + continue mainLoop; + } + } + } + + // State is fully traversed. + currentTrajectoryWithFitness = null; +*/ + } + // Interrupted. + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstStoreManager.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstStoreManager.java new file mode 100644 index 00000000..d1fd7884 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstStoreManager.java @@ -0,0 +1,71 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.strategy; + +import org.eclipse.collections.api.block.procedure.Procedure; +import tools.refinery.store.dse.transition.DesignSpaceExplorationStoreAdapter; +import tools.refinery.store.dse.transition.VersionWithObjectiveValue; +import tools.refinery.store.dse.transition.statespace.ActivationStore; +import tools.refinery.store.dse.transition.statespace.EquivalenceClassStore; +import tools.refinery.store.dse.transition.statespace.ObjectivePriorityQueue; +import tools.refinery.store.dse.transition.statespace.SolutionStore; +import tools.refinery.store.dse.transition.statespace.internal.ActivationStoreImpl; +import tools.refinery.store.dse.transition.statespace.internal.FastEquivalenceClassStore; +import tools.refinery.store.dse.transition.statespace.internal.ObjectivePriorityQueueImpl; +import tools.refinery.store.dse.transition.statespace.internal.SolutionStoreImpl; +import tools.refinery.store.map.Version; +import tools.refinery.store.model.ModelStore; +import tools.refinery.store.statecoding.StateCoderStoreAdapter; + +public class BestFirstStoreManager { + ModelStore modelStore; + ObjectivePriorityQueue objectiveStore; + ActivationStore activationStore; + SolutionStore solutionStore; + EquivalenceClassStore equivalenceClassStore; + + public BestFirstStoreManager(ModelStore modelStore) { + this.modelStore = modelStore; + DesignSpaceExplorationStoreAdapter storeAdapter = + modelStore.getAdapter(DesignSpaceExplorationStoreAdapter.class); + + objectiveStore = new ObjectivePriorityQueueImpl(storeAdapter.getObjectives()); + Procedure whenAllActivationsVisited = x -> objectiveStore.remove(x); + activationStore = new ActivationStoreImpl(storeAdapter.getTransformations().size(), whenAllActivationsVisited); + solutionStore = new SolutionStoreImpl(1); + equivalenceClassStore = new FastEquivalenceClassStore(modelStore.getAdapter(StateCoderStoreAdapter.class)) { + @Override + protected void delegate(VersionWithObjectiveValue version, int[] emptyActivations, boolean accept) { + objectiveStore.submit(version); + activationStore.markNewAsVisited(version, emptyActivations); + if(accept) { + solutionStore.submit(version); + } + } + }; + } + + ObjectivePriorityQueue getObjectiveStore() { + return objectiveStore; + } + + ActivationStore getActivationStore() { + return activationStore; + } + + SolutionStore getSolutionStore() { + return solutionStore; + } + + EquivalenceClassStore getEquivalenceClassStore() { + return equivalenceClassStore; + } + + public void startExploration(Version initial) { + BestFirstExplorer bestFirstExplorer = new BestFirstExplorer(this, modelStore.createModelForState(initial), 1); + bestFirstExplorer.explore(); + } +} 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 deleted file mode 100644 index 92d878ce..00000000 --- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstStrategy.java +++ /dev/null @@ -1,203 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010-2016, Andras Szabolcs Nagy, Zoltan Ujhelyi and Daniel Varro - * Copyright (c) 2023 The Refinery Authors - * 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.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.*; - -public class BestFirstStrategy implements Strategy { - - private DesignSpaceExplorationAdapter dseAdapter; - - private int maxDepth = Integer.MAX_VALUE; - private int maxSolutions = Integer.MAX_VALUE; - private boolean backTrackIfSolution = true; - private boolean onlyBetterFirst = false; - - private PriorityQueue trajectoriesToExplore; - - private record TrajectoryWithFitness(List trajectory, Fitness fitness) { - @Override - public String toString() { - return trajectory.toString() + fitness.toString(); - } - - @Override - public int hashCode() { - return trajectory.get(trajectory.size() - 1).hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof TrajectoryWithFitness other) { - return Objects.equals(trajectory.get(trajectory.size() - 1), other.trajectory.get(other.trajectory.size() - 1)); -// return trajectory.equals(((TrajectoryWithFitness) obj).trajectory); - } - return false; - } - } - - public BestFirstStrategy withDepthLimit(int maxDepth) { - if (maxDepth >= 0) { - this.maxDepth = maxDepth; - } - return this; - } - - public BestFirstStrategy withSolutionLimit(int maxSolutions) { - if (maxSolutions >= 0) { - this.maxSolutions = maxSolutions; - } - return this; - } - - public BestFirstStrategy continueIfHardObjectivesFulfilled() { - backTrackIfSolution = false; - return this; - } - - public BestFirstStrategy goOnOnlyIfFitnessIsBetter() { - onlyBetterFirst = true; - return this; - } - - @Override - public void initialize(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() { - if (maxSolutions == 0) { - return; - } - 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.getFitness(); - if (firstFitness.isSatisfiesHardObjectives()) { - dseAdapter.newSolution(); - // First state is a solution. Terminate. - if (backTrackIfSolution) { - return; - } - } - - if (maxDepth == 0) { - return; - } - - - var firstTrajectoryWithFitness = new TrajectoryWithFitness(dseAdapter.getTrajectory(), firstFitness); - trajectoriesToExplore.add(firstTrajectoryWithFitness); - TrajectoryWithFitness currentTrajectoryWithFitness = null; - - mainLoop: while (true) { - - if (currentTrajectoryWithFitness == null) { - if (trajectoriesToExplore.isEmpty()) { - // State space is fully traversed. - return; - } else { - currentTrajectoryWithFitness = trajectoriesToExplore.element(); - // 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); - } - - // Executing new activation - 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.getFitness(); - if (nextFitness.isSatisfiesHardObjectives()) { - dseAdapter.newSolution(); - var solutions = dseAdapter.getSolutions().size(); - if (solutions >= maxSolutions) { - return; - } - // 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 - currentTrajectoryWithFitness = nextTrajectoryWithFitness; - continue mainLoop; - } else if (compare == 0) { - if (onlyBetterFirst) { - // Equally good fitness, backtrack - dseAdapter.backtrack(); - } else { - // Equally good fitness, moving on - currentTrajectoryWithFitness = nextTrajectoryWithFitness; - continue mainLoop; - } - } else { - //"Worse fitness - currentTrajectoryWithFitness = null; - continue mainLoop; - } - } - } - - // State is fully traversed. - currentTrajectoryWithFitness = null; - - } - // Interrupted. - } -} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstWorker.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstWorker.java new file mode 100644 index 00000000..ea7fe43f --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstWorker.java @@ -0,0 +1,113 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.strategy; + +import tools.refinery.store.dse.transition.DesignSpaceExplorationAdapter; +import tools.refinery.store.dse.transition.ObjectiveValue; +import tools.refinery.store.dse.transition.VersionWithObjectiveValue; +import tools.refinery.store.dse.transition.statespace.internal.ActivationStoreWorker; +import tools.refinery.store.map.Version; +import tools.refinery.store.model.Model; +import tools.refinery.store.statecoding.StateCoderAdapter; + + +import java.util.Random; + +public class BestFirstWorker { + final BestFirstStoreManager storeManager; + final Model model; + final ActivationStoreWorker activationStoreWorker; + final StateCoderAdapter stateCoderAdapter; + final DesignSpaceExplorationAdapter explorationAdapter; + + public BestFirstWorker(BestFirstStoreManager storeManager, Model model) { + this.storeManager = storeManager; + this.model = model; + + explorationAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); + stateCoderAdapter = model.getAdapter(StateCoderAdapter.class); + activationStoreWorker = new ActivationStoreWorker(storeManager.getActivationStore(), + explorationAdapter.getTransformations()); + } + + private VersionWithObjectiveValue last = null; + + //public boolean isIncluded + + public SubmitResult submit() { + if (explorationAdapter.checkExclude()) { + last = null; + return new SubmitResult(false, false, null, null); + } + + Version version = model.commit(); + ObjectiveValue objectiveValue = explorationAdapter.getObjectiveValue(); + var res = new VersionWithObjectiveValue(version, objectiveValue); + var code = stateCoderAdapter.calculateStateCode(); + var accepted = explorationAdapter.checkAccept(); + + boolean isNew = storeManager.getEquivalenceClassStore().submit(res, code, + activationStoreWorker.calculateEmptyActivationSize(), accepted); + + last = new VersionWithObjectiveValue(version, objectiveValue); + return new SubmitResult(isNew, accepted, objectiveValue, last); + } + + public void restoreToLast() { + if (explorationAdapter.getModel().hasUncommittedChanges()) { + explorationAdapter.getModel().restore(last.version()); + } + } + + public VersionWithObjectiveValue restoreToBest() { + var bestVersion = storeManager.getObjectiveStore().getBest(); + if (bestVersion != null) { + this.model.restore(bestVersion.version()); + } + return bestVersion; + } + + public VersionWithObjectiveValue restoreToRandom(Random random) { + var randomVersion = storeManager.getObjectiveStore().getRandom(random); + last = randomVersion; + if (randomVersion != null) { + this.model.restore(randomVersion.version()); + } + return randomVersion; + } + + public int compare(VersionWithObjectiveValue s1, VersionWithObjectiveValue s2) { + return storeManager.getObjectiveStore().getComparator().compare(s1, s2); + } + + public boolean stateHasUnvisited() { + if (!model.hasUncommittedChanges()) { + return storeManager.getActivationStore().hasUnmarkedActivation(last); + } else { + throw new IllegalStateException("The model has uncommitted changes!"); + } + } + + record RandomVisitResult(SubmitResult submitResult, boolean shouldRetry) { + } + + public RandomVisitResult visitRandomUnvisited(Random random) { + if (!model.hasUncommittedChanges()) { + var visitResult = activationStoreWorker.fireRandomActivation(this.last, random); + if (visitResult.successfulVisit()) { + return new RandomVisitResult(submit(), visitResult.mayHaveMore()); + } else { + return new RandomVisitResult(null, visitResult.mayHaveMore()); + } + } else { + throw new IllegalStateException("The model has uncommitted changes!"); + } + } + + public boolean hasEnoughSolution() { + return storeManager.solutionStore.hasEnoughSolution(); + } +} 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 deleted file mode 100644 index 0a0caa7e..00000000 --- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/DepthFirstStrategy.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors - * - * SPDX-License-Identifier: EPL-2.0 - */ -package tools.refinery.store.dse.strategy; - -import tools.refinery.store.dse.DesignSpaceExplorationAdapter; -import tools.refinery.store.dse.Strategy; -import tools.refinery.store.dse.objectives.Fitness; - -public class DepthFirstStrategy implements Strategy { - - private DesignSpaceExplorationAdapter dseAdapter; - - private int maxDepth = Integer.MAX_VALUE; - private int maxSolutions = Integer.MAX_VALUE; - private boolean backtrackFromSolution = true; - - public DepthFirstStrategy withDepthLimit(int maxDepth) { - if (maxDepth >= 0) { - this.maxDepth = maxDepth; - } - return this; - } - - public DepthFirstStrategy withSolutionLimit(int maxSolutions) { - if (maxSolutions >= 0) { - this.maxSolutions = maxSolutions; - } - return this; - } - - public DepthFirstStrategy continueIfHardObjectivesFulfilled() { - backtrackFromSolution = false; - return this; - } - - @Override - public void initialize(DesignSpaceExplorationAdapter designSpaceExplorationAdapter) { - this.dseAdapter = designSpaceExplorationAdapter; - } - - @Override - public void explore() { - if (maxSolutions == 0) { - return; - } - while (dseAdapter.getSolutions().size() < maxSolutions) { - if (!checkAndHandleGlobalConstraints()) { - return; - } - - Fitness fitness = dseAdapter.getFitness(); - if (fitness.isSatisfiesHardObjectives()) { - dseAdapter.newSolution(); - if (backtrackFromSolution && !dseAdapter.backtrack()) { - return; - } - } - - if (!checkAndHandleDepth()) { - return; - } - - if (!backtrackToLastUntraversed()) { - return; - } - - if (!dseAdapter.fireRandomActivation()) { - return; - } - } - } - - private boolean checkAndHandleGlobalConstraints() { - return dseAdapter.checkGlobalConstraints() || dseAdapter.backtrack(); - } - - private boolean checkAndHandleDepth() { - return dseAdapter.getDepth() < maxDepth || dseAdapter.backtrack(); - } - - private boolean backtrackToLastUntraversed() { - while (dseAdapter.getUntraversedActivations().isEmpty()) { - if (!dseAdapter.backtrack()) { - return false; - } - } - return true; - } -} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/SubmitResult.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/SubmitResult.java new file mode 100644 index 00000000..37d548d7 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/SubmitResult.java @@ -0,0 +1,14 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.strategy; + +import tools.refinery.store.dse.transition.ObjectiveValue; +import tools.refinery.store.dse.transition.VersionWithObjectiveValue; +import tools.refinery.store.map.Version; + +public record SubmitResult(boolean include, boolean accepted, ObjectiveValue objective, VersionWithObjectiveValue newVersion) { + + } diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/DesignSpaceExplorationAdapter.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/DesignSpaceExplorationAdapter.java new file mode 100644 index 00000000..37448309 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/DesignSpaceExplorationAdapter.java @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition; + +import tools.refinery.store.adapter.ModelAdapter; +import tools.refinery.store.dse.transition.internal.DesignSpaceExplorationBuilderImpl; +import tools.refinery.store.map.Version; +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(); + } + List getTransformations(); + boolean checkAccept(); + boolean checkExclude(); + ObjectiveValue getObjectiveValue(); +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/DesignSpaceExplorationBuilder.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/DesignSpaceExplorationBuilder.java new file mode 100644 index 00000000..3855a20a --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/DesignSpaceExplorationBuilder.java @@ -0,0 +1,59 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition; + +import tools.refinery.store.adapter.ModelAdapterBuilder; +import tools.refinery.store.dse.transition.objectives.Criterion; +import tools.refinery.store.dse.transition.objectives.Objective; + +import java.util.Collection; +import java.util.List; + +public interface DesignSpaceExplorationBuilder extends ModelAdapterBuilder { + + DesignSpaceExplorationBuilder transformation(TransformationRule transformationRuleDefinition); + default DesignSpaceExplorationBuilder transformations(TransformationRule... transformationRuleDefinitions) { + return transformations(List.of(transformationRuleDefinitions)); + } + + default DesignSpaceExplorationBuilder transformations(Collection transformationRules) { + transformationRules.forEach(this::transformation); + return this; + } + + DesignSpaceExplorationBuilder accept(Criterion criteria); + + default DesignSpaceExplorationBuilder accept(Criterion... criteria) { + return accept(List.of(criteria)); + } + + default DesignSpaceExplorationBuilder accept(Collection criteria) { + criteria.forEach(this::accept); + return this; + } + + DesignSpaceExplorationBuilder exclude(Criterion criteria); + + default DesignSpaceExplorationBuilder exclude(Criterion... criteria) { + return exclude(List.of(criteria)); + } + + default DesignSpaceExplorationBuilder exclude(Collection criteria) { + criteria.forEach(this::exclude); + return this; + } + + DesignSpaceExplorationBuilder objective(Objective objective); + + default DesignSpaceExplorationBuilder objectives(Objective... objectives) { + return objectives(List.of(objectives)); + } + + default DesignSpaceExplorationBuilder objectives(Collection objectives) { + objectives.forEach(this::objective); + return this; + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/DesignSpaceExplorationStoreAdapter.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/DesignSpaceExplorationStoreAdapter.java new file mode 100644 index 00000000..5c8c7a4d --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/DesignSpaceExplorationStoreAdapter.java @@ -0,0 +1,27 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition; + +import tools.refinery.store.adapter.ModelStoreAdapter; +import tools.refinery.store.dse.transition.objectives.Criterion; +import tools.refinery.store.dse.transition.objectives.Objective; +import tools.refinery.store.model.Model; + +import java.util.List; + +public interface DesignSpaceExplorationStoreAdapter extends ModelStoreAdapter +{ + @Override + DesignSpaceExplorationAdapter createModelAdapter(Model model); + + List getTransformations(); + + List getAccepts(); + + List getExcludes(); + + List getObjectives(); +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/ObjectiveValue.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/ObjectiveValue.java new file mode 100644 index 00000000..89ee61c8 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/ObjectiveValue.java @@ -0,0 +1,24 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition; + +public interface ObjectiveValue { + double get(int index); + int getSize(); + + static ObjectiveValue of(double v1) { + return new ObjectiveValues.ObjectiveValue1(v1); + } + + static ObjectiveValue of(double v1, double v2) { + return new ObjectiveValues.ObjectiveValue2(v1,v2); + } + + static ObjectiveValue of(double[] v) { + return new ObjectiveValues.ObjectiveValueN(v); + } + +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/ObjectiveValues.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/ObjectiveValues.java new file mode 100644 index 00000000..60913ff3 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/ObjectiveValues.java @@ -0,0 +1,69 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition; + +import java.util.Arrays; + +public interface ObjectiveValues { + public record ObjectiveValue1(double value0) implements ObjectiveValue { + @Override + public double get(int index) { + if(index == 0) return value0; + else throw new IllegalArgumentException("No value at " + index); + } + + @Override + public int getSize() { + return 1; + } + } + public record ObjectiveValue2(double value0, double value1) implements ObjectiveValue { + @Override + public double get(int index) { + if(index == 0) return value0; + else if(index == 1) return value1; + else throw new IllegalArgumentException("No value at " + index); + } + + @Override + public int getSize() { + return 2; + } + } + public record ObjectiveValueN(double[] values) implements ObjectiveValue { + @Override + public double get(int index) { + return values[index]; + } + + @Override + public int getSize() { + return values().length; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ObjectiveValueN that = (ObjectiveValueN) o; + + return Arrays.equals(values, that.values); + } + + @Override + public int hashCode() { + return Arrays.hashCode(values); + } + + @Override + public String toString() { + return "ObjectiveValueN{" + + "values=" + Arrays.toString(values) + + '}'; + } + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/Transformation.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/Transformation.java new file mode 100644 index 00000000..2cce738f --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/Transformation.java @@ -0,0 +1,43 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition; + +import org.eclipse.collections.api.block.procedure.Procedure; +import tools.refinery.store.query.resultset.OrderedResultSet; +import tools.refinery.store.query.resultset.ResultSet; +import tools.refinery.store.tuple.Tuple; + +public class Transformation { + private final TransformationRule definition; + + private final OrderedResultSet activations; + + private final Procedure action; + + public Transformation(TransformationRule definition, OrderedResultSet activations, Procedure action) { + this.definition = definition; + this.activations = activations; + this.action = action; + } + + public TransformationRule getDefinition() { + return definition; + } + + public ResultSet getAllActivationsAsResultSet() { + return activations; + } + + public Tuple getActivation(int index) { + return activations.getKey(index); + } + + public boolean fireActivation(Tuple activation) { + action.accept(activation); + //queryEngine.flushChanges(); + return true; + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/TransformationRule.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/TransformationRule.java new file mode 100644 index 00000000..d64a3db1 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/TransformationRule.java @@ -0,0 +1,63 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition; + +import tools.refinery.store.model.Model; +import tools.refinery.store.model.ModelStoreBuilder; +import tools.refinery.store.query.ModelQueryAdapter; +import tools.refinery.store.query.ModelQueryBuilder; +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.*; + +public class TransformationRule { + + private final String name; + private final RelationalQuery precondition; + private final ActionFactory actionFactory; + + 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 void doConfigure(ModelStoreBuilder storeBuilder) { + var queryBuilder = storeBuilder.getAdapter(ModelQueryBuilder.class); + queryBuilder.query(this.precondition); + } + + public Transformation prepare(Model model) { + var queryEngine = model.getAdapter(ModelQueryAdapter.class); + var activations = new OrderedResultSet<>(queryEngine.getResultSet(precondition)); + var action = actionFactory.prepare(model); + return new Transformation(this,activations,action); + } + + public String getName() { + return name; + } + + public RelationalQuery getPrecondition() { + return precondition; + } + +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/VersionWithObjectiveValue.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/VersionWithObjectiveValue.java new file mode 100644 index 00000000..ca28e27f --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/VersionWithObjectiveValue.java @@ -0,0 +1,11 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition; + +import tools.refinery.store.map.Version; + +public record VersionWithObjectiveValue(Version version, ObjectiveValue objectiveValue) { +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/internal/DesignSpaceExplorationAdapterImpl.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/internal/DesignSpaceExplorationAdapterImpl.java new file mode 100644 index 00000000..e1a29d40 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/internal/DesignSpaceExplorationAdapterImpl.java @@ -0,0 +1,90 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition.internal; + +import tools.refinery.store.dse.transition.DesignSpaceExplorationAdapter; +import tools.refinery.store.dse.transition.DesignSpaceExplorationStoreAdapter; +import tools.refinery.store.dse.transition.ObjectiveValue; +import tools.refinery.store.dse.transition.Transformation; +import tools.refinery.store.dse.transition.objectives.CriterionCalculator; +import tools.refinery.store.dse.transition.objectives.ObjectiveCalculator; +import tools.refinery.store.model.Model; + +import java.util.List; + +public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExplorationAdapter { + final Model model; + final DesignSpaceExplorationStoreAdapter designSpaceExplorationStoreAdapter; + + final List transformations; + final List accepts; + final List excludes; + final List objectives; + + public DesignSpaceExplorationAdapterImpl(Model model, + DesignSpaceExplorationStoreAdapter designSpaceExplorationStoreAdapter, + List transformations, + List accepts, + List excludes, + List objectives) { + this.model = model; + this.designSpaceExplorationStoreAdapter = designSpaceExplorationStoreAdapter; + + this.transformations = transformations; + this.accepts = accepts; + this.excludes = excludes; + this.objectives = objectives; + } + + @Override + public Model getModel() { + return model; + } + + @Override + public DesignSpaceExplorationStoreAdapter getStoreAdapter() { + return designSpaceExplorationStoreAdapter; + } + + public List getTransformations() { + return transformations; + } + + @Override + public boolean checkAccept() { + for (var accept : this.accepts) { + if (!accept.isSatisfied()) { + return false; + } + } + return true; + } + + @Override + public boolean checkExclude() { + for (var exclude : this.excludes) { + if (exclude.isSatisfied()) { + return true; + } + } + return false; + } + + @Override + public ObjectiveValue getObjectiveValue() { + if (objectives.size() == 1) { + return ObjectiveValue.of(objectives.get(0).getValue()); + } else if (objectives.size() == 2) { + return ObjectiveValue.of(objectives.get(0).getValue(), objectives.get(1).getValue()); + } else { + double[] res = new double[objectives.size()]; + for (int i = 0; i < objectives.size(); i++) { + res[i] = objectives.get(i).getValue(); + } + return ObjectiveValue.of(res); + } + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/internal/DesignSpaceExplorationBuilderImpl.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/internal/DesignSpaceExplorationBuilderImpl.java new file mode 100644 index 00000000..4371cc03 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/internal/DesignSpaceExplorationBuilderImpl.java @@ -0,0 +1,75 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition.internal; + +import tools.refinery.store.adapter.AbstractModelAdapterBuilder; +import tools.refinery.store.dse.transition.DesignSpaceExplorationBuilder; +import tools.refinery.store.dse.transition.TransformationRule; +import tools.refinery.store.dse.transition.objectives.Criterion; +import tools.refinery.store.dse.transition.objectives.Objective; +import tools.refinery.store.model.ModelStore; +import tools.refinery.store.model.ModelStoreBuilder; + +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; + +public class DesignSpaceExplorationBuilderImpl + extends AbstractModelAdapterBuilder + implements DesignSpaceExplorationBuilder { + + LinkedHashSet transformationRuleDefinitions = new LinkedHashSet<>(); + LinkedHashSet accepts = new LinkedHashSet<>(); + LinkedHashSet excludes = new LinkedHashSet<>(); + LinkedHashSet objectives = new LinkedHashSet<>(); + + @Override + public DesignSpaceExplorationBuilder transformation(TransformationRule transformationRuleDefinition) { + transformationRuleDefinitions.add(transformationRuleDefinition); + return this; + } + + @Override + public DesignSpaceExplorationBuilder accept(Criterion criteria) { + accepts.add(criteria); + return this; + } + + @Override + public DesignSpaceExplorationBuilder exclude(Criterion criteria) { + excludes.add(criteria); + return this; + } + + + @Override + public DesignSpaceExplorationBuilder objective(Objective objective) { + objectives.add(objective); + return this; + } + + @Override + protected void doConfigure(ModelStoreBuilder storeBuilder) { + transformationRuleDefinitions.forEach(x -> x.doConfigure(storeBuilder)); + accepts.forEach(x -> x.doConfigure(storeBuilder)); + excludes.forEach(x -> x.doConfigure(storeBuilder)); + objectives.forEach(x -> x.doConfigure(storeBuilder)); + + super.doConfigure(storeBuilder); + } + + @Override + protected DesignSpaceExplorationStoreAdapterImpl doBuild(ModelStore store) { + List transformationRuleDefinitiions1 = new ArrayList<>(transformationRuleDefinitions); + List accepts1 = new ArrayList<>(accepts); + List excludes1 = new ArrayList<>(excludes); + List objectives1 = new ArrayList<>(objectives); + + return new DesignSpaceExplorationStoreAdapterImpl(store, + transformationRuleDefinitiions1, accepts1, + excludes1, objectives1); + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/internal/DesignSpaceExplorationStoreAdapterImpl.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/internal/DesignSpaceExplorationStoreAdapterImpl.java new file mode 100644 index 00000000..3319e148 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/internal/DesignSpaceExplorationStoreAdapterImpl.java @@ -0,0 +1,70 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition.internal; + +import tools.refinery.store.dse.transition.DesignSpaceExplorationStoreAdapter; +import tools.refinery.store.dse.transition.Transformation; +import tools.refinery.store.dse.transition.TransformationRule; +import tools.refinery.store.dse.transition.objectives.Criterion; +import tools.refinery.store.dse.transition.objectives.CriterionCalculator; +import tools.refinery.store.dse.transition.objectives.Objective; +import tools.refinery.store.dse.transition.objectives.ObjectiveCalculator; +import tools.refinery.store.model.Model; +import tools.refinery.store.model.ModelStore; + +import java.util.List; + +public class DesignSpaceExplorationStoreAdapterImpl implements DesignSpaceExplorationStoreAdapter { + protected final ModelStore store; + + protected final List transformationRuleDefinitions; + protected final List accepts; + protected final List excludes; + protected final List objectives; + + public DesignSpaceExplorationStoreAdapterImpl(ModelStore store, + List transformationRuleDefinitions, + List accepts, List excludes, + List objectives) { + this.store = store; + + this.transformationRuleDefinitions = transformationRuleDefinitions; + this.accepts = accepts; + this.excludes = excludes; + this.objectives = objectives; + } + + @Override + public ModelStore getStore() { + return store; + } + + @Override + public DesignSpaceExplorationAdapterImpl createModelAdapter(Model model) { + final List t = this.transformationRuleDefinitions.stream().map(x->x.prepare(model)).toList(); + final List a = this.accepts.stream().map(x->x.createCalculator(model)).toList(); + final List e = this.excludes.stream().map(x->x.createCalculator(model)).toList(); + final List o = this.objectives.stream().map(x->x.createCalculator(model)).toList(); + + return new DesignSpaceExplorationAdapterImpl(model, this, t, a, e, o); + } + @Override + public List getTransformations() { + return transformationRuleDefinitions; + } + @Override + public List getAccepts() { + return accepts; + } + @Override + public List getExcludes() { + return excludes; + } + @Override + public List getObjectives() { + return objectives; + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/Criterion.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/Criterion.java new file mode 100644 index 00000000..66ca6f5e --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/Criterion.java @@ -0,0 +1,15 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition.objectives; + +import tools.refinery.store.model.Model; +import tools.refinery.store.model.ModelStoreBuilder; + +public interface Criterion { + default void doConfigure(ModelStoreBuilder storeBuilder) { + } + CriterionCalculator createCalculator(Model model); +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/CriterionCalculator.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/CriterionCalculator.java new file mode 100644 index 00000000..944ffed6 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/CriterionCalculator.java @@ -0,0 +1,10 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition.objectives; + +public interface CriterionCalculator { + boolean isSatisfied(); +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/Objective.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/Objective.java new file mode 100644 index 00000000..b5924455 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/Objective.java @@ -0,0 +1,15 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition.objectives; + +import tools.refinery.store.model.Model; +import tools.refinery.store.model.ModelStoreBuilder; + +public interface Objective { + default void doConfigure(ModelStoreBuilder storeBuilder) { + } + ObjectiveCalculator createCalculator(Model model); +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/ObjectiveCalculator.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/ObjectiveCalculator.java new file mode 100644 index 00000000..f01b8de9 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/ObjectiveCalculator.java @@ -0,0 +1,10 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition.objectives; + +public interface ObjectiveCalculator { + double getValue(); +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/QueryCriteria.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/QueryCriteria.java new file mode 100644 index 00000000..e2260cca --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/QueryCriteria.java @@ -0,0 +1,44 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition.objectives; + +import tools.refinery.store.model.Model; +import tools.refinery.store.model.ModelStoreBuilder; +import tools.refinery.store.query.ModelQueryAdapter; +import tools.refinery.store.query.ModelQueryBuilder; +import tools.refinery.store.query.dnf.AnyQuery; + +public class QueryCriteria implements Criterion { + protected final boolean acceptIfHasMatch; + protected final AnyQuery query; + + /** + * Criteria based on the existence of matches evaluated on the model. + * @param query The query evaluated on the model. + * @param acceptIfHasMatch If true, the criteria satisfied if the query has any match on the model. Otherwise, + * the criteria satisfied if the query has no match on the model. + */ + public QueryCriteria(AnyQuery query, boolean acceptIfHasMatch) { + this.query = query; + this.acceptIfHasMatch = acceptIfHasMatch; + } + + @Override + public CriterionCalculator createCalculator(Model model) { + var resultSet = model.getAdapter(ModelQueryAdapter.class).getResultSet(query); + if(acceptIfHasMatch) { + return () -> resultSet.size() > 0; + } else { + return () -> resultSet.size() == 0; + } + } + + @Override + public void doConfigure(ModelStoreBuilder storeBuilder) { + Criterion.super.doConfigure(storeBuilder); + storeBuilder.getAdapter(ModelQueryBuilder.class).query(query); + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/QueryObjective.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/QueryObjective.java new file mode 100644 index 00000000..dfddccfc --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/QueryObjective.java @@ -0,0 +1,44 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition.objectives; + +import tools.refinery.store.model.Model; +import tools.refinery.store.model.ModelStoreBuilder; +import tools.refinery.store.query.ModelQueryAdapter; +import tools.refinery.store.query.ModelQueryBuilder; +import tools.refinery.store.query.dnf.FunctionalQuery; + +public class QueryObjective implements Objective { + protected final FunctionalQuery objectiveFunction; + + public QueryObjective(FunctionalQuery objectiveFunction) { + this.objectiveFunction = objectiveFunction; + } + + @Override + public ObjectiveCalculator createCalculator(Model model) { + var resultSet = model.getAdapter(ModelQueryAdapter.class).getResultSet(objectiveFunction); + return () -> { + var cursor = resultSet.getAll(); + boolean hasElement = cursor.move(); + if(hasElement) { + double result = cursor.getValue().doubleValue(); + if(cursor.move()) { + throw new IllegalStateException("Query providing the objective function has multiple values!"); + } + return result; + } else { + throw new IllegalStateException("Query providing the objective function has no values!"); + } + }; + } + + @Override + public void doConfigure(ModelStoreBuilder storeBuilder) { + Objective.super.doConfigure(storeBuilder); + storeBuilder.getAdapter(ModelQueryBuilder.class).query(objectiveFunction); + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/ActivationStore.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/ActivationStore.java new file mode 100644 index 00000000..52e0611d --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/ActivationStore.java @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition.statespace; + +import tools.refinery.store.dse.transition.VersionWithObjectiveValue; +import tools.refinery.store.map.Version; + +import java.util.Random; + +public interface ActivationStore { + record VisitResult(boolean successfulVisit, boolean mayHaveMore, int transformation, int activation) { } + VisitResult markNewAsVisited(VersionWithObjectiveValue to, int[] emptyEntrySizes); + boolean hasUnmarkedActivation(VersionWithObjectiveValue version); + VisitResult getRandomAndMarkAsVisited(VersionWithObjectiveValue version, Random random); +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/EquivalenceClassStore.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/EquivalenceClassStore.java new file mode 100644 index 00000000..bbe26fe5 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/EquivalenceClassStore.java @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition.statespace; + +import tools.refinery.store.dse.transition.VersionWithObjectiveValue; +import tools.refinery.store.statecoding.StateCoderResult; + +public interface EquivalenceClassStore { + boolean submit(VersionWithObjectiveValue version, StateCoderResult stateCoderResult, int[] emptyActivations, boolean accept); + boolean hasUnresolvedSymmetry(); + void resolveOneSymmetry(); + int getNumberOfUnresolvedSymmetries(); +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/ObjectivePriorityQueue.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/ObjectivePriorityQueue.java new file mode 100644 index 00000000..df72c343 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/ObjectivePriorityQueue.java @@ -0,0 +1,21 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition.statespace; + +import tools.refinery.store.dse.transition.VersionWithObjectiveValue; +import tools.refinery.store.map.Version; + +import java.util.Comparator; +import java.util.Random; + +public interface ObjectivePriorityQueue { + Comparator getComparator(); + void submit(VersionWithObjectiveValue versionWithObjectiveValue); + void remove(VersionWithObjectiveValue versionWithObjectiveValue); + int getSize(); + VersionWithObjectiveValue getBest(); + VersionWithObjectiveValue getRandom(Random random); +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/SolutionStore.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/SolutionStore.java new file mode 100644 index 00000000..d1bfaa79 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/SolutionStore.java @@ -0,0 +1,17 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition.statespace; + +import tools.refinery.store.dse.transition.VersionWithObjectiveValue; + +import java.util.List; +import java.util.concurrent.Future; + +public interface SolutionStore { + boolean submit(VersionWithObjectiveValue version); + List getSolutions(); + boolean hasEnoughSolution(); +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/AbstractEquivalenceClassStore.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/AbstractEquivalenceClassStore.java new file mode 100644 index 00000000..8466a0f3 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/AbstractEquivalenceClassStore.java @@ -0,0 +1,47 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition.statespace.internal; + +import tools.refinery.store.dse.transition.VersionWithObjectiveValue; +import tools.refinery.store.dse.transition.statespace.EquivalenceClassStore; +import tools.refinery.store.statecoding.StateCoderResult; +import tools.refinery.store.statecoding.StateCoderStoreAdapter; + +public abstract class AbstractEquivalenceClassStore implements EquivalenceClassStore { + protected final StateCoderStoreAdapter stateCoderStoreAdapter; + AbstractEquivalenceClassStore(StateCoderStoreAdapter stateCoderStoreAdapter) { + this.stateCoderStoreAdapter = stateCoderStoreAdapter; + } + + protected int numberOfUnresolvedSymmetries = 0; + + protected abstract void delegate(VersionWithObjectiveValue version, int[] emptyActivations, boolean accept); + protected abstract boolean tryToAdd(StateCoderResult stateCoderResult, VersionWithObjectiveValue newVersion, + int[] emptyActivations, boolean accept); + + @Override + public synchronized boolean submit(VersionWithObjectiveValue version, StateCoderResult stateCoderResult, + int[] emptyActivations, boolean accept) { + boolean hasNewVersion = tryToAdd(stateCoderResult, version, emptyActivations, accept); + if (hasNewVersion) { + delegate(version, emptyActivations, accept); + return true; + } else { + numberOfUnresolvedSymmetries++; + return false; + } + } + + @Override + public boolean hasUnresolvedSymmetry() { + return numberOfUnresolvedSymmetries > 0; + } + + @Override + public int getNumberOfUnresolvedSymmetries() { + return numberOfUnresolvedSymmetries; + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreBitVectorEntry.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreBitVectorEntry.java new file mode 100644 index 00000000..ba243d7d --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreBitVectorEntry.java @@ -0,0 +1,46 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition.statespace.internal; + +public class ActivationStoreBitVectorEntry extends ActivationStoreEntry { + final int[] selected; + + ActivationStoreBitVectorEntry(int numberOfActivations) { + super(numberOfActivations); + this.selected = new int[(numberOfActivations / Integer.SIZE) + 1]; + } + + @Override + public int getNumberOfUnvisitedActivations() { + int visited = 0; + for (int i : selected) { + visited += Integer.bitCount(i); + } + return visited; + } + + private static final int ELEMENT_POSITION = 5; // size of Integer.SIZE + private static final int ELEMENT_BITMASK = (1<> ELEMENT_POSITION; + final int selectedBit = position & ELEMENT_BITMASK; + if((selected[selectedElement] & selectedBit) == 0) { + selected[selectedElement] |= selectedBit; + return position; + } else { + if(position < this.numberOfActivations) { + position++; + } else { + position = 0; + } + } + } while(position != index); + throw new IllegalArgumentException("There is are no unvisited activations!"); + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreEntry.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreEntry.java new file mode 100644 index 00000000..f69b234c --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreEntry.java @@ -0,0 +1,32 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition.statespace.internal; + +public abstract class ActivationStoreEntry { + protected final int numberOfActivations; + + ActivationStoreEntry(int numberOfActivations) { + this.numberOfActivations = numberOfActivations; + } + + public int getNumberOfVisitedActivations() { + return numberOfActivations; + } + + public abstract int getNumberOfUnvisitedActivations(); + public abstract int getAndAddActivationAfter(int index); + + // public abstract boolean contains(int activation) + // public abstract boolean add(int activation) + + public static ActivationStoreEntry create(int size) { + if(size <= Integer.SIZE*6) { + return new ActivationStoreBitVectorEntry(size); + } else { + return new ActivationStoreListEntry(size); + } + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreImpl.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreImpl.java new file mode 100644 index 00000000..1229ec15 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreImpl.java @@ -0,0 +1,131 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition.statespace.internal; + +import org.eclipse.collections.api.block.procedure.Procedure; +import tools.refinery.store.dse.transition.VersionWithObjectiveValue; +import tools.refinery.store.dse.transition.statespace.ActivationStore; + +import java.util.*; + +public class ActivationStoreImpl implements ActivationStore { + final int numberOfTransformations; + final Procedure actionWhenAllActivationVisited; + final Map> versionToActivations; + + public ActivationStoreImpl(final int numberOfTransformations, + Procedure actionWhenAllActivationVisited) { + this.numberOfTransformations = numberOfTransformations; + this.actionWhenAllActivationVisited = actionWhenAllActivationVisited; + versionToActivations = new HashMap<>(); + } + + public synchronized VisitResult markNewAsVisited(VersionWithObjectiveValue to, int[] emptyEntrySizes) { + boolean[] successful = new boolean[]{false}; + var entries = versionToActivations.computeIfAbsent(to, x -> { + successful[0] = true; + List result = new ArrayList<>(emptyEntrySizes.length); + for(int emptyEntrySize : emptyEntrySizes) { + result.add(ActivationStoreListEntry.create(emptyEntrySize)); + } + return result; + }); + boolean hasMore = false; + for (var entry : entries) { + if (entry.getNumberOfUnvisitedActivations() > 0) { + hasMore = true; + break; + } + } + if(!hasMore) { + actionWhenAllActivationVisited.accept(to); + } + return new VisitResult(successful[0], hasMore, -1, -1); + } + + public synchronized VisitResult visitActivation(VersionWithObjectiveValue from, int transformationIndex, int activationIndex) { + var entries = versionToActivations.get(from); + var entry = entries.get(transformationIndex); + final int unvisited = entry.getNumberOfUnvisitedActivations(); + + final boolean successfulVisit = unvisited > 0; + final boolean hasMoreInActivation = unvisited > 1; + final boolean hasMore; + final int transformation; + final int activation; + + if (successfulVisit) { + transformation = transformationIndex; + activation = entry.getAndAddActivationAfter(activationIndex); + + } else { + transformation = -1; + activation = -1; + } + + if(hasMoreInActivation) { + boolean hasMoreInOtherTransformation = false; + for (var e : entries) { + if (e != entry && e.getNumberOfVisitedActivations() > 0) { + hasMoreInOtherTransformation = true; + break; + } + } + hasMore = hasMoreInOtherTransformation; + } else { + hasMore = true; + } + + if(!hasMore) { + actionWhenAllActivationVisited.accept(from); + } + + return new VisitResult(false, hasMore, transformation, activation); + } + + @Override + public synchronized boolean hasUnmarkedActivation(VersionWithObjectiveValue version) { + var entries = versionToActivations.get(version); + boolean hasMore = false; + for (var entry : entries) { + if (entry.getNumberOfUnvisitedActivations() > 0) { + hasMore = true; + break; + } + } + return hasMore; + } + + @Override + public synchronized VisitResult getRandomAndMarkAsVisited(VersionWithObjectiveValue version, Random random) { + var entries = versionToActivations.get(version); + + int sum1 = 0; + for (var entry : entries) { + sum1 += entry.getNumberOfUnvisitedActivations(); + } + + int selected = random.nextInt(sum1); + int sum2 = 0; + int transformation = 0; + int activation = -1; + for (; transformation < entries.size(); transformation++) { + var entry = entries.get(transformation); + int unvisited = entry.getNumberOfUnvisitedActivations(); + if (selected < sum2 + unvisited) { + activation = sum2 + unvisited - selected; + break; + } else { + sum2 += unvisited; + } + } + if (activation == -1) { + throw new IllegalArgumentException("no unvisited"); + } + + return this.visitActivation(version, transformation, activation); + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreListEntry.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreListEntry.java new file mode 100644 index 00000000..9e25301f --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreListEntry.java @@ -0,0 +1,95 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition.statespace.internal; + +import org.eclipse.collections.impl.list.mutable.primitive.IntArrayList; + +public class ActivationStoreListEntry extends ActivationStoreEntry { + IntArrayList visitedActivations; + + ActivationStoreListEntry(int numberOfActivations) { + super(numberOfActivations); + visitedActivations = new IntArrayList(); + } + + @Override + public int getNumberOfUnvisitedActivations() { + return this.numberOfActivations - visitedActivations.size(); + } + + @Override + public int getAndAddActivationAfter(int index) { + // If it is empty, just add it. + if(this.visitedActivations.isEmpty()) { + this.visitedActivations.add(index); + return index; + } + + int position = getPosition(index); + + // If the index is not in the position, one can insert it + if(this.visitedActivations.get(position) != index) { + this.visitedActivations.addAtIndex(position,index); + return index; + } + + // Otherwise, get the next empty space between two elements + while(position + 2 < this.visitedActivations.size()) { + position++; + if(this.visitedActivations.get(position+1)-this.visitedActivations.get(position) > 1) { + this.visitedActivations.addAtIndex(position+1, this.visitedActivations.get(position+1)+1); + } + } + + // Otherwise, try to add to the last space + int last = this.visitedActivations.get(this.visitedActivations.size()-1); + if(last 0) { + this.visitedActivations.add(0); + return 0; + } + + // Otherwise, get the next empty space between two elements + position = 0; + while(position + 2 < this.visitedActivations.size()) { + position++; + if(this.visitedActivations.get(position+1)-this.visitedActivations.get(position) > 1) { + this.visitedActivations.addAtIndex(position+1, this.visitedActivations.get(position+1)+1); + } + } + + throw new IllegalArgumentException("There is are no unvisited activations!"); + } + + /** + * Returns the position of an index in the {@code visitedActivations}. If the collection contains the index, in + * returns its position, otherwise, it returns the position where the index need to be put. + * + * @param index Index of an activation. + * @return The position of the index. + */ + private int getPosition(int index) { + int left = 0; + int right = this.visitedActivations.size() - 1; + while (left <= right) { + final int middle = (right - left) / 2 + left; + final int middleElement = visitedActivations.get(middle); + if(middleElement == index) { + return middle; + } else if(middleElement < index) { + left = middle +1; + } else{ + right = middle-1; + } + } + return right+1; + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreWorker.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreWorker.java new file mode 100644 index 00000000..e05f5122 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreWorker.java @@ -0,0 +1,56 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition.statespace.internal; + +import tools.refinery.store.dse.transition.Transformation; +import tools.refinery.store.dse.transition.VersionWithObjectiveValue; +import tools.refinery.store.dse.transition.statespace.ActivationStore; +import tools.refinery.store.map.Version; + +import java.util.List; +import java.util.Random; + +public class ActivationStoreWorker { + final ActivationStore store; + final List transformations; + + public ActivationStoreWorker(ActivationStore store, List transformations) { + this.store = store; + this.transformations = transformations; + } + + public int[] calculateEmptyActivationSize() { + int[] result = new int[transformations.size()]; + for (int i = 0; i < result.length; i++) { + result[i] = transformations.get(i).getAllActivationsAsResultSet().size(); + } + return result; + } + + + public ActivationStore.VisitResult fireRandomActivation(VersionWithObjectiveValue thisVersion, Random random) { + var result = store.getRandomAndMarkAsVisited(thisVersion, random); + if(result.successfulVisit()) { + int selectedTransformation = result.transformation(); + int selectedActivation = result.activation(); + + Transformation transformation = transformations.get(selectedTransformation); + var tuple = transformation.getActivation(selectedActivation); + + boolean success = transformation.fireActivation(tuple); + if(success) { + return result; + } else { + return new ActivationStore.VisitResult( + false, + result.mayHaveMore(), + selectedActivation, + selectedActivation); + } + } + return result; + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/CompleteEquivalenceClassStore.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/CompleteEquivalenceClassStore.java new file mode 100644 index 00000000..1555c3be --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/CompleteEquivalenceClassStore.java @@ -0,0 +1,107 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition.statespace.internal; + +import org.eclipse.collections.impl.map.mutable.primitive.IntObjectHashMap; +import tools.refinery.store.dse.transition.VersionWithObjectiveValue; +import tools.refinery.store.dse.transition.statespace.ActivationStore; +import tools.refinery.store.dse.transition.statespace.ObjectivePriorityQueue; +import tools.refinery.store.dse.transition.statespace.SolutionStore; +import tools.refinery.store.dse.transition.statespace.EquivalenceClassStore; +import tools.refinery.store.statecoding.StateCoderResult; +import tools.refinery.store.statecoding.StateCoderStoreAdapter; +import tools.refinery.store.statecoding.StateEquivalenceChecker; + +import java.util.ArrayList; + +public abstract class CompleteEquivalenceClassStore extends AbstractEquivalenceClassStore implements EquivalenceClassStore { + + static class SymmetryStoreArray extends ArrayList { + final int[] activationSizes; + final boolean accept; + + SymmetryStoreArray(int[] activationSizes, boolean accept) { + super(); + this.activationSizes = activationSizes; + this.accept = accept; + } + } + + final IntObjectHashMap modelCode2Versions; + + protected CompleteEquivalenceClassStore(StateCoderStoreAdapter stateCoderStoreAdapter) { + super(stateCoderStoreAdapter); + this.modelCode2Versions = new IntObjectHashMap<>(); + } + + @Override + protected boolean tryToAdd(StateCoderResult stateCoderResult, VersionWithObjectiveValue newVersion, + int[] emptyActivations, boolean accept) { + int modelCode = stateCoderResult.modelCode(); + Object old = modelCode2Versions.updateValue( + modelCode, + () -> newVersion, + x -> { + if (x instanceof SymmetryStoreArray array) { + if(array.accept != accept || array.activationSizes != emptyActivations) { + this.delegate(newVersion,emptyActivations,accept); + return x; + } + array.add(newVersion); + return array; + } else { + SymmetryStoreArray result = new SymmetryStoreArray(emptyActivations, accept); + result.add((VersionWithObjectiveValue) x); + result.add(newVersion); + return result; + } + }); + return old == null; + } + + @Override + public void resolveOneSymmetry() { + var unresolvedSimilarity = getOneUnresolvedSymmetry(); + if (unresolvedSimilarity == null) { + return; + } + var outcome = this.stateCoderStoreAdapter.checkEquivalence(unresolvedSimilarity.get(0), + unresolvedSimilarity.get(1)); + if (outcome != StateEquivalenceChecker.EquivalenceResult.ISOMORPHIC) { + delegate(unresolvedSimilarity.get(1), unresolvedSimilarity.activationSizes, unresolvedSimilarity.accept); + } + } + + //record UnresolvedSymmetryResult + + private synchronized SymmetryStoreArray getOneUnresolvedSymmetry() { + if (numberOfUnresolvedSymmetries <= 0) { + return null; + } + + for (var entry : modelCode2Versions.keyValuesView()) { + int hash = entry.getOne(); + var value = entry.getTwo(); + if (value instanceof SymmetryStoreArray array) { + int size = array.size(); + var representative = array.get(0); + var similar = array.get(size - 1); + array.remove(size - 1); + + if (size <= 2) { + modelCode2Versions.put(hash, representative); + } + + var result = new SymmetryStoreArray(array.activationSizes, array.accept); + result.add(representative); + result.add(similar); + return result; + } + } + + return null; + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/FastEquivalenceClassStore.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/FastEquivalenceClassStore.java new file mode 100644 index 00000000..75e117c0 --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/FastEquivalenceClassStore.java @@ -0,0 +1,32 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition.statespace.internal; + +import org.eclipse.collections.impl.set.mutable.primitive.IntHashSet; +import tools.refinery.store.dse.transition.VersionWithObjectiveValue; +import tools.refinery.store.dse.transition.statespace.EquivalenceClassStore; +import tools.refinery.store.statecoding.StateCoderResult; +import tools.refinery.store.statecoding.StateCoderStoreAdapter; + +public abstract class FastEquivalenceClassStore extends AbstractEquivalenceClassStore implements EquivalenceClassStore { + + final IntHashSet codes; + + public FastEquivalenceClassStore(StateCoderStoreAdapter stateCoderStoreAdapter) { + super(stateCoderStoreAdapter); + this.codes = new IntHashSet(); + } + + @Override + protected boolean tryToAdd(StateCoderResult stateCoderResult, VersionWithObjectiveValue newVersion, int[] emptyActivations, boolean accept) { + return this.codes.add(stateCoderResult.modelCode()); + } + + @Override + public void resolveOneSymmetry() { + throw new IllegalArgumentException("This equivalence storage is not prepared to resolve symmetries!"); + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ObjectivePriorityQueueImpl.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ObjectivePriorityQueueImpl.java new file mode 100644 index 00000000..249b22da --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ObjectivePriorityQueueImpl.java @@ -0,0 +1,74 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition.statespace.internal; + +import tools.refinery.store.dse.transition.ObjectiveValues; +import tools.refinery.store.dse.transition.VersionWithObjectiveValue; +import tools.refinery.store.dse.transition.objectives.Objective; +import tools.refinery.store.dse.transition.statespace.ObjectivePriorityQueue; +import tools.refinery.store.map.Version; + +import java.util.Comparator; +import java.util.List; +import java.util.PriorityQueue; +import java.util.Random; + +public class ObjectivePriorityQueueImpl implements ObjectivePriorityQueue { + public static final Comparator c1 = (o1, o2) -> Double.compare( + ((ObjectiveValues.ObjectiveValue1) o1.objectiveValue()).value0(), + ((ObjectiveValues.ObjectiveValue1) o2.objectiveValue()).value0()); + // TODO: support multi objective! + final PriorityQueue priorityQueue; + + public ObjectivePriorityQueueImpl(List objectives) { + + if(objectives.size() == 1) { + this.priorityQueue = new PriorityQueue<>(c1); + } else { + throw new UnsupportedOperationException("Only single objective comparator is implemented currently!"); + } + } + @Override + public Comparator getComparator() { + return c1; + } + + @Override + public void submit(VersionWithObjectiveValue versionWithObjectiveValue) { + priorityQueue.add(versionWithObjectiveValue); + } + + @Override + public void remove(VersionWithObjectiveValue versionWithObjectiveValue) { + priorityQueue.remove(versionWithObjectiveValue); + } + + @Override + public int getSize() { + return priorityQueue.size(); + } + + @Override + public VersionWithObjectiveValue getBest() { + var best = priorityQueue.peek(); + if (best != null) { + return best; + } else { + throw new IllegalArgumentException("The objective store is empty!"); + } + } + + @Override + public VersionWithObjectiveValue getRandom(Random random) { + int randomPosition = random.nextInt(getSize()); + for (VersionWithObjectiveValue entry : this.priorityQueue) { + if (randomPosition-- == 0) { + return entry; + } + } + throw new IllegalStateException("The priority queue is inconsistent!"); + } +} diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/SolutionStoreImpl.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/SolutionStoreImpl.java new file mode 100644 index 00000000..cc48864f --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/SolutionStoreImpl.java @@ -0,0 +1,53 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition.statespace.internal; + +import tools.refinery.store.dse.transition.VersionWithObjectiveValue; +import tools.refinery.store.dse.transition.statespace.SolutionStore; + +import java.util.ArrayList; +import java.util.List; +import java.util.SortedSet; +import java.util.TreeSet; + +public class SolutionStoreImpl implements SolutionStore { + final int maxNumberSolutions; + public static final int UNLIMITED = -1; + final SortedSet solutions; + + public SolutionStoreImpl(int maxNumberSolutions) { + this.maxNumberSolutions = maxNumberSolutions; + solutions = new TreeSet<>(ObjectivePriorityQueueImpl.c1); + } + + + @Override + public synchronized boolean submit(VersionWithObjectiveValue version) { + boolean removeLast = hasEnoughSolution(); + solutions.add(version); + if(removeLast) { + var last = solutions.last(); + solutions.remove(last); + return last != version; + } else { + return true; + } + } + + @Override + public List getSolutions() { + return new ArrayList<>(solutions); + } + + @Override + public boolean hasEnoughSolution() { + if (maxNumberSolutions == UNLIMITED) { + return false; + } else { + return solutions.size() >= maxNumberSolutions; + } + } +} 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 index 225de32e..b0b416e1 100644 --- 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 @@ -8,13 +8,13 @@ package tools.refinery.store.dse; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import tools.refinery.store.dse.objectives.AlwaysSatisfiedRandomHardObjective; +import tools.refinery.store.dse.transition.DesignSpaceExplorationAdapter; 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.transition.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; @@ -282,5 +282,5 @@ class CRAExamplesTest { var states = dseAdapter.explore(); System.out.println("states size: " + states.size()); } - +*/ } 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 index c6da896c..461d9353 100644 --- 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 @@ -8,11 +8,11 @@ package tools.refinery.store.dse; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import tools.refinery.store.dse.objectives.AlwaysSatisfiedRandomHardObjective; +import tools.refinery.store.dse.transition.DesignSpaceExplorationAdapter; 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.transition.TransformationRule; import tools.refinery.store.dse.strategy.DepthFirstStrategy; import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; import tools.refinery.store.query.view.AnySymbolView; 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 index 91e33f4a..083f7ec3 100644 --- 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 @@ -6,10 +6,11 @@ package tools.refinery.store.dse; import org.junit.jupiter.api.Test; +import tools.refinery.store.dse.transition.DesignSpaceExplorationAdapter; 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.transition.TransformationRule; import tools.refinery.store.dse.strategy.BestFirstStrategy; import tools.refinery.store.dse.strategy.DepthFirstStrategy; import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; 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 index 5d24d712..1672b63a 100644 --- 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 @@ -7,10 +7,11 @@ package tools.refinery.store.dse; import org.junit.jupiter.api.Test; import tools.refinery.store.dse.strategy.DepthFirstStrategy; +import tools.refinery.store.dse.transition.DesignSpaceExplorationAdapter; 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.transition.TransformationRule; import tools.refinery.store.query.viatra.ViatraModelQueryAdapter; import tools.refinery.store.query.view.AnySymbolView; import tools.refinery.store.query.view.KeyOnlyView; diff --git a/subprojects/store-dse/src/test/java/tools/refinery/store/dse/transition/statespace/internal/ActivationUnitTest.java b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/transition/statespace/internal/ActivationUnitTest.java new file mode 100644 index 00000000..e7960a06 --- /dev/null +++ b/subprojects/store-dse/src/test/java/tools/refinery/store/dse/transition/statespace/internal/ActivationUnitTest.java @@ -0,0 +1,72 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.transition.statespace.internal; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +class ActivationUnitTest { + private final static int SMALL_SIZE = 5; + + private static Stream entries() { + return Stream.of( + new ActivationStoreBitVectorEntry(SMALL_SIZE), + new ActivationStoreListEntry(SMALL_SIZE)); + } + + void addTest(ActivationStoreEntry entry, int elementsAdded) { + Assertions.assertEquals(elementsAdded,entry.getNumberOfVisitedActivations()); + Assertions.assertEquals(SMALL_SIZE-elementsAdded,entry.getNumberOfUnvisitedActivations()); + } + + @ParameterizedTest + @MethodSource("entries") + void testDifferent(ActivationStoreEntry entry) { + int elementsAdded = 0; + addTest(entry,elementsAdded); + Assertions.assertEquals(2, entry.getAndAddActivationAfter(2)); + addTest(entry,++elementsAdded); + Assertions.assertEquals(3,entry.getAndAddActivationAfter(3)); + addTest(entry,++elementsAdded); + Assertions.assertEquals(1,entry.getAndAddActivationAfter(1)); + addTest(entry,++elementsAdded); + Assertions.assertEquals(4,entry.getAndAddActivationAfter(4)); + addTest(entry,++elementsAdded); + Assertions.assertEquals(0,entry.getAndAddActivationAfter(0)); + addTest(entry,++elementsAdded); + } + + @ParameterizedTest + @MethodSource("entries") + void testSame(ActivationStoreEntry entry) { + int elementsAdded = 0; + addTest(entry,elementsAdded); + entry.getAndAddActivationAfter(2); + addTest(entry,++elementsAdded); + entry.getAndAddActivationAfter(2); + addTest(entry,++elementsAdded); + entry.getAndAddActivationAfter(2); + addTest(entry,++elementsAdded); + entry.getAndAddActivationAfter(2); + addTest(entry,++elementsAdded); + entry.getAndAddActivationAfter(2); + addTest(entry,++elementsAdded); + } + + @ParameterizedTest + @MethodSource("entries") + void testFilling(ActivationStoreEntry entry) { + int elementsAdded = 0; + while(elementsAdded < SMALL_SIZE) { + entry.getAndAddActivationAfter(2); + elementsAdded++; + } + Assertions.assertThrows(IllegalArgumentException.class,()-> entry.getAndAddActivationAfter(2)); + } +} -- cgit v1.2.3-54-g00ecf