1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds |
4 |
|
* |
5 |
|
* This file is part of the cvc5 project. |
6 |
|
* |
7 |
|
* Copyright (c) 2009-2021 by the authors listed in the file AUTHORS |
8 |
|
* in the top-level source directory and their institutional affiliations. |
9 |
|
* All rights reserved. See the file COPYING in the top-level source |
10 |
|
* directory for licensing information. |
11 |
|
* **************************************************************************** |
12 |
|
* |
13 |
|
* Implementation of the justification SAT decision strategy |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "cvc5_private.h" |
17 |
|
|
18 |
|
#ifndef CVC5__DECISION__JUSTIFICATION_STRATEGY_H |
19 |
|
#define CVC5__DECISION__JUSTIFICATION_STRATEGY_H |
20 |
|
|
21 |
|
#include "context/cdinsert_hashmap.h" |
22 |
|
#include "context/cdo.h" |
23 |
|
#include "decision/assertion_list.h" |
24 |
|
#include "decision/decision_engine.h" |
25 |
|
#include "decision/justify_info.h" |
26 |
|
#include "decision/justify_stack.h" |
27 |
|
#include "decision/justify_stats.h" |
28 |
|
#include "expr/node.h" |
29 |
|
#include "options/decision_options.h" |
30 |
|
#include "prop/cnf_stream.h" |
31 |
|
#include "prop/sat_solver.h" |
32 |
|
#include "prop/sat_solver_types.h" |
33 |
|
|
34 |
|
namespace cvc5 { |
35 |
|
|
36 |
|
namespace prop { |
37 |
|
class SkolemDefManager; |
38 |
|
} |
39 |
|
|
40 |
|
namespace decision { |
41 |
|
|
42 |
|
/** |
43 |
|
* An implementation of justification SAT decision heuristic. This class |
44 |
|
* is given access to the set of input formulas, and chooses next decisions |
45 |
|
* based on the structure of the input formula. |
46 |
|
* |
47 |
|
* Notice that the SAT solver still propagates values for literals in the |
48 |
|
* normal way based on BCP when using this SAT decision heuristic. This means |
49 |
|
* that values for literals can be assigned between calls to get next |
50 |
|
* decision. Thus, this module has access to the SAT solver for the purpose |
51 |
|
* of looking up values already assigned to literals. |
52 |
|
* |
53 |
|
* One novel feature of this module is that it maintains a SAT-context-dependent |
54 |
|
* stack corresponding to the current path in the input formula we are trying |
55 |
|
* to satisfy. This means that computing the next decision does not require |
56 |
|
* traversing the current assertion. |
57 |
|
* |
58 |
|
* As an example, say our input formulas are: |
59 |
|
* (or (and A B) C D), (or E F) |
60 |
|
* where A, B, C, D, E, F are theory literals. Moreover, say we are in a |
61 |
|
* state where the SAT solver has initially assigned values: |
62 |
|
* { A -> false, E -> true } |
63 |
|
* Given a call to getNext, this module will analyze what is the next |
64 |
|
* literal that would contribute towards making the input formulas evaluate to |
65 |
|
* true. Assuming it works on assertions and terms left-to-right, it will |
66 |
|
* perform the following reasoning: |
67 |
|
* - The desired value of (or (and A B) C D) is true |
68 |
|
* - The desired value of (and A B) is true |
69 |
|
* - The desired value of A is true, |
70 |
|
* ...The value of A was assigned false |
71 |
|
* ...The value of (and A B) is false |
72 |
|
* - Moving to the next literal, the desired value of C is true |
73 |
|
* ...The value of C is unassigned, return C as a decision. |
74 |
|
* After deciding C, assuming no backtracking occurs, we end up in a state |
75 |
|
* where we have assigned: |
76 |
|
* { A -> false, E -> true, C -> true } |
77 |
|
* In the next call to getNext, this module will proceed, keeping the stack |
78 |
|
* from the previous call: |
79 |
|
* ... The value of C is true |
80 |
|
* ... The value of (or (and A B) C D) is true |
81 |
|
* - Moving to the next assertion, the desired value of (or E F) is true |
82 |
|
* - The desired value of E is true |
83 |
|
* ... The value of E is (already) assigned true |
84 |
|
* ... the value of (or E F) is true. |
85 |
|
* - The are no further assertions. |
86 |
|
* Hence it will return the null SAT decision literal, indicating that no |
87 |
|
* further decisions are necessary to satisfy the input assertions. |
88 |
|
* |
89 |
|
* This class has special handling of "skolem definitions", which arise when |
90 |
|
* lemmas are introduced that correspond to the behavior of skolems. As an |
91 |
|
* example, say our input, prior to preprocessing, is: |
92 |
|
* (or (P (ite A 1 2)) Q) |
93 |
|
* where P is an uninterpreted predicate of type Int -> Bool. After |
94 |
|
* preprocessing, in particular term formula removal which replaces term-level |
95 |
|
* ITE terms with fresh skolems, we get this set of assertions: |
96 |
|
* (or (P k) Q), (ite A (= k 1) (= k 2)) |
97 |
|
* The second assertion is the skolem definition for k. Conceptually, this |
98 |
|
* lemma is only relevant if we have asserted a literal that contains k. |
99 |
|
* This module thus maintains two separate assertion lists, one for |
100 |
|
* input assertions, and one for skolem definitions. The latter is populated |
101 |
|
* only as skolems appear in assertions. In this example, we have initially: |
102 |
|
* input assertions = { (or (P k) Q) } |
103 |
|
* relevant skolem definitions = {} |
104 |
|
* SAT context = {} |
105 |
|
* Say this module returns (P k) as a decision. When this is asserted to |
106 |
|
* the theory engine, a call to notifyAsserted is made with (P k). The |
107 |
|
* skolem definition manager will recognize that (P k) contains k and hence |
108 |
|
* its skolem definition is activated, giving us this state: |
109 |
|
* input assertions = { (or (P k) Q) } |
110 |
|
* relevant skolem definitions = { (ite A (= k 1) (= k 2)) } |
111 |
|
* SAT context = { (P k) } |
112 |
|
* We then proceed by satisfying (ite A (= k 1) (= k 2)), e.g. by returning |
113 |
|
* A as a decision for getNext. |
114 |
|
* |
115 |
|
* Notice that the above policy allows us to ignore certain skolem definitions |
116 |
|
* entirely. For example, if Q were to have been asserted instead of (P k), |
117 |
|
* then (ite A (= k 1) (= k 2)) would not be added as a relevant skolem |
118 |
|
* definition, and Q alone would have sufficed to show the input formula |
119 |
|
* was satisfied. |
120 |
|
*/ |
121 |
15556 |
class JustificationStrategy : public DecisionEngine |
122 |
|
{ |
123 |
|
public: |
124 |
|
/** Constructor */ |
125 |
|
JustificationStrategy(context::Context* c, |
126 |
|
context::UserContext* u, |
127 |
|
prop::SkolemDefManager* skdm, |
128 |
|
ResourceManager* rm); |
129 |
|
|
130 |
|
/** Presolve, called at the beginning of each check-sat call */ |
131 |
|
void presolve() override; |
132 |
|
|
133 |
|
/** |
134 |
|
* Gets the next decision based on the current assertion to satisfy. This |
135 |
|
* returns undefSatLiteral if there are no more assertions. In this case, |
136 |
|
* all relevant input assertions are already propositionally satisfied by |
137 |
|
* the current assignment. |
138 |
|
* |
139 |
|
* @param stopSearch Set to true if we can stop the search |
140 |
|
* @return The next SAT literal to decide on. |
141 |
|
*/ |
142 |
|
prop::SatLiteral getNextInternal(bool& stopSearch) override; |
143 |
|
|
144 |
|
/** |
145 |
|
* Are we finished assigning values to literals? |
146 |
|
* |
147 |
|
* @return true if and only if all relevant input assertions are already |
148 |
|
* propositionally satisfied by the current assignment. |
149 |
|
*/ |
150 |
|
bool isDone() override; |
151 |
|
|
152 |
|
/** |
153 |
|
* Notify this class that assertion is an (input) assertion, not corresponding |
154 |
|
* to a skolem definition. |
155 |
|
*/ |
156 |
|
void addAssertion(TNode assertion) override; |
157 |
|
/** |
158 |
|
* Notify this class that lem is the skolem definition for skolem, which is |
159 |
|
* a part of the current assertions. |
160 |
|
*/ |
161 |
|
void addSkolemDefinition(TNode lem, TNode skolem) override; |
162 |
|
/** |
163 |
|
* Notify this class that literal n has been asserted. This is triggered when |
164 |
|
* n is sent to TheoryEngine. This activates skolem definitions for skolems |
165 |
|
* k that occur in n. |
166 |
|
*/ |
167 |
|
void notifyAsserted(TNode n) override; |
168 |
|
|
169 |
|
private: |
170 |
|
/** |
171 |
|
* Helper method to insert assertions in `toProcess` to `d_assertions` or |
172 |
|
* `d_skolemAssertions` based on `useSkolemList`. |
173 |
|
*/ |
174 |
|
void insertToAssertionList(std::vector<TNode>& toProcess, bool useSkolemList); |
175 |
|
/** |
176 |
|
* Refresh current assertion. This ensures that d_stack has a current |
177 |
|
* assertion to satisfy. If it does not already have one, we take the next |
178 |
|
* assertion from the list of input assertions, or from the relevant |
179 |
|
* skolem definitions based on the JutificationSkolemMode mode. |
180 |
|
* |
181 |
|
* @return true if we successfully initialized d_stack with the next |
182 |
|
* assertion to satisfy. |
183 |
|
*/ |
184 |
|
bool refreshCurrentAssertion(); |
185 |
|
/** |
186 |
|
* Implements the above function for the case where d_stack must get a new |
187 |
|
* assertion to satisfy. |
188 |
|
* |
189 |
|
* @param useSkolemList If this is true, we pull the next assertion from |
190 |
|
* the list of relevant skolem definitions. |
191 |
|
* @return true if we successfully initialized d_stack with the next |
192 |
|
* assertion to satisfy. |
193 |
|
*/ |
194 |
|
bool refreshCurrentAssertionFromList(bool useSkolemList); |
195 |
|
/** |
196 |
|
* Let n be the node referenced by ji. |
197 |
|
* |
198 |
|
* This method is called either when we have yet to process any children of n, |
199 |
|
* or we just determined that the last child we processed of n had value |
200 |
|
* lastChildVal. |
201 |
|
* |
202 |
|
* Note that knowing which child of n we processed last is the value of |
203 |
|
* ji->d_childIndex. |
204 |
|
* |
205 |
|
* @param ji The justify node to process |
206 |
|
* @param lastChildVal The value determined for the last child of the node of |
207 |
|
* ji. |
208 |
|
* @return Either (1) the justify node corresponding to the next child of n to |
209 |
|
* consider adding to the stack, and its desired polarity, or |
210 |
|
* (2) a null justify node and updates lastChildVal to the value of n. |
211 |
|
*/ |
212 |
|
JustifyNode getNextJustifyNode(JustifyInfo* ji, prop::SatValue& lastChildVal); |
213 |
|
/** |
214 |
|
* Returns the value TRUE/FALSE for n, or UNKNOWN otherwise. |
215 |
|
* |
216 |
|
* We return a value for n only if we have justified its values based on its |
217 |
|
* children. For example, we return UNKNOWN for n of the form (and A B) if |
218 |
|
* A and B have UNKNOWN value, even if the SAT solver has assigned a value for |
219 |
|
* (internal) node n. If n itself is a theory literal, we lookup its value |
220 |
|
* in the SAT solver if it is not already cached. |
221 |
|
*/ |
222 |
|
prop::SatValue lookupValue(TNode n); |
223 |
|
/** Is n a theory literal? */ |
224 |
|
static bool isTheoryLiteral(TNode n); |
225 |
|
/** Is n a theory atom? */ |
226 |
|
static bool isTheoryAtom(TNode n); |
227 |
|
/** Pointer to the skolem definition manager */ |
228 |
|
prop::SkolemDefManager* d_skdm; |
229 |
|
/** The assertions, which are user-context dependent. */ |
230 |
|
AssertionList d_assertions; |
231 |
|
/** The skolem assertions */ |
232 |
|
AssertionList d_skolemAssertions; |
233 |
|
|
234 |
|
/** Mapping from non-negated nodes to their SAT value */ |
235 |
|
context::CDInsertHashMap<Node, prop::SatValue> d_justified; |
236 |
|
/** A justify stack */ |
237 |
|
JustifyStack d_stack; |
238 |
|
/** The last decision literal */ |
239 |
|
context::CDO<TNode> d_lastDecisionLit; |
240 |
|
//------------------------------------ activity |
241 |
|
/** Current assertion we are checking for status (context-independent) */ |
242 |
|
Node d_currUnderStatus; |
243 |
|
/** Whether we have added a decision while considering d_currUnderStatus */ |
244 |
|
bool d_currStatusDec; |
245 |
|
//------------------------------------ options |
246 |
|
/** using relevancy order */ |
247 |
|
bool d_useRlvOrder; |
248 |
|
/** using stop only */ |
249 |
|
bool d_decisionStopOnly; |
250 |
|
/** skolem mode */ |
251 |
|
options::JutificationSkolemMode d_jhSkMode; |
252 |
|
/** skolem relevancy mode */ |
253 |
|
options::JutificationSkolemRlvMode d_jhSkRlvMode; |
254 |
|
/** The statistics */ |
255 |
|
JustifyStatistics d_stats; |
256 |
|
}; |
257 |
|
|
258 |
|
} // namespace decision |
259 |
|
} // namespace cvc5 |
260 |
|
|
261 |
|
#endif /* CVC5__DECISION__JUSTIFICATION_STRATEGY_H */ |