# Path: hep_ml/commonutils.py
# def check_sample_weight(y_true, sample_weight):
#     """
#     Checks the weights, returns normalized version
#     :param y_true: numpy.array of shape [n_samples]
#     :param sample_weight: array-like of shape [n_samples] or None
#     :returns: numpy.array with weights of shape [n_samples]"""
#     if sample_weight is None:
#         return numpy.ones(len(y_true), dtype=numpy.float)
#     else:
#         sample_weight = numpy.array(sample_weight, dtype=numpy.float)
#         assert len(y_true) == len(sample_weight), \
#             "The length of weights is different: not {0}, but {1}".format(len(y_true), len(sample_weight))
#         return sample_weight
# 
# def sigmoid_function(x, width):
#     """ Sigmoid function is smoothing of Heaviside function,
#     the less width, the closer we are to Heaviside function
#     :type x: array-like with floats, arbitrary shape
#     :type width: float, if width == 0, this is simply Heaviside function
#     """
#     assert width >= 0, 'the width should be non-negative'
#     if abs(width) > 0.0001:
#         return expit(x / width)
#     else:
#         return (x > 0) * 1.0
# 
# def compute_cut_for_efficiency(efficiency, mask, y_pred, sample_weight=None):
#     """ Computes such cut(s), that provide given signal efficiency.
#     :type efficiency: float or numpy.array with target efficiencies, shape = [n_effs]
#     :type mask: array-like, shape = [n_samples], True for needed classes
#     :type y_pred: array-like, shape = [n_samples], predictions or scores (float)
#     :type sample_weight: None | array-like, shape = [n_samples]
#     :return: float or numpy.array, shape = [n_effs]
#     """
#     sample_weight = check_sample_weight(mask, sample_weight)
#     assert len(mask) == len(y_pred), 'lengths are different'
#     efficiency = numpy.array(efficiency)
#     is_signal = mask > 0.5
#     y_pred, sample_weight = y_pred[is_signal], sample_weight[is_signal]
#     return weighted_percentile(y_pred, 1. - efficiency, sample_weight=sample_weight)


import numpy
from .commonutils import check_sample_weight, sigmoid_function, compute_cut_for_efficiency
from sklearn.utils.validation import column_or_1d
    result = 0.
    for bin, bin_weight in enumerate(bin_weights):
        if bin_weight <= 0:
            continue
        local_distribution = y_pred[bin_indices == bin]
        local_weights = sample_weight[bin_indices == bin]
        result += bin_weight * \
                  _ks_2samp_fast(prepared_data, local_distribution, prepared_weight, local_weights, prep_F)
    return result


def groups_based_ks(y_pred, mask, sample_weight, groups_indices):
    """Kolmogorov-Smirnov flatness on groups """
    assert len(y_pred) == len(sample_weight) == len(mask)
    group_weights = compute_group_weights(groups_indices, sample_weight=sample_weight)
    prepared_data, prepared_weight, prep_F = prepare_distibution(y_pred[mask], weights=sample_weight[mask])

    result = 0.
    for group_weight, group_indices in zip(group_weights, groups_indices):
        local_distribution = y_pred[group_indices]
        local_weights = sample_weight[group_indices]
        result += group_weight * \
                  _ks_2samp_fast(prepared_data, local_distribution, prepared_weight, local_weights, prep_F)
    return result


def cvm_2samp(data1, data2, weights1=None, weights2=None, power=2.):
    """A handmade function for Cramer-von Mises similarity,
    \int |F_2 - F_1|^p dF_1
    This implementation sorts the arrays each time, so it's slow"""

# Path: hep_ml/commonutils.py
# def check_sample_weight(y_true, sample_weight):
#     """
#     Checks the weights, returns normalized version
#     :param y_true: numpy.array of shape [n_samples]
#     :param sample_weight: array-like of shape [n_samples] or None
#     :returns: numpy.array with weights of shape [n_samples]"""
#     if sample_weight is None:
#         return numpy.ones(len(y_true), dtype=numpy.float)
#     else:
#         sample_weight = numpy.array(sample_weight, dtype=numpy.float)
#         assert len(y_true) == len(sample_weight), \
#             "The length of weights is different: not {0}, but {1}".format(len(y_true), len(sample_weight))
#         return sample_weight
# 
# def sigmoid_function(x, width):
#     """ Sigmoid function is smoothing of Heaviside function,
#     the less width, the closer we are to Heaviside function
#     :type x: array-like with floats, arbitrary shape
#     :type width: float, if width == 0, this is simply Heaviside function
#     """
#     assert width >= 0, 'the width should be non-negative'
#     if abs(width) > 0.0001:
#         return expit(x / width)
#     else:
#         return (x > 0) * 1.0
# 
# def compute_cut_for_efficiency(efficiency, mask, y_pred, sample_weight=None):
#     """ Computes such cut(s), that provide given signal efficiency.
#     :type efficiency: float or numpy.array with target efficiencies, shape = [n_effs]
#     :type mask: array-like, shape = [n_samples], True for needed classes
#     :type y_pred: array-like, shape = [n_samples], predictions or scores (float)
#     :type sample_weight: None | array-like, shape = [n_samples]
#     :return: float or numpy.array, shape = [n_effs]
#     """
#     sample_weight = check_sample_weight(mask, sample_weight)
#     assert len(mask) == len(y_pred), 'lengths are different'
#     efficiency = numpy.array(efficiency)
#     is_signal = mask > 0.5
#     y_pred, sample_weight = y_pred[is_signal], sample_weight[is_signal]
#     return weighted_percentile(y_pred, 1. - efficiency, sample_weight=sample_weight)


# Path: hep_ml/metrics_utils.py
import numpy
from .commonutils import check_sample_weight, sigmoid_function, compute_cut_for_efficiency
from sklearn.utils.validation import column_or_1d

    result = 0.
    for bin, bin_weight in enumerate(bin_weights):
        if bin_weight <= 0:
            continue
        local_distribution = y_pred[bin_indices == bin]
        local_weights = sample_weight[bin_indices == bin]
        result += bin_weight * \
                  _ks_2samp_fast(prepared_data, local_distribution, prepared_weight, local_weights, prep_F)
    return result


def groups_based_ks(y_pred, mask, sample_weight, groups_indices):
    """Kolmogorov-Smirnov flatness on groups """
    assert len(y_pred) == len(sample_weight) == len(mask)
    group_weights = compute_group_weights(groups_indices, sample_weight=sample_weight)
    prepared_data, prepared_weight, prep_F = prepare_distibution(y_pred[mask], weights=sample_weight[mask])

    result = 0.
    for group_weight, group_indices in zip(group_weights, groups_indices):
        local_distribution = y_pred[group_indices]
        local_weights = sample_weight[group_indices]
        result += group_weight * \
                  _ks_2samp_fast(prepared_data, local_distribution, prepared_weight, local_weights, prep_F)
    return result


def cvm_2samp(data1, data2, weights1=None, weights2=None, power=2.):
    """A handmade function for Cramer-von Mises similarity,
    \int |F_2 - F_1|^p dF_1
    This implementation sorts the arrays each time, so it's slow"""

    weights1 = check_sample_weight(data1, sample_weight=weights1)