| # 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 |