Branch data Line data Source code
1 : : /****************************************************************************** 2 : : * This file is part of the cvc5 project. 3 : : * 4 : : * Copyright (c) 2009-2026 by the authors listed in the file AUTHORS 5 : : * in the top-level source directory and their institutional affiliations. 6 : : * All rights reserved. See the file COPYING in the top-level source 7 : : * directory for licensing information. 8 : : * **************************************************************************** 9 : : * 10 : : * A class for finding unsoundness in the rewriter 11 : : */ 12 : : 13 : : #include "theory/quantifiers/rewrite_verifier.h" 14 : : 15 : : #include "expr/node_algorithm.h" 16 : : #include "smt/env.h" 17 : : 18 : : namespace cvc5::internal { 19 : : namespace theory { 20 : : namespace quantifiers { 21 : : 22 : 12 : RewriteVerifier::RewriteVerifier(Env& env) : ExprMiner(env) {} 23 : : 24 : 12 : bool RewriteVerifier::addTerm(Node n, std::vector<Node>& rewrites) 25 : : { 26 : 12 : Node nr = rewrite(n); 27 [ - + ]: 12 : if (!checkEquivalent(n, nr)) 28 : : { 29 : 0 : std::stringstream ss; 30 : 0 : checkEquivalent(n, nr, &ss); 31 : 0 : Warning() << ss.str(); 32 : 0 : rewrites.push_back(n.eqNode(nr)); 33 : 0 : return true; 34 : 0 : } 35 : 12 : return false; 36 : 12 : } 37 : : 38 : 12 : bool RewriteVerifier::checkEquivalent(Node bv, Node bvr, std::ostream* out) 39 : : { 40 [ + + ]: 12 : if (bv == bvr) 41 : : { 42 : 7 : return true; 43 : : } 44 [ + - ][ - + ]: 5 : if (d_sampler == nullptr || d_sampler->getNumSamplePoints() == 0) [ - + ] 45 : : { 46 : 0 : DebugUnhandled() << "Expected a sampler to test rewrites"; 47 : : return true; 48 : : } 49 : : // check if it has variables from d_vars, if not, we only test one point 50 : 5 : std::unordered_set<Node> syms; 51 : 5 : expr::getFreeVariables(bv, syms); 52 : 5 : bool hasVar = false; 53 [ + + ]: 5 : for (const Node& sym : syms) 54 : : { 55 [ + - ]: 4 : if (std::find(d_vars.begin(), d_vars.end(), sym) != d_vars.end()) 56 : : { 57 : 4 : hasVar = true; 58 : 4 : break; 59 : : } 60 : : } 61 [ + + ]: 5 : size_t npoints = hasVar ? d_sampler->getNumSamplePoints() : 1; 62 [ + - ]: 10 : Trace("sygus-rr-verify") << "Testing rewrite rule " << bv << " ---> " << bvr 63 : 0 : << " over " << npoints << " points for " << d_vars 64 : 5 : << std::endl; 65 : : 66 : : // see if they evaluate to same thing on all sample points 67 : 5 : bool ptDisequal = false; 68 : 5 : bool ptDisequalConst = false; 69 : 5 : size_t pt_index = 0; 70 : 5 : Node bve, bvre; 71 : : // if we don't have variables from sample, further points don't matter 72 [ + + ]: 4006 : for (size_t i = 0; i < npoints; i++) 73 : : { 74 : : // do not use the rewriter in the calls to evaluate here 75 : 4001 : const std::vector<Node>& pt = d_sampler->getSamplePoint(i); 76 [ - + ][ - + ]: 4001 : Assert(pt.size() == d_vars.size()); [ - - ] 77 : 4001 : bve = evaluate(bv, d_vars, pt, false); 78 : 4001 : bvre = evaluate(bvr, d_vars, pt, false); 79 [ - + ]: 4001 : if (bve != bvre) 80 : : { 81 : 0 : ptDisequal = true; 82 : 0 : pt_index = i; 83 : 0 : if (bve.isConst() && bvre.isConst()) 84 : : { 85 : 0 : ptDisequalConst = true; 86 : 0 : break; 87 : : } 88 : : } 89 : : } 90 [ + - ]: 5 : Trace("sygus-rr-verify") << "...finished" << std::endl; 91 : : // bv and bvr should be equivalent under examples 92 [ - + ]: 5 : if (ptDisequal) 93 : : { 94 : 0 : std::vector<Node> vars; 95 : 0 : d_sampler->getVariables(vars); 96 : 0 : const std::vector<Node>& pt = d_sampler->getSamplePoint(pt_index); 97 : 0 : Assert(vars.size() == pt.size()); 98 : 0 : std::stringstream ptOut; 99 [ - - ]: 0 : for (size_t i = 0, size = pt.size(); i < size; i++) 100 : : { 101 : 0 : ptOut << " " << vars[i] << " -> " << pt[i] << std::endl; 102 : : } 103 [ - - ]: 0 : if (!ptDisequalConst) 104 : : { 105 : 0 : d_env.verbose(1) 106 : 0 : << "Warning: " << bv << " and " << bvr 107 : 0 : << " evaluate to different (non-constant) values on point:" 108 : 0 : << std::endl; 109 : 0 : d_env.verbose(1) << ptOut.str(); 110 : 0 : return true; 111 : : } 112 : : // we have detected unsoundness in the rewriter 113 : : // debugging information 114 [ - - ]: 0 : if (out) 115 : : { 116 : 0 : (*out) << "find-synth: terms " << bv << " and " << bvr 117 : 0 : << " are not equivalent for :" << std::endl; 118 : 0 : (*out) << ptOut.str(); 119 : 0 : Assert(bve != bvre); 120 : 0 : (*out) << "where they evaluate to " << bve << " and " << bvre 121 : 0 : << std::endl; 122 : : } 123 : 0 : return false; 124 : 0 : } 125 : 5 : return true; 126 : 5 : } 127 : : 128 : : } // namespace quantifiers 129 : : } // namespace theory 130 : : } // namespace cvc5::internal