Skip to content

Commit 80a9bd6

Browse files
committed
Minor fixes
1 parent 6e6d149 commit 80a9bd6

File tree

4 files changed

+88
-77
lines changed

4 files changed

+88
-77
lines changed

Generator.py

Lines changed: 37 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,24 @@
66
import os
77
import argparse
88
import numpy as np
9-
import scipy.io
10-
import logging
9+
import hashlib
1110
from scipy.sparse import csr_matrix
12-
sys.path.append(os.path.join(os.environ['PHD_ROOT'], 'imin', 'src'))
13-
sys.path.append(os.path.join(os.environ['PHD_ROOT'], 'imin', 'scripts'))
14-
import helpers
15-
from FileManager import *
1611

1712
class Generator:
1813
def __init__(self, params):
1914
self.params = params
2015
self.generators = {
2116
'powerlaw_cluster': lambda: nx.powerlaw_cluster_graph(params["n"], params["m"], params["p"]),
22-
'stanford': lambda: self.get_stanford_graph(),
23-
'gnutella': lambda: self.get_gnutella_graph(),
2417
'grid': lambda: nx.convert_node_labels_to_integers(nx.grid_2d_graph(params['n'], params['n'])),
2518
'path': lambda: nx.path_graph(params["n"]),
2619
'binomial': lambda: nx.fast_gnp_random_graph(params['n'], params['p']),
2720
'watts_strogatz': lambda: nx.watts_strogatz_graph(params['n'], params['k'], params['p']),
2821
'karate': lambda: nx.karate_club_graph(),
29-
'vk': lambda: self.get_vk_graph(),
3022
'gaussian_random_partition': lambda: nx.gaussian_random_partition_graph(params['n'], params['s'], params['v'], params['p_in'], params['p_out'])
3123
}
3224

3325
def gen_graph_id(self):
34-
return str(helpers.get_static_hash(str(int(time.time())) + str(random.randint(10000, 99999)) + "_".join([str(self.params[p]) for p in self.params])))
26+
return str(self.get_static_hash(str(int(time.time())) + str(random.randint(10000, 99999)) + "_".join([str(self.params[p]) for p in self.params])))
3527

3628
def generate(self, number_of_graphs=1):
3729
for i in range(number_of_graphs):
@@ -80,49 +72,10 @@ def add_random_directions(G, both=False):
8072
dG[e[1]][e[0]][key] = G[e[0]][e[1]][key]
8173
return dG
8274

83-
def get_stanford_graph(self):
84-
mat = scipy.io.loadmat(os.path.join(os.environ['ALLDATA_PATH'], 'imin', 'wb-cs-stanford.mat'))
85-
sparse = mat['Problem'][0][0][2]
86-
m = csr_matrix(sparse)
87-
g = nx.DiGraph()
88-
G = nx.from_numpy_matrix(m.toarray(), create_using=g)
89-
return G
90-
# g = G
91-
# g = G.to_undirected() -- mistake
92-
# nodeset = []
93-
# for g1 in nx.connected_components(g):
94-
# if len(g1) > 1000:
95-
# nodeset = g1
96-
# break
97-
# return G.subgraph(nodeset).copy()
98-
99-
def get_gnutella_graph(self):
100-
edges = []
101-
with open(os.path.join(os.environ['ALLDATA_PATH'], 'imin', 'p2p-Gnutella31.txt')) as f:
102-
nodes, edge_count = f.readline().split()
103-
nodes = int(nodes)
104-
edge_count = int(edge_count)
105-
for line in f:
106-
edges.append((int(line.split()[0]), int(line.split()[1])))
107-
assert(len(edges) == edge_count)
108-
G = nx.DiGraph()
109-
G.add_nodes_from(range(nodes))
110-
G.add_edges_from(edges)
111-
return G
112-
113-
def get_vk_graph(self):
114-
G = nx.read_gpickle(os.path.join(os.environ['ALLDATA_PATH'], 'imin', 'vk_graph_cleaned.pkl'))
115-
return G
116-
11775
@staticmethod
11876
def analyze_graph(G):
11977
G.graph['directed'] = nx.is_directed(G)
12078
G_und = G.to_undirected()
121-
# if G.graph['directed']:
122-
# G.graph['weakly_connected_components'] = nx.number_weakly_connected_components(G)
123-
# G.graph['largest_weak_component'] = max(nx.weakly_connected_components(G), key=len)
124-
# G.graph['strongly_connected_components'] = nx.number_strongly_connected_components(G)
125-
# else:
12679
G.graph['connected_components'] = nx.number_connected_components(G_und)
12780
G.graph['largest_component'] = len(max(nx.connected_components(G_und), key=len))
12881

@@ -136,3 +89,38 @@ def analyze_graph(G):
13689
G.graph['std_degree'] = np.std(degrees)
13790
G.graph['median_degree'] = np.median(degrees)
13891
logging.info("Graph ID {}: degrees analyzed.".format(G.graph['graph_id']))
92+
93+
@staticmethod
94+
def get_static_hash(string):
95+
h = int(hashlib.md5(string.encode('utf-8')).hexdigest(), 16)
96+
return h
97+
98+
if __name__ == "__main__":
99+
parser = argparse.ArgumentParser(description="Generate graph with seeds")
100+
parser.add_argument("graph_type", type=str)
101+
parser.add_argument("graph_outfile", type=str)
102+
parser.add_argument("seed_outfile", type=str)
103+
parser.add_argument("-s", "--number_of_seeds", type=str, default=1)
104+
parser.add_argument("-b", "--both_directions", type=int, default=1)
105+
parser.add_argument("-w", "--weight_scale", type=float, default=0.3)
106+
parser.add_argument("-p", "--other_params", type=str, nargs="*")
107+
108+
args = parser.parse_args()
109+
other_params = {"graph_type": args.graph_type,
110+
"both_directions": args.both_directions,
111+
"weight_scale": args.weight_scale,
112+
"random_weight": 1}
113+
if args.other_params:
114+
for i in range(int(len(args.other_params)/2)):
115+
if args.other_params[2*i+1].isdigit():
116+
other_params[args.other_params[2*i]] = int(args.other_params[2*i+1])
117+
else:
118+
other_params[args.other_params[2*i]] = args.other_params[2*i+1]
119+
z = dict(other_params)
120+
gen = Generator(z)
121+
G = next(gen.generate())
122+
nx.write_gpickle(G, args.graph_outfile)
123+
n = args.number_of_seeds
124+
seeds = np.random.choice([node for node in G.nodes()], n, replace=False)
125+
np.savetxt(args.seed_outfile, seeds, fmt="%1u")
126+
print("Done.")

Readme.md

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,56 @@
22

33
The repository contains source files for Node Immunization algorithms. Given a directed network and a set of seed nodes, the problem is to select k nodes which to block/immunize so that the expected influence spread in the network is minimized. Simulations performed under Independent Cascade model.
44

5+
Supported algorithms:
6+
- Degree : degree heuristic
7+
- Dom : DAVA, dominator tree based algorithm
8+
- NetShape : Convex optimization of a hazard matrix
9+
- NetShield : Minimization of a shield value
10+
- Random : Random selection of blocked nodes
11+
512
# Requirements
613

7-
The repository is provided by the pipenv file that includes necessary requirements.
14+
Required libraries: NetworkX, SciPy, NumPy.
15+
```bash
16+
pip3 install networkx scipy numpy
17+
```
18+
19+
The repository is provided by Pipfile.
820

921
# Data
1022

11-
All algorithms require two files with a network and a seed set, in pickled NetworkX format for the network and csv file with node ids for seeds. Generator class generate random networks according to several growth models.
23+
All algorithms require two files with a network and a seed set, in pickled NetworkX format for the network and csv file with node ids for seeds. Graphs should have 'graph_id' attribute.
24+
25+
For synthetic data, Generator class is used to generate random networks according to several growth models. Real-world networks are not included in the repository.
1226

1327
# Usage
1428

29+
## Graph Generation
30+
31+
```python
32+
python3 Generator.py graph_type [-p other params]
33+
```
34+
35+
For example:
36+
```python
37+
python3 Generator.py grid a.pkl b.csv -p n 10
38+
```
39+
40+
## Benchmarking
41+
1542
The script run_solver.py applies an algorithm to a graph with seeds, and runs simulations for the objective evaluations (number of saved nodes in the graph).
1643

1744
Minimum usage:
18-
'''
45+
```python
1946
python3 run_solver.py path_to_graph path_to_seeds k algorithm_name
20-
'''
47+
```
2148

22-
'python3 run_solver.py' for other parameters.
49+
For other parameters run:
50+
```python
51+
python3 run_solver.py -h
52+
```
2353

24-
Supported algorithms:
25-
- Degree : degree heuristic
26-
- Dom : DAVA, dominator tree based algorithm
27-
- NetShape : Convex optimization of a hazard matrix
28-
- NetShield : Minimization of a shield value
29-
- Random : Random selection of blocked nodes
54+
If using pipenv, then all commands should precede by `pipenv run`.
3055

3156
# Notes
3257

Solver.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import helpers
21
import time
3-
import json
42

53
class Solver:
64
def __init__(self, G, seeds, k, **params):

run_solver.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
import os
22
import sys
33
import time
4-
import hashlib
54
import argparse
65
import numpy as np
7-
import signal
6+
import json
7+
import pickle as pkl
88
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
9-
from iMinSolver import *
109
from DegreeSolver import *
1110
from DomSolver import *
1211
from RandomSolver import *
1312
from NetShapeSolver import *
1413
from NetShieldSolver import *
15-
from Walk8Solver import *
14+
from Simulator import *
1615

1716
if __name__ == "__main__":
1817
t1 = time.time()
@@ -26,26 +25,27 @@
2625
parser.add_argument("-p", "--other_params", type=str, nargs="*")
2726
args = parser.parse_args()
2827

29-
G, seeds = helpers.load_graph_and_seed(args.graph, args.seeds)
28+
G, seeds = pkl.load(open(args.graph,'rb')), np.atleast_1d(np.loadtxt(args.seeds))
3029
k = args.nodes_to_block
3130
problem_params = {}
32-
if args.problem_params:
33-
for i in range(int(len(args.problem_params)/2)):
31+
if args.other_params:
32+
for i in range(int(len(args.other_params)/2)):
3433
if args.problem_params[2*i+1].isdigit():
35-
problem_params[args.problem_params[2*i]] = int(args.problem_params[2*i+1])
34+
problem_params[args.other_params[2*i]] = int(args.other_params[2*i+1])
3635
else:
37-
problem_params[args.problem_params[2*i]] = args.problem_params[2*i+1]
36+
problem_params[args.other_params[2*i]] = args.other_params[2*i+1]
3837
z = dict(problem_params)
3938

4039
Solver = eval(args.algorithm + "Solver")
4140
solver = Solver(G, seeds, k, **z)
4241
solver.run()
4342
print("%s blocked %d nodes in a graph of size %d." % (solver.get_name(), k, len(G)))
4443
print("Running simulations...")
45-
results = []
46-
for i in range(args.simulation_iterations):
47-
results.append(simulation.simulate(G, seeds, solver.log['Blocked nodes'])['saved nodes'])
48-
solver.log.update({"saved mean": np.mean(results), "saved std": np.std(results)})
49-
solver.save_log(args.outfile)
50-
print("Time: %1.5fs; Objective (saved): %1.1f pm %1.1f; Total time: %1.5s" % (solver.log["Total time"], np.mean(results), np.std(results), (time.time() - t1)))
44+
45+
simulator = Simulator(G, seeds)
46+
simulator.add_blocked(0, solver.log['Blocked nodes'])
47+
results = simulator.run(args.simulation_iterations)
48+
solver.log.update({"simulation": results['solvers'][0]})
49+
json.dump(solver.log, open(args.outfile, "w"))
50+
print("Solver Time: %1.5fs; Objective (saved): %1.1f; Total time: %1.5s" % (solver.log["Total time"], results['solvers'][0]["saved nodes"]["mean"], (time.time() - t1)))
5151
print("Logs saved to {}.".format(args.outfile))

0 commit comments

Comments
 (0)