Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/bottleneck/benchmark/bench_detailed.py: 12%
67 statements
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-23 06:06 +0000
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-23 06:06 +0000
1import numpy as np
2import bottleneck as bn
3from .autotimeit import autotimeit
5__all__ = ["bench_detailed"]
8def bench_detailed(function="nansum", fraction_nan=0.0):
9 """
10 Benchmark a single function in detail or, optionally, all functions.
12 Parameters
13 ----------
14 function : str, optional
15 Name of function, as a string, to benchmark. Default ('nansum') is
16 to benchmark bn.nansum. If `function` is 'all' then detailed
17 benchmarks are run on all bottleneck functions.
18 fraction_nan : float, optional
19 Fraction of array elements that should, on average, be NaN. The
20 default (0.0) is not to set any elements to NaN.
22 Returns
23 -------
24 A benchmark report is printed to stdout.
26 """
28 if function == "all":
29 # benchmark all bottleneck functions
30 funcs = bn.get_functions("all", as_string=True)
31 funcs.sort()
32 for func in funcs:
33 bench_detailed(func, fraction_nan)
35 if fraction_nan < 0 or fraction_nan > 1:
36 raise ValueError("`fraction_nan` must be between 0 and 1, inclusive")
38 tab = " "
40 # Header
41 print("%s benchmark" % function)
42 print("%sBottleneck %s; Numpy %s" % (tab, bn.__version__, np.__version__))
43 print("%sSpeed is NumPy time divided by Bottleneck time" % tab)
44 if fraction_nan == 0:
45 print("%sNone of the array elements are NaN" % tab)
46 else:
47 print(
48 "%s%.1f%% of the array elements are NaN (on average)"
49 % (tab, fraction_nan * 100)
50 )
51 print("")
53 print(" Speed Call Array")
54 suite = benchsuite(function, fraction_nan)
55 for test in suite:
56 name = test["name"]
57 speed = timer(test["statements"], test["setup"], test["repeat"])
58 print("%8.1f %s %s" % (speed, name[0].ljust(27), name[1]))
61def timer(statements, setup, repeat):
62 if len(statements) != 2:
63 raise ValueError("Two statements needed.")
64 with np.errstate(invalid="ignore"):
65 t0 = autotimeit(statements[0], setup, repeat=repeat)
66 t1 = autotimeit(statements[1], setup, repeat=repeat)
67 speed = t1 / t0
68 return speed
71def benchsuite(function, fraction_nan):
73 # setup is called before each run of each function
74 setup = """
75 from bottleneck import %s as bn_fn
76 try: from numpy import %s as sl_fn
77 except ImportError: from bottleneck.slow import %s as sl_fn
79 # avoid all-nan slice warnings from np.median and np.nanmedian
80 if "%s" == "median": from bottleneck.slow import median as sl_fn
81 if "%s" == "nanmedian": from bottleneck.slow import nanmedian as sl_fn
83 from numpy import array, nan
84 from numpy.random import RandomState
85 rand = RandomState(123).rand
87 a = %s
88 if %s != 0: a[a < %s] = nan
89 """
90 setup = "\n".join([s.strip() for s in setup.split("\n")])
92 # what kind of function signature do we need to use?
93 if function in bn.get_functions("reduce", as_string=True):
94 index = 0
95 elif function in ["rankdata", "nanrankdata"]:
96 index = 0
97 elif function in bn.get_functions("move", as_string=True):
98 index = 1
99 elif function in ["partition", "argpartition", "push"]:
100 index = 2
101 elif function == "replace":
102 index = 3
103 else:
104 raise ValueError("`function` (%s) not recognized" % function)
106 # create benchmark suite
107 instructions = get_instructions()
108 f = function
109 suite = []
110 for instruction in instructions:
111 signature = instruction[index + 1]
112 if signature is None:
113 continue
114 array = instruction[0]
115 repeat = instruction[-1]
116 run = {}
117 run["name"] = [f + signature, array]
118 run["statements"] = ["bn_fn" + signature, "sl_fn" + signature]
119 run["setup"] = setup % (f, f, f, f, f, array, fraction_nan, fraction_nan)
120 run["repeat"] = repeat
121 suite.append(run)
123 return suite
126def get_instructions():
128 instructions = [
129 # 1d input array
130 (
131 "rand(1)",
132 "(a)", # reduce + (nan)rankdata
133 "(a, 1)", # move
134 "(a, 0)", # (arg)partition
135 "(a, np.nan, 0)", # replace
136 10,
137 ),
138 ("rand(10)", "(a)", "(a, 2)", "(a, 2)", "(a, np.nan, 0)", 10),
139 ("rand(100)", "(a)", "(a, 20)", "(a, 20)", "(a, np.nan, 0)", 6),
140 ("rand(1000)", "(a)", "(a, 200)", "(a, 200)", "(a, np.nan, 0)", 3),
141 ("rand(1000000)", "(a)", "(a, 200)", "(a, 200)", "(a, np.nan, 0)", 2),
142 # 2d input array
143 ("rand(10, 10)", "(a)", "(a, 2)", "(a, 2)", "(a, np.nan, 0)", 6),
144 ("rand(100, 100)", "(a)", "(a, 20)", "(a, 20)", "(a, np.nan, 0)", 3),
145 ("rand(1000, 1000)", "(a)", "(a, 200)", "(a, 200)", "(a, np.nan, 0)", 2),
146 ("rand(10, 10)", "(a, 1)", None, None, None, 6),
147 ("rand(100, 100)", "(a, 1)", None, None, None, 3),
148 ("rand(1000, 1000)", "(a, 1)", None, None, None, 2),
149 ("rand(100000, 2)", "(a, 1)", "(a, 1)", "(a, 1)", None, 2),
150 ("rand(10, 10)", "(a, 0)", None, None, None, 6),
151 ("rand(100, 100)", "(a, 0)", "(a, 20, axis=0)", None, None, 3),
152 ("rand(1000, 1000)", "(a, 0)", "(a, 200, axis=0)", None, None, 2),
153 # 3d input array
154 (
155 "rand(100, 100, 100)",
156 "(a, 0)",
157 "(a, 20, axis=0)",
158 "(a, 20, axis=0)",
159 None,
160 2,
161 ),
162 (
163 "rand(100, 100, 100)",
164 "(a, 1)",
165 "(a, 20, axis=1)",
166 "(a, 20, axis=1)",
167 None,
168 2,
169 ),
170 (
171 "rand(100, 100, 100)",
172 "(a, 2)",
173 "(a, 20, axis=2)",
174 "(a, 20, axis=2)",
175 "(a, np.nan, 0)",
176 2,
177 ),
178 # 0d input array
179 ("array(1.0)", "(a)", None, None, "(a, 0, 2)", 10),
180 ]
182 return instructions