diff --git a/cpp/memilio/utils/abstract_parameter_distribution.h b/cpp/memilio/utils/abstract_parameter_distribution.h index 6c30b020c7..4abfcd7919 100644 --- a/cpp/memilio/utils/abstract_parameter_distribution.h +++ b/cpp/memilio/utils/abstract_parameter_distribution.h @@ -27,10 +27,17 @@ #include "parameter_distributions.h" #include #include +#include namespace mio { +template +concept HasSampleFunction = requires(T t) { + { t.get_sample(std::declval()) } -> std::convertible_to; + { t.get_sample(std::declval()) } -> std::convertible_to; +}; + /** * @brief This class represents an arbitrary ParameterDistribution. * @see mio::ParameterDistribution @@ -44,7 +51,7 @@ class AbstractParameterDistribution * The implementation handed to the constructor should have get_sample function * overloaded with mio::RandomNumberGenerator and mio::abm::PersonalRandomNumberGenerator as input arguments */ - template + template AbstractParameterDistribution(Impl&& dist) : m_dist(std::make_shared(std::move(dist))) , sample_impl1([](void* d, RandomNumberGenerator& rng) { diff --git a/pycode/examples/simulation/abm_minimal_example.py b/pycode/examples/simulation/abm_minimal_example.py new file mode 100644 index 0000000000..c3a0ec61e8 --- /dev/null +++ b/pycode/examples/simulation/abm_minimal_example.py @@ -0,0 +1,195 @@ +############################################################################# +# Copyright (C) 2020-2026 MEmilio +# +# Authors: Carlotta Gerstein +# +# Contact: Martin J. Kuehn +# +# 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. +############################################################################# + +from memilio.simulation import AgeGroup +import memilio.simulation.abm as abm +import memilio.simulation as mio + +import numpy as np +import random + +num_age_groups = 4 + +model = abm.Model(num_age_groups) + +# Set parameters + +for age_group in range(num_age_groups): + model.parameters.TimeExposedToNoSymptoms[abm.VirusVariant.Wildtype, AgeGroup(age_group)] = mio.AbstractParameterDistribution(mio.ParameterDistributionLogNormal( + 4., 1.)) + + model.parameters.AgeGroupGotoSchool[AgeGroup(age_group)] = False + model.parameters.AgeGroupGotoWork[AgeGroup(age_group)] = False + +model.parameters.AgeGroupGotoSchool[AgeGroup(1)] = True +model.parameters.AgeGroupGotoWork[AgeGroup(2)] = True +model.parameters.AgeGroupGotoWork[AgeGroup(3)] = True + +for age in range(num_age_groups): + model.parameters.InfectionProtectionFactor[abm.ProtectionType.GenericVaccine, AgeGroup( + age), abm.VirusVariant.Wildtype] = mio.TimeSeriesFunctor( + [[0, 0.0], [14, 0.67], [180, 0.4]]) + + model.parameters.SeverityProtectionFactor[abm.ProtectionType.GenericVaccine, AgeGroup( + age), abm.VirusVariant.Wildtype] = mio.TimeSeriesFunctor( + [[0, 0.0], [14, 0.85], [180, 0.7]]) + +model.parameters.check_constraints() + +# Set populations + +n_households = 10 + +child = abm.HouseholdMember(num_age_groups) +child.age_weights[AgeGroup(0)] = 1. +child.age_weights[AgeGroup(1)] = 1. + +parent = abm.HouseholdMember(num_age_groups) +parent.age_weights[AgeGroup(2)] = 1. +parent.age_weights[AgeGroup(3)] = 1. + +twoPersonHousehold_group = abm.HouseholdGroup() +twoPersonHousehold_full = abm.Household() +twoPersonHousehold_full.add_members(child, 1) +twoPersonHousehold_full.add_members(parent, 1) +twoPersonHousehold_group.add_households(twoPersonHousehold_full, n_households) +abm.add_household_group_to_model(model, twoPersonHousehold_group) + +threePersonHousehold_group = abm.HouseholdGroup() +threePersonHousehold_full = abm.Household() +threePersonHousehold_full.add_members(child, 1) +threePersonHousehold_full.add_members(parent, 2) +threePersonHousehold_group.add_households( + threePersonHousehold_full, n_households) +abm.add_household_group_to_model(model, threePersonHousehold_group) + +# Set locations + +event = model.add_location(abm.LocationType.SocialEvent) +model.get_location(event).infection_parameters.MaximumContacts = 5 + +hospital = model.add_location(abm.LocationType.Hospital) +model.get_location(hospital).infection_parameters.MaximumContacts = 5 +icu = model.add_location(abm.LocationType.ICU) +model.get_location(icu).infection_parameters.MaximumContacts = 5 + +shop = model.add_location(abm.LocationType.BasicsShop) +model.get_location(shop).infection_parameters.MaximumContacts = 20 + +school = model.add_location(abm.LocationType.School) +model.get_location(school).infection_parameters.MaximumContacts = 20 + +work = model.add_location(abm.LocationType.Work) +model.get_location(work).infection_parameters.MaximumContacts = 20 + +model.parameters.AerosolTransmissionRates[abm.VirusVariant.Wildtype] = 10 + +contacts = np.zeros((num_age_groups, num_age_groups)) +contacts[2, 3] = 10 + +model.get_location( + work).infection_parameters.ContactRates.baseline = contacts + +# Testing Schemes + +validity_period = abm.days(1) +probability = 0.5 +start_date = abm.TimePoint(0) +end_date = abm.TimePoint(0) + abm.days(10) +test_type = abm.TestType.Antigen +test_parameters = model.parameters.TestData[test_type] + +testing_criteria_work = abm.TestingCriteria() +testing_scheme_work = abm.TestingScheme( + testing_criteria_work, validity_period, start_date, end_date, test_parameters, probability) + +model.testing_strategy.add_scheme( + abm.LocationType.Work, testing_scheme_work) + +# Seed infections + +infection_distribution = [0.5, 0.3, 0.05, 0.05, 0.05, 0.05, 0.0, 0.0] +rng = np.random.default_rng() +for person in model.persons: + infection_state = abm.InfectionState(rng.choice( + len(infection_distribution), p=infection_distribution)) + + if infection_state != abm.InfectionState.Susceptible: + person.add_new_infection(model, abm.VirusVariant.Wildtype, + person.age, model.parameters, start_date, infection_state) + +# Assign locations + +for person in model.persons: + id = person.id + + model.assign_location(id, event) + model.assign_location(id, shop) + + model.assign_location(id, hospital) + model.assign_location(id, icu) + + if person.age == AgeGroup(1): + model.assign_location(id, school) + + if person.age == AgeGroup(2) or person.age == AgeGroup(3): + model.assign_location(id, work) + +# Vaccinations + +vacc_rate = 0.7 +vaccination_priority = [AgeGroup(3), AgeGroup(2), AgeGroup(1)] +vaccination_time = start_date - abm.days(20) + +persons_by_age = [[] for _ in range(num_age_groups)] +for idx, person in enumerate(model.persons): + persons_by_age[person.age.get()].append(idx) + +for age in vaccination_priority: + indices = persons_by_age[age.get()] + + random.shuffle(indices) + + temp = vacc_rate * len(indices) + n_to_vaccinate = int(np.round(vacc_rate * len(indices))) + + count = 0 + for i in range(n_to_vaccinate): + person = model.persons[indices[i]] + if person.get_infection_state(vaccination_time) == abm.InfectionState.Susceptible: + person.add_new_vaccination( + abm.ProtectionType.GenericVaccine, vaccination_time) + +# Simulate + +t_lockdown = start_date + abm.days(10) +abm.close_social_events(t_lockdown, 0.9, model.parameters) + +t0 = start_date +tmax = t0 + abm.days(10) +sim = abm.Simulation(t0, model) + + +history = abm.TimeSeriesWriterLogInfectionStateHistory( + mio.TimeSeries(len(abm.InfectionState.values()))) + +sim.advance(tmax, history) + +history.get_log().print_table() diff --git a/pycode/memilio-simulation/memilio/simulation/bindings/math/time_series_functor.h b/pycode/memilio-simulation/memilio/simulation/bindings/math/time_series_functor.h new file mode 100644 index 0000000000..2842b2edff --- /dev/null +++ b/pycode/memilio-simulation/memilio/simulation/bindings/math/time_series_functor.h @@ -0,0 +1,48 @@ +/* +* Copyright (C) 2020-2026 MEmilio +* +* Authors: Carlotta Gerstein +* +* Contact: Martin J. Kuehn +* +* 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 "memilio/math/time_series_functor.h" +#include "memilio/math/interpolation.h" + +#include "pybind_util.h" +#include "pybind11/pybind11.h" + +namespace py = pybind11; + +namespace pymio +{ + +void bind_time_series_functor(py::module_& m, std::string const& name) +{ + bind_class, EnablePickling::Never>(m, name.c_str()) + .def(py::init()) + .def(py::init>()) + .def(py::init([](const mio::TimeSeries& data) { + return mio::TimeSeriesFunctor(mio::TimeSeriesFunctorType::LinearInterpolation, data); + })) + .def(py::init([](std::vector>&& table) { + return mio::TimeSeriesFunctor(mio::TimeSeriesFunctorType::LinearInterpolation, table); + })) + .def("__call__", [](mio::TimeSeriesFunctor& self, double time) { + return self(time); + }); +} + +} // namespace pymio diff --git a/pycode/memilio-simulation/memilio/simulation/bindings/models/abm.cpp b/pycode/memilio-simulation/memilio/simulation/bindings/models/abm.cpp index 289395bf4c..99a3f027aa 100644 --- a/pycode/memilio-simulation/memilio/simulation/bindings/models/abm.cpp +++ b/pycode/memilio-simulation/memilio/simulation/bindings/models/abm.cpp @@ -27,6 +27,9 @@ //Includes from MEmilio #include "abm/simulation.h" +#include "abm/household.h" +#include "abm/lockdown_rules.h" +#include "abm/common_abm_loggers.h" #include "pybind11/attr.h" #include "pybind11/cast.h" @@ -127,12 +130,19 @@ PYBIND11_MODULE(_simulation_abm, m) pymio::bind_CustomIndexArray, mio::abm::VirusVariant, mio::AgeGroup>( m, "_AgeParameterArray"); + pymio::bind_CustomIndexArray( + m, "_DistAgeParameterArray"); + pymio::bind_CustomIndexArray(m, "_boolAgeParameterArray"); + pymio::bind_CustomIndexArray(m, "_intAgeParameterArray"); + pymio::bind_CustomIndexArray(m, "_doubleVirusVariantArray"); pymio::bind_CustomIndexArray(m, "_TestData"); - pymio::bind_Index(m, "ProtectionTypeIndex"); + pymio::bind_CustomIndexArray, mio::abm::ProtectionType, mio::AgeGroup, + mio::abm::VirusVariant>(m, "_ProtectionFactorArray"); pymio::bind_ParameterSet(m, "ParametersBase"); pymio::bind_class(m, "Parameters") - .def(py::init()) - .def("check_constraints", &mio::abm::Parameters::check_constraints); + .def(py::init()) + .def("check_constraints", &mio::abm::Parameters::check_constraints) + .def_property_readonly("num_age_groups", &mio::abm::Parameters::get_num_groups); pymio::bind_ParameterSet( m, "LocalInfectionParameters") @@ -151,11 +161,24 @@ PYBIND11_MODULE(_simulation_abm, m) &mio::abm::Person::set_assigned_location)) .def_property_readonly("location", py::overload_cast<>(&mio::abm::Person::get_location, py::const_)) .def_property_readonly("age", &mio::abm::Person::get_age) - .def_property_readonly("is_in_quarantine", &mio::abm::Person::is_in_quarantine); + .def_property_readonly("is_in_quarantine", &mio::abm::Person::is_in_quarantine) + .def_property_readonly("id", &mio::abm::Person::get_id) + .def("add_new_infection", + [](mio::abm::Person& self, mio::abm::Model& model, mio::abm::VirusVariant variant, mio::AgeGroup age, + mio::abm::Parameters& parameters, mio::abm::TimePoint start_date, + mio::abm::InfectionState infection_state) { + mio::abm::PersonalRandomNumberGenerator person_rng(model.get_rng(), self); + self.add_new_infection( + mio::abm::Infection(person_rng, variant, age, parameters, start_date, infection_state)); + }) + .def("add_new_vaccination", &mio::abm::Person::add_new_vaccination, py::return_value_policy::reference_internal) + .def("get_infection_state", &mio::abm::Person::get_infection_state) + .def_property_readonly("vaccinations", py::overload_cast<>(&mio::abm::Person::get_vaccinations, py::const_)); pymio::bind_class(m, "TestingCriteria") .def(py::init&, const std::vector&>(), - py::arg("age_groups"), py::arg("infection_states")); + py::arg("age_groups"), py::arg("infection_states")) + .def(py::init<>()); pymio::bind_class(m, "TestingScheme") .def(py::init(m, "TestingStrategy") .def(py::init&, - const std::vector&>()); + const std::vector&>()) + .def("add_scheme", + py::overload_cast( + &mio::abm::TestingStrategy::add_scheme), + py::arg("location_type"), py::arg("testing_scheme")) + .def("add_scheme", + py::overload_cast( + &mio::abm::TestingStrategy::add_scheme), + py::arg("location_id"), py::arg("testing_scheme")); pymio::bind_class(m, "Location") + .def(py::init(), py::arg("location_type"), py::arg("loc_id")) .def_property_readonly("type", &mio::abm::Location::get_type) .def_property_readonly("id", &mio::abm::Location::get_id) .def_property("infection_parameters", @@ -210,6 +242,8 @@ PYBIND11_MODULE(_simulation_abm, m) py::keep_alive<1, 0>{}) //keep this model alive while contents are referenced in ranges .def_property_readonly("persons", py::overload_cast<>(&mio::abm::Model::get_persons, py::const_), py::keep_alive<1, 0>{}) + .def("get_location", py::overload_cast(&mio::abm::Model::get_location), + py::arg("location_id"), py::return_value_policy::reference_internal) .def_property( "trip_list", py::overload_cast<>(&mio::abm::Model::get_trip_list), [](mio::abm::Model& self, const mio::abm::TripList& list) { @@ -224,15 +258,63 @@ PYBIND11_MODULE(_simulation_abm, m) [](mio::abm::Model& self, mio::abm::TestingStrategy strategy) { self.get_testing_strategy() = strategy; }, - py::return_value_policy::reference_internal); + py::return_value_policy::reference_internal) + .def("seed_rng", [](mio::abm::Model& self, std::vector seeds) { + self.get_rng().seed(seeds); + }); pymio::bind_class, pymio::EnablePickling::Never>(m, "Simulation") .def(py::init()) - .def("advance", - static_cast::*)(mio::abm::TimePoint)>(&mio::abm::Simulation<>::advance), - py::arg("tmax")) + .def(py::init([](mio::abm::TimePoint t, mio::abm::Model& model) { + return mio::abm::Simulation(t, std::move(model)); + }), + py::return_value_policy::reference_internal) + .def( + "advance", + [](mio::abm::Simulation<>& sim, mio::abm::TimePoint tmax) { + sim.advance(tmax); + }, + py::arg("tmax")) + .def( + "advance", + [](mio::abm::Simulation<>& sim, mio::abm::TimePoint tmax, + mio::History& history) { + sim.advance(tmax, history); + }, + py::arg("tmax"), py::arg("history")) .def_property_readonly("model", py::overload_cast<>(&mio::abm::Simulation<>::get_model)); + pymio::bind_class(m, "HouseholdMember") + .def(py::init(), py::arg("num_agegroups") = 1) + .def_property("age_weights", &mio::abm::HouseholdMember::get_age_weights, + &mio::abm::HouseholdMember::set_age_weight); + + pymio::bind_class(m, "HouseholdGroup") + .def(py::init<>()) + .def("add_households", &mio::abm::HouseholdGroup::add_households) + .def_property_readonly("num_households", &mio::abm::HouseholdGroup::get_total_number_of_households); + + pymio::bind_class(m, "Household") + .def(py::init<>()) + .def("add_members", &mio::abm::Household::add_members) + .def_property_readonly("num_members", &mio::abm::Household::get_total_number_of_members); + + m.def("add_household_group_to_model", &mio::abm::add_household_group_to_model); + + pymio::bind_class(m, "Infection"); + + m.def("close_social_events", &mio::abm::close_social_events); + + pymio::bind_class, + pymio::EnablePickling::Never>(m, "TimeSeriesWriterLogInfectionStateHistory") + .def(py::init>()) + .def( + "get_log", + [](mio::History& self) { + return std::get<0>(self.get_log()); + }, + py::return_value_policy::reference_internal); + m.attr("__version__") = "dev"; } diff --git a/pycode/memilio-simulation/memilio/simulation/bindings/pybind_util.h b/pycode/memilio-simulation/memilio/simulation/bindings/pybind_util.h index dc48195817..822ded1839 100644 --- a/pycode/memilio-simulation/memilio/simulation/bindings/pybind_util.h +++ b/pycode/memilio-simulation/memilio/simulation/bindings/pybind_util.h @@ -255,7 +255,7 @@ auto bind_Range(pybind11::module_& m, const std::string& class_name) .def( "__iter__", [](Range& self) { - return self; + return Iterator{{self.begin(), self.end()}}; }, pybind11::keep_alive<1, 0>{}) //keep alive the Range as long as there is an iterator .def( diff --git a/pycode/memilio-simulation/memilio/simulation/bindings/simulation.cpp b/pycode/memilio-simulation/memilio/simulation/bindings/simulation.cpp index 5bb3793ce1..1da0f33985 100755 --- a/pycode/memilio-simulation/memilio/simulation/bindings/simulation.cpp +++ b/pycode/memilio-simulation/memilio/simulation/bindings/simulation.cpp @@ -28,7 +28,9 @@ #include "epidemiology/dynamic_npis.h" #include "epidemiology/simulation_day.h" #include "math/integrator.h" +#include "math/time_series_functor.h" #include "mobility/metapopulation_mobility_instant.h" +#include "utils/abstract_parameter_distribution.h" #include "utils/date.h" #include "utils/logging.h" #include "utils/time_series.h" @@ -36,6 +38,7 @@ #include "utils/uncertain_value.h" #include "utils/index.h" #include "utils/custom_index_array.h" +#include "utils/random_number_generator.h" //Includes from MEmilio #include "memilio/mobility/metapopulation_mobility_instant.h" @@ -53,9 +56,12 @@ PYBIND11_MODULE(_simulation, m) { pymio::bind_parameter_distribution(m, "ParameterDistribution"); pymio::bind_parameter_distribution_normal(m, "ParameterDistributionNormal"); + pymio::bind_parameter_distribution_lognormal(m, "ParameterDistributionLogNormal"); pymio::bind_parameter_distribution_uniform(m, "ParameterDistributionUniform"); pymio::bind_uncertain_value(m, "UncertainValue"); + pymio::bind_abstract_parameter_distribution(m, "AbstractParameterDistribution"); + pymio::bind_CustomIndexArray, mio::AgeGroup>(m, "AgeGroupArray"); pymio::bind_class>(m, "AgeGroup") .def(py::init()); @@ -155,5 +161,9 @@ PYBIND11_MODULE(_simulation, m) mio::thread_local_rng().seed(mio::RandomNumberGenerator::generate_seeds()); }); + pymio::bind_random_number_generator(m, "RandomNumberGenerator"); + + pymio::bind_time_series_functor(m, "TimeSeriesFunctor"); + m.attr("__version__") = "dev"; } diff --git a/pycode/memilio-simulation/memilio/simulation/bindings/utils/abstract_parameter_distribution.h b/pycode/memilio-simulation/memilio/simulation/bindings/utils/abstract_parameter_distribution.h new file mode 100644 index 0000000000..641e97e9c8 --- /dev/null +++ b/pycode/memilio-simulation/memilio/simulation/bindings/utils/abstract_parameter_distribution.h @@ -0,0 +1,40 @@ +/* +* Copyright (C) 2020-2026 MEmilio +* +* Authors: Carlotta Gerstein +* +* Contact: Martin J. Kuehn +* +* 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 "memilio/utils/abstract_parameter_distribution.h" +#include "memilio/utils/random_number_generator.h" +#include "pybind_util.h" + +namespace py = pybind11; + +namespace pymio +{ +void bind_abstract_parameter_distribution(py::module_& m, std::string const& name) +{ + bind_class(m, name.c_str()) + .def(py::init<>()) + .def(py::init(), py::arg("dist")) + .def("get", + [](mio::AbstractParameterDistribution& self, mio::RandomNumberGenerator& rng) { + return self.get(rng); + }) + .def("params", &mio::AbstractParameterDistribution::params); +} +} // namespace pymio \ No newline at end of file diff --git a/pycode/memilio-simulation/memilio/simulation/bindings/utils/custom_index_array.h b/pycode/memilio-simulation/memilio/simulation/bindings/utils/custom_index_array.h index 2fd49f2c3f..694896333f 100755 --- a/pycode/memilio-simulation/memilio/simulation/bindings/utils/custom_index_array.h +++ b/pycode/memilio-simulation/memilio/simulation/bindings/utils/custom_index_array.h @@ -231,7 +231,7 @@ void bind_CustomIndexArray(pybind11::module_& m, std::string const& name) //scalar assignment .def("__setitem__", &assign_scalar); - //scalar assignment with conversion from double + // scalar assignment with conversion from double if constexpr (std::is_convertible::value) { c.def("__setitem__", &assign_scalar); } diff --git a/pycode/memilio-simulation/memilio/simulation/bindings/utils/index.h b/pycode/memilio-simulation/memilio/simulation/bindings/utils/index.h index cbaf6f8315..3d497cdfc2 100644 --- a/pycode/memilio-simulation/memilio/simulation/bindings/utils/index.h +++ b/pycode/memilio-simulation/memilio/simulation/bindings/utils/index.h @@ -51,6 +51,7 @@ void bind_Index(pybind11::module_& m, std::string const& name) c.def(pybind11::init(), pybind11::arg("value")); c.def(pybind11::self == pybind11::self); c.def(pybind11::self != pybind11::self); + c.def("get", &mio::Index::get); bind_Index_members_if_enum(c); } diff --git a/pycode/memilio-simulation/memilio/simulation/bindings/utils/parameter_distributions.cpp b/pycode/memilio-simulation/memilio/simulation/bindings/utils/parameter_distributions.cpp index 28498ddd2a..15abfced48 100644 --- a/pycode/memilio-simulation/memilio/simulation/bindings/utils/parameter_distributions.cpp +++ b/pycode/memilio-simulation/memilio/simulation/bindings/utils/parameter_distributions.cpp @@ -51,6 +51,15 @@ void bind_parameter_distribution_normal(py::module_& m, std::string const& name) &mio::ParameterDistributionNormal::set_standard_dev); } +void bind_parameter_distribution_lognormal(py::module_& m, std::string const& name) +{ + bind_class( + m, name.c_str()) + .def(py::init(), py::arg("log_mean"), py::arg("log_stddev")) + .def_property_readonly("log_mean", &mio::ParameterDistributionLogNormal::get_log_mean) + .def_property_readonly("log_standard_dev", &mio::ParameterDistributionLogNormal::get_log_stddev); +} + void bind_parameter_distribution_uniform(py::module_& m, std::string const& name) { bind_class(m, diff --git a/pycode/memilio-simulation/memilio/simulation/bindings/utils/parameter_distributions.h b/pycode/memilio-simulation/memilio/simulation/bindings/utils/parameter_distributions.h index d82bce8ec4..e516e525c2 100644 --- a/pycode/memilio-simulation/memilio/simulation/bindings/utils/parameter_distributions.h +++ b/pycode/memilio-simulation/memilio/simulation/bindings/utils/parameter_distributions.h @@ -29,6 +29,8 @@ void bind_parameter_distribution(pybind11::module_& m, std::string const& name); void bind_parameter_distribution_normal(pybind11::module_& m, std::string const& name); +void bind_parameter_distribution_lognormal(pybind11::module_& m, std::string const& name); + void bind_parameter_distribution_uniform(pybind11::module_& m, std::string const& name); } // namespace pymio diff --git a/pycode/memilio-simulation/memilio/simulation/bindings/utils/random_number_generator.h b/pycode/memilio-simulation/memilio/simulation/bindings/utils/random_number_generator.h new file mode 100644 index 0000000000..568980e73d --- /dev/null +++ b/pycode/memilio-simulation/memilio/simulation/bindings/utils/random_number_generator.h @@ -0,0 +1,45 @@ +/* +* Copyright (C) 2020-2026 MEmilio +* +* Authors: Carlotta Gerstein +* +* Contact: Martin J. Kuehn +* +* 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 "memilio/utils/random_number_generator.h" +#include "pybind_util.h" + +namespace py = pybind11; + +namespace pymio +{ +void bind_random_number_generator(py::module_& m, std::string const& name) +{ + bind_class(m, name.c_str()) + .def(py::init<>()) + .def_property_readonly("key", &mio::RandomNumberGenerator::get_key) + .def_property("counter", &mio::RandomNumberGenerator::get_counter, &mio::RandomNumberGenerator::set_counter) + .def_property_readonly("seeds", &mio::RandomNumberGenerator::get_seeds) + .def("increment_counter", &mio::RandomNumberGenerator::increment_counter) + .def("seed", &mio::RandomNumberGenerator::seed, py::arg("seeds")); +} + +void bind_discrete_distribution(py::module_& m, std::string const& name) +{ + bind_class, EnablePickling::Never>(m, name.c_str()) + .def("get_instance", &mio::DiscreteDistribution::get_instance, + py::return_value_policy::reference_internal); +} +} // namespace pymio \ No newline at end of file diff --git a/pycode/memilio-simulation/memilio/simulation/bindings/utils/time_series.cpp b/pycode/memilio-simulation/memilio/simulation/bindings/utils/time_series.cpp index 862d22a72f..9ff15c7059 100644 --- a/pycode/memilio-simulation/memilio/simulation/bindings/utils/time_series.cpp +++ b/pycode/memilio-simulation/memilio/simulation/bindings/utils/time_series.cpp @@ -19,6 +19,7 @@ */ #include "utils/time_series.h" #include "memilio/utils/time_series.h" +#include "memilio/math/time_series_functor.h" #include "pybind_util.h" #include @@ -34,6 +35,7 @@ void bind_time_series(py::module_& m, std::string const& name) { bind_class, EnablePickling::Required>(m, name.c_str()) .def(py::init(), py::arg("num_elements")) + .def(py::init>>(), py::arg("table")) .def("get_num_time_points", &mio::TimeSeries::get_num_time_points) .def("get_num_elements", &mio::TimeSeries::get_num_elements) .def("get_time", py::overload_cast(&mio::TimeSeries::get_time), py::arg("index"))