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/theory.h"
22 #include "util/integer.h"
27 EvalResult::EvalResult(const EvalResult
& other
)
32 case BOOL
: d_bool
= other
.d_bool
; break;
34 new (&d_bv
) BitVector
;
38 new (&d_rat
) Rational
;
49 EvalResult
& EvalResult::operator=(const EvalResult
& other
)
56 case BOOL
: d_bool
= other
.d_bool
; break;
58 new (&d_bv
) BitVector
;
62 new (&d_rat
) Rational
;
75 EvalResult::~EvalResult()
99 Node
EvalResult::toNode() const
101 NodeManager
* nm
= NodeManager::currentNM();
104 case EvalResult::BOOL
: return nm
->mkConst(d_bool
);
105 case EvalResult::BITVECTOR
: return nm
->mkConst(d_bv
);
106 case EvalResult::RATIONAL
: return nm
->mkConst(d_rat
);
107 case EvalResult::STRING
: return nm
->mkConst(d_str
);
110 Trace("evaluator") << "Missing conversion from " << d_tag
<< " to node"
117 Node
Evaluator::eval(TNode n
,
118 const std::vector
<Node
>& args
,
119 const std::vector
<Node
>& vals
)
121 Trace("evaluator") << "Evaluating " << n
<< " under substitution " << args
122 << " " << vals
<< std::endl
;
123 std::unordered_map
<TNode
, Node
, NodeHashFunction
> evalAsNode
;
124 Node ret
= evalInternal(n
, args
, vals
, evalAsNode
).toNode();
127 // maybe it was stored in the evaluation-as-node map
128 std::unordered_map
<TNode
, Node
, NodeHashFunction
>::iterator itn
=
130 if (itn
!= evalAsNode
.end())
138 EvalResult
Evaluator::evalInternal(
140 const std::vector
<Node
>& args
,
141 const std::vector
<Node
>& vals
,
142 std::unordered_map
<TNode
, Node
, NodeHashFunction
>& evalAsNode
)
144 std::unordered_map
<TNode
, EvalResult
, TNodeHashFunction
> results
;
145 std::vector
<TNode
> queue
;
146 queue
.emplace_back(n
);
147 std::unordered_map
<TNode
, Node
, NodeHashFunction
>::iterator itn
;
148 std::unordered_map
<TNode
, EvalResult
, TNodeHashFunction
>::iterator itr
;
149 NodeManager
* nm
= NodeManager::currentNM();
151 while (queue
.size() != 0)
153 TNode currNode
= queue
.back();
155 if (results
.find(currNode
) != results
.end())
161 bool doProcess
= true;
163 for (const auto& currNodeChild
: currNode
)
165 itr
= results
.find(currNodeChild
);
166 if (itr
== results
.end())
168 queue
.emplace_back(currNodeChild
);
171 else if (itr
->second
.d_tag
== EvalResult::INVALID
)
173 // we cannot evaluate since there was an invalid child
177 Trace("evaluator") << "Evaluator: visit " << currNode
178 << ", process = " << doProcess
179 << ", evaluate = " << doEval
<< std::endl
;
185 Node currNodeVal
= currNode
;
187 // The code below should either:
188 // (1) store a valid EvalResult into results[currNode], or
189 // (2) store an invalid EvalResult into results[currNode] and
190 // store the result of substitution + rewriting currNode { args -> vals }
191 // into evalAsNode[currNode].
193 // If we did not successfully evaluate all children
196 // Reconstruct the node with a combination of the children that
197 // successfully evaluated, and the children that did not.
198 Trace("evaluator") << "Evaluator: collect arguments" << std::endl
;
199 std::vector
<Node
> echildren
;
200 if (currNode
.getMetaKind() == kind::metakind::PARAMETERIZED
)
202 echildren
.push_back(currNode
.getOperator());
204 for (const auto& currNodeChild
: currNode
)
206 itr
= results
.find(currNodeChild
);
207 if (itr
->second
.d_tag
== EvalResult::INVALID
)
209 // could not evaluate this child, look in the node cache
210 itn
= evalAsNode
.find(currNodeChild
);
211 Assert(itn
!= evalAsNode
.end());
212 echildren
.push_back(itn
->second
);
216 // otherwise, use the evaluation
217 echildren
.push_back(itr
->second
.toNode());
220 // The value is the result of our (partially) successful evaluation
222 currNodeVal
= nm
->mkNode(currNode
.getKind(), echildren
);
223 Trace("evaluator") << "Evaluator: partially evaluated " << currNodeVal
225 // Use rewriting. Notice we do not need to substitute here since
226 // all substitutions should already have been applied recursively.
227 currNodeVal
= Rewriter::rewrite(currNodeVal
);
228 Trace("evaluator") << "Evaluator: now after substitution + rewriting: "
229 << currNodeVal
<< std::endl
;
230 if (currNodeVal
.getNumChildren() > 0)
232 // We may continue with a valid EvalResult at this point only if
233 // we have no children. We must otherwise fail here since some of
234 // our children may not have successful evaluations.
235 results
[currNode
] = EvalResult();
236 evalAsNode
[currNode
] = currNodeVal
;
239 // Otherwise, we may be able to turn the overall result into an
240 // valid EvalResult and continue. We fallthrough and continue with the
241 // block of code below.
244 if (currNode
.isVar())
246 const auto& it
= std::find(args
.begin(), args
.end(), currNode
);
247 if (it
== args
.end())
249 evalAsNode
[currNode
] = currNode
;
250 results
[currNode
] = EvalResult();
253 ptrdiff_t pos
= std::distance(args
.begin(), it
);
254 currNodeVal
= vals
[pos
];
256 else if (currNode
.getKind() == kind::APPLY_UF
257 && currNode
.getOperator().getKind() == kind::LAMBDA
)
259 // Create a copy of the current substitutions
260 std::vector
<Node
> lambdaArgs(args
);
261 std::vector
<Node
> lambdaVals(vals
);
263 // Add the values for the arguments of the lambda as substitutions at
264 // the beginning of the vector to shadow variables from outer scopes
265 // with the same name
266 Node op
= currNode
.getOperator();
267 for (const auto& lambdaArg
: op
[0])
269 lambdaArgs
.insert(lambdaArgs
.begin(), lambdaArg
);
272 for (const auto& lambdaVal
: currNode
)
274 lambdaVals
.insert(lambdaVals
.begin(), results
[lambdaVal
].toNode());
277 // Lambdas are evaluated in a recursive fashion because each evaluation
278 // requires different substitutions. We use a fresh cache since the
279 // evaluation of op[1] is under a new substitution and thus should not
280 // be cached. We could alternatively copy evalAsNode to evalAsNodeC but
281 // favor avoiding this copy for performance reasons.
282 std::unordered_map
<TNode
, Node
, NodeHashFunction
> evalAsNodeC
;
284 evalInternal(op
[1], lambdaArgs
, lambdaVals
, evalAsNodeC
);
285 if (results
[currNode
].d_tag
== EvalResult::INVALID
)
287 // evaluation was invalid, we take the node of op[1] as the result
288 evalAsNode
[currNode
] = evalAsNodeC
[op
[1]];
293 switch (currNodeVal
.getKind())
295 case kind::CONST_BOOLEAN
:
296 results
[currNode
] = EvalResult(currNodeVal
.getConst
<bool>());
301 results
[currNode
] = EvalResult(!(results
[currNode
[0]].d_bool
));
307 bool res
= results
[currNode
[0]].d_bool
;
308 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
310 res
= res
&& results
[currNode
[i
]].d_bool
;
312 results
[currNode
] = EvalResult(res
);
318 bool res
= results
[currNode
[0]].d_bool
;
319 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
321 res
= res
|| results
[currNode
[i
]].d_bool
;
323 results
[currNode
] = EvalResult(res
);
327 case kind::CONST_RATIONAL
:
329 const Rational
& r
= currNodeVal
.getConst
<Rational
>();
330 results
[currNode
] = EvalResult(r
);
336 Rational res
= results
[currNode
[0]].d_rat
;
337 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
339 res
= res
+ results
[currNode
[i
]].d_rat
;
341 results
[currNode
] = EvalResult(res
);
347 const Rational
& x
= results
[currNode
[0]].d_rat
;
348 const Rational
& y
= results
[currNode
[1]].d_rat
;
349 results
[currNode
] = EvalResult(x
- y
);
355 const Rational
& x
= results
[currNode
[0]].d_rat
;
356 results
[currNode
] = EvalResult(-x
);
361 Rational res
= results
[currNode
[0]].d_rat
;
362 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
364 res
= res
* results
[currNode
[i
]].d_rat
;
366 results
[currNode
] = EvalResult(res
);
372 const Rational
& x
= results
[currNode
[0]].d_rat
;
373 const Rational
& y
= results
[currNode
[1]].d_rat
;
374 results
[currNode
] = EvalResult(x
>= y
);
379 const Rational
& x
= results
[currNode
[0]].d_rat
;
380 const Rational
& y
= results
[currNode
[1]].d_rat
;
381 results
[currNode
] = EvalResult(x
<= y
);
386 const Rational
& x
= results
[currNode
[0]].d_rat
;
387 const Rational
& y
= results
[currNode
[1]].d_rat
;
388 results
[currNode
] = EvalResult(x
> y
);
393 const Rational
& x
= results
[currNode
[0]].d_rat
;
394 const Rational
& y
= results
[currNode
[1]].d_rat
;
395 results
[currNode
] = EvalResult(x
< y
);
400 const Rational
& x
= results
[currNode
[0]].d_rat
;
401 results
[currNode
] = EvalResult(x
.abs());
404 case kind::CONST_STRING
:
405 results
[currNode
] = EvalResult(currNodeVal
.getConst
<String
>());
408 case kind::STRING_CONCAT
:
410 String res
= results
[currNode
[0]].d_str
;
411 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
413 res
= res
.concat(results
[currNode
[i
]].d_str
);
415 results
[currNode
] = EvalResult(res
);
419 case kind::STRING_LENGTH
:
421 const String
& s
= results
[currNode
[0]].d_str
;
422 results
[currNode
] = EvalResult(Rational(s
.size()));
426 case kind::STRING_SUBSTR
:
428 const String
& s
= results
[currNode
[0]].d_str
;
429 Integer
s_len(s
.size());
430 Integer i
= results
[currNode
[1]].d_rat
.getNumerator();
431 Integer j
= results
[currNode
[2]].d_rat
.getNumerator();
433 if (i
.strictlyNegative() || j
.strictlyNegative() || i
>= s_len
)
435 results
[currNode
] = EvalResult(String(""));
437 else if (i
+ j
> s_len
)
440 EvalResult(s
.suffix((s_len
- i
).toUnsignedInt()));
445 EvalResult(s
.substr(i
.toUnsignedInt(), j
.toUnsignedInt()));
450 case kind::STRING_CHARAT
:
452 const String
& s
= results
[currNode
[0]].d_str
;
453 Integer
s_len(s
.size());
454 Integer i
= results
[currNode
[1]].d_rat
.getNumerator();
455 if (i
.strictlyNegative() || i
>= s_len
)
457 results
[currNode
] = EvalResult(String(""));
461 results
[currNode
] = EvalResult(s
.substr(i
.toUnsignedInt(), 1));
466 case kind::STRING_STRCTN
:
468 const String
& s
= results
[currNode
[0]].d_str
;
469 const String
& t
= results
[currNode
[1]].d_str
;
470 results
[currNode
] = EvalResult(s
.find(t
) != std::string::npos
);
474 case kind::STRING_STRIDOF
:
476 const String
& s
= results
[currNode
[0]].d_str
;
477 Integer
s_len(s
.size());
478 const String
& x
= results
[currNode
[1]].d_str
;
479 Integer i
= results
[currNode
[2]].d_rat
.getNumerator();
481 if (i
.strictlyNegative())
483 results
[currNode
] = EvalResult(Rational(-1));
487 size_t r
= s
.find(x
, i
.toUnsignedInt());
488 if (r
== std::string::npos
)
490 results
[currNode
] = EvalResult(Rational(-1));
494 results
[currNode
] = EvalResult(Rational(r
));
500 case kind::STRING_STRREPL
:
502 const String
& s
= results
[currNode
[0]].d_str
;
503 const String
& x
= results
[currNode
[1]].d_str
;
504 const String
& y
= results
[currNode
[2]].d_str
;
505 results
[currNode
] = EvalResult(s
.replace(x
, y
));
509 case kind::STRING_PREFIX
:
511 const String
& t
= results
[currNode
[0]].d_str
;
512 const String
& s
= results
[currNode
[1]].d_str
;
513 if (s
.size() < t
.size())
515 results
[currNode
] = EvalResult(false);
519 results
[currNode
] = EvalResult(s
.prefix(t
.size()) == t
);
524 case kind::STRING_SUFFIX
:
526 const String
& t
= results
[currNode
[0]].d_str
;
527 const String
& s
= results
[currNode
[1]].d_str
;
528 if (s
.size() < t
.size())
530 results
[currNode
] = EvalResult(false);
534 results
[currNode
] = EvalResult(s
.suffix(t
.size()) == t
);
539 case kind::STRING_ITOS
:
541 Integer i
= results
[currNode
[0]].d_rat
.getNumerator();
542 if (i
.strictlyNegative())
544 results
[currNode
] = EvalResult(String(""));
548 results
[currNode
] = EvalResult(String(i
.toString()));
553 case kind::STRING_STOI
:
555 const String
& s
= results
[currNode
[0]].d_str
;
558 results
[currNode
] = EvalResult(Rational(s
.toNumber()));
562 results
[currNode
] = EvalResult(Rational(-1));
567 case kind::STRING_CODE
:
569 const String
& s
= results
[currNode
[0]].d_str
;
572 results
[currNode
] = EvalResult(
573 Rational(String::convertUnsignedIntToCode(s
.getVec()[0])));
577 results
[currNode
] = EvalResult(Rational(-1));
582 case kind::CONST_BITVECTOR
:
583 results
[currNode
] = EvalResult(currNodeVal
.getConst
<BitVector
>());
586 case kind::BITVECTOR_NOT
:
587 results
[currNode
] = EvalResult(~results
[currNode
[0]].d_bv
);
590 case kind::BITVECTOR_NEG
:
591 results
[currNode
] = EvalResult(-results
[currNode
[0]].d_bv
);
594 case kind::BITVECTOR_EXTRACT
:
596 unsigned lo
= bv::utils::getExtractLow(currNodeVal
);
597 unsigned hi
= bv::utils::getExtractHigh(currNodeVal
);
599 EvalResult(results
[currNode
[0]].d_bv
.extract(hi
, lo
));
603 case kind::BITVECTOR_CONCAT
:
605 BitVector res
= results
[currNode
[0]].d_bv
;
606 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
608 res
= res
.concat(results
[currNode
[i
]].d_bv
);
610 results
[currNode
] = EvalResult(res
);
614 case kind::BITVECTOR_PLUS
:
616 BitVector res
= results
[currNode
[0]].d_bv
;
617 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
619 res
= res
+ results
[currNode
[i
]].d_bv
;
621 results
[currNode
] = EvalResult(res
);
625 case kind::BITVECTOR_MULT
:
627 BitVector res
= results
[currNode
[0]].d_bv
;
628 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
630 res
= res
* results
[currNode
[i
]].d_bv
;
632 results
[currNode
] = EvalResult(res
);
635 case kind::BITVECTOR_AND
:
637 BitVector res
= results
[currNode
[0]].d_bv
;
638 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
640 res
= res
& results
[currNode
[i
]].d_bv
;
642 results
[currNode
] = EvalResult(res
);
646 case kind::BITVECTOR_OR
:
648 BitVector res
= results
[currNode
[0]].d_bv
;
649 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
651 res
= res
| results
[currNode
[i
]].d_bv
;
653 results
[currNode
] = EvalResult(res
);
657 case kind::BITVECTOR_XOR
:
659 BitVector res
= results
[currNode
[0]].d_bv
;
660 for (size_t i
= 1, end
= currNode
.getNumChildren(); i
< end
; i
++)
662 res
= res
^ results
[currNode
[i
]].d_bv
;
664 results
[currNode
] = EvalResult(res
);
667 case kind::BITVECTOR_UDIV
:
668 case kind::BITVECTOR_UDIV_TOTAL
:
670 if (currNodeVal
.getKind() == kind::BITVECTOR_UDIV_TOTAL
671 || results
[currNode
[1]].d_bv
.getValue() != 0)
673 BitVector res
= results
[currNode
[0]].d_bv
;
674 res
= res
.unsignedDivTotal(results
[currNode
[1]].d_bv
);
675 results
[currNode
] = EvalResult(res
);
679 results
[currNode
] = EvalResult();
680 evalAsNode
[currNode
] = currNodeVal
;
684 case kind::BITVECTOR_UREM
:
685 case kind::BITVECTOR_UREM_TOTAL
:
687 if (currNodeVal
.getKind() == kind::BITVECTOR_UREM_TOTAL
688 || results
[currNode
[1]].d_bv
.getValue() != 0)
690 BitVector res
= results
[currNode
[0]].d_bv
;
691 res
= res
.unsignedRemTotal(results
[currNode
[1]].d_bv
);
692 results
[currNode
] = EvalResult(res
);
696 results
[currNode
] = EvalResult();
697 evalAsNode
[currNode
] = currNodeVal
;
704 EvalResult lhs
= results
[currNode
[0]];
705 EvalResult rhs
= results
[currNode
[1]];
709 case EvalResult::BOOL
:
711 results
[currNode
] = EvalResult(lhs
.d_bool
== rhs
.d_bool
);
715 case EvalResult::BITVECTOR
:
717 results
[currNode
] = EvalResult(lhs
.d_bv
== rhs
.d_bv
);
721 case EvalResult::RATIONAL
:
723 results
[currNode
] = EvalResult(lhs
.d_rat
== rhs
.d_rat
);
727 case EvalResult::STRING
:
729 results
[currNode
] = EvalResult(lhs
.d_str
== rhs
.d_str
);
735 Trace("evaluator") << "Theory " << Theory::theoryOf(currNode
[0])
736 << " not supported" << std::endl
;
737 results
[currNode
] = EvalResult();
738 evalAsNode
[currNode
] = currNodeVal
;
748 if (results
[currNode
[0]].d_bool
)
750 results
[currNode
] = results
[currNode
[1]];
754 results
[currNode
] = results
[currNode
[2]];
761 Trace("evaluator") << "Kind " << currNodeVal
.getKind()
762 << " not supported" << std::endl
;
763 results
[currNode
] = EvalResult();
764 evalAsNode
[currNode
] = currNodeVal
;
773 } // namespace theory