InfluenceDiffusion 0.0.15__tar.gz → 0.0.17__tar.gz
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.
- {influencediffusion-0.0.15 → influencediffusion-0.0.17}/InfluenceDiffusion/Inference.py +14 -2
- influencediffusion-0.0.17/InfluenceDiffusion/estimation_models/CDFEstimation.py +177 -0
- {influencediffusion-0.0.15 → influencediffusion-0.0.17}/InfluenceDiffusion/estimation_models/OptimEstimation.py +28 -1
- {influencediffusion-0.0.15 → influencediffusion-0.0.17}/InfluenceDiffusion/plot_utils.py +36 -22
- {influencediffusion-0.0.15 → influencediffusion-0.0.17}/InfluenceDiffusion/utils.py +0 -14
- {influencediffusion-0.0.15 → influencediffusion-0.0.17}/InfluenceDiffusion.egg-info/PKG-INFO +1 -1
- {influencediffusion-0.0.15 → influencediffusion-0.0.17}/PKG-INFO +1 -1
- {influencediffusion-0.0.15 → influencediffusion-0.0.17}/setup.py +1 -1
- influencediffusion-0.0.15/InfluenceDiffusion/estimation_models/CDFEstimation.py +0 -73
- {influencediffusion-0.0.15 → influencediffusion-0.0.17}/InfluenceDiffusion/Graph.py +0 -0
- {influencediffusion-0.0.15 → influencediffusion-0.0.17}/InfluenceDiffusion/Trace.py +0 -0
- {influencediffusion-0.0.15 → influencediffusion-0.0.17}/InfluenceDiffusion/__init__.py +0 -0
- {influencediffusion-0.0.15 → influencediffusion-0.0.17}/InfluenceDiffusion/estimation_models/BaseWeightEstimator.py +0 -0
- {influencediffusion-0.0.15 → influencediffusion-0.0.17}/InfluenceDiffusion/estimation_models/EMEstimation.py +0 -0
- {influencediffusion-0.0.15 → influencediffusion-0.0.17}/InfluenceDiffusion/estimation_models/__init__.py +0 -0
- {influencediffusion-0.0.15 → influencediffusion-0.0.17}/InfluenceDiffusion/influence_models.py +0 -0
- {influencediffusion-0.0.15 → influencediffusion-0.0.17}/InfluenceDiffusion/weight_samplers.py +0 -0
- {influencediffusion-0.0.15 → influencediffusion-0.0.17}/InfluenceDiffusion.egg-info/SOURCES.txt +0 -0
- {influencediffusion-0.0.15 → influencediffusion-0.0.17}/InfluenceDiffusion.egg-info/dependency_links.txt +0 -0
- {influencediffusion-0.0.15 → influencediffusion-0.0.17}/InfluenceDiffusion.egg-info/requires.txt +0 -0
- {influencediffusion-0.0.15 → influencediffusion-0.0.17}/InfluenceDiffusion.egg-info/top_level.txt +0 -0
- {influencediffusion-0.0.15 → influencediffusion-0.0.17}/LICENSE +0 -0
- {influencediffusion-0.0.15 → influencediffusion-0.0.17}/README.md +0 -0
- {influencediffusion-0.0.15 → influencediffusion-0.0.17}/setup.cfg +0 -0
|
@@ -4,9 +4,9 @@ import numpy as np
|
|
|
4
4
|
from typing import Dict, Callable
|
|
5
5
|
from functools import partial
|
|
6
6
|
from scipy.stats import norm
|
|
7
|
+
from scipy.stats._distn_infrastructure import rv_frozen
|
|
7
8
|
|
|
8
9
|
from .estimation_models.OptimEstimation import GLTWeightEstimator
|
|
9
|
-
from .utils import make_jax_cdf
|
|
10
10
|
|
|
11
11
|
__all__ = ["GLTInferenceModule"]
|
|
12
12
|
|
|
@@ -15,7 +15,7 @@ class GLTInferenceModule:
|
|
|
15
15
|
def __init__(self, estimator: GLTWeightEstimator, vertex_2_jax_cdf: Dict[int, Callable] = None):
|
|
16
16
|
self.estimator = estimator
|
|
17
17
|
if vertex_2_jax_cdf is None:
|
|
18
|
-
self.vertex_2_jax_cdf = {vertex:
|
|
18
|
+
self.vertex_2_jax_cdf = {vertex: self._make_jax_cdf(distrib)
|
|
19
19
|
for vertex, distrib in self.estimator.vertex_2_distrib.items()}
|
|
20
20
|
else:
|
|
21
21
|
self.vertex_2_jax_cdf = vertex_2_jax_cdf
|
|
@@ -41,6 +41,18 @@ class GLTInferenceModule:
|
|
|
41
41
|
masks_tm1 = jnp.vstack([tm1_active_masks, tm1_failed_masks], dtype=jnp.float32)
|
|
42
42
|
return ys, masks_t, masks_tm1
|
|
43
43
|
|
|
44
|
+
@staticmethod
|
|
45
|
+
def _make_jax_cdf(distrib: rv_frozen):
|
|
46
|
+
name = distrib.dist.name
|
|
47
|
+
args = distrib.args
|
|
48
|
+
kwargs = distrib.kwds
|
|
49
|
+
local_dic = {}
|
|
50
|
+
exec(f"jax_distrib=jax.scipy.stats.{name}", None, local_dic)
|
|
51
|
+
jax_distrib = local_dic["jax_distrib"]
|
|
52
|
+
if name == "expon":
|
|
53
|
+
return lambda x: 1. - jnp.exp(-x)
|
|
54
|
+
return lambda x: jax_distrib.cdf(x, *args, **kwargs)
|
|
55
|
+
|
|
44
56
|
@staticmethod
|
|
45
57
|
def _vertex_ll(parent_weights, cdf, ys, masks_t, masks_tm1, eps=1e-6):
|
|
46
58
|
F_t = cdf(masks_t @ parent_weights)
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
from typing import List, Tuple, Any
|
|
2
|
+
from scipy.stats._distn_infrastructure import rv_continuous
|
|
3
|
+
from scipy.interpolate import interp1d
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
__all__ = ["CensoredCDFEstimator"]
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class CensoredCDFEstimator(rv_continuous):
|
|
10
|
+
"""
|
|
11
|
+
This class implements the Turnbull estimator of the cumulative distribution function (CDF)
|
|
12
|
+
from a collection of censored intervals within which sample points are observed.
|
|
13
|
+
See: Turnbull, Bruce W. (1976).
|
|
14
|
+
“The Empirical Distribution Function with Arbitrarily Grouped, Censored and Truncated Data.”
|
|
15
|
+
Journal of the Royal Statistical Society. Series B (Methodological) 38(3), 290–295.
|
|
16
|
+
|
|
17
|
+
Parameters
|
|
18
|
+
----------
|
|
19
|
+
support : tuple of float, optional
|
|
20
|
+
Explicit support (min, max) for the estimator. Default is (-np.inf, np.inf).
|
|
21
|
+
a : float, optional
|
|
22
|
+
Lower bound of the distribution. Default is None.
|
|
23
|
+
b : float, optional
|
|
24
|
+
Upper bound of the distribution. Default is None.
|
|
25
|
+
momtype : int, optional
|
|
26
|
+
Moment type used by `rv_continuous`. Default is 1.
|
|
27
|
+
xtol : float, optional
|
|
28
|
+
Tolerance for calculations in `rv_continuous`. Default is 1e-14.
|
|
29
|
+
badvalue : optional
|
|
30
|
+
Value to return for invalid inputs. Default is None.
|
|
31
|
+
name : str, optional
|
|
32
|
+
Name of the distribution. Default is None.
|
|
33
|
+
longname : str, optional
|
|
34
|
+
Long descriptive name of the distribution. Default is None.
|
|
35
|
+
shapes : str or None, optional
|
|
36
|
+
Shape parameters (if any) for the distribution. Default is None.
|
|
37
|
+
extradoc : str, optional
|
|
38
|
+
Additional documentation string. Default is None.
|
|
39
|
+
seed : int or np.random.Generator, optional
|
|
40
|
+
Random seed for reproducibility. Default is None.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def __init__(self, support: Tuple[float, float] = (-np.inf, np.inf),
|
|
44
|
+
momtype=1,
|
|
45
|
+
a=None,
|
|
46
|
+
b=None,
|
|
47
|
+
xtol=1e-14,
|
|
48
|
+
badvalue=None,
|
|
49
|
+
name=None,
|
|
50
|
+
longname=None,
|
|
51
|
+
shapes=None,
|
|
52
|
+
extradoc=None,
|
|
53
|
+
seed=None):
|
|
54
|
+
|
|
55
|
+
super().__init__(momtype=momtype, a=a, b=b, xtol=xtol, badvalue=badvalue,
|
|
56
|
+
name=name, longname=longname, shapes=shapes, seed=seed)
|
|
57
|
+
self.support_ = support
|
|
58
|
+
|
|
59
|
+
def fit(self, intervals: List[Tuple[float, float]],
|
|
60
|
+
max_iter=50, tol=1e-4, verbose=False, verbose_interval=1):
|
|
61
|
+
"""
|
|
62
|
+
Fit the CDF estimator to interval-censored data using an EM-like algorithm.
|
|
63
|
+
|
|
64
|
+
Parameters
|
|
65
|
+
----------
|
|
66
|
+
intervals : list of tuple of float
|
|
67
|
+
List of observed intervals (left, right) for each sample.
|
|
68
|
+
max_iter : int, default 50
|
|
69
|
+
Maximum number of iterations for the EM procedure.
|
|
70
|
+
tol : float, default 1e-4
|
|
71
|
+
Convergence tolerance for the probability updates.
|
|
72
|
+
verbose : bool, default False
|
|
73
|
+
If True, prints iteration progress.
|
|
74
|
+
verbose_interval : int, default 1
|
|
75
|
+
Interval at which verbose output is printed.
|
|
76
|
+
|
|
77
|
+
Returns
|
|
78
|
+
-------
|
|
79
|
+
self : CensoredCDFEstimator
|
|
80
|
+
The fitted estimator with computed CDF probabilities and interpolator.
|
|
81
|
+
"""
|
|
82
|
+
self.qp_ints_ = self._extract_disjoint_intervals(intervals)
|
|
83
|
+
|
|
84
|
+
alphas = np.fromfunction(
|
|
85
|
+
np.vectorize(lambda i, j: self._if_sub_interval(intervals[i], self.qp_ints_[j])),
|
|
86
|
+
shape=(len(intervals), len(self.qp_ints_)), dtype=int)
|
|
87
|
+
|
|
88
|
+
self.qp_probs_ = np.ones(len(self.qp_ints_)) / len(self.qp_ints_)
|
|
89
|
+
|
|
90
|
+
for iteration in range(max_iter):
|
|
91
|
+
cur_probs = self.qp_probs_.copy()
|
|
92
|
+
ms = (alphas * cur_probs) / (alphas @ cur_probs).reshape(-1, 1)
|
|
93
|
+
self.qp_probs_ = ms.sum(0) / ms.sum()
|
|
94
|
+
diff = np.linalg.norm(cur_probs - self.qp_probs_)
|
|
95
|
+
if verbose and iteration % verbose_interval == 0:
|
|
96
|
+
print(f"Iteration: {iteration}, Probs diff l2-norm: {round(diff, int(2 - np.log10(tol)))}")
|
|
97
|
+
if diff < tol:
|
|
98
|
+
break
|
|
99
|
+
|
|
100
|
+
if len(self.qp_ints_[:, 0]) >= 2:
|
|
101
|
+
self._cdf_interpolator = interp1d(self.qp_ints_[:, 0], np.cumsum(self.qp_probs_),
|
|
102
|
+
bounds_error=False, fill_value=(0.0, 1.0))
|
|
103
|
+
else:
|
|
104
|
+
self._cdf_interpolator = lambda x: np.clip(x, 0, 1)
|
|
105
|
+
|
|
106
|
+
return self
|
|
107
|
+
|
|
108
|
+
def _cdf(self, x: Any, *args, **kwargs):
|
|
109
|
+
"""
|
|
110
|
+
Evaluate the CDF at given points.
|
|
111
|
+
|
|
112
|
+
Parameters
|
|
113
|
+
----------
|
|
114
|
+
x : array-like or float
|
|
115
|
+
Points at which to evaluate the CDF.
|
|
116
|
+
|
|
117
|
+
Returns
|
|
118
|
+
-------
|
|
119
|
+
array-like or float
|
|
120
|
+
Evaluated CDF values at `x`.
|
|
121
|
+
"""
|
|
122
|
+
return self._cdf_interpolator(x)
|
|
123
|
+
|
|
124
|
+
def support(self):
|
|
125
|
+
"""
|
|
126
|
+
Get the support of the distribution.
|
|
127
|
+
|
|
128
|
+
Returns
|
|
129
|
+
-------
|
|
130
|
+
tuple of float
|
|
131
|
+
Lower and upper bounds of the support.
|
|
132
|
+
"""
|
|
133
|
+
return self.support_
|
|
134
|
+
|
|
135
|
+
@staticmethod
|
|
136
|
+
def _if_sub_interval(interval1: Tuple[float, float], interval2: Tuple[float, float]):
|
|
137
|
+
"""
|
|
138
|
+
Check if interval2 is fully contained within interval1.
|
|
139
|
+
|
|
140
|
+
Parameters
|
|
141
|
+
----------
|
|
142
|
+
interval1 : tuple of float
|
|
143
|
+
Parent interval (left, right).
|
|
144
|
+
interval2 : tuple of float
|
|
145
|
+
Candidate sub-interval (left, right).
|
|
146
|
+
|
|
147
|
+
Returns
|
|
148
|
+
-------
|
|
149
|
+
bool
|
|
150
|
+
True if interval2 is contained within interval1, False otherwise.
|
|
151
|
+
"""
|
|
152
|
+
return (interval1[0] <= interval2[0]) and (interval1[1] >= interval2[1])
|
|
153
|
+
|
|
154
|
+
@staticmethod
|
|
155
|
+
def _extract_disjoint_intervals(intervals: List[Tuple[float, float]]):
|
|
156
|
+
"""
|
|
157
|
+
Convert overlapping intervals into a sorted array of disjoint intervals.
|
|
158
|
+
|
|
159
|
+
Parameters
|
|
160
|
+
----------
|
|
161
|
+
intervals : list of tuple of float
|
|
162
|
+
List of input intervals (left, right).
|
|
163
|
+
|
|
164
|
+
Returns
|
|
165
|
+
-------
|
|
166
|
+
np.ndarray, shape (n_disjoint, 2)
|
|
167
|
+
Array of disjoint intervals covering the same range as the input.
|
|
168
|
+
"""
|
|
169
|
+
assert len(intervals) > 0, "At least one interval should be provided"
|
|
170
|
+
assert all(interval[0] <= interval[1] for interval in intervals)
|
|
171
|
+
lefts, rights = zip(*intervals)
|
|
172
|
+
sort_endpoints = sorted([(left, "L") for left in lefts] + [(right, "R") for right in rights])
|
|
173
|
+
disjoint_intervals = []
|
|
174
|
+
for (ep, next_ep) in zip(sort_endpoints[:-1], sort_endpoints[1:]):
|
|
175
|
+
if ep[1] == "L" and next_ep[1] == "R":
|
|
176
|
+
disjoint_intervals.append((ep[0], next_ep[0]))
|
|
177
|
+
return np.array(disjoint_intervals)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import numpy as np
|
|
2
|
+
from warnings import warn
|
|
2
3
|
from typing import List, Union, Dict, Tuple
|
|
3
4
|
from scipy.optimize import LinearConstraint, minimize
|
|
4
5
|
from scipy.stats._distn_infrastructure import rv_frozen
|
|
@@ -294,7 +295,13 @@ class GLTGridSearchEstimator(GLTWeightEstimator):
|
|
|
294
295
|
|
|
295
296
|
class GLTWeightDistribEstimator(GLTWeightEstimator):
|
|
296
297
|
"""
|
|
297
|
-
Estimator of weights and vertex threshold distributions under the GLT diffusion model
|
|
298
|
+
Estimator of weights and vertex threshold distributions under the GLT diffusion model.
|
|
299
|
+
This estimator alternates estimation of the GLT weights and estimation of the vertex threshold CDF
|
|
300
|
+
using the Turnbull estimator. For the Turnbull estimator, see:
|
|
301
|
+
|
|
302
|
+
Turnbull, Bruce W. (1976).
|
|
303
|
+
“The Empirical Distribution Function with Arbitrarily Grouped, Censored and Truncated Data.”
|
|
304
|
+
Journal of the Royal Statistical Society. Series B (Methodological) 38(3), 290–295.
|
|
298
305
|
"""
|
|
299
306
|
|
|
300
307
|
def __init__(self, graph: Graph,
|
|
@@ -303,17 +310,37 @@ class GLTWeightDistribEstimator(GLTWeightEstimator):
|
|
|
303
310
|
|
|
304
311
|
"""Initialize the GLTWeightDistribEstimator.
|
|
305
312
|
|
|
313
|
+
|
|
306
314
|
Parameters
|
|
307
315
|
----------
|
|
308
316
|
graph : Graph
|
|
309
317
|
The graph structure.
|
|
318
|
+
threshold_support : Tuple[float, float]
|
|
319
|
+
Support for the vertex threshold distributions.
|
|
310
320
|
n_jobs : int, optional
|
|
311
321
|
Number of jobs for parallel processing.
|
|
312
322
|
"""
|
|
313
323
|
super().__init__(graph=graph, vertex_2_distrib=None, n_jobs=n_jobs)
|
|
324
|
+
warn("This estimator is currently unstable and can only estimate CDF accurately for high indeg vertices!")
|
|
314
325
|
self.threshold_support = threshold_support
|
|
315
326
|
|
|
316
327
|
def _construct_vertex_threshold_observed_intervals(self, vertex: int, parent_weights: np.array):
|
|
328
|
+
"""
|
|
329
|
+
Construct the observed intervals for a vertex's threshold based on parent activations.
|
|
330
|
+
|
|
331
|
+
Parameters
|
|
332
|
+
----------
|
|
333
|
+
vertex : int
|
|
334
|
+
The vertex for which to construct threshold intervals.
|
|
335
|
+
parent_weights : np.ndarray
|
|
336
|
+
Current weights of the parent vertices.
|
|
337
|
+
|
|
338
|
+
Returns
|
|
339
|
+
-------
|
|
340
|
+
List[Tuple[float, float]]
|
|
341
|
+
List of intervals containing the lower and upper bounds for the vertex threshold
|
|
342
|
+
based on observed activations.
|
|
343
|
+
"""
|
|
317
344
|
intervals = []
|
|
318
345
|
for mask_tm1, mask_t in zip(self._vertex_2_active_parent_mask_tm1[vertex],
|
|
319
346
|
self._vertex_2_active_parent_mask_t[vertex]):
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import numpy as np
|
|
2
2
|
import matplotlib.pyplot as plt
|
|
3
3
|
|
|
4
|
-
|
|
5
4
|
__all__ = ["plot_with_conf_intervals", "plot_hist_with_normal_fit"]
|
|
6
5
|
|
|
7
6
|
|
|
@@ -13,22 +12,31 @@ def plot_with_conf_intervals(x_true, x_pred, conf_intervals=None,
|
|
|
13
12
|
Plot a scatter plot of `x_true` vs `x_pred` with confidence intervals as a filled area
|
|
14
13
|
and a diagonal line y=x.
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
15
|
+
Parameters
|
|
16
|
+
----------
|
|
17
|
+
x_true : array-like
|
|
18
|
+
True values.
|
|
19
|
+
x_pred : array-like
|
|
20
|
+
Predicted values.
|
|
21
|
+
conf_intervals : array-like, shape (2, len(x_pred)), optional
|
|
22
|
+
Lower and upper bounds of the confidence intervals. If None, no intervals are plotted.
|
|
23
|
+
fontsize : int, default 12
|
|
24
|
+
Font size for axis labels.
|
|
25
|
+
figsize : tuple, default (10, 8)
|
|
26
|
+
Figure size in inches (width, height).
|
|
27
|
+
color : str or tuple, default "blue"
|
|
28
|
+
Color of the scatter points and confidence interval area.
|
|
29
|
+
ax : matplotlib.axes.Axes, optional
|
|
30
|
+
Existing axes to plot on. If None, a new figure and axes are created.
|
|
31
|
+
xlab : str, default "True activation probability"
|
|
32
|
+
Label for the x-axis.
|
|
33
|
+
ylab : str, default "Predicted activation probability"
|
|
34
|
+
Label for the y-axis.
|
|
28
35
|
"""
|
|
29
36
|
assert len(x_pred) == len(x_true), "x_pred and x_true must have the same length"
|
|
30
|
-
|
|
31
|
-
|
|
37
|
+
if conf_intervals is not None:
|
|
38
|
+
assert conf_intervals.shape[1] == len(x_pred), "conf_intervals must have same second dim as x_pred"
|
|
39
|
+
assert conf_intervals.shape[0] == 2, "conf_intervals must have two rows for lower and upper bounds"
|
|
32
40
|
|
|
33
41
|
# Sort by x_true so fill_between works correctly
|
|
34
42
|
sort_idx = np.argsort(x_true)
|
|
@@ -62,10 +70,16 @@ def plot_hist_with_normal_fit(sample, true_value, true_std=None, n_bins=20):
|
|
|
62
70
|
"""
|
|
63
71
|
Plot a histogram of a sample with a fitted normal curve and a vertical line at the true value.
|
|
64
72
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
73
|
+
Parameters
|
|
74
|
+
----------
|
|
75
|
+
sample : array-like
|
|
76
|
+
Sample data points.
|
|
77
|
+
true_value : float
|
|
78
|
+
The true value.
|
|
79
|
+
true_std : float, optional
|
|
80
|
+
The true standard deviation, used to plot the theoretical normal curve.
|
|
81
|
+
n_bins : int, default 20
|
|
82
|
+
Number of bins for the histogram.
|
|
69
83
|
"""
|
|
70
84
|
from scipy.stats import norm
|
|
71
85
|
|
|
@@ -80,15 +94,15 @@ def plot_hist_with_normal_fit(sample, true_value, true_std=None, n_bins=20):
|
|
|
80
94
|
p_fit = norm.pdf(x, loc=mean, scale=std)
|
|
81
95
|
plt.plot(x, p_fit, 'b', linewidth=2, label="Fitted Gaussian")
|
|
82
96
|
|
|
83
|
-
#
|
|
97
|
+
# Plot the theoretical normal curve
|
|
84
98
|
if true_std is not None:
|
|
85
99
|
p = norm.pdf(x, loc=true_value, scale=true_std)
|
|
86
100
|
plt.plot(x, p, 'r', linewidth=2, label="Theoretical Gaussian")
|
|
87
101
|
|
|
88
|
-
# Plot
|
|
102
|
+
# Plot vertical line at the true value
|
|
89
103
|
plt.axvline(true_value, color='black', linestyle='--', linewidth=1.5, label="True value")
|
|
90
104
|
|
|
91
|
-
#
|
|
105
|
+
# Labels and legend
|
|
92
106
|
plt.xlabel('Value')
|
|
93
107
|
plt.ylabel('Density')
|
|
94
108
|
plt.legend()
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import numpy as np
|
|
2
2
|
from typing import Iterable, Set
|
|
3
|
-
from scipy.stats._distn_infrastructure import rv_frozen
|
|
4
|
-
import jax.numpy as jnp
|
|
5
3
|
|
|
6
4
|
|
|
7
5
|
def multiple_union(set_list: Iterable[Set]):
|
|
@@ -29,15 +27,3 @@ def random_vector_inside_simplex(dim: int, ub: float = 1.):
|
|
|
29
27
|
def random_vector_on_simplex(dim: int, ub: float = 1.):
|
|
30
28
|
X = random_vector_inside_simplex(dim=dim, ub=1)
|
|
31
29
|
return X / np.sum(X) * ub
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def make_jax_cdf(distrib: rv_frozen):
|
|
35
|
-
name = distrib.dist.name
|
|
36
|
-
args = distrib.args
|
|
37
|
-
kwargs = distrib.kwds
|
|
38
|
-
local_dic = {}
|
|
39
|
-
exec(f"jax_distrib=jax.scipy.stats.{name}", None, local_dic)
|
|
40
|
-
jax_distrib = local_dic["jax_distrib"]
|
|
41
|
-
if name == "expon":
|
|
42
|
-
return lambda x: 1. - jnp.exp(-x)
|
|
43
|
-
return lambda x: jax_distrib.cdf(x, *args, **kwargs)
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
from typing import List, Tuple, Any
|
|
2
|
-
from scipy.stats._distn_infrastructure import rv_continuous
|
|
3
|
-
from scipy.interpolate import interp1d
|
|
4
|
-
import numpy as np
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class CensoredCDFEstimator(rv_continuous):
|
|
8
|
-
def __init__(self, support: Tuple[float, float] = (-np.inf, np.inf),
|
|
9
|
-
momtype=1,
|
|
10
|
-
a=None,
|
|
11
|
-
b=None,
|
|
12
|
-
xtol=1e-14,
|
|
13
|
-
badvalue=None,
|
|
14
|
-
name=None,
|
|
15
|
-
longname=None,
|
|
16
|
-
shapes=None,
|
|
17
|
-
extradoc=None,
|
|
18
|
-
seed=None):
|
|
19
|
-
|
|
20
|
-
super().__init__(momtype=momtype, a=a, b=b, xtol=xtol, badvalue=badvalue,
|
|
21
|
-
name=name, longname=longname, shapes=shapes, seed=seed)
|
|
22
|
-
self.support_ = support
|
|
23
|
-
|
|
24
|
-
def fit(self, intervals: List[Tuple[float, float]],
|
|
25
|
-
max_iter=50, tol=1e-4, verbose=False, verbose_interval=1):
|
|
26
|
-
|
|
27
|
-
self.qp_ints_ = self._extract_disjoint_intervals(intervals)
|
|
28
|
-
|
|
29
|
-
alphas = np.fromfunction(
|
|
30
|
-
np.vectorize(lambda i, j: self._if_sub_interval(intervals[i], self.qp_ints_[j])),
|
|
31
|
-
shape=(len(intervals), len(self.qp_ints_)), dtype=int)
|
|
32
|
-
|
|
33
|
-
self.qp_probs_ = np.ones(len(self.qp_ints_)) / len(self.qp_ints_)
|
|
34
|
-
|
|
35
|
-
for iteration in range(max_iter):
|
|
36
|
-
cur_probs = self.qp_probs_.copy()
|
|
37
|
-
ms = (alphas * cur_probs) / (alphas @ cur_probs).reshape(-1, 1)
|
|
38
|
-
self.qp_probs_ = ms.sum(0) / ms.sum()
|
|
39
|
-
diff = np.linalg.norm(cur_probs - self.qp_probs_)
|
|
40
|
-
if verbose and iteration % verbose_interval == 0:
|
|
41
|
-
print(f"Iteration: {iteration}, Probs diff l2-norm: {round(diff, int(2 - np.log10(tol)))}")
|
|
42
|
-
if diff < tol:
|
|
43
|
-
break
|
|
44
|
-
|
|
45
|
-
if len(self.qp_ints_[:, 0]) >= 2:
|
|
46
|
-
self._cdf_interpolator = interp1d(self.qp_ints_[:, 0], np.cumsum(self.qp_probs_),
|
|
47
|
-
bounds_error=False, fill_value=(0.0, 1.0))
|
|
48
|
-
else:
|
|
49
|
-
self._cdf_interpolator = lambda x: np.clip(x, 0, 1)
|
|
50
|
-
|
|
51
|
-
return self
|
|
52
|
-
|
|
53
|
-
def _cdf(self, x: Any, *args, **kwargs):
|
|
54
|
-
return self._cdf_interpolator(x)
|
|
55
|
-
|
|
56
|
-
def support(self):
|
|
57
|
-
return self.support_
|
|
58
|
-
|
|
59
|
-
@staticmethod
|
|
60
|
-
def _if_sub_interval(interval1: Tuple[float, float], interval2: Tuple[float, float]):
|
|
61
|
-
return (interval1[0] <= interval2[0]) and (interval1[1] >= interval2[1])
|
|
62
|
-
|
|
63
|
-
@staticmethod
|
|
64
|
-
def _extract_disjoint_intervals(intervals: List[Tuple[float, float]]):
|
|
65
|
-
assert len(intervals) > 0, "At least one interval should be provided"
|
|
66
|
-
assert all(interval[0] <= interval[1] for interval in intervals)
|
|
67
|
-
lefts, rights = zip(*intervals)
|
|
68
|
-
sort_endpoints = sorted([(left, "L") for left in lefts] + [(right, "R") for right in rights])
|
|
69
|
-
disjoint_intervals = []
|
|
70
|
-
for (ep, next_ep) in zip(sort_endpoints[:-1], sort_endpoints[1:]):
|
|
71
|
-
if ep[1] == "L" and next_ep[1] == "R":
|
|
72
|
-
disjoint_intervals.append((ep[0], next_ep[0]))
|
|
73
|
-
return np.array(disjoint_intervals)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{influencediffusion-0.0.15 → influencediffusion-0.0.17}/InfluenceDiffusion/influence_models.py
RENAMED
|
File without changes
|
{influencediffusion-0.0.15 → influencediffusion-0.0.17}/InfluenceDiffusion/weight_samplers.py
RENAMED
|
File without changes
|
{influencediffusion-0.0.15 → influencediffusion-0.0.17}/InfluenceDiffusion.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{influencediffusion-0.0.15 → influencediffusion-0.0.17}/InfluenceDiffusion.egg-info/requires.txt
RENAMED
|
File without changes
|
{influencediffusion-0.0.15 → influencediffusion-0.0.17}/InfluenceDiffusion.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|