|  | # Copyright 2016 The Chromium Authors. All rights reserved. | 
|  | # Use of this source code is governed by a BSD-style license that can be | 
|  | # found in the LICENSE file. | 
|  |  | 
|  | import copy | 
|  | import functools | 
|  | import math | 
|  | import random | 
|  |  | 
|  |  | 
|  | def RandomLowInteger(low, high, beta=31.0): | 
|  | """Like random.randint, but heavily skewed toward the low end""" | 
|  | assert low <= high | 
|  | return low + int(math.floor(random.betavariate(1.0, beta) * (high - low))) | 
|  |  | 
|  |  | 
|  | def UniformExpoInteger(low, high, base=2): | 
|  | """Returns base to a power uniformly distributed between low and high. | 
|  |  | 
|  | This is useful for exploring large ranges of integers while ensuring that | 
|  | values of all different sizes are represented. | 
|  | """ | 
|  | return int(math.floor(math.pow(base, random.uniform(low, high)))) | 
|  |  | 
|  |  | 
|  | def WeightedChoice(choices): | 
|  | """Chooses an item given a sequence of (choice, weight) tuples""" | 
|  | total = sum(w for c, w in choices) | 
|  | r = random.uniform(0, total) | 
|  | upto = 0 | 
|  | for c, w in choices: | 
|  | upto += w | 
|  | if upto >= r: | 
|  | return c | 
|  | assert False | 
|  |  | 
|  |  | 
|  | def Pipeline(*funcs): | 
|  | """Given a number of single-argument functions, returns a single-argument | 
|  | function which computes their composition. Each of the functions are applied | 
|  | to the input in order from left to right, with the result of each function | 
|  | passed as the argument to the next function.""" | 
|  | return reduce(lambda f, g: lambda x: g(f(x)), funcs) | 
|  |  | 
|  |  | 
|  | def DeepMemoize(obj): | 
|  | """A memoizing decorator that returns deep copies of the function results.""" | 
|  | cache = obj.cache = {} | 
|  | @functools.wraps(obj) | 
|  | def Memoize(*args): | 
|  | if args not in cache: | 
|  | cache[args] = copy.deepcopy(obj(*args)) | 
|  | return copy.deepcopy(cache[args]) | 
|  | return Memoize |