#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

range = getattr(__builtins__, 'xrange', range)
# end of py2 compatability boilerplate

import numpy as np

from matrixprofile import core
from matrixprofile.algorithms.mpdist import mpdist_vector


def snippets(ts, snippet_size, num_snippets=2, window_size=None):
    """
    The snippets algorithm is used to summarize your time series by
    identifying N number of representative subsequences. If you want to
    identify typical patterns in your time series, then this is the algorithm
    to use.

    Parameters
    ----------
    ts : array_like
        The time series.
    snippet_size : int
        The size of snippet desired.
    num_snippets : int, Default 2
        The number of snippets you would like to find.
    window_size : int, Default (snippet_size / 2)
        The window size.

    Returns
    -------
    list : snippets
        A list of snippets as dictionary objects with the following structure.
        
        >>> {
        >>> 	fraction: fraction of the snippet,
        >>> 	index: the index of the snippet,
        >>> 	snippet: the snippet values
        >>> }

    """
    ts = core.to_np_array(ts).astype('d')
    n = len(ts)

    if not isinstance(snippet_size, int) or snippet_size < 4:
        raise ValueError('snippet_size must be an integer >= 4')

    if n < (2 * snippet_size):
        raise ValueError('Time series is too short relative to snippet length')

    if not window_size:
        window_size = int(np.floor(snippet_size / 2))

    if window_size >= snippet_size:
        raise ValueError('window_size must be smaller than snippet_size')

    # pad end of time series with zeros
    num_zeros = int(snippet_size * np.ceil(n / snippet_size) - n)
    ts = np.append(ts, np.zeros(num_zeros))

    # compute all profiles
    indices = np.arange(0, len(ts) - snippet_size, snippet_size)
    distances = []

    for j, i in enumerate(indices):
        distance = mpdist_vector(ts, ts[i:(i + snippet_size - 1)], int(window_size))
        distances.append(distance)

    distances = np.array(distances)	

    # find N snippets
    snippets = []
    minis = np.inf
    total_min = None
    for n in range(num_snippets):
        minims = np.inf

        for i in range(len(indices)):
            s = np.sum(np.minimum(distances[i, :], minis))

            if minims > s:
                minims = s
                index = i

        minis = np.minimum(distances[index, :], minis)
        actual_index = indices[index]
        snippet = ts[actual_index:actual_index + snippet_size]
        snippet_distance = distances[index]
        snippets.append({
            'index': actual_index,
            'snippet': snippet,
            'distance': snippet_distance
        })

        if isinstance(total_min, type(None)):
            total_min = snippet_distance
        else:
            total_min = np.minimum(total_min, snippet_distance)

    # compute the fraction of each snippet
    for snippet in snippets:
        mask = (snippet['distance'] <= total_min)
        snippet['fraction'] = mask.sum() / (len(ts) - snippet_size)
        total_min = total_min - mask
        del snippet['distance']

    return snippets

[((74, 16, 74, 35), 'numpy.array', 'np.array', ({(74, 25, 74, 34): 'distances'}, {}), '(distances)', True, 'import numpy as np\n'), ((64, 23, 64, 42), 'numpy.zeros', 'np.zeros', ({(64, 32, 64, 41): 'num_zeros'}, {}), '(num_zeros)', True, 'import numpy as np\n'), ((90, 16, 90, 54), 'numpy.minimum', 'np.minimum', ({(90, 27, 90, 46): 'distances[(index), :]', (90, 48, 90, 53): 'minis'}, {}), '(distances[(index), :], minis)', True, 'import numpy as np\n'), ((47, 9, 47, 29), 'matrixprofile.core.to_np_array', 'core.to_np_array', ({(47, 26, 47, 28): 'ts'}, {}), '(ts)', False, 'from matrixprofile import core\n'), ((57, 26, 57, 52), 'numpy.floor', 'np.floor', ({(57, 35, 57, 51): 'snippet_size / 2'}, {}), '(snippet_size / 2)', True, 'import numpy as np\n'), ((103, 24, 103, 63), 'numpy.minimum', 'np.minimum', ({(103, 35, 103, 44): 'total_min', (103, 46, 103, 62): 'snippet_distance'}, {}), '(total_min, snippet_distance)', True, 'import numpy as np\n'), ((63, 35, 63, 60), 'numpy.ceil', 'np.ceil', ({(63, 43, 63, 59): 'n / snippet_size'}, {}), '(n / snippet_size)', True, 'import numpy as np\n'), ((84, 23, 84, 57), 'numpy.minimum', 'np.minimum', ({(84, 34, 84, 49): 'distances[(i), :]', (84, 51, 84, 56): 'minis'}, {}), '(distances[(i), :], minis)', True, 'import numpy as np\n')]