1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Mathias Preiner, Aina Niemetz |
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 |
|
* Utilities used for querying about equality information. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/quantifiers/equality_query.h" |
17 |
|
|
18 |
|
#include "options/quantifiers_options.h" |
19 |
|
#include "theory/quantifiers/first_order_model.h" |
20 |
|
#include "theory/quantifiers/quantifiers_attributes.h" |
21 |
|
#include "theory/quantifiers/quantifiers_state.h" |
22 |
|
#include "theory/quantifiers/term_util.h" |
23 |
|
|
24 |
|
using namespace std; |
25 |
|
using namespace cvc5::kind; |
26 |
|
using namespace cvc5::context; |
27 |
|
|
28 |
|
namespace cvc5 { |
29 |
|
namespace theory { |
30 |
|
namespace quantifiers { |
31 |
|
|
32 |
15273 |
EqualityQuery::EqualityQuery(Env& env, QuantifiersState& qs, FirstOrderModel* m) |
33 |
|
: QuantifiersUtil(env), |
34 |
|
d_qstate(qs), |
35 |
|
d_model(m), |
36 |
|
d_eqi_counter(context()), |
37 |
15273 |
d_reset_count(0) |
38 |
|
{ |
39 |
15273 |
} |
40 |
|
|
41 |
15268 |
EqualityQuery::~EqualityQuery() {} |
42 |
|
|
43 |
34975 |
bool EqualityQuery::reset(Theory::Effort e) |
44 |
|
{ |
45 |
34975 |
d_int_rep.clear(); |
46 |
34975 |
d_reset_count++; |
47 |
34975 |
return true; |
48 |
|
} |
49 |
|
|
50 |
76584 |
Node EqualityQuery::getInternalRepresentative(Node a, Node q, size_t index) |
51 |
|
{ |
52 |
76584 |
Assert(q.isNull() || q.getKind() == FORALL); |
53 |
153168 |
Node r = d_qstate.getRepresentative(a); |
54 |
76584 |
if (options().quantifiers.finiteModelFind) |
55 |
|
{ |
56 |
66114 |
if( r.isConst() && quantifiers::TermUtil::containsUninterpretedConstant( r ) ){ |
57 |
|
//map back from values assigned by model, if any |
58 |
5445 |
if (d_model != nullptr) |
59 |
|
{ |
60 |
10890 |
Node tr = d_model->getRepSet()->getTermForRepresentative(r); |
61 |
5445 |
if (!tr.isNull()) |
62 |
|
{ |
63 |
5445 |
r = tr; |
64 |
5445 |
r = d_qstate.getRepresentative(r); |
65 |
|
}else{ |
66 |
|
if( r.getType().isSort() ){ |
67 |
|
Trace("internal-rep-warn") << "No representative for UF constant." << std::endl; |
68 |
|
//should never happen : UF constants should never escape model |
69 |
|
Assert(false); |
70 |
|
} |
71 |
|
} |
72 |
|
} |
73 |
|
} |
74 |
|
} |
75 |
153168 |
TypeNode v_tn = q.isNull() ? a.getType() : q[0][index].getType(); |
76 |
76584 |
if (options().quantifiers.quantRepMode == options::QuantRepMode::EE) |
77 |
|
{ |
78 |
|
int32_t score = getRepScore(r, q, index, v_tn); |
79 |
|
if (score >= 0) |
80 |
|
{ |
81 |
|
return r; |
82 |
|
} |
83 |
|
// if we are not a valid representative, try to select one below |
84 |
|
} |
85 |
76584 |
std::map<Node, Node>& v_int_rep = d_int_rep[v_tn]; |
86 |
76584 |
std::map<Node, Node>::const_iterator itir = v_int_rep.find(r); |
87 |
76584 |
if (itir != v_int_rep.end()) |
88 |
|
{ |
89 |
68207 |
return itir->second; |
90 |
|
} |
91 |
|
// find best selection for representative |
92 |
16754 |
Node r_best; |
93 |
16754 |
std::vector<Node> eqc; |
94 |
8377 |
d_qstate.getEquivalenceClass(r, eqc); |
95 |
16754 |
Trace("internal-rep-select") |
96 |
8377 |
<< "Choose representative for equivalence class : " << eqc |
97 |
8377 |
<< ", type = " << v_tn << std::endl; |
98 |
8377 |
int32_t r_best_score = -1; |
99 |
65106 |
for (const Node& n : eqc) |
100 |
|
{ |
101 |
56729 |
int32_t score = getRepScore(n, q, index, v_tn); |
102 |
56729 |
if (score != -2) |
103 |
|
{ |
104 |
104966 |
if (r_best.isNull() |
105 |
52483 |
|| (score >= 0 && (r_best_score < 0 || score < r_best_score))) |
106 |
|
{ |
107 |
8601 |
r_best = n; |
108 |
8601 |
r_best_score = score; |
109 |
|
} |
110 |
|
} |
111 |
|
} |
112 |
8377 |
if (r_best.isNull()) |
113 |
|
{ |
114 |
|
Trace("internal-rep-warn") |
115 |
|
<< "No valid choice for representative in eqc class " << eqc |
116 |
|
<< std::endl; |
117 |
|
return Node::null(); |
118 |
|
} |
119 |
|
// now, make sure that no other member of the class is an instance |
120 |
16754 |
std::unordered_map<TNode, Node> cache; |
121 |
8377 |
r_best = getInstance(r_best, eqc, cache); |
122 |
|
// store that this representative was chosen at this point |
123 |
8377 |
if (d_rep_score.find(r_best) == d_rep_score.end()) |
124 |
|
{ |
125 |
1766 |
d_rep_score[r_best] = d_reset_count; |
126 |
|
} |
127 |
16754 |
Trace("internal-rep-select") |
128 |
8377 |
<< "...Choose " << r_best << " with score " << r_best_score |
129 |
8377 |
<< " and type " << r_best.getType() << std::endl; |
130 |
8377 |
Assert(r_best.getType().isSubtypeOf(v_tn)); |
131 |
8377 |
v_int_rep[r] = r_best; |
132 |
8377 |
if (Trace.isOn("internal-rep-debug")) |
133 |
|
{ |
134 |
|
if (r_best != a) |
135 |
|
{ |
136 |
|
Trace("internal-rep-debug") |
137 |
|
<< "rep( " << a << " ) = " << r << ", " << std::endl; |
138 |
|
Trace("internal-rep-debug") |
139 |
|
<< "int_rep( " << a << " ) = " << r_best << ", " << std::endl; |
140 |
|
} |
141 |
|
} |
142 |
8377 |
return r_best; |
143 |
|
} |
144 |
|
|
145 |
|
//helper functions |
146 |
|
|
147 |
12785 |
Node EqualityQuery::getInstance(Node n, |
148 |
|
const std::vector<Node>& eqc, |
149 |
|
std::unordered_map<TNode, Node>& cache) |
150 |
|
{ |
151 |
12785 |
if(cache.find(n) != cache.end()) { |
152 |
499 |
return cache[n]; |
153 |
|
} |
154 |
16682 |
for( size_t i=0; i<n.getNumChildren(); i++ ){ |
155 |
8804 |
Node nn = getInstance( n[i], eqc, cache ); |
156 |
4408 |
if( !nn.isNull() ){ |
157 |
12 |
return cache[n] = nn; |
158 |
|
} |
159 |
|
} |
160 |
12274 |
if( std::find( eqc.begin(), eqc.end(), n )!=eqc.end() ){ |
161 |
8377 |
return cache[n] = n; |
162 |
|
}else{ |
163 |
3897 |
return cache[n] = Node::null(); |
164 |
|
} |
165 |
|
} |
166 |
|
|
167 |
|
//-2 : invalid, -1 : undesired, otherwise : smaller the score, the better |
168 |
56729 |
int32_t EqualityQuery::getRepScore(Node n, Node q, size_t index, TypeNode v_tn) |
169 |
|
{ |
170 |
56729 |
if (options().quantifiers.cegqi && quantifiers::TermUtil::hasInstConstAttr(n)) |
171 |
|
{ // reject |
172 |
|
return -2; |
173 |
|
} |
174 |
56729 |
else if (!n.getType().isSubtypeOf(v_tn)) |
175 |
|
{ // reject if incorrect type |
176 |
4246 |
return -2; |
177 |
|
} |
178 |
52483 |
else if (options().quantifiers.instMaxLevel != -1) |
179 |
|
{ |
180 |
|
//score prefer lowest instantiation level |
181 |
|
if( n.hasAttribute(InstLevelAttribute()) ){ |
182 |
|
return n.getAttribute(InstLevelAttribute()); |
183 |
|
} |
184 |
|
return options().quantifiers.instLevelInputOnly ? -1 : 0; |
185 |
|
} |
186 |
52483 |
else if (options().quantifiers.quantRepMode == options::QuantRepMode::FIRST) |
187 |
|
{ |
188 |
|
// score prefers earliest use of this term as a representative |
189 |
52483 |
return d_rep_score.find(n) == d_rep_score.end() ? -1 : d_rep_score[n]; |
190 |
|
} |
191 |
|
Assert(options().quantifiers.quantRepMode == options::QuantRepMode::DEPTH); |
192 |
|
return quantifiers::TermUtil::getTermDepth(n); |
193 |
|
} |
194 |
|
|
195 |
|
} // namespace quantifiers |
196 |
|
} // namespace theory |
197 |
31137 |
} // namespace cvc5 |