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 |
9853 |
EqualityQuery::EqualityQuery(QuantifiersState& qs, FirstOrderModel* m) |
33 |
|
: d_qstate(qs), |
34 |
|
d_model(m), |
35 |
|
d_eqi_counter(qs.getSatContext()), |
36 |
9853 |
d_reset_count(0) |
37 |
|
{ |
38 |
9853 |
} |
39 |
|
|
40 |
9853 |
EqualityQuery::~EqualityQuery() {} |
41 |
|
|
42 |
28528 |
bool EqualityQuery::reset(Theory::Effort e) |
43 |
|
{ |
44 |
28528 |
d_int_rep.clear(); |
45 |
28528 |
d_reset_count++; |
46 |
28528 |
return true; |
47 |
|
} |
48 |
|
|
49 |
73134 |
Node EqualityQuery::getInternalRepresentative(Node a, Node q, size_t index) |
50 |
|
{ |
51 |
73134 |
Assert(q.isNull() || q.getKind() == FORALL); |
52 |
146268 |
Node r = d_qstate.getRepresentative(a); |
53 |
73134 |
if( options::finiteModelFind() ){ |
54 |
65773 |
if( r.isConst() && quantifiers::TermUtil::containsUninterpretedConstant( r ) ){ |
55 |
|
//map back from values assigned by model, if any |
56 |
5339 |
if (d_model != nullptr) |
57 |
|
{ |
58 |
10678 |
Node tr = d_model->getRepSet()->getTermForRepresentative(r); |
59 |
5339 |
if (!tr.isNull()) |
60 |
|
{ |
61 |
5339 |
r = tr; |
62 |
5339 |
r = d_qstate.getRepresentative(r); |
63 |
|
}else{ |
64 |
|
if( r.getType().isSort() ){ |
65 |
|
Trace("internal-rep-warn") << "No representative for UF constant." << std::endl; |
66 |
|
//should never happen : UF constants should never escape model |
67 |
|
Assert(false); |
68 |
|
} |
69 |
|
} |
70 |
|
} |
71 |
|
} |
72 |
|
} |
73 |
146268 |
TypeNode v_tn = q.isNull() ? a.getType() : q[0][index].getType(); |
74 |
73134 |
if (options::quantRepMode() == options::QuantRepMode::EE) |
75 |
|
{ |
76 |
|
int32_t score = getRepScore(r, q, index, v_tn); |
77 |
|
if (score >= 0) |
78 |
|
{ |
79 |
|
return r; |
80 |
|
} |
81 |
|
// if we are not a valid representative, try to select one below |
82 |
|
} |
83 |
73134 |
std::map<Node, Node>& v_int_rep = d_int_rep[v_tn]; |
84 |
73134 |
std::map<Node, Node>::const_iterator itir = v_int_rep.find(r); |
85 |
73134 |
if (itir != v_int_rep.end()) |
86 |
|
{ |
87 |
65443 |
return itir->second; |
88 |
|
} |
89 |
|
// find best selection for representative |
90 |
15382 |
Node r_best; |
91 |
15382 |
std::vector<Node> eqc; |
92 |
7691 |
d_qstate.getEquivalenceClass(r, eqc); |
93 |
15382 |
Trace("internal-rep-select") |
94 |
7691 |
<< "Choose representative for equivalence class : " << eqc |
95 |
7691 |
<< ", type = " << v_tn << std::endl; |
96 |
7691 |
int32_t r_best_score = -1; |
97 |
59027 |
for (const Node& n : eqc) |
98 |
|
{ |
99 |
51336 |
int32_t score = getRepScore(n, q, index, v_tn); |
100 |
51336 |
if (score != -2) |
101 |
|
{ |
102 |
93628 |
if (r_best.isNull() |
103 |
46814 |
|| (score >= 0 && (r_best_score < 0 || score < r_best_score))) |
104 |
|
{ |
105 |
7925 |
r_best = n; |
106 |
7925 |
r_best_score = score; |
107 |
|
} |
108 |
|
} |
109 |
|
} |
110 |
7691 |
if (r_best.isNull()) |
111 |
|
{ |
112 |
|
Trace("internal-rep-warn") |
113 |
|
<< "No valid choice for representative in eqc class " << eqc |
114 |
|
<< std::endl; |
115 |
|
return Node::null(); |
116 |
|
} |
117 |
|
// now, make sure that no other member of the class is an instance |
118 |
15382 |
std::unordered_map<TNode, Node> cache; |
119 |
7691 |
r_best = getInstance(r_best, eqc, cache); |
120 |
|
// store that this representative was chosen at this point |
121 |
7691 |
if (d_rep_score.find(r_best) == d_rep_score.end()) |
122 |
|
{ |
123 |
1696 |
d_rep_score[r_best] = d_reset_count; |
124 |
|
} |
125 |
15382 |
Trace("internal-rep-select") |
126 |
7691 |
<< "...Choose " << r_best << " with score " << r_best_score |
127 |
7691 |
<< " and type " << r_best.getType() << std::endl; |
128 |
7691 |
Assert(r_best.getType().isSubtypeOf(v_tn)); |
129 |
7691 |
v_int_rep[r] = r_best; |
130 |
7691 |
if (Trace.isOn("internal-rep-debug")) |
131 |
|
{ |
132 |
|
if (r_best != a) |
133 |
|
{ |
134 |
|
Trace("internal-rep-debug") |
135 |
|
<< "rep( " << a << " ) = " << r << ", " << std::endl; |
136 |
|
Trace("internal-rep-debug") |
137 |
|
<< "int_rep( " << a << " ) = " << r_best << ", " << std::endl; |
138 |
|
} |
139 |
|
} |
140 |
7691 |
return r_best; |
141 |
|
} |
142 |
|
|
143 |
|
//helper functions |
144 |
|
|
145 |
12030 |
Node EqualityQuery::getInstance(Node n, |
146 |
|
const std::vector<Node>& eqc, |
147 |
|
std::unordered_map<TNode, Node>& cache) |
148 |
|
{ |
149 |
12030 |
if(cache.find(n) != cache.end()) { |
150 |
495 |
return cache[n]; |
151 |
|
} |
152 |
15862 |
for( size_t i=0; i<n.getNumChildren(); i++ ){ |
153 |
8666 |
Node nn = getInstance( n[i], eqc, cache ); |
154 |
4339 |
if( !nn.isNull() ){ |
155 |
12 |
return cache[n] = nn; |
156 |
|
} |
157 |
|
} |
158 |
11523 |
if( std::find( eqc.begin(), eqc.end(), n )!=eqc.end() ){ |
159 |
7691 |
return cache[n] = n; |
160 |
|
}else{ |
161 |
3832 |
return cache[n] = Node::null(); |
162 |
|
} |
163 |
|
} |
164 |
|
|
165 |
|
//-2 : invalid, -1 : undesired, otherwise : smaller the score, the better |
166 |
51336 |
int32_t EqualityQuery::getRepScore(Node n, Node q, size_t index, TypeNode v_tn) |
167 |
|
{ |
168 |
51336 |
if( options::cegqi() && quantifiers::TermUtil::hasInstConstAttr(n) ){ //reject |
169 |
|
return -2; |
170 |
51336 |
}else if( !n.getType().isSubtypeOf( v_tn ) ){ //reject if incorrect type |
171 |
4522 |
return -2; |
172 |
46814 |
}else if( options::instMaxLevel()!=-1 ){ |
173 |
|
//score prefer lowest instantiation level |
174 |
|
if( n.hasAttribute(InstLevelAttribute()) ){ |
175 |
|
return n.getAttribute(InstLevelAttribute()); |
176 |
|
} |
177 |
|
return options::instLevelInputOnly() ? -1 : 0; |
178 |
|
} |
179 |
46814 |
else if (options::quantRepMode() == options::QuantRepMode::FIRST) |
180 |
|
{ |
181 |
|
// score prefers earliest use of this term as a representative |
182 |
46814 |
return d_rep_score.find(n) == d_rep_score.end() ? -1 : d_rep_score[n]; |
183 |
|
} |
184 |
|
Assert(options::quantRepMode() == options::QuantRepMode::DEPTH); |
185 |
|
return quantifiers::TermUtil::getTermDepth(n); |
186 |
|
} |
187 |
|
|
188 |
|
} // namespace quantifiers |
189 |
|
} // namespace theory |
190 |
29340 |
} // namespace cvc5 |