1 /* -*- mode: C -*- */
2 /*
3 IGraph library.
4 Copyright (C) 2009-2012 Gabor Csardi <csardi.gabor@gmail.com>
5 334 Harvard street, Cambridge, MA 02139 USA
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA
21
22 */
23
24 #include "igraph_mixing.h"
25
26 #include "igraph_interface.h"
27
28 /**
29 * \function igraph_assortativity_nominal
30 * Assortativity of a graph based on vertex categories
31 *
32 * Assuming the vertices of the input graph belong to different
33 * categories, this function calculates the assortativity coefficient of
34 * the graph. The assortativity coefficient is between minus one and one
35 * and it is one if all connections stay within categories, it is
36 * minus one, if the network is perfectly disassortative. For a
37 * randomly connected network it is (asymptotically) zero.
38 *
39 * </para><para>See equation (2) in M. E. J. Newman: Mixing patterns
40 * in networks, Phys. Rev. E 67, 026126 (2003)
41 * (http://arxiv.org/abs/cond-mat/0209450) for the proper
42 * definition.
43 *
44 * \param graph The input graph, it can be directed or undirected.
45 * \param types Vector giving the vertex types. They are assumed to be
46 * integer numbers, starting with zero.
47 * \param res Pointer to a real variable, the result is stored here.
48 * \param directed Boolean, it gives whether to consider edge
49 * directions in a directed graph. It is ignored for undirected
50 * graphs.
51 * \return Error code.
52 *
53 * Time complexity: O(|E|+t), |E| is the number of edges, t is the
54 * number of vertex types.
55 *
56 * \sa \ref igraph_assortativity if the vertex types are defines by
57 * numeric values (e.g. vertex degree), instead of categories.
58 *
59 * \example examples/simple/assortativity.c
60 */
61
igraph_assortativity_nominal(const igraph_t * graph,const igraph_vector_t * types,igraph_real_t * res,igraph_bool_t directed)62 int igraph_assortativity_nominal(const igraph_t *graph,
63 const igraph_vector_t *types,
64 igraph_real_t *res,
65 igraph_bool_t directed) {
66
67 long int no_of_nodes = igraph_vcount(graph);
68 long int no_of_edges = igraph_ecount(graph);
69 long int no_of_types;
70 igraph_vector_t ai, bi, eii;
71 long int e, i;
72 igraph_real_t sumaibi = 0.0, sumeii = 0.0;
73
74 if (igraph_vector_size(types) != no_of_nodes) {
75 IGRAPH_ERROR("Invalid `types' vector length", IGRAPH_EINVAL);
76 }
77
78 if (igraph_vector_min(types) < 0) {
79 IGRAPH_ERROR("Invalid `types' vector", IGRAPH_EINVAL);
80 }
81
82 directed = directed && igraph_is_directed(graph);
83
84 no_of_types = (long int) igraph_vector_max(types) + 1;
85 IGRAPH_VECTOR_INIT_FINALLY(&ai, no_of_types);
86 IGRAPH_VECTOR_INIT_FINALLY(&bi, no_of_types);
87 IGRAPH_VECTOR_INIT_FINALLY(&eii, no_of_types);
88
89 for (e = 0; e < no_of_edges; e++) {
90 long int from = IGRAPH_FROM(graph, e);
91 long int to = IGRAPH_TO(graph, e);
92 long int from_type = (long int) VECTOR(*types)[from];
93 long int to_type = (long int) VECTOR(*types)[to];
94
95 VECTOR(ai)[from_type] += 1;
96 VECTOR(bi)[to_type] += 1;
97 if (from_type == to_type) {
98 VECTOR(eii)[from_type] += 1;
99 }
100 if (!directed) {
101 if (from_type == to_type) {
102 VECTOR(eii)[from_type] += 1;
103 }
104 VECTOR(ai)[to_type] += 1;
105 VECTOR(bi)[from_type] += 1;
106 }
107 }
108
109 for (i = 0; i < no_of_types; i++) {
110 sumaibi += (VECTOR(ai)[i] / no_of_edges) * (VECTOR(bi)[i] / no_of_edges);
111 sumeii += (VECTOR(eii)[i] / no_of_edges);
112 }
113
114 if (!directed) {
115 sumaibi /= 4.0;
116 sumeii /= 2.0;
117 }
118
119 *res = (sumeii - sumaibi) / (1.0 - sumaibi);
120
121 igraph_vector_destroy(&eii);
122 igraph_vector_destroy(&bi);
123 igraph_vector_destroy(&ai);
124 IGRAPH_FINALLY_CLEAN(3);
125
126 return 0;
127 }
128
129 /**
130 * \function igraph_assortativity
131 * Assortativity based on numeric properties of vertices
132 *
133 * This function calculates the assortativity coefficient of the input
134 * graph. This coefficient is basically the correlation between the
135 * actual connectivity patterns of the vertices and the pattern
136 * expected from the distribution of the vertex types.
137 *
138 * </para><para>See equation (21) in M. E. J. Newman: Mixing patterns
139 * in networks, Phys. Rev. E 67, 026126 (2003)
140 * (http://arxiv.org/abs/cond-mat/0209450) for the proper
141 * definition. The actual calculation is performed using equation (26)
142 * in the same paper for directed graphs, and equation (4) in
143 * M. E. J. Newman: Assortative mixing in networks,
144 * Phys. Rev. Lett. 89, 208701 (2002)
145 * (http://arxiv.org/abs/cond-mat/0205405/) for undirected graphs.
146 *
147 * \param graph The input graph, it can be directed or undirected.
148 * \param types1 The vertex values, these can be arbitrary numeric
149 * values.
150 * \param types2 A second value vector to be using for the incoming
151 * edges when calculating assortativity for a directed graph.
152 * Supply a null pointer here if you want to use the same values
153 * for outgoing and incoming edges. This argument is ignored
154 * (with a warning) if it is not a null pointer and undirected
155 * assortativity coefficient is being calculated.
156 * \param res Pointer to a real variable, the result is stored here.
157 * \param directed Boolean, whether to consider edge directions for
158 * directed graphs. It is ignored for undirected graphs.
159 * \return Error code.
160 *
161 * Time complexity: O(|E|), linear in the number of edges of the
162 * graph.
163 *
164 * \sa \ref igraph_assortativity_nominal() if you have discrete vertex
165 * categories instead of numeric labels, and \ref
166 * igraph_assortativity_degree() for the special case of assortativity
167 * based on vertex degree.
168 *
169 * \example examples/simple/assortativity.c
170 */
171
igraph_assortativity(const igraph_t * graph,const igraph_vector_t * types1,const igraph_vector_t * types2,igraph_real_t * res,igraph_bool_t directed)172 int igraph_assortativity(const igraph_t *graph,
173 const igraph_vector_t *types1,
174 const igraph_vector_t *types2,
175 igraph_real_t *res,
176 igraph_bool_t directed) {
177
178 long int no_of_nodes = igraph_vcount(graph);
179 long int no_of_edges = igraph_ecount(graph);
180 long int e;
181
182 directed = directed && igraph_is_directed(graph);
183
184 if (!directed && types2) {
185 IGRAPH_WARNING("Only `types1' is used for undirected case");
186 }
187
188 if (igraph_vector_size(types1) != no_of_nodes) {
189 IGRAPH_ERROR("Invalid `types1' vector length", IGRAPH_EINVAL);
190 }
191
192 if (types2 && igraph_vector_size(types2) != no_of_nodes) {
193 IGRAPH_ERROR("Invalid `types2' vector length", IGRAPH_EINVAL);
194 }
195
196 if (!directed) {
197 igraph_real_t num1 = 0.0, num2 = 0.0, den1 = 0.0;
198
199 for (e = 0; e < no_of_edges; e++) {
200 long int from = IGRAPH_FROM(graph, e);
201 long int to = IGRAPH_TO(graph, e);
202 igraph_real_t from_type = VECTOR(*types1)[from];
203 igraph_real_t to_type = VECTOR(*types1)[to];
204
205 num1 += from_type * to_type;
206 num2 += from_type + to_type;
207 den1 += from_type * from_type + to_type * to_type;
208 }
209
210 num1 /= no_of_edges;
211 den1 /= no_of_edges * 2;
212 num2 /= no_of_edges * 2;
213 num2 = num2 * num2;
214
215 *res = (num1 - num2) / (den1 - num2);
216
217 } else {
218 igraph_real_t num1 = 0.0, num2 = 0.0, num3 = 0.0,
219 den1 = 0.0, den2 = 0.0;
220 igraph_real_t num, den;
221
222 if (!types2) {
223 types2 = types1;
224 }
225
226 for (e = 0; e < no_of_edges; e++) {
227 long int from = IGRAPH_FROM(graph, e);
228 long int to = IGRAPH_TO(graph, e);
229 igraph_real_t from_type = VECTOR(*types1)[from];
230 igraph_real_t to_type = VECTOR(*types2)[to];
231
232 num1 += from_type * to_type;
233 num2 += from_type;
234 num3 += to_type;
235 den1 += from_type * from_type;
236 den2 += to_type * to_type;
237 }
238
239 num = num1 - num2 * num3 / no_of_edges;
240 den = sqrt(den1 - num2 * num2 / no_of_edges) *
241 sqrt(den2 - num3 * num3 / no_of_edges);
242
243 *res = num / den;
244 }
245
246 return 0;
247 }
248
249 /**
250 * \function igraph_assortativity_degree
251 * Assortativity of a graph based on vertex degree
252 *
253 * Assortativity based on vertex degree, please see the discussion at
254 * the documentation of \ref igraph_assortativity() for details.
255 *
256 * \param graph The input graph, it can be directed or undirected.
257 * \param res Pointer to a real variable, the result is stored here.
258 * \param directed Boolean, whether to consider edge directions for
259 * directed graphs. This argument is ignored for undirected
260 * graphs. Supply 1 (=TRUE) here to do the natural thing, i.e. use
261 * directed version of the measure for directed graphs and the
262 * undirected version for undirected graphs.
263 * \return Error code.
264 *
265 * Time complexity: O(|E|+|V|), |E| is the number of edges, |V| is
266 * the number of vertices.
267 *
268 * \sa \ref igraph_assortativity() for the general function
269 * calculating assortativity for any kind of numeric vertex values.
270 *
271 * \example examples/simple/assortativity.c
272 */
273
igraph_assortativity_degree(const igraph_t * graph,igraph_real_t * res,igraph_bool_t directed)274 int igraph_assortativity_degree(const igraph_t *graph,
275 igraph_real_t *res,
276 igraph_bool_t directed) {
277
278 directed = directed && igraph_is_directed(graph);
279
280 if (directed) {
281 igraph_vector_t indegree, outdegree;
282 igraph_vector_init(&indegree, 0);
283 igraph_vector_init(&outdegree, 0);
284 igraph_degree(graph, &indegree, igraph_vss_all(), IGRAPH_IN, /*loops=*/ 1);
285 igraph_degree(graph, &outdegree, igraph_vss_all(), IGRAPH_OUT, /*loops=*/ 1);
286 igraph_vector_add_constant(&indegree, -1);
287 igraph_vector_add_constant(&outdegree, -1);
288 igraph_assortativity(graph, &outdegree, &indegree, res, /*directed=*/ 1);
289 igraph_vector_destroy(&indegree);
290 igraph_vector_destroy(&outdegree);
291 } else {
292 igraph_vector_t degree;
293 igraph_vector_init(°ree, 0);
294 igraph_degree(graph, °ree, igraph_vss_all(), IGRAPH_ALL, /*loops=*/ 1);
295 igraph_vector_add_constant(°ree, -1);
296 igraph_assortativity(graph, °ree, 0, res, /*directed=*/ 0);
297 igraph_vector_destroy(°ree);
298 }
299
300 return 0;
301 }
302