aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store-dse/src/main/java/tools/refinery/store/dse
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/store-dse/src/main/java/tools/refinery/store/dse')
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/ActionFactory.java14
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationAdapter.java71
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationBuilder.java48
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationStoreAdapter.java29
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/Strategy.java13
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/Activation.java14
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationAdapterImpl.java303
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationBuilderImpl.java67
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationStoreAdapterImpl.java65
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/TransformationRule.java99
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/ActionVariable.java12
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/ActivationVariable.java54
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/AtomicAction.java18
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/DeleteAction.java40
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/InsertAction.java94
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/NewItemVariable.java45
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/TransformationAction.java129
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/DanglingEdges.java12
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/ModificationAdapter.java24
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/ModificationBuilder.java11
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/ModificationStoreAdapter.java11
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/actions/CreateActionLiteral.java43
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/actions/DeleteActionLiteral.java51
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/actions/ModificationActionLiterals.java23
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/internal/ModificationAdapterImpl.java107
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/internal/ModificationBuilderImpl.java29
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/internal/ModificationStoreAdapterImpl.java29
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/AlwaysSatisfiedDummyHardObjective.java52
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/AlwaysSatisfiedRandomHardObjective.java57
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/BaseObjective.java132
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Comparators.java26
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Fitness.java46
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/Objective.java101
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/ObjectiveComparatorHelper.java60
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/BoundPropagator.java11
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/PropagationAdapter.java20
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/PropagationBuilder.java32
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/PropagationResult.java28
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/PropagationStoreAdapter.java14
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/Propagator.java17
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/PropagationAdapterImpl.java75
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/PropagationBuilderImpl.java53
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/PropagationStoreAdapterImpl.java38
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/rule/BoundPropagationRule.java40
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/rule/BoundRuleBasedPropagator.java43
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/rule/RuleBasedPropagator.java36
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstExplorer.java65
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstStoreManager.java87
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstStrategy.java203
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstWorker.java164
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/DepthFirstStrategy.java92
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/SubmitResult.java14
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/DesignSpaceExplorationAdapter.java28
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/DesignSpaceExplorationBuilder.java61
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/DesignSpaceExplorationStoreAdapter.java27
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/ObjectiveValue.java24
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/ObjectiveValues.java69
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/Rule.java99
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/RuleBuilder.java71
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/Transformation.java43
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/VersionWithObjectiveValue.java11
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/AbstractActionLiteral.java9
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/Action.java132
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/ActionLiteral.java19
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/ActionLiterals.java33
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/BoundAction.java119
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/BoundActionLiteral.java16
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/PutActionLiteral.java64
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/ActionCallback0.java15
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/ActionCallback1.java16
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/ActionCallback2.java16
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/ActionCallback3.java16
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/ActionCallback4.java16
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/RuleCallback0.java13
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/RuleCallback1.java14
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/RuleCallback2.java14
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/RuleCallback3.java14
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/RuleCallback4.java14
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/internal/DesignSpaceExplorationAdapterImpl.java94
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/internal/DesignSpaceExplorationBuilderImpl.java75
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/internal/DesignSpaceExplorationStoreAdapterImpl.java74
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/AndCriterion.java53
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/CompositeCriterion.java43
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/CompositeObjective.java69
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/CountObjective.java47
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/Criteria.java47
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/Criterion.java22
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/CriterionCalculator.java10
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/Objective.java23
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/ObjectiveCalculator.java10
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/Objectives.java41
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/OrCriterion.java53
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/QueryCriterion.java59
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/QueryObjective.java41
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/ActivationStore.java18
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/EquivalenceClassStore.java17
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/ObjectivePriorityQueue.java21
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/SolutionStore.java17
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/AbstractEquivalenceClassStore.java54
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreBitVectorEntry.java50
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreEntry.java37
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreImpl.java138
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreListEntry.java104
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreWorker.java55
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/CompleteEquivalenceClassStore.java104
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/FastEquivalenceClassStore.java37
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ObjectivePriorityQueueImpl.java68
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/SolutionStoreImpl.java52
108 files changed, 3583 insertions, 1884 deletions
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/ActionFactory.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/ActionFactory.java
deleted file mode 100644
index 524c2f55..00000000
--- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/ActionFactory.java
+++ /dev/null
@@ -1,14 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse;
7
8import org.eclipse.collections.api.block.procedure.Procedure;
9import tools.refinery.store.model.Model;
10import tools.refinery.store.tuple.Tuple;
11
12public interface ActionFactory {
13 Procedure<Tuple> prepare(Model model);
14}
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 ab87ddd5..00000000
--- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/DesignSpaceExplorationAdapter.java
+++ /dev/null
@@ -1,71 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse;
7
8import tools.refinery.store.adapter.ModelAdapter;
9import tools.refinery.store.dse.internal.TransformationRule;
10import tools.refinery.store.map.Version;
11import tools.refinery.store.dse.internal.Activation;
12import tools.refinery.store.dse.internal.DesignSpaceExplorationBuilderImpl;
13import tools.refinery.store.dse.objectives.Fitness;
14import tools.refinery.store.dse.objectives.ObjectiveComparatorHelper;
15import tools.refinery.store.tuple.Tuple;
16import tools.refinery.store.tuple.Tuple1;
17
18import java.util.Collection;
19import java.util.List;
20import java.util.Random;
21
22public interface DesignSpaceExplorationAdapter extends ModelAdapter {
23 @Override
24 DesignSpaceExplorationStoreAdapter getStoreAdapter();
25
26 static DesignSpaceExplorationBuilder builder() {
27 return new DesignSpaceExplorationBuilderImpl();
28 }
29
30 Collection<Version> explore();
31
32 public int getModelSize();
33
34 public Tuple1 createObject();
35
36 public Tuple deleteObject(Tuple tuple);
37
38 public boolean checkGlobalConstraints();
39
40 public boolean backtrack();
41
42 public boolean backtrack(String reason);
43
44 public Fitness getFitness();
45
46 public void newSolution();
47
48 public int getDepth();
49
50 public Collection<Activation> getUntraversedActivations();
51
52 public boolean fireActivation(Activation activation);
53
54 public boolean fireRandomActivation();
55
56 public List<Version> getTrajectory();
57
58 public boolean isCurrentStateAlreadyTraversed();
59
60 public ObjectiveComparatorHelper getObjectiveComparatorHelper();
61
62 public void restoreTrajectory(List<Version> trajectory);
63
64 public void setRandom(Random random);
65
66 public void setRandom(long seed);
67
68 public List<Version> getSolutions();
69
70 void addTransformationRule(TransformationRule transformationRule);
71}
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 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse;
7
8import tools.refinery.store.adapter.ModelAdapterBuilder;
9import tools.refinery.store.query.dnf.RelationalQuery;
10import tools.refinery.store.dse.internal.TransformationRule;
11import tools.refinery.store.dse.objectives.Objective;
12
13import java.util.Collection;
14import java.util.List;
15
16public interface DesignSpaceExplorationBuilder extends ModelAdapterBuilder {
17 default DesignSpaceExplorationBuilder transformations(TransformationRule... transformationRules) {
18 return transformations(List.of(transformationRules));
19 }
20
21 default DesignSpaceExplorationBuilder transformations(Collection<? extends TransformationRule> transformationRules) {
22 transformationRules.forEach(this::transformation);
23 return this;
24 }
25
26 default DesignSpaceExplorationBuilder globalConstraints(RelationalQuery... globalConstraints) {
27 return globalConstraints(List.of(globalConstraints));
28 }
29
30 default DesignSpaceExplorationBuilder globalConstraints(Collection<RelationalQuery> globalConstraints) {
31 globalConstraints.forEach(this::globalConstraint);
32 return this;
33 }
34
35 default DesignSpaceExplorationBuilder objectives(Objective... objectives) {
36 return objectives(List.of(objectives));
37 }
38
39 default DesignSpaceExplorationBuilder objectives(Collection<? extends Objective> objectives) {
40 objectives.forEach(this::objective);
41 return this;
42 }
43
44 DesignSpaceExplorationBuilder transformation(TransformationRule transformationRule);
45 DesignSpaceExplorationBuilder globalConstraint(RelationalQuery globalConstraint);
46 DesignSpaceExplorationBuilder objective(Objective objective);
47 DesignSpaceExplorationBuilder strategy(Strategy strategy);
48}
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 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse;
7
8import tools.refinery.store.adapter.ModelStoreAdapter;
9import tools.refinery.store.dse.internal.TransformationRule;
10import tools.refinery.store.dse.objectives.Objective;
11import tools.refinery.store.model.Model;
12import tools.refinery.store.query.dnf.RelationalQuery;
13
14import java.util.List;
15import java.util.Set;
16
17public interface DesignSpaceExplorationStoreAdapter extends ModelStoreAdapter {
18
19 @Override
20 DesignSpaceExplorationAdapter createModelAdapter(Model model);
21
22 Set<TransformationRule> getTransformationSpecifications();
23
24 Set<RelationalQuery> getGlobalConstraints();
25
26 List<Objective> getObjectives();
27
28 Strategy getStrategy();
29}
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 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse;
7
8public interface Strategy {
9
10 void initialize(DesignSpaceExplorationAdapter designSpaceExplorationAdapter);
11
12 void explore();
13}
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 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.internal;
7
8import tools.refinery.store.tuple.Tuple;
9
10public record Activation(TransformationRule transformationRule, Tuple activation) {
11 public boolean fire() {
12 return transformationRule.fireActivation(activation);
13 }
14}
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 1ae09916..00000000
--- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/DesignSpaceExplorationAdapterImpl.java
+++ /dev/null
@@ -1,303 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
3 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools/>
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v. 2.0 which is available at
6 * http://www.eclipse.org/legal/epl-v20.html.
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *******************************************************************************/
10package tools.refinery.store.dse.internal;
11
12import tools.refinery.store.map.Version;
13import tools.refinery.store.model.Interpretation;
14import tools.refinery.store.model.Model;
15import tools.refinery.store.query.ModelQueryAdapter;
16import tools.refinery.store.query.dnf.Query;
17import tools.refinery.store.query.dnf.RelationalQuery;
18import tools.refinery.store.dse.DesignSpaceExplorationAdapter;
19import tools.refinery.store.dse.DesignSpaceExplorationStoreAdapter;
20import tools.refinery.store.dse.Strategy;
21import tools.refinery.store.dse.objectives.Fitness;
22import tools.refinery.store.dse.objectives.Objective;
23import tools.refinery.store.dse.objectives.ObjectiveComparatorHelper;
24import tools.refinery.store.query.resultset.ResultSet;
25import tools.refinery.store.representation.Symbol;
26import tools.refinery.store.tuple.Tuple;
27import tools.refinery.store.tuple.Tuple1;
28import tools.refinery.visualization.ModelVisualizerAdapter;
29
30import java.util.*;
31
32public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExplorationAdapter {
33 static final Symbol<Integer> NODE_COUNT_SYMBOL = Symbol.of("MODEL_SIZE", 0, Integer.class, 0);
34 private final Model model;
35 private final ModelQueryAdapter queryEngine;
36 private final DesignSpaceExplorationStoreAdapterImpl storeAdapter;
37 private final Set<TransformationRule> transformationRules;
38 private final Set<RelationalQuery> globalConstraints;
39 private final List<Objective> objectives;
40 private final LinkedHashSet<ResultSet<Boolean>> globalConstraintResultSets = new LinkedHashSet<>();
41 private final Interpretation<Integer> sizeInterpretation;
42 private final Strategy strategy;
43
44 private ObjectiveComparatorHelper objectiveComparatorHelper;
45 private List<Version> trajectory = new ArrayList<>();
46 private Map<Version, Version> parents = new HashMap<>();
47 private final List<Version> solutions = new ArrayList<>();
48 private Map<Version, List<Activation>> statesAndTraversedActivations;
49 @SuppressWarnings("squid:S2245")
50 private Random random = new Random();
51 private boolean isNewState = false;
52 private final boolean isVisualizationEnabled;
53 private final ModelVisualizerAdapter modelVisualizerAdapter;
54
55 private final Map<Version, Fitness> fitnessCache = new HashMap<>();
56
57 public DesignSpaceExplorationAdapterImpl(Model model, DesignSpaceExplorationStoreAdapterImpl storeAdapter) {
58 this.model = model;
59 this.storeAdapter = storeAdapter;
60 this.sizeInterpretation = model.getInterpretation(NODE_COUNT_SYMBOL);
61 queryEngine = model.getAdapter(ModelQueryAdapter.class);
62
63 globalConstraints = storeAdapter.getGlobalConstraints();
64 for (var constraint : globalConstraints) {
65 globalConstraintResultSets.add(queryEngine.getResultSet(constraint));
66 }
67
68 transformationRules = storeAdapter.getTransformationSpecifications();
69 for (var rule : transformationRules) {
70 rule.prepare(model, queryEngine);
71 }
72
73 objectives = storeAdapter.getObjectives();
74 statesAndTraversedActivations = new HashMap<>();
75 strategy = storeAdapter.getStrategy();
76 strategy.initialize(this);
77 modelVisualizerAdapter = model.tryGetAdapter(ModelVisualizerAdapter.class).orElse(null);
78 isVisualizationEnabled = modelVisualizerAdapter != null;
79
80 }
81
82 @Override
83 public void addTransformationRule(TransformationRule rule) {
84 transformationRules.add(rule);
85 rule.prepare(model, queryEngine);
86 }
87
88 public List<Version> getTrajectory() {
89 return new ArrayList<>(trajectory);
90 }
91
92 @Override
93 public Model getModel() {
94 return model;
95 }
96
97 @Override
98 public DesignSpaceExplorationStoreAdapter getStoreAdapter() {
99 return storeAdapter;
100 }
101
102 @Override
103 public List<Version> explore() {
104 var state = model.commit();
105 trajectory.add(state);
106 strategy.explore();
107 if (isVisualizationEnabled) {
108 modelVisualizerAdapter.visualize();
109 }
110 return solutions;
111 }
112
113 @Override
114 public int getModelSize() {
115 return sizeInterpretation.get(Tuple.of());
116 }
117
118 @Override
119 public Tuple1 createObject() {
120 var newNodeId = getModelSize();
121 sizeInterpretation.put(Tuple.of(), newNodeId + 1);
122 return Tuple.of(newNodeId);
123 }
124
125 @Override
126 public Tuple deleteObject(Tuple tuple) {
127 if (tuple.getSize() != 1) {
128 throw new IllegalArgumentException("Tuple size must be 1");
129 }
130// TODO: implement more efficient deletion
131// if (tuple.get(0) == getModelSize() - 1) {
132// sizeInterpretation.put(Tuple.of(), getModelSize() - 1);
133// }
134 return tuple;
135 }
136
137 @Override
138 public boolean checkGlobalConstraints() {
139 for (var resultSet : globalConstraintResultSets) {
140 if (resultSet.size() > 0) {
141 return false;
142 }
143 }
144 return true;
145 }
146
147 @Override
148 public boolean backtrack() {
149 return backtrack("");
150 }
151 @Override
152 public boolean backtrack(String reason) {
153 if (trajectory.size() < 2) {
154 return false;
155 }
156 var currentState = model.getState();
157 if (!parents.containsKey(currentState)) {
158 return false;
159 }
160 if (isVisualizationEnabled) {
161 modelVisualizerAdapter.addTransition(trajectory.get(trajectory.size() - 1),
162 trajectory.get(trajectory.size() - 2), "backtrack(" + reason + ")");
163 }
164 model.restore(parents.get(model.getState()));
165 trajectory.remove(trajectory.size() - 1);
166 return true;
167 }
168
169 @Override
170 public void restoreTrajectory(List<Version> trajectory) {
171 model.restore(trajectory.get(trajectory.size() - 1));
172// if (isVisualizationEnabled) {
173// modelVisualizerAdapter.addTransition(this.trajectory.get(trajectory.size() - 1),
174// trajectory.get(trajectory.size() - 1), "restore");
175// }
176 this.trajectory = new ArrayList<>(trajectory);
177
178 }
179
180 @Override
181 public void setRandom(Random random) {
182 this.random = random;
183 }
184
185 @Override
186 @SuppressWarnings("squid:S2245")
187 public void setRandom(long seed) {
188 this.random = new Random(seed);
189 }
190
191 @Override
192 public List<Version> getSolutions() {
193 return solutions;
194 }
195
196 @Override
197 public Fitness getFitness() {
198 return fitnessCache.computeIfAbsent(model.getState(), s -> calculateFitness());
199 }
200
201 private Fitness calculateFitness() {
202 Fitness result = new Fitness();
203 boolean satisfiesHardObjectives = true;
204 for (Objective objective : objectives) {
205 var fitness = objective.getFitness(this);
206 result.put(objective.getName(), fitness);
207 if (objective.isHardObjective() && !objective.satisfiesHardObjective(fitness)) {
208 satisfiesHardObjectives = false;
209 }
210 }
211 result.setSatisfiesHardObjectives(satisfiesHardObjectives);
212
213 return result;
214 }
215
216 @Override
217 public void newSolution() {
218 var state = model.getState();
219 solutions.add(state);
220 if (isVisualizationEnabled) {
221 modelVisualizerAdapter.addSolution(state);
222 }
223 }
224
225 @Override
226 public int getDepth() {
227 return trajectory.size() - 1;
228 }
229
230 public LinkedHashSet<Activation> getUntraversedActivations() {
231 var traversedActivations = statesAndTraversedActivations.get(model.getState());
232 if (traversedActivations == null) {
233 return new LinkedHashSet<>(getAllActivations());
234 }
235 else {
236 LinkedHashSet<Activation> untraversedActivations = new LinkedHashSet<>();
237 for (Activation activation : getAllActivations()) {
238 if (!traversedActivations.contains(activation)) {
239 untraversedActivations.add(activation);
240 }
241 }
242 return untraversedActivations;
243 }
244 }
245
246 @Override
247 public boolean fireActivation(Activation activation) {
248 if (activation == null) {
249 return false;
250 }
251 var previousState = model.getState();
252 if (!activation.fire()) {
253 return false;
254 }
255 statesAndTraversedActivations.computeIfAbsent(previousState, s -> new ArrayList<>()).add(activation);
256 var newState = model.commit();
257 trajectory.add(newState);
258 parents.put(newState, previousState);
259 isNewState = !statesAndTraversedActivations.containsKey(newState);
260 if (isVisualizationEnabled) {
261 if (isNewState) {
262 modelVisualizerAdapter.addState(newState, getFitness().values());
263 }
264 modelVisualizerAdapter.addTransition(previousState, newState, activation.transformationRule().getName(),
265 activation.activation());
266 }
267 return true;
268 }
269
270 @Override
271 public boolean fireRandomActivation() {
272 var activations = getUntraversedActivations();
273 if (activations.isEmpty()) {
274 return false;
275 }
276 int index = random.nextInt(activations.size());
277 var iterator = activations.iterator();
278 while (index-- > 0) {
279 iterator.next();
280 }
281 var activationId = iterator.next();
282 return fireActivation(activationId);
283 }
284
285 public List<Activation> getAllActivations() {
286 List<Activation> result = new LinkedList<>();
287 for (var rule : transformationRules) {
288 result.addAll(rule.getAllActivationsAsList());
289 }
290 return result;
291 }
292
293 public boolean isCurrentStateAlreadyTraversed() {
294 return !isNewState;
295 }
296
297 public ObjectiveComparatorHelper getObjectiveComparatorHelper() {
298 if (objectiveComparatorHelper == null) {
299 objectiveComparatorHelper = new ObjectiveComparatorHelper(objectives);
300 }
301 return objectiveComparatorHelper;
302 }
303}
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 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.internal;
7
8import tools.refinery.store.adapter.AbstractModelAdapterBuilder;
9import tools.refinery.store.model.ModelStore;
10import tools.refinery.store.model.ModelStoreBuilder;
11import tools.refinery.store.query.dnf.RelationalQuery;
12import tools.refinery.store.dse.DesignSpaceExplorationBuilder;
13import tools.refinery.store.dse.Strategy;
14import tools.refinery.store.dse.objectives.Objective;
15
16import java.util.LinkedHashSet;
17import java.util.LinkedList;
18import java.util.List;
19
20public class DesignSpaceExplorationBuilderImpl
21 extends AbstractModelAdapterBuilder<DesignSpaceExplorationStoreAdapterImpl>
22 implements DesignSpaceExplorationBuilder {
23 private final LinkedHashSet<TransformationRule> transformationSpecifications = new LinkedHashSet<>();
24 private final LinkedHashSet<RelationalQuery> globalConstraints = new LinkedHashSet<>();
25 private final List<Objective> objectives = new LinkedList<>();
26 private Strategy strategy;
27
28 @Override
29 protected DesignSpaceExplorationStoreAdapterImpl doBuild(ModelStore store) {
30 return new DesignSpaceExplorationStoreAdapterImpl(store, transformationSpecifications, globalConstraints,
31 objectives, strategy);
32 }
33
34 @Override
35 public DesignSpaceExplorationBuilder transformation(TransformationRule transformationRule) {
36 checkNotConfigured();
37 transformationSpecifications.add(transformationRule);
38 return this;
39 }
40
41 @Override
42 public DesignSpaceExplorationBuilder globalConstraint(RelationalQuery globalConstraint) {
43 checkNotConfigured();
44 globalConstraints.add(globalConstraint);
45 return this;
46 }
47
48 @Override
49 public DesignSpaceExplorationBuilder objective(Objective objective) {
50 checkNotConfigured();
51 objectives.add(objective);
52 return this;
53 }
54
55 @Override
56 public DesignSpaceExplorationBuilder strategy(Strategy strategy) {
57 checkNotConfigured();
58 this.strategy = strategy;
59 return this;
60 }
61
62 @Override
63 protected void doConfigure(ModelStoreBuilder storeBuilder) {
64 storeBuilder.symbols(DesignSpaceExplorationAdapterImpl.NODE_COUNT_SYMBOL);
65 super.doConfigure(storeBuilder);
66 }
67}
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 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.internal;
7
8import tools.refinery.store.dse.DesignSpaceExplorationStoreAdapter;
9import tools.refinery.store.dse.Strategy;
10import tools.refinery.store.dse.objectives.Objective;
11import tools.refinery.store.model.Model;
12import tools.refinery.store.model.ModelStore;
13import tools.refinery.store.query.dnf.RelationalQuery;
14
15import java.util.List;
16import java.util.Set;
17
18public class DesignSpaceExplorationStoreAdapterImpl implements DesignSpaceExplorationStoreAdapter {
19 private final ModelStore store;
20 private final Set<TransformationRule> transformationSpecifications;
21 private final Set<RelationalQuery> globalConstraints;
22 private final List<Objective> objectives;
23 private final Strategy strategy;
24
25 public DesignSpaceExplorationStoreAdapterImpl(ModelStore store,
26 Set<TransformationRule> transformationSpecifications,
27 Set<RelationalQuery> globalConstraints,
28 List<Objective> objectives, Strategy strategy) {
29 this.store = store;
30 this.transformationSpecifications = transformationSpecifications;
31 this.globalConstraints = globalConstraints;
32 this.objectives = objectives;
33 this.strategy = strategy;
34 }
35
36 @Override
37 public ModelStore getStore() {
38 return store;
39 }
40
41 @Override
42 public DesignSpaceExplorationAdapterImpl createModelAdapter(Model model) {
43 return new DesignSpaceExplorationAdapterImpl(model, this);
44 }
45
46 @Override
47 public Set<TransformationRule> getTransformationSpecifications() {
48 return transformationSpecifications;
49 }
50
51 @Override
52 public Set<RelationalQuery> getGlobalConstraints() {
53 return globalConstraints;
54 }
55
56 @Override
57 public List<Objective> getObjectives() {
58 return objectives;
59 }
60
61 @Override
62 public Strategy getStrategy() {
63 return strategy;
64 }
65}
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 37117164..00000000
--- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/TransformationRule.java
+++ /dev/null
@@ -1,99 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.internal;
7
8import org.eclipse.collections.api.block.procedure.Procedure;
9import tools.refinery.store.model.Model;
10import tools.refinery.store.query.ModelQueryAdapter;
11import tools.refinery.store.query.dnf.RelationalQuery;
12import tools.refinery.store.dse.ActionFactory;
13import tools.refinery.store.query.resultset.OrderedResultSet;
14import tools.refinery.store.query.resultset.ResultSet;
15import tools.refinery.store.tuple.Tuple;
16
17import java.util.*;
18
19public class TransformationRule {
20
21 private final String name;
22 private final RelationalQuery precondition;
23 private final ActionFactory actionFactory;
24 private Procedure<Tuple> action;
25 private OrderedResultSet<Boolean> activations;
26 private Random random;
27 private ModelQueryAdapter queryEngine;
28
29 @SuppressWarnings("squid:S2245")
30 public TransformationRule(String name, RelationalQuery precondition, ActionFactory actionFactory) {
31 this(name, precondition, actionFactory, new Random());
32 }
33
34 @SuppressWarnings("squid:S2245")
35 public TransformationRule(String name, RelationalQuery precondition, ActionFactory actionFactory, long seed) {
36 this(name, precondition, actionFactory, new Random(seed));
37 }
38
39 public TransformationRule(String name, RelationalQuery precondition, ActionFactory actionFactory, Random random) {
40 this.name = name;
41 this.precondition = precondition;
42 this.actionFactory = actionFactory;
43 this.random = random;
44 }
45 public boolean prepare(Model model, ModelQueryAdapter queryEngine) {
46 action = actionFactory.prepare(model);
47 this.queryEngine = queryEngine;
48 activations = new OrderedResultSet<>(queryEngine.getResultSet(precondition));
49 return true;
50 }
51
52 public boolean fireActivation(Tuple activation) {
53 action.accept(activation);
54 queryEngine.flushChanges();
55 return true;
56 }
57
58 public boolean fireRandomActivation() {
59 return getRandomActivation().fire();
60 }
61
62 public String getName() {
63 return name;
64 }
65
66 public RelationalQuery getPrecondition() {
67 return precondition;
68 }
69
70 public ResultSet<Boolean> getAllActivationsAsResultSet() {
71 return activations;
72 }
73
74 public Set<Activation> getAllActivations() {
75 var result = new LinkedHashSet<Activation>();
76 var cursor = activations.getAll();
77 while (cursor.move()) {
78 result.add(new Activation(this, cursor.getKey()));
79 }
80 return result;
81 }
82
83 public List<Activation> getAllActivationsAsList() {
84 var result = new ArrayList<Activation>();
85 var cursor = activations.getAll();
86 while (cursor.move()) {
87 result.add(new Activation(this, cursor.getKey()));
88 }
89 return result;
90 }
91
92 public Activation getRandomActivation() {
93 return new Activation(this, activations.getKey(random.nextInt(activations.size())));
94 }
95
96 public Activation getActivation(int index) {
97 return new Activation(this, activations.getKey(index));
98 }
99}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/ActionVariable.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/ActionVariable.java
deleted file mode 100644
index 92de565d..00000000
--- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/ActionVariable.java
+++ /dev/null
@@ -1,12 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.internal.action;
7
8import tools.refinery.store.tuple.Tuple;
9
10public interface ActionVariable extends AtomicAction {
11 Tuple getValue();
12}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/ActivationVariable.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/ActivationVariable.java
deleted file mode 100644
index 6b4c6340..00000000
--- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/ActivationVariable.java
+++ /dev/null
@@ -1,54 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.internal.action;
7
8import tools.refinery.store.model.Model;
9import tools.refinery.store.tuple.Tuple;
10
11public class ActivationVariable implements ActionVariable {
12
13 private final int index;
14 private Tuple value;
15
16 public ActivationVariable() {
17 this(0);
18 }
19
20 public ActivationVariable(int index) {
21 this.index = index;
22 }
23
24 @Override
25 public void fire(Tuple activation) {
26 value = Tuple.of(activation.get(index));
27 }
28
29 @Override
30 public ActivationVariable prepare(Model model) {
31 return this;
32 }
33
34 @Override
35 public Tuple getValue() {
36 return value;
37 }
38
39 @Override
40 public boolean equalsWithSubstitution(AtomicAction other) {
41 if (other == null || getClass() != other.getClass()) {
42 return false;
43 }
44 var otherAction = (ActivationVariable) other;
45
46 if (index != otherAction.index) {
47 return false;
48 }
49 if (value == null) {
50 return otherAction.value == null;
51 }
52 return value.equals(otherAction.value);
53 }
54}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/AtomicAction.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/AtomicAction.java
deleted file mode 100644
index a8f10bca..00000000
--- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/AtomicAction.java
+++ /dev/null
@@ -1,18 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.internal.action;
7
8import tools.refinery.store.model.Model;
9import tools.refinery.store.tuple.Tuple;
10
11public interface AtomicAction {
12
13 void fire(Tuple activation);
14
15 AtomicAction prepare(Model model);
16
17 boolean equalsWithSubstitution(AtomicAction other);
18}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/DeleteAction.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/DeleteAction.java
deleted file mode 100644
index 9900390f..00000000
--- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/DeleteAction.java
+++ /dev/null
@@ -1,40 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.internal.action;
7
8import tools.refinery.store.dse.DesignSpaceExplorationAdapter;
9import tools.refinery.store.model.Model;
10import tools.refinery.store.tuple.Tuple;
11
12public class DeleteAction implements AtomicAction {
13
14 private final ActionVariable variable;
15 private DesignSpaceExplorationAdapter dseAdapter;
16
17 public DeleteAction(ActionVariable variable) {
18 this.variable = variable;
19 }
20
21 @Override
22 public void fire(Tuple activation) {
23 dseAdapter.deleteObject(variable.getValue());
24 }
25
26 @Override
27 public DeleteAction prepare(Model model) {
28 dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
29 return this;
30 }
31
32 @Override
33 public boolean equalsWithSubstitution(AtomicAction other) {
34 if (other == null || getClass() != other.getClass()) {
35 return false;
36 }
37 var otherAction = (DeleteAction) other;
38 return this.variable.getClass() == otherAction.variable.getClass();
39 }
40}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/InsertAction.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/InsertAction.java
deleted file mode 100644
index 90fcc5ac..00000000
--- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/InsertAction.java
+++ /dev/null
@@ -1,94 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.internal.action;
7
8import tools.refinery.store.model.Interpretation;
9import tools.refinery.store.model.Model;
10import tools.refinery.store.tuple.Tuple;
11import tools.refinery.store.tuple.Tuple0;
12
13import java.util.Arrays;
14
15public class InsertAction<T> implements AtomicAction {
16
17 private final Interpretation<T> interpretation;
18 private final T value;
19 private final int arity;
20 private final ActionVariable[] variables;
21
22 public InsertAction(Interpretation<T> interpretation, T value, ActionVariable... variables) {
23 this.interpretation = interpretation;
24 this.value = value;
25 this.variables = variables;
26 this.arity = interpretation.getSymbol().arity();
27 if (variables.length != arity) {
28 throw new IllegalArgumentException("Expected " + arity + " variables, but got " + variables.length);
29 }
30 }
31
32 @Override
33 public void fire(Tuple activation) {
34 Tuple tuple;
35 if (arity == 0) {
36 tuple = Tuple0.INSTANCE;
37 }
38 else if (arity == 1) {
39 tuple = variables[0].getValue();
40 }
41 else if (arity == 2) {
42 tuple = Tuple.of(variables[0].getValue().get(0), variables[1].getValue().get(0));
43 }
44 else if (arity == 3) {
45 tuple = Tuple.of(variables[0].getValue().get(0), variables[1].getValue().get(0), variables[2].getValue().get(0));
46 }
47 else {
48 tuple = Tuple.of(Arrays.stream(variables).map(variable -> variable.getValue().get(0))
49 .mapToInt(Integer::intValue).toArray());
50 }
51 interpretation.put(tuple, value);
52 }
53
54 public void put(Tuple tuple) {
55 interpretation.put(tuple, value);
56 }
57
58 @Override
59 public InsertAction<T> prepare(Model model) {
60 return this;
61 }
62
63 public ActionVariable[] getVariables() {
64 return variables;
65 }
66
67 @Override
68 public boolean equalsWithSubstitution(AtomicAction other) {
69 if (other == null || getClass() != other.getClass()) {
70 return false;
71 }
72 var otherAction = (InsertAction<?>) other;
73 if (variables.length != otherAction.variables.length) {
74 return false;
75 }
76 if (!interpretation.equals(otherAction.interpretation)) {
77 return false;
78 }
79 if (value == null) {
80 if (otherAction.value != null) {
81 return false;
82 }
83 }
84 else if (!value.equals(otherAction.value)) {
85 return false;
86 }
87 for (var i = 0; i < variables.length; i++) {
88 if (!variables[i].equalsWithSubstitution(otherAction.variables[i])) {
89 return false;
90 }
91 }
92 return true;
93 }
94}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/NewItemVariable.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/NewItemVariable.java
deleted file mode 100644
index cbb9697e..00000000
--- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/NewItemVariable.java
+++ /dev/null
@@ -1,45 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.internal.action;
7
8import tools.refinery.store.dse.DesignSpaceExplorationAdapter;
9import tools.refinery.store.model.Model;
10import tools.refinery.store.tuple.Tuple;
11import tools.refinery.store.tuple.Tuple1;
12
13public class NewItemVariable implements ActionVariable {
14 private DesignSpaceExplorationAdapter dseAdapter;
15 private Tuple1 value;
16
17 @Override
18 public void fire(Tuple activation) {
19 value = dseAdapter.createObject();
20 }
21
22 @Override
23 public NewItemVariable prepare(Model model) {
24 dseAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
25 return this;
26 }
27
28 @Override
29 public Tuple1 getValue() {
30 return value;
31 }
32
33 @Override
34 public boolean equalsWithSubstitution(AtomicAction other) {
35 if (other == null || getClass() != other.getClass()) {
36 return false;
37 }
38 var otherAction = (NewItemVariable) other;
39 if (value == null) {
40 return otherAction.value == null;
41 }
42 return value.equals(otherAction.value);
43
44 }
45}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/TransformationAction.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/TransformationAction.java
deleted file mode 100644
index adc4df9e..00000000
--- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/internal/action/TransformationAction.java
+++ /dev/null
@@ -1,129 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.internal.action;
7
8import tools.refinery.store.model.Model;
9import tools.refinery.store.tuple.Tuple;
10import tools.refinery.store.tuple.Tuple2;
11
12import java.util.*;
13
14public class TransformationAction {
15 private final List<ActionVariable> actionVariables = new ArrayList<>();
16 private final List<InsertAction<?>> insertActions = new ArrayList<>();
17 private final List<DeleteAction> deleteActions = new ArrayList<>();
18 private boolean configured = false;
19 private final Map<Integer, List<Tuple2>> actionVariableUsageMap = new LinkedHashMap<>();
20
21 public TransformationAction add(ActionVariable action) {
22 checkConfigured();
23 actionVariables.add(action);
24 return this;
25 }
26
27 public TransformationAction add(InsertAction<?> action) {
28 checkConfigured();
29 insertActions.add(action);
30 return this;
31 }
32
33 public TransformationAction add(DeleteAction action) {
34 checkConfigured();
35 deleteActions.add(action);
36 return this;
37 }
38
39 private void checkConfigured() {
40 if (configured) {
41 throw new IllegalStateException("Action already configured.");
42 }
43 }
44
45 public TransformationAction prepare(Model model) {
46 for (ActionVariable action : actionVariables) {
47 action.prepare(model);
48 }
49 for (InsertAction<?> action : insertActions) {
50 action.prepare(model);
51 }
52 for (DeleteAction action : deleteActions) {
53 action.prepare(model);
54 }
55
56 for (var insertAction : insertActions) {
57 var actionIndex = insertActions.indexOf(insertAction);
58 var variables = insertAction.getVariables();
59 for (var i = 0; i < variables.length; i++) {
60 var variablelGlobalIndex = actionVariables.indexOf(variables[i]);
61 actionVariableUsageMap.computeIfAbsent(variablelGlobalIndex, k -> new ArrayList<>());
62 actionVariableUsageMap.get(variablelGlobalIndex).add(Tuple.of(actionIndex, i));
63 }
64 }
65
66 configured = true;
67 return this;
68 }
69
70 public boolean fire(Tuple activation) {
71 for (ActionVariable action : actionVariables) {
72 action.fire(activation);
73 }
74 for (InsertAction<?> action : insertActions) {
75 action.fire(activation);
76 }
77 for (DeleteAction action : deleteActions) {
78 action.fire(activation);
79 }
80 return true;
81 }
82
83 // Returns true if ActionVariables and InsertActions are inserted in same order, ActionVariables are equal (they
84 // have the same index for getting the value from the activation Tuple) and InsertActions are equal (they have
85 // the same arity and value to be set).
86 public boolean equalsWithSubstitution(TransformationAction other) {
87 if (other == this) {
88 return true;
89 }
90
91 if (actionVariables.size() != other.actionVariables.size()) {
92 return false;
93 }
94
95 if (insertActions.size() != other.insertActions.size()) {
96 return false;
97 }
98
99 if (deleteActions.size() != other.deleteActions.size()) {
100 return false;
101 }
102
103 for (var i = 0; i < actionVariables.size(); i++) {
104 var variable = actionVariables.get(i);
105 var otherVariable = other.actionVariables.get(i);
106 if (!variable.equalsWithSubstitution(otherVariable)) {
107 return false;
108 }
109 }
110
111 for (var i = 0; i < insertActions.size(); i++) {
112 var insertAction = insertActions.get(i);
113 var otherInsertAction = other.insertActions.get(i);
114 if (!insertAction.equalsWithSubstitution(otherInsertAction)) {
115 return false;
116 }
117 }
118
119 for (var i = 0; i < deleteActions.size(); i++) {
120 var deleteAction = deleteActions.get(i);
121 var otherDeleteAction = other.deleteActions.get(i);
122 if (!deleteAction.equalsWithSubstitution(otherDeleteAction)) {
123 return false;
124 }
125 }
126 return this.actionVariableUsageMap.equals(other.actionVariableUsageMap);
127
128 }
129}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/DanglingEdges.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/DanglingEdges.java
new file mode 100644
index 00000000..ac9d125b
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/DanglingEdges.java
@@ -0,0 +1,12 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.modification;
7
8public enum DanglingEdges {
9 IGNORE,
10 DELETE,
11 FAIL
12}
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..58b60499
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/ModificationAdapter.java
@@ -0,0 +1,24 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.modification;
7
8import tools.refinery.store.adapter.ModelAdapter;
9import tools.refinery.store.dse.modification.internal.ModificationBuilderImpl;
10import tools.refinery.store.tuple.Tuple;
11import tools.refinery.store.tuple.Tuple1;
12
13public interface ModificationAdapter extends ModelAdapter {
14
15 int getModelSize();
16
17 Tuple1 createObject();
18
19 boolean deleteObject(Tuple tuple, DanglingEdges danglingEdges);
20
21 static ModificationBuilder builder() {
22 return new ModificationBuilderImpl();
23 }
24}
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 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.modification;
7
8import tools.refinery.store.adapter.ModelAdapterBuilder;
9
10public interface ModificationBuilder extends ModelAdapterBuilder {
11}
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 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.modification;
7
8import tools.refinery.store.adapter.ModelStoreAdapter;
9
10public interface ModificationStoreAdapter extends ModelStoreAdapter {
11}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/actions/CreateActionLiteral.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/actions/CreateActionLiteral.java
new file mode 100644
index 00000000..5b86a5e1
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/actions/CreateActionLiteral.java
@@ -0,0 +1,43 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.modification.actions;
7
8import tools.refinery.store.dse.modification.ModificationAdapter;
9import tools.refinery.store.dse.transition.actions.AbstractActionLiteral;
10import tools.refinery.store.dse.transition.actions.BoundActionLiteral;
11import tools.refinery.store.model.Model;
12import tools.refinery.store.query.term.NodeVariable;
13
14import java.util.List;
15
16public class CreateActionLiteral extends AbstractActionLiteral {
17 private final NodeVariable variable;
18
19 public CreateActionLiteral(NodeVariable variable) {
20
21 this.variable = variable;
22 }
23
24 public NodeVariable getVariable() {
25 return variable;
26 }
27
28 @Override
29 public List<NodeVariable> getInputVariables() {
30 return List.of();
31 }
32
33 @Override
34 public List<NodeVariable> getOutputVariables() {
35 return List.of(variable);
36 }
37
38 @Override
39 public BoundActionLiteral bindToModel(Model model) {
40 var adapter = model.getAdapter(ModificationAdapter.class);
41 return ignoredTuple -> adapter.createObject();
42 }
43}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/actions/DeleteActionLiteral.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/actions/DeleteActionLiteral.java
new file mode 100644
index 00000000..18ad2b9d
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/actions/DeleteActionLiteral.java
@@ -0,0 +1,51 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.modification.actions;
7
8import tools.refinery.store.dse.modification.DanglingEdges;
9import tools.refinery.store.dse.modification.ModificationAdapter;
10import tools.refinery.store.dse.transition.actions.AbstractActionLiteral;
11import tools.refinery.store.dse.transition.actions.BoundActionLiteral;
12import tools.refinery.store.model.Model;
13import tools.refinery.store.query.term.NodeVariable;
14import tools.refinery.store.tuple.Tuple;
15
16import java.util.List;
17
18public class DeleteActionLiteral extends AbstractActionLiteral {
19 private final NodeVariable variable;
20 private final DanglingEdges danglingEdges;
21
22 public DeleteActionLiteral(NodeVariable variable, DanglingEdges danglingEdges) {
23
24 this.variable = variable;
25 this.danglingEdges = danglingEdges;
26 }
27
28 public NodeVariable getVariable() {
29 return variable;
30 }
31
32 public DanglingEdges getDanglingEdges() {
33 return danglingEdges;
34 }
35
36 @Override
37 public List<NodeVariable> getInputVariables() {
38 return List.of(variable);
39 }
40
41 @Override
42 public List<NodeVariable> getOutputVariables() {
43 return List.of();
44 }
45
46 @Override
47 public BoundActionLiteral bindToModel(Model model) {
48 var adapter = model.getAdapter(ModificationAdapter.class);
49 return tuple -> adapter.deleteObject(tuple, danglingEdges) ? Tuple.of() : null;
50 }
51}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/actions/ModificationActionLiterals.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/actions/ModificationActionLiterals.java
new file mode 100644
index 00000000..31f50ac7
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/actions/ModificationActionLiterals.java
@@ -0,0 +1,23 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.modification.actions;
7
8import tools.refinery.store.dse.modification.DanglingEdges;
9import tools.refinery.store.query.term.NodeVariable;
10
11public class ModificationActionLiterals {
12 private ModificationActionLiterals() {
13 throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly");
14 }
15
16 public static CreateActionLiteral create(NodeVariable variable) {
17 return new CreateActionLiteral(variable);
18 }
19
20 public static DeleteActionLiteral delete(NodeVariable variable, DanglingEdges danglingEdges) {
21 return new DeleteActionLiteral(variable, danglingEdges);
22 }
23}
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..4e77c462
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/internal/ModificationAdapterImpl.java
@@ -0,0 +1,107 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.modification.internal;
7
8import tools.refinery.store.adapter.ModelStoreAdapter;
9import tools.refinery.store.dse.modification.DanglingEdges;
10import tools.refinery.store.dse.modification.ModificationAdapter;
11import tools.refinery.store.model.Interpretation;
12import tools.refinery.store.model.Model;
13import tools.refinery.store.representation.Symbol;
14import tools.refinery.store.tuple.Tuple;
15import tools.refinery.store.tuple.Tuple1;
16
17import java.util.HashSet;
18
19public class ModificationAdapterImpl implements ModificationAdapter {
20 static final Symbol<Integer> NEXT_ID = Symbol.of("NEXT_ID", 0, Integer.class, 0);
21
22 final ModelStoreAdapter storeAdapter;
23 final Model model;
24 Interpretation<Integer> nodeCountInterpretation;
25
26 ModificationAdapterImpl(ModelStoreAdapter storeAdapter, Model model) {
27 this.storeAdapter = storeAdapter;
28 this.model = model;
29 this.nodeCountInterpretation = model.getInterpretation(NEXT_ID);
30 }
31
32 @Override
33 public Model getModel() {
34 return model;
35 }
36
37 @Override
38 public ModelStoreAdapter getStoreAdapter() {
39 return storeAdapter;
40 }
41
42 @Override
43 public int getModelSize() {
44 return nodeCountInterpretation.get(Tuple.of());
45 }
46
47 @Override
48 public Tuple1 createObject() {
49 var newNodeId = getModelSize();
50 nodeCountInterpretation.put(Tuple.of(), newNodeId + 1);
51 return Tuple.of(newNodeId);
52 }
53
54 @Override
55 public boolean deleteObject(Tuple tuple, DanglingEdges danglingEdges) {
56 if (tuple.getSize() != 1) {
57 throw new IllegalArgumentException("Tuple size must be 1");
58 }
59 int objectId = tuple.get(0);
60 if (danglingEdges == DanglingEdges.DELETE) {
61 deleteDanglingEdges(objectId);
62 } else if (danglingEdges == DanglingEdges.FAIL && hasDanglingEdges(objectId)) {
63 return false;
64
65 }
66 int modelSize = getModelSize();
67 if (objectId == modelSize - 1) {
68 nodeCountInterpretation.put(Tuple.of(), modelSize - 1);
69 }
70 return true;
71 }
72
73 private void deleteDanglingEdges(int objectId) {
74 for (var symbol : model.getStore().getSymbols()) {
75 deleteDanglingEdges(objectId, (Symbol<?>) symbol);
76 }
77 }
78
79 private <T> void deleteDanglingEdges(int objectId, Symbol<T> symbol) {
80 var interpretation = model.getInterpretation(symbol);
81 var toDelete = new HashSet<Tuple>();
82 int arity = symbol.arity();
83 for (int i = 0; i < arity; i++) {
84 var cursor = interpretation.getAdjacent(i, objectId);
85 while (cursor.move()) {
86 toDelete.add(cursor.getKey());
87 }
88 }
89 var defaultValue = symbol.defaultValue();
90 for (var tuple : toDelete) {
91 interpretation.put(tuple, defaultValue);
92 }
93 }
94
95 private boolean hasDanglingEdges(int objectId) {
96 for (var symbol : model.getStore().getSymbols()) {
97 var interpretation = model.getInterpretation(symbol);
98 int arity = symbol.arity();
99 for (int i = 0; i < arity; i++) {
100 if (interpretation.getAdjacentSize(i, objectId) > 0) {
101 return true;
102 }
103 }
104 }
105 return false;
106 }
107}
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 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.modification.internal;
7
8import tools.refinery.store.adapter.AbstractModelAdapterBuilder;
9import tools.refinery.store.dse.modification.ModificationBuilder;
10import tools.refinery.store.dse.modification.ModificationStoreAdapter;
11import tools.refinery.store.model.ModelStore;
12import tools.refinery.store.model.ModelStoreBuilder;
13import tools.refinery.store.statecoding.StateCoderBuilder;
14
15public class ModificationBuilderImpl extends AbstractModelAdapterBuilder<ModificationStoreAdapter> implements ModificationBuilder {
16
17 @Override
18 protected void doConfigure(ModelStoreBuilder storeBuilder) {
19 storeBuilder.symbols(ModificationAdapterImpl.NEXT_ID);
20 storeBuilder.tryGetAdapter(StateCoderBuilder.class).ifPresent(
21 coderBuilder -> coderBuilder.exclude(ModificationAdapterImpl.NEXT_ID));
22 super.doConfigure(storeBuilder);
23 }
24
25 @Override
26 protected ModificationStoreAdapter doBuild(ModelStore store) {
27 return new ModificationStoreAdapterImpl(store);
28 }
29}
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..62e4227b
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/modification/internal/ModificationStoreAdapterImpl.java
@@ -0,0 +1,29 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.modification.internal;
7
8import tools.refinery.store.adapter.ModelAdapter;
9import tools.refinery.store.dse.modification.ModificationStoreAdapter;
10import tools.refinery.store.model.Model;
11import tools.refinery.store.model.ModelStore;
12
13public class ModificationStoreAdapterImpl implements ModificationStoreAdapter {
14 ModelStore store;
15
16 ModificationStoreAdapterImpl(ModelStore store) {
17 this.store = store;
18 }
19
20 @Override
21 public ModelStore getStore() {
22 return store;
23 }
24
25 @Override
26 public ModelAdapter createModelAdapter(Model model) {
27 return new ModificationAdapterImpl(this, model);
28 }
29}
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 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Andras Szabolcs Nagy, Zoltan Ujhelyi and Daniel Varro
3 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools/>
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v. 2.0 which is available at
6 * http://www.eclipse.org/legal/epl-v20.html.
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *******************************************************************************/
10package tools.refinery.store.dse.objectives;
11
12import tools.refinery.store.dse.DesignSpaceExplorationAdapter;
13
14/**
15 * This hard objective is fulfilled in any circumstances. Use it if all states should be regarded as a valid solution.
16 *
17 * @author Andras Szabolcs Nagy
18 *
19 */
20public class AlwaysSatisfiedDummyHardObjective extends BaseObjective {
21
22 private static final String DEFAULT_NAME = "AlwaysSatisfiedDummyHardObjective";
23
24 public AlwaysSatisfiedDummyHardObjective() {
25 super(DEFAULT_NAME);
26 }
27
28 public AlwaysSatisfiedDummyHardObjective(String name) {
29 super(name);
30 }
31
32 @Override
33 public Double getFitness(DesignSpaceExplorationAdapter context) {
34 return 0d;
35 }
36
37 @Override
38 public boolean isHardObjective() {
39 return true;
40 }
41
42 @Override
43 public boolean satisfiesHardObjective(Double fitness) {
44 return true;
45 }
46
47 @Override
48 public Objective createNew() {
49 return this;
50 }
51
52}
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 cdd1754f..00000000
--- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/objectives/AlwaysSatisfiedRandomHardObjective.java
+++ /dev/null
@@ -1,57 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Andras Szabolcs Nagy, Zoltan Ujhelyi and Daniel Varro
3 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools/>
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v. 2.0 which is available at
6 * http://www.eclipse.org/legal/epl-v20.html.
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *******************************************************************************/
10package tools.refinery.store.dse.objectives;
11
12import tools.refinery.store.dse.DesignSpaceExplorationAdapter;
13
14import java.util.Random;
15
16/**
17 * This hard objective is fulfilled in any circumstances. Use it if all states should be regarded as a valid solution.
18 *
19 * @author Andras Szabolcs Nagy
20 *
21 */
22public class AlwaysSatisfiedRandomHardObjective extends BaseObjective {
23
24 private static final String DEFAULT_NAME = "AlwaysSatisfiedDummyHardObjective";
25 @SuppressWarnings("squid:S2245")
26 private static final Random random = new Random(0);
27
28 public AlwaysSatisfiedRandomHardObjective() {
29 super(DEFAULT_NAME);
30 }
31
32 public AlwaysSatisfiedRandomHardObjective(String name) {
33 super(name);
34 }
35
36 @Override
37 public Double getFitness(DesignSpaceExplorationAdapter context) {
38// return 0d;
39 return random.nextDouble();
40 }
41
42 @Override
43 public boolean isHardObjective() {
44 return true;
45 }
46
47 @Override
48 public boolean satisfiesHardObjective(Double fitness) {
49 return true;
50 }
51
52 @Override
53 public Objective createNew() {
54 return this;
55 }
56
57}
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 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
3 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools/>
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v. 2.0 which is available at
6 * http://www.eclipse.org/legal/epl-v20.html.
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *******************************************************************************/
10package tools.refinery.store.dse.objectives;
11
12import tools.refinery.store.dse.DesignSpaceExplorationAdapter;
13
14import java.util.Comparator;
15import java.util.Objects;
16
17/**
18 * This abstract class implements the basic functionality of an objective ({@link Objective} namely its name,
19 * comparator, level and fitness hard constraint.
20 *
21 * @author Andras Szabolcs Nagy
22 *
23 */
24public abstract class BaseObjective implements Objective {
25
26 protected final String name;
27 protected Comparator<Double> comparator = Comparators.HIGHER_IS_BETTER;
28
29 protected double fitnessConstraint;
30 protected boolean isThereFitnessConstraint = false;
31 protected Comparator<Double> fitnessConstraintComparator;
32
33 protected BaseObjective(String name) {
34 Objects.requireNonNull(name, "Name of the objective cannot be null.");
35 this.name = name;
36 }
37
38 @Override
39 public String getName() {
40 return name;
41 }
42
43 @Override
44 public void setComparator(Comparator<Double> comparator) {
45 this.comparator = comparator;
46 }
47
48 @Override
49 public Comparator<Double> getComparator() {
50 return comparator;
51 }
52
53 public BaseObjective withComparator(Comparator<Double> comparator) {
54 setComparator(comparator);
55 return this;
56 }
57
58 /**
59 * Adds a hard constraint on the fitness value. For example, the fitness value must be better than 10 to accept the
60 * current state as a solution.
61 *
62 * @param fitnessConstraint
63 * Solutions should be better than this value.
64 * @param fitnessConstraintComparator
65 * {@link Comparator} to determine if the current state is better than the given value.
66 * @return The actual instance to enable builder pattern like usage.
67 */
68 public BaseObjective withHardConstraintOnFitness(double fitnessConstraint,
69 Comparator<Double> fitnessConstraintComparator) {
70 this.fitnessConstraint = fitnessConstraint;
71 this.fitnessConstraintComparator = fitnessConstraintComparator;
72 this.isThereFitnessConstraint = true;
73 return this;
74 }
75
76 /**
77 * Adds a hard constraint on the fitness value. For example, the fitness value must be better than 10 to accept the
78 * current state as a solution. The provided comparator will be used.
79 *
80 * @param fitnessConstraint
81 * Solutions should be better than this value.
82 * @return The actual instance to enable builder pattern like usage.
83 */
84 public BaseObjective withHardConstraintOnFitness(double fitnessConstraint) {
85 return withHardConstraintOnFitness(fitnessConstraint, null);
86 }
87
88 @Override
89 public void init(DesignSpaceExplorationAdapter context) {
90 if (fitnessConstraintComparator == null) {
91 fitnessConstraintComparator = comparator;
92 }
93 }
94
95 @Override
96 public boolean isHardObjective() {
97 return isThereFitnessConstraint;
98 }
99
100 @Override
101 public boolean satisfiesHardObjective(Double fitness) {
102 if (isThereFitnessConstraint) {
103 int compare = fitnessConstraintComparator.compare(fitness, fitnessConstraint);
104 if (compare < 0) {
105 return false;
106 }
107 }
108 return true;
109 }
110
111 @Override
112 public int hashCode() {
113 return name.hashCode();
114 }
115
116 @Override
117 public boolean equals(Object obj) {
118 if (this == obj) {
119 return true;
120 }
121 if (obj instanceof BaseObjective baseObjective) {
122 return name.equals(baseObjective.getName());
123 }
124 return false;
125 }
126
127 @Override
128 public String toString() {
129 return name;
130 }
131
132}
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 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
3 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools/>
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v. 2.0 which is available at
6 * http://www.eclipse.org/legal/epl-v20.html.
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *******************************************************************************/
10package tools.refinery.store.dse.objectives;
11
12import java.util.Comparator;
13
14public class Comparators {
15
16 private Comparators() { /*Utility class constructor*/ }
17
18 public static final Comparator<Double> HIGHER_IS_BETTER = Double::compareTo;
19
20 public static final Comparator<Double> LOWER_IS_BETTER = (o1, o2) -> o2.compareTo(o1);
21
22 private static final Double ZERO = (double) 0;
23
24 public static final Comparator<Double> DIFFERENCE_TO_ZERO_IS_BETTER = (o1, o2) -> ZERO.compareTo(Math.abs(o1)-Math.abs(o2));
25
26}
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 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
3 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools/>
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v. 2.0 which is available at
6 * http://www.eclipse.org/legal/epl-v20.html.
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *******************************************************************************/
10package tools.refinery.store.dse.objectives;
11
12import java.util.HashMap;
13
14public class Fitness extends HashMap<String, Double> {
15
16 private boolean satisfiesHardObjectives;
17
18 public boolean isSatisfiesHardObjectives() {
19 return satisfiesHardObjectives;
20 }
21
22 public void setSatisfiesHardObjectives(boolean satisfiesHardObjectives) {
23 this.satisfiesHardObjectives = satisfiesHardObjectives;
24 }
25
26 @Override
27 public String toString() {
28 return super.toString() + " hardObjectives=" + satisfiesHardObjectives;
29 }
30
31 @Override
32 public boolean equals(Object other) {
33 if (other == null) return false;
34 if (getClass() != other.getClass()) return false;
35 if (!super.equals(other)) return false;
36 return satisfiesHardObjectives == ((Fitness) other).satisfiesHardObjectives;
37 }
38
39 @Override
40 public int hashCode() {
41 int h = super.hashCode();
42 h = h * 31 + (satisfiesHardObjectives ? 1 : 0);
43 return h;
44 }
45
46}
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 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Miklos Foldenyi, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
3 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools/>
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v. 2.0 which is available at
6 * http://www.eclipse.org/legal/epl-v20.html.
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *******************************************************************************/
10package tools.refinery.store.dse.objectives;
11
12import tools.refinery.store.dse.DesignSpaceExplorationAdapter;
13
14import java.util.Comparator;
15
16/**
17 *
18 * Implementation of this interface represents a single objective of the DSE problem, which can assess a solution
19 * (trajectory) in a single number. It has a name and a comparator which orders two solution based on the calculated
20 * value.
21 * <p>
22 * Objectives can be either hard or soft objectives. Hard objectives can be satisfied or unsatisfied. If all of the hard
23 * objectives are satisfied on a single solution, then it is considered to be a valid (or goal) solution.
24 * <p>
25 * Certain objectives can have inner state for calculating the fitness value. In this case a new instance is necessary
26 * for every new thread, and the {@code createNew} method should not return the same instance more than once.
27 *
28 * @author Andras Szabolcs Nagy
29 *
30 */
31public interface Objective {
32
33 /**
34 * Returns the name of the objective.
35 *
36 * @return The name of the objective.
37 */
38 String getName();
39
40 /**
41 * Sets the {@link Comparator} which is used to compare fitness (doubles). It determines whether the objective is to
42 * minimize or maximize (or minimize or maximize a delta from a given number).
43 *
44 * @param comparator The comparator.
45 */
46 void setComparator(Comparator<Double> comparator);
47
48 /**
49 * Returns a {@link Comparator} which is used to compare fitness (doubles). It determines whether the objective is
50 * to minimize or maximize (or minimize or maximize a delta from a given number).
51 *
52 * @return The comparator.
53 */
54 Comparator<Double> getComparator();
55
56 /**
57 * Calculates the value of the objective on a given solution (trajectory).
58 *
59 * @param context
60 * The {@link DesignSpaceExplorationAdapter}
61 * @return The objective value in double.
62 */
63 Double getFitness(DesignSpaceExplorationAdapter context);
64
65 /**
66 * Initializes the objective. It is called exactly once for every thread starts.
67 *
68 * @param context
69 * The {@link DesignSpaceExplorationAdapter}.
70 */
71 void init(DesignSpaceExplorationAdapter context);
72
73 /**
74 * Returns an instance of the {@link Objective}. If it returns the same instance, all the methods has to be thread
75 * save as they are called concurrently.
76 *
77 * @return An instance of the objective.
78 */
79 Objective createNew();
80
81 /**
82 * Returns true if the objective is a hard objective. In such a case the method
83 * {@link Objective#satisfiesHardObjective(Double)} is called.
84 *
85 * @return True if the objective is a hard objective.
86 * @see Objective#satisfiesHardObjective(Double)
87 * @see Objective
88 */
89 boolean isHardObjective();
90
91 /**
92 * Determines if the given fitness value satisfies the hard objective.
93 *
94 * @param fitness
95 * The fitness value of a solution.
96 * @return True if it satisfies the hard objective or it is a soft constraint.
97 * @see Objective
98 */
99 boolean satisfiesHardObjective(Double fitness);
100
101}
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 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2015, Andras Szabolcs Nagy, Abel Hegedus, Akos Horvath, Zoltan Ujhelyi and Daniel Varro
3 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools/>
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v. 2.0 which is available at
6 * http://www.eclipse.org/legal/epl-v20.html.
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *******************************************************************************/
10package tools.refinery.store.dse.objectives;
11
12import java.util.List;
13
14/**
15 * This class is responsible to compare and sort fitness values.
16 *
17 * @author András Szabolcs Nagy
18 */
19public class ObjectiveComparatorHelper {
20
21 private final List<Objective> objectives;
22
23 public ObjectiveComparatorHelper(List<Objective> objectives) {
24 this.objectives = objectives;
25 }
26
27 /**
28 * Compares two fitnesses based on dominance. Returns -1 if the second parameter {@code o2} is a better
29 * solution ({@code o2} dominates {@code o1}), 1 if the first parameter {@code o1} is better ({@code o1} dominates
30 * {@code o2}) and returns 0 if they are non-dominating each other.
31 */
32 public int compare(Fitness o1, Fitness o2) {
33
34 boolean o1HasBetterFitness = false;
35 boolean o2HasBetterFitness = false;
36
37 for (Objective objective : objectives) {
38 String objectiveName = objective.getName();
39 int sgn = objective.getComparator().compare(o1.get(objectiveName), o2.get(objectiveName));
40
41 if (sgn < 0) {
42 o2HasBetterFitness = true;
43 }
44 if (sgn > 0) {
45 o1HasBetterFitness = true;
46 }
47 if (o1HasBetterFitness && o2HasBetterFitness) {
48 break;
49 }
50 }
51 if (o2HasBetterFitness) {
52 return -1;
53 } else if (o1HasBetterFitness) {
54 return 1;
55 }
56
57 return 0;
58
59 }
60}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/BoundPropagator.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/BoundPropagator.java
new file mode 100644
index 00000000..5ad61463
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/BoundPropagator.java
@@ -0,0 +1,11 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.propagation;
7
8@FunctionalInterface
9public interface BoundPropagator {
10 PropagationResult propagateOne();
11}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/PropagationAdapter.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/PropagationAdapter.java
new file mode 100644
index 00000000..3ea5a75f
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/PropagationAdapter.java
@@ -0,0 +1,20 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.propagation;
7
8import tools.refinery.store.adapter.ModelAdapter;
9import tools.refinery.store.dse.propagation.impl.PropagationBuilderImpl;
10
11public interface PropagationAdapter extends ModelAdapter {
12 @Override
13 PropagationStoreAdapter getStoreAdapter();
14
15 PropagationResult propagate();
16
17 static PropagationBuilder builder() {
18 return new PropagationBuilderImpl();
19 }
20}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/PropagationBuilder.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/PropagationBuilder.java
new file mode 100644
index 00000000..f8a89b30
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/PropagationBuilder.java
@@ -0,0 +1,32 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.propagation;
7
8import tools.refinery.store.adapter.ModelAdapterBuilder;
9import tools.refinery.store.dse.transition.Rule;
10import tools.refinery.store.model.ModelStore;
11
12import java.util.Collection;
13import java.util.List;
14
15@SuppressWarnings("UnusedReturnValue")
16public interface PropagationBuilder extends ModelAdapterBuilder {
17 PropagationBuilder rule(Rule propagationRule);
18
19 default PropagationBuilder rules(Rule... propagationRules) {
20 return rules(List.of(propagationRules));
21 }
22
23 default PropagationBuilder rules(Collection<Rule> propagationRules) {
24 propagationRules.forEach(this::rule);
25 return this;
26 }
27
28 PropagationBuilder propagator(Propagator propagator);
29
30 @Override
31 PropagationStoreAdapter build(ModelStore store);
32}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/PropagationResult.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/PropagationResult.java
new file mode 100644
index 00000000..ea56653a
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/PropagationResult.java
@@ -0,0 +1,28 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.propagation;
7
8public enum PropagationResult {
9 UNCHANGED,
10 PROPAGATED,
11 REJECTED;
12
13 public PropagationResult andThen(PropagationResult next) {
14 return switch (this) {
15 case UNCHANGED -> next;
16 case PROPAGATED -> next == REJECTED ? REJECTED : PROPAGATED;
17 case REJECTED -> REJECTED;
18 };
19 }
20
21 public boolean isRejected() {
22 return this == REJECTED;
23 }
24
25 public boolean isChanged() {
26 return this == PROPAGATED;
27 }
28}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/PropagationStoreAdapter.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/PropagationStoreAdapter.java
new file mode 100644
index 00000000..82cba909
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/PropagationStoreAdapter.java
@@ -0,0 +1,14 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.propagation;
7
8import tools.refinery.store.adapter.ModelStoreAdapter;
9import tools.refinery.store.model.Model;
10
11public interface PropagationStoreAdapter extends ModelStoreAdapter {
12 @Override
13 PropagationAdapter createModelAdapter(Model model);
14}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/Propagator.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/Propagator.java
new file mode 100644
index 00000000..c6b4e1c9
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/Propagator.java
@@ -0,0 +1,17 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.propagation;
7
8import tools.refinery.store.model.Model;
9import tools.refinery.store.model.ModelStoreBuilder;
10
11@FunctionalInterface
12public interface Propagator {
13 default void configure(ModelStoreBuilder storeBuilder) {
14 }
15
16 BoundPropagator bindToModel(Model model);
17}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/PropagationAdapterImpl.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/PropagationAdapterImpl.java
new file mode 100644
index 00000000..fdd19217
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/PropagationAdapterImpl.java
@@ -0,0 +1,75 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.propagation.impl;
7
8import tools.refinery.store.dse.propagation.BoundPropagator;
9import tools.refinery.store.dse.propagation.PropagationAdapter;
10import tools.refinery.store.dse.propagation.PropagationResult;
11import tools.refinery.store.dse.propagation.PropagationStoreAdapter;
12import tools.refinery.store.model.Model;
13
14class PropagationAdapterImpl implements PropagationAdapter {
15 private final Model model;
16 private final PropagationStoreAdapterImpl storeAdapter;
17 private final BoundPropagator[] boundPropagators;
18
19 public PropagationAdapterImpl(Model model, PropagationStoreAdapterImpl storeAdapter) {
20 this.model = model;
21 this.storeAdapter = storeAdapter;
22 var propagators = storeAdapter.getPropagators();
23 boundPropagators = new BoundPropagator[propagators.size()];
24 for (int i = 0; i < boundPropagators.length; i++) {
25 boundPropagators[i] = propagators.get(i).bindToModel(model);
26 }
27 }
28
29 @Override
30 public PropagationResult propagate() {
31 PropagationResult result = PropagationResult.UNCHANGED;
32 PropagationResult lastResult;
33 do {
34 model.checkCancelled();
35 lastResult = propagateOne();
36 result = result.andThen(lastResult);
37 } while (lastResult.isChanged());
38 return result;
39 }
40
41 private PropagationResult propagateOne() {
42 PropagationResult result = PropagationResult.UNCHANGED;
43 for (int i = 0; i < boundPropagators.length; i++) {
44 model.checkCancelled();
45 var lastResult = propagateUntilFixedPoint(i);
46 result = result.andThen(lastResult);
47 if (result.isRejected()) {
48 break;
49 }
50 }
51 return result;
52 }
53
54 private PropagationResult propagateUntilFixedPoint(int propagatorIndex) {
55 var propagator = boundPropagators[propagatorIndex];
56 PropagationResult result = PropagationResult.UNCHANGED;
57 PropagationResult lastResult;
58 do {
59 model.checkCancelled();
60 lastResult = propagator.propagateOne();
61 result = result.andThen(lastResult);
62 } while (lastResult.isChanged());
63 return result;
64 }
65
66 @Override
67 public Model getModel() {
68 return model;
69 }
70
71 @Override
72 public PropagationStoreAdapter getStoreAdapter() {
73 return storeAdapter;
74 }
75}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/PropagationBuilderImpl.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/PropagationBuilderImpl.java
new file mode 100644
index 00000000..c844a89f
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/PropagationBuilderImpl.java
@@ -0,0 +1,53 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.propagation.impl;
7
8import tools.refinery.store.adapter.AbstractModelAdapterBuilder;
9import tools.refinery.store.dse.propagation.PropagationBuilder;
10import tools.refinery.store.dse.propagation.PropagationStoreAdapter;
11import tools.refinery.store.dse.propagation.Propagator;
12import tools.refinery.store.dse.propagation.impl.rule.RuleBasedPropagator;
13import tools.refinery.store.dse.transition.Rule;
14import tools.refinery.store.model.ModelStore;
15import tools.refinery.store.model.ModelStoreBuilder;
16
17import java.util.*;
18
19public class PropagationBuilderImpl extends AbstractModelAdapterBuilder<PropagationStoreAdapter>
20 implements PropagationBuilder {
21 private final Set<Rule> propagationRules = new LinkedHashSet<>();
22 private final Deque<Propagator> propagators = new ArrayDeque<>();
23
24 @Override
25 public PropagationBuilder rule(Rule propagationRule) {
26 checkNotConfigured();
27 propagationRules.add(propagationRule);
28 return this;
29 }
30
31 @Override
32 public PropagationBuilder propagator(Propagator propagator) {
33 checkNotConfigured();
34 propagators.addFirst(propagator);
35 return this;
36 }
37
38 @Override
39 protected void doConfigure(ModelStoreBuilder storeBuilder) {
40 super.doConfigure(storeBuilder);
41 if (!propagationRules.isEmpty()) {
42 propagators.addFirst(new RuleBasedPropagator(List.copyOf(propagationRules)));
43 }
44 for (var propagator : propagators) {
45 propagator.configure(storeBuilder);
46 }
47 }
48
49 @Override
50 protected PropagationStoreAdapter doBuild(ModelStore store) {
51 return new PropagationStoreAdapterImpl(store, List.copyOf(propagators));
52 }
53}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/PropagationStoreAdapterImpl.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/PropagationStoreAdapterImpl.java
new file mode 100644
index 00000000..a223caed
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/PropagationStoreAdapterImpl.java
@@ -0,0 +1,38 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.propagation.impl;
7
8import tools.refinery.store.dse.propagation.PropagationAdapter;
9import tools.refinery.store.dse.propagation.PropagationStoreAdapter;
10import tools.refinery.store.dse.propagation.Propagator;
11import tools.refinery.store.model.Model;
12import tools.refinery.store.model.ModelStore;
13
14import java.util.List;
15
16class PropagationStoreAdapterImpl implements PropagationStoreAdapter {
17 private final ModelStore store;
18 private final List<Propagator> propagators;
19
20 PropagationStoreAdapterImpl(ModelStore store, List<Propagator> propagators) {
21 this.store = store;
22 this.propagators = propagators;
23 }
24
25 @Override
26 public ModelStore getStore() {
27 return store;
28 }
29
30 @Override
31 public PropagationAdapter createModelAdapter(Model model) {
32 return new PropagationAdapterImpl(model, this);
33 }
34
35 List<Propagator> getPropagators() {
36 return propagators;
37 }
38}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/rule/BoundPropagationRule.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/rule/BoundPropagationRule.java
new file mode 100644
index 00000000..a70292ad
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/rule/BoundPropagationRule.java
@@ -0,0 +1,40 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.propagation.impl.rule;
7
8import tools.refinery.store.dse.propagation.PropagationResult;
9import tools.refinery.store.dse.transition.Rule;
10import tools.refinery.store.dse.transition.actions.BoundAction;
11import tools.refinery.store.model.Model;
12import tools.refinery.store.query.ModelQueryAdapter;
13import tools.refinery.store.query.resultset.ResultSet;
14
15class BoundPropagationRule {
16 private final Model model;
17 private final ResultSet<Boolean> resultSet;
18 private final BoundAction action;
19
20 public BoundPropagationRule(Model model, Rule rule) {
21 this.model = model;
22 resultSet = model.getAdapter(ModelQueryAdapter.class).getResultSet(rule.getPrecondition());
23 action = rule.createAction(model);
24 }
25
26 public PropagationResult fireAll() {
27 if (resultSet.size() == 0) {
28 return PropagationResult.UNCHANGED;
29 }
30 var cursor = resultSet.getAll();
31 while (cursor.move()) {
32 model.checkCancelled();
33 var result = action.fire(cursor.getKey());
34 if (!result) {
35 return PropagationResult.REJECTED;
36 }
37 }
38 return PropagationResult.PROPAGATED;
39 }
40}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/rule/BoundRuleBasedPropagator.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/rule/BoundRuleBasedPropagator.java
new file mode 100644
index 00000000..bd03f923
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/rule/BoundRuleBasedPropagator.java
@@ -0,0 +1,43 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.propagation.impl.rule;
7
8import tools.refinery.store.dse.propagation.BoundPropagator;
9import tools.refinery.store.dse.propagation.PropagationResult;
10import tools.refinery.store.dse.transition.Rule;
11import tools.refinery.store.model.Model;
12import tools.refinery.store.query.ModelQueryAdapter;
13
14import java.util.List;
15
16public class BoundRuleBasedPropagator implements BoundPropagator {
17 private final ModelQueryAdapter queryEngine;
18 private final BoundPropagationRule[] boundRules;
19
20 public BoundRuleBasedPropagator(Model model, List<Rule> propagationRules) {
21 queryEngine = model.getAdapter(ModelQueryAdapter.class);
22 boundRules = new BoundPropagationRule[propagationRules.size()];
23 for (int i = 0; i < boundRules.length; i++) {
24 boundRules[i] = new BoundPropagationRule(model, propagationRules.get(i));
25 }
26 }
27
28 @Override
29 public PropagationResult propagateOne() {
30 queryEngine.flushChanges();
31 PropagationResult result = PropagationResult.UNCHANGED;
32 // Use a classic for loop to avoid allocating an iterator.
33 //noinspection ForLoopReplaceableByForEach
34 for (int i = 0; i < boundRules.length; i++) {
35 var lastResult = boundRules[i].fireAll();
36 result = result.andThen(lastResult);
37 if (result.isRejected()) {
38 break;
39 }
40 }
41 return result;
42 }
43}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/rule/RuleBasedPropagator.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/rule/RuleBasedPropagator.java
new file mode 100644
index 00000000..709b2416
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/rule/RuleBasedPropagator.java
@@ -0,0 +1,36 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.propagation.impl.rule;
7
8import tools.refinery.store.dse.propagation.BoundPropagator;
9import tools.refinery.store.dse.propagation.Propagator;
10import tools.refinery.store.dse.transition.Rule;
11import tools.refinery.store.model.Model;
12import tools.refinery.store.model.ModelStoreBuilder;
13import tools.refinery.store.query.ModelQueryBuilder;
14
15import java.util.List;
16
17public class RuleBasedPropagator implements Propagator {
18 private final List<Rule> propagationRules;
19
20 public RuleBasedPropagator(List<Rule> propagationRules) {
21 this.propagationRules = propagationRules;
22 }
23
24 @Override
25 public void configure(ModelStoreBuilder storeBuilder) {
26 var queryBuilder = storeBuilder.getAdapter(ModelQueryBuilder.class);
27 for (var propagationRule : propagationRules) {
28 queryBuilder.query(propagationRule.getPrecondition());
29 }
30 }
31
32 @Override
33 public BoundPropagator bindToModel(Model model) {
34 return new BoundRuleBasedPropagator(model, propagationRules);
35 }
36}
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..5e2f8fa9
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstExplorer.java
@@ -0,0 +1,65 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.strategy;
7
8import tools.refinery.store.model.Model;
9
10import java.util.Random;
11
12public class BestFirstExplorer extends BestFirstWorker {
13 final int id;
14 Random random;
15
16 public BestFirstExplorer(BestFirstStoreManager storeManager, Model model, int id) {
17 super(storeManager, model);
18 this.id = id;
19 this.random = new Random(id);
20 }
21
22 private boolean shouldRun() {
23 model.checkCancelled();
24 return !hasEnoughSolution();
25 }
26
27 public void explore() {
28 var lastBest = submit().newVersion();
29 while (shouldRun()) {
30 if (lastBest == null) {
31 if (random.nextInt(10) == 0) {
32 lastBest = restoreToRandom(random);
33 } else {
34 lastBest = restoreToBest();
35 }
36 if (lastBest == null) {
37 return;
38 }
39 }
40 boolean tryActivation = true;
41 while (tryActivation && shouldRun()) {
42 var randomVisitResult = this.visitRandomUnvisited(random);
43 tryActivation = randomVisitResult.shouldRetry();
44 var newSubmit = randomVisitResult.submitResult();
45 if (newSubmit != null) {
46 if (!newSubmit.include()) {
47 restoreToLast();
48 } else {
49 var newVisit = newSubmit.newVersion();
50 int compareResult = compare(lastBest, newVisit);
51 if (compareResult >= 0) {
52 lastBest = newVisit;
53 } else {
54 lastBest = null;
55 }
56 break;
57 }
58 } else {
59 lastBest = null;
60 break;
61 }
62 }
63 }
64 }
65}
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..3d32f84c
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstStoreManager.java
@@ -0,0 +1,87 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.strategy;
7
8import tools.refinery.store.dse.transition.DesignSpaceExplorationStoreAdapter;
9import tools.refinery.store.dse.transition.VersionWithObjectiveValue;
10import tools.refinery.store.dse.transition.statespace.ActivationStore;
11import tools.refinery.store.dse.transition.statespace.EquivalenceClassStore;
12import tools.refinery.store.dse.transition.statespace.ObjectivePriorityQueue;
13import tools.refinery.store.dse.transition.statespace.SolutionStore;
14import tools.refinery.store.dse.transition.statespace.internal.ActivationStoreImpl;
15import tools.refinery.store.dse.transition.statespace.internal.FastEquivalenceClassStore;
16import tools.refinery.store.dse.transition.statespace.internal.ObjectivePriorityQueueImpl;
17import tools.refinery.store.dse.transition.statespace.internal.SolutionStoreImpl;
18import tools.refinery.store.map.Version;
19import tools.refinery.store.model.ModelStore;
20import tools.refinery.store.statecoding.StateCoderStoreAdapter;
21import tools.refinery.visualization.statespace.VisualizationStore;
22import tools.refinery.visualization.statespace.internal.VisualizationStoreImpl;
23
24import java.util.function.Consumer;
25
26public class BestFirstStoreManager {
27
28 ModelStore modelStore;
29 ObjectivePriorityQueue objectiveStore;
30 ActivationStore activationStore;
31 SolutionStore solutionStore;
32 EquivalenceClassStore equivalenceClassStore;
33 VisualizationStore visualizationStore;
34
35 public BestFirstStoreManager(ModelStore modelStore, int maxNumberOfSolutions) {
36 this.modelStore = modelStore;
37 DesignSpaceExplorationStoreAdapter storeAdapter =
38 modelStore.getAdapter(DesignSpaceExplorationStoreAdapter.class);
39
40 objectiveStore = new ObjectivePriorityQueueImpl(storeAdapter.getObjectives());
41 Consumer<VersionWithObjectiveValue> whenAllActivationsVisited = x -> objectiveStore.remove(x);
42 activationStore = new ActivationStoreImpl(storeAdapter.getTransformations().size(), whenAllActivationsVisited);
43 solutionStore = new SolutionStoreImpl(maxNumberOfSolutions);
44 equivalenceClassStore = new FastEquivalenceClassStore(modelStore.getAdapter(StateCoderStoreAdapter.class)) {
45 @Override
46 protected void delegate(VersionWithObjectiveValue version, int[] emptyActivations, boolean accept) {
47 throw new UnsupportedOperationException("This equivalence storage is not prepared to resolve " +
48 "symmetries!");
49 }
50 };
51 visualizationStore = new VisualizationStoreImpl();
52 }
53
54 public ModelStore getModelStore() {
55 return modelStore;
56 }
57
58 ObjectivePriorityQueue getObjectiveStore() {
59 return objectiveStore;
60 }
61
62 ActivationStore getActivationStore() {
63 return activationStore;
64 }
65
66 public SolutionStore getSolutionStore() {
67 return solutionStore;
68 }
69
70 EquivalenceClassStore getEquivalenceClassStore() {
71 return equivalenceClassStore;
72 }
73
74 public VisualizationStore getVisualizationStore() {
75 return visualizationStore;
76 }
77
78 public void startExploration(Version initial) {
79 startExploration(initial, 1);
80 }
81
82 public void startExploration(Version initial, int randomSeed) {
83 BestFirstExplorer bestFirstExplorer = new BestFirstExplorer(this, modelStore.createModelForState(initial),
84 randomSeed);
85 bestFirstExplorer.explore();
86 }
87}
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 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2016, Andras Szabolcs Nagy, Zoltan Ujhelyi and Daniel Varro
3 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools/>
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v. 2.0 which is available at
6 * http://www.eclipse.org/legal/epl-v20.html.
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *******************************************************************************/
10package tools.refinery.store.dse.strategy;
11
12import tools.refinery.store.map.Version;
13import tools.refinery.store.dse.DesignSpaceExplorationAdapter;
14import tools.refinery.store.dse.Strategy;
15import tools.refinery.store.dse.internal.Activation;
16import tools.refinery.store.dse.objectives.Fitness;
17import tools.refinery.store.dse.objectives.ObjectiveComparatorHelper;
18
19import java.util.*;
20
21public class BestFirstStrategy implements Strategy {
22
23 private DesignSpaceExplorationAdapter dseAdapter;
24
25 private int maxDepth = Integer.MAX_VALUE;
26 private int maxSolutions = Integer.MAX_VALUE;
27 private boolean backTrackIfSolution = true;
28 private boolean onlyBetterFirst = false;
29
30 private PriorityQueue<TrajectoryWithFitness> trajectoriesToExplore;
31
32 private record TrajectoryWithFitness(List<Version> trajectory, Fitness fitness) {
33 @Override
34 public String toString() {
35 return trajectory.toString() + fitness.toString();
36 }
37
38 @Override
39 public int hashCode() {
40 return trajectory.get(trajectory.size() - 1).hashCode();
41 }
42
43 @Override
44 public boolean equals(Object obj) {
45 if (obj instanceof TrajectoryWithFitness other) {
46 return Objects.equals(trajectory.get(trajectory.size() - 1), other.trajectory.get(other.trajectory.size() - 1));
47// return trajectory.equals(((TrajectoryWithFitness) obj).trajectory);
48 }
49 return false;
50 }
51 }
52
53 public BestFirstStrategy withDepthLimit(int maxDepth) {
54 if (maxDepth >= 0) {
55 this.maxDepth = maxDepth;
56 }
57 return this;
58 }
59
60 public BestFirstStrategy withSolutionLimit(int maxSolutions) {
61 if (maxSolutions >= 0) {
62 this.maxSolutions = maxSolutions;
63 }
64 return this;
65 }
66
67 public BestFirstStrategy continueIfHardObjectivesFulfilled() {
68 backTrackIfSolution = false;
69 return this;
70 }
71
72 public BestFirstStrategy goOnOnlyIfFitnessIsBetter() {
73 onlyBetterFirst = true;
74 return this;
75 }
76
77 @Override
78 public void initialize(DesignSpaceExplorationAdapter designSpaceExplorationAdapter) {
79 this.dseAdapter = designSpaceExplorationAdapter;
80 final ObjectiveComparatorHelper objectiveComparatorHelper = dseAdapter.getObjectiveComparatorHelper();
81
82 trajectoriesToExplore = new PriorityQueue<>(11,
83 (o1, o2) -> objectiveComparatorHelper.compare(o2.fitness, o1.fitness));
84 }
85
86 @Override
87 public void explore() {
88 if (maxSolutions == 0) {
89 return;
90 }
91 final ObjectiveComparatorHelper objectiveComparatorHelper = dseAdapter.getObjectiveComparatorHelper();
92
93 boolean globalConstraintsAreSatisfied = dseAdapter.checkGlobalConstraints();
94 if (!globalConstraintsAreSatisfied) {
95 // Global constraint is not satisfied in the first state. Terminate.
96 return;
97 }
98
99 final Fitness firstFitness = dseAdapter.getFitness();
100 if (firstFitness.isSatisfiesHardObjectives()) {
101 dseAdapter.newSolution();
102 // First state is a solution. Terminate.
103 if (backTrackIfSolution) {
104 return;
105 }
106 }
107
108 if (maxDepth == 0) {
109 return;
110 }
111
112
113 var firstTrajectoryWithFitness = new TrajectoryWithFitness(dseAdapter.getTrajectory(), firstFitness);
114 trajectoriesToExplore.add(firstTrajectoryWithFitness);
115 TrajectoryWithFitness currentTrajectoryWithFitness = null;
116
117 mainLoop: while (true) {
118
119 if (currentTrajectoryWithFitness == null) {
120 if (trajectoriesToExplore.isEmpty()) {
121 // State space is fully traversed.
122 return;
123 } else {
124 currentTrajectoryWithFitness = trajectoriesToExplore.element();
125 // New trajectory is chosen: " + currentTrajectoryWithFitness
126 dseAdapter.restoreTrajectory(currentTrajectoryWithFitness.trajectory);
127 }
128 }
129
130 Collection<Activation> activations = dseAdapter.getUntraversedActivations();
131 Iterator<Activation> iterator = activations.iterator();
132
133
134
135 while (iterator.hasNext()) {
136 final Activation nextActivation = iterator.next();
137 if (!iterator.hasNext()) {
138 // Last untraversed activation of the state.
139 trajectoriesToExplore.remove(currentTrajectoryWithFitness);
140 }
141
142 // Executing new activation
143 dseAdapter.fireActivation(nextActivation);
144 if (dseAdapter.isCurrentStateAlreadyTraversed()) {
145 // The new state is already visited.
146 dseAdapter.backtrack();
147 } else if (!dseAdapter.checkGlobalConstraints()) {
148 // Global constraint is not satisfied.
149 dseAdapter.backtrack();
150 } else {
151 final Fitness nextFitness = dseAdapter.getFitness();
152 if (nextFitness.isSatisfiesHardObjectives()) {
153 dseAdapter.newSolution();
154 var solutions = dseAdapter.getSolutions().size();
155 if (solutions >= maxSolutions) {
156 return;
157 }
158 // Found a solution.
159 if (backTrackIfSolution) {
160 dseAdapter.backtrack();
161 continue;
162 }
163 }
164 if (dseAdapter.getDepth() >= maxDepth) {
165 // Reached max depth.
166 dseAdapter.backtrack();
167 continue;
168 }
169
170 TrajectoryWithFitness nextTrajectoryWithFitness = new TrajectoryWithFitness(
171 dseAdapter.getTrajectory(), nextFitness);
172 trajectoriesToExplore.add(nextTrajectoryWithFitness);
173
174 int compare = objectiveComparatorHelper.compare(currentTrajectoryWithFitness.fitness,
175 nextTrajectoryWithFitness.fitness);
176 if (compare < 0) {
177 // Better fitness, moving on
178 currentTrajectoryWithFitness = nextTrajectoryWithFitness;
179 continue mainLoop;
180 } else if (compare == 0) {
181 if (onlyBetterFirst) {
182 // Equally good fitness, backtrack
183 dseAdapter.backtrack();
184 } else {
185 // Equally good fitness, moving on
186 currentTrajectoryWithFitness = nextTrajectoryWithFitness;
187 continue mainLoop;
188 }
189 } else {
190 //"Worse fitness
191 currentTrajectoryWithFitness = null;
192 continue mainLoop;
193 }
194 }
195 }
196
197 // State is fully traversed.
198 currentTrajectoryWithFitness = null;
199
200 }
201 // Interrupted.
202 }
203}
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..aca800a3
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstWorker.java
@@ -0,0 +1,164 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.strategy;
7
8import org.jetbrains.annotations.Nullable;
9import tools.refinery.store.dse.propagation.PropagationAdapter;
10import tools.refinery.store.dse.transition.DesignSpaceExplorationAdapter;
11import tools.refinery.store.dse.transition.ObjectiveValue;
12import tools.refinery.store.dse.transition.VersionWithObjectiveValue;
13import tools.refinery.store.dse.transition.statespace.internal.ActivationStoreWorker;
14import tools.refinery.store.map.Version;
15import tools.refinery.store.model.Model;
16import tools.refinery.store.query.ModelQueryAdapter;
17import tools.refinery.store.statecoding.StateCoderAdapter;
18import tools.refinery.visualization.statespace.VisualizationStore;
19
20import java.util.Random;
21
22public class BestFirstWorker {
23 final BestFirstStoreManager storeManager;
24 final Model model;
25 final ActivationStoreWorker activationStoreWorker;
26 final StateCoderAdapter stateCoderAdapter;
27 final DesignSpaceExplorationAdapter explorationAdapter;
28 final ModelQueryAdapter queryAdapter;
29 final @Nullable PropagationAdapter propagationAdapter;
30 final VisualizationStore visualizationStore;
31 final boolean isVisualizationEnabled;
32
33 public BestFirstWorker(BestFirstStoreManager storeManager, Model model) {
34 this.storeManager = storeManager;
35 this.model = model;
36
37 explorationAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
38 stateCoderAdapter = model.getAdapter(StateCoderAdapter.class);
39 queryAdapter = model.getAdapter(ModelQueryAdapter.class);
40 propagationAdapter = model.tryGetAdapter(PropagationAdapter.class).orElse(null);
41 activationStoreWorker = new ActivationStoreWorker(storeManager.getActivationStore(),
42 explorationAdapter.getTransformations());
43 visualizationStore = storeManager.getVisualizationStore();
44 isVisualizationEnabled = visualizationStore != null;
45 }
46
47 protected VersionWithObjectiveValue last = null;
48
49 public SubmitResult submit() {
50 checkSynchronized();
51 if (queryAdapter.hasPendingChanges()) {
52 throw new AssertionError("Pending changes detected before model submission");
53 }
54 if (explorationAdapter.checkExclude()) {
55 return new SubmitResult(false, false, null, null);
56 }
57
58 var code = stateCoderAdapter.calculateStateCode();
59
60 boolean isNew = storeManager.getEquivalenceClassStore().submit(code);
61 if (isNew) {
62 Version version = model.commit();
63 ObjectiveValue objectiveValue = explorationAdapter.getObjectiveValue();
64 var versionWithObjectiveValue = new VersionWithObjectiveValue(version, objectiveValue);
65 last = versionWithObjectiveValue;
66 var accepted = explorationAdapter.checkAccept();
67
68 storeManager.getObjectiveStore().submit(versionWithObjectiveValue);
69 storeManager.getActivationStore().markNewAsVisited(versionWithObjectiveValue, activationStoreWorker.calculateEmptyActivationSize());
70 if(accepted) {
71 storeManager.solutionStore.submit(versionWithObjectiveValue);
72 }
73
74 if (isVisualizationEnabled) {
75 visualizationStore.addState(last.version(), last.objectiveValue().toString());
76 if (accepted) {
77 visualizationStore.addSolution(last.version());
78 }
79 }
80
81 return new SubmitResult(true, accepted, objectiveValue, last);
82 }
83
84 return new SubmitResult(false, false, null, null);
85 }
86
87 public void restoreToLast() {
88 if (explorationAdapter.getModel().hasUncommittedChanges()) {
89 explorationAdapter.getModel().restore(last.version());
90 }
91 }
92
93 public VersionWithObjectiveValue restoreToBest() {
94 var bestVersion = storeManager.getObjectiveStore().getBest();
95 last = bestVersion;
96 if (bestVersion != null) {
97 this.model.restore(bestVersion.version());
98 }
99 return last;
100 }
101
102 public VersionWithObjectiveValue restoreToRandom(Random random) {
103 var objectiveStore = storeManager.getObjectiveStore();
104 if (objectiveStore.getSize() == 0) {
105 return null;
106 }
107 var randomVersion = objectiveStore.getRandom(random);
108 last = randomVersion;
109 if (randomVersion != null) {
110 this.model.restore(randomVersion.version());
111 }
112 return last;
113 }
114
115 public int compare(VersionWithObjectiveValue s1, VersionWithObjectiveValue s2) {
116 return storeManager.getObjectiveStore().getComparator().compare(s1, s2);
117 }
118
119 public record RandomVisitResult(SubmitResult submitResult, boolean shouldRetry) {
120 }
121
122 public RandomVisitResult visitRandomUnvisited(Random random) {
123 checkSynchronized();
124 if (model.hasUncommittedChanges()) {
125 throw new IllegalStateException("The model has uncommitted changes!");
126 }
127
128 var visitResult = activationStoreWorker.fireRandomActivation(this.last, random);
129
130 if (!visitResult.successfulVisit()) {
131 return new RandomVisitResult(null, visitResult.mayHaveMore());
132 }
133
134 if (propagationAdapter != null) {
135 var propagationResult = propagationAdapter.propagate();
136 if (propagationResult.isRejected()) {
137 return new RandomVisitResult(null, visitResult.mayHaveMore());
138 }
139 }
140 queryAdapter.flushChanges();
141
142 Version oldVersion = null;
143 if (isVisualizationEnabled) {
144 oldVersion = last.version();
145 }
146 var submitResult = submit();
147 if (isVisualizationEnabled && submitResult.newVersion() != null) {
148 var newVersion = submitResult.newVersion().version();
149 visualizationStore.addTransition(oldVersion, newVersion,
150 "fire: " + visitResult.transformation() + ", " + visitResult.activation());
151 }
152 return new RandomVisitResult(submitResult, visitResult.mayHaveMore());
153 }
154
155 public boolean hasEnoughSolution() {
156 return storeManager.solutionStore.hasEnoughSolution();
157 }
158
159 private void checkSynchronized() {
160 if (last != null && !last.version().equals(model.getState())) {
161 throw new AssertionError("Worker is not synchronized with model state");
162 }
163 }
164}
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 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.strategy;
7
8import tools.refinery.store.dse.DesignSpaceExplorationAdapter;
9import tools.refinery.store.dse.Strategy;
10import tools.refinery.store.dse.objectives.Fitness;
11
12public class DepthFirstStrategy implements Strategy {
13
14 private DesignSpaceExplorationAdapter dseAdapter;
15
16 private int maxDepth = Integer.MAX_VALUE;
17 private int maxSolutions = Integer.MAX_VALUE;
18 private boolean backtrackFromSolution = true;
19
20 public DepthFirstStrategy withDepthLimit(int maxDepth) {
21 if (maxDepth >= 0) {
22 this.maxDepth = maxDepth;
23 }
24 return this;
25 }
26
27 public DepthFirstStrategy withSolutionLimit(int maxSolutions) {
28 if (maxSolutions >= 0) {
29 this.maxSolutions = maxSolutions;
30 }
31 return this;
32 }
33
34 public DepthFirstStrategy continueIfHardObjectivesFulfilled() {
35 backtrackFromSolution = false;
36 return this;
37 }
38
39 @Override
40 public void initialize(DesignSpaceExplorationAdapter designSpaceExplorationAdapter) {
41 this.dseAdapter = designSpaceExplorationAdapter;
42 }
43
44 @Override
45 public void explore() {
46 if (maxSolutions == 0) {
47 return;
48 }
49 while (dseAdapter.getSolutions().size() < maxSolutions) {
50 if (!checkAndHandleGlobalConstraints()) {
51 return;
52 }
53
54 Fitness fitness = dseAdapter.getFitness();
55 if (fitness.isSatisfiesHardObjectives()) {
56 dseAdapter.newSolution();
57 if (backtrackFromSolution && !dseAdapter.backtrack()) {
58 return;
59 }
60 }
61
62 if (!checkAndHandleDepth()) {
63 return;
64 }
65
66 if (!backtrackToLastUntraversed()) {
67 return;
68 }
69
70 if (!dseAdapter.fireRandomActivation()) {
71 return;
72 }
73 }
74 }
75
76 private boolean checkAndHandleGlobalConstraints() {
77 return dseAdapter.checkGlobalConstraints() || dseAdapter.backtrack();
78 }
79
80 private boolean checkAndHandleDepth() {
81 return dseAdapter.getDepth() < maxDepth || dseAdapter.backtrack();
82 }
83
84 private boolean backtrackToLastUntraversed() {
85 while (dseAdapter.getUntraversedActivations().isEmpty()) {
86 if (!dseAdapter.backtrack()) {
87 return false;
88 }
89 }
90 return true;
91 }
92}
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 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.strategy;
7
8import tools.refinery.store.dse.transition.ObjectiveValue;
9import tools.refinery.store.dse.transition.VersionWithObjectiveValue;
10import tools.refinery.store.map.Version;
11
12public record SubmitResult(boolean include, boolean accepted, ObjectiveValue objective, VersionWithObjectiveValue newVersion) {
13
14 }
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..d326f1dd
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/DesignSpaceExplorationAdapter.java
@@ -0,0 +1,28 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition;
7
8import tools.refinery.store.adapter.ModelAdapter;
9import tools.refinery.store.dse.transition.internal.DesignSpaceExplorationBuilderImpl;
10
11import java.util.List;
12
13public interface DesignSpaceExplorationAdapter extends ModelAdapter {
14 @Override
15 DesignSpaceExplorationStoreAdapter getStoreAdapter();
16
17 static DesignSpaceExplorationBuilder builder() {
18 return new DesignSpaceExplorationBuilderImpl();
19 }
20
21 List<Transformation> getTransformations();
22
23 boolean checkAccept();
24
25 boolean checkExclude();
26
27 ObjectiveValue getObjectiveValue();
28}
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..800cf8f7
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/DesignSpaceExplorationBuilder.java
@@ -0,0 +1,61 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition;
7
8import tools.refinery.store.adapter.ModelAdapterBuilder;
9import tools.refinery.store.dse.transition.objectives.Criterion;
10import tools.refinery.store.dse.transition.objectives.Objective;
11
12import java.util.Collection;
13import java.util.List;
14
15// Builder pattern with methods returning {@code this} for convenience.
16@SuppressWarnings("UnusedReturnValue")
17public interface DesignSpaceExplorationBuilder extends ModelAdapterBuilder {
18 DesignSpaceExplorationBuilder transformation(Rule transformationRuleDefinition);
19
20 default DesignSpaceExplorationBuilder transformations(Rule... transformationRuleDefinitions) {
21 return transformations(List.of(transformationRuleDefinitions));
22 }
23
24 default DesignSpaceExplorationBuilder transformations(Collection<? extends Rule> transformationRules) {
25 transformationRules.forEach(this::transformation);
26 return this;
27 }
28
29 DesignSpaceExplorationBuilder accept(Criterion criteria);
30
31 default DesignSpaceExplorationBuilder accept(Criterion... criteria) {
32 return accept(List.of(criteria));
33 }
34
35 default DesignSpaceExplorationBuilder accept(Collection<Criterion> criteria) {
36 criteria.forEach(this::accept);
37 return this;
38 }
39
40 DesignSpaceExplorationBuilder exclude(Criterion criteria);
41
42 default DesignSpaceExplorationBuilder exclude(Criterion... criteria) {
43 return exclude(List.of(criteria));
44 }
45
46 default DesignSpaceExplorationBuilder exclude(Collection<Criterion> criteria) {
47 criteria.forEach(this::exclude);
48 return this;
49 }
50
51 DesignSpaceExplorationBuilder objective(Objective objective);
52
53 default DesignSpaceExplorationBuilder objectives(Objective... objectives) {
54 return objectives(List.of(objectives));
55 }
56
57 default DesignSpaceExplorationBuilder objectives(Collection<? extends Objective> objectives) {
58 objectives.forEach(this::objective);
59 return this;
60 }
61}
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..fb082fae
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/DesignSpaceExplorationStoreAdapter.java
@@ -0,0 +1,27 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition;
7
8import tools.refinery.store.adapter.ModelStoreAdapter;
9import tools.refinery.store.dse.transition.objectives.Criterion;
10import tools.refinery.store.dse.transition.objectives.Objective;
11import tools.refinery.store.model.Model;
12
13import java.util.List;
14
15public interface DesignSpaceExplorationStoreAdapter extends ModelStoreAdapter
16{
17 @Override
18 DesignSpaceExplorationAdapter createModelAdapter(Model model);
19
20 List<Rule> getTransformations();
21
22 List<Criterion> getAccepts();
23
24 List<Criterion> getExcludes();
25
26 List<Objective> getObjectives();
27}
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 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition;
7
8public interface ObjectiveValue {
9 double get(int index);
10 int getSize();
11
12 static ObjectiveValue of(double v1) {
13 return new ObjectiveValues.ObjectiveValue1(v1);
14 }
15
16 static ObjectiveValue of(double v1, double v2) {
17 return new ObjectiveValues.ObjectiveValue2(v1,v2);
18 }
19
20 static ObjectiveValue of(double[] v) {
21 return new ObjectiveValues.ObjectiveValueN(v);
22 }
23
24}
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 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition;
7
8import java.util.Arrays;
9
10public interface ObjectiveValues {
11 public record ObjectiveValue1(double value0) implements ObjectiveValue {
12 @Override
13 public double get(int index) {
14 if(index == 0) return value0;
15 else throw new IllegalArgumentException("No value at " + index);
16 }
17
18 @Override
19 public int getSize() {
20 return 1;
21 }
22 }
23 public record ObjectiveValue2(double value0, double value1) implements ObjectiveValue {
24 @Override
25 public double get(int index) {
26 if(index == 0) return value0;
27 else if(index == 1) return value1;
28 else throw new IllegalArgumentException("No value at " + index);
29 }
30
31 @Override
32 public int getSize() {
33 return 2;
34 }
35 }
36 public record ObjectiveValueN(double[] values) implements ObjectiveValue {
37 @Override
38 public double get(int index) {
39 return values[index];
40 }
41
42 @Override
43 public int getSize() {
44 return values().length;
45 }
46
47 @Override
48 public boolean equals(Object o) {
49 if (this == o) return true;
50 if (o == null || getClass() != o.getClass()) return false;
51
52 ObjectiveValueN that = (ObjectiveValueN) o;
53
54 return Arrays.equals(values, that.values);
55 }
56
57 @Override
58 public int hashCode() {
59 return Arrays.hashCode(values);
60 }
61
62 @Override
63 public String toString() {
64 return "ObjectiveValueN{" +
65 "values=" + Arrays.toString(values) +
66 '}';
67 }
68 }
69}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/Rule.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/Rule.java
new file mode 100644
index 00000000..ff45ed3e
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/Rule.java
@@ -0,0 +1,99 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition;
7
8import tools.refinery.store.dse.transition.actions.Action;
9import tools.refinery.store.dse.transition.actions.BoundAction;
10import tools.refinery.store.dse.transition.callback.*;
11import tools.refinery.store.model.Model;
12import tools.refinery.store.query.dnf.RelationalQuery;
13
14public class Rule {
15 private final String name;
16 private final RelationalQuery precondition;
17 private final Action action;
18
19 public Rule(String name, RelationalQuery precondition, Action action) {
20 if (precondition.arity() != action.getArity()) {
21 throw new IllegalArgumentException("Expected an action clause with %d parameters, got %d instead"
22 .formatted(precondition.arity(), action.getArity()));
23 }
24 this.name = name;
25 this.precondition = precondition;
26 this.action = action;
27 }
28
29 public String getName() {
30 return name;
31 }
32
33 public RelationalQuery getPrecondition() {
34 return precondition;
35 }
36
37 public BoundAction createAction(Model model) {
38 return action.bindToModel(model);
39 }
40
41 public static RuleBuilder builder(String name) {
42 return new RuleBuilder(name);
43 }
44
45 public static RuleBuilder builder() {
46 return builder(null);
47 }
48
49 public static Rule of(String name, RuleCallback0 callback) {
50 var builder = builder(name);
51 callback.accept(builder);
52 return builder.build();
53 }
54
55 public static Rule of(RuleCallback0 callback) {
56 return of(null, callback);
57 }
58
59 public static Rule of(String name, RuleCallback1 callback) {
60 var builder = builder(name);
61 callback.accept(builder, builder.parameter("p1"));
62 return builder.build();
63 }
64
65 public static Rule of(RuleCallback1 callback) {
66 return of(null, callback);
67 }
68
69 public static Rule of(String name, RuleCallback2 callback) {
70 var builder = builder(name);
71 callback.accept(builder, builder.parameter("p1"), builder.parameter("p2"));
72 return builder.build();
73 }
74
75 public static Rule of(RuleCallback2 callback) {
76 return of(null, callback);
77 }
78
79 public static Rule of(String name, RuleCallback3 callback) {
80 var builder = builder(name);
81 callback.accept(builder, builder.parameter("p1"), builder.parameter("p2"), builder.parameter("p3"));
82 return builder.build();
83 }
84
85 public static Rule of(RuleCallback3 callback) {
86 return of(null, callback);
87 }
88
89 public static Rule of(String name, RuleCallback4 callback) {
90 var builder = builder(name);
91 callback.accept(builder, builder.parameter("p1"), builder.parameter("p2"), builder.parameter("p3"),
92 builder.parameter("p4"));
93 return builder.build();
94 }
95
96 public static Rule of(RuleCallback4 callback) {
97 return of(null, callback);
98 }
99}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/RuleBuilder.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/RuleBuilder.java
new file mode 100644
index 00000000..865ac369
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/RuleBuilder.java
@@ -0,0 +1,71 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition;
7
8import tools.refinery.store.dse.transition.actions.Action;
9import tools.refinery.store.dse.transition.actions.ActionLiteral;
10import tools.refinery.store.dse.transition.callback.*;
11import tools.refinery.store.query.dnf.AbstractQueryBuilder;
12import tools.refinery.store.query.dnf.Dnf;
13import tools.refinery.store.query.term.Variable;
14
15import java.util.List;
16
17public class RuleBuilder extends AbstractQueryBuilder<RuleBuilder> {
18 private final String name;
19 private List<ActionLiteral> action;
20
21 RuleBuilder(String name) {
22 super(Dnf.builder(name == null ? null : name + "#precondition"));
23 this.name = name;
24 }
25
26 @Override
27 protected RuleBuilder self() {
28 return this;
29 }
30
31 public RuleBuilder action(ActionLiteral... literals) {
32 return action(List.of(literals));
33 }
34
35 public RuleBuilder action(List<? extends ActionLiteral> literals) {
36 if (this.action != null) {
37 throw new IllegalStateException("Actions have already been set");
38 }
39 this.action = List.copyOf(literals);
40 return this;
41 }
42
43 public RuleBuilder action(Action action) {
44 return action(action.getActionLiterals());
45 }
46
47 public RuleBuilder action(ActionCallback0 callback) {
48 return action(callback.toLiterals());
49 }
50
51 public RuleBuilder action(ActionCallback1 callback) {
52 return action(callback.toLiterals(Variable.of("v1")));
53 }
54
55 public RuleBuilder action(ActionCallback2 callback) {
56 return action(callback.toLiterals(Variable.of("v1"), Variable.of("v2")));
57 }
58
59 public RuleBuilder action(ActionCallback3 callback) {
60 return action(callback.toLiterals(Variable.of("v1"), Variable.of("v2"), Variable.of("v3")));
61 }
62
63 public RuleBuilder action(ActionCallback4 callback) {
64 return action(callback.toLiterals(Variable.of("v1"), Variable.of("v2"), Variable.of("v3"), Variable.of("v4")));
65 }
66
67 public Rule build() {
68 var precondition = dnfBuilder.build().asRelation();
69 return new Rule(name, precondition, Action.ofPrecondition(precondition, action));
70 }
71}
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..0eeccbdf
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/Transformation.java
@@ -0,0 +1,43 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition;
7
8import tools.refinery.store.dse.transition.actions.BoundAction;
9import tools.refinery.store.model.Model;
10import tools.refinery.store.query.ModelQueryAdapter;
11import tools.refinery.store.query.resultset.OrderedResultSet;
12import tools.refinery.store.query.resultset.ResultSet;
13import tools.refinery.store.tuple.Tuple;
14
15public class Transformation {
16 private final Rule definition;
17 private final OrderedResultSet<Boolean> activations;
18 private final BoundAction action;
19
20 public Transformation(Model model, Rule definition) {
21 this.definition = definition;
22 var precondition = definition.getPrecondition();
23 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
24 activations = new OrderedResultSet<>(queryEngine.getResultSet(precondition));
25 action = definition.createAction(model);
26 }
27
28 public Rule getDefinition() {
29 return definition;
30 }
31
32 public ResultSet<Boolean> getAllActivationsAsResultSet() {
33 return activations;
34 }
35
36 public Tuple getActivation(int index) {
37 return activations.getKey(index);
38 }
39
40 public boolean fireActivation(Tuple activation) {
41 return action.fire(activation);
42 }
43}
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 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition;
7
8import tools.refinery.store.map.Version;
9
10public record VersionWithObjectiveValue(Version version, ObjectiveValue objectiveValue) {
11}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/AbstractActionLiteral.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/AbstractActionLiteral.java
new file mode 100644
index 00000000..e30f06bb
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/AbstractActionLiteral.java
@@ -0,0 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.actions;
7
8public abstract class AbstractActionLiteral implements ActionLiteral {
9}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/Action.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/Action.java
new file mode 100644
index 00000000..d63ddfdd
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/Action.java
@@ -0,0 +1,132 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.actions;
7
8import org.eclipse.collections.api.factory.primitive.ObjectIntMaps;
9import org.eclipse.collections.api.map.primitive.MutableObjectIntMap;
10import org.jetbrains.annotations.Nullable;
11import tools.refinery.store.model.Model;
12import tools.refinery.store.query.dnf.RelationalQuery;
13import tools.refinery.store.query.dnf.SymbolicParameter;
14import tools.refinery.store.query.term.NodeVariable;
15
16import java.util.*;
17
18public class Action {
19 private final List<NodeVariable> parameters;
20 private final Set<NodeVariable> localVariables;
21 private final List<ActionLiteral> actionLiterals;
22 private final int[] @Nullable [] inputAllocations;
23 private final int[] @Nullable [] outputAllocations;
24
25 public Action(List<NodeVariable> parameters, List<? extends ActionLiteral> actionLiterals) {
26 this.parameters = List.copyOf(parameters);
27 this.actionLiterals = List.copyOf(actionLiterals);
28 var allocation = ObjectIntMaps.mutable.<NodeVariable>empty();
29 int arity = parameters.size();
30 for (int i = 0; i < arity; i++) {
31 allocation.put(parameters.get(i), i);
32 }
33 var mutableLocalVariables = new LinkedHashSet<NodeVariable>();
34 int size = actionLiterals.size();
35 inputAllocations = new int[size][];
36 outputAllocations = new int[size][];
37 for (int i = 0; i < size; i++) {
38 computeInputAllocation(i, parameters, allocation);
39 computeOutputAllocation(i, mutableLocalVariables, allocation);
40 }
41 this.localVariables = Collections.unmodifiableSet(mutableLocalVariables);
42 }
43
44 private void computeInputAllocation(int actionIndex, List<NodeVariable> parameters,
45 MutableObjectIntMap<NodeVariable> allocation) {
46 var actionLiteral = actionLiterals.get(actionIndex);
47 var inputVariables = actionLiteral.getInputVariables();
48 if (inputVariables.equals(parameters)) {
49 // Identity mappings use a {@code null} allocation to pass the activation tuple unchanged.
50 return;
51 }
52 var inputs = new int[inputVariables.size()];
53 for (int i = 0; i < inputs.length; i++) {
54 var variable = inputVariables.get(i);
55 if (!allocation.containsKey(variable)) {
56 throw new IllegalArgumentException("Unbound input variable %s of action literal %s"
57 .formatted(variable, actionLiteral));
58 }
59 inputs[i] = allocation.get(variable);
60 }
61 inputAllocations[actionIndex] = inputs;
62 }
63
64 private void computeOutputAllocation(int actionIndex, Set<NodeVariable> mutableLocalVariable,
65 MutableObjectIntMap<NodeVariable> allocation) {
66 var actionLiteral = actionLiterals.get(actionIndex);
67 var outputVariables = actionLiteral.getOutputVariables();
68 int size = outputVariables.size();
69 if (size == 0) {
70 // Identity mappings use a {@code null} allocation to avoid iterating over the output tuple.
71 return;
72 }
73 if (size >= 2 && new HashSet<>(outputVariables).size() != size) {
74 throw new IllegalArgumentException("Action literal %s has duplicate output variables %s"
75 .formatted(actionLiteral, outputVariables));
76 }
77 int arity = parameters.size();
78 var outputs = new int[size];
79 for (int i = 0; i < size; i++) {
80 var variable = outputVariables.get(i);
81 if (allocation.containsKey(variable)) {
82 throw new IllegalArgumentException("Output variable %s of action literal %s was already assigned"
83 .formatted(variable, actionLiteral));
84 }
85 int variableId = mutableLocalVariable.size();
86 allocation.put(variable, arity + variableId);
87 outputs[i] = variableId;
88 mutableLocalVariable.add(variable);
89 }
90 outputAllocations[actionIndex] = outputs;
91 }
92
93 public List<NodeVariable> getParameters() {
94 return parameters;
95 }
96
97 public int getArity() {
98 return parameters.size();
99 }
100
101 public Set<NodeVariable> getLocalVariables() {
102 return localVariables;
103 }
104
105 public List<ActionLiteral> getActionLiterals() {
106 return actionLiterals;
107 }
108
109 int @Nullable [] getInputAllocation(int actionIndex) {
110 return inputAllocations[actionIndex];
111 }
112
113 int @Nullable [] getOutputAllocation(int actionIndex) {
114 return outputAllocations[actionIndex];
115 }
116
117 public BoundAction bindToModel(Model model) {
118 return new BoundAction(this, model);
119 }
120
121 public static Action ofSymbolicParameters(List<SymbolicParameter> symbolicParameters,
122 List<? extends ActionLiteral> actionLiterals) {
123 var nodeVariables = symbolicParameters.stream()
124 .map(symbolicParameter -> symbolicParameter.getVariable().asNodeVariable())
125 .toList();
126 return new Action(nodeVariables, actionLiterals);
127 }
128
129 public static Action ofPrecondition(RelationalQuery precondition, List<? extends ActionLiteral> actionLiterals) {
130 return ofSymbolicParameters(precondition.getDnf().getSymbolicParameters(), actionLiterals);
131 }
132}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/ActionLiteral.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/ActionLiteral.java
new file mode 100644
index 00000000..a721ef73
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/ActionLiteral.java
@@ -0,0 +1,19 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.actions;
7
8import tools.refinery.store.model.Model;
9import tools.refinery.store.query.term.NodeVariable;
10
11import java.util.List;
12
13public interface ActionLiteral {
14 List<NodeVariable> getInputVariables();
15
16 List<NodeVariable> getOutputVariables();
17
18 BoundActionLiteral bindToModel(Model model);
19}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/ActionLiterals.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/ActionLiterals.java
new file mode 100644
index 00000000..275e1e25
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/ActionLiterals.java
@@ -0,0 +1,33 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.actions;
7
8import tools.refinery.store.query.term.NodeVariable;
9import tools.refinery.store.representation.Symbol;
10
11import java.util.List;
12import java.util.Objects;
13
14public final class ActionLiterals {
15 private ActionLiterals() {
16 throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly");
17 }
18
19 public static <T> PutActionLiteral<T> put(Symbol<T> symbol, T value, NodeVariable... parameters) {
20 return new PutActionLiteral<>(symbol, value, List.of(parameters));
21 }
22
23 public static PutActionLiteral<Boolean> add(Symbol<Boolean> symbol, NodeVariable... parameters) {
24 if (!Objects.equals(symbol.defaultValue(), false)) {
25 throw new IllegalArgumentException("Use put to add a value to symbols other than two-valued logic");
26 }
27 return put(symbol, true, parameters);
28 }
29
30 public static <T> PutActionLiteral<T> remove(Symbol<T> symbol, NodeVariable... parameters) {
31 return put(symbol, symbol.defaultValue(), parameters);
32 }
33}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/BoundAction.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/BoundAction.java
new file mode 100644
index 00000000..4da609fa
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/BoundAction.java
@@ -0,0 +1,119 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.actions;
7
8import org.jetbrains.annotations.Nullable;
9import tools.refinery.store.model.Model;
10import tools.refinery.store.tuple.Tuple;
11
12public class BoundAction {
13 private final Action action;
14 private final Model model;
15 private BoundActionLiteral @Nullable [] boundLiterals;
16 private Tuple activation;
17 private final int[] localVariables;
18
19 BoundAction(Action action, Model model) {
20 this.action = action;
21 this.model = model;
22 localVariables = new int[action.getLocalVariables().size()];
23 }
24
25 public boolean fire(Tuple activation) {
26 model.checkCancelled();
27 if (this.activation != null) {
28 throw new IllegalStateException("Reentrant firing is not allowed");
29 }
30 this.activation = activation;
31 if (boundLiterals == null) {
32 boundLiterals = bindLiterals();
33 }
34 try {
35 int size = boundLiterals.length;
36 for (int i = 0; i < size; i++) {
37 var inputAllocation = action.getInputAllocation(i);
38 var boundLiteral = boundLiterals[i];
39 var input = getInputTuple(inputAllocation);
40 var output = boundLiteral.fire(input);
41 if (output == null) {
42 return false;
43 }
44 var outputAllocation = this.action.getOutputAllocation(i);
45 setOutputTuple(outputAllocation, output);
46 }
47 } finally {
48 this.activation = null;
49 }
50 return true;
51 }
52
53 private BoundActionLiteral[] bindLiterals() {
54 var actionLiterals = action.getActionLiterals();
55 int size = actionLiterals.size();
56 var boundLiteralsArray = new BoundActionLiteral[size];
57 for (int i = 0; i < size; i++) {
58 boundLiteralsArray[i] = actionLiterals.get(i).bindToModel(model);
59 }
60 return boundLiteralsArray;
61 }
62
63 private Tuple getInputTuple(int @Nullable [] inputAllocation) {
64 if (inputAllocation == null) {
65 // Identity allocation.
66 return activation;
67 }
68 return switch (inputAllocation.length) {
69 case 0 -> Tuple.of();
70 case 1 -> Tuple.of(getInput(inputAllocation[0]));
71 case 2 -> Tuple.of(getInput(inputAllocation[0]), getInput(inputAllocation[1]));
72 case 3 -> Tuple.of(getInput(inputAllocation[0]), getInput(inputAllocation[1]),
73 getInput(inputAllocation[2]));
74 case 4 -> Tuple.of(getInput(inputAllocation[0]), getInput(inputAllocation[1]),
75 getInput(inputAllocation[2]), getInput(inputAllocation[3]));
76 default -> {
77 var elements = new int[inputAllocation.length];
78 for (var i = 0; i < inputAllocation.length; i++) {
79 elements[i] = getInput(inputAllocation[i]);
80 }
81 yield Tuple.of(elements);
82 }
83 };
84 }
85
86 private int getInput(int index) {
87 int arity = action.getArity();
88 return index < arity ? activation.get(index) : localVariables[index - arity];
89 }
90
91 private void setOutputTuple(int @Nullable [] outputAllocation, Tuple output) {
92 if (outputAllocation == null || outputAllocation.length == 0) {
93 return;
94 }
95 switch (outputAllocation.length) {
96 case 1 -> localVariables[outputAllocation[0]] = output.get(0);
97 case 2 -> {
98 localVariables[outputAllocation[0]] = output.get(0);
99 localVariables[outputAllocation[1]] = output.get(1);
100 }
101 case 3 -> {
102 localVariables[outputAllocation[0]] = output.get(0);
103 localVariables[outputAllocation[1]] = output.get(1);
104 localVariables[outputAllocation[2]] = output.get(2);
105 }
106 case 4 -> {
107 localVariables[outputAllocation[0]] = output.get(0);
108 localVariables[outputAllocation[1]] = output.get(1);
109 localVariables[outputAllocation[2]] = output.get(2);
110 localVariables[outputAllocation[3]] = output.get(3);
111 }
112 default -> {
113 for (int i = 0; i < outputAllocation.length; i++) {
114 localVariables[outputAllocation[i]] = output.get(i);
115 }
116 }
117 }
118 }
119}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/BoundActionLiteral.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/BoundActionLiteral.java
new file mode 100644
index 00000000..09c3c58c
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/BoundActionLiteral.java
@@ -0,0 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.actions;
7
8import org.jetbrains.annotations.NotNull;
9import org.jetbrains.annotations.Nullable;
10import tools.refinery.store.tuple.Tuple;
11
12@FunctionalInterface
13public interface BoundActionLiteral {
14 @Nullable
15 Tuple fire(@NotNull Tuple tuple);
16}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/PutActionLiteral.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/PutActionLiteral.java
new file mode 100644
index 00000000..86288921
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/PutActionLiteral.java
@@ -0,0 +1,64 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.actions;
7
8import tools.refinery.store.model.Model;
9import tools.refinery.store.query.term.NodeVariable;
10import tools.refinery.store.representation.Symbol;
11import tools.refinery.store.tuple.Tuple;
12
13import java.util.List;
14
15public class PutActionLiteral<T> extends AbstractActionLiteral {
16 private final Symbol<T> symbol;
17 private final List<NodeVariable> parameters;
18 private final T value;
19
20 public PutActionLiteral(Symbol<T> symbol, T value, List<NodeVariable> parameters) {
21 if (symbol.arity() != parameters.size()) {
22 throw new IllegalArgumentException("Expected %d parameters for symbol %s, got %d instead"
23 .formatted(symbol.arity(), symbol, parameters.size()));
24 }
25 if (value != null && !symbol.valueType().isInstance(value)) {
26 throw new IllegalArgumentException("Expected value of type %s for symbol %s, got %s of type %s instead"
27 .formatted(symbol.valueType().getName(), symbol, value, value.getClass().getName()));
28 }
29 this.symbol = symbol;
30 this.parameters = List.copyOf(parameters);
31 this.value = value;
32 }
33
34 public Symbol<T> getSymbol() {
35 return symbol;
36 }
37
38 public List<NodeVariable> getParameters() {
39 return parameters;
40 }
41
42 public T getValue() {
43 return value;
44 }
45
46 @Override
47 public List<NodeVariable> getInputVariables() {
48 return getParameters();
49 }
50
51 @Override
52 public List<NodeVariable> getOutputVariables() {
53 return List.of();
54 }
55
56 @Override
57 public BoundActionLiteral bindToModel(Model model) {
58 var interpretation = model.getInterpretation(symbol);
59 return tuple -> {
60 interpretation.put(tuple, value);
61 return Tuple.of();
62 };
63 }
64}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/ActionCallback0.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/ActionCallback0.java
new file mode 100644
index 00000000..1190fdeb
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/ActionCallback0.java
@@ -0,0 +1,15 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.callback;
7
8import tools.refinery.store.dse.transition.actions.ActionLiteral;
9
10import java.util.List;
11
12@FunctionalInterface
13public interface ActionCallback0 {
14 List<ActionLiteral> toLiterals();
15}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/ActionCallback1.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/ActionCallback1.java
new file mode 100644
index 00000000..869f1a96
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/ActionCallback1.java
@@ -0,0 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.callback;
7
8import tools.refinery.store.dse.transition.actions.ActionLiteral;
9import tools.refinery.store.query.term.NodeVariable;
10
11import java.util.List;
12
13@FunctionalInterface
14public interface ActionCallback1 {
15 List<ActionLiteral> toLiterals(NodeVariable v1);
16}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/ActionCallback2.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/ActionCallback2.java
new file mode 100644
index 00000000..a648fc93
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/ActionCallback2.java
@@ -0,0 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.callback;
7
8import tools.refinery.store.dse.transition.actions.ActionLiteral;
9import tools.refinery.store.query.term.NodeVariable;
10
11import java.util.List;
12
13@FunctionalInterface
14public interface ActionCallback2 {
15 List<ActionLiteral> toLiterals(NodeVariable v1, NodeVariable v2);
16}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/ActionCallback3.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/ActionCallback3.java
new file mode 100644
index 00000000..a9b1d334
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/ActionCallback3.java
@@ -0,0 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.callback;
7
8import tools.refinery.store.dse.transition.actions.ActionLiteral;
9import tools.refinery.store.query.term.NodeVariable;
10
11import java.util.List;
12
13@FunctionalInterface
14public interface ActionCallback3 {
15 List<ActionLiteral> toLiterals(NodeVariable v1, NodeVariable v2, NodeVariable v3);
16}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/ActionCallback4.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/ActionCallback4.java
new file mode 100644
index 00000000..aef1351c
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/ActionCallback4.java
@@ -0,0 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.callback;
7
8import tools.refinery.store.dse.transition.actions.ActionLiteral;
9import tools.refinery.store.query.term.NodeVariable;
10
11import java.util.List;
12
13@FunctionalInterface
14public interface ActionCallback4 {
15 List<ActionLiteral> toLiterals(NodeVariable v1, NodeVariable v2, NodeVariable v3, NodeVariable v4);
16}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/RuleCallback0.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/RuleCallback0.java
new file mode 100644
index 00000000..538c23ba
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/RuleCallback0.java
@@ -0,0 +1,13 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.callback;
7
8import tools.refinery.store.dse.transition.RuleBuilder;
9
10@FunctionalInterface
11public interface RuleCallback0 {
12 void accept(RuleBuilder builder);
13}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/RuleCallback1.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/RuleCallback1.java
new file mode 100644
index 00000000..bd7bf4f5
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/RuleCallback1.java
@@ -0,0 +1,14 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.callback;
7
8import tools.refinery.store.dse.transition.RuleBuilder;
9import tools.refinery.store.query.term.NodeVariable;
10
11@FunctionalInterface
12public interface RuleCallback1 {
13 void accept(RuleBuilder builder, NodeVariable p1);
14}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/RuleCallback2.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/RuleCallback2.java
new file mode 100644
index 00000000..7b02b68a
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/RuleCallback2.java
@@ -0,0 +1,14 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.callback;
7
8import tools.refinery.store.dse.transition.RuleBuilder;
9import tools.refinery.store.query.term.NodeVariable;
10
11@FunctionalInterface
12public interface RuleCallback2 {
13 void accept(RuleBuilder builder, NodeVariable p1, NodeVariable p2);
14}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/RuleCallback3.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/RuleCallback3.java
new file mode 100644
index 00000000..6f112d48
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/RuleCallback3.java
@@ -0,0 +1,14 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.callback;
7
8import tools.refinery.store.dse.transition.RuleBuilder;
9import tools.refinery.store.query.term.NodeVariable;
10
11@FunctionalInterface
12public interface RuleCallback3 {
13 void accept(RuleBuilder builder, NodeVariable p1, NodeVariable p2, NodeVariable p3);
14}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/RuleCallback4.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/RuleCallback4.java
new file mode 100644
index 00000000..dbcf8567
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/callback/RuleCallback4.java
@@ -0,0 +1,14 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.callback;
7
8import tools.refinery.store.dse.transition.RuleBuilder;
9import tools.refinery.store.query.term.NodeVariable;
10
11@FunctionalInterface
12public interface RuleCallback4 {
13 void accept(RuleBuilder builder, NodeVariable p1, NodeVariable p2, NodeVariable p3, NodeVariable p4);
14}
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..23325a1f
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/internal/DesignSpaceExplorationAdapterImpl.java
@@ -0,0 +1,94 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.internal;
7
8import tools.refinery.store.dse.transition.DesignSpaceExplorationAdapter;
9import tools.refinery.store.dse.transition.DesignSpaceExplorationStoreAdapter;
10import tools.refinery.store.dse.transition.ObjectiveValue;
11import tools.refinery.store.dse.transition.Transformation;
12import tools.refinery.store.dse.transition.objectives.CriterionCalculator;
13import tools.refinery.store.dse.transition.objectives.ObjectiveCalculator;
14import tools.refinery.store.model.Model;
15
16import java.util.List;
17
18public class DesignSpaceExplorationAdapterImpl implements DesignSpaceExplorationAdapter {
19 final Model model;
20 final DesignSpaceExplorationStoreAdapter designSpaceExplorationStoreAdapter;
21
22 final List<Transformation> transformations;
23 final List<CriterionCalculator> accepts;
24 final List<CriterionCalculator> excludes;
25 final List<ObjectiveCalculator> objectives;
26
27 public DesignSpaceExplorationAdapterImpl(Model model,
28 DesignSpaceExplorationStoreAdapter designSpaceExplorationStoreAdapter,
29 List<Transformation> transformations,
30 List<CriterionCalculator> accepts,
31 List<CriterionCalculator> excludes,
32 List<ObjectiveCalculator> objectives) {
33 this.model = model;
34 this.designSpaceExplorationStoreAdapter = designSpaceExplorationStoreAdapter;
35
36 this.transformations = transformations;
37 this.accepts = accepts;
38 this.excludes = excludes;
39 this.objectives = objectives;
40 }
41
42 @Override
43 public Model getModel() {
44 return model;
45 }
46
47 @Override
48 public DesignSpaceExplorationStoreAdapter getStoreAdapter() {
49 return designSpaceExplorationStoreAdapter;
50 }
51
52 public List<Transformation> getTransformations() {
53 return transformations;
54 }
55
56 @Override
57 public boolean checkAccept() {
58 for (var accept : this.accepts) {
59 model.checkCancelled();
60 if (!accept.isSatisfied()) {
61 return false;
62 }
63 }
64 return true;
65 }
66
67 @Override
68 public boolean checkExclude() {
69 for (var exclude : this.excludes) {
70 model.checkCancelled();
71 if (exclude.isSatisfied()) {
72 return true;
73 }
74 }
75 return false;
76 }
77
78 @Override
79 public ObjectiveValue getObjectiveValue() {
80 model.checkCancelled();
81 if (objectives.size() == 1) {
82 return ObjectiveValue.of(objectives.get(0).getValue());
83 } else if (objectives.size() == 2) {
84 return ObjectiveValue.of(objectives.get(0).getValue(), objectives.get(1).getValue());
85 } else {
86 double[] res = new double[objectives.size()];
87 for (int i = 0; i < objectives.size(); i++) {
88 model.checkCancelled();
89 res[i] = objectives.get(i).getValue();
90 }
91 return ObjectiveValue.of(res);
92 }
93 }
94}
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..a91f6870
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/internal/DesignSpaceExplorationBuilderImpl.java
@@ -0,0 +1,75 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.internal;
7
8import tools.refinery.store.adapter.AbstractModelAdapterBuilder;
9import tools.refinery.store.dse.transition.DesignSpaceExplorationBuilder;
10import tools.refinery.store.dse.transition.Rule;
11import tools.refinery.store.dse.transition.objectives.Criterion;
12import tools.refinery.store.dse.transition.objectives.Objective;
13import tools.refinery.store.model.ModelStore;
14import tools.refinery.store.model.ModelStoreBuilder;
15import tools.refinery.store.query.ModelQueryBuilder;
16
17import java.util.LinkedHashSet;
18import java.util.List;
19
20public class DesignSpaceExplorationBuilderImpl
21 extends AbstractModelAdapterBuilder<DesignSpaceExplorationStoreAdapterImpl>
22 implements DesignSpaceExplorationBuilder {
23
24 LinkedHashSet<Rule> transformationRuleDefinitions = new LinkedHashSet<>();
25 LinkedHashSet<Criterion> accepts = new LinkedHashSet<>();
26 LinkedHashSet<Criterion> excludes = new LinkedHashSet<>();
27 LinkedHashSet<Objective> objectives = new LinkedHashSet<>();
28
29 @Override
30 public DesignSpaceExplorationBuilder transformation(Rule transformationRuleDefinition) {
31 transformationRuleDefinitions.add(transformationRuleDefinition);
32 return this;
33 }
34
35 @Override
36 public DesignSpaceExplorationBuilder accept(Criterion criteria) {
37 accepts.add(criteria);
38 return this;
39 }
40
41 @Override
42 public DesignSpaceExplorationBuilder exclude(Criterion criteria) {
43 excludes.add(criteria);
44 return this;
45 }
46
47
48 @Override
49 public DesignSpaceExplorationBuilder objective(Objective objective) {
50 objectives.add(objective);
51 return this;
52 }
53
54 @Override
55 protected void doConfigure(ModelStoreBuilder storeBuilder) {
56 var queryEngine = storeBuilder.getAdapter(ModelQueryBuilder.class);
57 transformationRuleDefinitions.forEach(x -> queryEngine.query(x.getPrecondition()));
58 accepts.forEach(x -> x.configure(storeBuilder));
59 excludes.forEach(x -> x.configure(storeBuilder));
60 objectives.forEach(x -> x.configure(storeBuilder));
61
62 super.doConfigure(storeBuilder);
63 }
64
65 @Override
66 protected DesignSpaceExplorationStoreAdapterImpl doBuild(ModelStore store) {
67 List<Rule> transformationRuleDefinitionsList = List.copyOf(transformationRuleDefinitions);
68 List<Criterion> acceptsList = List.copyOf(accepts);
69 List<Criterion> excludesList = List.copyOf(excludes);
70 List<Objective> objectivesList = List.copyOf(objectives);
71
72 return new DesignSpaceExplorationStoreAdapterImpl(store, transformationRuleDefinitionsList, acceptsList,
73 excludesList, objectivesList);
74 }
75}
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..bd85e7a6
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/internal/DesignSpaceExplorationStoreAdapterImpl.java
@@ -0,0 +1,74 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.internal;
7
8import tools.refinery.store.dse.transition.DesignSpaceExplorationStoreAdapter;
9import tools.refinery.store.dse.transition.Transformation;
10import tools.refinery.store.dse.transition.Rule;
11import tools.refinery.store.dse.transition.objectives.Criterion;
12import tools.refinery.store.dse.transition.objectives.CriterionCalculator;
13import tools.refinery.store.dse.transition.objectives.Objective;
14import tools.refinery.store.dse.transition.objectives.ObjectiveCalculator;
15import tools.refinery.store.model.Model;
16import tools.refinery.store.model.ModelStore;
17
18import java.util.List;
19
20public class DesignSpaceExplorationStoreAdapterImpl implements DesignSpaceExplorationStoreAdapter {
21 protected final ModelStore store;
22
23 protected final List<Rule> ruleDefinitions;
24 protected final List<Criterion> accepts;
25 protected final List<Criterion> excludes;
26 protected final List<Objective> objectives;
27
28 public DesignSpaceExplorationStoreAdapterImpl(
29 ModelStore store, List<Rule> ruleDefinitions, List<Criterion> accepts, List<Criterion> excludes,
30 List<Objective> objectives) {
31 this.store = store;
32 this.ruleDefinitions = ruleDefinitions;
33 this.accepts = accepts;
34 this.excludes = excludes;
35 this.objectives = objectives;
36 }
37
38 @Override
39 public ModelStore getStore() {
40 return store;
41 }
42
43 @Override
44 public DesignSpaceExplorationAdapterImpl createModelAdapter(Model model) {
45 final List<Transformation> t = this.ruleDefinitions.stream()
46 .map(x -> new Transformation(model, x))
47 .toList();
48 final List<CriterionCalculator> a = this.accepts.stream().map(x -> x.createCalculator(model)).toList();
49 final List<CriterionCalculator> e = this.excludes.stream().map(x -> x.createCalculator(model)).toList();
50 final List<ObjectiveCalculator> o = this.objectives.stream().map(x -> x.createCalculator(model)).toList();
51
52 return new DesignSpaceExplorationAdapterImpl(model, this, t, a, e, o);
53 }
54
55 @Override
56 public List<Rule> getTransformations() {
57 return ruleDefinitions;
58 }
59
60 @Override
61 public List<Criterion> getAccepts() {
62 return accepts;
63 }
64
65 @Override
66 public List<Criterion> getExcludes() {
67 return excludes;
68 }
69
70 @Override
71 public List<Objective> getObjectives() {
72 return objectives;
73 }
74}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/AndCriterion.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/AndCriterion.java
new file mode 100644
index 00000000..0ad2b7a4
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/AndCriterion.java
@@ -0,0 +1,53 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.objectives;
7
8import tools.refinery.store.model.Model;
9import tools.refinery.store.model.ModelStore;
10import tools.refinery.store.query.literal.Reduction;
11
12import java.util.ArrayList;
13import java.util.Collection;
14
15public final class AndCriterion extends CompositeCriterion {
16 AndCriterion(Collection<? extends Criterion> criteria) {
17 super(criteria);
18 }
19
20 @Override
21 public Reduction getReduction(ModelStore store) {
22 for (var criterion : getCriteria()) {
23 var reduction = criterion.getReduction(store);
24 if (reduction == Reduction.ALWAYS_FALSE) {
25 return Reduction.ALWAYS_FALSE;
26 } else if (reduction == Reduction.NOT_REDUCIBLE) {
27 return Reduction.NOT_REDUCIBLE;
28 }
29 }
30 return Reduction.ALWAYS_TRUE;
31 }
32
33 @Override
34 public CriterionCalculator createCalculator(Model model) {
35 var calculators = new ArrayList<CriterionCalculator>();
36 for (var criterion : getCriteria()) {
37 var reduction = criterion.getReduction(model.getStore());
38 if (reduction == Reduction.ALWAYS_FALSE) {
39 return () -> false;
40 } else if (reduction == Reduction.NOT_REDUCIBLE) {
41 calculators.add(criterion.createCalculator(model));
42 }
43 }
44 return () -> {
45 for (var calculator : calculators) {
46 if (!calculator.isSatisfied()) {
47 return false;
48 }
49 }
50 return true;
51 };
52 }
53}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/CompositeCriterion.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/CompositeCriterion.java
new file mode 100644
index 00000000..5746cc7e
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/CompositeCriterion.java
@@ -0,0 +1,43 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.objectives;
7
8import tools.refinery.store.model.ModelStore;
9import tools.refinery.store.model.ModelStoreBuilder;
10import tools.refinery.store.query.literal.Reduction;
11
12import java.util.*;
13
14public abstract sealed class CompositeCriterion implements Criterion permits AndCriterion, OrCriterion {
15 private final List<Criterion> criteria;
16
17 protected CompositeCriterion(Collection<? extends Criterion> criteria) {
18 var deDuplicatedCriteria = new LinkedHashSet<Criterion>();
19 for (var criterion : criteria) {
20 if (criterion.getClass() == this.getClass()) {
21 var childCriteria = ((CompositeCriterion) criterion).getCriteria();
22 deDuplicatedCriteria.addAll(childCriteria);
23 } else {
24 deDuplicatedCriteria.add(criterion);
25 }
26 }
27 this.criteria = List.copyOf(deDuplicatedCriteria);
28 }
29
30 public List<Criterion> getCriteria() {
31 return criteria;
32 }
33
34 @Override
35 public abstract Reduction getReduction(ModelStore store);
36
37 @Override
38 public void configure(ModelStoreBuilder storeBuilder) {
39 for (var criterion : criteria) {
40 criterion.configure(storeBuilder);
41 }
42 }
43}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/CompositeObjective.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/CompositeObjective.java
new file mode 100644
index 00000000..192a824b
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/CompositeObjective.java
@@ -0,0 +1,69 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.objectives;
7
8import tools.refinery.store.model.Model;
9import tools.refinery.store.model.ModelStore;
10import tools.refinery.store.model.ModelStoreBuilder;
11
12import java.util.ArrayList;
13import java.util.Collection;
14import java.util.Collections;
15import java.util.List;
16
17public class CompositeObjective implements Objective {
18 private final List<Objective> objectives;
19
20 CompositeObjective(Collection<? extends Objective> objectives) {
21 var unwrappedObjectives = new ArrayList<Objective>();
22 for (var objective : objectives) {
23 if (objective instanceof CompositeObjective compositeObjective) {
24 unwrappedObjectives.addAll(compositeObjective.getObjectives());
25 } else {
26 unwrappedObjectives.add(objective);
27 }
28 }
29 this.objectives = Collections.unmodifiableList(unwrappedObjectives);
30 }
31
32 public List<Objective> getObjectives() {
33 return objectives;
34 }
35
36 @Override
37 public boolean isAlwaysZero(ModelStore store) {
38 for (var objective : objectives) {
39 if (!objective.isAlwaysZero(store)) {
40 return false;
41 }
42 }
43 return true;
44 }
45
46 @Override
47 public ObjectiveCalculator createCalculator(Model model) {
48 var calculators = new ArrayList<ObjectiveCalculator>();
49 for (var objective : objectives) {
50 if (!objective.isAlwaysZero(model.getStore())) {
51 calculators.add(objective.createCalculator(model));
52 }
53 }
54 return () -> {
55 double value = 0;
56 for (var calculator : calculators) {
57 value += calculator.getValue();
58 }
59 return value;
60 };
61 }
62
63 @Override
64 public void configure(ModelStoreBuilder storeBuilder) {
65 for (var objective : objectives) {
66 objective.configure(storeBuilder);
67 }
68 }
69}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/CountObjective.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/CountObjective.java
new file mode 100644
index 00000000..fbd05ded
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/CountObjective.java
@@ -0,0 +1,47 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.objectives;
7
8import tools.refinery.store.model.Model;
9import tools.refinery.store.model.ModelStore;
10import tools.refinery.store.model.ModelStoreBuilder;
11import tools.refinery.store.query.ModelQueryAdapter;
12import tools.refinery.store.query.ModelQueryBuilder;
13import tools.refinery.store.query.ModelQueryStoreAdapter;
14import tools.refinery.store.query.dnf.RelationalQuery;
15import tools.refinery.store.query.literal.Reduction;
16
17public class CountObjective implements Objective {
18 private final RelationalQuery query;
19 private final double weight;
20
21 public CountObjective(RelationalQuery query) {
22 this(query, 1);
23 }
24
25 public CountObjective(RelationalQuery query, double weight) {
26 this.query = query;
27 this.weight = weight;
28 }
29
30 @Override
31 public boolean isAlwaysZero(ModelStore store) {
32 var queryStore = store.getAdapter(ModelQueryStoreAdapter.class);
33 var canonicalQuery = queryStore.getCanonicalQuery(query);
34 return canonicalQuery.getDnf().getReduction() == Reduction.ALWAYS_FALSE;
35 }
36
37 @Override
38 public ObjectiveCalculator createCalculator(Model model) {
39 var resultSet = model.getAdapter(ModelQueryAdapter.class).getResultSet(query);
40 return () -> resultSet.size() * weight;
41 }
42
43 @Override
44 public void configure(ModelStoreBuilder storeBuilder) {
45 storeBuilder.getAdapter(ModelQueryBuilder.class).query(query);
46 }
47}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/Criteria.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/Criteria.java
new file mode 100644
index 00000000..0e4ec5c9
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/Criteria.java
@@ -0,0 +1,47 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.objectives;
7
8import tools.refinery.store.query.dnf.AnyQuery;
9
10import java.util.Collection;
11import java.util.List;
12
13public final class Criteria {
14 private Criteria() {
15 throw new IllegalStateException("This is a static utility class and should not be instantiated directly");
16 }
17
18 public static QueryCriterion whenHasMatch(AnyQuery query) {
19 return new QueryCriterion(query, true);
20 }
21
22 public static QueryCriterion whenNoMatch(AnyQuery query) {
23 return new QueryCriterion(query, false);
24 }
25
26 public static Criterion and(Criterion... criteria) {
27 return and(List.of(criteria));
28 }
29
30 public static Criterion and(Collection<? extends Criterion> criteria) {
31 if (criteria.size() == 1) {
32 return criteria.iterator().next();
33 }
34 return new AndCriterion(criteria);
35 }
36
37 public static Criterion or(Criterion... criteria) {
38 return or(List.of(criteria));
39 }
40
41 public static Criterion or(Collection<? extends Criterion> criteria) {
42 if (criteria.size() == 1) {
43 return criteria.iterator().next();
44 }
45 return new OrCriterion(criteria);
46 }
47}
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..c827f20e
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/Criterion.java
@@ -0,0 +1,22 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.objectives;
7
8import tools.refinery.store.model.Model;
9import tools.refinery.store.model.ModelStore;
10import tools.refinery.store.model.ModelStoreBuilder;
11import tools.refinery.store.query.literal.Reduction;
12
13public interface Criterion {
14 default void configure(ModelStoreBuilder storeBuilder) {
15 }
16
17 default Reduction getReduction(ModelStore store) {
18 return Reduction.NOT_REDUCIBLE;
19 }
20
21 CriterionCalculator createCalculator(Model model);
22}
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 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.objectives;
7
8public interface CriterionCalculator {
9 boolean isSatisfied();
10}
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..49c34d87
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/Objective.java
@@ -0,0 +1,23 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.objectives;
7
8import tools.refinery.store.model.Model;
9import tools.refinery.store.model.ModelStore;
10import tools.refinery.store.model.ModelStoreBuilder;
11
12public interface Objective {
13 default void configure(ModelStoreBuilder storeBuilder) {
14 }
15
16 // The name {@code isAlwaysZero} is more straightforward than something like {@code canBeNonZero}.
17 @SuppressWarnings("BooleanMethodIsAlwaysInverted")
18 default boolean isAlwaysZero(ModelStore store) {
19 return false;
20 }
21
22 ObjectiveCalculator createCalculator(Model model);
23}
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 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.objectives;
7
8public interface ObjectiveCalculator {
9 double getValue();
10}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/Objectives.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/Objectives.java
new file mode 100644
index 00000000..e552d14c
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/Objectives.java
@@ -0,0 +1,41 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.objectives;
7
8import tools.refinery.store.query.dnf.FunctionalQuery;
9import tools.refinery.store.query.dnf.RelationalQuery;
10
11import java.util.Collection;
12import java.util.List;
13
14public final class Objectives {
15 private Objectives() {
16 throw new IllegalStateException("This is a static utility class and should not be instantiated directly");
17 }
18
19 public static CountObjective count(RelationalQuery query, double weight) {
20 return new CountObjective(query, weight);
21 }
22
23 public static CountObjective count(RelationalQuery query) {
24 return new CountObjective(query);
25 }
26
27 public static QueryObjective value(FunctionalQuery<? extends Number> query) {
28 return new QueryObjective(query);
29 }
30
31 public static Objective sum(Objective... objectives) {
32 return sum(List.of(objectives));
33 }
34
35 public static Objective sum(Collection<? extends Objective> objectives) {
36 if (objectives.size() == 1) {
37 return objectives.iterator().next();
38 }
39 return new CompositeObjective(objectives);
40 }
41}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/OrCriterion.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/OrCriterion.java
new file mode 100644
index 00000000..7a8d7778
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/OrCriterion.java
@@ -0,0 +1,53 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.objectives;
7
8import tools.refinery.store.model.Model;
9import tools.refinery.store.model.ModelStore;
10import tools.refinery.store.query.literal.Reduction;
11
12import java.util.ArrayList;
13import java.util.Collection;
14
15public final class OrCriterion extends CompositeCriterion {
16 OrCriterion(Collection<? extends Criterion> criteria) {
17 super(criteria);
18 }
19
20 @Override
21 public Reduction getReduction(ModelStore store) {
22 for (var criterion : getCriteria()) {
23 var reduction = criterion.getReduction(store);
24 if (reduction == Reduction.ALWAYS_TRUE) {
25 return Reduction.ALWAYS_TRUE;
26 } else if (reduction == Reduction.NOT_REDUCIBLE) {
27 return Reduction.NOT_REDUCIBLE;
28 }
29 }
30 return Reduction.ALWAYS_FALSE;
31 }
32
33 @Override
34 public CriterionCalculator createCalculator(Model model) {
35 var calculators = new ArrayList<CriterionCalculator>();
36 for (var criterion : getCriteria()) {
37 var reduction = criterion.getReduction(model.getStore());
38 if (reduction == Reduction.ALWAYS_TRUE) {
39 return () -> true;
40 } else if (reduction == Reduction.NOT_REDUCIBLE) {
41 calculators.add(criterion.createCalculator(model));
42 }
43 }
44 return () -> {
45 for (var calculator : calculators) {
46 if (calculator.isSatisfied()) {
47 return true;
48 }
49 }
50 return false;
51 };
52 }
53}
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/QueryCriterion.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/QueryCriterion.java
new file mode 100644
index 00000000..e15e4e41
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/QueryCriterion.java
@@ -0,0 +1,59 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.objectives;
7
8import tools.refinery.store.model.Model;
9import tools.refinery.store.model.ModelStore;
10import tools.refinery.store.model.ModelStoreBuilder;
11import tools.refinery.store.query.ModelQueryAdapter;
12import tools.refinery.store.query.ModelQueryBuilder;
13import tools.refinery.store.query.ModelQueryStoreAdapter;
14import tools.refinery.store.query.dnf.AnyQuery;
15import tools.refinery.store.query.literal.Reduction;
16
17public class QueryCriterion implements Criterion {
18 protected final boolean satisfiedIfHasMatch;
19 protected final AnyQuery query;
20
21 /**
22 * Criteria based on the existence of matches evaluated on the model.
23 *
24 * @param query The query evaluated on the model.
25 * @param satisfiedIfHasMatch If true, the criteria satisfied if the query has any match on the model. Otherwise,
26 * the criteria satisfied if the query has no match on the model.
27 */
28 public QueryCriterion(AnyQuery query, boolean satisfiedIfHasMatch) {
29 this.query = query;
30 this.satisfiedIfHasMatch = satisfiedIfHasMatch;
31 }
32
33 @Override
34 public Reduction getReduction(ModelStore store) {
35 var queryStore = store.getAdapter(ModelQueryStoreAdapter.class);
36 var canonicalQuery = queryStore.getCanonicalQuery(query);
37 var reduction = canonicalQuery.getDnf().getReduction();
38 if (satisfiedIfHasMatch) {
39 return reduction;
40 }
41 return reduction.negate();
42 }
43
44 @Override
45 public CriterionCalculator createCalculator(Model model) {
46 var resultSet = model.getAdapter(ModelQueryAdapter.class).getResultSet(query);
47 if (satisfiedIfHasMatch) {
48 return () -> resultSet.size() > 0;
49 } else {
50 return () -> resultSet.size() == 0;
51 }
52 }
53
54 @Override
55 public void configure(ModelStoreBuilder storeBuilder) {
56 Criterion.super.configure(storeBuilder);
57 storeBuilder.getAdapter(ModelQueryBuilder.class).query(query);
58 }
59}
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..5a7ba8f4
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/QueryObjective.java
@@ -0,0 +1,41 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.objectives;
7
8import tools.refinery.store.model.Model;
9import tools.refinery.store.model.ModelStoreBuilder;
10import tools.refinery.store.query.ModelQueryAdapter;
11import tools.refinery.store.query.ModelQueryBuilder;
12import tools.refinery.store.query.dnf.FunctionalQuery;
13
14public class QueryObjective implements Objective {
15 protected final FunctionalQuery<? extends Number> objectiveFunction;
16
17 public QueryObjective(FunctionalQuery<? extends Number> objectiveFunction) {
18 if (objectiveFunction.arity() != 0) {
19 throw new IllegalArgumentException("Objective functions must have 0 parameters, got %d instead"
20 .formatted(objectiveFunction.arity()));
21 }
22 this.objectiveFunction = objectiveFunction;
23 }
24
25 @Override
26 public ObjectiveCalculator createCalculator(Model model) {
27 var resultSet = model.getAdapter(ModelQueryAdapter.class).getResultSet(objectiveFunction);
28 return () -> {
29 var cursor = resultSet.getAll();
30 if (!cursor.move()) {
31 return 0;
32 }
33 return Math.max(cursor.getValue().doubleValue(), 0);
34 };
35 }
36
37 @Override
38 public void configure(ModelStoreBuilder storeBuilder) {
39 storeBuilder.getAdapter(ModelQueryBuilder.class).query(objectiveFunction);
40 }
41}
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 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.statespace;
7
8import tools.refinery.store.dse.transition.VersionWithObjectiveValue;
9import tools.refinery.store.map.Version;
10
11import java.util.Random;
12
13public interface ActivationStore {
14 record VisitResult(boolean successfulVisit, boolean mayHaveMore, int transformation, int activation) { }
15 VisitResult markNewAsVisited(VersionWithObjectiveValue to, int[] emptyEntrySizes);
16 boolean hasUnmarkedActivation(VersionWithObjectiveValue version);
17 VisitResult getRandomAndMarkAsVisited(VersionWithObjectiveValue version, Random random);
18}
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..28d1488b
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/EquivalenceClassStore.java
@@ -0,0 +1,17 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.statespace;
7
8import tools.refinery.store.dse.transition.VersionWithObjectiveValue;
9import tools.refinery.store.statecoding.StateCoderResult;
10
11public interface EquivalenceClassStore {
12 boolean submit(VersionWithObjectiveValue version, StateCoderResult stateCoderResult, int[] emptyActivations, boolean accept);
13 boolean submit(StateCoderResult stateCoderResult);
14 boolean hasUnresolvedSymmetry();
15 void resolveOneSymmetry();
16 int getNumberOfUnresolvedSymmetries();
17}
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 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.statespace;
7
8import tools.refinery.store.dse.transition.VersionWithObjectiveValue;
9import tools.refinery.store.map.Version;
10
11import java.util.Comparator;
12import java.util.Random;
13
14public interface ObjectivePriorityQueue {
15 Comparator<VersionWithObjectiveValue> getComparator();
16 void submit(VersionWithObjectiveValue versionWithObjectiveValue);
17 void remove(VersionWithObjectiveValue versionWithObjectiveValue);
18 int getSize();
19 VersionWithObjectiveValue getBest();
20 VersionWithObjectiveValue getRandom(Random random);
21}
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 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.statespace;
7
8import tools.refinery.store.dse.transition.VersionWithObjectiveValue;
9
10import java.util.List;
11import java.util.concurrent.Future;
12
13public interface SolutionStore {
14 boolean submit(VersionWithObjectiveValue version);
15 List<VersionWithObjectiveValue> getSolutions();
16 boolean hasEnoughSolution();
17}
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..b5087e86
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/AbstractEquivalenceClassStore.java
@@ -0,0 +1,54 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.statespace.internal;
7
8import tools.refinery.store.dse.transition.VersionWithObjectiveValue;
9import tools.refinery.store.dse.transition.statespace.EquivalenceClassStore;
10import tools.refinery.store.statecoding.StateCoderResult;
11import tools.refinery.store.statecoding.StateCoderStoreAdapter;
12
13public abstract class AbstractEquivalenceClassStore implements EquivalenceClassStore {
14 protected final StateCoderStoreAdapter stateCoderStoreAdapter;
15 AbstractEquivalenceClassStore(StateCoderStoreAdapter stateCoderStoreAdapter) {
16 this.stateCoderStoreAdapter = stateCoderStoreAdapter;
17 }
18
19 protected int numberOfUnresolvedSymmetries = 0;
20
21 protected abstract void delegate(VersionWithObjectiveValue version, int[] emptyActivations, boolean accept);
22 protected abstract boolean tryToAdd(StateCoderResult stateCoderResult, VersionWithObjectiveValue newVersion,
23 int[] emptyActivations, boolean accept);
24
25 public abstract boolean tryToAdd(StateCoderResult stateCoderResult);
26
27 @Override
28 public boolean submit(StateCoderResult stateCoderResult) {
29 return tryToAdd(stateCoderResult);
30 }
31
32 @Override
33 public synchronized boolean submit(VersionWithObjectiveValue version, StateCoderResult stateCoderResult,
34 int[] emptyActivations, boolean accept) {
35 boolean hasNewVersion = tryToAdd(stateCoderResult, version, emptyActivations, accept);
36 if (hasNewVersion) {
37 delegate(version, emptyActivations, accept);
38 return true;
39 } else {
40 numberOfUnresolvedSymmetries++;
41 return false;
42 }
43 }
44
45 @Override
46 public boolean hasUnresolvedSymmetry() {
47 return numberOfUnresolvedSymmetries > 0;
48 }
49
50 @Override
51 public int getNumberOfUnresolvedSymmetries() {
52 return numberOfUnresolvedSymmetries;
53 }
54}
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..c204ae35
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreBitVectorEntry.java
@@ -0,0 +1,50 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.statespace.internal;
7
8public class ActivationStoreBitVectorEntry extends ActivationStoreEntry {
9 final int[] selected;
10
11 ActivationStoreBitVectorEntry(int numberOfActivations) {
12 super(numberOfActivations);
13 this.selected = new int[(numberOfActivations / Integer.SIZE) + 1];
14 }
15
16 @Override
17 public int getNumberOfVisitedActivations() {
18 int visited = 0;
19 // Use indexed for loop to avoid allocating an iterator.
20 //noinspection ForLoopReplaceableByForEach
21 for (int i = 0; i < selected.length; i++) {
22 visited += Integer.bitCount(selected[i]);
23 }
24 return visited;
25 }
26
27 private static final int ELEMENT_POSITION = 5; // size of Integer.SIZE
28 private static final int ELEMENT_BITMASK = (1 << ELEMENT_POSITION) - 1;
29
30 @Override
31 public int getAndAddActivationAfter(int index) {
32 int position = index;
33 do {
34 final int selectedElement = position >> ELEMENT_POSITION;
35 final int selectedBit = 1 << (position & ELEMENT_BITMASK);
36
37 if ((selected[selectedElement] & selectedBit) == 0) {
38 selected[selectedElement] |= selectedBit;
39 return position;
40 } else {
41 if (position < this.numberOfActivations - 1) {
42 position++;
43 } else {
44 position = 0;
45 }
46 }
47 } while (position != index);
48 throw new IllegalArgumentException("There is are no unvisited activations!");
49 }
50}
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..7249751c
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreEntry.java
@@ -0,0 +1,37 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.statespace.internal;
7
8public abstract class ActivationStoreEntry {
9 protected final int numberOfActivations;
10
11 ActivationStoreEntry(int numberOfActivations) {
12 this.numberOfActivations = numberOfActivations;
13 }
14
15 public abstract int getNumberOfVisitedActivations();
16
17 public int getNumberOfUnvisitedActivations() {
18 return numberOfActivations - getNumberOfVisitedActivations();
19 }
20
21 public int getNumberOfActivations() {
22 return numberOfActivations;
23 }
24
25 public abstract int getAndAddActivationAfter(int index);
26
27 // public abstract boolean contains(int activation)
28 // public abstract boolean add(int activation)
29
30 public static ActivationStoreEntry create(int size) {
31 if(size <= Integer.SIZE*6) {
32 return new ActivationStoreBitVectorEntry(size);
33 } else {
34 return new ActivationStoreListEntry(size);
35 }
36 }
37}
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..82f89db7
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreImpl.java
@@ -0,0 +1,138 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.statespace.internal;
7
8import tools.refinery.store.dse.transition.VersionWithObjectiveValue;
9import tools.refinery.store.dse.transition.statespace.ActivationStore;
10
11import java.util.*;
12import java.util.function.Consumer;
13
14public class ActivationStoreImpl implements ActivationStore {
15 final int numberOfTransformations;
16 final Consumer<VersionWithObjectiveValue> actionWhenAllActivationVisited;
17 final Map<VersionWithObjectiveValue, List<ActivationStoreEntry>> versionToActivations;
18
19 public ActivationStoreImpl(final int numberOfTransformations,
20 Consumer<VersionWithObjectiveValue> actionWhenAllActivationVisited) {
21 this.numberOfTransformations = numberOfTransformations;
22 this.actionWhenAllActivationVisited = actionWhenAllActivationVisited;
23 versionToActivations = new HashMap<>();
24 }
25
26 public synchronized VisitResult markNewAsVisited(VersionWithObjectiveValue to, int[] emptyEntrySizes) {
27 boolean[] successful = new boolean[]{false};
28 var entries = versionToActivations.computeIfAbsent(to, x -> {
29 successful[0] = true;
30 List<ActivationStoreEntry> result = new ArrayList<>(emptyEntrySizes.length);
31 for (int emptyEntrySize : emptyEntrySizes) {
32 result.add(ActivationStoreEntry.create(emptyEntrySize));
33 }
34 return result;
35 });
36 boolean hasMore = false;
37 for (var entry : entries) {
38 if (entry.getNumberOfUnvisitedActivations() > 0) {
39 hasMore = true;
40 break;
41 }
42 }
43 if (!hasMore) {
44 actionWhenAllActivationVisited.accept(to);
45 }
46 return new VisitResult(successful[0], hasMore, -1, -1);
47 }
48
49 public synchronized VisitResult visitActivation(VersionWithObjectiveValue from, int transformationIndex,
50 int activationIndex) {
51 var entries = versionToActivations.get(from);
52 var entry = entries.get(transformationIndex);
53 final int unvisited = entry.getNumberOfUnvisitedActivations();
54
55 final boolean successfulVisit = unvisited > 0;
56 final boolean hasMoreInActivation = unvisited > 1;
57 final boolean hasMore;
58 final int transformation;
59 final int activation;
60
61 if (successfulVisit) {
62 transformation = transformationIndex;
63 activation = entry.getAndAddActivationAfter(activationIndex);
64
65 } else {
66 transformation = -1;
67 activation = -1;
68 }
69
70 if (!hasMoreInActivation) {
71 boolean hasMoreInOtherTransformation = false;
72 for (var e : entries) {
73 if (e != entry && e.getNumberOfUnvisitedActivations() > 0) {
74 hasMoreInOtherTransformation = true;
75 break;
76 }
77 }
78 hasMore = hasMoreInOtherTransformation;
79 } else {
80 hasMore = true;
81 }
82
83 if (!hasMore) {
84 actionWhenAllActivationVisited.accept(from);
85 }
86
87 return new VisitResult(successfulVisit, hasMore, transformation, activation);
88 }
89
90 @Override
91 public synchronized boolean hasUnmarkedActivation(VersionWithObjectiveValue version) {
92 var entries = versionToActivations.get(version);
93 boolean hasMore = false;
94 for (var entry : entries) {
95 if (entry.getNumberOfUnvisitedActivations() > 0) {
96 hasMore = true;
97 break;
98 }
99 }
100 return hasMore;
101 }
102
103 @Override
104 public synchronized VisitResult getRandomAndMarkAsVisited(VersionWithObjectiveValue version, Random random) {
105 var entries = versionToActivations.get(version);
106
107 var weights = new double[entries.size()];
108 double totalWeight = 0;
109 int numberOfAllUnvisitedActivations = 0;
110 for (int i = 0; i < weights.length; i++) {
111 var entry = entries.get(i);
112 int unvisited = entry.getNumberOfUnvisitedActivations();
113 double weight = unvisited == 0 ? 0 : unvisited; //(Math.log(unvisited) + 1.0);
114 weights[i] = weight;
115 totalWeight += weight;
116 numberOfAllUnvisitedActivations += unvisited;
117 }
118
119 if (numberOfAllUnvisitedActivations == 0) {
120 this.actionWhenAllActivationVisited.accept(version);
121 return new VisitResult(false, false, -1, -1);
122 }
123
124 double offset = random.nextDouble(totalWeight);
125 int transformation = 0;
126 for (; transformation < entries.size(); transformation++) {
127 double weight = weights[transformation];
128 if (weight > 0 && offset < weight) {
129 var entry = entries.get(transformation);
130 int activation = random.nextInt(entry.getNumberOfActivations());
131 return this.visitActivation(version, transformation, activation);
132 }
133 offset -= weight;
134 }
135
136 throw new AssertionError("Unvisited activation %f not found".formatted(offset));
137 }
138}
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..14298bee
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreListEntry.java
@@ -0,0 +1,104 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.statespace.internal;
7
8import org.eclipse.collections.api.factory.primitive.IntLists;
9import org.eclipse.collections.api.list.primitive.MutableIntList;
10
11public class ActivationStoreListEntry extends ActivationStoreEntry {
12 private final MutableIntList visitedActivations = IntLists.mutable.empty();
13
14 ActivationStoreListEntry(int numberOfActivations) {
15 super(numberOfActivations);
16 }
17
18 @Override
19 public int getNumberOfVisitedActivations() {
20 return visitedActivations.size();
21 }
22
23 @Override
24 public int getAndAddActivationAfter(int index) {
25 // If it is empty, just add it.
26 if(this.visitedActivations.isEmpty()) {
27 this.visitedActivations.add(index);
28 return index;
29 }
30 final int positionInSearch = getPosition(index);
31 int position = positionInSearch;
32
33 // if the position is after the last, we can insert it at the end of the list
34 if(position == this.visitedActivations.size()) {
35 this.visitedActivations.add(index);
36 return index;
37 } else if(this.visitedActivations.get(position) != index) {
38 // If the index is not in the position, one can insert it
39
40 this.visitedActivations.addAtIndex(position,index);
41 return index;
42 }
43
44 // Otherwise, get the next empty space between two elements
45 while(position + 1 < this.visitedActivations.size()) {
46 if(this.visitedActivations.get(position+1)-this.visitedActivations.get(position) > 1) {
47 int newElement = this.visitedActivations.get(position)+1;
48 this.visitedActivations.addAtIndex(position+1, newElement);
49 return newElement;
50 }
51 position++;
52 }
53
54 // Otherwise, try to add to the last space
55 int last = this.visitedActivations.get(this.visitedActivations.size()-1);
56 if(last<this.numberOfActivations-1) {
57 this.visitedActivations.add(last+1);
58 return last+1;
59 }
60
61 // Otherwise, try to put to the beginning
62 if(this.visitedActivations.get(0) > 0) {
63 this.visitedActivations.addAtIndex(0,0);
64 return 0;
65 }
66
67 // Otherwise, get the next empty space between two elements
68 position = 0;
69 while(position < positionInSearch) {
70 if(this.visitedActivations.get(position+1)-this.visitedActivations.get(position) > 1) {
71 int newElement = this.visitedActivations.get(position)+1;
72 this.visitedActivations.addAtIndex(position+1, newElement);
73 return newElement;
74 }
75 position++;
76 }
77
78 throw new IllegalArgumentException("There is are no unvisited activations!");
79 }
80
81 /**
82 * Returns the position of an index in the {@code visitedActivations}. If the collection contains the index, in
83 * returns its position, otherwise, it returns the position where the index need to be put.
84 *
85 * @param index Index of an activation.
86 * @return The position of the index.
87 */
88 private int getPosition(int index) {
89 int left = 0;
90 int right = this.visitedActivations.size() - 1;
91 while (left <= right) {
92 final int middle = (right - left) / 2 + left;
93 final int middleElement = visitedActivations.get(middle);
94 if(middleElement == index) {
95 return middle;
96 } else if(middleElement < index) {
97 left = middle +1;
98 } else{
99 right = middle-1;
100 }
101 }
102 return right+1;
103 }
104}
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..1d7c5ce5
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreWorker.java
@@ -0,0 +1,55 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.statespace.internal;
7
8import tools.refinery.store.dse.transition.Transformation;
9import tools.refinery.store.dse.transition.VersionWithObjectiveValue;
10import tools.refinery.store.dse.transition.statespace.ActivationStore;
11
12import java.util.List;
13import java.util.Random;
14
15public class ActivationStoreWorker {
16 final ActivationStore store;
17 final List<Transformation> transformations;
18
19 public ActivationStoreWorker(ActivationStore store, List<Transformation> transformations) {
20 this.store = store;
21 this.transformations = transformations;
22 }
23
24 public int[] calculateEmptyActivationSize() {
25 int[] result = new int[transformations.size()];
26 for (int i = 0; i < result.length; i++) {
27 result[i] = transformations.get(i).getAllActivationsAsResultSet().size();
28 }
29 return result;
30 }
31
32
33 public ActivationStore.VisitResult fireRandomActivation(VersionWithObjectiveValue thisVersion, Random random) {
34 var result = store.getRandomAndMarkAsVisited(thisVersion, random);
35 if (result.successfulVisit()) {
36 int selectedTransformation = result.transformation();
37 int selectedActivation = result.activation();
38
39 Transformation transformation = transformations.get(selectedTransformation);
40 var tuple = transformation.getActivation(selectedActivation);
41
42 boolean success = transformation.fireActivation(tuple);
43 if (success) {
44 return result;
45 } else {
46 return new ActivationStore.VisitResult(
47 false,
48 result.mayHaveMore(),
49 selectedTransformation,
50 selectedActivation);
51 }
52 }
53 return result;
54 }
55}
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..20a026b6
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/CompleteEquivalenceClassStore.java
@@ -0,0 +1,104 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.statespace.internal;
7
8import org.eclipse.collections.api.factory.primitive.IntObjectMaps;
9import org.eclipse.collections.api.map.primitive.MutableIntObjectMap;
10import tools.refinery.store.dse.transition.VersionWithObjectiveValue;
11import tools.refinery.store.dse.transition.statespace.EquivalenceClassStore;
12import tools.refinery.store.statecoding.StateCoderResult;
13import tools.refinery.store.statecoding.StateCoderStoreAdapter;
14import tools.refinery.store.statecoding.StateEquivalenceChecker;
15
16import java.util.ArrayList;
17
18public abstract class CompleteEquivalenceClassStore extends AbstractEquivalenceClassStore implements EquivalenceClassStore {
19
20 static class SymmetryStoreArray extends ArrayList<VersionWithObjectiveValue> {
21 final int[] activationSizes;
22 final boolean accept;
23
24 SymmetryStoreArray(int[] activationSizes, boolean accept) {
25 super();
26 this.activationSizes = activationSizes;
27 this.accept = accept;
28 }
29 }
30
31 private final MutableIntObjectMap<Object> modelCode2Versions = IntObjectMaps.mutable.empty();
32
33 protected CompleteEquivalenceClassStore(StateCoderStoreAdapter stateCoderStoreAdapter) {
34 super(stateCoderStoreAdapter);
35 }
36
37 @Override
38 protected boolean tryToAdd(StateCoderResult stateCoderResult, VersionWithObjectiveValue newVersion,
39 int[] emptyActivations, boolean accept) {
40 int modelCode = stateCoderResult.modelCode();
41 Object old = modelCode2Versions.updateValue(
42 modelCode,
43 () -> newVersion,
44 x -> {
45 if (x instanceof SymmetryStoreArray array) {
46 if(array.accept != accept || array.activationSizes != emptyActivations) {
47 this.delegate(newVersion,emptyActivations,accept);
48 return x;
49 }
50 array.add(newVersion);
51 return array;
52 } else {
53 SymmetryStoreArray result = new SymmetryStoreArray(emptyActivations, accept);
54 result.add((VersionWithObjectiveValue) x);
55 result.add(newVersion);
56 return result;
57 }
58 });
59 return old == null;
60 }
61
62 @Override
63 public void resolveOneSymmetry() {
64 var unresolvedSimilarity = getOneUnresolvedSymmetry();
65 if (unresolvedSimilarity == null) {
66 return;
67 }
68 var outcome = this.stateCoderStoreAdapter.checkEquivalence(unresolvedSimilarity.get(0).version(),
69 unresolvedSimilarity.get(1).version());
70 if (outcome != StateEquivalenceChecker.EquivalenceResult.ISOMORPHIC) {
71 delegate(unresolvedSimilarity.get(1), unresolvedSimilarity.activationSizes, unresolvedSimilarity.accept);
72 }
73 }
74
75 //record UnresolvedSymmetryResult
76
77 private synchronized SymmetryStoreArray getOneUnresolvedSymmetry() {
78 if (numberOfUnresolvedSymmetries <= 0) {
79 return null;
80 }
81
82 for (var entry : modelCode2Versions.keyValuesView()) {
83 int hash = entry.getOne();
84 var value = entry.getTwo();
85 if (value instanceof SymmetryStoreArray array) {
86 int size = array.size();
87 var representative = array.get(0);
88 var similar = array.get(size - 1);
89 array.remove(size - 1);
90
91 if (size <= 2) {
92 modelCode2Versions.put(hash, representative);
93 }
94
95 var result = new SymmetryStoreArray(array.activationSizes, array.accept);
96 result.add(representative);
97 result.add(similar);
98 return result;
99 }
100 }
101
102 return null;
103 }
104}
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..6d028124
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/FastEquivalenceClassStore.java
@@ -0,0 +1,37 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.statespace.internal;
7
8import org.eclipse.collections.api.factory.primitive.IntSets;
9import org.eclipse.collections.api.set.primitive.MutableIntSet;
10import tools.refinery.store.dse.transition.VersionWithObjectiveValue;
11import tools.refinery.store.dse.transition.statespace.EquivalenceClassStore;
12import tools.refinery.store.statecoding.StateCoderResult;
13import tools.refinery.store.statecoding.StateCoderStoreAdapter;
14
15public abstract class FastEquivalenceClassStore extends AbstractEquivalenceClassStore implements EquivalenceClassStore {
16
17 private final MutableIntSet codes = IntSets.mutable.empty();
18
19 protected FastEquivalenceClassStore(StateCoderStoreAdapter stateCoderStoreAdapter) {
20 super(stateCoderStoreAdapter);
21 }
22
23 @Override
24 protected synchronized boolean tryToAdd(StateCoderResult stateCoderResult, VersionWithObjectiveValue newVersion,
25 int[] emptyActivations, boolean accept) {
26 return this.codes.add(stateCoderResult.modelCode());
27 }
28
29 public synchronized boolean tryToAdd(StateCoderResult stateCoderResult) {
30 return this.codes.add(stateCoderResult.modelCode());
31 }
32
33 @Override
34 public void resolveOneSymmetry() {
35 throw new IllegalArgumentException("This equivalence storage is not prepared to resolve symmetries!");
36 }
37}
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..2f3e142a
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ObjectivePriorityQueueImpl.java
@@ -0,0 +1,68 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.statespace.internal;
7
8import tools.refinery.store.dse.transition.ObjectiveValues;
9import tools.refinery.store.dse.transition.VersionWithObjectiveValue;
10import tools.refinery.store.dse.transition.objectives.Objective;
11import tools.refinery.store.dse.transition.statespace.ObjectivePriorityQueue;
12
13import java.util.Comparator;
14import java.util.List;
15import java.util.PriorityQueue;
16import java.util.Random;
17
18public class ObjectivePriorityQueueImpl implements ObjectivePriorityQueue {
19 public static final Comparator<VersionWithObjectiveValue> c1 = (o1, o2) -> Double.compare(
20 ((ObjectiveValues.ObjectiveValue1) o1.objectiveValue()).value0(),
21 ((ObjectiveValues.ObjectiveValue1) o2.objectiveValue()).value0());
22 // TODO: support multi objective!
23 final PriorityQueue<VersionWithObjectiveValue> priorityQueue;
24
25 public ObjectivePriorityQueueImpl(List<Objective> objectives) {
26
27 if(objectives.size() == 1) {
28 this.priorityQueue = new PriorityQueue<>(c1);
29 } else {
30 throw new UnsupportedOperationException("Only single objective comparator is implemented currently!");
31 }
32 }
33 @Override
34 public Comparator<VersionWithObjectiveValue> getComparator() {
35 return c1;
36 }
37
38 @Override
39 public synchronized void submit(VersionWithObjectiveValue versionWithObjectiveValue) {
40 priorityQueue.add(versionWithObjectiveValue);
41 }
42
43 @Override
44 public synchronized void remove(VersionWithObjectiveValue versionWithObjectiveValue) {
45 priorityQueue.remove(versionWithObjectiveValue);
46 }
47
48 @Override
49 public synchronized int getSize() {
50 return priorityQueue.size();
51 }
52
53 @Override
54 public synchronized VersionWithObjectiveValue getBest() {
55 return priorityQueue.peek();
56 }
57
58 @Override
59 public synchronized VersionWithObjectiveValue getRandom(Random random) {
60 int randomPosition = random.nextInt(getSize());
61 for (VersionWithObjectiveValue entry : this.priorityQueue) {
62 if (randomPosition-- == 0) {
63 return entry;
64 }
65 }
66 throw new IllegalStateException("The priority queue is inconsistent!");
67 }
68}
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..43548eaa
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/SolutionStoreImpl.java
@@ -0,0 +1,52 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.dse.transition.statespace.internal;
7
8import tools.refinery.store.dse.transition.VersionWithObjectiveValue;
9import tools.refinery.store.dse.transition.statespace.SolutionStore;
10
11import java.util.ArrayList;
12import java.util.List;
13import java.util.PriorityQueue;
14
15
16public class SolutionStoreImpl implements SolutionStore {
17 final int maxNumberSolutions;
18 public static final int UNLIMITED = -1;
19 final PriorityQueue<VersionWithObjectiveValue> solutions;
20
21 public SolutionStoreImpl(int maxNumberSolutions) {
22 this.maxNumberSolutions = maxNumberSolutions;
23 solutions = new PriorityQueue<>(ObjectivePriorityQueueImpl.c1.reversed());
24 }
25
26
27 @Override
28 public synchronized boolean submit(VersionWithObjectiveValue version) {
29 boolean removeLast = hasEnoughSolution();
30 solutions.add(version);
31 if(removeLast) {
32 var last = solutions.poll();
33 return last != version;
34 } else {
35 return true;
36 }
37 }
38
39 @Override
40 public List<VersionWithObjectiveValue> getSolutions() {
41 return new ArrayList<>(solutions);
42 }
43
44 @Override
45 public boolean hasEnoughSolution() {
46 if (maxNumberSolutions == UNLIMITED) {
47 return false;
48 } else {
49 return solutions.size() >= maxNumberSolutions;
50 }
51 }
52}