/** * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * . * * (c) Vincenzo Nicosia 2009-2017 -- * * This file is part of NetBunch, a package for complex network * analysis and modelling. For more information please visit: * * http://www.complex-networks.net/ * * If you use this software, please add a reference to * * V. Latora, V. Nicosia, G. Russo * "Complex Networks: Principles, Methods and Applications" * Cambridge University Press (2017) * ISBN: 9781107103184 * *********************************************************************** * * This in an implementation of the hidden-variable model by Bogunya' * and Pastor-Satorras. The program creates a random graph whose * joint degree distribution is identical to that of a network given * as input. * * References: * * [1] M. Boguna and R. Pastor-Satorras. "Class of correlated random * networks with hidden variables". Phys. Rev. E 68 (2003), 036112. * */ #include #include #include #include #include #include "utils.h" #include "cum_distr.h" void usage(char *argv[]){ printf("********************************************************************\n" "** **\n" "** -*- hv_net -*- **\n" "** **\n" "** Create a random graph whose joint degree distribution is **\n" "** identical to that of a network provided as input. **\n" "** **\n" "** If 'graph_in' is equal to '-' (dash), read the edge list **\n" "** from STDIN. **\n" "** **\n" "** The program prints on STDOUT the edge-list of the sampled **\n" "** graph. **\n" "** **\n" "** If 'SHOW' is specified as second parameter, the program **\n" "** prints on STDERR the values of the hidden variable **\n" "** associated to each node and of the actual degree they have **\n" "** in the newly-created random graph, in the format: **\n" "** **\n" "** h_1 k_1 **\n" "** h_2 k_2 **\n" "** ... **\n" "** h_N k_N **\n" "** **\n" "********************************************************************\n" " This is Free Software - You can use and distribute it under \n" " the terms of the GNU General Public License, version 3 or later\n\n" " (c) Vincenzo Nicosia 2009-2017 (v.nicosia@qmul.ac.uk)\n\n" "********************************************************************\n\n" ); printf("Usage: %s [SHOW]\n", argv[0]); } typedef struct{ unsigned int N; unsigned int K; unsigned int *J_slap; unsigned int *r_slap; unsigned int k_min; unsigned int k_max; double *pk; /* degree distribution -- this is equal to rho!!!! */ double **pkk; /* joint degree distribution */ double **f; /* the linking function */ unsigned int *h; /* The array containing hidden variables for the N nodes */ unsigned int *new_degs; /* the new degrees of the sampled graph */ } params_t; /** * * sample the hidden degrees of the nodes using the cumulative * distribution P(k) * */ void sample_node_variables(params_t *p, cum_distr_t *P){ unsigned int i; unsigned int k; for(i=0; iN; i++){ k = cum_distr_sample(P); p->h[i] = k; } } /** * * Compute the function f(h,h') for each pair of degrees * */ void compute_fhh(params_t *p){ unsigned int k1, k2; double avg_k; avg_k = 1.0 * p->K / p->N; for(k1 = p->k_min; k1 <= p->k_max; k1++){ for(k2 = k1; k2 <= p->k_max; k2++){ p->f[k1][k2] = p->f[k2][k1] = avg_k * p->pkk[k1][k2] / (p->N * p->pk[k1] * p->pk[k2]); } } } /** * * Sample the edges of the graph * */ void sample_edges(params_t *p){ unsigned int i, j, ki, kj; double val; for(i=0; iN; i++){ ki = p->h[i]; for (j=i+1; jN; j++){ kj = p->h[j]; val = 1.0 * rand() / RAND_MAX; /* we create the edge (i,j) with proability f[ki][kj]*/ if (val < p->f[ki][kj]){ printf("%d %d\n", i, j); p->new_degs[i] += 1; p->new_degs[j] += 1; } } } } void init_hv_params(params_t *p){ unsigned int i; p->h = malloc(p->N * sizeof(unsigned int)); p->f = malloc((p->k_max + 1) * sizeof(double*)); p->new_degs = malloc(p->N * sizeof(unsigned int)); for(i=0; i<=p->k_max; i++){ p->f[i] = malloc((p->k_max + 1) * sizeof(double)); } for (i=0; iN; i++){ p->new_degs[i] = 0; } } void compute_distributions(params_t *g){ unsigned int i,j, neigh, k1, k2; double sumk, sumkk; g->k_min = g->N; g->k_max = 0; g->pk = NULL; /* Compute (and allocate on the fly) the degree distribution */ for(i=0; i< g->N; i ++){ k1 = g->r_slap [i+1] - g->r_slap[i]; if (k1 > g->k_max){ g->pk = realloc(g->pk, (k1 + 1) * sizeof(double)); for(j=g->k_max+1; j<=k1; j++){ g->pk[j] = 0; } g->k_max = k1; } else if(k1 < g->k_min){ g->k_min = k1; } g->pk[k1] += 1; } /* Allocate and initialise the joint degree distribution */ g->pkk = malloc((g->k_max + 1 ) * sizeof(double*)); for(i=0; i<=g->k_max ; i++){ g->pkk[i] = malloc((g->k_max + 1) * sizeof(double)); memset(g->pkk[i], 0, (g->k_max + 1) * sizeof(double)); } for(i=0; iN; i++){ k1 = g->r_slap[i+1] - g->r_slap[i]; for(j=g->r_slap[i]; j< g->r_slap[i+1]; j++){ neigh = g->J_slap[j]; k2 = g->r_slap[neigh+1] - g->r_slap[neigh]; g->pkk[k1][k2] += 1; } } /* Now we normalise both pk and pkk...*/ sumk = sumkk = 0.0; for(i=0; i<=g->k_max; i++){ g->pk[i] /= g->N; sumk += g->pk[i]; g->pkk[i][i] /= (g->K); sumkk += g->pkk[i][i]; for(j=i+1; j<=g->k_max; j++){ g->pkk[i][j] /= (g->K); g->pkk[j][i] = g->pkk[i][j]; sumkk += 2* g->pkk[i][j]; } } } void compute_rho(params_t *g, cum_distr_t *P){ unsigned int k; for(k=g->k_min; k<= g->k_max; k++){ if(g->pk[k] > 0){ if (cum_distr_add(P, k, g->pk[k]) != 0){ fprintf(stderr, "Error in the computation of the cumulative degree distribution!!!!" " Exiting!!!\n"); exit(3); } } } } void dump_deg_h(params_t *p){ unsigned int i; for(i=0; iN; i++){ fprintf(stderr, "%d %d\n", p->h[i], p->new_degs[i]); } } int main(int argc, char *argv[]){ params_t p; cum_distr_t *P; int i; FILE *filein; if (argc < 2){ usage(argv); exit(1); } srand(time(NULL)); if (!strcmp(argv[1], "-")){ /* take the input from STDIN */ filein = stdin; } else { filein = openfile_or_exit(argv[1], "r", 2); } p.J_slap = p.r_slap = NULL; read_slap(filein, &(p.K), &(p.N), &(p.J_slap), &(p.r_slap)); fclose(filein); compute_distributions(&p); init_hv_params(&p); P = cum_distr_init(p.k_max + 1); compute_rho(&p, P); compute_fhh(&p); sample_node_variables(&p, P); sample_edges(&p); /* * If 'SHOW' is provided, print on STDERR the value of the hidden * variable of each node */ if (argc > 2 && !my_strcasecmp(argv[2], "SHOW")){ dump_deg_h(&p); } cum_distr_destroy(P); free(p.J_slap); free(p.r_slap); free(p.pk); free(p.h); free(p.new_degs); for(i=0; i<=p.k_max ; i++){ free(p.pkk[i]); free(p.f[i]); } free(p.pkk); free(p.f); }