1# Copyright 2016 The Chromium Authors 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import copy 6import functools 7import math 8import random 9 10 11def RandomLowInteger(low, high, beta=31.0): 12 """Like random.randint, but heavily skewed toward the low end""" 13 assert low <= high 14 return low + int(math.floor(random.betavariate(1.0, beta) * (high - low))) 15 16 17def UniformExpoInteger(low, high, base=2): 18 """Returns base to a power uniformly distributed between low and high. 19 20 This is useful for exploring large ranges of integers while ensuring that 21 values of all different sizes are represented. 22 """ 23 return int(math.floor(math.pow(base, random.uniform(low, high)))) 24 25 26def WeightedChoice(choices): # pylint: disable=inconsistent-return-statements 27 """Chooses an item given a sequence of (choice, weight) tuples""" 28 total = sum(w for c, w in choices) 29 r = random.uniform(0, total) 30 upto = 0 31 for c, w in choices: 32 upto += w 33 if upto >= r: 34 return c 35 assert False 36 37 38def Pipeline(*funcs): 39 """Given a number of single-argument functions, returns a single-argument 40 function which computes their composition. Each of the functions are applied 41 to the input in order from left to right, with the result of each function 42 passed as the argument to the next function.""" 43 return reduce(lambda f, g: lambda x: g(f(x)), funcs) 44 45 46def DeepMemoize(obj): 47 """A memoizing decorator that returns deep copies of the function results.""" 48 cache = obj.cache = {} 49 @functools.wraps(obj) 50 def Memoize(*args): 51 if args not in cache: 52 cache[args] = copy.deepcopy(obj(*args)) 53 return copy.deepcopy(cache[args]) 54 return Memoize 55