8eb0ef6866a57bc6c69a8e84b3d48db2cd021057
1 /********************* */
2 /*! \file fun_def_evaluator.cpp
4 ** Top contributors (to current version):
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2019 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 techniques for evaluating terms with recursively
16 #include "theory/quantifiers/fun_def_evaluator.h"
18 #include "options/quantifiers_options.h"
19 #include "theory/quantifiers/quantifiers_attributes.h"
20 #include "theory/rewriter.h"
22 using namespace CVC4::kind
;
26 namespace quantifiers
{
28 FunDefEvaluator::FunDefEvaluator() {}
30 void FunDefEvaluator::assertDefinition(Node q
)
32 Trace("fd-eval") << "FunDefEvaluator: assertDefinition " << q
<< std::endl
;
33 Node h
= QuantAttributes::getFunDefHead(q
);
36 // not a function definition
39 // h possibly with zero arguments?
40 Node f
= h
.hasOperator() ? h
.getOperator() : h
;
41 Assert(d_funDefMap
.find(f
) == d_funDefMap
.end())
42 << "FunDefEvaluator::assertDefinition: function already defined";
43 FunDefInfo
& fdi
= d_funDefMap
[f
];
44 fdi
.d_body
= QuantAttributes::getFunDefBody(q
);
45 Assert(!fdi
.d_body
.isNull());
46 fdi
.d_args
.insert(fdi
.d_args
.end(), q
[0].begin(), q
[0].end());
47 Trace("fd-eval") << "FunDefEvaluator: function " << f
<< " is defined with "
48 << fdi
.d_args
<< " / " << fdi
.d_body
<< std::endl
;
51 Node
FunDefEvaluator::evaluate(Node n
) const
53 // should do standard rewrite before this call
54 Assert(Rewriter::rewrite(n
) == n
);
55 Trace("fd-eval") << "FunDefEvaluator: evaluate " << n
<< std::endl
;
56 NodeManager
* nm
= NodeManager::currentNM();
57 std::unordered_map
<TNode
, unsigned, TNodeHashFunction
> funDefCount
;
58 std::unordered_map
<TNode
, unsigned, TNodeHashFunction
>::iterator itCount
;
59 std::unordered_map
<TNode
, Node
, TNodeHashFunction
> visited
;
60 std::unordered_map
<TNode
, Node
, TNodeHashFunction
>::iterator it
;
61 std::map
<Node
, FunDefInfo
>::const_iterator itf
;
62 std::vector
<TNode
> visit
;
71 it
= visited
.find(cur
);
72 Trace("fd-eval-debug") << "evaluate subterm " << cur
<< std::endl
;
74 if (it
== visited
.end())
78 Trace("fd-eval-debug") << "constant " << cur
<< std::endl
;
81 else if (cur
.getKind() == ITE
)
83 Trace("fd-eval-debug") << "ITE " << cur
<< std::endl
;
84 visited
[cur
] = Node::null();
86 visit
.push_back(cur
[0]);
90 Trace("fd-eval-debug") << "recurse " << cur
<< std::endl
;
91 visited
[cur
] = Node::null();
93 for (const Node
& cn
: cur
)
101 curEval
= it
->second
;
102 if (curEval
.isNull())
104 Trace("fd-eval-debug") << "from arguments " << cur
<< std::endl
;
106 bool childChanged
= false;
107 std::vector
<Node
> children
;
108 Kind ck
= cur
.getKind();
109 // If a parameterized node that is not APPLY_UF (which is handled below,
110 // we add it to the children vector.
111 if (ck
!= APPLY_UF
&& cur
.getMetaKind() == metakind::PARAMETERIZED
)
113 children
.push_back(cur
.getOperator());
117 // get evaluation of condition
118 it
= visited
.find(cur
[0]);
119 Assert(it
!= visited
.end());
120 Assert(!it
->second
.isNull());
121 if (!it
->second
.isConst())
123 Trace("fd-eval") << "FunDefEvaluator: couldn't reduce condition of "
124 "ITE to const, FAIL\n";
127 // pick child to evaluate depending on condition eval
128 unsigned childIdxToEval
= it
->second
.getConst
<bool>() ? 1 : 2;
129 Trace("fd-eval-debug2")
130 << "FunDefEvaluator: result of ITE condition : "
131 << it
->second
.getConst
<bool>() << "\n";
132 // the result will be the result of evaluation the child
133 visited
[cur
] = cur
[childIdxToEval
];
134 // push back self and child. The child will be evaluated first and
135 // result will be the result of evaluation child
136 visit
.push_back(cur
);
137 visit
.push_back(cur
[childIdxToEval
]);
138 Trace("fd-eval-debug2") << "FunDefEvaluator: result will be from : "
139 << cur
[childIdxToEval
] << "\n";
142 unsigned child CVC4_UNUSED
= 0;
143 for (const Node
& cn
: cur
)
145 it
= visited
.find(cn
);
146 Assert(it
!= visited
.end());
147 Assert(!it
->second
.isNull());
148 childChanged
= childChanged
|| cn
!= it
->second
;
149 children
.push_back(it
->second
);
150 Trace("fd-eval-debug2") << "argument " << child
++
151 << " eval : " << it
->second
<< std::endl
;
153 if (cur
.getKind() == APPLY_UF
)
155 // need to evaluate it
156 f
= cur
.getOperator();
157 Trace("fd-eval-debug2")
158 << "FunDefEvaluator: need to eval " << f
<< "\n";
159 itf
= d_funDefMap
.find(f
);
160 itCount
= funDefCount
.find(f
);
161 if (itCount
== funDefCount
.end())
164 itCount
= funDefCount
.find(f
);
166 if (itf
== d_funDefMap
.end()
167 || itCount
->second
> options::sygusRecFunEvalLimit())
170 << "FunDefEvaluator: "
171 << (itf
== d_funDefMap
.end() ? "no definition for "
172 : "too many evals for ")
173 << f
<< ", FAIL" << std::endl
;
177 // get the function definition
178 Node sbody
= itf
->second
.d_body
;
179 Trace("fd-eval-debug2")
180 << "FunDefEvaluator: definition: " << sbody
<< "\n";
181 const std::vector
<Node
>& args
= itf
->second
.d_args
;
184 // invoke it on arguments
185 sbody
= sbody
.substitute(
186 args
.begin(), args
.end(), children
.begin(), children
.end());
188 sbody
= Rewriter::rewrite(sbody
);
189 if (Trace
.isOn("fd-eval-debug2"))
191 Trace("fd-eval-debug2")
192 << "FunDefEvaluator: evaluation with args:\n";
193 for (const Node
& child
: children
)
195 Trace("fd-eval-debug2") << "..." << child
<< "\n";
197 Trace("fd-eval-debug2")
198 << "FunDefEvaluator: results in " << sbody
<< "\n";
201 // our result is the result of the body
202 visited
[cur
] = sbody
;
203 // If its not constant, we push back self and the substituted body.
204 // Thus, we evaluate the body first; our result will be the result of
205 // evaluating the body.
206 if (!sbody
.isConst())
208 Trace("fd-eval-debug2") << "FunDefEvaluator: will map " << cur
209 << " from body " << sbody
<< "\n";
210 visit
.push_back(cur
);
211 visit
.push_back(sbody
);
218 ret
= nm
->mkNode(cur
.getKind(), children
);
219 ret
= Rewriter::rewrite(ret
);
221 Trace("fd-eval-debug2") << "built from arguments " << ret
<< "\n";
225 else if (cur
!= curEval
&& !curEval
.isConst())
227 Trace("fd-eval-debug") << "from body " << cur
<< std::endl
;
228 Trace("fd-eval-debug") << "and eval " << curEval
<< std::endl
;
229 // we had to evaluate our body, which should have a definition now
230 it
= visited
.find(curEval
);
231 if (it
== visited
.end())
233 Trace("fd-eval-debug2") << "eval without definition\n";
234 // this is the case where curEval was not a constant but it was
235 // irreducible, for example (DT_SYGUS_EVAL e args)
236 visited
[cur
] = curEval
;
240 Trace("fd-eval-debug2")
241 << "eval with definition " << it
->second
<< "\n";
242 visited
[cur
] = it
->second
;
246 } while (!visit
.empty());
247 Trace("fd-eval") << "FunDefEvaluator: return " << visited
[n
] << ", SUCCESS\n";
248 Assert(visited
.find(n
) != visited
.end());
249 Assert(!visited
.find(n
)->second
.isNull());
253 bool FunDefEvaluator::hasDefinitions() const { return !d_funDefMap
.empty(); }
255 } // namespace quantifiers
256 } // namespace theory