| 1 | #!/usr/bin/env python3 |
| 2 | # Desc: Pauses a random amount of time. Random distribution is inverse gaussian. |
| 3 | # Version: 0.0.4 |
| 4 | # Depends: python 3.7.3 |
| 5 | # Usage: ./sleepRand.py [-v] [-p L] SECONDS |
| 6 | # Input: SECONDS: float seconds (mean of inverse gaussian distribution) |
| 7 | # L: precision (lambda of inverse gaussian distribution) |
| 8 | # Example: python3 sleepRand.py -vv -p 8.0 60.0 |
| 9 | |
| 10 | import argparse; |
| 11 | import math, time, random, sys; |
| 12 | import logging; |
| 13 | |
| 14 | # Set up argument parser (see https://docs.python.org/3.7/library/argparse.html ) |
| 15 | parser = argparse.ArgumentParser( |
| 16 | description='Delay activity for a random number of seconds. Delays sampled from an inverse gaussian distribution.', |
| 17 | epilog="Author: Steven Baltakatei Sandoval. License: GPLv3+"); |
| 18 | parser.add_argument('-v','--verbose', |
| 19 | action='count', |
| 20 | dest='verbosity', |
| 21 | default=0, |
| 22 | help='Verbose output. (repeat for increased verbosity)'); |
| 23 | parser.add_argument('mean', |
| 24 | action='store', |
| 25 | metavar='SECONDS', |
| 26 | nargs=1, |
| 27 | default=1, |
| 28 | type=float, |
| 29 | help='Mean seconds of delay. Is the mean of the inverse gaussian distribution.'); |
| 30 | parser.add_argument('--precision','-p', |
| 31 | action='store', |
| 32 | metavar='P', |
| 33 | nargs=1, |
| 34 | default=[4.0], |
| 35 | type=float, |
| 36 | help='How concentrated delays are around the mean (default: 4.0). Must be a positive integer or floating point value. Is the lambda factor in the inverse gaussian distribution. High values (e.g. > 10.0) cause random delays to rarely stray far from MEAN. Small values (e.g. < 0.10) result in many small delays plus occasional long delays.'); |
| 37 | args = parser.parse_args(); |
| 38 | |
| 39 | # Define functions |
| 40 | def setup_logging(verbosity): |
| 41 | # Depends: module: argparse |
| 42 | # Ref/Attrib: Haas, Florian; Configure logging with argparse; https://xahteiwi.eu/resources/hints-and-kinks/python-cli-logging-options/ |
| 43 | base_loglevel = 30; |
| 44 | verbosity = min(verbosity, 2); |
| 45 | loglevel = base_loglevel - (verbosity * 10); |
| 46 | logging.basicConfig(level=loglevel, |
| 47 | format='%(message)s'); |
| 48 | |
| 49 | def randInvGau(mu, lam): |
| 50 | """Returns random variate of inverse gaussian distribution""" |
| 51 | # input: mu: mean of inverse gaussian distribution |
| 52 | # lam: shape parameter |
| 53 | # output: float sampled from inv. gaus. with range 0 to infinity, mean mu |
| 54 | # example: sample = float(randInvGau(1.0,4.0)); |
| 55 | # Ref/Attrib: Michael, John R. "Generating Random Variates Using Transformations with Multiple Roots" https://doi.org/10.2307/2683801 |
| 56 | nu = random.gauss(0,1); |
| 57 | y = nu ** 2; |
| 58 | xTerm1 = mu; |
| 59 | xTerm2 = mu ** 2 * y / (2 * lam); |
| 60 | xTerm3 = (- mu / (2 * lam)) * math.sqrt(4 * mu * lam * y + mu ** 2 * y ** 2); |
| 61 | x = xTerm1 + xTerm2 + xTerm3; |
| 62 | z = random.uniform(0.0,1.0); |
| 63 | if z <= (mu / (mu + x)): |
| 64 | return x; |
| 65 | else: |
| 66 | return (mu ** 2 / x); |
| 67 | |
| 68 | # Process input |
| 69 | ## Start up logger |
| 70 | setup_logging(args.verbosity); |
| 71 | logging.debug('DEBUG:Debug logging output enabled.'); |
| 72 | logging.debug('DEBUG:args.verbosity:' + str(args.verbosity)); |
| 73 | logging.debug('DEBUG:args:' + str(args)); |
| 74 | ## Reject negative floats. |
| 75 | try: |
| 76 | ### Get desired mean |
| 77 | desMean = args.mean[0]; |
| 78 | logging.debug('DEBUG:Desired mean:' + str(desMean)); |
| 79 | ### Get lambda precision factor |
| 80 | lambdaFactor = args.precision[0]; |
| 81 | logging.debug('DEBUG:Lambda precision factor:' + str(lambdaFactor)); |
| 82 | if desMean < 0: |
| 83 | logging.error('ERROR:Desired mean is negative:' + str(desMean)); |
| 84 | raise ValueError('Negative number error.'); |
| 85 | if lambdaFactor < 0: |
| 86 | logging.error('ERROR:Lambda precision factor is negative:' + str(lambdaFactor)); |
| 87 | raise ValueError('Negative number error.'); |
| 88 | except ValueError: |
| 89 | sys.exit(1); |
| 90 | |
| 91 | # Calculate delay |
| 92 | delay = randInvGau(desMean, desMean * lambdaFactor); |
| 93 | logging.debug('delay:' + str(delay)); |
| 94 | |
| 95 | # Sleep |
| 96 | time.sleep(float(delay)); |
| 97 | |
| 98 | # Author: Steven Baltakatei Sandoal |
| 99 | # License: GPLv3+ |