<commit_before>/*++
Copyright (c) 2013 Microsoft Corporation

Module Name:

    optsmt.cpp

Abstract:

    Objective optimization method.

Author:

    Anh-Dung Phan (t-anphan) 2013-10-16

Notes:

    Suppose we obtain solution t1 = k1, ..., tn = kn-epsilon
    Assert:
      t1 > k1 \/ t2 > k2 \/ ... \/ tn >= kn
    If this solution is satisfiable, then for each t_i, maximize the
    assignment and assert the new frontier.
    Claim: we don't necessarily have to freeze assignments of
    t_i when optimizing assignment for t_j
    because the state will always satisfy the disjunction.
    If one of the k_i is unbounded, then omit a disjunction for it.

--*/

#include <typeinfo>
#include "optsmt.h"
#include "opt_solver.h"
#include "arith_decl_plugin.h"
#include "theory_arith.h"
#include "ast_pp.h"
#include "model_pp.h"
#include "th_rewriter.h"
#include "opt_params.hpp"

namespace opt {

    void optsmt::set_cancel(bool f) {
        TRACE("opt", tout << "set cancel: " << f << "\n";);
        m_cancel = f;
    }

    void optsmt::set_max(vector<inf_eps>& dst, vector<inf_eps> const& src, expr_ref_vector& fmls) {
        for (unsigned i = 0; i < src.size(); ++i) {
            if (src[i] >= dst[i]) {
                dst[i] = src[i];
                m_lower_fmls[i] = fmls[i].get();
                if (dst[i].is_pos() && !dst[i].is_finite()) { // review: likely done already.
                    m_lower_fmls[i] = m.mk_false();
                    fmls[i] = m.mk_false();
                }
            }
            else if (src[i] < dst[i] && !m.is_true(m_lower_fmls[i].get())) {
                fmls[i] = m_lower_fmls[i].get();
            }
        }
    }

    /*
        Enumerate locally optimal assignments until fixedpoint.
    */
    lbool optsmt::basic_opt() {
        lbool is_sat = l_true;

        while (is_sat == l_true && !m_cancel) {
            is_sat = m_s->check_sat(0, 0);
            if (is_sat == l_true) {
                update_lower();
            }
        }

        if (m_cancel || is_sat == l_undef) {
            return l_undef;
        }

        // set the solution tight.
        for (unsigned i = 0; i < m_lower.size(); ++i) {
            m_upper[i] = m_lower[i];
        }

        return l_true;
    }

    /*
        Enumerate locally optimal assignments until fixedpoint.
    */
    lbool optsmt::farkas_opt() {
        smt::theory_opt& opt = m_s->get_optimizer();

        if (typeid(smt::theory_inf_arith) != typeid(opt)) {
            return l_undef;
        }

        lbool is_sat = l_true;

        while (is_sat == l_true && !m_cancel) {
            is_sat = update_upper();
        }

        if (m_cancel || is_sat == l_undef) {
            return l_undef;
        }

        // set the solution tight.
        for (unsigned i = 0; i < m_lower.size(); ++i) {
            m_upper[i] = m_lower[i];
        }

        return l_true;
    }

    lbool optsmt::symba_opt() {
        smt::theory_opt& opt = m_s->get_optimizer();

        if (typeid(smt::theory_inf_arith) != typeid(opt)) {
            return l_undef;
        }

        expr_ref_vector ors(m), disj(m);
        expr_ref or(m), bound(m.mk_true(), m);
        for (unsigned i = 0; i < m_upper.size(); ++i) {
            ors.push_back(m_s->mk_ge(i, m_upper[i]));
        }
        {
            solver::scoped_push _push(*m_s);
            or = m.mk_or(ors.size(), ors.c_ptr());
            m_s->assert_expr(or);
            lbool is_sat = l_true;
            while (!m_cancel) {
                is_sat = m_s->check_sat(0,0);
                if (is_sat == l_true) {
                    disj.reset();
                    m_s->maximize_objectives(disj);
                    m_s->get_model(m_model);
                    for (unsigned i = 0; i < ors.size(); ++i) {
                        expr_ref tmp(m);
                        m_model->eval(ors[i].get(), tmp);
                        if (m.is_true(tmp)) {
                            m_lower[i] = m_upper[i];
                            ors[i]  = m.mk_false();
                            disj[i] = m.mk_false();
                        }
                    }
                    set_max(m_lower, m_s->get_objective_values(), disj);
                    or = m.mk_or(ors.size(), ors.c_ptr());
                    m_s->assert_expr(or);
                }
                else if (is_sat == l_undef) {
                    return l_undef;
                }
                else {
                    break;
                }
            }
        }
        bound = m.mk_or(m_lower_fmls.size(), m_lower_fmls.c_ptr());
        m_s->assert_expr(bound);

        if (m_cancel) {
            return l_undef;
        }
        return basic_opt();
    }

    void optsmt::update_lower(unsigned idx, inf_eps const& v) {
        m_lower_fmls[idx] = m_s->mk_ge(idx, v);
        m_lower[idx] = v;
    }

    void optsmt::update_upper(unsigned idx, inf_eps const& v) {
        m_upper[idx] = v;
    }

    void optsmt::update_lower() {
        expr_ref_vector disj(m);
        m_s->get_model(m_model);
        m_s->maximize_objectives(disj);
        set_max(m_lower, m_s->get_objective_values(), disj);
        TRACE("opt",
              for (unsigned i = 0; i < m_lower.size(); ++i) {
                  tout << m_lower[i] << " ";
              }
              tout << "\n";
              model_pp(tout, *m_model);
              );
        IF_VERBOSE(2, verbose_stream() << "(optsmt.lower ";
                   for (unsigned i = 0; i < m_lower.size(); ++i) {
                       verbose_stream() << m_lower[i] << " ";
                   }
                   verbose_stream() << ")\n";);
        IF_VERBOSE(3, verbose_stream() << disj << "\n";);
        IF_VERBOSE(3, model_pp(verbose_stream(), *m_model););

        expr_ref constraint(m);
        constraint = m.mk_or(disj.size(), disj.c_ptr());
        m_s->assert_expr(constraint);
    }

    lbool optsmt::update_upper() {
        smt::theory_opt& opt = m_s->get_optimizer();
        SASSERT(typeid(smt::theory_inf_arith) == typeid(opt));
        smt::theory_inf_arith& th = dynamic_cast<smt::theory_inf_arith&>(opt);
        expr_ref bound(m);
        expr_ref_vector bounds(m);

        solver::scoped_push _push(*m_s);

        //
        // NB: we have to create all bound expressions before calling check_sat
        // because the state after check_sat is not at base level.
        //

        vector<inf_eps> mid;

        for (unsigned i = 0; i < m_lower.size() && !m_cancel; ++i) {
            if (m_lower[i] < m_upper[i]) {
                mid.push_back((m_upper[i]+m_lower[i])/rational(2));
                //mid.push_back(m_upper[i]);
                bound = m_s->mk_ge(i, mid[i]);
                bounds.push_back(bound);
            }
            else {
                bounds.push_back(0);
                mid.push_back(inf_eps());
            }
        }
        bool progress = false;
        for (unsigned i = 0; i < m_lower.size() && !m_cancel; ++i) {
            if (m_lower[i] <= mid[i] && mid[i] <= m_upper[i] && m_lower[i] < m_upper[i]) {
                th.enable_record_conflict(bounds[i].get());
                lbool is_sat = m_s->check_sat(1, bounds.c_ptr() + i);
                switch(is_sat) {
                case l_true:
                    IF_VERBOSE(2, verbose_stream() << "(optsmt lower bound for v" << m_vars[i] << " := " << m_upper[i] << ")\n";);
                    m_lower[i] = mid[i];
                    th.enable_record_conflict(0);
                    update_lower();
                    break;
                case l_false:
                    IF_VERBOSE(2, verbose_stream() << "(optsmt conflict: " << th.conflict_minimize() << ") \n";);
                    if (!th.conflict_minimize().is_finite()) {
                        // bounds is not in the core. The context is unsat.
                        m_upper[i] = m_lower[i];
                        return l_false;
                    }
                    else {
                        m_upper[i] = std::min(m_upper[i], th.conflict_minimize());
                    }
                    break;
                default:
                    th.enable_record_conflict(0);
                    return l_undef;
                }
                th.enable_record_conflict(0);
                progress = true;
            }
        }
        if (m_cancel) {
            return l_undef;
        }
        if (!progress) {
            return l_false;
        }
        return l_true;
    }

    void optsmt::setup(opt_solver& solver) {
        m_s = &solver;
        solver.reset_objectives();
        m_vars.reset();

        // force base level
        {
            solver::scoped_push _push(solver);
        }

        for (unsigned i = 0; i < m_objs.size(); ++i) {
            smt::theory_var v = solver.add_objective(m_objs[i].get());
            if (v == smt::null_theory_var) {
                std::ostringstream out;
                out << "Objective function '" << mk_pp(m_objs[i].get(), m) << "' is not supported";
                throw default_exception(out.str());
            }
            m_vars.push_back(v);
        }
    }

    lbool optsmt::lex(unsigned obj_index, bool is_maximize) {
        TRACE("opt", tout << "optsmt:lex\n";);
        solver::scoped_push _push(*m_s);
        SASSERT(obj_index < m_vars.size());
        return basic_lex(obj_index, is_maximize);
    }

    lbool optsmt::basic_lex(unsigned obj_index, bool is_maximize) {
        lbool is_sat = l_true;
        expr_ref block(m), tmp(m);

        while (is_sat == l_true && !m_cancel) {
            is_sat = m_s->check_sat(0, 0);
            if (is_sat != l_true) break;

            m_s->maximize_objective(obj_index, block);
            m_s->get_model(m_model);
            inf_eps obj = m_s->saved_objective_value(obj_index);
            if (obj > m_lower[obj_index]) {
                m_lower[obj_index] = obj;
                IF_VERBOSE(1,
                           if (is_maximize)
                               verbose_stream() << "(optsmt lower bound: " << obj << ")\n";
                           else
                               verbose_stream() << "(optsmt upper bound: " << (-obj) << ")\n";
                           );
                for (unsigned i = obj_index+1; i < m_vars.size(); ++i) {
                    m_s->maximize_objective(i, tmp);
                    m_lower[i] = m_s->saved_objective_value(i);
                }
            }
            m_s->assert_expr(block);

            // TBD: only works for simplex
            // blocking formula should be extracted based
            // on current state.
        }

        if (m_cancel || is_sat == l_undef) {
            TRACE("opt", tout << "undef: " << m_cancel << " " << is_sat << "\n";);
            return l_undef;
        }

        // set the solution tight.
        m_upper[obj_index] = m_lower[obj_index];
        for (unsigned i = obj_index+1; i < m_lower.size(); ++i) {
            m_lower[i] = inf_eps(rational(-1), inf_rational(0));
        }
        return l_true;
    }

    /**
       Takes solver with hard constraints added.
       Returns an optimal assignment to objective functions.
    */
    lbool optsmt::box() {
        lbool is_sat = l_true;
        if (m_vars.empty()) {
            return is_sat;
        }
        // assertions added during search are temporary.
        solver::scoped_push _push(*m_s);
        if (m_optsmt_engine == symbol("farkas")) {
            is_sat = farkas_opt();
        }
        else if (m_optsmt_engine == symbol("symba")) {
            is_sat = symba_opt();
        }
        else {
            is_sat = basic_opt();
        }
        return is_sat;
    }

    inf_eps optsmt::get_lower(unsigned i) const {
        if (i >= m_lower.size()) return inf_eps();
        return m_lower[i];
    }

    inf_eps optsmt::get_upper(unsigned i) const {
        if (i >= m_upper.size()) return inf_eps();
        return m_upper[i];
    }

    void optsmt::get_model(model_ref& mdl) {
        mdl = m_model.get();
    }

    // force lower_bound(i) <= objective_value(i)
    void optsmt::commit_assignment(unsigned i) {
        inf_eps lo = m_lower[i];
        TRACE("opt", tout << "set lower bound of " << mk_pp(m_objs[i].get(), m) << " to: " << lo << "\n";
              tout << get_lower(i) << ":" << get_upper(i) << "\n";);
        // Only assert bounds for bounded objectives
        if (lo.is_finite()) {
            m_s->assert_expr(m_s->mk_ge(i, lo));
        }
    }

    unsigned optsmt::add(app* t) {
        expr_ref t1(t, m), t2(m);
        th_rewriter rw(m);
        rw(t1, t2);
        SASSERT(is_app(t2));
        m_objs.push_back(to_app(t2));
        m_lower.push_back(inf_eps(rational(-1),inf_rational(0)));
        m_upper.push_back(inf_eps(rational(1), inf_rational(0)));
        m_lower_fmls.push_back(m.mk_true());
        return m_objs.size()-1;
    }

    void optsmt::updt_params(params_ref& p) {
        opt_params _p(p);
        m_optsmt_engine = _p.optsmt_engine();
    }

    void optsmt::reset() {
        m_lower.reset();
        m_upper.reset();
        m_objs.reset();
        m_vars.reset();
        m_model.reset();
        m_lower_fmls.reset();
        m_s = 0;
    }
}

<commit_msg>rename 'or' to 'fml' toe mae gcc happy, reported by Geroge Karpenkov<commit_after>/*++
Copyright (c) 2013 Microsoft Corporation

Module Name:

    optsmt.cpp

Abstract:

    Objective optimization method.

Author:

    Anh-Dung Phan (t-anphan) 2013-10-16

Notes:

    Suppose we obtain solution t1 = k1, ..., tn = kn-epsilon
    Assert:
      t1 > k1 \/ t2 > k2 \/ ... \/ tn >= kn
    If this solution is satisfiable, then for each t_i, maximize the
    assignment and assert the new frontier.
    Claim: we don't necessarily have to freeze assignments of
    t_i when optimizing assignment for t_j
    because the state will always satisfy the disjunction.
    If one of the k_i is unbounded, then omit a disjunction for it.

--*/

#include <typeinfo>
#include "optsmt.h"
#include "opt_solver.h"
#include "arith_decl_plugin.h"
#include "theory_arith.h"
#include "ast_pp.h"
#include "model_pp.h"
#include "th_rewriter.h"
#include "opt_params.hpp"

namespace opt {

    void optsmt::set_cancel(bool f) {
        TRACE("opt", tout << "set cancel: " << f << "\n";);
        m_cancel = f;
    }

    void optsmt::set_max(vector<inf_eps>& dst, vector<inf_eps> const& src, expr_ref_vector& fmls) {
        for (unsigned i = 0; i < src.size(); ++i) {
            if (src[i] >= dst[i]) {
                dst[i] = src[i];
                m_lower_fmls[i] = fmls[i].get();
                if (dst[i].is_pos() && !dst[i].is_finite()) { // review: likely done already.
                    m_lower_fmls[i] = m.mk_false();
                    fmls[i] = m.mk_false();
                }
            }
            else if (src[i] < dst[i] && !m.is_true(m_lower_fmls[i].get())) {
                fmls[i] = m_lower_fmls[i].get();
            }
        }
    }

    /*
        Enumerate locally optimal assignments until fixedpoint.
    */
    lbool optsmt::basic_opt() {
        lbool is_sat = l_true;

        while (is_sat == l_true && !m_cancel) {
            is_sat = m_s->check_sat(0, 0);
            if (is_sat == l_true) {
                update_lower();
            }
        }

        if (m_cancel || is_sat == l_undef) {
            return l_undef;
        }

        // set the solution tight.
        for (unsigned i = 0; i < m_lower.size(); ++i) {
            m_upper[i] = m_lower[i];
        }

        return l_true;
    }

    /*
        Enumerate locally optimal assignments until fixedpoint.
    */
    lbool optsmt::farkas_opt() {
        smt::theory_opt& opt = m_s->get_optimizer();

        if (typeid(smt::theory_inf_arith) != typeid(opt)) {
            return l_undef;
        }

        lbool is_sat = l_true;

        while (is_sat == l_true && !m_cancel) {
            is_sat = update_upper();
        }

        if (m_cancel || is_sat == l_undef) {
            return l_undef;
        }

        // set the solution tight.
        for (unsigned i = 0; i < m_lower.size(); ++i) {
            m_upper[i] = m_lower[i];
        }

        return l_true;
    }

    lbool optsmt::symba_opt() {
        smt::theory_opt& opt = m_s->get_optimizer();

        if (typeid(smt::theory_inf_arith) != typeid(opt)) {
            return l_undef;
        }

        expr_ref_vector ors(m), disj(m);
        expr_ref fml(m), bound(m.mk_true(), m);
        for (unsigned i = 0; i < m_upper.size(); ++i) {
            ors.push_back(m_s->mk_ge(i, m_upper[i]));
        }
        {
            solver::scoped_push _push(*m_s);
            fml = m.mk_or(ors.size(), ors.c_ptr());
            m_s->assert_expr(fml);
            lbool is_sat = l_true;
            while (!m_cancel) {
                is_sat = m_s->check_sat(0,0);
                if (is_sat == l_true) {
                    disj.reset();
                    m_s->maximize_objectives(disj);
                    m_s->get_model(m_model);
                    for (unsigned i = 0; i < ors.size(); ++i) {
                        expr_ref tmp(m);
                        m_model->eval(ors[i].get(), tmp);
                        if (m.is_true(tmp)) {
                            m_lower[i] = m_upper[i];
                            ors[i]  = m.mk_false();
                            disj[i] = m.mk_false();
                        }
                    }
                    set_max(m_lower, m_s->get_objective_values(), disj);
                    fml = m.mk_or(ors.size(), ors.c_ptr());
                    m_s->assert_expr(fml);
                }
                else if (is_sat == l_undef) {
                    return l_undef;
                }
                else {
                    break;
                }
            }
        }
        bound = m.mk_or(m_lower_fmls.size(), m_lower_fmls.c_ptr());
        m_s->assert_expr(bound);

        if (m_cancel) {
            return l_undef;
        }
        return basic_opt();
    }

    void optsmt::update_lower(unsigned idx, inf_eps const& v) {
        m_lower_fmls[idx] = m_s->mk_ge(idx, v);
        m_lower[idx] = v;
    }

    void optsmt::update_upper(unsigned idx, inf_eps const& v) {
        m_upper[idx] = v;
    }

    void optsmt::update_lower() {
        expr_ref_vector disj(m);
        m_s->get_model(m_model);
        m_s->maximize_objectives(disj);
        set_max(m_lower, m_s->get_objective_values(), disj);
        TRACE("opt",
              for (unsigned i = 0; i < m_lower.size(); ++i) {
                  tout << m_lower[i] << " ";
              }
              tout << "\n";
              model_pp(tout, *m_model);
              );
        IF_VERBOSE(2, verbose_stream() << "(optsmt.lower ";
                   for (unsigned i = 0; i < m_lower.size(); ++i) {
                       verbose_stream() << m_lower[i] << " ";
                   }
                   verbose_stream() << ")\n";);
        IF_VERBOSE(3, verbose_stream() << disj << "\n";);
        IF_VERBOSE(3, model_pp(verbose_stream(), *m_model););

        expr_ref constraint(m);
        constraint = m.mk_or(disj.size(), disj.c_ptr());
        m_s->assert_expr(constraint);
    }

    lbool optsmt::update_upper() {
        smt::theory_opt& opt = m_s->get_optimizer();
        SASSERT(typeid(smt::theory_inf_arith) == typeid(opt));
        smt::theory_inf_arith& th = dynamic_cast<smt::theory_inf_arith&>(opt);
        expr_ref bound(m);
        expr_ref_vector bounds(m);

        solver::scoped_push _push(*m_s);

        //
        // NB: we have to create all bound expressions before calling check_sat
        // because the state after check_sat is not at base level.
        //

        vector<inf_eps> mid;

        for (unsigned i = 0; i < m_lower.size() && !m_cancel; ++i) {
            if (m_lower[i] < m_upper[i]) {
                mid.push_back((m_upper[i]+m_lower[i])/rational(2));
                //mid.push_back(m_upper[i]);
                bound = m_s->mk_ge(i, mid[i]);
                bounds.push_back(bound);
            }
            else {
                bounds.push_back(0);
                mid.push_back(inf_eps());
            }
        }
        bool progress = false;
        for (unsigned i = 0; i < m_lower.size() && !m_cancel; ++i) {
            if (m_lower[i] <= mid[i] && mid[i] <= m_upper[i] && m_lower[i] < m_upper[i]) {
                th.enable_record_conflict(bounds[i].get());
                lbool is_sat = m_s->check_sat(1, bounds.c_ptr() + i);
                switch(is_sat) {
                case l_true:
                    IF_VERBOSE(2, verbose_stream() << "(optsmt lower bound for v" << m_vars[i] << " := " << m_upper[i] << ")\n";);
                    m_lower[i] = mid[i];
                    th.enable_record_conflict(0);
                    update_lower();
                    break;
                case l_false:
                    IF_VERBOSE(2, verbose_stream() << "(optsmt conflict: " << th.conflict_minimize() << ") \n";);
                    if (!th.conflict_minimize().is_finite()) {
                        // bounds is not in the core. The context is unsat.
                        m_upper[i] = m_lower[i];
                        return l_false;
                    }
                    else {
                        m_upper[i] = std::min(m_upper[i], th.conflict_minimize());
                    }
                    break;
                default:
                    th.enable_record_conflict(0);
                    return l_undef;
                }
                th.enable_record_conflict(0);
                progress = true;
            }
        }
        if (m_cancel) {
            return l_undef;
        }
        if (!progress) {
            return l_false;
        }
        return l_true;
    }

    void optsmt::setup(opt_solver& solver) {
        m_s = &solver;
        solver.reset_objectives();
        m_vars.reset();

        // force base level
        {
            solver::scoped_push _push(solver);
        }

        for (unsigned i = 0; i < m_objs.size(); ++i) {
            smt::theory_var v = solver.add_objective(m_objs[i].get());
            if (v == smt::null_theory_var) {
                std::ostringstream out;
                out << "Objective function '" << mk_pp(m_objs[i].get(), m) << "' is not supported";
                throw default_exception(out.str());
            }
            m_vars.push_back(v);
        }
    }

    lbool optsmt::lex(unsigned obj_index, bool is_maximize) {
        TRACE("opt", tout << "optsmt:lex\n";);
        solver::scoped_push _push(*m_s);
        SASSERT(obj_index < m_vars.size());
        return basic_lex(obj_index, is_maximize);
    }

    lbool optsmt::basic_lex(unsigned obj_index, bool is_maximize) {
        lbool is_sat = l_true;
        expr_ref block(m), tmp(m);

        while (is_sat == l_true && !m_cancel) {
            is_sat = m_s->check_sat(0, 0);
            if (is_sat != l_true) break;

            m_s->maximize_objective(obj_index, block);
            m_s->get_model(m_model);
            inf_eps obj = m_s->saved_objective_value(obj_index);
            if (obj > m_lower[obj_index]) {
                m_lower[obj_index] = obj;
                IF_VERBOSE(1,
                           if (is_maximize)
                               verbose_stream() << "(optsmt lower bound: " << obj << ")\n";
                           else
                               verbose_stream() << "(optsmt upper bound: " << (-obj) << ")\n";
                           );
                for (unsigned i = obj_index+1; i < m_vars.size(); ++i) {
                    m_s->maximize_objective(i, tmp);
                    m_lower[i] = m_s->saved_objective_value(i);
                }
            }
            m_s->assert_expr(block);

            // TBD: only works for simplex
            // blocking formula should be extracted based
            // on current state.
        }

        if (m_cancel || is_sat == l_undef) {
            TRACE("opt", tout << "undef: " << m_cancel << " " << is_sat << "\n";);
            return l_undef;
        }

        // set the solution tight.
        m_upper[obj_index] = m_lower[obj_index];
        for (unsigned i = obj_index+1; i < m_lower.size(); ++i) {
            m_lower[i] = inf_eps(rational(-1), inf_rational(0));
        }
        return l_true;
    }

    /**
       Takes solver with hard constraints added.
       Returns an optimal assignment to objective functions.
    */
    lbool optsmt::box() {
        lbool is_sat = l_true;
        if (m_vars.empty()) {
            return is_sat;
        }
        // assertions added during search are temporary.
        solver::scoped_push _push(*m_s);
        if (m_optsmt_engine == symbol("farkas")) {
            is_sat = farkas_opt();
        }
        else if (m_optsmt_engine == symbol("symba")) {
            is_sat = symba_opt();
        }
        else {
            is_sat = basic_opt();
        }
        return is_sat;
    }

    inf_eps optsmt::get_lower(unsigned i) const {
        if (i >= m_lower.size()) return inf_eps();
        return m_lower[i];
    }

    inf_eps optsmt::get_upper(unsigned i) const {
        if (i >= m_upper.size()) return inf_eps();
        return m_upper[i];
    }

    void optsmt::get_model(model_ref& mdl) {
        mdl = m_model.get();
    }

    // force lower_bound(i) <= objective_value(i)
    void optsmt::commit_assignment(unsigned i) {
        inf_eps lo = m_lower[i];
        TRACE("opt", tout << "set lower bound of " << mk_pp(m_objs[i].get(), m) << " to: " << lo << "\n";
              tout << get_lower(i) << ":" << get_upper(i) << "\n";);
        // Only assert bounds for bounded objectives
        if (lo.is_finite()) {
            m_s->assert_expr(m_s->mk_ge(i, lo));
        }
    }

    unsigned optsmt::add(app* t) {
        expr_ref t1(t, m), t2(m);
        th_rewriter rw(m);
        rw(t1, t2);
        SASSERT(is_app(t2));
        m_objs.push_back(to_app(t2));
        m_lower.push_back(inf_eps(rational(-1),inf_rational(0)));
        m_upper.push_back(inf_eps(rational(1), inf_rational(0)));
        m_lower_fmls.push_back(m.mk_true());
        return m_objs.size()-1;
    }

    void optsmt::updt_params(params_ref& p) {
        opt_params _p(p);
        m_optsmt_engine = _p.optsmt_engine();
    }

    void optsmt::reset() {
        m_lower.reset();
        m_upper.reset();
        m_objs.reset();
        m_vars.reset();
        m_model.reset();
        m_lower_fmls.reset();
        m_s = 0;
    }
}

<|endoftext|>


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/
#include <osg/Notify>
#include <osg/ApplicationUsage>
#include <osg/os_utils>
#include <osg/ref_ptr>
#include <string>
#include <stdlib.h>
#include <stdio.h>
#include <sstream>
#include <iostream>

#include <ctype.h>

#define OSG_INIT_SINGLETON_PROXY(ProxyName, Func) static struct ProxyName{ ProxyName() { Func; } } s_##ProxyName;

namespace osg
{

class NullStreamBuffer : public std::streambuf
{
private:
    std::streamsize xsputn(const std::streambuf::char_type * /*str*/, std::streamsize n)
    {
        return n;
    }
};

struct NullStream : public std::ostream
{
public:
    NullStream():
        std::ostream(new NullStreamBuffer)
    {
        _buffer = static_cast<NullStreamBuffer *>(rdbuf());
    }

    ~NullStream()
    {
        rdbuf(0);
        delete _buffer;
    }

protected:
    NullStreamBuffer* _buffer;
};

/** Stream buffer calling notify handler when buffer is synchronized (usually on std::endl).
 * Stream stores last notification severity to pass it to handler call.
 */
struct NotifyStreamBuffer : public std::stringbuf
{
    NotifyStreamBuffer() : _severity(osg::NOTICE)
    {
        /* reduce the need to reallocate the std::ostream buffer behind osg::Notify (causing multitreading issues) by pre-allocating 4095 bytes */
        str(std::string(4095, 0));
        pubseekpos(0, std::ios_base::out);
    }

    void setNotifyHandler(osg::NotifyHandler *handler) { _handler = handler; }
    osg::NotifyHandler *getNotifyHandler() const { return _handler.get(); }

    /** Sets severity for next call of notify handler */
    void setCurrentSeverity(osg::NotifySeverity severity)
    {
        if (_severity != severity)
        {
            sync();
            _severity = severity;
        }
    }

    osg::NotifySeverity getCurrentSeverity() const { return _severity; }

private:

    int sync()
    {
        sputc(0); // string termination
        if (_handler.valid())
            _handler->notify(_severity, pbase());
        pubseekpos(0, std::ios_base::out); // or str(std::string())
        return 0;
    }

    osg::ref_ptr<osg::NotifyHandler> _handler;
    osg::NotifySeverity _severity;
};

struct NotifyStream : public std::ostream
{
public:
    NotifyStream():
        std::ostream(new NotifyStreamBuffer)
    {
        _buffer = static_cast<NotifyStreamBuffer *>(rdbuf());
    }

    void setCurrentSeverity(osg::NotifySeverity severity)
    {
        _buffer->setCurrentSeverity(severity);
    }

    osg::NotifySeverity getCurrentSeverity() const
    {
        return _buffer->getCurrentSeverity();
    }

    ~NotifyStream()
    {
        rdbuf(0);
        delete _buffer;
    }

protected:
    NotifyStreamBuffer* _buffer;
};

}

using namespace osg;

static osg::ApplicationUsageProxy Notify_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE, "OSG_NOTIFY_LEVEL <mode>", "FATAL | WARN | NOTICE | DEBUG_INFO | DEBUG_FP | DEBUG | INFO | ALWAYS");

struct NotifySingleton
{
    NotifySingleton()
    {
        // _notifyLevel
        // =============

        _notifyLevel = osg::NOTICE; // Default value

        std::string OSGNOTIFYLEVEL;
        if(getEnvVar("OSG_NOTIFY_LEVEL", OSGNOTIFYLEVEL) || getEnvVar("OSGNOTIFYLEVEL", OSGNOTIFYLEVEL))
        {

            std::string stringOSGNOTIFYLEVEL(OSGNOTIFYLEVEL);

            // Convert to upper case
            for(std::string::iterator i=stringOSGNOTIFYLEVEL.begin();
                i!=stringOSGNOTIFYLEVEL.end();
                ++i)
            {
                *i=toupper(*i);
            }

            if(stringOSGNOTIFYLEVEL.find("ALWAYS")!=std::string::npos)          _notifyLevel=osg::ALWAYS;
            else if(stringOSGNOTIFYLEVEL.find("FATAL")!=std::string::npos)      _notifyLevel=osg::FATAL;
            else if(stringOSGNOTIFYLEVEL.find("WARN")!=std::string::npos)       _notifyLevel=osg::WARN;
            else if(stringOSGNOTIFYLEVEL.find("NOTICE")!=std::string::npos)     _notifyLevel=osg::NOTICE;
            else if(stringOSGNOTIFYLEVEL.find("DEBUG_INFO")!=std::string::npos) _notifyLevel=osg::DEBUG_INFO;
            else if(stringOSGNOTIFYLEVEL.find("DEBUG_FP")!=std::string::npos)   _notifyLevel=osg::DEBUG_FP;
            else if(stringOSGNOTIFYLEVEL.find("DEBUG")!=std::string::npos)      _notifyLevel=osg::DEBUG_INFO;
            else if(stringOSGNOTIFYLEVEL.find("INFO")!=std::string::npos)       _notifyLevel=osg::INFO;
            else std::cout << "Warning: invalid OSG_NOTIFY_LEVEL set ("<<stringOSGNOTIFYLEVEL<<")"<<std::endl;

        }

        // Setup standard notify handler
        osg::NotifyStreamBuffer *buffer = dynamic_cast<osg::NotifyStreamBuffer *>(_notifyStream.rdbuf());
        if (buffer && !buffer->getNotifyHandler())
            buffer->setNotifyHandler(new StandardNotifyHandler);
    }

    osg::NotifySeverity _notifyLevel;
    osg::NullStream     _nullStream;
    osg::NotifyStream   _notifyStream;
};

static NotifySingleton& getNotifySingleton()
{
    static NotifySingleton s_NotifySingleton;
    return s_NotifySingleton;
}

bool osg::initNotifyLevel()
{
    getNotifySingleton();
    return true;
}

// Use a proxy to force the initialization of the NotifySingleton during static initialization
OSG_INIT_SINGLETON_PROXY(NotifySingletonProxy, osg::initNotifyLevel())

void osg::setNotifyLevel(osg::NotifySeverity severity)
{
    getNotifySingleton()._notifyLevel = severity;
}

osg::NotifySeverity osg::getNotifyLevel()
{
    return getNotifySingleton()._notifyLevel;
}

void osg::setNotifyHandler(osg::NotifyHandler *handler)
{
    osg::NotifyStreamBuffer *buffer = static_cast<osg::NotifyStreamBuffer*>(getNotifySingleton()._notifyStream.rdbuf());
    if (buffer) buffer->setNotifyHandler(handler);
}

osg::NotifyHandler* osg::getNotifyHandler()
{
    osg::NotifyStreamBuffer *buffer = static_cast<osg::NotifyStreamBuffer *>(getNotifySingleton()._notifyStream.rdbuf());
    return buffer ? buffer->getNotifyHandler() : 0;
}

#ifndef OSG_NOTIFY_DISABLED
bool osg::isNotifyEnabled( osg::NotifySeverity severity )
{
    return severity<=getNotifySingleton()._notifyLevel;
}
#endif

std::ostream& osg::notify(const osg::NotifySeverity severity)
{
    if (osg::isNotifyEnabled(severity))
    {
        getNotifySingleton()._notifyStream.setCurrentSeverity(severity);
        return getNotifySingleton()._notifyStream;
    }
    return getNotifySingleton()._nullStream;
}

void osg::StandardNotifyHandler::notify(osg::NotifySeverity severity, const char *message)
{
    if (severity <= osg::WARN)
        fputs(message, stderr);
    else
        fputs(message, stdout);
}

#if defined(WIN32) && !defined(__CYGWIN__)

#ifndef WIN32_LEAN_AND_MEAN
    #define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>

void osg::WinDebugNotifyHandler::notify(osg::NotifySeverity severity, const char *message)
{
    OutputDebugStringA(message);
}

#endif
<commit_msg>Notify: silence warning about unused argument<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/
#include <osg/Notify>
#include <osg/ApplicationUsage>
#include <osg/os_utils>
#include <osg/ref_ptr>
#include <string>
#include <stdlib.h>
#include <stdio.h>
#include <sstream>
#include <iostream>

#include <ctype.h>

#define OSG_INIT_SINGLETON_PROXY(ProxyName, Func) static struct ProxyName{ ProxyName() { Func; } } s_##ProxyName;

namespace osg
{

class NullStreamBuffer : public std::streambuf
{
private:
    std::streamsize xsputn(const std::streambuf::char_type * /*str*/, std::streamsize n)
    {
        return n;
    }
};

struct NullStream : public std::ostream
{
public:
    NullStream():
        std::ostream(new NullStreamBuffer)
    {
        _buffer = static_cast<NullStreamBuffer *>(rdbuf());
    }

    ~NullStream()
    {
        rdbuf(0);
        delete _buffer;
    }

protected:
    NullStreamBuffer* _buffer;
};

/** Stream buffer calling notify handler when buffer is synchronized (usually on std::endl).
 * Stream stores last notification severity to pass it to handler call.
 */
struct NotifyStreamBuffer : public std::stringbuf
{
    NotifyStreamBuffer() : _severity(osg::NOTICE)
    {
        /* reduce the need to reallocate the std::ostream buffer behind osg::Notify (causing multitreading issues) by pre-allocating 4095 bytes */
        str(std::string(4095, 0));
        pubseekpos(0, std::ios_base::out);
    }

    void setNotifyHandler(osg::NotifyHandler *handler) { _handler = handler; }
    osg::NotifyHandler *getNotifyHandler() const { return _handler.get(); }

    /** Sets severity for next call of notify handler */
    void setCurrentSeverity(osg::NotifySeverity severity)
    {
        if (_severity != severity)
        {
            sync();
            _severity = severity;
        }
    }

    osg::NotifySeverity getCurrentSeverity() const { return _severity; }

private:

    int sync()
    {
        sputc(0); // string termination
        if (_handler.valid())
            _handler->notify(_severity, pbase());
        pubseekpos(0, std::ios_base::out); // or str(std::string())
        return 0;
    }

    osg::ref_ptr<osg::NotifyHandler> _handler;
    osg::NotifySeverity _severity;
};

struct NotifyStream : public std::ostream
{
public:
    NotifyStream():
        std::ostream(new NotifyStreamBuffer)
    {
        _buffer = static_cast<NotifyStreamBuffer *>(rdbuf());
    }

    void setCurrentSeverity(osg::NotifySeverity severity)
    {
        _buffer->setCurrentSeverity(severity);
    }

    osg::NotifySeverity getCurrentSeverity() const
    {
        return _buffer->getCurrentSeverity();
    }

    ~NotifyStream()
    {
        rdbuf(0);
        delete _buffer;
    }

protected:
    NotifyStreamBuffer* _buffer;
};

}

using namespace osg;

static osg::ApplicationUsageProxy Notify_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE, "OSG_NOTIFY_LEVEL <mode>", "FATAL | WARN | NOTICE | DEBUG_INFO | DEBUG_FP | DEBUG | INFO | ALWAYS");

struct NotifySingleton
{
    NotifySingleton()
    {
        // _notifyLevel
        // =============

        _notifyLevel = osg::NOTICE; // Default value

        std::string OSGNOTIFYLEVEL;
        if(getEnvVar("OSG_NOTIFY_LEVEL", OSGNOTIFYLEVEL) || getEnvVar("OSGNOTIFYLEVEL", OSGNOTIFYLEVEL))
        {

            std::string stringOSGNOTIFYLEVEL(OSGNOTIFYLEVEL);

            // Convert to upper case
            for(std::string::iterator i=stringOSGNOTIFYLEVEL.begin();
                i!=stringOSGNOTIFYLEVEL.end();
                ++i)
            {
                *i=toupper(*i);
            }

            if(stringOSGNOTIFYLEVEL.find("ALWAYS")!=std::string::npos)          _notifyLevel=osg::ALWAYS;
            else if(stringOSGNOTIFYLEVEL.find("FATAL")!=std::string::npos)      _notifyLevel=osg::FATAL;
            else if(stringOSGNOTIFYLEVEL.find("WARN")!=std::string::npos)       _notifyLevel=osg::WARN;
            else if(stringOSGNOTIFYLEVEL.find("NOTICE")!=std::string::npos)     _notifyLevel=osg::NOTICE;
            else if(stringOSGNOTIFYLEVEL.find("DEBUG_INFO")!=std::string::npos) _notifyLevel=osg::DEBUG_INFO;
            else if(stringOSGNOTIFYLEVEL.find("DEBUG_FP")!=std::string::npos)   _notifyLevel=osg::DEBUG_FP;
            else if(stringOSGNOTIFYLEVEL.find("DEBUG")!=std::string::npos)      _notifyLevel=osg::DEBUG_INFO;
            else if(stringOSGNOTIFYLEVEL.find("INFO")!=std::string::npos)       _notifyLevel=osg::INFO;
            else std::cout << "Warning: invalid OSG_NOTIFY_LEVEL set ("<<stringOSGNOTIFYLEVEL<<")"<<std::endl;

        }

        // Setup standard notify handler
        osg::NotifyStreamBuffer *buffer = dynamic_cast<osg::NotifyStreamBuffer *>(_notifyStream.rdbuf());
        if (buffer && !buffer->getNotifyHandler())
            buffer->setNotifyHandler(new StandardNotifyHandler);
    }

    osg::NotifySeverity _notifyLevel;
    osg::NullStream     _nullStream;
    osg::NotifyStream   _notifyStream;
};

static NotifySingleton& getNotifySingleton()
{
    static NotifySingleton s_NotifySingleton;
    return s_NotifySingleton;
}

bool osg::initNotifyLevel()
{
    getNotifySingleton();
    return true;
}

// Use a proxy to force the initialization of the NotifySingleton during static initialization
OSG_INIT_SINGLETON_PROXY(NotifySingletonProxy, osg::initNotifyLevel())

void osg::setNotifyLevel(osg::NotifySeverity severity)
{
    getNotifySingleton()._notifyLevel = severity;
}

osg::NotifySeverity osg::getNotifyLevel()
{
    return getNotifySingleton()._notifyLevel;
}

void osg::setNotifyHandler(osg::NotifyHandler *handler)
{
    osg::NotifyStreamBuffer *buffer = static_cast<osg::NotifyStreamBuffer*>(getNotifySingleton()._notifyStream.rdbuf());
    if (buffer) buffer->setNotifyHandler(handler);
}

osg::NotifyHandler* osg::getNotifyHandler()
{
    osg::NotifyStreamBuffer *buffer = static_cast<osg::NotifyStreamBuffer *>(getNotifySingleton()._notifyStream.rdbuf());
    return buffer ? buffer->getNotifyHandler() : 0;
}

#ifndef OSG_NOTIFY_DISABLED
bool osg::isNotifyEnabled( osg::NotifySeverity severity )
{
    return severity<=getNotifySingleton()._notifyLevel;
}
#endif

std::ostream& osg::notify(const osg::NotifySeverity severity)
{
    if (osg::isNotifyEnabled(severity))
    {
        getNotifySingleton()._notifyStream.setCurrentSeverity(severity);
        return getNotifySingleton()._notifyStream;
    }
    return getNotifySingleton()._nullStream;
}

void osg::StandardNotifyHandler::notify(osg::NotifySeverity severity, const char *message)
{
    if (severity <= osg::WARN)
        fputs(message, stderr);
    else
        fputs(message, stdout);
}

#if defined(WIN32) && !defined(__CYGWIN__)

#ifndef WIN32_LEAN_AND_MEAN
    #define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>

void osg::WinDebugNotifyHandler::notify(osg::NotifySeverity severity, const char *message)
{
    OSG_UNUSED(severity);

    OutputDebugStringA(message);
}

#endif
<|endoftext|>


<commit_before>#include "Mesh.hxx"
#include "Functional.hxx"

#include "../ostream_vector.hxx"

// We convert the optimization problem into a regular linear
// programming problem.
//
// 1) Each polynomial in Block::polys adds two variables.  The
// weights of those polynomials are unbounded, while linear
// programming requires a strictly positive variable.  So we
// substitute W_n = w_n+ - w_n+, where both w_n+ and w_n- are
// strictly positive.  All blocks should have the same number of
// polynomials, so we only need to look at the first one.
//
// 2) Each constraint adds one 'slack' variable s_n.  There is one
// constraint per coordinate 'x', with each block having multiple,
// separate coordinates.
//
// 3) One more global variable delta, which gives the linear
// program something to minimize.
//
// This turns the problem
//
//   A_0 . W > 0
//   A_1 . W > 0
//   ...
//
// into
//
//   min delta
//
// where
//
//   A_0 . (w_+ - w_-) + delta - s_0 = 0
//   A_1 . (w_+ - w_-) + delta - s_1 = 0
//   ...
//   w_n+, w_n-, s_n, delta >= 0
//
// There is a constraint for every point that is sampled.  At the
// beginning, we sample the min and max for each block, so there are
// 2*num_blocks constraints.  In general
//
// => num_rows == num_constraints
// => num_columns == 2*num_weights + num_constraints + 1

std::vector<El::BigFloat> get_new_points(const Mesh &mesh);
El::BigFloat max_value(const Mesh &mesh);

void solve_LP(const El::Matrix<El::BigFloat> &A,
              const El::Matrix<El::BigFloat> &b,
              const El::Matrix<El::BigFloat> &c,
              std::vector<El::BigFloat> &weights);

int main(int argc, char **argv)
{
  El::Environment env(argc, argv);
  const int64_t precision(256);
  El::gmp::SetPrecision(precision);

  // Functional functional("polys", "test/single_corr_poles");
  Functional functional("test/single_corr_polys", "test/single_corr_poles");
  // Functional functional("test/toy_polys", "");
  size_t num_weights(functional.blocks.at(0).polys.size());

  // for(auto &pole: functional.blocks[0].poles)
  //   {
  //     std::cout << "pole: " << pole << "\n";
  //   }

  // std::cout << "prefactor: "
  //           << (functional.prefactor(1.44) *
  //           functional.blocks[0].pole_prefactor(1.44)) << " "
  //           << functional.blocks.at(0).polys.at(0)(1.44) << " "
  //           << "\n";
  // // std::cout << functional.blocks.at(0).polys.at(0) << "\n";

  // for(size_t index(0); index<functional.blocks[0].polys.size(); ++index)
  //   {
  //     std::cout << index << " "
  //               << (functional.blocks.at(0).polys.at(index)(0.0)
  //                   * functional.prefactor(0.0)
  //                   * functional.blocks[0].pole_prefactor(0.0))
  //               << "\n";
  //   }
  // exit(0);

  const size_t num_blocks(functional.blocks.size());
  const El::BigFloat min_x(0.0), max_x(100.0);
  std::vector<El::BigFloat> scale(num_blocks);
  std::vector<El::BigFloat> weights(num_weights, 1);

  const El::BigFloat prefactor(functional.prefactor(max_x));
  for(size_t block(0); block != num_blocks; ++block)
    {
      scale[block] = Abs(
        prefactor * functional.blocks[block].eval_weighted(max_x, weights));
    }

  const El::BigFloat scalar_gap(1.44);
  std::vector<std::vector<El::BigFloat>> points(num_blocks,
                                                {min_x, scalar_gap}),
    // std::vector<std::vector<El::BigFloat>> points(num_blocks,
    //                                               {min_x}),
    new_points(num_blocks, {max_x});

  bool has_new_points(true);
  while(has_new_points)
    {
      has_new_points = false;
      size_t num_constraints(0);
      for(size_t block(0); block != num_blocks; ++block)
        {
          for(auto &point : new_points.at(block))
            {
              points.at(block).emplace_back(point);
            }
          num_constraints += points.at(block).size();
          std::sort(points.at(block).begin(), points.at(block).end());
          std::cout << "points: " << block << " " << points.at(block) << "\n";
        }

      const size_t num_rows(num_constraints),
        num_columns(2 * weights.size() + num_constraints + 1);

      El::Matrix<El::BigFloat> A(num_rows, num_columns);
      El::Zero(A);

      size_t row(0);
      for(size_t block(0); block != num_blocks; ++block)
        {
          // One constraint per point
          for(size_t point(0); point != points.at(block).size(); ++point)
            {
              // delta term
              A(row, 0) = 1;
              // slack term
              A(row, 2 * weights.size() + row + 1) = -1;

              const El::BigFloat &x(points.at(block)[point]);
              const El::BigFloat prefactor(
                functional.prefactor(x)
                * functional.blocks.at(block).pole_prefactor(x));
              for(size_t poly_index(0);
                  poly_index != functional.blocks.at(block).polys.size();
                  ++poly_index)
                {
                  A(row, 2 * poly_index + 1)
                    = prefactor
                      * functional.blocks.at(block).polys.at(poly_index)(x);
                  A(row, 2 * poly_index + 2) = -A(row, 2 * poly_index + 1);
                }
              ++row;
            }
        }

      El::Matrix<El::BigFloat> b(num_rows, 1), c(num_columns, 1);
      El::Zero(b);
      El::Zero(c);
      c(0, 0) = 1;

      // std::cout << "A: "
      //           << A.Height() << " "
      //           << A.Width() << " "
      //           << b.Height() << " "
      //           << b.Width() << " "
      //           << c.Height() << " "
      //           << c.Width() << " "
      //           << "\n";

      // for(size_t row(0); row!=A.Height(); ++row)
      // for(size_t column(0); column!=A.Width(); ++column)
      //   {
      //     size_t row(0);
      //     std::cout << "A: "
      //               << row << " "
      //               << column << " "
      //               << A(row,column) << "\n";
      //   }
      // El::Print(A, "A");
      // El::Print(b, "\nb");
      // El::Print(c, "\nc");
      // std::cout << "\n";

      solve_LP(A, b, c, weights);

      std::cout << "weight: " << weights << "\n";
      for(size_t block(0); block != num_blocks; ++block)
        {
          // std::cout.precision(precision / 3.3);
          // std::cout << "solve: " << points.at(block).size() << " " << weights
          //           << "\n";

          // 0.01 should be a small enough relative error so that we are
          // in the regime of convergence.  Then the error estimates will
          // work
          Mesh mesh(min_x, max_x,
                    [&](const El::BigFloat &x) {
                      return functional.prefactor(x)
                             * functional.blocks.at(block).eval_weighted(
                                 x, weights);
                    },
                    0.01);
          new_points.at(block) = get_new_points(mesh);
          std::cout.precision(precision/3.3);
          std::cout << "new: " << block << " " << new_points.at(block) << "\n";
          std::cout.precision(6);
          scale.at(block) = max_value(mesh);
          has_new_points = has_new_points || !new_points.at(block).empty();
        }
    }
  // std::cout.precision(precision / 3.3);
  std::cout << "weights: " << weights << "\n";
}
<commit_msg>Cleanup<commit_after>#include "Mesh.hxx"
#include "Functional.hxx"

#include "../ostream_vector.hxx"

// We convert the optimization problem into a regular linear
// programming problem.
//
// 1) Each polynomial in Block::polys adds two variables.  The
// weights of those polynomials are unbounded, while linear
// programming requires a strictly positive variable.  So we
// substitute W_n = w_n+ - w_n+, where both w_n+ and w_n- are
// strictly positive.  All blocks should have the same number of
// polynomials, so we only need to look at the first one.
//
// 2) Each constraint adds one 'slack' variable s_n.  There is one
// constraint per coordinate 'x', with each block having multiple,
// separate coordinates.
//
// 3) One more global variable delta, which gives the linear
// program something to minimize.
//
// This turns the problem
//
//   A_0 . W > 0
//   A_1 . W > 0
//   ...
//
// into
//
//   min delta
//
// where
//
//   A_0 . (w_+ - w_-) + delta - s_0 = 0
//   A_1 . (w_+ - w_-) + delta - s_1 = 0
//   ...
//   w_n+, w_n-, s_n, delta >= 0
//
// There is a constraint for every point that is sampled.  At the
// beginning, we sample the min and max for each block, so there are
// 2*num_blocks constraints.  In general
//
// => num_rows == num_constraints
// => num_columns == 2*num_weights + num_constraints + 1

std::vector<El::BigFloat> get_new_points(const Mesh &mesh);
El::BigFloat max_value(const Mesh &mesh);

void solve_LP(const El::Matrix<El::BigFloat> &A,
              const El::Matrix<El::BigFloat> &b,
              const El::Matrix<El::BigFloat> &c,
              std::vector<El::BigFloat> &weights);

int main(int argc, char **argv)
{
  El::Environment env(argc, argv);
  const int64_t precision(256);
  El::gmp::SetPrecision(precision);

  // Functional functional("test/single_corr_polys", "test/single_corr_poles");
  Functional functional("test/toy_polys", "");
  size_t num_weights(functional.blocks.at(0).polys.size());

  const size_t num_blocks(functional.blocks.size());
  const El::BigFloat min_x(0.0), max_x(100.0);
  std::vector<El::BigFloat> scale(num_blocks);
  std::vector<El::BigFloat> weights(num_weights, 1);

  const El::BigFloat prefactor(functional.prefactor(max_x));
  for(size_t block(0); block != num_blocks; ++block)
    {
      scale[block] = Abs(
        prefactor * functional.blocks[block].eval_weighted(max_x, weights));
    }

  const El::BigFloat scalar_gap(1.44);
  std::vector<std::vector<El::BigFloat>> points(num_blocks,
                                                {min_x, scalar_gap}),
    // std::vector<std::vector<El::BigFloat>> points(num_blocks,
    //                                               {min_x}),
    new_points(num_blocks, {max_x});

  bool has_new_points(true);
  while(has_new_points)
    {
      has_new_points = false;
      size_t num_constraints(0);
      for(size_t block(0); block != num_blocks; ++block)
        {
          for(auto &point : new_points.at(block))
            {
              points.at(block).emplace_back(point);
            }
          num_constraints += points.at(block).size();
          std::sort(points.at(block).begin(), points.at(block).end());
          std::cout << "points: " << block << " " << points.at(block) << "\n";
        }

      const size_t num_rows(num_constraints),
        num_columns(2 * weights.size() + num_constraints + 1);

      El::Matrix<El::BigFloat> A(num_rows, num_columns);
      El::Zero(A);

      size_t row(0);
      for(size_t block(0); block != num_blocks; ++block)
        {
          // One constraint per point
          for(size_t point(0); point != points.at(block).size(); ++point)
            {
              // delta term
              A(row, 0) = 1;
              // slack term
              A(row, 2 * weights.size() + row + 1) = -1;

              const El::BigFloat &x(points.at(block)[point]);
              const El::BigFloat prefactor(
                functional.prefactor(x)
                * functional.blocks.at(block).pole_prefactor(x));
              for(size_t poly_index(0);
                  poly_index != functional.blocks.at(block).polys.size();
                  ++poly_index)
                {
                  A(row, 2 * poly_index + 1)
                    = prefactor
                      * functional.blocks.at(block).polys.at(poly_index)(x);
                  A(row, 2 * poly_index + 2) = -A(row, 2 * poly_index + 1);
                }
              ++row;
            }
        }

      El::Matrix<El::BigFloat> b(num_rows, 1), c(num_columns, 1);
      El::Zero(b);
      El::Zero(c);
      c(0, 0) = 1;

      // std::cout << "A: "
      //           << A.Height() << " "
      //           << A.Width() << " "
      //           << b.Height() << " "
      //           << b.Width() << " "
      //           << c.Height() << " "
      //           << c.Width() << " "
      //           << "\n";

      // for(size_t row(0); row!=A.Height(); ++row)
      // for(size_t column(0); column!=A.Width(); ++column)
      //   {
      //     size_t row(0);
      //     std::cout << "A: "
      //               << row << " "
      //               << column << " "
      //               << A(row,column) << "\n";
      //   }
      // El::Print(A, "A");
      // El::Print(b, "\nb");
      // El::Print(c, "\nc");
      // std::cout << "\n";

      solve_LP(A, b, c, weights);

      std::cout << "weight: " << weights << "\n";
      for(size_t block(0); block != num_blocks; ++block)
        {
          // std::cout.precision(precision / 3.3);
          // std::cout << "solve: " << points.at(block).size() << " " << weights
          //           << "\n";

          // 0.01 should be a small enough relative error so that we are
          // in the regime of convergence.  Then the error estimates will
          // work
          Mesh mesh(min_x, max_x,
                    [&](const El::BigFloat &x) {
                      return functional.prefactor(x)
                             * functional.blocks.at(block).eval_weighted(
                                 x, weights);
                    },
                    0.01);
          new_points.at(block) = get_new_points(mesh);
          std::cout.precision(precision/3.3);
          std::cout << "new: " << block << " " << new_points.at(block) << "\n";
          std::cout.precision(6);
          scale.at(block) = max_value(mesh);
          has_new_points = has_new_points || !new_points.at(block).empty();
        }
    }
  // std::cout.precision(precision / 3.3);
  std::cout << "weights: " << weights << "\n";
}
<|endoftext|>


<commit_before>/*
    KPeople
    Copyright (C) 2012  Aleix Pol Gonzalez <aleixpol@blue-systems.com>
    Copyright (C) 2013  Martin Klapetek <mklapetek@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "persondata.h"
#include "persons-model.h"
#include "persons-model-item.h"
#include "persons-presence-model.h"

#include <Nepomuk2/Resource>
#include <Nepomuk2/Query/Query>
#include <Nepomuk2/ResourceManager>
#include <Nepomuk2/ResourceWatcher>
#include <Nepomuk2/Vocabulary/PIMO>
#include <Nepomuk2/Vocabulary/NCO>
#include <Nepomuk2/Vocabulary/NIE>
#include <Nepomuk2/Variant>

#include <Soprano/Model>
#include <Soprano/QueryResultIterator>

#include <KDebug>

using namespace Nepomuk2::Vocabulary;

class PersonDataPrivate {
public:
    QString uri;
    QString id;
    Nepomuk2::Resource res;
    PersonsPresenceModel *presenceModel;
};

K_GLOBAL_STATIC(PersonsPresenceModel, s_presenceModel)

PersonData::PersonData(const QString &uri, QObject *parent)
    : QObject(parent),
      d_ptr(new PersonDataPrivate)
{
    Q_D(PersonData);
    d->uri = uri;
    d->res = Nepomuk2::Resource(uri);

    d->res.setWatchEnabled(true);
    d->presenceModel = s_presenceModel;

    connect(d->presenceModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
            this, SIGNAL(dataChanged()));

    Nepomuk2::ResourceWatcher *watcher = new Nepomuk2::ResourceWatcher(this);
    watcher->addResource(d->res);

    connect(watcher, SIGNAL(propertyChanged(Nepomuk2::Resource,Nepomuk2::Types::Property,QVariantList,QVariantList)),
            this, SIGNAL(dataChanged()));
}

void PersonData::setContactId(const QString &id)
{
    Q_D(PersonData);
    if (d->id == id) {
        return;
    }

    d->id = id;

    QString query = QString::fromUtf8(
        "select DISTINCT ?uri "
        "WHERE { "
            "?uri a nco:PersonContact. "
            "?uri nco:hasContactMedium ?a . "
            "?a ?b \"%1\"^^xsd:string . "
        "}").arg(id);

    Soprano::Model *model = Nepomuk2::ResourceManager::instance()->mainModel();
    Soprano::QueryResultIterator it = model->executeQuery(query, Soprano::Query::QueryLanguageSparql);
    QString uri;
    while (it.next()) {
        uri = it["uri"].uri().toString();
    }

    if (d->uri != uri) {
        d->uri = uri;
        d->res = Nepomuk2::Resource(uri);
        d->res.setWatchEnabled(true);
    }
}

QString PersonData::contactId() const
{
    Q_D(const PersonData);
    return d->id;
}

QString PersonData::uri() const
{
    Q_D(const PersonData);
    return d->uri;
}

void PersonData::setUri(const QString &uri)
{
    Q_D(PersonData);

    d->uri = uri;
    d->res = Nepomuk2::Resource(uri);
    d->res.setWatchEnabled(true);
}

QString PersonData::status() const
{
    Q_D(const PersonData);

    QStringList presenceList;

    if (d->res.type() == PIMO::Person()) {
        Q_FOREACH (const Nepomuk2::Resource &resource, d->res.property(PIMO::groundingOccurrence()).toResourceList()) {
            if (resource.hasProperty(NCO::hasIMAccount())) {
                QString imID = resource.property(NCO::hasIMAccount()).toResource().property(NCO::imID()).toString();
                presenceList << d->presenceModel->dataForContactId(imID, PersonsModel::StatusRole).toString();
            }
        }

        return findMostOnlinePresence(presenceList);
    } else {
        QString imID = d->res.property(NCO::hasIMAccount()).toResource().property(NCO::imID()).toString();
        return d->presenceModel->dataForContactId(imID, PersonsModel::StatusRole).toString();
    }
}

QUrl PersonData::avatar() const
{
    Q_D(const PersonData);

    Nepomuk2::Resource r;

    if (d->res.type() == PIMO::Person()) {
        Q_FOREACH (const Nepomuk2::Resource &resource, d->res.property(PIMO::groundingOccurrence()).toResourceList()) {
            if (resource.hasProperty(NCO::photo())) {
                r = resource;
                break;
            }
        }
    } else {
        r = d->res;
    }

    return r.property(NCO::photo()).toResource().property(NIE::url()).toUrl();
}

QString PersonData::name() const
{
    Q_D(const PersonData);

    QString label;
    Nepomuk2::Resource r;

    if (d->res.type() == PIMO::Person()) {
        //simply pick the first GO for now
        r = d->res.property(PIMO::groundingOccurrence()).toResource();
    } else {
        r = d->res;
    }

    label = r.property(NCO::hasEmailAddress()).toResource().property(NCO::fullname()).toString();

    if (!label.isEmpty()) {
        return label;
    }

    label = r.property(NCO::hasIMAccount()).toResource().property(NCO::imNickname()).toString();

    if (!label.isEmpty()) {
        return label;
    }

    return d->res.property(NCO::hasContactMedium()).toResource().genericLabel();
}

QStringList PersonData::emails() const
{
    Q_D(const PersonData);

    QStringList emails;

    if (d->res.type() == PIMO::Person()) {
        Q_FOREACH (const Nepomuk2::Resource &resource, d->res.property(PIMO::groundingOccurrence()).toResourceList()) {
            if (resource.hasProperty(NCO::hasEmailAddress())) {
                Q_FOREACH (const Nepomuk2::Resource &email, resource.property(NCO::hasEmailAddress()).toResourceList()) {
                    emails << email.property(NCO::emailAddress()).toString();
                }
            }
        }
    } else {
        if (d->res.hasProperty(NCO::hasEmailAddress())) {
            Q_FOREACH (const Nepomuk2::Resource &email, d->res.property(NCO::hasEmailAddress()).toResourceList()) {
                emails << email.property(NCO::emailAddress()).toString();
            }
        }
    }

    return emails;
}

QStringList PersonData::phones() const
{
    Q_D(const PersonData);

    QStringList phones;

    if (d->res.type() == PIMO::Person()) {
        Q_FOREACH (const Nepomuk2::Resource &resource, d->res.property(PIMO::groundingOccurrence()).toResourceList()) {
            if (resource.hasProperty(NCO::hasPhoneNumber())) {
                Q_FOREACH (const Nepomuk2::Resource &phone, resource.property(NCO::hasPhoneNumber()).toResourceList()) {
                    phones << phone.property(NCO::phoneNumber()).toString();
                }
            }
        }
    } else {
        if (d->res.hasProperty(NCO::hasPhoneNumber())) {
            Q_FOREACH (const Nepomuk2::Resource &phone, d->res.property(NCO::hasPhoneNumber()).toResourceList()) {
                phones << phone.property(NCO::phoneNumber()).toString();
            }
        }
    }

    return phones;
}

QStringList PersonData::imAccounts() const
{
    Q_D(const PersonData);

    QStringList ims;

    if (d->res.type() == PIMO::Person()) {
        Q_FOREACH (const Nepomuk2::Resource &resource, d->res.property(PIMO::groundingOccurrence()).toResourceList()) {
            if (resource.hasProperty(NCO::hasIMAccount())) {
                Q_FOREACH (const Nepomuk2::Resource &im, resource.property(NCO::hasIMAccount()).toResourceList()) {
                    ims << im.property(NCO::imAccountType()).toString();
                    ims << im.property(NCO::imNickname()).toString();
                    ims << im.property(NCO::imID()).toString();
                }
            }
        }
    } else {
        if (d->res.hasProperty(NCO::hasIMAccount())) {
            Q_FOREACH (const Nepomuk2::Resource &im, d->res.property(NCO::hasIMAccount()).toResourceList()) {
                ims << im.property(NCO::imAccountType()).toString();
                ims << im.property(NCO::imNickname()).toString();
                ims << im.property(NCO::imID()).toString();
            }
        }
    }

    return ims;
}

// QStringList PersonData::bareContacts() const
// {
//     return personIndex().data(PersonsModel::ContactIdRole).toStringList();
// }
//
// QModelIndex PersonData::personIndex() const
// {
//     Q_D(const PersonData);
//     Q_ASSERT(d->model->rowCount()>0);
//     QModelIndex idx = d->model->index(0,0);
//     Q_ASSERT(idx.isValid());
//     return idx;
// }
//

bool PersonData::isPerson() const
{
    Q_D(const PersonData);
    return d->res.type() == PIMO::Person();
}

QString PersonData::findMostOnlinePresence(const QStringList &presences) const
{
    if (presences.contains("available")) {
        return "available";
    }
    if (presences.contains("away")) {
        return "away";
    }
    if (presences.contains("busy") || presences.contains("dnd")) {
        return "busy";
    }
    if (presences.contains("xa")) {
        return "xa";
    }

    return "offline";
}
<commit_msg>Minor Optimizations in PersonData<commit_after>/*
    KPeople
    Copyright (C) 2012  Aleix Pol Gonzalez <aleixpol@blue-systems.com>
    Copyright (C) 2013  Martin Klapetek <mklapetek@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "persondata.h"
#include "persons-model.h"
#include "persons-model-item.h"
#include "persons-presence-model.h"

#include <Nepomuk2/Resource>
#include <Nepomuk2/Query/Query>
#include <Nepomuk2/ResourceManager>
#include <Nepomuk2/ResourceWatcher>
#include <Nepomuk2/Vocabulary/PIMO>
#include <Nepomuk2/Vocabulary/NCO>
#include <Nepomuk2/Vocabulary/NIE>
#include <Nepomuk2/Variant>

#include <Soprano/Model>
#include <Soprano/QueryResultIterator>

#include <KDebug>

using namespace Nepomuk2::Vocabulary;

class PersonDataPrivate {
public:
    QString uri;
    QString id;
    Nepomuk2::Resource res;
    PersonsPresenceModel *presenceModel;
};

K_GLOBAL_STATIC(PersonsPresenceModel, s_presenceModel)

PersonData::PersonData(const QString &uri, QObject *parent)
    : QObject(parent),
      d_ptr(new PersonDataPrivate)
{
    Q_D(PersonData);
    d->uri = uri;
    d->res = Nepomuk2::Resource(uri);

    d->res.setWatchEnabled(true);
    d->presenceModel = s_presenceModel;

    connect(d->presenceModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
            this, SIGNAL(dataChanged()));

    Nepomuk2::ResourceWatcher *watcher = new Nepomuk2::ResourceWatcher(this);
    watcher->addResource(d->res);

    connect(watcher, SIGNAL(propertyChanged(Nepomuk2::Resource,Nepomuk2::Types::Property,QVariantList,QVariantList)),
            this, SIGNAL(dataChanged()));
}

void PersonData::setContactId(const QString &id)
{
    Q_D(PersonData);
    if (d->id == id) {
        return;
    }

    d->id = id;

    QString query = QString::fromUtf8(
        "select DISTINCT ?uri "
        "WHERE { "
            "?uri a nco:PersonContact. "
            "?uri nco:hasContactMedium ?a . "
            "?a ?b \"%1\"^^xsd:string . "
        "}").arg(id);

    Soprano::Model *model = Nepomuk2::ResourceManager::instance()->mainModel();
    Soprano::QueryResultIterator it = model->executeQuery(query, Soprano::Query::QueryLanguageSparqlNoInference);
    QString uri;
    while (it.next()) {
        uri = it[0].uri().toString();
    }

    if (d->uri != uri) {
        d->uri = uri;
        d->res = Nepomuk2::Resource(uri);
        d->res.setWatchEnabled(true);
    }
}

QString PersonData::contactId() const
{
    Q_D(const PersonData);
    return d->id;
}

QString PersonData::uri() const
{
    Q_D(const PersonData);
    return d->uri;
}

void PersonData::setUri(const QString &uri)
{
    Q_D(PersonData);

    d->uri = uri;
    d->res = Nepomuk2::Resource(uri);
    d->res.setWatchEnabled(true);
}

QString PersonData::status() const
{
    Q_D(const PersonData);

    QStringList presenceList;

    if (d->res.type() == PIMO::Person()) {
        Q_FOREACH (const Nepomuk2::Resource &resource, d->res.property(PIMO::groundingOccurrence()).toResourceList()) {
            if (resource.hasProperty(NCO::hasIMAccount())) {
                QString imID = resource.property(NCO::hasIMAccount()).toResource().property(NCO::imID()).toString();
                presenceList << d->presenceModel->dataForContactId(imID, PersonsModel::StatusRole).toString();
            }
        }

        return findMostOnlinePresence(presenceList);
    } else {
        QString imID = d->res.property(NCO::hasIMAccount()).toResource().property(NCO::imID()).toString();
        return d->presenceModel->dataForContactId(imID, PersonsModel::StatusRole).toString();
    }
}

QUrl PersonData::avatar() const
{
    Q_D(const PersonData);

    Nepomuk2::Resource r;

    if (d->res.type() == PIMO::Person()) {
        Q_FOREACH (const Nepomuk2::Resource &resource, d->res.property(PIMO::groundingOccurrence()).toResourceList()) {
            if (resource.hasProperty(NCO::photo())) {
                r = resource;
                break;
            }
        }
    } else {
        r = d->res;
    }

    return r.property(NCO::photo()).toResource().property(NIE::url()).toUrl();
}

QString PersonData::name() const
{
    Q_D(const PersonData);

    QString label;
    Nepomuk2::Resource r;

    if (d->res.type() == PIMO::Person()) {
        //simply pick the first GO for now
        r = d->res.property(PIMO::groundingOccurrence()).toResource();
    } else {
        r = d->res;
    }

    label = r.property(NCO::hasEmailAddress()).toResource().property(NCO::fullname()).toString();

    if (!label.isEmpty()) {
        return label;
    }

    label = r.property(NCO::hasIMAccount()).toResource().property(NCO::imNickname()).toString();

    if (!label.isEmpty()) {
        return label;
    }

    return d->res.property(NCO::hasContactMedium()).toResource().genericLabel();
}

QStringList PersonData::emails() const
{
    Q_D(const PersonData);

    QStringList emails;

    if (d->res.type() == PIMO::Person()) {
        Q_FOREACH (const Nepomuk2::Resource &resource, d->res.property(PIMO::groundingOccurrence()).toResourceList()) {
            if (resource.hasProperty(NCO::hasEmailAddress())) {
                Q_FOREACH (const Nepomuk2::Resource &email, resource.property(NCO::hasEmailAddress()).toResourceList()) {
                    emails << email.property(NCO::emailAddress()).toString();
                }
            }
        }
    } else {
        if (d->res.hasProperty(NCO::hasEmailAddress())) {
            Q_FOREACH (const Nepomuk2::Resource &email, d->res.property(NCO::hasEmailAddress()).toResourceList()) {
                emails << email.property(NCO::emailAddress()).toString();
            }
        }
    }

    return emails;
}

QStringList PersonData::phones() const
{
    Q_D(const PersonData);

    QStringList phones;

    if (d->res.type() == PIMO::Person()) {
        Q_FOREACH (const Nepomuk2::Resource &resource, d->res.property(PIMO::groundingOccurrence()).toResourceList()) {
            if (resource.hasProperty(NCO::hasPhoneNumber())) {
                Q_FOREACH (const Nepomuk2::Resource &phone, resource.property(NCO::hasPhoneNumber()).toResourceList()) {
                    phones << phone.property(NCO::phoneNumber()).toString();
                }
            }
        }
    } else {
        if (d->res.hasProperty(NCO::hasPhoneNumber())) {
            Q_FOREACH (const Nepomuk2::Resource &phone, d->res.property(NCO::hasPhoneNumber()).toResourceList()) {
                phones << phone.property(NCO::phoneNumber()).toString();
            }
        }
    }

    return phones;
}

QStringList PersonData::imAccounts() const
{
    Q_D(const PersonData);

    QStringList ims;

    if (d->res.type() == PIMO::Person()) {
        Q_FOREACH (const Nepomuk2::Resource &resource, d->res.property(PIMO::groundingOccurrence()).toResourceList()) {
            if (resource.hasProperty(NCO::hasIMAccount())) {
                Q_FOREACH (const Nepomuk2::Resource &im, resource.property(NCO::hasIMAccount()).toResourceList()) {
                    ims << im.property(NCO::imAccountType()).toString();
                    ims << im.property(NCO::imNickname()).toString();
                    ims << im.property(NCO::imID()).toString();
                }
            }
        }
    } else {
        if (d->res.hasProperty(NCO::hasIMAccount())) {
            Q_FOREACH (const Nepomuk2::Resource &im, d->res.property(NCO::hasIMAccount()).toResourceList()) {
                ims << im.property(NCO::imAccountType()).toString();
                ims << im.property(NCO::imNickname()).toString();
                ims << im.property(NCO::imID()).toString();
            }
        }
    }

    return ims;
}

// QStringList PersonData::bareContacts() const
// {
//     return personIndex().data(PersonsModel::ContactIdRole).toStringList();
// }
//
// QModelIndex PersonData::personIndex() const
// {
//     Q_D(const PersonData);
//     Q_ASSERT(d->model->rowCount()>0);
//     QModelIndex idx = d->model->index(0,0);
//     Q_ASSERT(idx.isValid());
//     return idx;
// }
//

bool PersonData::isPerson() const
{
    Q_D(const PersonData);
    return d->res.type() == PIMO::Person();
}

QString PersonData::findMostOnlinePresence(const QStringList &presences) const
{
    if (presences.contains("available")) {
        return "available";
    }
    if (presences.contains("away")) {
        return "away";
    }
    if (presences.contains("busy") || presences.contains("dnd")) {
        return "busy";
    }
    if (presences.contains("xa")) {
        return "xa";
    }

    return "offline";
}
<|endoftext|>


<commit_before>///
/// @file   primecount.cpp
/// @brief  primecount C++ API
///
/// Copyright (C) 2014 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount.hpp>
#include <primecount-internal.hpp>
#include <calculator.hpp>
#include <ptypes.hpp>
#include <pmath.hpp>

#include <algorithm>
#include <ctime>
#include <iostream>
#include <iomanip>
#include <limits>
#include <sstream>
#include <string>
#include <stdint.h>

#ifdef _OPENMP
  #include <omp.h>
#endif

namespace {

int threads_ = primecount::MAX_THREADS;

bool print_status_ = false;

}

namespace primecount {

int64_t pi(int64_t x)
{
  return pi(x, threads_);
}

int64_t pi(int64_t x, int threads)
{
  return pi_deleglise_rivat(x, threads);
}

#ifdef HAVE_INT128_T

int128_t pi(int128_t x)
{
  return pi(x, threads_);
}

int128_t pi(int128_t x, int threads)
{
  return pi_deleglise_rivat(x, threads);
}

#endif

/// Alias for the fastest prime counting function in primecount.
/// @param x  integer or arithmetic expression like "10^12".
/// @pre   x  <= primecount::max().
///
std::string pi(const std::string& x)
{
  return pi(x, threads_);
}

/// Alias for the fastest prime counting function in primecount.
/// @param x  integer or arithmetic expression like "10^12".
/// @pre   x  <= primecount::max().
///
std::string pi(const std::string& x, int threads)
{
  maxint_t n = to_maxint(x);
  maxint_t pin = pi(n, threads);
  std::ostringstream oss;
  oss << pin;
  return oss.str();
}

/// Calculate the number of primes below x using the
/// Deleglise-Rivat algorithm.
/// Run time: O(x^(2/3) / (log x)^2) operations, O(x^(1/3) * (log x)^3) space.
///
int64_t pi_deleglise_rivat(int64_t x)
{
  return pi_deleglise_rivat(x, threads_);
}

/// Calculate the number of primes below x using the
/// Deleglise-Rivat algorithm.
/// Run time: O(x^(2/3) / (log x)^2) operations, O(x^(1/3) * (log x)^3) space.
///
int64_t pi_deleglise_rivat(int64_t x, int threads)
{
  if (threads <= 1)
    return pi_deleglise_rivat3(x);

  return pi_deleglise_rivat_parallel3(x, threads);
}

#ifdef HAVE_INT128_T

/// Calculate the number of primes below x using the
/// Deleglise-Rivat algorithm.
/// Run time: O(x^(2/3) / (log x)^2) operations, O(x^(1/3) * (log x)^3) space.
///
int128_t pi_deleglise_rivat(int128_t x)
{
  return pi_deleglise_rivat(x, threads_);
}

/// Calculate the number of primes below x using the
/// Deleglise-Rivat algorithm.
/// Run time: O(x^(2/3) / (log x)^2) operations, O(x^(1/3) * (log x)^3) space.
///
int128_t pi_deleglise_rivat(int128_t x, int threads)
{
  // use 64-bit if possible
  if (x <= std::numeric_limits<int64_t>::max())
    return pi_deleglise_rivat((int64_t) x, threads);

  if (threads <= 1)
    return pi_deleglise_rivat4(x);
  else
    return pi_deleglise_rivat_parallel4(x, threads);
}

#endif

/// Calculate the number of primes below x using Legendre's formula.
/// Run time: O(x) operations, O(x^(1/2)) space.
///
int64_t pi_legendre(int64_t x)
{
  return pi_legendre(x, threads_);
}

/// Calculate the number of primes below x using Lehmer's formula.
/// Run time: O(x/(log x)^4) operations, O(x^(1/2)) space.
///
int64_t pi_lehmer(int64_t x)
{
  return pi_lehmer(x, threads_);
}

/// Calculate the number of primes below x using the
/// Lagarias-Miller-Odlyzko algorithm.
/// Run time: O(x^(2/3) / log x) operations, O(x^(1/3) * (log x)^2) space.
///
int64_t pi_lmo(int64_t x)
{
  return pi_lmo(x, threads_);
}

/// Parallel implementation of the Lagarias-Miller-Odlyzko
/// prime counting algorithm using OpenMP.
/// Run time: O(x^(2/3) / log x) operations, O(x^(1/3) * (log x)^2) space.
///
int64_t pi_lmo(int64_t x, int threads)
{
  if (threads <= 1)
    return pi_lmo5(x);

  return pi_lmo_parallel3(x, threads);
}

/// Calculate the number of primes below x using Meissel's formula.
/// Run time: O(x/(log x)^3) operations, O(x^(1/2) / log x) space.
///
int64_t pi_meissel(int64_t x)
{
  return pi_meissel(x, threads_);
}

/// Calculate the number of primes below x using an optimized
/// segmented sieve of Eratosthenes implementation.
/// Run time: O(x log log x) operations, O(x^(1/2)) space.
///
int64_t pi_primesieve(int64_t x)
{
  return pi_primesieve(x, threads_);
}

/// Calculate the nth prime using a combination of an efficient prime
/// counting function implementation and the sieve of Eratosthenes.
/// Run time: O(x^(2/3) / (log x)^2) operations, O(x^(1/2)) space.
///
int64_t nth_prime(int64_t n)
{
  return nth_prime(n, threads_);
}

/// Partial sieve function (a.k.a. Legendre-sum).
/// phi(x, a) counts the numbers <= x that are not divisible
/// by any of the first a primes.
///
int64_t phi(int64_t x, int64_t a)
{
  return phi(x, a, threads_);
}

/// Returns the largest integer that can be used with
/// pi(std::string x). The return type is a string as max may be a
/// 128-bit integer which is not supported by all compilers.
///
std::string max()
{
#ifdef HAVE_INT128_T
  // max = 10^27 if int128_t is supported
  return std::string("1") + std::string(27, '0');
#else
  std::ostringstream oss;
  oss << std::numeric_limits<int64_t>::max();
  return oss.str();
#endif
}

/// Get the wall time in seconds.
double get_wtime()
{
#ifdef _OPENMP
  return omp_get_wtime();
#else
  return static_cast<double>(std::clock()) / CLOCKS_PER_SEC;
#endif
}

int validate_threads(int threads)
{
#ifdef _OPENMP
  if (threads == MAX_THREADS)
    threads = omp_get_max_threads();
  return in_between(1, threads, omp_get_max_threads());
#else
  threads = 1;
  return threads;
#endif
}

int validate_threads(int threads, int64_t sieve_limit, int64_t thread_threshold)
{
  threads = validate_threads(threads);
  threads = (int) std::min((int64_t) threads, sieve_limit / thread_threshold);
  threads = std::max(1, threads);
  return threads;
}

void set_num_threads(int threads)
{
  threads_ = validate_threads(threads);
}

int get_num_threads()
{
  return validate_threads(threads_);
}

maxint_t to_maxint(const std::string& expr)
{
  maxint_t n = calculator::eval<maxint_t>(expr);
  return n;
}

void print_percent(maxint_t s2_current, maxint_t s2_approx, double rsd)
{
  int percent = get_percent(s2_current, s2_approx);
  int load_balance = (int) in_between(0, 100 - rsd + 0.5, 100);
  std::cout << "\rStatus: " << percent << "%, Load balance: " << load_balance << "%" << std::flush;
}

void print_result(const std::string& str, maxint_t res, double time)
{
  std::cout << "\rStatus: 100%" << std::string(30, ' ') << std::endl;
  std::cout << str << " = " << res << std::endl;
  print_seconds(get_wtime() - time);
}

void print_seconds(double seconds)
{
  std::cout << "Seconds: " << std::fixed << std::setprecision(3) << seconds << std::endl;
}

void print_megabytes(std::size_t bytes)
{
  double megabytes = bytes / (double) (1 << 20);
  std::cout << "memory usage = " << std::fixed << std::setprecision(3) << megabytes << " megabytes" << std::endl;
}

void set_print_status(bool print_status)
{
  print_status_ = print_status;
}

bool print_status()
{
  return print_status_;
}

} // namespace primecount
<commit_msg>using namespace std<commit_after>///
/// @file   primecount.cpp
/// @brief  primecount C++ API
///
/// Copyright (C) 2014 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount.hpp>
#include <primecount-internal.hpp>
#include <calculator.hpp>
#include <ptypes.hpp>
#include <pmath.hpp>

#include <algorithm>
#include <ctime>
#include <iostream>
#include <iomanip>
#include <limits>
#include <sstream>
#include <string>
#include <stdint.h>

#ifdef _OPENMP
  #include <omp.h>
#endif

using namespace std;

namespace {

int threads_ = primecount::MAX_THREADS;

bool print_status_ = false;

}

namespace primecount {

int64_t pi(int64_t x)
{
  return pi(x, threads_);
}

int64_t pi(int64_t x, int threads)
{
  return pi_deleglise_rivat(x, threads);
}

#ifdef HAVE_INT128_T

int128_t pi(int128_t x)
{
  return pi(x, threads_);
}

int128_t pi(int128_t x, int threads)
{
  return pi_deleglise_rivat(x, threads);
}

#endif

/// Alias for the fastest prime counting function in primecount.
/// @param x  integer or arithmetic expression like "10^12".
/// @pre   x  <= primecount::max().
///
std::string pi(const std::string& x)
{
  return pi(x, threads_);
}

/// Alias for the fastest prime counting function in primecount.
/// @param x  integer or arithmetic expression like "10^12".
/// @pre   x  <= primecount::max().
///
std::string pi(const std::string& x, int threads)
{
  maxint_t n = to_maxint(x);
  maxint_t pin = pi(n, threads);
  ostringstream oss;
  oss << pin;
  return oss.str();
}

/// Calculate the number of primes below x using the
/// Deleglise-Rivat algorithm.
/// Run time: O(x^(2/3) / (log x)^2) operations, O(x^(1/3) * (log x)^3) space.
///
int64_t pi_deleglise_rivat(int64_t x)
{
  return pi_deleglise_rivat(x, threads_);
}

/// Calculate the number of primes below x using the
/// Deleglise-Rivat algorithm.
/// Run time: O(x^(2/3) / (log x)^2) operations, O(x^(1/3) * (log x)^3) space.
///
int64_t pi_deleglise_rivat(int64_t x, int threads)
{
  if (threads <= 1)
    return pi_deleglise_rivat3(x);

  return pi_deleglise_rivat_parallel3(x, threads);
}

#ifdef HAVE_INT128_T

/// Calculate the number of primes below x using the
/// Deleglise-Rivat algorithm.
/// Run time: O(x^(2/3) / (log x)^2) operations, O(x^(1/3) * (log x)^3) space.
///
int128_t pi_deleglise_rivat(int128_t x)
{
  return pi_deleglise_rivat(x, threads_);
}

/// Calculate the number of primes below x using the
/// Deleglise-Rivat algorithm.
/// Run time: O(x^(2/3) / (log x)^2) operations, O(x^(1/3) * (log x)^3) space.
///
int128_t pi_deleglise_rivat(int128_t x, int threads)
{
  // use 64-bit if possible
  if (x <= numeric_limits<int64_t>::max())
    return pi_deleglise_rivat((int64_t) x, threads);

  if (threads <= 1)
    return pi_deleglise_rivat4(x);
  else
    return pi_deleglise_rivat_parallel4(x, threads);
}

#endif

/// Calculate the number of primes below x using Legendre's formula.
/// Run time: O(x) operations, O(x^(1/2)) space.
///
int64_t pi_legendre(int64_t x)
{
  return pi_legendre(x, threads_);
}

/// Calculate the number of primes below x using Lehmer's formula.
/// Run time: O(x/(log x)^4) operations, O(x^(1/2)) space.
///
int64_t pi_lehmer(int64_t x)
{
  return pi_lehmer(x, threads_);
}

/// Calculate the number of primes below x using the
/// Lagarias-Miller-Odlyzko algorithm.
/// Run time: O(x^(2/3) / log x) operations, O(x^(1/3) * (log x)^2) space.
///
int64_t pi_lmo(int64_t x)
{
  return pi_lmo(x, threads_);
}

/// Parallel implementation of the Lagarias-Miller-Odlyzko
/// prime counting algorithm using OpenMP.
/// Run time: O(x^(2/3) / log x) operations, O(x^(1/3) * (log x)^2) space.
///
int64_t pi_lmo(int64_t x, int threads)
{
  if (threads <= 1)
    return pi_lmo5(x);

  return pi_lmo_parallel3(x, threads);
}

/// Calculate the number of primes below x using Meissel's formula.
/// Run time: O(x/(log x)^3) operations, O(x^(1/2) / log x) space.
///
int64_t pi_meissel(int64_t x)
{
  return pi_meissel(x, threads_);
}

/// Calculate the number of primes below x using an optimized
/// segmented sieve of Eratosthenes implementation.
/// Run time: O(x log log x) operations, O(x^(1/2)) space.
///
int64_t pi_primesieve(int64_t x)
{
  return pi_primesieve(x, threads_);
}

/// Calculate the nth prime using a combination of an efficient prime
/// counting function implementation and the sieve of Eratosthenes.
/// Run time: O(x^(2/3) / (log x)^2) operations, O(x^(1/2)) space.
///
int64_t nth_prime(int64_t n)
{
  return nth_prime(n, threads_);
}

/// Partial sieve function (a.k.a. Legendre-sum).
/// phi(x, a) counts the numbers <= x that are not divisible
/// by any of the first a primes.
///
int64_t phi(int64_t x, int64_t a)
{
  return phi(x, a, threads_);
}

/// Returns the largest integer that can be used with
/// pi(std::string x). The return type is a string as max may be a
/// 128-bit integer which is not supported by all compilers.
///
std::string max()
{
#ifdef HAVE_INT128_T
  return string("1") + string(27, '0');
#else
  ostringstream oss;
  oss << numeric_limits<int64_t>::max();
  return oss.str();
#endif
}

/// Get the wall time in seconds.
double get_wtime()
{
#ifdef _OPENMP
  return omp_get_wtime();
#else
  return static_cast<double>(std::clock()) / CLOCKS_PER_SEC;
#endif
}

int validate_threads(int threads)
{
#ifdef _OPENMP
  if (threads == MAX_THREADS)
    threads = omp_get_max_threads();
  return in_between(1, threads, omp_get_max_threads());
#else
  threads = 1;
  return threads;
#endif
}

int validate_threads(int threads, int64_t sieve_limit, int64_t thread_threshold)
{
  threads = validate_threads(threads);
  threads = (int) std::min((int64_t) threads, sieve_limit / thread_threshold);
  threads = std::max(1, threads);
  return threads;
}

void set_num_threads(int threads)
{
  threads_ = validate_threads(threads);
}

int get_num_threads()
{
  return validate_threads(threads_);
}

maxint_t to_maxint(const std::string& expr)
{
  maxint_t n = calculator::eval<maxint_t>(expr);
  return n;
}

void print_percent(maxint_t s2_current, maxint_t s2_approx, double rsd)
{
  int percent = get_percent(s2_current, s2_approx);
  int load_balance = (int) in_between(0, 100 - rsd + 0.5, 100);
  cout << "\rStatus: " << percent << "%, Load balance: " << load_balance << "%" << flush;
}

void print_result(const std::string& str, maxint_t res, double time)
{
  cout << "\rStatus: 100%" << string(30, ' ') << endl;
  cout << str << " = " << res << endl;
  print_seconds(get_wtime() - time);
}

void print_seconds(double seconds)
{
  cout << "Seconds: " << fixed << setprecision(3) << seconds << endl;
}

void print_megabytes(std::size_t bytes)
{
  double megabytes = bytes / (double) (1 << 20);
  cout << "memory usage = " << fixed << setprecision(3) << megabytes << " megabytes" << endl;
}

void set_print_status(bool print_status)
{
  print_status_ = print_status;
}

bool print_status()
{
  return print_status_;
}

} // namespace primecount
<|endoftext|>


<commit_before>/**
 * \file psdd.cc
 *
 *
 *
 * \author Ethan Burns
 * \date 2008-10-24
 */

#include <pthread.h>

#include <limits>
#include <iostream>
#include <vector>

#include "psdd_search.h"
#include "psdd/nblock_graph.h"
#include "psdd/nblock.h"
#include "util/thread.h"
#include "util/timer.h"
#include "projection.h"
#include "open_list.h"
#include "closed_list.h"

using namespace std;
using namespace PSDD;

/**
 * Create a new PSDD Search thread.
 */
PSDDSearch::PSDDThread::PSDDThread(NBlockGraph *graph, PSDDSearch *search)
	: graph(graph), search(search), lowest_out_of_bounds(fp_infinity) {}

PSDDSearch::PSDDThread::~PSDDThread() {}

/**
 * The thread work method for a PSDD search.
 */
void PSDDSearch::PSDDThread::run(void)
{
	vector<State *> *path;
	NBlock *n = NULL;

	do {
		n = graph->next_nblock(n);
		if (!n)		// no solution
			break;

		exp_this_block = 0;

		path = search_nblock(n);

		if (path) {
			search->set_path(path);
			graph->set_path_found();
		}

		ave_exp_per_nblock.add_val(exp_this_block);

	} while(!search->path_found());
}

fp_type PSDDSearch::PSDDThread::get_ave_exp_per_nblock(void)
{
	return ave_exp_per_nblock.read();
}

/**
 * Search a single NBlock.
 * \param n The NBlock.
 * \return NULL, or a path to a goal.
 */
vector<State *> *PSDDSearch::PSDDThread::search_nblock(NBlock *n)
{
	vector<State *> *path = NULL;
	OpenList *cur_open = &n->open[graph->get_cur_layer()];

	while (!cur_open->empty()) {
		State *s = cur_open->take();

		if (s->is_goal()) {
			path = s->get_path();
			break;
		}

		exp_this_block += 1;

		vector<State *> *children = search->expand(s);
		vector<State *>::iterator iter;
		for (iter = children->begin();
		     iter != children->end();
		     iter++) {

			if ((*iter)->get_f() > search->bound.read()) {
				if ((*iter)->get_f() < lowest_out_of_bounds)
					lowest_out_of_bounds = (*iter)->get_f();

				delete *iter;
				continue;
			}

			unsigned int block = search->project->project(*iter);
			NBlock *b = graph->get_nblock(block);
			OpenList *next_open = &b->open[graph->get_next_layer()];
			ClosedList *next_closed = &graph->get_nblock(block)->closed;
			State *dup = next_closed->lookup(*iter);
			if (dup) {
				if (dup->get_g() > (*iter)->get_g()) {
					dup->update((*iter)->get_parent(),
						    (*iter)->get_g());
					if (!dup->is_open())
						next_open->add(dup);
				}
				delete *iter;
			} else {
				next_closed->add(*iter);
				if ((*iter)->is_goal()) {
					path = (*iter)->get_path();
					delete children;
					return path;
				}
				next_open->add(*iter);
			}
		}
		delete children;

	}

	return path;
}

fp_type PSDDSearch::PSDDThread::get_lowest_out_of_bounds(void)
{
	return lowest_out_of_bounds;
}

/**********************************************************************/

/**
 * Create a new Parallel Structured Duplicate Detection search.
 */
PSDDSearch::PSDDSearch(unsigned int n_threads)
	: bound(fp_infinity),
	  n_threads(n_threads),
	  project(NULL),
	  path(NULL),
	  graph(NULL),
	  lowest_out_of_bounds(fp_infinity),
	  print(true)
{
	pthread_mutex_init(&path_mutex, NULL);
}

/**
 * Create a new Parallel Structured Duplicate Detection search with a
 * given bound.
 */
PSDDSearch::PSDDSearch(unsigned int n_threads, fp_type bound)
	: bound(bound),
	  n_threads(n_threads),
	  project(NULL),
	  path(NULL),
	  graph(NULL),
	  lowest_out_of_bounds(fp_infinity)
{
	pthread_mutex_init(&path_mutex, NULL);
}

/**
 * Destructor.
 */
PSDDSearch::~PSDDSearch(void)
{
	if (graph)
		delete graph;
}

/**
 * Set the path to the goal.
 */
void PSDDSearch::set_path(vector<State *> *p)
{
	pthread_mutex_lock(&path_mutex);
	if (path) {
		vector<State *>::iterator iter;

		for (iter = p->begin(); iter != p->end(); iter++)
			delete *iter;

		delete p;
	} else {
		path = p;
	}
	pthread_mutex_unlock(&path_mutex);
}

/**
 * Test if there has been a path to the goal found yet.
 */
bool PSDDSearch::path_found(void) const
{
	return path != NULL;
}

/**
 * Perform the search.
 */
vector<State *> *PSDDSearch::search(State *initial)
{
	project = initial->get_domain()->get_projection();

	vector<PSDDThread *> threads;
	vector<PSDDThread *>::iterator iter;
	fp_type sum = 0.0;
	unsigned int num = 0;
	Timer t;

	if (!graph) {
		t.start();
		graph = new NBlockGraph(project, initial);
		t.stop();
	} else {
		graph->reset(project, initial);
	}

	for (unsigned int i = 0; i < n_threads; i += 1) {
		PSDDThread *t = new PSDDThread(graph, this);
		threads.push_back(t);
		t->start();
	}

	for (iter = threads.begin(); iter != threads.end(); iter++) {
		(*iter)->join();
		if ((*iter)->get_lowest_out_of_bounds()
		    < lowest_out_of_bounds) {
			lowest_out_of_bounds =
				(*iter)->get_lowest_out_of_bounds();
		}

		fp_type ave = (*iter)->get_ave_exp_per_nblock();
		if (ave != 0.0) {
			sum += ave;
			num += 1;
		}

		delete *iter;
	}

	if (num == 0)
		cout << "expansions-per-nblock: -1" << endl;
	else
		cout << "expansions-per-nblock: " << sum / num << endl;

	cout << "nblock-graph-creation-time: " << t.get_wall_time() << endl;

	cout << "total-nblocks: " << project->get_num_nblocks() << endl;
	cout << "created-nblocks: " << graph->get_ncreated_nblocks() << endl;

	return path;
}

/**
 * Set the bound.
 */
void PSDDSearch::set_bound(fp_type b)
{
	this->bound.set(b);
}

fp_type PSDDSearch::get_lowest_out_of_bounds(void)
{
	return lowest_out_of_bounds;
}

void PSDDSearch::reset(void)
{
	lowest_out_of_bounds = fp_infinity;
	path = NULL;
}

void PSDDSearch::do_not_print(void)
{
	print = false;
}
<commit_msg>Do not have PSDD output in the search function.<commit_after>/**
 * \file psdd.cc
 *
 *
 *
 * \author Ethan Burns
 * \date 2008-10-24
 */

#include <pthread.h>

#include <limits>
#include <iostream>
#include <vector>

#include "psdd_search.h"
#include "psdd/nblock_graph.h"
#include "psdd/nblock.h"
#include "util/thread.h"
#include "util/timer.h"
#include "projection.h"
#include "open_list.h"
#include "closed_list.h"

using namespace std;
using namespace PSDD;

/**
 * Create a new PSDD Search thread.
 */
PSDDSearch::PSDDThread::PSDDThread(NBlockGraph *graph, PSDDSearch *search)
	: graph(graph), search(search), lowest_out_of_bounds(fp_infinity) {}

PSDDSearch::PSDDThread::~PSDDThread() {}

/**
 * The thread work method for a PSDD search.
 */
void PSDDSearch::PSDDThread::run(void)
{
	vector<State *> *path;
	NBlock *n = NULL;

	do {
		n = graph->next_nblock(n);
		if (!n)		// no solution
			break;

		exp_this_block = 0;

		path = search_nblock(n);

		if (path) {
			search->set_path(path);
			graph->set_path_found();
		}

		ave_exp_per_nblock.add_val(exp_this_block);

	} while(!search->path_found());
}

fp_type PSDDSearch::PSDDThread::get_ave_exp_per_nblock(void)
{
	return ave_exp_per_nblock.read();
}

/**
 * Search a single NBlock.
 * \param n The NBlock.
 * \return NULL, or a path to a goal.
 */
vector<State *> *PSDDSearch::PSDDThread::search_nblock(NBlock *n)
{
	vector<State *> *path = NULL;
	OpenList *cur_open = &n->open[graph->get_cur_layer()];

	while (!cur_open->empty()) {
		State *s = cur_open->take();

		if (s->is_goal()) {
			path = s->get_path();
			break;
		}

		exp_this_block += 1;

		vector<State *> *children = search->expand(s);
		vector<State *>::iterator iter;
		for (iter = children->begin();
		     iter != children->end();
		     iter++) {

			if ((*iter)->get_f() > search->bound.read()) {
				if ((*iter)->get_f() < lowest_out_of_bounds)
					lowest_out_of_bounds = (*iter)->get_f();

				delete *iter;
				continue;
			}

			unsigned int block = search->project->project(*iter);
			NBlock *b = graph->get_nblock(block);
			OpenList *next_open = &b->open[graph->get_next_layer()];
			ClosedList *next_closed = &graph->get_nblock(block)->closed;
			State *dup = next_closed->lookup(*iter);
			if (dup) {
				if (dup->get_g() > (*iter)->get_g()) {
					dup->update((*iter)->get_parent(),
						    (*iter)->get_g());
					if (!dup->is_open())
						next_open->add(dup);
				}
				delete *iter;
			} else {
				next_closed->add(*iter);
				if ((*iter)->is_goal()) {
					path = (*iter)->get_path();
					delete children;
					return path;
				}
				next_open->add(*iter);
			}
		}
		delete children;

	}

	return path;
}

fp_type PSDDSearch::PSDDThread::get_lowest_out_of_bounds(void)
{
	return lowest_out_of_bounds;
}

/**********************************************************************/

/**
 * Create a new Parallel Structured Duplicate Detection search.
 */
PSDDSearch::PSDDSearch(unsigned int n_threads)
	: bound(fp_infinity),
	  n_threads(n_threads),
	  project(NULL),
	  path(NULL),
	  graph(NULL),
	  lowest_out_of_bounds(fp_infinity),
	  print(true)
{
	pthread_mutex_init(&path_mutex, NULL);
}

/**
 * Create a new Parallel Structured Duplicate Detection search with a
 * given bound.
 */
PSDDSearch::PSDDSearch(unsigned int n_threads, fp_type bound)
	: bound(bound),
	  n_threads(n_threads),
	  project(NULL),
	  path(NULL),
	  graph(NULL),
	  lowest_out_of_bounds(fp_infinity)
{
	pthread_mutex_init(&path_mutex, NULL);
}

/**
 * Destructor.
 */
PSDDSearch::~PSDDSearch(void)
{
	if (graph)
		delete graph;
}

/**
 * Set the path to the goal.
 */
void PSDDSearch::set_path(vector<State *> *p)
{
	pthread_mutex_lock(&path_mutex);
	if (path) {
		vector<State *>::iterator iter;

		for (iter = p->begin(); iter != p->end(); iter++)
			delete *iter;

		delete p;
	} else {
		path = p;
	}
	pthread_mutex_unlock(&path_mutex);
}

/**
 * Test if there has been a path to the goal found yet.
 */
bool PSDDSearch::path_found(void) const
{
	return path != NULL;
}

/**
 * Perform the search.
 */
vector<State *> *PSDDSearch::search(State *initial)
{
	project = initial->get_domain()->get_projection();

	vector<PSDDThread *> threads;
	vector<PSDDThread *>::iterator iter;
	fp_type sum = 0.0;
	unsigned int num = 0;
	Timer t;

	if (!graph) {
		t.start();
		graph = new NBlockGraph(project, initial);
		t.stop();
	} else {
		graph->reset(project, initial);
	}

	for (unsigned int i = 0; i < n_threads; i += 1) {
		PSDDThread *t = new PSDDThread(graph, this);
		threads.push_back(t);
		t->start();
	}

	for (iter = threads.begin(); iter != threads.end(); iter++) {
		(*iter)->join();
		if ((*iter)->get_lowest_out_of_bounds()
		    < lowest_out_of_bounds) {
			lowest_out_of_bounds =
				(*iter)->get_lowest_out_of_bounds();
		}

		fp_type ave = (*iter)->get_ave_exp_per_nblock();
		if (ave != 0.0) {
			sum += ave;
			num += 1;
		}

		delete *iter;
	}

/* This output should not happen here inside the search function */
//	if (num == 0 )
// 		cout << "expansions-per-nblock: -1" << endl;
// 	else
// 		cout << "expansions-per-nblock: " << sum / num << endl;

// 	cout << "nblock-graph-creation-time: " << t.get_wall_time() << endl;

// 	cout << "total-nblocks: " << project->get_num_nblocks() << endl;
// 	cout << "created-nblocks: " << graph->get_ncreated_nblocks() << endl;

	return path;
}

/**
 * Set the bound.
 */
void PSDDSearch::set_bound(fp_type b)
{
	this->bound.set(b);
}

fp_type PSDDSearch::get_lowest_out_of_bounds(void)
{
	return lowest_out_of_bounds;
}

void PSDDSearch::reset(void)
{
	lowest_out_of_bounds = fp_infinity;
	path = NULL;
}

void PSDDSearch::do_not_print(void)
{
	print = false;
}
<|endoftext|>