GitLab Repo

amachine.am_random

 1import numpy as np
 2import random
 3import math
 4
 5_rng = np.random.default_rng()
 6
 7def srand_global(seed: int):
 8    global _rng
 9    _rng = np.random.default_rng(seed)
10    np.random.seed(seed)
11    random.seed(seed)
12
13def resolve_rng(np_rng):
14    global _rng
15    return _rng if np_rng is None else np_rng
16
17def exp_uniform_blend(n: int, alpha: float, np_rng=None ) -> list[float]:
18    global _rng
19    rng = resolve_rng(np_rng)
20    exp_probs = np.exp(-np.arange(n))
21    exp_probs /= exp_probs.sum()
22    uniform = np.ones(n) / n
23    probs = ( (1 - alpha) * exp_probs + alpha * uniform)
24    return rng.permutation( probs ).tolist()
25
26def unique_random_combinations(
27    bin_sizes,
28    n_samples: int,
29    np_rng : np.random.Generator | None = None,
30) -> list[np.ndarray]:
31
32    np_rng = resolve_rng( np_rng )
33
34    sizes = tuple(map(int, bin_sizes))
35    total = math.prod(sizes)
36
37    if n_samples > total:
38        raise ValueError(
39            f"Cannot draw {n_samples} unique samples: "
40            f"only {total} combinations exist."
41        )
42
43    if total < 2**27:
44        flat = np_rng.choice( range( 1, total ), size=n_samples, replace=False )
45        return np.stack(np.unravel_index(flat, shape=sizes), axis=1).tolist()
46
47    else:
48        seen: set[tuple] = {tuple(0 for _ in sizes)}
49        rows: list[tuple] = []
50        while len(rows) < n_samples:
51            combo = tuple(int(np_rng.integers(0, s)) for s in sizes)
52            if combo not in seen:
53                seen.add(combo)
54                rows.append(combo)
55
56        return np.array(rows, dtype=np.intp).tolist()
57
58def unique_random_permutations(
59    bin_sizes,
60    n_samples: int,
61    np_rng: np.random.Generator | None = None,
62) -> list[dict[int, dict[int, int]]]:
63
64    np_rng = resolve_rng( np_rng )
65    bin_sizes = [int(s) for s in bin_sizes]
66    factorial_sizes = [math.factorial(s) for s in bin_sizes]
67
68    lehmer_combinations = unique_random_combinations(
69        bin_sizes=factorial_sizes,
70        n_samples=n_samples,
71        np_rng=np_rng,
72    )
73
74    def lehmer_decode(size: int, idx: int) -> dict[int, int]:
75        remaining = list(range(size))
76        result = []
77        for i in range(size, 0, -1):
78            f = math.factorial(i - 1)
79            k = idx // f
80            idx %= f
81            result.append(remaining.pop(k))
82        return dict(enumerate(result))
83
84    return [
85        {c: lehmer_decode(bin_sizes[c], codes[c]) for c in range(len(bin_sizes))}
86        for codes in lehmer_combinations
87    ]
def srand_global(seed: int):
 8def srand_global(seed: int):
 9    global _rng
10    _rng = np.random.default_rng(seed)
11    np.random.seed(seed)
12    random.seed(seed)
def resolve_rng(np_rng):
14def resolve_rng(np_rng):
15    global _rng
16    return _rng if np_rng is None else np_rng
def exp_uniform_blend(n: int, alpha: float, np_rng=None) -> list[float]:
18def exp_uniform_blend(n: int, alpha: float, np_rng=None ) -> list[float]:
19    global _rng
20    rng = resolve_rng(np_rng)
21    exp_probs = np.exp(-np.arange(n))
22    exp_probs /= exp_probs.sum()
23    uniform = np.ones(n) / n
24    probs = ( (1 - alpha) * exp_probs + alpha * uniform)
25    return rng.permutation( probs ).tolist()
def unique_random_combinations( bin_sizes, n_samples: int, np_rng: numpy.random._generator.Generator | None = None) -> list[numpy.ndarray]:
27def unique_random_combinations(
28    bin_sizes,
29    n_samples: int,
30    np_rng : np.random.Generator | None = None,
31) -> list[np.ndarray]:
32
33    np_rng = resolve_rng( np_rng )
34
35    sizes = tuple(map(int, bin_sizes))
36    total = math.prod(sizes)
37
38    if n_samples > total:
39        raise ValueError(
40            f"Cannot draw {n_samples} unique samples: "
41            f"only {total} combinations exist."
42        )
43
44    if total < 2**27:
45        flat = np_rng.choice( range( 1, total ), size=n_samples, replace=False )
46        return np.stack(np.unravel_index(flat, shape=sizes), axis=1).tolist()
47
48    else:
49        seen: set[tuple] = {tuple(0 for _ in sizes)}
50        rows: list[tuple] = []
51        while len(rows) < n_samples:
52            combo = tuple(int(np_rng.integers(0, s)) for s in sizes)
53            if combo not in seen:
54                seen.add(combo)
55                rows.append(combo)
56
57        return np.array(rows, dtype=np.intp).tolist()
def unique_random_permutations( bin_sizes, n_samples: int, np_rng: numpy.random._generator.Generator | None = None) -> list[dict[int, dict[int, int]]]:
59def unique_random_permutations(
60    bin_sizes,
61    n_samples: int,
62    np_rng: np.random.Generator | None = None,
63) -> list[dict[int, dict[int, int]]]:
64
65    np_rng = resolve_rng( np_rng )
66    bin_sizes = [int(s) for s in bin_sizes]
67    factorial_sizes = [math.factorial(s) for s in bin_sizes]
68
69    lehmer_combinations = unique_random_combinations(
70        bin_sizes=factorial_sizes,
71        n_samples=n_samples,
72        np_rng=np_rng,
73    )
74
75    def lehmer_decode(size: int, idx: int) -> dict[int, int]:
76        remaining = list(range(size))
77        result = []
78        for i in range(size, 0, -1):
79            f = math.factorial(i - 1)
80            k = idx // f
81            idx %= f
82            result.append(remaining.pop(k))
83        return dict(enumerate(result))
84
85    return [
86        {c: lehmer_decode(bin_sizes[c], codes[c]) for c in range(len(bin_sizes))}
87        for codes in lehmer_combinations
88    ]