diff options
author | 2023-09-14 19:29:36 +0200 | |
---|---|---|
committer | 2023-09-14 19:29:36 +0200 | |
commit | 98ed3b6db5f4e51961a161050cc31c66015116e8 (patch) | |
tree | 8bfd6d9bc8d6ed23b9eb0f889dd40b6c24fe8f92 /subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java | |
parent | Merge pull request #38 from nagilooh/design-space-exploration (diff) | |
parent | Merge remote-tracking branch 'upstream/main' into partial-interpretation (diff) | |
download | refinery-98ed3b6db5f4e51961a161050cc31c66015116e8.tar.gz refinery-98ed3b6db5f4e51961a161050cc31c66015116e8.tar.zst refinery-98ed3b6db5f4e51961a161050cc31c66015116e8.zip |
Merge pull request #39 from kris7t/partial-interpretation
Implement partial interpretation based model generation
Diffstat (limited to 'subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java')
-rw-r--r-- | subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java | 136 |
1 files changed, 40 insertions, 96 deletions
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java index ac41d170..889f595f 100644 --- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java | |||
@@ -5,124 +5,68 @@ | |||
5 | */ | 5 | */ |
6 | package tools.refinery.store.reasoning.lifting; | 6 | package tools.refinery.store.reasoning.lifting; |
7 | 7 | ||
8 | import org.jetbrains.annotations.Nullable; | 8 | import tools.refinery.store.query.dnf.*; |
9 | import tools.refinery.store.query.dnf.Dnf; | 9 | import tools.refinery.store.query.equality.DnfEqualityChecker; |
10 | import tools.refinery.store.query.dnf.DnfBuilder; | ||
11 | import tools.refinery.store.query.dnf.DnfClause; | ||
12 | import tools.refinery.store.query.literal.CallLiteral; | ||
13 | import tools.refinery.store.query.literal.CallPolarity; | ||
14 | import tools.refinery.store.query.literal.Literal; | 10 | import tools.refinery.store.query.literal.Literal; |
15 | import tools.refinery.store.query.term.NodeVariable; | 11 | import tools.refinery.store.reasoning.literal.Concreteness; |
16 | import tools.refinery.store.query.term.Variable; | ||
17 | import tools.refinery.store.reasoning.ReasoningAdapter; | ||
18 | import tools.refinery.store.reasoning.literal.ModalConstraint; | ||
19 | import tools.refinery.store.reasoning.literal.Modality; | 12 | import tools.refinery.store.reasoning.literal.Modality; |
20 | import tools.refinery.store.reasoning.literal.PartialLiterals; | ||
21 | import tools.refinery.store.util.CycleDetectingMapper; | ||
22 | 13 | ||
23 | import java.util.ArrayList; | 14 | import java.util.HashMap; |
24 | import java.util.LinkedHashSet; | ||
25 | import java.util.List; | 15 | import java.util.List; |
16 | import java.util.Map; | ||
26 | 17 | ||
27 | public class DnfLifter { | 18 | public class DnfLifter { |
28 | private final CycleDetectingMapper<ModalDnf, Dnf> mapper = new CycleDetectingMapper<>(ModalDnf::toString, | 19 | private final Map<ModalDnf, Dnf> cache = new HashMap<>(); |
29 | this::doLift); | ||
30 | 20 | ||
31 | public Dnf lift(Modality modality, Dnf query) { | 21 | public <T> Query<T> lift(Modality modality, Concreteness concreteness, Query<T> query) { |
32 | return mapper.map(new ModalDnf(modality, query)); | 22 | var liftedDnf = lift(modality, concreteness, query.getDnf()); |
23 | return query.withDnf(liftedDnf); | ||
24 | } | ||
25 | |||
26 | public RelationalQuery lift(Modality modality, Concreteness concreteness, RelationalQuery query) { | ||
27 | var liftedDnf = lift(modality, concreteness, query.getDnf()); | ||
28 | return query.withDnf(liftedDnf); | ||
29 | } | ||
30 | |||
31 | public <T> FunctionalQuery<T> lift(Modality modality, Concreteness concreteness, FunctionalQuery<T> query) { | ||
32 | var liftedDnf = lift(modality, concreteness, query.getDnf()); | ||
33 | return query.withDnf(liftedDnf); | ||
34 | } | ||
35 | |||
36 | public Dnf lift(Modality modality, Concreteness concreteness, Dnf dnf) { | ||
37 | return cache.computeIfAbsent(new ModalDnf(modality, concreteness, dnf), this::doLift); | ||
33 | } | 38 | } |
34 | 39 | ||
35 | private Dnf doLift(ModalDnf modalDnf) { | 40 | private Dnf doLift(ModalDnf modalDnf) { |
36 | var modality = modalDnf.modality(); | 41 | var modality = modalDnf.modality(); |
42 | var concreteness = modalDnf.concreteness(); | ||
37 | var dnf = modalDnf.dnf(); | 43 | var dnf = modalDnf.dnf(); |
38 | var builder = Dnf.builder(); | 44 | var builder = Dnf.builder(decorateName(dnf.name(), modality, concreteness)); |
39 | builder.symbolicParameters(dnf.getSymbolicParameters()); | 45 | builder.symbolicParameters(dnf.getSymbolicParameters()); |
40 | boolean changed = false; | 46 | builder.functionalDependencies(dnf.getFunctionalDependencies()); |
41 | for (var clause : dnf.getClauses()) { | 47 | for (var clause : dnf.getClauses()) { |
42 | if (liftClause(modality, dnf, clause, builder)) { | 48 | builder.clause(liftClause(modality, concreteness, dnf, clause)); |
43 | changed = true; | ||
44 | } | ||
45 | } | 49 | } |
46 | if (changed) { | 50 | var liftedDnf = builder.build(); |
47 | return builder.build(); | 51 | if (dnf.equalsWithSubstitution(DnfEqualityChecker.DEFAULT, liftedDnf)) { |
52 | return dnf; | ||
48 | } | 53 | } |
49 | return dnf; | 54 | return liftedDnf; |
50 | } | 55 | } |
51 | 56 | ||
52 | private boolean liftClause(Modality modality, Dnf originalDnf, DnfClause clause, DnfBuilder builder) { | 57 | private List<Literal> liftClause(Modality modality, Concreteness concreteness, Dnf dnf, DnfClause clause) { |
53 | boolean changed = false; | 58 | var lifter = new ClauseLifter(modality, concreteness, dnf, clause); |
54 | var quantifiedVariables = getQuantifiedDataVariables(originalDnf, clause); | 59 | return lifter.liftClause(); |
55 | var literals = clause.literals(); | ||
56 | var liftedLiterals = new ArrayList<Literal>(literals.size()); | ||
57 | for (var literal : literals) { | ||
58 | Literal liftedLiteral = liftLiteral(modality, literal); | ||
59 | if (liftedLiteral == null) { | ||
60 | liftedLiteral = literal; | ||
61 | } else { | ||
62 | changed = true; | ||
63 | } | ||
64 | liftedLiterals.add(liftedLiteral); | ||
65 | var variable = isExistsLiteralForVariable(modality, liftedLiteral); | ||
66 | if (variable != null) { | ||
67 | // If we already quantify over the existence of the variable with the expected modality, | ||
68 | // we don't need to insert quantification manually. | ||
69 | quantifiedVariables.remove(variable); | ||
70 | } | ||
71 | } | ||
72 | for (var quantifiedVariable : quantifiedVariables) { | ||
73 | // Quantify over data variables that are not already quantified with the expected modality. | ||
74 | liftedLiterals.add(new CallLiteral(CallPolarity.POSITIVE, | ||
75 | new ModalConstraint(modality, ReasoningAdapter.EXISTS), List.of(quantifiedVariable))); | ||
76 | } | ||
77 | builder.clause(liftedLiterals); | ||
78 | return changed || !quantifiedVariables.isEmpty(); | ||
79 | } | ||
80 | |||
81 | private static LinkedHashSet<Variable> getQuantifiedDataVariables(Dnf originalDnf, DnfClause clause) { | ||
82 | var quantifiedVariables = new LinkedHashSet<>(clause.positiveVariables()); | ||
83 | for (var symbolicParameter : originalDnf.getSymbolicParameters()) { | ||
84 | // The existence of parameters will be checked outside this DNF. | ||
85 | quantifiedVariables.remove(symbolicParameter.getVariable()); | ||
86 | } | ||
87 | quantifiedVariables.removeIf(variable -> !(variable instanceof NodeVariable)); | ||
88 | return quantifiedVariables; | ||
89 | } | 60 | } |
90 | 61 | ||
91 | @Nullable | 62 | private record ModalDnf(Modality modality, Concreteness concreteness, Dnf dnf) { |
92 | private Variable isExistsLiteralForVariable(Modality modality, Literal literal) { | 63 | @Override |
93 | if (literal instanceof CallLiteral callLiteral && | 64 | public String toString() { |
94 | callLiteral.getPolarity() == CallPolarity.POSITIVE && | 65 | return "%s %s %s".formatted(modality, concreteness, dnf.name()); |
95 | callLiteral.getTarget() instanceof ModalConstraint modalConstraint && | ||
96 | modalConstraint.modality() == modality && | ||
97 | modalConstraint.constraint().equals(ReasoningAdapter.EXISTS)) { | ||
98 | return callLiteral.getArguments().get(0); | ||
99 | } | 66 | } |
100 | return null; | ||
101 | } | 67 | } |
102 | 68 | ||
103 | @Nullable | 69 | public static String decorateName(String name, Modality modality, Concreteness concreteness) { |
104 | private Literal liftLiteral(Modality modality, Literal literal) { | 70 | return "%s#%s#%s".formatted(name, modality, concreteness); |
105 | if (!(literal instanceof CallLiteral callLiteral)) { | ||
106 | return null; | ||
107 | } | ||
108 | var target = callLiteral.getTarget(); | ||
109 | if (target instanceof ModalConstraint modalTarget) { | ||
110 | var actualTarget = modalTarget.constraint(); | ||
111 | if (actualTarget instanceof Dnf dnf) { | ||
112 | var targetModality = modalTarget.modality(); | ||
113 | var liftedTarget = lift(targetModality, dnf); | ||
114 | return new CallLiteral(callLiteral.getPolarity(), liftedTarget, callLiteral.getArguments()); | ||
115 | } | ||
116 | // No more lifting to be done, pass any modal call to a partial symbol through. | ||
117 | return null; | ||
118 | } else if (target instanceof Dnf dnf) { | ||
119 | var polarity = callLiteral.getPolarity(); | ||
120 | var liftedTarget = lift(modality.commute(polarity), dnf); | ||
121 | // Use == instead of equals(), because lift will return the same object by reference is there are no | ||
122 | // changes made during lifting. | ||
123 | return liftedTarget == target ? null : new CallLiteral(polarity, liftedTarget, callLiteral.getArguments()); | ||
124 | } else { | ||
125 | return PartialLiterals.addModality(callLiteral, modality); | ||
126 | } | ||
127 | } | 71 | } |
128 | } | 72 | } |