diff options
Diffstat (limited to 'subprojects/logic/src/main/java/tools/refinery/logic/rewriter/ClauseInputParameterResolver.java')
-rw-r--r-- | subprojects/logic/src/main/java/tools/refinery/logic/rewriter/ClauseInputParameterResolver.java | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/subprojects/logic/src/main/java/tools/refinery/logic/rewriter/ClauseInputParameterResolver.java b/subprojects/logic/src/main/java/tools/refinery/logic/rewriter/ClauseInputParameterResolver.java new file mode 100644 index 00000000..83fd44c5 --- /dev/null +++ b/subprojects/logic/src/main/java/tools/refinery/logic/rewriter/ClauseInputParameterResolver.java | |||
@@ -0,0 +1,160 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.logic.rewriter; | ||
7 | |||
8 | import tools.refinery.logic.dnf.Dnf; | ||
9 | import tools.refinery.logic.dnf.DnfClause; | ||
10 | import tools.refinery.logic.substitution.Substitution; | ||
11 | import tools.refinery.logic.term.Variable; | ||
12 | import tools.refinery.logic.literal.*; | ||
13 | import tools.refinery.logic.term.ParameterDirection; | ||
14 | |||
15 | import java.util.*; | ||
16 | |||
17 | class ClauseInputParameterResolver { | ||
18 | private final InputParameterResolver rewriter; | ||
19 | private final String dnfName; | ||
20 | private final int clauseIndex; | ||
21 | private final Set<Variable> positiveVariables = new LinkedHashSet<>(); | ||
22 | private final List<Literal> inlinedLiterals = new ArrayList<>(); | ||
23 | private final Deque<Literal> workList; | ||
24 | private int helperIndex = 0; | ||
25 | |||
26 | public ClauseInputParameterResolver(InputParameterResolver rewriter, List<Literal> context, DnfClause clause, | ||
27 | String dnfName, int clauseIndex) { | ||
28 | this.rewriter = rewriter; | ||
29 | this.dnfName = dnfName; | ||
30 | this.clauseIndex = clauseIndex; | ||
31 | workList = new ArrayDeque<>(clause.literals().size() + context.size()); | ||
32 | for (var literal : context) { | ||
33 | workList.addLast(literal); | ||
34 | } | ||
35 | for (var literal : clause.literals()) { | ||
36 | workList.addLast(literal); | ||
37 | } | ||
38 | } | ||
39 | |||
40 | public List<Literal> rewriteClause() { | ||
41 | while (!workList.isEmpty()) { | ||
42 | var literal = workList.removeFirst(); | ||
43 | processLiteral(literal); | ||
44 | } | ||
45 | return inlinedLiterals; | ||
46 | } | ||
47 | |||
48 | private void processLiteral(Literal literal) { | ||
49 | if (!(literal instanceof AbstractCallLiteral abstractCallLiteral) || | ||
50 | !(abstractCallLiteral.getTarget() instanceof Dnf targetDnf)) { | ||
51 | markAsDone(literal); | ||
52 | return; | ||
53 | } | ||
54 | boolean hasInputParameter = hasInputParameter(targetDnf); | ||
55 | if (!hasInputParameter) { | ||
56 | targetDnf = rewriter.rewrite(targetDnf); | ||
57 | } | ||
58 | if (inlinePositiveClause(abstractCallLiteral, targetDnf)) { | ||
59 | return; | ||
60 | } | ||
61 | if (eliminateDoubleNegation(abstractCallLiteral, targetDnf)) { | ||
62 | return; | ||
63 | } | ||
64 | if (hasInputParameter) { | ||
65 | rewriteWithCurrentContext(abstractCallLiteral, targetDnf); | ||
66 | return; | ||
67 | } | ||
68 | markAsDone(abstractCallLiteral.withTarget(targetDnf)); | ||
69 | } | ||
70 | |||
71 | private void markAsDone(Literal literal) { | ||
72 | positiveVariables.addAll(literal.getOutputVariables()); | ||
73 | inlinedLiterals.add(literal); | ||
74 | } | ||
75 | |||
76 | private boolean inlinePositiveClause(AbstractCallLiteral abstractCallLiteral, Dnf targetDnf) { | ||
77 | var targetLiteral = getSingleLiteral(abstractCallLiteral, targetDnf, CallPolarity.POSITIVE); | ||
78 | if (targetLiteral == null) { | ||
79 | return false; | ||
80 | } | ||
81 | var substitution = asSubstitution(abstractCallLiteral, targetDnf); | ||
82 | var substitutedLiteral = targetLiteral.substitute(substitution); | ||
83 | workList.addFirst(substitutedLiteral); | ||
84 | return true; | ||
85 | } | ||
86 | |||
87 | private boolean eliminateDoubleNegation(AbstractCallLiteral abstractCallLiteral, Dnf targetDnf) { | ||
88 | var targetLiteral = getSingleLiteral(abstractCallLiteral, targetDnf, CallPolarity.NEGATIVE); | ||
89 | if (!(targetLiteral instanceof CallLiteral targetCallLiteral) || | ||
90 | targetCallLiteral.getPolarity() != CallPolarity.NEGATIVE) { | ||
91 | return false; | ||
92 | } | ||
93 | var substitution = asSubstitution(abstractCallLiteral, targetDnf); | ||
94 | var substitutedLiteral = (CallLiteral) targetCallLiteral.substitute(substitution); | ||
95 | workList.addFirst(substitutedLiteral.negate()); | ||
96 | return true; | ||
97 | } | ||
98 | |||
99 | private void rewriteWithCurrentContext(AbstractCallLiteral abstractCallLiteral, Dnf targetDnf) { | ||
100 | var contextBuilder = Dnf.builder("%s#clause%d#helper%d".formatted(dnfName, clauseIndex, helperIndex)); | ||
101 | helperIndex++; | ||
102 | contextBuilder.parameters(positiveVariables, ParameterDirection.OUT); | ||
103 | contextBuilder.clause(inlinedLiterals); | ||
104 | var contextDnf = contextBuilder.build(); | ||
105 | var contextCall = new CallLiteral(CallPolarity.POSITIVE, contextDnf, List.copyOf(positiveVariables)); | ||
106 | inlinedLiterals.clear(); | ||
107 | var substitution = Substitution.builder().renewing().build(); | ||
108 | var context = new ArrayList<Literal>(); | ||
109 | context.add(contextCall.substitute(substitution)); | ||
110 | int arity = targetDnf.arity(); | ||
111 | for (int i = 0; i < arity; i++) { | ||
112 | var parameter = targetDnf.getSymbolicParameters().get(i).getVariable(); | ||
113 | var argument = abstractCallLiteral.getArguments().get(i); | ||
114 | context.add(new EquivalenceLiteral(true, parameter, substitution.getSubstitute(argument))); | ||
115 | } | ||
116 | var rewrittenDnf = rewriter.rewriteWithContext(context, targetDnf); | ||
117 | workList.addFirst(abstractCallLiteral.withTarget(rewrittenDnf)); | ||
118 | workList.addFirst(contextCall); | ||
119 | } | ||
120 | |||
121 | private static boolean hasInputParameter(Dnf targetDnf) { | ||
122 | for (var parameter : targetDnf.getParameters()) { | ||
123 | if (parameter.getDirection() != ParameterDirection.OUT) { | ||
124 | return true; | ||
125 | } | ||
126 | } | ||
127 | return false; | ||
128 | } | ||
129 | |||
130 | private static Literal getSingleLiteral(AbstractCallLiteral abstractCallLiteral, Dnf targetDnf, | ||
131 | CallPolarity polarity) { | ||
132 | if (!(abstractCallLiteral instanceof CallLiteral callLiteral) || | ||
133 | callLiteral.getPolarity() != polarity) { | ||
134 | return null; | ||
135 | } | ||
136 | var clauses = targetDnf.getClauses(); | ||
137 | if (clauses.size() != 1) { | ||
138 | return null; | ||
139 | } | ||
140 | var targetLiterals = clauses.get(0).literals(); | ||
141 | if (targetLiterals.size() != 1) { | ||
142 | return null; | ||
143 | } | ||
144 | return targetLiterals.get(0); | ||
145 | } | ||
146 | |||
147 | private static Substitution asSubstitution(AbstractCallLiteral callLiteral, Dnf targetDnf) { | ||
148 | var builder = Substitution.builder().renewing(); | ||
149 | var arguments = callLiteral.getArguments(); | ||
150 | var parameters = targetDnf.getSymbolicParameters(); | ||
151 | int arity = arguments.size(); | ||
152 | if (parameters.size() != arity) { | ||
153 | throw new IllegalArgumentException("Call %s of %s arity mismatch".formatted(callLiteral, targetDnf)); | ||
154 | } | ||
155 | for (int i = 0; i < arity; i++) { | ||
156 | builder.putChecked(parameters.get(i).getVariable(), arguments.get(i)); | ||
157 | } | ||
158 | return builder.build(); | ||
159 | } | ||
160 | } | ||