Source code for skcriteria.utils.dict_cmp

#!/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
# =============================================================================

from collections.abc import Mapping

import numpy as np

# =============================================================================
# CONSTANTS
# =============================================================================

_INEXACT_TYPES = (float, complex, np.inexact)

# =============================================================================
# CLASSES
# =============================================================================


[docs] 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, Mapping): is_equal = dict_allclose( left_value, right_value, rtol=rtol, atol=atol, equal_nan=equal_nan, ) elif isinstance(left_value, np.ndarray) and issubclass( left_value.dtype.type, _INEXACT_TYPES ): is_equal = np.allclose( left_value, right_value, rtol=rtol, atol=atol, equal_nan=equal_nan, ) else: is_equal = np.array_equal(left_value, right_value) return is_equal