Example #1
0
box contractor_int::prune(box b, SMTConfig & config) const {
    // ======= Proof =======
    thread_local static box old_box(b);
    if (config.nra_proof) { old_box = b; }

    m_input  = ibex::BitSet::empty(b.size());
    m_output = ibex::BitSet::empty(b.size());
    unsigned i = 0;
    ibex::IntervalVector & iv = b.get_values();
    for (Enode * e : b.get_vars()) {
        if (e->hasSortInt()) {
            auto old_iv = iv[i];
            iv[i] = ibex::integer(iv[i]);
            if (old_iv != iv[i]) {
                m_input.add(i);
                m_output.add(i);
            }
            if (iv[i].is_empty()) {
                b.set_empty();
                break;
            }
        }
        i++;
    }

    // ======= Proof =======
    if (config.nra_proof) {
        output_pruning_step(config.nra_proof_out, old_box, b, config.nra_readable_proof, "integer pruning");
    }
    return b;
}
Example #2
0
contractor_int::contractor_int(box const & b) : contractor_cell(contractor_kind::INT) {
    m_input = ibex::BitSet::empty(b.size());
    auto const & vars = b.get_vars();
    for (unsigned i = 0; i < b.size(); ++i) {
        Enode * const e = vars[i];
        if (e->hasSortInt()) {
            m_input.add(i);
        }
    }
}
box shrink_for_dop(box b) {
    for (Enode * e : b.get_vars()) {
        string const name = e->getCar()->getNameFull();
        if (starts_with(name, "forall_")) {
            string const exist_var_name = name.substr(7);
            auto exist_var_intv = b[exist_var_name];
            b[name] = exist_var_intv;
        }
    }
    return b;
}
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;
}
Example #5
0
contractor default_strategy::build_contractor(box const & box,
                                              scoped_vec<shared_ptr<constraint>> const & ctrs,
                                              bool const complete,
                                              SMTConfig const & config) const {
    bool const use_cache = true;

    // 1. Categorize constraints
    vector<shared_ptr<nonlinear_constraint>> nl_ctrs;
    vector<shared_ptr<ode_constraint>> ode_ctrs_rev;
    vector<shared_ptr<generic_forall_constraint>> generic_forall_ctrs;
    for (shared_ptr<constraint> const ctr : ctrs.get_reverse()) {
        switch (ctr->get_type()) {
        case constraint_type::Nonlinear: {
            auto nl_ctr = dynamic_pointer_cast<nonlinear_constraint>(ctr);
            nl_ctrs.push_back(nl_ctr);
            break;
        }
        case constraint_type::ODE: {
            auto ode_ctr = dynamic_pointer_cast<ode_constraint>(ctr);
            ode_ctrs_rev.push_back(ode_ctr);
            break;
        }
        case constraint_type::GenericForall: {
            auto gf_ctr = dynamic_pointer_cast<generic_forall_constraint>(ctr);
            generic_forall_ctrs.push_back(gf_ctr);
            break;
        }
        case constraint_type::ForallT: {
            // Do nothing
            break;
        }
        default:
            DREAL_LOG_FATAL << "Unknown Constraint Type: " << ctr->get_type() << " " <<  *ctr << endl;
        }
    }
    vector<shared_ptr<ode_constraint>> ode_ctrs(ode_ctrs_rev);
    reverse(ode_ctrs.begin(), ode_ctrs.end());

    vector<contractor> ctcs;
    ctcs.reserve(ctrs.size());
    // 2.0 Build Sample Contractor
    if (config.nra_sample > 0 && complete) {
        ctcs.push_back(mk_contractor_sample(box, config.nra_sample, ctrs.get_vec()));
    }
    // 2.1 Build nonlinear contractors
    vector<contractor> nl_ctcs;
    for (auto const & nl_ctr : nl_ctrs) {
        if (!nl_ctr->is_neq()) {
            nl_ctcs.push_back(mk_contractor_ibex_fwdbwd(nl_ctr, use_cache));
        } else {
            // Case: != (not equal), do nothing
        }
    }
    contractor nl_ctc = mk_contractor_seq(nl_ctcs);
    ctcs.insert(ctcs.end(), nl_ctcs.begin(), nl_ctcs.end());

    // 2.2. Build Polytope Contractor
    if (config.nra_polytope) {
        ctcs.push_back(mk_contractor_ibex_polytope(config.nra_precision, box.get_vars(), nl_ctrs));
    }
    // 2.3. Int Contractor
    ctcs.push_back(mk_contractor_int(box));
    // 2.4. Build generic forall contractors
    for (auto const & generic_forall_ctr : generic_forall_ctrs) {
        ctcs.push_back(mk_contractor_generic_forall(box, generic_forall_ctr));
    }

    if (complete && ode_ctrs.size() > 0) {
        // Add ODE Contractors only for complete check
        // 2.5. Build GSL Contractors (using CAPD4)
        vector<contractor> ode_gsl_ctcs;
        if (config.nra_ODE_sampling) {
            // 2.5.1 Build Eval contractors
            vector<contractor> eval_ctcs;
            for (auto const & nl_ctr : nl_ctrs) {
                eval_ctcs.push_back(mk_contractor_eval(nl_ctr, false));
            }
            contractor eval_ctc = mk_contractor_seq(eval_ctcs);
            if (config.nra_parallel) {
                vector<contractor> nl_ctcs2;
                for (auto const & nl_ctr : nl_ctrs) {
                    if (!nl_ctr->is_neq()) {
                        nl_ctcs2.push_back(mk_contractor_ibex_fwdbwd(nl_ctr, false));
                    } else {
                        // Case: != (not equal), do nothing
                    }
                }
                contractor nl_ctc2 = mk_contractor_seq(nl_ctcs2);
                for (auto const & ode_ctr : ode_ctrs) {
                    // Add Forward ODE Pruning (Underapproximation, using GNU GSL)
                    ode_gsl_ctcs.push_back(mk_contractor_gsl(box, ode_ctr, eval_ctc, ode_direction::FWD, false, config.nra_ODE_fwd_timeout));
                    ode_gsl_ctcs.push_back(nl_ctc2);
                }
            } else {
                for (auto const & ode_ctr : ode_ctrs) {
                    // Add Forward ODE Pruning (Underapproximation, using GNU GSL)
                    ode_gsl_ctcs.push_back(mk_contractor_gsl(box, ode_ctr, eval_ctc, ode_direction::FWD, use_cache, config.nra_ODE_fwd_timeout));
                    ode_gsl_ctcs.push_back(nl_ctc);
                }
            }
        }
        // 2.6. Build ODE Contractors (using CAPD4)
        vector<contractor> ode_capd4_fwd_ctcs;
        vector<contractor> ode_capd4_bwd_ctcs;
        for (auto const & ode_ctr : ode_ctrs) {
            // 2.6.1. Add Forward ODE Pruning (Overapproximation, using CAPD4)
            if (config.nra_ODE_cache) {
                ode_capd4_fwd_ctcs.emplace_back(
                    mk_contractor_cache(
                        mk_contractor_try(
                            mk_contractor_seq(mk_contractor_capd_full(box, ode_ctr, ode_direction::FWD, config.nra_ODE_taylor_order, config.nra_ODE_grid_size, use_cache, config.nra_ODE_fwd_timeout),
                                              nl_ctc))));
            } else {
                ode_capd4_fwd_ctcs.emplace_back(
                    mk_contractor_try(
                        mk_contractor_seq(
                            mk_contractor_capd_full(box, ode_ctr, ode_direction::FWD, config.nra_ODE_taylor_order, config.nra_ODE_grid_size, use_cache, config.nra_ODE_fwd_timeout),
                            nl_ctc)));
            }
        }
        if (!config.nra_ODE_forward_only) {
            // 2.6.2. Add Backward ODE Pruning (Overapproximation, using CAPD4)
            for (auto const & ode_ctr : ode_ctrs_rev) {
                if (config.nra_ODE_cache) {
                    ode_capd4_bwd_ctcs.emplace_back(
                        mk_contractor_cache(
                            mk_contractor_try(
                                mk_contractor_seq(
                                    mk_contractor_capd_full(box, ode_ctr, ode_direction::BWD, config.nra_ODE_taylor_order, config.nra_ODE_grid_size, use_cache, config.nra_ODE_bwd_timeout),
                                    nl_ctc))));
                } else {
                    ode_capd4_bwd_ctcs.emplace_back(
                        mk_contractor_try(
                            mk_contractor_seq(
                                mk_contractor_capd_full(box, ode_ctr, ode_direction::BWD, config.nra_ODE_taylor_order, config.nra_ODE_grid_size, use_cache, config.nra_ODE_bwd_timeout),
                                nl_ctc)));
                }
            }
        }
        if (config.nra_ODE_sampling) {
            if (config.nra_parallel) {
                ctcs.push_back(mk_contractor_parallel_any(
                                   mk_contractor_try_or(mk_contractor_throw_if_empty(mk_contractor_seq(ode_gsl_ctcs)),
                                                        mk_contractor_empty()),
                                   mk_contractor_seq(mk_contractor_seq(ode_capd4_fwd_ctcs),
                                                     mk_contractor_seq(ode_capd4_bwd_ctcs))));
            } else {
                ctcs.push_back(
                    mk_contractor_try_or(
                        // Try Underapproximation(GSL) if it fails try Overapproximation(CAPD4)
                        mk_contractor_throw_if_empty(mk_contractor_seq(ode_gsl_ctcs)),
                        mk_contractor_seq(mk_contractor_seq(ode_capd4_fwd_ctcs),
                                          mk_contractor_seq(ode_capd4_bwd_ctcs))));
            }
        } else {
            ctcs.insert(ctcs.end(), ode_capd4_fwd_ctcs.begin(), ode_capd4_fwd_ctcs.end());
            ctcs.insert(ctcs.end(), ode_capd4_bwd_ctcs.begin(), ode_capd4_bwd_ctcs.end());
        }
    }
    if (complete) {
        // 2.7 Build Eval contractors
        vector<contractor> eval_ctcs;
        for (auto const & nl_ctr : nl_ctrs) {
            eval_ctcs.push_back(mk_contractor_eval(nl_ctr, use_cache));
        }
        return mk_contractor_seq(mk_contractor_fixpoint(default_strategy::term_cond, ctcs),
                                 mk_contractor_seq(eval_ctcs));
    } else {
        return mk_contractor_fixpoint(default_strategy::term_cond, ctcs);
    }
}
Example #6
0
box ncbt_icp::solve(box b, contractor & ctc, SMTConfig & config) {
    thread_local static unordered_set<shared_ptr<constraint>> used_constraints;
    used_constraints.clear();
    static unsigned prune_count = 0;
    thread_local static vector<box> box_stack;
    box_stack.clear();
    box_stack.push_back(b);
    do {
        // Loop Invariant
        DREAL_LOG_INFO << "ncbt_icp::solve - loop"
                       << "\t" << "box stack Size = " << box_stack.size();
        b = box_stack.back();
        try {
            ctc.prune(b, config);
            auto const this_used_constraints = ctc.used_constraints();
            used_constraints.insert(this_used_constraints.begin(), this_used_constraints.end());
            if (config.nra_use_stat) { config.nra_stat.increase_prune(); }
        } catch (contractor_exception & e) {
            // Do nothing
        }
        prune_count++;
        box_stack.pop_back();
        if (!b.is_empty()) {
            // SAT
            tuple<int, box, box> splits = b.bisect(config.nra_precision);
            if (config.nra_use_stat) { config.nra_stat.increase_branch(); }
            int const index = get<0>(splits);
            if (index >= 0) {
                box const & first    = get<1>(splits);
                box const & second   = get<2>(splits);
                assert(first.get_idx_last_branched() == index);
                assert(second.get_idx_last_branched() == index);
                if (second.is_bisectable()) {
                    box_stack.push_back(second);
                    box_stack.push_back(first);
                } else {
                    box_stack.push_back(first);
                    box_stack.push_back(second);
                }
            } else {
                break;
            }
        } else {
            // UNSAT (b is emptified by pruning operators)
            // If this bisect_var is not used in all used
            // constraints, this box is safe to be popped.
            thread_local static unordered_set<Enode *> used_vars;
            used_vars.clear();
            for (auto used_ctr : used_constraints) {
                auto this_used_vars = used_ctr->get_vars();
                used_vars.insert(this_used_vars.begin(), this_used_vars.end());
            }
            while (box_stack.size() > 0) {
                int const bisect_var = box_stack.back().get_idx_last_branched();
                assert(bisect_var >= 0);
                // If this bisect_var is not used in all used
                // constraints, this box is safe to be popped.
                if (used_vars.find(b.get_vars()[bisect_var]) != used_vars.end()) {
                    // DREAL_LOG_FATAL << b.get_vars()[bisect_var] << " is used in "
                    //                 << *used_ctr << " and it's not safe to skip";
                    break;
                }
                // DREAL_LOG_FATAL << b.get_vars()[bisect_var] << " is not used and it's safe to skip this box"
                //                 << " (" << box_stack.size() << ")";
                box_stack.pop_back();
            }
        }
    } while (box_stack.size() > 0);
    DREAL_LOG_DEBUG << "prune count = " << prune_count;
    ctc.set_used_constraints(used_constraints);
    return b;
}
void contractor_generic_forall::handle_disjunction(box & b, vector<Enode *> const &vec, bool const p, SMTConfig & config) {
    DREAL_LOG_DEBUG << "contractor_generic_forall::handle_disjunction" << endl;
    unordered_set<Enode *> forall_vars;
    for (Enode * e : vec) {
        std::unordered_set<Enode *> const & vars = e->get_forall_vars();
        forall_vars.insert(vars.begin(), vars.end());
    }

    unordered_map<Enode*, ibex::Interval> subst;
    if (!forall_vars.empty()) {
        // Step 2. Find a counter-example
        //         Solve(¬ l_1 ∧ ¬ l_2 ∧ ... ∧ ¬ l_n)
        //
        //         Make each ¬ l_i as a contractor ctc_i
        //         Make a fixed_point contractor with ctc_is.
        //         Pass it to icp::solve

        box counterexample = find_CE(b, forall_vars, vec, p, config);
        if (counterexample.is_empty()) {
            // Step 2.1. (NO Counterexample)
            //           Return B.
            DREAL_LOG_DEBUG << "handle_disjunction: no counterexample found." << endl
                            << "current box = " << endl
                            << b << endl;
            return;
        } else {
            // Step 2.2. (There IS a counterexample C)
            //
            //      Using C, prune B.
            //
            // We've found a counterexample (c1, c2) where ¬ f(c1, c2) holds
            // Prune X using a point 'y = c2'. (technically, a point in c2, which is an interval)
            subst = make_subst_from_value(counterexample, forall_vars);
        }
    }

    // Step 3. Compute B_i = prune(B, l_i)
    //         Update B with ∨ B_i
    //                       i
    thread_local static vector<box> boxes;
    boxes.clear();
    auto vars = b.get_vars();
    unordered_set<Enode*> const var_set(vars.begin(), vars.end());
    for (Enode * e : vec) {
        if (!e->get_exist_vars().empty()) {
            lbool polarity = p ? l_True : l_False;
            if (e->isNot()) {
                polarity = !polarity;
                e = e->get1st();
            }
            auto ctr = make_shared<nonlinear_constraint>(e, var_set, polarity, subst);
            if (ctr->get_var_array().size() == 0) {
                auto result = ctr->eval(b);
                if (result.first != false) {
                    boxes.emplace_back(b);
                }
            } else {
                contractor ctc = mk_contractor_ibex_fwdbwd(ctr);
                box bt(b);
                ctc.prune(bt, config);
                m_output.union_with(ctc.output());
                unordered_set<shared_ptr<constraint>> const & used_ctrs = ctc.used_constraints();
                m_used_constraints.insert(used_ctrs.begin(), used_ctrs.end());
                boxes.emplace_back(bt);
            }
        }
    }
    b = hull(boxes);
    return;
}