diff options
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 | 107 |
1 files changed, 107 insertions, 0 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 new file mode 100644 index 00000000..966e080a --- /dev/null +++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java | |||
@@ -0,0 +1,107 @@ | |||
1 | package tools.refinery.store.reasoning.lifting; | ||
2 | |||
3 | import org.jetbrains.annotations.Nullable; | ||
4 | import tools.refinery.store.reasoning.literal.ModalDnfCallLiteral; | ||
5 | import tools.refinery.store.reasoning.Reasoning; | ||
6 | import tools.refinery.store.reasoning.literal.ModalRelationLiteral; | ||
7 | import tools.refinery.store.reasoning.literal.PartialRelationLiteral; | ||
8 | import tools.refinery.store.query.Dnf; | ||
9 | import tools.refinery.store.query.DnfBuilder; | ||
10 | import tools.refinery.store.query.DnfClause; | ||
11 | import tools.refinery.store.query.Variable; | ||
12 | import tools.refinery.store.query.literal.CallPolarity; | ||
13 | import tools.refinery.store.query.literal.DnfCallLiteral; | ||
14 | import tools.refinery.store.query.literal.Literal; | ||
15 | import tools.refinery.store.reasoning.literal.Modality; | ||
16 | import tools.refinery.store.util.CycleDetectingMapper; | ||
17 | |||
18 | import java.util.ArrayList; | ||
19 | import java.util.HashSet; | ||
20 | import java.util.List; | ||
21 | |||
22 | public class DnfLifter { | ||
23 | private final CycleDetectingMapper<ModalDnf, Dnf> mapper = new CycleDetectingMapper<>(ModalDnf::toString, | ||
24 | this::doLift); | ||
25 | |||
26 | public Dnf lift(Modality modality, Dnf query) { | ||
27 | return mapper.map(new ModalDnf(modality, query)); | ||
28 | } | ||
29 | |||
30 | private Dnf doLift(ModalDnf modalDnf) { | ||
31 | var modality = modalDnf.modality(); | ||
32 | var dnf = modalDnf.dnf(); | ||
33 | var builder = Dnf.builder(); | ||
34 | builder.parameters(dnf.getParameters()); | ||
35 | boolean changed = false; | ||
36 | for (var clause : dnf.getClauses()) { | ||
37 | if (liftClause(modality, clause, builder)) { | ||
38 | changed = true; | ||
39 | } | ||
40 | } | ||
41 | if (changed) { | ||
42 | return builder.build(); | ||
43 | } | ||
44 | return dnf; | ||
45 | } | ||
46 | |||
47 | private boolean liftClause(Modality modality, DnfClause clause, DnfBuilder builder) { | ||
48 | boolean changed = false; | ||
49 | var quantifiedVariables = new HashSet<>(clause.quantifiedVariables()); | ||
50 | var literals = clause.literals(); | ||
51 | var liftedLiterals = new ArrayList<Literal>(literals.size()); | ||
52 | for (var literal : literals) { | ||
53 | Literal liftedLiteral = liftLiteral(modality, literal); | ||
54 | if (liftedLiteral == null) { | ||
55 | liftedLiteral = literal; | ||
56 | } else { | ||
57 | changed = true; | ||
58 | } | ||
59 | liftedLiterals.add(liftedLiteral); | ||
60 | var variable = isExistsLiteralForVariable(modality, liftedLiteral); | ||
61 | if (variable != null) { | ||
62 | // If we already quantify over the existence of the variable with the expected modality, | ||
63 | // we don't need to insert quantification manually. | ||
64 | quantifiedVariables.remove(variable); | ||
65 | } | ||
66 | } | ||
67 | for (var quantifiedVariable : quantifiedVariables) { | ||
68 | // Quantify over variables that are not already quantified with the expected modality. | ||
69 | liftedLiterals.add(Reasoning.EXISTS.call(CallPolarity.POSITIVE, modality, | ||
70 | List.of(quantifiedVariable))); | ||
71 | } | ||
72 | builder.clause(liftedLiterals); | ||
73 | return changed || !quantifiedVariables.isEmpty(); | ||
74 | } | ||
75 | |||
76 | @Nullable | ||
77 | private Variable isExistsLiteralForVariable(Modality modality, Literal literal) { | ||
78 | if (literal instanceof ModalRelationLiteral modalRelationLiteral && | ||
79 | modalRelationLiteral.getPolarity() == CallPolarity.POSITIVE && | ||
80 | modalRelationLiteral.getModality() == modality && | ||
81 | modalRelationLiteral.getTarget().equals(Reasoning.EXISTS)) { | ||
82 | return modalRelationLiteral.getArguments().get(0); | ||
83 | } | ||
84 | return null; | ||
85 | } | ||
86 | |||
87 | @Nullable | ||
88 | private Literal liftLiteral(Modality modality, Literal literal) { | ||
89 | if (literal instanceof PartialRelationLiteral partialRelationLiteral) { | ||
90 | return new ModalRelationLiteral(modality, partialRelationLiteral); | ||
91 | } else if (literal instanceof DnfCallLiteral dnfCallLiteral) { | ||
92 | var polarity = dnfCallLiteral.getPolarity(); | ||
93 | var target = dnfCallLiteral.getTarget(); | ||
94 | var liftedTarget = lift(modality.commute(polarity), target); | ||
95 | if (target.equals(liftedTarget)) { | ||
96 | return null; | ||
97 | } | ||
98 | return new DnfCallLiteral(polarity, liftedTarget, dnfCallLiteral.getArguments()); | ||
99 | } else if (literal instanceof ModalDnfCallLiteral modalDnfCallLiteral) { | ||
100 | var liftedTarget = lift(modalDnfCallLiteral.getModality(), modalDnfCallLiteral.getTarget()); | ||
101 | return new DnfCallLiteral(modalDnfCallLiteral.getPolarity(), liftedTarget, | ||
102 | modalDnfCallLiteral.getArguments()); | ||
103 | } else { | ||
104 | return null; | ||
105 | } | ||
106 | } | ||
107 | } | ||