aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java
diff options
context:
space:
mode:
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.java107
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 @@
1package tools.refinery.store.reasoning.lifting;
2
3import org.jetbrains.annotations.Nullable;
4import tools.refinery.store.reasoning.literal.ModalDnfCallLiteral;
5import tools.refinery.store.reasoning.Reasoning;
6import tools.refinery.store.reasoning.literal.ModalRelationLiteral;
7import tools.refinery.store.reasoning.literal.PartialRelationLiteral;
8import tools.refinery.store.query.Dnf;
9import tools.refinery.store.query.DnfBuilder;
10import tools.refinery.store.query.DnfClause;
11import tools.refinery.store.query.Variable;
12import tools.refinery.store.query.literal.CallPolarity;
13import tools.refinery.store.query.literal.DnfCallLiteral;
14import tools.refinery.store.query.literal.Literal;
15import tools.refinery.store.reasoning.literal.Modality;
16import tools.refinery.store.util.CycleDetectingMapper;
17
18import java.util.ArrayList;
19import java.util.HashSet;
20import java.util.List;
21
22public 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}