aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <marussy@mit.bme.hu>2023-09-14 19:29:36 +0200
committerLibravatar GitHub <noreply@github.com>2023-09-14 19:29:36 +0200
commit98ed3b6db5f4e51961a161050cc31c66015116e8 (patch)
tree8bfd6d9bc8d6ed23b9eb0f889dd40b6c24fe8f92 /subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java
parentMerge pull request #38 from nagilooh/design-space-exploration (diff)
parentMerge remote-tracking branch 'upstream/main' into partial-interpretation (diff)
downloadrefinery-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.java136
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 */
6package tools.refinery.store.reasoning.lifting; 6package tools.refinery.store.reasoning.lifting;
7 7
8import org.jetbrains.annotations.Nullable; 8import tools.refinery.store.query.dnf.*;
9import tools.refinery.store.query.dnf.Dnf; 9import tools.refinery.store.query.equality.DnfEqualityChecker;
10import tools.refinery.store.query.dnf.DnfBuilder;
11import tools.refinery.store.query.dnf.DnfClause;
12import tools.refinery.store.query.literal.CallLiteral;
13import tools.refinery.store.query.literal.CallPolarity;
14import tools.refinery.store.query.literal.Literal; 10import tools.refinery.store.query.literal.Literal;
15import tools.refinery.store.query.term.NodeVariable; 11import tools.refinery.store.reasoning.literal.Concreteness;
16import tools.refinery.store.query.term.Variable;
17import tools.refinery.store.reasoning.ReasoningAdapter;
18import tools.refinery.store.reasoning.literal.ModalConstraint;
19import tools.refinery.store.reasoning.literal.Modality; 12import tools.refinery.store.reasoning.literal.Modality;
20import tools.refinery.store.reasoning.literal.PartialLiterals;
21import tools.refinery.store.util.CycleDetectingMapper;
22 13
23import java.util.ArrayList; 14import java.util.HashMap;
24import java.util.LinkedHashSet;
25import java.util.List; 15import java.util.List;
16import java.util.Map;
26 17
27public class DnfLifter { 18public 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}