Utopia 2
Framework for studying models of complex & adaptive systems.
Loading...
Searching...
No Matches
Classes | Functions | Variables
Utopia::Models::Opinionet::Utils Namespace Reference

Classes

struct  Infrastructure
 
struct  TestNetworkD
 
struct  TestNetworkD_small
 
struct  TestNetworkU
 

Functions

 BOOST_FIXTURE_TEST_CASE (test_get_rand, Infrastructure)
 
 BOOST_AUTO_TEST_CASE (test_is_directed)
 
 BOOST_FIXTURE_TEST_CASE (test_get_rand_neighbor, TestNetworkU)
 
 BOOST_FIXTURE_TEST_CASE (test_set_and_normalize_weights, TestNetworkD, *boost::unit_test::tolerance(1e-12))
 
 BOOST_FIXTURE_TEST_CASE (test_select_neighbour, TestNetworkD_small, *boost::unit_test::tolerance(1.0))
 
template<typename RT , typename T , typename RNGType >
RT get_rand (std::pair< T, T > range, RNGType &rng)
 Generate a random number within the given range.
 
template<typename NWType >
constexpr bool is_directed ()
 Check whether the network type allows for directed edges.
 
template<typename NWType , typename VertexDescType , typename RNGType >
auto get_rand_neighbor (const VertexDescType v, NWType &nw, RNGType &rng)
 
template<typename NWType , typename RNGType , typename VertexDescType >
VertexDescType select_neighbor (const VertexDescType v, NWType &nw, std::uniform_real_distribution< double > &prob_distr, RNGType &rng)
 
template<typename NWType , typename VertexDescType >
double opinion_difference (VertexDescType v, VertexDescType w, NWType &nw)
 Calculate the absolute opinion difference of two vertices.
 
template<typename NWType , typename VertexDescType >
void set_and_normalize_weights (const VertexDescType v, NWType &nw, const double weighting)
 Set and normalize weights according to opinion difference.
 

Variables

std::uniform_real_distribution< doubleuniform_prob_distr
 

Function Documentation

◆ BOOST_AUTO_TEST_CASE()

Utopia::Models::Opinionet::Utils::BOOST_AUTO_TEST_CASE ( test_is_directed  )
115{
116 BOOST_TEST(is_directed<NetworkDirected>());
117 BOOST_TEST(!is_directed<NetworkUndirected>());
118}

◆ BOOST_FIXTURE_TEST_CASE() [1/4]

Utopia::Models::Opinionet::Utils::BOOST_FIXTURE_TEST_CASE ( test_get_rand  ,
Infrastructure   
)
78{
79 const auto test_cfg = cfg["test_funcs"]["test_get_rand"];
80
81 const std::vector<std::pair<int, int>> to_assert_int
82 = get_as<std::vector<std::pair<int, int>>>("vals_int", test_cfg);
83 for(const auto& val: to_assert_int) {
84 const int rand = get_rand<int>(val, *rng);
85 BOOST_TEST(rand >= val.first);
86 BOOST_TEST(rand <= val.second);
87 }
88
89 const std::vector<std::pair<double, double>> to_assert_double
90 = get_as<std::vector<std::pair<double, double>>>("vals_double",
91 test_cfg);
92 for(const auto& val: to_assert_int) {
93 const double rand = get_rand<double>(val, *rng);
94 BOOST_TEST(rand >= val.first);
95 BOOST_TEST(rand <= val.second);
96 }
97
98 const std::vector<std::pair<double, double>> to_assert_fail
99 = get_as<std::vector<std::pair<double, double>>>("assert_fail",
100 test_cfg);
101 for(const auto& val: to_assert_fail) {
102 TestTools::check_exception<std::invalid_argument>(
103 [&](){
104 get_rand<double>(val, *rng);
105 },
106 "Error, invalid parameter range! Upper limit has to be "
107 "higher than the lower limit." // expected error message
108 );
109 }
110}

◆ BOOST_FIXTURE_TEST_CASE() [2/4]

Utopia::Models::Opinionet::Utils::BOOST_FIXTURE_TEST_CASE ( test_get_rand_neighbor  ,
TestNetworkU   
)
122{
123 for (const auto v : range<IterateOver::vertices>(nw)) {
124 if (boost::out_degree(v, nw) != 0) {
125 vertex w = get_rand_neighbor(v, nw, *rng);
126 // Test edge exists
127 BOOST_TEST(edge(v, w, nw).second);
128
129 // Test edge selection by probability works on undirected networks
130 vertex x = select_neighbor(v, nw, uniform_prob_distr, *rng);
131 BOOST_TEST(edge(v, x, nw).second);
132 }
133 }
134}
IterateOver
Over which graph entity to iterate.
Definition iterator.hh:19
decltype(auto) range(const Graph &g)
Get the iterator range over selected graph entities.
Definition iterator.hh:149
@ vertices
Iterate over vertices.
auto get_rand_neighbor(const VertexDescType v, NWType &nw, RNGType &rng)
Definition utils.hh:44
VertexDescType select_neighbor(const VertexDescType v, NWType &nw, std::uniform_real_distribution< double > &prob_distr, RNGType &rng)
Definition utils.hh:57

◆ BOOST_FIXTURE_TEST_CASE() [3/4]

Utopia::Models::Opinionet::Utils::BOOST_FIXTURE_TEST_CASE ( test_select_neighbour  ,
TestNetworkD_small  ,
boost::unit_test::tolerance1.0 
)
167{
168 const std::vector<double> init_opinions =
169 get_as<std::vector<double>>(
170 "init_opinions",
171 cfg["test_funcs"]["test_select_neighbour"]
172 );
173
174 const std::vector<double> weighting =
175 get_as<std::vector<double>>("weighting",
176 cfg["test_funcs"]["test_select_neighbour"]);
177
178 for(const auto& w: weighting) {
179
180 for (size_t i = 0; i<boost::num_vertices(nw); ++i) {
181 nw[i].opinion = init_opinions.at(i);
182 }
183
184 for (const auto v : range<IterateOver::vertices>(nw)) {
185 set_and_normalize_weights(v, nw, w);
186 }
187
188 const int num_steps = 100000;
189
190 // Check interaction partner selection probability is same as ratio of
191 // opinions
192 int v2_selected = 0;
193 int v3_selected = 0;
194 for (int i=0; i<num_steps; ++i) {
195 vertex w = select_neighbor(v1, nw, uniform_prob_distr, *rng);
196 if (w == v2) { ++v2_selected; }
197 else if (w == v3) { ++v3_selected; }
198 }
199
200 BOOST_TEST((static_cast<double>(v2_selected))/v3_selected
201 == exp(-w*(fabs(nw[v2].opinion-nw[v1].opinion)
202 -fabs(nw[v3].opinion-nw[v1].opinion)))
203 );
204
205 // Repeat for vertex 4
206 int v1_selected = 0;
207 v2_selected = 0;
208 for (int i=0; i<num_steps; ++i) {
209 vertex w = select_neighbor(v4, nw, uniform_prob_distr, *rng);
210 if (w == v1) { ++v1_selected; }
211 else if (w == v2) { ++v2_selected; }
212 }
213
214 BOOST_TEST((static_cast<double>(v1_selected))/v2_selected
215 == exp(-w*(fabs(nw[v1].opinion-nw[v4].opinion)
216 -fabs(nw[v2].opinion-nw[v4].opinion)))
217 );
218 }
219}
BOOST_TEST(constrain_angle(+1.)==+1.)
Assert the basic working of the regularisation function for angles.

◆ BOOST_FIXTURE_TEST_CASE() [4/4]

Utopia::Models::Opinionet::Utils::BOOST_FIXTURE_TEST_CASE ( test_set_and_normalize_weights  ,
TestNetworkD  ,
boost::unit_test::tolerance1e-12 
)
140{
141 const std::vector<double> weighting =
142 get_as<std::vector<double>>("weighting",
143 cfg["test_funcs"]["test_set_and_normalize_weights"]);
144
145 std::pair<double, double> opinion_range = {-5., 5.};
146 for(const auto& w: weighting) {
147 for (const auto v : range<IterateOver::vertices>(nw)) {
148 nw[v].opinion = get_rand<double>(opinion_range, *rng);
149 set_and_normalize_weights(v, nw, w);
150 }
151 for (const auto v : range<IterateOver::vertices>(nw)) {
152 double sum_of_weights = 0;
153 for (const auto e : range<IterateOver::out_edges>(v, nw)) {
154 BOOST_TEST(nw[e].weight >= 0);
155 sum_of_weights += nw[e].weight;
156 }
157 if (boost::out_degree(v, nw) != 0) {
158 BOOST_TEST(sum_of_weights == 1.);
159 }
160 }
161 }
162}
@ out_edges
Iterate over the out edges of a vertex.

◆ get_rand()

template<typename RT , typename T , typename RNGType >
RT Utopia::Models::Opinionet::Utils::get_rand ( std::pair< T, T >  range,
RNGType rng 
)

Generate a random number within the given range.

14 {
15 if (range.first > range.second) {
16 throw std::invalid_argument(
17 "Error, invalid parameter range! Upper limit has to be higher "
18 "than the lower limit."
19 );
20 }
21 if constexpr (std::is_floating_point<RT>()) {
22 return
23 std::uniform_real_distribution<RT>(range.first, range.second)(rng);
24 }
25 else {
26 return
27 std::uniform_int_distribution<RT>(range.first, range.second)(rng);
28 }
29}

◆ get_rand_neighbor()

auto Utopia::Models::Opinionet::Utils::get_rand_neighbor ( const VertexDescType  v,
NWType nw,
RNGType rng 
)

Get random neighbour of vertex v (for directed and undirected graphs). Only appliable to vertices with degree > 0

44 {
45
46 const int nb_shift = get_rand<int>(
47 std::make_pair<int, int>(0, boost::out_degree(v, nw)-1), rng
48 );
49 auto nb = boost::adjacent_vertices(v, nw).first;
50 nb += nb_shift;
51 return *nb;
52}

◆ is_directed()

template<typename NWType >
constexpr bool Utopia::Models::Opinionet::Utils::is_directed ( )
constexpr

Check whether the network type allows for directed edges.

35 {
36 return std::is_convertible<
37 typename boost::graph_traits<NWType>::directed_category,
38 boost::directed_tag>::value;
39}

◆ opinion_difference()

double Utopia::Models::Opinionet::Utils::opinion_difference ( VertexDescType  v,
VertexDescType  w,
NWType nw 
)

Calculate the absolute opinion difference of two vertices.

87 {
88 return fabs(nw[v].opinion - nw[w].opinion);
89}

◆ select_neighbor()

VertexDescType Utopia::Models::Opinionet::Utils::select_neighbor ( const VertexDescType  v,
NWType nw,
std::uniform_real_distribution< double > &  prob_distr,
RNGType rng 
)

Select random neighbor with probability proportional to edge weight. Only applicable to vertices with degree > 0

62{
63 auto nb = v;
64
65 if constexpr (Utils::is_directed<NWType>()) {
66 // The probability for choosing neighbor w is given by the weight on
67 // the edge (v, w).
68 const double nb_prob_frac = prob_distr(rng);
69 double cumulative_weights = 0.;
70 for (const auto w : range<IterateOver::neighbors>(v, nw)) {
71 cumulative_weights += nw[boost::edge(v, w, nw).first].weight;
72 if (cumulative_weights >= nb_prob_frac) {
73 nb = w;
74 break;
75 }
76 }
77 }
78 else {
79 nb = Utils::get_rand_neighbor(v, nw, rng);
80 }
81
82 return nb;
83}
@ neighbors
Iterate over neighbors (adjacent_vertices).

◆ set_and_normalize_weights()

void Utopia::Models::Opinionet::Utils::set_and_normalize_weights ( const VertexDescType  v,
NWType nw,
const double  weighting 
)

Set and normalize weights according to opinion difference.

Iterates over a vertex' out-edges and sets the weights to exp(- weighting * abs(opinion difference)), then normalizes them (softmax).

Warning
This assumes that the vertex has at least one out-edge. Make sure to check this in the calling scope, otherwise this will lead to a zero division error during normalisation.
106{
107 double weight_norm = 0.;
108 for (const auto e : range<IterateOver::out_edges>(v, nw)) {
109 double op_diff = opinion_difference(boost::target(e, nw), v, nw);
110 nw[e].weight = exp(-(weighting*op_diff));
111 weight_norm += nw[e].weight;
112 }
113 for (const auto e : range<IterateOver::out_edges>(v, nw)) {
114 nw[e].weight /= weight_norm;
115 }
116}
double opinion_difference(VertexDescType v, VertexDescType w, NWType &nw)
Calculate the absolute opinion difference of two vertices.
Definition utils.hh:87

Variable Documentation

◆ uniform_prob_distr

std::uniform_real_distribution<double> Utopia::Models::Opinionet::Utils::uniform_prob_distr