1 /********************* */
2 /*! \file inst_strategy_enumerative.cpp
4 ** Top contributors (to current version):
5 ** Andrew Reynolds, Morgan Deters
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2020 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.\endverbatim
12 ** \brief Implementation of an enumerative instantiation strategy.
15 #include "theory/quantifiers/inst_strategy_enumerative.h"
17 #include "options/quantifiers_options.h"
18 #include "theory/quantifiers/instantiate.h"
19 #include "theory/quantifiers/relevant_domain.h"
20 #include "theory/quantifiers/term_database.h"
21 #include "theory/quantifiers/term_util.h"
22 #include "theory/quantifiers_engine.h"
27 using namespace context
;
33 namespace quantifiers
{
35 InstStrategyEnum::InstStrategyEnum(QuantifiersEngine
* qe
,
37 QuantifiersInferenceManager
& qim
,
39 : QuantifiersModule(qs
, qim
, qe
), d_rd(rd
), d_fullSaturateLimit(-1)
42 void InstStrategyEnum::presolve()
44 d_fullSaturateLimit
= options::fullSaturateLimit();
46 bool InstStrategyEnum::needsCheck(Theory::Effort e
)
48 if (d_fullSaturateLimit
== 0)
52 if (options::fullSaturateInterleave())
54 if (d_quantEngine
->getInstWhenNeedsCheck(e
))
59 if (options::fullSaturateQuant())
61 if (e
>= Theory::EFFORT_LAST_CALL
)
69 void InstStrategyEnum::reset_round(Theory::Effort e
) {}
70 void InstStrategyEnum::check(Theory::Effort e
, QEffort quant_e
)
73 bool fullEffort
= false;
74 if (d_fullSaturateLimit
!= 0)
76 if (options::fullSaturateInterleave())
78 // we only add when interleaved with other strategies
79 doCheck
= quant_e
== QEFFORT_STANDARD
&& d_quantEngine
->hasAddedLemma();
81 if (options::fullSaturateQuant() && !doCheck
)
83 if (!d_quantEngine
->theoryEngineNeedsCheck())
85 doCheck
= quant_e
== QEFFORT_LAST_CALL
;
94 Assert(!d_quantEngine
->inConflict());
96 if (Trace
.isOn("fs-engine"))
98 clSet
= double(clock()) / double(CLOCKS_PER_SEC
);
99 Trace("fs-engine") << "---Full Saturation Round, effort = " << e
<< "---"
102 unsigned rstart
= options::fullSaturateQuantRd() ? 0 : 1;
103 unsigned rend
= fullEffort
? 1 : rstart
;
104 unsigned addedLemmas
= 0;
105 // First try in relevant domain of all quantified formulas, if no
106 // instantiations exist, try arbitrary ground terms.
107 // Notice that this stratification of effort levels makes it so that some
108 // quantified formulas may not be instantiated (if they have no instances
109 // at effort level r=0 but another quantified formula does). We prefer
110 // this stratification since effort level r=1 may be highly expensive in the
111 // case where we have a quantified formula with many entailed instances.
112 FirstOrderModel
* fm
= d_quantEngine
->getModel();
113 unsigned nquant
= fm
->getNumAssertedQuantifiers();
114 std::map
<Node
, bool> alreadyProc
;
115 for (unsigned r
= rstart
; r
<= rend
; r
++)
121 Trace("inst-alg") << "-> Relevant domain instantiate..." << std::endl
;
122 Trace("inst-alg-debug") << "Compute relevant domain..." << std::endl
;
124 Trace("inst-alg-debug") << "...finished" << std::endl
;
128 Trace("inst-alg") << "-> Ground term instantiate..." << std::endl
;
130 for (unsigned i
= 0; i
< nquant
; i
++)
132 Node q
= fm
->getAssertedQuantifier(i
, true);
133 bool doProcess
= d_quantEngine
->hasOwnership(q
, this)
134 && fm
->isQuantifierActive(q
)
135 && alreadyProc
.find(q
) == alreadyProc
.end();
138 if (process(q
, fullEffort
, r
== 0))
140 // don't need to mark this if we are not stratifying
141 if (!options::fullSaturateStratify())
143 alreadyProc
[q
] = true;
148 if (d_quantEngine
->inConflict())
154 if (d_quantEngine
->inConflict()
155 || (addedLemmas
> 0 && options::fullSaturateStratify()))
157 // we break if we are in conflict, or if we added any lemma at this
158 // effort level and we stratify effort levels.
163 if (Trace
.isOn("fs-engine"))
165 Trace("fs-engine") << "Added lemmas = " << addedLemmas
<< std::endl
;
166 double clSet2
= double(clock()) / double(CLOCKS_PER_SEC
);
167 Trace("fs-engine") << "Finished full saturation engine, time = "
168 << (clSet2
- clSet
) << std::endl
;
170 if (d_fullSaturateLimit
> 0)
172 d_fullSaturateLimit
--;
176 bool InstStrategyEnum::process(Node f
, bool fullEffort
, bool isRd
)
178 // ignore if constant true (rare case of non-standard quantifier whose body is
179 // rewritten to true)
180 if (f
[1].isConst() && f
[1].getConst
<bool>())
184 unsigned final_max_i
= 0;
185 std::vector
<unsigned> maxs
;
186 std::vector
<bool> max_zero
;
187 bool has_zero
= false;
188 std::map
<TypeNode
, std::vector
<Node
> > term_db_list
;
189 std::vector
<TypeNode
> ftypes
;
190 TermDb
* tdb
= d_quantEngine
->getTermDatabase();
191 EqualityQuery
* qy
= d_quantEngine
->getEqualityQuery();
192 // iterate over substitutions for variables
193 for (unsigned i
= 0; i
< f
[0].getNumChildren(); i
++)
195 TypeNode tn
= f
[0][i
].getType();
196 ftypes
.push_back(tn
);
200 ts
= d_rd
->getRDomain(f
, i
)->d_terms
.size();
204 ts
= tdb
->getNumTypeGroundTerms(tn
);
205 std::map
<TypeNode
, std::vector
<Node
> >::iterator ittd
=
206 term_db_list
.find(tn
);
207 if (ittd
== term_db_list
.end())
209 std::map
<Node
, Node
> reps_found
;
210 for (unsigned j
= 0; j
< ts
; j
++)
212 Node gt
= tdb
->getTypeGroundTerm(ftypes
[i
], j
);
213 if (!options::cegqi() || !quantifiers::TermUtil::hasInstConstAttr(gt
))
215 Node rep
= qy
->getRepresentative(gt
);
216 if (reps_found
.find(rep
) == reps_found
.end())
218 reps_found
[rep
] = gt
;
219 term_db_list
[tn
].push_back(gt
);
223 ts
= term_db_list
[tn
].size();
227 ts
= ittd
->second
.size();
230 // consider a default value if at full effort
231 max_zero
.push_back(fullEffort
&& ts
== 0);
232 ts
= (fullEffort
&& ts
== 0) ? 1 : ts
;
233 Trace("inst-alg-rd") << "Variable " << i
<< " has " << ts
234 << " in relevant domain." << std::endl
;
241 if (ts
> final_max_i
)
248 Trace("inst-alg-rd") << "Will do " << final_max_i
249 << " stages of instantiation." << std::endl
;
252 Instantiate
* ie
= d_quantEngine
->getInstantiate();
253 while (max_i
<= final_max_i
)
255 Trace("inst-alg-rd") << "Try stage " << max_i
<< "..." << std::endl
;
256 std::vector
<unsigned> childIndex
;
260 while (index
>= 0 && index
< (int)f
[0].getNumChildren())
262 if (index
== static_cast<int>(childIndex
.size()))
264 childIndex
.push_back(-1);
268 Assert(index
== static_cast<int>(childIndex
.size()) - 1);
269 unsigned nv
= childIndex
[index
] + 1;
270 if (nv
< maxs
[index
] && nv
<= max_i
)
272 childIndex
[index
] = nv
;
277 childIndex
.pop_back();
282 success
= index
>= 0;
285 if (Trace
.isOn("inst-alg-rd"))
287 Trace("inst-alg-rd") << "Try instantiation { ";
288 for (unsigned i
: childIndex
)
290 Trace("inst-alg-rd") << i
<< " ";
292 Trace("inst-alg-rd") << "}" << std::endl
;
295 std::vector
<Node
> terms
;
296 for (unsigned i
= 0, nchild
= f
[0].getNumChildren(); i
< nchild
; i
++)
300 // no terms available, will report incomplete instantiation
301 terms
.push_back(Node::null());
302 Trace("inst-alg-rd") << " null" << std::endl
;
306 terms
.push_back(d_rd
->getRDomain(f
, i
)->d_terms
[childIndex
[i
]]);
308 << " (rd) " << d_rd
->getRDomain(f
, i
)->d_terms
[childIndex
[i
]]
313 Assert(childIndex
[i
] < term_db_list
[ftypes
[i
]].size());
314 terms
.push_back(term_db_list
[ftypes
[i
]][childIndex
[i
]]);
316 << " " << term_db_list
[ftypes
[i
]][childIndex
[i
]]
319 Assert(terms
[i
].isNull()
320 || terms
[i
].getType().isComparableTo(ftypes
[i
]))
321 << "Incompatible type " << f
<< ", " << terms
[i
].getType()
322 << ", " << ftypes
[i
] << std::endl
;
324 if (ie
->addInstantiation(f
, terms
))
326 Trace("inst-alg-rd") << "Success!" << std::endl
;
327 ++(d_quantEngine
->d_statistics
.d_instantiations_guess
);
334 if (d_quantEngine
->inConflict())
336 // could be conflicting for an internal reason (such as term
337 // indices computed in above calls)
345 // TODO : term enumerator instantiation?
349 } /* CVC4::theory::quantifiers namespace */
350 } /* CVC4::theory namespace */
351 } /* CVC4 namespace */