text:
/*
 *             Copyright Andrey Semashev 2018.
 * 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)
 */
/*!
 * \file   abi_test_tools.hpp
 * \author Andrey Semashev
 * \date   09.03.2018
 *
 * \brief  This file contains a set of ABI testing tools
 */

#ifndef BOOST_WINAPI_TEST_RUN_ABI_TEST_TOOLS_HPP_INCLUDED_
#define BOOST_WINAPI_TEST_RUN_ABI_TEST_TOOLS_HPP_INCLUDED_

#include <boost/winapi/config.hpp>
#include <boost/config.hpp>
#include <boost/current_function.hpp>
#include <boost/core/is_same.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/tuple/elem.hpp>
#include <cstddef> // offsetof

//! The macro produces Boost.WinAPI equivalent for a Windows SDK constant or type name
#define BOOST_WINAPI_NAME(name)\
    boost::winapi::name

//! The macro tests that the given constant has the same value in Boost.WinAPI and Windows SDK
#define BOOST_WINAPI_TEST_CONSTANT(name)\
    BOOST_TEST_EQ(name, BOOST_WINAPI_NAME(name ## _))

//! The macro tests that the given type is the same in Boost.WinAPI and Windows SDK
#define BOOST_WINAPI_TEST_TYPE_SAME(name)\
    BOOST_TEST_TRAIT_TRUE((boost::core::is_same< name, BOOST_WINAPI_NAME(name ## _) >))

//! The macro tests that the given type has the same size in Boost.WinAPI and Windows SDK
#define BOOST_WINAPI_TEST_TYPE_SIZE(name)\
    BOOST_TEST_EQ(sizeof(name), sizeof(BOOST_WINAPI_NAME(name ## _)))

#define BOOST_WINAPI_TEST_STRUCT_FIELD(r, names, field)\
    BOOST_TEST_EQ(sizeof(BOOST_PP_TUPLE_ELEM(2, 0, names)().field), sizeof(BOOST_PP_TUPLE_ELEM(2, 1, names)().field));\
    BOOST_TEST_EQ(offsetof(BOOST_PP_TUPLE_ELEM(2, 0, names), field), offsetof(BOOST_PP_TUPLE_ELEM(2, 1, names), field));

//! The macro tests that the structure has the same size, and its fields have the same size and offsets in Boost.WinAPI and Windows SDK
#define BOOST_WINAPI_TEST_STRUCT(name, fields)\
    BOOST_PP_SEQ_FOR_EACH(BOOST_WINAPI_TEST_STRUCT_FIELD, (name, BOOST_WINAPI_NAME(name ## _)), fields)\
    BOOST_TEST_EQ(sizeof(name), sizeof(BOOST_WINAPI_NAME(name ## _)))

#if defined(BOOST_MSVC)
#pragma warning(push, 3)
// conditional expression is constant
#pragma warning(disable: 4127)
#endif

template< typename Windows_SDK_Signature, typename BoostWinAPI_Signature >
inline void test_equal_signatures(Windows_SDK_Signature*, BoostWinAPI_Signature*, const char* test_name, const char* file, int line)
{
    if (!boost::core::is_same< Windows_SDK_Signature, BoostWinAPI_Signature >::value)
        boost::detail::test_failed_impl(test_name, file, line, BOOST_CURRENT_FUNCTION); // pass BOOST_CURRENT_FUNCTION here to include signature types in the error message
}

#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif

/*!
 * \brief The macro tests that the given function signature is the same in Boost.WinAPI and Windows SDK
 *
 * If the signatures don't match, the test may fail to compile instead of failing at runtime. Depending on the compiler,
 * the error message may say that either there are multiple different declarations of an extern "C" function, or that
 * \c test_equal_signatures cannot be instantiated because of an unresolved overloaded function. This is because we currently
 * have forward declarations of Windows functions in the global namespace, so technically the declaration from Boost.WinAPI
 * and from Windows SDK are either two declarations of the same function (if they match) or declarations of two overloaded
 * functions (which is an error because both of them are extern "C"). Anyway, the test will fail if there's an error and
 * will pass if everything's fine, which is what we want.
 *
 * \note Do not use this macro to compare function signatures where we use our own structures binary-compatible with Windows SDK.
 *       Such functions are defined as inline wrappers in Boost.WinAPI headers and the wrappers will obviously not compare equal
 *       to the functions in Windows SDK. Currently, there's no way to test those function declarations because Boost.WinAPI
 *       declares Windows functions in the global namespace. They are implicitly tested by the compiler though, which should fail
 *       to compile if the declarations don't match.
 */
#if !defined(BOOST_NO_CXX11_DECLTYPE)
#define BOOST_WINAPI_TEST_FUNCTION_SIGNATURE(name)\
    test_equal_signatures((decltype(&name))0, (decltype(&BOOST_WINAPI_NAME(name)))0, "BOOST_WINAPI_TEST_FUNCTION_SIGNATURE(" #name ")", __FILE__, __LINE__)
#else
#define BOOST_WINAPI_TEST_FUNCTION_SIGNATURE(name)\
    test_equal_signatures(&name, &BOOST_WINAPI_NAME(name), "BOOST_WINAPI_TEST_FUNCTION_SIGNATURE(" #name ")", __FILE__, __LINE__)
#endif

#endif // BOOST_WINAPI_TEST_RUN_ABI_TEST_TOOLS_HPP_INCLUDED_

ext: hpp


text:
// Copyright 2021-present MongoDB Inc.
//
// 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 <bsoncxx/json.hpp>
#include <bsoncxx/builder/stream/document.hpp>

#include <boost/exception/diagnostic_information.hpp>

#include <yaml-cpp/yaml.h>

#include <testlib/MongoTestFixture.hpp>
#include <testlib/ActorHelper.hpp>
#include <testlib/helpers.hpp>
#include <regex>
#include <gennylib/context.hpp>

namespace genny {
namespace {
using namespace genny::testing;
namespace bson_stream = bsoncxx::builder::stream;
using std::regex_search;
using namespace bsoncxx;

TEST_CASE_METHOD(MongoTestFixture, "MonotonicLoader - create records and add indexes",
          "[standalone][single_node_replset][three_node_replset][sharded][MonotonicLoader]") {

    dropAllDatabases();
    auto db = client.database("mydb");

    NodeSource nodes = NodeSource(R"(
        SchemaVersion: 2018-07-01
        Actors:
        - Name: MonotonicLoader
          Type: MonotonicLoader
          Threads: 1
          Phases:
          - Repeat: 1
            Database: mydb
            Collection: mycoll
            CollectionCount: 1
            Threads: 1
            DocumentCount: 10000
            BatchSize: 3000
            Document: {
                field1: {^RandomInt: {min: 0, max: 100}},
                field2: {^RandomInt: {min: 0, max: 100}},
                field3: {^RandomInt: {min: 0, max: 100}},
                field4: {^RandomInt: {min: 0, max: 100}},
            }
            Indexes:
            - keys: {field1: 1, field2: -1}
            - keys: {field1: -1, field2: -1}
            - keys: {field1: 1, field2: 1}
            - keys: {field2: 1, field1: 1}
            - keys: {field2: 1}
              options: {name: "a_index", sparse: true}
            - keys: {field1: 1}
              options: {sparse: true}
            - keys: {field3: 1, field4: 1}
              options: {sparse: true}
            - keys: {field3: 4}
              options: {sparse: true, expireAfterSeconds: 3600}

    )",
    __FILE__);

    SECTION("Inserts documents, create indexes and check if indexed and documents are created") {
        try {
            const auto indexRegex = std::regex(".*\\\"firstBatch\\\"\\s:\\s\\[(.*)\\]");
            genny::ActorHelper ah(nodes.root(), 1, MongoTestFixture::connectionUri().to_string());
            ah.run([](const genny::WorkloadContext& wc) { wc.actors()[0]->run(); });

            auto builder = bson_stream::document{};
            builder << bson_stream::finalize;
            document::value doc = builder << "listIndexes" << "Collection0" << builder::stream::finalize;
            auto indexes = db.run_command(doc.view());
            auto outputString = to_json(indexes.view());
            std::cmatch matches;
            std::regex_search(const_cast<char*>(outputString.c_str()), matches, indexRegex);
            std::string actual_response(matches[1]);
            auto expected_response = " { \"v\" : 2, \"key\" : { \"_id\" : 1 }, "
                                     "\"name\" : \"_id_\" }, "
                                     "{ \"v\" : 2, \"key\" : { \"field1\" : 1, \"field2\" : -1 }, "
                                     "\"name\" : \"field1_1_field2_-1\" }, "
                                     "{ \"v\" : 2, \"key\" : { \"field1\" : -1, \"field2\" : -1 }, "
                                     "\"name\" : \"field1_-1_field2_-1\" }, "
                                     "{ \"v\" : 2, \"key\" : { \"field1\" : 1, \"field2\" : 1 }, "
                                     "\"name\" : \"field1_1_field2_1\" }, "
                                     "{ \"v\" : 2, \"key\" : { \"field2\" : 1, \"field1\" : 1 }, "
                                     "\"name\" : \"field2_1_field1_1\" },"
                                     " { \"v\" : 2, \"key\" : { \"field2\" : 1 },"
                                     " \"name\" : \"a_index\", \"sparse\" : true },"
                                     " { \"v\" : 2, \"key\" : { \"field1\" : 1 }, "
                                     "\"name\" : \"field1_1\", \"sparse\" : true },"
                                     " { \"v\" : 2, \"key\" : { \"field3\" : 1, \"field4\" : 1 }, "
                                     "\"name\" : \"field3_1_field4_1\", \"sparse\" : true },"
                                     " { \"v\" : 2, \"key\" : { \"field3\" : 4 }, "
                                     "\"name\" : \"field3_4\", \"sparse\" : true, "
                                     "\"expireAfterSeconds\" : 3600 } ";
            INFO("Actual Response:   " << actual_response);
            INFO("Expected Response: " << expected_response);
            REQUIRE(actual_response == expected_response);
            auto count = db.collection("Collection0").count_documents(builder.view());
            REQUIRE(count == 10000);

        } catch (const std::exception& e) {
            auto diagInfo = boost::diagnostic_information(e);
            INFO("CAUGHT " << diagInfo);
            FAIL(diagInfo);
        }
    }
}
}  // namespace
}  // namespace genny

ext: cpp


text:
// SIRFilter.hpp
// Copyright 2019 Mikko Lauri
//
// 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.

#ifndef SIRFILTER_HPP
#define SIRFILTER_HPP
#include "History.h"
#include "PRNG.h"
#include "ParticleUtilities.h"
#include <boost/random/uniform_int_distribution.hpp>
#include <boost/random/discrete_distribution.hpp>

namespace pgi {
template <typename State, typename StateTransitionModel,
          typename ObservationModel>
void SIR(std::vector<State>& states, std::vector<double>& weights,
         const History& h, const StateTransitionModel& t,
         const ObservationModel& o, PRNG& rng) {
  assert(states.size() == weights.size());
  for (const auto& ao : h) {
    SIR_step(states, weights, ao.action_index_, ao.observation_index_, t, o,
             0.2 * static_cast<double>(weights.size()), rng);
  }
}

template <typename State, typename StateTransitionModel,
          typename ObservationModel>
double SIR_step(std::vector<State>& states, std::vector<double>& weights,
              std::size_t j_act, std::size_t j_obs,
              const StateTransitionModel& t, const ObservationModel& o,
              double effective_sample_size_threshold, PRNG& rng) {
  double po = 0.0; // p(o | a)
  for (std::size_t i = 0; i < states.size(); ++i) {
    states[i] = t.sample_next_state(states[i], j_act, rng);
    const double p = o.get(j_obs, states[i], j_act);
    po += weights[i] * p;
    weights[i] *= p;
  }
  normalize(weights);
  if (effective_sample_size_threshold > effective_size(weights)) {
    resample_particles(states, weights, rng);
    for (auto& s : states) {
      s.reinvigorate(rng);
    }
  }
  return po;
}

template <typename State>
void sample_to_fixed_size(std::vector<State>& states,
  std::vector<double>& weights, int N, PRNG& rng)
{
  std::size_t sz = weights.size();
  const int ns = N - static_cast<int>(sz);
  if (ns == 0)
    return;

  if (ns < 0)
  {
    // need to discard samples
    std::vector<State> keep_states(N);
    std::vector<double> keep_weights(N);
    for (int i = 0; i < N; ++i)
    {
      boost::random::discrete_distribution<> dist(weights.begin(), weights.end());
      const auto k = rng(dist);
      keep_states[i] = states[k];
      keep_weights[i] = weights[k];
      weights[k] = 0.0;
    }
    states = keep_states;
    weights = keep_weights;
    normalize(weights);
  }
  else
  {
    // need more samples
    resample_particles(states, weights, rng);

    weights.resize(N);
    std::fill(weights.begin(), weights.end(), 1.0 / static_cast<double>(N));

    states.resize(N);

    boost::random::uniform_int_distribution<std::size_t> dist(0, weights.size()-1);
    for (int i = 0; i < ns; ++i)
    {
      const std::size_t r = rng(dist);
      states[sz+i] = states[r];
      states[sz+i].reinvigorate(rng);
    }
  }
}

template <typename State>
void resample_particles(std::vector<State>& states,
                        std::vector<double>& weights, PRNG& rng) {
  std::vector<std::size_t> resample_indices(0, weights.size());
  resample(weights, resample_indices, rng);

  std::vector<State> resampled_states(states);
  for (std::size_t i = 0; i < states.size(); ++i)
    resampled_states[i] = states[resample_indices[i]];
  states = resampled_states;
  std::fill(weights.begin(), weights.end(),
            1.0 / static_cast<double>(weights.size()));
}

}  // namespace pgi

#endif  // SIRFILTER_HPP