1 /********************* */
2 /*! \file evaluator.cpp
4 ** Top contributors (to current version):
5 ** Andres Noetzli, Andrew Reynolds
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 The Evaluator class
14 ** The Evaluator class.
17 #include "theory/evaluator.h"
19 #include "theory/bv/theory_bv_utils.h"
20 #include "theory/rewriter.h"
21 #include "theory/strings/theory_strings_utils.h"
22 #include "theory/theory.h"
23 #include "util/integer.h"
28 EvalResult::EvalResult(const EvalResult
& other
)
33 case BOOL
: d_bool
= other
.d_bool
; break;
35 new (&d_bv
) BitVector
;
39 new (&d_rat
) Rational
;
50 EvalResult
& EvalResult::operator=(const EvalResult
& other
)
57 case BOOL
: d_bool
= other
.d_bool
; break;
59 new (&d_bv
) BitVector
;
63 new (&d_rat
) Rational
;
76 EvalResult::~EvalResult()
100 Node
EvalResult::toNode() const
102 NodeManager
* nm
= NodeManager::currentNM();
105 case EvalResult::BOOL
: return nm
->mkConst(d_bool
);
106 case EvalResult::BITVECTOR
: return nm
->mkConst(d_bv
);
107 case EvalResult::RATIONAL
: return nm
->mkConst(d_rat
);
108 case EvalResult::STRING
: return nm
->mkConst(d_str
);
111 Trace("evaluator") << "Missing conversion from " << d_tag
<< " to node"
118 Node
Evaluator::eval(TNode n
,
119 const std::vector
<Node
>& args
,
120 const std::vector
<Node
>& vals
,
121 bool useRewriter
) const
123 std::unordered_map
<Node
, Node
, NodeHashFunction
> visited
;
124 return eval(n
, args
, vals
, visited
, useRewriter
);
126 Node
Evaluator::eval(
128 const std::vector
<Node
>& args
,
129 const std::vector
<Node
>& vals
,
130 const std::unordered_map
<Node
, Node
, NodeHashFunction
>& visited
,
131 bool useRewriter
) const
133 Trace("evaluator") << "Evaluating " << n
<< " under substitution " << args
134 << " " << vals
<< " with visited size = " << visited
.size()
136 std::unordered_map
<TNode
, Node
, NodeHashFunction
> evalAsNode
;
137 std::unordered_map
<TNode
, EvalResult
, TNodeHashFunction
> results
;
138 // add visited to results
139 for (const std::pair
<const Node
, Node
>& p
: visited
)
141 Trace("evaluator") << "Add " << p
.first
<< " == " << p
.second
<< std::endl
;
142 results
[p
.first
] = evalInternal(p
.second
, args
, vals
, evalAsNode
, results
, useRewriter
);
143 if (results
[p
.first
].d_tag
== EvalResult::INVALID
)
145 // could not evaluate, use the evalAsNode map
146 std::unordered_map
<TNode
, Node
, NodeHashFunction
>::iterator itn
=
147 evalAsNode
.find(p
.second
);
148 Assert(itn
!= evalAsNode
.end());
149 Node val
= itn
->second
;
152 val
= Rewriter::rewrite(val
);
154 evalAsNode
[p
.first
] = val
;
157 Trace("evaluator") << "Run eval internal..." << std::endl
;
158 Node ret
= evalInternal(n
, args
, vals
, evalAsNode
, results
, useRewriter
).toNode();
159 // if we failed to evaluate
160 if (ret
.isNull() && useRewriter
)
162 // should be stored in the evaluation-as-node map
163 std::unordered_map
<TNode
, Node
, NodeHashFunction
>::iterator itn
=
165 Assert(itn
!= evalAsNode
.end());
166 ret
= Rewriter::rewrite(itn
->second
);
168 // should be the same as substitution + rewriting, or possibly null if
169 // useRewriter is false
170 Assert((ret
.isNull() && !useRewriter
)
172 == Rewriter::rewrite(n
.substitute(
173 args
.begin(), args
.end(), vals
.begin(), vals
.end())));
177 EvalResult
Evaluator::evalInternal(
179 const std::vector
<Node
>& args
,
180 const std::vector
<Node
>& vals
,
181 std::unordered_map
<TNode
, Node
, NodeHashFunction
>& evalAsNode
,
182 std::unordered_map
<TNode
, EvalResult
, TNodeHashFunction
>& results
,
183 bool useRewriter
) const
185 std::vector
<TNode
> queue
;
186 queue
.emplace_back(n
);
187 std::unordered_map
<TNode
, EvalResult
, TNodeHashFunction
>::iterator itr
;
189 while (queue
.size() != 0)
191 TNode currNode
= queue
.back();
193 if (results
.find(currNode
) != results
.end())
199 bool doProcess
= true;
201 if (currNode
.getMetaKind() == kind::metakind::PARAMETERIZED
)
203 TNode op
= currNode
.getOperator();
204 // Certain nodes are parameterized with constant operators, including
205 // bitvector extract. These operators do not need to be evaluated.
208 itr
= results
.find(op
);
209 if (itr
== results
.end())
211 queue
.emplace_back(op
);
214 else if (itr
->second
.d_tag
== EvalResult::INVALID
)
220 for (const auto& currNodeChild
: currNode
)
222 itr
= results
.find(currNodeChild
);
223 if (itr
== results
.end())
225 queue
.emplace_back(currNodeChild
);
228 else if (itr
->second
.d_tag
== EvalResult::INVALID
)
230 // we cannot evaluate since there was an invalid child
234 Trace("evaluator") << "Evaluator: visit " << currNode
235 << ", process = " << doProcess
236 << ", evaluate = " << doEval
<< std::endl
;
242 Node currNodeVal
= currNode
;
243 // whether we need to reconstruct the current node in the case of failure
244 bool needsReconstruct
= true;
246 // The code below should either:
247 // (1) store a valid EvalResult into results[currNode], or
248 // (2) store an invalid EvalResult into results[currNode] and
249 // store the result of substitution + rewriting currNode { args -> vals }
250 // into evalAsNode[currNode].
252 // If we did not successfully evaluate all children
255 // Reconstruct the node with a combination of the children that
256 // successfully evaluated, and the children that did not.
257 Trace("evaluator") << "Evaluator: collect arguments" << std::endl
;
258 currNodeVal
= reconstruct(currNodeVal
, results
, evalAsNode
);
261 // Rewrite the result now, if we use the rewriter. We will see below
262 // if we are able to turn it into a valid EvalResult.
263 currNodeVal
= Rewriter::rewrite(currNodeVal
);
265 needsReconstruct
= false;
266 Trace("evaluator") << "Evaluator: now after substitution + rewriting: "
267 << currNodeVal
<< std::endl
;
268 if (currNodeVal
.getNumChildren() > 0)
270 // We may continue with a valid EvalResult at this point only if
271 // we have no children. We must otherwise fail here since some of
272 // our children may not have successful evaluations.
273 results
[currNode
] = EvalResult();
274 evalAsNode
[currNode
] = currNodeVal
;
277 // Otherwise, we may be able to turn the overall result into an
278 // valid EvalResult and continue. We fallthrough and continue with the
279 // block of code below.
282 if (currNode
.isVar())
284 const auto& it
= std::find(args
.begin(), args
.end(), currNode
);
285 if (it
== args
.end())
287 // variable with no substitution is itself
288 evalAsNode
[currNode
] = currNode
;
289 results
[currNode
] = EvalResult();
292 ptrdiff_t pos
= std::distance(args
.begin(), it
);
293 currNodeVal
= vals
[pos
];
294 // Don't need to reconstruct since range of substitution should already
296 needsReconstruct
= false;
298 else if (currNode
.getKind() == kind::APPLY_UF
)
300 Trace("evaluator") << "Evaluate " << currNode
<< std::endl
;
301 TNode op
= currNode
.getOperator();
302 Assert(evalAsNode
.find(op
) != evalAsNode
.end());
303 // no function can be a valid EvalResult
305 Trace("evaluator") << "Operator evaluated to " << op
<< std::endl
;
306 if (op
.getKind() != kind::LAMBDA
)
308 // this node is not evaluatable due to operator, must add to
310 results
[currNode
] = EvalResult();
311 evalAsNode
[currNode
] = reconstruct(currNode
, results
, evalAsNode
);
314 // Create a copy of the current substitutions
315 std::vector
<Node
> lambdaArgs(args
);
316 std::vector
<Node
> lambdaVals(vals
);
318 // Add the values for the arguments of the lambda as substitutions at
319 // the beginning of the vector to shadow variables from outer scopes
320 // with the same name
321 for (const auto& lambdaArg
: op
[0])
323 lambdaArgs
.insert(lambdaArgs
.begin(), lambdaArg
);
326 for (const auto& lambdaVal
: currNode
)
328 lambdaVals
.insert(lambdaVals
.begin(), results
[lambdaVal
].toNode());
331 // Lambdas are evaluated in a recursive fashion because each evaluation
332 // requires different substitutions. We use a fresh cache since the
333 // evaluation of op[1] is under a new substitution and thus should not
334 // be cached. We could alternatively copy evalAsNode to evalAsNodeC but
335 // favor avoiding this copy for performance reasons.
336 std::unordered_map
<TNode
, Node
, NodeHashFunction
> evalAsNodeC
;
337 std::unordered_map
<TNode
, EvalResult
, TNodeHashFunction
> resultsC
;
339 evalInternal(op
[1], lambdaArgs
, lambdaVals
, evalAsNodeC
, resultsC
, useRewriter
);
340 Trace("evaluator") << "Evaluated via arguments to "
341 << results
[currNode
].d_tag
<< std::endl
;
342 if (results
[currNode
].d_tag
== EvalResult::INVALID
)
344 // evaluation was invalid, we take the node of op[1] as the result
345 evalAsNode
[currNode
] = evalAsNodeC
[op
[1]];
347 << "Take node evaluation: " << evalAsNodeC
[op
[1]] << std::endl
;
352 switch (currNodeVal
.getKind())
354 case kind::CONST_BOOLEAN
:
355 results
[currNode
] = EvalResult(currNodeVal
.getConst
<bool>());
360 results
[currNode
] = EvalResult(!(results
[currNode
[0]].d_bool
));
366 bool res
= results
[currNode
[0]].d_bool
;
367 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
369 res
= res
&& results
[currNode
[i
]].d_bool
;
371 results
[currNode
] = EvalResult(res
);
377 bool res
= results
[currNode
[0]].d_bool
;
378 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
380 res
= res
|| results
[currNode
[i
]].d_bool
;
382 results
[currNode
] = EvalResult(res
);
386 case kind::CONST_RATIONAL
:
388 const Rational
& r
= currNodeVal
.getConst
<Rational
>();
389 results
[currNode
] = EvalResult(r
);
395 Rational res
= results
[currNode
[0]].d_rat
;
396 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
398 res
= res
+ results
[currNode
[i
]].d_rat
;
400 results
[currNode
] = EvalResult(res
);
406 const Rational
& x
= results
[currNode
[0]].d_rat
;
407 const Rational
& y
= results
[currNode
[1]].d_rat
;
408 results
[currNode
] = EvalResult(x
- y
);
414 const Rational
& x
= results
[currNode
[0]].d_rat
;
415 results
[currNode
] = EvalResult(-x
);
419 case kind::NONLINEAR_MULT
:
421 Rational res
= results
[currNode
[0]].d_rat
;
422 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
424 res
= res
* results
[currNode
[i
]].d_rat
;
426 results
[currNode
] = EvalResult(res
);
432 const Rational
& x
= results
[currNode
[0]].d_rat
;
433 const Rational
& y
= results
[currNode
[1]].d_rat
;
434 results
[currNode
] = EvalResult(x
>= y
);
439 const Rational
& x
= results
[currNode
[0]].d_rat
;
440 const Rational
& y
= results
[currNode
[1]].d_rat
;
441 results
[currNode
] = EvalResult(x
<= y
);
446 const Rational
& x
= results
[currNode
[0]].d_rat
;
447 const Rational
& y
= results
[currNode
[1]].d_rat
;
448 results
[currNode
] = EvalResult(x
> y
);
453 const Rational
& x
= results
[currNode
[0]].d_rat
;
454 const Rational
& y
= results
[currNode
[1]].d_rat
;
455 results
[currNode
] = EvalResult(x
< y
);
460 const Rational
& x
= results
[currNode
[0]].d_rat
;
461 results
[currNode
] = EvalResult(x
.abs());
464 case kind::CONST_STRING
:
465 results
[currNode
] = EvalResult(currNodeVal
.getConst
<String
>());
468 case kind::STRING_CONCAT
:
470 String res
= results
[currNode
[0]].d_str
;
471 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
473 res
= res
.concat(results
[currNode
[i
]].d_str
);
475 results
[currNode
] = EvalResult(res
);
479 case kind::STRING_LENGTH
:
481 const String
& s
= results
[currNode
[0]].d_str
;
482 results
[currNode
] = EvalResult(Rational(s
.size()));
486 case kind::STRING_SUBSTR
:
488 const String
& s
= results
[currNode
[0]].d_str
;
489 Integer
s_len(s
.size());
490 Integer i
= results
[currNode
[1]].d_rat
.getNumerator();
491 Integer j
= results
[currNode
[2]].d_rat
.getNumerator();
493 if (i
.strictlyNegative() || j
.strictlyNegative() || i
>= s_len
)
495 results
[currNode
] = EvalResult(String(""));
497 else if (i
+ j
> s_len
)
500 EvalResult(s
.suffix((s_len
- i
).toUnsignedInt()));
505 EvalResult(s
.substr(i
.toUnsignedInt(), j
.toUnsignedInt()));
510 case kind::STRING_CHARAT
:
512 const String
& s
= results
[currNode
[0]].d_str
;
513 Integer
s_len(s
.size());
514 Integer i
= results
[currNode
[1]].d_rat
.getNumerator();
515 if (i
.strictlyNegative() || i
>= s_len
)
517 results
[currNode
] = EvalResult(String(""));
521 results
[currNode
] = EvalResult(s
.substr(i
.toUnsignedInt(), 1));
526 case kind::STRING_STRCTN
:
528 const String
& s
= results
[currNode
[0]].d_str
;
529 const String
& t
= results
[currNode
[1]].d_str
;
530 results
[currNode
] = EvalResult(s
.find(t
) != std::string::npos
);
534 case kind::STRING_STRIDOF
:
536 const String
& s
= results
[currNode
[0]].d_str
;
537 Integer
s_len(s
.size());
538 const String
& x
= results
[currNode
[1]].d_str
;
539 Integer i
= results
[currNode
[2]].d_rat
.getNumerator();
541 if (i
.strictlyNegative())
543 results
[currNode
] = EvalResult(Rational(-1));
547 size_t r
= s
.find(x
, i
.toUnsignedInt());
548 if (r
== std::string::npos
)
550 results
[currNode
] = EvalResult(Rational(-1));
554 results
[currNode
] = EvalResult(Rational(r
));
560 case kind::STRING_STRREPL
:
562 const String
& s
= results
[currNode
[0]].d_str
;
563 const String
& x
= results
[currNode
[1]].d_str
;
564 const String
& y
= results
[currNode
[2]].d_str
;
565 results
[currNode
] = EvalResult(s
.replace(x
, y
));
569 case kind::STRING_PREFIX
:
571 const String
& t
= results
[currNode
[0]].d_str
;
572 const String
& s
= results
[currNode
[1]].d_str
;
573 if (s
.size() < t
.size())
575 results
[currNode
] = EvalResult(false);
579 results
[currNode
] = EvalResult(s
.prefix(t
.size()) == t
);
584 case kind::STRING_SUFFIX
:
586 const String
& t
= results
[currNode
[0]].d_str
;
587 const String
& s
= results
[currNode
[1]].d_str
;
588 if (s
.size() < t
.size())
590 results
[currNode
] = EvalResult(false);
594 results
[currNode
] = EvalResult(s
.suffix(t
.size()) == t
);
599 case kind::STRING_ITOS
:
601 Integer i
= results
[currNode
[0]].d_rat
.getNumerator();
602 if (i
.strictlyNegative())
604 results
[currNode
] = EvalResult(String(""));
608 results
[currNode
] = EvalResult(String(i
.toString()));
613 case kind::STRING_STOI
:
615 const String
& s
= results
[currNode
[0]].d_str
;
618 results
[currNode
] = EvalResult(Rational(s
.toNumber()));
622 results
[currNode
] = EvalResult(Rational(-1));
627 case kind::STRING_FROM_CODE
:
629 Integer i
= results
[currNode
[0]].d_rat
.getNumerator();
630 if (i
>= 0 && i
< strings::utils::getAlphabetCardinality())
632 std::vector
<unsigned> svec
= {i
.toUnsignedInt()};
633 results
[currNode
] = EvalResult(String(svec
));
637 results
[currNode
] = EvalResult(String(""));
642 case kind::STRING_TO_CODE
:
644 const String
& s
= results
[currNode
[0]].d_str
;
647 results
[currNode
] = EvalResult(Rational(s
.getVec()[0]));
651 results
[currNode
] = EvalResult(Rational(-1));
656 case kind::CONST_BITVECTOR
:
657 results
[currNode
] = EvalResult(currNodeVal
.getConst
<BitVector
>());
660 case kind::BITVECTOR_NOT
:
661 results
[currNode
] = EvalResult(~results
[currNode
[0]].d_bv
);
664 case kind::BITVECTOR_NEG
:
665 results
[currNode
] = EvalResult(-results
[currNode
[0]].d_bv
);
668 case kind::BITVECTOR_EXTRACT
:
670 unsigned lo
= bv::utils::getExtractLow(currNodeVal
);
671 unsigned hi
= bv::utils::getExtractHigh(currNodeVal
);
673 EvalResult(results
[currNode
[0]].d_bv
.extract(hi
, lo
));
677 case kind::BITVECTOR_CONCAT
:
679 BitVector res
= results
[currNode
[0]].d_bv
;
680 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
682 res
= res
.concat(results
[currNode
[i
]].d_bv
);
684 results
[currNode
] = EvalResult(res
);
688 case kind::BITVECTOR_PLUS
:
690 BitVector res
= results
[currNode
[0]].d_bv
;
691 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
693 res
= res
+ results
[currNode
[i
]].d_bv
;
695 results
[currNode
] = EvalResult(res
);
699 case kind::BITVECTOR_MULT
:
701 BitVector res
= results
[currNode
[0]].d_bv
;
702 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
704 res
= res
* results
[currNode
[i
]].d_bv
;
706 results
[currNode
] = EvalResult(res
);
709 case kind::BITVECTOR_AND
:
711 BitVector res
= results
[currNode
[0]].d_bv
;
712 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
714 res
= res
& results
[currNode
[i
]].d_bv
;
716 results
[currNode
] = EvalResult(res
);
720 case kind::BITVECTOR_OR
:
722 BitVector res
= results
[currNode
[0]].d_bv
;
723 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
725 res
= res
| results
[currNode
[i
]].d_bv
;
727 results
[currNode
] = EvalResult(res
);
731 case kind::BITVECTOR_XOR
:
733 BitVector res
= results
[currNode
[0]].d_bv
;
734 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
736 res
= res
^ results
[currNode
[i
]].d_bv
;
738 results
[currNode
] = EvalResult(res
);
741 case kind::BITVECTOR_UDIV
:
742 case kind::BITVECTOR_UDIV_TOTAL
:
744 if (currNodeVal
.getKind() == kind::BITVECTOR_UDIV_TOTAL
745 || results
[currNode
[1]].d_bv
.getValue() != 0)
747 BitVector res
= results
[currNode
[0]].d_bv
;
748 res
= res
.unsignedDivTotal(results
[currNode
[1]].d_bv
);
749 results
[currNode
] = EvalResult(res
);
753 results
[currNode
] = EvalResult();
754 evalAsNode
[currNode
] =
755 needsReconstruct
? reconstruct(currNode
, results
, evalAsNode
)
760 case kind::BITVECTOR_UREM
:
761 case kind::BITVECTOR_UREM_TOTAL
:
763 if (currNodeVal
.getKind() == kind::BITVECTOR_UREM_TOTAL
764 || results
[currNode
[1]].d_bv
.getValue() != 0)
766 BitVector res
= results
[currNode
[0]].d_bv
;
767 res
= res
.unsignedRemTotal(results
[currNode
[1]].d_bv
);
768 results
[currNode
] = EvalResult(res
);
772 results
[currNode
] = EvalResult();
773 evalAsNode
[currNode
] =
774 needsReconstruct
? reconstruct(currNode
, results
, evalAsNode
)
782 EvalResult lhs
= results
[currNode
[0]];
783 EvalResult rhs
= results
[currNode
[1]];
787 case EvalResult::BOOL
:
789 results
[currNode
] = EvalResult(lhs
.d_bool
== rhs
.d_bool
);
793 case EvalResult::BITVECTOR
:
795 results
[currNode
] = EvalResult(lhs
.d_bv
== rhs
.d_bv
);
799 case EvalResult::RATIONAL
:
801 results
[currNode
] = EvalResult(lhs
.d_rat
== rhs
.d_rat
);
805 case EvalResult::STRING
:
807 results
[currNode
] = EvalResult(lhs
.d_str
== rhs
.d_str
);
813 Trace("evaluator") << "Theory " << Theory::theoryOf(currNode
[0])
814 << " not supported" << std::endl
;
815 results
[currNode
] = EvalResult();
816 evalAsNode
[currNode
] =
817 needsReconstruct
? reconstruct(currNode
, results
, evalAsNode
)
828 if (results
[currNode
[0]].d_bool
)
830 results
[currNode
] = results
[currNode
[1]];
834 results
[currNode
] = results
[currNode
[2]];
841 Trace("evaluator") << "Kind " << currNodeVal
.getKind()
842 << " not supported" << std::endl
;
843 results
[currNode
] = EvalResult();
844 evalAsNode
[currNode
] =
845 needsReconstruct
? reconstruct(currNode
, results
, evalAsNode
)
855 Node
Evaluator::reconstruct(
857 std::unordered_map
<TNode
, EvalResult
, TNodeHashFunction
>& eresults
,
858 std::unordered_map
<TNode
, Node
, NodeHashFunction
>& evalAsNode
) const
860 if (n
.getNumChildren() == 0)
864 Trace("evaluator") << "Evaluator: reconstruct " << n
<< std::endl
;
865 NodeManager
* nm
= NodeManager::currentNM();
866 std::unordered_map
<TNode
, EvalResult
, TNodeHashFunction
>::iterator itr
;
867 std::unordered_map
<TNode
, Node
, NodeHashFunction
>::iterator itn
;
868 std::vector
<Node
> echildren
;
869 if (n
.getMetaKind() == kind::metakind::PARAMETERIZED
)
871 TNode op
= n
.getOperator();
874 echildren
.push_back(op
);
878 itr
= eresults
.find(op
);
879 Assert(itr
!= eresults
.end());
880 if (itr
->second
.d_tag
== EvalResult::INVALID
)
882 // could not evaluate the operator, look in the node cache
883 itn
= evalAsNode
.find(op
);
884 Assert(itn
!= evalAsNode
.end());
885 echildren
.push_back(itn
->second
);
889 // otherwise, use the evaluation of the operator
890 echildren
.push_back(itr
->second
.toNode());
894 for (const auto& currNodeChild
: n
)
896 itr
= eresults
.find(currNodeChild
);
897 Assert(itr
!= eresults
.end());
898 if (itr
->second
.d_tag
== EvalResult::INVALID
)
900 // could not evaluate this child, look in the node cache
901 itn
= evalAsNode
.find(currNodeChild
);
902 Assert(itn
!= evalAsNode
.end());
903 echildren
.push_back(itn
->second
);
907 // otherwise, use the evaluation
908 echildren
.push_back(itr
->second
.toNode());
911 // The value is the result of our (partially) successful evaluation
913 Node nn
= nm
->mkNode(n
.getKind(), echildren
);
914 Trace("evaluator") << "Evaluator: reconstructed " << nn
<< std::endl
;
915 // Return node, without rewriting. Notice we do not need to substitute here
916 // since all substitutions should already have been applied recursively.
920 } // namespace theory