1 /********************* */
2 /*! \file theory_strings.h
4 ** Original author: Tianyi Liang
5 ** Major contributors: Andrew Reynolds
6 ** Minor contributors (to current version): Martin Brain <>, Morgan Deters
7 ** This file is part of the CVC4 project.
8 ** Copyright (c) 2009-2014 New York University and The University of Iowa
9 ** See the file COPYING in the top-level source directory for licensing
10 ** information.\endverbatim
12 ** \brief Theory of strings
17 #include "cvc4_private.h"
19 #ifndef __CVC4__THEORY__STRINGS__THEORY_STRINGS_H
20 #define __CVC4__THEORY__STRINGS__THEORY_STRINGS_H
22 #include "theory/theory.h"
23 #include "theory/uf/equality_engine.h"
24 #include "theory/strings/theory_strings_preprocess.h"
25 #include "theory/strings/regexp_operation.h"
27 #include "context/cdchunk_list.h"
28 #include "context/cdhashset.h"
37 * Decision procedure for strings.
41 class TheoryStrings
: public Theory
{
42 typedef context::CDChunkList
<Node
> NodeList
;
43 typedef context::CDHashMap
<Node
, NodeList
*, NodeHashFunction
> NodeListMap
;
44 typedef context::CDHashMap
<Node
, bool, NodeHashFunction
> NodeBoolMap
;
45 typedef context::CDHashMap
<Node
, int, NodeHashFunction
> NodeIntMap
;
46 typedef context::CDHashMap
<Node
, Node
, NodeHashFunction
> NodeNodeMap
;
47 typedef context::CDHashSet
<Node
, NodeHashFunction
> NodeSet
;
50 TheoryStrings(context::Context
* c
, context::UserContext
* u
, OutputChannel
& out
, Valuation valuation
, const LogicInfo
& logicInfo
);
53 void setMasterEqualityEngine(eq::EqualityEngine
* eq
);
55 std::string
identify() const { return std::string("TheoryStrings"); }
58 void propagate(Effort e
);
59 bool propagate(TNode literal
);
60 void explain( TNode literal
, std::vector
<TNode
>& assumptions
);
61 Node
explain( TNode literal
);
64 // NotifyClass for equality engine
65 class NotifyClass
: public eq::EqualityEngineNotify
{
68 NotifyClass(TheoryStrings
& t_str
): d_str(t_str
) {}
69 bool eqNotifyTriggerEquality(TNode equality
, bool value
) {
70 Debug("strings") << "NotifyClass::eqNotifyTriggerEquality(" << equality
<< ", " << (value
? "true" : "false" )<< ")" << std::endl
;
72 return d_str
.propagate(equality
);
74 // We use only literal triggers so taking not is safe
75 return d_str
.propagate(equality
.notNode());
78 bool eqNotifyTriggerPredicate(TNode predicate
, bool value
) {
79 Debug("strings") << "NotifyClass::eqNotifyTriggerPredicate(" << predicate
<< ", " << (value
? "true" : "false") << ")" << std::endl
;
81 return d_str
.propagate(predicate
);
83 return d_str
.propagate(predicate
.notNode());
86 bool eqNotifyTriggerTermEquality(TheoryId tag
, TNode t1
, TNode t2
, bool value
) {
87 Debug("strings") << "NotifyClass::eqNotifyTriggerTermMerge(" << tag
<< ", " << t1
<< ", " << t2
<< ")" << std::endl
;
89 return d_str
.propagate(t1
.eqNode(t2
));
91 return d_str
.propagate(t1
.eqNode(t2
).notNode());
94 void eqNotifyConstantTermMerge(TNode t1
, TNode t2
) {
95 Debug("strings") << "NotifyClass::eqNotifyConstantTermMerge(" << t1
<< ", " << t2
<< ")" << std::endl
;
96 d_str
.conflict(t1
, t2
);
98 void eqNotifyNewClass(TNode t
) {
99 Debug("strings") << "NotifyClass::eqNotifyNewClass(" << t
<< std::endl
;
100 d_str
.eqNotifyNewClass(t
);
102 void eqNotifyPreMerge(TNode t1
, TNode t2
) {
103 Debug("strings") << "NotifyClass::eqNotifyPreMerge(" << t1
<< ", " << t2
<< std::endl
;
104 d_str
.eqNotifyPreMerge(t1
, t2
);
106 void eqNotifyPostMerge(TNode t1
, TNode t2
) {
107 Debug("strings") << "NotifyClass::eqNotifyPostMerge(" << t1
<< ", " << t2
<< std::endl
;
108 d_str
.eqNotifyPostMerge(t1
, t2
);
110 void eqNotifyDisequal(TNode t1
, TNode t2
, TNode reason
) {
111 Debug("strings") << "NotifyClass::eqNotifyDisequal(" << t1
<< ", " << t2
<< ", " << reason
<< std::endl
;
112 d_str
.eqNotifyDisequal(t1
, t2
, reason
);
114 };/* class TheoryStrings::NotifyClass */
118 * Function symbol used to implement uninterpreted undefined string
119 * semantics. Needed to deal with partial charat/substr function.
130 CVC4::Rational RMAXINT
;
131 unsigned d_card_size
;
134 bool d_opt_regexp_gcd
;
136 Node
getRepresentative( Node t
);
137 bool hasTerm( Node a
);
138 bool areEqual( Node a
, Node b
);
139 bool areDisequal( Node a
, Node b
);
140 Node
getLengthTerm( Node t
);
141 Node
getLength( Node t
, bool use_t
= false );
144 /** The notify class */
145 NotifyClass d_notify
;
146 /** Equaltity engine */
147 eq::EqualityEngine d_equalityEngine
;
148 /** Are we in conflict */
149 context::CDO
<bool> d_conflict
;
150 //list of pairs of nodes to merge
151 std::map
< Node
, Node
> d_pending_exp
;
152 std::vector
< Node
> d_pending
;
153 std::vector
< Node
> d_lemma_cache
;
154 std::map
< Node
, bool > d_pending_req_phase
;
157 NodeList d_infer_exp
;
159 std::map
< Node
, Node
> d_normal_forms_base
;
160 std::map
< Node
, std::vector
< Node
> > d_normal_forms
;
161 std::map
< Node
, std::vector
< Node
> > d_normal_forms_exp
;
162 //map of pairs of terms that have the same normal form
163 NodeListMap d_nf_pairs
;
164 void addNormalFormPair( Node n1
, Node n2
);
165 bool isNormalFormPair( Node n1
, Node n2
);
166 bool isNormalFormPair2( Node n1
, Node n2
);
168 NodeSet d_loop_antec
;
169 NodeSet d_length_intro_vars
;
171 NodeSet d_registered_terms_cache
;
173 std::vector
< Node
> d_terms_cache
;
174 void collectTerm( Node n
);
175 void appendTermLemma();
177 StringsPreprocess d_preproc
;
178 NodeBoolMap d_preproc_cache
;
180 /////////////////////////////////////////////////////////////////////////////
182 /////////////////////////////////////////////////////////////////////////////
184 void collectModelInfo(TheoryModel
* m
, bool fullModel
);
186 /////////////////////////////////////////////////////////////////////////////
188 /////////////////////////////////////////////////////////////////////////////
193 /////////////////////////////////////////////////////////////////////////////
195 /////////////////////////////////////////////////////////////////////////////
197 void addSharedTerm(TNode n
);
198 EqualityStatus
getEqualityStatus(TNode a
, TNode b
);
203 EqcInfo( context::Context
* c
);
205 //constant in this eqc
206 context::CDO
< Node
> d_const_term
;
207 context::CDO
< Node
> d_length_term
;
208 context::CDO
< unsigned > d_cardinality_lem_k
;
209 // 1 = added length lemma
210 context::CDO
< Node
> d_normalized_length
;
212 /** map from representatives to information necessary for equivalence classes */
213 std::map
< Node
, EqcInfo
* > d_eqc_info
;
214 EqcInfo
* getOrMakeEqcInfo( Node eqc
, bool doMake
= true );
215 //maintain which concat terms have the length lemma instantiated
216 NodeNodeMap d_proxy_var
;
218 void mergeCstVec(std::vector
< Node
> &vec_strings
);
219 bool getNormalForms(Node
&eqc
, std::vector
< Node
> & visited
, std::vector
< Node
> & nf
,
220 std::vector
< std::vector
< Node
> > &normal_forms
,
221 std::vector
< std::vector
< Node
> > &normal_forms_exp
,
222 std::vector
< Node
> &normal_form_src
);
223 bool detectLoop(std::vector
< std::vector
< Node
> > &normal_forms
,
224 int i
, int j
, int index_i
, int index_j
,
225 int &loop_in_i
, int &loop_in_j
);
226 bool processLoop(std::vector
< Node
> &antec
,
227 std::vector
< std::vector
< Node
> > &normal_forms
,
228 std::vector
< Node
> &normal_form_src
,
229 int i
, int j
, int loop_n_index
, int other_n_index
,
230 int loop_index
, int index
, int other_index
);
231 bool processNEqc(std::vector
< std::vector
< Node
> > &normal_forms
,
232 std::vector
< std::vector
< Node
> > &normal_forms_exp
,
233 std::vector
< Node
> &normal_form_src
);
234 bool processReverseNEq(std::vector
< std::vector
< Node
> > &normal_forms
,
235 std::vector
< Node
> &normal_form_src
, std::vector
< Node
> &curr_exp
, unsigned i
, unsigned j
);
236 bool processSimpleNEq( std::vector
< std::vector
< Node
> > &normal_forms
,
237 std::vector
< Node
> &normal_form_src
, std::vector
< Node
> &curr_exp
, unsigned i
, unsigned j
,
238 unsigned& index_i
, unsigned& index_j
, bool isRev
);
239 bool normalizeEquivalenceClass( Node n
, std::vector
< Node
> & visited
, std::vector
< Node
> & nf
, std::vector
< Node
> & nf_exp
);
240 bool processDeq( Node n1
, Node n2
);
241 int processReverseDeq( std::vector
< Node
>& nfi
, std::vector
< Node
>& nfj
, Node ni
, Node nj
);
242 int processSimpleDeq( std::vector
< Node
>& nfi
, std::vector
< Node
>& nfj
, Node ni
, Node nj
, unsigned& index
, bool isRev
);
243 //bool unrollStar( Node atom );
244 Node
mkRegExpAntec(Node atom
, Node ant
);
246 //bool checkSimple();
247 void checkNormalForms();
249 void checkLengthsEqc();
250 void checkCardinality();
251 bool checkInductiveEquations();
252 //check membership constraints
253 Node
normalizeRegexp(Node r
);
254 bool normalizePosMemberships(std::map
< Node
, std::vector
< Node
> > &memb_with_exps
);
255 bool applyRConsume( CVC4::String
&s
, Node
&r
);
256 Node
applyRSplit(Node s1
, Node s2
, Node r
);
257 bool applyRLen(std::map
< Node
, std::vector
< Node
> > &XinR_with_exps
);
258 bool checkMembershipsWithoutLength(
259 std::map
< Node
, std::vector
< Node
> > &memb_with_exps
,
260 std::map
< Node
, std::vector
< Node
> > &XinR_with_exps
);
261 void checkMemberships();
263 bool checkMemberships2();
264 bool checkPDerivative(Node x
, Node r
, Node atom
, bool &addedLemma
,
265 std::vector
< Node
> &processed
, std::vector
< Node
> &cprocessed
,
266 std::vector
< Node
> &nf_exp
);
267 void checkExtendedFuncs();
268 void checkPosContains( std::vector
< Node
>& posContains
);
269 void checkNegContains( std::vector
< Node
>& negContains
);
270 void checkExtendedFuncsEval();
271 Node
inferConstantDefinition( Node n
, std::vector
< Node
>& exp
, std::map
< Node
, Node
>& visited
);
272 Node
getSymbolicDefinition( Node n
, std::vector
< Node
>& exp
);
273 void checkExtendedFuncsReduction();
276 void preRegisterTerm(TNode n
);
277 Node
expandDefinition(LogicRequest
&logicRequest
, Node n
);
278 void check(Effort e
);
280 /** Conflict when merging two constants */
281 void conflict(TNode a
, TNode b
);
282 /** called when a new equivalence class is created */
283 void eqNotifyNewClass(TNode t
);
284 /** called when two equivalence classes will merge */
285 void eqNotifyPreMerge(TNode t1
, TNode t2
);
286 /** called when two equivalence classes have merged */
287 void eqNotifyPostMerge(TNode t1
, TNode t2
);
288 /** called when two equivalence classes are made disequal */
289 void eqNotifyDisequal(TNode t1
, TNode t2
, TNode reason
);
291 /** compute care graph */
292 void computeCareGraph();
295 void assertPendingFact(Node atom
, bool polarity
, Node exp
);
296 void doPendingFacts();
297 void doPendingLemmas();
300 bool registerTerm( Node n
);
302 void sendLemma( Node ant
, Node conc
, const char * c
);
303 void sendInfer( Node eq_exp
, Node eq
, const char * c
);
304 void sendSplit( Node a
, Node b
, const char * c
, bool preq
= true );
305 void sendLengthLemma( Node n
);
307 inline Node
mkConcat( Node n1
, Node n2
);
308 inline Node
mkConcat( Node n1
, Node n2
, Node n3
);
309 inline Node
mkConcat( const std::vector
< Node
>& c
);
311 inline Node
mkSkolemS(const char * c
, int isLenSplit
= 0);
312 //inline Node mkSkolemI(const char * c);
314 Node
mkExplain( std::vector
< Node
>& a
);
315 Node
mkExplain( std::vector
< Node
>& a
, std::vector
< Node
>& an
);
317 Node
mkAnd( std::vector
< Node
>& a
);
318 /** get concat vector */
319 void getConcatVec( Node n
, std::vector
< Node
>& c
);
321 //get equivalence classes
322 void getEquivalenceClasses( std::vector
< Node
>& eqcs
);
323 //get final normal form
324 void getFinalNormalForm( Node n
, std::vector
< Node
>& nf
, std::vector
< Node
>& exp
);
326 //separate into collections with equal length
327 void separateByLength( std::vector
< Node
>& n
, std::vector
< std::vector
< Node
> >& col
, std::vector
< Node
>& lts
);
328 void printConcat( std::vector
< Node
>& n
, const char * c
);
330 void inferSubstitutionProxyVars( Node n
, std::vector
< Node
>& vars
, std::vector
< Node
>& subs
, std::vector
< Node
>& unproc
, std::vector
< Node
>& exp
);
332 std::map
< Node
, std::map
< Node
, std::map
< int, Node
> > > d_skolem_cache
;
333 Node
mkSkolemSplit( Node a
, Node b
, const char * c
, int isLenSplit
= 0 );
335 Node
mkSplitEq( const char * c
, const char * info
, Node lhs
, Node rhs
, bool lgtZero
);
337 // Special String Functions
338 NodeSet d_neg_ctn_eqlen
;
339 NodeSet d_neg_ctn_ulen
;
340 NodeSet d_pos_ctn_cached
;
341 NodeSet d_neg_ctn_cached
;
342 //extended string terms and whether they have been reduced
343 NodeBoolMap d_ext_func_terms
;
344 //collect extended operator terms
345 void collectExtendedFuncTerms( Node n
, std::map
< Node
, bool >& visited
);
347 // Symbolic Regular Expression
349 // regular expression memberships
350 NodeList d_regexp_memberships
;
351 NodeSet d_regexp_ucached
;
352 NodeSet d_regexp_ccached
;
354 NodeListMap d_pos_memberships
;
355 NodeListMap d_neg_memberships
;
356 // semi normal forms for symbolic expression
357 std::map
< Node
, Node
> d_nf_regexps
;
358 std::map
< Node
, std::vector
< Node
> > d_nf_regexps_exp
;
360 NodeNodeMap d_inter_cache
;
361 NodeIntMap d_inter_index
;
362 // processed memberships
363 NodeSet d_processed_memberships
;
364 // antecedant for why regexp membership must be true
365 NodeNodeMap d_regexp_ant
;
367 //std::map< Node, bool > d_membership_length;
368 // regular expression operations
369 RegExpOpr d_regexp_opr
;
371 CVC4::String
getHeadConst( Node x
);
372 bool deriveRegExp( Node x
, Node r
, Node ant
);
373 bool addMembershipLength(Node atom
);
374 void addMembership(Node assertion
);
375 Node
getNormalString(Node x
, std::vector
<Node
> &nf_exp
);
376 Node
getNormalSymRegExp(Node r
, std::vector
<Node
> &nf_exp
);
379 // Finite Model Finding
381 NodeSet d_input_vars
;
382 context::CDO
< Node
> d_input_var_lsum
;
383 context::CDHashMap
< int, Node
> d_cardinality_lits
;
384 context::CDO
< int > d_curr_cardinality
;
386 //for finite model finding
387 Node
getNextDecisionRequest();
388 void assertNode( Node lit
);
391 /** statistics class */
396 IntStat d_deq_splits
;
397 IntStat d_loop_lemmas
;
398 IntStat d_new_skolems
;
401 };/* class TheoryStrings::Statistics */
402 Statistics d_statistics
;
403 };/* class TheoryStrings */
405 }/* CVC4::theory::strings namespace */
406 }/* CVC4::theory namespace */
407 }/* CVC4 namespace */
409 #endif /* __CVC4__THEORY__STRINGS__THEORY_STRINGS_H */