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-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 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
) const
122 std::unordered_map
<Node
, Node
, NodeHashFunction
> visited
;
123 return eval(n
, args
, vals
, visited
);
125 Node
Evaluator::eval(
127 const std::vector
<Node
>& args
,
128 const std::vector
<Node
>& vals
,
129 const std::unordered_map
<Node
, Node
, NodeHashFunction
>& visited
) const
131 Trace("evaluator") << "Evaluating " << n
<< " under substitution " << args
132 << " " << vals
<< " with visited size = " << visited
.size()
134 std::unordered_map
<TNode
, Node
, NodeHashFunction
> evalAsNode
;
135 std::unordered_map
<TNode
, EvalResult
, TNodeHashFunction
> results
;
136 // add visited to results
137 for (const std::pair
<const Node
, Node
>& p
: visited
)
139 Trace("evaluator") << "Add " << p
.first
<< " == " << p
.second
<< std::endl
;
140 results
[p
.first
] = evalInternal(p
.second
, args
, vals
, evalAsNode
, results
);
141 if (results
[p
.first
].d_tag
== EvalResult::INVALID
)
143 // could not evaluate, use the evalAsNode map
144 evalAsNode
[p
.first
] = evalAsNode
[p
.second
];
147 Trace("evaluator") << "Run eval internal..." << std::endl
;
148 Node ret
= evalInternal(n
, args
, vals
, evalAsNode
, results
).toNode();
149 // if we failed to evaluate
152 // should be stored in the evaluation-as-node map
153 std::unordered_map
<TNode
, Node
, NodeHashFunction
>::iterator itn
=
155 Assert(itn
!= evalAsNode
.end());
158 // should be the same as substitution + rewriting
160 == Rewriter::rewrite(
161 n
.substitute(args
.begin(), args
.end(), vals
.begin(), vals
.end())));
165 EvalResult
Evaluator::evalInternal(
167 const std::vector
<Node
>& args
,
168 const std::vector
<Node
>& vals
,
169 std::unordered_map
<TNode
, Node
, NodeHashFunction
>& evalAsNode
,
170 std::unordered_map
<TNode
, EvalResult
, TNodeHashFunction
>& results
) const
172 std::vector
<TNode
> queue
;
173 queue
.emplace_back(n
);
174 std::unordered_map
<TNode
, EvalResult
, TNodeHashFunction
>::iterator itr
;
176 while (queue
.size() != 0)
178 TNode currNode
= queue
.back();
180 if (results
.find(currNode
) != results
.end())
186 bool doProcess
= true;
188 if (currNode
.getMetaKind() == kind::metakind::PARAMETERIZED
)
190 TNode op
= currNode
.getOperator();
191 // Certain nodes are parameterized with constant operators, including
192 // bitvector extract. These operators do not need to be evaluated.
195 itr
= results
.find(op
);
196 if (itr
== results
.end())
198 queue
.emplace_back(op
);
201 else if (itr
->second
.d_tag
== EvalResult::INVALID
)
207 for (const auto& currNodeChild
: currNode
)
209 itr
= results
.find(currNodeChild
);
210 if (itr
== results
.end())
212 queue
.emplace_back(currNodeChild
);
215 else if (itr
->second
.d_tag
== EvalResult::INVALID
)
217 // we cannot evaluate since there was an invalid child
221 Trace("evaluator") << "Evaluator: visit " << currNode
222 << ", process = " << doProcess
223 << ", evaluate = " << doEval
<< std::endl
;
229 Node currNodeVal
= currNode
;
230 // whether we need to reconstruct the current node in the case of failure
231 bool needsReconstruct
= true;
233 // The code below should either:
234 // (1) store a valid EvalResult into results[currNode], or
235 // (2) store an invalid EvalResult into results[currNode] and
236 // store the result of substitution + rewriting currNode { args -> vals }
237 // into evalAsNode[currNode].
239 // If we did not successfully evaluate all children
242 // Reconstruct the node with a combination of the children that
243 // successfully evaluated, and the children that did not.
244 Trace("evaluator") << "Evaluator: collect arguments" << std::endl
;
245 currNodeVal
= reconstruct(currNodeVal
, results
, evalAsNode
);
246 needsReconstruct
= false;
247 Trace("evaluator") << "Evaluator: now after substitution + rewriting: "
248 << currNodeVal
<< std::endl
;
249 if (currNodeVal
.getNumChildren() > 0)
251 // We may continue with a valid EvalResult at this point only if
252 // we have no children. We must otherwise fail here since some of
253 // our children may not have successful evaluations.
254 results
[currNode
] = EvalResult();
255 evalAsNode
[currNode
] = currNodeVal
;
258 // Otherwise, we may be able to turn the overall result into an
259 // valid EvalResult and continue. We fallthrough and continue with the
260 // block of code below.
263 if (currNode
.isVar())
265 const auto& it
= std::find(args
.begin(), args
.end(), currNode
);
266 if (it
== args
.end())
268 // variable with no substitution is itself
269 evalAsNode
[currNode
] = currNode
;
270 results
[currNode
] = EvalResult();
273 ptrdiff_t pos
= std::distance(args
.begin(), it
);
274 currNodeVal
= vals
[pos
];
275 // Don't need to reconstruct since range of substitution should already
277 Assert(vals
[pos
] == Rewriter::rewrite(vals
[pos
]));
278 needsReconstruct
= false;
280 else if (currNode
.getKind() == kind::APPLY_UF
)
282 Trace("evaluator") << "Evaluate " << currNode
<< std::endl
;
283 TNode op
= currNode
.getOperator();
284 Assert(evalAsNode
.find(op
) != evalAsNode
.end());
285 // no function can be a valid EvalResult
287 Trace("evaluator") << "Operator evaluated to " << op
<< std::endl
;
288 if (op
.getKind() != kind::LAMBDA
)
290 // this node is not evaluatable due to operator, must add to
292 results
[currNode
] = EvalResult();
293 evalAsNode
[currNode
] = reconstruct(currNode
, results
, evalAsNode
);
296 // Create a copy of the current substitutions
297 std::vector
<Node
> lambdaArgs(args
);
298 std::vector
<Node
> lambdaVals(vals
);
300 // Add the values for the arguments of the lambda as substitutions at
301 // the beginning of the vector to shadow variables from outer scopes
302 // with the same name
303 for (const auto& lambdaArg
: op
[0])
305 lambdaArgs
.insert(lambdaArgs
.begin(), lambdaArg
);
308 for (const auto& lambdaVal
: currNode
)
310 lambdaVals
.insert(lambdaVals
.begin(), results
[lambdaVal
].toNode());
313 // Lambdas are evaluated in a recursive fashion because each evaluation
314 // requires different substitutions. We use a fresh cache since the
315 // evaluation of op[1] is under a new substitution and thus should not
316 // be cached. We could alternatively copy evalAsNode to evalAsNodeC but
317 // favor avoiding this copy for performance reasons.
318 std::unordered_map
<TNode
, Node
, NodeHashFunction
> evalAsNodeC
;
319 std::unordered_map
<TNode
, EvalResult
, TNodeHashFunction
> resultsC
;
321 evalInternal(op
[1], lambdaArgs
, lambdaVals
, evalAsNodeC
, resultsC
);
322 Trace("evaluator") << "Evaluated via arguments to "
323 << results
[currNode
].d_tag
<< std::endl
;
324 if (results
[currNode
].d_tag
== EvalResult::INVALID
)
326 // evaluation was invalid, we take the node of op[1] as the result
327 evalAsNode
[currNode
] = evalAsNodeC
[op
[1]];
329 << "Take node evaluation: " << evalAsNodeC
[op
[1]] << std::endl
;
334 switch (currNodeVal
.getKind())
336 case kind::CONST_BOOLEAN
:
337 results
[currNode
] = EvalResult(currNodeVal
.getConst
<bool>());
342 results
[currNode
] = EvalResult(!(results
[currNode
[0]].d_bool
));
348 bool res
= results
[currNode
[0]].d_bool
;
349 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
351 res
= res
&& results
[currNode
[i
]].d_bool
;
353 results
[currNode
] = EvalResult(res
);
359 bool res
= results
[currNode
[0]].d_bool
;
360 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
362 res
= res
|| results
[currNode
[i
]].d_bool
;
364 results
[currNode
] = EvalResult(res
);
368 case kind::CONST_RATIONAL
:
370 const Rational
& r
= currNodeVal
.getConst
<Rational
>();
371 results
[currNode
] = EvalResult(r
);
377 Rational res
= results
[currNode
[0]].d_rat
;
378 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
380 res
= res
+ results
[currNode
[i
]].d_rat
;
382 results
[currNode
] = EvalResult(res
);
388 const Rational
& x
= results
[currNode
[0]].d_rat
;
389 const Rational
& y
= results
[currNode
[1]].d_rat
;
390 results
[currNode
] = EvalResult(x
- y
);
396 const Rational
& x
= results
[currNode
[0]].d_rat
;
397 results
[currNode
] = EvalResult(-x
);
401 case kind::NONLINEAR_MULT
:
403 Rational res
= results
[currNode
[0]].d_rat
;
404 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
406 res
= res
* results
[currNode
[i
]].d_rat
;
408 results
[currNode
] = EvalResult(res
);
414 const Rational
& x
= results
[currNode
[0]].d_rat
;
415 const Rational
& y
= results
[currNode
[1]].d_rat
;
416 results
[currNode
] = EvalResult(x
>= y
);
421 const Rational
& x
= results
[currNode
[0]].d_rat
;
422 const Rational
& y
= results
[currNode
[1]].d_rat
;
423 results
[currNode
] = EvalResult(x
<= y
);
428 const Rational
& x
= results
[currNode
[0]].d_rat
;
429 const Rational
& y
= results
[currNode
[1]].d_rat
;
430 results
[currNode
] = EvalResult(x
> y
);
435 const Rational
& x
= results
[currNode
[0]].d_rat
;
436 const Rational
& y
= results
[currNode
[1]].d_rat
;
437 results
[currNode
] = EvalResult(x
< y
);
442 const Rational
& x
= results
[currNode
[0]].d_rat
;
443 results
[currNode
] = EvalResult(x
.abs());
446 case kind::CONST_STRING
:
447 results
[currNode
] = EvalResult(currNodeVal
.getConst
<String
>());
450 case kind::STRING_CONCAT
:
452 String res
= results
[currNode
[0]].d_str
;
453 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
455 res
= res
.concat(results
[currNode
[i
]].d_str
);
457 results
[currNode
] = EvalResult(res
);
461 case kind::STRING_LENGTH
:
463 const String
& s
= results
[currNode
[0]].d_str
;
464 results
[currNode
] = EvalResult(Rational(s
.size()));
468 case kind::STRING_SUBSTR
:
470 const String
& s
= results
[currNode
[0]].d_str
;
471 Integer
s_len(s
.size());
472 Integer i
= results
[currNode
[1]].d_rat
.getNumerator();
473 Integer j
= results
[currNode
[2]].d_rat
.getNumerator();
475 if (i
.strictlyNegative() || j
.strictlyNegative() || i
>= s_len
)
477 results
[currNode
] = EvalResult(String(""));
479 else if (i
+ j
> s_len
)
482 EvalResult(s
.suffix((s_len
- i
).toUnsignedInt()));
487 EvalResult(s
.substr(i
.toUnsignedInt(), j
.toUnsignedInt()));
492 case kind::STRING_CHARAT
:
494 const String
& s
= results
[currNode
[0]].d_str
;
495 Integer
s_len(s
.size());
496 Integer i
= results
[currNode
[1]].d_rat
.getNumerator();
497 if (i
.strictlyNegative() || i
>= s_len
)
499 results
[currNode
] = EvalResult(String(""));
503 results
[currNode
] = EvalResult(s
.substr(i
.toUnsignedInt(), 1));
508 case kind::STRING_STRCTN
:
510 const String
& s
= results
[currNode
[0]].d_str
;
511 const String
& t
= results
[currNode
[1]].d_str
;
512 results
[currNode
] = EvalResult(s
.find(t
) != std::string::npos
);
516 case kind::STRING_STRIDOF
:
518 const String
& s
= results
[currNode
[0]].d_str
;
519 Integer
s_len(s
.size());
520 const String
& x
= results
[currNode
[1]].d_str
;
521 Integer i
= results
[currNode
[2]].d_rat
.getNumerator();
523 if (i
.strictlyNegative())
525 results
[currNode
] = EvalResult(Rational(-1));
529 size_t r
= s
.find(x
, i
.toUnsignedInt());
530 if (r
== std::string::npos
)
532 results
[currNode
] = EvalResult(Rational(-1));
536 results
[currNode
] = EvalResult(Rational(r
));
542 case kind::STRING_STRREPL
:
544 const String
& s
= results
[currNode
[0]].d_str
;
545 const String
& x
= results
[currNode
[1]].d_str
;
546 const String
& y
= results
[currNode
[2]].d_str
;
547 results
[currNode
] = EvalResult(s
.replace(x
, y
));
551 case kind::STRING_PREFIX
:
553 const String
& t
= results
[currNode
[0]].d_str
;
554 const String
& s
= results
[currNode
[1]].d_str
;
555 if (s
.size() < t
.size())
557 results
[currNode
] = EvalResult(false);
561 results
[currNode
] = EvalResult(s
.prefix(t
.size()) == t
);
566 case kind::STRING_SUFFIX
:
568 const String
& t
= results
[currNode
[0]].d_str
;
569 const String
& s
= results
[currNode
[1]].d_str
;
570 if (s
.size() < t
.size())
572 results
[currNode
] = EvalResult(false);
576 results
[currNode
] = EvalResult(s
.suffix(t
.size()) == t
);
581 case kind::STRING_ITOS
:
583 Integer i
= results
[currNode
[0]].d_rat
.getNumerator();
584 if (i
.strictlyNegative())
586 results
[currNode
] = EvalResult(String(""));
590 results
[currNode
] = EvalResult(String(i
.toString()));
595 case kind::STRING_STOI
:
597 const String
& s
= results
[currNode
[0]].d_str
;
600 results
[currNode
] = EvalResult(Rational(s
.toNumber()));
604 results
[currNode
] = EvalResult(Rational(-1));
609 case kind::STRING_FROM_CODE
:
611 Integer i
= results
[currNode
[0]].d_rat
.getNumerator();
612 if (i
>= 0 && i
< strings::utils::getAlphabetCardinality())
614 std::vector
<unsigned> svec
= {i
.toUnsignedInt()};
615 results
[currNode
] = EvalResult(String(svec
));
619 results
[currNode
] = EvalResult(String(""));
624 case kind::STRING_TO_CODE
:
626 const String
& s
= results
[currNode
[0]].d_str
;
629 results
[currNode
] = EvalResult(Rational(s
.getVec()[0]));
633 results
[currNode
] = EvalResult(Rational(-1));
638 case kind::CONST_BITVECTOR
:
639 results
[currNode
] = EvalResult(currNodeVal
.getConst
<BitVector
>());
642 case kind::BITVECTOR_NOT
:
643 results
[currNode
] = EvalResult(~results
[currNode
[0]].d_bv
);
646 case kind::BITVECTOR_NEG
:
647 results
[currNode
] = EvalResult(-results
[currNode
[0]].d_bv
);
650 case kind::BITVECTOR_EXTRACT
:
652 unsigned lo
= bv::utils::getExtractLow(currNodeVal
);
653 unsigned hi
= bv::utils::getExtractHigh(currNodeVal
);
655 EvalResult(results
[currNode
[0]].d_bv
.extract(hi
, lo
));
659 case kind::BITVECTOR_CONCAT
:
661 BitVector res
= results
[currNode
[0]].d_bv
;
662 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
664 res
= res
.concat(results
[currNode
[i
]].d_bv
);
666 results
[currNode
] = EvalResult(res
);
670 case kind::BITVECTOR_PLUS
:
672 BitVector res
= results
[currNode
[0]].d_bv
;
673 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
675 res
= res
+ results
[currNode
[i
]].d_bv
;
677 results
[currNode
] = EvalResult(res
);
681 case kind::BITVECTOR_MULT
:
683 BitVector res
= results
[currNode
[0]].d_bv
;
684 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
686 res
= res
* results
[currNode
[i
]].d_bv
;
688 results
[currNode
] = EvalResult(res
);
691 case kind::BITVECTOR_AND
:
693 BitVector res
= results
[currNode
[0]].d_bv
;
694 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
696 res
= res
& results
[currNode
[i
]].d_bv
;
698 results
[currNode
] = EvalResult(res
);
702 case kind::BITVECTOR_OR
:
704 BitVector res
= results
[currNode
[0]].d_bv
;
705 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
707 res
= res
| results
[currNode
[i
]].d_bv
;
709 results
[currNode
] = EvalResult(res
);
713 case kind::BITVECTOR_XOR
:
715 BitVector res
= results
[currNode
[0]].d_bv
;
716 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
718 res
= res
^ results
[currNode
[i
]].d_bv
;
720 results
[currNode
] = EvalResult(res
);
723 case kind::BITVECTOR_UDIV
:
724 case kind::BITVECTOR_UDIV_TOTAL
:
726 if (currNodeVal
.getKind() == kind::BITVECTOR_UDIV_TOTAL
727 || results
[currNode
[1]].d_bv
.getValue() != 0)
729 BitVector res
= results
[currNode
[0]].d_bv
;
730 res
= res
.unsignedDivTotal(results
[currNode
[1]].d_bv
);
731 results
[currNode
] = EvalResult(res
);
735 results
[currNode
] = EvalResult();
736 evalAsNode
[currNode
] =
737 needsReconstruct
? reconstruct(currNode
, results
, evalAsNode
)
742 case kind::BITVECTOR_UREM
:
743 case kind::BITVECTOR_UREM_TOTAL
:
745 if (currNodeVal
.getKind() == kind::BITVECTOR_UREM_TOTAL
746 || results
[currNode
[1]].d_bv
.getValue() != 0)
748 BitVector res
= results
[currNode
[0]].d_bv
;
749 res
= res
.unsignedRemTotal(results
[currNode
[1]].d_bv
);
750 results
[currNode
] = EvalResult(res
);
754 results
[currNode
] = EvalResult();
755 evalAsNode
[currNode
] =
756 needsReconstruct
? reconstruct(currNode
, results
, evalAsNode
)
764 EvalResult lhs
= results
[currNode
[0]];
765 EvalResult rhs
= results
[currNode
[1]];
769 case EvalResult::BOOL
:
771 results
[currNode
] = EvalResult(lhs
.d_bool
== rhs
.d_bool
);
775 case EvalResult::BITVECTOR
:
777 results
[currNode
] = EvalResult(lhs
.d_bv
== rhs
.d_bv
);
781 case EvalResult::RATIONAL
:
783 results
[currNode
] = EvalResult(lhs
.d_rat
== rhs
.d_rat
);
787 case EvalResult::STRING
:
789 results
[currNode
] = EvalResult(lhs
.d_str
== rhs
.d_str
);
795 Trace("evaluator") << "Theory " << Theory::theoryOf(currNode
[0])
796 << " not supported" << std::endl
;
797 results
[currNode
] = EvalResult();
798 evalAsNode
[currNode
] =
799 needsReconstruct
? reconstruct(currNode
, results
, evalAsNode
)
810 if (results
[currNode
[0]].d_bool
)
812 results
[currNode
] = results
[currNode
[1]];
816 results
[currNode
] = results
[currNode
[2]];
823 Trace("evaluator") << "Kind " << currNodeVal
.getKind()
824 << " not supported" << std::endl
;
825 results
[currNode
] = EvalResult();
826 evalAsNode
[currNode
] =
827 needsReconstruct
? reconstruct(currNode
, results
, evalAsNode
)
837 Node
Evaluator::reconstruct(
839 std::unordered_map
<TNode
, EvalResult
, TNodeHashFunction
>& eresults
,
840 std::unordered_map
<TNode
, Node
, NodeHashFunction
>& evalAsNode
) const
842 if (n
.getNumChildren() == 0)
846 Trace("evaluator") << "Evaluator: reconstruct " << n
<< std::endl
;
847 NodeManager
* nm
= NodeManager::currentNM();
848 std::unordered_map
<TNode
, EvalResult
, TNodeHashFunction
>::iterator itr
;
849 std::unordered_map
<TNode
, Node
, NodeHashFunction
>::iterator itn
;
850 std::vector
<Node
> echildren
;
851 if (n
.getMetaKind() == kind::metakind::PARAMETERIZED
)
853 TNode op
= n
.getOperator();
856 echildren
.push_back(op
);
860 itr
= eresults
.find(op
);
861 Assert(itr
!= eresults
.end());
862 if (itr
->second
.d_tag
== EvalResult::INVALID
)
864 // could not evaluate the operator, look in the node cache
865 itn
= evalAsNode
.find(op
);
866 Assert(itn
!= evalAsNode
.end());
867 echildren
.push_back(itn
->second
);
871 // otherwise, use the evaluation of the operator
872 echildren
.push_back(itr
->second
.toNode());
876 for (const auto& currNodeChild
: n
)
878 itr
= eresults
.find(currNodeChild
);
879 Assert(itr
!= eresults
.end());
880 if (itr
->second
.d_tag
== EvalResult::INVALID
)
882 // could not evaluate this child, look in the node cache
883 itn
= evalAsNode
.find(currNodeChild
);
884 Assert(itn
!= evalAsNode
.end());
885 echildren
.push_back(itn
->second
);
889 // otherwise, use the evaluation
890 echildren
.push_back(itr
->second
.toNode());
893 // The value is the result of our (partially) successful evaluation
895 Node nn
= nm
->mkNode(n
.getKind(), echildren
);
896 Trace("evaluator") << "Evaluator: reconstructed " << nn
<< std::endl
;
897 // Use rewriting. Notice we do not need to substitute here since
898 // all substitutions should already have been applied recursively.
899 return Rewriter::rewrite(nn
);
902 } // namespace theory