Skip to content

Commit

Permalink
Merge pull request #14 from seldon-code/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
MSallermann authored Oct 18, 2023
2 parents 8b88e0c + 3ef8c61 commit 2f7fb41
Show file tree
Hide file tree
Showing 12 changed files with 75 additions and 27 deletions.
7 changes: 5 additions & 2 deletions examples/ActivityDriven/conf.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -17,4 +20,4 @@ K = 3.0 # Social interaction strength

[network]
number_of_agents = 1000
connections_per_agent = 10
connections_per_agent = 10
3 changes: 2 additions & 1 deletion include/network_generation.hpp
Original file line number Diff line number Diff line change
@@ -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
12 changes: 11 additions & 1 deletion include/simulation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "model_base.hpp"
#include "network.hpp"
#include <memory>
#include <optional>
#include <random>
#include <string>

Expand All @@ -11,15 +12,24 @@ 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;

public:
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 );
const std::string & config_file, const std::optional<std::string> & cli_network_file,
const std::optional<std::string> & cli_agent_file );
};

} // namespace Seldon
4 changes: 2 additions & 2 deletions include/util/math.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down Expand Up @@ -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 } );
Expand Down
4 changes: 3 additions & 1 deletion meson.build
Original file line number Diff line number Diff line change
@@ -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')

Expand Down
25 changes: 20 additions & 5 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,34 @@ 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_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_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;
}
3 changes: 1 addition & 2 deletions src/models/ActivityDrivenModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
12 changes: 7 additions & 5 deletions src/network.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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;
Expand Down
8 changes: 5 additions & 3 deletions src/network_generation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@
#include <fmt/ostream.h>
#include <fmt/ranges.h>
#include <algorithm>
#include <cstddef>
#include <fstream>
#include <iterator>
#include <stdexcept>
#include <string>
#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;

Expand Down Expand Up @@ -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 );
Expand Down
18 changes: 16 additions & 2 deletions src/simulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
#include "util/tomlplusplus.hpp"
#include <fmt/format.h>
#include <fmt/ostream.h>
#include <cstddef>
#include <iostream>
#include <optional>
#include <set>
#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" };

Expand All @@ -29,9 +31,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() )
Expand Down
2 changes: 1 addition & 1 deletion test/test_network.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions test/test_sampling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 ) );
}
};

Expand Down

0 comments on commit 2f7fb41

Please sign in to comment.