~ubuntu-branches/ubuntu/lucid/igraph/lucid

« back to all changes in this revision

Viewing changes to src/forestfire.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathieu Malaterre
  • Date: 2009-11-16 18:12:42 UTC
  • Revision ID: james.westby@ubuntu.com-20091116181242-mzv9p5fz9uj57xd1
Tags: upstream-0.5.3
ImportĀ upstreamĀ versionĀ 0.5.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: C -*-  */
 
2
/* 
 
3
   IGraph library.
 
4
   Copyright (C) 2007  Gabor Csardi <csardi@rmki.kfki.hu>
 
5
   MTA RMKI, Konkoly-Thege Miklos st. 29-33, Budapest 1121, Hungary
 
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.h"
 
25
#include "memory.h"
 
26
#include "random.h"
 
27
#include "config.h"
 
28
 
 
29
typedef struct igraph_i_forest_fire_data_t {
 
30
  igraph_vector_t *inneis;
 
31
  igraph_vector_t *outneis;
 
32
  long int no_of_nodes;
 
33
} igraph_i_forest_fire_data_t;
 
34
  
 
35
 
 
36
void igraph_i_forest_fire_free(igraph_i_forest_fire_data_t *data) {
 
37
  long int i;
 
38
  for (i=0; i<data->no_of_nodes; i++) {
 
39
    igraph_vector_destroy(data->inneis+i);
 
40
    igraph_vector_destroy(data->outneis+i);
 
41
  }
 
42
}
 
43
 
 
44
/**
 
45
 * \function igraph_forest_fire_game
 
46
 * \brief Generates a network according to the \quote forest fire game \endquote
 
47
 * 
 
48
 * The forest fire model intends to reproduce the following network
 
49
 * characteristics, observed in real networks:
 
50
 * \ilist
 
51
 * \ili Heavy-tailed in-degree distribution. 
 
52
 * \ili Heavy-tailed out-degree distribution.
 
53
 * \ili Communities.
 
54
 * \ili Densification power-law. The network is densifying in time,
 
55
 *      according to a power-law rule.
 
56
 * \ili Shrinking diameter. The diameter of the network decreases in
 
57
 *      time.
 
58
 * \endilist
 
59
 * 
 
60
 * </para><para>
 
61
 * The network is generated in the following way. One vertex is added at
 
62
 * a time. This vertex connects to (cites) <code>ambs</code> vertices already
 
63
 * present in the network, chosen uniformly random. Now, for each cited
 
64
 * vertex <code>v</code> we do the following procedure:
 
65
 * \olist
 
66
 * \oli We generate two random number, <code>x</code> and <code>y</code>, that are
 
67
 *   geometrically distributed with means <code>p/(1-p)</code> and
 
68
 *   <code>rp(1-rp)</code>. (<code>p</code> is <code>fw_prob</code>, <code>r</code> is
 
69
 *   <code>bw_factor</code>.) The new vertex cites <code>x</code> outgoing neighbors
 
70
 *   and <code>y</code> incoming neighbors of <code>v</code>, from those which are
 
71
 *   not yet cited by the new vertex. If there are less than <code>x</code> or
 
72
 *   <code>y</code> such vertices available then we cite all of them.
 
73
 * \oli The same procedure is applied to all the newly cited
 
74
 *   vertices.
 
75
 * \endolist
 
76
 * </para><para>
 
77
 * See also:
 
78
 * Jure Leskovec, Jon Kleinberg and Christos Faloutsos. Graphs over time:
 
79
 * densification laws, shrinking diameters and possible explanations.
 
80
 * \emb KDD '05: Proceeding of the eleventh ACM SIGKDD international
 
81
 * conference on Knowledge discovery in data mining \eme, 177--187, 2005.
 
82
 * </para><para>
 
83
 * Note however, that the version of the model in the published paper is incorrect
 
84
 * in the sense that it cannot generate the kind of graphs the authors
 
85
 * claim. A corrected version is available from
 
86
 * http://www.cs.cmu.edu/~jure/pubs/powergrowth-tkdd.pdf, our
 
87
 * implementation is based on this.
 
88
 * 
 
89
 * \param graph Pointer to an uninitialized graph object.
 
90
 * \param nodes The number of vertices in the graph.
 
91
 * \param fw_prob The forward burning probability.
 
92
 * \param bw_factor The backward burning ratio. The backward burning
 
93
      probability is calculated as <code>bw.factor*fw.prob</code>.
 
94
 * \param pambs The number of ambassador vertices.
 
95
 * \param directed Whether to create a directed graph.
 
96
 * \return Error code.
 
97
 * 
 
98
 * Time complexity: TODO.
 
99
 */
 
100
 
 
101
int igraph_forest_fire_game(igraph_t *graph, igraph_integer_t nodes,
 
102
                            igraph_real_t fw_prob, igraph_real_t bw_factor,
 
103
                            igraph_integer_t pambs, igraph_bool_t directed) {
 
104
  
 
105
  igraph_vector_long_t visited;
 
106
  long int no_of_nodes=nodes, actnode, i;
 
107
  igraph_vector_t edges;
 
108
  igraph_vector_t *inneis, *outneis;
 
109
  igraph_i_forest_fire_data_t data;
 
110
  igraph_dqueue_t neiq;
 
111
  long int ambs=pambs;
 
112
  igraph_real_t param_geom_out=1-fw_prob;
 
113
  igraph_real_t param_geom_in=1-fw_prob*bw_factor;
 
114
  
 
115
  if (fw_prob < 0) {
 
116
    IGRAPH_ERROR("Forest fire model: 'fw_prob' should be between non-negative", 
 
117
                 IGRAPH_EINVAL);
 
118
  }
 
119
  if (bw_factor < 0) {
 
120
    IGRAPH_ERROR("Forest fire model: 'bw_factor' should be non-negative",
 
121
                 IGRAPH_EINVAL);
 
122
  }
 
123
  if (ambs < 0) {
 
124
    IGRAPH_ERROR("Number of ambassadors ('ambs') should be non-negative",
 
125
                 IGRAPH_EINVAL);
 
126
  }
 
127
  
 
128
  if (fw_prob == 0 || ambs == 0) {
 
129
    IGRAPH_WARNING("'fw_prob or ambs is zero, creating empty graph");
 
130
    IGRAPH_CHECK(igraph_empty(graph, nodes, directed));
 
131
    return 0;
 
132
  }
 
133
  
 
134
  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
 
135
 
 
136
  inneis=igraph_Calloc(no_of_nodes, igraph_vector_t);
 
137
  if (!inneis) {
 
138
    IGRAPH_ERROR("Cannot run forest fire model", IGRAPH_ENOMEM);
 
139
  }
 
140
  IGRAPH_FINALLY(igraph_free, inneis);
 
141
  outneis=igraph_Calloc(no_of_nodes, igraph_vector_t);
 
142
  if (!outneis) {
 
143
    IGRAPH_ERROR("Cannot run forest fire model", IGRAPH_ENOMEM);
 
144
  }
 
145
  IGRAPH_FINALLY(igraph_free, outneis);  
 
146
  data.inneis=inneis; 
 
147
  data.outneis=outneis;
 
148
  data.no_of_nodes=no_of_nodes;
 
149
  IGRAPH_FINALLY(igraph_i_forest_fire_free, &data);
 
150
  for (i=0; i<no_of_nodes; i++) {
 
151
    IGRAPH_CHECK(igraph_vector_init(inneis+i, 0));
 
152
    IGRAPH_CHECK(igraph_vector_init(outneis+i, 0));
 
153
  }  
 
154
 
 
155
  IGRAPH_CHECK(igraph_vector_long_init(&visited, no_of_nodes));
 
156
  IGRAPH_FINALLY(igraph_vector_long_destroy, &visited);
 
157
  IGRAPH_DQUEUE_INIT_FINALLY(&neiq, 10);
 
158
 
 
159
  RNG_BEGIN();
 
160
 
 
161
#define ADD_EDGE_TO(nei) \
 
162
      if (VECTOR(visited)[(nei)] != actnode+1) {                     \
 
163
        VECTOR(visited)[(nei)] = actnode+1;                          \
 
164
        IGRAPH_CHECK(igraph_dqueue_push(&neiq, nei));                \
 
165
        IGRAPH_CHECK(igraph_vector_push_back(&edges, actnode));      \
 
166
        IGRAPH_CHECK(igraph_vector_push_back(&edges, nei));          \
 
167
        IGRAPH_CHECK(igraph_vector_push_back(outneis+actnode, nei)); \
 
168
        IGRAPH_CHECK(igraph_vector_push_back(inneis+nei, actnode));  \
 
169
      }
 
170
  
 
171
  IGRAPH_PROGRESS("Forest fire: ", 0.0, NULL);
 
172
  
 
173
  for (actnode=1; actnode < no_of_nodes; actnode++) {
 
174
 
 
175
    IGRAPH_PROGRESS("Forest fire: ", 100.0*actnode/no_of_nodes, NULL);
 
176
 
 
177
    IGRAPH_ALLOW_INTERRUPTION();    
 
178
    
 
179
    /* We don't want to visit the current vertex */
 
180
    VECTOR(visited)[actnode] = actnode+1;
 
181
 
 
182
    /* Choose ambassador(s) */
 
183
    for (i=0; i<ambs; i++) {
 
184
      long int a=RNG_INTEGER(0, actnode-1);
 
185
      ADD_EDGE_TO(a);
 
186
    }
 
187
    
 
188
    while (!igraph_dqueue_empty(&neiq)) {
 
189
      long int actamb=igraph_dqueue_pop(&neiq);
 
190
      igraph_vector_t *outv=outneis+actamb;
 
191
      igraph_vector_t *inv=inneis+actamb;
 
192
      long int no_in=igraph_vector_size(inv);
 
193
      long int no_out=igraph_vector_size(outv);
 
194
      long int neis_out=RNG_GEOM(param_geom_out);
 
195
      long int neis_in=RNG_GEOM(param_geom_in);
 
196
      /* outgoing neighbors */
 
197
      if (neis_out >= no_out) {
 
198
        for (i=0; i<no_out; i++) {
 
199
          long int nei=VECTOR(*outv)[i];
 
200
          ADD_EDGE_TO(nei);
 
201
        }
 
202
      } else {
 
203
        long int oleft=no_out;
 
204
        for (i=0; i<neis_out && oleft > 0; ) {
 
205
          long int which=RNG_INTEGER(0, oleft-1);
 
206
          long int nei=VECTOR(*outv)[which];
 
207
          VECTOR(*outv)[which] = VECTOR(*outv)[oleft-1];
 
208
          VECTOR(*outv)[oleft-1] = nei;
 
209
          if (VECTOR(visited)[nei] != actnode+1) {
 
210
            ADD_EDGE_TO(nei);
 
211
            i++;
 
212
          }
 
213
          oleft--;
 
214
        }
 
215
      }
 
216
      /* incoming neighbors */
 
217
      if (neis_in >= no_in) {
 
218
        for (i=0; i<no_in; i++) {
 
219
          long int nei=VECTOR(*inv)[i];
 
220
          ADD_EDGE_TO(nei);
 
221
        }
 
222
      } else {
 
223
        long int ileft=no_in;
 
224
        for (i=0; i<neis_in && ileft > 0; ) {
 
225
          long int which=RNG_INTEGER(0, ileft-1);
 
226
          long int nei=VECTOR(*inv)[which];
 
227
          VECTOR(*inv)[which] = VECTOR(*inv)[ileft-1];
 
228
          VECTOR(*inv)[ileft-1] = which;
 
229
          if (VECTOR(visited)[nei] != actnode+1) {
 
230
            ADD_EDGE_TO(nei);
 
231
            i++;
 
232
          }
 
233
          ileft--;
 
234
        }
 
235
      }
 
236
      
 
237
    } /* while neiq not empty */
 
238
 
 
239
  } /* actnode < no_of_nodes */
 
240
 
 
241
#undef ADD_EDGE_TO  
 
242
 
 
243
  RNG_END();
 
244
 
 
245
  IGRAPH_PROGRESS("Forest fire: ", 100.0, NULL);
 
246
  
 
247
  igraph_dqueue_destroy(&neiq);
 
248
  igraph_vector_long_destroy(&visited);
 
249
  igraph_i_forest_fire_free(&data);
 
250
  igraph_free(outneis);
 
251
  igraph_free(inneis);  
 
252
  IGRAPH_FINALLY_CLEAN(5);
 
253
 
 
254
  IGRAPH_CHECK(igraph_create(graph, &edges, nodes, directed));
 
255
  igraph_vector_destroy(&edges);
 
256
  IGRAPH_FINALLY_CLEAN(1);
 
257
 
 
258
  return 0;
 
259
}