InfluenceDiffusion 0.0.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,614 @@
1
+ import numpy as np
2
+ from copy import deepcopy
3
+ from scipy import stats
4
+ from scipy.stats._distn_infrastructure import rv_frozen
5
+ from typing import Dict, Set, Union, List
6
+ from joblib import Parallel, delayed
7
+ from Graph import Graph
8
+ from Trace import Trace, Traces
9
+
10
+
11
+ class InfluenceModel:
12
+ """Base class for influence models on a graph.
13
+
14
+ Parameters
15
+ ----------
16
+ g : Graph
17
+ The graph on which the influence model operates.
18
+ check_init : bool, optional
19
+ Whether to check the parameters upon initialization (default is True).
20
+ random_state : int, optional
21
+ Seed for random number generation (default is None).
22
+ n_jobs : int, optional
23
+ Number of parallel jobs for simulations (default is None).
24
+
25
+ Attributes
26
+ ----------
27
+ g : Graph
28
+ The graph on which the influence model operates.
29
+ vertices : List[int]
30
+ The list of vertices in the graph.
31
+ random_state : int
32
+ Seed for random number generation.
33
+ n_jobs : int
34
+ Number of parallel jobs for simulations.
35
+ seed_set : Set[int]
36
+ Set of initial active nodes.
37
+ _cur_influence_nodes : Set[int]
38
+ Nodes currently influencing others.
39
+ all_influenced_nodes : Set[int]
40
+ All nodes that have been influenced.
41
+ _propagation_trace : List[Set[int]]
42
+ Trace of the propagation process.
43
+ """
44
+
45
+ def __init__(self, g: Graph, check_init: bool = True, random_state: int = None, n_jobs: int = None) -> None:
46
+ self.g = g
47
+ self.vertices = list(self.g.get_vertices())
48
+ self.random_state = random_state
49
+ self.n_jobs = n_jobs
50
+ if check_init:
51
+ self.check_param_init_correctness()
52
+
53
+ def check_param_init_correctness(self) -> None:
54
+ """Check the correctness of the model's parameters.
55
+
56
+ Raises
57
+ ------
58
+ NotImplementedError
59
+ This method should be implemented in derived classes.
60
+ """
61
+ raise NotImplementedError()
62
+
63
+ def _init_simulation_rvs(self, simulation_rvs=None) -> None:
64
+ """Initialize simulation random variables.
65
+
66
+ Parameters
67
+ ----------
68
+ simulation_rvs : np.ndarray, optional
69
+ Predefined random variables for simulation (default is None).
70
+
71
+ Raises
72
+ ------
73
+ NotImplementedError
74
+ This method should be implemented in derived classes.
75
+ """
76
+ raise NotImplementedError()
77
+
78
+ def _generate_simulation_rvs(self, n_runs: int = 1) -> List:
79
+ """Generate random variables for simulation.
80
+
81
+ Parameters
82
+ ----------
83
+ n_runs : int, optional
84
+ Number of simulation runs (default is 1).
85
+
86
+ Returns
87
+ -------
88
+ List
89
+ Generated random variables for the simulation.
90
+
91
+ Raises
92
+ ------
93
+ NotImplementedError
94
+ This method should be implemented in derived classes.
95
+ """
96
+ raise NotImplementedError()
97
+
98
+ def _pre_simulation_init(self, seed_set: Set[int], simulation_rvs=None) -> None:
99
+ """Prepare for simulation by initializing parameters.
100
+
101
+ Parameters
102
+ ----------
103
+ seed_set : Set[int]
104
+ Set of initial active nodes.
105
+ simulation_rvs : np.ndarray, optional
106
+ Predefined random variables for simulation (default is None).
107
+
108
+ Raises
109
+ ------
110
+ AssertionError
111
+ If the seed set is empty.
112
+ """
113
+ assert len(seed_set) > 0, "Seed set should contain at least one vertex"
114
+ self.seed_set = set(seed_set)
115
+ self._cur_influence_nodes = deepcopy(self.seed_set)
116
+ self.all_influenced_nodes = deepcopy(self.seed_set)
117
+ self._propagation_trace: List[Set[int]] = [self.seed_set]
118
+ self._init_simulation_rvs(simulation_rvs)
119
+
120
+ def _make_edge_influence_attempt(self, v: int, v_adj: int) -> bool:
121
+ """Attempt to influence adjacent vertex.
122
+
123
+ Parameters
124
+ ----------
125
+ v : int
126
+ The current influencing vertex.
127
+ v_adj : int
128
+ The adjacent vertex to be influenced.
129
+
130
+ Returns
131
+ -------
132
+ bool
133
+ True if the adjacent vertex is influenced, otherwise False.
134
+
135
+ Raises
136
+ ------
137
+ NotImplementedError
138
+ This method should be implemented in derived classes.
139
+ """
140
+ raise NotImplementedError()
141
+
142
+ def _simulate_trace(self, out_trace_type: bool = True) -> Union[Trace, List[Set[int]]]:
143
+ """Simulate the influence spread.
144
+
145
+ Parameters
146
+ ----------
147
+ out_trace_type : bool, optional
148
+ Whether to return a Trace object (default is True).
149
+
150
+ Returns
151
+ -------
152
+ Union[Trace, List[Set[int]]]
153
+ The trace of influenced nodes or a Trace object.
154
+ """
155
+ while self._cur_influence_nodes:
156
+ self._make_step()
157
+ return Trace(self.g, tuple(self._propagation_trace)) if out_trace_type else self._propagation_trace
158
+
159
+ def sample_trace(self, seed_set: Set[int],
160
+ out_trace_type: bool = True,
161
+ simulation_rvs=None) -> Union[Trace, List[Set[int]]]:
162
+ """Sample a single trace from the model.
163
+
164
+ Parameters
165
+ ----------
166
+ seed_set : Set[int]
167
+ Set of initial active nodes.
168
+ out_trace_type : bool, optional
169
+ Whether to return a Trace object (default is True).
170
+ simulation_rvs : np.ndarray, optional
171
+ Predefined random variables for simulation (default is None).
172
+
173
+ Returns
174
+ -------
175
+ Union[Trace, List[Set[int]]]
176
+ The sampled trace of influenced nodes or a Trace object.
177
+ """
178
+ self._pre_simulation_init(seed_set, simulation_rvs=simulation_rvs)
179
+ return self._simulate_trace(out_trace_type=out_trace_type)
180
+
181
+ def make_simulation(self, seed_set: Set[int], simulation_rvs=None) -> np.ndarray:
182
+ """Run a simulation and return the propagation trace.
183
+
184
+ Parameters
185
+ ----------
186
+ seed_set : Set[int]
187
+ Set of initial active nodes.
188
+ simulation_rvs : np.ndarray, optional
189
+ Predefined random variables for simulation (default is None).
190
+
191
+ Returns
192
+ -------
193
+ np.ndarray
194
+ The propagation trace as an array.
195
+ """
196
+ self._pre_simulation_init(seed_set, simulation_rvs=simulation_rvs)
197
+ return self._simulate_trace()
198
+
199
+ def sample_traces(self, n_traces: int = 100,
200
+ seed_size_range: List[int] = None,
201
+ out_trace_type: bool = True) -> Union[Traces, List[List[Set[int]]]]:
202
+ """Sample multiple traces.
203
+
204
+ Parameters
205
+ ----------
206
+ n_traces : int, optional
207
+ Number of traces to sample (default is 100).
208
+ seed_size_range : List[int], optional
209
+ Range of seed sizes to sample from (default is None).
210
+ out_trace_type : bool, optional
211
+ Whether to return a Traces object (default is True).
212
+
213
+ Returns
214
+ -------
215
+ Union[Traces, List[List[Set[int]]]]
216
+ The sampled traces or a Traces object.
217
+ """
218
+ seed_sets = self._sample_seeds(n_seeds=n_traces, seed_size_range=seed_size_range)
219
+ return self.sample_traces_from_seeds(seed_sets, out_trace_type=out_trace_type)
220
+
221
+ def sample_traces_from_seeds(self, seed_sets: List[Set[int]], out_trace_type: bool = True) -> Union[Traces, List[List[Set[int]]]]:
222
+ """Sample traces from a list of seed sets.
223
+
224
+ Parameters
225
+ ----------
226
+ seed_sets : List[Set[int]]
227
+ List of seed sets for sampling.
228
+ out_trace_type : bool, optional
229
+ Whether to return a Traces object (default is True).
230
+
231
+ Returns
232
+ -------
233
+ Union[Traces, List[List[Set[int]]]]
234
+ The sampled traces or a Traces object.
235
+ """
236
+ simulation_rvs_over_runs = self._generate_simulation_rvs(n_runs=len(seed_sets))
237
+ traces = Parallel(n_jobs=self.n_jobs)(
238
+ delayed(lambda seed_set, simulation_rvs:
239
+ self.sample_trace(seed_set=seed_set, out_trace_type=False, simulation_rvs=simulation_rvs))
240
+ (seed_set, thresholds)
241
+ for seed_set, thresholds in zip(seed_sets, simulation_rvs_over_runs)
242
+ )
243
+ return Traces(self.g, traces) if out_trace_type else traces
244
+
245
+ def _make_step(self) -> None:
246
+ """Make a simulation step by activating new nodes.
247
+
248
+ This method updates the current influence nodes and the propagation trace.
249
+ """
250
+ new_influence_nodes = set()
251
+ for v in self._cur_influence_nodes:
252
+ for v_adj in self.g.get_children(v).difference(self.all_influenced_nodes):
253
+ influence_res = self._make_edge_influence_attempt(v, v_adj)
254
+ if influence_res:
255
+ new_influence_nodes.add(v_adj)
256
+
257
+ self._cur_influence_nodes = new_influence_nodes
258
+ self.all_influenced_nodes.update(new_influence_nodes)
259
+
260
+ # Append to the propagation trace if there are new nodes influenced
261
+ if new_influence_nodes:
262
+ self._propagation_trace.append(new_influence_nodes)
263
+
264
+ def _sample_seeds(self, n_seeds: int, seed_size_range: List[int] = None) -> List[Set[int]]:
265
+ """Sample seed sets from the graph.
266
+
267
+ Parameters
268
+ ----------
269
+ n_seeds : int
270
+ Number of seed sets to sample.
271
+ seed_size_range : List[int], optional
272
+ Range of seed sizes to sample from (default is None).
273
+
274
+ Returns
275
+ -------
276
+ List[Set[int]]
277
+ List of sampled seed sets.
278
+
279
+ Raises
280
+ ------
281
+ AssertionError
282
+ If values in seed_size_range are out of bounds.
283
+ """
284
+ if seed_size_range is None:
285
+ seed_size_range = range(1, self.g.count_vertices() + 1)
286
+ else:
287
+ assert max(seed_size_range) <= self.g.count_vertices() and min(seed_size_range) > 0, \
288
+ "Values of `seed_size_range should be between 1 and the number of vertices in the graph"
289
+
290
+ if self.random_state:
291
+ np.random.seed(self.random_state)
292
+ seed_sizes = np.random.choice(seed_size_range, size=n_seeds, replace=True)
293
+ seed_sets = [set(np.random.choice(self.vertices, size=size, replace=False)) for size in seed_sizes]
294
+ return seed_sets
295
+
296
+ def estimate_spread(self, seed_set: Set[int], n_runs: int = 100, with_std: bool = False) -> Union[float, tuple]:
297
+ """Estimate the spread of influence from a seed set.
298
+
299
+ Parameters
300
+ ----------
301
+ seed_set : Set[int]
302
+ Set of initial active nodes.
303
+ n_runs : int, optional
304
+ Number of simulation runs (default is 100).
305
+ with_std : bool, optional
306
+ Whether to return standard deviation along with the mean (default is False).
307
+
308
+ Returns
309
+ -------
310
+ Union[float, tuple]
311
+ Mean spread, or a tuple of (mean spread, standard deviation) if with_std is True.
312
+ """
313
+ traces = self.sample_traces_from_seeds([seed_set] * n_runs, out_trace_type=True)
314
+ spread_over_runs = [len(trace.get_all_activated_vertices()) for trace in traces]
315
+ mean_spread, std_spread = np.mean(spread_over_runs), np.std(spread_over_runs)
316
+ return (mean_spread, std_spread) if with_std else mean_spread
317
+
318
+ def find_optimal_seed_greedily(self, seed_size: int, n_runs_per_node: int = 100) -> List[int]:
319
+ """Find the optimal seed set using a greedy approach.
320
+
321
+ Parameters
322
+ ----------
323
+ seed_size : int
324
+ Desired size of the seed set.
325
+ n_runs_per_node : int, optional
326
+ Number of runs to estimate the spread for each candidate node (default is 100).
327
+
328
+ Returns
329
+ -------
330
+ List[int]
331
+ List of vertices in the optimal seed set.
332
+ """
333
+ seed_set = []
334
+ unseen_seeds = list(range(len(self.vertices)))
335
+
336
+ for _ in range(seed_size):
337
+ spread_over_seeds = [
338
+ self.estimate_spread(seed_set=set(seed_set + [vertex]), n_runs=n_runs_per_node)
339
+ for vertex in unseen_seeds
340
+ ]
341
+ best_node_idx = np.argmax(spread_over_seeds)
342
+ best_node = unseen_seeds[best_node_idx]
343
+ seed_set.append(best_node)
344
+ unseen_seeds.pop(best_node_idx)
345
+ return seed_set
346
+
347
+
348
+ class LTM(InfluenceModel):
349
+ """Linear Threshold Model (LTM) for influence spread.
350
+
351
+ Parameters
352
+ ----------
353
+ g : Graph
354
+ The graph on which the LTM operates.
355
+ threshold_generator : rv_frozen, optional
356
+ Distribution for generating thresholds (default is uniform distribution).
357
+ check_init : bool, optional
358
+ Whether to check the parameters upon initialization (default is True).
359
+ random_state : int, optional
360
+ Seed for random number generation (default is None).
361
+ n_jobs : int, optional
362
+ Number of parallel jobs for simulations (default is None).
363
+
364
+ Attributes
365
+ ----------
366
+ vertex_2_threshold : Dict[int, float]
367
+ Mapping of vertices to their corresponding thresholds.
368
+ vertex_2_influence_counter : Dict[int, float]
369
+ Mapping of vertices to their current influence counter.
370
+ """
371
+
372
+ def __init__(self, g: Graph, threshold_generator=stats.uniform(0, 1),
373
+ check_init: bool = True, random_state: int = None, n_jobs: int = None) -> None:
374
+ self.threshold_generator = threshold_generator
375
+ super().__init__(g, check_init=check_init, random_state=random_state, n_jobs=n_jobs)
376
+
377
+ def _generate_simulation_rvs(self, n_runs: int = 1) -> np.ndarray:
378
+ """Generate random thresholds for simulation.
379
+
380
+ Parameters
381
+ ----------
382
+ n_runs : int, optional
383
+ Number of simulation runs (default is 1).
384
+
385
+ Returns
386
+ -------
387
+ np.ndarray
388
+ Generated thresholds for each vertex.
389
+ """
390
+ thresholds = self.threshold_generator.rvs(size=(n_runs, len(self.vertices)),
391
+ random_state=self.random_state)
392
+ return thresholds[0] if n_runs == 1 else thresholds
393
+
394
+ def _init_simulation_rvs(self, simulation_rvs=None) -> None:
395
+ """Initialize thresholds for vertices.
396
+
397
+ Parameters
398
+ ----------
399
+ simulation_rvs : np.ndarray, optional
400
+ Predefined thresholds for vertices (default is None).
401
+
402
+ Raises
403
+ ------
404
+ AssertionError
405
+ If the length of simulation_rvs does not match the number of vertices.
406
+ """
407
+ if simulation_rvs is None:
408
+ simulation_rvs = self._generate_simulation_rvs()
409
+ else:
410
+ assert len(simulation_rvs) == len(self.vertices), \
411
+ "Length of simulation_rvs should match the number of nodes in the graph for LTM"
412
+ self.vertex_2_threshold = dict(zip(self.vertices, simulation_rvs))
413
+
414
+ def _pre_simulation_init(self, seed_set: Set[int], simulation_rvs=None) -> None:
415
+ """Prepare for simulation by initializing parameters specific to LTM.
416
+
417
+ Parameters
418
+ ----------
419
+ seed_set : Set[int]
420
+ Set of initial active nodes.
421
+ simulation_rvs : np.ndarray, optional
422
+ Predefined thresholds for vertices (default is None).
423
+ """
424
+ super()._pre_simulation_init(seed_set, simulation_rvs=simulation_rvs)
425
+ self.vertex_2_influence_counter = {vertex: self.vertex_2_threshold[vertex] if vertex in seed_set else 0.0
426
+ for vertex in self.vertices}
427
+
428
+ def _make_edge_influence_attempt(self, v: int, v_adj: int) -> bool:
429
+ """Attempt to influence an adjacent vertex based on its threshold and received influence.
430
+
431
+ Parameters
432
+ ----------
433
+ v : int
434
+ The current influencing vertex.
435
+ v_adj : int
436
+ The adjacent vertex to be influenced.
437
+
438
+ Returns
439
+ -------
440
+ bool
441
+ True if the adjacent vertex is influenced, otherwise False.
442
+ """
443
+ self.vertex_2_influence_counter[v_adj] += self.g.get_edge_weight((v, v_adj))
444
+ return self.vertex_2_threshold[v_adj] <= self.vertex_2_influence_counter[v_adj]
445
+
446
+ def check_param_init_correctness(self, eps: float = 1e-6) -> None:
447
+ """Validate parameters of the LTM model.
448
+
449
+ Parameters
450
+ ----------
451
+ eps : float, optional
452
+ Tolerance for validating indegree constraints (default is 1e-6).
453
+
454
+ Raises
455
+ ------
456
+ AssertionError
457
+ If the parameters are not valid.
458
+ """
459
+ assert isinstance(self.threshold_generator, rv_frozen), "Only scipy distributions are allowed"
460
+ dist_min, dist_max = self.threshold_generator.support()
461
+ indegrees = np.array([self.g.get_indegree(vertex, weighted=True) for vertex in self.g.get_vertices()])
462
+ assert np.all((indegrees >= dist_min - eps) & (indegrees <= dist_max + eps))
463
+
464
+
465
+ class GLTM(LTM):
466
+ """General Linear Threshold Model (GLTM).
467
+
468
+ Parameters
469
+ ----------
470
+ g : Graph
471
+ The graph on which the GLTM operates.
472
+ threshold_distribs : Dict[int, rv_frozen]
473
+ Mapping of vertices to their corresponding threshold distributions.
474
+ check_init : bool, optional
475
+ Whether to check the parameters upon initialization (default is True).
476
+ random_state : int, optional
477
+ Seed for random number generation (default is None).
478
+ n_jobs : int, optional
479
+ Number of parallel jobs for simulations (default is None).
480
+
481
+ Attributes
482
+ ----------
483
+ threshold_distribs : Dict[int, rv_frozen]
484
+ Mapping of vertices to their corresponding threshold distributions.
485
+ """
486
+
487
+ def __init__(self, g: Graph, threshold_distribs: Dict[int, rv_frozen],
488
+ check_init: bool = True, random_state: int = None, n_jobs: int = None) -> None:
489
+ self.threshold_distribs = threshold_distribs
490
+ super().__init__(g, check_init=check_init, random_state=random_state, n_jobs=n_jobs)
491
+
492
+ def _generate_simulation_rvs(self, n_runs: int = 1) -> np.ndarray:
493
+ """Generate random thresholds for each vertex using their specific distributions.
494
+
495
+ Parameters
496
+ ----------
497
+ n_runs : int, optional
498
+ Number of simulation runs (default is 1).
499
+
500
+ Returns
501
+ -------
502
+ np.ndarray
503
+ Generated thresholds for each vertex.
504
+ """
505
+ if self.random_state:
506
+ np.random.seed(self.random_state)
507
+ thresholds = np.random.rand(n_runs, len(self.vertices))
508
+ for idx, vertex in enumerate(self.vertices):
509
+ inv_cdf = self.threshold_distribs[vertex].ppf
510
+ thresholds[:, idx] = inv_cdf(thresholds[:, idx])
511
+ return thresholds[0] if n_runs == 1 else thresholds
512
+
513
+ def check_param_init_correctness(self, eps: float = 1e-6) -> None:
514
+ """Validate parameters of the GLT model.
515
+
516
+ Parameters
517
+ ----------
518
+ eps : float, optional
519
+ Tolerance for validating indegree constraints (default is 1e-6).
520
+
521
+ Raises
522
+ ------
523
+ AssertionError
524
+ If the parameters are not valid.
525
+ """
526
+ assert isinstance(self.threshold_distribs, dict), \
527
+ "Threshold distributions should be a dict with vertices as keys and rv_frozen objects as values"
528
+ indegrees = self.g.get_indegrees_dict(weighted=True)
529
+ for vertex, threshold_dist in self.threshold_distribs.items():
530
+ assert isinstance(threshold_dist, rv_frozen), "Only scipy distributions are allowed"
531
+ dist_min, dist_max = threshold_dist.support()
532
+ assert (indegrees[vertex] >= dist_min - eps) and (indegrees[vertex] <= dist_max + eps), \
533
+ f"Indegree of vertex {vertex} is out of the distribution support range."
534
+
535
+
536
+ class ICM(InfluenceModel):
537
+ """Independent Cascade Model (ICM) for influence spread.
538
+
539
+ Parameters
540
+ ----------
541
+ g : Graph
542
+ The graph on which the ICM operates.
543
+ check_init : bool, optional
544
+ Whether to check the parameters upon initialization (default is True).
545
+ random_state : int, optional
546
+ Seed for random number generation (default is None).
547
+ n_jobs : int, optional
548
+ Number of parallel jobs for simulations (default is None).
549
+ """
550
+
551
+ def check_param_init_correctness(self) -> None:
552
+ """Check if the graph edge weights are valid for the ICM.
553
+
554
+ Raises
555
+ ------
556
+ AssertionError
557
+ If any edge weight is not in the range [0, 1].
558
+ """
559
+ assert np.all((0 <= self.g.weights) & (self.g.weights <= 1))
560
+
561
+ def _make_edge_influence_attempt(self, v: int, v_adj: int) -> bool:
562
+ """Attempt to influence an adjacent vertex based on edge activation.
563
+
564
+ Parameters
565
+ ----------
566
+ v : int
567
+ The current influencing vertex.
568
+ v_adj : int
569
+ The adjacent vertex to be influenced.
570
+
571
+ Returns
572
+ -------
573
+ bool
574
+ True if the adjacent vertex is influenced, otherwise False.
575
+ """
576
+ return self.edge_activations[self.g.get_edge_index((v, v_adj))]
577
+
578
+ def _generate_simulation_rvs(self, n_runs: int = 1) -> List:
579
+ """Generate random activations for edges.
580
+
581
+ Parameters
582
+ ----------
583
+ n_runs : int, optional
584
+ Number of simulation runs (default is 1).
585
+
586
+ Returns
587
+ -------
588
+ List[np.ndarray]
589
+ Random activation results for each edge.
590
+ """
591
+ if self.random_state:
592
+ np.random.seed(self.random_state)
593
+ edge_activations = np.random.rand(n_runs, self.g.count_edges()) <= self.g.weights
594
+ return edge_activations[0] if n_runs == 1 else edge_activations
595
+
596
+ def _init_simulation_rvs(self, simulation_rvs=None) -> None:
597
+ """Initialize edge activations for the ICM.
598
+
599
+ Parameters
600
+ ----------
601
+ simulation_rvs : np.ndarray, optional
602
+ Predefined edge activations (default is None).
603
+
604
+ Raises
605
+ ------
606
+ AssertionError
607
+ If the length of simulation_rvs does not match the number of edges.
608
+ """
609
+ if simulation_rvs is None:
610
+ simulation_rvs = self._generate_simulation_rvs()
611
+ else:
612
+ assert len(simulation_rvs) == self.g.count_edges(), \
613
+ "Length of edge_activations must match the number of edges in the graph"
614
+ self.edge_activations = simulation_rvs
@@ -0,0 +1,29 @@
1
+ import numpy as np
2
+ from typing import Iterable, Set, List
3
+
4
+
5
+ def multiple_union(set_list: Iterable[Set]):
6
+ final_set = set()
7
+ for cur_set in set_list:
8
+ final_set = final_set.union(cur_set)
9
+ return final_set
10
+
11
+
12
+ def invert_non_zeros(array):
13
+ out = np.array(array, dtype=float)
14
+ non_zero_mask = array != 0
15
+ out[non_zero_mask] = 1. / out[non_zero_mask]
16
+ return out
17
+
18
+
19
+ def random_vector_inside_simplex(dim, ub=1):
20
+ U = np.random.uniform(low=0, high=ub, size=dim)
21
+ U_sorted = np.sort(U)
22
+ U_sorted = np.concatenate(([0], U_sorted))
23
+ x = np.diff(U_sorted)
24
+ return x
25
+
26
+
27
+ def random_vector_on_simplex(dim, ub=1):
28
+ X = random_vector_inside_simplex(dim=dim, ub=1)
29
+ return X / np.sum(X) * ub
@@ -0,0 +1,21 @@
1
+ Metadata-Version: 2.1
2
+ Name: InfluenceDiffusion
3
+ Version: 0.0.3
4
+ Summary: InfluenceDiffusion package
5
+ Author: Alexander Kagan
6
+ Author-email: <amkagan@umich.edu>
7
+ Keywords: python,Influence Maximization,Network diffusion models,General Linear Threshold model,Social Networks,Independent Cascade model
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Education
10
+ Classifier: Programming Language :: Python :: 2
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Operating System :: MacOS :: MacOS X
13
+ Classifier: Operating System :: Microsoft :: Windows
14
+ Requires-Dist: numpy
15
+ Requires-Dist: scipy
16
+ Requires-Dist: networkx
17
+ Requires-Dist: typing
18
+ Requires-Dist: joblib
19
+ Requires-Dist: os
20
+
21
+ in this package, we implement popular network diffusion models and methods for their estimation.
@@ -0,0 +1,13 @@
1
+ InfluenceDiffusion/Graph.py,sha256=KivMsqW8Zl1Yp6I-Z32JTfOsuf3vPgqysTt0DCnmWww,15159
2
+ InfluenceDiffusion/Trace.py,sha256=LoOimi8tB9eItHI0VaTQk6qnc-BixzWWHdrjaHJHo4o,15272
3
+ InfluenceDiffusion/__init__.py,sha256=uSesPBwxMshakiwcev7rtwWUoEdVVV62NcPzOEeIzQU,91
4
+ InfluenceDiffusion/influence_models.py,sha256=-AUiJ3VSY8-Ra69lswfKAzMI2Lhoxa9GmQS6_RmldcE,22472
5
+ InfluenceDiffusion/utils.py,sha256=KysTdA99OGqZbcMQXpNxFi-rBfkjLdUSwtE56FV19TI,723
6
+ InfluenceDiffusion/estimation_models/BaseWeightEstimator.py,sha256=WpikOb5q74QWe2LyRWHHK5Bhp3sEx_TGBw-xWXgDWMI,18140
7
+ InfluenceDiffusion/estimation_models/EMEstimation.py,sha256=OEUcqzOxmMyqKp0IIsC0CXcGeTbKrkYxuZwo0R9qRt8,9871
8
+ InfluenceDiffusion/estimation_models/OptimEstimation.py,sha256=LvyKOPlB5GvfUyM7s8xghhwo7cSQ-dCVxlL5UImX0wI,10707
9
+ InfluenceDiffusion/estimation_models/__init__.py,sha256=Ow7q6gMnlRMp7jAaI3d-GMRukz7RWVmL-lSaVs1DpV8,91
10
+ InfluenceDiffusion-0.0.3.dist-info/METADATA,sha256=JTXgMGDsHrKT8T2Sph2iMxJRJF5MHKx0FXp6hqRbH9U,805
11
+ InfluenceDiffusion-0.0.3.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
12
+ InfluenceDiffusion-0.0.3.dist-info/top_level.txt,sha256=Fad_YlZYnVYGG5UerSx2REIoxBrEjVKJKleHguMf8rw,19
13
+ InfluenceDiffusion-0.0.3.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: bdist_wheel (0.37.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ InfluenceDiffusion