Commit | Line | Data |
---|---|---|
a5a89c7f SBS |
1 | #!/usr/bin/env python3 |
2 | # Desc: Pauses a random amount of time. Random distribution is inverse gaussian. | |
3 | # Version: 0.0.6 | |
4 | # Depends: python 3.7.3 | |
5 | # Usage: ./sleepRand.py [-v] [-p P] SECONDS | |
6 | # Input: SECONDS: float seconds (mean of inverse gaussian distribution) | |
7 | # P: 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 | parser.add_argument('--upper','-u', | |
38 | action='store', | |
39 | metavar='U', | |
40 | nargs=1, | |
41 | default=[None], | |
42 | type=float, | |
43 | help='Upper bound for possible delays (default: no bound). Without bound, extremely high delays are unlikely but possible.'); | |
44 | args = parser.parse_args(); | |
45 | ||
46 | # Define functions | |
47 | def setup_logging(verbosity): | |
48 | '''Sets up logging''' | |
49 | # Depends: module: argparse | |
50 | # Ref/Attrib: Haas, Florian; Configure logging with argparse; https://xahteiwi.eu/resources/hints-and-kinks/python-cli-logging-options/ | |
51 | base_loglevel = 30; | |
52 | verbosity = min(verbosity, 2); | |
53 | loglevel = base_loglevel - (verbosity * 10); | |
54 | logging.basicConfig(level=loglevel, | |
55 | format='%(message)s'); | |
56 | ||
57 | def randInvGau(mu, lam): | |
58 | """Returns random variate of inverse gaussian distribution""" | |
59 | # input: mu: mean of inverse gaussian distribution | |
60 | # lam: shape parameter | |
61 | # output: float sampled from inv. gaus. with range 0 to infinity, mean mu | |
62 | # example: sample = float(randInvGau(1.0,4.0)); | |
63 | # Ref/Attrib: Michael, John R. "Generating Random Variates Using Transformations with Multiple Roots" https://doi.org/10.2307/2683801 | |
64 | nu = random.gauss(0,1); | |
65 | y = nu ** 2; | |
66 | xTerm1 = mu; | |
67 | xTerm2 = mu ** 2 * y / (2 * lam); | |
68 | xTerm3 = (- mu / (2 * lam)) * math.sqrt(4 * mu * lam * y + mu ** 2 * y ** 2); | |
69 | x = xTerm1 + xTerm2 + xTerm3; | |
70 | z = random.uniform(0.0,1.0); | |
71 | if z <= (mu / (mu + x)): | |
72 | return x; | |
73 | else: | |
74 | return (mu ** 2 / x); | |
75 | ||
76 | # Process input | |
77 | ## Start up logger | |
78 | setup_logging(args.verbosity); | |
79 | logging.debug('DEBUG:Debug logging output enabled.'); | |
80 | logging.debug('DEBUG:args.verbosity:' + str(args.verbosity)); | |
81 | logging.debug('DEBUG:args:' + str(args)); | |
82 | ||
83 | ## Receive input arguments | |
84 | try: | |
85 | ### Get desired mean | |
86 | desMean = args.mean[0]; | |
87 | logging.debug('DEBUG:Desired mean:' + str(desMean)); | |
88 | ||
89 | ### Get lambda precision factor | |
90 | lambdaFactor = args.precision[0]; | |
91 | logging.debug('DEBUG:Lambda precision factor:' + str(lambdaFactor)); | |
92 | ||
93 | ### Get upper bound | |
94 | if isinstance(args.upper[0], float): | |
95 | logging.debug('DEBUG:args.upper[0] is float:' + str(args.upper[0])); | |
96 | upperBound = args.upper[0]; | |
97 | elif args.upper[0] is None: | |
98 | logging.debug('DEBUG:args.upper[0] is None:' + str(args.upper[0])); | |
99 | upperBound = None; | |
100 | else: | |
101 | raise TypeError('Upper bound not set correctly.'); | |
102 | logging.debug('DEBUG:Upper bound:' + str(upperBound)); | |
103 | ||
104 | ### Reject negative floats. | |
105 | if desMean < 0: | |
106 | logging.error('ERROR:Desired mean is negative:' + str(desMean)); | |
107 | raise ValueError('Negative number error.'); | |
108 | if lambdaFactor < 0: | |
109 | logging.error('ERROR:Lambda precision factor is negative:' + str(lambdaFactor)); | |
110 | raise ValueError('Negative number error.'); | |
111 | except ValueError: | |
112 | sys.exit(1); | |
113 | ||
114 | # Calculate delay | |
115 | rawDelay = randInvGau(desMean, desMean * lambdaFactor); | |
116 | logging.debug('DEBUG:rawDelay(seconds):' + str(rawDelay)); | |
117 | if isinstance(upperBound,float): | |
118 | delay = min(upperBound, rawDelay); | |
119 | elif upperBound is None: | |
120 | delay = rawDelay; | |
121 | logging.debug('DEBUG:delay(seconds) :' + str(delay)); | |
122 | ||
123 | # Sleep | |
124 | time.sleep(float(delay)); | |
125 | ||
126 | # Author: Steven Baltakatei Sandoal | |
127 | # License: GPLv3+ |