diff --git a/test/res/deffuant_16x16_agents.toml b/test/res/deffuant_16x16_agents.toml new file mode 100644 index 0000000..fcb0d8e --- /dev/null +++ b/test/res/deffuant_16x16_agents.toml @@ -0,0 +1,22 @@ +[simulation] +model = "Deffuant" +# 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 = false # Print the iteration time ; if not set, then does not prints +# output_initial = true # Print the initial opinions and network file from step 0. If not set, this is true by default. +# start_output = 1 # Start writing out opinions and/or network files from this iteration. If not set, this is 1. + +[model] +max_iterations = 10000 # If not set, max iterations is infinite + +[Deffuant] +homophily_threshold = 1.0 # d in the paper; agents interact if difference in opinion is less than this value +mu = 0.5 # convergence parameter; similar to social interaction strength K (0,0.5] +use_network = true + +[network] +number_of_agents = 256 +connections_per_agent = 0 diff --git a/test/test_deffuant.cpp b/test/test_deffuant.cpp index 5e37762..0504467 100644 --- a/test/test_deffuant.cpp +++ b/test/test_deffuant.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -59,4 +60,56 @@ TEST_CASE( "Test the basic deffuant model for two agents", "[deffuantTwoAgents]" double expected_diff = std::pow( 1.0 - 2.0 * mu, 2 * n_iterations ) * ( agent1_init - agent2_init ); REQUIRE_THAT( agent1_opinion - agent2_opinion, WithinRel( expected_diff ) ); +} + +TEST_CASE( "Test the lattice deffuant model for 16x16 agents", "[deffuantLattice16x16]" ) +{ + using namespace Seldon; + using namespace Catch::Matchers; + using AgentT = DeffuantModel::AgentT; + + auto proj_root_path = fs::current_path(); + auto input_file = proj_root_path / fs::path( "test/res/deffuant_16x16_agents.toml" ); + + auto options = Config::parse_config_file( input_file.string() ); + + auto simulation = Simulation( options, std::nullopt, std::nullopt ); + + // 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_deffuant" ); + + auto model_settings = std::get( options.model_settings ); + auto homophily_threshold = model_settings.homophily_threshold; + + auto n_agents = simulation.network.n_agents(); + + // first half with low opinions + size_t n_agents_half = n_agents / 2; + double avg_opinion = 0; + for( size_t idx_agent = 0; idx_agent < n_agents_half; idx_agent++ ) + { + auto op = -homophily_threshold - 0.5 * idx_agent / n_agents * homophily_threshold; + avg_opinion += op / double( n_agents_half ); + simulation.network.agents[idx_agent].data.opinion = op; + } + + // second half with low opinions + for( size_t idx_agent = n_agents_half; idx_agent < n_agents; idx_agent++ ) + { + auto op = homophily_threshold + 0.5 * ( idx_agent - n_agents_half ) / n_agents * homophily_threshold; + simulation.network.agents[idx_agent].data.opinion = op; + } + + // The two halves are so far apart that they should not interact an therefore form two stable clusters. + simulation.run( output_dir_path ); + + for( size_t idx_agent = 0; idx_agent < n_agents_half; idx_agent++ ) + { + REQUIRE_THAT( simulation.network.agents[idx_agent].data.opinion, WithinRel( avg_opinion ) ); + } + + for( size_t idx_agent = n_agents_half; idx_agent < n_agents; idx_agent++ ) + { + REQUIRE_THAT( simulation.network.agents[idx_agent].data.opinion, WithinRel( -avg_opinion ) ); + } } \ No newline at end of file