map<Enode *, bool> CoreSMTSolver::getBoolModel() { map<Enode *, bool> ret; for (int i = 0; i < trail.size(); i++) { Lit const & l = trail[i]; Var const v = var(l); if (v >= 2) { Enode * e = theory_handler->varToEnode(v); bool p = value(l) == l_True; if (e->isNot()) { e = e->get1st(); p = !p; } if (e->isVar()) { if (sign(l)) { p = !p; } ret.emplace(e, p); } } } return ret; }
box refine_CE_with_nlopt_core(box counterexample, vector<Enode*> const & opt_ctrs, vector<Enode*> const & side_ctrs) { // Plug-in `a` into the constraint and optimize `b` in the counterexample `M` by solving: // // ∃ y_opt ∈ I_y. ∀ y ∈ I_y. f(a, y_opt) >= f(a, y) — (2) // // using local optimizer (i.e. nlopt). // Let `M’ = (a, b_opt)` be a model for (2). DREAL_LOG_DEBUG << "================================" << endl; DREAL_LOG_DEBUG << " Before Refinement " << endl; DREAL_LOG_DEBUG << "================================" << endl; DREAL_LOG_DEBUG << counterexample << endl; DREAL_LOG_DEBUG << "================================" << endl; static bool initialized = false; static vector<double> lb, ub, init; init.clear(); for (Enode * e : counterexample.get_vars()) { if (e->isForallVar()) { if (!initialized) { lb.push_back(e->getDomainLowerBound()); ub.push_back(e->getDomainUpperBound()); } init.push_back(counterexample[e].mid()); DREAL_LOG_DEBUG << lb.back() << " <= " << init.back() << " <= " << ub.back() << endl; } } auto const n = init.size(); static nlopt::opt opt(nlopt::LD_SLSQP, n); if (!initialized) { opt.set_lower_bounds(lb); opt.set_upper_bounds(ub); // set tollerance // TODO(soonhok): set precision // opt.set_xtol_rel(0.0001); opt.set_xtol_abs(0.001); opt.set_maxtime(0.01); initialized = true; } opt.remove_equality_constraints(); opt.remove_inequality_constraints(); // set objective function vector<tuple<Enode *, box const &, bool> *> extra_vec; Enode * e = opt_ctrs[0]; bool polarity = false; while (e->isNot()) { e = e->get1st(); polarity = !polarity; } auto extra = new tuple<Enode *, box const &, bool>(e, counterexample, polarity); extra_vec.push_back(extra); opt.set_min_objective(nlopt_obj, extra); opt.add_inequality_constraint(nlopt_side_condition, extra); DREAL_LOG_DEBUG << "objective function is added: " << e << endl; // set side conditions for (Enode * e : side_ctrs) { bool polarity = false; while (e->isNot()) { e = e->get1st(); polarity = !polarity; } auto extra = new tuple<Enode *, box const &, bool>(e, counterexample, polarity); extra_vec.push_back(extra); DREAL_LOG_DEBUG << "refine_counterexample_with_nlopt: Side condition is added: " << e << endl; if (e->isEq()) { opt.add_equality_constraint(nlopt_side_condition, extra); } else if (e->isLt() || e->isLeq() || e->isGt() || e->isGeq()) { opt.add_inequality_constraint(nlopt_side_condition, extra); } } try { vector<double> output = opt.optimize(init); unsigned i = 0; for (Enode * e : counterexample.get_vars()) { if (e->isForallVar()) { counterexample[e] = output[i]; i++; } } } catch (nlopt::roundoff_limited & e) { } catch (std::runtime_error & e) { DREAL_LOG_DEBUG << e.what() << endl; } for (auto extra : extra_vec) { delete extra; } DREAL_LOG_DEBUG << "================================" << endl; DREAL_LOG_DEBUG << " After Refinement " << endl; DREAL_LOG_DEBUG << "================================" << endl; DREAL_LOG_DEBUG << counterexample << endl; DREAL_LOG_DEBUG << "================================" << endl; return counterexample; }
// // Performs the actual cnfization // bool Tseitin::cnfize( Enode * formula, map< enodeid_t, Enode * > & cnf_cache ) { (void)cnf_cache; assert( formula ); assert( !formula->isAnd( ) ); Enode * arg_def = egraph.valDupMap1( formula ); if ( arg_def != NULL ) { vector< Enode * > clause; clause.push_back( arg_def ); #ifdef PRODUCE_PROOF if ( config.produce_inter > 0 ) return solver.addSMTClause( clause, egraph.getIPartitions( formula ) ); #endif return solver.addSMTClause( clause ); } vector< Enode * > unprocessed_enodes; // Stack for unprocessed enodes unprocessed_enodes.push_back( formula ); // formula needs to be processed // // Visit the DAG of the formula from the leaves to the root // while( !unprocessed_enodes.empty( ) ) { Enode * enode = unprocessed_enodes.back( ); // // Skip if the node has already been processed before // if ( egraph.valDupMap1( enode ) != NULL ) { unprocessed_enodes.pop_back( ); continue; } bool unprocessed_children = false; Enode * arg_list; for ( arg_list = enode->getCdr( ) ; arg_list != egraph.enil ; arg_list = arg_list->getCdr( ) ) { Enode * arg = arg_list->getCar( ); assert( arg->isTerm( ) ); // // Push only if it is an unprocessed boolean operator // if ( enode->isBooleanOperator( ) && egraph.valDupMap1( arg ) == NULL ) { unprocessed_enodes.push_back( arg ); unprocessed_children = true; } // // If it is an atom (either boolean or theory) just // store it in the cache // else if ( arg->isAtom( ) ) { egraph.storeDupMap1( arg, arg ); } } // // SKip if unprocessed_children // if ( unprocessed_children ) continue; unprocessed_enodes.pop_back( ); Enode * result = NULL; // // At this point, every child has been processed // // // Do the actual cnfization, according to the node type // char def_name[ 32 ]; if ( enode->isLit( ) ) { result = enode; } else if ( enode->isNot( ) ) { Enode * arg_def = egraph.valDupMap1( enode->get1st( ) ); assert( arg_def ); result = egraph.mkNot( egraph.cons( arg_def ) ); // Toggle the literal } else { Enode * arg_def = NULL; Enode * new_arg_list = egraph.copyEnodeEtypeListWithCache( enode->getCdr( ) ); // // If the enode is not top-level it needs a definition // if ( formula != enode ) { sprintf( def_name, CNF_STR, formula->getId( ), enode->getId( ) ); egraph.newSymbol( def_name, sstore.mkBool( ) ); arg_def = egraph.mkVar( def_name ); #ifdef PRODUCE_PROOF if ( config.produce_inter > 0 ) { // Tag Positive and negative literals egraph.tagIFormula( arg_def , egraph.getIPartitions( enode ) ); egraph.tagIFormula( egraph.mkNot( egraph.cons( arg_def ) ) , egraph.getIPartitions( enode ) ); } #endif } #ifdef PRODUCE_PROOF uint64_t partitions = 0; if ( config.produce_inter > 0 ) { partitions = egraph.getIPartitions( enode ); assert( partitions != 0 ); } #endif // // Handle boolean operators // if ( enode->isAnd( ) ) cnfizeAnd( new_arg_list, arg_def #ifdef PRODUCE_PROOF , partitions #endif ); else if ( enode->isOr( ) ) cnfizeOr( new_arg_list, arg_def #ifdef PRODUCE_PROOF , partitions #endif ); else if ( enode->isIff( ) ) cnfizeIff( new_arg_list, arg_def #ifdef PRODUCE_PROOF , partitions #endif ); else if ( enode->isXor( ) ) cnfizeXor( new_arg_list, arg_def #ifdef PRODUCE_PROOF , partitions #endif ); else { opensmt_error2( "operator not handled ", enode->getCar( ) ); } if ( arg_def != NULL ) result = arg_def; } assert( egraph.valDupMap1( enode ) == NULL ); egraph.storeDupMap1( enode, result ); } if ( formula->isNot( ) ) { // Retrieve definition of argument Enode * arg_def = egraph.valDupMap1( formula->get1st( ) ); assert( arg_def ); vector< Enode * > clause; clause.push_back( toggleLit( arg_def ) ); #ifdef PRODUCE_PROOF if ( config.produce_inter > 0 ) return solver.addSMTClause( clause, egraph.getIPartitions( formula ) ); #endif return solver.addSMTClause( clause ); } return true; }