diff --git a/cpp/models/ode_secir/model.h b/cpp/models/ode_secir/model.h
index 59e9fdb991..2f7f1c63f3 100644
--- a/cpp/models/ode_secir/model.h
+++ b/cpp/models/ode_secir/model.h
@@ -22,8 +22,11 @@
#include "memilio/compartments/compartmentalmodel.h"
#include "memilio/compartments/simulation.h"
+#include "memilio/config.h"
#include "memilio/epidemiology/populations.h"
+#include "memilio/io/io.h"
#include "ode_secir/infection_state.h"
+#include "memilio/math/interpolation.h"
#include "ode_secir/parameters.h"
#include "memilio/math/smoother.h"
#include "memilio/math/eigen_util.h"
@@ -308,6 +311,264 @@ double get_infections_relative(const Simulation& sim, double /*t*/, const
return inf_rel;
}
+/**
+*@brief Computes the reproduction number at a given index time of the Model output obtained by the Simulation.
+*@param t_idx The index time at which the reproduction number is computed.
+*@param sim The simulation handling the secir model
+*@tparam Base simulation type that uses a secir compartment model. see Simulation.
+*@returns The computed reproduction number at the provided index time.
+*/
+
+template
+IOResult get_reproduction_number(size_t t_idx, const Simulation& sim)
+{
+
+ if (!(t_idx < static_cast(sim.get_result().get_num_time_points()))) {
+ return mio::failure(mio::StatusCode::OutOfRange, "t_idx is not a valid index for the TimeSeries");
+ }
+
+ auto const& params = sim.get_model().parameters;
+ const size_t num_groups = (size_t)sim.get_model().parameters.get_num_groups();
+ size_t num_infected_compartments = 5;
+ size_t total_infected_compartments = num_infected_compartments * num_groups;
+
+ Eigen::MatrixXd F(total_infected_compartments, total_infected_compartments);
+ Eigen::MatrixXd V(total_infected_compartments, total_infected_compartments);
+ F = Eigen::MatrixXd::Zero(total_infected_compartments,
+ total_infected_compartments); //Initialize matrices F and V with zeroes
+ V = Eigen::MatrixXd::Zero(total_infected_compartments, total_infected_compartments);
+
+ auto test_and_trace_required = 0.0;
+ auto icu_occupancy = 0.0;
+ for (auto i = AgeGroup(0); i < (mio::AgeGroup)num_groups; ++i) {
+ auto rateINS = 0.5 / (params.template get()[i] - params.template get()[i]);
+ test_and_trace_required +=
+ (1 - params.template get()[i]) * rateINS *
+ sim.get_result().get_value(
+ t_idx)[sim.get_model().populations.get_flat_index({i, InfectionState::InfectedNoSymptoms})];
+ icu_occupancy += sim.get_result().get_value(
+ t_idx)[sim.get_model().populations.get_flat_index({i, InfectionState::InfectedCritical})];
+ }
+
+ double season_val =
+ (1 + params.template get() *
+ sin(3.141592653589793 * (std::fmod((sim.get_model().parameters.template get() +
+ sim.get_result().get_time(t_idx)),
+ 365.0) /
+ 182.5 +
+ 0.5)));
+ ContactMatrixGroup const& contact_matrix = sim.get_model().parameters.template get();
+
+ Eigen::MatrixXd cont_freq_eff(num_groups, num_groups);
+ Eigen::MatrixXd riskFromInfectedSymptomatic_derivatives(num_groups, num_groups);
+ Eigen::VectorXd divN(num_groups);
+ Eigen::VectorXd riskFromInfectedSymptomatic(num_groups);
+ Eigen::VectorXd rateINS(num_groups);
+
+ for (mio::AgeGroup k = 0; k < (mio::AgeGroup)num_groups; k++) {
+ double temp = sim.get_result().get_value(
+ t_idx)[sim.get_model().populations.get_flat_index({k, InfectionState::Susceptible})] +
+ sim.get_result().get_value(
+ t_idx)[sim.get_model().populations.get_flat_index({k, InfectionState::Exposed})] +
+ sim.get_result().get_value(
+ t_idx)[sim.get_model().populations.get_flat_index({k, InfectionState::InfectedNoSymptoms})] +
+ sim.get_result().get_value(
+ t_idx)[sim.get_model().populations.get_flat_index({k, InfectionState::InfectedSymptoms})] +
+ sim.get_result().get_value(
+ t_idx)[sim.get_model().populations.get_flat_index({k, InfectionState::InfectedSevere})] +
+ sim.get_result().get_value(
+ t_idx)[sim.get_model().populations.get_flat_index({k, InfectionState::InfectedCritical})] +
+ sim.get_result().get_value(
+ t_idx)[sim.get_model().populations.get_flat_index({k, InfectionState::Recovered})];
+ if (temp == 0) {
+ temp = 1;
+ }
+ divN[(size_t)k] = 1 / temp;
+
+ riskFromInfectedSymptomatic[(size_t)k] = smoother_cosine(
+ test_and_trace_required, params.template get(),
+ (params.template get()) * 5, params.template get()[k],
+ params.template get()[k]);
+
+ rateINS[(size_t)k] =
+ 0.5 / (params.template get()[k] - params.template get()[(mio::AgeGroup)k]);
+
+ for (mio::AgeGroup l = 0; l < (mio::AgeGroup)num_groups; l++) {
+ if (test_and_trace_required < params.template get() ||
+ test_and_trace_required > 5 * params.template get()) {
+ riskFromInfectedSymptomatic_derivatives((size_t)k, (size_t)l) = 0;
+ }
+ else {
+ riskFromInfectedSymptomatic_derivatives((size_t)k, (size_t)l) =
+ -0.5 * 3.14159265358979323846 *
+ (params.template get()[k] -
+ params.template get()[k]) /
+ (4 * params.template get()) *
+ (1 - params.template get()[l]) * rateINS[(size_t)l] *
+ std::sin(3.14159265358979323846 / (4 * params.template get()) *
+ (test_and_trace_required - params.template get()));
+ }
+ }
+
+ for (Eigen::Index l = 0; l < (Eigen::Index)num_groups; l++) {
+ cont_freq_eff(l, (size_t)k) =
+ season_val * contact_matrix.get_matrix_at(static_cast(t_idx))(
+ static_cast((size_t)l), static_cast((size_t)k));
+ }
+ }
+
+ //Check criterion if matrix V will be invertible by checking if subblock J is invertible
+ Eigen::MatrixXd J(num_groups, num_groups);
+ J = Eigen::MatrixXd::Zero(num_groups, num_groups);
+ for (size_t i = 0; i < num_groups; i++) {
+ J(i, i) = 1 / (params.template get()[(mio::AgeGroup)i]);
+
+ if (!(icu_occupancy < 0.9 * params.template get() ||
+ icu_occupancy > (double)(params.template get()))) {
+ for (size_t j = 0; j < num_groups; j++) {
+ J(i, j) -= sim.get_result().get_value(t_idx)[sim.get_model().populations.get_flat_index(
+ {(mio::AgeGroup)i, InfectionState::InfectedSevere})] /
+ params.template get()[(mio::AgeGroup)i] * 5 *
+ params.template get()[(mio::AgeGroup)i] * 3.141592653589793 /
+ (params.template get()) *
+ std::sin(3.141592653589793 / (0.1 * params.template get()) *
+ (icu_occupancy - 0.9 * params.template get()));
+ }
+ }
+ }
+
+ //Try to invert J
+ Eigen::FullPivLU lu(J); //Check invertibility via LU Decomposition
+ if (!lu.isInvertible()) {
+ return mio::failure(mio::StatusCode::UnknownError, "Matrix V is not invertible");
+ }
+
+ //Eigen::Array Jnew = J;
+
+ //Initialize the matrix F
+ for (size_t i = 0; i < num_groups; i++) {
+
+ for (size_t j = 0; j < num_groups; j++) {
+
+ double temp = 0;
+ for (Eigen::Index k = 0; k < (Eigen::Index)num_groups; k++) {
+ temp += cont_freq_eff(i, k) *
+ sim.get_result().get_value(t_idx)[sim.get_model().populations.get_flat_index(
+ {(mio::AgeGroup)k, InfectionState::InfectedSymptoms})] *
+ riskFromInfectedSymptomatic_derivatives(k, j) * divN[k];
+ }
+
+ F(i, j + num_groups) =
+ sim.get_result().get_value(t_idx)[sim.get_model().populations.get_flat_index(
+ {(mio::AgeGroup)i, InfectionState::Susceptible})] *
+ params.template get()[(mio::AgeGroup)i] *
+ (cont_freq_eff(i, j) * params.template get()[(mio::AgeGroup)j] *
+ divN[(size_t)j] +
+ temp);
+ }
+
+ for (size_t j = 0; j < num_groups; j++) {
+ F(i, j + 2 * num_groups) = sim.get_result().get_value(t_idx)[sim.get_model().populations.get_flat_index(
+ {(mio::AgeGroup)i, InfectionState::Susceptible})] *
+ params.template get()[(mio::AgeGroup)i] *
+ cont_freq_eff(i, j) * riskFromInfectedSymptomatic[(size_t)j] * divN[(size_t)j];
+ }
+ }
+
+ //Initialize the matrix V
+ for (Eigen::Index i = 0; i < (Eigen::Index)num_groups; i++) {
+
+ double rateE = 1.0 / (2 * params.template get()[(mio::AgeGroup)i] -
+ params.template get()[(mio::AgeGroup)i]);
+
+ double criticalPerSevereAdjusted = smoother_cosine(
+ icu_occupancy, 0.90 * params.template get(), params.template get(),
+ params.template get()[(mio::AgeGroup)i], 0);
+
+ V(i, i) = rateE;
+ V(i + num_groups, i) = -rateE;
+ V(i + num_groups, i + num_groups) = rateINS[i];
+ V(i + 2 * num_groups, i + num_groups) =
+ -(1 - params.template get()[(mio::AgeGroup)i]) * rateINS[i];
+ V(i + 2 * num_groups, i + 2 * num_groups) = (1 / params.template get()[(mio::AgeGroup)i]);
+ V(i + 3 * num_groups, i + 2 * num_groups) =
+ -params.template get()[(mio::AgeGroup)i] /
+ params.template get()[(mio::AgeGroup)i];
+ V(i + 3 * num_groups, i + 3 * num_groups) = 1 / (params.template get()[(mio::AgeGroup)i]);
+ V(i + 4 * num_groups, i + 3 * num_groups) =
+ -criticalPerSevereAdjusted / (params.template get()[(mio::AgeGroup)i]);
+
+ for (size_t j = 0; j < num_groups; j++) {
+ V(i + 4 * num_groups, j + 4 * num_groups) = J(i, j);
+ }
+ }
+
+ V = V.inverse();
+
+ //Compute F*V
+ Eigen::MatrixXd NextGenMatrix(5 * num_groups, 5 * num_groups);
+ NextGenMatrix = F * V;
+
+ //Compute the largest eigenvalue in absolute value
+ Eigen::ComplexEigenSolver ces;
+
+ ces.compute(NextGenMatrix);
+ const Eigen::VectorXcd eigen_vals = ces.eigenvalues();
+
+ Eigen::VectorXd eigen_vals_abs;
+ eigen_vals_abs.resize(eigen_vals.size());
+
+ for (int i = 0; i < eigen_vals.size(); i++) {
+ eigen_vals_abs[i] = std::abs(eigen_vals[i]);
+ }
+ return mio::success(eigen_vals_abs.maxCoeff());
+}
+/**
+*@brief Computes the reproduction number for all time points of the Model output obtained by the Simulation.
+*@param sim The Model Simulation.
+*@returns vector containing all reproduction numbers
+*/
+
+template
+Eigen::VectorXd get_reproduction_numbers(const Simulation& sim)
+{
+ Eigen::VectorXd temp(sim.get_result().get_num_time_points());
+ for (int i = 0; i < sim.get_result().get_num_time_points(); i++) {
+ temp[i] = get_reproduction_number((size_t)i, sim).value();
+ }
+ return temp;
+}
+
+/**
+*@brief Computes the reproduction number at a given time point of the Model output obtained by the Simulation. If the particular time point is not inside the output, a linearly interpolated value is returned.
+*@param t_value The time point at which the reproduction number is computed.
+*@param sim The Model Simulation.
+*@returns The computed reproduction number at the provided time point, potentially using linear interpolation.
+*/
+template
+IOResult get_reproduction_number(ScalarType t_value, const Simulation& sim)
+{
+ if (t_value < sim.get_result().get_time(0) || t_value > sim.get_result().get_last_time()) {
+ return mio::failure(mio::StatusCode::OutOfRange,
+ "Cannot interpolate reproduction number outside computed horizon of the TimeSeries");
+ }
+
+ if (t_value == sim.get_result().get_time(0)) {
+ return mio::success(get_reproduction_number((size_t)0, sim).value());
+ }
+
+ auto times = std::vector(sim.get_result().get_times().begin(), sim.get_result().get_times().end());
+
+ auto time_late = std::distance(times.begin(), std::lower_bound(times.begin(), times.end(), t_value));
+
+ ScalarType y1 = get_reproduction_number(static_cast(time_late - 1), sim).value();
+ ScalarType y2 = get_reproduction_number(static_cast(time_late), sim).value();
+
+ auto result = linear_interpolation(t_value, sim.get_result().get_time(time_late - 1),
+ sim.get_result().get_time(time_late), y1, y2);
+ return mio::success(static_cast(result));
+}
+
/**
* Get migration factors.
* Used by migration graph simulation.
diff --git a/cpp/tests/test_odesecir.cpp b/cpp/tests/test_odesecir.cpp
index 728b398c11..6fd9725a88 100644
--- a/cpp/tests/test_odesecir.cpp
+++ b/cpp/tests/test_odesecir.cpp
@@ -19,6 +19,10 @@
*/
#include "matchers.h"
#include "load_test_data.h"
+#include "memilio/compartments/simulation.h"
+#include "memilio/epidemiology/age_group.h"
+#include "memilio/utils/time_series.h"
+#include "ode_secir/infection_state.h"
#include "ode_secir/model.h"
#include "memilio/math/adapt_rk.h"
#include "ode_secir/parameter_space.h"
@@ -26,6 +30,7 @@
#include "ode_secir/parameters.h"
#include
#include
+#include
TEST(TestOdeSecir, compareWithPreviousRun)
{
@@ -726,6 +731,167 @@ TEST(Secir, getInfectionsRelative)
(100. + 50. + 25.) / (10'000 + 20'000 + 40'000));
}
+TEST(Secir, get_reproduction_number)
+{
+ size_t num_groups = 3;
+ mio::osecir::Model model((int)num_groups);
+
+ mio::ContactMatrixGroup& contact_matrix = model.parameters.get();
+ contact_matrix[0] = mio::ContactMatrix(Eigen::MatrixXd::Constant(3, 3, 10));
+
+ model.parameters.set(60);
+ model.parameters.set(0.2);
+
+ //total population of 10.000
+ model.populations[{mio::AgeGroup(0), mio::osecir::InfectionState::Susceptible}] = 3000;
+ model.populations[{mio::AgeGroup(0), mio::osecir::InfectionState::Exposed}] = 400;
+ model.populations[{mio::AgeGroup(0), mio::osecir::InfectionState::InfectedNoSymptoms}] = 50;
+ model.populations[{mio::AgeGroup(0), mio::osecir::InfectionState::InfectedSymptoms}] = 50;
+ model.populations[{mio::AgeGroup(0), mio::osecir::InfectionState::InfectedSevere}] = 0;
+ model.populations[{mio::AgeGroup(0), mio::osecir::InfectionState::InfectedCritical}] = 0;
+ model.populations[{mio::AgeGroup(0), mio::osecir::InfectionState::Recovered}] = 0;
+ model.populations[{mio::AgeGroup(0), mio::osecir::InfectionState::Dead}] = 0;
+
+ model.populations[{mio::AgeGroup(1), mio::osecir::InfectionState::Susceptible}] = 4000;
+ model.populations[{mio::AgeGroup(1), mio::osecir::InfectionState::Exposed}] = 350;
+ model.populations[{mio::AgeGroup(1), mio::osecir::InfectionState::InfectedNoSymptoms}] = 50;
+ model.populations[{mio::AgeGroup(1), mio::osecir::InfectionState::InfectedSymptoms}] = 100;
+ model.populations[{mio::AgeGroup(1), mio::osecir::InfectionState::InfectedSevere}] = 0;
+ model.populations[{mio::AgeGroup(1), mio::osecir::InfectionState::InfectedCritical}] = 0;
+ model.populations[{mio::AgeGroup(1), mio::osecir::InfectionState::Recovered}] = 0;
+ model.populations[{mio::AgeGroup(1), mio::osecir::InfectionState::Dead}] = 0;
+
+ model.populations[{mio::AgeGroup(2), mio::osecir::InfectionState::Susceptible}] = 1500;
+ model.populations[{mio::AgeGroup(2), mio::osecir::InfectionState::Exposed}] = 200;
+ model.populations[{mio::AgeGroup(2), mio::osecir::InfectionState::InfectedNoSymptoms}] = 100;
+ model.populations[{mio::AgeGroup(2), mio::osecir::InfectionState::InfectedSymptoms}] = 100;
+ model.populations[{mio::AgeGroup(2), mio::osecir::InfectionState::InfectedSevere}] = 50;
+ model.populations[{mio::AgeGroup(2), mio::osecir::InfectionState::InfectedCritical}] = 50;
+ model.populations[{mio::AgeGroup(2), mio::osecir::InfectionState::Recovered}] = 0;
+ model.populations[{mio::AgeGroup(2), mio::osecir::InfectionState::Dead}] = 0;
+
+ for (auto i = mio::AgeGroup(0); i < (mio::AgeGroup)num_groups; i++) {
+ model.parameters.get()[i] = 5.2;
+ model.parameters.get()[i] = 5.8;
+ model.parameters.get()[i] = 4.2;
+ model.parameters.get()[i] = 9.5;
+ model.parameters.get()[i] = 7.1;
+
+ model.parameters.get()[i] = 0.05;
+ model.parameters.get()[i] = 0.7;
+ model.parameters.get()[i] = 0.09;
+ model.parameters.get()[i] = 0.25;
+ model.parameters.get()[i] = 0.45;
+ model.parameters.get()[i] = 0.2;
+ model.parameters.get()[i] = 0.25;
+ model.parameters.get()[i] = 0.3;
+ }
+ model.parameters.get() = std::numeric_limits::max();
+ model.parameters.get() = std::numeric_limits::max();
+
+ mio::TimeSeries time_series1((int)mio::osecir::InfectionState::Count * num_groups);
+ mio::TimeSeries::Vector result_0((int)mio::osecir::InfectionState::Count * num_groups);
+ mio::TimeSeries::Vector result_1((int)mio::osecir::InfectionState::Count * num_groups);
+ mio::TimeSeries::Vector result_2((int)mio::osecir::InfectionState::Count * num_groups);
+ mio::TimeSeries::Vector result_3((int)mio::osecir::InfectionState::Count * num_groups);
+ mio::TimeSeries::Vector result_4((int)mio::osecir::InfectionState::Count * num_groups);
+ mio::TimeSeries::Vector result_5((int)mio::osecir::InfectionState::Count * num_groups);
+ mio::TimeSeries::Vector result_6((int)mio::osecir::InfectionState::Count * num_groups);
+
+ model.apply_constraints();
+
+ result_0 << 3000, 400, 50, 0, 50, 0, 0, 0, 0, 0, 4000, 350, 50, 0, 100, 0, 0, 0, 0, 0, 1500, 200, 100, 0, 100, 0,
+ 50, 50, 0, 0;
+
+ result_1 << 2900, 500, 50, 0, 50, 0, 0, 0, 0, 0, 4000, 350, 50, 0, 100, 0, 0, 0, 0, 0, 1500, 200, 100, 0, 100, 0,
+ 50, 50, 0, 0;
+
+ result_2 << 2850, 550, 50, 0, 50, 0, 0, 0, 0, 0, 4000, 350, 0, 0, 150, 0, 0, 0, 0, 0, 1500, 200, 100, 0, 100, 0, 50,
+ 50, 0, 0;
+
+ result_3 << 2850, 550, 50, 0, 50, 0, 0, 0, 0, 0, 4000, 350, 0, 0, 150, 0, 0, 0, 0, 0, 1300, 400, 100, 0, 100, 0, 50,
+ 50, 0, 0;
+
+ result_4 << 2800, 600, 50, 0, 50, 0, 0, 0, 0, 0, 4000, 300, 0, 0, 200, 0, 0, 0, 0, 0, 1300, 400, 100, 0, 100, 0, 50,
+ 50, 0, 0;
+
+ result_5 << 2800, 600, 50, 0, 50, 0, 0, 0, 0, 0, 4000, 300, 0, 0, 200, 0, 0, 0, 0, 0, 1300, 400, 100, 0, 100, 0, 50,
+ 50, 0, 0;
+
+ result_6 << 2700, 600, 100, 0, 100, 0, 0, 0, 0, 0, 4000, 300, 0, 0, 200, 0, 0, 0, 0, 0, 1300, 400, 100, 0, 100, 0,
+ 0, 100, 0, 0;
+
+ time_series1.add_time_point(0.0, result_0);
+ time_series1.add_time_point(0.1000000000000000000, result_1);
+ time_series1.add_time_point(0.2000000000000000000, result_2);
+ time_series1.add_time_point(0.4000000000000000000, result_3);
+ time_series1.add_time_point(0.6000000000000000000, result_4);
+ time_series1.add_time_point(0.8000000000000000000, result_5);
+ time_series1.add_time_point(1.0, result_6);
+
+ mio::osecir::Simulation<> sim(model, 0.0);
+ sim.get_result() = time_series1;
+
+ EXPECT_FALSE(
+ mio::osecir::get_reproduction_number(time_series1.get_time(0) - 0.5, sim)); //Test for indices out of range
+ EXPECT_FALSE(mio::osecir::get_reproduction_number(time_series1.get_last_time() + 0.5, sim));
+ EXPECT_FALSE(mio::osecir::get_reproduction_number((size_t)time_series1.get_num_time_points(), sim));
+
+ EXPECT_EQ(mio::osecir::get_reproduction_number((size_t)0, sim).value(),
+ mio::osecir::get_reproduction_number(0.0, sim).value());
+
+ //Test one function for integer timepoints
+ EXPECT_NEAR(mio::osecir::get_reproduction_number((size_t)0, sim).value(), 3.7417747463385571, 1e-12);
+ EXPECT_NEAR(mio::osecir::get_reproduction_number((size_t)4, sim).value(), 3.5005445618245297, 1e-12);
+ EXPECT_NEAR(mio::osecir::get_reproduction_number((size_t)6, sim).value(), 3.4540372055485653, 1e-12);
+ EXPECT_NEAR(mio::osecir::get_reproduction_number(0.05, sim).value(), 3.719862942211813, 1e-12);
+ EXPECT_NEAR(mio::osecir::get_reproduction_number(0.5, sim).value(), 3.5121859116705565, 1e-12);
+ EXPECT_NEAR(mio::osecir::get_reproduction_number(0.85, sim).value(), 3.4874972585249733, 1e-12);
+
+ //Test handling non-invertibility of V for certain values
+ mio::TimeSeries::Vector result_7((int)mio::osecir::InfectionState::Count * num_groups);
+ double icu_occupancy = 0.95 * model.parameters.get();
+ double severe1 = model.parameters.get()[(mio::AgeGroup)0] /
+ (model.parameters.get()[(mio::AgeGroup)0] * 5 *
+ model.parameters.get()[(mio::AgeGroup)1] * 3.141592653589793 /
+ (model.parameters.get()) *
+ std::sin(3.141592653589793 / (0.1 * model.parameters.get()) *
+ (icu_occupancy - 0.9 * model.parameters.get())));
+
+ mio::TimeSeries time_series2((int)mio::osecir::InfectionState::Count * num_groups);
+ result_7 << 1000, 0, 0, 0, 0, 0, severe1, 0.95 * model.parameters.get(), 0, 0, 1000, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1000, 0, 0, 0, 0, 0, 0, 0, 0, 0;
+ time_series2.add_time_point(0.0, result_7);
+ sim.get_result() = time_series2;
+ EXPECT_FALSE(mio::osecir::get_reproduction_number((size_t)0, sim));
+
+ //Test in the case of limited test-and-trace capacity:
+
+ //Test for small test and trace
+ model.parameters.get() = 0;
+ mio::osecir::Simulation<> sim2(model, 0.0);
+ sim2.get_result() = time_series1;
+ EXPECT_NEAR(mio::osecir::get_reproduction_number((size_t)0, sim2).value(), 5.1941804908632792, 1e-12);
+
+ // Test special domain for test-and-trace capacity/requirement:
+ model.parameters.get() = 1;
+ mio::TimeSeries time_series3((int)mio::osecir::InfectionState::Count * num_groups);
+ mio::TimeSeries::Vector result_8((int)mio::osecir::InfectionState::Count * num_groups);
+ result_8 << 10, 0, 4.3956043956043956, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 100, 0;
+ time_series3.add_time_point(0.0, result_8);
+ sim.get_result() = time_series3;
+ EXPECT_NEAR(mio::osecir::get_reproduction_number((size_t)0, sim).value(), 0.97371260459013254, 1e-12);
+
+ //Test handling of zero population in at least one agegroup
+ mio::TimeSeries time_series4((int)mio::osecir::InfectionState::Count * num_groups);
+ mio::TimeSeries::Vector result_9((int)mio::osecir::InfectionState::Count * num_groups);
+ result_9 << 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
+ time_series4.add_time_point(0.0, result_9);
+ sim.get_result() = time_series4;
+ EXPECT_TRUE(mio::osecir::get_reproduction_number((size_t)0, sim));
+}
+
TEST(Secir, get_migration_factors)
{
auto beta = 0.25;
diff --git a/cpp/thirdparty/boost_1_75_0.tar.gz b/cpp/thirdparty/boost_1_75_0.tar.gz
index 04d1e16733..f3f36c2369 100644
Binary files a/cpp/thirdparty/boost_1_75_0.tar.gz and b/cpp/thirdparty/boost_1_75_0.tar.gz differ
diff --git a/cpp/thirdparty/boost_1_75_0.tar.gz.old b/cpp/thirdparty/boost_1_75_0.tar.gz.old
new file mode 100644
index 0000000000..04d1e16733
Binary files /dev/null and b/cpp/thirdparty/boost_1_75_0.tar.gz.old differ
diff --git a/cpp/thirdparty/boost_1_75_0/Jamroot b/cpp/thirdparty/boost_1_75_0/Jamroot
new file mode 100644
index 0000000000..af2f220988
--- /dev/null
+++ b/cpp/thirdparty/boost_1_75_0/Jamroot
@@ -0,0 +1,332 @@
+# Copyright Vladimir Prus 2002-2006.
+# Copyright Dave Abrahams 2005-2006.
+# Copyright Rene Rivera 2005-2007.
+# Copyright Douglas Gregor 2005.
+#
+# 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)
+
+# Usage:
+#
+# b2 [options] [properties] [install|stage]
+#
+# Builds and installs Boost.
+#
+# Targets and Related Options:
+#
+# install Install headers and compiled library files to the
+# ======= configured locations (below).
+#
+# --prefix= Install architecture independent files here.
+# Default: C:\Boost on Windows
+# Default: /usr/local on Unix, Linux, etc.
+#
+# --exec-prefix= Install architecture dependent files here.
+# Default:
+#
+# --libdir= Install library files here.
+# Default: /lib
+#
+# --includedir= Install header files here.
+# Default: /include
+#
+# --cmakedir= Install CMake configuration files here.
+# Default: /cmake
+#
+# --no-cmake-config Do not install CMake configuration files.
+#
+# stage Build and install only compiled library files to the
+# ===== stage directory.
+#
+# --stagedir= Install library files here
+# Default: ./stage
+#
+# Other Options:
+#
+# --build-type= Build the specified pre-defined set of variations of
+# the libraries. Note, that which variants get built
+# depends on what each library supports.
+#
+# -- minimal -- (default) Builds a minimal set of
+# variants. On Windows, these are static
+# multithreaded libraries in debug and release
+# modes, using shared runtime. On Linux, these are
+# static and shared multithreaded libraries in
+# release mode.
+#
+# -- complete -- Build all possible variations.
+#
+# --build-dir=DIR Build in this location instead of building within
+# the distribution tree. Recommended!
+#
+# --show-libraries Display the list of Boost libraries that require
+# build and installation steps, and then exit.
+#
+# --layout= Determine whether to choose library names and header
+# locations such that multiple versions of Boost or
+# multiple compilers can be used on the same system.
+#
+# -- versioned -- Names of boost binaries include
+# the Boost version number, name and version of
+# the compiler and encoded build properties. Boost
+# headers are installed in a subdirectory of
+# whose name contains the Boost version
+# number.
+#
+# -- tagged -- Names of boost binaries include the
+# encoded build properties such as variant and
+# threading, but do not including compiler name
+# and version, or Boost version. This option is
+# useful if you build several variants of Boost,
+# using the same compiler.
+#
+# -- system -- Binaries names do not include the
+# Boost version number or the name and version
+# number of the compiler. Boost headers are
+# installed directly into . This option is
+# intended for system integrators building
+# distribution packages.
+#
+# The default value is 'versioned' on Windows, and
+# 'system' on Unix.
+#
+# --buildid=ID Add the specified ID to the name of built libraries.
+# The default is to not add anything.
+#
+# --python-buildid=ID Add the specified ID to the name of built libraries
+# that depend on Python. The default is to not add
+# anything. This ID is added in addition to --buildid.
+#
+# --help This message.
+#
+# --with- Build and install the specified . If this
+# option is used, only libraries specified using this
+# option will be built.
+#
+# --without- Do not build, stage, or install the specified
+# . By default, all libraries are built.
+#
+# Properties:
+#
+# toolset=toolset Indicate the toolset to build with.
+#
+# variant=debug|release Select the build variant
+#
+# link=static|shared Whether to build static or shared libraries
+#
+# threading=single|multi Whether to build single or multithreaded binaries
+#
+# runtime-link=static|shared
+# Whether to link to static or shared C and C++
+# runtime.
+#
+
+# TODO:
+# - handle boost version
+# - handle python options such as pydebug
+
+import boostcpp ;
+import package ;
+
+import sequence ;
+import xsltproc ;
+import set ;
+import path ;
+import link ;
+import notfile ;
+import virtual-target ;
+import "class" : new ;
+import property-set ;
+import threadapi-feature ;
+import option ;
+# Backslash because of `bcp --namespace`
+import tools/boost\_install/boost-install ;
+
+path-constant BOOST_ROOT : . ;
+constant BOOST_VERSION : 1.75.0 ;
+constant BOOST_JAMROOT_MODULE : $(__name__) ;
+
+# Allow subprojects to simply `import config : requires ;` to get access to the requires rule
+modules.poke : BOOST_BUILD_PATH : $(BOOST_ROOT)/libs/config/checks [ modules.peek : BOOST_BUILD_PATH ] ;
+
+boostcpp.set-version $(BOOST_VERSION) ;
+
+use-project /boost/architecture : libs/config/checks/architecture ;
+
+local all-headers =
+ [ MATCH .*libs/(.*)/include/boost : [ glob libs/*/include/boost libs/*/*/include/boost ] ] ;
+
+for dir in $(all-headers)
+{
+ link-directory $(dir)-headers : libs/$(dir)/include/boost : . ;
+ explicit $(dir)-headers ;
+}
+
+if $(all-headers)
+{
+ constant BOOST_MODULARLAYOUT : $(all-headers) ;
+}
+
+project boost
+ : requirements .
+
+ [ boostcpp.architecture ]
+ [ boostcpp.address-model ]
+
+ # Disable auto-linking for all targets here, primarily because it caused
+ # troubles with V2.
+ BOOST_ALL_NO_LIB=1
+ # Used to encode variant in target name. See the 'tag' rule below.
+ @$(__name__).tag
+ @handle-static-runtime
+ # Comeau does not support shared lib
+ como:static
+ como-linux:_GNU_SOURCE=1
+ # When building docs within Boost, we want the standard Boost style
+ boost.defaults=Boost
+ @threadapi-feature.detect
+ : usage-requirements .
+ : default-build
+ hidden
+ multi
+ : build-dir bin.v2
+ ;
+
+# This rule is called by Boost.Build to determine the name of target. We use it
+# to encode the build variant, compiler name and boost version in the target
+# name.
+#
+rule tag ( name : type ? : property-set )
+{
+ return [ boostcpp.tag $(name) : $(type) : $(property-set) ] ;
+}
+
+rule python-tag ( name : type ? : property-set )
+{
+ return [ boostcpp.python-tag $(name) : $(type) : $(property-set) ] ;
+}
+
+rule handle-static-runtime ( properties * )
+{
+ # Using static runtime with shared libraries is impossible on Linux, and
+ # dangerous on Windows. Therefore, we disallow it. This might be drastic,
+ # but it was disabled for a while without anybody complaining.
+
+ # For CW, static runtime is needed so that std::locale works.
+ if shared in $(properties) && static in $(properties) &&
+ ! ( cw in $(properties) )
+ {
+ if ! $(.shared-static-warning-emitted)
+ {
+ ECHO "warning: skipping configuration link=shared, runtime-link=static" ;
+ ECHO "warning: this combination is either impossible or too dangerous" ;
+ ECHO "warning: to be of any use" ;
+ .shared-static-warning-emitted = 1 ;
+ }
+
+ return no ;
+ }
+}
+
+all-libraries = [ MATCH .*libs/(.*)/build/.* : [ glob libs/*/build/Jamfile.v2 ]
+ [ glob libs/*/build/Jamfile ] ] ;
+
+all-libraries = [ sequence.unique $(all-libraries) ] ;
+# The function_types library has a Jamfile, but it's used for maintenance
+# purposes, there's no library to build and install.
+all-libraries = [ set.difference $(all-libraries) : function_types ] ;
+
+# Setup convenient aliases for all libraries.
+
+local rule explicit-alias ( id : targets + )
+{
+ alias $(id) : $(targets) ;
+ explicit $(id) ;
+}
+
+# First, the complicated libraries: where the target name in Jamfile is
+# different from its directory name.
+explicit-alias prg_exec_monitor : libs/test/build//boost_prg_exec_monitor ;
+explicit-alias test_exec_monitor : libs/test/build//boost_test_exec_monitor ;
+explicit-alias unit_test_framework : libs/test/build//boost_unit_test_framework ;
+explicit-alias bgl-vis : libs/graps/build//bgl-vis ;
+explicit-alias serialization : libs/serialization/build//boost_serialization ;
+explicit-alias wserialization : libs/serialization/build//boost_wserialization ;
+for local l in $(all-libraries)
+{
+ if ! $(l) in test graph serialization headers
+ {
+ explicit-alias $(l) : libs/$(l)/build//boost_$(l) ;
+ }
+}
+
+# Log has an additional target
+explicit-alias log_setup : libs/log/build//boost_log_setup ;
+
+rule do-nothing { }
+
+rule generate-alias ( project name : property-set : sources * )
+{
+ local action-name = [ $(property-set).get ] ;
+ local m = [ MATCH ^@(.*) : $(action-name) ] ;
+ property-set = [ property-set.empty ] ;
+ local action = [ new action $(sources) : $(m[1]) : $(property-set) ] ;
+ local t = [ new notfile-target $(name) : $(project) : $(action) ] ;
+ return [ virtual-target.register $(t) ] ;
+}
+
+generate headers : $(all-headers)-headers : @generate-alias @do-nothing : : . ;
+
+#alias headers : $(all-headers)-headers : : : . ;
+explicit headers ;
+
+# Make project ids of all libraries known.
+for local l in $(all-libraries)
+{
+ use-project /boost/$(l) : libs/$(l)/build ;
+}
+
+if [ path.exists $(BOOST_ROOT)/tools/inspect/build ]
+{
+ use-project /boost/tools/inspect : tools/inspect/build ;
+}
+
+if [ path.exists $(BOOST_ROOT)/libs/wave/tool/build ]
+{
+ use-project /boost/libs/wave/tool : libs/wave/tool/build ;
+}
+
+# Make the boost-install rule visible in subprojects
+
+# This rule should be called from libraries' Jamfiles and will create two
+# targets, "install" and "stage", that will install or stage that library. The
+# --prefix option is respected, but --with and --without options, naturally, are
+# ignored.
+#
+# - libraries -- list of library targets to install.
+
+rule boost-install ( libraries * )
+{
+ boost-install.boost-install $(libraries) ;
+}
+
+# Creates a library target, adding autolink support and also creates
+# stage and install targets via boost-install, above.
+rule boost-lib ( name : sources * : requirements * : default-build * : usage-requirements * )
+{
+ autolink = shared:BOOST_$(name:U)_DYN_LINK=1 ;
+ name = boost_$(name) ;
+ lib $(name)
+ : $(sources)
+ : $(requirements) $(autolink)
+ : $(default-build)
+ : $(usage-requirements) $(autolink)
+ ;
+ boost-install $(name) ;
+}
+
+
+# Declare special top-level targets that build and install the desired variants
+# of the libraries.
+boostcpp.declare-targets $(all-libraries) ;
diff --git a/cpp/thirdparty/boost_1_75_0/boost.png b/cpp/thirdparty/boost_1_75_0/boost.png
new file mode 100644
index 0000000000..b4d51fcd5c
Binary files /dev/null and b/cpp/thirdparty/boost_1_75_0/boost.png differ
diff --git a/cpp/thirdparty/boost_1_75_0/boost/algorithm/cxx11/all_of.hpp b/cpp/thirdparty/boost_1_75_0/boost/algorithm/cxx11/all_of.hpp
new file mode 100644
index 0000000000..f7ee311b28
--- /dev/null
+++ b/cpp/thirdparty/boost_1_75_0/boost/algorithm/cxx11/all_of.hpp
@@ -0,0 +1,84 @@
+/*
+ Copyright (c) Marshall Clow 2008-2012.
+
+ 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 all_of.hpp
+/// \brief Test ranges to see if all elements match a value or predicate.
+/// \author Marshall Clow
+
+#ifndef BOOST_ALGORITHM_ALL_OF_HPP
+#define BOOST_ALGORITHM_ALL_OF_HPP
+
+#include
+#include
+#include
+
+namespace boost { namespace algorithm {
+
+/// \fn all_of ( InputIterator first, InputIterator last, Predicate p )
+/// \return true if all elements in [first, last) satisfy the predicate 'p'
+/// \note returns true on an empty range
+///
+/// \param first The start of the input sequence
+/// \param last One past the end of the input sequence
+/// \param p A predicate for testing the elements of the sequence
+///
+/// \note This function is part of the C++2011 standard library.
+template
+BOOST_CXX14_CONSTEXPR bool all_of ( InputIterator first, InputIterator last, Predicate p )
+{
+ for ( ; first != last; ++first )
+ if ( !p(*first))
+ return false;
+ return true;
+}
+
+/// \fn all_of ( const Range &r, Predicate p )
+/// \return true if all elements in the range satisfy the predicate 'p'
+/// \note returns true on an empty range
+///
+/// \param r The input range
+/// \param p A predicate for testing the elements of the range
+///
+template
+BOOST_CXX14_CONSTEXPR bool all_of ( const Range &r, Predicate p )
+{
+ return boost::algorithm::all_of ( boost::begin (r), boost::end (r), p );
+}
+
+/// \fn all_of_equal ( InputIterator first, InputIterator last, const T &val )
+/// \return true if all elements in [first, last) are equal to 'val'
+/// \note returns true on an empty range
+///
+/// \param first The start of the input sequence
+/// \param last One past the end of the input sequence
+/// \param val A value to compare against
+///
+template
+BOOST_CXX14_CONSTEXPR bool all_of_equal ( InputIterator first, InputIterator last, const T &val )
+{
+ for ( ; first != last; ++first )
+ if ( val != *first )
+ return false;
+ return true;
+}
+
+/// \fn all_of_equal ( const Range &r, const T &val )
+/// \return true if all elements in the range are equal to 'val'
+/// \note returns true on an empty range
+///
+/// \param r The input range
+/// \param val A value to compare against
+///
+template
+BOOST_CXX14_CONSTEXPR bool all_of_equal ( const Range &r, const T &val )
+{
+ return boost::algorithm::all_of_equal ( boost::begin (r), boost::end (r), val );
+}
+
+}} // namespace boost and algorithm
+
+#endif // BOOST_ALGORITHM_ALL_OF_HPP
diff --git a/cpp/thirdparty/boost_1_75_0/boost/algorithm/string/classification.hpp b/cpp/thirdparty/boost_1_75_0/boost/algorithm/string/classification.hpp
new file mode 100644
index 0000000000..ca43602d47
--- /dev/null
+++ b/cpp/thirdparty/boost_1_75_0/boost/algorithm/string/classification.hpp
@@ -0,0 +1,312 @@
+// Boost string_algo library classification.hpp header file ---------------------------//
+
+// Copyright Pavol Droba 2002-2003.
+//
+// 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)
+
+// See http://www.boost.org/ for updates, documentation, and revision history.
+
+#ifndef BOOST_STRING_CLASSIFICATION_HPP
+#define BOOST_STRING_CLASSIFICATION_HPP
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+/*! \file
+ Classification predicates are included in the library to give
+ some more convenience when using algorithms like \c trim() and \c all().
+ They wrap functionality of STL classification functions ( e.g. \c std::isspace() )
+ into generic functors.
+*/
+
+namespace boost {
+ namespace algorithm {
+
+// classification functor generator -------------------------------------//
+
+ //! is_classified predicate
+ /*!
+ Construct the \c is_classified predicate. This predicate holds if the input is
+ of specified \c std::ctype category.
+
+ \param Type A \c std::ctype category
+ \param Loc A locale used for classification
+ \return An instance of the \c is_classified predicate
+ */
+ inline detail::is_classifiedF
+ is_classified(std::ctype_base::mask Type, const std::locale& Loc=std::locale())
+ {
+ return detail::is_classifiedF(Type, Loc);
+ }
+
+ //! is_space predicate
+ /*!
+ Construct the \c is_classified predicate for the \c ctype_base::space category.
+
+ \param Loc A locale used for classification
+ \return An instance of the \c is_classified predicate
+ */
+ inline detail::is_classifiedF
+ is_space(const std::locale& Loc=std::locale())
+ {
+ return detail::is_classifiedF(std::ctype_base::space, Loc);
+ }
+
+ //! is_alnum predicate
+ /*!
+ Construct the \c is_classified predicate for the \c ctype_base::alnum category.
+
+ \param Loc A locale used for classification
+ \return An instance of the \c is_classified predicate
+ */
+ inline detail::is_classifiedF
+ is_alnum(const std::locale& Loc=std::locale())
+ {
+ return detail::is_classifiedF(std::ctype_base::alnum, Loc);
+ }
+
+ //! is_alpha predicate
+ /*!
+ Construct the \c is_classified predicate for the \c ctype_base::alpha category.
+
+ \param Loc A locale used for classification
+ \return An instance of the \c is_classified predicate
+ */
+ inline detail::is_classifiedF
+ is_alpha(const std::locale& Loc=std::locale())
+ {
+ return detail::is_classifiedF(std::ctype_base::alpha, Loc);
+ }
+
+ //! is_cntrl predicate
+ /*!
+ Construct the \c is_classified predicate for the \c ctype_base::cntrl category.
+
+ \param Loc A locale used for classification
+ \return An instance of the \c is_classified predicate
+ */
+ inline detail::is_classifiedF
+ is_cntrl(const std::locale& Loc=std::locale())
+ {
+ return detail::is_classifiedF(std::ctype_base::cntrl, Loc);
+ }
+
+ //! is_digit predicate
+ /*!
+ Construct the \c is_classified predicate for the \c ctype_base::digit category.
+
+ \param Loc A locale used for classification
+ \return An instance of the \c is_classified predicate
+ */
+ inline detail::is_classifiedF
+ is_digit(const std::locale& Loc=std::locale())
+ {
+ return detail::is_classifiedF(std::ctype_base::digit, Loc);
+ }
+
+ //! is_graph predicate
+ /*!
+ Construct the \c is_classified predicate for the \c ctype_base::graph category.
+
+ \param Loc A locale used for classification
+ \return An instance of the \c is_classified predicate
+ */
+ inline detail::is_classifiedF
+ is_graph(const std::locale& Loc=std::locale())
+ {
+ return detail::is_classifiedF(std::ctype_base::graph, Loc);
+ }
+
+ //! is_lower predicate
+ /*!
+ Construct the \c is_classified predicate for the \c ctype_base::lower category.
+
+ \param Loc A locale used for classification
+ \return An instance of \c is_classified predicate
+ */
+ inline detail::is_classifiedF
+ is_lower(const std::locale& Loc=std::locale())
+ {
+ return detail::is_classifiedF(std::ctype_base::lower, Loc);
+ }
+
+ //! is_print predicate
+ /*!
+ Construct the \c is_classified predicate for the \c ctype_base::print category.
+
+ \param Loc A locale used for classification
+ \return An instance of the \c is_classified predicate
+ */
+ inline detail::is_classifiedF
+ is_print(const std::locale& Loc=std::locale())
+ {
+ return detail::is_classifiedF(std::ctype_base::print, Loc);
+ }
+
+ //! is_punct predicate
+ /*!
+ Construct the \c is_classified predicate for the \c ctype_base::punct category.
+
+ \param Loc A locale used for classification
+ \return An instance of the \c is_classified predicate
+ */
+ inline detail::is_classifiedF
+ is_punct(const std::locale& Loc=std::locale())
+ {
+ return detail::is_classifiedF(std::ctype_base::punct, Loc);
+ }
+
+ //! is_upper predicate
+ /*!
+ Construct the \c is_classified predicate for the \c ctype_base::upper category.
+
+ \param Loc A locale used for classification
+ \return An instance of the \c is_classified predicate
+ */
+ inline detail::is_classifiedF
+ is_upper(const std::locale& Loc=std::locale())
+ {
+ return detail::is_classifiedF(std::ctype_base::upper, Loc);
+ }
+
+ //! is_xdigit predicate
+ /*!
+ Construct the \c is_classified predicate for the \c ctype_base::xdigit category.
+
+ \param Loc A locale used for classification
+ \return An instance of the \c is_classified predicate
+ */
+ inline detail::is_classifiedF
+ is_xdigit(const std::locale& Loc=std::locale())
+ {
+ return detail::is_classifiedF(std::ctype_base::xdigit, Loc);
+ }
+
+ //! is_any_of predicate
+ /*!
+ Construct the \c is_any_of predicate. The predicate holds if the input
+ is included in the specified set of characters.
+
+ \param Set A set of characters to be recognized
+ \return An instance of the \c is_any_of predicate
+ */
+ template
+ inline detail::is_any_ofF<
+ BOOST_STRING_TYPENAME range_value::type>
+ is_any_of( const RangeT& Set )
+ {
+ iterator_range::type> lit_set(boost::as_literal(Set));
+ return detail::is_any_ofF::type>(lit_set);
+ }
+
+ //! is_from_range predicate
+ /*!
+ Construct the \c is_from_range predicate. The predicate holds if the input
+ is included in the specified range. (i.e. From <= Ch <= To )
+
+ \param From The start of the range
+ \param To The end of the range
+ \return An instance of the \c is_from_range predicate
+ */
+ template
+ inline detail::is_from_rangeF is_from_range(CharT From, CharT To)
+ {
+ return detail::is_from_rangeF(From,To);
+ }
+
+ // predicate combinators ---------------------------------------------------//
+
+ //! predicate 'and' composition predicate
+ /*!
+ Construct the \c class_and predicate. This predicate can be used
+ to logically combine two classification predicates. \c class_and holds,
+ if both predicates return true.
+
+ \param Pred1 The first predicate
+ \param Pred2 The second predicate
+ \return An instance of the \c class_and predicate
+ */
+ template
+ inline detail::pred_andF
+ operator&&(
+ const predicate_facade& Pred1,
+ const predicate_facade& Pred2 )
+ {
+ // Doing the static_cast with the pointer instead of the reference
+ // is a workaround for some compilers which have problems with
+ // static_cast's of template references, i.e. CW8. /grafik/
+ return detail::pred_andF(
+ *static_cast(&Pred1),
+ *static_cast(&Pred2) );
+ }
+
+ //! predicate 'or' composition predicate
+ /*!
+ Construct the \c class_or predicate. This predicate can be used
+ to logically combine two classification predicates. \c class_or holds,
+ if one of the predicates return true.
+
+ \param Pred1 The first predicate
+ \param Pred2 The second predicate
+ \return An instance of the \c class_or predicate
+ */
+ template
+ inline detail::pred_orF
+ operator||(
+ const predicate_facade& Pred1,
+ const predicate_facade& Pred2 )
+ {
+ // Doing the static_cast with the pointer instead of the reference
+ // is a workaround for some compilers which have problems with
+ // static_cast's of template references, i.e. CW8. /grafik/
+ return detail::pred_orF(
+ *static_cast(&Pred1),
+ *static_cast(&Pred2));
+ }
+
+ //! predicate negation operator
+ /*!
+ Construct the \c class_not predicate. This predicate represents a negation.
+ \c class_or holds if of the predicates return false.
+
+ \param Pred The predicate to be negated
+ \return An instance of the \c class_not predicate
+ */
+ template
+ inline detail::pred_notF
+ operator!( const predicate_facade& Pred )
+ {
+ // Doing the static_cast with the pointer instead of the reference
+ // is a workaround for some compilers which have problems with
+ // static_cast's of template references, i.e. CW8. /grafik/
+ return detail::pred_notF(*static_cast(&Pred));
+ }
+
+ } // namespace algorithm
+
+ // pull names to the boost namespace
+ using algorithm::is_classified;
+ using algorithm::is_space;
+ using algorithm::is_alnum;
+ using algorithm::is_alpha;
+ using algorithm::is_cntrl;
+ using algorithm::is_digit;
+ using algorithm::is_graph;
+ using algorithm::is_lower;
+ using algorithm::is_upper;
+ using algorithm::is_print;
+ using algorithm::is_punct;
+ using algorithm::is_xdigit;
+ using algorithm::is_any_of;
+ using algorithm::is_from_range;
+
+} // namespace boost
+
+#endif // BOOST_STRING_PREDICATE_HPP
diff --git a/cpp/thirdparty/boost_1_75_0/boost/algorithm/string/compare.hpp b/cpp/thirdparty/boost_1_75_0/boost/algorithm/string/compare.hpp
new file mode 100644
index 0000000000..dc34007cf0
--- /dev/null
+++ b/cpp/thirdparty/boost_1_75_0/boost/algorithm/string/compare.hpp
@@ -0,0 +1,199 @@
+// Boost string_algo library compare.hpp header file -------------------------//
+
+// Copyright Pavol Droba 2002-2006.
+//
+// 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)
+
+// See http://www.boost.org/ for updates, documentation, and revision history.
+
+#ifndef BOOST_STRING_COMPARE_HPP
+#define BOOST_STRING_COMPARE_HPP
+
+#include
+#include
+
+/*! \file
+ Defines element comparison predicates. Many algorithms in this library can
+ take an additional argument with a predicate used to compare elements.
+ This makes it possible, for instance, to have case insensitive versions
+ of the algorithms.
+*/
+
+namespace boost {
+ namespace algorithm {
+
+ // is_equal functor -----------------------------------------------//
+
+ //! is_equal functor
+ /*!
+ Standard STL equal_to only handle comparison between arguments
+ of the same type. This is a less restrictive version which wraps operator ==.
+ */
+ struct is_equal
+ {
+ //! Function operator
+ /*!
+ Compare two operands for equality
+ */
+ template< typename T1, typename T2 >
+ bool operator()( const T1& Arg1, const T2& Arg2 ) const
+ {
+ return Arg1==Arg2;
+ }
+ };
+
+ //! case insensitive version of is_equal
+ /*!
+ Case insensitive comparison predicate. Comparison is done using
+ specified locales.
+ */
+ struct is_iequal
+ {
+ //! Constructor
+ /*!
+ \param Loc locales used for comparison
+ */
+ is_iequal( const std::locale& Loc=std::locale() ) :
+ m_Loc( Loc ) {}
+
+ //! Function operator
+ /*!
+ Compare two operands. Case is ignored.
+ */
+ template< typename T1, typename T2 >
+ bool operator()( const T1& Arg1, const T2& Arg2 ) const
+ {
+ #if defined(BOOST_BORLANDC) && (BOOST_BORLANDC >= 0x560) && (BOOST_BORLANDC <= 0x564) && !defined(_USE_OLD_RW_STL)
+ return std::toupper(Arg1)==std::toupper(Arg2);
+ #else
+ return std::toupper(Arg1,m_Loc)==std::toupper(Arg2,m_Loc);
+ #endif
+ }
+
+ private:
+ std::locale m_Loc;
+ };
+
+ // is_less functor -----------------------------------------------//
+
+ //! is_less functor
+ /*!
+ Convenient version of standard std::less. Operation is templated, therefore it is
+ not required to specify the exact types upon the construction
+ */
+ struct is_less
+ {
+ //! Functor operation
+ /*!
+ Compare two operands using > operator
+ */
+ template< typename T1, typename T2 >
+ bool operator()( const T1& Arg1, const T2& Arg2 ) const
+ {
+ return Arg1
+ bool operator()( const T1& Arg1, const T2& Arg2 ) const
+ {
+ #if defined(BOOST_BORLANDC) && (BOOST_BORLANDC >= 0x560) && (BOOST_BORLANDC <= 0x564) && !defined(_USE_OLD_RW_STL)
+ return std::toupper(Arg1)(Arg1,m_Loc)(Arg2,m_Loc);
+ #endif
+ }
+
+ private:
+ std::locale m_Loc;
+ };
+
+ // is_not_greater functor -----------------------------------------------//
+
+ //! is_not_greater functor
+ /*!
+ Convenient version of standard std::not_greater_to. Operation is templated, therefore it is
+ not required to specify the exact types upon the construction
+ */
+ struct is_not_greater
+ {
+ //! Functor operation
+ /*!
+ Compare two operands using > operator
+ */
+ template< typename T1, typename T2 >
+ bool operator()( const T1& Arg1, const T2& Arg2 ) const
+ {
+ return Arg1<=Arg2;
+ }
+ };
+
+
+ //! case insensitive version of is_not_greater
+ /*!
+ Case insensitive comparison predicate. Comparison is done using
+ specified locales.
+ */
+ struct is_not_igreater
+ {
+ //! Constructor
+ /*!
+ \param Loc locales used for comparison
+ */
+ is_not_igreater( const std::locale& Loc=std::locale() ) :
+ m_Loc( Loc ) {}
+
+ //! Function operator
+ /*!
+ Compare two operands. Case is ignored.
+ */
+ template< typename T1, typename T2 >
+ bool operator()( const T1& Arg1, const T2& Arg2 ) const
+ {
+ #if defined(BOOST_BORLANDC) && (BOOST_BORLANDC >= 0x560) && (BOOST_BORLANDC <= 0x564) && !defined(_USE_OLD_RW_STL)
+ return std::toupper(Arg1)<=std::toupper(Arg2);
+ #else
+ return std::toupper(Arg1,m_Loc)<=std::toupper(Arg2,m_Loc);
+ #endif
+ }
+
+ private:
+ std::locale m_Loc;
+ };
+
+
+ } // namespace algorithm
+
+ // pull names to the boost namespace
+ using algorithm::is_equal;
+ using algorithm::is_iequal;
+ using algorithm::is_less;
+ using algorithm::is_iless;
+ using algorithm::is_not_greater;
+ using algorithm::is_not_igreater;
+
+} // namespace boost
+
+
+#endif // BOOST_STRING_COMPARE_HPP
diff --git a/cpp/thirdparty/boost_1_75_0/boost/algorithm/string/concept.hpp b/cpp/thirdparty/boost_1_75_0/boost/algorithm/string/concept.hpp
new file mode 100644
index 0000000000..17e8349596
--- /dev/null
+++ b/cpp/thirdparty/boost_1_75_0/boost/algorithm/string/concept.hpp
@@ -0,0 +1,83 @@
+// Boost string_algo library concept.hpp header file ---------------------------//
+
+// Copyright Pavol Droba 2002-2003.
+//
+// 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)
+
+// See http://www.boost.org/ for updates, documentation, and revision history.
+
+#ifndef BOOST_STRING_CONCEPT_HPP
+#define BOOST_STRING_CONCEPT_HPP
+
+#include
+#include
+#include
+#include
+
+/*! \file
+ Defines concepts used in string_algo library
+*/
+
+namespace boost {
+ namespace algorithm {
+
+ //! Finder concept
+ /*!
+ Defines the Finder concept. Finder is a functor which selects
+ an arbitrary part of a string. Search is performed on
+ the range specified by starting and ending iterators.
+
+ Result of the find operation must be convertible to iterator_range.
+ */
+ template
+ struct FinderConcept
+ {
+ private:
+ typedef iterator_range range;
+ public:
+ void constraints()
+ {
+ // Operation
+ r=(*pF)(i,i);
+ }
+ private:
+ range r;
+ IteratorT i;
+ FinderT* pF;
+ }; // Finder_concept
+
+
+ //! Formatter concept
+ /*!
+ Defines the Formatter concept. Formatter is a functor, which
+ takes a result from a finder operation and transforms it
+ in a specific way.
+
+ Result must be a container supported by container_traits,
+ or a reference to it.
+ */
+ template
+ struct FormatterConcept
+ {
+ public:
+ void constraints()
+ {
+ // Operation
+ ::boost::begin((*pFo)( (*pF)(i,i) ));
+ ::boost::end((*pFo)( (*pF)(i,i) ));
+ }
+ private:
+ IteratorT i;
+ FinderT* pF;
+ FormatterT *pFo;
+ }; // FormatterConcept;
+
+ } // namespace algorithm
+} // namespace boost
+
+
+
+
+#endif // BOOST_STRING_CONCEPT_HPP
diff --git a/cpp/thirdparty/boost_1_75_0/boost/algorithm/string/config.hpp b/cpp/thirdparty/boost_1_75_0/boost/algorithm/string/config.hpp
new file mode 100644
index 0000000000..559750ac8a
--- /dev/null
+++ b/cpp/thirdparty/boost_1_75_0/boost/algorithm/string/config.hpp
@@ -0,0 +1,28 @@
+// Boost string_algo library config.hpp header file ---------------------------//
+
+// Copyright Pavol Droba 2002-2003.
+//
+// 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)
+
+// See http://www.boost.org/ for updates, documentation, and revision history.
+
+#ifndef BOOST_STRING_CONFIG_HPP
+#define BOOST_STRING_CONFIG_HPP
+
+#include
+#include
+
+#ifdef BOOST_STRING_DEDUCED_TYPENAME
+# error "macro already defined!"
+#endif
+
+#define BOOST_STRING_TYPENAME BOOST_DEDUCED_TYPENAME
+
+// Metrowerks workaround
+#if BOOST_WORKAROUND(__MWERKS__, <= 0x3003) // 8.x
+#pragma parse_func_templ off
+#endif
+
+#endif // BOOST_STRING_CONFIG_HPP
diff --git a/cpp/thirdparty/boost_1_75_0/boost/algorithm/string/constants.hpp b/cpp/thirdparty/boost_1_75_0/boost/algorithm/string/constants.hpp
new file mode 100644
index 0000000000..6ed70effca
--- /dev/null
+++ b/cpp/thirdparty/boost_1_75_0/boost/algorithm/string/constants.hpp
@@ -0,0 +1,36 @@
+// Boost string_algo library constants.hpp header file ---------------------------//
+
+// Copyright Pavol Droba 2002-2003.
+//
+// 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)
+
+// See http://www.boost.org/ for updates, documentation, and revision history.
+
+#ifndef BOOST_STRING_CONSTANTS_HPP
+#define BOOST_STRING_CONSTANTS_HPP
+
+namespace boost {
+ namespace algorithm {
+
+ //! Token compression mode
+ /*!
+ Specifies token compression mode for the token_finder.
+ */
+ enum token_compress_mode_type
+ {
+ token_compress_on, //!< Compress adjacent tokens
+ token_compress_off //!< Do not compress adjacent tokens
+ };
+
+ } // namespace algorithm
+
+ // pull the names to the boost namespace
+ using algorithm::token_compress_on;
+ using algorithm::token_compress_off;
+
+} // namespace boost
+
+#endif // BOOST_STRING_CONSTANTS_HPP
+
diff --git a/cpp/thirdparty/boost_1_75_0/boost/algorithm/string/detail/classification.hpp b/cpp/thirdparty/boost_1_75_0/boost/algorithm/string/detail/classification.hpp
new file mode 100644
index 0000000000..30a37c698e
--- /dev/null
+++ b/cpp/thirdparty/boost_1_75_0/boost/algorithm/string/detail/classification.hpp
@@ -0,0 +1,355 @@
+// Boost string_algo library classification.hpp header file ---------------------------//
+
+// Copyright Pavol Droba 2002-2003.
+//
+// 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)
+
+// See http://www.boost.org/ for updates, documentation, and revision history.
+
+#ifndef BOOST_STRING_CLASSIFICATION_DETAIL_HPP
+#define BOOST_STRING_CLASSIFICATION_DETAIL_HPP
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+
+namespace boost {
+ namespace algorithm {
+ namespace detail {
+
+// classification functors -----------------------------------------------//
+
+ // is_classified functor
+ struct is_classifiedF :
+ public predicate_facade
+ {
+ // Boost.ResultOf support
+ typedef bool result_type;
+
+ // Constructor from a locale
+ is_classifiedF(std::ctype_base::mask Type, std::locale const & Loc = std::locale()) :
+ m_Type(Type), m_Locale(Loc) {}
+ // Operation
+ template
+ bool operator()( CharT Ch ) const
+ {
+ return std::use_facet< std::ctype >(m_Locale).is( m_Type, Ch );
+ }
+
+ #if defined(BOOST_BORLANDC) && (BOOST_BORLANDC >= 0x560) && (BOOST_BORLANDC <= 0x582) && !defined(_USE_OLD_RW_STL)
+ template<>
+ bool operator()( char const Ch ) const
+ {
+ return std::use_facet< std::ctype >(m_Locale).is( m_Type, Ch );
+ }
+ #endif
+
+ private:
+ std::ctype_base::mask m_Type;
+ std::locale m_Locale;
+ };
+
+
+ // is_any_of functor
+ /*
+ returns true if the value is from the specified set
+ */
+ template
+ struct is_any_ofF :
+ public predicate_facade >
+ {
+ private:
+ // set cannot operate on const value-type
+ typedef typename ::boost::remove_const::type set_value_type;
+
+ public:
+ // Boost.ResultOf support
+ typedef bool result_type;
+
+ // Constructor
+ template
+ is_any_ofF( const RangeT& Range ) : m_Size(0)
+ {
+ // Prepare storage
+ m_Storage.m_dynSet=0;
+
+ std::size_t Size=::boost::distance(Range);
+ m_Size=Size;
+ set_value_type* Storage=0;
+
+ if(use_fixed_storage(m_Size))
+ {
+ // Use fixed storage
+ Storage=&m_Storage.m_fixSet[0];
+ }
+ else
+ {
+ // Use dynamic storage
+ m_Storage.m_dynSet=new set_value_type[m_Size];
+ Storage=m_Storage.m_dynSet;
+ }
+
+ // Use fixed storage
+ ::std::copy(::boost::begin(Range), ::boost::end(Range), Storage);
+ ::std::sort(Storage, Storage+m_Size);
+ }
+
+ // Copy constructor
+ is_any_ofF(const is_any_ofF& Other) : m_Size(Other.m_Size)
+ {
+ // Prepare storage
+ m_Storage.m_dynSet=0;
+ const set_value_type* SrcStorage=0;
+ set_value_type* DestStorage=0;
+
+ if(use_fixed_storage(m_Size))
+ {
+ // Use fixed storage
+ DestStorage=&m_Storage.m_fixSet[0];
+ SrcStorage=&Other.m_Storage.m_fixSet[0];
+ }
+ else
+ {
+ // Use dynamic storage
+ m_Storage.m_dynSet=new set_value_type[m_Size];
+ DestStorage=m_Storage.m_dynSet;
+ SrcStorage=Other.m_Storage.m_dynSet;
+ }
+
+ // Use fixed storage
+ ::std::memcpy(DestStorage, SrcStorage, sizeof(set_value_type)*m_Size);
+ }
+
+ // Destructor
+ ~is_any_ofF()
+ {
+ if(!use_fixed_storage(m_Size) && m_Storage.m_dynSet!=0)
+ {
+ delete [] m_Storage.m_dynSet;
+ }
+ }
+
+ // Assignment
+ is_any_ofF& operator=(const is_any_ofF& Other)
+ {
+ // Handle self assignment
+ if(this==&Other) return *this;
+
+ // Prepare storage
+ const set_value_type* SrcStorage;
+ set_value_type* DestStorage;
+
+ if(use_fixed_storage(Other.m_Size))
+ {
+ // Use fixed storage
+ DestStorage=&m_Storage.m_fixSet[0];
+ SrcStorage=&Other.m_Storage.m_fixSet[0];
+
+ // Delete old storage if was present
+ if(!use_fixed_storage(m_Size) && m_Storage.m_dynSet!=0)
+ {
+ delete [] m_Storage.m_dynSet;
+ }
+
+ // Set new size
+ m_Size=Other.m_Size;
+ }
+ else
+ {
+ // Other uses dynamic storage
+ SrcStorage=Other.m_Storage.m_dynSet;
+
+ // Check what kind of storage are we using right now
+ if(use_fixed_storage(m_Size))
+ {
+ // Using fixed storage, allocate new
+ set_value_type* pTemp=new set_value_type[Other.m_Size];
+ DestStorage=pTemp;
+ m_Storage.m_dynSet=pTemp;
+ m_Size=Other.m_Size;
+ }
+ else
+ {
+ // Using dynamic storage, check if can reuse
+ if(m_Storage.m_dynSet!=0 && m_Size>=Other.m_Size && m_Size
+ bool operator()( Char2T Ch ) const
+ {
+ const set_value_type* Storage=
+ (use_fixed_storage(m_Size))
+ ? &m_Storage.m_fixSet[0]
+ : m_Storage.m_dynSet;
+
+ return ::std::binary_search(Storage, Storage+m_Size, Ch);
+ }
+ private:
+ // check if the size is eligible for fixed storage
+ static bool use_fixed_storage(std::size_t size)
+ {
+ return size<=sizeof(set_value_type*)*2;
+ }
+
+
+ private:
+ // storage
+ // The actual used storage is selected on the type
+ union
+ {
+ set_value_type* m_dynSet;
+ set_value_type m_fixSet[sizeof(set_value_type*)*2];
+ }
+ m_Storage;
+
+ // storage size
+ ::std::size_t m_Size;
+ };
+
+ // is_from_range functor
+ /*
+ returns true if the value is from the specified range.
+ (i.e. x>=From && x>=To)
+ */
+ template
+ struct is_from_rangeF :
+ public predicate_facade< is_from_rangeF >
+ {
+ // Boost.ResultOf support
+ typedef bool result_type;
+
+ // Constructor
+ is_from_rangeF( CharT From, CharT To ) : m_From(From), m_To(To) {}
+
+ // Operation
+ template
+ bool operator()( Char2T Ch ) const
+ {
+ return ( m_From <= Ch ) && ( Ch <= m_To );
+ }
+
+ private:
+ CharT m_From;
+ CharT m_To;
+ };
+
+ // class_and composition predicate
+ template
+ struct pred_andF :
+ public predicate_facade< pred_andF >
+ {
+ public:
+
+ // Boost.ResultOf support
+ typedef bool result_type;
+
+ // Constructor
+ pred_andF( Pred1T Pred1, Pred2T Pred2 ) :
+ m_Pred1(Pred1), m_Pred2(Pred2) {}
+
+ // Operation
+ template
+ bool operator()( CharT Ch ) const
+ {
+ return m_Pred1(Ch) && m_Pred2(Ch);
+ }
+
+ private:
+ Pred1T m_Pred1;
+ Pred2T m_Pred2;
+ };
+
+ // class_or composition predicate
+ template
+ struct pred_orF :
+ public predicate_facade< pred_orF >
+ {
+ public:
+ // Boost.ResultOf support
+ typedef bool result_type;
+
+ // Constructor
+ pred_orF( Pred1T Pred1, Pred2T Pred2 ) :
+ m_Pred1(Pred1), m_Pred2(Pred2) {}
+
+ // Operation
+ template
+ bool operator()( CharT Ch ) const
+ {
+ return m_Pred1(Ch) || m_Pred2(Ch);
+ }
+
+ private:
+ Pred1T m_Pred1;
+ Pred2T m_Pred2;
+ };
+
+ // class_not composition predicate
+ template< typename PredT >
+ struct pred_notF :
+ public predicate_facade< pred_notF >
+ {
+ public:
+ // Boost.ResultOf support
+ typedef bool result_type;
+
+ // Constructor
+ pred_notF( PredT Pred ) : m_Pred(Pred) {}
+
+ // Operation
+ template
+ bool operator()( CharT Ch ) const
+ {
+ return !m_Pred(Ch);
+ }
+
+ private:
+ PredT m_Pred;
+ };
+
+ } // namespace detail
+ } // namespace algorithm
+} // namespace boost
+
+
+#endif // BOOST_STRING_CLASSIFICATION_DETAIL_HPP
diff --git a/cpp/thirdparty/boost_1_75_0/boost/algorithm/string/detail/find_iterator.hpp b/cpp/thirdparty/boost_1_75_0/boost/algorithm/string/detail/find_iterator.hpp
new file mode 100644
index 0000000000..4f90a98fc0
--- /dev/null
+++ b/cpp/thirdparty/boost_1_75_0/boost/algorithm/string/detail/find_iterator.hpp
@@ -0,0 +1,87 @@
+// Boost string_algo library find_iterator.hpp header file ---------------------------//
+
+// Copyright Pavol Droba 2002-2003.
+//
+// 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)
+
+// See http://www.boost.org/ for updates, documentation, and revision history.
+
+#ifndef BOOST_STRING_FIND_ITERATOR_DETAIL_HPP
+#define BOOST_STRING_FIND_ITERATOR_DETAIL_HPP
+
+#include
+#include
+#include
+#include
+#include
+
+namespace boost {
+ namespace algorithm {
+ namespace detail {
+
+// find_iterator base -----------------------------------------------//
+
+ // Find iterator base
+ template
+ class find_iterator_base
+ {
+ protected:
+ // typedefs
+ typedef IteratorT input_iterator_type;
+ typedef iterator_range match_type;
+ typedef function2<
+ match_type,
+ input_iterator_type,
+ input_iterator_type> finder_type;
+
+ protected:
+ // Protected construction/destruction
+
+ // Default constructor
+ find_iterator_base() {}
+ // Copy construction
+ find_iterator_base( const find_iterator_base& Other ) :
+ m_Finder(Other.m_Finder) {}
+
+ // Constructor
+ template
+ find_iterator_base( FinderT Finder, int ) :
+ m_Finder(Finder) {}
+
+ // Destructor
+ ~find_iterator_base() {}
+
+ // Find operation
+ match_type do_find(
+ input_iterator_type Begin,
+ input_iterator_type End ) const
+ {
+ if (!m_Finder.empty())
+ {
+ return m_Finder(Begin,End);
+ }
+ else
+ {
+ return match_type(End,End);
+ }
+ }
+
+ // Check
+ bool is_null() const
+ {
+ return m_Finder.empty();
+ }
+
+ private:
+ // Finder
+ finder_type m_Finder;
+ };
+
+ } // namespace detail
+ } // namespace algorithm
+} // namespace boost
+
+
+#endif // BOOST_STRING_FIND_ITERATOR_DETAIL_HPP
diff --git a/cpp/thirdparty/boost_1_75_0/boost/algorithm/string/detail/finder.hpp b/cpp/thirdparty/boost_1_75_0/boost/algorithm/string/detail/finder.hpp
new file mode 100644
index 0000000000..8e70240dec
--- /dev/null
+++ b/cpp/thirdparty/boost_1_75_0/boost/algorithm/string/detail/finder.hpp
@@ -0,0 +1,639 @@
+// Boost string_algo library finder.hpp header file ---------------------------//
+
+// Copyright Pavol Droba 2002-2006.
+//
+// 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)
+
+// See http://www.boost.org/ for updates, documentation, and revision history.
+
+#ifndef BOOST_STRING_FINDER_DETAIL_HPP
+#define BOOST_STRING_FINDER_DETAIL_HPP
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+namespace boost {
+ namespace algorithm {
+ namespace detail {
+
+
+// find first functor -----------------------------------------------//
+
+ // find a subsequence in the sequence ( functor )
+ /*
+ Returns a pair marking the subsequence in the sequence.
+ If the find fails, functor returns
+ */
+ template
+ struct first_finderF
+ {
+ typedef SearchIteratorT search_iterator_type;
+
+ // Construction
+ template< typename SearchT >
+ first_finderF( const SearchT& Search, PredicateT Comp ) :
+ m_Search(::boost::begin(Search), ::boost::end(Search)), m_Comp(Comp) {}
+ first_finderF(
+ search_iterator_type SearchBegin,
+ search_iterator_type SearchEnd,
+ PredicateT Comp ) :
+ m_Search(SearchBegin, SearchEnd), m_Comp(Comp) {}
+
+ // Operation
+ template< typename ForwardIteratorT >
+ iterator_range
+ operator()(
+ ForwardIteratorT Begin,
+ ForwardIteratorT End ) const
+ {
+ typedef iterator_range result_type;
+ typedef ForwardIteratorT input_iterator_type;
+
+ // Outer loop
+ for(input_iterator_type OuterIt=Begin;
+ OuterIt!=End;
+ ++OuterIt)
+ {
+ // Sanity check
+ if( boost::empty(m_Search) )
+ return result_type( End, End );
+
+ input_iterator_type InnerIt=OuterIt;
+ search_iterator_type SubstrIt=m_Search.begin();
+ for(;
+ InnerIt!=End && SubstrIt!=m_Search.end();
+ ++InnerIt,++SubstrIt)
+ {
+ if( !( m_Comp(*InnerIt,*SubstrIt) ) )
+ break;
+ }
+
+ // Substring matching succeeded
+ if ( SubstrIt==m_Search.end() )
+ return result_type( OuterIt, InnerIt );
+ }
+
+ return result_type( End, End );
+ }
+
+ private:
+ iterator_range m_Search;
+ PredicateT m_Comp;
+ };
+
+// find last functor -----------------------------------------------//
+
+ // find the last match a subsequence in the sequence ( functor )
+ /*
+ Returns a pair