Skip to content

Commit

Permalink
Merge pull request #18 from seldon-code/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
MSallermann authored Mar 9, 2024
2 parents 8701380 + 9b26bf5 commit 1aad416
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 35 deletions.
18 changes: 10 additions & 8 deletions examples/ActivityDrivenBot/conf.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ rng_seed = 120 # Leaving this empty will pick a random seed

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

[model]
max_iterations = 1000 # If not set, max iterations is infinite
Expand All @@ -16,16 +16,18 @@ 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 = 3.0 # aka beta. if zero, agents pick their interaction partners at random
alpha = 0.25 # Controversialness of the issue, must be greater than 0.
alpha = 0.25 # 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
mean_weights = false

bot_present = true
n_bots = 2
bot_m = [300, 300]
bot_activity = [1.0, 1.0]
bot_opinion = [-2, 2]
n_bots = 2 # The number of bots to be used; if not specified defaults to 0 (which means bots are deactivated)
# Bots are agents with fixed opinions and different parameters, the parameters are specified in the following lists
# If n_bots is smaller than the length of any of the lists, the first n_bots entries are used. If n_bots is greater the code will throw an exception.
bot_m = [300, 300] # If not specified, defaults to `m`
bot_homophily = [0.7, 0.2] # If not specified, defaults to `homophily`
bot_activity = [1.0, 1.0] # If not specified, defaults to 0
bot_opinion = [-2, 2] # The fixed opinions of the bots

[network]
number_of_agents = 1000
Expand Down
16 changes: 11 additions & 5 deletions include/models/ActivityDrivenModel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,17 @@ class ActivityAgentModel : public Model<Agent<ActivityAgentData>>
double convergence_tol = 1e-12; // TODO: ??

// bot @TODO: less hacky
bool bot_present = false;
size_t n_bots = 0; // The first n_bots agents are bots
std::vector<int> bot_m = std::vector<int>( 0 );
std::vector<double> bot_activity = std::vector<double>( 0 );
std::vector<double> bot_opinion = std::vector<double>( 0 );

size_t n_bots = 0; // The first n_bots agents are bots
std::vector<int> bot_m = std::vector<int>( 0 );
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 );

[[nodiscard]] bool bot_present() const
{
return n_bots > 0;
}

ActivityAgentModel( int n_agents, Network & network, std::mt19937 & gen );

Expand Down
3 changes: 3 additions & 0 deletions include/util/math.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ template<typename WeightCallbackT>
void reservoir_sampling_A_ExpJ(
size_t k, size_t n, WeightCallbackT weight, std::vector<std::size_t> & buffer, std::mt19937 & mt )
{
if( k == 0 )
return;

std::uniform_real_distribution<double> distribution( 0.0, 1.0 );

std::vector<size_t> reservoir( k );
Expand Down
34 changes: 22 additions & 12 deletions src/models/ActivityDrivenModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ void Seldon::ActivityAgentModel::get_agents_from_power_law()
}
}

if( bot_present )
if( bot_present() )
{
for( size_t bot_idx = 0; bot_idx < n_bots; bot_idx++ )
{
Expand All @@ -62,17 +62,22 @@ void Seldon::ActivityAgentModel::update_network_probabilistic()
{
// 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 ) {
double homophily = this->homophily;

if( bot_present() && idx_agent < n_bots )
{
homophily = this->bot_homophily[idx_agent];
}
if( idx_agent == j ) // The agent does not contact itself
return 0.0;
return std::pow(
std::abs( this->agents[idx_agent].data.opinion - this->agents[j].data.opinion ), -this->homophily );
std::abs( this->agents[idx_agent].data.opinion - this->agents[j].data.opinion ), -homophily );
};

int m_temp = this->m;

if( bot_present && idx_agent < n_bots )
if( bot_present() && idx_agent < n_bots )
{
m_temp = bot_m[idx_agent];
}
Expand Down Expand Up @@ -129,8 +134,7 @@ void Seldon::ActivityAgentModel::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 All @@ -141,13 +145,19 @@ void Seldon::ActivityAgentModel::update_network_mean()
{
// 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 ) {
double homophily = this->homophily;

if( bot_present() && idx_agent < n_bots )
{
homophily = this->bot_homophily[idx_agent];
}

constexpr double tolerance = 1e-16;
auto opinion_diff = std::abs( this->agents[idx_agent].data.opinion - this->agents[j].data.opinion );
if( opinion_diff < tolerance )
return 0.0;
return std::pow( opinion_diff, -this->homophily );
return std::pow( opinion_diff, -homophily );
};

double normalization = 0;
Expand All @@ -160,7 +170,7 @@ void Seldon::ActivityAgentModel::update_network_mean()
// Calculate the probability of i contacting j (in 1 to m rounds, assuming
// the agent is activated
int m_temp = m;
if( bot_present && idx_agent < n_bots )
if( bot_present() && idx_agent < n_bots )
{
m_temp = bot_m[idx_agent];
}
Expand Down Expand Up @@ -236,7 +246,7 @@ void Seldon::ActivityAgentModel::iteration()
/ 6.0;
}

if( bot_present )
if( bot_present() )
{
for( size_t bot_idx = 0; bot_idx < n_bots; bot_idx++ )
{
Expand Down
45 changes: 35 additions & 10 deletions src/simulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@
#include <set>
#include <stdexcept>

template<typename T>
bool check_bot_param_size( size_t n_bots, auto & arr )
{
if( arr.template value<T>() )
{
return n_bots > arr.as_array()->size();
}
return false;
}

Seldon::Simulation::Simulation(
const std::string & config_file, const std::optional<std::string> & cli_network_file,
const std::optional<std::string> & cli_agent_file )
Expand Down Expand Up @@ -127,28 +137,43 @@ Seldon::Simulation::Simulation(
model_activityDriven->max_iterations = max_iterations;

// bot
model_activityDriven->bot_present = tbl["ActivityDriven"]["bot_present"].value_or<bool>( false );

if( model_activityDriven->bot_present )
model_activityDriven->n_bots = tbl["ActivityDriven"]["n_bots"].value_or<size_t>( 0 );
if( model_activityDriven->bot_present() )
{
model_activityDriven->n_bots = tbl["ActivityDriven"]["n_bots"].value_or<size_t>( 0 );

fmt::print( "Using {} bots\n", model_activityDriven->n_bots );

auto bot_opinion = tbl["ActivityDriven"]["bot_opinion"];
auto bot_m = tbl["ActivityDriven"]["bot_m"];
auto bot_activity = tbl["ActivityDriven"]["bot_activity"];
auto bot_opinion = tbl["ActivityDriven"]["bot_opinion"];
auto bot_m = tbl["ActivityDriven"]["bot_m"];
auto bot_activity = tbl["ActivityDriven"]["bot_activity"];
auto bot_homophily = tbl["ActivityDriven"]["bot_homophily"];

auto n_bots = model_activityDriven->n_bots;

if(
// clang-format off
check_bot_param_size<double>(n_bots, bot_opinion)
|| check_bot_param_size<int>(n_bots, bot_m)
|| check_bot_param_size<double>(n_bots, bot_activity)
|| check_bot_param_size<double>(n_bots, bot_homophily)
// clang-format on
)
{
throw std::runtime_error( "One of the bot parameter arrays is smaller than n_bots" );
}

for( size_t i = 0; i < model_activityDriven->n_bots; i++ )
{
model_activityDriven->bot_opinion.push_back( bot_opinion[i].value_or<double>( 0.0 ) );
model_activityDriven->bot_m.push_back( bot_m[i].value_or<size_t>( 0 ) );
model_activityDriven->bot_m.push_back( bot_m[i].value_or<size_t>( size_t( model_activityDriven->m ) ) );
model_activityDriven->bot_activity.push_back( bot_activity[i].value_or<double>( 0.0 ) );
model_activityDriven->bot_homophily.push_back(
bot_homophily[i].value_or<double>( double( model_activityDriven->homophily ) ) );
}

fmt::print( "Bot opinions {}\n", model_activityDriven->bot_opinion );
fmt::print( "Bot m {}\n", model_activityDriven->bot_m );
fmt::print( "Bot activities {}\n", model_activityDriven->bot_activity );
fmt::print( "Bot activity(s) {}\n", model_activityDriven->bot_activity );
fmt::print( "Bot homophily(s) {}\n", model_activityDriven->bot_homophily );
}

model_activityDriven->get_agents_from_power_law();
Expand Down

0 comments on commit 1aad416

Please sign in to comment.