Source code for codeviking.math.comparisons

r"""

Comparing floating-point numbers for equality can be problematic.  Testing
for exact equality is usually not a good idea.  Instead, we usually want to
consider two values equal if they are very close.  The functions in this
module can be used to create comparison functions that tolerate a
user-specified amount of error.

Definitions:
````````````

  Relative Difference
    :math:`\textrm{rel_diff}(a, b) = \frac{\left| a - b \right|}{\max\left(
    |a|,|b|\right)}`


  Absolute Difference
    :math:`\textrm{abs_diff}(a, b) = |a - b|`

"""


[docs]def make_relative_equals(tol): r""" Create a comparison function `is_equal(a,b)` that returns True if :math:`\textrm{rel_diff}(a, b) \leq tol` :param tol: relative tolerance :type tol: float :return: function that returns True if relative difference between a and b is less than tol. :rtype: (float, float) -> bool """ def is_equal(a, b): mx = max(abs(a), abs(b)) delta = abs(a - b) return delta <= tol * mx return is_equal
[docs]def make_absolute_equals(tol): r""" Create a comparison function `is_equal(a,b)` that returns True if :math:`\textrm{abs_diff}(a, b) \leq tol` :param tol: absolute tolerance :type tol: float :return: function that returns True if absolute difference between a and b is less than tol. :rtype: (float, float) -> bool """ def is_equal(a, b): delta = abs(a - b) return delta <= tol return is_equal
[docs]def make_equals(abs_tol, rel_tol): r""" Create a comparison that returns True if either :math:`\textrm{rel_diff}(a, b) \leq \textit{rel_tol}` or :math:`\textrm{ rel_diff}(a, b) \leq \textit{abs_tol}` :param abs_tol: absolute tolerance :type abs_tol: float :param rel_tol: relative tolerance :type rel_tol: float :return: function that returns True if either the relative difference is less than rel_tol or absolute difference is less than abs_tol :rtype: (float, float) -> bool """ def is_equal(a, b): mx = max(abs(a), abs(b)) delta = abs(a - b) return delta <= max(abs_tol, rel_tol * mx) return is_equal
[docs]def make_seq_equals(eq_func): r""" Create a comparison function that compares corresponding elements of two sequences. Two sequences are considered equal if they have the same length, and :math:`\textrm{eq_func}(a_i, b_i) \forall i=0, ..., n` :param equals_func: The function used to compare elements :type equals_func: (float, float) -> bool :return: comparison function :rtype: (list[float], list[float]) -> bool """ def _(a, b): if len(a) != len(b): return False for i in range(len(a)): if not eq_func(a[i], b[i]): return False return True return _