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
,
38 QuantifiersRegistry
& qr
,
40 : QuantifiersModule(qs
, qim
, qr
, qe
), d_rd(rd
), d_fullSaturateLimit(-1)
43 void InstStrategyEnum::presolve()
45 d_fullSaturateLimit
= options::fullSaturateLimit();
47 bool InstStrategyEnum::needsCheck(Theory::Effort e
)
49 if (d_fullSaturateLimit
== 0)
53 if (options::fullSaturateInterleave())
55 if (d_quantEngine
->getInstWhenNeedsCheck(e
))
60 if (options::fullSaturateQuant())
62 if (e
>= Theory::EFFORT_LAST_CALL
)
70 void InstStrategyEnum::reset_round(Theory::Effort e
) {}
71 void InstStrategyEnum::check(Theory::Effort e
, QEffort quant_e
)
74 bool fullEffort
= false;
75 if (d_fullSaturateLimit
!= 0)
77 if (options::fullSaturateInterleave())
79 // we only add when interleaved with other strategies
80 doCheck
= quant_e
== QEFFORT_STANDARD
&& d_qim
.hasPendingLemma();
82 if (options::fullSaturateQuant() && !doCheck
)
84 if (!d_qstate
.getValuation().needCheck())
86 doCheck
= quant_e
== QEFFORT_LAST_CALL
;
95 Assert(!d_qstate
.isInConflict());
97 if (Trace
.isOn("fs-engine"))
99 clSet
= double(clock()) / double(CLOCKS_PER_SEC
);
100 Trace("fs-engine") << "---Full Saturation Round, effort = " << e
<< "---"
103 unsigned rstart
= options::fullSaturateQuantRd() ? 0 : 1;
104 unsigned rend
= fullEffort
? 1 : rstart
;
105 unsigned addedLemmas
= 0;
106 // First try in relevant domain of all quantified formulas, if no
107 // instantiations exist, try arbitrary ground terms.
108 // Notice that this stratification of effort levels makes it so that some
109 // quantified formulas may not be instantiated (if they have no instances
110 // at effort level r=0 but another quantified formula does). We prefer
111 // this stratification since effort level r=1 may be highly expensive in the
112 // case where we have a quantified formula with many entailed instances.
113 FirstOrderModel
* fm
= d_quantEngine
->getModel();
114 unsigned nquant
= fm
->getNumAssertedQuantifiers();
115 std::map
<Node
, bool> alreadyProc
;
116 for (unsigned r
= rstart
; r
<= rend
; r
++)
122 Trace("inst-alg") << "-> Relevant domain instantiate..." << std::endl
;
123 Trace("inst-alg-debug") << "Compute relevant domain..." << std::endl
;
125 Trace("inst-alg-debug") << "...finished" << std::endl
;
129 Trace("inst-alg") << "-> Ground term instantiate..." << std::endl
;
131 for (unsigned i
= 0; i
< nquant
; i
++)
133 Node q
= fm
->getAssertedQuantifier(i
, true);
134 bool doProcess
= d_qreg
.hasOwnership(q
, this)
135 && fm
->isQuantifierActive(q
)
136 && alreadyProc
.find(q
) == alreadyProc
.end();
139 if (process(q
, fullEffort
, r
== 0))
141 // don't need to mark this if we are not stratifying
142 if (!options::fullSaturateStratify())
144 alreadyProc
[q
] = true;
149 if (d_qstate
.isInConflict())
155 if (d_qstate
.isInConflict()
156 || (addedLemmas
> 0 && options::fullSaturateStratify()))
158 // we break if we are in conflict, or if we added any lemma at this
159 // effort level and we stratify effort levels.
164 if (Trace
.isOn("fs-engine"))
166 Trace("fs-engine") << "Added lemmas = " << addedLemmas
<< std::endl
;
167 double clSet2
= double(clock()) / double(CLOCKS_PER_SEC
);
168 Trace("fs-engine") << "Finished full saturation engine, time = "
169 << (clSet2
- clSet
) << std::endl
;
171 if (d_fullSaturateLimit
> 0)
173 d_fullSaturateLimit
--;
177 bool InstStrategyEnum::process(Node f
, bool fullEffort
, bool isRd
)
179 // ignore if constant true (rare case of non-standard quantifier whose body is
180 // rewritten to true)
181 if (f
[1].isConst() && f
[1].getConst
<bool>())
185 unsigned final_max_i
= 0;
186 std::vector
<unsigned> maxs
;
187 std::vector
<bool> max_zero
;
188 bool has_zero
= false;
189 std::map
<TypeNode
, std::vector
<Node
> > term_db_list
;
190 std::vector
<TypeNode
> ftypes
;
191 TermDb
* tdb
= d_quantEngine
->getTermDatabase();
192 QuantifiersState
& qs
= d_quantEngine
->getState();
193 // iterate over substitutions for variables
194 for (unsigned i
= 0; i
< f
[0].getNumChildren(); i
++)
196 TypeNode tn
= f
[0][i
].getType();
197 ftypes
.push_back(tn
);
201 ts
= d_rd
->getRDomain(f
, i
)->d_terms
.size();
205 ts
= tdb
->getNumTypeGroundTerms(tn
);
206 std::map
<TypeNode
, std::vector
<Node
> >::iterator ittd
=
207 term_db_list
.find(tn
);
208 if (ittd
== term_db_list
.end())
210 std::map
<Node
, Node
> reps_found
;
211 for (unsigned j
= 0; j
< ts
; j
++)
213 Node gt
= tdb
->getTypeGroundTerm(ftypes
[i
], j
);
214 if (!options::cegqi() || !quantifiers::TermUtil::hasInstConstAttr(gt
))
216 Node rep
= qs
.getRepresentative(gt
);
217 if (reps_found
.find(rep
) == reps_found
.end())
219 reps_found
[rep
] = gt
;
220 term_db_list
[tn
].push_back(gt
);
224 ts
= term_db_list
[tn
].size();
228 ts
= ittd
->second
.size();
231 // consider a default value if at full effort
232 max_zero
.push_back(fullEffort
&& ts
== 0);
233 ts
= (fullEffort
&& ts
== 0) ? 1 : ts
;
234 Trace("inst-alg-rd") << "Variable " << i
<< " has " << ts
235 << " in relevant domain." << std::endl
;
242 if (ts
> final_max_i
)
249 Trace("inst-alg-rd") << "Will do " << final_max_i
250 << " stages of instantiation." << std::endl
;
253 Instantiate
* ie
= d_quantEngine
->getInstantiate();
254 while (max_i
<= final_max_i
)
256 Trace("inst-alg-rd") << "Try stage " << max_i
<< "..." << std::endl
;
257 std::vector
<unsigned> childIndex
;
261 while (index
>= 0 && index
< (int)f
[0].getNumChildren())
263 if (index
== static_cast<int>(childIndex
.size()))
265 childIndex
.push_back(-1);
269 Assert(index
== static_cast<int>(childIndex
.size()) - 1);
270 unsigned nv
= childIndex
[index
] + 1;
271 if (nv
< maxs
[index
] && nv
<= max_i
)
273 childIndex
[index
] = nv
;
278 childIndex
.pop_back();
283 success
= index
>= 0;
286 if (Trace
.isOn("inst-alg-rd"))
288 Trace("inst-alg-rd") << "Try instantiation { ";
289 for (unsigned i
: childIndex
)
291 Trace("inst-alg-rd") << i
<< " ";
293 Trace("inst-alg-rd") << "}" << std::endl
;
296 std::vector
<Node
> terms
;
297 for (unsigned i
= 0, nchild
= f
[0].getNumChildren(); i
< nchild
; i
++)
301 // no terms available, will report incomplete instantiation
302 terms
.push_back(Node::null());
303 Trace("inst-alg-rd") << " null" << std::endl
;
307 terms
.push_back(d_rd
->getRDomain(f
, i
)->d_terms
[childIndex
[i
]]);
309 << " (rd) " << d_rd
->getRDomain(f
, i
)->d_terms
[childIndex
[i
]]
314 Assert(childIndex
[i
] < term_db_list
[ftypes
[i
]].size());
315 terms
.push_back(term_db_list
[ftypes
[i
]][childIndex
[i
]]);
317 << " " << term_db_list
[ftypes
[i
]][childIndex
[i
]]
320 Assert(terms
[i
].isNull()
321 || terms
[i
].getType().isComparableTo(ftypes
[i
]))
322 << "Incompatible type " << f
<< ", " << terms
[i
].getType()
323 << ", " << ftypes
[i
] << std::endl
;
325 if (ie
->addInstantiation(f
, terms
))
327 Trace("inst-alg-rd") << "Success!" << std::endl
;
328 ++(d_quantEngine
->d_statistics
.d_instantiations_guess
);
335 if (d_qstate
.isInConflict())
337 // could be conflicting for an internal reason (such as term
338 // indices computed in above calls)
346 // TODO : term enumerator instantiation?
350 } /* CVC4::theory::quantifiers namespace */
351 } /* CVC4::theory namespace */
352 } /* CVC4 namespace */