max-div 0.0.3__py3-none-any.whl → 0.1.1__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.
- max_div/_cli.py +99 -0
- max_div/benchmark/__init__.py +2 -1
- max_div/benchmark/_formatting.py +218 -0
- max_div/benchmark/randint.py +104 -0
- max_div/benchmark/randint_constrained.py +355 -0
- max_div/constraints/__init__.py +2 -0
- max_div/constraints/_numba.py +110 -0
- max_div/constraints/constraint.py +10 -0
- max_div/constraints/constraints.py +47 -0
- max_div/internal/benchmarking/_micro_benchmark.py +48 -7
- max_div/internal/formatting/__init__.py +1 -0
- max_div/internal/formatting/_markdown.py +43 -0
- max_div/internal/math/__init__.py +1 -0
- max_div/internal/math/fast_log.py +167 -0
- max_div/internal/math/random.py +166 -0
- max_div/internal/math/select_k_minmax.py +250 -0
- max_div/sampling/__init__.py +1 -1
- max_div/sampling/con.py +350 -0
- max_div/sampling/uncon.py +269 -0
- {max_div-0.0.3.dist-info → max_div-0.1.1.dist-info}/METADATA +13 -8
- max_div-0.1.1.dist-info/RECORD +32 -0
- max_div-0.1.1.dist-info/entry_points.txt +2 -0
- max_div/benchmark/sample_int.py +0 -85
- max_div/internal/compat/__init__.py +0 -1
- max_div/internal/compat/_numba/__init__.py +0 -14
- max_div/internal/compat/_numba/_dummy_numba.py +0 -94
- max_div/internal/compat/_numba/_helpers.py +0 -14
- max_div/sampling/discrete.py +0 -176
- max_div-0.0.3.dist-info/RECORD +0 -23
- max_div-0.0.3.dist-info/entry_points.txt +0 -2
- {max_div-0.0.3.dist-info → max_div-0.1.1.dist-info}/WHEEL +0 -0
- {max_div-0.0.3.dist-info → max_div-0.1.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
max_div/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
max_div/_cli.py,sha256=WMGA-kw3hi3un6MCngjxbQ_WUMVvKxKtz02n2ydqWU0,3276
|
|
3
|
+
max_div/benchmark/__init__.py,sha256=9lru2A83WlZCYeM6Ppy0XWN9K4dzb6twpCqpo8CQA3I,102
|
|
4
|
+
max_div/benchmark/_formatting.py,sha256=zFUMU0Nz6HHngvDqgo7vzi6v5LtVWrXvk2P9PdAKIgM,8991
|
|
5
|
+
max_div/benchmark/randint.py,sha256=-SMK59LVXCZIxDbuEFmtsxAXU-zGeVyP2KyDXxTCJ0Y,3502
|
|
6
|
+
max_div/benchmark/randint_constrained.py,sha256=SF5XaCiOEnvpkqlbjWBJtJmYXzjJF7oRIgUFJt3dS4o,12477
|
|
7
|
+
max_div/constraints/__init__.py,sha256=K2CnAb9llDxNu8qtGEAx4vZ8SLWVqs5zXfhbXzkGBog,72
|
|
8
|
+
max_div/constraints/_numba.py,sha256=VyQqmsF8Kcfay73dRVnGmOPcWrpsXL-yqhd6mH71uAw,4485
|
|
9
|
+
max_div/constraints/constraint.py,sha256=MK2kbexHCrxYkYMT_n76KVzwC9gARIyF3nMdjk01UAk,246
|
|
10
|
+
max_div/constraints/constraints.py,sha256=ARn7v8tu1ESx66KcXyGpfKyqM0SNAxHk0T4V48OEboI,1675
|
|
11
|
+
max_div/internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
+
max_div/internal/benchmarking/__init__.py,sha256=WNjrLlGI_vkI-nZkQMPICgi67rTVole_MCc4jNe_OxI,83
|
|
13
|
+
max_div/internal/benchmarking/_micro_benchmark.py,sha256=cZGkx3ngZSJDRAAF5TP56bEkEvNpfAAg1-1tuiGeBPQ,5992
|
|
14
|
+
max_div/internal/benchmarking/_timer.py,sha256=gpA3KgreDTtK2QUARJKI4Ir9dTDMKW7B5GQuThRbYh8,1050
|
|
15
|
+
max_div/internal/formatting/__init__.py,sha256=3TzBpe_KfCY_3ETvOoRIl_qAtfgjT1b-8o3iYpVK9ZE,182
|
|
16
|
+
max_div/internal/formatting/_markdown.py,sha256=Nf0fSDSmmJF2pYbnLoG23-1_d1S8RLYCWSYrNghTgO8,1441
|
|
17
|
+
max_div/internal/formatting/_time_duration.py,sha256=dO88GPZeMbxVk0YF9Zr2Y0NLCXaiW_HwTa7S-PT9e9E,6740
|
|
18
|
+
max_div/internal/math/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
19
|
+
max_div/internal/math/fast_log.py,sha256=e3rGXdEqBJN_v1DGNniE5CtPfF7zzTzr9sfeda_V73A,5609
|
|
20
|
+
max_div/internal/math/random.py,sha256=XnNnCxkFitdl6nBmCi7gI_6VGNhOabqXXYIm1EU2kRY,6548
|
|
21
|
+
max_div/internal/math/select_k_minmax.py,sha256=q2z6uLYAwfcAox4RzFyZwa4jJ9CoiPK50mCrEMEKEhY,10112
|
|
22
|
+
max_div/internal/utils/__init__.py,sha256=Xqb7Rh9Lq6WsUK-5B9aouwWMhAh0c1a7pF0rdaP5kgo,62
|
|
23
|
+
max_div/internal/utils/_clip.py,sha256=kWUCKG9uFxNvFWvThMyFdWLlzVb9cFADngpBYl5b38U,230
|
|
24
|
+
max_div/internal/utils/_precision.py,sha256=3eEUdJQmXA3Q6Tg4jb3vG0RTwOBNgnc09j5ts0gcIdw,125
|
|
25
|
+
max_div/sampling/__init__.py,sha256=HNmw64ps3rXURPYuXvVUcePT6aKi5PJWXu_Ex7yavRg,57
|
|
26
|
+
max_div/sampling/con.py,sha256=bgkeRagZ2Epv2sSajqqvdhmIec6Dn2EI4osHwYIZRS4,13856
|
|
27
|
+
max_div/sampling/uncon.py,sha256=jmrLIvqr7FcPaST5uBgXtFVj_ZDiJYuPbkY-_i1BtIU,13219
|
|
28
|
+
max_div-0.1.1.dist-info/METADATA,sha256=NG3ccEDS75fPE80bfHZNCFl0dkG1bxYfZOsslwibgQM,1884
|
|
29
|
+
max_div-0.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
30
|
+
max_div-0.1.1.dist-info/entry_points.txt,sha256=Q-xCOAOZ6vSRodScs7U1cF_S6IM_1GCRdD4JTeWzYKc,45
|
|
31
|
+
max_div-0.1.1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
32
|
+
max_div-0.1.1.dist-info/RECORD,,
|
max_div/benchmark/sample_int.py
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import math
|
|
2
|
-
|
|
3
|
-
import numpy as np
|
|
4
|
-
|
|
5
|
-
from max_div.internal.benchmarking import BenchmarkResult, benchmark
|
|
6
|
-
from max_div.internal.compat import is_numba_installed
|
|
7
|
-
from max_div.sampling.discrete import sample_int
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def benchmark_sample_int(turbo: bool = False) -> None:
|
|
11
|
-
"""
|
|
12
|
-
Benchmarks the `sample_int` function from `max_div.sampling.discrete`.
|
|
13
|
-
|
|
14
|
-
Different scenarios are tested:
|
|
15
|
-
|
|
16
|
-
* with & without replacement
|
|
17
|
-
* uniform & non-uniform sampling
|
|
18
|
-
* `use_numba` True and False
|
|
19
|
-
* different sizes of (`n`, `k`):
|
|
20
|
-
* (10, 1), (100, 1), (1000, 1), (5000, 1), (10000, 1)
|
|
21
|
-
* (10000, 10), (10000, 100), (10000, 1000), (10000, 5000), (10000, 10000)
|
|
22
|
-
|
|
23
|
-
:param turbo: If `True`, a much shorter (but less reliable) benchmark is run; intended for testing purposes.
|
|
24
|
-
"""
|
|
25
|
-
|
|
26
|
-
if not is_numba_installed():
|
|
27
|
-
print("====================================================================================")
|
|
28
|
-
print(" WARNING: Numba is not installed!!!")
|
|
29
|
-
print("====================================================================================")
|
|
30
|
-
|
|
31
|
-
print("Benchmarking `sample_int`...")
|
|
32
|
-
print()
|
|
33
|
-
print("".ljust(30) + "use_numba=False".rjust(25) + "use_numba=True".rjust(25))
|
|
34
|
-
|
|
35
|
-
for replace, use_p, desc in [
|
|
36
|
-
(True, False, "with replacement, uniform"),
|
|
37
|
-
(False, False, "without replacement, uniform"),
|
|
38
|
-
(True, True, "with replacement, non-uniform"),
|
|
39
|
-
(False, True, "without replacement, non-uniform"),
|
|
40
|
-
]:
|
|
41
|
-
print(desc.upper())
|
|
42
|
-
|
|
43
|
-
for n, k in [
|
|
44
|
-
(10, 1),
|
|
45
|
-
(100, 1),
|
|
46
|
-
(1000, 1),
|
|
47
|
-
(5000, 1),
|
|
48
|
-
(10000, 1),
|
|
49
|
-
(10000, 10),
|
|
50
|
-
(10000, 100),
|
|
51
|
-
(10000, 1000),
|
|
52
|
-
(10000, 5000),
|
|
53
|
-
(10000, 10000),
|
|
54
|
-
]:
|
|
55
|
-
size_str = f"{k:<6_} out of {n:<6_}"
|
|
56
|
-
|
|
57
|
-
results: list[BenchmarkResult] = []
|
|
58
|
-
for use_numba in [False, True]:
|
|
59
|
-
if use_p:
|
|
60
|
-
p = np.random.rand(n)
|
|
61
|
-
p /= p.sum()
|
|
62
|
-
else:
|
|
63
|
-
p = None
|
|
64
|
-
|
|
65
|
-
def func_to_benchmark():
|
|
66
|
-
sample_int(n=n, k=k, replace=replace, p=p, use_numba=use_numba)
|
|
67
|
-
|
|
68
|
-
results.append(
|
|
69
|
-
benchmark(
|
|
70
|
-
f=func_to_benchmark,
|
|
71
|
-
t_per_run=0.001 if turbo else 0.1,
|
|
72
|
-
n_warmup=3 if turbo else 10,
|
|
73
|
-
n_benchmark=3 if turbo else 30,
|
|
74
|
-
silent=True,
|
|
75
|
-
)
|
|
76
|
-
)
|
|
77
|
-
|
|
78
|
-
print(
|
|
79
|
-
(" " * 4)
|
|
80
|
-
+ size_str.ljust(26)
|
|
81
|
-
+ results[0].t_sec_with_uncertainty_str.rjust(25)
|
|
82
|
-
+ results[1].t_sec_with_uncertainty_str.rjust(25)
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
print()
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
from ._numba import is_numba_installed, numba
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# =================================================================================================
|
|
2
|
-
# Transparant handling of original numba vs dummy numba
|
|
3
|
-
# =================================================================================================
|
|
4
|
-
try:
|
|
5
|
-
import numba
|
|
6
|
-
except ImportError:
|
|
7
|
-
from ._dummy_numba import Numba as numba
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
# =================================================================================================
|
|
11
|
-
# Helpers
|
|
12
|
-
# =================================================================================================
|
|
13
|
-
def is_numba_installed() -> bool:
|
|
14
|
-
return numba.__version__ != "0.0.0"
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Implements a dummy version of Numba for environments where Numba is not available.
|
|
3
|
-
Main goal is that code that uses @numba.njit or numba.tuped.Dict, ... does not break and transparently falls back to standard Python.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
from ._helpers import dummy_decorator
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
# =================================================================================================
|
|
10
|
-
# Dummy typed containers
|
|
11
|
-
# =================================================================================================
|
|
12
|
-
class NumbaTypedDict(dict):
|
|
13
|
-
@staticmethod
|
|
14
|
-
def empty(*args, **kwargs):
|
|
15
|
-
return dict()
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class NumbaTypedList(list):
|
|
19
|
-
@staticmethod
|
|
20
|
-
def empty_list(*args, **kwargs):
|
|
21
|
-
return list()
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
# =================================================================================================
|
|
25
|
-
# Main dummy package tree
|
|
26
|
-
# =================================================================================================
|
|
27
|
-
class NumbaTyped:
|
|
28
|
-
# implements subset
|
|
29
|
-
Dict = NumbaTypedDict
|
|
30
|
-
List = NumbaTypedList
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class NumbaTypes:
|
|
34
|
-
# implements dummies for all members of numba.types.__all__
|
|
35
|
-
int8 = object()
|
|
36
|
-
int16 = object()
|
|
37
|
-
int32 = object()
|
|
38
|
-
int64 = object()
|
|
39
|
-
uint8 = object()
|
|
40
|
-
uint16 = object()
|
|
41
|
-
uint32 = object()
|
|
42
|
-
uint64 = object()
|
|
43
|
-
intp = object()
|
|
44
|
-
uintp = object()
|
|
45
|
-
intc = object()
|
|
46
|
-
uintc = object()
|
|
47
|
-
ssize_t = object()
|
|
48
|
-
size_t = object()
|
|
49
|
-
boolean = object()
|
|
50
|
-
float32 = object()
|
|
51
|
-
float64 = object()
|
|
52
|
-
complex64 = object()
|
|
53
|
-
complex128 = object()
|
|
54
|
-
bool_ = object()
|
|
55
|
-
byte = object()
|
|
56
|
-
char = object()
|
|
57
|
-
uchar = object()
|
|
58
|
-
short = object()
|
|
59
|
-
ushort = object()
|
|
60
|
-
int_ = object()
|
|
61
|
-
uint = object()
|
|
62
|
-
long_ = object()
|
|
63
|
-
ulong = object()
|
|
64
|
-
longlong = object()
|
|
65
|
-
ulonglong = object()
|
|
66
|
-
double = object()
|
|
67
|
-
void = object()
|
|
68
|
-
none = object()
|
|
69
|
-
b1 = object()
|
|
70
|
-
i1 = object()
|
|
71
|
-
i2 = object()
|
|
72
|
-
i4 = object()
|
|
73
|
-
i8 = object()
|
|
74
|
-
u1 = object()
|
|
75
|
-
u2 = object()
|
|
76
|
-
u4 = object()
|
|
77
|
-
u8 = object()
|
|
78
|
-
f4 = object()
|
|
79
|
-
f8 = object()
|
|
80
|
-
c8 = object()
|
|
81
|
-
c16 = object()
|
|
82
|
-
optional = object()
|
|
83
|
-
ffi_forced_object = object()
|
|
84
|
-
ffi = object()
|
|
85
|
-
deferred_type = object()
|
|
86
|
-
bool = object()
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
class Numba:
|
|
90
|
-
__version__ = "0.0.0"
|
|
91
|
-
jit = dummy_decorator
|
|
92
|
-
njit = dummy_decorator
|
|
93
|
-
typed = NumbaTyped
|
|
94
|
-
types = NumbaTypes
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
from typing import Callable
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
def dummy_decorator(*args, **kwargs):
|
|
5
|
-
# dummy decorator that does nothing and can be used with or without arguments
|
|
6
|
-
if len(args) == 1 and isinstance(args[0], Callable):
|
|
7
|
-
# decorator used without arguments
|
|
8
|
-
return args[0]
|
|
9
|
-
else:
|
|
10
|
-
# decorator used with arguments
|
|
11
|
-
def decorator(func):
|
|
12
|
-
return func
|
|
13
|
-
|
|
14
|
-
return decorator
|
max_div/sampling/discrete.py
DELETED
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
|
|
3
|
-
from max_div.internal.compat import numba
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
# =================================================================================================
|
|
7
|
-
# sample_int
|
|
8
|
-
# =================================================================================================
|
|
9
|
-
def sample_int(
|
|
10
|
-
n: int,
|
|
11
|
-
k: int | None = None,
|
|
12
|
-
replace: bool = True,
|
|
13
|
-
p: np.ndarray[float] | None = None,
|
|
14
|
-
seed: int | None = None,
|
|
15
|
-
use_numba: bool = True,
|
|
16
|
-
) -> int | np.ndarray[np.int64]:
|
|
17
|
-
"""
|
|
18
|
-
Randomly sample `k` integers from range `[0, n-1]`, optionally with replacement and per-value probabilities.
|
|
19
|
-
|
|
20
|
-
Different implementation is used, depending on the case:
|
|
21
|
-
|
|
22
|
-
| `use_numba` | `p` specified | `replace` | `k` | Method Used | Complexity |
|
|
23
|
-
|----------------|----------------|------------|------|------------------------------------------|-----------------|
|
|
24
|
-
| No | Any | Any | Any | `np.random.choice` | depends |
|
|
25
|
-
| Yes | No | True | Any | `np.random.randint`, uniform sampling | O(k) |
|
|
26
|
-
| Yes | No | False | Any | k-element Fisher-Yates shuffle | O(n) |
|
|
27
|
-
| Yes | Yes | Any | 1 | Multinomial sampling using CDF | O(n + log(n)) |
|
|
28
|
-
| Yes | Yes | True | >1 | Multinomial sampling using CDF | O(n + k log(n)) |
|
|
29
|
-
| Yes | Yes | False | >1 | Efraimidis-Spirakis sampling + exponential key sampling (Gumbel-Max Trick) using the Ziggurat algorithm. | O(n) |
|
|
30
|
-
|
|
31
|
-
:param n: defines population to sample from as range [0, n-1]. `n` must be >0.
|
|
32
|
-
:param k: The number of integers to sample (>0). `k=None` indicates a single integer sample.
|
|
33
|
-
:param replace: Whether to sample with replacement.
|
|
34
|
-
:param p: Optional 1D array of probabilities associated with each integer in the range.
|
|
35
|
-
Size must be equal to max_value + 1 and sum to 1.
|
|
36
|
-
:param seed: Optional random seed for reproducibility.
|
|
37
|
-
:param use_numba: Use the self-implemented algorithm (which is `numba`-accelerated if `numba` is installed)
|
|
38
|
-
:return: `k=None` --> single integer; `k>=1` --> (k,)-sized array with sampled integers.
|
|
39
|
-
"""
|
|
40
|
-
|
|
41
|
-
# -------------------------------------------------------------------------
|
|
42
|
-
# Don't try using numba
|
|
43
|
-
# -------------------------------------------------------------------------
|
|
44
|
-
if not use_numba:
|
|
45
|
-
# --- argument handling ---------------------------
|
|
46
|
-
if (k == 1) or (k is None):
|
|
47
|
-
replace = True # single sample, replacement makes no difference, so we can fall back to faster methods
|
|
48
|
-
|
|
49
|
-
# --- argument validation -------------------------
|
|
50
|
-
if n < 1:
|
|
51
|
-
raise ValueError(f"n must be >=1. (here: {n})")
|
|
52
|
-
if k is not None:
|
|
53
|
-
if k < 1:
|
|
54
|
-
raise ValueError(f"k must be >=1. (here: {k})")
|
|
55
|
-
if (not replace) and (k > n):
|
|
56
|
-
raise ValueError(f"Cannot sample {k} unique values from range [0, {n}) without replacement.")
|
|
57
|
-
|
|
58
|
-
# --- sampling ------------------------------------
|
|
59
|
-
if seed is not None:
|
|
60
|
-
np.random.seed(seed)
|
|
61
|
-
|
|
62
|
-
if k is None:
|
|
63
|
-
# returns scalar
|
|
64
|
-
return np.random.choice(n, size=None, replace=replace, p=p)
|
|
65
|
-
else:
|
|
66
|
-
# returns array
|
|
67
|
-
return np.random.choice(n, size=k, replace=replace, p=p)
|
|
68
|
-
|
|
69
|
-
# -------------------------------------------------------------------------
|
|
70
|
-
# Try using numba
|
|
71
|
-
# -------------------------------------------------------------------------
|
|
72
|
-
else:
|
|
73
|
-
# --- argument handling ---------------------------
|
|
74
|
-
k_orig = k # remember, to know what return value we need
|
|
75
|
-
if (k == 1) or (k is None):
|
|
76
|
-
k = 1 # make sure we always have an integer for the numba function
|
|
77
|
-
replace = True # single sample, replacement makes no difference, so we can fall back to faster methods
|
|
78
|
-
if p is None:
|
|
79
|
-
use_p = False
|
|
80
|
-
p = np.zeros(0, dtype=np.float64) # dummy value
|
|
81
|
-
else:
|
|
82
|
-
use_p = True
|
|
83
|
-
if seed is None:
|
|
84
|
-
use_seed = False
|
|
85
|
-
seed = 42 # dummy value
|
|
86
|
-
else:
|
|
87
|
-
use_seed = True
|
|
88
|
-
|
|
89
|
-
# --- argument validation -------------------------
|
|
90
|
-
if n < 1:
|
|
91
|
-
raise ValueError(f"n must be >=1. (here: {n})")
|
|
92
|
-
if k < 1:
|
|
93
|
-
raise ValueError(f"k must be >=1. (here: {k})")
|
|
94
|
-
if (not replace) and (k > n):
|
|
95
|
-
raise ValueError(f"Cannot sample {k} unique values from range [0, {n}) without replacement.")
|
|
96
|
-
if use_p:
|
|
97
|
-
if (p.ndim != 1) or (p.size != n):
|
|
98
|
-
raise ValueError(f"p must be a 1D array of size {n}. (here: shape={p.shape})")
|
|
99
|
-
|
|
100
|
-
# --- call numba function -------------------------
|
|
101
|
-
samples = sample_int_numba(n=n, k=k, replace=replace, use_p=use_p, p=p, use_seed=use_seed, seed=seed)
|
|
102
|
-
if k_orig is None:
|
|
103
|
-
return samples[0]
|
|
104
|
-
else:
|
|
105
|
-
return samples
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
@numba.njit
|
|
109
|
-
def sample_int_numba(
|
|
110
|
-
n: int,
|
|
111
|
-
k: int,
|
|
112
|
-
replace: bool,
|
|
113
|
-
use_p: bool = False,
|
|
114
|
-
p: np.ndarray[float] = np.zeros(0),
|
|
115
|
-
use_seed: bool = False,
|
|
116
|
-
seed: int = 42,
|
|
117
|
-
) -> np.ndarray[int]:
|
|
118
|
-
"""
|
|
119
|
-
See native python version docstring. We split the implementation into a core numba-decorated function and
|
|
120
|
-
a Python front-end, because numba-decorated functions do not allow for multiple possible return types.
|
|
121
|
-
"""
|
|
122
|
-
if use_seed:
|
|
123
|
-
np.random.seed(seed)
|
|
124
|
-
|
|
125
|
-
if (k == n) and (not replace):
|
|
126
|
-
# corner case: return all elements in random order
|
|
127
|
-
population = np.arange(n, dtype=np.int64)
|
|
128
|
-
np.random.shuffle(population)
|
|
129
|
-
return population
|
|
130
|
-
|
|
131
|
-
if not use_p:
|
|
132
|
-
if replace:
|
|
133
|
-
# UNIFORM sampling with replacement
|
|
134
|
-
return np.random.choice(n, size=k) # O(k)
|
|
135
|
-
else:
|
|
136
|
-
# UNIFORM sampling without replacement using Fisher-Yates shuffle
|
|
137
|
-
population = np.arange(n, dtype=np.int64) # O(n)
|
|
138
|
-
for i in range(k): # k x O(1)
|
|
139
|
-
j = np.random.randint(i, n)
|
|
140
|
-
population[i], population[j] = population[j], population[i]
|
|
141
|
-
return population[:k] # O(k)
|
|
142
|
-
else:
|
|
143
|
-
if replace:
|
|
144
|
-
# NON-UNIFORM sampling with replacement using CDF
|
|
145
|
-
cdf = np.empty(n) # O(n)
|
|
146
|
-
csum = 0.0
|
|
147
|
-
for i in range(n): # n x O(1)
|
|
148
|
-
csum += p[i]
|
|
149
|
-
cdf[i] = csum
|
|
150
|
-
samples = np.empty(k, dtype=np.int64) # O(k)
|
|
151
|
-
for i in range(k): # k x O(log(n))
|
|
152
|
-
r = np.random.random()
|
|
153
|
-
idx = np.searchsorted(cdf, r)
|
|
154
|
-
samples[i] = idx
|
|
155
|
-
return samples
|
|
156
|
-
else:
|
|
157
|
-
# NON-UNIFORM sampling without replacement using Efraimidis-Spirakis + Exponential keys
|
|
158
|
-
# algorithm description:
|
|
159
|
-
# Efraimidis: select k elements corresponding to k largest values of u_i^{1/p_i} (u_i ~ U(0,1))
|
|
160
|
-
# Gumbel-Max Trick: select k smallest values of -log(u_i)/p_i (u_i ~ U(0,1))
|
|
161
|
-
# Ziggurat: (TODO) generate log(u_i) more efficiently, applying the Ziggurat algorithm
|
|
162
|
-
# to the exponential distribution, which avoids usage of transcendental
|
|
163
|
-
# functions for the majority of the samples.
|
|
164
|
-
keys = np.empty(n, dtype=np.float64) # O(n)
|
|
165
|
-
u = np.random.random(n) # O(n)
|
|
166
|
-
for i in range(n): # n x O(1)
|
|
167
|
-
if p[i] == 0.0:
|
|
168
|
-
keys[i] = np.inf
|
|
169
|
-
else:
|
|
170
|
-
keys[i] = -np.log(u[i]) / p[i]
|
|
171
|
-
|
|
172
|
-
# Get indices of k smallest keys
|
|
173
|
-
if k > 1:
|
|
174
|
-
return np.argpartition(keys, k)[:k] # O(n) average case
|
|
175
|
-
else:
|
|
176
|
-
return np.array([np.argmin(keys)]) # O(n)
|
max_div-0.0.3.dist-info/RECORD
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
max_div/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
max_div/benchmark/__init__.py,sha256=wzyPThNW4GETpkPh5yXDKTkQbJQ1ulungL2jQL8Ak2s,45
|
|
3
|
-
max_div/benchmark/sample_int.py,sha256=mueD3v0tqP0zTN9Gf1LjnvrCEm0fV3zlgcE-Eh3V0vQ,2817
|
|
4
|
-
max_div/internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
-
max_div/internal/benchmarking/__init__.py,sha256=WNjrLlGI_vkI-nZkQMPICgi67rTVole_MCc4jNe_OxI,83
|
|
6
|
-
max_div/internal/benchmarking/_micro_benchmark.py,sha256=hvQxmKG72MnG9dANrLbYm8D7NsJP-2pGapl5idX_E7I,4183
|
|
7
|
-
max_div/internal/benchmarking/_timer.py,sha256=gpA3KgreDTtK2QUARJKI4Ir9dTDMKW7B5GQuThRbYh8,1050
|
|
8
|
-
max_div/internal/compat/__init__.py,sha256=ApHeMuO_9zlP34BnSZMRVLVyEEv1VEkGXNJzw5ddaK4,46
|
|
9
|
-
max_div/internal/compat/_numba/__init__.py,sha256=fKwHEiafrYMmk_GOaOKZBb3rDU9q0sYqzi3BPPtV0A4,631
|
|
10
|
-
max_div/internal/compat/_numba/_dummy_numba.py,sha256=FPguZfpQzpWRxmc4pYSGVCoPzgofsgQO_bknF_bK8aQ,2341
|
|
11
|
-
max_div/internal/compat/_numba/_helpers.py,sha256=pQqAjHYbSwPos9011xpmbkJeZ5cPBUZq14qh8G6GtjQ,402
|
|
12
|
-
max_div/internal/formatting/__init__.py,sha256=UMim6fo_e4JGJo7pl8FZ1nNpmStlfbGB7O49LhCZwWo,104
|
|
13
|
-
max_div/internal/formatting/_time_duration.py,sha256=dO88GPZeMbxVk0YF9Zr2Y0NLCXaiW_HwTa7S-PT9e9E,6740
|
|
14
|
-
max_div/internal/utils/__init__.py,sha256=Xqb7Rh9Lq6WsUK-5B9aouwWMhAh0c1a7pF0rdaP5kgo,62
|
|
15
|
-
max_div/internal/utils/_clip.py,sha256=kWUCKG9uFxNvFWvThMyFdWLlzVb9cFADngpBYl5b38U,230
|
|
16
|
-
max_div/internal/utils/_precision.py,sha256=3eEUdJQmXA3Q6Tg4jb3vG0RTwOBNgnc09j5ts0gcIdw,125
|
|
17
|
-
max_div/sampling/__init__.py,sha256=_tsDiQNr4brsMiROQVbJFpq7Um79HV7P0ec6ChMd_iY,33
|
|
18
|
-
max_div/sampling/discrete.py,sha256=VYBpeYYIUbLeuA3Ld4PTBkVwq6ziIBW0KlkJVqmqNuU,8048
|
|
19
|
-
max_div-0.0.3.dist-info/METADATA,sha256=PwZtrIAsZRKs5bCVw_SzDOQpfPtCVOcDxHTvuBRrLAM,1604
|
|
20
|
-
max_div-0.0.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
21
|
-
max_div-0.0.3.dist-info/entry_points.txt,sha256=EL6VQ4tIThMRtNqBtQvj2yAMBJm-7OM801VYPBsRwp4,80
|
|
22
|
-
max_div-0.0.3.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
23
|
-
max_div-0.0.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|