double nlopt_eval_enode(const double* x, void * extra) { auto extra_info = static_cast<tuple<Enode *, box const &, bool> *>(extra); Enode * e = get<0>(*extra_info); box const & b = get<1>(*extra_info); bool const polarity = get<2>(*extra_info); unordered_map<Enode *, double> var_map; unsigned i = 0; for (Enode * e : b.get_vars()) { if (e->isForallVar()) { var_map.emplace(e, x[i]); i++; } else { var_map.emplace(e, b[e].mid()); } } try { double const ret1 = eval_enode(e->get1st(), var_map); double const ret2 = eval_enode(e->get2nd(), var_map); double ret = 0; if (e->isLt() || e->isLeq() || e->isEq()) { ret = ret1 - ret2; } else if (e->isGt() || e->isGeq()) { ret = ret2 - ret1; } else if (e->isEq()) { throw runtime_error("nlopt_obj: something is wrong."); } if (!polarity) { ret = - ret; } return ret; } catch (exception & e) { DREAL_LOG_FATAL << "Exception in nlopt_eval_enode: " << e.what() << endl; throw e; } }
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; }
Enode * Egraph::canonizeDTC( Enode * formula, bool split_eqs ) { assert( config.sat_lazy_dtc != 0 ); assert( config.logic == QF_UFLRA || config.logic == QF_UFIDL ); list< Enode * > dtc_axioms; vector< Enode * > unprocessed_enodes; initDupMap1( ); unprocessed_enodes.push_back( formula ); // // 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 ( valDupMap1( enode ) != NULL ) { unprocessed_enodes.pop_back( ); continue; } bool unprocessed_children = false; Enode * arg_list; for ( arg_list = enode->getCdr( ) ; arg_list != enil ; arg_list = arg_list->getCdr( ) ) { Enode * arg = arg_list->getCar( ); assert( arg->isTerm( ) ); // // Push only if it is unprocessed // if ( valDupMap1( arg ) == NULL ) { unprocessed_enodes.push_back( arg ); unprocessed_children = true; } } // // SKip if unprocessed_children // if ( unprocessed_children ) continue; unprocessed_enodes.pop_back( ); Enode * result = NULL; // // Replace arithmetic atoms with canonized version // if ( enode->isTAtom( ) && !enode->isUp( ) ) { // No need to do anything if node is purely UF if ( isRootUF( enode ) ) { if ( config.verbosity > 2 ) cerr << "# Egraph::Skipping canonization of " << enode << " as it's root is purely UF" << endl; result = enode; } else { LAExpression a( enode ); result = a.toEnode( *this ); #ifdef PRODUCE_PROOF const uint64_t partitions = getIPartitions( enode ); assert( partitions != 0 ); setIPartitions( result, partitions ); #endif if ( split_eqs && result->isEq( ) ) { #ifdef PRODUCE_PROOF if ( config.produce_inter > 0 ) opensmt_error2( "can't compute interpolant for equalities at the moment ", enode ); #endif LAExpression aa( enode ); Enode * e = aa.toEnode( *this ); #ifdef PRODUCE_PROOF assert( partitions != 0 ); setIPartitions( e, partitions ); #endif Enode * lhs = e->get1st( ); Enode * rhs = e->get2nd( ); Enode * leq = mkLeq( cons( lhs, cons( rhs ) ) ); LAExpression b( leq ); leq = b.toEnode( *this ); #ifdef PRODUCE_PROOF assert( partitions != 0 ); setIPartitions( leq, partitions ); #endif Enode * geq = mkGeq( cons( lhs, cons( rhs ) ) ); LAExpression c( geq ); geq = c.toEnode( *this ); #ifdef PRODUCE_PROOF assert( partitions != 0 ); setIPartitions( geq, partitions ); #endif Enode * not_e = mkNot( cons( enode ) ); Enode * not_l = mkNot( cons( leq ) ); Enode * not_g = mkNot( cons( geq ) ); // Add clause ( !x=y v x<=y ) Enode * c1 = mkOr( cons( not_e , cons( leq ) ) ); // Add clause ( !x=y v x>=y ) Enode * c2 = mkOr( cons( not_e , cons( geq ) ) ); // Add clause ( x=y v !x>=y v !x<=y ) Enode * c3 = mkOr( cons( enode , cons( not_l , cons( not_g ) ) ) ); // Add conjunction of clauses Enode * ax = mkAnd( cons( c1 , cons( c2 , cons( c3 ) ) ) ); dtc_axioms.push_back( ax ); result = enode; } } } // // If nothing have been done copy and simplify // if ( result == NULL ) result = copyEnodeEtypeTermWithCache( enode ); assert( valDupMap1( enode ) == NULL ); storeDupMap1( enode, result ); #ifdef PRODUCE_PROOF if ( config.produce_inter > 0 ) { // Setting partitions for result setIPartitions( result, getIPartitions( enode ) ); // Setting partitions for negation as well occ if atom if ( result->hasSortBool( ) ) { setIPartitions( mkNot( cons( result ) ) , getIPartitions( enode ) ); } } #endif } Enode * new_formula = valDupMap1( formula ); assert( new_formula ); doneDupMap1( ); if ( !dtc_axioms.empty( ) ) { dtc_axioms.push_back( new_formula ); new_formula = mkAnd( cons( dtc_axioms ) ); } return new_formula; }