Skip to content

Commit

Permalink
ActivityDrivenModel: Parse reluctance options
Browse files Browse the repository at this point in the history
Reluctance options are not part of ConfigParser. Defaults are set and
some checks are completed. Also added an example with the reluctance.
TODO: Make a unit test on the ActivityDrivenModel with reluctances.

Co-authored-by: Moritz Sallermann <[email protected]>
  • Loading branch information
amritagos and MSallermann committed Mar 16, 2024
1 parent c8520b9 commit 20d7eac
Show file tree
Hide file tree
Showing 9 changed files with 83 additions and 20 deletions.
33 changes: 33 additions & 0 deletions examples/ActivityDrivenReluctance/conf.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[simulation]
model = "ActivityDriven"
# rng_seed = 120 # Leaving this empty will pick a random seed

[io]
n_output_network = 20 # Write the network every 20 iterations
n_output_agents = 1 # Write the opinions of agents after every iteration
print_progress = true # Print the iteration time ; if not set, then always print

[model]
max_iterations = 500 # If not set, max iterations is infinite

[ActivityDriven]
dt = 0.01 # Timestep for the integration of the coupled ODEs
m = 10 # Number of agents contacted, when the agent is active
eps = 0.01 # Minimum activity epsilon; a_i belongs to [epsilon,1]
gamma = 2.1 # Exponent of activity power law distribution of activities
reciprocity = 0.5 # probability that when agent i contacts j via weighted reservoir sampling, j also sends feedback to i. So every agent can have more than m incoming connections
homophily = 0.5 # aka beta. if zero, agents pick their interaction partners at random
alpha = 3.0 # Controversialness of the issue, must be greater than 0.
K = 3.0 # Social interaction strength
mean_activities = false # Use the mean value of the powerlaw distribution for the activities of all agents
mean_weights = false # Use the meanfield approximation of the network edges

reluctances = true # Assigns a "reluctance" (m_i) to each agent. By default; false and every agent has a reluctance of 1
reluctance_mean = 1.0 # Mean of distribution before drawing from a truncated normal distribution (default set to 1.0)
reluctance_sigma = 0.25 # Width of normal distribution (before truncating)
reluctance_eps = 0.01 # Minimum such that the normal distribution is truncated at this value
covariance_factor = 0.0 # Determines whether activities and reluctances will be correlated. If set to 0.0 (default) then they will not be correlated.

[network]
number_of_agents = 1000
connections_per_agent = 10
5 changes: 5 additions & 0 deletions include/config_parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ struct ActivityDrivenSettings
std::vector<double> bot_activity = std::vector<double>( 0 );
std::vector<double> bot_opinion = std::vector<double>( 0 );
std::vector<double> bot_homophily = std::vector<double>( 0 );
bool use_reluctances = false;
double reluctance_mean = 1.0;
double reluctance_sigma = 0.25;
double reluctance_eps = 0.01;
double covariance_factor = 0.0;
};

struct InitialNetworkSettings
Expand Down
12 changes: 10 additions & 2 deletions include/simulation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ class Simulation : public SimulationInterface
auto degroot_settings = std::get<Config::DeGrootSettings>( options.model_settings );

// DeGroot specific parameters
model = [&]() {
model = [&]()
{
auto model = std::make_unique<DeGrootModel>( network );
model->max_iterations = degroot_settings.max_iterations;
model->convergence_tol = degroot_settings.convergence_tol;
Expand All @@ -101,7 +102,8 @@ class Simulation : public SimulationInterface
{
auto activitydriven_settings = std::get<Config::ActivityDrivenSettings>( options.model_settings );

model = [&]() {
model = [&]()
{
auto model = std::make_unique<ActivityDrivenModel>( network, gen );
model->dt = activitydriven_settings.dt;
model->m = activitydriven_settings.m;
Expand All @@ -114,6 +116,12 @@ class Simulation : public SimulationInterface
model->mean_activities = activitydriven_settings.mean_activities;
model->mean_weights = activitydriven_settings.mean_weights;
model->max_iterations = activitydriven_settings.max_iterations;
// Reluctance
model->use_reluctances = activitydriven_settings.use_reluctances;
model->reluctance_mean = activitydriven_settings.reluctance_mean;
model->reluctance_sigma = activitydriven_settings.reluctance_sigma;
model->reluctance_eps = activitydriven_settings.reluctance_eps;
model->covariance_factor = activitydriven_settings.covariance_factor;
// bot
model->n_bots = activitydriven_settings.n_bots;
model->bot_opinion = activitydriven_settings.bot_opinion;
Expand Down
38 changes: 26 additions & 12 deletions src/config_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,27 +70,36 @@ SimulationOptions parse_config_file( std::string_view config_file_path )
model_settings.K = tbl["ActivityDriven"]["K"].value_or<double>( 3.0 );
model_settings.mean_activities = tbl["ActivityDriven"]["mean_activities"].value_or<bool>( false );
model_settings.mean_weights = tbl["ActivityDriven"]["mean_weights"].value_or<bool>( false );
// Reluctances
model_settings.use_reluctances = tbl["ActivityDriven"]["reluctances"].value_or<bool>( false );
model_settings.reluctance_mean = tbl["ActivityDriven"]["reluctance_mean"].value_or<double>( 1.0 );
model_settings.reluctance_sigma = tbl["ActivityDriven"]["reluctance_sigma"].value_or<double>( 0.25 );
model_settings.reluctance_eps = tbl["ActivityDriven"]["reluctance_eps"].value_or<double>( 0.01 );
model_settings.covariance_factor = tbl["ActivityDriven"]["covariance_factor"].value_or<double>( 0.0 );

model_settings.max_iterations = tbl["model"]["max_iterations"].value<int>();

// bot
model_settings.n_bots = tbl["ActivityDriven"]["n_bots"].value_or<size_t>( 0 );

auto push_back_bot_array = [&]( auto toml_node, auto & options_array, auto default_value ) {
auto push_back_bot_array = [&]( auto toml_node, auto & options_array, auto default_value )
{
if( toml_node.is_array() )
{
toml::array * toml_arr = toml_node.as_array();

toml_arr->for_each( [&]( auto && elem ) {
if( elem.is_integer() )
{
options_array.push_back( elem.as_integer()->get() );
}
else if( elem.is_floating_point() )
toml_arr->for_each(
[&]( auto && elem )
{
options_array.push_back( elem.as_floating_point()->get() );
}
} );
if( elem.is_integer() )
{
options_array.push_back( elem.as_integer()->get() );
}
else if( elem.is_floating_point() )
{
options_array.push_back( elem.as_floating_point()->get() );
}
} );
}
else
{
Expand Down Expand Up @@ -155,7 +164,12 @@ void validate_settings( const SimulationOptions & options )
check( name_and_var( model_settings.alpha ), geq_zero );
// check( name_and_var( model_settings.homophily ), geq_zero );
check( name_and_var( model_settings.reciprocity ), geq_zero );

// Reluctance options
check( name_and_var( model_settings.reluctance_mean ), g_zero );
check( name_and_var( model_settings.reluctance_sigma ), g_zero );
check( name_and_var( model_settings.reluctance_eps ), g_zero );
check( name_and_var( model_settings.covariance_factor ), geq_zero );
// Bot options
size_t n_bots = model_settings.n_bots;
auto check_bot_size = [&]( auto x ) { return x.size() >= n_bots; };
const std::string bot_msg = "Length needs to be >= n_bots";
Expand All @@ -176,7 +190,7 @@ void print_settings( const SimulationOptions & options )
fmt::print( "INFO: Seeding with seed {}\n", options.rng_seed );
fmt::print( "Model type: {}\n", options.model_string );
fmt::print( "Network has {} agents\n", options.network_settings.n_agents );

// @TODO: Optionally print *all* settings to the console, including defaults that were set
if( options.model == Model::ActivityDrivenModel )
{
auto model_settings = std::get<ActivityDrivenSettings>( options.model_settings );
Expand Down
3 changes: 2 additions & 1 deletion src/models/ActivityDrivenModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,8 @@ void ActivityDrivenModel::update_network_mean()
contact_prob_list[idx_agent] = weights; // set to zero
}

auto probability_helper = []( double omega, size_t m ) {
auto probability_helper = []( double omega, size_t m )
{
double p = 0;
for( size_t i = 1; i <= m; i++ )
p += ( std::pow( -omega, i + 1 ) + omega ) / ( omega + 1 );
Expand Down
2 changes: 1 addition & 1 deletion test/res/10_agents_meanfield_activity.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ model = "ActivityDriven"
# rng_seed = 120 # Leaving this empty will pick a random seed

[io]
n_output_network = 1 # Write the network every 20 iterations
# n_output_network = 1 # Write the network every 20 iterations
# n_output_agents = 1
print_progress = false # Print the iteration time ; if not set, then always print

Expand Down
2 changes: 1 addition & 1 deletion test/res/opinions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
# comment
0, 2.1127107987061544, 0.044554683389757696
1,0.8088982488089491, 0.015813166022685163
2,-0.8802809369462433 , 0.015863953902810535
2,-0.8802809369462433 , 0.015863953902810535, 2.3

5 changes: 3 additions & 2 deletions test/test_activity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ TEST_CASE( "Test the meanfield activity driven model with 10 agents", "[activity
auto mean_activity = dist.mean();

// Calculate the critical controversialness
auto set_opinions_and_run = [&]( bool above_critical_controversialness ) {
auto set_opinions_and_run = [&]( bool above_critical_controversialness )
{
auto simulation = Simulation<AgentT>( options, std::nullopt, std::nullopt );
auto initial_opinion_delta = 0.1; // Set the initial opinion in the interval [-delta, delta]

Expand All @@ -184,7 +185,7 @@ TEST_CASE( "Test the meanfield activity driven model with 10 agents", "[activity

// We need an output path for Simulation, but we won't write anything out there
fs::path output_dir_path = proj_root_path / fs::path( "test/output_meanfield_test" );
fs::create_directories( output_dir_path );
// fs::create_directories( output_dir_path );

// run that mofo
simulation.run( output_dir_path );
Expand Down
3 changes: 2 additions & 1 deletion test/test_sampling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ 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 ) {
auto weight_callback = []( size_t idx )
{
if( ( idx == ignore_idx ) || ( idx == ignore_idx2 ) )
{
return 0.0;
Expand Down

0 comments on commit 20d7eac

Please sign in to comment.