summaryrefslogtreecommitdiff
path: root/src/silx/math/test/test_histogramnd_error.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/silx/math/test/test_histogramnd_error.py')
-rw-r--r--src/silx/math/test/test_histogramnd_error.py487
1 files changed, 487 insertions, 0 deletions
diff --git a/src/silx/math/test/test_histogramnd_error.py b/src/silx/math/test/test_histogramnd_error.py
new file mode 100644
index 0000000..c640b4a
--- /dev/null
+++ b/src/silx/math/test/test_histogramnd_error.py
@@ -0,0 +1,487 @@
+# /*##########################################################################
+# Copyright (C) 2016-2023 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 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.
+ """
+
+ __test__ = False # ignore abstract class
+
+ def setUp(self):
+ self.skipTest("Abstract class")
+
+ 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,
+ "<weights> 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 = (
+ "<histo_range> error : expected {n_dims} sets "
+ "of lower and upper bin edges, "
+ "got the following instead : {histo_range}. "
+ "(provided <sample> 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 = "<n_bins> : 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:
+ test_msg = "Testing invalid histo shape : {0}" "".format(err_h_shape)
+
+ expected_txt = (
+ "Provided <histo> array doesn't have "
+ "a shape compatible with <n_bins> "
+ ": 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 <histo> 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:
+ test_msg = "Testing invalid weighted_histo shape : {0}" "".format(
+ err_h_shape
+ )
+
+ expected_txt = (
+ "Provided <weighted_histo> array doesn't have "
+ "a shape compatible with <n_bins> "
+ ": 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 <weighted_histo> 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 = "<wh_dtype> 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 = "<histo> 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 = "<weighted_histo> 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.
+ """
+
+ __test__ = True # because _Test_chistogramnd_errors is ignored
+
+ 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.0, 100.0]
+ 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], [0.0, 1.0, 2.0], [[0.0], [1.0]])
+ 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.
+ """
+
+ __test__ = True # because _Test_chistogramnd_errors is ignored
+
+ 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.0, 100.0], [0.0, 100.0], [0.0, 100.0]]
+ 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],
+ [0.0, 1.0],
+ [[0.0, 10.0], [0.0, 10.0]],
+ [0.0, 10.0, 0, 10.0, 0, 10.0],
+ )
+ 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),
+ )