aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store-dse
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-09-09 12:57:49 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2023-09-09 12:57:49 +0200
commit0bdb400deef88cb2a7c0b8c90afebf84b29c04d5 (patch)
treed8cf379d3f1321cb1e3e44e19226c48634ae97f2 /subprojects/store-dse
parentrefactor(store): neighborhood optimization (diff)
downloadrefinery-0bdb400deef88cb2a7c0b8c90afebf84b29c04d5.tar.gz
refinery-0bdb400deef88cb2a7c0b8c90afebf84b29c04d5.tar.zst
refinery-0bdb400deef88cb2a7c0b8c90afebf84b29c04d5.zip
feat: integrate DSE with partial interpretation
Diffstat (limited to 'subprojects/store-dse')
-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.java72
-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.java37
-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.java8
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/strategy/BestFirstWorker.java63
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/BoundAction.java23
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/QueryObjective.java4
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreImpl.java23
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/statespace/internal/ActivationStoreWorker.java6
18 files changed, 478 insertions, 50 deletions
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..586a8d7a
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/PropagationAdapterImpl.java
@@ -0,0 +1,72 @@
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 lastResult = propagateOne();
35 result = result.andThen(lastResult);
36 } while (lastResult.isChanged());
37 return result;
38 }
39
40 private PropagationResult propagateOne() {
41 PropagationResult result = PropagationResult.UNCHANGED;
42 for (int i = 0; i < boundPropagators.length; i++) {
43 var lastResult = propagateUntilFixedPoint(i);
44 result = result.andThen(lastResult);
45 if (result.isRejected()) {
46 break;
47 }
48 }
49 return result;
50 }
51
52 private PropagationResult propagateUntilFixedPoint(int propagatorIndex) {
53 var propagator = boundPropagators[propagatorIndex];
54 PropagationResult result = PropagationResult.UNCHANGED;
55 PropagationResult lastResult;
56 do {
57 lastResult = propagator.propagateOne();
58 result = result.andThen(lastResult);
59 } while (lastResult.isChanged());
60 return result;
61 }
62
63 @Override
64 public Model getModel() {
65 return model;
66 }
67
68 @Override
69 public PropagationStoreAdapter getStoreAdapter() {
70 return storeAdapter;
71 }
72}
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..6e6a78d2
--- /dev/null
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/rule/BoundPropagationRule.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.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 ResultSet<Boolean> resultSet;
17 private final BoundAction action;
18
19 public BoundPropagationRule(Model model, Rule rule) {
20 resultSet = model.getAdapter(ModelQueryAdapter.class).getResultSet(rule.getPrecondition());
21 action = rule.createAction(model);
22 }
23
24 public PropagationResult fireAll() {
25 if (resultSet.size() == 0) {
26 return PropagationResult.UNCHANGED;
27 }
28 var cursor = resultSet.getAll();
29 while (cursor.move()) {
30 var result = action.fire(cursor.getKey());
31 if (!result) {
32 return PropagationResult.REJECTED;
33 }
34 }
35 return PropagationResult.PROPAGATED;
36 }
37}
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
index 8f7e3bdc..4a75a3a6 100644
--- 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
@@ -33,7 +33,11 @@ public class BestFirstExplorer extends BestFirstWorker {
33 var lastBest = submit().newVersion(); 33 var lastBest = submit().newVersion();
34 while (shouldRun()) { 34 while (shouldRun()) {
35 if (lastBest == null) { 35 if (lastBest == null) {
36 lastBest = restoreToBest(); 36 if (random.nextInt(10) == 0) {
37 lastBest = restoreToRandom(random);
38 } else {
39 lastBest = restoreToBest();
40 }
37 if (lastBest == null) { 41 if (lastBest == null) {
38 return; 42 return;
39 } 43 }
@@ -49,7 +53,7 @@ public class BestFirstExplorer extends BestFirstWorker {
49 } else { 53 } else {
50 var newVisit = newSubmit.newVersion(); 54 var newVisit = newSubmit.newVersion();
51 int compareResult = compare(lastBest, newVisit); 55 int compareResult = compare(lastBest, newVisit);
52 if (compareResult >= 0) { 56 if (compareResult >= 0) {
53 lastBest = newVisit; 57 lastBest = newVisit;
54 } else { 58 } else {
55 lastBest = null; 59 lastBest = null;
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
index 5d738297..aca800a3 100644
--- 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
@@ -5,6 +5,8 @@
5 */ 5 */
6package tools.refinery.store.dse.strategy; 6package tools.refinery.store.dse.strategy;
7 7
8import org.jetbrains.annotations.Nullable;
9import tools.refinery.store.dse.propagation.PropagationAdapter;
8import tools.refinery.store.dse.transition.DesignSpaceExplorationAdapter; 10import tools.refinery.store.dse.transition.DesignSpaceExplorationAdapter;
9import tools.refinery.store.dse.transition.ObjectiveValue; 11import tools.refinery.store.dse.transition.ObjectiveValue;
10import tools.refinery.store.dse.transition.VersionWithObjectiveValue; 12import tools.refinery.store.dse.transition.VersionWithObjectiveValue;
@@ -24,6 +26,7 @@ public class BestFirstWorker {
24 final StateCoderAdapter stateCoderAdapter; 26 final StateCoderAdapter stateCoderAdapter;
25 final DesignSpaceExplorationAdapter explorationAdapter; 27 final DesignSpaceExplorationAdapter explorationAdapter;
26 final ModelQueryAdapter queryAdapter; 28 final ModelQueryAdapter queryAdapter;
29 final @Nullable PropagationAdapter propagationAdapter;
27 final VisualizationStore visualizationStore; 30 final VisualizationStore visualizationStore;
28 final boolean isVisualizationEnabled; 31 final boolean isVisualizationEnabled;
29 32
@@ -34,6 +37,7 @@ public class BestFirstWorker {
34 explorationAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); 37 explorationAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class);
35 stateCoderAdapter = model.getAdapter(StateCoderAdapter.class); 38 stateCoderAdapter = model.getAdapter(StateCoderAdapter.class);
36 queryAdapter = model.getAdapter(ModelQueryAdapter.class); 39 queryAdapter = model.getAdapter(ModelQueryAdapter.class);
40 propagationAdapter = model.tryGetAdapter(PropagationAdapter.class).orElse(null);
37 activationStoreWorker = new ActivationStoreWorker(storeManager.getActivationStore(), 41 activationStoreWorker = new ActivationStoreWorker(storeManager.getActivationStore(),
38 explorationAdapter.getTransformations()); 42 explorationAdapter.getTransformations());
39 visualizationStore = storeManager.getVisualizationStore(); 43 visualizationStore = storeManager.getVisualizationStore();
@@ -96,7 +100,11 @@ public class BestFirstWorker {
96 } 100 }
97 101
98 public VersionWithObjectiveValue restoreToRandom(Random random) { 102 public VersionWithObjectiveValue restoreToRandom(Random random) {
99 var randomVersion = storeManager.getObjectiveStore().getRandom(random); 103 var objectiveStore = storeManager.getObjectiveStore();
104 if (objectiveStore.getSize() == 0) {
105 return null;
106 }
107 var randomVersion = objectiveStore.getRandom(random);
100 last = randomVersion; 108 last = randomVersion;
101 if (randomVersion != null) { 109 if (randomVersion != null) {
102 this.model.restore(randomVersion.version()); 110 this.model.restore(randomVersion.version());
@@ -108,41 +116,40 @@ public class BestFirstWorker {
108 return storeManager.getObjectiveStore().getComparator().compare(s1, s2); 116 return storeManager.getObjectiveStore().getComparator().compare(s1, s2);
109 } 117 }
110 118
111 public boolean stateHasUnvisited() {
112 if (!model.hasUncommittedChanges()) {
113 return storeManager.getActivationStore().hasUnmarkedActivation(last);
114 } else {
115 throw new IllegalStateException("The model has uncommitted changes!");
116 }
117 }
118
119 public record RandomVisitResult(SubmitResult submitResult, boolean shouldRetry) { 119 public record RandomVisitResult(SubmitResult submitResult, boolean shouldRetry) {
120 } 120 }
121 121
122 public RandomVisitResult visitRandomUnvisited(Random random) { 122 public RandomVisitResult visitRandomUnvisited(Random random) {
123 checkSynchronized(); 123 checkSynchronized();
124 if (!model.hasUncommittedChanges()) { 124 if (model.hasUncommittedChanges()) {
125 var visitResult = activationStoreWorker.fireRandomActivation(this.last, random); 125 throw new IllegalStateException("The model has uncommitted changes!");
126 queryAdapter.flushChanges(); 126 }
127 127
128 if (visitResult.successfulVisit()) { 128 var visitResult = activationStoreWorker.fireRandomActivation(this.last, random);
129 Version oldVersion = null; 129
130 if (isVisualizationEnabled) { 130 if (!visitResult.successfulVisit()) {
131 oldVersion = last.version(); 131 return new RandomVisitResult(null, visitResult.mayHaveMore());
132 } 132 }
133 var submitResult = submit(); 133
134 if (isVisualizationEnabled && submitResult.newVersion() != null) { 134 if (propagationAdapter != null) {
135 var newVersion = submitResult.newVersion().version(); 135 var propagationResult = propagationAdapter.propagate();
136 visualizationStore.addTransition(oldVersion, newVersion, 136 if (propagationResult.isRejected()) {
137 "fire: " + visitResult.transformation() + ", " + visitResult.activation());
138 }
139 return new RandomVisitResult(submitResult, visitResult.mayHaveMore());
140 } else {
141 return new RandomVisitResult(null, visitResult.mayHaveMore()); 137 return new RandomVisitResult(null, visitResult.mayHaveMore());
142 } 138 }
143 } else {
144 throw new IllegalStateException("The model has uncommitted changes!");
145 } 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());
146 } 153 }
147 154
148 public boolean hasEnoughSolution() { 155 public boolean hasEnoughSolution() {
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
index 55f43735..ed2ff33d 100644
--- 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
@@ -11,18 +11,14 @@ import tools.refinery.store.tuple.Tuple;
11 11
12public class BoundAction { 12public class BoundAction {
13 private final Action action; 13 private final Action action;
14 private final BoundActionLiteral[] boundLiterals; 14 private final Model model;
15 private BoundActionLiteral @Nullable [] boundLiterals;
15 private Tuple activation; 16 private Tuple activation;
16 private final int[] localVariables; 17 private final int[] localVariables;
17 18
18 BoundAction(Action action, Model model) { 19 BoundAction(Action action, Model model) {
19 this.action = action; 20 this.action = action;
20 var actionLiterals = action.getActionLiterals(); 21 this.model = model;
21 int size = actionLiterals.size();
22 boundLiterals = new BoundActionLiteral[size];
23 for (int i = 0; i < size; i++) {
24 boundLiterals[i] = actionLiterals.get(i).bindToModel(model);
25 }
26 localVariables = new int[action.getLocalVariables().size()]; 22 localVariables = new int[action.getLocalVariables().size()];
27 } 23 }
28 24
@@ -31,6 +27,9 @@ public class BoundAction {
31 throw new IllegalStateException("Reentrant firing is not allowed"); 27 throw new IllegalStateException("Reentrant firing is not allowed");
32 } 28 }
33 this.activation = activation; 29 this.activation = activation;
30 if (boundLiterals == null) {
31 boundLiterals = bindLiterals();
32 }
34 try { 33 try {
35 int size = boundLiterals.length; 34 int size = boundLiterals.length;
36 for (int i = 0; i < size; i++) { 35 for (int i = 0; i < size; i++) {
@@ -50,6 +49,16 @@ public class BoundAction {
50 return true; 49 return true;
51 } 50 }
52 51
52 private BoundActionLiteral[] bindLiterals() {
53 var actionLiterals = action.getActionLiterals();
54 int size = actionLiterals.size();
55 var boundLiteralsArray = new BoundActionLiteral[size];
56 for (int i = 0; i < size; i++) {
57 boundLiteralsArray[i] = actionLiterals.get(i).bindToModel(model);
58 }
59 return boundLiteralsArray;
60 }
61
53 private Tuple getInputTuple(int @Nullable [] inputAllocation) { 62 private Tuple getInputTuple(int @Nullable [] inputAllocation) {
54 if (inputAllocation == null) { 63 if (inputAllocation == null) {
55 // Identity allocation. 64 // Identity allocation.
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
index 9f4bb536..5a7ba8f4 100644
--- 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
@@ -28,9 +28,9 @@ public class QueryObjective implements Objective {
28 return () -> { 28 return () -> {
29 var cursor = resultSet.getAll(); 29 var cursor = resultSet.getAll();
30 if (!cursor.move()) { 30 if (!cursor.move()) {
31 throw new IllegalStateException("Query providing the objective function has no values!"); 31 return 0;
32 } 32 }
33 return cursor.getValue().doubleValue(); 33 return Math.max(cursor.getValue().doubleValue(), 0);
34 }; 34 };
35 } 35 }
36 36
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
index d9e29eca..82f89db7 100644
--- 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
@@ -104,9 +104,16 @@ public class ActivationStoreImpl implements ActivationStore {
104 public synchronized VisitResult getRandomAndMarkAsVisited(VersionWithObjectiveValue version, Random random) { 104 public synchronized VisitResult getRandomAndMarkAsVisited(VersionWithObjectiveValue version, Random random) {
105 var entries = versionToActivations.get(version); 105 var entries = versionToActivations.get(version);
106 106
107 var weights = new double[entries.size()];
108 double totalWeight = 0;
107 int numberOfAllUnvisitedActivations = 0; 109 int numberOfAllUnvisitedActivations = 0;
108 for (var entry : entries) { 110 for (int i = 0; i < weights.length; i++) {
109 numberOfAllUnvisitedActivations += entry.getNumberOfUnvisitedActivations(); 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;
110 } 117 }
111 118
112 if (numberOfAllUnvisitedActivations == 0) { 119 if (numberOfAllUnvisitedActivations == 0) {
@@ -114,18 +121,18 @@ public class ActivationStoreImpl implements ActivationStore {
114 return new VisitResult(false, false, -1, -1); 121 return new VisitResult(false, false, -1, -1);
115 } 122 }
116 123
117 int offset = random.nextInt(numberOfAllUnvisitedActivations); 124 double offset = random.nextDouble(totalWeight);
118 int transformation = 0; 125 int transformation = 0;
119 for (; transformation < entries.size(); transformation++) { 126 for (; transformation < entries.size(); transformation++) {
120 var entry = entries.get(transformation); 127 double weight = weights[transformation];
121 int unvisited = entry.getNumberOfUnvisitedActivations(); 128 if (weight > 0 && offset < weight) {
122 if (unvisited > 0 && offset < unvisited) { 129 var entry = entries.get(transformation);
123 int activation = random.nextInt(entry.getNumberOfActivations()); 130 int activation = random.nextInt(entry.getNumberOfActivations());
124 return this.visitActivation(version, transformation, activation); 131 return this.visitActivation(version, transformation, activation);
125 } 132 }
126 offset -= unvisited; 133 offset -= weight;
127 } 134 }
128 135
129 throw new AssertionError("Unvisited activation %d not found".formatted(offset)); 136 throw new AssertionError("Unvisited activation %f not found".formatted(offset));
130 } 137 }
131} 138}
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
index 881b133c..1d7c5ce5 100644
--- 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
@@ -32,7 +32,7 @@ public class ActivationStoreWorker {
32 32
33 public ActivationStore.VisitResult fireRandomActivation(VersionWithObjectiveValue thisVersion, Random random) { 33 public ActivationStore.VisitResult fireRandomActivation(VersionWithObjectiveValue thisVersion, Random random) {
34 var result = store.getRandomAndMarkAsVisited(thisVersion, random); 34 var result = store.getRandomAndMarkAsVisited(thisVersion, random);
35 if(result.successfulVisit()) { 35 if (result.successfulVisit()) {
36 int selectedTransformation = result.transformation(); 36 int selectedTransformation = result.transformation();
37 int selectedActivation = result.activation(); 37 int selectedActivation = result.activation();
38 38
@@ -40,13 +40,13 @@ public class ActivationStoreWorker {
40 var tuple = transformation.getActivation(selectedActivation); 40 var tuple = transformation.getActivation(selectedActivation);
41 41
42 boolean success = transformation.fireActivation(tuple); 42 boolean success = transformation.fireActivation(tuple);
43 if(success) { 43 if (success) {
44 return result; 44 return result;
45 } else { 45 } else {
46 return new ActivationStore.VisitResult( 46 return new ActivationStore.VisitResult(
47 false, 47 false,
48 result.mayHaveMore(), 48 result.mayHaveMore(),
49 selectedActivation, 49 selectedTransformation,
50 selectedActivation); 50 selectedActivation);
51 } 51 }
52 } 52 }