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-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.\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_tuple_enumerator.h"
22 #include "theory/quantifiers/term_util.h"
23 #include "theory/quantifiers_engine.h"
25 using namespace CVC4::kind
;
26 using namespace CVC4::context
;
30 namespace quantifiers
{
32 InstStrategyEnum::InstStrategyEnum(QuantifiersEngine
* qe
,
34 QuantifiersInferenceManager
& qim
,
35 QuantifiersRegistry
& qr
,
37 : QuantifiersModule(qs
, qim
, qr
, qe
), d_rd(rd
), d_fullSaturateLimit(-1)
40 void InstStrategyEnum::presolve()
42 d_fullSaturateLimit
= options::fullSaturateLimit();
44 bool InstStrategyEnum::needsCheck(Theory::Effort e
)
46 if (d_fullSaturateLimit
== 0)
50 if (options::fullSaturateInterleave())
52 // if interleaved, we run at the same time as E-matching
53 if (d_qstate
.getInstWhenNeedsCheck(e
))
58 if (options::fullSaturateQuant())
60 if (e
>= Theory::EFFORT_LAST_CALL
)
68 void InstStrategyEnum::reset_round(Theory::Effort e
) {}
69 void InstStrategyEnum::check(Theory::Effort e
, QEffort quant_e
)
72 bool fullEffort
= false;
73 if (d_fullSaturateLimit
!= 0)
75 if (options::fullSaturateInterleave())
77 // we only add when interleaved with other strategies
78 doCheck
= quant_e
== QEFFORT_STANDARD
&& d_qim
.hasPendingLemma();
80 if (options::fullSaturateQuant() && !doCheck
)
82 if (!d_qstate
.getValuation().needCheck())
84 doCheck
= quant_e
== QEFFORT_LAST_CALL
;
93 Assert(!d_qstate
.isInConflict());
95 if (Trace
.isOn("fs-engine"))
97 clSet
= double(clock()) / double(CLOCKS_PER_SEC
);
98 Trace("fs-engine") << "---Full Saturation Round, effort = " << e
<< "---"
101 unsigned rstart
= options::fullSaturateQuantRd() ? 0 : 1;
102 unsigned rend
= fullEffort
? 1 : rstart
;
103 unsigned addedLemmas
= 0;
104 // First try in relevant domain of all quantified formulas, if no
105 // instantiations exist, try arbitrary ground terms.
106 // Notice that this stratification of effort levels makes it so that some
107 // quantified formulas may not be instantiated (if they have no instances
108 // at effort level r=0 but another quantified formula does). We prefer
109 // this stratification since effort level r=1 may be highly expensive in the
110 // case where we have a quantified formula with many entailed instances.
111 FirstOrderModel
* fm
= d_quantEngine
->getModel();
112 unsigned nquant
= fm
->getNumAssertedQuantifiers();
113 std::map
<Node
, bool> alreadyProc
;
114 for (unsigned r
= rstart
; r
<= rend
; r
++)
120 Trace("inst-alg") << "-> Relevant domain instantiate..." << std::endl
;
121 Trace("inst-alg-debug") << "Compute relevant domain..." << std::endl
;
123 Trace("inst-alg-debug") << "...finished" << std::endl
;
127 Trace("inst-alg") << "-> Ground term instantiate..." << std::endl
;
129 for (unsigned i
= 0; i
< nquant
; i
++)
131 Node q
= fm
->getAssertedQuantifier(i
, true);
132 bool doProcess
= d_qreg
.hasOwnership(q
, this)
133 && fm
->isQuantifierActive(q
)
134 && alreadyProc
.find(q
) == alreadyProc
.end();
137 if (process(q
, fullEffort
, r
== 0))
139 // don't need to mark this if we are not stratifying
140 if (!options::fullSaturateStratify())
142 alreadyProc
[q
] = true;
147 if (d_qstate
.isInConflict())
153 if (d_qstate
.isInConflict()
154 || (addedLemmas
> 0 && options::fullSaturateStratify()))
156 // we break if we are in conflict, or if we added any lemma at this
157 // effort level and we stratify effort levels.
162 if (Trace
.isOn("fs-engine"))
164 Trace("fs-engine") << "Added lemmas = " << addedLemmas
<< std::endl
;
165 double clSet2
= double(clock()) / double(CLOCKS_PER_SEC
);
166 Trace("fs-engine") << "Finished full saturation engine, time = "
167 << (clSet2
- clSet
) << std::endl
;
169 if (d_fullSaturateLimit
> 0)
171 d_fullSaturateLimit
--;
175 bool InstStrategyEnum::process(Node quantifier
, bool fullEffort
, bool isRd
)
177 // ignore if constant true (rare case of non-standard quantifier whose body
178 // is rewritten to true)
179 if (quantifier
[1].isConst() && quantifier
[1].getConst
<bool>())
184 TermTupleEnumeratorContext ttec
;
185 ttec
.d_quantEngine
= d_quantEngine
;
187 ttec
.d_fullEffort
= fullEffort
;
188 ttec
.d_increaseSum
= options::fullSaturateSum();
190 std::unique_ptr
<TermTupleEnumeratorInterface
> enumerator(
191 mkTermTupleEnumerator(quantifier
, &ttec
));
192 std::vector
<Node
> terms
;
193 std::vector
<bool> failMask
;
194 Instantiate
* ie
= d_qim
.getInstantiate();
195 for (enumerator
->init(); enumerator
->hasNext();)
197 if (d_qstate
.isInConflict())
199 // could be conflicting for an internal reason
202 enumerator
->next(terms
);
205 /* if (ie->addInstantiation(quantifier, terms)) */
206 if (ie
->addInstantiationExpFail(
207 quantifier
, terms
, failMask
, InferenceId::QUANTIFIERS_INST_ENUM
))
209 Trace("inst-alg-rd") << "Success!" << std::endl
;
214 enumerator
->failureReason(failMask
);
218 // TODO : term enumerator instantiation?
221 } // namespace quantifiers
222 } // namespace theory