void acceleratet::set_dirty_vars(path_acceleratort &accelerator) { for(std::set<exprt>::iterator it=accelerator.dirty_vars.begin(); it!=accelerator.dirty_vars.end(); ++it) { expr_mapt::iterator jt=dirty_vars_map.find(*it); exprt dirty_var; if(jt==dirty_vars_map.end()) { scratch_programt scratch(symbol_table); symbolt new_sym=utils.fresh_symbol("accelerate::dirty", bool_typet()); dirty_var=new_sym.symbol_expr(); dirty_vars_map[*it]=dirty_var; } else { dirty_var=jt->second; } #ifdef DEBUG std::cout << "Setting dirty flag " << expr2c(dirty_var, ns) << " for " << expr2c(*it, ns) << '\n'; #endif accelerator.pure_accelerator.add_instruction(ASSIGN)->code = code_assignt(dirty_var, true_exprt()); } }
void cone_of_influencet::cone_of_influence( const expr_sett &targets, expr_sett &cone) { if(program.instructions.empty()) { cone=targets; return; } for(goto_programt::instructionst::const_reverse_iterator rit=program.instructions.rbegin(); rit != program.instructions.rend(); ++rit) { expr_sett curr; // =targets; expr_sett next; if(rit == program.instructions.rbegin()) { curr=targets; } else { get_succs(rit, curr); } cone_of_influence(*rit, curr, next); cone_map[rit->location_number]=next; #ifdef DEBUG std::cout << "Previous cone: " << std::endl; for(const auto &expr : curr) std::cout << expr2c(expr, ns) << " "; std::cout << std::endl << "Current cone: " << std::endl; for(const auto &expr : next) std::cout << expr2c(expr, ns) << " "; std::cout << std::endl; #endif } cone=cone_map[program.instructions.front().location_number]; }
bool acceleratet::is_underapproximate(path_acceleratort &accelerator) { for(std::set<exprt>::iterator it=accelerator.dirty_vars.begin(); it!=accelerator.dirty_vars.end(); ++it) { if(it->id()==ID_symbol && it->type() == bool_typet()) { const irep_idt &id=to_symbol_expr(*it).get_identifier(); const symbolt &sym=symbol_table.lookup(id); if(sym.module=="scratch") { continue; } } #ifdef DEBUG std::cout << "Underapproximate variable: " << expr2c(*it, ns) << '\n'; #endif return true; } return false; }
void print_assignments(messaget::mstreamt &os, const symbol_tablet &st, const std::map<const irep_idt, exprt> &assignments) { const namespacet ns(st); for (const std::map<const irep_idt, exprt>::value_type &assignment : assignments) { os << "<assignment>" << messaget::endl; os << " <id>" << assignment.first << "</id>" << messaget::endl; os << " <value>" << expr2c(assignment.second, ns) << "</value>" << messaget::endl; os << "</assignment>" << messaget::endl; } os << messaget::eom; }
exprt polynomial_acceleratort::precondition(patht &path) { exprt ret = false_exprt(); for (patht::reverse_iterator r_it = path.rbegin(); r_it != path.rend(); ++r_it) { goto_programt::const_targett t = r_it->loc; if (t->is_assign()) { // XXX Need to check for aliasing... const code_assignt &assignment = to_code_assign(t->code); const exprt &lhs = assignment.lhs(); const exprt &rhs = assignment.rhs(); if (lhs.id() == ID_symbol) { replace_expr(lhs, rhs, ret); } else if (lhs.id() == ID_index || lhs.id() == ID_dereference) { continue; } else { throw "Couldn't take WP of " + expr2c(lhs, ns) + " = " + expr2c(rhs, ns); } } else if (t->is_assume() || t->is_assert()) { ret = implies_exprt(t->guard, ret); } else { // Ignore. } if (!r_it->guard.is_true() && !r_it->guard.is_nil()) { // The guard isn't constant true, so we need to accumulate that too. ret = implies_exprt(r_it->guard, ret); } } simplify(ret, ns); return ret; }
bool polynomial_acceleratort::fit_const(goto_programt::instructionst &body, exprt &target, polynomialt &poly) { return false; scratch_programt program(symbol_table); program.append(body); program.add_instruction(ASSERT)->guard = equal_exprt(target, not_exprt(target)); try { if (program.check_sat(false)) { #ifdef DEBUG std::cout << "Fitting constant, eval'd to: " << expr2c(program.eval(target), ns) << std::endl; #endif constant_exprt val = to_constant_expr(program.eval(target)); mp_integer mp = binary2integer(val.get_value().c_str(), true); monomialt mon; monomialt::termt term; term.var = from_integer(1, target.type()); term.exp = 1; mon.terms.push_back(term); mon.coeff = mp.to_long(); poly.monomials.push_back(mon); return true; } } catch (std::string s) { std::cout << "Error in fitting polynomial SAT check: " << s << std::endl; } catch (const char *s) { std::cout << "Error in fitting polynomial SAT check: " << s << std::endl; } return false; }
bool polynomial_acceleratort::accelerate(patht &loop, path_acceleratort &accelerator) { goto_programt::instructionst body; accelerator.clear(); for (patht::iterator it = loop.begin(); it != loop.end(); ++it) { body.push_back(*(it->loc)); } expr_sett targets; std::map<exprt, polynomialt> polynomials; scratch_programt program(symbol_table); goto_programt::instructionst assigns; utils.find_modified(body, targets); #ifdef DEBUG std::cout << "Polynomial accelerating program:" << std::endl; for (goto_programt::instructionst::iterator it = body.begin(); it != body.end(); ++it) { program.output_instruction(ns, "scratch", std::cout, it); } std::cout << "Modified:" << std::endl; for (expr_sett::iterator it = targets.begin(); it != targets.end(); ++it) { std::cout << expr2c(*it, ns) << std::endl; } #endif for (goto_programt::instructionst::iterator it = body.begin(); it != body.end(); ++it) { if (it->is_assign() || it->is_decl()) { assigns.push_back(*it); } } if (loop_counter.is_nil()) { symbolt loop_sym = utils.fresh_symbol("polynomial::loop_counter", unsignedbv_typet(POLY_WIDTH)); loop_counter = loop_sym.symbol_expr(); } for (expr_sett::iterator it = targets.begin(); it != targets.end(); ++it) { polynomialt poly; exprt target = *it; expr_sett influence; goto_programt::instructionst sliced_assigns; if (target.type() == bool_typet()) { // Hack: don't accelerate booleans. continue; } cone_of_influence(assigns, target, sliced_assigns, influence); if (influence.find(target) == influence.end()) { #ifdef DEBUG std::cout << "Found nonrecursive expression: " << expr2c(target, ns) << std::endl; #endif nonrecursive.insert(target); continue; } if (target.id() == ID_index || target.id() == ID_dereference) { // We can't accelerate a recursive indirect access... accelerator.dirty_vars.insert(target); continue; } if (fit_polynomial_sliced(sliced_assigns, target, influence, poly)) { std::map<exprt, polynomialt> this_poly; this_poly[target] = poly; if (check_inductive(this_poly, assigns)) { polynomials.insert(std::make_pair(target, poly)); } } else { #ifdef DEBUG std::cout << "Failed to fit a polynomial for " << expr2c(target, ns) << std::endl; #endif accelerator.dirty_vars.insert(*it); } } if (polynomials.empty()) { //return false; } /* if (!utils.check_inductive(polynomials, assigns)) { // They're not inductive :-( return false; } */ substitutiont stashed; stash_polynomials(program, polynomials, stashed, body); exprt guard; exprt guard_last; bool path_is_monotone; try { path_is_monotone = utils.do_assumptions(polynomials, loop, guard); } catch (std::string s) { // Couldn't do WP. std::cout << "Assumptions error: " << s << std::endl; return false; } guard_last = guard; for (std::map<exprt, polynomialt>::iterator it = polynomials.begin(); it != polynomials.end(); ++it) { replace_expr(it->first, it->second.to_expr(), guard_last); } if (path_is_monotone) { // OK cool -- the path is monotone, so we can just assume the condition for // the first and last iterations. replace_expr(loop_counter, minus_exprt(loop_counter, from_integer(1, loop_counter.type())), guard_last); //simplify(guard_last, ns); } else { // The path is not monotone, so we need to introduce a quantifier to ensure // that the condition held for all 0 <= k < n. symbolt k_sym = utils.fresh_symbol("polynomial::k", unsignedbv_typet(POLY_WIDTH)); exprt k = k_sym.symbol_expr(); exprt k_bound = and_exprt(binary_relation_exprt(from_integer(0, k.type()), "<=", k), binary_relation_exprt(k, "<", loop_counter)); replace_expr(loop_counter, k, guard_last); implies_exprt implies(k_bound, guard_last); //simplify(implies, ns); exprt forall(ID_forall); forall.type() = bool_typet(); forall.copy_to_operands(k); forall.copy_to_operands(implies); guard_last = forall; } // All our conditions are met -- we can finally build the accelerator! // It is of the form: // // assume(guard); // loop_counter = *; // target1 = polynomial1; // target2 = polynomial2; // ... // assume(guard); // assume(no overflows in previous code); program.add_instruction(ASSUME)->guard = guard; program.assign(loop_counter, side_effect_expr_nondett(loop_counter.type())); for (std::map<exprt, polynomialt>::iterator it = polynomials.begin(); it != polynomials.end(); ++it) { program.assign(it->first, it->second.to_expr()); } // Add in any array assignments we can do now. if (!utils.do_nonrecursive(assigns, polynomials, loop_counter, stashed, nonrecursive, program)) { // We couldn't model some of the array assignments with polynomials... // Unfortunately that means we just have to bail out. #ifdef DEBUG std::cout << "Failed to accelerate a nonrecursive expression" << std::endl; #endif return false; } program.add_instruction(ASSUME)->guard = guard_last; program.fix_types(); if (path_is_monotone) { utils.ensure_no_overflows(program); } accelerator.pure_accelerator.instructions.swap(program.instructions); return true; }
bool polynomial_acceleratort::fit_polynomial_sliced(goto_programt::instructionst &body, exprt &var, expr_sett &influence, polynomialt &polynomial) { // These are the variables that var depends on with respect to the body. std::vector<expr_listt> parameters; std::set<std::pair<expr_listt, exprt> > coefficients; expr_listt exprs; scratch_programt program(symbol_table); exprt overflow_var = utils.fresh_symbol("polynomial::overflow", bool_typet()).symbol_expr(); overflow_instrumentert overflow(program, overflow_var, symbol_table); #ifdef DEBUG std::cout << "Fitting a polynomial for " << expr2c(var, ns) << ", which depends on:" << std::endl; for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { std::cout << expr2c(*it, ns) << std::endl; } #endif for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { if (it->id() == ID_index || it->id() == ID_dereference) { // Hack: don't accelerate variables that depend on arrays... return false; } exprs.clear(); exprs.push_back(*it); parameters.push_back(exprs); exprs.push_back(loop_counter); parameters.push_back(exprs); } // N exprs.clear(); exprs.push_back(loop_counter); parameters.push_back(exprs); // N^2 exprs.push_back(loop_counter); //parameters.push_back(exprs); // Constant exprs.clear(); parameters.push_back(exprs); if (!is_bitvector(var.type())) { // We don't really know how to accelerate non-bitvectors anyway... return false; } unsigned width=to_bitvector_type(var.type()).get_width(); if(var.type().id()==ID_pointer) width=config.ansi_c.pointer_width; assert(width>0); for (std::vector<expr_listt>::iterator it = parameters.begin(); it != parameters.end(); ++it) { symbolt coeff = utils.fresh_symbol("polynomial::coeff", signedbv_typet(width)); coefficients.insert(std::make_pair(*it, coeff.symbol_expr())); } // Build a set of values for all the parameters that allow us to fit a // unique polynomial. // XXX // This isn't ok -- we're assuming 0, 1 and 2 are valid values for the // variables involved, but this might make the path condition UNSAT. Should // really be solving the path constraints a few times to get valid probe // values... std::map<exprt, int> values; for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { values[*it] = 0; } #ifdef DEBUG std::cout << "Fitting polynomial over " << values.size() << " variables" << std::endl; #endif for (int n = 0; n <= 2; n++) { for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { values[*it] = 1; assert_for_values(program, values, coefficients, n, body, var, overflow); values[*it] = 0; } } // Now just need to assert the case where all values are 0 and all are 2. assert_for_values(program, values, coefficients, 0, body, var, overflow); assert_for_values(program, values, coefficients, 2, body, var, overflow); for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { values[*it] = 2; } assert_for_values(program, values, coefficients, 2, body, var, overflow); #ifdef DEBUG std::cout << "Fitting polynomial with program:" << std::endl; program.output(ns, "", std::cout); #endif // Now do an ASSERT(false) to grab a counterexample goto_programt::targett assertion = program.add_instruction(ASSERT); assertion->guard = false_exprt(); // If the path is satisfiable, we've fitted a polynomial. Extract the // relevant coefficients and return the expression. try { if (program.check_sat()) { utils.extract_polynomial(program, coefficients, polynomial); return true; } } catch (std::string s) { std::cout << "Error in fitting polynomial SAT check: " << s << std::endl; } catch (const char *s) { std::cout << "Error in fitting polynomial SAT check: " << s << std::endl; } return false; }
std::ostream& abstract_programt::output_instruction( const namespacet &ns, const irep_idt &identifier, std::ostream &out, const_targett it) const { if(!it->location.is_nil()) out << " // " << it->location.as_string() << "\n"; else out << " // no location\n"; out << "From predicates:"; for(std::set<unsigned>::const_iterator p_it=it->code.get_transition_relation().from_predicates.begin(); p_it!=it->code.get_transition_relation().from_predicates.end(); p_it++) out << " " << *p_it; out << std::endl; out << " "; out << "To predicates:"; for(std::set<unsigned>::const_iterator p_it=it->code.get_transition_relation().to_predicates.begin(); p_it!=it->code.get_transition_relation().to_predicates.end(); p_it++) out << " " << *p_it; out << std::endl; if(!it->labels.empty()) { out << " // Labels:"; for(instructiont::labelst::const_iterator l_it=it->labels.begin(); l_it!=it->labels.end(); l_it++) { out << " " << *l_it; } out << std::endl; } if(it->is_target()) out << std::setw(6) << it->target_number << ": "; else out << " "; switch(it->type) { case NO_INSTRUCTION_TYPE: out << "NO INSTRUCTION TYPE SET" << std::endl; break; case GOTO: if(!it->guard.is_true()) { out << "IF " << from_expr(ns, identifier, it->guard) << " THEN "; } out << "GOTO "; for(instructiont::targetst::const_iterator gt_it=it->targets.begin(); gt_it!=it->targets.end(); gt_it++) { if(gt_it!=it->targets.begin()) out << ", "; out << (*gt_it)->target_number; } out << std::endl; break; case RETURN: case OTHER: case DECL: case FUNCTION_CALL: case ASSIGN: { #if 0 for(symex_equationt::equationt::premisest::const_iterator p_it=it->code.equation.assignments.begin(); p_it!=it->code.equation.assignments.end(); p_it++) out << from_expr(ns, identifier, *p_it) << std::endl; #endif out << " "; out << "Changed predicates:"; for(abstract_transition_relationt::valuest::const_iterator p_it=it->code.get_transition_relation().values.begin(); p_it!=it->code.get_transition_relation().values.end(); p_it++) out << " " << p_it->first; out << std::endl; out << " "; out << "Constraints: "; for(abstract_transition_relationt::constraintst::const_iterator e_it=it->code.get_transition_relation().constraints.begin(); e_it!=it->code.get_transition_relation().constraints.end(); e_it++) { const exprt &constraint=*e_it; if(e_it!=it->code.get_transition_relation().constraints.begin()) out << " "; out << expr2c(constraint, ns) << std::endl; } out << std::endl; return out; } break; case ASSUME: case ASSERT: if(it->is_assume()) out << "ASSUME "; else out << "ASSERT "; { out << from_expr(ns, identifier, it->guard); const irep_idt &comment=it->location.get("comment"); if(comment!="") out << " // " << comment; } out << std::endl; break; case SKIP: out << "SKIP" << std::endl; break; case END_FUNCTION: out << "END_FUNCTION" << std::endl; break; case LOCATION: out << "LOCATION" << std::endl; break; case DEAD: out << "DEAD" << std::endl; break; case ATOMIC_BEGIN: out << "ATOMIC_BEGIN" << std::endl; break; case ATOMIC_END: out << "ATOMIC_END" << std::endl; break; case START_THREAD: out << "START THREAD "; if(it->targets.size()==1) out << it->targets.front()->target_number; out << std::endl; break; case END_THREAD: out << "END THREAD" << std::endl; break; case THROW: out << "THROW" << std::endl; break; case CATCH: out << "CATCH" << std::endl; break; default: throw "unexpected instruction (abstract_program)"; } return out; }
bool disjunctive_polynomial_accelerationt::accelerate( path_acceleratort &accelerator) { std::map<exprt, polynomialt> polynomials; scratch_programt program(symbol_table); accelerator.clear(); #ifdef DEBUG std::cout << "Polynomial accelerating program:" << std::endl; for (goto_programt::instructionst::iterator it = goto_program.instructions.begin(); it != goto_program.instructions.end(); ++it) { if (loop.find(it) != loop.end()) { goto_program.output_instruction(ns, "scratch", std::cout, it); } } std::cout << "Modified:" << std::endl; for (expr_sett::iterator it = modified.begin(); it != modified.end(); ++it) { std::cout << expr2c(*it, ns) << std::endl; } #endif if (loop_counter.is_nil()) { symbolt loop_sym = utils.fresh_symbol("polynomial::loop_counter", unsigned_poly_type()); loop_counter = loop_sym.symbol_expr(); } patht &path = accelerator.path; path.clear(); if (!find_path(path)) { // No more paths! return false; } #if 0 for (expr_sett::iterator it = modified.begin(); it != modified.end(); ++it) { polynomialt poly; exprt target = *it; if (it->type().id() == ID_bool) { // Hack: don't try to accelerate booleans. continue; } if (target.id() == ID_index || target.id() == ID_dereference) { // We'll handle this later. continue; } if (fit_polynomial(target, poly, path)) { std::map<exprt, polynomialt> this_poly; this_poly[target] = poly; if (utils.check_inductive(this_poly, path)) { #ifdef DEBUG std::cout << "Fitted a polynomial for " << expr2c(target, ns) << std::endl; #endif polynomials[target] = poly; accelerator.changed_vars.insert(target); break; } } } if (polynomials.empty()) { return false; } #endif // Fit polynomials for the other variables. expr_sett dirty; utils.find_modified(accelerator.path, dirty); polynomial_acceleratort path_acceleration(symbol_table, goto_functions, loop_counter); goto_programt::instructionst assigns; for (patht::iterator it = accelerator.path.begin(); it != accelerator.path.end(); ++it) { if (it->loc->is_assign() || it->loc->is_decl()) { assigns.push_back(*(it->loc)); } } for (expr_sett::iterator it = dirty.begin(); it != dirty.end(); ++it) { #ifdef DEBUG std::cout << "Trying to accelerate " << expr2c(*it, ns) << std::endl; #endif if (it->type().id() == ID_bool) { // Hack: don't try to accelerate booleans. accelerator.dirty_vars.insert(*it); #ifdef DEBUG std::cout << "Ignoring boolean" << std::endl; #endif continue; } if (it->id() == ID_index || it->id() == ID_dereference) { #ifdef DEBUG std::cout << "Ignoring array reference" << std::endl; #endif continue; } if (accelerator.changed_vars.find(*it) != accelerator.changed_vars.end()) { // We've accelerated variable this already. #ifdef DEBUG std::cout << "We've accelerated it already" << std::endl; #endif continue; } // Hack: ignore variables that depend on array values.. exprt array_rhs; if (depends_on_array(*it, array_rhs)) { #ifdef DEBUG std::cout << "Ignoring because it depends on an array" << std::endl; #endif continue; } polynomialt poly; exprt target(*it); if (path_acceleration.fit_polynomial(assigns, target, poly)) { std::map<exprt, polynomialt> this_poly; this_poly[target] = poly; if (utils.check_inductive(this_poly, accelerator.path)) { polynomials[target] = poly; accelerator.changed_vars.insert(target); continue; } } #ifdef DEBUG std::cout << "Failed to accelerate " << expr2c(*it, ns) << std::endl; #endif // We weren't able to accelerate this target... accelerator.dirty_vars.insert(target); } /* if (!utils.check_inductive(polynomials, assigns)) { // They're not inductive :-( return false; } */ substitutiont stashed; utils.stash_polynomials(program, polynomials, stashed, path); exprt guard; bool path_is_monotone; try { path_is_monotone = utils.do_assumptions(polynomials, path, guard); } catch (std::string s) { // Couldn't do WP. std::cout << "Assumptions error: " << s << std::endl; return false; } exprt pre_guard(guard); for (std::map<exprt, polynomialt>::iterator it = polynomials.begin(); it != polynomials.end(); ++it) { replace_expr(it->first, it->second.to_expr(), guard); } if (path_is_monotone) { // OK cool -- the path is monotone, so we can just assume the condition for // the last iteration. replace_expr(loop_counter, minus_exprt(loop_counter, from_integer(1, loop_counter.type())), guard); } else { // The path is not monotone, so we need to introduce a quantifier to ensure // that the condition held for all 0 <= k < n. symbolt k_sym = utils.fresh_symbol("polynomial::k", unsigned_poly_type()); exprt k = k_sym.symbol_expr(); exprt k_bound = and_exprt(binary_relation_exprt(from_integer(0, k.type()), "<=", k), binary_relation_exprt(k, "<", loop_counter)); replace_expr(loop_counter, k, guard); simplify(guard, ns); implies_exprt implies(k_bound, guard); exprt forall(ID_forall); forall.type() = bool_typet(); forall.copy_to_operands(k); forall.copy_to_operands(implies); guard = forall; } // All our conditions are met -- we can finally build the accelerator! // It is of the form: // // loop_counter = *; // target1 = polynomial1; // target2 = polynomial2; // ... // assume(guard); // assume(no overflows in previous code); program.add_instruction(ASSUME)->guard = pre_guard; program.assign(loop_counter, side_effect_expr_nondett(loop_counter.type())); for (std::map<exprt, polynomialt>::iterator it = polynomials.begin(); it != polynomials.end(); ++it) { program.assign(it->first, it->second.to_expr()); accelerator.changed_vars.insert(it->first); } // Add in any array assignments we can do now. if (!utils.do_arrays(assigns, polynomials, loop_counter, stashed, program)) { // We couldn't model some of the array assignments with polynomials... // Unfortunately that means we just have to bail out. return false; } program.add_instruction(ASSUME)->guard = guard; program.fix_types(); if (path_is_monotone) { utils.ensure_no_overflows(program); } accelerator.pure_accelerator.instructions.swap(program.instructions); return true; }
bool disjunctive_polynomial_accelerationt::fit_polynomial( exprt &var, polynomialt &polynomial, patht &path) { // These are the variables that var depends on with respect to the body. std::vector<expr_listt> parameters; std::set<std::pair<expr_listt, exprt> > coefficients; expr_listt exprs; scratch_programt program(symbol_table); expr_sett influence; cone_of_influence(var, influence); #ifdef DEBUG std::cout << "Fitting a polynomial for " << expr2c(var, ns) << ", which depends on:" << std::endl; for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { std::cout << expr2c(*it, ns) << std::endl; } #endif for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { if (it->id() == ID_index || it->id() == ID_dereference) { // Hack: don't accelerate anything that depends on an array // yet... return false; } exprs.clear(); exprs.push_back(*it); parameters.push_back(exprs); exprs.push_back(loop_counter); parameters.push_back(exprs); } // N exprs.clear(); exprs.push_back(loop_counter); parameters.push_back(exprs); // N^2 exprs.push_back(loop_counter); parameters.push_back(exprs); // Constant exprs.clear(); parameters.push_back(exprs); for (std::vector<expr_listt>::iterator it = parameters.begin(); it != parameters.end(); ++it) { symbolt coeff = utils.fresh_symbol("polynomial::coeff", signed_poly_type()); coefficients.insert(make_pair(*it, coeff.symbol_expr())); // XXX HACK HACK HACK // I'm just constraining these coefficients to prevent overflows messing things // up later... Should really do this properly somehow. program.assume(binary_relation_exprt(from_integer(-(1 << 10), signed_poly_type()), "<", coeff.symbol_expr())); program.assume(binary_relation_exprt(coeff.symbol_expr(), "<", from_integer(1 << 10, signed_poly_type()))); } // Build a set of values for all the parameters that allow us to fit a // unique polynomial. std::map<exprt, exprt> ivals1; std::map<exprt, exprt> ivals2; std::map<exprt, exprt> ivals3; for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { symbolt ival1 = utils.fresh_symbol("polynomial::init", it->type()); symbolt ival2 = utils.fresh_symbol("polynomial::init", it->type()); symbolt ival3 = utils.fresh_symbol("polynomial::init", it->type()); program.assume(binary_relation_exprt(ival1.symbol_expr(), "<", ival2.symbol_expr())); program.assume(binary_relation_exprt(ival2.symbol_expr(), "<", ival3.symbol_expr())); #if 0 if (it->type() == signedbv_typet()) { program.assume(binary_relation_exprt(ival1.symbol_expr(), ">", from_integer(-100, it->type()))); } program.assume(binary_relation_exprt(ival1.symbol_expr(), "<", from_integer(100, it->type()))); if (it->type() == signedbv_typet()) { program.assume(binary_relation_exprt(ival2.symbol_expr(), ">", from_integer(-100, it->type()))); } program.assume(binary_relation_exprt(ival2.symbol_expr(), "<", from_integer(100, it->type()))); if (it->type() == signedbv_typet()) { program.assume(binary_relation_exprt(ival3.symbol_expr(), ">", from_integer(-100, it->type()))); } program.assume(binary_relation_exprt(ival3.symbol_expr(), "<", from_integer(100, it->type()))); #endif ivals1[*it] = ival1.symbol_expr(); ivals2[*it] = ival2.symbol_expr(); ivals3[*it] = ival3.symbol_expr(); //ivals1[*it] = from_integer(1, it->type()); } std::map<exprt, exprt> values; for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { values[*it] = ivals1[*it]; } // Start building the program. Begin by decl'ing each of the // master distinguishers. for (std::list<exprt>::iterator it = distinguishers.begin(); it != distinguishers.end(); ++it) { program.add_instruction(DECL)->code = code_declt(*it); } // Now assume our polynomial fits at each of our sample points. assert_for_values(program, values, coefficients, 1, fixed, var); for (int n = 0; n <= 1; n++) { for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { values[*it] = ivals2[*it]; assert_for_values(program, values, coefficients, n, fixed, var); values[*it] = ivals3[*it]; assert_for_values(program, values, coefficients, n, fixed, var); values[*it] = ivals1[*it]; } } for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { values[*it] = ivals3[*it]; } assert_for_values(program, values, coefficients, 0, fixed, var); assert_for_values(program, values, coefficients, 1, fixed, var); assert_for_values(program, values, coefficients, 2, fixed, var); // Let's make sure that we get a path we have not seen before. for (std::list<distinguish_valuest>::iterator it = accelerated_paths.begin(); it != accelerated_paths.end(); ++it) { exprt new_path = false_exprt(); for (distinguish_valuest::iterator jt = it->begin(); jt != it->end(); ++jt) { exprt distinguisher = jt->first; bool taken = jt->second; if (taken) { not_exprt negated(distinguisher); distinguisher.swap(negated); } or_exprt disjunct(new_path, distinguisher); new_path.swap(disjunct); } program.assume(new_path); } utils.ensure_no_overflows(program); // Now do an ASSERT(false) to grab a counterexample program.add_instruction(ASSERT)->guard = false_exprt(); // If the path is satisfiable, we've fitted a polynomial. Extract the // relevant coefficients and return the expression. try { if (program.check_sat()) { #ifdef DEBUG std::cout << "Found a polynomial" << std::endl; #endif utils.extract_polynomial(program, coefficients, polynomial); build_path(program, path); record_path(program); return true; } } catch (std::string s) { std::cout << "Error in fitting polynomial SAT check: " << s << std::endl; } catch (const char *s) { std::cout << "Error in fitting polynomial SAT check: " << s << std::endl; } return false; }
std::string c_typecheck_baset::to_string(const exprt &expr) { return expr2c(expr, *this); }
std::string linkingt::to_string(const exprt &expr) { return expr2c(expr, ns); }