diff options
author | 2023-09-07 18:04:42 +0200 | |
---|---|---|
committer | 2023-09-07 18:04:42 +0200 | |
commit | a128e05f18a101983d331d0819008740b521d6df (patch) | |
tree | cc23c330eea900ab7b513a6c21a241ebf0795785 /subprojects/store-dse | |
parent | feat(dse): transformation rule builder (diff) | |
download | refinery-a128e05f18a101983d331d0819008740b521d6df.tar.gz refinery-a128e05f18a101983d331d0819008740b521d6df.tar.zst refinery-a128e05f18a101983d331d0819008740b521d6df.zip |
feat: declarative DSE rules and model refinement
Diffstat (limited to 'subprojects/store-dse')
12 files changed, 400 insertions, 23 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 | ||
8 | import tools.refinery.store.adapter.ModelAdapter; | 8 | import tools.refinery.store.adapter.ModelAdapter; |
9 | import tools.refinery.store.dse.transition.internal.DesignSpaceExplorationBuilderImpl; | 9 | import tools.refinery.store.dse.transition.internal.DesignSpaceExplorationBuilderImpl; |
10 | import tools.refinery.store.map.Version; | ||
11 | import tools.refinery.store.tuple.Tuple; | ||
12 | import tools.refinery.store.tuple.Tuple1; | ||
13 | 10 | ||
14 | import java.util.Collection; | ||
15 | import java.util.List; | 11 | import java.util.List; |
16 | 12 | ||
17 | public interface DesignSpaceExplorationAdapter extends ModelAdapter { | 13 | public 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 | */ | ||
6 | package tools.refinery.store.dse.transition.objectives; | ||
7 | |||
8 | import tools.refinery.store.model.Model; | ||
9 | import tools.refinery.store.model.ModelStore; | ||
10 | import tools.refinery.store.query.literal.Reduction; | ||
11 | |||
12 | import java.util.ArrayList; | ||
13 | import java.util.Collection; | ||
14 | |||
15 | public 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 | */ | ||
6 | package tools.refinery.store.dse.transition.objectives; | ||
7 | |||
8 | import tools.refinery.store.model.ModelStore; | ||
9 | import tools.refinery.store.model.ModelStoreBuilder; | ||
10 | import tools.refinery.store.query.literal.Reduction; | ||
11 | |||
12 | import java.util.*; | ||
13 | |||
14 | public 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 | */ | ||
6 | package tools.refinery.store.dse.transition.objectives; | ||
7 | |||
8 | import tools.refinery.store.model.Model; | ||
9 | import tools.refinery.store.model.ModelStore; | ||
10 | import tools.refinery.store.model.ModelStoreBuilder; | ||
11 | |||
12 | import java.util.ArrayList; | ||
13 | import java.util.Collection; | ||
14 | import java.util.Collections; | ||
15 | import java.util.List; | ||
16 | |||
17 | public 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 | */ | ||
6 | package tools.refinery.store.dse.transition.objectives; | ||
7 | |||
8 | import tools.refinery.store.model.Model; | ||
9 | import tools.refinery.store.model.ModelStore; | ||
10 | import tools.refinery.store.model.ModelStoreBuilder; | ||
11 | import tools.refinery.store.query.ModelQueryAdapter; | ||
12 | import tools.refinery.store.query.ModelQueryBuilder; | ||
13 | import tools.refinery.store.query.ModelQueryStoreAdapter; | ||
14 | import tools.refinery.store.query.dnf.RelationalQuery; | ||
15 | import tools.refinery.store.query.literal.Reduction; | ||
16 | |||
17 | public 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 | */ | ||
6 | package tools.refinery.store.dse.transition.objectives; | ||
7 | |||
8 | import tools.refinery.store.query.dnf.AnyQuery; | ||
9 | |||
10 | import java.util.Collection; | ||
11 | import java.util.List; | ||
12 | |||
13 | public 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 @@ | |||
6 | package tools.refinery.store.dse.transition.objectives; | 6 | package tools.refinery.store.dse.transition.objectives; |
7 | 7 | ||
8 | import tools.refinery.store.model.Model; | 8 | import tools.refinery.store.model.Model; |
9 | import tools.refinery.store.model.ModelStore; | ||
9 | import tools.refinery.store.model.ModelStoreBuilder; | 10 | import tools.refinery.store.model.ModelStoreBuilder; |
11 | import tools.refinery.store.query.literal.Reduction; | ||
10 | 12 | ||
11 | public interface Criterion { | 13 | public 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 @@ | |||
6 | package tools.refinery.store.dse.transition.objectives; | 6 | package tools.refinery.store.dse.transition.objectives; |
7 | 7 | ||
8 | import tools.refinery.store.model.Model; | 8 | import tools.refinery.store.model.Model; |
9 | import tools.refinery.store.model.ModelStore; | ||
9 | import tools.refinery.store.model.ModelStoreBuilder; | 10 | import tools.refinery.store.model.ModelStoreBuilder; |
10 | 11 | ||
11 | public interface Objective { | 12 | public 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 | */ | ||
6 | package tools.refinery.store.dse.transition.objectives; | ||
7 | |||
8 | import tools.refinery.store.query.dnf.FunctionalQuery; | ||
9 | import tools.refinery.store.query.dnf.RelationalQuery; | ||
10 | |||
11 | import java.util.Collection; | ||
12 | import java.util.List; | ||
13 | |||
14 | public 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 | */ | ||
6 | package tools.refinery.store.dse.transition.objectives; | ||
7 | |||
8 | import tools.refinery.store.model.Model; | ||
9 | import tools.refinery.store.model.ModelStore; | ||
10 | import tools.refinery.store.query.literal.Reduction; | ||
11 | |||
12 | import java.util.ArrayList; | ||
13 | import java.util.Collection; | ||
14 | |||
15 | public 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 @@ | |||
6 | package tools.refinery.store.dse.transition.objectives; | 6 | package tools.refinery.store.dse.transition.objectives; |
7 | 7 | ||
8 | import tools.refinery.store.model.Model; | 8 | import tools.refinery.store.model.Model; |
9 | import tools.refinery.store.model.ModelStore; | ||
9 | import tools.refinery.store.model.ModelStoreBuilder; | 10 | import tools.refinery.store.model.ModelStoreBuilder; |
10 | import tools.refinery.store.query.ModelQueryAdapter; | 11 | import tools.refinery.store.query.ModelQueryAdapter; |
11 | import tools.refinery.store.query.ModelQueryBuilder; | 12 | import tools.refinery.store.query.ModelQueryBuilder; |
13 | import tools.refinery.store.query.ModelQueryStoreAdapter; | ||
12 | import tools.refinery.store.query.dnf.AnyQuery; | 14 | import tools.refinery.store.query.dnf.AnyQuery; |
15 | import tools.refinery.store.query.literal.Reduction; | ||
13 | 16 | ||
14 | public class QueryCriteria implements Criterion { | 17 | public 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 | } |