|
| 1 | +#!/usr/bin/env python |
| 2 | +# |
| 3 | +# This script is intended to benchmark fancy indexiing with respect to |
| 4 | +# for loops. |
| 5 | +# |
| 6 | +# It takes the following commannd line arguments: |
| 7 | +# * --n: the numer of rows/columns in the matrix |
| 8 | +# * --r: the number of repetitions |
| 9 | +# * --algo: the algorithm(s) to use (either 'iterative' or 'fancy', or both) |
| 10 | +# This option can be specified multiple times, once for each of |
| 11 | +# the algorithms to use. |
| 12 | +# For each repetition, the algorithm is timed to microsecond precision. |
| 13 | +# For each repetition, the following values are printed to standard output: |
| 14 | +# * the name of the algorithm |
| 15 | +# * the number of rows/columns in the matrix |
| 16 | +# * the number of the repetition |
| 17 | +# * the time it took to run the algorithm, in microseconds. |
| 18 | +# When all repetitions are done, the following values are printed to standard |
| 19 | +# output: |
| 20 | +# * the name of the algorithm |
| 21 | +# * the number of rows/columns in the matrix |
| 22 | +# * the number of repetitions |
| 23 | +# * the average time it took to run the algorithm, in microseconds. |
| 24 | +# * the standard deviation of the time it took to run the algorithm, in |
| 25 | +# microseconds. |
| 26 | +# * the factor by which the value for the algorithm is slower than the |
| 27 | +# fastest algorithm. |
| 28 | +# |
| 29 | +# ----------------------------------------------------------------------------- |
| 30 | + |
| 31 | +import argparse |
| 32 | +from collections import defaultdict |
| 33 | +import numpy as np |
| 34 | +import timeit |
| 35 | + |
| 36 | + |
| 37 | +def setup(n): |
| 38 | + A = np.random.uniform(-1.0, 1.0, size=(n, n)) |
| 39 | + B = np.random.uniform(-1.0, 1.0, size=A.shape) |
| 40 | + return A, B |
| 41 | + |
| 42 | +def flip_signs_iterative(A, B): |
| 43 | + for i in range(A.shape[0]): |
| 44 | + for j in range(A.shape[1]): |
| 45 | + if B[i, j] > 0.5: |
| 46 | + A[i, j] *= -A[i, j] |
| 47 | + |
| 48 | +def flip_signs_fancy(A, B): |
| 49 | + A[B > 0.5] *= -A[B > 0.5] |
| 50 | + |
| 51 | +def main(): |
| 52 | + parser = argparse.ArgumentParser() |
| 53 | + parser.add_argument('--n', type=int, default=100, |
| 54 | + help='number of rows/columns in the matrix (default: 100') |
| 55 | + parser.add_argument('--r', type=int, default=1, |
| 56 | + help='number of repetitions (default: 1') |
| 57 | + parser.add_argument('--algo', action='append', default=[], |
| 58 | + choices=['iterative', 'fancy'], |
| 59 | + help='algorithm(s) to use (default: none)') |
| 60 | + args = parser.parse_args() |
| 61 | + |
| 62 | + algorithms_lib = { |
| 63 | + 'iterative': flip_signs_iterative, |
| 64 | + 'fancy': flip_signs_fancy, |
| 65 | + } |
| 66 | + algorithms = [algorithms_lib[algo] for algo in args.algo] |
| 67 | + |
| 68 | + timings = defaultdict(list) |
| 69 | + print('algorithm,n,repetition,time') |
| 70 | + for i in range(1, args.r + 1): |
| 71 | + for algo in algorithms: |
| 72 | + A, B = setup(args.n) |
| 73 | + timings[algo].append(timeit.timeit(lambda: algo(A, B), number=1)) |
| 74 | + print(f'{algo.__name__},{args.n},{i},{timings[algo][-1]:.6f}') |
| 75 | + print('summary:') |
| 76 | + min_time = min([np.mean(timings[algo]) for algo in algorithms]) |
| 77 | + print(' algorithm,n,repetitions,mean,std,relative') |
| 78 | + for algo in algorithms: |
| 79 | + print(f' {algo.__name__},{args.n},{args.r},{np.mean(timings[algo]):.6f},{np.std(timings[algo]):.6f},{np.mean(timings[algo]) / min_time:.2f}') |
| 80 | + |
| 81 | +if __name__ == '__main__': |
| 82 | + main() |
0 commit comments