<commit_before>"""Module containing utility functions to compare parameters and results"""

__author__ = '<NAME>'

from collections import Sequence, Mapping, Set

try:
    from future_builtins import zip
except ImportError:  # not 2.6+ or is 3.x
    try:
        from itertools import izip as zip  # < 2.5 or 3.x
    except ImportError:
        pass
import numpy as np
import pandas as pd
import scipy.sparse as spsp

import pypet.pypetconstants as pypetconstants
import pypet.compat as compat


def results_equal(a, b):
    """Compares two result instances

    Checks full name and all data. Does not consider the comment.

    :return: True or False

    :raises: ValueError if both inputs are no result instances

    """
    if a.v_is_parameter or b.v_is_parameter:
        raise ValueError('Both inputs are not results.')

    if a.v_is_parameter or b.v_is_parameter:
        return False

    if not a.v_name == b.v_name:
        return False

    if not a.v_location == b.v_location:
        return False

    if not a.v_full_name == b.v_full_name:
        return False

    if hasattr(a, '_data') and not hasattr(b, '_data'):
        return False

    if hasattr(a, '_data'):
        akeyset = set(a._data.keys())
        bkeyset = set(b._data.keys())

        if akeyset != bkeyset:
            return False

        for key in a._data:
            val = a._data[key]
            bval = b._data[key]

            if not nested_equal(val, bval):
                return False

    return True


def parameters_equal(a, b):
    """Compares two parameter instances

    Checks full name, data, and ranges. Does not consider the comment.

    :return: True or False

    :raises: ValueError if both inputs are no parameter instances

    """
    if (not b.v_is_parameter and
            not a.v_is_parameter):
        raise ValueError('Both inputs are not parameters')

    if (not b.v_is_parameter or
            not a.v_is_parameter):
        return False

    if not a.v_name == b.v_name:
        return False

    if not a.v_location == b.v_location:
        return False

    if not a.v_full_name == b.v_full_name:
        return False

    # I allow different comments for now
    # if not a.get_comment() == b.get_comment():
    # return False

    if not a._values_of_same_type(a.f_get(), b.f_get()):
        return False

    if not a._equal_values(a.f_get(), b.f_get()):
        return False

    if not len(a) == len(b):
        return False

    if a.f_has_range():
        for myitem, bitem in zip(a.f_get_range(), b.f_get_range()):
            if not a._values_of_same_type(myitem, bitem):
                return False

            if not a._equal_values(myitem, bitem):
                return False

    return True


def nested_equal(a, b):
    """Compares two objects recursively by their elements, also handling numpy objects.

    Assumes hashable items are not mutable in a way that affects equality.
    Based on the suggestion from HERE_, thanks again <NAME> :-)

    .. _HERE: http://stackoverflow.com/questions/18376935/best-practice-for-equality-in-python

    """
    try:
        if a is b:
            return True
        # for types that support __eq__
        try:
            custom_eq = a.__eq__(b)  # Best way I came up with to check in python 2 and 3
            # if equality is implemented
            if isinstance(custom_eq, bool):
                return custom_eq
        except (AttributeError, NotImplementedError, TypeError, ValueError):
            pass

        # Check equality according to type type [sic].
        if a is None:
            return b is None
        if isinstance(a, (compat.unicode_type, compat.bytes_type)):
            return a == b
        if isinstance(a, pypetconstants.PARAMETER_SUPPORTED_DATA):
            return a == b
        if isinstance(a, (pd.Panel, pd.Panel4D)):
            return nested_equal(a.to_frame(), b.to_frame())
        if spsp.isspmatrix(a):
            if a.nnz == 0:
                return b.nnz == 0
            else:
                return np.all((a == b).data)
        if isinstance(a, (pd.DataFrame, pd.Series)):
            try:
                new_frame = a == b
                new_frame = new_frame | (pd.isnull(a) & pd.isnull(b))
                return np.all(new_frame.as_matrix())<commit_msg>fixed nested_equal for old pandas versions<commit_after>"""Module containing utility functions to compare parameters and results"""

__author__ = '<NAME>'

from collections import Sequence, Mapping, Set

try:
    from future_builtins import zip
except ImportError:  # not 2.6+ or is 3.x
    try:
        from itertools import izip as zip  # < 2.5 or 3.x
    except ImportError:
        pass
import numpy as np
import pandas as pd
import scipy.sparse as spsp

import pypet.pypetconstants as pypetconstants
import pypet.compat as compat


def results_equal(a, b):
    """Compares two result instances

    Checks full name and all data. Does not consider the comment.

    :return: True or False

    :raises: ValueError if both inputs are no result instances

    """
    if a.v_is_parameter or b.v_is_parameter:
        raise ValueError('Both inputs are not results.')

    if a.v_is_parameter or b.v_is_parameter:
        return False

    if not a.v_name == b.v_name:
        return False

    if not a.v_location == b.v_location:
        return False

    if not a.v_full_name == b.v_full_name:
        return False

    if hasattr(a, '_data') and not hasattr(b, '_data'):
        return False

    if hasattr(a, '_data'):
        akeyset = set(a._data.keys())
        bkeyset = set(b._data.keys())

        if akeyset != bkeyset:
            return False

        for key in a._data:
            val = a._data[key]
            bval = b._data[key]

            if not nested_equal(val, bval):
                return False

    return True


def parameters_equal(a, b):
    """Compares two parameter instances

    Checks full name, data, and ranges. Does not consider the comment.

    :return: True or False

    :raises: ValueError if both inputs are no parameter instances

    """
    if (not b.v_is_parameter and
            not a.v_is_parameter):
        raise ValueError('Both inputs are not parameters')

    if (not b.v_is_parameter or
            not a.v_is_parameter):
        return False

    if not a.v_name == b.v_name:
        return False

    if not a.v_location == b.v_location:
        return False

    if not a.v_full_name == b.v_full_name:
        return False

    # I allow different comments for now
    # if not a.get_comment() == b.get_comment():
    # return False

    if not a._values_of_same_type(a.f_get(), b.f_get()):
        return False

    if not a._equal_values(a.f_get(), b.f_get()):
        return False

    if not len(a) == len(b):
        return False

    if a.f_has_range():
        for myitem, bitem in zip(a.f_get_range(), b.f_get_range()):
            if not a._values_of_same_type(myitem, bitem):
                return False

            if not a._equal_values(myitem, bitem):
                return False

    return True


def nested_equal(a, b):
    """Compares two objects recursively by their elements, also handling numpy objects.

    Assumes hashable items are not mutable in a way that affects equality.
    Based on the suggestion from HERE_, thanks again <NAME> :-)

    .. _HERE: http://stackoverflow.com/questions/18376935/best-practice-for-equality-in-python

    """
    try:
        if a is b:
            return True
        # for types that support __eq__
        try:
            custom_eq = a.__eq__(b)  # Best way I came up with to check in python 2 and 3
            # if equality is implemented
            if isinstance(custom_eq, (bool, np.bool_)):
                return custom_eq
        except (AttributeError, NotImplementedError, TypeError, ValueError):
            pass

        # Check equality according to type type [sic].
        if a is None:
            return b is None
        if isinstance(a, (compat.unicode_type, compat.bytes_type)):
            return a == b
        if isinstance(a, pypetconstants.PARAMETER_SUPPORTED_DATA):
            return a == b
        if isinstance(a, (pd.Panel, pd.Panel4D)):
            return nested_equal(a.to_frame(), b.to_frame())
        if spsp.isspmatrix(a):
            if a.nnz == 0:
                return b.nnz == 0
            else:
                return np.all((a == b).data)
        if isinstance(a, (pd.DataFrame, pd.Series)):
            try:
                new_frame = a == b
                new_frame = new_frame | (pd.isnull(a) & pd.isnull(b))
                if isinstance(new_frame, pd.DataFrame):
                    return np.all(new_frame.as_matrix())
                else:
                    eq = new_frame.all() # In older pandas versions,
                    # series do not support as_matrix
                    if isinstance(eq, (bool, np.bool_)):
                        return eq
                    else:
                        raise ValueError('')
{'fraction_non_alphanumeric': 0.08747779751332149, 'fraction_numerical': 0.0042184724689165185, 'mean_word_length': 2.003, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '633813', 'n_tokens_mistral': 2773, 'n_tokens_neox': 2643, 'n_words': 881}