1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Tianyi Liang, Mathias Preiner |
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 |
|
* Theory of strings. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "cvc5_private.h" |
17 |
|
|
18 |
|
#ifndef CVC5__THEORY__STRINGS__THEORY_STRINGS_H |
19 |
|
#define CVC5__THEORY__STRINGS__THEORY_STRINGS_H |
20 |
|
|
21 |
|
#include <climits> |
22 |
|
#include <deque> |
23 |
|
|
24 |
|
#include "context/cdhashset.h" |
25 |
|
#include "context/cdlist.h" |
26 |
|
#include "expr/node_trie.h" |
27 |
|
#include "theory/ext_theory.h" |
28 |
|
#include "theory/strings/base_solver.h" |
29 |
|
#include "theory/strings/core_solver.h" |
30 |
|
#include "theory/strings/eager_solver.h" |
31 |
|
#include "theory/strings/extf_solver.h" |
32 |
|
#include "theory/strings/infer_info.h" |
33 |
|
#include "theory/strings/inference_manager.h" |
34 |
|
#include "theory/strings/normal_form.h" |
35 |
|
#include "theory/strings/proof_checker.h" |
36 |
|
#include "theory/strings/regexp_elim.h" |
37 |
|
#include "theory/strings/regexp_operation.h" |
38 |
|
#include "theory/strings/regexp_solver.h" |
39 |
|
#include "theory/strings/sequences_stats.h" |
40 |
|
#include "theory/strings/solver_state.h" |
41 |
|
#include "theory/strings/strategy.h" |
42 |
|
#include "theory/strings/strings_fmf.h" |
43 |
|
#include "theory/strings/strings_rewriter.h" |
44 |
|
#include "theory/strings/term_registry.h" |
45 |
|
#include "theory/theory.h" |
46 |
|
#include "theory/uf/equality_engine.h" |
47 |
|
|
48 |
|
namespace cvc5 { |
49 |
|
namespace theory { |
50 |
|
namespace strings { |
51 |
|
|
52 |
|
/** |
53 |
|
* A theory solver for strings. At a high level, the solver implements |
54 |
|
* techniques described in: |
55 |
|
* - Liang et al, CAV 2014, |
56 |
|
* - Reynolds et al, CAV 2017, |
57 |
|
* - Reynolds et al, IJCAR 2020. |
58 |
|
* Its rewriter is described in: |
59 |
|
* - Reynolds et al, CAV 2019. |
60 |
|
*/ |
61 |
|
class TheoryStrings : public Theory { |
62 |
|
friend class InferenceManager; |
63 |
|
typedef context::CDHashSet<Node> NodeSet; |
64 |
|
typedef context::CDHashSet<TypeNode, std::hash<TypeNode>> TypeNodeSet; |
65 |
|
|
66 |
|
public: |
67 |
|
TheoryStrings(context::Context* c, |
68 |
|
context::UserContext* u, |
69 |
|
OutputChannel& out, |
70 |
|
Valuation valuation, |
71 |
|
const LogicInfo& logicInfo, |
72 |
|
ProofNodeManager* pnm); |
73 |
|
~TheoryStrings(); |
74 |
|
//--------------------------------- initialization |
75 |
|
/** get the official theory rewriter of this theory */ |
76 |
|
TheoryRewriter* getTheoryRewriter() override; |
77 |
|
/** get the proof checker of this theory */ |
78 |
|
ProofRuleChecker* getProofChecker() override; |
79 |
|
/** |
80 |
|
* Returns true if we need an equality engine. If so, we initialize the |
81 |
|
* information regarding how it should be setup. For details, see the |
82 |
|
* documentation in Theory::needsEqualityEngine. |
83 |
|
*/ |
84 |
|
bool needsEqualityEngine(EeSetupInfo& esi) override; |
85 |
|
/** finish initialization */ |
86 |
|
void finishInit() override; |
87 |
|
//--------------------------------- end initialization |
88 |
|
/** Identify this theory */ |
89 |
|
std::string identify() const override; |
90 |
|
/** Explain */ |
91 |
|
TrustNode explain(TNode literal) override; |
92 |
|
/** presolve */ |
93 |
|
void presolve() override; |
94 |
|
/** shutdown */ |
95 |
9847 |
void shutdown() override {} |
96 |
|
/** preregister term */ |
97 |
|
void preRegisterTerm(TNode n) override; |
98 |
|
//--------------------------------- standard check |
99 |
|
/** Do we need a check call at last call effort? */ |
100 |
|
bool needsCheckLastEffort() override; |
101 |
|
bool preNotifyFact(TNode atom, |
102 |
|
bool pol, |
103 |
|
TNode fact, |
104 |
|
bool isPrereg, |
105 |
|
bool isInternal) override; |
106 |
|
void notifyFact(TNode atom, bool pol, TNode fact, bool isInternal) override; |
107 |
|
/** Post-check, called after the fact queue of the theory is processed. */ |
108 |
|
void postCheck(Effort level) override; |
109 |
|
//--------------------------------- end standard check |
110 |
|
/** propagate method */ |
111 |
|
bool propagateLit(TNode literal); |
112 |
|
/** Conflict when merging two constants */ |
113 |
|
void conflict(TNode a, TNode b); |
114 |
|
/** called when a new equivalence class is created */ |
115 |
|
void eqNotifyNewClass(TNode t); |
116 |
|
/** preprocess rewrite */ |
117 |
|
TrustNode ppRewrite(TNode atom, std::vector<SkolemLemma>& lems) override; |
118 |
|
/** Collect model values in m based on the relevant terms given by termSet */ |
119 |
|
bool collectModelValues(TheoryModel* m, |
120 |
|
const std::set<Node>& termSet) override; |
121 |
|
|
122 |
|
private: |
123 |
|
/** NotifyClass for equality engine */ |
124 |
9853 |
class NotifyClass : public eq::EqualityEngineNotify { |
125 |
|
public: |
126 |
9853 |
NotifyClass(TheoryStrings& ts) : d_str(ts), d_eagerSolver(ts.d_eagerSolver) |
127 |
|
{ |
128 |
9853 |
} |
129 |
463488 |
bool eqNotifyTriggerPredicate(TNode predicate, bool value) override |
130 |
|
{ |
131 |
926976 |
Debug("strings") << "NotifyClass::eqNotifyTriggerPredicate(" << predicate |
132 |
463488 |
<< ", " << (value ? "true" : "false") << ")" << std::endl; |
133 |
463488 |
if (value) |
134 |
|
{ |
135 |
250472 |
return d_str.propagateLit(predicate); |
136 |
|
} |
137 |
213016 |
return d_str.propagateLit(predicate.notNode()); |
138 |
|
} |
139 |
482840 |
bool eqNotifyTriggerTermEquality(TheoryId tag, |
140 |
|
TNode t1, |
141 |
|
TNode t2, |
142 |
|
bool value) override |
143 |
|
{ |
144 |
482840 |
Debug("strings") << "NotifyClass::eqNotifyTriggerTermMerge(" << tag << ", " << t1 << ", " << t2 << ")" << std::endl; |
145 |
482840 |
if (value) { |
146 |
373997 |
return d_str.propagateLit(t1.eqNode(t2)); |
147 |
|
} |
148 |
108843 |
return d_str.propagateLit(t1.eqNode(t2).notNode()); |
149 |
|
} |
150 |
1032 |
void eqNotifyConstantTermMerge(TNode t1, TNode t2) override |
151 |
|
{ |
152 |
1032 |
Debug("strings") << "NotifyClass::eqNotifyConstantTermMerge(" << t1 << ", " << t2 << ")" << std::endl; |
153 |
1032 |
d_str.conflict(t1, t2); |
154 |
1032 |
} |
155 |
119502 |
void eqNotifyNewClass(TNode t) override |
156 |
|
{ |
157 |
119502 |
Debug("strings") << "NotifyClass::eqNotifyNewClass(" << t << std::endl; |
158 |
119502 |
d_str.eqNotifyNewClass(t); |
159 |
119502 |
} |
160 |
1283956 |
void eqNotifyMerge(TNode t1, TNode t2) override |
161 |
|
{ |
162 |
2567912 |
Debug("strings") << "NotifyClass::eqNotifyMerge(" << t1 << ", " << t2 |
163 |
1283956 |
<< std::endl; |
164 |
1283956 |
d_eagerSolver.eqNotifyMerge(t1, t2); |
165 |
1283956 |
} |
166 |
181108 |
void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) override |
167 |
|
{ |
168 |
181108 |
Debug("strings") << "NotifyClass::eqNotifyDisequal(" << t1 << ", " << t2 << ", " << reason << std::endl; |
169 |
181108 |
d_eagerSolver.eqNotifyDisequal(t1, t2, reason); |
170 |
181108 |
} |
171 |
|
|
172 |
|
private: |
173 |
|
/** The theory of strings object to notify */ |
174 |
|
TheoryStrings& d_str; |
175 |
|
/** The eager solver of the theory of strings */ |
176 |
|
EagerSolver& d_eagerSolver; |
177 |
|
};/* class TheoryStrings::NotifyClass */ |
178 |
|
/** compute care graph */ |
179 |
|
void computeCareGraph() override; |
180 |
|
/** |
181 |
|
* Are x and y shared terms that are not equal? This is used for constructing |
182 |
|
* the care graph in the above function. |
183 |
|
*/ |
184 |
|
bool areCareDisequal(TNode x, TNode y); |
185 |
|
/** Add care pairs */ |
186 |
|
void addCarePairs(TNodeTrie* t1, |
187 |
|
TNodeTrie* t2, |
188 |
|
unsigned arity, |
189 |
|
unsigned depth); |
190 |
|
/** Collect model info for type tn |
191 |
|
* |
192 |
|
* Assigns model values (in m) to all relevant terms of the string-like type |
193 |
|
* tn in the current context, which are stored in repSet[tn]. |
194 |
|
* |
195 |
|
* @param tn The type to compute model values for |
196 |
|
* @param toProcess Remaining types to compute model values for |
197 |
|
* @param repSet A map of types to the representatives of the equivalence |
198 |
|
* classes of the given type |
199 |
|
* @return false if a conflict is discovered while doing this assignment. |
200 |
|
*/ |
201 |
|
bool collectModelInfoType( |
202 |
|
TypeNode tn, |
203 |
|
std::unordered_set<TypeNode>& toProcess, |
204 |
|
const std::map<TypeNode, std::unordered_set<Node>>& repSet, |
205 |
|
TheoryModel* m); |
206 |
|
|
207 |
|
/** assert pending fact |
208 |
|
* |
209 |
|
* This asserts atom with polarity to the equality engine of this class, |
210 |
|
* where exp is the explanation of why (~) atom holds. |
211 |
|
* |
212 |
|
* This call may trigger further initialization steps involving the terms |
213 |
|
* of atom, including calls to registerTerm. |
214 |
|
*/ |
215 |
|
void assertPendingFact(Node atom, bool polarity, Node exp); |
216 |
|
//-----------------------inference steps |
217 |
|
/** check register terms pre-normal forms |
218 |
|
* |
219 |
|
* This calls registerTerm(n,2) on all non-congruent strings in the |
220 |
|
* equality engine of this class. |
221 |
|
*/ |
222 |
|
void checkRegisterTermsPreNormalForm(); |
223 |
|
/** check codes |
224 |
|
* |
225 |
|
* This inference schema ensures that constraints between str.code terms |
226 |
|
* are satisfied by models that correspond to extensions of the current |
227 |
|
* assignment. In particular, this method ensures that str.code can be |
228 |
|
* given an interpretation that is injective for string arguments with length |
229 |
|
* one. It may add lemmas of the form: |
230 |
|
* str.code(x) == -1 V str.code(x) != str.code(y) V x == y |
231 |
|
*/ |
232 |
|
void checkCodes(); |
233 |
|
/** check register terms for normal forms |
234 |
|
* |
235 |
|
* This calls registerTerm(str.++(t1, ..., tn ), 3) on the normal forms |
236 |
|
* (t1, ..., tn) of all string equivalence classes { s1, ..., sm } such that |
237 |
|
* there does not exist a term of the form str.len(si) in the current context. |
238 |
|
*/ |
239 |
|
void checkRegisterTermsNormalForms(); |
240 |
|
//-----------------------end inference steps |
241 |
|
/** run the given inference step */ |
242 |
|
void runInferStep(InferStep s, int effort); |
243 |
|
/** run strategy for effort e */ |
244 |
|
void runStrategy(Theory::Effort e); |
245 |
|
/** print strings equivalence classes for debugging */ |
246 |
|
std::string debugPrintStringsEqc(); |
247 |
|
/** Commonly used constants */ |
248 |
|
Node d_true; |
249 |
|
Node d_false; |
250 |
|
Node d_zero; |
251 |
|
Node d_one; |
252 |
|
Node d_neg_one; |
253 |
|
/** the cardinality of the alphabet */ |
254 |
|
uint32_t d_cardSize; |
255 |
|
/** The notify class */ |
256 |
|
NotifyClass d_notify; |
257 |
|
/** |
258 |
|
* Statistics for the theory of strings/sequences. All statistics for these |
259 |
|
* theories is collected in this object. |
260 |
|
*/ |
261 |
|
SequencesStatistics d_statistics; |
262 |
|
/** The solver state object */ |
263 |
|
SolverState d_state; |
264 |
|
/** The eager solver */ |
265 |
|
EagerSolver d_eagerSolver; |
266 |
|
/** The term registry for this theory */ |
267 |
|
TermRegistry d_termReg; |
268 |
|
/** The extended theory callback */ |
269 |
|
StringsExtfCallback d_extTheoryCb; |
270 |
|
/** Extended theory, responsible for context-dependent simplification. */ |
271 |
|
ExtTheory d_extTheory; |
272 |
|
/** The (custom) output channel of the theory of strings */ |
273 |
|
InferenceManager d_im; |
274 |
|
/** The theory rewriter for this theory. */ |
275 |
|
StringsRewriter d_rewriter; |
276 |
|
/** The proof rule checker */ |
277 |
|
StringProofRuleChecker d_checker; |
278 |
|
/** |
279 |
|
* The base solver, responsible for reasoning about congruent terms and |
280 |
|
* inferring constants for equivalence classes. |
281 |
|
*/ |
282 |
|
BaseSolver d_bsolver; |
283 |
|
/** |
284 |
|
* The core solver, responsible for reasoning about string concatenation |
285 |
|
* with length constraints. |
286 |
|
*/ |
287 |
|
CoreSolver d_csolver; |
288 |
|
/** |
289 |
|
* Extended function solver, responsible for reductions and simplifications |
290 |
|
* involving extended string functions. |
291 |
|
*/ |
292 |
|
ExtfSolver d_esolver; |
293 |
|
/** regular expression solver module */ |
294 |
|
RegExpSolver d_rsolver; |
295 |
|
/** regular expression elimination module */ |
296 |
|
RegExpElimination d_regexp_elim; |
297 |
|
/** Strings finite model finding decision strategy */ |
298 |
|
StringsFmf d_stringsFmf; |
299 |
|
/** The representation of the strategy */ |
300 |
|
Strategy d_strat; |
301 |
|
};/* class TheoryStrings */ |
302 |
|
|
303 |
|
} // namespace strings |
304 |
|
} // namespace theory |
305 |
|
} // namespace cvc5 |
306 |
|
|
307 |
|
#endif /* CVC5__THEORY__STRINGS__THEORY_STRINGS_H */ |