Utopia 2
Framework for studying models of complex & adaptive systems.
Loading...
Searching...
No Matches
Opinionet.hh
Go to the documentation of this file.
1#ifndef UTOPIA_MODELS_OPINIONET_HH
2#define UTOPIA_MODELS_OPINIONET_HH
3
4#include <functional>
5#include <boost/graph/random.hpp>
6
10#include <utopia/core/graph.hh>
12
13#include "modes.hh"
14#include "revision.hh"
15
16
18
21using Modes::Rewiring;
22
24struct Agent {
25 double opinion;
26};
27
29struct Edge {
30 double weight;
31};
32
33// ++ Type definitions ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
34
36using VertexContainer = boost::vecS;
37
39using EdgeContainer = boost::vecS;
40
42using NetworkUndirected = boost::adjacency_list<
45 boost::undirectedS,
46 Agent>;
47
49using NetworkDirected = boost::adjacency_list<
52 boost::bidirectionalS,
53 Agent,
54 Edge>;
55
56// The undirected network type
57using NetworkUndir = boost::adjacency_list<
60 boost::undirectedS,
61 Agent
62>;
63
68
71
72// ++ Model definition ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
73
75
79template<typename NWType=NetworkUndirected>
81 public Model<Opinionet<NWType>, OpinionetTypes>
82{
83public:
86
88 using Config = typename Base::Config;
89
91 using DataGroup = typename Base::DataGroup;
92
94 using DataSet = typename Base::DataSet;
95
97 using RNG = typename Base::RNG;
98
99private:
100 // Base members: _time, _name, _cfg, _hdfgrp, _rng, _monitor, _log, _space
101
103 const Interaction_type _interaction;
104 const Opinion_space_type _opinion_space;
105 const Rewiring _rewire;
106
109 const double _tolerance;
110 const double _susceptibility;
111 const double _weighting;
112
114 std::uniform_real_distribution<double> _uniform_prob_distr;
115
116 // Datasets and Datagroups
117 const std::shared_ptr<DataGroup> _dgrp_nw;
118 const std::shared_ptr<DataSet> _dset_opinion;
119 const std::shared_ptr<DataSet> _dset_edge_weights;
120
121public:
123
126 template<class ParentModel>
127 Opinionet (const std::string name,
129 :
130 // Initialize first via base model
131 Base(name, parent),
132 // Initialize modes
136 // Initialize the network
138 // Initialize the model parameters
139 _tolerance(get_as<double>("tolerance", this->_cfg)),
140 _susceptibility(get_as<double>("susceptibility", this->_cfg)),
142 "weighting", this->_cfg["network"]["edges"])),
143 _uniform_prob_distr(0., 1.),
144 // Create datagroups and datasets
145 _dgrp_nw(create_graph_group(_nw, this->_hdfgrp, "nw")),
147 {boost::num_vertices(_nw)})),
149 {
150 this->_log->debug("Constructing the Opinionet Model ...");
151
152 // Initialize the network properties
153 this->initialize_properties();
154
155 this->_log->info(
156 "Initialized network with {} vertices and {} edges. Directed: {}",
157 boost::num_vertices(_nw),
158 boost::num_edges(_nw),
159 boost::is_directed(_nw)
160 );
161
162 // Mark the datasets as vertex properties and add dimensions and
163 // coordinates.
164 _dset_opinion->add_attribute("is_vertex_property", true);
165 _dset_opinion->add_attribute("dim_name__1", "vertex_idx");
166 _dset_opinion->add_attribute("coords_mode__vertex_idx", "trivial");
167
168 if (_rewire == Rewiring::RewiringOff) {
169 save_graph(_nw, _dgrp_nw);
170 this->_log->debug("Network saved.");
171 }
172
173 else {
174 // Write the vertex data once, as it does not change with time
175 auto _dset_vertices = _dgrp_nw->open_dataset(
176 "_vertices", {boost::num_vertices(_nw)}
177 );
178 auto [v, v_end] = boost::vertices(_nw);
179 _dset_vertices->write(
180 v, v_end,
181 [&](auto vd){
182 return boost::get(boost::vertex_index_t(), _nw, vd);
183 }
184 );
185 _dset_vertices->add_attribute("dim_name__0", "vertex_idx");
186 _dset_vertices->add_attribute(
187 "coords_mode__vertex_idx", "trivial"
188 );
189 }
190
191 }
192
193private:
194
195 // .. Setup functions .....................................................
196
197 Interaction_type initialize_interaction() {
198 if (get_as<std::string>("interaction_function", this->_cfg)
199 == "Deffuant")
200 {
201 return Interaction_type::Deffuant;
202 }
203 else {
204 return Interaction_type::HegselmannKrause;
205 }
206 }
207
208 Opinion_space_type initialize_opinion_space() {
209 if (get_as<std::string>("type", this->_cfg["opinion_space"])
210 == "discrete")
211 {
212 return Opinion_space_type::discrete;
213 }
214 else {
215 return Opinion_space_type::continuous;
216 }
217 }
218
220 if (get_as<bool>("rewiring", this->_cfg["network"]["edges"])) {
221 return Rewiring::RewiringOn;
222 }
223 else {
224 return Rewiring::RewiringOff;
225 }
226 }
227
229 this->_log->debug("Initializing the properties ...");
230
231 // Continuous opinion space: draw opinions from a continuous interval
232 if (_opinion_space == Opinion_space_type::continuous) {
233 const std::pair<double, double> opinion_interval =
235 "interval", this->_cfg["opinion_space"]
236 );
237
238 if (opinion_interval.first >= opinion_interval.second) {
239 throw std::invalid_argument("Error: The given opinion interval"
240 " is invalid! Specify an interval of the kind [a, b], "
241 "with a<b!");
242 }
243
244 for (const auto v : range<IterateOver::vertices>(_nw)) {
245 _nw[v].opinion = Utils::get_rand<double>(
246 opinion_interval, *this->_rng);
247 }
248 }
249 // Discrete opinion space: draw opinions from a discrete set
250 else {
251 const int opinion_values =
252 get_as<int>("num_opinions", this->_cfg["opinion_space"]);
253
254 for (const auto v : range<IterateOver::vertices>(_nw)) {
255 _nw[v].opinion =
256 Utils::get_rand<int>(
257 std::make_pair<int, int>(0, opinion_values-1),
258 *this->_rng
259 );
260 }
261 }
262
263 // For directed network: Initialize weights depending on the opinion
264 // distances. In the undirected case, weights are not required.
265 if constexpr (Utils::is_directed<NWType>()) {
266 for (const auto v : range<IterateOver::vertices>(_nw)) {
267 if (boost::out_degree(v, _nw) != 0) {
269 }
270 }
271 }
272 }
273
275 this->_log->debug("Creating the network ...");
276
277 auto g = Graph::create_graph<NWType>(this->_cfg["network"], *this->_rng);
278
279 this->_log->debug("Network created.");
280
281 return g;
282 }
283
284 // Only initialize edge weight dataset for directed graphs
285 std::shared_ptr<DataSet> create_edge_weight_dset() {
286 if constexpr (Utils::is_directed<NWType>()) {
287 return this->create_dset(
288 "edge_weights", _dgrp_nw, {boost::num_edges(_nw)}
289 );
290 }
291 else {
292 return 0;
293 }
294 }
295
296
297public:
298
299 // .. Runtime functions ...................................................
300
310 {
312 _nw,
318 _rewire,
320 *this->_rng
321 );
322 }
323
324
326
330 void monitor () {
331 double mean_opinion = 0.;
332 double opinion_std = 0.;
333 double min_opinion = std::numeric_limits<double>::infinity();
334 double max_opinion = -std::numeric_limits<double>::infinity();
335
336 double temp_op;
337 for (const auto v : range<IterateOver::vertices>(_nw)) {
338 temp_op = _nw[v].opinion;
340
341 if (temp_op < min_opinion) {
343 }
344
345 if (temp_op > max_opinion) {
347 }
348 }
349
350 mean_opinion /= boost::num_vertices(_nw);
351
352 for (const auto v : range<IterateOver::vertices>(_nw)) {
353 opinion_std += std::pow(_nw[v].opinion - mean_opinion, 2.);
354 }
355
356 opinion_std = std::sqrt(opinion_std / (boost::num_vertices(_nw) - 1.));
357
358 this->_monitor.set_entry("mean_opinion", mean_opinion);
359 this->_monitor.set_entry("opinion_std", opinion_std);
360 this->_monitor.set_entry("min_opinion", min_opinion);
361 this->_monitor.set_entry("max_opinion", max_opinion);
362 }
363
364
367 {
368 // Get the vertex iterators
369 auto [v, v_end] = boost::vertices(_nw);
370
371 // Write opinions
372 _dset_opinion->write(
373 v, v_end, [this](auto vd) { return _nw[vd].opinion; }
374 );
375
376 // Write edges
377 if (_rewire == Rewiring::RewiringOn){
378 // Adaptor tuple that allows to save the edge data
379 const auto get_edge_data = std::make_tuple(
380 std::make_tuple("_edges", "type",
381 std::make_tuple("source",
382 [](auto& ed, auto& _nw) {
383 return boost::get(
384 boost::vertex_index_t(), _nw,
385 boost::source(ed, _nw));
386 }
387 ),
388 std::make_tuple("target",
389 [](auto& ed, auto& _nw) {
390 return boost::get(
391 boost::vertex_index_t(), _nw,
392 boost::target(ed, _nw));
393 }
394 )
395 )
396 );
397 // Save the edge data using the current time as label.
398 save_edge_properties(
399 _nw, _dgrp_nw, std::to_string(this->get_time()), get_edge_data
400 );
401 }
402
403 // Write edge weights
404 if constexpr (Utils::is_directed<NWType>()) {
405
406 auto [e, e_end] = boost::edges(_nw);
407
408 _dset_edge_weights->write(
409 e, e_end, [this](auto ed) { return _nw[ed].weight; }
410 );
411 }
412 }
413
414 // .. Getters and setters .................................................
415 // Add getters and setters here to interface with other model
416};
417
418} // namespace Utopia::Models::Opinionet
419
420#endif // UTOPIA_MODELS_OPINIONET_HH
Base class interface for Models using the CRT Pattern.
Definition model.hh:112
const std::shared_ptr< DataGroup > _hdfgrp
The HDF group this model instance should write its data to.
Definition model.hh:176
Monitor _monitor
The monitor.
Definition model.hh:188
typename ModelTypes::DataSet DataSet
Data type that is used for storing data.
Definition model.hh:125
const Config _cfg
Config node belonging to this model instance.
Definition model.hh:158
Time get_time() const
Return the current time of this model.
Definition model.hh:393
typename ModelTypes::DataGroup DataGroup
Data type that is used for storing datasets.
Definition model.hh:122
typename ModelTypes::Config Config
Data type that holds the configuration.
Definition model.hh:116
typename ModelTypes::RNG RNG
Data type of the shared RNG.
Definition model.hh:128
const std::shared_ptr< spdlog::logger > _log
The (model) logger.
Definition model.hh:164
const std::shared_ptr< RNG > _rng
The RNG shared between models.
Definition model.hh:161
std::shared_ptr< DataSet > create_dset(const std::string name, const std::shared_ptr< DataGroup > &hdfgrp, std::vector< hsize_t > add_write_shape, const std::size_t compression_level=1, const std::vector< hsize_t > chunksize={})
Create a new dataset within the given group.
Definition model.hh:752
The Opinionet model class.
Definition Opinionet.hh:82
typename Base::Config Config
Data type that holds the configuration.
Definition Opinionet.hh:88
Rewiring initialize_rewiring()
Definition Opinionet.hh:219
const double _tolerance
Definition Opinionet.hh:109
const double _susceptibility
Definition Opinionet.hh:110
const std::shared_ptr< DataSet > _dset_edge_weights
Definition Opinionet.hh:119
typename Base::DataSet DataSet
Data type for a dataset.
Definition Opinionet.hh:94
NWType _nw
Network and model dynamics parameters.
Definition Opinionet.hh:108
void write_data()
Write data.
Definition Opinionet.hh:366
const Opinion_space_type _opinion_space
Definition Opinionet.hh:104
std::shared_ptr< DataSet > create_edge_weight_dset()
Definition Opinionet.hh:285
void monitor()
Monitor model information.
Definition Opinionet.hh:330
Opinion_space_type initialize_opinion_space()
Definition Opinionet.hh:208
const std::shared_ptr< DataSet > _dset_opinion
Definition Opinionet.hh:118
const double _weighting
Definition Opinionet.hh:111
void initialize_properties()
Definition Opinionet.hh:228
typename Base::DataGroup DataGroup
Data type of the group to write model data to, holding datasets.
Definition Opinionet.hh:91
typename Base::RNG RNG
Data type of the shared RNG.
Definition Opinionet.hh:97
void perform_step()
Iterate a single step Each step consists of an opinion update and edge rewiring.
Definition Opinionet.hh:309
const std::shared_ptr< DataGroup > _dgrp_nw
Definition Opinionet.hh:117
NWType initialize_nw() const
Definition Opinionet.hh:274
Opinionet(const std::string name, ParentModel &parent)
Construct the Opinionet model.
Definition Opinionet.hh:127
Interaction_type initialize_interaction()
Definition Opinionet.hh:197
const Interaction_type _interaction
Modes.
Definition Opinionet.hh:103
const Rewiring _rewire
Definition Opinionet.hh:105
std::uniform_real_distribution< double > _uniform_prob_distr
A uniform probability distribution.
Definition Opinionet.hh:114
ReturnType get_as(const std::string &key, const DataIO::Config &node)
This function is a wrapper around the yaml-cpp YAML::Node::as function.
Definition cfg_utils.hh:158
Container select_entities(const Manager &mngr, const DataIO::Config &sel_cfg)
Select entities according to parameters specified in a configuration.
Definition select.hh:213
Opinion_space_type
Definition modes.hh:13
Interaction_type
Definition modes.hh:8
Rewiring
Definition modes.hh:18
void revision(NWType &nw, const double susceptibility, const double tolerance, const double weighting, const Interaction_type interaction, const Opinion_space_type opinion_space, const Rewiring rewire, std::uniform_real_distribution< double > &prob_distr, RNGType &rng)
Performs an opinion update and edge rewiring (if enabled).
Definition revision.hh:149
void set_and_normalize_weights(const VertexDescType v, NWType &nw, const double weighting)
Set and normalize weights according to opinion difference.
Definition utils.hh:102
Definition modes.hh:4
boost::adjacency_list< EdgeContainer, VertexContainer, boost::undirectedS, Agent > NetworkUndirected
The undirected network type.
Definition Opinionet.hh:46
boost::adjacency_list< EdgeContainer, VertexContainer, boost::bidirectionalS, Agent, Edge > NetworkDirected
The directed network type.
Definition Opinionet.hh:54
boost::vecS VertexContainer
The vertex container type.
Definition Opinionet.hh:36
boost::vecS EdgeContainer
The edge container type.
Definition Opinionet.hh:39
InteractionMode
Definition Opinionet.hh:64
@ hegselmann_krause
Definition Opinionet.hh:66
@ deffuant
Definition Opinionet.hh:65
boost::adjacency_list< EdgeContainer, VertexContainer, boost::undirectedS, Agent > NetworkUndir
Definition Opinionet.hh:62
Wrapper struct for defining model class data types.
Definition model.hh:92
Each node in the network accomodates a single agent.
Definition Opinionet.hh:24
double opinion
Definition Opinionet.hh:25
Each network edge has a weight representing an interaction probability.
Definition Opinionet.hh:29
double weight
Definition Opinionet.hh:30