From 0bdb400deef88cb2a7c0b8c90afebf84b29c04d5 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Sat, 9 Sep 2023 12:57:49 +0200 Subject: feat: integrate DSE with partial interpretation --- .../store/dse/propagation/BoundPropagator.java | 11 ++++ .../store/dse/propagation/PropagationAdapter.java | 20 ++++++ .../store/dse/propagation/PropagationBuilder.java | 32 ++++++++++ .../store/dse/propagation/PropagationResult.java | 28 +++++++++ .../dse/propagation/PropagationStoreAdapter.java | 14 +++++ .../refinery/store/dse/propagation/Propagator.java | 17 +++++ .../propagation/impl/PropagationAdapterImpl.java | 72 ++++++++++++++++++++++ .../propagation/impl/PropagationBuilderImpl.java | 53 ++++++++++++++++ .../impl/PropagationStoreAdapterImpl.java | 38 ++++++++++++ .../impl/rule/BoundPropagationRule.java | 37 +++++++++++ .../impl/rule/BoundRuleBasedPropagator.java | 43 +++++++++++++ .../propagation/impl/rule/RuleBasedPropagator.java | 36 +++++++++++ .../store/dse/strategy/BestFirstExplorer.java | 8 ++- .../store/dse/strategy/BestFirstWorker.java | 63 ++++++++++--------- .../store/dse/transition/actions/BoundAction.java | 23 ++++--- .../dse/transition/objectives/QueryObjective.java | 4 +- .../statespace/internal/ActivationStoreImpl.java | 23 ++++--- .../statespace/internal/ActivationStoreWorker.java | 6 +- 18 files changed, 478 insertions(+), 50 deletions(-) create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/BoundPropagator.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/PropagationAdapter.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/PropagationBuilder.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/PropagationResult.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/PropagationStoreAdapter.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/Propagator.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/PropagationAdapterImpl.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/PropagationBuilderImpl.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/PropagationStoreAdapterImpl.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/rule/BoundPropagationRule.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/rule/BoundRuleBasedPropagator.java create mode 100644 subprojects/store-dse/src/main/java/tools/refinery/store/dse/propagation/impl/rule/RuleBasedPropagator.java (limited to 'subprojects/store-dse/src') 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 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.propagation; + +@FunctionalInterface +public interface BoundPropagator { + PropagationResult propagateOne(); +} 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 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.propagation; + +import tools.refinery.store.adapter.ModelAdapter; +import tools.refinery.store.dse.propagation.impl.PropagationBuilderImpl; + +public interface PropagationAdapter extends ModelAdapter { + @Override + PropagationStoreAdapter getStoreAdapter(); + + PropagationResult propagate(); + + static PropagationBuilder builder() { + return new PropagationBuilderImpl(); + } +} 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 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.propagation; + +import tools.refinery.store.adapter.ModelAdapterBuilder; +import tools.refinery.store.dse.transition.Rule; +import tools.refinery.store.model.ModelStore; + +import java.util.Collection; +import java.util.List; + +@SuppressWarnings("UnusedReturnValue") +public interface PropagationBuilder extends ModelAdapterBuilder { + PropagationBuilder rule(Rule propagationRule); + + default PropagationBuilder rules(Rule... propagationRules) { + return rules(List.of(propagationRules)); + } + + default PropagationBuilder rules(Collection propagationRules) { + propagationRules.forEach(this::rule); + return this; + } + + PropagationBuilder propagator(Propagator propagator); + + @Override + PropagationStoreAdapter build(ModelStore store); +} 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 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.propagation; + +public enum PropagationResult { + UNCHANGED, + PROPAGATED, + REJECTED; + + public PropagationResult andThen(PropagationResult next) { + return switch (this) { + case UNCHANGED -> next; + case PROPAGATED -> next == REJECTED ? REJECTED : PROPAGATED; + case REJECTED -> REJECTED; + }; + } + + public boolean isRejected() { + return this == REJECTED; + } + + public boolean isChanged() { + return this == PROPAGATED; + } +} 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 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.propagation; + +import tools.refinery.store.adapter.ModelStoreAdapter; +import tools.refinery.store.model.Model; + +public interface PropagationStoreAdapter extends ModelStoreAdapter { + @Override + PropagationAdapter createModelAdapter(Model model); +} 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 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.propagation; + +import tools.refinery.store.model.Model; +import tools.refinery.store.model.ModelStoreBuilder; + +@FunctionalInterface +public interface Propagator { + default void configure(ModelStoreBuilder storeBuilder) { + } + + BoundPropagator bindToModel(Model model); +} 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 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.propagation.impl; + +import tools.refinery.store.dse.propagation.BoundPropagator; +import tools.refinery.store.dse.propagation.PropagationAdapter; +import tools.refinery.store.dse.propagation.PropagationResult; +import tools.refinery.store.dse.propagation.PropagationStoreAdapter; +import tools.refinery.store.model.Model; + +class PropagationAdapterImpl implements PropagationAdapter { + private final Model model; + private final PropagationStoreAdapterImpl storeAdapter; + private final BoundPropagator[] boundPropagators; + + public PropagationAdapterImpl(Model model, PropagationStoreAdapterImpl storeAdapter) { + this.model = model; + this.storeAdapter = storeAdapter; + var propagators = storeAdapter.getPropagators(); + boundPropagators = new BoundPropagator[propagators.size()]; + for (int i = 0; i < boundPropagators.length; i++) { + boundPropagators[i] = propagators.get(i).bindToModel(model); + } + } + + @Override + public PropagationResult propagate() { + PropagationResult result = PropagationResult.UNCHANGED; + PropagationResult lastResult; + do { + lastResult = propagateOne(); + result = result.andThen(lastResult); + } while (lastResult.isChanged()); + return result; + } + + private PropagationResult propagateOne() { + PropagationResult result = PropagationResult.UNCHANGED; + for (int i = 0; i < boundPropagators.length; i++) { + var lastResult = propagateUntilFixedPoint(i); + result = result.andThen(lastResult); + if (result.isRejected()) { + break; + } + } + return result; + } + + private PropagationResult propagateUntilFixedPoint(int propagatorIndex) { + var propagator = boundPropagators[propagatorIndex]; + PropagationResult result = PropagationResult.UNCHANGED; + PropagationResult lastResult; + do { + lastResult = propagator.propagateOne(); + result = result.andThen(lastResult); + } while (lastResult.isChanged()); + return result; + } + + @Override + public Model getModel() { + return model; + } + + @Override + public PropagationStoreAdapter getStoreAdapter() { + return storeAdapter; + } +} 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 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.propagation.impl; + +import tools.refinery.store.adapter.AbstractModelAdapterBuilder; +import tools.refinery.store.dse.propagation.PropagationBuilder; +import tools.refinery.store.dse.propagation.PropagationStoreAdapter; +import tools.refinery.store.dse.propagation.Propagator; +import tools.refinery.store.dse.propagation.impl.rule.RuleBasedPropagator; +import tools.refinery.store.dse.transition.Rule; +import tools.refinery.store.model.ModelStore; +import tools.refinery.store.model.ModelStoreBuilder; + +import java.util.*; + +public class PropagationBuilderImpl extends AbstractModelAdapterBuilder + implements PropagationBuilder { + private final Set propagationRules = new LinkedHashSet<>(); + private final Deque propagators = new ArrayDeque<>(); + + @Override + public PropagationBuilder rule(Rule propagationRule) { + checkNotConfigured(); + propagationRules.add(propagationRule); + return this; + } + + @Override + public PropagationBuilder propagator(Propagator propagator) { + checkNotConfigured(); + propagators.addFirst(propagator); + return this; + } + + @Override + protected void doConfigure(ModelStoreBuilder storeBuilder) { + super.doConfigure(storeBuilder); + if (!propagationRules.isEmpty()) { + propagators.addFirst(new RuleBasedPropagator(List.copyOf(propagationRules))); + } + for (var propagator : propagators) { + propagator.configure(storeBuilder); + } + } + + @Override + protected PropagationStoreAdapter doBuild(ModelStore store) { + return new PropagationStoreAdapterImpl(store, List.copyOf(propagators)); + } +} 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 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.propagation.impl; + +import tools.refinery.store.dse.propagation.PropagationAdapter; +import tools.refinery.store.dse.propagation.PropagationStoreAdapter; +import tools.refinery.store.dse.propagation.Propagator; +import tools.refinery.store.model.Model; +import tools.refinery.store.model.ModelStore; + +import java.util.List; + +class PropagationStoreAdapterImpl implements PropagationStoreAdapter { + private final ModelStore store; + private final List propagators; + + PropagationStoreAdapterImpl(ModelStore store, List propagators) { + this.store = store; + this.propagators = propagators; + } + + @Override + public ModelStore getStore() { + return store; + } + + @Override + public PropagationAdapter createModelAdapter(Model model) { + return new PropagationAdapterImpl(model, this); + } + + List getPropagators() { + return propagators; + } +} 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 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.propagation.impl.rule; + +import tools.refinery.store.dse.propagation.PropagationResult; +import tools.refinery.store.dse.transition.Rule; +import tools.refinery.store.dse.transition.actions.BoundAction; +import tools.refinery.store.model.Model; +import tools.refinery.store.query.ModelQueryAdapter; +import tools.refinery.store.query.resultset.ResultSet; + +class BoundPropagationRule { + private final ResultSet resultSet; + private final BoundAction action; + + public BoundPropagationRule(Model model, Rule rule) { + resultSet = model.getAdapter(ModelQueryAdapter.class).getResultSet(rule.getPrecondition()); + action = rule.createAction(model); + } + + public PropagationResult fireAll() { + if (resultSet.size() == 0) { + return PropagationResult.UNCHANGED; + } + var cursor = resultSet.getAll(); + while (cursor.move()) { + var result = action.fire(cursor.getKey()); + if (!result) { + return PropagationResult.REJECTED; + } + } + return PropagationResult.PROPAGATED; + } +} 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 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.propagation.impl.rule; + +import tools.refinery.store.dse.propagation.BoundPropagator; +import tools.refinery.store.dse.propagation.PropagationResult; +import tools.refinery.store.dse.transition.Rule; +import tools.refinery.store.model.Model; +import tools.refinery.store.query.ModelQueryAdapter; + +import java.util.List; + +public class BoundRuleBasedPropagator implements BoundPropagator { + private final ModelQueryAdapter queryEngine; + private final BoundPropagationRule[] boundRules; + + public BoundRuleBasedPropagator(Model model, List propagationRules) { + queryEngine = model.getAdapter(ModelQueryAdapter.class); + boundRules = new BoundPropagationRule[propagationRules.size()]; + for (int i = 0; i < boundRules.length; i++) { + boundRules[i] = new BoundPropagationRule(model, propagationRules.get(i)); + } + } + + @Override + public PropagationResult propagateOne() { + queryEngine.flushChanges(); + PropagationResult result = PropagationResult.UNCHANGED; + // Use a classic for loop to avoid allocating an iterator. + //noinspection ForLoopReplaceableByForEach + for (int i = 0; i < boundRules.length; i++) { + var lastResult = boundRules[i].fireAll(); + result = result.andThen(lastResult); + if (result.isRejected()) { + break; + } + } + return result; + } +} 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 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.dse.propagation.impl.rule; + +import tools.refinery.store.dse.propagation.BoundPropagator; +import tools.refinery.store.dse.propagation.Propagator; +import tools.refinery.store.dse.transition.Rule; +import tools.refinery.store.model.Model; +import tools.refinery.store.model.ModelStoreBuilder; +import tools.refinery.store.query.ModelQueryBuilder; + +import java.util.List; + +public class RuleBasedPropagator implements Propagator { + private final List propagationRules; + + public RuleBasedPropagator(List propagationRules) { + this.propagationRules = propagationRules; + } + + @Override + public void configure(ModelStoreBuilder storeBuilder) { + var queryBuilder = storeBuilder.getAdapter(ModelQueryBuilder.class); + for (var propagationRule : propagationRules) { + queryBuilder.query(propagationRule.getPrecondition()); + } + } + + @Override + public BoundPropagator bindToModel(Model model) { + return new BoundRuleBasedPropagator(model, propagationRules); + } +} 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 { var lastBest = submit().newVersion(); while (shouldRun()) { if (lastBest == null) { - lastBest = restoreToBest(); + if (random.nextInt(10) == 0) { + lastBest = restoreToRandom(random); + } else { + lastBest = restoreToBest(); + } if (lastBest == null) { return; } @@ -49,7 +53,7 @@ public class BestFirstExplorer extends BestFirstWorker { } else { var newVisit = newSubmit.newVersion(); int compareResult = compare(lastBest, newVisit); - if (compareResult >= 0) { + if (compareResult >= 0) { lastBest = newVisit; } else { 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 @@ */ package tools.refinery.store.dse.strategy; +import org.jetbrains.annotations.Nullable; +import tools.refinery.store.dse.propagation.PropagationAdapter; import tools.refinery.store.dse.transition.DesignSpaceExplorationAdapter; import tools.refinery.store.dse.transition.ObjectiveValue; import tools.refinery.store.dse.transition.VersionWithObjectiveValue; @@ -24,6 +26,7 @@ public class BestFirstWorker { final StateCoderAdapter stateCoderAdapter; final DesignSpaceExplorationAdapter explorationAdapter; final ModelQueryAdapter queryAdapter; + final @Nullable PropagationAdapter propagationAdapter; final VisualizationStore visualizationStore; final boolean isVisualizationEnabled; @@ -34,6 +37,7 @@ public class BestFirstWorker { explorationAdapter = model.getAdapter(DesignSpaceExplorationAdapter.class); stateCoderAdapter = model.getAdapter(StateCoderAdapter.class); queryAdapter = model.getAdapter(ModelQueryAdapter.class); + propagationAdapter = model.tryGetAdapter(PropagationAdapter.class).orElse(null); activationStoreWorker = new ActivationStoreWorker(storeManager.getActivationStore(), explorationAdapter.getTransformations()); visualizationStore = storeManager.getVisualizationStore(); @@ -96,7 +100,11 @@ public class BestFirstWorker { } public VersionWithObjectiveValue restoreToRandom(Random random) { - var randomVersion = storeManager.getObjectiveStore().getRandom(random); + var objectiveStore = storeManager.getObjectiveStore(); + if (objectiveStore.getSize() == 0) { + return null; + } + var randomVersion = objectiveStore.getRandom(random); last = randomVersion; if (randomVersion != null) { this.model.restore(randomVersion.version()); @@ -108,41 +116,40 @@ public class BestFirstWorker { return storeManager.getObjectiveStore().getComparator().compare(s1, s2); } - public boolean stateHasUnvisited() { - if (!model.hasUncommittedChanges()) { - return storeManager.getActivationStore().hasUnmarkedActivation(last); - } else { - throw new IllegalStateException("The model has uncommitted changes!"); - } - } - public record RandomVisitResult(SubmitResult submitResult, boolean shouldRetry) { } public RandomVisitResult visitRandomUnvisited(Random random) { checkSynchronized(); - if (!model.hasUncommittedChanges()) { - var visitResult = activationStoreWorker.fireRandomActivation(this.last, random); - queryAdapter.flushChanges(); - - if (visitResult.successfulVisit()) { - Version oldVersion = null; - if (isVisualizationEnabled) { - oldVersion = last.version(); - } - var submitResult = submit(); - if (isVisualizationEnabled && submitResult.newVersion() != null) { - var newVersion = submitResult.newVersion().version(); - visualizationStore.addTransition(oldVersion, newVersion, - "fire: " + visitResult.transformation() + ", " + visitResult.activation()); - } - return new RandomVisitResult(submitResult, visitResult.mayHaveMore()); - } else { + if (model.hasUncommittedChanges()) { + throw new IllegalStateException("The model has uncommitted changes!"); + } + + var visitResult = activationStoreWorker.fireRandomActivation(this.last, random); + + if (!visitResult.successfulVisit()) { + return new RandomVisitResult(null, visitResult.mayHaveMore()); + } + + if (propagationAdapter != null) { + var propagationResult = propagationAdapter.propagate(); + if (propagationResult.isRejected()) { return new RandomVisitResult(null, visitResult.mayHaveMore()); } - } else { - throw new IllegalStateException("The model has uncommitted changes!"); } + queryAdapter.flushChanges(); + + Version oldVersion = null; + if (isVisualizationEnabled) { + oldVersion = last.version(); + } + var submitResult = submit(); + if (isVisualizationEnabled && submitResult.newVersion() != null) { + var newVersion = submitResult.newVersion().version(); + visualizationStore.addTransition(oldVersion, newVersion, + "fire: " + visitResult.transformation() + ", " + visitResult.activation()); + } + return new RandomVisitResult(submitResult, visitResult.mayHaveMore()); } 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; public class BoundAction { private final Action action; - private final BoundActionLiteral[] boundLiterals; + private final Model model; + private BoundActionLiteral @Nullable [] boundLiterals; private Tuple activation; private final int[] localVariables; BoundAction(Action action, Model model) { this.action = action; - var actionLiterals = action.getActionLiterals(); - int size = actionLiterals.size(); - boundLiterals = new BoundActionLiteral[size]; - for (int i = 0; i < size; i++) { - boundLiterals[i] = actionLiterals.get(i).bindToModel(model); - } + this.model = model; localVariables = new int[action.getLocalVariables().size()]; } @@ -31,6 +27,9 @@ public class BoundAction { throw new IllegalStateException("Reentrant firing is not allowed"); } this.activation = activation; + if (boundLiterals == null) { + boundLiterals = bindLiterals(); + } try { int size = boundLiterals.length; for (int i = 0; i < size; i++) { @@ -50,6 +49,16 @@ public class BoundAction { return true; } + private BoundActionLiteral[] bindLiterals() { + var actionLiterals = action.getActionLiterals(); + int size = actionLiterals.size(); + var boundLiteralsArray = new BoundActionLiteral[size]; + for (int i = 0; i < size; i++) { + boundLiteralsArray[i] = actionLiterals.get(i).bindToModel(model); + } + return boundLiteralsArray; + } + private Tuple getInputTuple(int @Nullable [] inputAllocation) { if (inputAllocation == null) { // 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 { return () -> { var cursor = resultSet.getAll(); if (!cursor.move()) { - throw new IllegalStateException("Query providing the objective function has no values!"); + return 0; } - return cursor.getValue().doubleValue(); + return Math.max(cursor.getValue().doubleValue(), 0); }; } 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 { public synchronized VisitResult getRandomAndMarkAsVisited(VersionWithObjectiveValue version, Random random) { var entries = versionToActivations.get(version); + var weights = new double[entries.size()]; + double totalWeight = 0; int numberOfAllUnvisitedActivations = 0; - for (var entry : entries) { - numberOfAllUnvisitedActivations += entry.getNumberOfUnvisitedActivations(); + for (int i = 0; i < weights.length; i++) { + var entry = entries.get(i); + int unvisited = entry.getNumberOfUnvisitedActivations(); + double weight = unvisited == 0 ? 0 : unvisited; //(Math.log(unvisited) + 1.0); + weights[i] = weight; + totalWeight += weight; + numberOfAllUnvisitedActivations += unvisited; } if (numberOfAllUnvisitedActivations == 0) { @@ -114,18 +121,18 @@ public class ActivationStoreImpl implements ActivationStore { return new VisitResult(false, false, -1, -1); } - int offset = random.nextInt(numberOfAllUnvisitedActivations); + double offset = random.nextDouble(totalWeight); int transformation = 0; for (; transformation < entries.size(); transformation++) { - var entry = entries.get(transformation); - int unvisited = entry.getNumberOfUnvisitedActivations(); - if (unvisited > 0 && offset < unvisited) { + double weight = weights[transformation]; + if (weight > 0 && offset < weight) { + var entry = entries.get(transformation); int activation = random.nextInt(entry.getNumberOfActivations()); return this.visitActivation(version, transformation, activation); } - offset -= unvisited; + offset -= weight; } - throw new AssertionError("Unvisited activation %d not found".formatted(offset)); + throw new AssertionError("Unvisited activation %f not found".formatted(offset)); } } 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 { public ActivationStore.VisitResult fireRandomActivation(VersionWithObjectiveValue thisVersion, Random random) { var result = store.getRandomAndMarkAsVisited(thisVersion, random); - if(result.successfulVisit()) { + if (result.successfulVisit()) { int selectedTransformation = result.transformation(); int selectedActivation = result.activation(); @@ -40,13 +40,13 @@ public class ActivationStoreWorker { var tuple = transformation.getActivation(selectedActivation); boolean success = transformation.fireActivation(tuple); - if(success) { + if (success) { return result; } else { return new ActivationStore.VisitResult( false, result.mayHaveMore(), - selectedActivation, + selectedTransformation, selectedActivation); } } -- cgit v1.2.3-54-g00ecf