text:
//
// Copyright (c) Antony Polukhin, 2013-2014.
//
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef BOOST_TYPE_INDEX_TYPE_INDEX_FACADE_HPP
#define BOOST_TYPE_INDEX_TYPE_INDEX_FACADE_HPP

#include <boost/config.hpp>
#include <boost/functional/hash_fwd.hpp>
#include <string>
#include <cstring>

#if !defined(BOOST_NO_IOSTREAM)
#if !defined(BOOST_NO_IOSFWD)
#include <iosfwd>               // for std::basic_ostream
#else
#include <ostream>
#endif
#endif

#ifdef BOOST_HAS_PRAGMA_ONCE
# pragma once
#endif

namespace boost { namespace typeindex {

/// \class type_index_facade
///
/// This class takes care about the comparison operators, hash functions and
/// ostream operators. Use this class as a public base class for defining new
/// type_info-conforming classes.
///
/// \b Example:
/// \code
/// class stl_type_index: public type_index_facade<stl_type_index, std::type_info>
/// {
/// public:
///     typedef std::type_info type_info_t;
/// private:
///     const type_info_t* data_;
///
/// public:
///     stl_type_index(const type_info_t& data) noexcept
///         : data_(&data)
///     {}
/// // ...
/// };
/// \endcode
///
/// \tparam Derived Class derived from type_index_facade.
/// \tparam TypeInfo Class that will be used as a base type_info class.
/// \note Take a look at the protected methods. They are \b not \b defined in type_index_facade.
/// Protected member functions raw_name() \b must be defined in Derived class. All the other
/// methods are mandatory.
/// \see 'Making a custom type_index' section for more information about
/// creating your own type_index using type_index_facade.
template <class Derived, class TypeInfo>
class type_index_facade {
private:
    /// @cond
    const Derived & derived() const BOOST_NOEXCEPT {
      return *static_cast<Derived const*>(this);
    }
    /// @endcond
public:
    typedef TypeInfo                                type_info_t;

    /// \b Override: This function \b may be redefined in Derived class. Overrides \b must not throw.
    /// \return Name of a type. By default returns Derived::raw_name().
    inline const char* name() const BOOST_NOEXCEPT {
        return derived().raw_name();
    }

    /// \b Override: This function \b may be redefined in Derived class. Overrides may throw.
    /// \return Human readable type name. By default returns Derived::name().
    inline std::string pretty_name() const {
        return derived().name();
    }

    /// \b Override: This function \b may be redefined in Derived class. Overrides \b must not throw.
    /// \return True if two types are equal. By default compares types by raw_name().
    inline bool equal(const Derived& rhs) const BOOST_NOEXCEPT {
        const char* const left = derived().raw_name();
        const char* const right = rhs.raw_name();
        return left == right || !std::strcmp(left, right);
    }

    /// \b Override: This function \b may be redefined in Derived class. Overrides \b must not throw.
    /// \return True if rhs is greater than this. By default compares types by raw_name().
    inline bool before(const Derived& rhs) const BOOST_NOEXCEPT {
        const char* const left = derived().raw_name();
        const char* const right = rhs.raw_name();
        return left != right && std::strcmp(left, right) < 0;
    }

    /// \b Override: This function \b may be redefined in Derived class. Overrides \b must not throw.
    /// \return Hash code of a type. By default hashes types by raw_name().
    /// \note <boost/functional/hash.hpp> has to be included if this function is used.
    inline std::size_t hash_code() const BOOST_NOEXCEPT {
        const char* const name = derived().raw_name();
        return boost::hash_range(name, name + std::strlen(name));
    }

#if defined(BOOST_TYPE_INDEX_DOXYGEN_INVOKED)
protected:
    /// \b Override: This function \b must be redefined in Derived class. Overrides \b must not throw.
    /// \return Pointer to unredable/raw type name.
    inline const char* raw_name() const BOOST_NOEXCEPT;

    /// \b Override: This function \b may be redefined in Derived class. Overrides \b must not throw.
    /// \return Const reference to underlying low level type_info_t.
    inline const type_info_t& type_info() const BOOST_NOEXCEPT;

    /// This is a factory method that is used to create instances of Derived classes.
    /// boost::typeindex::type_id() will call this method, if Derived has same type as boost::typeindex::type_index.
    ///
    /// \b Override: This function \b may be redefined and made public in Derived class. Overrides \b must not throw.
    /// Overrides \b must remove const, volatile && and & modifiers from T.
    /// \tparam T Type for which type_index must be created.
    /// \return type_index for type T.
    template <class T>
    static Derived type_id() BOOST_NOEXCEPT;

    /// This is a factory method that is used to create instances of Derived classes.
    /// boost::typeindex::type_id_with_cvr() will call this method, if Derived has same type as boost::typeindex::type_index.
    ///
    /// \b Override: This function \b may be redefined and made public in Derived class. Overrides \b must not throw.
    /// Overrides \b must \b not remove const, volatile && and & modifiers from T.
    /// \tparam T Type for which type_index must be created.
    /// \return type_index for type T.
    template <class T>
    static Derived type_id_with_cvr() BOOST_NOEXCEPT;

    /// This is a factory method that is used to create instances of Derived classes.
    /// boost::typeindex::type_id_runtime(const T&) will call this method, if Derived has same type as boost::typeindex::type_index.
    ///
    /// \b Override: This function \b may be redefined and made public in Derived class.
    /// \param variable Variable which runtime type will be stored in type_index.
    /// \return type_index with runtime type of variable.
    template <class T>
    static Derived type_id_runtime(const T& variable) BOOST_NOEXCEPT;

#endif

};

/// @cond
template <class Derived, class TypeInfo>
inline bool operator == (const type_index_facade<Derived, TypeInfo>& lhs, const type_index_facade<Derived, TypeInfo>& rhs) BOOST_NOEXCEPT {
    return static_cast<Derived const&>(lhs).equal(static_cast<Derived const&>(rhs));
}

template <class Derived, class TypeInfo>
inline bool operator < (const type_index_facade<Derived, TypeInfo>& lhs, const type_index_facade<Derived, TypeInfo>& rhs) BOOST_NOEXCEPT {
    return static_cast<Derived const&>(lhs).before(static_cast<Derived const&>(rhs));;
}

template <class Derived, class TypeInfo>
inline bool operator > (const type_index_facade<Derived, TypeInfo>& lhs, const type_index_facade<Derived, TypeInfo>& rhs) BOOST_NOEXCEPT {
    return rhs < lhs;
}

template <class Derived, class TypeInfo>
inline bool operator <= (const type_index_facade<Derived, TypeInfo>& lhs, const type_index_facade<Derived, TypeInfo>& rhs) BOOST_NOEXCEPT {
    return !(lhs > rhs);
}

template <class Derived, class TypeInfo>
inline bool operator >= (const type_index_facade<Derived, TypeInfo>& lhs, const type_index_facade<Derived, TypeInfo>& rhs) BOOST_NOEXCEPT {
    return !(lhs < rhs);
}

template <class Derived, class TypeInfo>
inline bool operator != (const type_index_facade<Derived, TypeInfo>& lhs, const type_index_facade<Derived, TypeInfo>& rhs) BOOST_NOEXCEPT {
    return !(lhs == rhs);
}

// ######################### COMPARISONS with Derived ############################ //
template <class Derived, class TypeInfo>
inline bool operator == (const TypeInfo& lhs, const type_index_facade<Derived, TypeInfo>& rhs) BOOST_NOEXCEPT {
    return Derived(lhs) == rhs;
}

template <class Derived, class TypeInfo>
inline bool operator < (const TypeInfo& lhs, const type_index_facade<Derived, TypeInfo>& rhs) BOOST_NOEXCEPT {
    return Derived(lhs) < rhs;
}

template <class Derived, class TypeInfo>
inline bool operator > (const TypeInfo& lhs, const type_index_facade<Derived, TypeInfo>& rhs) BOOST_NOEXCEPT {
    return rhs < Derived(lhs);
}

template <class Derived, class TypeInfo>
inline bool operator <= (const TypeInfo& lhs, const type_index_facade<Derived, TypeInfo>& rhs) BOOST_NOEXCEPT {
    return !(Derived(lhs) > rhs);
}

template <class Derived, class TypeInfo>
inline bool operator >= (const TypeInfo& lhs, const type_index_facade<Derived, TypeInfo>& rhs) BOOST_NOEXCEPT {
    return !(Derived(lhs) < rhs);
}

template <class Derived, class TypeInfo>
inline bool operator != (const TypeInfo& lhs, const type_index_facade<Derived, TypeInfo>& rhs) BOOST_NOEXCEPT {
    return !(Derived(lhs) == rhs);
}

template <class Derived, class TypeInfo>
inline bool operator == (const type_index_facade<Derived, TypeInfo>& lhs, const TypeInfo& rhs) BOOST_NOEXCEPT {
    return lhs == Derived(rhs);
}

template <class Derived, class TypeInfo>
inline bool operator < (const type_index_facade<Derived, TypeInfo>& lhs, const TypeInfo& rhs) BOOST_NOEXCEPT {
    return lhs < Derived(rhs);
}

template <class Derived, class TypeInfo>
inline bool operator > (const type_index_facade<Derived, TypeInfo>& lhs, const TypeInfo& rhs) BOOST_NOEXCEPT {
    return Derived(rhs) < lhs;
}

template <class Derived, class TypeInfo>
inline bool operator <= (const type_index_facade<Derived, TypeInfo>& lhs, const TypeInfo& rhs) BOOST_NOEXCEPT {
    return !(lhs > Derived(rhs));
}

template <class Derived, class TypeInfo>
inline bool operator >= (const type_index_facade<Derived, TypeInfo>& lhs, const TypeInfo& rhs) BOOST_NOEXCEPT {
    return !(lhs < Derived(rhs));
}

template <class Derived, class TypeInfo>
inline bool operator != (const type_index_facade<Derived, TypeInfo>& lhs, const TypeInfo& rhs) BOOST_NOEXCEPT {
    return !(lhs == Derived(rhs));
}

// ######################### COMPARISONS with Derived END ############################ //

/// @endcond

#if defined(BOOST_TYPE_INDEX_DOXYGEN_INVOKED)

/// noexcept comparison operators for type_index_facade classes.
bool operator ==, !=, <, ... (const type_index_facade& lhs, const type_index_facade& rhs) noexcept;

/// noexcept comparison operators for type_index_facade and it's TypeInfo classes.
bool operator ==, !=, <, ... (const type_index_facade& lhs, const TypeInfo& rhs) noexcept;

/// noexcept comparison operators for type_index_facade's TypeInfo and type_index_facade classes.
bool operator ==, !=, <, ... (const TypeInfo& lhs, const type_index_facade& rhs) noexcept;

#endif

#ifndef BOOST_NO_IOSTREAM
#ifdef BOOST_NO_TEMPLATED_IOSTREAMS
/// @cond
/// Ostream operator that will output demangled name
template <class Derived, class TypeInfo>
inline std::ostream& operator<<(std::ostream& ostr, const type_index_facade<Derived, TypeInfo>& ind) {
    ostr << static_cast<Derived const&>(ind).pretty_name();
    return ostr;
}
/// @endcond
#else
/// Ostream operator that will output demangled name.
template <class CharT, class TriatT, class Derived, class TypeInfo>
inline std::basic_ostream<CharT, TriatT>& operator<<(
    std::basic_ostream<CharT, TriatT>& ostr,
    const type_index_facade<Derived, TypeInfo>& ind)
{
    ostr << static_cast<Derived const&>(ind).pretty_name();
    return ostr;
}
#endif // BOOST_NO_TEMPLATED_IOSTREAMS
#endif // BOOST_NO_IOSTREAM

/// This free function is used by Boost's unordered containers.
/// \note <boost/functional/hash.hpp> has to be included if this function is used.
template <class Derived, class TypeInfo>
inline std::size_t hash_value(const type_index_facade<Derived, TypeInfo>& lhs) BOOST_NOEXCEPT {
    return static_cast<Derived const&>(lhs).hash_code();
}

}} // namespace boost::typeindex

#endif // BOOST_TYPE_INDEX_TYPE_INDEX_FACADE_HPP


text: #include <boost/polygon/interval_traits.hpp>

ext: hpp

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
/* Copyright © 2019 Apple Inc. All rights reserved.
 *
 * Use of this source code is governed by a BSD-3-clause license that can
 * be found in the LICENSE.txt file or at https://opensource.org/licenses/BSD-3-Clause
 */

#define BOOST_TEST_MODULE test_dc_data_iterator

#include <toolkits/drawing_classifier/dc_data_iterator.hpp>
#include <toolkits/drawing_classifier/drawing_classifier.hpp>

#include <algorithm>

#include <boost/test/unit_test.hpp>
#include <core/util/test_macros.hpp>
#include <model_server/lib/image_util.hpp>

#include "../neural_net/neural_net_mocks.hpp"
#include "dc_data_utils.hpp"
#include "dc_mock_interface.hpp"

namespace turi {
namespace drawing_classifier {

namespace {

using turi::neural_net::compute_context;
using turi::neural_net::float_array_map;
using turi::neural_net::shared_float_array;
using turi::neural_net::mock_compute_context;
using turi::neural_net::mock_model_backend;
using turi::neural_net::model_backend;
using turi::neural_net::model_spec;
using turi::neural_net::shared_float_array;

/* ==================== global variables  ====================== */

/**
 * tuple of batch_size, num_of_rows, num_of_classes
 *
 * batch_size, num_of_rows, num_of_classes
 * 1. batch_size > num_of_rows
 * 2. batch_size == num_of_rows
 * 3. num_of_rows can divide batch_size
 * 4. num_of_rows can not divide batch_size
 *
 **/
std::vector<std::tuple<unsigned, unsigned, unsigned>> TEST_CASES = {
    {2, 1, 1}, {2, 1, 2}, {2, 2, 2}, {2, 4, 2},
    {2, 4, 3}, {2, 5, 2}, {2, 5, 3}};

constexpr auto PRED_NAME = "preds";

/* ============== utils borrowed from gl_sframe.cxx ============= */
// TODO: create a common util class
void _assert_flexvec_equals(const std::vector<flexible_type>& sa,
                            const std::vector<flexible_type>& sb) {
  TS_ASSERT_EQUALS(sa.size(), sb.size());
  for (size_t i = 0; i < sa.size(); ++i) {
    if (sa[i] != sb[i]) {
      std::cout << sa[i] << " vs " << sb[i] << std::endl;
    }
    TS_ASSERT_EQUALS(sa[i], sb[i]);
  }
}

void _assert_sframe_equals(gl_sframe sa, gl_sframe sb) {
  TS_ASSERT_EQUALS(sa.size(), sb.size());
  TS_ASSERT_EQUALS(sa.num_columns(), sb.num_columns());
  auto a_cols = sa.column_names();
  auto b_cols = sb.column_names();
  std::sort(a_cols.begin(), a_cols.end());
  std::sort(b_cols.begin(), b_cols.end());
  for (size_t i = 0; i < a_cols.size(); ++i)
    TS_ASSERT_EQUALS(a_cols[i], b_cols[i]);
  sb = sb[sa.column_names()];
  for (size_t i = 0; i < sa.size(); ++i) {
    _assert_flexvec_equals(sa[i], sb[i]);
  }
}

/* ========================= test drivers & utils ======================== */

#ifndef NDEBUG
#define log_for_debug(x) \
  { logprogress_stream << ">>>" << (x) << std::endl; }
#else
#define log_for_debug(x) {}
#endif

struct mock_perform_inference : public test_drawing_classifier {
  inline gl_sframe get_inference_result(data_iterator* data) {
    return perform_inference(data);
  }
};

gl_sframe set_up_perform_inference(
    test_drawing_classifier& mock_model,
    std::unique_ptr<mock_model_backend>& mock_backend,
    std::unique_ptr<mock_compute_context>& mock_context, size_t batch_size,
    const size_t num_of_rows, const size_t num_of_classes) {
  ASSERT_MSG(num_of_rows > 0, "num_of_rows should be bigger than 0");
  ASSERT_MSG(num_of_classes > 0, "num_of_classes should be bigger than 0");
  ASSERT_MSG(batch_size > 0, "batch_size should be bigger than 0");

  gl_sframe expected_sf;
  {
    std::vector<float> buffer(num_of_classes * batch_size);

    std::default_random_engine eng;
    std::uniform_int_distribution<float> distribution(0, 20);

    gl_sframe_writer writer({PRED_NAME}, {flex_type_enum::VECTOR},
                            /* num_segments */ 1);

    size_t ii = 0;
    while (ii < num_of_rows) {
      buffer.clear();

      size_t repeat =
          ii + batch_size > num_of_rows ? num_of_rows - ii : batch_size;

      ii += batch_size;

      for (size_t jj = 0; jj < repeat; ++jj) {
        auto pbeg = buffer.begin() + jj * num_of_classes;
        auto pend = pbeg + num_of_classes;
        std::generate(pbeg, pend, [&]() { return distribution(eng); });
        float my_sum = std::accumulate(pbeg, pend, 0.0f, std::plus<float>());
        std::transform(pbeg, pend, pbeg,
                       [=](float num) { return num / my_sum; });

        writer.write({flex_vec{pbeg, pend}}, 0);
      }

      auto to_return =
          shared_float_array::copy(buffer.data(), {num_of_classes, repeat});

      mock_backend->predict_calls_.push_back([=](const float_array_map& input) {
        TS_ASSERT_EQUALS(input.at("input").size(), repeat * 28 * 28);
        return float_array_map({{"output", to_return}});
      });
    }
    // since we are using push front;
    expected_sf = writer.close();
  }

  TS_ASSERT_EQUALS(expected_sf.size(), num_of_rows);

  TS_ASSERT_EQUALS(mock_backend->predict_calls_.size(),
                   num_of_rows % batch_size ? num_of_rows / batch_size + 1
                                            : num_of_rows / batch_size);

  mock_model.add_or_update_state(
      {{"num_classes", num_of_classes},
       {"batch_size", batch_size}});

  auto create_drawing_classifier_impl =
      [&mock_backend](const float_array_map&, size_t batch_size,
                      size_t num_classes) { return std::move(mock_backend); };

  mock_context->create_drawing_classifier_calls_.push_back(
      create_drawing_classifier_impl);

  // be extremely careful about reference a unique_ptr
  // never use mock_context after this line
  auto create_compute_context_impl = [&] { return std::move(mock_context); };
  mock_model.create_compute_context_calls_.push_back(
      create_compute_context_impl);

  return expected_sf;
}

std::unique_ptr<data_iterator> prepare_data_for_prediction(
    bool is_bitmap_based, size_t num_of_rows, size_t num_of_classes) {
  flex_list class_labels;

  class_labels.reserve(num_of_classes);
  for (size_t ii = 0; ii < num_of_classes; ++ii) {
    class_labels.push_back(std::to_string(ii));
  }

  // Create an arbitrary SFrame with test_num_rows rows.
  drawing_data_generator data_generator(/* is_bitmap_based */ is_bitmap_based,
                                        num_of_rows, class_labels);
  gl_sframe my_data = data_generator.get_data();

  TS_ASSERT_EQUALS(my_data.size(), num_of_rows);

  data_iterator::parameters params;
  params.data = my_data;
  // no repeat since it's not iterating training
  params.repeat = false;
  params.target_column_name = data_generator.get_target_column_name();
  params.feature_column_name = data_generator.get_feature_column_name();

  params.is_train = false;

  return std::unique_ptr<data_iterator>(new simple_data_iterator(params));
}

using test_runner_t =
    std::function<void(test_drawing_classifier&, gl_sframe, gl_sframe)>;

void prediction_test_driver(size_t batch_size, size_t num_of_rows,
                            size_t num_of_classes, test_runner_t runner,
                            bool is_bitmap_based) {
#ifndef NDEBUG
  logprogress_stream << "batch_size=" << batch_size
                     << "; num_of_rows=" << num_of_rows
                     << "; num_of_classes=" << num_of_classes << std::endl;
#endif

  const std::string feature_name = "feature";
  const std::string target_name = "target";

  // mode the data iterator first
  test_drawing_classifier mock_model;
  std::unique_ptr<mock_model_backend> mock_backend(new mock_model_backend);
  std::unique_ptr<mock_compute_context> mock_context(new mock_compute_context);

  auto expected_sf =
      set_up_perform_inference(mock_model, mock_backend, mock_context,
                               batch_size, num_of_rows, num_of_classes);

  // make sure the output is what expected
  flex_list class_labels;
  class_labels.reserve(num_of_classes);
  for (size_t ii = 0; ii < num_of_classes; ++ii) {
    class_labels.push_back(std::to_string(ii));
  }

  // name 'target', 'feature' are used by create_iterator
  drawing_data_generator data_generator(/* is_bitmap_based */ is_bitmap_based,
                                        num_of_rows, class_labels, target_name,
                                        feature_name);

  gl_sframe my_data = data_generator.get_data();
  TS_ASSERT_EQUALS(my_data.size(), num_of_rows);

  mock_model.create_iterator_calls_.push_back(
      [=](data_iterator::parameters my_params) {
        return std::unique_ptr<data_iterator>(
            new simple_data_iterator(my_params));
      });

  // specific for predict
  mock_model.add_or_update_state(
      {{"target", target_name},
       {"feature", feature_name},
       {"classes", class_labels}});

  runner(mock_model, my_data, expected_sf);
}
}  // namespace

/* ========================= perform inference ===========================*/

BOOST_AUTO_TEST_CASE(test_drawing_classifier_perform_inference) {
  log_for_debug("test_drawing_classifier_perform_inference");

  for (auto& entry : TEST_CASES) {
    size_t batch_size = std::get<0>(entry);
    size_t num_of_rows = std::get<1>(entry);
    size_t num_of_classes = std::get<2>(entry);

#ifndef NDEBUG
    logprogress_stream << "batch_size=" << batch_size
                       << "; num_of_rows=" << num_of_rows
                       << "; num_of_classes=" << num_of_classes << std::endl;
#endif

    const std::string feature_name = "feature";
    const std::string target_name = "target";

    // mode the data iterator first
    mock_perform_inference mock_model;
    std::unique_ptr<mock_model_backend> mock_backend(new mock_model_backend);
    std::unique_ptr<mock_compute_context> mock_context(
        new mock_compute_context);

    auto expected_sf =
        set_up_perform_inference(mock_model, mock_backend, mock_context,
                                 batch_size, num_of_rows, num_of_classes);

    // For perform inference,
    // we only want to test with is_bitmap_based set to true.
    auto data_itr = prepare_data_for_prediction(/* is_bitmap_based */ true,
      num_of_rows, num_of_classes);
    auto result = mock_model.get_inference_result(data_itr.get());
    _assert_sframe_equals(result, expected_sf);
    // make sure the output is what expected
  }
}

/* ============================= predict ================================*/

BOOST_AUTO_TEST_CASE(test_drawing_classifier_predict_rank) {
  log_for_debug("test_drawing_classifier_predict_rank");

  for (auto& entry : TEST_CASES) {
    size_t batch_size = std::get<0>(entry);
    size_t num_of_rows = std::get<1>(entry);
    size_t num_of_classes = std::get<2>(entry);

    auto runner = [](test_drawing_classifier& mock_model, gl_sframe my_data,
                     gl_sframe expected) {
      auto result_class = mock_model.predict(my_data, "class");

      TS_ASSERT_EQUALS(result_class.size(), expected.size());

      for (size_t ii = 0; ii < result_class.size(); ++ii) {
        flex_vec probs = expected[PRED_NAME][ii];
        TS_ASSERT_EQUALS(result_class[ii].get_type(), flex_type_enum::STRING);

        size_t label_idx = std::stoi(result_class[ii].to<flex_string>());
        auto expected_idx =
            std::max_element(probs.begin(), probs.end()) - probs.begin();
        TS_ASSERT_EQUALS(label_idx, expected_idx);
      }
    };

    for (bool is_bitmap_based : {true, false}) {
      prediction_test_driver(batch_size, num_of_rows, num_of_classes, runner,
                             is_bitmap_based);
    }
  }
}

BOOST_AUTO_TEST_CASE(test_drawing_classifier_predict_prob_vec) {
  log_for_debug("test_drawing_classifier_predict_prob_vec");

  for (auto& entry : TEST_CASES) {
    size_t batch_size = std::get<0>(entry);
    size_t num_of_rows = std::get<1>(entry);
    size_t num_of_classes = std::get<2>(entry);

    auto runner = [](test_drawing_classifier& mock_model, gl_sframe my_data,
                     gl_sframe expected) {
      auto result_prob = mock_model.predict(my_data, "probability_vector");

      TS_ASSERT_EQUALS(result_prob.size(), expected[PRED_NAME].size());
      _assert_sframe_equals(gl_sframe({{PRED_NAME, result_prob}}), expected);
    };

    for (bool is_bitmap_based : {true, false}) {
      prediction_test_driver(batch_size, num_of_rows, num_of_classes, runner,
                             is_bitmap_based);
    }
  }
}

BOOST_AUTO_TEST_CASE(test_drawing_classifier_predict_prob) {
  log_for_debug("test_drawing_classifier_predict_prob");

  for (auto& entry : TEST_CASES) {
    size_t batch_size = std::get<0>(entry);
    size_t num_of_rows = std::get<1>(entry);
    size_t num_of_classes = std::get<2>(entry);

    auto runner = [&num_of_classes](test_drawing_classifier& mock_model,
                                    gl_sframe my_data, gl_sframe expected) {
      if (num_of_classes > 2) {
        TS_ASSERT_THROWS_ANYTHING(mock_model.predict(my_data, "probability"));

      } else {
        auto result_prob = mock_model.predict(my_data, "probability");

        for (size_t ii = 0; ii < result_prob.size(); ++ii) {
          flex_float expected_prob =
              expected[PRED_NAME][ii][num_of_classes - 1];
          TS_ASSERT_EQUALS(result_prob[ii].get_type(), flex_type_enum::FLOAT);
          TS_ASSERT_EQUALS(expected_prob, result_prob[ii]);
        }
        TS_ASSERT_EQUALS(result_prob.size(), expected[PRED_NAME].size());
      }
    };

    for (bool is_bitmap_based : {true, false}) {
      prediction_test_driver(batch_size, num_of_rows, num_of_classes, runner,
                             is_bitmap_based);
    }
  }
}

/* ========================= predict top k ============================*/

namespace {

void verify_topk_result(size_t kk, size_t num_of_classes, size_t num_of_rows,
                        gl_sframe result, gl_sframe expected) {
  bool test_rank = result.contains_column("rank");

  std::vector<unsigned> idx_vec;
  if (test_rank) idx_vec.resize(num_of_classes);
  flex_vec output(kk);

  for (size_t ii = 0; ii < num_of_rows; ++ii) {
    flex_vec prob_vec = expected[PRED_NAME][ii];

    size_t idx_beg = ii * kk;

    if (test_rank) {
      // reset for each iteration
      std::iota(idx_vec.begin(), idx_vec.end(), 0);

      auto compare = [&](size_t i, size_t j) {
        return prob_vec[i] > prob_vec[j];
      };

      std::sort(idx_vec.begin(), idx_vec.end(), compare);

      // using rank
      for (size_t jj = 0; jj < kk; ++jj) {
        output[jj] = prob_vec[result["rank"][idx_beg + jj]];
      }
    } else {
      // test probability
      for (size_t jj = 0; jj < kk; ++jj) {
        output[jj] = result["probability"][idx_beg + jj];
      }
    }

    auto prob_vec_sorted = prob_vec;
    std::sort(prob_vec_sorted.begin(), prob_vec_sorted.end(),
              std::greater<double>());

    TS_ASSERT(std::equal(prob_vec_sorted.begin(), prob_vec_sorted.begin(),
                         output.begin()));

    // label is stringized sequence [0, num_of_classes)
    auto get_index_of_label = [](const std::string& label) {
      return std::stoi(label);
    };

    for (size_t jj = 0; jj < kk; ++jj) {
      output[jj] = prob_vec[get_index_of_label(
          result["class"][idx_beg + jj].get<flex_string>())];
    }

    TS_ASSERT(std::equal(prob_vec_sorted.begin(), prob_vec_sorted.begin(),
                         output.begin()));
  }
};

}  // namespace

BOOST_AUTO_TEST_CASE(test_drawing_classifier_predict_topk_rank_zero_k) {
  log_for_debug("test_drawing_classifier_predict_topk_rank_zero_k");

  size_t batch_size = 2;
  size_t num_of_rows = 1;
  size_t num_of_classes = 2;

  size_t kk = 0;
  auto runner = [=](test_drawing_classifier& mock_model, gl_sframe my_data,
                    gl_sframe expected) {
    auto result_rank = mock_model.predict_topk(my_data, "rank", kk);

    TS_ASSERT_EQUALS(result_rank.size(), num_of_rows);
    TS_ASSERT_EQUALS(result_rank["rank"].size(), expected[PRED_NAME].size());
    // stack empty list will return undefined value
    TS_ASSERT_EQUALS(result_rank["rank"][0].get_type(),
                     flex_type_enum::UNDEFINED);
  };

  for (bool is_bitmap_based : {true, false}) {
    prediction_test_driver(batch_size, num_of_rows, num_of_classes, runner,
                           is_bitmap_based);
  }
}

BOOST_AUTO_TEST_CASE(test_drawing_classifier_predict_topk_rank_normal_k) {
  log_for_debug("test_drawing_classifier_predict_topk_rank_normal_k");

  for (auto& entry : TEST_CASES) {
    size_t batch_size = std::get<0>(entry);
    size_t num_of_rows = std::get<1>(entry);
    size_t num_of_classes = std::get<2>(entry);

    if (num_of_classes == 0) continue;

    size_t kk = num_of_classes > 1 ? num_of_classes - 1 : 1;

    auto runner = [=](test_drawing_classifier& mock_model, gl_sframe my_data,
                      gl_sframe expected) {
      auto result_rank = mock_model.predict_topk(my_data, "rank", kk);

      TS_ASSERT_EQUALS(result_rank.size(), num_of_rows * kk);
      TS_ASSERT_EQUALS(result_rank["rank"].size() / kk,
                       expected[PRED_NAME].size());
      // label should be string type
      TS_ASSERT_EQUALS(result_rank["rank"][0].get_type(),
                       flex_type_enum::INTEGER);
      TS_ASSERT_EQUALS(result_rank["class"][0].get_type(),
                       flex_type_enum::STRING);

      verify_topk_result(kk, num_of_classes, num_of_rows, result_rank,
                         expected);
    };

    for (bool is_bitmap_based : {true, false}) {
      prediction_test_driver(batch_size, num_of_rows, num_of_classes, runner,
                             is_bitmap_based);
    }
  }
}

BOOST_AUTO_TEST_CASE(test_drawing_classifier_predict_topk_rank_big_k) {
  log_for_debug("test_drawing_classifier_predict_topk_rank_big_k");

  for (auto& entry : TEST_CASES) {
    size_t batch_size = std::get<0>(entry);
    size_t num_of_rows = std::get<1>(entry);
    size_t num_of_classes = std::get<2>(entry);

    if (num_of_classes == 0) continue;

    size_t kk = num_of_classes + 1;

    auto runner = [=](test_drawing_classifier& mock_model, gl_sframe my_data,
                      gl_sframe expected) {
      auto result_rank = mock_model.predict_topk(my_data, "rank", kk);

      size_t realk = num_of_classes;
      TS_ASSERT_EQUALS(result_rank.size(), num_of_rows * realk);
      TS_ASSERT_EQUALS(result_rank["rank"].size() / realk,
                       expected[PRED_NAME].size());
      // label should be string type
      TS_ASSERT_EQUALS(result_rank["rank"][0].get_type(),
                       flex_type_enum::INTEGER);
      TS_ASSERT_EQUALS(result_rank["class"][0].get_type(),
                       flex_type_enum::STRING);

      verify_topk_result(realk, num_of_classes, num_of_rows, result_rank,
                         expected);
    };

    for (bool is_bitmap_based : {true, false}) {
      prediction_test_driver(batch_size, num_of_rows, num_of_classes, runner,
                             is_bitmap_based);
    }
  }
}

BOOST_AUTO_TEST_CASE(test_drawing_classifier_predict_topk_prob_zero_k) {
  log_for_debug("test_drawing_classifier_predict_topk_prob_zero_k");

  size_t batch_size = 2;
  size_t num_of_rows = 1;
  size_t num_of_classes = 2;

  size_t kk = 0;
  auto runner = [=](test_drawing_classifier& mock_model, gl_sframe my_data,
                    gl_sframe expected) {
    auto result_rank = mock_model.predict_topk(my_data, "probability", kk);

    TS_ASSERT_EQUALS(result_rank.size(), num_of_rows);
    TS_ASSERT_EQUALS(result_rank["probability"].size(),
                     expected[PRED_NAME].size());
    // stack empty list will return undefined value
    TS_ASSERT_EQUALS(result_rank["probability"][0].get_type(),
                     flex_type_enum::UNDEFINED);
  };

  for (bool is_bitmap_based : {true, false}) {
    prediction_test_driver(batch_size, num_of_rows, num_of_classes, runner,
                           is_bitmap_based);
  }
}

BOOST_AUTO_TEST_CASE(test_drawing_classifier_predict_topk_prob_normal_k) {
  log_for_debug("test_drawing_classifier_predict_topk_prob_normal_k");

  for (auto& entry : TEST_CASES) {
    size_t batch_size = std::get<0>(entry);
    size_t num_of_rows = std::get<1>(entry);
    size_t num_of_classes = std::get<2>(entry);

    if (num_of_classes == 0) continue;

    size_t kk = num_of_classes > 1 ? num_of_classes - 1 : 1;

    auto runner = [=](test_drawing_classifier& mock_model, gl_sframe my_data,
                      gl_sframe expected) {
      auto result_rank = mock_model.predict_topk(my_data, "probability", kk);

      TS_ASSERT_EQUALS(result_rank.size(), num_of_rows * kk);
      TS_ASSERT_EQUALS(result_rank["probability"].size() / kk,
                       expected[PRED_NAME].size());
      // label should be string type
      TS_ASSERT_EQUALS(result_rank["probability"][0].get_type(),
                       flex_type_enum::FLOAT);
      TS_ASSERT_EQUALS(result_rank["class"][0].get_type(),
                       flex_type_enum::STRING);

      verify_topk_result(kk, num_of_classes, num_of_rows, result_rank,
                         expected);
    };

    for (bool is_bitmap_based : {true, false}) {
      prediction_test_driver(batch_size, num_of_rows, num_of_classes, runner,
                             is_bitmap_based);
    }
  }
}

BOOST_AUTO_TEST_CASE(test_drawing_classifier_predict_topk_prob_big_k) {
  log_for_debug("test_drawing_classifier_predict_topk_prob_big_k");

  for (auto& entry : TEST_CASES) {
    size_t batch_size = std::get<0>(entry);
    size_t num_of_rows = std::get<1>(entry);
    size_t num_of_classes = std::get<2>(entry);

    if (num_of_classes == 0) continue;

    size_t kk = num_of_classes + 1;

    auto runner = [=](test_drawing_classifier& mock_model, gl_sframe my_data,
                      gl_sframe expected) {
      auto result_rank = mock_model.predict_topk(my_data, "probability", kk);

      size_t realk = num_of_classes;
      TS_ASSERT_EQUALS(result_rank.size(), num_of_rows * realk);
      TS_ASSERT_EQUALS(result_rank["probability"].size() / realk,
                       expected[PRED_NAME].size());
      // label should be string type
      TS_ASSERT_EQUALS(result_rank["probability"][0].get_type(),
                       flex_type_enum::FLOAT);
      TS_ASSERT_EQUALS(result_rank["class"][0].get_type(),
                       flex_type_enum::STRING);

      verify_topk_result(realk, num_of_classes, num_of_rows, result_rank,
                         expected);
    };

    for (bool is_bitmap_based : {true, false}) {
      prediction_test_driver(batch_size, num_of_rows, num_of_classes, runner,
                             is_bitmap_based);
    }
  }
}

}  // namespace drawing_classifier
}  // namespace turi

ext: cxx

max_stars_repo_name: pappasG/turicreate

max_issues_repo_name: pappasG/turicreate

max_forks_repo_name: pappasG/turicreate


text:
#include <fstream>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include "Info.hpp"

int main(int argc, char** argv) {
    Info info;
    info.AddFilename("ThisFile.txt");
    info.AddFilename("ThatFile.txt");
    info.AddFilename("OtherFile.txt");

    // Сохранить данные об именах файлов содержащиеся в объекте класса Info:
    {
      // Создать выходной архив:
      std::ofstream ofs("store.dat");
      boost::archive::text_oarchive ar(ofs);

      // Сохранить данные:
      ar & info;
    }

    // Восставление из сохраненных данных:
    Info restored_info;
    {
        // Создать входной архив:
        std::ifstream ifs("store.dat");
        boost::archive::text_iarchive ar(ifs);

        // Загрузить данные:
        ar & restored_info;
    }

    // Печать для верификации контента:
    restored_info.Print();

    return 0;
}

ext: cpp

max_stars_repo_name: gusenov/examples-boost

max_issues_repo_name: gusenov/examples-boost

max_forks_repo_name: gusenov/examples-boost


text:
/*
 * Copyright © 2012-2015 VMware, Inc.  All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the “License”); you may not
 * use this file except in compliance with the License.  You may obtain a copy
 * of the License at 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/python.hpp>

#include <boost/python/return_opaque_pointer.hpp>
#include <boost/python/def.hpp>
#include <boost/python/module.hpp>
#include <boost/python/return_value_policy.hpp>
#include <boost/python/enum.hpp>

#include <string>
#include <stdio.h>
#include <vmafd.h>
#include <afdclient.h>
using namespace boost::python;

PyObject *VMAFDExceptionType = NULL;

void translateVMAFDException(vmafd_exception const &e)
{
  assert(VMAFDExceptionType != NULL);
  boost::python::object pythonExceptionInstance(e);
  PyErr_SetObject(VMAFDExceptionType, pythonExceptionInstance.ptr());
}

BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(opaque_)

BOOST_PYTHON_MODULE(vmafd)
{
    class_<client>("client", init<std::string>())
        .def(init<>())
        .def("GetStatus",                &client::GetStatus)
        .def("GetDomainName",            &client::GetDomainName)
        .def("SetDomainName",            &client::SetDomainName)
        .def("GetDomainState",           &client::GetDomainState)
        .def("GetLDU",                   &client::GetLDU)
        .def("SetLDU",                   &client::SetLDU)
        .def("SetRHTTPProxyPort",        &client::SetRHTTPProxyPort)
        .def("SetDCPort",                &client::SetDCPort)
        .def("GetCMLocation",            &client::GetCMLocation)
        .def("GetLSLocation",            &client::GetLSLocation)
        .def("GetDCName" ,               &client::GetDCName)
        .def("SetDCName" ,               &client::SetDCName)
        .def("GetPNID",                  &client::GetPNID)
        .def("SetPNID",                  &client::SetPNID)
        .def("GetCAPath",                &client::GetCAPath)
        .def("SetCAPath",                &client::SetCAPath)
        .def("GetMachineName",           &client::GetMachineName)
        .def("GetMachinePassword",       &client::GetMachinePassword)
        .def("GetMachineCert",           &client::GetMachineCert)
        .def("GetMachinePrivateKey",     &client::GetMachinePrivateKey)
        .def("SetMachineCert",           &client::SetMachineCert)
        .def("SetMachineCertWithString", &client::SetMachineCertWithString)
        .def("GetSiteGUID",              &client::GetSiteGUID)
        .def("GetMachineID",             &client::GetMachineID)
        .def("SetMachineID",             &client::SetMachineID)
        .def("JoinDomain",               &client::JoinDomain)
        .def("CreateCertStore",          &client::CreateCertStore,
                                             return_value_policy<return_opaque_pointer>())
        .def("OpenCertStore",            &client::OpenCertStore,
                                             return_value_policy<return_opaque_pointer>())
        .def("CloseCertStore",           &client::CloseCertStore)
        .def("AddCert",                  &client::AddCert)
        .def("AddTrustedRoot",           &client::AddTrustedRoot)
        .def("GetCertByAlias",           &client::GetCertByAlias)
        .def("GetPrivateKeyByAlias",     &client::GetPrivateKeyByAlias)
        .def("GetEntryCount",            &client::GetEntryCount)
        .def("BeginEnumAliases",         &client::BeginEnumAliases,
                                             return_value_policy<return_opaque_pointer>())
        .def("EnumAliases",              &client::EnumAliases)
        .def("EndEnumAliases",           &client::EndEnumAliases)
        .def("DeleteCert",               &client::DeleteCert)
        .def("DeleteCertStore",          &client::DeleteCertStore)
    ;

    class_<vmafd_exception> vmafd_exceptionClass("vmafd_exception", boost::python::init<int>());

    vmafd_exceptionClass.add_property("message", &vmafd_exception::getMessage)
    .add_property("errorcode", &vmafd_exception::getErrorCode);

    VMAFDExceptionType = vmafd_exceptionClass.ptr();

    boost::python::register_exception_translator<vmafd_exception>
    (&translateVMAFDException);
}

max_stars_repo_name: slachiewicz/lightwave

max_issues_repo_name: slachiewicz/lightwave

max_forks_repo_name: slachiewicz/lightwave


text:
#include "manager.h"
#include "async_result.h"

#include <gtest/gtest.h>
#include <boost/algorithm/string/predicate.hpp>

namespace di = boost::di;

namespace {

using FactoryExecuter = di::extension::factory<Executer>;

template <typename TInjector>
struct FactoryGroupImpl : IFactoryGroup
{
    FactoryGroupImpl(const TInjector& i) : injector{const_cast<TInjector&>(i)} {}

    std::unique_ptr<IGroup> create(Ssid&& ssid) const override {
        auto groupSize = injector.template create<GroupSize>();
        auto factory = injector.template create<std::shared_ptr<IFactoryExecuter>>();
        return std::make_unique<Group>(std::move(ssid), groupSize, std::move(factory));
    }

    TInjector& injector;
};

struct FactoryGroup {
  template <class TInjector, class TDependency>
  std::shared_ptr<FactoryGroupImpl<TInjector>> operator()(const TInjector& injector, const TDependency&) const {
    return std::make_shared<FactoryGroupImpl<TInjector>>(injector);
  }
};

auto config = []() {
    return di::make_injector(
        di::bind<ILogger>.to<Logger>().in(di::singleton),

        di::bind<IFactoryExecuter>.to<>(FactoryExecuter{}),
        di::bind<IFactoryGroup>().to<>(FactoryGroup{}),

        di::bind<GroupSize>().to(GroupSize{2})
    );
};

} // Anonymous namespace

TEST(Product, _) {
    auto injector = di::make_injector(config());
    auto manager = injector.create<std::unique_ptr<Manager>>();

    IoContextWrapper ioContext;

    auto [promise1, future1] = AsyncResult::create(ioContext);
    auto handler1 = [p = promise1](const std::string& result) mutable {
        p(result);
    };
    manager->getExecuter(Ssid{"Cygnus"}).process("aSdFgH", handler1);

    auto [promise2, future2] = AsyncResult::create(ioContext);
    auto handler2 = [p = promise2](const std::string& result) mutable {
        p(result);
    };
    manager->getExecuter(Ssid{"Columba"}).process("AsDfGh", handler2);

    ioContext.run();
    manager->stopAll();

    std::string result1 = future1.get();
    std::string result2 = future2.get();

    EXPECT_TRUE(boost::algorithm::starts_with(result1, "AsDfGh"));
    EXPECT_TRUE(boost::algorithm::ends_with(result1, "[Cygnus-0]"));

    EXPECT_TRUE(boost::algorithm::starts_with(result2, "aSdFgH"));
    EXPECT_TRUE(boost::algorithm::ends_with(result2, "[Columba-0]"));
}

max_stars_repo_name: dvetutnev/boost-di-example

max_issues_repo_name: dvetutnev/boost-di-example

max_forks_repo_name: dvetutnev/boost-di-example


text:
//==================================================================================================
/*!
  @file

  @copyright 2016 NumScale SAS
  @copyright 2016 J.T. Lapreste

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#ifndef BOOST_SIMD_FUNCTION_SUBS_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_SUBS_HPP_INCLUDED

#if defined(DOXYGEN_ONLY)
namespace boost { namespace simd
{

 /*!

    @ingroup group-arithmetic
    Function object implementing subs capabilities

    Computes the saturated difference of its parameters.

    @par semantic:
    For any given value @c x,  @c y of type @c T:

    @code
    T r = subs(x, y);
    @endcode

    This function coincides with @ref minus for floating point parameters.
    For integral type, it is similar to:

    @code
    T r = (x-y > Valmax) ? Valmax : (x-y < Valmin ? Valmin : x-y);
    @endcode

  **/
  const boost::dispatch::functor<tag::subs_> subs = {};

} }
#endif

#include <boost/simd/function/scalar/subs.hpp>
#include <boost/simd/function/simd/subs.hpp>

#endif


text:
#define BOOST_TEST_MODULE "VariadicTemplateAlgorithms Tests"
#include <boost/test/unit_test.hpp>


text:
//
//  Copyright (C) 2013-2018 Greg Landrum
//
//   @@ All Rights Reserved @@
//  This file is part of the RDKit.
//  The contents are covered by the terms of the BSD license
//  which is included in the file license.txt, found at the root
//  of the RDKit source tree.
//

#include "MolFragmenter.h"
#include "ChemTransforms.h"
#include <RDGeneral/utils.h>
#include <RDGeneral/Invariant.h>
#include <RDGeneral/RDLog.h>
#include <RDGeneral/Exceptions.h>
#include <GraphMol/RDKitBase.h>
#include <boost/dynamic_bitset.hpp>
#include <boost/tokenizer.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/range/adaptor/reversed.hpp>
#include <cstdint>
#include <vector>
#include <algorithm>
#include <GraphMol/SmilesParse/SmilesParse.h>
#include <GraphMol/SmilesParse/SmilesWrite.h>
#include <GraphMol/Substruct/SubstructMatch.h>
#include <RDGeneral/StreamOps.h>

#include <RDGeneral/BoostStartInclude.h>
#include <boost/flyweight.hpp>
#include <boost/flyweight/no_tracking.hpp>
#include <boost/functional/hash.hpp>
#include <RDGeneral/BoostEndInclude.h>

#include <sstream>
#include <map>

namespace RDKit {
namespace MolFragmenter {
std::size_t hash_value(const FragmenterBondType &fbt) {
  size_t res = boost::hash<int>()((int)fbt.bondType);
  boost::hash_combine(res, fbt.atom1Label);
  boost::hash_combine(res, fbt.atom2Label);
  return res;
}
bool operator==(const FragmenterBondType &v1, const FragmenterBondType &v2) {
  return (v1.atom1Label == v2.atom1Label) && (v1.atom2Label == v2.atom2Label) &&
         (v1.bondType == v2.bondType);
}
void constructFragmenterAtomTypes(
    std::istream *inStream, std::map<unsigned int, std::string> &defs,
    const std::string &comment, bool validate,
    std::map<unsigned int, ROMOL_SPTR> *environs) {
  PRECONDITION(inStream, "no stream");
  defs.clear();
  unsigned int line = 0;
  while (!inStream->eof() && !inStream->fail()) {
    ++line;
    std::string tempStr = getLine(inStream);
    if (tempStr == "" || tempStr.find(comment) == 0) {
      continue;
    }
    std::vector<std::string> tokens;
    boost::split(tokens, tempStr, boost::is_any_of(" \t"),
                 boost::token_compress_on);
    if (tokens.size() < 2) {
      BOOST_LOG(rdWarningLog)
          << "line " << line << " is too short" << std::endl;
      continue;
    }
    auto idx = boost::lexical_cast<unsigned int>(tokens[0]);
    if (defs.find(idx) != defs.end()) {
      BOOST_LOG(rdWarningLog)
          << "definition #" << idx
          << " encountered more than once. Using the first occurrence."
          << std::endl;
      continue;
    }
    if (validate || environs) {
      ROMol *p = SmartsToMol(tokens[1]);
      if (!p) {
        BOOST_LOG(rdWarningLog) << "cannot convert SMARTS " << tokens[1]
                                << " to molecule at line " << line << std::endl;
        continue;
      }
      if (!environs) {
        delete p;
      } else {
        (*environs)[idx] = ROMOL_SPTR(p);
      }
    }
    defs[idx] = tokens[1];
  }
}
void constructFragmenterAtomTypes(
    const std::string &str, std::map<unsigned int, std::string> &defs,
    const std::string &comment, bool validate,
    std::map<unsigned int, ROMOL_SPTR> *environs) {
  std::stringstream istr(str);
  constructFragmenterAtomTypes(&istr, defs, comment, validate, environs);
}
void constructBRICSAtomTypes(std::map<unsigned int, std::string> &defs,
                             std::map<unsigned int, ROMOL_SPTR> *environs) {
  /*
     After some discussion, the L2 definitions ("N.pl3" in the original
     paper) have been removed and incorporated into a (almost) general
     purpose amine definition in L5 ("N.sp3" in the paper).

     The problem is one of consistency.
        Based on the original definitions you should get the following
        fragmentations:
          C1CCCCC1NC(=O)C -> C1CCCCC1N[2*].[1*]C(=O)C
          c1ccccc1NC(=O)C -> c1ccccc1[16*].[2*]N[2*].[1*]C(=O)C
        This difference just didn't make sense to us. By switching to
        the unified definition we end up with:
          C1CCCCC1NC(=O)C -> C1CCCCC1[15*].[5*]N[5*].[1*]C(=O)C
          c1ccccc1NC(=O)C -> c1ccccc1[16*].[5*]N[5*].[1*]C(=O)C
  */
  const std::string BRICSdefs =
      "1 [C;D3]([#0,#6,#7,#8])(=O)\n\
3 [O;D2]-;!@[#0,#6,#1]\n\
5 [N;!D1;!$(N=*);!$(N-[!#6;!#16;!#0;!#1]);!$([N;R]@[C;R]=O)]\n\
9 [n;+0;$(n(:[c,n,o,s]):[c,n,o,s])]\n\
10 [N;R;$(N(@C(=O))@[C,N,O,S])]\n\
11 [S;D2](-;!@[#0,#6])\n\
12 [S;D4]([#6,#0])(=O)(=O)\n\
6 [C;D3;!R](=O)-;!@[#0,#6,#7,#8]\n\
13 [C;$(C(-;@[C,N,O,S])-;@[N,O,S])]\n\
14 [c;$(c(:[c,n,o,s]):[n,o,s])]\n\
15 [C;$(C(-;@C)-;@C)]\n\
4 [C;!D1;!$(C=*)]-;!@[#6]\n\
7 [C;D2,D3]-[#6]\n\
8 [C;!R;!D1;!$(C!-*)]\n\
16 [c;$(c(:c):c)]";
  constructFragmenterAtomTypes(BRICSdefs, defs, "//", true, environs);
}

void constructFragmenterBondTypes(
    std::istream *inStream,
    const std::map<unsigned int, std::string> &atomTypes,
    std::vector<FragmenterBondType> &defs, const std::string &comment,
    bool validate, bool labelByConnector) {
  PRECONDITION(inStream, "no stream");
  defs.clear();
  defs.resize(0);

  unsigned int line = 0;
  while (!inStream->eof() && !inStream->fail()) {
    ++line;
    std::string tempStr = getLine(inStream);
    if (tempStr == "" || tempStr.find(comment) == 0) {
      continue;
    }
    std::vector<std::string> tokens;
    boost::split(tokens, tempStr, boost::is_any_of(" \t"),
                 boost::token_compress_on);
    if (tokens.size() < 3) {
      BOOST_LOG(rdWarningLog)
          << "line " << line << " is too short" << std::endl;
      continue;
    }
    auto idx1 = boost::lexical_cast<unsigned int>(tokens[0]);
    if (atomTypes.find(idx1) == atomTypes.end()) {
      BOOST_LOG(rdWarningLog)
          << "atom type #" << idx1 << " not recognized." << std::endl;
      continue;
    }
    auto idx2 = boost::lexical_cast<unsigned int>(tokens[1]);
    if (atomTypes.find(idx2) == atomTypes.end()) {
      BOOST_LOG(rdWarningLog)
          << "atom type #" << idx2 << " not recognized." << std::endl;
      continue;
    }
    std::string sma1 = atomTypes.find(idx1)->second;
    std::string sma2 = atomTypes.find(idx2)->second;
    std::string smarts = "[$(" + sma1 + ")]" + tokens[2] + "[$(" + sma2 + ")]";
    ROMol *p = SmartsToMol(smarts);
    if (validate) {
      if (!p) {
        BOOST_LOG(rdWarningLog) << "cannot convert SMARTS " << smarts
                                << " to molecule at line " << line << std::endl;
        continue;
      }
    }
    FragmenterBondType fbt;
    fbt.atom1Type = idx1;
    fbt.atom2Type = idx2;
    if (labelByConnector) {
      fbt.atom1Label = idx1;
      fbt.atom2Label = idx2;
    } else {
      fbt.atom1Label = idx2;
      fbt.atom2Label = idx1;
    }
    if (p) {
      // for the purposes of replacing the bond, we'll use just the first
      // character to set the bond type (if we recognize it):
      switch (tokens[2][0]) {
        case '-':
          fbt.bondType = Bond::SINGLE;
          break;
        case '=':
          fbt.bondType = Bond::DOUBLE;
          break;
        case '#':
          fbt.bondType = Bond::TRIPLE;
          break;
        case ':':
          fbt.bondType = Bond::AROMATIC;
          break;
        default:
          fbt.bondType = p->getBondWithIdx(0)->getBondType();
      }
      fbt.query = ROMOL_SPTR(p);
    } else {
      fbt.bondType = Bond::UNSPECIFIED;
      fbt.query = ROMOL_SPTR();
    }
    defs.push_back(fbt);
  }
}

void constructFragmenterBondTypes(
    const std::string &str,
    const std::map<unsigned int, std::string> &atomTypes,
    std::vector<FragmenterBondType> &defs, const std::string &comment,
    bool validate, bool labelByConnector) {
  std::stringstream istr(str);
  constructFragmenterBondTypes(&istr, atomTypes, defs, comment, validate,
                               labelByConnector);
}
void constructBRICSBondTypes(std::vector<FragmenterBondType> &defs) {
  const std::string BRICSdefs =
      "// L1\n\
1 3 -;!@\n\
1 5 -;!@\n\
1 10 -;!@\n\
// L3 \n\
3 4 -;!@\n\
3 13 -;!@\n\
3 14 -;!@\n\
3 15 -;!@\n\
3 16 -;!@\n\
// L4\n\
4 5 -;!@\n\
4 11 -;!@\n\
// L5\n\
5 12 -;!@\n\
5 14 -;!@\n\
5 16 -;!@\n\
5 13 -;!@\n\
5 15 -;!@\n\
// L6\n\
6 13 -;!@\n\
6 14 -;!@\n\
6 15 -;!@\n\
6 16 -;!@\n\
// L7\n\
7 7 =;!@\n\
// L8\n\
8 9 -;!@\n\
8 10 -;!@\n\
8 13 -;!@\n\
8 14 -;!@\n\
8 15 -;!@\n\
8 16 -;!@\n\
// L9\n\
9 13 -;!@ // not in original paper\n\
9 14 -;!@ // not in original paper\n\
9 15 -;!@\n\
9 16 -;!@\n\
// L10\n\
10 13 -;!@\n\
10 14 -;!@\n\
10 15 -;!@\n\
10 16 -;!@\n\
// L11\n\
11 13 -;!@\n\
11 14 -;!@\n\
11 15 -;!@\n\
11 16 -;!@\n\
// L12\n\
// none left\n\
// L13\n\
13 14 -;!@\n\
13 15 -;!@\n\
13 16 -;!@\n\
// L14\n\
14 14 -;!@ // not in original paper\n\
14 15 -;!@\n\
14 16 -;!@\n\
// L15\n\
15 16 -;!@\n\
// L16\n\
16 16 -;!@ // not in original paper";
  std::map<unsigned int, std::string> atTypes;
  constructBRICSAtomTypes(atTypes);
  constructFragmenterBondTypes(BRICSdefs, atTypes, defs, "//", true, false);
}

namespace {
boost::uint64_t nextBitCombo(boost::uint64_t v) {
  // code from:
  // http://graphics.stanford.edu/~seander/bithacks.html#NextBitPermutation
  boost::uint64_t t = (v | (v - 1)) + 1;
  return t | ((((t & -t) / (v & -v)) >> 1) - 1);
}
}  // namespace

void fragmentOnSomeBonds(
    const ROMol &mol, const std::vector<unsigned int> &bondIndices,
    std::vector<ROMOL_SPTR> &resMols, unsigned int maxToCut, bool addDummies,
    const std::vector<std::pair<unsigned int, unsigned int>> *dummyLabels,
    const std::vector<Bond::BondType> *bondTypes,
    std::vector<std::vector<unsigned int>> *nCutsPerAtom) {
  PRECONDITION((!dummyLabels || dummyLabels->size() == bondIndices.size()),
               "bad dummyLabel vector");
  PRECONDITION((!bondTypes || bondTypes->size() == bondIndices.size()),
               "bad bondType vector");
  if (bondIndices.size() > 63) {
    throw ValueErrorException("currently can only fragment on up to 63 bonds");
  }
  if (!maxToCut || !mol.getNumAtoms() || !bondIndices.size()) {
    return;
  }

  boost::uint64_t state = (0x1L << maxToCut) - 1;
  boost::uint64_t stop = 0x1L << bondIndices.size();
  std::vector<unsigned int> fragmentHere(maxToCut);
  std::vector<std::pair<unsigned int, unsigned int>> *dummyLabelsHere = nullptr;
  if (dummyLabels) {
    dummyLabelsHere =
        new std::vector<std::pair<unsigned int, unsigned int>>(maxToCut);
  }
  std::vector<Bond::BondType> *bondTypesHere = nullptr;
  if (bondTypes) {
    bondTypesHere = new std::vector<Bond::BondType>(maxToCut);
  }
  while (state < stop) {
    unsigned int nSeen = 0;
    for (unsigned int i = 0; i < bondIndices.size() && nSeen < maxToCut; ++i) {
      if (state & (0x1L << i)) {
        fragmentHere[nSeen] = bondIndices[i];
        if (dummyLabelsHere) {
          (*dummyLabelsHere)[nSeen] = (*dummyLabels)[i];
        }
        if (bondTypesHere) {
          (*bondTypesHere)[nSeen] = (*bondTypes)[i];
        }
        ++nSeen;
      }
    }
    std::vector<unsigned int> *lCutsPerAtom = nullptr;
    if (nCutsPerAtom) {
      nCutsPerAtom->push_back(std::vector<unsigned int>(mol.getNumAtoms()));
      lCutsPerAtom = &(nCutsPerAtom->back());
    }
    ROMol *nm = fragmentOnBonds(mol, fragmentHere, addDummies, dummyLabelsHere,
                                bondTypesHere, lCutsPerAtom);
    resMols.emplace_back(nm);

    state = nextBitCombo(state);
  }
  delete dummyLabelsHere;
  delete bondTypesHere;
}

namespace {
void checkChiralityPostMove(const ROMol &mol, const Atom *oAt, Atom *nAt,
                            const Bond *bond) {
  static const std::string newBondOrder = "_newBondOrder";
  INT_LIST newOrder;
  INT_LIST incomingOrder;

  const int check_bond_index = static_cast<int>(bond->getIdx());
  // since we may call this function more than once, we need to keep track of
  // whether or not we've already been called and what the new atom order is.
  // we do this with a property.
  // this was github #1734
  if (nAt->getPropIfPresent(newBondOrder, incomingOrder)) {
    for (int bidx : incomingOrder) {
      if (bidx != check_bond_index) {
        newOrder.push_back(bidx);
      }
    }
  } else {
    ROMol::OEDGE_ITER beg, end;
    boost::tie(beg, end) = mol.getAtomBonds(oAt);
    while (beg != end) {
      const Bond *obond = mol[*beg];
      ++beg;
      if (obond == bond) {
        continue;
      }
      newOrder.push_back(obond->getIdx());
    }
  }
  newOrder.push_back(bond->getIdx());
  nAt->setProp(newBondOrder, newOrder, true);
  unsigned int nSwaps = oAt->getPerturbationOrder(newOrder);
  // std::copy(newOrder.begin(), newOrder.end(),
  //           std::ostream_iterator<int>(std::cerr, ", "));
  // std::cerr << std::endl;
  // std::cerr<<"ccpm: "<<oAt->getIdx()<<"->"<<nAt->getIdx()<<" bond:
  // "<<bond->getIdx()<<" swaps: "<<nSwaps<<std::endl;
  nAt->setChiralTag(oAt->getChiralTag());
  if (nSwaps % 2) {
    nAt->invertChirality();
  }
}

std::vector<std::pair<Bond *, std::vector<int>>> getNbrBondStereo(
    RWMol &mol, const Bond *bnd) {
  PRECONDITION(bnd, "null bond");
  // loop over neighboring double bonds and remove their stereo atom
  std::vector<std::pair<Bond *, std::vector<int>>> res;
  const auto bgn = bnd->getBeginAtom();
  const auto end = bnd->getEndAtom();
  for (const auto *atom : {bgn, end}) {
    ROMol::OEDGE_ITER a1, a2;
    for (boost::tie(a1, a2) = mol.getAtomBonds(atom); a1 != a2; ++a1) {
      Bond *obnd = mol[*a1];
      if (obnd->getIdx() != bnd->getIdx() && !obnd->getStereoAtoms().empty()) {
        res.emplace_back(obnd, obnd->getStereoAtoms());
      }
    }
  }
  return res;
}
}  // namespace

ROMol *fragmentOnBonds(
    const ROMol &mol, const std::vector<unsigned int> &bondIndices,
    bool addDummies,
    const std::vector<std::pair<unsigned int, unsigned int>> *dummyLabels,
    const std::vector<Bond::BondType> *bondTypes,
    std::vector<unsigned int> *nCutsPerAtom) {
  PRECONDITION((!dummyLabels || dummyLabels->size() == bondIndices.size()),
               "bad dummyLabel vector");
  PRECONDITION((!bondTypes || bondTypes->size() == bondIndices.size()),
               "bad bondType vector");
  PRECONDITION((!nCutsPerAtom || nCutsPerAtom->size() == mol.getNumAtoms()),
               "bad nCutsPerAtom vector");
  if (nCutsPerAtom) {
    for (auto &nCuts : *nCutsPerAtom) {
      nCuts = 0;
    }
  }
  auto *res = new RWMol(mol);
  if (!mol.getNumAtoms()) {
    return res;
  }

  std::vector<Bond *> bondsToRemove;
  bondsToRemove.reserve(bondIndices.size());
  for (auto bondIdx : bondIndices) {
    bondsToRemove.push_back(res->getBondWithIdx(bondIdx));
  }
  for (unsigned int i = 0; i < bondsToRemove.size(); ++i) {
    const Bond *bond = bondsToRemove[i];
    unsigned int bidx = bond->getBeginAtomIdx();
    unsigned int eidx = bond->getEndAtomIdx();
    Bond::BondType bT = bond->getBondType();
    Bond::BondDir bD = bond->getBondDir();
    unsigned int bondidx;
    auto nbr_bond_stereo = getNbrBondStereo(*res, bond);
    res->removeBond(bidx, eidx);
    if (nCutsPerAtom) {
      (*nCutsPerAtom)[bidx] += 1;
      (*nCutsPerAtom)[eidx] += 1;
    }
    if (addDummies) {
      Atom *at1, *at2;
      at1 = new Atom(0);
      at2 = new Atom(0);
      if (dummyLabels) {
        at1->setIsotope((*dummyLabels)[i].first);
        at2->setIsotope((*dummyLabels)[i].second);
      } else {
        at1->setIsotope(bidx);
        at2->setIsotope(eidx);
      }
      unsigned int idx1 = res->addAtom(at1, false, true);
      if (bondTypes) {
        bT = (*bondTypes)[i];
      }
      bondidx = res->addBond(at1->getIdx(), eidx, bT) - 1;
      // the dummy replaces the original start atom, so the
      // direction will be ok as long as it's one of the
      // states associated with double bond stereo
      if (bD == Bond::ENDDOWNRIGHT || bD == Bond::ENDUPRIGHT) {
        res->getBondWithIdx(bondidx)->setBondDir(bD);
      }

      unsigned int idx2 = res->addAtom(at2, false, true);
      bondidx = res->addBond(bidx, at2->getIdx(), bT) - 1;
      // this bond starts at the same atom, so its direction should always be
      // correct:
      res->getBondWithIdx(bondidx)->setBondDir(bD);

      // restore stereo atoms
      for (auto &stereo_atoms : nbr_bond_stereo) {
        std::replace(stereo_atoms.second.begin(), stereo_atoms.second.end(),
                     bidx, idx1);
        std::replace(stereo_atoms.second.begin(), stereo_atoms.second.end(),
                     eidx, idx2);
        stereo_atoms.first->getStereoAtoms().swap(stereo_atoms.second);
      }

      // figure out if we need to change the stereo tags on the atoms:
      if (mol.getAtomWithIdx(bidx)->getChiralTag() ==
              Atom::CHI_TETRAHEDRAL_CCW ||
          mol.getAtomWithIdx(bidx)->getChiralTag() ==
              Atom::CHI_TETRAHEDRAL_CW) {
        checkChiralityPostMove(mol, mol.getAtomWithIdx(bidx),
                               res->getAtomWithIdx(bidx),
                               mol.getBondBetweenAtoms(bidx, eidx));
      }
      if (mol.getAtomWithIdx(eidx)->getChiralTag() ==
              Atom::CHI_TETRAHEDRAL_CCW ||
          mol.getAtomWithIdx(eidx)->getChiralTag() ==
              Atom::CHI_TETRAHEDRAL_CW) {
        checkChiralityPostMove(mol, mol.getAtomWithIdx(eidx),
                               res->getAtomWithIdx(eidx),
                               mol.getBondBetweenAtoms(bidx, eidx));
      }

      for (auto confIt = res->beginConformers(); confIt != res->endConformers();
           ++confIt) {
        Conformer *conf = (*confIt).get();
        conf->setAtomPos(idx1, conf->getAtomPos(bidx));
        conf->setAtomPos(idx2, conf->getAtomPos(eidx));
      }
    } else {
      // was github issue 429
      Atom *tatom = res->getAtomWithIdx(bidx);
      if (tatom->getIsAromatic() && tatom->getAtomicNum() != 6) {
        tatom->setNumExplicitHs(tatom->getNumExplicitHs() + 1);
      }
      tatom = res->getAtomWithIdx(eidx);
      if (tatom->getIsAromatic() && tatom->getAtomicNum() != 6) {
        tatom->setNumExplicitHs(tatom->getNumExplicitHs() + 1);
      }
    }
  }
  res->clearComputedProps();
  return static_cast<ROMol *>(res);
}

ROMol *fragmentOnBonds(const ROMol &mol,
                       const std::vector<FragmenterBondType> &bondPatterns,
                       const std::map<unsigned int, ROMOL_SPTR> *atomEnvirons,
                       std::vector<unsigned int> *nCutsPerAtom) {
  PRECONDITION((!nCutsPerAtom || nCutsPerAtom->size() == mol.getNumAtoms()),
               "bad nCutsPerAtom vector");
  std::vector<unsigned int> bondIndices;
  std::vector<std::pair<unsigned int, unsigned int>> dummyLabels;
  std::vector<Bond::BondType> bondTypes;

  std::map<unsigned int, bool> environsMatch;
  if (atomEnvirons) {
    for (const auto &atomEnviron : *atomEnvirons) {
      MatchVectType mv;
      environsMatch[atomEnviron.first] =
          SubstructMatch(mol, *(atomEnviron.second), mv);
    }
  }

  boost::dynamic_bitset<> bondsUsed(mol.getNumBonds(), 0);
  // the bond definitions are organized (more or less) general -> specific, so
  // loop over them backwards
  for (const auto &fbt : boost::adaptors::reverse(bondPatterns)) {
    if (fbt.query->getNumAtoms() != 2 || fbt.query->getNumBonds() != 1) {
      BOOST_LOG(rdErrorLog)
          << "fragmentation queries must have 2 atoms and 1 bond" << std::endl;
      continue;
    }
    if (atomEnvirons &&
        (!environsMatch[fbt.atom1Type] || !environsMatch[fbt.atom2Type])) {
      continue;
    }
    // std::cerr<<"  >>> "<<fbt.atom1Label<<" "<<fbt.atom2Label<<std::endl;
    std::vector<MatchVectType> bondMatches;
    SubstructMatch(mol, *fbt.query.get(), bondMatches);
    for (const auto &mv : bondMatches) {
      const Bond *bond = mol.getBondBetweenAtoms(mv[0].second, mv[1].second);
      // std::cerr<<"          "<<bond->getIdx()<<std::endl;
      TEST_ASSERT(bond);
      if (bondsUsed[bond->getIdx()]) {
        // BOOST_LOG(rdWarningLog)<<"bond #"<<bond->getIdx()<<" matched multiple
        // times in decomposition. Later matches ignored."<<std::endl;
        continue;
      }
      bondsUsed.set(bond->getIdx());
      bondIndices.push_back(bond->getIdx());
      if (bond->getBeginAtomIdx() == static_cast<unsigned int>(mv[0].second)) {
        dummyLabels.emplace_back(fbt.atom1Label, fbt.atom2Label);
      } else {
        dummyLabels.emplace_back(fbt.atom2Label, fbt.atom1Label);
      }
      bondTypes.push_back(fbt.bondType);
    }
  }
  return fragmentOnBonds(mol, bondIndices, true, &dummyLabels, &bondTypes,
                         nCutsPerAtom);
}

boost::flyweight<std::vector<FragmenterBondType>,
                 boost::flyweights::no_tracking>
    bondPatterns;
boost::flyweight<std::map<unsigned int, ROMOL_SPTR>,
                 boost::flyweights::no_tracking>
    atomEnvs;
ROMol *fragmentOnBRICSBonds(const ROMol &mol) {
  if (bondPatterns.get().size() == 0) {
    std::map<unsigned int, std::string> adefs;
    std::map<unsigned int, ROMOL_SPTR> aenvs;
    constructBRICSAtomTypes(adefs, &aenvs);
    atomEnvs = aenvs;
    std::vector<FragmenterBondType> tbondPatterns;
    constructBRICSBondTypes(tbondPatterns);
    bondPatterns = tbondPatterns;
  }
  return fragmentOnBonds(mol, bondPatterns, &(atomEnvs.get()));
}
}  // namespace MolFragmenter

namespace {
const unsigned int NOLABEL = std::numeric_limits<unsigned int>::max();
// Get the atom label - this might be useful as a util class
unsigned int get_label(const Atom *a, const MolzipParams &p) {
  PRECONDITION(a, "bad atom in MolZip::get_label")
  unsigned int idx = NOLABEL;
  switch (p.label) {
    case MolzipLabel::AtomMapNumber:
      if (a->getAtomicNum() == 0) {
        auto mapno = a->getAtomMapNum();
        return mapno ? mapno : NOLABEL;
      }
      break;
    case MolzipLabel::Isotope:
      if (a->getAtomicNum() == 0) {
        auto iso = a->getIsotope();
        return iso ? iso : NOLABEL;
      }
      break;
    case MolzipLabel::AtomType: {
      idx = std::distance(p.atomSymbols.begin(),
                          std::find(p.atomSymbols.begin(), p.atomSymbols.end(),
                                    a->getSymbol()));
      if (idx == p.atomSymbols.size()) {
        idx = NOLABEL;
      }
      break;
      case MolzipLabel::FragmentOnBonds:
        // shouldn't ever get here
        CHECK_INVARIANT(
            0, "FragmentOnBonds is not an atom label, it is an atom index");
        break;
      default:
        CHECK_INVARIANT(0, "bogus MolZipLabel value in MolZip::get_label");
    }
  }
  return idx;
}

// Return the connected atom
//  n.b. There can be only one connection from a mapped atom
Atom *get_other_atom(Atom *a) {
  PRECONDITION(a, "null atom in MolZip::get_other_atom");
  auto &m = a->getOwningMol();
  if (m.getAtomDegree(a) != 1) {
    return nullptr;
  }

  return m[*m.getAtomNeighbors(a).first];
}

int num_swaps_to_interconvert(std::vector<unsigned int> &orders) {
  int nswaps = 0;
  std::vector<bool> seen(orders.size());
  for (size_t i = 0; i < orders.size(); ++i) {
    if (!seen[i]) {
      auto j = i;
      while (orders[j] != i) {
        j = orders[j];
        seen[j] = true;
        nswaps++;
      }
    }
  }
  return nswaps;
}

// Simple bookkeeping class to bond attachments and handle stereo
struct ZipBond {
  Atom *a;        // atom being bonded
  Atom *a_dummy;  // Labelled atom, i.e. [*:1]-C  will bond the C to something
  Atom *b;        // atom being bonded
  Atom *b_dummy;  // Labelled atom, i.e. [*:1]-O will bond the O to something

  // Backup the original chirality mark_chirality must be called first
  //  as it checks the datastructure for validity;
  void mark_chirality() const {
    PRECONDITION(a, "Must have a begin atom to bond");
    PRECONDITION(b, "Must have an end atom to bond");
    PRECONDITION(a_dummy, "Must have a begin dummy atom");
    PRECONDITION(b_dummy, "Must have an end dummy atom");

    mark(a, a_dummy, b);
    mark(b, b_dummy, a);
  }

  // bond a<->b for now only use single bonds
  //  XXX FIX ME take the highest bond order.
  bool bond(RWMol &newmol) const {
    if (!a || !b || !a_dummy || !b_dummy) {
      BOOST_LOG(rdWarningLog)
          << "Incomplete atom labelling, cannot make bond" << std::endl;
      return false;
    }
    if (!a->getOwningMol().getBondBetweenAtoms(a->getIdx(), b->getIdx())) {
      CHECK_INVARIANT(&a->getOwningMol() == &newmol,
                      "Owning mol is not the combined molecule!!");
      auto bnd = newmol.getBondBetweenAtoms(a->getIdx(), a_dummy->getIdx());
      CHECK_INVARIANT(bnd != nullptr,
                      "molzip: begin atom and specified dummy atom connection "
                      "are not bonded.")
      auto bond_type_a = bnd->getBondType();
      bnd = newmol.getBondBetweenAtoms(b->getIdx(), b_dummy->getIdx());
      CHECK_INVARIANT(bnd != nullptr,
                      "molzip: end atom and specified dummy connection atom "
                      "are not bonded.")
      auto bond_type_b = bnd->getBondType();
      if (bond_type_a != Bond::BondType::SINGLE) {
        newmol.addBond(a, b, bond_type_a);
      } else if (bond_type_b != Bond::BondType::SINGLE) {
        newmol.addBond(a, b, bond_type_b);
      } else {
        newmol.addBond(a, b, Bond::BondType::SINGLE);
      }
    }
    a_dummy->setProp("__molzip_used", true);
    b_dummy->setProp("__molzip_used", true);

    return true;
  }

  // Restore the marked chirality (mark_chirality must be called first)
  void restore_chirality(std::set<Atom *> &already_checked) const {
    PRECONDITION(a, "Must have a begin atom to bond");
    PRECONDITION(b, "Must have an end atom to bond");
    PRECONDITION(a_dummy, "Must have a begin dummy atom");
    PRECONDITION(b_dummy, "Must have an end dummy atom");
    if (already_checked.find(a) == already_checked.end()) {
      restore(a);
      already_checked.insert(a);
    }
    if (already_checked.find(b) == already_checked.end()) {
      restore(b);
      already_checked.insert(b);
    }

    // now do bond stereo
    std::string mark = "__molzip_bond_stereo_mark";
    for (auto *bond : a->getOwningMol().bonds()) {
      if (bond->hasProp(mark)) {
        std::vector<int> atoms;
        for (auto *atom : bond->getProp<std::vector<Atom *>>(mark)) {
          atoms.push_back(rdcast<int>(atom->getIdx()));
        }
        bond->getStereoAtoms().swap(atoms);
        bond->setStereo(
            bond->getProp<Bond::BondStereo>("__molzip_bond_stereo"));
      }
    }
  }

 private:
  // Mark the original order of the nbr atoms including the dummy
  //  The goal is to copy the dummy chiral order over to the
  //  atom being bonded
  void mark(Atom *chiral_atom, Atom *dummy_atom, Atom *new_atom) const {
    if (chiral_atom->getChiralTag()) {
      std::string mark =
          "__molzip_mark_" + std::to_string(chiral_atom->getIdx());
      chiral_atom->setProp("__molzip_chiral_mark", mark);
      int order = 0;
      auto &m = chiral_atom->getOwningMol();
      for (auto nbrIdx :
           boost::make_iterator_range(m.getAtomNeighbors(chiral_atom))) {
        m[nbrIdx]->setProp(mark, order);
        ++order;
      }
      new_atom->setProp(mark, dummy_atom->getProp<int>(mark));
    }

    // check bond stereo
    auto &m = chiral_atom->getOwningMol();
    for (auto nbrIdx :
         boost::make_iterator_range(m.getAtomNeighbors(chiral_atom))) {
      auto bond = m.getBondBetweenAtoms(chiral_atom->getIdx(), nbrIdx);
      if (bond->getStereo()) {
        std::string mark = "__molzip_bond_stereo_mark";
        std::vector<Atom *> atoms;
        bool has_dummy = false;
        for (auto idx : bond->getStereoAtoms()) {
          if (static_cast<unsigned>(idx) == dummy_atom->getIdx()) {
            atoms.push_back(new_atom);
            has_dummy = true;
          } else {
            atoms.push_back(m.getAtomWithIdx(idx));
          }
        }
        if (has_dummy) {
          bond->setProp(mark, atoms);
          bond->setProp<Bond::BondStereo>("__molzip_bond_stereo",
                                          bond->getStereo());
        }
      }
    }
  }

  // Restore the atom's chirality by comparing the original order
  //  to the current
  void restore(Atom *chiral_atom) const {
    if (!chiral_atom->getChiralTag()) {
      return;
    }
    std::string mark =
        chiral_atom->getProp<std::string>("__molzip_chiral_mark");
    // std::vector<unsigned int> orders1;
    std::vector<unsigned int> orders2;
    auto &m = chiral_atom->getOwningMol();
    for (auto nbrIdx :
         boost::make_iterator_range(m.getAtomNeighbors(chiral_atom))) {
      orders2.push_back(m[nbrIdx]->getProp<int>(mark));
    }
    if (num_swaps_to_interconvert(orders2) % 2 == 1) {
      chiral_atom->invertChirality();
    }
  }
};
}  // namespace

std::unique_ptr<ROMol> molzip(const ROMol &a, const ROMol &b,
                              const MolzipParams &params) {
  std::unique_ptr<RWMol> newmol;
  if (b.getNumAtoms()) {
    newmol.reset(static_cast<RWMol *>(combineMols(a, b)));
  } else {
    newmol.reset(new RWMol(a));
  }

  std::map<unsigned int, ZipBond> mappings;
  std::map<Atom *, std::vector<const ZipBond *>> mappings_by_atom;
  std::vector<Atom *> deletions;
  if (params.label == MolzipLabel::FragmentOnBonds) {
    for (auto *atom : newmol->atoms()) {
      if (atom->getAtomicNum() == 0) {
        auto molno = atom->getIsotope();
        auto attached_atom = get_other_atom(atom);
        auto &bond = mappings[molno];
        bond.a = attached_atom;
        bond.a_dummy = atom;
        bond.b = newmol->getAtomWithIdx(molno);
        for (auto nbrIdx :
             boost::make_iterator_range(newmol->getAtomNeighbors(bond.b))) {
          auto *nbr = (*newmol)[nbrIdx];
          if (nbr->getAtomicNum() == 0 &&
              nbr->getIsotope() == attached_atom->getIdx()) {
            bond.b_dummy = nbr;
            break;
          }
        }
        if (!bond.b_dummy) {
          BOOST_LOG(rdErrorLog)
              << "Cannot find atom to bond using FragmentOnBond labelling"
              << std::endl;
          return std::unique_ptr<ROMol>();
        }
        mappings_by_atom[atom].push_back(&bond);
        deletions.push_back(atom);
      }
    }
  } else {
    for (auto *atom : newmol->atoms()) {
      auto molno = get_label(atom, params);
      if (molno != NOLABEL) {
        auto attached_atom = get_other_atom(atom);
        if (mappings.find(molno) == mappings.end()) {
          auto &bond = mappings[molno];
          CHECK_INVARIANT(
              !bond.a,
              "molzip: bond info already setup for bgn atom with label:" +
                  std::to_string(molno));
          bond.a = attached_atom;
          bond.a_dummy = atom;
        } else {
          auto &bond = mappings[molno];
          CHECK_INVARIANT(
              bond.a,
              "molzip: bond info not properly setup for bgn atom with label:" +
                  std::to_string(molno));
          CHECK_INVARIANT(
              !bond.b,
              "molzip: bond info already exists for end atom with label:" +
                  std::to_string(molno));
          bond.b = attached_atom;
          bond.b_dummy = atom;
          mappings_by_atom[bond.a].push_back(&bond);
        }
        deletions.push_back(atom);
      }
    }
  }
  for (auto &kv : mappings_by_atom) {
    for (auto &bond : kv.second) {
      bond->mark_chirality();
    }
  }
  for (auto &kv : mappings) {
    kv.second.bond(*newmol);
  }
  newmol->beginBatchEdit();
  for (auto &atom : deletions) {
    if (atom->hasProp("__molzip_used")) {
      newmol->removeAtom(atom);
    }
  }
  newmol->commitBatchEdit();

  std::set<Atom *> already_checked;
  for (auto &kv : mappings_by_atom) {
    for (auto &bond : kv.second) {
      bond->restore_chirality(already_checked);
    }
  }
  // remove all molzip tags
  for (auto *atom : newmol->atoms()) {
    auto propnames = atom->getPropList();
    for (auto &prop : propnames) {
      if (prop.find("__molzip") == 0) {
        atom->clearProp(prop);
      }
    }
  }
  for (auto *bond : newmol->bonds()) {
    auto propnames = bond->getPropList();
    for (auto &prop : propnames) {
      if (prop.find("__molzip") == 0) {
        bond->clearProp(prop);
      }
    }
  }
  newmol->updatePropertyCache(params.enforceValenceRules);
  newmol->setProp(common_properties::_StereochemDone, true);
  return newmol;
}

std::unique_ptr<ROMol> molzip(const ROMol &a, const MolzipParams &params) {
  const static ROMol b;
  return molzip(a, b, params);
}
}  // end of namespace RDKit

max_stars_repo_name: i-tub/rdkit

max_issues_repo_name: i-tub/rdkit

max_forks_repo_name: i-tub/rdkit


text:
#ifndef BOOST_PREPROCESSOR_LIST_FOR_EACH_HPP
#define BOOST_PREPROCESSOR_LIST_FOR_EACH_HPP

/* Copyright (C) 2001
 * Housemarque Oy
 * http://www.housemarque.com
 *
 * Permission to copy, use, modify, sell and distribute this software is
 * granted provided this copyright notice appears in all copies. This
 * software is provided "as is" without express or implied warranty, and
 * with no claim as to its suitability for any purpose.
 *
 * See http://www.boost.org for most recent version.
 */

#include <boost/preprocessor/list/for_each_i.hpp>

/**
Repeats MACRO(R,DATA,BOOST_PP_LIST_AT(LIST,INDEX)) for each INDEX = [0,
BOOST_PP_LIST_SIZE(LIST)).

In other words, expands to the sequence:

  MACRO(R,DATA,BOOST_PP_LIST_AT(LIST,0))
  MACRO(R,DATA,BOOST_PP_LIST_AT(LIST,1))
  ...
  MACRO(R,DATA,BOOST_PP_LIST_AT(LIST,BOOST_PP_DEC(BOOST_PP_LIST_SIZE(LIST))))

For example,

  #define TEST(R,DATA,X) BOOST_PP_CAT(DATA,X)();
  BOOST_PP_LIST_FOR_EACH(TEST,prefix_,BOOST_PP_TUPLE_TO_LIST(3,(A,B,C)))

expands to:

  prefix_A(); prefix_B(); prefix_C();

Example

catch_builtin.cpp

Uses

BOOST_PP_FOR() (see for explanation of the R parameter)

BOOST_PP_LIST_FOR_EACH_I()

Test

list_test.cpp

*/
#define BOOST_PP_LIST_FOR_EACH(MACRO,DATA,LIST) BOOST_PP_LIST_FOR_EACH_R(0,MACRO,DATA,LIST)

/**
Can be used inside BOOST_PP_FOR().
 */
#define BOOST_PP_LIST_FOR_EACH_R(R,MACRO,DATA,LIST) BOOST_PP_LIST_FOR_EACH_I_R(R,BOOST_PP_LIST_FOR_EACH_F,(MACRO,DATA),LIST)
#define BOOST_PP_LIST_FOR_EACH_F(R,FP,I,X) BOOST_PP_TUPLE_ELEM(2,0,FP)(R,BOOST_PP_TUPLE_ELEM(2,1,FP),X)
#endif


text:
/**
 * @file clean_shared_memory.cpp
 * @author Vincent Berenz
 * @license License BSD-3-Clause
 * @copyright Copyright (c) 2019, New York University and Max Planck
 * Gesellschaft.
 * @date 2019-05-22
 *
 * @brief Clean the shared memory of the benchmark, the unnittests, ...
 */

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include "shared_memory/benchmarks/benchmark_common.hh"

int main()
{
    boost::interprocess::named_mutex::remove(SHM_NAME.c_str());
    boost::interprocess::shared_memory_object::remove(SHM_OBJECT_NAME.c_str());
    boost::interprocess::shared_memory_object::remove("main_memory");
    return 0;
}