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):
def
resolve_rng(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 ]