diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/_site/03-algorithm.html b/_site/03-algorithm.html index a01eb1d..820743b 100644 --- a/_site/03-algorithm.html +++ b/_site/03-algorithm.html @@ -90,27 +90,27 @@
In this section, we are going to explore the implementation of linear threshold model in R studio.
+In this coding section, we’ll cover the implementation of the Linear Threshold Model in RStudio.
@@ -3032,7 +3032,7 @@Selected node: 15 with influence: 39
Selected node: 11 with influence: 39
Selected node: 22 with influence: 44
-[1] "Total time: 0.149544954299927"
+[1] "Total time: 0.149084091186523"
Selected node: 35 with influence: 40
Selected node: 16 with influence: 45
Selected node: 13 with influence: 38
-[1] "Total time: 0.196632862091064"
+[1] "Total time: 0.194490909576416"
seed_set
Explore various functions of the Linear Threshold Model (LTM) and interactive Shiny apps for simulations! Click “Show Code” to see the implementation details. 🌟
+Explore various functions of the Linear Threshold Model (LTM) and interactive Shiny apps for simulations! Click “Show Code” to see the implementation details.
# Function to run linear threshold model
runLT <- function(G, S, Ew) {
T <- unique(S) # Targeted set with unique nodes
- lv <- sapply(V(G), function(u) runif(1)) # Threshold for nodes
- W <- rep(0, vcount(G)) # Weighted number of activated in-neighbors
+ lv <- sapply(V(G), function(u) runif(1)) # Threshold for nodes
+ W <- rep(0, vcount(G)) # Weighted number of activated in-neighbors
Sj <- unique(S)
while (length(Sj) > 0) {
- if (length(T) >= vcount(G)) {
+ if (length(T) >= vcount(G)) {
break # Break if the number of active nodes exceeds or equals the total number of nodes in G
}
Snew <- c()
for (u in Sj) {
- neighbors <- neighbors(G, u, mode = "in")
+ neighbors <- neighbors(G, u, mode = "in")
for (v in neighbors) {
- e <- as.character(get.edge.ids(G, c(v, u))) # Define 'e' as the edge index
+ e <- as.character(get.edge.ids(G, c(v, u))) # Define 'e' as the edge index
if (!(v %in% T)) {
# Calculate the total weight of the activated in-neighbors
total_weight <- sum(Ew[[e]])
@@ -2588,8 +2588,8 @@ Liner Threshold Model
total_active_nodes[i] <- total_active # Update total active nodes for current iteration
# Limit total active nodes to the number of nodes in the graph
- if (total_active_nodes[i] >= vcount(G)) {
- total_active_nodes[i] <- vcount(G)
+ if (total_active_nodes[i] >= vcount(G)) {
+ total_active_nodes[i] <- vcount(G)
}
# Update data frame with current iteration's total active nodes
@@ -2620,24 +2620,24 @@ Erdős-Rényi model
## Erdős–Rényi model
set.seed(123)
# Create a random graph with 50 nodes and edge weights satisfying the constraint
-random_graph_50 <- erdos.renyi.game(50, p = 0.05, directed = TRUE) # random graph set up
+random_graph_50 <- erdos.renyi.game(50, p = 0.05, directed = TRUE) # random graph set up
# Equal edge weight for node v -> Calculate uniform edge weights
Ew_uniform <- uniformWeights(random_graph_50)
# Scale edge width based on the weights in Ew_uniform
-edge_width <- sapply(E(random_graph_50), function(e) {
- v <- ends(random_graph_50, e)[2]
+edge_width <- sapply(E(random_graph_50), function(e) {
+ v <- ends(random_graph_50, e)[2]
Ew_uniform[[as.character(e)]]
})
# Map edge_width to color_palette
-color_palette <- wes_palette(n=5, name="Zissou1")
+color_palette <- wes_palette(n=5, name="Zissou1")
edge_color <- color_palette[cut(edge_width, breaks = 5)]
# Plot the graph with gradient edge color
par(mar=c(0,0,0,0)+.1)
-p1 <- plot.igraph(random_graph_50,
+p1 <- plot.igraph(random_graph_50,
edge.width = edge_width,
edge.color = edge_color,
edge.arrow.size = 0.4,
@@ -2663,24 +2663,24 @@ Preferential attachment model
## Preferential attachment model
set.seed(123)
# Create a random graph with 50 nodes and edge weights satisfying the constraint
-random_graph_50 <- sample_pa(50, power = 1, m = 5) # random graph set up
+random_graph_50 <- sample_pa(50, power = 1, m = 5) # random graph set up
# Equal edge weight for node v -> Calculate uniform edge weights
Ew_uniform <- uniformWeights(random_graph_50)
# Scale edge width based on the weights in Ew_uniform
-edge_width <- sapply(E(random_graph_50), function(e) {
- v <- ends(random_graph_50, e)[2]
+edge_width <- sapply(E(random_graph_50), function(e) {
+ v <- ends(random_graph_50, e)[2]
Ew_uniform[[as.character(e)]]
})
# Map edge_width to color_palette
-color_palette <- wes_palette(n=5, name="Zissou1")
+color_palette <- wes_palette(n=5, name="Zissou1")
edge_color <- color_palette[cut(edge_width, breaks = 5)]
# Plot the graph with gradient edge color
par(mar=c(0,0,0,0)+.1)
-p1 <- plot.igraph(random_graph_50,
+p1 <- plot.igraph(random_graph_50,
edge.width = edge_width,
edge.color = edge_color,
edge.arrow.size = 0.4,
@@ -2725,10 +2725,10 @@ Greedy Algorithm for LTM
S <- c() # Initialize the seed set
for (i in 1:k) {
- inf <- data.frame(nodes = V(G), influence = NA) # Initialize the influence table
+ inf <- data.frame(nodes = V(G), influence = NA) # Initialize the influence table
# Calculate the influence for nodes not in S
- for (v in V(G)) {
+ for (v in V(G)) {
if (!(v %in% S)) {
inf$influence[v] <- avgLT(G, c(S, v), Ew, iterations = 1)
}
@@ -2781,8 +2781,8 @@ Animation
total_active_nodes[i] <- total_active # Update total active nodes for current iteration
# Limit total active nodes to the number of nodes in the graph
- if (total_active_nodes[i] >= vcount(G)) {
- total_active_nodes[i] <- vcount(G)
+ if (total_active_nodes[i] >= vcount(G)) {
+ total_active_nodes[i] <- vcount(G)
}
# Update data frame with current iteration's total active nodes
@@ -2801,7 +2801,7 @@ Animation
# Example usage
-random_graph <- erdos.renyi.game(50, 0.1, directed = TRUE)
+random_graph <- erdos.renyi.game(50, 0.1, directed = TRUE)
# Calculate uniform edge weights
Ew_uniform <- uniformWeights(random_graph)
@@ -2812,7 +2812,7 @@ Animation
Selected node: 2 with influence: 37
Selected node: 22 with influence: 38
Selected node: 32 with influence: 40
-[1] "Total time: 0.191519975662231"
+[1] "Total time: 0.208096981048584"
active_df_selectedSeed <- activeNodes_list(random_graph, seed_set, Ew_uniform, iterations = 5)
# Scale edge width based on the weights in Ew_uniform
-edge_width <- sapply(E(random_graph), function(e) {
- v <- ends(random_graph, e)[2]
+edge_width <- sapply(E(random_graph), function(e) {
+ v <- ends(random_graph, e)[2]
Ew_uniform[[as.character(e)]]
})
# Map edge_width to color_palette
-color_palette <- wes_palette(n = 5, name = "Zissou1")
+color_palette <- wes_palette(n = 5, name = "Zissou1")
edge_color <- color_palette[cut(edge_width, breaks = 5)]
@@ -2836,12 +2836,12 @@ Animation
T_list_with_seed <- c(list(seed_set), active_df_selectedSeed[["T_list"]])
# Create the GIF
-saveGIF(
+saveGIF(
expr = {
for (i in seq_along(T_list_with_seed)) {
T <- T_list_with_seed[[i]]
par(mar=c(6,0,0,0)+.1)
- p <- plot.igraph(
+ p <- plot.igraph(
random_graph,
edge.width = edge_width,
edge.color = edge_color,
@@ -2849,7 +2849,7 @@ Animation
layout = layout.circle,
# vertex.label = NA,
vertex.size = 10,
- vertex.color = ifelse(1:vcount(random_graph) %in% T, "#FC888F", "#A9AABC")
+ vertex.color = ifelse(1:vcount(random_graph) %in% T, "#FC888F", "#A9AABC")
)
title(p, ifelse(i == 1, "Initial Seed Set", paste("In Step", i - 1)))
}
diff --git a/_site/Library.bib b/_site/Library.bib
deleted file mode 100644
index 11dd7d4..0000000
--- a/_site/Library.bib
+++ /dev/null
@@ -1,11 +0,0 @@
-@article{Chen2010ScalableIM,
- title={Scalable Influence Maximization in Social Networks under the Linear Threshold Model},
- author={Wei Chen and Yifei Yuan and Li Zhang},
- journal={2010 IEEE International Conference on Data Mining},
- year={2010},
- pages={88-97},
- url={https://api.semanticscholar.org/CorpusID:14294472}
-}
-
-
-
\ No newline at end of file
diff --git a/_site/search.json b/_site/search.json
index 9a6cc3f..2008901 100644
--- a/_site/search.json
+++ b/_site/search.json
@@ -6,23 +6,23 @@
"description": "The methodology section introduces the Linear Threshold Model (LTM), a tool used to simulate influence propagation in networks. It explains the significance of solving the influence maximization problem and outlines the hill-climbing algorithm used for optimization.\n",
"author": [],
"contents": "\nSetting Up\nLinear Threshold Model (LTM) is one of the famous models simulating the spread of influence in networks. Continuing with the movie-inspired analogy, let’s delve into the mechanics of how influence spreads through a network, denoted as \\(G\\). In this directed network, each individual is represented as a node, categorized as either active (an adopter of the idea) or inactive. Drawing from our motivation, the general assumption is that each node tends to become active.\nNow, let’s consider the process in which nodes transition from being inactive to active. This transition occurs monotonically, meaning nodes can only shift from being inactive to active, but not the other way around. Thus, as time progresses, more and more of a node \\(v\\)’s neighbors become active. At some point, a neighbor node \\(w\\) influences \\(v\\) to become active, triggering further decisions among other nodes connected to \\(v\\).\nLinear Threshold Model (LTM)\n\n\n\nFigure 1: Linear Threshold Model example\n\n\n\nIn the Linear Threshold model, a node \\(v\\) is influenced by each neighbor \\(w\\) with a weight \\(b_{v,w}\\) such that\n\\[\\sum_{w \\text{ neighbor of v}} b_{v,w} \\le 1\\]\n. Each node \\(v\\) has a threshold \\(\\theta_v\\) which is randomly drawn from the uniform distribution over the interval \\([0,1]\\), representing the different levels of tendency for each node to adopt the idea from their neighbors.\nWith a given a random threshold and an initial set of active nodes \\(A_0\\) (while all other nodes are inactive), the model operates in discrete steps. In step \\(t\\), all nodes that are active in step \\(t-1\\) remain active, and any inactive node \\(v\\) in step \\(t-1\\) becomes active if the weighted sum of its active neighbors is at least \\(\\theta_v\\):\n\\[\\sum_{w\\text{ active neighbors of v}} b_{v,w}\\ge \\theta_v\\]\nInfluence Maximization Problem\nThe Influence Maximization Problem focuses on finding the best starting nodes to kick off the spread of influence in a network. It’s all about figuring out: Where should we begin to maximize the nodes’ impact?\nTo crack this problem, we define the influence of a set of nodes \\(A\\), denoted as \\(\\sigma(A)\\), as the expected number of active nodes at the end of the process, assuming \\(A\\) is our initial set of active nodes \\(A_0\\). So, the goal of the influence maximization problem is to identify the best initial set of nodes \\(A_0\\), given a certain number \\(k\\) where \\(k\\in \\bf{N}\\), to maximize our influence.\nWhy is it important?\nThis problem is important because it helps us understand how information or behavior spreads in networks. By finding the most influential starting points, we can set off a chain reaction that gets more and more people on board with our idea or action. This matters a lot in areas like marketing, where we want to reach as many customers as possible, in disease control, where we aim to stop outbreaks before they spread, and in understanding social networks, where we want to see how trends catch on among groups of people.\nApporximation for Influence Maximization\nHowever, it turns out that the influence maximization problem is acutally NP-hard, meaning that it could not be solved in polynomial time (assuming \\(P\\neq NP\\)). Thus, solving it efficiently isn’t straightforward–it’s a really complex problem that could take a long time to solve, especially as the size of the network is huge (Processing 30,000 nodes will take days to complete).\nTherefore, the best approach will be approximating the influence maximization problem. Here are several approximation guarantees to ensure that the following approximation method works.\nFor an arbitrary instance of Linear Threshold Model, the resulting influence function \\(\\sigma(\\cdot)\\) is submodular.\n\\(\\sigma(\\cdot)\\) is submodular if it exhibits the “diminishing marginal returns”, meaning that the marginal gain from adding a element to a set \\(S\\) is at least as high as the marginal gain from adding the same element to \\(T\\) where \\(S\\subseteq T\\). Mathematically, this is represented as: \\(f(S\\cup \\{v\\})-f(S) \\ge f(T\\cup \\{v\\})-f(T), \\forall\\) elements \\(v\\) and all pairs of sets \\(S\\subseteq T\\).\nSubmodularity is important because it guarantees that the greedy algorithm’s approximation will not overshoot the optimal solution too much. Specifically, it ensures that the marginal gain achieved by adding a node to the seed set diminishes as the size of the seed set increases. This property allows the greedy algorithm to make locally optimal decisions at each step.\nThis also implies that \\(\\sigma(\\cdot)\\) is also a monotone function. This means that adding an element to the set cannot make the overall influence decrease, which aligns with the intuitive expectation that more influencers lead to more influence.\n\nAlgorithm: Greedy Hill-Climbing\nOne proposed approximation strategy is to use the greedy hill-climbing.\nGreedy hill-climbing is an iterative algorithm that begins with an arbitrary solution to a problem and then tries to enhance it by making small incremental adjustments. If a change results in a better solution, the algorithm adopts it and continues making further adjustments until no further improvements can be made.\nIn the context of the influence maximization problem, we employ greedy hill-climbing to identify the most influential nodes. We begin with an empty active set \\(A_0\\). At each step \\(i\\), the algorithm selects one node to activate, aiming to maximize its influence on the network. However, it’s important to note that this approach may only lead to finding local maximum seed nodes, rather than a globally optimal solution.\nThis approach achieves an approximation ratio of 63% but performs fairly slow and not salable.\n\n\n\nFigure 2: Hill Climbing Algorithm. Created by Mahyavanshi, B.\n\n\n\nReferences\nChen, W., Yuan, Y., & Zhang, L. (2010). Scalable Influence Maximization in Social Networks under the Linear Threshold Model. 2010 IEEE International Conference on Data Mining, 88-97.\nKempe, D., Kleinberg, J.M., & Tardos, É. (2003). Maximizing the spread of influence through a social network. Theory Comput., 11, 105-147.\nMahyavanshi, B. (2019, September 8). Introduction to hill climbing: Artificial intelligence. Medium. https://medium.com/@bhavek.mahyavanshi50/introduction-to-hill-climbing-artificial-intelligence-a3714ed2d8d8\n\n\n\n",
- "last_modified": "2024-04-30T11:03:54-05:00"
+ "last_modified": "2024-04-30T12:32:14-05:00"
},
{
"path": "03-algorithm.html",
"title": "R code",
"description": "In this coding section, we'll cover the implementation of the Linear Threshold Model in RStudio.\n",
"author": [],
- "contents": "\nLoad Packages\n\n\n# Use `install.packages(\"_package name_\")` if you haven't install them\nlibrary(tidyverse) \nlibrary(ggpubr)\nlibrary(igraph)\nlibrary(poweRlaw)\nlibrary(ggformula)\nlibrary(data.table)\nlibrary(graphics)\nlibrary(knitr)\nlibrary(rmarkdown)\nlibrary(wesanderson) # color\nlibrary(animation) \n\ntheme_set(theme_bw())\n\n\nLiner Threshold Model\n\n\n# Function to calculate uniform edge weights\n## Every incoming edge of v with degree dv has weight 1/dv.\nuniformWeights <- function(G) {\n # Initialize empty list to store edge weights\n Ew <- list()\n # Loop over edges in the graph\n for (e in E(G)) {\n # Get the target node of the edge\n v <- ends(G, e)[2]\n # Calculate the degree of the target node\n dv <- degree(G, v, mode = \"in\")\n # Assign weight to the edge\n Ew[[as.character(e)]] <- 1 / dv\n }\n return(Ew)\n}\n\n# Function to calculate random edge weights \n## Every edge has random weight. After weights assigned, we normalize weights of all incoming edges for each node so that they sum to 1.\nrandomWeights <- function(G) {\n Ew <- list() # Initialize empty list to store edge weights\n # Assign random weights to edges\n for (v in V(G)) {\n in_edges <- incident(G, v, mode = \"in\") # Get incoming edges for the current node\n ew <- runif(length(in_edges)) # Generate random weights for incoming edges\n total_weight <- sum(ew) # Calculate the total weight of incoming edges\n # Normalize weights so that they sum to 1 for each node\n ew <- ew / total_weight\n # Store the weights for the incoming edges\n for (i in seq_along(in_edges)) {\n Ew[[as.character(in_edges[i])]] <- ew[i]\n }\n }\n return(Ew)\n}\n\n\n# Function to run linear threshold model\nrunLT <- function(G, S, Ew) {\n T <- unique(S) # Targeted set with unique nodes\n lv <- sapply(V(G), function(u) runif(1)) # Threshold for nodes\n W <- rep(0, vcount(G)) # Weighted number of activated in-neighbors\n Sj <- unique(S)\n \n while (length(Sj) > 0) {\n if (length(T) >= vcount(G)) {\n break # Break if the number of active nodes exceeds or equals the total number of nodes in G\n }\n Snew <- c()\n for (u in Sj) {\n neighbors <- neighbors(G, u, mode = \"in\")\n for (v in neighbors) {\n e <- as.character(get.edge.ids(G, c(v, u))) # Define 'e' as the edge index\n if (!(v %in% T)) {\n # Calculate the total weight of the activated in-neighbors\n total_weight <- sum(Ew[[e]])\n \n # Update the weighted number of activated in-neighbors\n W[v] <- W[v] + total_weight\n \n # Check if the threshold is exceeded\n if (W[v] >= lv[v]) {\n Snew <- c(Snew, v)\n T <- c(T, v)\n }\n }\n }\n }\n Sj <- unique(Snew) # Ensure unique nodes in the new set\n }\n return(T) # Return all activated nodes\n}\n\n\n# Function to calculate the total number of active nodes at each iteration\nactiveNodes <- function(G, S, Ew, iterations) {\n active_df <- data.frame(iteration = integer(), \n total_active_nodes = integer())\n total_active_nodes <- rep(0, iterations) # Initialize empty vector to store total active nodes\n \n for (i in 1:iterations) {\n T <- runLT(G, S, Ew)\n message(\"--\", i,\"T: \", T, \"\\n\")\n total_active <- length(unique(T)) # Calculate the total active nodes in this iteration\n total_active_nodes[i] <- total_active # Update total active nodes for current iteration\n \n # Limit total active nodes to the number of nodes in the graph\n if (total_active_nodes[i] >= vcount(G)) {\n total_active_nodes[i] <- vcount(G) \n }\n \n # Update data frame with current iteration's total active nodes\n active_df <- rbind(active_df, data.frame(iteration = i, \n total_active_nodes = total_active_nodes[i]))\n \n # Update seed set S for the next iteration\n S <- unique(c(S, T))\n }\n return(active_df)\n}\n\n\nRandom Graph Set up\nErdős–Rényi model\n\n\n## Erdős–Rényi model\nset.seed(123)\n# Create a random graph with 50 nodes and edge weights satisfying the constraint\nrandom_graph_50 <- erdos.renyi.game(50, p = 0.05, directed = TRUE) # random graph set up\n\n# Equal edge weight for node v -> Calculate uniform edge weights\nEw_uniform <- uniformWeights(random_graph_50)\n\n# Scale edge width based on the weights in Ew_uniform\nedge_width <- sapply(E(random_graph_50), function(e) {\n v <- ends(random_graph_50, e)[2]\n Ew_uniform[[as.character(e)]]\n})\n\n# Map edge_width to color_palette\ncolor_palette <- wes_palette(n=5, name=\"Zissou1\")\nedge_color <- color_palette[cut(edge_width, breaks = 5)]\n\n# Plot the graph with gradient edge color\npar(mar=c(0,0,0,0)+.1)\np1 <- plot.igraph(random_graph_50, \n edge.width = edge_width, \n edge.color = edge_color,\n edge.arrow.size = 0.4,\n layout = layout.circle,\n vertex.label = NA,\n vertex.size = 10, \n vertex.color = \"#A9AABC\")\n\n\n\nPreferential attachment model\n\n\n## Preferential attachment model\nset.seed(123)\n# Create a random graph with 50 nodes and edge weights satisfying the constraint\nrandom_graph_50 <- sample_pa(50, power = 1, m = 5) # random graph set up\n\n# Equal edge weight for node v -> Calculate uniform edge weights\nEw_uniform <- uniformWeights(random_graph_50)\n\n# Scale edge width based on the weights in Ew_uniform\nedge_width <- sapply(E(random_graph_50), function(e) {\n v <- ends(random_graph_50, e)[2]\n Ew_uniform[[as.character(e)]]\n})\n\n# Map edge_width to color_palette\ncolor_palette <- wes_palette(n=5, name=\"Zissou1\")\nedge_color <- color_palette[cut(edge_width, breaks = 5)]\n\n# Plot the graph with gradient edge color\npar(mar=c(0,0,0,0)+.1)\np1 <- plot.igraph(random_graph_50, \n edge.width = edge_width, \n edge.color = edge_color,\n edge.arrow.size = 0.4,\n layout = layout.circle,\n vertex.label = NA,\n vertex.size = 10, \n vertex.color = \"#A9AABC\")\n\n\n\nExample Usage for LTM\nEqual edge weight for node v:\n\n\nset.seed(123)\nrandom_graph_50 <- erdos.renyi.game(50, p = 0.05, directed = TRUE) # random graph set up\n## Or on preferential attachment model\n# random_graph_50 <- sample_pa(50, p = 0.1, directed = TRUE) # random graph set up\nS <- sample(1:vcount(random_graph_50), 3) # Initial seed set of nodes\n\n# Equal edge weight for node v -> Calculate uniform edge weights\nEw_uniform <- uniformWeights(random_graph_50)\nhead(Ew_uniform)\n\n$`1`\n[1] 0.25\n\n$`2`\n[1] 0.25\n\n$`3`\n[1] 0.25\n\n$`4`\n[1] 0.25\n\n$`5`\n[1] 0.2\n\n$`6`\n[1] 0.2\n\n\n# Scale edge width based on the weights in Ew_uniform\nedge_width <- sapply(E(random_graph_50), function(e) {\n v <- ends(random_graph_50, e)[2]\n Ew_uniform[[as.character(e)]]\n})\n\n# Map edge_width to color_palette\ncolor_palette <- wes_palette(n=5, name=\"Zissou1\")\nedge_color <- color_palette[cut(edge_width, breaks = 5)]\n\n# Plot the graph with gradient edge color\npar(mar=c(0,0,0,0)+.1)\nplot.igraph(random_graph_50, \n edge.width = edge_width, \n edge.color = edge_color,\n edge.arrow.size = 0.4,\n layout = layout.circle,\n vertex.label = NA,\n vertex.size = 10, \n vertex.color = ifelse(1:vcount(random_graph_50) %in% S, \"#FC888F\", \"#A9AABC\"))\n\n\n\n\n# Try on 500 nodes\nrandom_graph_500 <- erdos.renyi.game(500, p = 0.05, directed = TRUE) # random graph set up\nS <- sample(1:vcount(random_graph_500), 2) # Initial seed set of nodes\n\n# Equal edge weight for node v -> Calculate uniform edge weights\nEw_uniform <- uniformWeights(random_graph_500)\nhead(Ew_uniform)\n\n$`1`\n[1] 0.04166667\n\n$`2`\n[1] 0.04166667\n\n$`3`\n[1] 0.04166667\n\n$`4`\n[1] 0.04166667\n\n$`5`\n[1] 0.04166667\n\n$`6`\n[1] 0.04166667\n\n\n# Scale edge width based on the weights in Ew_uniform\nedge_width <- sapply(E(random_graph_500), function(e) {\n v <- ends(random_graph_500, e)[2]\n Ew_uniform[[as.character(e)]]\n})\n\n## Run Linear Threshold model with uniform edge weights\n# activated_nodes <- runLT(random_graph_500, S, Ew_uniform) # single iteration\n# activated_nodes\n\nactive_df1 <- activeNodes(random_graph_500, S, Ew_uniform, iterations = 10)\npaged_table(active_df1)\n\n\n\n\n\nactive_df2 <- activeNodes(random_graph_500, S, Ew_uniform, iterations = 10)\nactive_df3 <- activeNodes(random_graph_500, S, Ew_uniform, iterations = 10)\nactive_df4 <- activeNodes(random_graph_500, S, Ew_uniform, iterations = 10)\nactive_df5 <- activeNodes(random_graph_500, S, Ew_uniform, iterations = 10)\n\nactive_df <- active_df1 %>% \n left_join(active_df2, by = \"iteration\") %>% \n left_join(active_df3, by = \"iteration\") %>% \n left_join(active_df4, by = \"iteration\") %>% \n left_join(active_df5, by = \"iteration\") %>% \n rename(df1 = total_active_nodes.x,\n df2 = total_active_nodes.y,\n df3 = total_active_nodes.x.x,\n df4 = total_active_nodes.y.y,\n df5 = total_active_nodes)\n\nactive_df %>% \n ggplot() + \n geom_line(aes(x = iteration, y = df1, color = \"df1\"), linetype = \"solid\") + \n geom_line(aes(x = iteration, y = df2, color = \"df2\"), linetype = \"solid\") + \n geom_line(aes(x = iteration, y = df3, color = \"df3\"), linetype = \"solid\") + \n geom_line(aes(x = iteration, y = df4, color = \"df4\"), linetype = \"solid\") + \n geom_line(aes(x = iteration, y = df5, color = \"df5\"), linetype = \"solid\") +\n scale_color_manual(values = c(\"#5E71C2\", \"#454655\", \"#A9AABC\", \"#C0535D\", \"#FC888F\")) +\n ylab(\"total_active_nodes\") + \n labs(color = \"Data\", \n title = \"Active Nodes over Iterations\", \n subtitle = \"3 random seed nodes with uniform edge weights\") +\n theme(legend.position = c(0.97, 0.02),\n legend.justification = c(1, 0),\n legend.box.background = element_rect(color = \"black\", linewidth = 0.5),\n legend.box.just = \"top\")\n\n\n\nRandom edge weight for node v:\n\n\nset.seed(123)\n# random_graph_50 <- erdos.renyi.game(50, p = 0.05, directed = TRUE) # random graph set up\n# S <- sample(1:vcount(random_graph_50), 3) # Initial seed set of nodes\n\n## Calculate random edge weights -> Random edge weights, then normalized to sum <= 1\nEw_random <- randomWeights(random_graph_50)\nhead(Ew_random)\n\n$`1`\n[1] 0.1214495\n\n$`2`\n[1] 0.3329164\n\n$`3`\n[1] 0.1727188\n\n$`4`\n[1] 0.3729152\n\n$`5`\n[1] 0.3179421\n\n$`6`\n[1] 0.0154012\n\n\n# Scale edge width based on the weights in Ew_random\nedge_width_random <- sapply(E(random_graph_50), function(e) {\n v <- ends(random_graph_50, e)[2]\n Ew_random[[as.character(e)]]\n})\n\n# Map edge_width to color_palette\ncolor_palette <- wes_palette(n=5, name=\"Zissou1\")\nedge_color <- color_palette[cut(edge_width_random, breaks = 5)]\n\n# Plot the graph with gradient edge color\npar(mar=c(0,0,0,0)+.1)\nplot.igraph(random_graph_50, \n edge.width = edge_width_random, \n edge.color = edge_color,\n edge.arrow.size = 0.4,\n layout = layout.circle,\n vertex.label = NA,\n vertex.size = 10, \n vertex.color = ifelse(1:vcount(random_graph_50) %in% S, \"#FC888F\", \"#A9AABC\"))\n\n\n\n\n# Try on 500 nodes\n# random_graph_500 <- erdos.renyi.game(500, p = 0.05, directed = TRUE) # random graph set up\n# S <- sample(1:vcount(random_graph_500), 3) # Initial seed set of nodes\n\n# Equal edge weight for node v -> Calculate uniform edge weights\nEw_random <- randomWeights(random_graph_500)\nhead(Ew_random)\n\n$`1`\n[1] 0.0254803\n\n$`2`\n[1] 0.01819753\n\n$`3`\n[1] 0.03059497\n\n$`4`\n[1] 0.0814968\n\n$`5`\n[1] 0.01276849\n\n$`6`\n[1] 0.007538763\n\n\n# Run Linear Threshold model with uniform edge weights\n# activated_nodes <- runLT(random_graph_500, S, Ew_random) # single iteration\n# activated_nodes\n\nactive_df1 <- activeNodes(random_graph_500, S, Ew_random, iterations = 10)\nactive_df2 <- activeNodes(random_graph_500, S, Ew_random, iterations = 10)\nactive_df3 <- activeNodes(random_graph_500, S, Ew_random, iterations = 10)\nactive_df4 <- activeNodes(random_graph_500, S, Ew_random, iterations = 10)\nactive_df5 <- activeNodes(random_graph_500, S, Ew_random, iterations = 10)\n\nactive_df <- active_df1 %>% \n left_join(active_df2, by = \"iteration\") %>% \n left_join(active_df3, by = \"iteration\") %>% \n left_join(active_df4, by = \"iteration\") %>% \n left_join(active_df5, by = \"iteration\") %>% \n rename(df1 = total_active_nodes.x,\n df2 = total_active_nodes.y,\n df3 = total_active_nodes.x.x,\n df4 = total_active_nodes.y.y,\n df5 = total_active_nodes)\n\npaged_table(head(active_df))\n\n\n\n\n\nactive_df %>% \n ggplot() + \n geom_line(aes(x = iteration, y = df1, color = \"df1\"), linetype = \"solid\") + \n geom_line(aes(x = iteration, y = df2, color = \"df2\"), linetype = \"solid\") + \n geom_line(aes(x = iteration, y = df3, color = \"df3\"), linetype = \"solid\") + \n geom_line(aes(x = iteration, y = df4, color = \"df4\"), linetype = \"solid\") + \n geom_line(aes(x = iteration, y = df5, color = \"df5\"), linetype = \"solid\") +\n scale_color_manual(values = c(\"#5E71C2\", \"#454655\", \"#A9AABC\", \"#C0535D\", \"#FC888F\")) +\n ylab(\"total_active_nodes\") + \n labs(color = \"Data\", \n title = \"Active Nodes over Iterations\", \n subtitle = \"3 random seed nodes with random edge weights\") +\n theme(legend.position = c(0.97, 0.02),\n legend.justification = c(1, 0),\n legend.box.background = element_rect(color = \"black\", linewidth = 0.5),\n legend.box.just = \"top\")\n\n\n\nGreedy Algorithm for LTM\n\n\n# Function to calculate average size of activated nodes\navgLT <- function(G, S, Ew, iterations=1) {\n avgSize <- 0\n for (i in 1:iterations) {\n T <- runLT(G, S, Ew)\n avgSize <- avgSize + length(T) / iterations\n }\n return(avgSize)\n}\n\n\n# Define the Greedy_LTM function\nGreedy_LTM <- function(G, Ew, k, iterations) {\n start <- Sys.time() # Record the start time\n S <- c() # Initialize the seed set\n \n for (i in 1:k) {\n inf <- data.frame(nodes = V(G), influence = NA) # Initialize the influence table\n \n # Calculate the influence for nodes not in S\n for (v in V(G)) {\n if (!(v %in% S)) {\n inf$influence[v] <- avgLT(G, c(S, v), Ew, iterations = 1)\n }\n }\n \n # Exclude nodes already in S\n inf_excluded <- inf[!inf$nodes %in% S, ]\n \n # Select the node with maximum influence and add it to the seed set\n u <- inf_excluded[which.max(inf_excluded$influence), ]$nodes\n cat(\"Selected node:\", u, \"with influence:\", max(inf_excluded$influence), \"\\n\")\n \n # Convert node name to numeric\n u <- as.numeric(u)\n \n # Add selected node to the seed set\n S <- c(S, u)\n }\n \n end <- Sys.time() # Record the end time\n # Print the total time taken\n print(paste(\"Total time:\", end - start))\n \n return(S) # Return the seed set\n}\n\n\nExample: Greedy Algorithm of Influence Max Problem on LTM\nAnimation\n\n\n# Adapt function to store the total number of active nodes at each iteration in list\nactiveNodes_list <- function(G, S, Ew, iterations) {\n active_df <- data.frame(iteration = integer(), \n total_active_nodes = integer())\n total_active_nodes <- rep(0, iterations) # Initialize empty vector to store total active nodes\n T_list <- list() # Initialize list to store T values\n \n for (i in 1:iterations) {\n T <- runLT(G, S, Ew)\n # cat(\"--\", i,\"T: \", T, \"\\n\")\n total_active <- length(unique(T)) # Calculate the total active nodes in this iteration\n total_active_nodes[i] <- total_active # Update total active nodes for current iteration\n \n # Limit total active nodes to the number of nodes in the graph\n if (total_active_nodes[i] >= vcount(G)) {\n total_active_nodes[i] <- vcount(G) \n }\n \n # Update data frame with current iteration's total active nodes\n active_df <- rbind(active_df, data.frame(iteration = i, \n total_active_nodes = total_active_nodes[i]))\n \n # Store T values in the list\n T_list[[i]] <- T\n \n # Update seed set S for the next iteration\n S <- unique(c(S, T))\n }\n \n return(list(active_df = active_df, T_list = T_list))\n}\n\n\n# Example usage\nrandom_graph <- erdos.renyi.game(50, 0.1, directed = TRUE)\n# Calculate uniform edge weights\nEw_uniform <- uniformWeights(random_graph)\n\n# Run the Greedy_LTM function\nseed_set <- Greedy_LTM(random_graph, Ew_uniform, k = 3, iterations = 5)\n\nSelected node: 15 with influence: 39 \nSelected node: 11 with influence: 39 \nSelected node: 22 with influence: 44 \n[1] \"Total time: 0.149544954299927\"\n\n\n\nactive_df_selectedSeed <- activeNodes_list(random_graph, seed_set, Ew_uniform, iterations = 5)\n\n# Scale edge width based on the weights in Ew_uniform\nedge_width <- sapply(E(random_graph), function(e) {\n v <- ends(random_graph, e)[2]\n Ew_uniform[[as.character(e)]]\n})\n# Map edge_width to color_palette\ncolor_palette <- wes_palette(n = 5, name = \"Zissou1\")\nedge_color <- color_palette[cut(edge_width, breaks = 5)]\n\n\n# Add seed set to the beginning of T_list\nT_list_with_seed <- c(list(seed_set), active_df_selectedSeed[[\"T_list\"]])\n\n# Create the GIF\nsaveGIF(\n expr = {\n for (i in seq_along(T_list_with_seed)) {\n T <- T_list_with_seed[[i]]\n par(mar=c(6,0,0,0)+.1)\n p <- plot.igraph(\n random_graph,\n edge.width = edge_width,\n edge.color = edge_color,\n edge.arrow.size = 0.4,\n layout = layout.circle,\n # vertex.label = NA,\n vertex.size = 10,\n vertex.color = ifelse(1:vcount(random_graph) %in% T, \"#FC888F\", \"#A9AABC\")\n )\n title(p, ifelse(i == 1, \"Initial Seed Set\", paste(\"In Step\", i - 1)))\n }\n },\n movie.name = \"LTM_animation_greedy.gif\",\n clean = TRUE,\n fps = 4, # Adjust fps value as needed\n fig.height = 4, # Adjust figure height\n fig.width = 6 # Adjust figure width\n)\n\n[1] TRUE\n\n\n# include animation\nknitr::include_graphics(\"LTM_animation_greedy.gif\")\n\n\n\nSimulation\n\n\nrandom_graph <- erdos.renyi.game(50, 0.1, directed = TRUE)\n# Calculate uniform edge weights\nEw_uniform <- uniformWeights(random_graph)\n\n# Run the Greedy_LTM function\nseed_set <- Greedy_LTM(random_graph, Ew_uniform, k = 3, iterations = 10)\n\nSelected node: 35 with influence: 40 \nSelected node: 16 with influence: 45 \nSelected node: 13 with influence: 38 \n[1] \"Total time: 0.196632862091064\"\n\nseed_set\n\n[1] 35 16 13\n\n\n# Scale edge width based on the weights in Ew_uniform\nedge_width <- sapply(E(random_graph), function(e) {\n v <- ends(random_graph, e)[2]\n Ew_uniform[[as.character(e)]]\n})\n\n# Map edge_width to color_palette\ncolor_palette <- wes_palette(n=5, name=\"Zissou1\")\nedge_color <- color_palette[cut(edge_width, breaks = 5)]\n\n# Plot the graph with gradient edge color\npar(mar=c(0,0,0,0)+.1)\np1 <- plot.igraph(random_graph, \n edge.width = edge_width, \n edge.color = edge_color,\n edge.arrow.size = 0.4,\n layout = layout.circle,\n # vertex.label = NA,\n vertex.size = 10, \n vertex.color = ifelse(1:vcount(random_graph) %in% seed_set, \"#FC888F\", \"#A9AABC\"))\n\n\n\nactive_df_selectedSeed <- activeNodes(random_graph, seed_set, Ew_uniform, iterations = 10)\n# paged_table(active_df_selectedSeed)\n\nS1 <- sample(1:vcount(random_graph), 3) # Initial seed set of nodes\nS2 <- sample(1:vcount(random_graph), 3) # Initial seed set of nodes\nS3 <- sample(1:vcount(random_graph), 3) # Initial seed set of nodes\n\nactive_df1 <- activeNodes(random_graph, S1, Ew_uniform, iterations = 10)\nactive_df2 <- activeNodes(random_graph, S2, Ew_uniform, iterations = 10)\nactive_df3 <- activeNodes(random_graph, S3, Ew_uniform, iterations = 10)\n\nactive_df <- active_df1 %>% \n left_join(active_df2, by = \"iteration\") %>% \n left_join(active_df3, by = \"iteration\") %>% \n left_join(active_df_selectedSeed, by = \"iteration\") %>% \n rename(df1 = total_active_nodes.x,\n df2 = total_active_nodes.y,\n df3 = total_active_nodes.x.x,\n greedy = total_active_nodes.y.y)\n\npaged_table(head(active_df))\n\n\n\n\n\nactive_df %>% \n ggplot() + \n geom_line(aes(x = iteration, y = df1, color = \"df1\"), linetype = \"solid\") + \n geom_line(aes(x = iteration, y = df2, color = \"df2\"), linetype = \"solid\") + \n geom_line(aes(x = iteration, y = df3, color = \"df3\"), linetype = \"solid\") + \n geom_line(aes(x = iteration, y= greedy, color = \"greedy\"), linetype = \"solid\") + \n scale_color_manual(values = c(\"black\", \"black\", \"black\", \"#FC888F\")) +\n ylab(\"total_active_nodes\") + \n labs(color = \"Data\", \n title = \"Active Nodes over Iterations\", \n subtitle = \"3 random seed nodes with random edge weights\") +\n theme(legend.position = c(0.97, 0.02),\n legend.justification = c(1, 0),\n legend.box.background = element_rect(color = \"black\", linewidth = 0.5),\n legend.box.just = \"top\")\n\n\n\n\n\n\n",
- "last_modified": "2024-04-30T10:37:11-05:00"
+ "contents": "\nLoad Packages\n\n\n# Use `install.packages(\"_package name_\")` if you haven't install them\nlibrary(tidyverse) \nlibrary(ggpubr)\nlibrary(igraph)\nlibrary(poweRlaw)\nlibrary(ggformula)\nlibrary(data.table)\nlibrary(graphics)\nlibrary(knitr)\nlibrary(rmarkdown)\nlibrary(wesanderson) # color\nlibrary(animation) \n\ntheme_set(theme_bw())\n\n\nLiner Threshold Model\n\n\n# Function to calculate uniform edge weights\n## Every incoming edge of v with degree dv has weight 1/dv.\nuniformWeights <- function(G) {\n # Initialize empty list to store edge weights\n Ew <- list()\n # Loop over edges in the graph\n for (e in E(G)) {\n # Get the target node of the edge\n v <- ends(G, e)[2]\n # Calculate the degree of the target node\n dv <- degree(G, v, mode = \"in\")\n # Assign weight to the edge\n Ew[[as.character(e)]] <- 1 / dv\n }\n return(Ew)\n}\n\n# Function to calculate random edge weights \n## Every edge has random weight. After weights assigned, we normalize weights of all incoming edges for each node so that they sum to 1.\nrandomWeights <- function(G) {\n Ew <- list() # Initialize empty list to store edge weights\n # Assign random weights to edges\n for (v in V(G)) {\n in_edges <- incident(G, v, mode = \"in\") # Get incoming edges for the current node\n ew <- runif(length(in_edges)) # Generate random weights for incoming edges\n total_weight <- sum(ew) # Calculate the total weight of incoming edges\n # Normalize weights so that they sum to 1 for each node\n ew <- ew / total_weight\n # Store the weights for the incoming edges\n for (i in seq_along(in_edges)) {\n Ew[[as.character(in_edges[i])]] <- ew[i]\n }\n }\n return(Ew)\n}\n\n\n# Function to run linear threshold model\nrunLT <- function(G, S, Ew) {\n T <- unique(S) # Targeted set with unique nodes\n lv <- sapply(V(G), function(u) runif(1)) # Threshold for nodes\n W <- rep(0, vcount(G)) # Weighted number of activated in-neighbors\n Sj <- unique(S)\n \n while (length(Sj) > 0) {\n if (length(T) >= vcount(G)) {\n break # Break if the number of active nodes exceeds or equals the total number of nodes in G\n }\n Snew <- c()\n for (u in Sj) {\n neighbors <- neighbors(G, u, mode = \"in\")\n for (v in neighbors) {\n e <- as.character(get.edge.ids(G, c(v, u))) # Define 'e' as the edge index\n if (!(v %in% T)) {\n # Calculate the total weight of the activated in-neighbors\n total_weight <- sum(Ew[[e]])\n \n # Update the weighted number of activated in-neighbors\n W[v] <- W[v] + total_weight\n \n # Check if the threshold is exceeded\n if (W[v] >= lv[v]) {\n Snew <- c(Snew, v)\n T <- c(T, v)\n }\n }\n }\n }\n Sj <- unique(Snew) # Ensure unique nodes in the new set\n }\n return(T) # Return all activated nodes\n}\n\n\n# Function to calculate the total number of active nodes at each iteration\nactiveNodes <- function(G, S, Ew, iterations) {\n active_df <- data.frame(iteration = integer(), \n total_active_nodes = integer())\n total_active_nodes <- rep(0, iterations) # Initialize empty vector to store total active nodes\n \n for (i in 1:iterations) {\n T <- runLT(G, S, Ew)\n message(\"--\", i,\"T: \", T, \"\\n\")\n total_active <- length(unique(T)) # Calculate the total active nodes in this iteration\n total_active_nodes[i] <- total_active # Update total active nodes for current iteration\n \n # Limit total active nodes to the number of nodes in the graph\n if (total_active_nodes[i] >= vcount(G)) {\n total_active_nodes[i] <- vcount(G) \n }\n \n # Update data frame with current iteration's total active nodes\n active_df <- rbind(active_df, data.frame(iteration = i, \n total_active_nodes = total_active_nodes[i]))\n \n # Update seed set S for the next iteration\n S <- unique(c(S, T))\n }\n return(active_df)\n}\n\n\nRandom Graph Set up\nErdős–Rényi model\n\n\n## Erdős–Rényi model\nset.seed(123)\n# Create a random graph with 50 nodes and edge weights satisfying the constraint\nrandom_graph_50 <- erdos.renyi.game(50, p = 0.05, directed = TRUE) # random graph set up\n\n# Equal edge weight for node v -> Calculate uniform edge weights\nEw_uniform <- uniformWeights(random_graph_50)\n\n# Scale edge width based on the weights in Ew_uniform\nedge_width <- sapply(E(random_graph_50), function(e) {\n v <- ends(random_graph_50, e)[2]\n Ew_uniform[[as.character(e)]]\n})\n\n# Map edge_width to color_palette\ncolor_palette <- wes_palette(n=5, name=\"Zissou1\")\nedge_color <- color_palette[cut(edge_width, breaks = 5)]\n\n# Plot the graph with gradient edge color\npar(mar=c(0,0,0,0)+.1)\np1 <- plot.igraph(random_graph_50, \n edge.width = edge_width, \n edge.color = edge_color,\n edge.arrow.size = 0.4,\n layout = layout.circle,\n vertex.label = NA,\n vertex.size = 10, \n vertex.color = \"#A9AABC\")\n\n\n\nPreferential attachment model\n\n\n## Preferential attachment model\nset.seed(123)\n# Create a random graph with 50 nodes and edge weights satisfying the constraint\nrandom_graph_50 <- sample_pa(50, power = 1, m = 5) # random graph set up\n\n# Equal edge weight for node v -> Calculate uniform edge weights\nEw_uniform <- uniformWeights(random_graph_50)\n\n# Scale edge width based on the weights in Ew_uniform\nedge_width <- sapply(E(random_graph_50), function(e) {\n v <- ends(random_graph_50, e)[2]\n Ew_uniform[[as.character(e)]]\n})\n\n# Map edge_width to color_palette\ncolor_palette <- wes_palette(n=5, name=\"Zissou1\")\nedge_color <- color_palette[cut(edge_width, breaks = 5)]\n\n# Plot the graph with gradient edge color\npar(mar=c(0,0,0,0)+.1)\np1 <- plot.igraph(random_graph_50, \n edge.width = edge_width, \n edge.color = edge_color,\n edge.arrow.size = 0.4,\n layout = layout.circle,\n vertex.label = NA,\n vertex.size = 10, \n vertex.color = \"#A9AABC\")\n\n\n\nExample Usage for LTM\nEqual edge weight for node v:\n\n\nset.seed(123)\nrandom_graph_50 <- erdos.renyi.game(50, p = 0.05, directed = TRUE) # random graph set up\n## Or on preferential attachment model\n# random_graph_50 <- sample_pa(50, p = 0.1, directed = TRUE) # random graph set up\nS <- sample(1:vcount(random_graph_50), 3) # Initial seed set of nodes\n\n# Equal edge weight for node v -> Calculate uniform edge weights\nEw_uniform <- uniformWeights(random_graph_50)\nhead(Ew_uniform)\n\n$`1`\n[1] 0.25\n\n$`2`\n[1] 0.25\n\n$`3`\n[1] 0.25\n\n$`4`\n[1] 0.25\n\n$`5`\n[1] 0.2\n\n$`6`\n[1] 0.2\n\n\n# Scale edge width based on the weights in Ew_uniform\nedge_width <- sapply(E(random_graph_50), function(e) {\n v <- ends(random_graph_50, e)[2]\n Ew_uniform[[as.character(e)]]\n})\n\n# Map edge_width to color_palette\ncolor_palette <- wes_palette(n=5, name=\"Zissou1\")\nedge_color <- color_palette[cut(edge_width, breaks = 5)]\n\n# Plot the graph with gradient edge color\npar(mar=c(0,0,0,0)+.1)\nplot.igraph(random_graph_50, \n edge.width = edge_width, \n edge.color = edge_color,\n edge.arrow.size = 0.4,\n layout = layout.circle,\n vertex.label = NA,\n vertex.size = 10, \n vertex.color = ifelse(1:vcount(random_graph_50) %in% S, \"#FC888F\", \"#A9AABC\"))\n\n\n\n\n# Try on 500 nodes\nrandom_graph_500 <- erdos.renyi.game(500, p = 0.05, directed = TRUE) # random graph set up\nS <- sample(1:vcount(random_graph_500), 2) # Initial seed set of nodes\n\n# Equal edge weight for node v -> Calculate uniform edge weights\nEw_uniform <- uniformWeights(random_graph_500)\nhead(Ew_uniform)\n\n$`1`\n[1] 0.04166667\n\n$`2`\n[1] 0.04166667\n\n$`3`\n[1] 0.04166667\n\n$`4`\n[1] 0.04166667\n\n$`5`\n[1] 0.04166667\n\n$`6`\n[1] 0.04166667\n\n\n# Scale edge width based on the weights in Ew_uniform\nedge_width <- sapply(E(random_graph_500), function(e) {\n v <- ends(random_graph_500, e)[2]\n Ew_uniform[[as.character(e)]]\n})\n\n## Run Linear Threshold model with uniform edge weights\n# activated_nodes <- runLT(random_graph_500, S, Ew_uniform) # single iteration\n# activated_nodes\n\nactive_df1 <- activeNodes(random_graph_500, S, Ew_uniform, iterations = 10)\npaged_table(active_df1)\n\n\n\n\n\nactive_df2 <- activeNodes(random_graph_500, S, Ew_uniform, iterations = 10)\nactive_df3 <- activeNodes(random_graph_500, S, Ew_uniform, iterations = 10)\nactive_df4 <- activeNodes(random_graph_500, S, Ew_uniform, iterations = 10)\nactive_df5 <- activeNodes(random_graph_500, S, Ew_uniform, iterations = 10)\n\nactive_df <- active_df1 %>% \n left_join(active_df2, by = \"iteration\") %>% \n left_join(active_df3, by = \"iteration\") %>% \n left_join(active_df4, by = \"iteration\") %>% \n left_join(active_df5, by = \"iteration\") %>% \n rename(df1 = total_active_nodes.x,\n df2 = total_active_nodes.y,\n df3 = total_active_nodes.x.x,\n df4 = total_active_nodes.y.y,\n df5 = total_active_nodes)\n\nactive_df %>% \n ggplot() + \n geom_line(aes(x = iteration, y = df1, color = \"df1\"), linetype = \"solid\") + \n geom_line(aes(x = iteration, y = df2, color = \"df2\"), linetype = \"solid\") + \n geom_line(aes(x = iteration, y = df3, color = \"df3\"), linetype = \"solid\") + \n geom_line(aes(x = iteration, y = df4, color = \"df4\"), linetype = \"solid\") + \n geom_line(aes(x = iteration, y = df5, color = \"df5\"), linetype = \"solid\") +\n scale_color_manual(values = c(\"#5E71C2\", \"#454655\", \"#A9AABC\", \"#C0535D\", \"#FC888F\")) +\n ylab(\"total_active_nodes\") + \n labs(color = \"Data\", \n title = \"Active Nodes over Iterations\", \n subtitle = \"3 random seed nodes with uniform edge weights\") +\n theme(legend.position = c(0.97, 0.02),\n legend.justification = c(1, 0),\n legend.box.background = element_rect(color = \"black\", linewidth = 0.5),\n legend.box.just = \"top\")\n\n\n\nRandom edge weight for node v:\n\n\nset.seed(123)\n# random_graph_50 <- erdos.renyi.game(50, p = 0.05, directed = TRUE) # random graph set up\n# S <- sample(1:vcount(random_graph_50), 3) # Initial seed set of nodes\n\n## Calculate random edge weights -> Random edge weights, then normalized to sum <= 1\nEw_random <- randomWeights(random_graph_50)\nhead(Ew_random)\n\n$`1`\n[1] 0.1214495\n\n$`2`\n[1] 0.3329164\n\n$`3`\n[1] 0.1727188\n\n$`4`\n[1] 0.3729152\n\n$`5`\n[1] 0.3179421\n\n$`6`\n[1] 0.0154012\n\n\n# Scale edge width based on the weights in Ew_random\nedge_width_random <- sapply(E(random_graph_50), function(e) {\n v <- ends(random_graph_50, e)[2]\n Ew_random[[as.character(e)]]\n})\n\n# Map edge_width to color_palette\ncolor_palette <- wes_palette(n=5, name=\"Zissou1\")\nedge_color <- color_palette[cut(edge_width_random, breaks = 5)]\n\n# Plot the graph with gradient edge color\npar(mar=c(0,0,0,0)+.1)\nplot.igraph(random_graph_50, \n edge.width = edge_width_random, \n edge.color = edge_color,\n edge.arrow.size = 0.4,\n layout = layout.circle,\n vertex.label = NA,\n vertex.size = 10, \n vertex.color = ifelse(1:vcount(random_graph_50) %in% S, \"#FC888F\", \"#A9AABC\"))\n\n\n\n\n# Try on 500 nodes\n# random_graph_500 <- erdos.renyi.game(500, p = 0.05, directed = TRUE) # random graph set up\n# S <- sample(1:vcount(random_graph_500), 3) # Initial seed set of nodes\n\n# Equal edge weight for node v -> Calculate uniform edge weights\nEw_random <- randomWeights(random_graph_500)\nhead(Ew_random)\n\n$`1`\n[1] 0.0254803\n\n$`2`\n[1] 0.01819753\n\n$`3`\n[1] 0.03059497\n\n$`4`\n[1] 0.0814968\n\n$`5`\n[1] 0.01276849\n\n$`6`\n[1] 0.007538763\n\n\n# Run Linear Threshold model with uniform edge weights\n# activated_nodes <- runLT(random_graph_500, S, Ew_random) # single iteration\n# activated_nodes\n\nactive_df1 <- activeNodes(random_graph_500, S, Ew_random, iterations = 10)\nactive_df2 <- activeNodes(random_graph_500, S, Ew_random, iterations = 10)\nactive_df3 <- activeNodes(random_graph_500, S, Ew_random, iterations = 10)\nactive_df4 <- activeNodes(random_graph_500, S, Ew_random, iterations = 10)\nactive_df5 <- activeNodes(random_graph_500, S, Ew_random, iterations = 10)\n\nactive_df <- active_df1 %>% \n left_join(active_df2, by = \"iteration\") %>% \n left_join(active_df3, by = \"iteration\") %>% \n left_join(active_df4, by = \"iteration\") %>% \n left_join(active_df5, by = \"iteration\") %>% \n rename(df1 = total_active_nodes.x,\n df2 = total_active_nodes.y,\n df3 = total_active_nodes.x.x,\n df4 = total_active_nodes.y.y,\n df5 = total_active_nodes)\n\npaged_table(head(active_df))\n\n\n\n\n\nactive_df %>% \n ggplot() + \n geom_line(aes(x = iteration, y = df1, color = \"df1\"), linetype = \"solid\") + \n geom_line(aes(x = iteration, y = df2, color = \"df2\"), linetype = \"solid\") + \n geom_line(aes(x = iteration, y = df3, color = \"df3\"), linetype = \"solid\") + \n geom_line(aes(x = iteration, y = df4, color = \"df4\"), linetype = \"solid\") + \n geom_line(aes(x = iteration, y = df5, color = \"df5\"), linetype = \"solid\") +\n scale_color_manual(values = c(\"#5E71C2\", \"#454655\", \"#A9AABC\", \"#C0535D\", \"#FC888F\")) +\n ylab(\"total_active_nodes\") + \n labs(color = \"Data\", \n title = \"Active Nodes over Iterations\", \n subtitle = \"3 random seed nodes with random edge weights\") +\n theme(legend.position = c(0.97, 0.02),\n legend.justification = c(1, 0),\n legend.box.background = element_rect(color = \"black\", linewidth = 0.5),\n legend.box.just = \"top\")\n\n\n\nGreedy Algorithm for LTM\n\n\n# Function to calculate average size of activated nodes\navgLT <- function(G, S, Ew, iterations=1) {\n avgSize <- 0\n for (i in 1:iterations) {\n T <- runLT(G, S, Ew)\n avgSize <- avgSize + length(T) / iterations\n }\n return(avgSize)\n}\n\n\n# Define the Greedy_LTM function\nGreedy_LTM <- function(G, Ew, k, iterations) {\n start <- Sys.time() # Record the start time\n S <- c() # Initialize the seed set\n \n for (i in 1:k) {\n inf <- data.frame(nodes = V(G), influence = NA) # Initialize the influence table\n \n # Calculate the influence for nodes not in S\n for (v in V(G)) {\n if (!(v %in% S)) {\n inf$influence[v] <- avgLT(G, c(S, v), Ew, iterations = 1)\n }\n }\n \n # Exclude nodes already in S\n inf_excluded <- inf[!inf$nodes %in% S, ]\n \n # Select the node with maximum influence and add it to the seed set\n u <- inf_excluded[which.max(inf_excluded$influence), ]$nodes\n cat(\"Selected node:\", u, \"with influence:\", max(inf_excluded$influence), \"\\n\")\n \n # Convert node name to numeric\n u <- as.numeric(u)\n \n # Add selected node to the seed set\n S <- c(S, u)\n }\n \n end <- Sys.time() # Record the end time\n # Print the total time taken\n print(paste(\"Total time:\", end - start))\n \n return(S) # Return the seed set\n}\n\n\nExample: Greedy Algorithm of Influence Max Problem on LTM\nAnimation\n\n\n# Adapt function to store the total number of active nodes at each iteration in list\nactiveNodes_list <- function(G, S, Ew, iterations) {\n active_df <- data.frame(iteration = integer(), \n total_active_nodes = integer())\n total_active_nodes <- rep(0, iterations) # Initialize empty vector to store total active nodes\n T_list <- list() # Initialize list to store T values\n \n for (i in 1:iterations) {\n T <- runLT(G, S, Ew)\n # cat(\"--\", i,\"T: \", T, \"\\n\")\n total_active <- length(unique(T)) # Calculate the total active nodes in this iteration\n total_active_nodes[i] <- total_active # Update total active nodes for current iteration\n \n # Limit total active nodes to the number of nodes in the graph\n if (total_active_nodes[i] >= vcount(G)) {\n total_active_nodes[i] <- vcount(G) \n }\n \n # Update data frame with current iteration's total active nodes\n active_df <- rbind(active_df, data.frame(iteration = i, \n total_active_nodes = total_active_nodes[i]))\n \n # Store T values in the list\n T_list[[i]] <- T\n \n # Update seed set S for the next iteration\n S <- unique(c(S, T))\n }\n \n return(list(active_df = active_df, T_list = T_list))\n}\n\n\n# Example usage\nrandom_graph <- erdos.renyi.game(50, 0.1, directed = TRUE)\n# Calculate uniform edge weights\nEw_uniform <- uniformWeights(random_graph)\n\n# Run the Greedy_LTM function\nseed_set <- Greedy_LTM(random_graph, Ew_uniform, k = 3, iterations = 5)\n\nSelected node: 15 with influence: 39 \nSelected node: 11 with influence: 39 \nSelected node: 22 with influence: 44 \n[1] \"Total time: 0.149084091186523\"\n\n\n\nactive_df_selectedSeed <- activeNodes_list(random_graph, seed_set, Ew_uniform, iterations = 5)\n\n# Scale edge width based on the weights in Ew_uniform\nedge_width <- sapply(E(random_graph), function(e) {\n v <- ends(random_graph, e)[2]\n Ew_uniform[[as.character(e)]]\n})\n# Map edge_width to color_palette\ncolor_palette <- wes_palette(n = 5, name = \"Zissou1\")\nedge_color <- color_palette[cut(edge_width, breaks = 5)]\n\n\n# Add seed set to the beginning of T_list\nT_list_with_seed <- c(list(seed_set), active_df_selectedSeed[[\"T_list\"]])\n\n# Create the GIF\nsaveGIF(\n expr = {\n for (i in seq_along(T_list_with_seed)) {\n T <- T_list_with_seed[[i]]\n par(mar=c(6,0,0,0)+.1)\n p <- plot.igraph(\n random_graph,\n edge.width = edge_width,\n edge.color = edge_color,\n edge.arrow.size = 0.4,\n layout = layout.circle,\n # vertex.label = NA,\n vertex.size = 10,\n vertex.color = ifelse(1:vcount(random_graph) %in% T, \"#FC888F\", \"#A9AABC\")\n )\n title(p, ifelse(i == 1, \"Initial Seed Set\", paste(\"In Step\", i - 1)))\n }\n },\n movie.name = \"LTM_animation_greedy.gif\",\n clean = TRUE,\n fps = 4, # Adjust fps value as needed\n fig.height = 4, # Adjust figure height\n fig.width = 6 # Adjust figure width\n)\n\n[1] TRUE\n\n\n# include animation\nknitr::include_graphics(\"LTM_animation_greedy.gif\")\n\n\n\nSimulation\n\n\nrandom_graph <- erdos.renyi.game(50, 0.1, directed = TRUE)\n# Calculate uniform edge weights\nEw_uniform <- uniformWeights(random_graph)\n\n# Run the Greedy_LTM function\nseed_set <- Greedy_LTM(random_graph, Ew_uniform, k = 3, iterations = 10)\n\nSelected node: 35 with influence: 40 \nSelected node: 16 with influence: 45 \nSelected node: 13 with influence: 38 \n[1] \"Total time: 0.194490909576416\"\n\nseed_set\n\n[1] 35 16 13\n\n\n# Scale edge width based on the weights in Ew_uniform\nedge_width <- sapply(E(random_graph), function(e) {\n v <- ends(random_graph, e)[2]\n Ew_uniform[[as.character(e)]]\n})\n\n# Map edge_width to color_palette\ncolor_palette <- wes_palette(n=5, name=\"Zissou1\")\nedge_color <- color_palette[cut(edge_width, breaks = 5)]\n\n# Plot the graph with gradient edge color\npar(mar=c(0,0,0,0)+.1)\np1 <- plot.igraph(random_graph, \n edge.width = edge_width, \n edge.color = edge_color,\n edge.arrow.size = 0.4,\n layout = layout.circle,\n # vertex.label = NA,\n vertex.size = 10, \n vertex.color = ifelse(1:vcount(random_graph) %in% seed_set, \"#FC888F\", \"#A9AABC\"))\n\n\n\nactive_df_selectedSeed <- activeNodes(random_graph, seed_set, Ew_uniform, iterations = 10)\n# paged_table(active_df_selectedSeed)\n\nS1 <- sample(1:vcount(random_graph), 3) # Initial seed set of nodes\nS2 <- sample(1:vcount(random_graph), 3) # Initial seed set of nodes\nS3 <- sample(1:vcount(random_graph), 3) # Initial seed set of nodes\n\nactive_df1 <- activeNodes(random_graph, S1, Ew_uniform, iterations = 10)\nactive_df2 <- activeNodes(random_graph, S2, Ew_uniform, iterations = 10)\nactive_df3 <- activeNodes(random_graph, S3, Ew_uniform, iterations = 10)\n\nactive_df <- active_df1 %>% \n left_join(active_df2, by = \"iteration\") %>% \n left_join(active_df3, by = \"iteration\") %>% \n left_join(active_df_selectedSeed, by = \"iteration\") %>% \n rename(df1 = total_active_nodes.x,\n df2 = total_active_nodes.y,\n df3 = total_active_nodes.x.x,\n greedy = total_active_nodes.y.y)\n\npaged_table(head(active_df))\n\n\n\n\n\nactive_df %>% \n ggplot() + \n geom_line(aes(x = iteration, y = df1, color = \"df1\"), linetype = \"solid\") + \n geom_line(aes(x = iteration, y = df2, color = \"df2\"), linetype = \"solid\") + \n geom_line(aes(x = iteration, y = df3, color = \"df3\"), linetype = \"solid\") + \n geom_line(aes(x = iteration, y= greedy, color = \"greedy\"), linetype = \"solid\") + \n scale_color_manual(values = c(\"black\", \"black\", \"black\", \"#FC888F\")) +\n ylab(\"total_active_nodes\") + \n labs(color = \"Data\", \n title = \"Active Nodes over Iterations\", \n subtitle = \"3 random seed nodes with random edge weights\") +\n theme(legend.position = c(0.97, 0.02),\n legend.justification = c(1, 0),\n legend.box.background = element_rect(color = \"black\", linewidth = 0.5),\n legend.box.just = \"top\")\n\n\n\n\n\n\n",
+ "last_modified": "2024-04-30T12:32:34-05:00"
},
{
"path": "03-results.html",
"title": "Results",
"description": "Explore various functions of the Linear Threshold Model (LTM) and interactive Shiny apps for simulations! Click \"Show Code\" to see the implementation details. \n",
"author": [],
- "contents": "\n\n\n\nLiner Threshold Model\nIn this section, I’ve developed key functions to implement the Linear Threshold Model.\nFirstly, I created two methods for assigning edge weights: uniform weights and random weights. Recall from the methodology, it’s crucial that the sum of weights from neighboring nodes doesn’t exceed 1, a requirement of the Linear Threshold Model (LTM):\n\\[\n\\sum_{w \\text{ neighbor of } v} b_{v,w} \\leq 1\n\\]\nThis ensures that the cumulative influence exerted by neighboring nodes remains within manageable bounds, facilitating robust analyses within the LTM framework.\nFor uniform weights (uniformWeights), each incoming edge to node \\(v\\) in graph \\(G\\) with degree \\(\\text{deg}_v\\) is assigned an equal weight of \\(\\frac{1}{\\text{deg}_v}\\). With random weights (randomWeights), each edge receives a random weight. After assignment, weights are normalized for all incoming edges of each node to ensure their sum equals 1.\n\n\nShow code\n\n# Function to calculate uniform edge weights\n## Every incoming edge of v with degree dv has weight 1/dv.\nuniformWeights <- function(G) {\n # Initialize empty list to store edge weights\n Ew <- list()\n # Loop over edges in the graph\n for (e in E(G)) {\n # Get the target node of the edge\n v <- ends(G, e)[2]\n # Calculate the degree of the target node\n dv <- degree(G, v, mode = \"in\")\n # Assign weight to the edge\n Ew[[as.character(e)]] <- 1 / dv\n }\n return(Ew)\n}\n\n# Function to calculate random edge weights \n## Every edge has random weight. After weights assigned, we normalize weights of all incoming edges for each \n# node so that they sum to 1.\nrandomWeights <- function(G) {\n Ew <- list() # Initialize empty list to store edge weights\n # Assign random weights to edges\n for (v in V(G)) {\n in_edges <- incident(G, v, mode = \"in\") # Get incoming edges for the current node\n ew <- runif(length(in_edges)) # Generate random weights for incoming edges\n total_weight <- sum(ew) # Calculate the total weight of incoming edges\n # Normalize weights so that they sum to 1 for each node\n ew <- ew / total_weight\n # Store the weights for the incoming edges\n for (i in seq_along(in_edges)) {\n Ew[[as.character(in_edges[i])]] <- ew[i]\n }\n }\n return(Ew)\n}\n\n\n\nWith the network, edge weight setup, and the set of initial active nodes \\(A_0\\) (referred to as \\(S\\) in the function), we’re ready to execute a linear threshold model!\nFocusing on a single iteration, the runLT function assigns a threshold to each node from a uniform distribution. It then calculates the total weight of the activated in-neighbors, updates it, and compares the total weights with the nodes’ thresholds. If the total weights exceed the threshold, the node is activated. The final output is a list of total active nodes in the network.\n\n\nShow code\n\n# Function to run linear threshold model\nrunLT <- function(G, S, Ew) {\n T <- unique(S) # Targeted set with unique nodes\n lv <- sapply(V(G), function(u) runif(1)) # Threshold for nodes\n W <- rep(0, vcount(G)) # Weighted number of activated in-neighbors\n Sj <- unique(S)\n \n while (length(Sj) > 0) {\n if (length(T) >= vcount(G)) {\n break # Break if the number of active nodes exceeds or equals the total number of nodes in G\n }\n Snew <- c()\n for (u in Sj) {\n neighbors <- neighbors(G, u, mode = \"in\")\n for (v in neighbors) {\n e <- as.character(get.edge.ids(G, c(v, u))) # Define 'e' as the edge index\n if (!(v %in% T)) {\n # Calculate the total weight of the activated in-neighbors\n total_weight <- sum(Ew[[e]])\n \n # Update the weighted number of activated in-neighbors\n W[v] <- W[v] + total_weight\n \n # Check if the threshold is exceeded\n if (W[v] >= lv[v]) {\n Snew <- c(Snew, v)\n T <- c(T, v)\n }\n }\n }\n }\n Sj <- unique(Snew) # Ensure unique nodes in the new set\n }\n return(T) # Return all activated nodes\n}\n\n\n\nNow, let’s extend to multiple iterations!\nThe activeNodes function is the main function for calculating the total number of active nodes at each iteration. It iterates through the process and prints out the names of the active nodes for each iteration in the console. The function outputs a two-column table displaying the total number of active nodes in each iteration.\n\n\nShow code\n\n# Function to calculate the total number of active nodes at each iteration\nactiveNodes <- function(G, S, Ew, iterations) {\n active_df <- data.frame(iteration = integer(), \n total_active_nodes = integer())\n total_active_nodes <- rep(0, iterations) # Initialize empty vector to store total active nodes\n \n for (i in 1:iterations) {\n T <- runLT(G, S, Ew)\n message(\"--\", i,\"T: \", T, \"\\n\") # print active node names for this iteration in the console\n total_active <- length(unique(T)) # Calculate the total active nodes in this iteration\n total_active_nodes[i] <- total_active # Update total active nodes for current iteration\n \n # Limit total active nodes to the number of nodes in the graph\n if (total_active_nodes[i] >= vcount(G)) {\n total_active_nodes[i] <- vcount(G) \n }\n \n # Update data frame with current iteration's total active nodes\n active_df <- rbind(active_df, data.frame(iteration = i, \n total_active_nodes = total_active_nodes[i]))\n \n # Update seed set S for the next iteration\n S <- unique(c(S, T))\n }\n return(active_df)\n}\n\n\n\nRandom Graph Setup\nWhat are some simple network?\nI employed the Erdős–Rényi model \\(G(n, p)\\) and the preferential attachment model. These models offer a straightforward way to simulate network structures, allowing for comparisons between random graphs and those with power law distributions.\nErdős-Rényi model\nHere’s an example of the Erdős-Rényi model with 50 nodes. Each edge has a 5% probability of being included. Using uniform edge weights, the edges vary in width and color: thinner and blue for smaller weights, and wider and red for larger weights.\n\n\nShow code\n\n## Erdős–Rényi model\nset.seed(123)\n# Create a random graph with 50 nodes and edge weights satisfying the constraint\nrandom_graph_50 <- erdos.renyi.game(50, p = 0.05, directed = TRUE) # random graph set up\n\n# Equal edge weight for node v -> Calculate uniform edge weights\nEw_uniform <- uniformWeights(random_graph_50)\n\n# Scale edge width based on the weights in Ew_uniform\nedge_width <- sapply(E(random_graph_50), function(e) {\n v <- ends(random_graph_50, e)[2]\n Ew_uniform[[as.character(e)]]\n})\n\n# Map edge_width to color_palette\ncolor_palette <- wes_palette(n=5, name=\"Zissou1\")\nedge_color <- color_palette[cut(edge_width, breaks = 5)]\n\n# Plot the graph with gradient edge color\npar(mar=c(0,0,0,0)+.1)\np1 <- plot.igraph(random_graph_50, \n edge.width = edge_width, \n edge.color = edge_color,\n edge.arrow.size = 0.4,\n layout = layout.circle,\n vertex.label = NA,\n vertex.size = 10, \n vertex.color = \"#A9AABC\")\n\n\n\nPreferential attachment model\nHere’s an example of the Preferential attachment model with 50 nodes. The graph follows a power-law distribution with power equal to \\(1\\). Each node connects to the existing nodes with a fixed number \\(m\\) of links. Similarly, using uniform edge weights, the edges vary in width and color: thinner and blue for smaller weights, and wider and red for larger weights.\n\nWhat is power law? In network science, it describes the distribution of node degrees, where a few nodes have many connections while most nodes have few connections.\n\n\n\nShow code\n\n## Preferential attachment model\nset.seed(123)\n# Create a random graph with 50 nodes and edge weights satisfying the constraint\nrandom_graph_50 <- sample_pa(50, power = 1, m = 5) # random graph set up\n\n# Equal edge weight for node v -> Calculate uniform edge weights\nEw_uniform <- uniformWeights(random_graph_50)\n\n# Scale edge width based on the weights in Ew_uniform\nedge_width <- sapply(E(random_graph_50), function(e) {\n v <- ends(random_graph_50, e)[2]\n Ew_uniform[[as.character(e)]]\n})\n\n# Map edge_width to color_palette\ncolor_palette <- wes_palette(n=5, name=\"Zissou1\")\nedge_color <- color_palette[cut(edge_width, breaks = 5)]\n\n# Plot the graph with gradient edge color\npar(mar=c(0,0,0,0)+.1)\np1 <- plot.igraph(random_graph_50, \n edge.width = edge_width, \n edge.color = edge_color,\n edge.arrow.size = 0.4,\n layout = layout.circle,\n vertex.label = NA,\n vertex.size = 10, \n vertex.color = \"#A9AABC\")\n\n\n\n\nExample Usage for LTM\nExperiment with various simulation setup! The plot and table depict the total active nodes for each iteration in five random graphs labeled as df1 to df5.\nIf the plot displays a horizontal line, it suggests no increase in active nodes, which can occur. Attempt running the simulation multiple times to observe changes.\n\n\nGreedy Algorithm for LTM\nI’ve developed two functions to implement the hill climbing algorithm on LTM.\nThe avgLT function calculates the average size of activated nodes in the current step. On the other hand, the Greedy_LTM function is the primary tool for the greedy hill climbing approach. It requires input parameters including the graph, edge weights, the initial seed set size (denoted as \\(k\\)), and the number of iterations. For instance, if the number of iterations is 10, it selects the node with the maximum influence in the current iteration and adds it to the seed set. The output is \\(k\\) initial active nodes that maximize the local influence.\n\n\nShow code\n\n# Function to calculate average size of activated nodes\navgLT <- function(G, S, Ew, iterations = 1) {\n avgSize <- 0\n for (i in 1:iterations) {\n T <- runLT(G, S, Ew)\n avgSize <- avgSize + length(T) / iterations\n }\n return(avgSize)\n}\n\n\n# Greedy_LTM function to select k initial active nodes that maximize the local influence\nGreedy_LTM <- function(G, Ew, k, iterations) {\n start <- Sys.time() # Record the start time\n S <- c() # Initialize the seed set\n \n for (i in 1:k) {\n inf <- data.frame(nodes = V(G), influence = NA) # Initialize the influence table\n \n # Calculate the influence for nodes not in S\n for (v in V(G)) {\n if (!(v %in% S)) {\n inf$influence[v] <- avgLT(G, c(S, v), Ew, iterations = 1)\n }\n }\n \n # Exclude nodes already in S\n inf_excluded <- inf[!inf$nodes %in% S, ]\n \n # Select the node with maximum influence and add it to the seed set\n u <- inf_excluded[which.max(inf_excluded$influence), ]$nodes\n cat(\"Selected node:\", u, \"with influence:\", max(inf_excluded$influence), \"\\n\")\n \n # Convert node name to numeric\n u <- as.numeric(u)\n \n # Add selected node to the seed set\n S <- c(S, u)\n }\n \n end <- Sys.time() # Record the end time\n # Print the total time taken\n print(paste(\"Total time:\", end - start))\n \n return(S) # Return the seed set\n}\n\n\nExample: Greedy Algorithm of Influence Max Problem on LTM\nAnimation\nTo illustrate the iterative process of the greedy algorithm, I’ve added a brief animation depicting how the active nodes increase based on the initial seed set. I modified the activeNodes function to activeNodes_list, which stores the names of active nodes in each iteration in a list.\nUsing this approach, I applied the hill-climbing algorithm to the Erdős–Rényi model with 50 nodes and uniform edge weights to select 3 initial active nodes. The animation showcases the activation process over 5 iterations.\n\n\nShow code\n\n# Adapt function to store the total number of active nodes at each iteration in list\nactiveNodes_list <- function(G, S, Ew, iterations) {\n active_df <- data.frame(iteration = integer(), \n total_active_nodes = integer())\n total_active_nodes <- rep(0, iterations) # Initialize empty vector to store total active nodes\n T_list <- list() # Initialize list to store T values\n \n for (i in 1:iterations) {\n T <- runLT(G, S, Ew)\n # cat(\"--\", i,\"T: \", T, \"\\n\")\n total_active <- length(unique(T)) # Calculate the total active nodes in this iteration\n total_active_nodes[i] <- total_active # Update total active nodes for current iteration\n \n # Limit total active nodes to the number of nodes in the graph\n if (total_active_nodes[i] >= vcount(G)) {\n total_active_nodes[i] <- vcount(G) \n }\n \n # Update data frame with current iteration's total active nodes\n active_df <- rbind(active_df, data.frame(iteration = i, \n total_active_nodes = total_active_nodes[i]))\n \n # Store T values in the list\n T_list[[i]] <- T\n \n # Update seed set S for the next iteration\n S <- unique(c(S, T))\n }\n \n return(list(active_df = active_df, T_list = T_list))\n}\n\n\n# Example usage\nrandom_graph <- erdos.renyi.game(50, 0.1, directed = TRUE)\n# Calculate uniform edge weights\nEw_uniform <- uniformWeights(random_graph)\n\n# Run the Greedy_LTM function\nseed_set <- Greedy_LTM(random_graph, Ew_uniform, k = 3, iterations = 5)\n\nSelected node: 2 with influence: 37 \nSelected node: 22 with influence: 38 \nSelected node: 32 with influence: 40 \n[1] \"Total time: 0.191519975662231\"\n\n\n\nShow code\n\nactive_df_selectedSeed <- activeNodes_list(random_graph, seed_set, Ew_uniform, iterations = 5)\n\n# Scale edge width based on the weights in Ew_uniform\nedge_width <- sapply(E(random_graph), function(e) {\n v <- ends(random_graph, e)[2]\n Ew_uniform[[as.character(e)]]\n})\n# Map edge_width to color_palette\ncolor_palette <- wes_palette(n = 5, name = \"Zissou1\")\nedge_color <- color_palette[cut(edge_width, breaks = 5)]\n\n\n# Add seed set to the beginning of T_list\nT_list_with_seed <- c(list(seed_set), active_df_selectedSeed[[\"T_list\"]])\n\n# Create the GIF\nsaveGIF(\n expr = {\n for (i in seq_along(T_list_with_seed)) {\n T <- T_list_with_seed[[i]]\n par(mar=c(6,0,0,0)+.1)\n p <- plot.igraph(\n random_graph,\n edge.width = edge_width,\n edge.color = edge_color,\n edge.arrow.size = 0.4,\n layout = layout.circle,\n # vertex.label = NA,\n vertex.size = 10,\n vertex.color = ifelse(1:vcount(random_graph) %in% T, \"#FC888F\", \"#A9AABC\")\n )\n title(p, ifelse(i == 1, \"Initial Seed Set\", paste(\"In Step\", i - 1)))\n }\n },\n movie.name = \"LTM_animation_greedy.gif\",\n clean = TRUE,\n fps = 4, # Adjust fps value as needed\n fig.height = 4, # Adjust figure height\n fig.width = 6 # Adjust figure width\n)\n\n[1] TRUE\n\nShow code\n\n\n# include animation\nknitr::include_graphics(\"LTM_animation_greedy.gif\")\n\n\n\nSimulation\nThe plot and table show the total active nodes for each iteration in three randomly generated graphs labeled as df1 to df3, and one graph with initially selected active nodes denoted as greedy. If the plot displays a horizontal line, it suggests no increase in active nodes, which can occur. Attempt running the simulation multiple times to observe changes.\nPlease be patient as the algorithm may take a few minutes to run for complicated setup.\n\n\nReferences\nERDdS, P., & R&wi, A. (1959). On random graphs I. Publ. math. debrecen, 6(290-297), 18.\nBarabási, A. L., & Albert, R. (1999). Emergence of scaling in random networks. science, 286(5439), 509-512.\n\n\n\n",
- "last_modified": "2024-04-30T10:55:13-05:00"
+ "contents": "\n\n\n\nLiner Threshold Model\nIn this section, I’ve developed key functions to implement the Linear Threshold Model.\nFirstly, I created two methods for assigning edge weights: uniform weights and random weights. Recall from the methodology, it’s crucial that the sum of weights from neighboring nodes doesn’t exceed 1, a requirement of the Linear Threshold Model (LTM):\n\\[\n\\sum_{w \\text{ neighbor of } v} b_{v,w} \\leq 1\n\\]\nThis ensures that the cumulative influence exerted by neighboring nodes remains within manageable bounds, facilitating robust analyses within the LTM framework.\nFor uniform weights (uniformWeights), each incoming edge to node \\(v\\) in graph \\(G\\) with degree \\(\\text{deg}_v\\) is assigned an equal weight of \\(\\frac{1}{\\text{deg}_v}\\). With random weights (randomWeights), each edge receives a random weight. After assignment, weights are normalized for all incoming edges of each node to ensure their sum equals 1.\n\n\nShow code\n\n# Function to calculate uniform edge weights\n## Every incoming edge of v with degree dv has weight 1/dv.\nuniformWeights <- function(G) {\n # Initialize empty list to store edge weights\n Ew <- list()\n # Loop over edges in the graph\n for (e in E(G)) {\n # Get the target node of the edge\n v <- ends(G, e)[2]\n # Calculate the degree of the target node\n dv <- degree(G, v, mode = \"in\")\n # Assign weight to the edge\n Ew[[as.character(e)]] <- 1 / dv\n }\n return(Ew)\n}\n\n# Function to calculate random edge weights \n## Every edge has random weight. After weights assigned, we normalize weights of all incoming edges for each \n# node so that they sum to 1.\nrandomWeights <- function(G) {\n Ew <- list() # Initialize empty list to store edge weights\n # Assign random weights to edges\n for (v in V(G)) {\n in_edges <- incident(G, v, mode = \"in\") # Get incoming edges for the current node\n ew <- runif(length(in_edges)) # Generate random weights for incoming edges\n total_weight <- sum(ew) # Calculate the total weight of incoming edges\n # Normalize weights so that they sum to 1 for each node\n ew <- ew / total_weight\n # Store the weights for the incoming edges\n for (i in seq_along(in_edges)) {\n Ew[[as.character(in_edges[i])]] <- ew[i]\n }\n }\n return(Ew)\n}\n\n\n\nWith the network, edge weight setup, and the set of initial active nodes \\(A_0\\) (referred to as \\(S\\) in the function), we’re ready to execute a linear threshold model!\nFocusing on a single iteration, the runLT function assigns a threshold to each node from a uniform distribution. It then calculates the total weight of the activated in-neighbors, updates it, and compares the total weights with the nodes’ thresholds. If the total weights exceed the threshold, the node is activated. The final output is a list of total active nodes in the network.\n\n\nShow code\n\n# Function to run linear threshold model\nrunLT <- function(G, S, Ew) {\n T <- unique(S) # Targeted set with unique nodes\n lv <- sapply(V(G), function(u) runif(1)) # Threshold for nodes\n W <- rep(0, vcount(G)) # Weighted number of activated in-neighbors\n Sj <- unique(S)\n \n while (length(Sj) > 0) {\n if (length(T) >= vcount(G)) {\n break # Break if the number of active nodes exceeds or equals the total number of nodes in G\n }\n Snew <- c()\n for (u in Sj) {\n neighbors <- neighbors(G, u, mode = \"in\")\n for (v in neighbors) {\n e <- as.character(get.edge.ids(G, c(v, u))) # Define 'e' as the edge index\n if (!(v %in% T)) {\n # Calculate the total weight of the activated in-neighbors\n total_weight <- sum(Ew[[e]])\n \n # Update the weighted number of activated in-neighbors\n W[v] <- W[v] + total_weight\n \n # Check if the threshold is exceeded\n if (W[v] >= lv[v]) {\n Snew <- c(Snew, v)\n T <- c(T, v)\n }\n }\n }\n }\n Sj <- unique(Snew) # Ensure unique nodes in the new set\n }\n return(T) # Return all activated nodes\n}\n\n\n\nNow, let’s extend to multiple iterations!\nThe activeNodes function is the main function for calculating the total number of active nodes at each iteration. It iterates through the process and prints out the names of the active nodes for each iteration in the console. The function outputs a two-column table displaying the total number of active nodes in each iteration.\n\n\nShow code\n\n# Function to calculate the total number of active nodes at each iteration\nactiveNodes <- function(G, S, Ew, iterations) {\n active_df <- data.frame(iteration = integer(), \n total_active_nodes = integer())\n total_active_nodes <- rep(0, iterations) # Initialize empty vector to store total active nodes\n \n for (i in 1:iterations) {\n T <- runLT(G, S, Ew)\n message(\"--\", i,\"T: \", T, \"\\n\") # print active node names for this iteration in the console\n total_active <- length(unique(T)) # Calculate the total active nodes in this iteration\n total_active_nodes[i] <- total_active # Update total active nodes for current iteration\n \n # Limit total active nodes to the number of nodes in the graph\n if (total_active_nodes[i] >= vcount(G)) {\n total_active_nodes[i] <- vcount(G) \n }\n \n # Update data frame with current iteration's total active nodes\n active_df <- rbind(active_df, data.frame(iteration = i, \n total_active_nodes = total_active_nodes[i]))\n \n # Update seed set S for the next iteration\n S <- unique(c(S, T))\n }\n return(active_df)\n}\n\n\n\nRandom Graph Setup\nWhat are some simple network?\nI employed the Erdős–Rényi model \\(G(n, p)\\) and the preferential attachment model. These models offer a straightforward way to simulate network structures, allowing for comparisons between random graphs and those with power law distributions.\nErdős-Rényi model\nHere’s an example of the Erdős-Rényi model with 50 nodes. Each edge has a 5% probability of being included. Using uniform edge weights, the edges vary in width and color: thinner and blue for smaller weights, and wider and red for larger weights.\n\n\nShow code\n\n## Erdős–Rényi model\nset.seed(123)\n# Create a random graph with 50 nodes and edge weights satisfying the constraint\nrandom_graph_50 <- erdos.renyi.game(50, p = 0.05, directed = TRUE) # random graph set up\n\n# Equal edge weight for node v -> Calculate uniform edge weights\nEw_uniform <- uniformWeights(random_graph_50)\n\n# Scale edge width based on the weights in Ew_uniform\nedge_width <- sapply(E(random_graph_50), function(e) {\n v <- ends(random_graph_50, e)[2]\n Ew_uniform[[as.character(e)]]\n})\n\n# Map edge_width to color_palette\ncolor_palette <- wes_palette(n=5, name=\"Zissou1\")\nedge_color <- color_palette[cut(edge_width, breaks = 5)]\n\n# Plot the graph with gradient edge color\npar(mar=c(0,0,0,0)+.1)\np1 <- plot.igraph(random_graph_50, \n edge.width = edge_width, \n edge.color = edge_color,\n edge.arrow.size = 0.4,\n layout = layout.circle,\n vertex.label = NA,\n vertex.size = 10, \n vertex.color = \"#A9AABC\")\n\n\n\nPreferential attachment model\nHere’s an example of the Preferential attachment model with 50 nodes. The graph follows a power-law distribution with power equal to \\(1\\). Each node connects to the existing nodes with a fixed number \\(m\\) of links. Similarly, using uniform edge weights, the edges vary in width and color: thinner and blue for smaller weights, and wider and red for larger weights.\n\nWhat is power law? In network science, it describes the distribution of node degrees, where a few nodes have many connections while most nodes have few connections.\n\n\n\nShow code\n\n## Preferential attachment model\nset.seed(123)\n# Create a random graph with 50 nodes and edge weights satisfying the constraint\nrandom_graph_50 <- sample_pa(50, power = 1, m = 5) # random graph set up\n\n# Equal edge weight for node v -> Calculate uniform edge weights\nEw_uniform <- uniformWeights(random_graph_50)\n\n# Scale edge width based on the weights in Ew_uniform\nedge_width <- sapply(E(random_graph_50), function(e) {\n v <- ends(random_graph_50, e)[2]\n Ew_uniform[[as.character(e)]]\n})\n\n# Map edge_width to color_palette\ncolor_palette <- wes_palette(n=5, name=\"Zissou1\")\nedge_color <- color_palette[cut(edge_width, breaks = 5)]\n\n# Plot the graph with gradient edge color\npar(mar=c(0,0,0,0)+.1)\np1 <- plot.igraph(random_graph_50, \n edge.width = edge_width, \n edge.color = edge_color,\n edge.arrow.size = 0.4,\n layout = layout.circle,\n vertex.label = NA,\n vertex.size = 10, \n vertex.color = \"#A9AABC\")\n\n\n\n\nExample Usage for LTM\nExperiment with various simulation setup! The plot and table depict the total active nodes for each iteration in five random graphs labeled as df1 to df5.\nIf the plot displays a horizontal line, it suggests no increase in active nodes, which can occur. Attempt running the simulation multiple times to observe changes.\n\n\nGreedy Algorithm for LTM\nI’ve developed two functions to implement the hill climbing algorithm on LTM.\nThe avgLT function calculates the average size of activated nodes in the current step. On the other hand, the Greedy_LTM function is the primary tool for the greedy hill climbing approach. It requires input parameters including the graph, edge weights, the initial seed set size (denoted as \\(k\\)), and the number of iterations. For instance, if the number of iterations is 10, it selects the node with the maximum influence in the current iteration and adds it to the seed set. The output is \\(k\\) initial active nodes that maximize the local influence.\n\n\nShow code\n\n# Function to calculate average size of activated nodes\navgLT <- function(G, S, Ew, iterations = 1) {\n avgSize <- 0\n for (i in 1:iterations) {\n T <- runLT(G, S, Ew)\n avgSize <- avgSize + length(T) / iterations\n }\n return(avgSize)\n}\n\n\n# Greedy_LTM function to select k initial active nodes that maximize the local influence\nGreedy_LTM <- function(G, Ew, k, iterations) {\n start <- Sys.time() # Record the start time\n S <- c() # Initialize the seed set\n \n for (i in 1:k) {\n inf <- data.frame(nodes = V(G), influence = NA) # Initialize the influence table\n \n # Calculate the influence for nodes not in S\n for (v in V(G)) {\n if (!(v %in% S)) {\n inf$influence[v] <- avgLT(G, c(S, v), Ew, iterations = 1)\n }\n }\n \n # Exclude nodes already in S\n inf_excluded <- inf[!inf$nodes %in% S, ]\n \n # Select the node with maximum influence and add it to the seed set\n u <- inf_excluded[which.max(inf_excluded$influence), ]$nodes\n cat(\"Selected node:\", u, \"with influence:\", max(inf_excluded$influence), \"\\n\")\n \n # Convert node name to numeric\n u <- as.numeric(u)\n \n # Add selected node to the seed set\n S <- c(S, u)\n }\n \n end <- Sys.time() # Record the end time\n # Print the total time taken\n print(paste(\"Total time:\", end - start))\n \n return(S) # Return the seed set\n}\n\n\nExample: Greedy Algorithm of Influence Max Problem on LTM\nAnimation\nTo illustrate the iterative process of the greedy algorithm, I’ve added a brief animation depicting how the active nodes increase based on the initial seed set. I modified the activeNodes function to activeNodes_list, which stores the names of active nodes in each iteration in a list.\nUsing this approach, I applied the hill-climbing algorithm to the Erdős–Rényi model with 50 nodes and uniform edge weights to select 3 initial active nodes. The animation showcases the activation process over 5 iterations.\n\n\nShow code\n\n# Adapt function to store the total number of active nodes at each iteration in list\nactiveNodes_list <- function(G, S, Ew, iterations) {\n active_df <- data.frame(iteration = integer(), \n total_active_nodes = integer())\n total_active_nodes <- rep(0, iterations) # Initialize empty vector to store total active nodes\n T_list <- list() # Initialize list to store T values\n \n for (i in 1:iterations) {\n T <- runLT(G, S, Ew)\n # cat(\"--\", i,\"T: \", T, \"\\n\")\n total_active <- length(unique(T)) # Calculate the total active nodes in this iteration\n total_active_nodes[i] <- total_active # Update total active nodes for current iteration\n \n # Limit total active nodes to the number of nodes in the graph\n if (total_active_nodes[i] >= vcount(G)) {\n total_active_nodes[i] <- vcount(G) \n }\n \n # Update data frame with current iteration's total active nodes\n active_df <- rbind(active_df, data.frame(iteration = i, \n total_active_nodes = total_active_nodes[i]))\n \n # Store T values in the list\n T_list[[i]] <- T\n \n # Update seed set S for the next iteration\n S <- unique(c(S, T))\n }\n \n return(list(active_df = active_df, T_list = T_list))\n}\n\n\n# Example usage\nrandom_graph <- erdos.renyi.game(50, 0.1, directed = TRUE)\n# Calculate uniform edge weights\nEw_uniform <- uniformWeights(random_graph)\n\n# Run the Greedy_LTM function\nseed_set <- Greedy_LTM(random_graph, Ew_uniform, k = 3, iterations = 5)\n\nSelected node: 2 with influence: 37 \nSelected node: 22 with influence: 38 \nSelected node: 32 with influence: 40 \n[1] \"Total time: 0.208096981048584\"\n\n\n\nShow code\n\nactive_df_selectedSeed <- activeNodes_list(random_graph, seed_set, Ew_uniform, iterations = 5)\n\n# Scale edge width based on the weights in Ew_uniform\nedge_width <- sapply(E(random_graph), function(e) {\n v <- ends(random_graph, e)[2]\n Ew_uniform[[as.character(e)]]\n})\n# Map edge_width to color_palette\ncolor_palette <- wes_palette(n = 5, name = \"Zissou1\")\nedge_color <- color_palette[cut(edge_width, breaks = 5)]\n\n\n# Add seed set to the beginning of T_list\nT_list_with_seed <- c(list(seed_set), active_df_selectedSeed[[\"T_list\"]])\n\n# Create the GIF\nsaveGIF(\n expr = {\n for (i in seq_along(T_list_with_seed)) {\n T <- T_list_with_seed[[i]]\n par(mar=c(6,0,0,0)+.1)\n p <- plot.igraph(\n random_graph,\n edge.width = edge_width,\n edge.color = edge_color,\n edge.arrow.size = 0.4,\n layout = layout.circle,\n # vertex.label = NA,\n vertex.size = 10,\n vertex.color = ifelse(1:vcount(random_graph) %in% T, \"#FC888F\", \"#A9AABC\")\n )\n title(p, ifelse(i == 1, \"Initial Seed Set\", paste(\"In Step\", i - 1)))\n }\n },\n movie.name = \"LTM_animation_greedy.gif\",\n clean = TRUE,\n fps = 4, # Adjust fps value as needed\n fig.height = 4, # Adjust figure height\n fig.width = 6 # Adjust figure width\n)\n\n[1] TRUE\n\nShow code\n\n\n# include animation\nknitr::include_graphics(\"LTM_animation_greedy.gif\")\n\n\n\nSimulation\nThe plot and table show the total active nodes for each iteration in three randomly generated graphs labeled as df1 to df3, and one graph with initially selected active nodes denoted as greedy. If the plot displays a horizontal line, it suggests no increase in active nodes, which can occur. Attempt running the simulation multiple times to observe changes.\nPlease be patient as the algorithm may take a few minutes to run for complicated setup.\n\n\nReferences\nERDdS, P., & R&wi, A. (1959). On random graphs I. Publ. math. debrecen, 6(290-297), 18.\nBarabási, A. L., & Albert, R. (1999). Emergence of scaling in random networks. science, 286(5439), 509-512.\n\n\n\n",
+ "last_modified": "2024-04-30T12:32:36-05:00"
},
{
"path": "04-more.html",
@@ -30,7 +30,7 @@
"description": "Some more models to explore.:)",
"author": [],
"contents": "\nInfluence maximization algorithm: LDAG\nAnother interesting influence maximization algorithm is LDAG algorithm. Due to the not-scalable and slow limitation of the hill-climbing algorithm, Chen Et al. invented a new algorithm that relies on the linear relationship in activation probabilities between a node and its in-neighbors in directed acyclic graphs (DAGs).\nThe algorithm involves creating a local DAG around each node in the network. This limits influence within the local DAG, making influence calculations quicker. Then, they used a greedy algorithm to choose local DAGs that capture a substantial influence spread. This LDAG algorithm gradually adds nodes to the local DAG of a given node \\(v\\), ensuring their individual influence exceeds the threshold \\(\\theta_v\\). Once the local DAGs are built, they integrate the greedy method again for selecting seeds that maximize incremental influence spread with a swift scheme for updating the spread of every node.\nOn the positive side, The LDAG algorithm offers faster influence computations within smaller local DAG structures, which improves tractability and speed, especially in large networks. However, the limited scope of local DAGs may not fully capture the network’s intricate influence dynamics. This can result in suboptimal seed selection and reduced influence spread compared to the comprehensive approach of the greedy hill-climbing algorithm.\n\nChen, W., Yuan, Y., & Zhang, L. (2010). Scalable Influence Maximization in Social Networks under the Linear Threshold Model. 2010 IEEE International Conference on Data Mining, 88-97.\n\nOther information diffusion models\nIndependent cascade model\nAnother famous information diffusion model is independent cascade model (ICM).\nThe ICM and the LTM both operate on discrete steps for information propagation within social networks and both use binary representation of opinions, where individuals either adopt the information or remain uninformed.\nHowever, they differ in their mechanisms of influence spread. In ICM, information spreads through a network in discrete steps or cascades. At each step, an individual who adopts the information can independently influence their neighbors with a certain probability. Conversely, LTM relies on a deterministic threshold mechanism, where nodes adopt or reject opinions based on predefined thresholds.\n\nKempe, D., Kleinberg, J.M., & Tardos, É. (2003). Maximizing the spread of influence through a social network. Theory Comput., 11, 105-147.\n\n\n\n\nFigure 1: IC model. Created by Kalyanee Devi.\n\n\n\nDeGroot learning model\nThe DeGroot learning model presents an alternative approach to understanding information diffusion in social networks compared to the Linear Threshold Model (LTM).\nUnlike LTM, which focuses on individual nodes adopting opinions based on a threshold of influenced neighbors, the DeGroot model emphasizes consensus formation through iterative averaging of opinions among network neighbors. In this model, each node’s opinion is updated by averaging its own opinion with those of its connected neighbors, weighted by the strength of their connections via a one-to-one trust matrix \\(T\\) where \\(T_{ij}\\) is the weight that person \\(i\\) puts on person \\(j\\)’s opinion. This iterative process updates by \\[p(t) = T\\cdot p(t-1)\\]\nuntil convergence, differing from LTM by emphasizing consensus rather than threshold-based adoption.\nMoreover, the DeGroot learning model uses continuous opinion values from 0 to 1, indicating the degree of agreement. In contrast, LTM relies on binary opinions: individuals adopt neighbor opinions if they exceed a threshold, otherwise maintaining their own. This distinction affects how opinions spread and consensus forms in social networks.\n\nDeGroot, M. H. (1974). Reaching a Consensus. Journal of the American Statistical Association, 69(345), 118–121. https://doi.org/10.2307/2285509\n\n\n\n\n",
- "last_modified": "2024-04-30T12:05:44-05:00"
+ "last_modified": "2024-04-30T12:32:36-05:00"
},
{
"path": "index.html",
@@ -38,7 +38,7 @@
"description": "By Wenxuan Zhu\n\nWelcome to the website. I hope you enjoy it!\n",
"author": [],
"contents": "\nIntro to Graphs\nGraphs (networks) are visual representations of connections between things. They consist of dots (nodes) connected by lines (edges). Graphs help us understand how things are related and how information flows in systems like social networks, transportation routes, and more.\nSpread of Influence\nImagine you’re planning a movie night with your friends. You suggest watching a new superhero movie, but not everyone is immediately on board. However, you know that once a few friends agree to watch it, they’ll start convincing others to join in.\nIn this scenario, your social circle forms a network where each person’s decision to watch the movie is influenced by their connections. When one friend agrees to watch, they start spreading the excitement to other connected peers in the network. Soon enough, more and more friends agree with the superhero movie bandwagon.\nThis simple example illustrates how influence can spread through a network, starting with just a few initial adopters and gradually reaching a larger portion of the group as the excitement/agreement spreads from friend to friend.\n\n\n\nFigure 1: Influence Spread Example\n\n\n\nWhat will be covered?\nIn this website, we will delve into the foundational concepts of the Linear Threshold Model (LTM), exploring its implications in understanding information diffusion and solving the influence maximization problem. We’ll provide insights into the methodology of LTM, its practical applications, and explore the hill-climbing algorithm—an indispensable tool for optimizing influence in networks.\nAcknowledgement\nA huge thank you to my professor Andrew Beveridge for delivering this amazing Network Science capstone class. Your expertise and passion have truly enriched our learning experience. :)\n\n\n\n",
- "last_modified": "2024-04-30T10:37:14-05:00"
+ "last_modified": "2024-04-30T12:32:36-05:00"
}
],
"collections": []