<commit_before>/*
 * Copyright 2009-2020 The VOTCA Development Team (http://www.votca.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
#include <boost/test/tools/old/interface.hpp>
#define BOOST_TEST_MAIN

#define BOOST_TEST_MODULE incrementalfockbuilder_test

// Third party includes
#include <boost/test/unit_test.hpp>

// Local VOTCA includes
#include "votca/xtp/IncrementalFockBuilder.h"

using namespace votca::xtp;

BOOST_AUTO_TEST_SUITE(incrementalfockbuilder)

BOOST_AUTO_TEST_CASE(off_test) {
  Logger log;

  // switched off
  IncrementalFockBuilder fb(log, 0.0, 3);

  Eigen::MatrixXd dmat = Eigen::MatrixXd::Random(10, 10);
  fb.Configure(dmat);
  fb.Start(2, 1e-5);

  Eigen::MatrixXd J = Eigen::MatrixXd::Random(10, 10);
  Eigen::MatrixXd K = Eigen::MatrixXd::Random(10, 10);
  fb.resetMatrices(J, K, dmat);
  BOOST_CHECK(J.isApproxToConstant(0.0));
  BOOST_CHECK(K.isApproxToConstant(0.0));

  BOOST_CHECK(fb.getDmat_diff().isApprox(dmat));

  fb.UpdateDmats(dmat, 1e-5, 2);

  // basically checks that using the same dmat twice leads to a diff of zero
  BOOST_CHECK(fb.getDmat_diff().isApproxToConstant(0.0));
}

BOOST_AUTO_TEST_CASE(on_test) {
  Logger log;

  // switched on
  IncrementalFockBuilder fb(log, 1e-5, 3);

  Eigen::MatrixXd dmat = Eigen::MatrixXd::Random(10, 10);
  fb.Configure(dmat);
  votca::Index iteration = 2;
  fb.Start(iteration, 1e-6);

  Eigen::MatrixXd J = Eigen::MatrixXd::Random(10, 10);
  Eigen::MatrixXd J2 = J;
  Eigen::MatrixXd K = Eigen::MatrixXd::Random(10, 10);
  Eigen::MatrixXd K2 = K;

  fb.resetMatrices(J, K, dmat);
  BOOST_CHECK(J.isApprox(J2));
  BOOST_CHECK(K.isApprox(K2));

  fb.UpdateCriteria(1e-6, iteration);
  fb.UpdateDmats(dmat, 1e-6, iteration);
  // basically checks that using the same dmat twice leads to a diff of zero
  BOOST_CHECK(fb.getDmat_diff().isApproxToConstant(0.0));
  iteration++;
  fb.UpdateCriteria(1e-6, iteration);
  fb.UpdateDmats(dmat, 1e-6, iteration);
  iteration++;
  fb.UpdateCriteria(1e-6, iteration);
  fb.UpdateDmats(dmat, 1e-6, iteration);

  // now reset should trigger
  fb.resetMatrices(J, K, dmat);
  BOOST_CHECK(J.isApproxToConstant(0.0));
  BOOST_CHECK(K.isApproxToConstant(0.0));
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>fixed test<commit_after>/*
 * Copyright 2009-2020 The VOTCA Development Team (http://www.votca.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
#include <boost/test/tools/old/interface.hpp>
#define BOOST_TEST_MAIN

#define BOOST_TEST_MODULE incrementalfockbuilder_test

// Third party includes
#include <boost/test/unit_test.hpp>

// Local VOTCA includes
#include "votca/xtp/IncrementalFockBuilder.h"

using namespace votca::xtp;

BOOST_AUTO_TEST_SUITE(incrementalfockbuilder)

BOOST_AUTO_TEST_CASE(off_test) {
  Logger log;

  // switched off
  IncrementalFockBuilder fb(log, 0.0, 3);

  Eigen::MatrixXd dmat = Eigen::MatrixXd::Random(10, 10);
  fb.Configure(dmat);
  fb.Start(2, 1e-5);

  Eigen::MatrixXd J = Eigen::MatrixXd::Random(10, 10);
  Eigen::MatrixXd K = Eigen::MatrixXd::Random(10, 10);
  fb.resetMatrices(J, K, dmat);
  BOOST_CHECK(J.isApproxToConstant(0.0));
  BOOST_CHECK(K.isApproxToConstant(0.0));

  BOOST_CHECK(fb.getDmat_diff().isApprox(dmat));

  fb.UpdateDmats(dmat, 1e-5, 2);

  // basically checks that using the same dmat twice leads to a diff of zero
  BOOST_CHECK(fb.getDmat_diff().isApproxToConstant(0.0));
}

BOOST_AUTO_TEST_CASE(on_test) {
  Logger log;

  // switched on
  IncrementalFockBuilder fb(log, 1e-5, 2);

  Eigen::MatrixXd dmat = Eigen::MatrixXd::Random(10, 10);
  fb.Configure(dmat);
  votca::Index iteration = 2;
  fb.Start(iteration, 1e-6);

  Eigen::MatrixXd J = Eigen::MatrixXd::Random(10, 10);
  Eigen::MatrixXd J2 = J;
  Eigen::MatrixXd K = Eigen::MatrixXd::Random(10, 10);
  Eigen::MatrixXd K2 = K;

  fb.resetMatrices(J, K, dmat);
  BOOST_CHECK(J.isApprox(J2));
  BOOST_CHECK(K.isApprox(K2));

  fb.UpdateCriteria(1e-6, iteration);
  fb.UpdateDmats(dmat, 1e-6, iteration);
  // basically checks that using the same dmat twice leads to a diff of zero
  BOOST_CHECK(fb.getDmat_diff().isApproxToConstant(0.0));
  iteration++;
  fb.UpdateCriteria(1e-6, iteration);
  fb.UpdateDmats(dmat, 1e-6, iteration);
  iteration++;
  fb.UpdateCriteria(1e-6, iteration);
  fb.UpdateDmats(dmat, 1e-6, iteration);\

  // now reset should trigger
  fb.resetMatrices(J, K, dmat);
  BOOST_CHECK(J.isApproxToConstant(0.0));
  BOOST_CHECK(K.isApproxToConstant(0.0));
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>/* Copyright (C) 2017 INRA
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublipnse, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "itm.hpp"

#include <set>

#include <cassert>

namespace bx = baryonyx;

struct merged_constraint_hash
{
    inline size_t operator()(
      const std::vector<bx::function_element>& fct) const noexcept
    {
        std::size_t seed{ fct.size() };

        for (auto& elem : fct)
            seed ^=
              elem.variable_index + 0x9e3779b9 + (seed << 6) + (seed >> 2);

        return seed;
    }
};

//
// Fills the cache and uses it to search same function and merge equal, less
// and greater equal constraints. To be use in any order, the fill operation
// depends of the operator type passed in parameter.
//
template<typename cacheT, typename retT>
static void
fill_merged_constraints(std::shared_ptr<bx::context> ctx,
                        cacheT& cache,
                        bx::operator_type op,
                        const bx::problem& pb,
                        retT& ret)
{
    switch (op) {
    case bx::operator_type::equal:
        for (const auto& elem : pb.equal_constraints) {
            auto it = cache.find(elem.elements);
            if (it == cache.end()) {
                cache.emplace(elem.elements, ret.size());
                ret.emplace_back(
                  elem.elements,
                  bx::numeric_cast<int>(std::lround(elem.value)),
                  bx::numeric_cast<int>(std::lround(elem.value)),

                  elem.id);
            } else {
                if (ret[it->second].min <= elem.value and
                    elem.value <= ret[it->second].max) {
                    ret[it->second].min = elem.value;
                    ret[it->second].max = elem.value;
                } else {
                    ctx->error(
                      "Constraint %d: is inconsistent with previous %d.\n",
                      elem.id,
                      ret[it->second].id);
                }
            }
        }
        break;
    case bx::operator_type::less:
        for (const auto& elem : pb.less_constraints) {
            auto it = cache.find(elem.elements);
            if (it == cache.end()) {
                cache.emplace(elem.elements, ret.size());
                ret.emplace_back(
                  elem.elements,
                  std::numeric_limits<int>::min(),
                  bx::numeric_cast<int>(std::lround(elem.value)),
                  elem.id);
            } else {
                ret[it->second].max =
                  std::min(ret[it->second].max,
                           bx::numeric_cast<int>(std::lround(elem.value)));
            }
        }
        break;
    case bx::operator_type::greater:
        for (const auto& elem : pb.greater_constraints) {
            auto it = cache.find(elem.elements);
            if (it == cache.end()) {
                cache.emplace(elem.elements, ret.size());
                ret.emplace_back(elem.elements,
                                 elem.value,
                                 std::numeric_limits<int>::max(),
                                 elem.id);
            } else {
                ret[it->second].min =
                  std::max(ret[it->second].min,
                           bx::numeric_cast<int>(std::lround(elem.value)));
            }
        }
        break;
    default:
        break;
    }
}

static inline bx::operator_type
operator_from_string(const std::string& op) noexcept
{
    if (op == "equal")
        return bx::operator_type::equal;
    if (op == "less")
        return bx::operator_type::less;
    if (op == "greater")
        return bx::operator_type::greater;

    return bx::operator_type::undefined;
}

//
// Restore original order: reorder merged constraints according to the
// merged_constraint::id (initially initialized in the lp format reading
// process).
//
static std::vector<bx::itm::merged_constraint>
make_unsorted_merged_constraints(std::shared_ptr<bx::context> ctx,
                                 const bx::problem& pb)
{
    ctx->info("  - merge constraints without any sort\n");

    std::unordered_map<std::vector<bx::function_element>,
                       std::size_t,
                       merged_constraint_hash>
      cache;

    std::vector<bx::itm::merged_constraint> ret;
    ret.reserve(pb.equal_constraints.size() + pb.less_constraints.size() +
                pb.greater_constraints.size());

    fill_merged_constraints(ctx, cache, bx::operator_type::equal, pb, ret);
    fill_merged_constraints(ctx, cache, bx::operator_type::less, pb, ret);
    fill_merged_constraints(ctx, cache, bx::operator_type::greater, pb, ret);

    std::sort(ret.begin(), ret.end(), [](const auto& lhs, const auto& rhs) {
        return lhs.id < rhs.id;
    });

    return ret;
}

//
// Reorder constraints according to the type of operator proposed into the
// preprocessing parameter. If parameter is badly defined, we fall back to the
// unsorted_merged_constraints.
//
static std::vector<bx::itm::merged_constraint>
make_ordered_merged_constraints(std::shared_ptr<bx::context> ctx,
                                const bx::problem& pb,
                                const bx::itm::parameters& p)
{
    ctx->info("  - merge constraints with ordered sort\n");

    auto first = p.preprocessing.find(',', 0);
    if (first != std::string::npos) {
        auto second = p.preprocessing.find(',', first + 1);
        if (second != std::string::npos) {
            auto op0 = p.preprocessing.substr(0, first);
            auto op1 = p.preprocessing.substr(first + 1, second - first - 1);
            auto op2 = p.preprocessing.substr(second + 1);

            bx::operator_type op[3] = { bx::operator_type::less,
                                        bx::operator_type::greater,
                                        bx::operator_type::equal };

            op[0] = operator_from_string(op0);
            op[1] = operator_from_string(op1);
            op[2] = operator_from_string(op2);

            if (op[0] != bx::operator_type::undefined and
                op[1] != bx::operator_type::undefined and
                op[2] != bx::operator_type::undefined and op[0] != op[1] and
                op[1] != op[2] and op[0] != op[2]) {

                std::unordered_map<std::vector<bx::function_element>,
                                   std::size_t,
                                   merged_constraint_hash>
                  cache;

                std::vector<bx::itm::merged_constraint> ret;
                ret.reserve(pb.equal_constraints.size() +
                            pb.less_constraints.size() +
                            pb.greater_constraints.size());

                fill_merged_constraints(ctx, cache, op[0], pb, ret);
                fill_merged_constraints(ctx, cache, op[1], pb, ret);
                fill_merged_constraints(ctx, cache, op[2], pb, ret);

                return ret;
            }
        }

        ctx->warning("    Bad preprocessing order mode: `%s`. Falling back "
                     "to the unsorted merged constraint\n",
                     p.preprocessing.c_str());
    }

    return make_unsorted_merged_constraints(ctx, pb);
}

//
// Reorder constraints according to the special operator proposed into the
// preprocessing parameter. If parameter is badly defined, we fall back to the
// unsorted_merged_constraints.
//
static std::vector<bx::itm::merged_constraint>
make_special_merged_constraints(std::shared_ptr<bx::context> ctx,
                                const bx::problem& pb,
                                const bx::itm::parameters& p)
{
    ctx->info("  - merge constraint according to the `%s` algorithm\n",
              p.preprocessing.c_str());

    auto ret = make_unsorted_merged_constraints(ctx, pb);

    std::vector<int> vars(pb.vars.values.size(), 0);
    std::vector<std::set<int>> linkvars(pb.vars.values.size());
    std::vector<std::set<int>> linkcst(pb.vars.values.size());

    for (auto it{ ret.begin() }, et{ ret.end() }; it != et; ++it) {
        for (std::size_t i{ 0 }, e{ it->elements.size() }; i != e; ++i) {

            linkcst[it->elements[i].variable_index].emplace(
              std::distance(it, ret.end()));

            for (std::size_t j{ 0 }; j != e; ++j) {
                if (i != j)
                    linkvars[it->elements[i].variable_index].emplace(
                      it->elements[j].variable_index);
            }
        }

        for (auto& f : it->elements) {
            vars[f.variable_index]++;
        }
    }

    std::vector<std::pair<bx::itm::merged_constraint, int>> tosort;

    if (p.preprocessing == "variables-number") {
        for (auto& cst : ret) {
            tosort.emplace_back(cst, 0);
            for (auto& elem : cst.elements) {
                for (auto& s : linkcst[elem.variable_index])
                    tosort.back().second += linkvars[s].size();
            }
        }

        std::sort(
          tosort.begin(), tosort.end(), [](const auto& lhs, const auto& rhs) {
              return rhs.second < lhs.second;
          });

        ret.clear();
        std::transform(tosort.begin(),
                       tosort.end(),
                       std::back_inserter(ret),
                       [](const auto& elem) { return elem.first; });

        return ret;
    }

    if (p.preprocessing == "variables-weight") {
        std::sort(
          ret.begin(), ret.end(), [vars](const auto& lhs, const auto& rhs) {
              int sumlhs{ 0 };
              int sumrhs{ 0 };

              for (auto& f : lhs.elements)
                  sumlhs += vars[f.variable_index];

              for (auto& f : rhs.elements)
                  sumrhs += vars[f.variable_index];

              return sumlhs < sumrhs;
          });

        return ret;
    }

    if (p.preprocessing == "constraints-weight") {
        std::sort(ret.begin(),
                  ret.end(),
                  [linkvars, linkcst](const auto& lhs, const auto& rhs) {
                      int sumlhs{ 1 };
                      int sumrhs{ 1 };

                      for (auto& f : lhs.elements)
                          sumlhs *= linkcst[f.variable_index].size();

                      for (auto& f : rhs.elements)
                          sumrhs *= linkcst[f.variable_index].size();

                      return sumrhs > sumlhs;
                  });

        return ret;
    }

    if (p.preprocessing == "implied") {
        // Algorithm to build a tosort vector according to constraints of type:
        // -x1 -x2 -x3 +x4 <= 0

        for (auto& cst : ret) {
            tosort.emplace_back(cst, 0);

            int nbneg{ 0 }, nbpos{ 0 };

            for (auto& elem : cst.elements)
                if (elem.factor < 0)
                    nbneg++;
                else
                    nbpos++;

            if (((nbneg > 1 and nbpos == 1) or (nbpos > 1 and nbneg == 1)) and
                cst.min == cst.max) {
                tosort.back().second = 1;
            }
        }

        std::sort(
          tosort.begin(), tosort.end(), [](const auto& lhs, const auto& rhs) {
              return rhs.second < lhs.second;
          });

        ret.clear();
        std::transform(tosort.begin(),
                       tosort.end(),
                       std::back_inserter(ret),
                       [](const auto& elem) { return elem.first; });

        return ret;
    }

    return ret;
}

namespace baryonyx {
namespace itm {

std::vector<merged_constraint>
make_merged_constraints(std::shared_ptr<context> ctx,
                        const problem& pb,
                        const parameters& p)
{
    auto original_nb = static_cast<int>(pb.equal_constraints.size() +
                                        pb.less_constraints.size() +
                                        pb.greater_constraints.size());

    std::vector<merged_constraint> ret;
    ret.reserve(original_nb);

    if (p.preprocessing.empty() or p.preprocessing == "none") {
        ret = make_unsorted_merged_constraints(ctx, pb);
    } else if (p.preprocessing.find(',') != std::string::npos) {
        ret = make_ordered_merged_constraints(ctx, pb, p);
    } else {
        ret = make_special_merged_constraints(ctx, pb, p);
    }

    ctx->info("  - merged constraints removed: %d\n",
              original_nb - static_cast<int>(ret.size()));

    return ret;
}
}
}
<commit_msg>itm: fix compilation issue<commit_after>/* Copyright (C) 2017 INRA
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublipnse, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "itm.hpp"

#include <set>

#include <cassert>

namespace bx = baryonyx;

struct merged_constraint_hash
{
    inline size_t operator()(
      const std::vector<bx::function_element>& fct) const noexcept
    {
        std::size_t seed{ fct.size() };

        for (auto& elem : fct)
            seed ^=
              elem.variable_index + 0x9e3779b9 + (seed << 6) + (seed >> 2);

        return seed;
    }
};

//
// Fills the cache and uses it to search same function and merge equal, less
// and greater equal constraints. To be use in any order, the fill operation
// depends of the operator type passed in parameter.
//
template<typename cacheT, typename retT>
static void
fill_merged_constraints(std::shared_ptr<bx::context> ctx,
                        cacheT& cache,
                        bx::operator_type op,
                        const bx::problem& pb,
                        retT& ret)
{
    switch (op) {
    case bx::operator_type::equal:
        for (const auto& elem : pb.equal_constraints) {
            auto it = cache.find(elem.elements);
            if (it == cache.end()) {
                cache.emplace(elem.elements, ret.size());
                ret.emplace_back(elem.elements,
                                 bx::numeric_cast<int>(elem.value),
                                 bx::numeric_cast<int>(elem.value),

                                 elem.id);
            } else {
                if (ret[it->second].min <= elem.value and
                    elem.value <= ret[it->second].max) {
                    ret[it->second].min = elem.value;
                    ret[it->second].max = elem.value;
                } else {
                    ctx->error(
                      "Constraint %d: is inconsistent with previous %d.\n",
                      elem.id,
                      ret[it->second].id);
                }
            }
        }
        break;
    case bx::operator_type::less:
        for (const auto& elem : pb.less_constraints) {
            auto it = cache.find(elem.elements);
            if (it == cache.end()) {
                cache.emplace(elem.elements, ret.size());
                ret.emplace_back(elem.elements,
                                 std::numeric_limits<int>::min(),
                                 bx::numeric_cast<int>(elem.value),
                                 elem.id);
            } else {
                ret[it->second].max = std::min(
                  ret[it->second].max, bx::numeric_cast<int>(elem.value));
            }
        }
        break;
    case bx::operator_type::greater:
        for (const auto& elem : pb.greater_constraints) {
            auto it = cache.find(elem.elements);
            if (it == cache.end()) {
                cache.emplace(elem.elements, ret.size());
                ret.emplace_back(elem.elements,
                                 elem.value,
                                 std::numeric_limits<int>::max(),
                                 elem.id);
            } else {
                ret[it->second].min = std::max(
                  ret[it->second].min, bx::numeric_cast<int>(elem.value));
            }
        }
        break;
    default:
        break;
    }
}

static inline bx::operator_type
operator_from_string(const std::string& op) noexcept
{
    if (op == "equal")
        return bx::operator_type::equal;
    if (op == "less")
        return bx::operator_type::less;
    if (op == "greater")
        return bx::operator_type::greater;

    return bx::operator_type::undefined;
}

//
// Restore original order: reorder merged constraints according to the
// merged_constraint::id (initially initialized in the lp format reading
// process).
//
static std::vector<bx::itm::merged_constraint>
make_unsorted_merged_constraints(std::shared_ptr<bx::context> ctx,
                                 const bx::problem& pb)
{
    ctx->info("  - merge constraints without any sort\n");

    std::unordered_map<std::vector<bx::function_element>,
                       std::size_t,
                       merged_constraint_hash>
      cache;

    std::vector<bx::itm::merged_constraint> ret;
    ret.reserve(pb.equal_constraints.size() + pb.less_constraints.size() +
                pb.greater_constraints.size());

    fill_merged_constraints(ctx, cache, bx::operator_type::equal, pb, ret);
    fill_merged_constraints(ctx, cache, bx::operator_type::less, pb, ret);
    fill_merged_constraints(ctx, cache, bx::operator_type::greater, pb, ret);

    std::sort(ret.begin(), ret.end(), [](const auto& lhs, const auto& rhs) {
        return lhs.id < rhs.id;
    });

    return ret;
}

//
// Reorder constraints according to the type of operator proposed into the
// preprocessing parameter. If parameter is badly defined, we fall back to the
// unsorted_merged_constraints.
//
static std::vector<bx::itm::merged_constraint>
make_ordered_merged_constraints(std::shared_ptr<bx::context> ctx,
                                const bx::problem& pb,
                                const bx::itm::parameters& p)
{
    ctx->info("  - merge constraints with ordered sort\n");

    auto first = p.preprocessing.find(',', 0);
    if (first != std::string::npos) {
        auto second = p.preprocessing.find(',', first + 1);
        if (second != std::string::npos) {
            auto op0 = p.preprocessing.substr(0, first);
            auto op1 = p.preprocessing.substr(first + 1, second - first - 1);
            auto op2 = p.preprocessing.substr(second + 1);

            bx::operator_type op[3] = { bx::operator_type::less,
                                        bx::operator_type::greater,
                                        bx::operator_type::equal };

            op[0] = operator_from_string(op0);
            op[1] = operator_from_string(op1);
            op[2] = operator_from_string(op2);

            if (op[0] != bx::operator_type::undefined and
                op[1] != bx::operator_type::undefined and
                op[2] != bx::operator_type::undefined and op[0] != op[1] and
                op[1] != op[2] and op[0] != op[2]) {

                std::unordered_map<std::vector<bx::function_element>,
                                   std::size_t,
                                   merged_constraint_hash>
                  cache;

                std::vector<bx::itm::merged_constraint> ret;
                ret.reserve(pb.equal_constraints.size() +
                            pb.less_constraints.size() +
                            pb.greater_constraints.size());

                fill_merged_constraints(ctx, cache, op[0], pb, ret);
                fill_merged_constraints(ctx, cache, op[1], pb, ret);
                fill_merged_constraints(ctx, cache, op[2], pb, ret);

                return ret;
            }
        }

        ctx->warning("    Bad preprocessing order mode: `%s`. Falling back "
                     "to the unsorted merged constraint\n",
                     p.preprocessing.c_str());
    }

    return make_unsorted_merged_constraints(ctx, pb);
}

//
// Reorder constraints according to the special operator proposed into the
// preprocessing parameter. If parameter is badly defined, we fall back to the
// unsorted_merged_constraints.
//
static std::vector<bx::itm::merged_constraint>
make_special_merged_constraints(std::shared_ptr<bx::context> ctx,
                                const bx::problem& pb,
                                const bx::itm::parameters& p)
{
    ctx->info("  - merge constraint according to the `%s` algorithm\n",
              p.preprocessing.c_str());

    auto ret = make_unsorted_merged_constraints(ctx, pb);

    std::vector<int> vars(pb.vars.values.size(), 0);
    std::vector<std::set<int>> linkvars(pb.vars.values.size());
    std::vector<std::set<int>> linkcst(pb.vars.values.size());

    for (auto it{ ret.begin() }, et{ ret.end() }; it != et; ++it) {
        for (std::size_t i{ 0 }, e{ it->elements.size() }; i != e; ++i) {

            linkcst[it->elements[i].variable_index].emplace(
              std::distance(it, ret.end()));

            for (std::size_t j{ 0 }; j != e; ++j) {
                if (i != j)
                    linkvars[it->elements[i].variable_index].emplace(
                      it->elements[j].variable_index);
            }
        }

        for (auto& f : it->elements) {
            vars[f.variable_index]++;
        }
    }

    std::vector<std::pair<bx::itm::merged_constraint, int>> tosort;

    if (p.preprocessing == "variables-number") {
        for (auto& cst : ret) {
            tosort.emplace_back(cst, 0);
            for (auto& elem : cst.elements) {
                for (auto& s : linkcst[elem.variable_index])
                    tosort.back().second += linkvars[s].size();
            }
        }

        std::sort(
          tosort.begin(), tosort.end(), [](const auto& lhs, const auto& rhs) {
              return rhs.second < lhs.second;
          });

        ret.clear();
        std::transform(tosort.begin(),
                       tosort.end(),
                       std::back_inserter(ret),
                       [](const auto& elem) { return elem.first; });

        return ret;
    }

    if (p.preprocessing == "variables-weight") {
        std::sort(
          ret.begin(), ret.end(), [vars](const auto& lhs, const auto& rhs) {
              int sumlhs{ 0 };
              int sumrhs{ 0 };

              for (auto& f : lhs.elements)
                  sumlhs += vars[f.variable_index];

              for (auto& f : rhs.elements)
                  sumrhs += vars[f.variable_index];

              return sumlhs < sumrhs;
          });

        return ret;
    }

    if (p.preprocessing == "constraints-weight") {
        std::sort(ret.begin(),
                  ret.end(),
                  [linkvars, linkcst](const auto& lhs, const auto& rhs) {
                      int sumlhs{ 1 };
                      int sumrhs{ 1 };

                      for (auto& f : lhs.elements)
                          sumlhs *= linkcst[f.variable_index].size();

                      for (auto& f : rhs.elements)
                          sumrhs *= linkcst[f.variable_index].size();

                      return sumrhs > sumlhs;
                  });

        return ret;
    }

    if (p.preprocessing == "implied") {
        // Algorithm to build a tosort vector according to constraints of type:
        // -x1 -x2 -x3 +x4 <= 0

        for (auto& cst : ret) {
            tosort.emplace_back(cst, 0);

            int nbneg{ 0 }, nbpos{ 0 };

            for (auto& elem : cst.elements)
                if (elem.factor < 0)
                    nbneg++;
                else
                    nbpos++;

            if (((nbneg > 1 and nbpos == 1) or (nbpos > 1 and nbneg == 1)) and
                cst.min == cst.max) {
                tosort.back().second = 1;
            }
        }

        std::sort(
          tosort.begin(), tosort.end(), [](const auto& lhs, const auto& rhs) {
              return rhs.second < lhs.second;
          });

        ret.clear();
        std::transform(tosort.begin(),
                       tosort.end(),
                       std::back_inserter(ret),
                       [](const auto& elem) { return elem.first; });

        return ret;
    }

    return ret;
}

namespace baryonyx {
namespace itm {

std::vector<merged_constraint>
make_merged_constraints(std::shared_ptr<context> ctx,
                        const problem& pb,
                        const parameters& p)
{
    auto original_nb = static_cast<int>(pb.equal_constraints.size() +
                                        pb.less_constraints.size() +
                                        pb.greater_constraints.size());

    std::vector<merged_constraint> ret;
    ret.reserve(original_nb);

    if (p.preprocessing.empty() or p.preprocessing == "none") {
        ret = make_unsorted_merged_constraints(ctx, pb);
    } else if (p.preprocessing.find(',') != std::string::npos) {
        ret = make_ordered_merged_constraints(ctx, pb, p);
    } else {
        ret = make_special_merged_constraints(ctx, pb, p);
    }

    ctx->info("  - merged constraints removed: %d\n",
              original_nb - static_cast<int>(ret.size()));

    return ret;
}
}
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include <pthread.h>
#include <memory.h>
#include <iostream>
#include "util/exception.h"

#define LEAN_MIN_STACK_SPACE 128*1024  // 128 Kb

namespace lean {
#ifdef LEAN_WINDOWS
size_t get_stack_size() {
    return LEAN_WIN_STACK_SIZE;
}
#elif defined (__APPLE__)
size_t get_stack_size() {
    pthread_attr_t attr;
    memset (&attr, 0, sizeof(attr));
    pthread_attr_init(&attr);
    size_t result;
    if (pthread_attr_getstacksize(&attr, &result) != 0) {
        // pthread_attr_getstacksize is supposed to return 0
        std::cerr << "get_stack_size error" << std::endl;
        throw stack_space_exception();
    }
    return result;
}
#else
size_t get_stack_size() {
    pthread_attr_t attr;
    memset (&attr, 0, sizeof(attr));
    pthread_getattr_np (pthread_self(), &attr);
    void * ptr;
    size_t result;
    pthread_attr_getstack (&attr, &ptr, &result);
    pthread_attr_destroy(&attr);
    return result;
}
#endif

static thread_local size_t g_stack_size;
static thread_local size_t g_stack_base;

void save_stack_info() {
    g_stack_size = get_stack_size();
    char x;
    g_stack_base = reinterpret_cast<size_t>(&x);
}

size_t get_used_stack_size() {
    char y;
    size_t curr_stack = reinterpret_cast<size_t>(&y);
    return g_stack_base - curr_stack;
}

size_t get_available_stack_size() {
    size_t sz = get_used_stack_size();
    if (sz > g_stack_size)
        return 0;
    else
        return g_stack_size - sz;
}

void check_stack() {
    if (get_used_stack_size() + LEAN_MIN_STACK_SPACE > g_stack_size)
        throw stack_space_exception();
}
}
<commit_msg>fix(util/stackinfo): handle error codes in the Linux version<commit_after>/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include <pthread.h>
#include <memory.h>
#include <iostream>
#include "util/exception.h"

#define LEAN_MIN_STACK_SPACE 128*1024  // 128 Kb

namespace lean {
static void throw_get_stack_size_failed() {
    throw exception("failed to retrieve thread stack size");
}

#ifdef LEAN_WINDOWS
size_t get_stack_size() {
    return LEAN_WIN_STACK_SIZE;
}
#elif defined (__APPLE__)
size_t get_stack_size() {
    pthread_attr_t attr;
    memset (&attr, 0, sizeof(attr));
    pthread_attr_init(&attr);
    size_t result;
    if (pthread_attr_getstacksize(&attr, &result) != 0) {
        throw_get_stack_size_failed();
    }
    return result;
}
#else
size_t get_stack_size() {
    pthread_attr_t attr;
    memset (&attr, 0, sizeof(attr));
    if (pthread_getattr_np(pthread_self(), &attr) != 0) {
        throw_get_stack_size_failed();
    }
    void * ptr;
    size_t result;
    if (pthread_attr_getstack (&attr, &ptr, &result) != 0) {
        throw_get_stack_size_failed();
    }
    if (pthread_attr_destroy(&attr) != 0) {
        throw_get_stack_size_failed();
    }
    return result;
}
#endif

static thread_local size_t g_stack_size;
static thread_local size_t g_stack_base;

void save_stack_info() {
    g_stack_size = get_stack_size();
    char x;
    g_stack_base = reinterpret_cast<size_t>(&x);
}

size_t get_used_stack_size() {
    char y;
    size_t curr_stack = reinterpret_cast<size_t>(&y);
    return g_stack_base - curr_stack;
}

size_t get_available_stack_size() {
    size_t sz = get_used_stack_size();
    if (sz > g_stack_size)
        return 0;
    else
        return g_stack_size - sz;
}

void check_stack() {
    if (get_used_stack_size() + LEAN_MIN_STACK_SPACE > g_stack_size)
        throw stack_space_exception();
}
}
<|endoftext|>


<commit_before>/*
 * Arbusto: A Python Compiler.
 * Alejandro Santos, @alejolp.
 * Licence: MIT
 */

#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <fstream>
#include <limits>
#include <memory>

class grammar_node;
class grammar;

/*

EBNF for Grammar/Grammar
========================

term = ( NT | T ) [ '+' | '*' ]
option = '[' rhs ']'
repetition = '(' rhs ')' [ '+' | '*' ]
sequence = ( term | option | repetition ) +
rhs = sequence ( '|' sequence ) *
rule = NT ':' rhs

 */

/* IMPORTANT: The EBNF does not exactly matches the generated tree */
enum grammar_node_type {
	GNODE_STRING, /* for leafs */
	GNODE_OPTIONAL, /* for [ optional ] */
	GNODE_REPETITION, /* for X* | X+ */
	GNODE_SEQUENCE, /* for a sequence A B C */
	GNODE_RHS, /* for alternatives A|B|C */
	GNODE_RULE /* the main rule: NAME ':' RHS */
};

typedef std::unique_ptr<grammar_node> grammar_node_ptr;

class grammar_node {
public:
	explicit grammar_node(grammar_node_type t) : type(t) {}

	grammar_node_type type;
};

class grammar_node_string : public grammar_node {
public:
	grammar_node_string(const std::string &v) : grammar_node(GNODE_STRING), value(v) {}

	std::string value;
};

class grammar_node_optional : public grammar_node {
public:
	grammar_node_optional(grammar_node_ptr &&c) : grammar_node(GNODE_OPTIONAL), child(std::move(c)) {}

	grammar_node_ptr child;
};

class grammar_node_repetition : public grammar_node {
public:
	grammar_node_repetition(grammar_node_ptr &&c, bool s) : grammar_node(GNODE_REPETITION), child(std::move(c)), star(s) {}

	grammar_node_ptr child;
	bool star;
};

class grammar_node_sequence : public grammar_node {
public:
	grammar_node_sequence() : grammar_node(GNODE_SEQUENCE) {}

	std::vector<grammar_node_ptr> childs;
};

class grammar_node_rhs : public grammar_node {
public:
	grammar_node_rhs() : grammar_node(GNODE_RHS) {}

	std::vector<grammar_node_ptr> choices;
};

class grammar_node_rule : public grammar_node {
public:
	grammar_node_rule(const std::string& s, grammar_node_ptr r) : grammar_node(GNODE_RULE), rule_name(s), rhs(std::move(r)) {}

	std::string rule_name;
	grammar_node_ptr rhs;
};

class tokens_iter {
public:
	tokens_iter(size_t begin, size_t end, std::vector<std::string> &tokens)
		: begin_(begin), end_(end), tokens_(tokens)
	{}

	bool eof() {
		return begin_ >= end_;
	}

	const std::string& peek() {
		static std::string empty;
		return eof() ? empty : tokens_.at(begin_);
	}

	const std::string& get() {
		const std::string& ret = peek();
		begin_++;
		return ret;
	}

	size_t pos() {
		return begin_;
	}

	void reset(size_t p) {
		begin_ = p;
	}

private:
	size_t begin_;
	size_t end_;
	std::vector<std::string> &tokens_;
};

class grammar {
public:
	void parse_grammar_file(const std::string& file_name);

	std::vector<std::string> tokens;
	std::map<std::string, grammar_node_ptr> rules;

private:
	void tokenize_grammar_file(const std::string& file_name);

	void parse_production(size_t p, size_t i);

	grammar_node_ptr parse_term(tokens_iter& it);
	grammar_node_ptr parse_option(tokens_iter& it);
	grammar_node_ptr parse_repetition(tokens_iter& it);
	grammar_node_ptr parse_sequence(tokens_iter& it);
	grammar_node_ptr parse_rhs(tokens_iter& it);
	grammar_node_ptr parse_rule(tokens_iter& it);

	inline bool valid_name_char(int c) {
		return std::isalnum(c) || c == '_';
	}

	inline bool is_token_NT(const std::string& s) {
		return s.size() && valid_name_char(s[0]);
	}

	inline bool is_token_T(const std::string& s) {
		return s.size() && s[0] == '\'';
	}
};

/* Tokenizer for the Grammar/Grammar Python file */
void grammar::tokenize_grammar_file(const std::string& file_name) {
	std::ifstream ifile;

	ifile.open(file_name);

	while (ifile) {
		auto c = (char) ifile.get();

		switch (c) {
		/* Eat the WS */
		case ' ':
		case '\t':
			break;

		/* NEWLINE */
		case '\r':
		case '\n':
			break;

		/* Literal string 'hey' */
		case '\'':
			{
				std::string S{c};
				while (ifile) {
					c = ifile.get();
					S += c;
					if (c == '\'') break;
				}
				tokens.emplace_back(S);
			}
			break;

		/* Single character tokens */
		case ':':
		case '|':
		case '(':
		case ')':
		case '[':
		case ']':
		case '+':
		case '*':
			{
				std::string S{c};
				tokens.emplace_back(S);
			}
			break;

		/* Eat the comment until EOL */
		case '#':
			while (ifile) {
				c = ifile.get();
				if (c == '\n') {
					ifile.unget();
					break;
				}
			}
			break;

		/* NAME */
		default:
			if (valid_name_char(c))
			{
				std::string S{c};
				while (ifile) {
					c = ifile.get();
					if (!valid_name_char(c)) {
						ifile.unget();
						break;
					}
					S += c;
				}
				tokens.emplace_back(S);
			}
		}
	}
}

/*
 * Parser for the Grammar/Grammar Python file
 * Implement a Recursive Descent Parser for the Grammar
 *
 * */
void grammar::parse_grammar_file(const std::string& file_name) {
	tokenize_grammar_file(file_name);
	size_t i, p = std::numeric_limits<size_t>::max();

	for (i = 0; i < tokens.size(); ++i) {
		if (tokens[i] == ":") {
			if (p != std::numeric_limits<size_t>::max()) {
				parse_production(p, i - 1);
			}
			p = i - 1;
		}
	}

	if (p != std::numeric_limits<size_t>::max()) {
		parse_production(p, i);
	}
}

grammar_node_ptr grammar::parse_term(tokens_iter& it) {
	/* term = ( NT | T ) [ '+' | '*' ] */

	auto p = it.pos();

	if (it.eof()) {
		it.reset(p);
		return grammar_node_ptr();
	}

	auto next = it.peek();

	if (is_token_NT(next) || is_token_T(next)) {
		it.get();
		grammar_node_ptr node = grammar_node_ptr(new grammar_node_string(next));

		auto next2 = it.peek();
		if (next2 == "*" || next2 == "+") {
			it.get();
			return grammar_node_ptr(new grammar_node_repetition(std::move(node), (next2 == "*")));
		}

		return node;
	}

	it.reset(p);
	return grammar_node_ptr();
}

grammar_node_ptr grammar::parse_option(tokens_iter& it) {
	/* option = '[' rhs ']' */
	auto p = it.pos();

	if (it.peek() != "[") {
		it.reset(p);
		return grammar_node_ptr();
	}

	std::string lbrace = it.get();

	auto rhs = parse_rhs(it);

	if (it.peek() != "]") {
		it.reset(p);
		return grammar_node_ptr();
	}

	std::string rbrace = it.get();

	return grammar_node_ptr(new grammar_node_optional(std::move(rhs)));
}

grammar_node_ptr grammar::parse_repetition(tokens_iter& it) {
	/* repetition = '(' rhs ')' [ '+' | '*' ] */
	auto p = it.pos();

	if (it.peek() != "(") {
		it.reset(p);
		return grammar_node_ptr();
	}

	std::string lpar = it.get();

	auto rhs = parse_rhs(it);

	if (it.peek() != ")") {
		it.reset(p);
		return grammar_node_ptr();
	}

	std::string rpar = it.get();
	std::string next = it.peek();

	if (next == "+" || next == "*") {
		it.get();
		return grammar_node_ptr(new grammar_node_repetition(std::move(rhs), (next == "*")));
	}

	return rhs;
}

grammar_node_ptr grammar::parse_sequence(tokens_iter& it) {
	/* sequence = ( term | option | repetition ) + */

	std::vector<grammar_node_ptr> childs;

	for (;;) {
		grammar_node_ptr next;

		next = parse_term(it);
		if (next) {
			childs.push_back(std::move(next));
			continue;
		}

		next = parse_option(it);
		if (next) {
			childs.push_back(std::move(next));
			continue;
		}

		next = parse_repetition(it);
		if (next) {
			childs.push_back(std::move(next));
			continue;
		}

		break;
	}

	if (childs.size()) {
		auto node = new grammar_node_sequence();
		node->childs = std::move(childs);
		return grammar_node_ptr(node);
	}

	return grammar_node_ptr();
}

grammar_node_ptr grammar::parse_rhs(tokens_iter& it) {
	/* rhs = sequence ( '|' sequence ) */

	auto p = it.pos();

	auto node = new grammar_node_rhs();
	grammar_node_ptr next;

	next = parse_sequence(it);
	if (!next) {
		it.reset(p);
		return grammar_node_ptr();
	}

	node->choices.push_back(std::move(next));

	for (;;) {
		if (it.peek() != "|") {
			break;
		}

		it.get();

		next = parse_sequence(it);
		if (!next) {
			/* FIXME: If this happens: broken text! RULE: A || B */
			it.reset(p);
			break;
		}

		node->choices.push_back(std::move(next));
		p = it.pos();
	}

	return grammar_node_ptr(node);
}

grammar_node_ptr grammar::parse_rule(tokens_iter& it) {
	/* rule = NT ':' rhs */

	auto p = it.pos();

	auto left = it.peek();

	if (!is_token_NT(left)) {
		it.reset(p);
		return grammar_node_ptr();
	}

	it.get();

	if (it.peek() != ":") {
		it.reset(p);
		return grammar_node_ptr();
	}

	it.get();

	auto rhs = parse_rhs(it);

	if (rhs) {
		return grammar_node_ptr(new grammar_node_rule(left, std::move(rhs)));
	}

	it.reset(p);
	return grammar_node_ptr();
}

void grammar::parse_production(size_t p, size_t i) {
#if 0
	std::cout << p << "; " << i << std::endl;
	while (p < i) {
		std::cout << tokens[p] << ", ";
		++p;
	}
	std::cout << std::endl;
#endif
	tokens_iter it(p, i, tokens);

	grammar_node_ptr node = parse_rule(it);

	if (node) {
		grammar_node_rule* rule = static_cast<grammar_node_rule*>(node.get());
		rules[rule->rule_name] = std::move(node);
	} else {
		std::cout << "ERROR for " << p << " " << i << std::endl;
	}
}

int main(int argc, char **argv) {
	grammar G;
	G.parse_grammar_file((argc > 1) ? argv[1] : "Grammar");
	std::cout << "TOKENS COUNT=" << G.tokens.size() << std::endl;
	std::cout << "RULES COUNT=" << G.rules.size() << std::endl;
	return 0;
}
<commit_msg>some debug<commit_after>/*
 * Arbusto: A Python Compiler.
 * Alejandro Santos, @alejolp.
 * Licence: MIT
 */

#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <fstream>
#include <limits>
#include <memory>

class grammar_node;
class grammar;

/*

EBNF for Grammar/Grammar
========================

term = ( NT | T ) [ '+' | '*' ]
option = '[' rhs ']'
repetition = '(' rhs ')' [ '+' | '*' ]
sequence = ( term | option | repetition ) +
rhs = sequence ( '|' sequence ) *
rule = NT ':' rhs

 */

/* IMPORTANT: The EBNF does not exactly matches the generated tree */
enum grammar_node_type {
	GNODE_STRING, /* for leafs */
	GNODE_OPTIONAL, /* for [ optional ] */
	GNODE_REPETITION, /* for X* | X+ */
	GNODE_SEQUENCE, /* for a sequence A B C */
	GNODE_RHS, /* for alternatives A|B|C */
	GNODE_RULE /* the main rule: NAME ':' RHS */
};

typedef std::unique_ptr<grammar_node> grammar_node_ptr;

class grammar_node {
public:
	explicit grammar_node(grammar_node_type t) : type(t) {}
	virtual ~grammar_node() {}

	virtual void print() = 0;

	grammar_node_type type;
};

class grammar_node_string : public grammar_node {
public:
	grammar_node_string(const std::string &v) : grammar_node(GNODE_STRING), value(v) {}

	virtual void print() {
		std::cout << "string(" << value << ")";
	}

	std::string value;
};

class grammar_node_optional : public grammar_node {
public:
	grammar_node_optional(grammar_node_ptr &&c) : grammar_node(GNODE_OPTIONAL), child(std::move(c)) {}

	virtual void print() {
		std::cout << "optional(";
		if (child) child->print();
		std::cout << ")";
	}

	grammar_node_ptr child;
};

class grammar_node_repetition : public grammar_node {
public:
	grammar_node_repetition(grammar_node_ptr &&c, bool s) : grammar_node(GNODE_REPETITION), child(std::move(c)), star(s) {}

	virtual void print() {
		std::cout << "repetition(" << (star ? "'*'" : "'+'") << ", ";
		if (child) child->print();
		std::cout << ")";
	}

	grammar_node_ptr child;
	bool star;
};

class grammar_node_sequence : public grammar_node {
public:
	grammar_node_sequence() : grammar_node(GNODE_SEQUENCE) {}

	virtual void print() {
		std::cout << "sequence(";
		for (auto& e : childs) {
			if (e) e->print();
			std::cout << ", ";
		}
		std::cout << ")";
	}

	std::vector<grammar_node_ptr> childs;
};

class grammar_node_rhs : public grammar_node {
public:
	grammar_node_rhs() : grammar_node(GNODE_RHS) {}

	virtual void print() {
		std::cout << "rhs(";
		for (auto& e : choices) {
			if (e) e->print();
			std::cout << ", ";
		}
		std::cout << ")";
	}

	std::vector<grammar_node_ptr> choices;
};

class grammar_node_rule : public grammar_node {
public:
	grammar_node_rule(const std::string& s, grammar_node_ptr r) : grammar_node(GNODE_RULE), rule_name(s), rhs(std::move(r)) {}

	virtual void print() {
		std::cout << "rule(" << rule_name << ", ";
		if (rhs) rhs->print();
		std::cout << ")";
	}

	std::string rule_name;
	grammar_node_ptr rhs;
};

class tokens_iter {
public:
	tokens_iter(size_t begin, size_t end, std::vector<std::string> &tokens)
		: begin_(begin), end_(end), tokens_(tokens)
	{}

	bool eof() {
		return begin_ >= end_;
	}

	const std::string& peek() {
		static std::string empty;
		return eof() ? empty : tokens_.at(begin_);
	}

	const std::string& get() {
		const std::string& ret = peek();
		begin_++;
		return ret;
	}

	size_t pos() {
		return begin_;
	}

	void reset(size_t p) {
		begin_ = p;
	}

private:
	size_t begin_;
	size_t end_;
	std::vector<std::string> &tokens_;
};

class grammar {
public:
	void parse_grammar_file(const std::string& file_name);

	std::vector<std::string> tokens;
	std::map<std::string, grammar_node_ptr> rules;

private:
	void tokenize_grammar_file(const std::string& file_name);

	void parse_production(size_t p, size_t i);

	grammar_node_ptr parse_term(tokens_iter& it);
	grammar_node_ptr parse_option(tokens_iter& it);
	grammar_node_ptr parse_repetition(tokens_iter& it);
	grammar_node_ptr parse_sequence(tokens_iter& it);
	grammar_node_ptr parse_rhs(tokens_iter& it);
	grammar_node_ptr parse_rule(tokens_iter& it);

	inline bool valid_name_char(int c) {
		return std::isalnum(c) || c == '_';
	}

	inline bool is_token_NT(const std::string& s) {
		return s.size() && valid_name_char(s[0]);
	}

	inline bool is_token_T(const std::string& s) {
		return s.size() && s[0] == '\'';
	}
};

/* Tokenizer for the Grammar/Grammar Python file */
void grammar::tokenize_grammar_file(const std::string& file_name) {
	std::ifstream ifile;

	ifile.open(file_name);

	while (ifile) {
		auto c = (char) ifile.get();

		switch (c) {
		/* Eat the WS */
		case ' ':
		case '\t':
			break;

		/* NEWLINE */
		case '\r':
		case '\n':
			break;

		/* Literal string 'hey' */
		case '\'':
			{
				std::string S{c};
				while (ifile) {
					c = ifile.get();
					S += c;
					if (c == '\'') break;
				}
				tokens.emplace_back(S);
			}
			break;

		/* Single character tokens */
		case ':':
		case '|':
		case '(':
		case ')':
		case '[':
		case ']':
		case '+':
		case '*':
			{
				std::string S{c};
				tokens.emplace_back(S);
			}
			break;

		/* Eat the comment until EOL */
		case '#':
			while (ifile) {
				c = ifile.get();
				if (c == '\n') {
					ifile.unget();
					break;
				}
			}
			break;

		/* NAME */
		default:
			if (valid_name_char(c))
			{
				std::string S{c};
				while (ifile) {
					c = ifile.get();
					if (!valid_name_char(c)) {
						ifile.unget();
						break;
					}
					S += c;
				}
				tokens.emplace_back(S);
			}
		}
	}
}

/*
 * Parser for the Grammar/Grammar Python file
 * Implement a Recursive Descent Parser for the Grammar
 *
 * */
void grammar::parse_grammar_file(const std::string& file_name) {
	tokenize_grammar_file(file_name);
	size_t i, p = std::numeric_limits<size_t>::max();

	for (i = 0; i < tokens.size(); ++i) {
		if (tokens[i] == ":") {
			if (p != std::numeric_limits<size_t>::max()) {
				parse_production(p, i - 1);
			}
			p = i - 1;
		}
	}

	if (p != std::numeric_limits<size_t>::max()) {
		parse_production(p, i);
	}
}

grammar_node_ptr grammar::parse_term(tokens_iter& it) {
	/* term = ( NT | T ) [ '+' | '*' ] */

	auto p = it.pos();

	if (it.eof()) {
		it.reset(p);
		return grammar_node_ptr();
	}

	auto next = it.peek();

	if (is_token_NT(next) || is_token_T(next)) {
		it.get();
		grammar_node_ptr node = grammar_node_ptr(new grammar_node_string(next));

		auto next2 = it.peek();
		if (next2 == "*" || next2 == "+") {
			it.get();
			return grammar_node_ptr(new grammar_node_repetition(std::move(node), (next2 == "*")));
		}

		return node;
	}

	it.reset(p);
	return grammar_node_ptr();
}

grammar_node_ptr grammar::parse_option(tokens_iter& it) {
	/* option = '[' rhs ']' */
	auto p = it.pos();

	if (it.peek() != "[") {
		it.reset(p);
		return grammar_node_ptr();
	}

	std::string lbrace = it.get();

	auto rhs = parse_rhs(it);

	if (it.peek() != "]") {
		it.reset(p);
		return grammar_node_ptr();
	}

	std::string rbrace = it.get();

	return grammar_node_ptr(new grammar_node_optional(std::move(rhs)));
}

grammar_node_ptr grammar::parse_repetition(tokens_iter& it) {
	/* repetition = '(' rhs ')' [ '+' | '*' ] */
	auto p = it.pos();

	if (it.peek() != "(") {
		it.reset(p);
		return grammar_node_ptr();
	}

	std::string lpar = it.get();

	auto rhs = parse_rhs(it);

	if (it.peek() != ")") {
		it.reset(p);
		return grammar_node_ptr();
	}

	std::string rpar = it.get();
	std::string next = it.peek();

	if (next == "+" || next == "*") {
		it.get();
		return grammar_node_ptr(new grammar_node_repetition(std::move(rhs), (next == "*")));
	}

	return rhs;
}

grammar_node_ptr grammar::parse_sequence(tokens_iter& it) {
	/* sequence = ( term | option | repetition ) + */

	std::vector<grammar_node_ptr> childs;

	for (;;) {
		grammar_node_ptr next;

		next = parse_term(it);
		if (next) {
			childs.push_back(std::move(next));
			continue;
		}

		next = parse_option(it);
		if (next) {
			childs.push_back(std::move(next));
			continue;
		}

		next = parse_repetition(it);
		if (next) {
			childs.push_back(std::move(next));
			continue;
		}

		break;
	}

	if (childs.size()) {
		auto node = new grammar_node_sequence();
		node->childs = std::move(childs);
		return grammar_node_ptr(node);
	}

	return grammar_node_ptr();
}

grammar_node_ptr grammar::parse_rhs(tokens_iter& it) {
	/* rhs = sequence ( '|' sequence ) */

	auto p = it.pos();

	auto node = new grammar_node_rhs();
	grammar_node_ptr next;

	next = parse_sequence(it);
	if (!next) {
		it.reset(p);
		return grammar_node_ptr();
	}

	node->choices.push_back(std::move(next));

	for (;;) {
		if (it.peek() != "|") {
			break;
		}

		it.get();

		next = parse_sequence(it);
		if (!next) {
			/* FIXME: If this happens: broken text! RULE: A || B */
			it.reset(p);
			break;
		}

		node->choices.push_back(std::move(next));
		p = it.pos();
	}

	return grammar_node_ptr(node);
}

grammar_node_ptr grammar::parse_rule(tokens_iter& it) {
	/* rule = NT ':' rhs */

	auto p = it.pos();

	auto left = it.peek();

	if (!is_token_NT(left)) {
		it.reset(p);
		return grammar_node_ptr();
	}

	it.get();

	if (it.peek() != ":") {
		it.reset(p);
		return grammar_node_ptr();
	}

	it.get();

	auto rhs = parse_rhs(it);

	if (rhs) {
		return grammar_node_ptr(new grammar_node_rule(left, std::move(rhs)));
	}

	it.reset(p);
	return grammar_node_ptr();
}

void grammar::parse_production(size_t p, size_t i) {
#if 0
	std::cout << p << "; " << i << std::endl;
	while (p < i) {
		std::cout << tokens[p] << ", ";
		++p;
	}
	std::cout << std::endl;
#endif
	tokens_iter it(p, i, tokens);

	grammar_node_ptr node = parse_rule(it);

	if (node) {
		node->print();
		std::cout << std::endl;
		grammar_node_rule* rule = static_cast<grammar_node_rule*>(node.get());
		rules[rule->rule_name] = std::move(node);
	} else {
		std::cout << "ERROR for " << p << " " << i << std::endl;
	}
}

int main(int argc, char **argv) {
	grammar G;
	G.parse_grammar_file((argc > 1) ? argv[1] : "Grammar");
	std::cout << "TOKENS COUNT=" << G.tokens.size() << std::endl;
	std::cout << "RULES COUNT=" << G.rules.size() << std::endl;
	return 0;
}
<|endoftext|>


<commit_before><commit_msg>Added print statement on the new Psi0 jumps<commit_after><|endoftext|>


<commit_before><commit_msg>Delete hello_wrold.cpp<commit_after><|endoftext|>


<commit_before>#include <bitcoin/utility/logger.hpp>

#include <iostream>

namespace libbitcoin {

std::string level_repr(log_level level)
{
    switch (level)
    {
        case log_level::null:
            return "NULL";
        case log_level::debug:
            return "DEBUG";
        case log_level::info:
            return "INFO";
        case log_level::warning:
            return "WARNING";
        case log_level::error:
            return "ERROR";
        case log_level::fatal:
            return "FATAL";
    }
    return "";
}

void output_ostream(std::ostream& ostr, log_level level,
    const std::string& domain, const std::string& body)
{
    std::cerr << level_repr(level);
    if (!domain.empty())
        std::cerr << " [" << domain << "]";
    std::cerr << ": " << body << std::endl;
}

void ignore_output(log_level level,
    const std::string& domain, const std::string& body)
{
}
void output_cout(log_level level,
    const std::string& domain, const std::string& body)
{
    output_ostream(std::cout, level, domain, body);
}
void output_cerr(log_level level,
    const std::string& domain, const std::string& body)
{
    output_ostream(std::cout, level, domain, body);
}

logger_wrapper::destination_map logger_wrapper::dests_{
#ifdef DEBUG
    std::make_pair(log_level::debug, ignore_output),
#else
    std::make_pair(log_level::debug, output_cout),
#endif
    std::make_pair(log_level::info, output_cout),
    std::make_pair(log_level::warning, output_cerr),
    std::make_pair(log_level::error, output_cerr),
    std::make_pair(log_level::fatal, output_cerr)
};

logger_wrapper::logger_wrapper(log_level lev, const std::string& domain)
  : level_(lev), domain_(domain)
{
}
// g++ bug in initializer list.
// It should be: stream_(std::move(other.stream_))
// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54316
logger_wrapper::logger_wrapper(logger_wrapper&& other)
  : level_(other.level_), stream_(other.stream_.str()),
    domain_(std::move(other.domain_))
{
}
logger_wrapper::~logger_wrapper()
{
    if (!dests_.count(level_))
        return;
    auto& outfunc = dests_[level_];
    outfunc(level_, domain_, stream_.str());
}

void logger_wrapper::set_output_function(logger_output_func outfunc)
{
    dests_[level_] = outfunc;
}

logger_wrapper log_debug(const std::string& domain)
{
    return logger_wrapper(log_level::debug, domain);
}

logger_wrapper log_info(const std::string& domain)
{
    return logger_wrapper(log_level::info, domain);
}

logger_wrapper log_warning(const std::string& domain)
{
    return logger_wrapper(log_level::warning, domain);
}

logger_wrapper log_error(const std::string& domain)
{
    return logger_wrapper(log_level::error, domain);
}

logger_wrapper log_fatal(const std::string& domain)
{
    return logger_wrapper(log_level::fatal, domain);
}

} // namespace libbitcoin

<commit_msg>fix mistake where log_debug() is by default outputing to stderr<commit_after>#include <bitcoin/utility/logger.hpp>

#include <iostream>

namespace libbitcoin {

std::string level_repr(log_level level)
{
    switch (level)
    {
        case log_level::null:
            return "NULL";
        case log_level::debug:
            return "DEBUG";
        case log_level::info:
            return "INFO";
        case log_level::warning:
            return "WARNING";
        case log_level::error:
            return "ERROR";
        case log_level::fatal:
            return "FATAL";
    }
    return "";
}

void output_ostream(std::ostream& ostr, log_level level,
    const std::string& domain, const std::string& body)
{
    ostr << level_repr(level);
    if (!domain.empty())
        ostr << " [" << domain << "]";
    ostr << ": " << body << std::endl;
}

void ignore_output(log_level level,
    const std::string& domain, const std::string& body)
{
}
void output_cout(log_level level,
    const std::string& domain, const std::string& body)
{
    output_ostream(std::cout, level, domain, body);
}
void output_cerr(log_level level,
    const std::string& domain, const std::string& body)
{
    output_ostream(std::cerr, level, domain, body);
}

logger_wrapper::destination_map logger_wrapper::dests_{
#ifdef ENABLE_DEBUG
    std::make_pair(log_level::debug, output_cout),
#else
    std::make_pair(log_level::debug, ignore_output),
#endif
    std::make_pair(log_level::info, output_cout),
    std::make_pair(log_level::warning, output_cerr),
    std::make_pair(log_level::error, output_cerr),
    std::make_pair(log_level::fatal, output_cerr)
};

logger_wrapper::logger_wrapper(log_level lev, const std::string& domain)
  : level_(lev), domain_(domain)
{
}
// g++ bug in initializer list.
// It should be: stream_(std::move(other.stream_))
// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54316
logger_wrapper::logger_wrapper(logger_wrapper&& other)
  : level_(other.level_), stream_(other.stream_.str()),
    domain_(std::move(other.domain_))
{
}
logger_wrapper::~logger_wrapper()
{
    if (!dests_.count(level_))
        return;
    auto& outfunc = dests_[level_];
    outfunc(level_, domain_, stream_.str());
}

void logger_wrapper::set_output_function(logger_output_func outfunc)
{
    dests_[level_] = outfunc;
}

logger_wrapper log_debug(const std::string& domain)
{
    return logger_wrapper(log_level::debug, domain);
}

logger_wrapper log_info(const std::string& domain)
{
    return logger_wrapper(log_level::info, domain);
}

logger_wrapper log_warning(const std::string& domain)
{
    return logger_wrapper(log_level::warning, domain);
}

logger_wrapper log_error(const std::string& domain)
{
    return logger_wrapper(log_level::error, domain);
}

logger_wrapper log_fatal(const std::string& domain)
{
    return logger_wrapper(log_level::fatal, domain);
}

} // namespace libbitcoin

<|endoftext|>


<commit_before>#include <algorithm>
#include <chrono>
#include <cmath>
#include <iomanip>
#include <numeric>
#include <sstream>
#include <thread>
#include "Model/MDLAModel.h"
#include "Color/CIE1931.h"
#include "Color/SRGB.h"
#include "Task/TaskScheduler.h"
#include "Task/TraceTask.h"
#include "ImageUpdater.h"
#include "Ray.h"
#include "Tracer.h"

namespace SPTracer {

	Tracer::Tracer(std::string fileName, unsigned int numThreads, unsigned int width, unsigned int height)
		: width_(width), height_(height), numThreads_(numThreads)
	{
		pixelsCount_ = static_cast<unsigned long>(width_) * height_;

		// create model from file
		model_ = std::make_unique<MDLAModel>(std::move(fileName));

		// create task scheduler that will spawn threads
		taskScheduler_ = std::make_unique<TaskScheduler>(*this, numThreads);

		// prepare array of pixels
		pixels_.resize(pixelsCount_);

		// spectrum
		spectrum_.min = 400.0f;
		spectrum_.max = 700.0f;
		spectrum_.step = 4.0f;

		// precompute count of wave lengths
		spectrum_.count = static_cast<unsigned int>((spectrum_.max - spectrum_.min) / spectrum_.step) + 1;

		// precompute wave length
		spectrum_.values = std::vector<float>(spectrum_.count);
		for (size_t i = 0; i < spectrum_.count; i++)
		{
			spectrum_.values[i] = spectrum_.min + spectrum_.step * static_cast<float>(i);
		}

		// xyz color converter
		xyzConverter_ = std::make_unique<CIE1931>();

		// rgb color system
		rgbConverter_ = std::make_unique<SRGB>();

	}

	Tracer::~Tracer()
	{
	}

	const Model& Tracer::GetModel() const
	{
		return *model_;
	}

	const XYZConverter& Tracer::GetXYZConverter() const
	{
		return *xyzConverter_;
	}

	TaskScheduler& Tracer::GetTaskScheduler() const
	{
		return *taskScheduler_;
	}

	const Spectrum& Tracer::GetSpectrum() const
	{
		return spectrum_;
	}

	unsigned int Tracer::GetWidth() const
	{
		return width_;
	}

	unsigned int Tracer::GetHeight() const
	{
		return height_;
	}

	unsigned long Tracer::GetPixelsCount() const
	{
		return pixelsCount_;
	}

	void Tracer::Run()
	{
		// record start time
		start_ = std::chrono::high_resolution_clock::now();

		// add tasks to start sampling
		for (size_t i = 0; i < numThreads_; i++)
		{
			taskScheduler_->AddTask(std::make_unique<TraceTask>(*this));
		}
	}

	void Tracer::AddSamples(std::vector<Vec3>& color)
	{
		// lock
		std::lock_guard<std::mutex> lock(mutex_);

		// for every pixel
		for (size_t i = 0; i < pixels_.size(); i++)
		{
			PixelData& pd = pixels_[i];
			pd += color[i];
			pd.samples++;
		}

		// increase count of completed samples
		completedPasses_++;

		// update image approximately every 10 seconds
		static const auto updateInterval = std::chrono::seconds(10);
		static auto nextUpdate = std::chrono::steady_clock::now() + updateInterval;
		auto now = std::chrono::steady_clock::now();
		if (now >= nextUpdate)
		{
			UpdateImage();
			nextUpdate = now + updateInterval;
		}
	}

	void Tracer::SetImageUpdater(std::shared_ptr<ImageUpdater> imageUpdater)
	{
		imageUpdater_ = std::move(imageUpdater);
	}

	float Tracer::FindExposure(const std::vector<Vec3>& xyzColor) const
	{
		float n = static_cast<float>(pixelsCount_);

		// Calculate the average intensity. Calculations are based
		// on the CIE Y component, which corresponds to lightness.
		float mean = std::accumulate(xyzColor.begin(), xyzColor.end(), 0.0f,
			[](float a, const Vec3& xyz) { return a + xyz.y; }) / n;

		// Then compute the standard deviation.
		float sqrMean = std::accumulate(xyzColor.begin(), xyzColor.end(), 0.0f,
			[](float a, const Vec3& xyz) { return a + xyz.y * xyz.y; }) / n;

		float variance = sqrMean - mean * mean;

		// The desired 'white' is one standard deviation above average
		return mean + std::sqrt(variance);
	}

	float Tracer::Clamp(float c) const
	{
		return std::min(1.0f, std::max(0.0f, c));
	}

	std::vector<Vec3> Tracer::Tonemap(const std::vector<Vec3>& xyzColor) const
	{
		float maxIntensity = FindExposure(xyzColor);
		std::vector<Vec3> rgbColor(xyzColor.size());

		for (size_t i = 0; i < xyzColor.size(); i++)
		{
			Vec3 xyz = xyzColor[i];
			Vec3& rgb = rgbColor[i];

			// Apply exposure correction
			xyz.x = std::log(xyz.x / maxIntensity + 1.0f) / std::log(4.0f);
			xyz.y = std::log(xyz.y / maxIntensity + 1.0f) / std::log(4.0f);
			xyz.z = std::log(xyz.z / maxIntensity + 1.0f) / std::log(4.0f);

			// Convert to sRGB.
			rgb = rgbConverter_->GetRGB(xyz);

			// Clamp colours to saturate.
			rgb.x = Clamp(rgb.x);
			rgb.y = Clamp(rgb.y);
			rgb.z = Clamp(rgb.z);
		}

		return rgbColor;
	}

	void Tracer::UpdateImage()
	{
		if (imageUpdater_ == nullptr)
		{
			return;
		}

		// divide XYZ color in pixels on the number of samples
		std::vector<Vec3> xyzColor;
		xyzColor.reserve(pixels_.size());
		for (size_t i = 0; i < pixels_.size(); i++)
		{
			PixelData& pd = pixels_[i];
			xyzColor.push_back(Vec3{
				static_cast<float>(pd.x / pd.samples),
				static_cast<float>(pd.y / pd.samples),
				static_cast<float>(pd.z / pd.samples)
			});
		}

		// tonemap XYZ to RGB
		std::vector<Vec3> rgbColor = Tonemap(xyzColor);

		// rays per pixel
		float spp = static_cast<float>(std::accumulate(pixels_.begin(), pixels_.end(), 0.0,
			[](double sum, const PixelData& pd) { return sum + pd.samples; }) / pixelsCount_);

		// rays per second
		auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
			std::chrono::high_resolution_clock::now() - start_);
		float rps = (static_cast<float>(completedPasses_ * pixelsCount_) /
			(static_cast<float>(duration.count()) / 1000.0f));

		std::ostringstream oss;
		oss << "SPP: " << FormatNumber(spp) << "  RPS: " << FormatNumber(rps);

		// call image updater
		imageUpdater_->UpdateImage(rgbColor, oss.str());
	}

	std::string Tracer::FormatNumber(float n) const
	{
		std::ostringstream oss;
		if (n < 1e3f)
		{
			oss << static_cast<unsigned long>(n);
		}
		else
		{
			oss << std::setprecision(2) << std::fixed;
			if (n < 1e6f)
			{
				oss << n / 1e3f << "K";
			}
			else if (n <= 1e9f)
			{
				oss << n / 1e6f << "M";
			}
			else
			{
				oss << n / 1e9f << "B";
			}
		}

		return oss.str();
	}

}
<commit_msg>Fixed bug when RPP counter would show wrong value due to overflow<commit_after>#include <algorithm>
#include <chrono>
#include <cmath>
#include <iomanip>
#include <numeric>
#include <sstream>
#include <thread>
#include "Model/MDLAModel.h"
#include "Color/CIE1931.h"
#include "Color/SRGB.h"
#include "Task/TaskScheduler.h"
#include "Task/TraceTask.h"
#include "ImageUpdater.h"
#include "Ray.h"
#include "Tracer.h"

namespace SPTracer {

	Tracer::Tracer(std::string fileName, unsigned int numThreads, unsigned int width, unsigned int height)
		: width_(width), height_(height), numThreads_(numThreads)
	{
		pixelsCount_ = static_cast<unsigned long>(width_) * height_;

		// create model from file
		model_ = std::make_unique<MDLAModel>(std::move(fileName));

		// create task scheduler that will spawn threads
		taskScheduler_ = std::make_unique<TaskScheduler>(*this, numThreads);

		// prepare array of pixels
		pixels_.resize(pixelsCount_);

		// spectrum
		spectrum_.min = 400.0f;
		spectrum_.max = 700.0f;
		spectrum_.step = 4.0f;

		// precompute count of wave lengths
		spectrum_.count = static_cast<unsigned int>((spectrum_.max - spectrum_.min) / spectrum_.step) + 1;

		// precompute wave length
		spectrum_.values = std::vector<float>(spectrum_.count);
		for (size_t i = 0; i < spectrum_.count; i++)
		{
			spectrum_.values[i] = spectrum_.min + spectrum_.step * static_cast<float>(i);
		}

		// xyz color converter
		xyzConverter_ = std::make_unique<CIE1931>();

		// rgb color system
		rgbConverter_ = std::make_unique<SRGB>();

	}

	Tracer::~Tracer()
	{
	}

	const Model& Tracer::GetModel() const
	{
		return *model_;
	}

	const XYZConverter& Tracer::GetXYZConverter() const
	{
		return *xyzConverter_;
	}

	TaskScheduler& Tracer::GetTaskScheduler() const
	{
		return *taskScheduler_;
	}

	const Spectrum& Tracer::GetSpectrum() const
	{
		return spectrum_;
	}

	unsigned int Tracer::GetWidth() const
	{
		return width_;
	}

	unsigned int Tracer::GetHeight() const
	{
		return height_;
	}

	unsigned long Tracer::GetPixelsCount() const
	{
		return pixelsCount_;
	}

	void Tracer::Run()
	{
		// record start time
		start_ = std::chrono::high_resolution_clock::now();

		// add tasks to start sampling
		for (size_t i = 0; i < numThreads_; i++)
		{
			taskScheduler_->AddTask(std::make_unique<TraceTask>(*this));
		}
	}

	void Tracer::AddSamples(std::vector<Vec3>& color)
	{
		// lock
		std::lock_guard<std::mutex> lock(mutex_);

		// for every pixel
		for (size_t i = 0; i < pixels_.size(); i++)
		{
			PixelData& pd = pixels_[i];
			pd += color[i];
			pd.samples++;
		}

		// increase count of completed samples
		completedPasses_++;

		// update image approximately every 10 seconds
		static const auto updateInterval = std::chrono::seconds(10);
		static auto nextUpdate = std::chrono::steady_clock::now() + updateInterval;
		auto now = std::chrono::steady_clock::now();
		if (now >= nextUpdate)
		{
			UpdateImage();
			nextUpdate = now + updateInterval;
		}
	}

	void Tracer::SetImageUpdater(std::shared_ptr<ImageUpdater> imageUpdater)
	{
		imageUpdater_ = std::move(imageUpdater);
	}

	float Tracer::FindExposure(const std::vector<Vec3>& xyzColor) const
	{
		float n = static_cast<float>(pixelsCount_);

		// Calculate the average intensity. Calculations are based
		// on the CIE Y component, which corresponds to lightness.
		float mean = std::accumulate(xyzColor.begin(), xyzColor.end(), 0.0f,
			[](float a, const Vec3& xyz) { return a + xyz.y; }) / n;

		// Then compute the standard deviation.
		float sqrMean = std::accumulate(xyzColor.begin(), xyzColor.end(), 0.0f,
			[](float a, const Vec3& xyz) { return a + xyz.y * xyz.y; }) / n;

		float variance = sqrMean - mean * mean;

		// The desired 'white' is one standard deviation above average
		return mean + std::sqrt(variance);
	}

	float Tracer::Clamp(float c) const
	{
		return std::min(1.0f, std::max(0.0f, c));
	}

	std::vector<Vec3> Tracer::Tonemap(const std::vector<Vec3>& xyzColor) const
	{
		float maxIntensity = FindExposure(xyzColor);
		std::vector<Vec3> rgbColor(xyzColor.size());

		for (size_t i = 0; i < xyzColor.size(); i++)
		{
			Vec3 xyz = xyzColor[i];
			Vec3& rgb = rgbColor[i];

			// Apply exposure correction
			xyz.x = std::log(xyz.x / maxIntensity + 1.0f) / std::log(4.0f);
			xyz.y = std::log(xyz.y / maxIntensity + 1.0f) / std::log(4.0f);
			xyz.z = std::log(xyz.z / maxIntensity + 1.0f) / std::log(4.0f);

			// Convert to sRGB.
			rgb = rgbConverter_->GetRGB(xyz);

			// Clamp colours to saturate.
			rgb.x = Clamp(rgb.x);
			rgb.y = Clamp(rgb.y);
			rgb.z = Clamp(rgb.z);
		}

		return rgbColor;
	}

	void Tracer::UpdateImage()
	{
		if (imageUpdater_ == nullptr)
		{
			return;
		}

		// divide XYZ color in pixels on the number of samples
		std::vector<Vec3> xyzColor;
		xyzColor.reserve(pixels_.size());
		for (size_t i = 0; i < pixels_.size(); i++)
		{
			PixelData& pd = pixels_[i];
			xyzColor.push_back(Vec3{
				static_cast<float>(pd.x / pd.samples),
				static_cast<float>(pd.y / pd.samples),
				static_cast<float>(pd.z / pd.samples)
			});
		}

		// tonemap XYZ to RGB
		std::vector<Vec3> rgbColor = Tonemap(xyzColor);

		// samples per pixel
		float spp = static_cast<float>(std::accumulate(pixels_.begin(), pixels_.end(), 0.0,
			[](double sum, const PixelData& pd) { return sum + pd.samples; }) / pixelsCount_);

		// rays per second
		auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
			std::chrono::high_resolution_clock::now() - start_);
		float rps = static_cast<float>(static_cast<double>(completedPasses_) * pixelsCount_ / duration.count() * 1000.0);

		std::ostringstream oss;
		oss << "SPP: " << FormatNumber(spp) << "  RPS: " << FormatNumber(rps);

		// call image updater
		imageUpdater_->UpdateImage(rgbColor, oss.str());
	}

	std::string Tracer::FormatNumber(float n) const
	{
		std::ostringstream oss;
		if (n < 1e3f)
		{
			oss << static_cast<unsigned long>(n);
		}
		else
		{
			oss << std::setprecision(2) << std::fixed;
			if (n < 1e6f)
			{
				oss << n / 1e3f << "K";
			}
			else if (n <= 1e9f)
			{
				oss << n / 1e6f << "M";
			}
			else
			{
				oss << n / 1e9f << "B";
			}
		}

		return oss.str();
	}

}
<|endoftext|>


<commit_before>#include "ghost/config.h"
#include "ghost/autogen.h"
#include "ghost/util.h"
#include <string>
#include <vector>
#include <algorithm>
#include <map>
#include <set>

using namespace std;

static map<string, set<string>> autogen_str_map;
static string autogen_str;
static int missingConfs = 0;

ghost_error ghost_autogen_kacz_nvecs(int **nvecs, int *n, int chunkheight, int nshifts)
{
    string configurations = GHOST_AUTOGEN_KACZ;
    if (configurations[configurations.length() - 1] != ';') {
        configurations += ";";
    }

    size_t pos = 0, commapos = 0;
    int cfg_chunkheight, cfg_nvecs, cfg_nshifts;
    string configuration;
    vector<int> nvecs_vec;

    while ((pos = configurations.find(";")) != string::npos) {
        configuration = configurations.substr(0, pos);

        commapos = configuration.find(",");
        string cfg_chunkheight_str = configuration.substr(0, commapos);

        if (!cfg_chunkheight_str.compare("*")) {
            cfg_chunkheight = chunkheight;
        } else {
            cfg_chunkheight = atoi(cfg_chunkheight_str.c_str());
        }
        configuration.erase(0, commapos + 1);

        commapos = configuration.find(",");
        string cfg_nvecs_str = configuration.substr(0, commapos);
        if (!cfg_nvecs_str.compare("*")) {
            configurations.erase(0, pos + 1);
            continue;
        } else {
            cfg_nvecs = atoi(cfg_nvecs_str.c_str());
        }
        configuration.erase(0, commapos + 1);

        string cfg_nshifts_str = configuration;
        if (!cfg_nshifts_str.compare("*")) {
            cfg_nshifts = nshifts;
        } else {
            cfg_nshifts = atoi(cfg_nshifts_str.c_str());
        }

        if (chunkheight == cfg_chunkheight && nshifts == cfg_nshifts) {
            nvecs_vec.push_back(cfg_nvecs);
        }

        configurations.erase(0, pos + 1);
    }

    sort(nvecs_vec.begin(), nvecs_vec.end());
    *n = nvecs_vec.size();
    ghost_malloc((void **)nvecs, sizeof(int) * (*n));

    int i;
    for (i = 0; i < *n; i++) {
        (*nvecs)[i] = nvecs_vec[i];
    }

    return GHOST_SUCCESS;
}

ghost_error ghost_autogen_spmmv_nvecs(int **nvecs, int *n, int chunkheight)
{
    string configurations;
    ghost_type mytype;
    ghost_type_get(&mytype);

    if (mytype == GHOST_TYPE_CUDA) {
        configurations = GHOST_AUTOGEN_SPMMV_CUDA;
    } else {
        configurations = GHOST_AUTOGEN_SPMMV;
    }

    if (configurations[configurations.length() - 1] != ';') {
        configurations += ";";
    }

    size_t pos = 0, commapos = 0;
    int cfg_chunkheight, cfg_nvecs;
    string configuration;
    vector<int> nvecs_vec;

    while ((pos = configurations.find(";")) != string::npos) {
        configuration = configurations.substr(0, pos);

        commapos = configuration.find(",");
        string cfg_chunkheight_str = configuration.substr(0, commapos);

        if (!cfg_chunkheight_str.compare("*")) {
            cfg_chunkheight = chunkheight;
        } else {
            cfg_chunkheight = atoi(cfg_chunkheight_str.c_str());
        }
        configuration.erase(0, commapos + 1);

        commapos = configuration.find(",");
        string cfg_nvecs_str = configuration.substr(0, commapos);
        if (!cfg_nvecs_str.compare("*")) {
            configurations.erase(0, pos + 1);
            continue;
        } else {
            cfg_nvecs = atoi(cfg_nvecs_str.c_str());
        }
        if (chunkheight == cfg_chunkheight) {
            nvecs_vec.push_back(cfg_nvecs);
        }
        configurations.erase(0, pos + 1);
    }

    sort(nvecs_vec.begin(), nvecs_vec.end());
    *n = nvecs_vec.size();
    ghost_malloc((void **)nvecs, sizeof(int) * (*n));

    int i;
    for (i = 0; i < *n; i++) {
        (*nvecs)[i] = nvecs_vec[i];
    }

    return GHOST_SUCCESS;
}

int ghost_autogen_spmmv_next_nvecs(int desired_nvecs, int chunkheight)
{
    int *nvecs = NULL;
    int n, i, found_nvecs = 0;

    if (ghost_autogen_spmmv_nvecs(&nvecs, &n, chunkheight) != GHOST_SUCCESS) {
        return 0;
    }
    if (n == 0) {
        free(nvecs);
        return 0;
    }
    for (i = n - 1; i >= 0; i--) {
        if (nvecs[i] <= desired_nvecs) {
            found_nvecs = nvecs[i];
            break;
        }
    }

    free(nvecs);

    return found_nvecs;
}

ghost_error ghost_autogen_string_add(const char *func, const char *par)
{
    /*    size_t funcpos = autogen_str.find(func);
      if (funcpos == string::npos) {
          autogen_str.append(" -DGHOST_AUTOGEN_");
          autogen_str.append(func);
          autogen_str.append("=\"");
          autogen_str.append(par);
          autogen_str.append("\"");
      } else {
          string funcstr = autogen_str.substr(funcpos+strlen(func)+1,autogen_str.find(" ",funcpos));
          string findpar_inner = ";"+string(par)+";";
          string findpar_last = ";"+string(par)+"\"";
          string findpar_first = "\""+string(par)+";";
          string findpar_only = "\""+string(par)+"\"";
          if ((funcstr.find(findpar_inner) == string::npos)
                  && (funcstr.find(findpar_last) == string::npos)
                  && (funcstr.find(findpar_first) == string::npos)
                  && (funcstr.find(findpar_only) == string::npos)) {
              autogen_str.insert(funcpos+strlen(func)+2,string(par)+";");
          }
      }
    */

    autogen_str_map[string(func)].insert(string(par));
    return GHOST_SUCCESS;
}

const char *ghost_autogen_string()
{
    autogen_str = "";

    for (auto &func : autogen_str_map) {
        autogen_str += string("-DGHOST_") + func.first + "=\"";
        for (auto &par : func.second) {
            autogen_str += par + ";";
        }
        autogen_str += string("\" ");
    }
    return autogen_str.c_str();
}

void ghost_autogen_set_missing() { missingConfs = 1; }

int ghost_autogen_missing() { return missingConfs; }
<commit_msg>missing autogen notice: add missing AUTOGEN to generated configure string, re #322<commit_after>#include "ghost/config.h"
#include "ghost/autogen.h"
#include "ghost/util.h"
#include <string>
#include <vector>
#include <algorithm>
#include <map>
#include <set>

using namespace std;

static map<string, set<string>> autogen_str_map;
static string autogen_str;
static int missingConfs = 0;

ghost_error ghost_autogen_kacz_nvecs(int **nvecs, int *n, int chunkheight, int nshifts)
{
    string configurations = GHOST_AUTOGEN_KACZ;
    if (configurations[configurations.length() - 1] != ';') {
        configurations += ";";
    }

    size_t pos = 0, commapos = 0;
    int cfg_chunkheight, cfg_nvecs, cfg_nshifts;
    string configuration;
    vector<int> nvecs_vec;

    while ((pos = configurations.find(";")) != string::npos) {
        configuration = configurations.substr(0, pos);

        commapos = configuration.find(",");
        string cfg_chunkheight_str = configuration.substr(0, commapos);

        if (!cfg_chunkheight_str.compare("*")) {
            cfg_chunkheight = chunkheight;
        } else {
            cfg_chunkheight = atoi(cfg_chunkheight_str.c_str());
        }
        configuration.erase(0, commapos + 1);

        commapos = configuration.find(",");
        string cfg_nvecs_str = configuration.substr(0, commapos);
        if (!cfg_nvecs_str.compare("*")) {
            configurations.erase(0, pos + 1);
            continue;
        } else {
            cfg_nvecs = atoi(cfg_nvecs_str.c_str());
        }
        configuration.erase(0, commapos + 1);

        string cfg_nshifts_str = configuration;
        if (!cfg_nshifts_str.compare("*")) {
            cfg_nshifts = nshifts;
        } else {
            cfg_nshifts = atoi(cfg_nshifts_str.c_str());
        }

        if (chunkheight == cfg_chunkheight && nshifts == cfg_nshifts) {
            nvecs_vec.push_back(cfg_nvecs);
        }

        configurations.erase(0, pos + 1);
    }

    sort(nvecs_vec.begin(), nvecs_vec.end());
    *n = nvecs_vec.size();
    ghost_malloc((void **)nvecs, sizeof(int) * (*n));

    int i;
    for (i = 0; i < *n; i++) {
        (*nvecs)[i] = nvecs_vec[i];
    }

    return GHOST_SUCCESS;
}

ghost_error ghost_autogen_spmmv_nvecs(int **nvecs, int *n, int chunkheight)
{
    string configurations;
    ghost_type mytype;
    ghost_type_get(&mytype);

    if (mytype == GHOST_TYPE_CUDA) {
        configurations = GHOST_AUTOGEN_SPMMV_CUDA;
    } else {
        configurations = GHOST_AUTOGEN_SPMMV;
    }

    if (configurations[configurations.length() - 1] != ';') {
        configurations += ";";
    }

    size_t pos = 0, commapos = 0;
    int cfg_chunkheight, cfg_nvecs;
    string configuration;
    vector<int> nvecs_vec;

    while ((pos = configurations.find(";")) != string::npos) {
        configuration = configurations.substr(0, pos);

        commapos = configuration.find(",");
        string cfg_chunkheight_str = configuration.substr(0, commapos);

        if (!cfg_chunkheight_str.compare("*")) {
            cfg_chunkheight = chunkheight;
        } else {
            cfg_chunkheight = atoi(cfg_chunkheight_str.c_str());
        }
        configuration.erase(0, commapos + 1);

        commapos = configuration.find(",");
        string cfg_nvecs_str = configuration.substr(0, commapos);
        if (!cfg_nvecs_str.compare("*")) {
            configurations.erase(0, pos + 1);
            continue;
        } else {
            cfg_nvecs = atoi(cfg_nvecs_str.c_str());
        }
        if (chunkheight == cfg_chunkheight) {
            nvecs_vec.push_back(cfg_nvecs);
        }
        configurations.erase(0, pos + 1);
    }

    sort(nvecs_vec.begin(), nvecs_vec.end());
    *n = nvecs_vec.size();
    ghost_malloc((void **)nvecs, sizeof(int) * (*n));

    int i;
    for (i = 0; i < *n; i++) {
        (*nvecs)[i] = nvecs_vec[i];
    }

    return GHOST_SUCCESS;
}

int ghost_autogen_spmmv_next_nvecs(int desired_nvecs, int chunkheight)
{
    int *nvecs = NULL;
    int n, i, found_nvecs = 0;

    if (ghost_autogen_spmmv_nvecs(&nvecs, &n, chunkheight) != GHOST_SUCCESS) {
        return 0;
    }
    if (n == 0) {
        free(nvecs);
        return 0;
    }
    for (i = n - 1; i >= 0; i--) {
        if (nvecs[i] <= desired_nvecs) {
            found_nvecs = nvecs[i];
            break;
        }
    }

    free(nvecs);

    return found_nvecs;
}

ghost_error ghost_autogen_string_add(const char *func, const char *par)
{
    /*    size_t funcpos = autogen_str.find(func);
      if (funcpos == string::npos) {
          autogen_str.append(" -DGHOST_AUTOGEN_");
          autogen_str.append(func);
          autogen_str.append("=\"");
          autogen_str.append(par);
          autogen_str.append("\"");
      } else {
          string funcstr = autogen_str.substr(funcpos+strlen(func)+1,autogen_str.find(" ",funcpos));
          string findpar_inner = ";"+string(par)+";";
          string findpar_last = ";"+string(par)+"\"";
          string findpar_first = "\""+string(par)+";";
          string findpar_only = "\""+string(par)+"\"";
          if ((funcstr.find(findpar_inner) == string::npos)
                  && (funcstr.find(findpar_last) == string::npos)
                  && (funcstr.find(findpar_first) == string::npos)
                  && (funcstr.find(findpar_only) == string::npos)) {
              autogen_str.insert(funcpos+strlen(func)+2,string(par)+";");
          }
      }
    */

    autogen_str_map[string(func)].insert(string(par));
    return GHOST_SUCCESS;
}

const char *ghost_autogen_string()
{
    autogen_str = "";

    for (auto &func : autogen_str_map) {
        autogen_str += string("-DGHOST_AUTOGEN") + func.first + "=\"";
        for (auto &par : func.second) {
            autogen_str += par + ";";
        }
        autogen_str += string("\" ");
    }
    return autogen_str.c_str();
}

void ghost_autogen_set_missing() { missingConfs = 1; }

int ghost_autogen_missing() { return missingConfs; }
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015-2017 Advanced Micro Devices, Inc.
 * All rights reserved.
 *
 * Copyright (c) 2003-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Nathan Binkert
 *          Anthony Gutierrez
 */

#ifndef __BASE_AMO_HH__
#define __BASE_AMO_HH__

struct AtomicOpFunctor
{
    virtual void operator()(uint8_t *p) = 0;
    virtual AtomicOpFunctor* clone() = 0;
    virtual ~AtomicOpFunctor() {}
};

template <class T>
struct TypedAtomicOpFunctor : public AtomicOpFunctor
{
    void operator()(uint8_t *p) { execute((T *)p); }
    virtual AtomicOpFunctor* clone() = 0;
    virtual void execute(T * p) = 0;
};

template<typename T>
class AtomicGeneric2Op : public TypedAtomicOpFunctor<T>
{
  public:
    AtomicGeneric2Op(T _a, std::function<void(T*,T)> _op)
        : a(_a), op(_op)
    {}
    AtomicOpFunctor* clone() override
    {
        return new AtomicGeneric2Op<T>(*this);
    }
    void execute(T *b) override
    {
        op(b, a);
    }
  private:
    T a;
    std::function<void(T*,T)> op;
 };

template<typename T>
class AtomicGeneric3Op : public TypedAtomicOpFunctor<T>
{
  public:
    AtomicGeneric3Op(T _a, T _c, std::function<void(T*, T, T)> _op)
        : a(_a), c(_c), op(_op)
    {}
    AtomicOpFunctor* clone() override
    {
        return new AtomicGeneric3Op<T>(*this);
    }
    void execute(T *b) override
    {
        op(b, a, c);
    }
  private:
    T a;
    T c;
    std::function<void(T*, T, T)> op;
};

template<typename T>
class AtomicGenericPair3Op : public TypedAtomicOpFunctor<T>
{
  public:
    AtomicGenericPair3Op(std::array<T, 2>& _a, std::array<T, 2> _c,
           std::function<void(T*, std::array<T, 2>&, std::array<T, 2>)> _op)
        : a(_a), c(_c), op(_op)
    {}
    AtomicOpFunctor* clone() override
    {
        return new AtomicGenericPair3Op<T>(*this);
    }
    void execute(T* b) override
    {
        op(b, a, c);
    }
  private:
    std::array<T, 2> a;
    std::array<T, 2> c;
    std::function<void(T*, std::array<T, 2>&, std::array<T, 2>)> op;
};

template<typename T>
class AtomicOpAnd : public TypedAtomicOpFunctor<T>
{
  public:
    T a;
    AtomicOpAnd(T _a) : a(_a) { }
    void execute(T *b) { *b &= a; }
    AtomicOpFunctor* clone () { return new AtomicOpAnd(a); }
};

template<typename T>
class AtomicOpOr : public TypedAtomicOpFunctor<T>
{
  public:
    T a;
    AtomicOpOr(T _a) : a(_a) { }
    void execute(T *b) { *b |= a; }
    AtomicOpFunctor* clone () { return new AtomicOpOr(a); }
};

template<typename T>
class AtomicOpXor : public TypedAtomicOpFunctor<T>
{
  public:
    T a;
    AtomicOpXor(T _a) : a(_a) {}
    void execute(T *b) { *b ^= a; }
    AtomicOpFunctor* clone () { return new AtomicOpXor(a); }
};

template<typename T>
class AtomicOpExch : public TypedAtomicOpFunctor<T>
{
  public:
    T a;
    AtomicOpExch(T _a) : a(_a) { }
    void execute(T *b) { *b = a; }
    AtomicOpFunctor* clone () { return new AtomicOpExch(a); }
};

template<typename T>
class AtomicOpAdd : public TypedAtomicOpFunctor<T>
{
  public:
    T a;
    AtomicOpAdd(T _a) : a(_a) { }
    void execute(T *b) { *b += a; }
    AtomicOpFunctor* clone () { return new AtomicOpAdd(a); }
};

template<typename T>
class AtomicOpSub : public TypedAtomicOpFunctor<T>
{
  public:
    T a;
    AtomicOpSub(T _a) : a(_a) { }
    void execute(T *b) { *b -= a; }
    AtomicOpFunctor* clone () { return new AtomicOpSub(a); }
};

template<typename T>
class AtomicOpInc : public TypedAtomicOpFunctor<T>
{
  public:
    AtomicOpInc() { }
    void execute(T *b) { *b += 1; }
    AtomicOpFunctor* clone () { return new AtomicOpInc(); }
};

template<typename T>
class AtomicOpDec : public TypedAtomicOpFunctor<T>
{
  public:
    AtomicOpDec() {}
    void execute(T *b) { *b -= 1; }
    AtomicOpFunctor* clone () { return new AtomicOpDec(); }
};

template<typename T>
class AtomicOpMax : public TypedAtomicOpFunctor<T>
{
  public:
    T a;
    AtomicOpMax(T _a) : a(_a) { }

    void
    execute(T *b)
    {
        if (a > *b)
            *b = a;
    }
    AtomicOpFunctor* clone () { return new AtomicOpMax(a); }
};

template<typename T>
class AtomicOpMin : public TypedAtomicOpFunctor<T>
{
  public:
    T a;
    AtomicOpMin(T _a) : a(_a) {}

    void
    execute(T *b)
    {
        if (a < *b)
            *b = a;
    }
    AtomicOpFunctor* clone () { return new AtomicOpMin(a); }
};

typedef std::unique_ptr<AtomicOpFunctor> AtomicOpFunctorPtr;

#endif // __BASE_AMO_HH__
<commit_msg>base: Include some required headers in amo.hh.<commit_after>/*
 * Copyright (c) 2015-2017 Advanced Micro Devices, Inc.
 * All rights reserved.
 *
 * Copyright (c) 2003-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Nathan Binkert
 *          Anthony Gutierrez
 */

#ifndef __BASE_AMO_HH__
#define __BASE_AMO_HH__

#include <array>
#include <cstdint>
#include <functional>

struct AtomicOpFunctor
{
    virtual void operator()(uint8_t *p) = 0;
    virtual AtomicOpFunctor* clone() = 0;
    virtual ~AtomicOpFunctor() {}
};

template <class T>
struct TypedAtomicOpFunctor : public AtomicOpFunctor
{
    void operator()(uint8_t *p) { execute((T *)p); }
    virtual AtomicOpFunctor* clone() = 0;
    virtual void execute(T * p) = 0;
};

template<typename T>
class AtomicGeneric2Op : public TypedAtomicOpFunctor<T>
{
  public:
    AtomicGeneric2Op(T _a, std::function<void(T*,T)> _op)
        : a(_a), op(_op)
    {}
    AtomicOpFunctor* clone() override
    {
        return new AtomicGeneric2Op<T>(*this);
    }
    void execute(T *b) override
    {
        op(b, a);
    }
  private:
    T a;
    std::function<void(T*,T)> op;
 };

template<typename T>
class AtomicGeneric3Op : public TypedAtomicOpFunctor<T>
{
  public:
    AtomicGeneric3Op(T _a, T _c, std::function<void(T*, T, T)> _op)
        : a(_a), c(_c), op(_op)
    {}
    AtomicOpFunctor* clone() override
    {
        return new AtomicGeneric3Op<T>(*this);
    }
    void execute(T *b) override
    {
        op(b, a, c);
    }
  private:
    T a;
    T c;
    std::function<void(T*, T, T)> op;
};

template<typename T>
class AtomicGenericPair3Op : public TypedAtomicOpFunctor<T>
{
  public:
    AtomicGenericPair3Op(std::array<T, 2>& _a, std::array<T, 2> _c,
           std::function<void(T*, std::array<T, 2>&, std::array<T, 2>)> _op)
        : a(_a), c(_c), op(_op)
    {}
    AtomicOpFunctor* clone() override
    {
        return new AtomicGenericPair3Op<T>(*this);
    }
    void execute(T* b) override
    {
        op(b, a, c);
    }
  private:
    std::array<T, 2> a;
    std::array<T, 2> c;
    std::function<void(T*, std::array<T, 2>&, std::array<T, 2>)> op;
};

template<typename T>
class AtomicOpAnd : public TypedAtomicOpFunctor<T>
{
  public:
    T a;
    AtomicOpAnd(T _a) : a(_a) { }
    void execute(T *b) { *b &= a; }
    AtomicOpFunctor* clone () { return new AtomicOpAnd(a); }
};

template<typename T>
class AtomicOpOr : public TypedAtomicOpFunctor<T>
{
  public:
    T a;
    AtomicOpOr(T _a) : a(_a) { }
    void execute(T *b) { *b |= a; }
    AtomicOpFunctor* clone () { return new AtomicOpOr(a); }
};

template<typename T>
class AtomicOpXor : public TypedAtomicOpFunctor<T>
{
  public:
    T a;
    AtomicOpXor(T _a) : a(_a) {}
    void execute(T *b) { *b ^= a; }
    AtomicOpFunctor* clone () { return new AtomicOpXor(a); }
};

template<typename T>
class AtomicOpExch : public TypedAtomicOpFunctor<T>
{
  public:
    T a;
    AtomicOpExch(T _a) : a(_a) { }
    void execute(T *b) { *b = a; }
    AtomicOpFunctor* clone () { return new AtomicOpExch(a); }
};

template<typename T>
class AtomicOpAdd : public TypedAtomicOpFunctor<T>
{
  public:
    T a;
    AtomicOpAdd(T _a) : a(_a) { }
    void execute(T *b) { *b += a; }
    AtomicOpFunctor* clone () { return new AtomicOpAdd(a); }
};

template<typename T>
class AtomicOpSub : public TypedAtomicOpFunctor<T>
{
  public:
    T a;
    AtomicOpSub(T _a) : a(_a) { }
    void execute(T *b) { *b -= a; }
    AtomicOpFunctor* clone () { return new AtomicOpSub(a); }
};

template<typename T>
class AtomicOpInc : public TypedAtomicOpFunctor<T>
{
  public:
    AtomicOpInc() { }
    void execute(T *b) { *b += 1; }
    AtomicOpFunctor* clone () { return new AtomicOpInc(); }
};

template<typename T>
class AtomicOpDec : public TypedAtomicOpFunctor<T>
{
  public:
    AtomicOpDec() {}
    void execute(T *b) { *b -= 1; }
    AtomicOpFunctor* clone () { return new AtomicOpDec(); }
};

template<typename T>
class AtomicOpMax : public TypedAtomicOpFunctor<T>
{
  public:
    T a;
    AtomicOpMax(T _a) : a(_a) { }

    void
    execute(T *b)
    {
        if (a > *b)
            *b = a;
    }
    AtomicOpFunctor* clone () { return new AtomicOpMax(a); }
};

template<typename T>
class AtomicOpMin : public TypedAtomicOpFunctor<T>
{
  public:
    T a;
    AtomicOpMin(T _a) : a(_a) {}

    void
    execute(T *b)
    {
        if (a < *b)
            *b = a;
    }
    AtomicOpFunctor* clone () { return new AtomicOpMin(a); }
};

typedef std::unique_ptr<AtomicOpFunctor> AtomicOpFunctorPtr;

#endif // __BASE_AMO_HH__
<|endoftext|>