From 59cf66fcba6b6766286887dfa7df9bdcc155d2df Mon Sep 17 00:00:00 2001 From: juanbc Date: Mon, 15 Jan 2024 22:51:04 -0300 Subject: [PATCH] rename and integration of diff in agg base --- .../utils/{npdict_cmp.rst => dict_cmp.rst} | 4 +- skcriteria/agg/_agg_base.py | 4 +- skcriteria/utils/__init__.py | 2 +- skcriteria/utils/dict_cmp.py | 90 +++++++++++++++++++ skcriteria/utils/npdict_cmp.py | 58 ------------ .../{test_npdict_cmp.py => test_dict_cmp.py} | 21 ++--- 6 files changed, 106 insertions(+), 73 deletions(-) rename docs/source/api/utils/{npdict_cmp.rst => dict_cmp.rst} (53%) create mode 100644 skcriteria/utils/dict_cmp.py delete mode 100644 skcriteria/utils/npdict_cmp.py rename tests/utils/{test_npdict_cmp.py => test_dict_cmp.py} (73%) diff --git a/docs/source/api/utils/npdict_cmp.rst b/docs/source/api/utils/dict_cmp.rst similarity index 53% rename from docs/source/api/utils/npdict_cmp.rst rename to docs/source/api/utils/dict_cmp.rst index ecda797..e75548a 100644 --- a/docs/source/api/utils/npdict_cmp.rst +++ b/docs/source/api/utils/dict_cmp.rst @@ -1,7 +1,7 @@ -``skcriteria.utils.npdict_cmp`` module +``skcriteria.utils.dict_cmp`` module ======================================== -.. automodule:: skcriteria.utils.npdict_cmp +.. automodule:: skcriteria.utils.dict_cmp :members: :undoc-members: :show-inheritance: diff --git a/skcriteria/agg/_agg_base.py b/skcriteria/agg/_agg_base.py index b9bb783..fe45e4a 100644 --- a/skcriteria/agg/_agg_base.py +++ b/skcriteria/agg/_agg_base.py @@ -30,7 +30,7 @@ deprecated, diff, doc_inherit, - npdict_all_equals, + dict_allclose, ) # ============================================================================= @@ -204,7 +204,7 @@ def array_allclose(left_value, right_value): "method": np.array_equal, "alternatives": np.array_equal, "values": array_allclose, - "extra_": npdict_all_equals, + "extra_": dict_allclose, } the_diff = diff(self, other, **members) diff --git a/skcriteria/utils/__init__.py b/skcriteria/utils/__init__.py index 9f36fb1..79da26d 100644 --- a/skcriteria/utils/__init__.py +++ b/skcriteria/utils/__init__.py @@ -21,7 +21,7 @@ from .cmanagers import df_temporal_header, hidden from .deprecate import deprecated, will_change from .doctools import doc_inherit -from .npdict_cmp import npdict_all_equals +from .dict_cmp import dict_allclose from .object_diff import DiffEqualityMixin, diff from .unames import unique_names diff --git a/skcriteria/utils/dict_cmp.py b/skcriteria/utils/dict_cmp.py new file mode 100644 index 0000000..71ea644 --- /dev/null +++ b/skcriteria/utils/dict_cmp.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# License: BSD-3 (https://tldrlegal.com/license/bsd-3-clause-license-(revised)) +# Copyright (c) 2016-2021, Cabral, Juan; Luczywo, Nadia +# Copyright (c) 2022, 2023, 2024 QuatroPe +# All rights reserved. + +# ============================================================================= +# DOCS +# ============================================================================= + +"""Utilities to compare two dictionaries with numpy arrays.""" + +# ============================================================================= +# IMPORTS +# ============================================================================= + +import numpy as np + +# ============================================================================= +# CLASSES +# ============================================================================= + +import numpy as np + +def dict_allclose(left, right, rtol=1e-05, atol=1e-08, equal_nan=False): + """Compares two dictionaries. If values of type "numpy.array" are \ + encountered, the function utilizes "numpy.allclose" for comparison. + + Parameters + ---------- + left : dict + The left dictionary. + right : dict + The right dictionary. + rtol : float, optional + The relative tolerance parameter for `np.allclose`. + atol : float, optional + The absolute tolerance parameter for `np.allclose`. + equal_nan : bool, optional + Whether to consider NaN values as equal. + + Returns + ------- + bool + True if the dictionaries are equal, False otherwise. + + Notes + ----- + This function iteratively compares the values of corresponding keys in the + input dictionaries `left` and `right`. It handles various data types, + including NumPy arrays, and uses the `np.allclose` function for numeric + array comparisons with customizable tolerance levels. The comparison is + performed iteratively, and the function returns True if all values are + equal based on the specified criteria. If the dictionaries have different + lengths or keys, or if the types of corresponding values differ, the + function returns False. + + """ + if left is right: # if they are the same object, return True + return True + + # Extra keys + keys = set(left).union(right) + + # If the keys are not the same on both sides, return False + if not (len(keys) == len(left) == len(right)): + return False + + is_equal = True # Flag to check if all keys are equal, optimist + while is_equal and keys: # Loop until all keys are equal + key = keys.pop() + left_value, right_value = left[key], right[key] + + if type(left_value) is not type(right_value): + is_equal = False + + elif isinstance(left_value, np.ndarray): + is_equal = np.allclose( + left_value, + right_value, + rtol=rtol, + atol=atol, + equal_nan=equal_nan, + ) + + else: + is_equal = left_value == right_value + + return is_equal diff --git a/skcriteria/utils/npdict_cmp.py b/skcriteria/utils/npdict_cmp.py deleted file mode 100644 index 4cb40b3..0000000 --- a/skcriteria/utils/npdict_cmp.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# License: BSD-3 (https://tldrlegal.com/license/bsd-3-clause-license-(revised)) -# Copyright (c) 2016-2021, Cabral, Juan; Luczywo, Nadia -# Copyright (c) 2022, 2023, 2024 QuatroPe -# All rights reserved. - -# ============================================================================= -# DOCS -# ============================================================================= - -"""Utilities to compare two dictionaries with numpy arrays.""" - -# ============================================================================= -# IMPORTS -# ============================================================================= - -import numpy as np - -# ============================================================================= -# CLASSES -# ============================================================================= - - -def npdict_all_equals(left, right, rtol=1e-05, atol=1e-08, equal_nan=False): - """Return True if the two dictionaries are equal within a tolerance.""" - - if left is right: # if they are the same object return True - return True - - # extra keys - keys = set(left).union(right) - - # if the keys are not the same on both sides return False - if not (len(keys) == len(left) == len(right)): - return False - - is_equal = True # flag to check if all keys are equal, optimist - while is_equal and keys: # loop until all keys are equal - key = keys.pop() - left_value, right_value = left[key], right[key] - - if type(left_value) is not type(right_value): - is_equal = False - - elif isinstance(left_value, np.ndarray): - is_equal = np.allclose( - left_value, - right_value, - rtol=rtol, - atol=atol, - equal_nan=equal_nan, - ) - - else: - is_equal = left_value == right_value - - return is_equal diff --git a/tests/utils/test_npdict_cmp.py b/tests/utils/test_dict_cmp.py similarity index 73% rename from tests/utils/test_npdict_cmp.py rename to tests/utils/test_dict_cmp.py index 2aa83ca..58ce5f0 100644 --- a/tests/utils/test_npdict_cmp.py +++ b/tests/utils/test_dict_cmp.py @@ -9,7 +9,7 @@ # DOCS # ============================================================================= -"""test for skcriteria.utils.npdict_cmp +"""test for skcriteria.utils.dict_cmp """ @@ -21,7 +21,7 @@ import numpy as np -from skcriteria.utils import npdict_cmp +from skcriteria.utils import dict_cmp # ============================================================================= @@ -29,24 +29,25 @@ # ============================================================================= -def test_npdict_all_equals_(): +def test_dict_allclose(): left = {"a": np.array([1, 2, 3]), "b": np.array([4, 5, 6]), "c": 1} right = {"a": np.array([1, 2, 3]), "b": np.array([4, 5, 6]), "c": 1} - assert npdict_cmp.npdict_all_equals(left, right) + assert dict_cmp.dict_allclose(left, right) -def test_npdict_all_equals_same_obj(): +def test_dict_allclose_same_obj(): dict0 = {"a": np.array([1, 2, 3]), "b": np.array([4, 5, 6]), "c": 1} - assert npdict_cmp.npdict_all_equals(dict0, dict0) + assert dict_cmp.dict_allclose(dict0, dict0) -def test_npdict_all_equals_different_keys(): +def test_dict_allclose_different_keys(): left = {"a": np.array([1, 2, 3]), "b": np.array([4, 5, 6]), "c": 1} right = {"a": np.array([1, 2, 3]), "b": np.array([4, 5, 6]), "d": 1} - assert npdict_cmp.npdict_all_equals(left, right) is False + assert dict_cmp.dict_allclose(left, right) is False -def test_npdict_all_equals_different_types(): +def test_dict_allclose_different_types(): left = {"a": np.array([1, 2, 3]), "b": np.array([4, 5, 6]), "c": 1} right = {"a": np.array([1, 2, 3]), "b": np.array([4, 5, 6]), "c": 1.0} - assert npdict_cmp.npdict_all_equals(left, right) is False + assert dict_cmp.dict_allclose(left, right) is False +