From 455c7356593d4c2eabb88ecf05a23260c2792d03 Mon Sep 17 00:00:00 2001 From: Moritz Sallermann <moritzsallermann@gmail.com> Date: Wed, 18 Oct 2023 14:35:45 +0000 Subject: [PATCH 1/6] deleted leftover print statement in main.cpp --- src/main.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 71483c1..15906d1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -42,8 +42,6 @@ int main( int argc, char * argv[] ) auto simulation = Seldon::Simulation( config_file_path.string(), network_file, agent_file ); - fmt::print( "{}", simulation.model->get_agent( 0 )->to_string() ); - Seldon::IO::network_to_dot_file( *simulation.network, ( output_dir_path / fs::path( "network.dot" ) ).string() ); Seldon::IO::network_to_file( simulation, ( output_dir_path / fs::path( "network.txt" ) ).string() ); auto filename = fmt::format( "opinions_{}.txt", 0 ); From 4c77e66e004287ddb6af23bbbfcc1fab099a3b0f Mon Sep 17 00:00:00 2001 From: Moritz Sallermann <moritzsallermann@gmail.com> Date: Wed, 18 Oct 2023 15:16:36 +0000 Subject: [PATCH 2/6] Implemented setting to control output of agents and network --- examples/ActivityDriven/conf.toml | 7 +++++-- include/simulation.hpp | 9 +++++++++ src/main.cpp | 25 +++++++++++++++++++++---- src/simulation.cpp | 15 ++++++++++++++- 4 files changed, 49 insertions(+), 7 deletions(-) diff --git a/examples/ActivityDriven/conf.toml b/examples/ActivityDriven/conf.toml index 699eedf..5070ee1 100644 --- a/examples/ActivityDriven/conf.toml +++ b/examples/ActivityDriven/conf.toml @@ -2,8 +2,11 @@ model = "ActivityDriven" # rng_seed = 120 # Leaving this empty will pick a random seed +[io] +n_output_network = 20 # Write the network every 20 iterations + [model] -max_iterations = 20 # If not set, max iterations is infinite +max_iterations = 500 # If not set, max iterations is infinite [ActivityDriven] dt = 0.01 # Timestep for the integration of the coupled ODEs @@ -17,4 +20,4 @@ K = 3.0 # Social interaction strength [network] number_of_agents = 1000 -connections_per_agent = 10 +connections_per_agent = 10 \ No newline at end of file diff --git a/include/simulation.hpp b/include/simulation.hpp index 993c594..3239049 100644 --- a/include/simulation.hpp +++ b/include/simulation.hpp @@ -3,6 +3,7 @@ #include "model_base.hpp" #include "network.hpp" #include <memory> +#include <optional> #include <random> #include <string> @@ -11,6 +12,13 @@ namespace Seldon class Simulation { + struct OutputSettings + { + // Write out the agents/network every n iterations, nullopt means never + std::optional<size_t> n_output_agents = 1; + std::optional<size_t> n_output_network = std::nullopt; + }; + private: std::mt19937 gen; @@ -18,6 +26,7 @@ class Simulation int n_agents; std::unique_ptr<ModelBase> model; std::unique_ptr<Network> network; + OutputSettings output_settings; Simulation( std::string toml_file, std::optional<std::string> cli_network_file, std::optional<std::string> cli_agent_file ); }; diff --git a/src/main.cpp b/src/main.cpp index 15906d1..4598f16 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -42,17 +42,34 @@ int main( int argc, char * argv[] ) auto simulation = Seldon::Simulation( config_file_path.string(), network_file, agent_file ); - Seldon::IO::network_to_dot_file( *simulation.network, ( output_dir_path / fs::path( "network.dot" ) ).string() ); - Seldon::IO::network_to_file( simulation, ( output_dir_path / fs::path( "network.txt" ) ).string() ); + // Seldon::IO::network_to_dot_file( *simulation.network, ( output_dir_path / fs::path( "network.dot" ) ).string() ); + + Seldon::IO::network_to_file( simulation, ( output_dir_path / fs::path( "network_0.txt" ) ).string() ); auto filename = fmt::format( "opinions_{}.txt", 0 ); Seldon::IO::opinions_to_file( simulation, ( output_dir_path / fs::path( filename ) ).string() ); + const std::optional<size_t> n_output_agents = simulation.output_settings.n_output_agents; + const std::optional<size_t> n_output_network = simulation.output_settings.n_output_network; do { simulation.model->iteration(); - filename = fmt::format( "opinions_{}.txt", simulation.model->n_iterations ); - Seldon::IO::opinions_to_file( simulation, ( output_dir_path / fs::path( filename ) ).string() ); + + // Write out the opinion? + if( n_output_agents.has_value() && ( simulation.model->n_iterations % n_output_agents.value() == 0 ) ) + { + filename = fmt::format( "opinions_{}.txt", simulation.model->n_iterations ); + Seldon::IO::opinions_to_file( simulation, ( output_dir_path / fs::path( filename ) ).string() ); + } + + // Write out the network? + if( n_output_network.has_value() && ( simulation.model->n_iterations % n_output_network.value() == 0 ) ) + { + filename = fmt::format( "network_{}.txt", simulation.model->n_iterations ); + Seldon::IO::network_to_file( simulation, ( output_dir_path / fs::path( filename ) ).string() ); + } + } while( !simulation.model->finished() ); + fmt::print( "Finished after {} iterations.\n", simulation.model->n_iterations ); return 0; } \ No newline at end of file diff --git a/src/simulation.cpp b/src/simulation.cpp index 0878403..5860dae 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -5,6 +5,7 @@ #include "util/tomlplusplus.hpp" #include <fmt/format.h> #include <fmt/ostream.h> +#include <cstddef> #include <iostream> #include <optional> #include <set> @@ -29,9 +30,21 @@ Seldon::Simulation::Simulation( rng_seed = std::random_device()(); fmt::print( "INFO: Seeding with seed {}!\n", rng_seed.value() ); } - gen = std::mt19937( rng_seed.value() ); + // Parse output settings + auto n_output_network = tbl["io"]["n_output_network"].value<size_t>(); + if( n_output_network.has_value() ) + { + output_settings.n_output_network = n_output_network.value(); + } + + auto n_output_agents = tbl["io"]["n_output_agents"].value<size_t>(); + if( n_output_agents.has_value() ) + { + output_settings.n_output_agents = n_output_agents.value(); + } + // Check if the 'model' keyword exists std::optional<std::string> model_opt = tbl["simulation"]["model"].value<std::string>(); if( !model_opt.has_value() ) From 10a434b12cb817d7794300608126292884590aa1 Mon Sep 17 00:00:00 2001 From: Moritz Sallermann <moritzsallermann@gmail.com> Date: Wed, 18 Oct 2023 15:17:36 +0000 Subject: [PATCH 3/6] formatting --- src/models/ActivityDrivenModel.cpp | 3 +-- src/network.cpp | 10 ++++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/models/ActivityDrivenModel.cpp b/src/models/ActivityDrivenModel.cpp index eb37181..2cbd95d 100644 --- a/src/models/ActivityDrivenModel.cpp +++ b/src/models/ActivityDrivenModel.cpp @@ -47,8 +47,7 @@ void Seldon::ActivityAgentModel::iteration() // Implement the weight for the probability of agent `idx_agent` contacting agent `j` // Not normalised since this is taken care of by the reservoir sampling - auto weight_callback = [idx_agent, this]( size_t j ) - { + auto weight_callback = [idx_agent, this]( size_t j ) { if( idx_agent == j ) // The agent does not contact itself return 0.0; return std::pow( diff --git a/src/network.cpp b/src/network.cpp index d693540..15b5f5e 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -48,10 +48,12 @@ void Seldon::Network::set_neighbours_and_weights( std::size_t agent_idx, const std::vector<size_t> & buffer_neighbours, const std::vector<Seldon::Network::WeightT> & buffer_weights ) { - if( buffer_neighbours.size() != buffer_weights.size() ) [[unlikely]] - { - throw std::runtime_error( "Network::set_neighbours_and_weights: both buffers need to have the same length!" ); - } + if( buffer_neighbours.size() != buffer_weights.size() ) + [[unlikely]] + { + throw std::runtime_error( + "Network::set_neighbours_and_weights: both buffers need to have the same length!" ); + } neighbour_list[agent_idx] = buffer_neighbours; weight_list[agent_idx] = buffer_weights; From ca1d7f154c2dfd382f06e30710caaec70ef17741 Mon Sep 17 00:00:00 2001 From: Moritz Sallermann <moritzsallermann@gmail.com> Date: Wed, 18 Oct 2023 15:30:45 +0000 Subject: [PATCH 4/6] Network: fixed an error in Network::set_neighbours_and_weights as well as the corresponding unit test --- src/network.cpp | 2 +- test/test_network.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/network.cpp b/src/network.cpp index 15b5f5e..75f2de4 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -38,7 +38,7 @@ void Seldon::Network::set_neighbours_and_weights( neighbour_list[agent_idx] = buffer_neighbours; weight_list[agent_idx].resize( buffer_neighbours.size() ); - for( auto w : weight_list[agent_idx] ) + for( auto & w : weight_list[agent_idx] ) { w = weight; } diff --git a/test/test_network.cpp b/test/test_network.cpp index 36f9fc8..5c18363 100644 --- a/test/test_network.cpp +++ b/test/test_network.cpp @@ -27,7 +27,7 @@ TEST_CASE( "Testing the network class" ) std::vector<Seldon::Network::WeightT> weight{ 0.5, 0.5 }; // new weights (const) network->set_neighbours_and_weights( 3, neigh, 0.5 ); network->get_weights( 3, buffer_w_get ); - REQUIRE_THAT( buffer_w_get, Catch::Matchers::UnorderedRangeEquals( buffer_w_get ) ); + REQUIRE_THAT( weight, Catch::Matchers::UnorderedRangeEquals( buffer_w_get ) ); // Change the connections for agent 3 std::vector<size_t> buffer_n{ { 0, 10, 15 } }; // new neighbours From 7d1acf6300e14097c3e538d48e67d00f26d05109 Mon Sep 17 00:00:00 2001 From: Moritz Sallermann <moritzsallermann@gmail.com> Date: Wed, 18 Oct 2023 15:32:24 +0000 Subject: [PATCH 5/6] Some code quality changes to reduce compiler warnings --- include/network_generation.hpp | 3 ++- include/simulation.hpp | 3 ++- include/util/math.hpp | 4 ++-- src/network_generation.cpp | 8 +++++--- src/simulation.cpp | 3 ++- test/test_sampling.cpp | 4 ++-- 6 files changed, 15 insertions(+), 10 deletions(-) diff --git a/include/network_generation.hpp b/include/network_generation.hpp index 0287ab0..3c14914 100644 --- a/include/network_generation.hpp +++ b/include/network_generation.hpp @@ -1,11 +1,12 @@ #pragma once #include "network.hpp" +#include <cstddef> #include <memory> #include <random> namespace Seldon { // Returns a unique pointer to a new network with n_connections per agent -std::unique_ptr<Network> generate_n_connections( int n_agents, int n_connections, std::mt19937 & gen ); +std::unique_ptr<Network> generate_n_connections( size_t n_agents, int n_connections, std::mt19937 & gen ); std::unique_ptr<Network> generate_from_file( const std::string & file ); } // namespace Seldon \ No newline at end of file diff --git a/include/simulation.hpp b/include/simulation.hpp index 3239049..9198985 100644 --- a/include/simulation.hpp +++ b/include/simulation.hpp @@ -28,7 +28,8 @@ class Simulation std::unique_ptr<Network> network; OutputSettings output_settings; Simulation( - std::string toml_file, std::optional<std::string> cli_network_file, std::optional<std::string> cli_agent_file ); + const std::string & config_file, const std::optional<std::string> & cli_network_file, + const std::optional<std::string> & cli_agent_file ); }; } // namespace Seldon \ No newline at end of file diff --git a/include/util/math.hpp b/include/util/math.hpp index a69b575..91532e6 100644 --- a/include/util/math.hpp +++ b/include/util/math.hpp @@ -38,7 +38,7 @@ inline void draw_unique_k_from_n( { return i; }; - bool operator==( const SequenceGenerator & it1 ) + bool operator==( const SequenceGenerator & it1 ) const { return i == it1.i; }; @@ -68,7 +68,7 @@ void reservoir_sampling_A_ExpJ( std::priority_queue<QueueItemT, std::vector<QueueItemT>, decltype( compare )> H; size_t idx = 0; - while( idx < n & H.size() < k ) + while( ( idx < n ) && ( H.size() < k ) ) { double r = std::pow( distribution( mt ), 1.0 / weight( idx ) ); H.push( { idx, r } ); diff --git a/src/network_generation.cpp b/src/network_generation.cpp index 0580068..c53b8d1 100644 --- a/src/network_generation.cpp +++ b/src/network_generation.cpp @@ -4,6 +4,7 @@ #include <fmt/ostream.h> #include <fmt/ranges.h> #include <algorithm> +#include <cstddef> #include <fstream> #include <iterator> #include <stdexcept> @@ -11,7 +12,8 @@ #include <util/math.hpp> #include <util/misc.hpp> -std::unique_ptr<Seldon::Network> Seldon::generate_n_connections( int n_agents, int n_connections, std::mt19937 & gen ) +std::unique_ptr<Seldon::Network> +Seldon::generate_n_connections( size_t n_agents, int n_connections, std::mt19937 & gen ) { using WeightT = Network::WeightT; @@ -129,8 +131,8 @@ std::unique_ptr<Seldon::Network> Seldon::generate_from_file( const std::string & n_neighbours = std::stoi( column_substring ); } else if( - idx_column >= 2 - & idx_column < 2 + n_neighbours ) // The next n_neighbours columsn contain the neighbour indices + ( idx_column >= 2 ) + && ( idx_column < 2 + n_neighbours ) ) // The next n_neighbours columsn contain the neighbour indices { const auto idx_neighbour = std::stoi( column_substring ); neighbour_list.back().push_back( idx_neighbour ); diff --git a/src/simulation.cpp b/src/simulation.cpp index 5860dae..bc58a7e 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -12,7 +12,8 @@ #include <stdexcept> Seldon::Simulation::Simulation( - std::string config_file, std::optional<std::string> cli_network_file, std::optional<std::string> cli_agent_file ) + const std::string & config_file, const std::optional<std::string> & cli_network_file, + const std::optional<std::string> & cli_agent_file ) { std::set<std::string> allowed_models = { "DeGroot", "ActivityDriven" }; diff --git a/test/test_sampling.cpp b/test/test_sampling.cpp index 3bc64d6..acf0c25 100644 --- a/test/test_sampling.cpp +++ b/test/test_sampling.cpp @@ -99,13 +99,13 @@ TEST_CASE( "Testing sampling functions" ) std::vector<size_t> histogram( n, 0 ); // Count how often each element occurs amongst all samples auto weight_callback = []( size_t idx ) { - if( ( idx == ignore_idx ) | ( idx == ignore_idx2 ) ) + if( ( idx == ignore_idx ) || ( idx == ignore_idx2 ) ) { return 0.0; } else { - std::abs( double( n / 2.0 ) - double( idx ) ); + return std::abs( double( n / 2.0 ) - double( idx ) ); } }; From 3ef8c610074a5fa42dd68224503bf6572063d841 Mon Sep 17 00:00:00 2001 From: Moritz Sallermann <moritzsallermann@gmail.com> Date: Wed, 18 Oct 2023 16:53:34 +0000 Subject: [PATCH 6/6] build: suppress GCC's 'unused-local-typedefs' warnings --- meson.build | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index cd58a5b..2d1439e 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,8 @@ project('seldon', 'cpp', version : '0.1', - default_options : ['warning_level=3', 'cpp_std=c++20']) + default_options : ['warning_level=3', 'cpp_std=c++20', ]) + +add_global_arguments('-Wno-unused-local-typedefs', language : 'cpp') incdir = include_directories('include')