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; }
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; }