# Tony Hyun Kim
# 2013 12 29
# Experiments with cascade-based graph inference
#------------------------------------------------------------
from __future__ import division
from collections import OrderedDict

import random
import snap

source = "graph.txt"
G = snap.LoadEdgeList(snap.PNGraph, source, 0, 1)

# Simulate a cascade
#------------------------------------------------------------
# Cascade parameters
beta  = 0.85 # Probability that a contagion propagates over an edge
alpha = 1.0 # Parametrization of incubation model

print "* beta = {:.4f}".format(beta)
print "* alpha = {:.4f}".format(alpha)

num_cascades = 100
for cind in range(num_cascades):
    print "* Cascade {} of {}...".format(cind, num_cascades)

    # Node id of initial outbreak
    c0 = G.GetRndNId()

    # We store the cascade dict as follows. If node u infects node
    #   v at time tv, the corresponding dict entry is:
    #   cascade[v] = (u, tv)
    #cascade = {}
    cascade = OrderedDict()
    cascade[c0] = (c0, 0.0)

    frontier = [c0] # TODO: Convert to priority queue

    # Simulate infection from current node u
    while (len(frontier) > 0):
        u = frontier.pop(0) # Retrieve node at head of list
        tu = cascade[u][1]  # Time that u was infected
        nu = G.GetNI(u)
        for v in nu.GetOutEdges():
            if not cascade.has_key(v):       # Don't infect already infected nodes
                if (random.random() < beta): # Propagate over this edge
                    incub_time = random.expovariate(1.0/alpha)
                    cascade[v] = (u, tu+incub_time)
                    frontier.append(v)

    # Dump the cascade data in the format (u, v, tv)
    #------------------------------------------------------------
    for k, v in cascade.iteritems():
        print "{} {} {:.4f}".format(v[0], k, v[1])
