aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-09-07 18:04:42 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2023-09-07 18:04:42 +0200
commita128e05f18a101983d331d0819008740b521d6df (patch)
treecc23c330eea900ab7b513a6c21a241ebf0795785
parentfeat(dse): transformation rule builder (diff)
downloadrefinery-a128e05f18a101983d331d0819008740b521d6df.tar.gz
refinery-a128e05f18a101983d331d0819008740b521d6df.tar.zst
refinery-a128e05f18a101983d331d0819008740b521d6df.zip
feat: declarative DSE rules and model refinement
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/DesignSpaceExplorationAdapter.java11
-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.java7
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/Objective.java8
-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.java (renamed from subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/QueryCriteria.java)29
-rw-r--r--subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/QueryObjective.java15
-rw-r--r--subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/LowerTypeScopePropagator.java40
-rw-r--r--subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/ScopePropagatorAdapterImpl.java22
-rw-r--r--subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/ScopePropagatorBuilderImpl.java11
-rw-r--r--subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/TypeScopePropagator.java12
-rw-r--r--subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/UpperTypeScopePropagator.java9
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningAdapter.java3
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningBuilder.java12
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/actions/FocusActionLiteral.java48
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/actions/MergeActionLiteral.java60
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/actions/PartialActionLiterals.java38
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java29
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningBuilderImpl.java18
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/PartialRelationTranslator.java92
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/PartialSymbolTranslator.java60
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainmentHierarchyTranslator.java42
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceTranslator.java18
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceTranslator.java18
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiobject/MultiObjectTranslator.java35
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiobject/MultiView.java (renamed from subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/MultiView.java)2
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiplicity/InvalidMultiplicityErrorTranslator.java35
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/predicate/PredicateTranslator.java9
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTranslator.java34
34 files changed, 988 insertions, 82 deletions
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
index 37448309..d326f1dd 100644
--- 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
@@ -7,25 +7,22 @@ package tools.refinery.store.dse.transition;
7 7
8import tools.refinery.store.adapter.ModelAdapter; 8import tools.refinery.store.adapter.ModelAdapter;
9import tools.refinery.store.dse.transition.internal.DesignSpaceExplorationBuilderImpl; 9import tools.refinery.store.dse.transition.internal.DesignSpaceExplorationBuilderImpl;
10import tools.refinery.store.map.Version;
11import tools.refinery.store.tuple.Tuple;
12import tools.refinery.store.tuple.Tuple1;
13 10
14import java.util.Collection;
15import java.util.List; 11import java.util.List;
16 12
17public interface DesignSpaceExplorationAdapter extends ModelAdapter { 13public interface DesignSpaceExplorationAdapter extends ModelAdapter {
18
19
20
21 @Override 14 @Override
22 DesignSpaceExplorationStoreAdapter getStoreAdapter(); 15 DesignSpaceExplorationStoreAdapter getStoreAdapter();
23 16
24 static DesignSpaceExplorationBuilder builder() { 17 static DesignSpaceExplorationBuilder builder() {
25 return new DesignSpaceExplorationBuilderImpl(); 18 return new DesignSpaceExplorationBuilderImpl();
26 } 19 }
20
27 List<Transformation> getTransformations(); 21 List<Transformation> getTransformations();
22
28 boolean checkAccept(); 23 boolean checkAccept();
24
29 boolean checkExclude(); 25 boolean checkExclude();
26
30 ObjectiveValue getObjectiveValue(); 27 ObjectiveValue getObjectiveValue();
31} 28}
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
index 4365cf9c..c827f20e 100644
--- 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
@@ -6,10 +6,17 @@
6package tools.refinery.store.dse.transition.objectives; 6package tools.refinery.store.dse.transition.objectives;
7 7
8import tools.refinery.store.model.Model; 8import tools.refinery.store.model.Model;
9import tools.refinery.store.model.ModelStore;
9import tools.refinery.store.model.ModelStoreBuilder; 10import tools.refinery.store.model.ModelStoreBuilder;
11import tools.refinery.store.query.literal.Reduction;
10 12
11public interface Criterion { 13public interface Criterion {
12 default void configure(ModelStoreBuilder storeBuilder) { 14 default void configure(ModelStoreBuilder storeBuilder) {
13 } 15 }
16
17 default Reduction getReduction(ModelStore store) {
18 return Reduction.NOT_REDUCIBLE;
19 }
20
14 CriterionCalculator createCalculator(Model model); 21 CriterionCalculator createCalculator(Model model);
15} 22}
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
index d2476a2e..49c34d87 100644
--- 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
@@ -6,10 +6,18 @@
6package tools.refinery.store.dse.transition.objectives; 6package tools.refinery.store.dse.transition.objectives;
7 7
8import tools.refinery.store.model.Model; 8import tools.refinery.store.model.Model;
9import tools.refinery.store.model.ModelStore;
9import tools.refinery.store.model.ModelStoreBuilder; 10import tools.refinery.store.model.ModelStoreBuilder;
10 11
11public interface Objective { 12public interface Objective {
12 default void configure(ModelStoreBuilder storeBuilder) { 13 default void configure(ModelStoreBuilder storeBuilder) {
13 } 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
14 ObjectiveCalculator createCalculator(Model model); 22 ObjectiveCalculator createCalculator(Model model);
15} 23}
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/QueryCriteria.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/QueryCriterion.java
index 8d0a56cf..e15e4e41 100644
--- a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/QueryCriteria.java
+++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/objectives/QueryCriterion.java
@@ -6,30 +6,45 @@
6package tools.refinery.store.dse.transition.objectives; 6package tools.refinery.store.dse.transition.objectives;
7 7
8import tools.refinery.store.model.Model; 8import tools.refinery.store.model.Model;
9import tools.refinery.store.model.ModelStore;
9import tools.refinery.store.model.ModelStoreBuilder; 10import tools.refinery.store.model.ModelStoreBuilder;
10import tools.refinery.store.query.ModelQueryAdapter; 11import tools.refinery.store.query.ModelQueryAdapter;
11import tools.refinery.store.query.ModelQueryBuilder; 12import tools.refinery.store.query.ModelQueryBuilder;
13import tools.refinery.store.query.ModelQueryStoreAdapter;
12import tools.refinery.store.query.dnf.AnyQuery; 14import tools.refinery.store.query.dnf.AnyQuery;
15import tools.refinery.store.query.literal.Reduction;
13 16
14public class QueryCriteria implements Criterion { 17public class QueryCriterion implements Criterion {
15 protected final boolean acceptIfHasMatch; 18 protected final boolean satisfiedIfHasMatch;
16 protected final AnyQuery query; 19 protected final AnyQuery query;
17 20
18 /** 21 /**
19 * Criteria based on the existence of matches evaluated on the model. 22 * Criteria based on the existence of matches evaluated on the model.
20 * @param query The query evaluated on the model. 23 *
21 * @param acceptIfHasMatch If true, the criteria satisfied if the query has any match on the model. Otherwise, 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,
22 * the criteria satisfied if the query has no match on the model. 26 * the criteria satisfied if the query has no match on the model.
23 */ 27 */
24 public QueryCriteria(AnyQuery query, boolean acceptIfHasMatch) { 28 public QueryCriterion(AnyQuery query, boolean satisfiedIfHasMatch) {
25 this.query = query; 29 this.query = query;
26 this.acceptIfHasMatch = acceptIfHasMatch; 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();
27 } 42 }
28 43
29 @Override 44 @Override
30 public CriterionCalculator createCalculator(Model model) { 45 public CriterionCalculator createCalculator(Model model) {
31 var resultSet = model.getAdapter(ModelQueryAdapter.class).getResultSet(query); 46 var resultSet = model.getAdapter(ModelQueryAdapter.class).getResultSet(query);
32 if(acceptIfHasMatch) { 47 if (satisfiedIfHasMatch) {
33 return () -> resultSet.size() > 0; 48 return () -> resultSet.size() > 0;
34 } else { 49 } else {
35 return () -> resultSet.size() == 0; 50 return () -> resultSet.size() == 0;
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 9553e0e0..9f4bb536 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
@@ -15,6 +15,10 @@ public class QueryObjective implements Objective {
15 protected final FunctionalQuery<? extends Number> objectiveFunction; 15 protected final FunctionalQuery<? extends Number> objectiveFunction;
16 16
17 public QueryObjective(FunctionalQuery<? extends Number> objectiveFunction) { 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 }
18 this.objectiveFunction = objectiveFunction; 22 this.objectiveFunction = objectiveFunction;
19 } 23 }
20 24
@@ -23,22 +27,15 @@ public class QueryObjective implements Objective {
23 var resultSet = model.getAdapter(ModelQueryAdapter.class).getResultSet(objectiveFunction); 27 var resultSet = model.getAdapter(ModelQueryAdapter.class).getResultSet(objectiveFunction);
24 return () -> { 28 return () -> {
25 var cursor = resultSet.getAll(); 29 var cursor = resultSet.getAll();
26 boolean hasElement = cursor.move(); 30 if (!cursor.move()) {
27 if(hasElement) {
28 double result = cursor.getValue().doubleValue();
29 if(cursor.move()) {
30 throw new IllegalStateException("Query providing the objective function has multiple values!");
31 }
32 return result;
33 } else {
34 throw new IllegalStateException("Query providing the objective function has no values!"); 31 throw new IllegalStateException("Query providing the objective function has no values!");
35 } 32 }
33 return cursor.getValue().doubleValue();
36 }; 34 };
37 } 35 }
38 36
39 @Override 37 @Override
40 public void configure(ModelStoreBuilder storeBuilder) { 38 public void configure(ModelStoreBuilder storeBuilder) {
41 Objective.super.configure(storeBuilder);
42 storeBuilder.getAdapter(ModelQueryBuilder.class).query(objectiveFunction); 39 storeBuilder.getAdapter(ModelQueryBuilder.class).query(objectiveFunction);
43 } 40 }
44} 41}
diff --git a/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/LowerTypeScopePropagator.java b/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/LowerTypeScopePropagator.java
index b1c421b7..393c4b72 100644
--- a/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/LowerTypeScopePropagator.java
+++ b/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/LowerTypeScopePropagator.java
@@ -5,43 +5,55 @@
5 */ 5 */
6package tools.refinery.store.reasoning.scope.internal; 6package tools.refinery.store.reasoning.scope.internal;
7 7
8import tools.refinery.store.dse.transition.DesignSpaceExplorationBuilder;
9import tools.refinery.store.dse.transition.objectives.Criteria;
10import tools.refinery.store.dse.transition.objectives.Objectives;
11import tools.refinery.store.model.ModelStoreBuilder;
8import tools.refinery.store.query.dnf.AnyQuery; 12import tools.refinery.store.query.dnf.AnyQuery;
9import tools.refinery.store.query.dnf.Query; 13import tools.refinery.store.query.dnf.Query;
10import tools.refinery.store.query.dnf.RelationalQuery; 14import tools.refinery.store.query.dnf.RelationalQuery;
15import tools.refinery.store.query.term.Variable;
16import tools.refinery.store.reasoning.ReasoningBuilder;
17import tools.refinery.store.reasoning.literal.CountCandidateLowerBoundLiteral;
11import tools.refinery.store.reasoning.representation.PartialRelation; 18import tools.refinery.store.reasoning.representation.PartialRelation;
12 19
13import java.util.Collection; 20import java.util.Collection;
14import java.util.List; 21import java.util.List;
15 22
23import static tools.refinery.store.query.literal.Literals.check;
24import static tools.refinery.store.query.term.int_.IntTerms.*;
16import static tools.refinery.store.reasoning.literal.PartialLiterals.may; 25import static tools.refinery.store.reasoning.literal.PartialLiterals.may;
26import static tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator.MULTI_VIEW;
17 27
18class LowerTypeScopePropagator extends TypeScopePropagator { 28class LowerTypeScopePropagator extends TypeScopePropagator {
19 private final int lowerBound; 29 private final int lowerBound;
20 30
21 private LowerTypeScopePropagator(ScopePropagatorAdapterImpl adapter, int lowerBound, RelationalQuery allQuery, 31 private LowerTypeScopePropagator(ScopePropagatorAdapterImpl adapter, int lowerBound, RelationalQuery allQuery,
22 RelationalQuery multiQuery) { 32 RelationalQuery multiQuery) {
23 super(adapter, allQuery, multiQuery); 33 super(adapter, allQuery, multiQuery);
24 this.lowerBound = lowerBound; 34 this.lowerBound = lowerBound;
25 } 35 }
26 36
27 @Override 37 @Override
28 public void updateBounds() { 38 public void updateBounds() {
29 constraint.setLb(lowerBound - getSingleCount()); 39 constraint.setLb((lowerBound - getSingleCount()));
30 } 40 }
31 41
32 public static class Factory implements TypeScopePropagator.Factory { 42 public static class Factory extends TypeScopePropagator.Factory {
43 private final PartialRelation type;
33 private final int lowerBound; 44 private final int lowerBound;
34 private final RelationalQuery allMay; 45 private final RelationalQuery allMay;
35 private final RelationalQuery multiMay; 46 private final RelationalQuery multiMay;
36 47
37 public Factory(RelationalQuery multi, PartialRelation type, int lowerBound) { 48 public Factory(PartialRelation type, int lowerBound) {
49 this.type = type;
38 this.lowerBound = lowerBound; 50 this.lowerBound = lowerBound;
39 allMay = Query.of(type.name() + "#may", (builder, instance) -> builder.clause( 51 allMay = Query.of(type.name() + "#may", (builder, instance) -> builder.clause(
40 may(type.call(instance)) 52 may(type.call(instance))
41 )); 53 ));
42 multiMay = Query.of(type.name() + "#multiMay", (builder, instance) -> builder.clause( 54 multiMay = Query.of(type.name() + "#multiMay", (builder, instance) -> builder.clause(
43 may(type.call(instance)), 55 may(type.call(instance)),
44 multi.call(instance) 56 MULTI_VIEW.call(instance)
45 )); 57 ));
46 } 58 }
47 59
@@ -51,8 +63,24 @@ class LowerTypeScopePropagator extends TypeScopePropagator {
51 } 63 }
52 64
53 @Override 65 @Override
54 public Collection<AnyQuery> getQueries() { 66 protected Collection<AnyQuery> getQueries() {
55 return List.of(allMay, multiMay); 67 return List.of(allMay, multiMay);
56 } 68 }
69
70 @Override
71 public void configure(ModelStoreBuilder storeBuilder) {
72 super.configure(storeBuilder);
73
74 var requiredObjects = Query.of(type.name() + "#required", Integer.class, (builder, output) -> builder
75 .clause(Integer.class, currentCount -> List.of(
76 new CountCandidateLowerBoundLiteral(currentCount, type, List.of(Variable.of())),
77 output.assign(sub(currentCount, constant(lowerBound))),
78 check(greater(currentCount, constant(0)))
79 )));
80
81 storeBuilder.getAdapter(ReasoningBuilder.class).objective(Objectives.value(requiredObjects));
82 storeBuilder.tryGetAdapter(DesignSpaceExplorationBuilder.class).ifPresent(dseBuilder ->
83 dseBuilder.accept(Criteria.whenNoMatch(requiredObjects)));
84 }
57 } 85 }
58} 86}
diff --git a/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/ScopePropagatorAdapterImpl.java b/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/ScopePropagatorAdapterImpl.java
index c257df6b..99c501ce 100644
--- a/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/ScopePropagatorAdapterImpl.java
+++ b/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/ScopePropagatorAdapterImpl.java
@@ -85,12 +85,7 @@ class ScopePropagatorAdapterImpl implements ScopePropagatorAdapter {
85 int nodeId = key.get(0); 85 int nodeId = key.get(0);
86 if ((toValue == null || toValue.equals(CardinalityIntervals.ONE))) { 86 if ((toValue == null || toValue.equals(CardinalityIntervals.ONE))) {
87 if (fromValue != null && !fromValue.equals(CardinalityIntervals.ONE)) { 87 if (fromValue != null && !fromValue.equals(CardinalityIntervals.ONE)) {
88 var variable = variables.get(nodeId); 88 removeActiveVariable(toValue, nodeId);
89 if (variable == null || !activeVariables.remove(nodeId)) {
90 throw new AssertionError("Variable not active: " + nodeId);
91 }
92 variable.setBounds(0, 0);
93 markAsChanged();
94 } 89 }
95 return; 90 return;
96 } 91 }
@@ -115,6 +110,21 @@ class ScopePropagatorAdapterImpl implements ScopePropagatorAdapter {
115 } 110 }
116 } 111 }
117 112
113 private void removeActiveVariable(CardinalityInterval toValue, int nodeId) {
114 var variable = variables.get(nodeId);
115 if (variable == null || !activeVariables.remove(nodeId)) {
116 throw new AssertionError("Variable not active: " + nodeId);
117 }
118 if (toValue == null) {
119 variable.setBounds(0, 0);
120 } else {
121 // Until queries are flushed and the constraints can be properly updated,
122 // the variable corresponding to the (previous) multi-object has to stand in for a single object.
123 variable.setBounds(1, 1);
124 }
125 markAsChanged();
126 }
127
118 MPConstraint makeConstraint() { 128 MPConstraint makeConstraint() {
119 return solver.makeConstraint(); 129 return solver.makeConstraint();
120 } 130 }
diff --git a/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/ScopePropagatorBuilderImpl.java b/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/ScopePropagatorBuilderImpl.java
index 11ca7381..531a7440 100644
--- a/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/ScopePropagatorBuilderImpl.java
+++ b/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/ScopePropagatorBuilderImpl.java
@@ -9,8 +9,6 @@ import com.google.ortools.Loader;
9import tools.refinery.store.adapter.AbstractModelAdapterBuilder; 9import tools.refinery.store.adapter.AbstractModelAdapterBuilder;
10import tools.refinery.store.model.ModelStore; 10import tools.refinery.store.model.ModelStore;
11import tools.refinery.store.model.ModelStoreBuilder; 11import tools.refinery.store.model.ModelStoreBuilder;
12import tools.refinery.store.query.ModelQueryBuilder;
13import tools.refinery.store.query.dnf.Query;
14import tools.refinery.store.reasoning.representation.PartialRelation; 12import tools.refinery.store.reasoning.representation.PartialRelation;
15import tools.refinery.store.reasoning.scope.ScopePropagatorBuilder; 13import tools.refinery.store.reasoning.scope.ScopePropagatorBuilder;
16import tools.refinery.store.reasoning.scope.ScopePropagatorStoreAdapter; 14import tools.refinery.store.reasoning.scope.ScopePropagatorStoreAdapter;
@@ -60,25 +58,22 @@ public class ScopePropagatorBuilderImpl extends AbstractModelAdapterBuilder<Scop
60 58
61 @Override 59 @Override
62 protected void doConfigure(ModelStoreBuilder storeBuilder) { 60 protected void doConfigure(ModelStoreBuilder storeBuilder) {
63 var multiQuery = Query.of("MULTI", (builder, instance) -> builder.clause(
64 new MultiView(countSymbol).call(instance)));
65 typeScopePropagatorFactories = new ArrayList<>(scopes.size()); 61 typeScopePropagatorFactories = new ArrayList<>(scopes.size());
66 for (var entry : scopes.entrySet()) { 62 for (var entry : scopes.entrySet()) {
67 var type = entry.getKey(); 63 var type = entry.getKey();
68 var bounds = entry.getValue(); 64 var bounds = entry.getValue();
69 if (bounds.lowerBound() > 0) { 65 if (bounds.lowerBound() > 0) {
70 var lowerFactory = new LowerTypeScopePropagator.Factory(multiQuery, type, bounds.lowerBound()); 66 var lowerFactory = new LowerTypeScopePropagator.Factory(type, bounds.lowerBound());
71 typeScopePropagatorFactories.add(lowerFactory); 67 typeScopePropagatorFactories.add(lowerFactory);
72 } 68 }
73 if (bounds.upperBound() instanceof FiniteUpperCardinality finiteUpperCardinality) { 69 if (bounds.upperBound() instanceof FiniteUpperCardinality finiteUpperCardinality) {
74 var upperFactory = new UpperTypeScopePropagator.Factory(multiQuery, type, 70 var upperFactory = new UpperTypeScopePropagator.Factory(type,
75 finiteUpperCardinality.finiteUpperBound()); 71 finiteUpperCardinality.finiteUpperBound());
76 typeScopePropagatorFactories.add(upperFactory); 72 typeScopePropagatorFactories.add(upperFactory);
77 } 73 }
78 } 74 }
79 var queryBuilder = storeBuilder.getAdapter(ModelQueryBuilder.class);
80 for (var factory : typeScopePropagatorFactories) { 75 for (var factory : typeScopePropagatorFactories) {
81 queryBuilder.queries(factory.getQueries()); 76 factory.configure(storeBuilder);
82 } 77 }
83 } 78 }
84 79
diff --git a/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/TypeScopePropagator.java b/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/TypeScopePropagator.java
index 98f6ed8b..cfb95829 100644
--- a/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/TypeScopePropagator.java
+++ b/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/TypeScopePropagator.java
@@ -6,7 +6,9 @@
6package tools.refinery.store.reasoning.scope.internal; 6package tools.refinery.store.reasoning.scope.internal;
7 7
8import com.google.ortools.linearsolver.MPConstraint; 8import com.google.ortools.linearsolver.MPConstraint;
9import tools.refinery.store.model.ModelStoreBuilder;
9import tools.refinery.store.query.ModelQueryAdapter; 10import tools.refinery.store.query.ModelQueryAdapter;
11import tools.refinery.store.query.ModelQueryBuilder;
10import tools.refinery.store.query.dnf.AnyQuery; 12import tools.refinery.store.query.dnf.AnyQuery;
11import tools.refinery.store.query.dnf.RelationalQuery; 13import tools.refinery.store.query.dnf.RelationalQuery;
12import tools.refinery.store.query.resultset.ResultSet; 14import tools.refinery.store.query.resultset.ResultSet;
@@ -53,9 +55,13 @@ abstract class TypeScopePropagator {
53 adapter.markAsChanged(); 55 adapter.markAsChanged();
54 } 56 }
55 57
56 interface Factory { 58 public abstract static class Factory {
57 TypeScopePropagator createPropagator(ScopePropagatorAdapterImpl adapter); 59 public abstract TypeScopePropagator createPropagator(ScopePropagatorAdapterImpl adapter);
58 60
59 Collection<AnyQuery> getQueries(); 61 protected abstract Collection<AnyQuery> getQueries();
62
63 public void configure(ModelStoreBuilder storeBuilder) {
64 storeBuilder.getAdapter(ModelQueryBuilder.class).queries(getQueries());
65 }
60 } 66 }
61} 67}
diff --git a/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/UpperTypeScopePropagator.java b/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/UpperTypeScopePropagator.java
index 9f09ed56..a0be0fb4 100644
--- a/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/UpperTypeScopePropagator.java
+++ b/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/UpperTypeScopePropagator.java
@@ -14,6 +14,7 @@ import java.util.Collection;
14import java.util.List; 14import java.util.List;
15 15
16import static tools.refinery.store.reasoning.literal.PartialLiterals.must; 16import static tools.refinery.store.reasoning.literal.PartialLiterals.must;
17import static tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator.MULTI_VIEW;
17 18
18class UpperTypeScopePropagator extends TypeScopePropagator { 19class UpperTypeScopePropagator extends TypeScopePropagator {
19 private final int upperBound; 20 private final int upperBound;
@@ -29,19 +30,19 @@ class UpperTypeScopePropagator extends TypeScopePropagator {
29 constraint.setUb(upperBound - getSingleCount()); 30 constraint.setUb(upperBound - getSingleCount());
30 } 31 }
31 32
32 public static class Factory implements TypeScopePropagator.Factory { 33 public static class Factory extends TypeScopePropagator.Factory {
33 private final int upperBound; 34 private final int upperBound;
34 private final RelationalQuery allMust; 35 private final RelationalQuery allMust;
35 private final RelationalQuery multiMust; 36 private final RelationalQuery multiMust;
36 37
37 public Factory(RelationalQuery multi, PartialRelation type, int upperBound) { 38 public Factory(PartialRelation type, int upperBound) {
38 this.upperBound = upperBound; 39 this.upperBound = upperBound;
39 allMust = Query.of(type.name() + "#must", (builder, instance) -> builder.clause( 40 allMust = Query.of(type.name() + "#must", (builder, instance) -> builder.clause(
40 must(type.call(instance)) 41 must(type.call(instance))
41 )); 42 ));
42 multiMust = Query.of(type.name() + "#multiMust", (builder, instance) -> builder.clause( 43 multiMust = Query.of(type.name() + "#multiMust", (builder, instance) -> builder.clause(
43 must(type.call(instance)), 44 must(type.call(instance)),
44 multi.call(instance) 45 MULTI_VIEW.call(instance)
45 )); 46 ));
46 } 47 }
47 48
@@ -51,7 +52,7 @@ class UpperTypeScopePropagator extends TypeScopePropagator {
51 } 52 }
52 53
53 @Override 54 @Override
54 public Collection<AnyQuery> getQueries() { 55 protected Collection<AnyQuery> getQueries() {
55 return List.of(allMust, multiMust); 56 return List.of(allMust, multiMust);
56 } 57 }
57 } 58 }
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningAdapter.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningAdapter.java
index 17aec09c..1dda7ac1 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningAdapter.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningAdapter.java
@@ -42,6 +42,9 @@ public interface ReasoningAdapter extends ModelAdapter {
42 @Nullable 42 @Nullable
43 Tuple1 split(int parentMultiObject); 43 Tuple1 split(int parentMultiObject);
44 44
45 @Nullable
46 Tuple1 focus(int parentObject);
47
45 boolean cleanup(int nodeToDelete); 48 boolean cleanup(int nodeToDelete);
46 49
47 static ReasoningBuilder builder() { 50 static ReasoningBuilder builder() {
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningBuilder.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningBuilder.java
index 3d4c672f..79bce33e 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningBuilder.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningBuilder.java
@@ -6,6 +6,7 @@
6package tools.refinery.store.reasoning; 6package tools.refinery.store.reasoning;
7 7
8import tools.refinery.store.adapter.ModelAdapterBuilder; 8import tools.refinery.store.adapter.ModelAdapterBuilder;
9import tools.refinery.store.dse.transition.objectives.Objective;
9import tools.refinery.store.model.ModelStore; 10import tools.refinery.store.model.ModelStore;
10import tools.refinery.store.query.dnf.Dnf; 11import tools.refinery.store.query.dnf.Dnf;
11import tools.refinery.store.query.dnf.FunctionalQuery; 12import tools.refinery.store.query.dnf.FunctionalQuery;
@@ -35,6 +36,17 @@ public interface ReasoningBuilder extends ModelAdapterBuilder {
35 36
36 ReasoningBuilder initializer(PartialModelInitializer initializer); 37 ReasoningBuilder initializer(PartialModelInitializer initializer);
37 38
39 ReasoningBuilder objective(Objective objective);
40
41 default ReasoningBuilder objectives(Objective... objectives) {
42 return objectives(List.of(objectives));
43 }
44
45 default ReasoningBuilder objectives(Collection<Objective> objectives) {
46 objectives.forEach(this::objective);
47 return this;
48 }
49
38 <T> Query<T> lift(Modality modality, Concreteness concreteness, Query<T> query); 50 <T> Query<T> lift(Modality modality, Concreteness concreteness, Query<T> query);
39 51
40 RelationalQuery lift(Modality modality, Concreteness concreteness, RelationalQuery query); 52 RelationalQuery lift(Modality modality, Concreteness concreteness, RelationalQuery query);
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/actions/FocusActionLiteral.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/actions/FocusActionLiteral.java
new file mode 100644
index 00000000..5a6f22d2
--- /dev/null
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/actions/FocusActionLiteral.java
@@ -0,0 +1,48 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.actions;
7
8import tools.refinery.store.dse.transition.actions.AbstractActionLiteral;
9import tools.refinery.store.dse.transition.actions.BoundActionLiteral;
10import tools.refinery.store.model.Model;
11import tools.refinery.store.query.term.NodeVariable;
12import tools.refinery.store.reasoning.ReasoningAdapter;
13
14import java.util.List;
15
16public class FocusActionLiteral extends AbstractActionLiteral {
17 private final NodeVariable parentNode;
18 private final NodeVariable childNode;
19
20 public FocusActionLiteral(NodeVariable parentNode, NodeVariable childNode) {
21 this.parentNode = parentNode;
22 this.childNode = childNode;
23 }
24
25 public NodeVariable getParentNode() {
26 return parentNode;
27 }
28
29 public NodeVariable getChildNode() {
30 return childNode;
31 }
32
33 @Override
34 public List<NodeVariable> getInputVariables() {
35 return List.of(parentNode);
36 }
37
38 @Override
39 public List<NodeVariable> getOutputVariables() {
40 return List.of(childNode);
41 }
42
43 @Override
44 public BoundActionLiteral bindToModel(Model model) {
45 var reasoningAdapter = model.getAdapter(ReasoningAdapter.class);
46 return tuple -> reasoningAdapter.focus(tuple.get(0));
47 }
48}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/actions/MergeActionLiteral.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/actions/MergeActionLiteral.java
new file mode 100644
index 00000000..8d0d7961
--- /dev/null
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/actions/MergeActionLiteral.java
@@ -0,0 +1,60 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.actions;
7
8import tools.refinery.store.dse.transition.actions.AbstractActionLiteral;
9import tools.refinery.store.dse.transition.actions.BoundActionLiteral;
10import tools.refinery.store.model.Model;
11import tools.refinery.store.query.term.NodeVariable;
12import tools.refinery.store.reasoning.ReasoningAdapter;
13import tools.refinery.store.reasoning.representation.PartialSymbol;
14import tools.refinery.store.tuple.Tuple;
15
16import java.util.List;
17
18public class MergeActionLiteral<A, C> extends AbstractActionLiteral {
19 private final PartialSymbol<A, C> partialSymbol;
20 private final List<NodeVariable> parameters;
21 private final A value;
22
23 public MergeActionLiteral(PartialSymbol<A, C> partialSymbol, A value, List<NodeVariable> parameters) {
24 if (partialSymbol.arity() != parameters.size()) {
25 throw new IllegalArgumentException("Expected %d parameters for partial symbol %s, got %d instead"
26 .formatted(partialSymbol.arity(), partialSymbol, parameters.size()));
27 }
28 this.partialSymbol = partialSymbol;
29 this.parameters = parameters;
30 this.value = value;
31 }
32
33 public PartialSymbol<A, C> getPartialSymbol() {
34 return partialSymbol;
35 }
36
37 public List<NodeVariable> getParameters() {
38 return parameters;
39 }
40
41 public A getValue() {
42 return value;
43 }
44
45 @Override
46 public List<NodeVariable> getInputVariables() {
47 return getParameters();
48 }
49
50 @Override
51 public List<NodeVariable> getOutputVariables() {
52 return List.of();
53 }
54
55 @Override
56 public BoundActionLiteral bindToModel(Model model) {
57 var refiner = model.getAdapter(ReasoningAdapter.class).getRefiner(partialSymbol);
58 return tuple -> refiner.merge(tuple, value) ? Tuple.of() : null;
59 }
60}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/actions/PartialActionLiterals.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/actions/PartialActionLiterals.java
new file mode 100644
index 00000000..990d11e5
--- /dev/null
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/actions/PartialActionLiterals.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.reasoning.actions;
7
8import tools.refinery.store.query.term.NodeVariable;
9import tools.refinery.store.reasoning.representation.PartialRelation;
10import tools.refinery.store.reasoning.representation.PartialSymbol;
11import tools.refinery.store.representation.TruthValue;
12
13import java.util.List;
14
15public final class PartialActionLiterals {
16 private PartialActionLiterals() {
17 throw new IllegalStateException("This is a static utility class and should not be instantiated directly");
18 }
19
20 public static <A, C> MergeActionLiteral<A, C> merge(PartialSymbol<A, C> partialSymbol, A value,
21 NodeVariable... parameters) {
22 return new MergeActionLiteral<>(partialSymbol, value, List.of(parameters));
23 }
24
25 public static MergeActionLiteral<TruthValue, Boolean> add(PartialRelation partialRelation,
26 NodeVariable... parameters) {
27 return merge(partialRelation, TruthValue.TRUE, parameters);
28 }
29
30 public static MergeActionLiteral<TruthValue, Boolean> remove(PartialRelation partialRelation,
31 NodeVariable... parameters) {
32 return merge(partialRelation, TruthValue.FALSE, parameters);
33 }
34
35 public static FocusActionLiteral focus(NodeVariable parent, NodeVariable child) {
36 return new FocusActionLiteral(parent, child);
37 }
38}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java
index 2fa744de..f91fdd07 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java
@@ -17,7 +17,10 @@ import tools.refinery.store.reasoning.refinement.PartialInterpretationRefiner;
17import tools.refinery.store.reasoning.refinement.StorageRefiner; 17import tools.refinery.store.reasoning.refinement.StorageRefiner;
18import tools.refinery.store.reasoning.representation.AnyPartialSymbol; 18import tools.refinery.store.reasoning.representation.AnyPartialSymbol;
19import tools.refinery.store.reasoning.representation.PartialSymbol; 19import tools.refinery.store.reasoning.representation.PartialSymbol;
20import tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator;
20import tools.refinery.store.representation.Symbol; 21import tools.refinery.store.representation.Symbol;
22import tools.refinery.store.representation.cardinality.CardinalityInterval;
23import tools.refinery.store.representation.cardinality.CardinalityIntervals;
21import tools.refinery.store.tuple.Tuple; 24import tools.refinery.store.tuple.Tuple;
22import tools.refinery.store.tuple.Tuple1; 25import tools.refinery.store.tuple.Tuple1;
23 26
@@ -32,6 +35,7 @@ class ReasoningAdapterImpl implements ReasoningAdapter {
32 private final Map<AnyPartialSymbol, AnyPartialInterpretationRefiner> refiners; 35 private final Map<AnyPartialSymbol, AnyPartialInterpretationRefiner> refiners;
33 private final StorageRefiner[] storageRefiners; 36 private final StorageRefiner[] storageRefiners;
34 private final Interpretation<Integer> nodeCountInterpretation; 37 private final Interpretation<Integer> nodeCountInterpretation;
38 private final Interpretation<CardinalityInterval> countInterpretation;
35 39
36 ReasoningAdapterImpl(Model model, ReasoningStoreAdapterImpl storeAdapter) { 40 ReasoningAdapterImpl(Model model, ReasoningStoreAdapterImpl storeAdapter) {
37 this.model = model; 41 this.model = model;
@@ -51,6 +55,11 @@ class ReasoningAdapterImpl implements ReasoningAdapter {
51 storageRefiners = storeAdapter.createStorageRefiner(model); 55 storageRefiners = storeAdapter.createStorageRefiner(model);
52 56
53 nodeCountInterpretation = model.getInterpretation(NODE_COUNT_SYMBOL); 57 nodeCountInterpretation = model.getInterpretation(NODE_COUNT_SYMBOL);
58 if (model.getStore().getSymbols().contains(MultiObjectTranslator.COUNT_STORAGE)) {
59 countInterpretation = model.getInterpretation(MultiObjectTranslator.COUNT_STORAGE);
60 } else {
61 countInterpretation = null;
62 }
54 } 63 }
55 64
56 private void createPartialInterpretations() { 65 private void createPartialInterpretations() {
@@ -161,6 +170,26 @@ class ReasoningAdapterImpl implements ReasoningAdapter {
161 } 170 }
162 171
163 @Override 172 @Override
173 public @Nullable Tuple1 focus(int parentObject) {
174 if (countInterpretation == null) {
175 throw new IllegalStateException("Cannot focus without " + MultiObjectTranslator.class.getSimpleName());
176 }
177 var tuple = Tuple.of(parentObject);
178 var count = countInterpretation.get(tuple);
179 if (CardinalityIntervals.ONE.equals(count)) {
180 return tuple;
181 }
182 if (CardinalityIntervals.LONE.equals(count)) {
183 countInterpretation.put(tuple, CardinalityIntervals.ONE);
184 return tuple;
185 }
186 if (CardinalityIntervals.NONE.equals(count)) {
187 return null;
188 }
189 return split(parentObject);
190 }
191
192 @Override
164 public boolean cleanup(int nodeToDelete) { 193 public boolean cleanup(int nodeToDelete) {
165 // Avoid creating an iterator object. 194 // Avoid creating an iterator object.
166 //noinspection ForLoopReplaceableByForEach 195 //noinspection ForLoopReplaceableByForEach
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningBuilderImpl.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningBuilderImpl.java
index b4971d2c..d2cd2eb0 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningBuilderImpl.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningBuilderImpl.java
@@ -6,6 +6,9 @@
6package tools.refinery.store.reasoning.internal; 6package tools.refinery.store.reasoning.internal;
7 7
8import tools.refinery.store.adapter.AbstractModelAdapterBuilder; 8import tools.refinery.store.adapter.AbstractModelAdapterBuilder;
9import tools.refinery.store.dse.transition.DesignSpaceExplorationBuilder;
10import tools.refinery.store.dse.transition.objectives.Objective;
11import tools.refinery.store.dse.transition.objectives.Objectives;
9import tools.refinery.store.model.ModelStore; 12import tools.refinery.store.model.ModelStore;
10import tools.refinery.store.model.ModelStoreBuilder; 13import tools.refinery.store.model.ModelStoreBuilder;
11import tools.refinery.store.query.ModelQueryBuilder; 14import tools.refinery.store.query.ModelQueryBuilder;
@@ -36,11 +39,13 @@ public class ReasoningBuilderImpl extends AbstractModelAdapterBuilder<ReasoningS
36 private final PartialQueryRewriter queryRewriter = new PartialQueryRewriter(lifter); 39 private final PartialQueryRewriter queryRewriter = new PartialQueryRewriter(lifter);
37 private Set<Concreteness> requiredInterpretations = Set.of(Concreteness.values()); 40 private Set<Concreteness> requiredInterpretations = Set.of(Concreteness.values());
38 private final Map<AnyPartialSymbol, AnyPartialSymbolTranslator> translators = new LinkedHashMap<>(); 41 private final Map<AnyPartialSymbol, AnyPartialSymbolTranslator> translators = new LinkedHashMap<>();
39 private final Map<AnyPartialSymbol, PartialInterpretation.Factory<?, ?>> symbolInterpreters = new LinkedHashMap<>(); 42 private final Map<AnyPartialSymbol, PartialInterpretation.Factory<?, ?>> symbolInterpreters =
43 new LinkedHashMap<>();
40 private final Map<AnyPartialSymbol, PartialInterpretationRefiner.Factory<?, ?>> symbolRefiners = 44 private final Map<AnyPartialSymbol, PartialInterpretationRefiner.Factory<?, ?>> symbolRefiners =
41 new LinkedHashMap<>(); 45 new LinkedHashMap<>();
42 private final Map<AnySymbol, StorageRefiner.Factory<?>> registeredStorageRefiners = new LinkedHashMap<>(); 46 private final Map<AnySymbol, StorageRefiner.Factory<?>> registeredStorageRefiners = new LinkedHashMap<>();
43 private final List<PartialModelInitializer> initializers = new ArrayList<>(); 47 private final List<PartialModelInitializer> initializers = new ArrayList<>();
48 private final List<Objective> objectives = new ArrayList<>();
44 49
45 @Override 50 @Override
46 public ReasoningBuilder requiredInterpretations(Collection<Concreteness> requiredInterpretations) { 51 public ReasoningBuilder requiredInterpretations(Collection<Concreteness> requiredInterpretations) {
@@ -75,6 +80,13 @@ public class ReasoningBuilderImpl extends AbstractModelAdapterBuilder<ReasoningS
75 } 80 }
76 81
77 @Override 82 @Override
83 public ReasoningBuilder objective(Objective objective) {
84 checkNotConfigured();
85 objectives.add(objective);
86 return this;
87 }
88
89 @Override
78 public <T> Query<T> lift(Modality modality, Concreteness concreteness, Query<T> query) { 90 public <T> Query<T> lift(Modality modality, Concreteness concreteness, Query<T> query) {
79 return lifter.lift(modality, concreteness, query); 91 return lifter.lift(modality, concreteness, query);
80 } 92 }
@@ -109,6 +121,10 @@ public class ReasoningBuilderImpl extends AbstractModelAdapterBuilder<ReasoningS
109 storeBuilder.symbols(registeredStorageRefiners.keySet()); 121 storeBuilder.symbols(registeredStorageRefiners.keySet());
110 var queryBuilder = storeBuilder.getAdapter(ModelQueryBuilder.class); 122 var queryBuilder = storeBuilder.getAdapter(ModelQueryBuilder.class);
111 queryBuilder.rewriter(queryRewriter); 123 queryBuilder.rewriter(queryRewriter);
124 if (!objectives.isEmpty()) {
125 storeBuilder.tryGetAdapter(DesignSpaceExplorationBuilder.class)
126 .ifPresent(dseBuilder -> dseBuilder.objective(Objectives.sum(objectives)));
127 }
112 } 128 }
113 129
114 private void doConfigure(ModelStoreBuilder storeBuilder, PartialRelationTranslator relationConfiguration) { 130 private void doConfigure(ModelStoreBuilder storeBuilder, PartialRelationTranslator relationConfiguration) {
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/PartialRelationTranslator.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/PartialRelationTranslator.java
index 4600d5a4..c2039afc 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/PartialRelationTranslator.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/PartialRelationTranslator.java
@@ -5,14 +5,21 @@
5 */ 5 */
6package tools.refinery.store.reasoning.translator; 6package tools.refinery.store.reasoning.translator;
7 7
8import tools.refinery.store.dse.transition.Rule;
9import tools.refinery.store.dse.transition.objectives.Criteria;
10import tools.refinery.store.dse.transition.objectives.Criterion;
11import tools.refinery.store.dse.transition.objectives.Objective;
12import tools.refinery.store.dse.transition.objectives.Objectives;
8import tools.refinery.store.model.ModelStoreBuilder; 13import tools.refinery.store.model.ModelStoreBuilder;
9import tools.refinery.store.query.Constraint; 14import tools.refinery.store.query.Constraint;
10import tools.refinery.store.query.dnf.Query; 15import tools.refinery.store.query.dnf.Query;
11import tools.refinery.store.query.dnf.QueryBuilder; 16import tools.refinery.store.query.dnf.QueryBuilder;
12import tools.refinery.store.query.dnf.RelationalQuery; 17import tools.refinery.store.query.dnf.RelationalQuery;
13import tools.refinery.store.query.term.Variable; 18import tools.refinery.store.query.literal.Literal;
19import tools.refinery.store.query.term.NodeVariable;
14import tools.refinery.store.query.view.MayView; 20import tools.refinery.store.query.view.MayView;
15import tools.refinery.store.query.view.MustView; 21import tools.refinery.store.query.view.MustView;
22import tools.refinery.store.reasoning.ReasoningAdapter;
16import tools.refinery.store.reasoning.ReasoningBuilder; 23import tools.refinery.store.reasoning.ReasoningBuilder;
17import tools.refinery.store.reasoning.interpretation.PartialInterpretation; 24import tools.refinery.store.reasoning.interpretation.PartialInterpretation;
18import tools.refinery.store.reasoning.interpretation.PartialRelationRewriter; 25import tools.refinery.store.reasoning.interpretation.PartialRelationRewriter;
@@ -21,6 +28,7 @@ import tools.refinery.store.reasoning.interpretation.QueryBasedRelationRewriter;
21import tools.refinery.store.reasoning.lifting.DnfLifter; 28import tools.refinery.store.reasoning.lifting.DnfLifter;
22import tools.refinery.store.reasoning.literal.Concreteness; 29import tools.refinery.store.reasoning.literal.Concreteness;
23import tools.refinery.store.reasoning.literal.Modality; 30import tools.refinery.store.reasoning.literal.Modality;
31import tools.refinery.store.reasoning.literal.PartialLiterals;
24import tools.refinery.store.reasoning.refinement.ConcreteSymbolRefiner; 32import tools.refinery.store.reasoning.refinement.ConcreteSymbolRefiner;
25import tools.refinery.store.reasoning.refinement.PartialInterpretationRefiner; 33import tools.refinery.store.reasoning.refinement.PartialInterpretationRefiner;
26import tools.refinery.store.reasoning.refinement.PartialModelInitializer; 34import tools.refinery.store.reasoning.refinement.PartialModelInitializer;
@@ -30,8 +38,11 @@ import tools.refinery.store.representation.AnySymbol;
30import tools.refinery.store.representation.Symbol; 38import tools.refinery.store.representation.Symbol;
31import tools.refinery.store.representation.TruthValue; 39import tools.refinery.store.representation.TruthValue;
32 40
41import java.util.ArrayList;
33import java.util.function.BiConsumer; 42import java.util.function.BiConsumer;
34 43
44import static tools.refinery.store.query.literal.Literals.not;
45
35@SuppressWarnings("UnusedReturnValue") 46@SuppressWarnings("UnusedReturnValue")
36public final class PartialRelationTranslator extends PartialSymbolTranslator<TruthValue, Boolean> { 47public final class PartialRelationTranslator extends PartialSymbolTranslator<TruthValue, Boolean> {
37 private final PartialRelation partialRelation; 48 private final PartialRelation partialRelation;
@@ -94,6 +105,30 @@ public final class PartialRelationTranslator extends PartialSymbolTranslator<Tru
94 return this; 105 return this;
95 } 106 }
96 107
108 @Override
109 public PartialRelationTranslator decision(Rule decisionRule) {
110 super.decision(decisionRule);
111 return this;
112 }
113
114 @Override
115 public PartialRelationTranslator accept(Criterion acceptanceCriterion) {
116 super.accept(acceptanceCriterion);
117 return this;
118 }
119
120 @Override
121 public PartialRelationTranslator exclude(Criterion exclusionCriterion) {
122 super.exclude(exclusionCriterion);
123 return this;
124 }
125
126 @Override
127 public PartialRelationTranslator objective(Objective objective) {
128 super.objective(objective);
129 return this;
130 }
131
97 public PartialRelationTranslator query(RelationalQuery query) { 132 public PartialRelationTranslator query(RelationalQuery query) {
98 checkNotConfigured(); 133 checkNotConfigured();
99 if (this.query != null) { 134 if (this.query != null) {
@@ -170,6 +205,8 @@ public final class PartialRelationTranslator extends PartialSymbolTranslator<Tru
170 createFallbackRewriter(); 205 createFallbackRewriter();
171 createFallbackInterpretation(); 206 createFallbackInterpretation();
172 createFallbackRefiner(); 207 createFallbackRefiner();
208 createFallbackExclude();
209 createFallbackObjective();
173 super.doConfigure(storeBuilder); 210 super.doConfigure(storeBuilder);
174 } 211 }
175 212
@@ -179,10 +216,10 @@ public final class PartialRelationTranslator extends PartialSymbolTranslator<Tru
179 } 216 }
180 } 217 }
181 218
182 private RelationalQuery createQuery(String name, BiConsumer<QueryBuilder, Variable[]> callback) { 219 private RelationalQuery createQuery(String name, BiConsumer<QueryBuilder, NodeVariable[]> callback) {
183 int arity = partialRelation.arity(); 220 int arity = partialRelation.arity();
184 var queryBuilder = Query.builder(name); 221 var queryBuilder = Query.builder(name);
185 var parameters = new Variable[arity]; 222 var parameters = new NodeVariable[arity];
186 for (int i = 0; i < arity; i++) { 223 for (int i = 0; i < arity; i++) {
187 parameters[i] = queryBuilder.parameter("p" + 1); 224 parameters[i] = queryBuilder.parameter("p" + 1);
188 } 225 }
@@ -293,6 +330,55 @@ public final class PartialRelationTranslator extends PartialSymbolTranslator<Tru
293 } 330 }
294 } 331 }
295 332
333 private void createFallbackExclude() {
334 if (excludeWasSet) {
335 return;
336 }
337 var excludeQuery = createQuery("exclude", (builder, parameters) -> {
338 var literals = new ArrayList<Literal>(parameters.length + 2);
339 literals.add(PartialLiterals.must(partialRelation.call(parameters)));
340 literals.add(not(PartialLiterals.may(partialRelation.call(parameters))));
341 for (var parameter : parameters) {
342 literals.add(PartialLiterals.must(ReasoningAdapter.EXISTS_SYMBOL.call(parameter)));
343 }
344 builder.clause(literals);
345 });
346 exclude = Criteria.whenHasMatch(excludeQuery);
347 }
348
349 private void createFallbackObjective() {
350 if (acceptWasSet && objectiveWasSet) {
351 return;
352 }
353 var invalidCandidate = createQuery("invalidCandidate", (builder, parameters) -> builder
354 .clause(
355 PartialLiterals.candidateMust(partialRelation.call(parameters)),
356 not(PartialLiterals.candidateMay(partialRelation.call(parameters)))
357 )
358 .clause(
359 PartialLiterals.candidateMust(partialRelation.call(parameters)),
360 not(PartialLiterals.may(partialRelation.call(parameters)))
361 )
362 .clause(
363 PartialLiterals.must(partialRelation.call(parameters)),
364 not(PartialLiterals.candidateMay(partialRelation.call(parameters)))
365 ));
366 var reject = createQuery("reject", (builder, parameters) -> {
367 var literals = new ArrayList<Literal>(parameters.length + 1);
368 literals.add(invalidCandidate.call(parameters));
369 for (var parameter : parameters) {
370 literals.add(PartialLiterals.candidateMust(ReasoningAdapter.EXISTS_SYMBOL.call(parameter)));
371 }
372 builder.clause(literals);
373 });
374 if (!acceptWasSet) {
375 accept = Criteria.whenNoMatch(reject);
376 }
377 if (!objectiveWasSet) {
378 objective = Objectives.count(reject);
379 }
380 }
381
296 public PartialRelationRewriter getRewriter() { 382 public PartialRelationRewriter getRewriter() {
297 checkConfigured(); 383 checkConfigured();
298 return rewriter; 384 return rewriter;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/PartialSymbolTranslator.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/PartialSymbolTranslator.java
index e7e26cb2..6cdb287d 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/PartialSymbolTranslator.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/PartialSymbolTranslator.java
@@ -5,10 +5,14 @@
5 */ 5 */
6package tools.refinery.store.reasoning.translator; 6package tools.refinery.store.reasoning.translator;
7 7
8import org.jetbrains.annotations.Nullable;
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;
8import tools.refinery.store.model.ModelStoreBuilder; 13import tools.refinery.store.model.ModelStoreBuilder;
9import tools.refinery.store.reasoning.ReasoningBuilder; 14import tools.refinery.store.reasoning.ReasoningBuilder;
10import tools.refinery.store.reasoning.interpretation.PartialInterpretation; 15import tools.refinery.store.reasoning.interpretation.PartialInterpretation;
11import tools.refinery.store.reasoning.literal.Concreteness;
12import tools.refinery.store.reasoning.refinement.PartialInterpretationRefiner; 16import tools.refinery.store.reasoning.refinement.PartialInterpretationRefiner;
13import tools.refinery.store.reasoning.refinement.PartialModelInitializer; 17import tools.refinery.store.reasoning.refinement.PartialModelInitializer;
14import tools.refinery.store.reasoning.refinement.StorageRefiner; 18import tools.refinery.store.reasoning.refinement.StorageRefiner;
@@ -17,7 +21,8 @@ import tools.refinery.store.reasoning.seed.SeedInitializer;
17import tools.refinery.store.representation.AnySymbol; 21import tools.refinery.store.representation.AnySymbol;
18import tools.refinery.store.representation.Symbol; 22import tools.refinery.store.representation.Symbol;
19 23
20import java.util.Set; 24import java.util.ArrayList;
25import java.util.List;
21 26
22@SuppressWarnings("UnusedReturnValue") 27@SuppressWarnings("UnusedReturnValue")
23public abstract sealed class PartialSymbolTranslator<A, C> implements AnyPartialSymbolTranslator 28public abstract sealed class PartialSymbolTranslator<A, C> implements AnyPartialSymbolTranslator
@@ -29,6 +34,13 @@ public abstract sealed class PartialSymbolTranslator<A, C> implements AnyPartial
29 protected StorageRefiner.Factory<?> storageRefiner; 34 protected StorageRefiner.Factory<?> storageRefiner;
30 protected PartialInterpretation.Factory<A, C> interpretationFactory; 35 protected PartialInterpretation.Factory<A, C> interpretationFactory;
31 protected PartialModelInitializer initializer; 36 protected PartialModelInitializer initializer;
37 protected List<Rule> decisionRules = new ArrayList<>();
38 protected boolean acceptWasSet;
39 protected @Nullable Criterion accept;
40 protected boolean excludeWasSet;
41 protected @Nullable Criterion exclude;
42 protected boolean objectiveWasSet;
43 protected @Nullable Objective objective;
32 44
33 PartialSymbolTranslator(PartialSymbol<A, C> partialSymbol) { 45 PartialSymbolTranslator(PartialSymbol<A, C> partialSymbol) {
34 this.partialSymbol = partialSymbol; 46 this.partialSymbol = partialSymbol;
@@ -102,6 +114,38 @@ public abstract sealed class PartialSymbolTranslator<A, C> implements AnyPartial
102 return this; 114 return this;
103 } 115 }
104 116
117 public PartialSymbolTranslator<A, C> decision(Rule decisionRule) {
118 decisionRules.add(decisionRule);
119 return this;
120 }
121
122 public PartialSymbolTranslator<A, C> accept(@Nullable Criterion acceptanceCriterion) {
123 if (acceptWasSet) {
124 throw new IllegalStateException("Accept was already set");
125 }
126 this.accept = acceptanceCriterion;
127 acceptWasSet = true;
128 return this;
129 }
130
131 public PartialSymbolTranslator<A, C> exclude(@Nullable Criterion exclusionCriterion) {
132 if (excludeWasSet) {
133 throw new IllegalStateException("Exclude was already set");
134 }
135 this.exclude = exclusionCriterion;
136 excludeWasSet = true;
137 return this;
138 }
139
140 public PartialSymbolTranslator<A, C> objective(Objective objective) {
141 if (objectiveWasSet) {
142 throw new IllegalStateException("Objective was already set");
143 }
144 this.objective = objective;
145 objectiveWasSet = true;
146 return this;
147 }
148
105 @Override 149 @Override
106 public void configure(ModelStoreBuilder storeBuilder) { 150 public void configure(ModelStoreBuilder storeBuilder) {
107 checkNotConfigured(); 151 checkNotConfigured();
@@ -124,6 +168,18 @@ public abstract sealed class PartialSymbolTranslator<A, C> implements AnyPartial
124 if (initializer != null) { 168 if (initializer != null) {
125 reasoningBuilder.initializer(initializer); 169 reasoningBuilder.initializer(initializer);
126 } 170 }
171 storeBuilder.tryGetAdapter(DesignSpaceExplorationBuilder.class).ifPresent(dseBuilder -> {
172 dseBuilder.transformations(decisionRules);
173 if (accept != null) {
174 dseBuilder.accept(accept);
175 }
176 if (exclude != null) {
177 dseBuilder.exclude(exclude);
178 }
179 });
180 if (objective != null) {
181 reasoningBuilder.objective(objective);
182 }
127 } 183 }
128 184
129 private <T> void registerStorageRefiner(ReasoningBuilder reasoningBuilder, StorageRefiner.Factory<T> factory) { 185 private <T> void registerStorageRefiner(ReasoningBuilder reasoningBuilder, StorageRefiner.Factory<T> factory) {
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainmentHierarchyTranslator.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainmentHierarchyTranslator.java
index dda9f2c8..5c3298ac 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainmentHierarchyTranslator.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/containment/ContainmentHierarchyTranslator.java
@@ -5,6 +5,8 @@
5 */ 5 */
6package tools.refinery.store.reasoning.translator.containment; 6package tools.refinery.store.reasoning.translator.containment;
7 7
8import tools.refinery.store.dse.transition.DesignSpaceExplorationBuilder;
9import tools.refinery.store.dse.transition.Rule;
8import tools.refinery.store.model.ModelStoreBuilder; 10import tools.refinery.store.model.ModelStoreBuilder;
9import tools.refinery.store.model.ModelStoreConfiguration; 11import tools.refinery.store.model.ModelStoreConfiguration;
10import tools.refinery.store.query.dnf.Query; 12import tools.refinery.store.query.dnf.Query;
@@ -22,6 +24,7 @@ import tools.refinery.store.reasoning.refinement.RefinementBasedInitializer;
22import tools.refinery.store.reasoning.representation.PartialRelation; 24import tools.refinery.store.reasoning.representation.PartialRelation;
23import tools.refinery.store.reasoning.translator.PartialRelationTranslator; 25import tools.refinery.store.reasoning.translator.PartialRelationTranslator;
24import tools.refinery.store.reasoning.translator.RoundingMode; 26import tools.refinery.store.reasoning.translator.RoundingMode;
27import tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator;
25import tools.refinery.store.reasoning.translator.multiplicity.ConstrainedMultiplicity; 28import tools.refinery.store.reasoning.translator.multiplicity.ConstrainedMultiplicity;
26import tools.refinery.store.reasoning.translator.multiplicity.InvalidMultiplicityErrorTranslator; 29import tools.refinery.store.reasoning.translator.multiplicity.InvalidMultiplicityErrorTranslator;
27import tools.refinery.store.representation.Symbol; 30import tools.refinery.store.representation.Symbol;
@@ -37,8 +40,9 @@ import static tools.refinery.store.query.literal.Literals.not;
37import static tools.refinery.store.query.term.int_.IntTerms.constant; 40import static tools.refinery.store.query.term.int_.IntTerms.constant;
38import static tools.refinery.store.query.term.int_.IntTerms.less; 41import static tools.refinery.store.query.term.int_.IntTerms.less;
39import static tools.refinery.store.reasoning.ReasoningAdapter.EXISTS_SYMBOL; 42import static tools.refinery.store.reasoning.ReasoningAdapter.EXISTS_SYMBOL;
40import static tools.refinery.store.reasoning.literal.PartialLiterals.may; 43import static tools.refinery.store.reasoning.actions.PartialActionLiterals.add;
41import static tools.refinery.store.reasoning.literal.PartialLiterals.must; 44import static tools.refinery.store.reasoning.actions.PartialActionLiterals.focus;
45import static tools.refinery.store.reasoning.literal.PartialLiterals.*;
42 46
43public class ContainmentHierarchyTranslator implements ModelStoreConfiguration { 47public class ContainmentHierarchyTranslator implements ModelStoreConfiguration {
44 public static final PartialRelation CONTAINED_SYMBOL = new PartialRelation("contained", 1); 48 public static final PartialRelation CONTAINED_SYMBOL = new PartialRelation("contained", 1);
@@ -104,6 +108,7 @@ public class ContainmentHierarchyTranslator implements ModelStoreConfiguration {
104 translateContainmentLinkType(storeBuilder, linkType, info); 108 translateContainmentLinkType(storeBuilder, linkType, info);
105 translateInvalidMultiplicity(storeBuilder, linkType, info); 109 translateInvalidMultiplicity(storeBuilder, linkType, info);
106 } 110 }
111 translateFocusNotContained(storeBuilder);
107 } 112 }
108 113
109 private void translateContainmentLinkType(ModelStoreBuilder storeBuilder, PartialRelation linkType, 114 private void translateContainmentLinkType(ModelStoreBuilder storeBuilder, PartialRelation linkType,
@@ -188,7 +193,17 @@ public class ContainmentHierarchyTranslator implements ModelStoreConfiguration {
188 ))) 193 )))
189 .roundingMode(RoundingMode.PREFER_FALSE) 194 .roundingMode(RoundingMode.PREFER_FALSE)
190 .refiner(ContainmentLinkRefiner.of(linkType, containsStorage, info.sourceType(), info.targetType())) 195 .refiner(ContainmentLinkRefiner.of(linkType, containsStorage, info.sourceType(), info.targetType()))
191 .initializer(new RefinementBasedInitializer<>(linkType))); 196 .initializer(new RefinementBasedInitializer<>(linkType))
197 .decision(Rule.of(linkType.name(), (builder, source, target) -> builder
198 .clause(
199 may(linkType.call(source, target)),
200 not(candidateMust(linkType.call(source, target))),
201 not(MultiObjectTranslator.MULTI_VIEW.call(source))
202 )
203 .action(focusedTarget -> List.of(
204 focus(target, focusedTarget),
205 add(linkType, source, focusedTarget)
206 )))));
192 } 207 }
193 208
194 private void translateInvalidMultiplicity(ModelStoreBuilder storeBuilder, PartialRelation linkType, 209 private void translateInvalidMultiplicity(ModelStoreBuilder storeBuilder, PartialRelation linkType,
@@ -216,4 +231,25 @@ public class ContainmentHierarchyTranslator implements ModelStoreConfiguration {
216 storeBuilder.with(new InvalidMultiplicityErrorTranslator(CONTAINED_SYMBOL, CONTAINS_SYMBOL, true, 231 storeBuilder.with(new InvalidMultiplicityErrorTranslator(CONTAINED_SYMBOL, CONTAINS_SYMBOL, true,
217 ConstrainedMultiplicity.of(CardinalityIntervals.ONE, INVALID_CONTAINER))); 232 ConstrainedMultiplicity.of(CardinalityIntervals.ONE, INVALID_CONTAINER)));
218 } 233 }
234
235 private void translateFocusNotContained(ModelStoreBuilder storeBuilder) {
236 var dseBuilderOption = storeBuilder.tryGetAdapter(DesignSpaceExplorationBuilder.class);
237 if (dseBuilderOption.isEmpty()) {
238 return;
239 }
240 var dseBuilder = dseBuilderOption.get();
241 dseBuilder.transformation(Rule.of("NOT_CONTAINED", (builder, multi) -> builder
242 .clause(
243 MultiObjectTranslator.MULTI_VIEW.call(multi),
244 not(may(CONTAINED_SYMBOL.call(multi)))
245 )
246 .clause((container) -> List.of(
247 MultiObjectTranslator.MULTI_VIEW.call(multi),
248 must(CONTAINS_SYMBOL.call(container, multi)),
249 not(MultiObjectTranslator.MULTI_VIEW.call(container))
250 ))
251 .action(
252 focus(multi, Variable.of())
253 )));
254 }
219} 255}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceTranslator.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceTranslator.java
index f978aad4..9028337c 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceTranslator.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/DirectedCrossReferenceTranslator.java
@@ -5,6 +5,7 @@
5 */ 5 */
6package tools.refinery.store.reasoning.translator.crossreference; 6package tools.refinery.store.reasoning.translator.crossreference;
7 7
8import tools.refinery.store.dse.transition.Rule;
8import tools.refinery.store.model.ModelStoreBuilder; 9import tools.refinery.store.model.ModelStoreBuilder;
9import tools.refinery.store.model.ModelStoreConfiguration; 10import tools.refinery.store.model.ModelStoreConfiguration;
10import tools.refinery.store.query.dnf.Query; 11import tools.refinery.store.query.dnf.Query;
@@ -22,8 +23,9 @@ import tools.refinery.store.representation.Symbol;
22import tools.refinery.store.representation.TruthValue; 23import tools.refinery.store.representation.TruthValue;
23 24
24import static tools.refinery.store.query.literal.Literals.not; 25import static tools.refinery.store.query.literal.Literals.not;
25import static tools.refinery.store.reasoning.literal.PartialLiterals.may; 26import static tools.refinery.store.reasoning.actions.PartialActionLiterals.add;
26import static tools.refinery.store.reasoning.literal.PartialLiterals.must; 27import static tools.refinery.store.reasoning.literal.PartialLiterals.*;
28import static tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator.MULTI_VIEW;
27 29
28public class DirectedCrossReferenceTranslator implements ModelStoreConfiguration { 30public class DirectedCrossReferenceTranslator implements ModelStoreConfiguration {
29 private final PartialRelation linkType; 31 private final PartialRelation linkType;
@@ -67,7 +69,17 @@ public class DirectedCrossReferenceTranslator implements ModelStoreConfiguration
67 } 69 }
68 })) 70 }))
69 .refiner(DirectedCrossReferenceRefiner.of(symbol, sourceType, targetType)) 71 .refiner(DirectedCrossReferenceRefiner.of(symbol, sourceType, targetType))
70 .initializer(new RefinementBasedInitializer<>(linkType))); 72 .initializer(new RefinementBasedInitializer<>(linkType))
73 .decision(Rule.of(linkType.name(), (builder, source, target) -> builder
74 .clause(
75 may(linkType.call(source, target)),
76 not(candidateMust(linkType.call(source, target))),
77 not(MULTI_VIEW.call(source)),
78 not(MULTI_VIEW.call(target))
79 )
80 .action(
81 add(linkType, source, target)
82 ))));
71 83
72 storeBuilder.with(new InvalidMultiplicityErrorTranslator(sourceType, linkType, false, 84 storeBuilder.with(new InvalidMultiplicityErrorTranslator(sourceType, linkType, false,
73 info.sourceMultiplicity())); 85 info.sourceMultiplicity()));
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceTranslator.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceTranslator.java
index e599992d..c554e2a4 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceTranslator.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/crossreference/UndirectedCrossReferenceTranslator.java
@@ -5,6 +5,7 @@
5 */ 5 */
6package tools.refinery.store.reasoning.translator.crossreference; 6package tools.refinery.store.reasoning.translator.crossreference;
7 7
8import tools.refinery.store.dse.transition.Rule;
8import tools.refinery.store.model.ModelStoreBuilder; 9import tools.refinery.store.model.ModelStoreBuilder;
9import tools.refinery.store.model.ModelStoreConfiguration; 10import tools.refinery.store.model.ModelStoreConfiguration;
10import tools.refinery.store.query.dnf.Query; 11import tools.refinery.store.query.dnf.Query;
@@ -20,8 +21,9 @@ import tools.refinery.store.representation.Symbol;
20import tools.refinery.store.representation.TruthValue; 21import tools.refinery.store.representation.TruthValue;
21 22
22import static tools.refinery.store.query.literal.Literals.not; 23import static tools.refinery.store.query.literal.Literals.not;
23import static tools.refinery.store.reasoning.literal.PartialLiterals.may; 24import static tools.refinery.store.reasoning.actions.PartialActionLiterals.add;
24import static tools.refinery.store.reasoning.literal.PartialLiterals.must; 25import static tools.refinery.store.reasoning.literal.PartialLiterals.*;
26import static tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator.MULTI_VIEW;
25 27
26public class UndirectedCrossReferenceTranslator implements ModelStoreConfiguration { 28public class UndirectedCrossReferenceTranslator implements ModelStoreConfiguration {
27 private final PartialRelation linkType; 29 private final PartialRelation linkType;
@@ -64,7 +66,17 @@ public class UndirectedCrossReferenceTranslator implements ModelStoreConfigurati
64 } 66 }
65 })) 67 }))
66 .refiner(UndirectedCrossReferenceRefiner.of(symbol, type)) 68 .refiner(UndirectedCrossReferenceRefiner.of(symbol, type))
67 .initializer(new RefinementBasedInitializer<>(linkType))); 69 .initializer(new RefinementBasedInitializer<>(linkType))
70 .decision(Rule.of(linkType.name(), (builder, source, target) -> builder
71 .clause(
72 may(linkType.call(source, target)),
73 not(candidateMust(linkType.call(source, target))),
74 not(MULTI_VIEW.call(source)),
75 not(MULTI_VIEW.call(target))
76 )
77 .action(
78 add(linkType, source, target)
79 ))));
68 80
69 storeBuilder.with(new InvalidMultiplicityErrorTranslator(type, linkType, false, info.multiplicity())); 81 storeBuilder.with(new InvalidMultiplicityErrorTranslator(type, linkType, false, info.multiplicity()));
70 } 82 }
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiobject/MultiObjectTranslator.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiobject/MultiObjectTranslator.java
index 735896fa..05704096 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiobject/MultiObjectTranslator.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiobject/MultiObjectTranslator.java
@@ -5,9 +5,14 @@
5 */ 5 */
6package tools.refinery.store.reasoning.translator.multiobject; 6package tools.refinery.store.reasoning.translator.multiobject;
7 7
8import tools.refinery.store.dse.transition.objectives.Criteria;
9import tools.refinery.store.dse.transition.objectives.Objectives;
8import tools.refinery.store.model.ModelStoreBuilder; 10import tools.refinery.store.model.ModelStoreBuilder;
9import tools.refinery.store.model.ModelStoreConfiguration; 11import tools.refinery.store.model.ModelStoreConfiguration;
10import tools.refinery.store.query.dnf.Query; 12import tools.refinery.store.query.dnf.Query;
13import tools.refinery.store.query.term.Variable;
14import tools.refinery.store.query.term.int_.IntTerms;
15import tools.refinery.store.query.term.uppercardinality.UpperCardinalityTerms;
11import tools.refinery.store.query.view.AnySymbolView; 16import tools.refinery.store.query.view.AnySymbolView;
12import tools.refinery.store.reasoning.ReasoningAdapter; 17import tools.refinery.store.reasoning.ReasoningAdapter;
13import tools.refinery.store.reasoning.ReasoningBuilder; 18import tools.refinery.store.reasoning.ReasoningBuilder;
@@ -23,16 +28,14 @@ import tools.refinery.store.representation.cardinality.UpperCardinality;
23import java.util.List; 28import java.util.List;
24 29
25import static tools.refinery.store.query.literal.Literals.check; 30import static tools.refinery.store.query.literal.Literals.check;
26import static tools.refinery.store.query.term.int_.IntTerms.constant; 31import static tools.refinery.store.query.term.int_.IntTerms.*;
27import static tools.refinery.store.query.term.int_.IntTerms.greaterEq;
28import static tools.refinery.store.query.term.uppercardinality.UpperCardinalityTerms.constant;
29import static tools.refinery.store.query.term.uppercardinality.UpperCardinalityTerms.greaterEq;
30 32
31public class MultiObjectTranslator implements ModelStoreConfiguration { 33public class MultiObjectTranslator implements ModelStoreConfiguration {
32 public static final Symbol<CardinalityInterval> COUNT_STORAGE = Symbol.of("COUNT", 1, CardinalityInterval.class, 34 public static final Symbol<CardinalityInterval> COUNT_STORAGE = Symbol.of("COUNT", 1, CardinalityInterval.class,
33 null); 35 null);
34 public static final AnySymbolView LOWER_CARDINALITY_VIEW = new LowerCardinalityView(COUNT_STORAGE); 36 public static final AnySymbolView LOWER_CARDINALITY_VIEW = new LowerCardinalityView(COUNT_STORAGE);
35 public static final AnySymbolView UPPER_CARDINALITY_VIEW = new UpperCardinalityView(COUNT_STORAGE); 37 public static final AnySymbolView UPPER_CARDINALITY_VIEW = new UpperCardinalityView(COUNT_STORAGE);
38 public static final AnySymbolView MULTI_VIEW = new MultiView(COUNT_STORAGE);
36 public static final PartialFunction<CardinalityInterval, Integer> COUNT_SYMBOL = new PartialFunction<>("COUNT", 1, 39 public static final PartialFunction<CardinalityInterval, Integer> COUNT_SYMBOL = new PartialFunction<>("COUNT", 1,
37 CardinalityDomain.INSTANCE); 40 CardinalityDomain.INSTANCE);
38 41
@@ -40,11 +43,23 @@ public class MultiObjectTranslator implements ModelStoreConfiguration {
40 public void apply(ModelStoreBuilder storeBuilder) { 43 public void apply(ModelStoreBuilder storeBuilder) {
41 storeBuilder.symbol(COUNT_STORAGE); 44 storeBuilder.symbol(COUNT_STORAGE);
42 45
46 var aboveLowerBound = Query.of("count#aboveLowerBound", Integer.class, (builder, node, output) -> builder
47 .clause(Integer.class, lowerBound -> List.of(
48 LOWER_CARDINALITY_VIEW.call(node, lowerBound),
49 output.assign(sub(lowerBound, IntTerms.constant(1))),
50 check(greater(output, IntTerms.constant(0)))
51 )));
52 var missingCardinality = Query.of("count#missing", Integer.class, (builder, output) -> builder
53 .clause(
54 output.assign(aboveLowerBound.aggregate(INT_SUM, Variable.of()))
55 ));
56
43 storeBuilder.with(PartialRelationTranslator.of(ReasoningAdapter.EXISTS_SYMBOL) 57 storeBuilder.with(PartialRelationTranslator.of(ReasoningAdapter.EXISTS_SYMBOL)
44 .may(Query.of("exists#may", (builder, p1) -> builder 58 .may(Query.of("exists#may", (builder, p1) -> builder
45 .clause(UpperCardinality.class, upper -> List.of( 59 .clause(UpperCardinality.class, upper -> List.of(
46 UPPER_CARDINALITY_VIEW.call(p1, upper), 60 UPPER_CARDINALITY_VIEW.call(p1, upper),
47 check(greaterEq(upper, constant(UpperCardinalities.ONE))) 61 check(UpperCardinalityTerms.greaterEq(upper,
62 UpperCardinalityTerms.constant(UpperCardinalities.ONE)))
48 )))) 63 ))))
49 .must(Query.of("exists#must", (builder, p1) -> builder 64 .must(Query.of("exists#must", (builder, p1) -> builder
50 .clause(Integer.class, lower -> List.of( 65 .clause(Integer.class, lower -> List.of(
@@ -52,11 +67,17 @@ public class MultiObjectTranslator implements ModelStoreConfiguration {
52 check(greaterEq(lower, constant(1))) 67 check(greaterEq(lower, constant(1)))
53 )))) 68 ))))
54 .roundingMode(RoundingMode.PREFER_FALSE) 69 .roundingMode(RoundingMode.PREFER_FALSE)
55 .refiner(ExistsRefiner.of(COUNT_STORAGE))); 70 .refiner(ExistsRefiner.of(COUNT_STORAGE))
71 .exclude(null)
72 .accept(Criteria.whenNoMatch(aboveLowerBound))
73 .objective(Objectives.value(missingCardinality)));
56 74
57 storeBuilder.with(PartialRelationTranslator.of(ReasoningAdapter.EQUALS_SYMBOL) 75 storeBuilder.with(PartialRelationTranslator.of(ReasoningAdapter.EQUALS_SYMBOL)
58 .rewriter(EqualsRelationRewriter.of(UPPER_CARDINALITY_VIEW)) 76 .rewriter(EqualsRelationRewriter.of(UPPER_CARDINALITY_VIEW))
59 .refiner(EqualsRefiner.of(COUNT_STORAGE))); 77 .refiner(EqualsRefiner.of(COUNT_STORAGE))
78 .exclude(null)
79 .accept(null)
80 .objective(null));
60 81
61 var reasoningBuilder = storeBuilder.getAdapter(ReasoningBuilder.class); 82 var reasoningBuilder = storeBuilder.getAdapter(ReasoningBuilder.class);
62 reasoningBuilder.initializer(new MultiObjectInitializer(COUNT_STORAGE)); 83 reasoningBuilder.initializer(new MultiObjectInitializer(COUNT_STORAGE));
diff --git a/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/MultiView.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiobject/MultiView.java
index cea4e07d..498bcd83 100644
--- a/subprojects/store-reasoning-scope/src/main/java/tools/refinery/store/reasoning/scope/internal/MultiView.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiobject/MultiView.java
@@ -3,7 +3,7 @@
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
6package tools.refinery.store.reasoning.scope.internal; 6package tools.refinery.store.reasoning.translator.multiobject;
7 7
8import tools.refinery.store.query.view.TuplePreservingView; 8import tools.refinery.store.query.view.TuplePreservingView;
9import tools.refinery.store.representation.Symbol; 9import tools.refinery.store.representation.Symbol;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiplicity/InvalidMultiplicityErrorTranslator.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiplicity/InvalidMultiplicityErrorTranslator.java
index c5e5e83e..ee982f4f 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiplicity/InvalidMultiplicityErrorTranslator.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/multiplicity/InvalidMultiplicityErrorTranslator.java
@@ -5,6 +5,7 @@
5 */ 5 */
6package tools.refinery.store.reasoning.translator.multiplicity; 6package tools.refinery.store.reasoning.translator.multiplicity;
7 7
8import tools.refinery.store.dse.transition.objectives.Objectives;
8import tools.refinery.store.model.ModelStoreBuilder; 9import tools.refinery.store.model.ModelStoreBuilder;
9import tools.refinery.store.model.ModelStoreConfiguration; 10import tools.refinery.store.model.ModelStoreConfiguration;
10import tools.refinery.store.query.dnf.Query; 11import tools.refinery.store.query.dnf.Query;
@@ -22,7 +23,10 @@ import tools.refinery.store.representation.cardinality.UpperCardinality;
22import java.util.List; 23import java.util.List;
23 24
24import static tools.refinery.store.query.literal.Literals.check; 25import static tools.refinery.store.query.literal.Literals.check;
26import static tools.refinery.store.query.term.int_.IntTerms.INT_SUM;
27import static tools.refinery.store.query.term.int_.IntTerms.constant;
25import static tools.refinery.store.query.term.int_.IntTerms.greater; 28import static tools.refinery.store.query.term.int_.IntTerms.greater;
29import static tools.refinery.store.query.term.int_.IntTerms.sub;
26import static tools.refinery.store.query.term.uppercardinality.UpperCardinalityTerms.constant; 30import static tools.refinery.store.query.term.uppercardinality.UpperCardinalityTerms.constant;
27import static tools.refinery.store.query.term.uppercardinality.UpperCardinalityTerms.less; 31import static tools.refinery.store.query.term.uppercardinality.UpperCardinalityTerms.less;
28import static tools.refinery.store.reasoning.literal.PartialLiterals.candidateMust; 32import static tools.refinery.store.reasoning.literal.PartialLiterals.candidateMust;
@@ -67,6 +71,8 @@ public class InvalidMultiplicityErrorTranslator implements ModelStoreConfigurati
67 .parameter(node); 71 .parameter(node);
68 var candidateMustBuilder = Query.builder(DnfLifter.decorateName(name, Modality.MUST, Concreteness.PARTIAL)) 72 var candidateMustBuilder = Query.builder(DnfLifter.decorateName(name, Modality.MUST, Concreteness.PARTIAL))
69 .parameter(node); 73 .parameter(node);
74 var missingOutput = Variable.of("missing", Integer.class);
75 var missingBuilder = Query.builder(name + "#missingMultiplicity").parameter(node).output(missingOutput);
70 76
71 int lowerBound = cardinalityInterval.lowerBound(); 77 int lowerBound = cardinalityInterval.lowerBound();
72 if (lowerBound > 0) { 78 if (lowerBound > 0) {
@@ -79,12 +85,18 @@ public class InvalidMultiplicityErrorTranslator implements ModelStoreConfigurati
79 candidateMayBuilder.clause(Integer.class, existingContents -> List.of( 85 candidateMayBuilder.clause(Integer.class, existingContents -> List.of(
80 candidateMust(nodeType.call(node)), 86 candidateMust(nodeType.call(node)),
81 new CountCandidateLowerBoundLiteral(existingContents, linkType, arguments), 87 new CountCandidateLowerBoundLiteral(existingContents, linkType, arguments),
82 check(IntTerms.less(existingContents, IntTerms.constant(lowerBound))) 88 check(IntTerms.less(existingContents, constant(lowerBound)))
83 )); 89 ));
84 candidateMustBuilder.clause(Integer.class, existingContents -> List.of( 90 candidateMustBuilder.clause(Integer.class, existingContents -> List.of(
85 candidateMust(nodeType.call(node)), 91 candidateMust(nodeType.call(node)),
86 new CountCandidateUpperBoundLiteral(existingContents, linkType, arguments), 92 new CountCandidateUpperBoundLiteral(existingContents, linkType, arguments),
87 check(IntTerms.less(existingContents, IntTerms.constant(lowerBound))) 93 check(IntTerms.less(existingContents, constant(lowerBound)))
94 ));
95 missingBuilder.clause(Integer.class, existingContents -> List.of(
96 candidateMust(nodeType.call(node)),
97 new CountCandidateLowerBoundLiteral(existingContents, linkType, arguments),
98 missingOutput.assign(sub(constant(lowerBound), existingContents)),
99 check(greater(missingOutput, constant(0)))
88 )); 100 ));
89 } 101 }
90 102
@@ -93,24 +105,35 @@ public class InvalidMultiplicityErrorTranslator implements ModelStoreConfigurati
93 mustBuilder.clause(Integer.class, existingContents -> List.of( 105 mustBuilder.clause(Integer.class, existingContents -> List.of(
94 must(nodeType.call(node)), 106 must(nodeType.call(node)),
95 new CountLowerBoundLiteral(existingContents, linkType, arguments), 107 new CountLowerBoundLiteral(existingContents, linkType, arguments),
96 check(greater(existingContents, IntTerms.constant(upperBound))) 108 check(greater(existingContents, constant(upperBound)))
97 )); 109 ));
98 candidateMayBuilder.clause(Integer.class, existingContents -> List.of( 110 candidateMayBuilder.clause(Integer.class, existingContents -> List.of(
99 candidateMust(nodeType.call(node)), 111 candidateMust(nodeType.call(node)),
100 new CountCandidateUpperBoundLiteral(existingContents, linkType, arguments), 112 new CountCandidateUpperBoundLiteral(existingContents, linkType, arguments),
101 check(greater(existingContents, IntTerms.constant(upperBound))) 113 check(greater(existingContents, constant(upperBound)))
102 )); 114 ));
103 candidateMustBuilder.clause(Integer.class, existingContents -> List.of( 115 candidateMustBuilder.clause(Integer.class, existingContents -> List.of(
104 candidateMust(nodeType.call(node)), 116 candidateMust(nodeType.call(node)),
105 new CountCandidateLowerBoundLiteral(existingContents, linkType, arguments), 117 new CountCandidateLowerBoundLiteral(existingContents, linkType, arguments),
106 check(greater(existingContents, IntTerms.constant(upperBound))) 118 check(greater(existingContents, constant(upperBound)))
119 ));
120 missingBuilder.clause(Integer.class, existingContents -> List.of(
121 candidateMust(nodeType.call(node)),
122 new CountCandidateUpperBoundLiteral(existingContents, linkType, arguments),
123 missingOutput.assign(sub(existingContents, constant(upperBound))),
124 check(greater(missingOutput, constant(0)))
107 )); 125 ));
108 } 126 }
109 127
128 var objective = Query.of(name + "#objective", Integer.class, (builder, output) -> builder.clause(
129 output.assign(missingBuilder.build().aggregate(INT_SUM, Variable.of()))
130 ));
131
110 storeBuilder.with(PartialRelationTranslator.of(constrainedMultiplicity.errorSymbol()) 132 storeBuilder.with(PartialRelationTranslator.of(constrainedMultiplicity.errorSymbol())
111 .mayNever() 133 .mayNever()
112 .must(mustBuilder.build()) 134 .must(mustBuilder.build())
113 .candidateMay(candidateMayBuilder.build()) 135 .candidateMay(candidateMayBuilder.build())
114 .candidateMust(candidateMustBuilder.build())); 136 .candidateMust(candidateMustBuilder.build())
137 .objective(Objectives.value(objective)));
115 } 138 }
116} 139}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/predicate/PredicateTranslator.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/predicate/PredicateTranslator.java
index 16745da1..b401118e 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/predicate/PredicateTranslator.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/predicate/PredicateTranslator.java
@@ -78,7 +78,14 @@ public class PredicateTranslator implements ModelStoreConfiguration {
78 .clause(mayLiterals) 78 .clause(mayLiterals)
79 .build(); 79 .build();
80 translator.may(may); 80 translator.may(may);
81 } else if (!defaultValue.may()) { 81 } else if (defaultValue.may()) {
82 // If all values are permitted, we don't need to check for any forbidden values in the model.
83 // If the result of this predicate of {@code ERROR}, some other partial relation (that we check for)
84 // will be {@code ERROR} as well.
85 translator.exclude(null);
86 translator.accept(null);
87 translator.objective(null);
88 } else {
82 translator.mayNever(); 89 translator.mayNever();
83 } 90 }
84 storeBuilder.with(translator); 91 storeBuilder.with(translator);
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTranslator.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTranslator.java
index 67e8035f..dc8a1d36 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTranslator.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTranslator.java
@@ -5,16 +5,26 @@
5 */ 5 */
6package tools.refinery.store.reasoning.translator.typehierarchy; 6package tools.refinery.store.reasoning.translator.typehierarchy;
7 7
8import tools.refinery.store.dse.transition.Rule;
9import tools.refinery.store.dse.transition.actions.ActionLiteral;
8import tools.refinery.store.model.ModelStoreBuilder; 10import tools.refinery.store.model.ModelStoreBuilder;
9import tools.refinery.store.model.ModelStoreConfiguration; 11import tools.refinery.store.model.ModelStoreConfiguration;
10import tools.refinery.store.query.dnf.Query; 12import tools.refinery.store.query.dnf.Query;
11import tools.refinery.store.reasoning.ReasoningBuilder; 13import tools.refinery.store.reasoning.ReasoningBuilder;
14import tools.refinery.store.reasoning.actions.PartialActionLiterals;
12import tools.refinery.store.reasoning.literal.PartialLiterals; 15import tools.refinery.store.reasoning.literal.PartialLiterals;
13import tools.refinery.store.reasoning.representation.PartialRelation; 16import tools.refinery.store.reasoning.representation.PartialRelation;
14import tools.refinery.store.reasoning.translator.PartialRelationTranslator; 17import tools.refinery.store.reasoning.translator.PartialRelationTranslator;
18import tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator;
15import tools.refinery.store.reasoning.translator.proxy.PartialRelationTranslatorProxy; 19import tools.refinery.store.reasoning.translator.proxy.PartialRelationTranslatorProxy;
16import tools.refinery.store.representation.Symbol; 20import tools.refinery.store.representation.Symbol;
17 21
22import java.util.ArrayList;
23
24import static tools.refinery.store.query.literal.Literals.not;
25import static tools.refinery.store.reasoning.literal.PartialLiterals.candidateMust;
26import static tools.refinery.store.reasoning.literal.PartialLiterals.may;
27
18public class TypeHierarchyTranslator implements ModelStoreConfiguration { 28public class TypeHierarchyTranslator implements ModelStoreConfiguration {
19 private final Symbol<InferredType> typeSymbol = Symbol.of("TYPE", 1, InferredType.class, InferredType.UNTYPED); 29 private final Symbol<InferredType> typeSymbol = Symbol.of("TYPE", 1, InferredType.class, InferredType.UNTYPED);
20 private final TypeHierarchy typeHierarchy; 30 private final TypeHierarchy typeHierarchy;
@@ -49,7 +59,7 @@ public class TypeHierarchyTranslator implements ModelStoreConfiguration {
49 builder.clause(new MayTypeView(typeSymbol, type).call(p1)); 59 builder.clause(new MayTypeView(typeSymbol, type).call(p1));
50 } 60 }
51 for (var subtype : result.getDirectSubtypes()) { 61 for (var subtype : result.getDirectSubtypes()) {
52 builder.clause(PartialLiterals.may(subtype.call(p1))); 62 builder.clause(may(subtype.call(p1)));
53 } 63 }
54 }); 64 });
55 65
@@ -66,11 +76,31 @@ public class TypeHierarchyTranslator implements ModelStoreConfiguration {
66 } 76 }
67 }); 77 });
68 78
69 return PartialRelationTranslator.of(type) 79 var translator = PartialRelationTranslator.of(type)
70 .may(may) 80 .may(may)
71 .must(must) 81 .must(must)
72 .candidate(candidate) 82 .candidate(candidate)
73 .refiner(InferredTypeRefiner.of(typeSymbol, result)); 83 .refiner(InferredTypeRefiner.of(typeSymbol, result));
84
85 if (!result.isAbstractType()) {
86 var decision = Rule.of(type.name(), (builder, instance) -> builder
87 .clause(
88 may(type.call(instance)),
89 not(candidateMust(type.call(instance))),
90 not(MultiObjectTranslator.MULTI_VIEW.call(instance))
91 )
92 .action(() -> {
93 var actionLiterals = new ArrayList<ActionLiteral>();
94 actionLiterals.add(PartialActionLiterals.add(type, instance));
95 for (var subtype : result.getDirectSubtypes()) {
96 actionLiterals.add(PartialActionLiterals.remove(subtype, instance));
97 }
98 return actionLiterals;
99 }));
100 translator.decision(decision);
101 }
102
103 return translator;
74 } 104 }
75 105
76 private ModelStoreConfiguration createEliminatedTypeTranslator( 106 private ModelStoreConfiguration createEliminatedTypeTranslator(