Advertisement
BenjaminLind

ClassSimulation.R

Jun 2nd, 2014
117
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
R 8.30 KB | None | 0 0
  1. library(Rcpp)
  2. library(igraph)
  3. library(compiler)
  4.  
  5. cppFunction('
  6. LogicalMatrix thresh_diffusion(int times, LogicalVector infected, NumericVector thresholds, IntegerMatrix el, double friendshipeffect){
  7.    int n = infected.size();
  8.    int ninfected = 0;
  9.    int nedges = el.nrow();
  10.    int friendsinfected;
  11.    int friendsuninfected;
  12.    double infectedeffect;
  13.    double uninfectedeffect;
  14.    double totaleffect;
  15.    LogicalVector newinfected(n);
  16.    LogicalMatrix infectedout(n, (times + 1));
  17.    
  18.    for (int i = 0; i < n; i++){        
  19.        if (infected[i]){
  20.         ninfected++;  
  21.         newinfected[i] = true;
  22.         }
  23.     else{
  24.         newinfected[i] = false;
  25.         }
  26.        infectedout(i, 0) = infected[i];
  27.        }
  28.    for (int i = 1; i < (times + 1); i++){
  29.        for (int j = 0; j < n; j++){
  30.         infectedout(j, i) = infectedout(j, (i - 1));
  31.            if (infectedout(j, i) == false){
  32.                friendsinfected = 0;
  33.             friendsuninfected = 0;
  34.             for (int k = 0; k < nedges; k++){
  35.                 if (el(k, 0) == j){
  36.                     if (newinfected[el(k, 1)]){
  37.                     friendsinfected++;
  38.                     }
  39.                 else {
  40.                     friendsuninfected++;
  41.                     }
  42.                     }
  43.                 if (el(k, 1) == j){
  44.                     if (newinfected[el(k, 0)]){
  45.                 friendsinfected++;
  46.                     friendsinfected++;
  47.                     }
  48.                 else {
  49.                     friendsuninfected++;
  50.                     }
  51.                     }
  52.                 }
  53.             infectedeffect = ninfected + ((friendshipeffect - 1) * friendsinfected);
  54.             uninfectedeffect = n - ninfected + ((friendshipeffect - 1) * friendsuninfected);
  55.             totaleffect = infectedeffect / (infectedeffect + uninfectedeffect);
  56.             infectedout(j, i) = totaleffect > thresholds[j];
  57.             if (infectedout(j, i)){
  58.             newinfected[j] = true;
  59.                 ninfected++;
  60.                 }
  61.             }
  62.            }
  63.        }
  64.    return infectedout;
  65.    }
  66. ')
  67.  
  68. # I have tried to write the function below in C++ instead, though it's sometimes much slower.
  69. vazquez.game.el<-function(N, u){
  70.   #_N_ is the number of nodes
  71.   #_u_ is the triadic closure parameter. Needs to be between 0 and 1.
  72.   #Alexei Vazquez.  2003.  "Growing network with local rules: Preferential attachment, clustering hierarchy, and degree correlations."  Physical Review E 67, 056104
  73.   add.node.edge<-function()
  74.     return(add.node=c(rbinom(1,1,1-u), close.tri=rbinom(1,1,u)))
  75.   vneigh<-function(v, el){
  76.     receivers<-el[which(el[,1]==v), 2]
  77.     senders<-el[which(el[,2]==v), 1]
  78.     return(unique(c(receivers, senders)))
  79.     }
  80.   g<-matrix(NA, 0, 2)
  81.   potentials<-matrix(NA, 0, 2)
  82.   ncount<-1
  83.   while(ncount<N){
  84.     a<-add.node.edge()
  85.     if (a[1]==1){
  86.       source.v<-ncount+1
  87.       target.v<-ifelse(ncount>1, sample.int(ncount, 1), 1)
  88.       target.neighbors<-vneigh(target.v, g)
  89.       g<-rbind(g, c(source.v, target.v))
  90.       n.neighbors<-length(target.neighbors)
  91.       if (n.neighbors>0){
  92.         new.potentials<-matrix(NA, n.neighbors, 2)
  93.         new.potentials[,1]<-source.v
  94.         new.potentials[,2]<-target.neighbors
  95.         potentials<-rbind(potentials, new.potentials)
  96.         rm(new.potentials)
  97.         }
  98.       rm(source.v, target.v, target.neighbors, n.neighbors)
  99.       ncount<-ncount+1
  100.       }
  101.     if ((a[2]==1)&(ncount>2)&(length(potentials)>=2)){
  102.       if (length(potentials)==2){
  103.         g<-rbind(g, c(potentials[1], potentials[2]))
  104.         potentials<-matrix(NA, 0, 2)
  105.         }
  106.       else{
  107.         potentials.ind<-sample.int(nrow(potentials), 1)
  108.         adders<-potentials[potentials.ind, ]
  109.         g<-rbind(g, c(adders[1], adders[2]))
  110.         potentials<-potentials[-potentials.ind,]
  111.         }
  112.       }    
  113.     }
  114.   return(g)
  115.   }; vazquez.game.el<-cmpfun(vazquez.game.el)
  116.  
  117. vazquez.game.noise <- function(N, u, p){
  118.     # _N_ is the number of nodes
  119.     # _u_ is the triadic closure parameter. Needs to be between 0 and 1.
  120.     # _p_ is the proportion of edges to rewire
  121.     g <- graph.edgelist(vazquez.game.el(N, u), directed = FALSE)
  122.     g <- rewire(g, mode = "simple", niter = round(p * ecount(g)))
  123.     }; vazquez.game.noise <- cmpfun(vazquez.game.noise)
  124.  
  125. thresh_diffusion_ig = function(g, infected, thresholds, iters, friendshipeffect = 2){
  126.     # _g_ is a simple, undirected igraph graph object
  127.     # _infected_ is the initial conditions as to who is infected (TRUE) and who is not (FALSE)
  128.     # _thresholds_ are the individual thresholds. If the proportion of the population exceeds an individual's threshold, that individual will participate. It should be between 0 and 1.
  129.     # _iters_ is how many waves to go through the threshold experiment.
  130.     # _friendshipeffect_ is how much each friend should count in an individual's decision. Granovetter says "2." That's the default, yet it's arbitrary and can be altered.
  131.     el <- get.edgelist(g, names = FALSE) - 1
  132.     return(thresh_diffusion(iters, infected, thresholds, el, friendshipeffect))
  133.     }; thresh_diffusion_ig = cmpfun(thresh_diffusion_ig)
  134.  
  135. # A pretty nice example of the simulation
  136. g <- vazquez.game.noise(100, .35, .20)    
  137. g.lo <- layout.fruchterman.reingold(g, params=list(niter = 2500, area = 100^3))
  138. infvec <- sample(c(TRUE, FALSE), 100, c(.05, .95), replace = TRUE)
  139. thresh <- runif(100, 0, 1)
  140. diffuse.out <- thresh_diffusion_ig(g, infvec, thresh, 5, friendshipeffect = 2)
  141. par(mfrow = c(2, 3), mar = c(0, 0, 0, 0))
  142. for (i in 1:6){    
  143.     plot(g, vertex.size = 5 + 3 * log(1/sqrt(thresh)), vertex.color = c("light blue", "pink")[diffuse.out[, i] + 1], vertex.label = "", layout = g.lo, margin = c(0, 0, 0, 0))
  144.     }
  145. plot(x = c(0:5), y = 100 * apply(diffuse.out, 2, mean), xlab = "Time", ylab = "Engaged (%)", main = "Threshold Model of Collective Action", type = "l")
  146.    
  147. dev.off()
  148. class_sim <- function(N, u, p.rewire, friendship = 2, trials = 5, p.initial = .05, threshdist = NULL){
  149.     if (is.null(threshdist)){
  150.         thresholds <- runif(N, min = 0, max = 1)
  151.     }
  152.     infvec <- sample(c(TRUE, FALSE), N, c(p.initial, 1 - p.initial), replace = TRUE)
  153.     g <- vazquez.game.noise(N, u, p.rewire)
  154.     infections <- thresh_diffusion_ig(g, infvec, thresholds, trials, friendshipeffect = friendship)
  155.     infectedcases <- round(100 * apply(infections, 2, mean), digits = 3)
  156.     infectionslope <- mean(diff(infectedcases))
  157.     return(list(graph = g, initial = infvec, thresholds = thresholds, infections = infections, cumulative.cases = infectedcases, slope = infectionslope, parameters = list(N = N, u = u, p.rewire = p.rewire, friendship = friendship, trials = trials, p.initial = p.initial, threshdist = threshdist)))
  158.     }; class_sim <- cmpfun(class_sim)
  159.  
  160. # Let's test increasing the density/transitivity of the network
  161. f1 <- function(){
  162.     temp = class_sim(100, runif(1, min = 0, max = 1), .20, 5)
  163.     return(c(u = temp$parameters$u, slope = temp$slope))
  164.     }; f1 <- cmpfun(f1)
  165. utest <- t(replicate(100, f1()))
  166. summary(lm(utest[,2] ~ utest[,1]))
  167. # Yes, positive effect between u and slope. As density/transitivity increases, so too does the rate of diffusion.
  168.  
  169. # Let's test increasing the network's randomization
  170. f2 <- function(){
  171.     temp = class_sim(100, .35, runif(1, 0, 1), 5)
  172.     return(c(rw = temp$parameters$p.rewire, slope = temp$slope))
  173.     }; f2 <- cmpfun(f2)
  174. rwtest <- t(replicate(100, f2()))
  175. summary(lm(rwtest[,2] ~ rwtest[,1]))
  176. # Seemingly no effect. Interesting--it would suggest the findings from early reflect density, not transitivity
  177.  
  178. # Let's test adjusting the friendship constant
  179. f3 <- function(){
  180.     temp = class_sim(100, .35, .20, 5, friendship = runif(1, 1, 5))
  181.     return(c(friendship = temp$parameters$friendship, slope = temp$slope))
  182.     }; f3 <- cmpfun(f3)
  183. friendshiptest <- t(replicate(100, f3()))
  184. summary(lm(friendshiptest[,2] ~ friendshiptest[,1]))
  185. # Nothing. So long as there's a friendship constant, it doesn't seem to matter.
  186.  
  187. # Let's test both the density and the rewiring effect.
  188. f4 <- function(){
  189.     temp = class_sim(100, runif(1, min = 0, max = 1), runif(1, 0, 1), 5)
  190.     return(c(u = temp$parameters$u, rw = temp$parameters$p.rewire, slope = temp$slope))
  191.     }; f4 <- cmpfun(f4)
  192. urwtest <- t(replicate(100, f4()))
  193. summary(lm(urwtest[,3] ~ urwtest[,1] + urwtest[,2]))
  194. # Again, density effects through u, but nothing from the rewiring test.
  195. # I have increased the number of replications and the results are the same.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement