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')