1"""Benchmarks for `numpy.lib`."""
2
3
4from .common import Benchmark
5
6import numpy as np
7
8
9class Pad(Benchmark):
10    """Benchmarks for `numpy.pad`.
11
12    When benchmarking the pad function it is useful to cover scenarios where
13    the ratio between the size of the input array and the output array differs
14    significantly (original area vs. padded area). This allows to evaluate for
15    which scenario a padding algorithm is optimized. Furthermore involving
16    large range of array sizes ensures that the effects of CPU-bound caching is
17    visible.
18
19    The table below shows the sizes of the arrays involved in this benchmark:
20
21    +-----------------+----------+-----------+-----------+-----------------+
22    | shape           | original | padded: 1 | padded: 8 | padded: (0, 32) |
23    +=================+==========+===========+===========+=================+
24    | (2 ** 22,)      | 32 MiB   | 32.0 MiB  | 32.0 MiB  | 32.0 MiB        |
25    +-----------------+----------+-----------+-----------+-----------------+
26    | (1024, 1024)    | 8 MiB    | 8.03 MiB  | 8.25 MiB  | 8.51 MiB        |
27    +-----------------+----------+-----------+-----------+-----------------+
28    | (256, 256, 1)   | 256 KiB  | 786 KiB   | 5.08 MiB  | 11.6 MiB        |
29    +-----------------+----------+-----------+-----------+-----------------+
30    | (4, 4, 4, 4)    | 2 KiB    | 10.1 KiB  | 1.22 MiB  | 12.8 MiB        |
31    +-----------------+----------+-----------+-----------+-----------------+
32    | (1, 1, 1, 1, 1) | 8 B      | 1.90 MiB  | 10.8 MiB  | 299 MiB         |
33    +-----------------+----------+-----------+-----------+-----------------+
34    """
35
36    param_names = ["shape", "pad_width", "mode"]
37    params = [
38        # Shape of the input arrays
39        [(2 ** 22,), (1024, 1024), (256, 128, 1),
40         (4, 4, 4, 4), (1, 1, 1, 1, 1)],
41        # Tested pad widths
42        [1, 8, (0, 32)],
43        # Tested modes: mean, median, minimum & maximum use the same code path
44        #               reflect & symmetric share a lot of their code path
45        ["constant", "edge", "linear_ramp", "mean", "reflect", "wrap"],
46    ]
47
48    def setup(self, shape, pad_width, mode):
49        # Make sure to fill the array to make the OS page fault
50        # in the setup phase and not the timed phase
51        self.array = np.full(shape, fill_value=1, dtype=np.float64)
52
53    def time_pad(self, shape, pad_width, mode):
54        np.pad(self.array, pad_width, mode)
55
56class Nan(Benchmark):
57    """Benchmarks for nan functions"""
58
59    param_names = ["array_size", "percent_nans"]
60    params = [
61            # sizes of the 1D arrays
62            [200, int(2e5)],
63            # percent of np.nan in arrays
64            [0, 0.1, 2., 50., 90.],
65            ]
66
67    def setup(self, array_size, percent_nans):
68        np.random.seed(123)
69        # produce a randomly shuffled array with the
70        # approximate desired percentage np.nan content
71        base_array = np.random.uniform(size=array_size)
72        base_array[base_array < percent_nans / 100.] = np.nan
73        self.arr = base_array
74
75    def time_nanmin(self, array_size, percent_nans):
76        np.nanmin(self.arr)
77
78    def time_nanmax(self, array_size, percent_nans):
79        np.nanmax(self.arr)
80
81    def time_nanargmin(self, array_size, percent_nans):
82        np.nanargmin(self.arr)
83
84    def time_nanargmax(self, array_size, percent_nans):
85        np.nanargmax(self.arr)
86
87    def time_nansum(self, array_size, percent_nans):
88        np.nansum(self.arr)
89
90    def time_nanprod(self, array_size, percent_nans):
91        np.nanprod(self.arr)
92
93    def time_nancumsum(self, array_size, percent_nans):
94        np.nancumsum(self.arr)
95
96    def time_nancumprod(self, array_size, percent_nans):
97        np.nancumprod(self.arr)
98
99    def time_nanmean(self, array_size, percent_nans):
100        np.nanmean(self.arr)
101
102    def time_nanvar(self, array_size, percent_nans):
103        np.nanvar(self.arr)
104
105    def time_nanstd(self, array_size, percent_nans):
106        np.nanstd(self.arr)
107
108    def time_nanmedian(self, array_size, percent_nans):
109        np.nanmedian(self.arr)
110
111    def time_nanquantile(self, array_size, percent_nans):
112        np.nanquantile(self.arr, q=0.2)
113
114    def time_nanpercentile(self, array_size, percent_nans):
115        np.nanpercentile(self.arr, q=50)
116