diff options
Diffstat (limited to 'src/silx/math/test/benchmark_combo.py')
-rw-r--r-- | src/silx/math/test/benchmark_combo.py | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/src/silx/math/test/benchmark_combo.py b/src/silx/math/test/benchmark_combo.py new file mode 100644 index 0000000..c12f590 --- /dev/null +++ b/src/silx/math/test/benchmark_combo.py @@ -0,0 +1,192 @@ +# coding: utf-8 +# /*########################################################################## +# Copyright (C) 2016-2017 European Synchrotron Radiation Facility +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# ############################################################################*/ +"""Benchmarks of the combo module""" + +from __future__ import division + +__authors__ = ["T. Vincent"] +__license__ = "MIT" +__date__ = "17/01/2018" + + +import logging +import os.path +import time +import unittest + +import numpy + +from silx.test.utils import temp_dir +from silx.utils.testutils import ParametricTestCase + +from silx.math import combo + +_logger = logging.getLogger(__name__) +_logger.setLevel(logging.DEBUG) + + +class TestBenchmarkMinMax(ParametricTestCase): + """Benchmark of min max combo""" + + DTYPES = ('float32', 'float64', + 'int8', 'int16', 'int32', 'int64', + 'uint8', 'uint16', 'uint32', 'uint64') + + ARANGE = 'ascent', 'descent', 'random' + + EXPONENT = 3, 4, 5, 6, 7 + + def test_benchmark_min_max(self): + """Benchmark min_max without min positive. + + Compares with: + + - numpy.nanmin, numpy.nanmax and + - numpy.argmin, numpy.argmax + + It runs bench for different types, different data size and 3 + data sets: increasing , decreasing and random data. + """ + durations = {'min/max': [], 'argmin/max': [], 'combo': []} + + _logger.info('Benchmark against argmin/argmax and nanmin/nanmax') + + for dtype in self.DTYPES: + for arange in self.ARANGE: + for exponent in self.EXPONENT: + size = 10**exponent + with self.subTest(dtype=dtype, size=size, arange=arange): + if arange == 'ascent': + data = numpy.arange(0, size, 1, dtype=dtype) + elif arange == 'descent': + data = numpy.arange(size, 0, -1, dtype=dtype) + else: + if dtype in ('float32', 'float64'): + data = numpy.random.random(size) + else: + data = numpy.random.randint(10**6, size=size) + data = numpy.array(data, dtype=dtype) + + start = time.time() + ref_min = numpy.nanmin(data) + ref_max = numpy.nanmax(data) + durations['min/max'].append(time.time() - start) + + start = time.time() + ref_argmin = numpy.argmin(data) + ref_argmax = numpy.argmax(data) + durations['argmin/max'].append(time.time() - start) + + start = time.time() + result = combo.min_max(data, min_positive=False) + durations['combo'].append(time.time() - start) + + _logger.info( + '%s-%s-10**%d\tx%.2f argmin/max x%.2f min/max', + dtype, arange, exponent, + durations['argmin/max'][-1] / durations['combo'][-1], + durations['min/max'][-1] / durations['combo'][-1]) + + self.assertEqual(result.minimum, ref_min) + self.assertEqual(result.maximum, ref_max) + self.assertEqual(result.argmin, ref_argmin) + self.assertEqual(result.argmax, ref_argmax) + + self.show_results('min/max', durations, 'combo') + + def test_benchmark_min_pos(self): + """Benchmark min_max wit min positive. + + Compares with: + + - numpy.nanmin(data[data > 0]); numpy.nanmin(pos); numpy.nanmax(pos) + + It runs bench for different types, different data size and 3 + data sets: increasing , decreasing and random data. + """ + durations = {'min/max': [], 'combo': []} + + _logger.info('Benchmark against min, max, positive min') + + for dtype in self.DTYPES: + for arange in self.ARANGE: + for exponent in self.EXPONENT: + size = 10**exponent + with self.subTest(dtype=dtype, size=size, arange=arange): + if arange == 'ascent': + data = numpy.arange(0, size, 1, dtype=dtype) + elif arange == 'descent': + data = numpy.arange(size, 0, -1, dtype=dtype) + else: + if dtype in ('float32', 'float64'): + data = numpy.random.random(size) + else: + data = numpy.random.randint(10**6, size=size) + data = numpy.array(data, dtype=dtype) + + start = time.time() + ref_min_positive = numpy.nanmin(data[data > 0]) + ref_min = numpy.nanmin(data) + ref_max = numpy.nanmax(data) + durations['min/max'].append(time.time() - start) + + start = time.time() + result = combo.min_max(data, min_positive=True) + durations['combo'].append(time.time() - start) + + _logger.info( + '%s-%s-10**%d\tx%.2f min/minpos/max', + dtype, arange, exponent, + durations['min/max'][-1] / durations['combo'][-1]) + + self.assertEqual(result.min_positive, ref_min_positive) + self.assertEqual(result.minimum, ref_min) + self.assertEqual(result.maximum, ref_max) + + self.show_results('min/max/min positive', durations, 'combo') + + def show_results(self, title, durations, ref_key): + try: + from matplotlib import pyplot + except ImportError: + _logger.warning('matplotlib not available') + return + + pyplot.title(title) + pyplot.xlabel('-'.join(self.DTYPES)) + pyplot.ylabel('duration (sec)') + for label, values in durations.items(): + pyplot.semilogy(values, label=label) + pyplot.legend() + pyplot.show() + + pyplot.title(title) + pyplot.xlabel('-'.join(self.DTYPES)) + pyplot.ylabel('Duration ratio') + ref = numpy.array(durations[ref_key]) + for label, values in durations.items(): + values = numpy.array(values) + pyplot.plot(values/ref, label=label + ' / ' + ref_key) + pyplot.legend() + pyplot.show() |