# Path: maxdiv/eval.py
# def pointwiseLabelsToIntervals(labels):
#     """Converts an array of boolean labels for each point in a time series to a list of contiguous intervals."""
#     
#     regions = []
#     current_start = None
#     
#     for i, lbl in enumerate(labels):
#         # Begin of new interval
#         if (current_start is None) and lbl:
#             current_start = i
#         # End of current interval
#         elif (current_start is not None) and (not lbl):
#             regions.append((current_start, i))
#             current_start = None
#     
#     # Terminate trailing interval
#     if current_start is not None:
#         regions.append((current_start, len(labels)))
#     
#     return regions
# 
# Path: maxdiv/maxdiv_util.py
# def calc_gaussian_kernel(X, kernel_sigma_sq = 1.0, normalized=True):
#     """ Calculate a normalized Gaussian kernel using the columns of X """
#     # Let's first compute the kernel matrix from our squared Euclidean distances in $D$.
#     D = calc_distance_matrix(X)
#     # compute proper normalized Gaussian kernel values
#     K = np.exp(-D/(2.0*kernel_sigma_sq))
#     if normalized:
#         K = K / ((2*np.pi*kernel_sigma_sq) ** (X.shape[0] / 2))
#     return K
# 
# def IoU(start1, len1, start2, len2):
#     """ Computes the intersection over union of two intervals starting at start1 and start2 with lengths len1 and len2. """
#     intersection = max(0, min(start1 + len1, start2 + len2) - max(start1, start2))
#     return float(intersection) / (len1 + len2 - intersection)


import numpy as np
    from sklearn.mixture import GMM
    from sklearn.mixture import GaussianMixture
from .eval import pointwiseLabelsToIntervals
from .maxdiv_util import calc_gaussian_kernel, IoU
    # Kernelized Iteratively Re-weighted Least Squares (KIRWLS)
    while True:
        J_old = J
        
        # Obtain new weights
        w = psi(normdiff, type, params) / normdiff
        w /= w.sum()
        
        # Compute loss of the new kernel space solution
        norm2mu = np.dot(w.T, np.dot(K, w)) # norm of the kernel space solution
        normdiff = np.sqrt(K.diagonal()) + norm2mu - 2 * K.dot(w) # norm of the difference between target and solution
        J = rho(normdiff, type, params) # compute loss
        
        # Check termination criterion
        if abs(J_old - J) < J_old * tol:
            break
    
    # Score points by their unlikelihood
    return (1.0 - np.sum(w * K, axis = 1))


def pointwiseScoresToIntervals(scores, min_length = 0):
    
    first_th = np.percentile(scores, 0.7)
    max_score = np.max(scores)
    
    thresholds = np.linspace(first_th, max_score, 10, endpoint = False)
    scores = np.array(scores)
    regions = []
    for th in thresholds[::-1]:

# Path: maxdiv/eval.py
# def pointwiseLabelsToIntervals(labels):
#     """Converts an array of boolean labels for each point in a time series to a list of contiguous intervals."""
#     
#     regions = []
#     current_start = None
#     
#     for i, lbl in enumerate(labels):
#         # Begin of new interval
#         if (current_start is None) and lbl:
#             current_start = i
#         # End of current interval
#         elif (current_start is not None) and (not lbl):
#             regions.append((current_start, i))
#             current_start = None
#     
#     # Terminate trailing interval
#     if current_start is not None:
#         regions.append((current_start, len(labels)))
#     
#     return regions
# 
# Path: maxdiv/maxdiv_util.py
# def calc_gaussian_kernel(X, kernel_sigma_sq = 1.0, normalized=True):
#     """ Calculate a normalized Gaussian kernel using the columns of X """
#     # Let's first compute the kernel matrix from our squared Euclidean distances in $D$.
#     D = calc_distance_matrix(X)
#     # compute proper normalized Gaussian kernel values
#     K = np.exp(-D/(2.0*kernel_sigma_sq))
#     if normalized:
#         K = K / ((2*np.pi*kernel_sigma_sq) ** (X.shape[0] / 2))
#     return K
# 
# def IoU(start1, len1, start2, len2):
#     """ Computes the intersection over union of two intervals starting at start1 and start2 with lengths len1 and len2. """
#     intersection = max(0, min(start1 + len1, start2 + len2) - max(start1, start2))
#     return float(intersection) / (len1 + len2 - intersection)


# Path: maxdiv/baselines_noninterval.py
import numpy as np
    from sklearn.mixture import GMM
    from sklearn.mixture import GaussianMixture
from .eval import pointwiseLabelsToIntervals
from .maxdiv_util import calc_gaussian_kernel, IoU

    # Kernelized Iteratively Re-weighted Least Squares (KIRWLS)
    while True:
        J_old = J
        
        # Obtain new weights
        w = psi(normdiff, type, params) / normdiff
        w /= w.sum()
        
        # Compute loss of the new kernel space solution
        norm2mu = np.dot(w.T, np.dot(K, w)) # norm of the kernel space solution
        normdiff = np.sqrt(K.diagonal()) + norm2mu - 2 * K.dot(w) # norm of the difference between target and solution
        J = rho(normdiff, type, params) # compute loss
        
        # Check termination criterion
        if abs(J_old - J) < J_old * tol:
            break
    
    # Score points by their unlikelihood
    return (1.0 - np.sum(w * K, axis = 1))


def pointwiseScoresToIntervals(scores, min_length = 0):
    
    first_th = np.percentile(scores, 0.7)
    max_score = np.max(scores)
    
    thresholds = np.linspace(first_th, max_score, 10, endpoint = False)
    scores = np.array(scores)
    regions = []
    for th in thresholds[::-1]:

        regions += [(a, b, scores[a:b].min()) for a, b in pointwiseLabelsToIntervals(scores >= th) if b - a >= min_length]