# coding: utf-8 # /*########################################################################## # Copyright (C) 2016 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. # # ############################################################################*/ __authors__ = ["D. Naudet"] __license__ = "MIT" __date__ = "01/02/2016" """ Tests of the histogramnd function, error cases. """ import sys import platform import unittest import numpy as np from silx.math.chistogramnd import chistogramnd as histogramnd from silx.math import Histogramnd # ============================================================== # ============================================================== # ============================================================== class _Test_chistogramnd_errors(unittest.TestCase): """ Unit tests of the chistogramnd error cases. """ def setUp(self): raise NotImplementedError('') def test_weights_shape(self): """ """ for err_w_shape in self.err_weights_shapes: test_msg = ('Testing invalid weights shape : {0}' ''.format(err_w_shape)) err_weights = np.random.randint(0, high=10, size=err_w_shape) err_weights = err_weights.astype(np.double) ex_str = None try: histo, cumul = histogramnd(self.sample, self.histo_range, self.n_bins, weights=err_weights)[0:2] except ValueError as ex: ex_str = str(ex) self.assertIsNotNone(ex_str, msg=test_msg) self.assertEqual(ex_str, ' must be an array whose length ' 'is equal to the number of samples.') def test_histo_range_shape(self): """ """ n_dims = 1 if len(self.s_shape) == 1 else self.s_shape[1] expected_txt_tpl = (' error : expected {n_dims} sets ' 'of lower and upper bin edges, ' 'got the following instead : {histo_range}. ' '(provided contains ' '{n_dims}D values)') for err_histo_range in self.err_histo_range_shapes: test_msg = ('Testing invalid histo_range shape : {0}' ''.format(err_histo_range)) expected_txt = expected_txt_tpl.format(histo_range=err_histo_range, n_dims=n_dims) ex_str = None try: histo, cumul = histogramnd(self.sample, err_histo_range, self.n_bins, weights=self.weights)[0:2] except ValueError as ex: ex_str = str(ex) self.assertIsNotNone(ex_str, msg=test_msg) self.assertEqual(ex_str, expected_txt, msg=test_msg) def test_nbins_shape(self): """ """ expected_txt = ('n_bins must be either a scalar (same number ' 'of bins for all dimensions) or ' 'an array (number of bins for each ' 'dimension).') for err_n_bins in self.err_n_bins_shapes: test_msg = ('Testing invalid n_bins shape : {0}' ''.format(err_n_bins)) ex_str = None try: histo, cumul = histogramnd(self.sample, self.histo_range, err_n_bins, weights=self.weights)[0:2] except ValueError as ex: ex_str = str(ex) self.assertIsNotNone(ex_str, msg=test_msg) self.assertEqual(ex_str, expected_txt, msg=test_msg) def test_nbins_values(self): """ """ expected_txt = (' : only positive values allowed.') for err_n_bins in self.err_n_bins_values: test_msg = ('Testing invalid n_bins value : {0}' ''.format(err_n_bins)) ex_str = None try: histo, cumul = histogramnd(self.sample, self.histo_range, err_n_bins, weights=self.weights)[0:2] except ValueError as ex: ex_str = str(ex) self.assertIsNotNone(ex_str, msg=test_msg) self.assertEqual(ex_str, expected_txt, msg=test_msg) def test_histo_shape(self): """ """ for err_h_shape in self.err_histo_shapes: # windows & python 2.7 : numpy shapes are long values if platform.system() == 'Windows': version = (sys.version_info.major, sys.version_info.minor) if version <= (2, 7): err_h_shape = tuple([long(val) for val in err_h_shape]) test_msg = ('Testing invalid histo shape : {0}' ''.format(err_h_shape)) expected_txt = ('Provided array doesn\'t have ' 'a shape compatible with ' ': should be {0} instead of {1}.' ''.format(self.h_shape, err_h_shape)) histo = np.zeros(shape=err_h_shape, dtype=np.uint32) ex_str = None try: histo, cumul = histogramnd(self.sample, self.histo_range, self.n_bins, weights=self.weights, histo=histo)[0:2] except ValueError as ex: ex_str = str(ex) self.assertIsNotNone(ex_str, msg=test_msg) self.assertEqual(ex_str, expected_txt, msg=test_msg) def test_histo_dtype(self): """ """ for err_h_dtype in self.err_histo_dtypes: test_msg = ('Testing invalid histo dtype : {0}' ''.format(err_h_dtype)) histo = np.zeros(shape=self.h_shape, dtype=err_h_dtype) expected_txt = ('Provided array doesn\'t have ' 'the expected type ' ': should be {0} instead of {1}.' ''.format(np.uint32, histo.dtype)) ex_str = None try: histo, cumul = histogramnd(self.sample, self.histo_range, self.n_bins, weights=self.weights, histo=histo)[0:2] except ValueError as ex: ex_str = str(ex) self.assertIsNotNone(ex_str, msg=test_msg) self.assertEqual(ex_str, expected_txt, msg=test_msg) def test_weighted_histo_shape(self): """ """ # using the same values as histo for err_h_shape in self.err_histo_shapes: # windows & python 2.7 : numpy shapes are long values if platform.system() == 'Windows': version = (sys.version_info.major, sys.version_info.minor) if version <= (2, 7): err_h_shape = tuple([long(val) for val in err_h_shape]) test_msg = ('Testing invalid weighted_histo shape : {0}' ''.format(err_h_shape)) expected_txt = ('Provided array doesn\'t have ' 'a shape compatible with ' ': should be {0} instead of {1}.' ''.format(self.h_shape, err_h_shape)) cumul = np.zeros(shape=err_h_shape, dtype=np.double) ex_str = None try: histo, cumul = histogramnd(self.sample, self.histo_range, self.n_bins, weights=self.weights, weighted_histo=cumul)[0:2] except ValueError as ex: ex_str = str(ex) self.assertIsNotNone(ex_str, msg=test_msg) self.assertEqual(ex_str, expected_txt, msg=test_msg) def test_cumul_dtype(self): """ """ # using the same values as histo for err_h_dtype in self.err_histo_dtypes: test_msg = ('Testing invalid weighted_histo dtype : {0}' ''.format(err_h_dtype)) cumul = np.zeros(shape=self.h_shape, dtype=err_h_dtype) expected_txt = ('Provided array doesn\'t have ' 'the expected type ' ': should be {0} or {1} instead of {2}.' ''.format(np.float64, np.float32, cumul.dtype)) ex_str = None try: histo, cumul = histogramnd(self.sample, self.histo_range, self.n_bins, weights=self.weights, weighted_histo=cumul)[0:2] except ValueError as ex: ex_str = str(ex) self.assertIsNotNone(ex_str, msg=test_msg) self.assertEqual(ex_str, expected_txt, msg=test_msg) def test_wh_histo_dtype(self): """ """ # using the same values as histo for err_h_dtype in self.err_histo_dtypes: test_msg = ('Testing invalid wh_dtype dtype : {0}' ''.format(err_h_dtype)) expected_txt = (' type not supported : {0}.' ''.format(err_h_dtype)) ex_str = None try: histo, cumul = histogramnd(self.sample, self.histo_range, self.n_bins, weights=self.weights, wh_dtype=err_h_dtype)[0:2] except ValueError as ex: ex_str = str(ex) self.assertIsNotNone(ex_str, msg=test_msg) self.assertEqual(ex_str, expected_txt, msg=test_msg) def test_unmanaged_dtypes(self): """ """ for err_unmanaged_dtype in self.err_unmanaged_dtypes: test_msg = ('Testing unmanaged dtypes : {0}' ''.format(err_unmanaged_dtype)) sample = self.sample.astype(err_unmanaged_dtype[0]) weights = self.weights.astype(err_unmanaged_dtype[1]) expected_txt = ('Case not supported - sample:{0} ' 'and weights:{1}.' ''.format(sample.dtype, weights.dtype)) ex_str = None try: histogramnd(sample, self.histo_range, self.n_bins, weights=weights) except TypeError as ex: ex_str = str(ex) self.assertIsNotNone(ex_str, msg=test_msg) self.assertEqual(ex_str, expected_txt, msg=test_msg) def test_uncontiguous_histo(self): """ """ # non contiguous array shape = np.array(self.n_bins, ndmin=1) shape[0] *= 2 histo_tmp = np.zeros(shape) histo = histo_tmp[::2, ...] expected_txt = (' must be a C_CONTIGUOUS numpy array.') ex_str = None try: histogramnd(self.sample, self.histo_range, self.n_bins, weights=self.weights, histo=histo) except ValueError as ex: ex_str = str(ex) self.assertIsNotNone(ex_str) self.assertEqual(ex_str, expected_txt) def test_uncontiguous_weighted_histo(self): """ """ # non contiguous array shape = np.array(self.n_bins, ndmin=1) shape[0] *= 2 cumul_tmp = np.zeros(shape) cumul = cumul_tmp[::2, ...] expected_txt = (' must be a C_CONTIGUOUS numpy array.') ex_str = None try: histogramnd(self.sample, self.histo_range, self.n_bins, weights=self.weights, weighted_histo=cumul) except ValueError as ex: ex_str = str(ex) self.assertIsNotNone(ex_str) self.assertEqual(ex_str, expected_txt) class Test_chistogramnd_1D_errors(_Test_chistogramnd_errors): """ Unit tests of the 1D histogramnd error cases. """ def setUp(self): # nominal values self.n_elements = 1000 self.s_shape = (self.n_elements,) self.w_shape = (self.n_elements,) self.histo_range = [0., 100.] self.n_bins = 10 self.h_shape = (self.n_bins,) self.sample = np.random.randint(0, high=10, size=self.s_shape) self.sample = self.sample.astype(np.double) self.weights = np.random.randint(0, high=10, size=self.w_shape) self.weights = self.weights.astype(np.double) self.err_weights_shapes = ((self.n_elements+1,), (self.n_elements-1,), (self.n_elements-1, 3)) self.err_histo_range_shapes = ([0.], [0., 1., 2.], [[0.], [1.]]) self.err_n_bins_shapes = ([10, 2], [[10], [2]]) self.err_n_bins_values = (0, [-10], None) self.err_histo_shapes = ((self.n_bins+1,), (self.n_bins-1,), (self.n_bins, self.n_bins)) # these are used for testing the histo parameter as well # as the weighted_histo parameter. self.err_histo_dtypes = (np.uint16, np.float16) self.err_unmanaged_dtypes = ((np.double, np.uint16), (np.uint16, np.double), (np.uint16, np.uint16)) class Test_chistogramnd_ND_range(unittest.TestCase): """ """ def test_invalid_histo_range(self): data = np.random.random((60, 60)) nbins = 10 with self.assertRaises(ValueError): histo_range = data.min(), np.inf Histogramnd(sample=data.ravel(), histo_range=histo_range, n_bins=nbins) histo_range = data.min(), np.nan Histogramnd(sample=data.ravel(), histo_range=histo_range, n_bins=nbins) class Test_chistogramnd_ND_errors(_Test_chistogramnd_errors): """ Unit tests of the 3D histogramnd error cases. """ def setUp(self): # nominal values self.n_elements = 1000 self.s_shape = (self.n_elements, 3) self.w_shape = (self.n_elements,) self.histo_range = [[0., 100.], [0., 100.], [0., 100.]] self.n_bins = (10, 20, 30) self.h_shape = self.n_bins self.sample = np.random.randint(0, high=10, size=self.s_shape) self.sample = self.sample.astype(np.double) self.weights = np.random.randint(0, high=10, size=self.w_shape) self.weights = self.weights.astype(np.double) self.err_weights_shapes = ((self.n_elements+1,), (self.n_elements-1,), (self.n_elements-1, 3)) self.err_histo_range_shapes = ([0.], [0., 1.], [[0., 10.], [0., 10.]], [0., 10., 0, 10., 0, 10.]) self.err_n_bins_shapes = ([10, 2], [[10], [20], [30]]) self.err_n_bins_values = (0, [-10], [10, 20, -4], None, [10, None, 30]) self.err_histo_shapes = ((self.n_bins[0]+1, self.n_bins[1], self.n_bins[2]), (self.n_bins[0], self.n_bins[1], self.n_bins[2]-1), (self.n_bins[0], self.n_bins[1]), (self.n_bins[1], self.n_bins[0], self.n_bins[2]), (self.n_bins[0], self.n_bins[1], self.n_bins[2], 10) ) # these are used for testing the histo parameter as well # as the weighted_histo parameter. self.err_histo_dtypes = (np.uint16, np.float16) self.err_unmanaged_dtypes = ((np.double, np.uint16), (np.uint16, np.double), (np.uint16, np.uint16)) # ============================================================== # ============================================================== # ============================================================== test_cases = (Test_chistogramnd_1D_errors, Test_chistogramnd_ND_errors, Test_chistogramnd_ND_range) def suite(): loader = unittest.defaultTestLoader test_suite = unittest.TestSuite() for test_class in test_cases: tests = loader.loadTestsFromTestCase(test_class) test_suite.addTests(tests) return test_suite if __name__ == '__main__': unittest.main(defaultTest="suite")