void abstract_expression( const predicatest &predicates, exprt &expr, const namespacet &ns) { if(expr.type().id()!=ID_bool) throw "abstract_expression expects expression of type Boolean"; simplify(expr, ns); if(is_valid(expr, ns)) { // If expr is valid, we can abstract it as 'true' expr.make_true(); } else if(is_unsatisfiable(expr, ns)) { // If expr is unsatisfiable, we can abstract it as 'false' expr.make_false(); } else if(expr.id()==ID_and || expr.id()==ID_or || expr.id()==ID_implies || expr.id()==ID_xor) { Forall_operands(it, expr) abstract_expression(predicates, *it, ns); } else if(expr.id()==ID_not) { assert(expr.operands().size()==1); abstract_expression(predicates, expr.op0(), ns); // remove double negation if(expr.op0().id()==ID_not && expr.op0().operands().size()==1) { exprt tmp; tmp.swap(expr.op0().op0()); expr.swap(tmp); } } else if(expr.id()==ID_if) { assert(expr.operands().size()==3); Forall_operands(it, expr) abstract_expression(predicates, *it, ns); exprt true_expr(ID_and, bool_typet()); true_expr.copy_to_operands(expr.op0(), expr.op1()); exprt false_expr(ID_and, bool_typet()); false_expr.copy_to_operands(gen_not(expr.op0()), expr.op2()); exprt or_expr(ID_or, bool_typet()); or_expr.move_to_operands(true_expr, false_expr); expr.swap(or_expr); } else if(expr.id()==ID_equal || expr.id()==ID_notequal) { if(expr.operands().size()!=2) throw expr.id_string()+" takes two operands"; // Is it equality on Booleans? if(expr.op0().type().id()==ID_bool && expr.op1().type().id()==ID_bool) { // leave it in Forall_operands(it, expr) abstract_expression(predicates, *it, ns); } else // other types, make it a predicate { if(has_non_boolean_if(expr)) { lift_if(expr); abstract_expression(predicates, expr, ns); } else make_it_a_predicate(predicates, expr, ns); } } else if(expr.is_constant()) { // leave it as is } else if(has_non_boolean_if(expr)) { lift_if(expr); abstract_expression(predicates, expr, ns); } else { make_it_a_predicate(predicates, expr, ns); } }
// ------------------------ // lemma_bool_inductive_generalizer /// Inductive generalization by dropping and expanding literals void lemma_bool_inductive_generalizer::operator()(lemma_ref &lemma) { if (lemma->get_cube().empty()) return; m_st.count++; scoped_watch _w_(m_st.watch); unsigned uses_level; pred_transformer &pt = lemma->get_pob()->pt(); ast_manager &m = pt.get_ast_manager(); contains_array_op_proc has_array_op(m); check_pred has_arrays(has_array_op, m); expr_ref_vector cube(m); cube.append(lemma->get_cube()); bool dirty = false; expr_ref true_expr(m.mk_true(), m); ptr_vector<expr> processed; expr_ref_vector extra_lits(m); unsigned weakness = lemma->weakness(); unsigned i = 0, num_failures = 0; while (i < cube.size() && (!m_failure_limit || num_failures < m_failure_limit)) { expr_ref lit(m); lit = cube.get(i); if (m_array_only && !has_arrays(lit)) { processed.push_back(lit); ++i; continue; } cube[i] = true_expr; if (cube.size() > 1 && pt.check_inductive(lemma->level(), cube, uses_level, weakness)) { num_failures = 0; dirty = true; for (i = 0; i < cube.size() && processed.contains(cube.get(i)); ++i); } else { // check if the literal can be expanded and any single // literal in the expansion can replace it extra_lits.reset(); extra_lits.push_back(lit); expand_literals(m, extra_lits); SASSERT(extra_lits.size() > 0); bool found = false; if (extra_lits.get(0) != lit && extra_lits.size() > 1) { for (unsigned j = 0, sz = extra_lits.size(); !found && j < sz; ++j) { cube[i] = extra_lits.get(j); if (pt.check_inductive(lemma->level(), cube, uses_level, weakness)) { num_failures = 0; dirty = true; found = true; processed.push_back(extra_lits.get(j)); for (i = 0; i < cube.size() && processed.contains(cube.get(i)); ++i); } } } if (!found) { cube[i] = lit; processed.push_back(lit); ++num_failures; ++m_st.num_failures; ++i; } } } if (dirty) { TRACE("spacer", tout << "Generalized from:\n" << mk_and(lemma->get_cube()) << "\ninto\n" << mk_and(cube) << "\n";); lemma->update_cube(lemma->get_pob(), cube); SASSERT(uses_level >= lemma->level()); lemma->set_level(uses_level); }