示例#1
0
def test_mathtools_cumulative_sums_pairwise_02():
    r'''Yield pairwise cumulative sums of l from 0.
    '''

    l = [1, 2, 3, 4, 5, 6]
    g = mathtools.cumulative_sums_pairwise(l)

    assert list(g) == [(0, 1), (1, 3), (3, 6), (6, 10), (10, 15), (15, 21)]
def test_mathtools_cumulative_sums_pairwise_01():
    r'''Yield pairwise cumulative sums of l from 0.
    '''

    l = [3, 1, 2, 1, 3, 3, 1]
    g = mathtools.cumulative_sums_pairwise(l)

    assert list(g) == [
        (0, 3), (3, 4), (4, 6), (6, 7), (7, 10), (10, 13), (13, 14)]
def test_mathtools_cumulative_sums_pairwise_02():
    r'''Yield pairwise cumulative sums of l from 0.
    '''

    l = [1, 2, 3, 4, 5, 6]
    g = mathtools.cumulative_sums_pairwise(l)

    assert list(g) == [
        (0, 1), (1, 3), (3, 6), (6, 10), (10, 15), (15, 21)]
示例#4
0
def partition_sequence_by_counts(
    sequence,
    counts,
    cyclic=False,
    overhang=False,
    reversed_=False,
    ):
    r'''Partitions `sequence` by `counts`.

    ..  container:: example

        **Example 1.** Partitions sequence once by counts without overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [3],
            ...     cyclic=False,
            ...     overhang=False,
            ...     )
            [[0, 1, 2]]

        **Example 2.** Partitions sequence once by counts without overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(16)),
            ...     [4, 3],
            ...     cyclic=False,
            ...     overhang=False,
            ...     )
            [[0, 1, 2, 3], [4, 5, 6]]

    ..  container:: example

        **Example 3.** Partitions sequence cyclically by counts without
        overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [3],
            ...     cyclic=True,
            ...     overhang=False,
            ...     )
            [[0, 1, 2], [3, 4, 5], [6, 7, 8]]

        **Example 4.** Partitions sequence cyclically by counts without
        overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(16)),
            ...     [4, 3],
            ...     cyclic=True,
            ...     overhang=False,
            ...     )
            [[0, 1, 2, 3], [4, 5, 6], [7, 8, 9, 10], [11, 12, 13]]

    ..  container:: example

        **Example 5.** Partitions sequence once by counts with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [3],
            ...     cyclic=False,
            ...     overhang=True,
            ...     )
            [[0, 1, 2], [3, 4, 5, 6, 7, 8, 9]]

        **Example 6.** Partitions sequence once by counts with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(16)),
            ...     [4, 3],
            ...     cyclic=False,
            ...     overhang=True,
            ...     )
            [[0, 1, 2, 3], [4, 5, 6], [7, 8, 9, 10, 11, 12, 13, 14, 15]]

    ..  container:: example

        **Example 7.** Partitions sequence cyclically by counts with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [3],
            ...     cyclic=True,
            ...     overhang=True,
            ...     )
            [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]

        **Example 8.** Partitions sequence cyclically by counts with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(16)),
            ...     [4, 3],
            ...     cyclic=True,
            ...     overhang=True,
            ...     )
            [[0, 1, 2, 3], [4, 5, 6], [7, 8, 9, 10], [11, 12, 13], [14, 15]]

    ..  container:: example

        **Example 9.** Partitions sequence once by counts and asserts
        that sequence partitions exactly (with no overhang):

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [2, 3, 5],
            ...     cyclic=False,
            ...     overhang=Exact,
            ...     )
            [[0, 1], [2, 3, 4], [5, 6, 7, 8, 9]]

        **Example 10.** Partitions sequence cyclically by counts and asserts
        that sequence partitions exactly (with no overhang):

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [2],
            ...     cyclic=True,
            ...     overhang=Exact,
            ...     )
            [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9]]

    ..  container:: example

        **Example 11.** Partitions list:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [3],
            ...     cyclic=False,
            ...     overhang=True,
            ...     )
            [[0, 1, 2], [3, 4, 5, 6, 7, 8, 9]]

        **Example 12.** Partitions tuple:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     tuple(range(10)),
            ...     [3],
            ...     cyclic=False,
            ...     overhang=True,
            ...     )
            [(0, 1, 2), (3, 4, 5, 6, 7, 8, 9)]

        **Example 13.** Partitions string:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     'some text',
            ...     [3],
            ...     cyclic=False,
            ...     overhang=True,
            ...     )
            ['som', 'e text']

    ..  container:: example

        **Example 14.** Reverses cyclic partition with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
            ...     [3],
            ...     cyclic=True,
            ...     overhang=True,
            ...     reversed_=True,
            ...     )
            [[0], [1, 2, 3], [4, 5, 6], [7, 8, 9]]

        **Example 15.** Reverses cyclic partition without overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
            ...     [3],
            ...     cyclic=True,
            ...     overhang=False,
            ...     reversed_=True,
            ...     )
            [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

        **Example 16.** Reverses acyclic partition with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
            ...     [3],
            ...     cyclic=False,
            ...     overhang=True,
            ...     reversed_=True,
            ...     )
            [[0, 1, 2, 3, 4, 5, 6], [7, 8, 9]]

        **Example 17.** Reverses acyclic partition without overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
            ...     [3],
            ...     cyclic=False,
            ...     overhang=False,
            ...     reversed_=True,
            ...     )
            [[7, 8, 9]]

    Returns list of objects with type equal to that of `sequence`.
    '''
    from abjad.tools import sequencetools

    if not isinstance(sequence, collections.Sequence):
        message = 'must be sequence: {!r}.'
        message = message.format(sequence)
        raise TypeError(message)
    if not isinstance(counts, collections.Iterable):
        message = 'must be iterable: {!r}.'
        message = message.format(counts)
        raise TypeError(message)

    sequence_type = type(sequence)
    if reversed_:
        sequence = reversed(sequence)    
        sequence = sequence_type(sequence)

    if overhang == Exact:
        result_with_overhang = partition_sequence_by_counts(
            sequence,
            counts,
            cyclic=cyclic,
            overhang=True,
            )
        result_without_overhang = partition_sequence_by_counts(
            sequence,
            counts,
            cyclic=cyclic,
            overhang=False,
            )
        if result_with_overhang == result_without_overhang:
            return result_without_overhang
        else:
            message = 'sequence does not partition exactly.'
            raise Exception(message)

    result = []
    if cyclic:
        if overhang:
            counts = sequencetools.repeat_sequence_to_weight(
                counts,
                len(sequence),
                )
        else:
            counts = sequencetools.repeat_sequence_to_weight(
                counts, 
                len(sequence), 
                allow_total=Less,
                )
    elif overhang:
        weight_counts = mathtools.weight(counts)
        len_sequence = len(sequence)
        if weight_counts < len_sequence:
            counts = list(counts)
            counts.append(len(sequence) - weight_counts)
    for start, stop in mathtools.cumulative_sums_pairwise(counts):
        part = sequence[start:stop]
        result.append(part)

    if reversed_:
        result_ = []
        for part in reversed(result):
            part_type = type(part)
            part = reversed(part)
            part = part_type(part)
            result_.append(part)
        result = result_

    return result
示例#5
0
def partition_sequence_by_counts(
    sequence,
    counts,
    cyclic=False,
    overhang=False,
    copy_elements=False,
):
    r'''Partitions sequence by counts.

    ..  container:: example

        **Example 1a.** Partition sequence once by counts without overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [3],
            ...     cyclic=False,
            ...     overhang=False,
            ...     )
            [[0, 1, 2]]

    ..  container:: example

        **Example 1b.** Partition sequence once by counts without overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(16)),
            ...     [4, 3],
            ...     cyclic=False,
            ...     overhang=False,
            ...     )
            [[0, 1, 2, 3], [4, 5, 6]]

    ..  container:: example

        **Example 2a.** Partition sequence cyclically by counts without
        overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [3],
            ...     cyclic=True,
            ...     overhang=False,
            ...     )
            [[0, 1, 2], [3, 4, 5], [6, 7, 8]]

    ..  container:: example

        **Example 2b.** Partition sequence cyclically by counts without
        overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(16)),
            ...     [4, 3],
            ...     cyclic=True,
            ...     overhang=False,
            ...     )
            [[0, 1, 2, 3], [4, 5, 6], [7, 8, 9, 10], [11, 12, 13]]

    ..  container:: example

        **Example 3a.** Partition sequence once by counts with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [3],
            ...     cyclic=False,
            ...     overhang=True,
            ...     )
            [[0, 1, 2], [3, 4, 5, 6, 7, 8, 9]]

    ..  container:: example

        **Example 3b.** Partition sequence once by counts with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(16)),
            ...     [4, 3],
            ...     cyclic=False,
            ...     overhang=True,
            ...     )
            [[0, 1, 2, 3], [4, 5, 6], [7, 8, 9, 10, 11, 12, 13, 14, 15]]

    ..  container:: example

        **Example 4a.** Partition sequence cyclically by counts with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [3],
            ...     cyclic=True,
            ...     overhang=True,
            ...     )
            [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]

    ..  container:: example

        **Example 4b.** Partition sequence cyclically by counts with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(16)),
            ...     [4, 3],
            ...     cyclic=True,
            ...     overhang=True,
            ...     )
            [[0, 1, 2, 3], [4, 5, 6], [7, 8, 9, 10], [11, 12, 13], [14, 15]]

    Returns list of sequence objects.
    '''
    from abjad.tools import sequencetools

    if not isinstance(counts, (tuple, list)):
        message = 'must be list or tuple: {!r}.'
        message = message.format(counts)
        raise TypeError(message)

    result = []

    if cyclic:
        if overhang:
            counts = sequencetools.repeat_sequence_to_weight(
                counts,
                len(sequence),
            )
        else:
            counts = sequencetools.repeat_sequence_to_weight(
                counts,
                len(sequence),
                allow_total=Less,
            )
    elif overhang:
        weight_counts = mathtools.weight(counts)
        len_sequence = len(sequence)
        if weight_counts < len_sequence:
            counts = list(counts)
            counts.append(len(sequence) - weight_counts)

    for start, stop in mathtools.cumulative_sums_pairwise(counts):
        result.append(type(sequence)(sequence[start:stop]))

    return result
    def tessalate_by_ratio(self, 
        ratio, 
        invert_on_negative=False, 
        reflect_on_negative=False,
        y_center=None,
        ):
        r'''Concatenate copies of a BreakPointFunction, stretched by 
        the weights in `ratio`:

        ::

            >>> bpf = interpolationtools.BreakPointFunction(
            ...     {0.: 0., 0.25: 0.9, 1.: 1.})

        ::

            >>> bpf.tessalate_by_ratio((1, 2, 3))
            BreakPointFunction({
                0.0: (0.0,),
                0.25: (0.9,),
                1.0: (1.0, 0.0),
                1.5: (0.9,),
                3.0: (1.0, 0.0),
                3.75: (0.9,),
                6.0: (1.0,)
            })

        Negative ratio values are still treated as weights.

        If `invert_on_negative` is True, copies corresponding to 
        negative ratio values will be inverted:

        ::

            >>> bpf.tessalate_by_ratio((1, -2, 3), invert_on_negative=True)
            BreakPointFunction({
                0.0: (0.0,),
                0.25: (0.9,),
                1.0: (1.0,),
                1.5: (0.09999999999999998,),
                3.0: (0.0,),
                3.75: (0.9,),
                6.0: (1.0,)
            })

        If `y_center` is not None, inversion will take `y_center` as 
        the axis of inversion:

        ::

            >>> bpf.tessalate_by_ratio((1, -2, 3), 
            ...     invert_on_negative=True, y_center=0)
            BreakPointFunction({
                0.0: (0.0,),
                0.25: (0.9,),
                1.0: (1.0, 0.0),
                1.5: (-0.9,),
                3.0: (-1.0, 0.0),
                3.75: (0.9,),
                6.0: (1.0,)
            })

        If `reflect_on_negative` is True, copies corresponding to 
        negative ratio values will be reflectd:

        ::

            >>> bpf.tessalate_by_ratio((1, -2, 3), reflect_on_negative=True)
            BreakPointFunction({
                0.0: (0.0,),
                0.25: (0.9,),
                1.0: (1.0,),
                2.5: (0.9,),
                3.0: (0.0,),
                3.75: (0.9,),
                6.0: (1.0,)
            })

        Inversion may be combined reflecting.

        Emit new `BreakPointFunction` instance.
        '''
        ratio = mathtools.Ratio(ratio)
        tessalated_bpf = None
        for i, pair in enumerate(mathtools.cumulative_sums_pairwise(
            [abs(x) for x in ratio])):
            sign = mathtools.sign(ratio[i])
            start, stop = pair
            bpf = self.scale_x_axis(start, stop)
            if sign < 0:
                if invert_on_negative:
                    bpf = bpf.invert(y_center)
                if reflect_on_negative:
                    bpf = bpf.reflect()
            if i == 0:
                tessalated_bpf = bpf
            else:
                tessalated_bpf = tessalated_bpf.concatenate(bpf)
        return tessalated_bpf
def partition_sequence_by_backgrounded_weights(sequence, weights):
    r'''Partition `sequence` by backgrounded `weights`:

    ::

        >>> sequencetools.partition_sequence_by_backgrounded_weights(
        ...     [-5, -15, -10], [20, 10])
        [[-5, -15], [-10]]

    Further examples:

    ::

        >>> sequencetools.partition_sequence_by_backgrounded_weights(
        ...     [-5, -15, -10], [5, 5, 5, 5, 5, 5])
        [[-5], [-15], [], [], [-10], []]

    ::

        >>> sequencetools.partition_sequence_by_backgrounded_weights(
        ...     [-5, -15, -10], [1, 29])
        [[-5], [-15, -10]]

    ::

        >>> sequencetools.partition_sequence_by_backgrounded_weights(
        ...     [-5, -15, -10], [2, 28])
        [[-5], [-15, -10]]

    ::

        >>> sequencetools.partition_sequence_by_backgrounded_weights(
        ...     [-5, -15, -10], [1, 1, 1, 1, 1, 25])
        [[-5], [], [], [], [], [-15, -10]]

    The term `backgrounded` is a short-hand concocted specifically
    for this function; rely on the formal definition to understand
    the function actually does.

    Input constraint: the weight of `sequence` must equal the weight
    of `weights` exactly.

    The signs of the elements in `sequence` are ignored.

    Formal definition: partition `sequence` into `parts` such that
    (1.) the length of `parts` equals the length of `weights`;
    (2.) the elements in `sequence` appear in order in `parts`; and
    (3.) some final condition that is difficult to formalize.

    Notionally what's going on here is that the elements of `weights`
    are acting as a list of successive time intervals into which the
    elements of `sequence` are being fit in accordance with the start
    offset of each `sequence` element.

    The function models the grouping together of successive timespans
    according to which of an underlying sequence of time intervals
    it is in which each time span begins.

    Note that, for any input to this function, the flattened output
    of this function always equals `sequence` exactly.

    Note too that while `partition` is being used here in the sense of
    the other partitioning functions in the API, the distinguishing feature
    is this funciton is its ability to produce empty lists as output.

    Returns list of `sequence` objects.
    '''
    from abjad.tools import sequencetools

    assert all(0 < x for x in weights)
    assert mathtools.weight(sequence) == mathtools.weight(weights)

    start_offsets = \
        mathtools.cumulative_sums([abs(x) for x in sequence])[:-1]
    indicator = zip(start_offsets, sequence)

    result = []
    for interval_start, interval_stop in \
        mathtools.cumulative_sums_pairwise(weights):
        part = []
        for pair in indicator[:]:
            if interval_start <= pair[0] < interval_stop:
                part.append(pair[1])
                indicator.remove(pair)
        result.append(part)

    return result
示例#8
0
    def tessalate_by_ratio(
        self,
        ratio,
        invert_on_negative=False,
        reflect_on_negative=False,
        y_center=None,
    ):
        r'''Concatenate copies of a BreakPointFunction, stretched by
        the weights in `ratio`:

        ::

            >>> bpf = interpolationtools.BreakPointFunction(
            ...     {0.: 0., 0.25: 0.9, 1.: 1.})

        ::

            >>> bpf.tessalate_by_ratio((1, 2, 3))
            BreakPointFunction({
                0.0: (0.0,),
                0.25: (0.9,),
                1.0: (1.0, 0.0),
                1.5: (0.9,),
                3.0: (1.0, 0.0),
                3.75: (0.9,),
                6.0: (1.0,)
            })

        Negative ratio values are still treated as weights.

        If `invert_on_negative` is True, copies corresponding to
        negative ratio values will be inverted:

        ::

            >>> bpf.tessalate_by_ratio((1, -2, 3), invert_on_negative=True)
            BreakPointFunction({
                0.0: (0.0,),
                0.25: (0.9,),
                1.0: (1.0,),
                1.5: (0.09999999999999998,),
                3.0: (0.0,),
                3.75: (0.9,),
                6.0: (1.0,)
            })

        If `y_center` is not None, inversion will take `y_center` as
        the axis of inversion:

        ::

            >>> bpf.tessalate_by_ratio((1, -2, 3),
            ...     invert_on_negative=True, y_center=0)
            BreakPointFunction({
                0.0: (0.0,),
                0.25: (0.9,),
                1.0: (1.0, 0.0),
                1.5: (-0.9,),
                3.0: (-1.0, 0.0),
                3.75: (0.9,),
                6.0: (1.0,)
            })

        If `reflect_on_negative` is True, copies corresponding to
        negative ratio values will be reflected:

        ::

            >>> bpf.tessalate_by_ratio((1, -2, 3), reflect_on_negative=True)
            BreakPointFunction({
                0.0: (0.0,),
                0.25: (0.9,),
                1.0: (1.0,),
                2.5: (0.9,),
                3.0: (0.0,),
                3.75: (0.9,),
                6.0: (1.0,)
            })

        Inversion may be combined reflecting.

        Emit new `BreakPointFunction` instance.
        '''
        ratio = mathtools.Ratio(ratio)
        tessalated_bpf = None
        for i, pair in enumerate(
                mathtools.cumulative_sums_pairwise(
                    [abs(x) for x in ratio.numbers])):
            sign = mathtools.sign(ratio.numbers[i])
            start, stop = pair
            bpf = self.scale_x_axis(start, stop)
            if sign < 0:
                if invert_on_negative:
                    bpf = bpf.invert(y_center)
                if reflect_on_negative:
                    bpf = bpf.reflect()
            if i == 0:
                tessalated_bpf = bpf
            else:
                tessalated_bpf = tessalated_bpf.concatenate(bpf)
        return tessalated_bpf
def partition_sequence_by_counts(
    sequence,
    counts,
    cyclic=False,
    overhang=False,
    copy_elements=False,
    ):
    r'''Partitions sequence by counts.

    ..  container:: example

        **Example 1a.** Partition sequence once by counts without overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [3],
            ...     cyclic=False,
            ...     overhang=False,
            ...     )
            [[0, 1, 2]]

    ..  container:: example

        **Example 1b.** Partition sequence once by counts without overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(16)),
            ...     [4, 3],
            ...     cyclic=False,
            ...     overhang=False,
            ...     )
            [[0, 1, 2, 3], [4, 5, 6]]

    ..  container:: example

        **Example 2a.** Partition sequence cyclically by counts without
        overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [3],
            ...     cyclic=True,
            ...     overhang=False,
            ...     )
            [[0, 1, 2], [3, 4, 5], [6, 7, 8]]

    ..  container:: example

        **Example 2b.** Partition sequence cyclically by counts without
        overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(16)),
            ...     [4, 3],
            ...     cyclic=True,
            ...     overhang=False,
            ...     )
            [[0, 1, 2, 3], [4, 5, 6], [7, 8, 9, 10], [11, 12, 13]]

    ..  container:: example

        **Example 3a.** Partition sequence once by counts with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [3],
            ...     cyclic=False,
            ...     overhang=True,
            ...     )
            [[0, 1, 2], [3, 4, 5, 6, 7, 8, 9]]

    ..  container:: example

        **Example 3b.** Partition sequence once by counts with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(16)),
            ...     [4, 3],
            ...     cyclic=False,
            ...     overhang=True,
            ...     )
            [[0, 1, 2, 3], [4, 5, 6], [7, 8, 9, 10, 11, 12, 13, 14, 15]]

    ..  container:: example

        **Example 4a.** Partition sequence cyclically by counts with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [3],
            ...     cyclic=True,
            ...     overhang=True,
            ...     )
            [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]

    ..  container:: example

        **Example 4b.** Partition sequence cyclically by counts with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(16)),
            ...     [4, 3],
            ...     cyclic=True,
            ...     overhang=True,
            ...     )
            [[0, 1, 2, 3], [4, 5, 6], [7, 8, 9, 10], [11, 12, 13], [14, 15]]

    Returns list of sequence objects.
    '''
    from abjad.tools import sequencetools

    result = []

    if cyclic:
        if overhang:
            counts = sequencetools.repeat_sequence_to_weight(
                counts, len(sequence))
        else:
            counts = sequencetools.repeat_sequence_to_weight(
                counts, len(sequence), allow_total=Less)
    elif overhang:
        weight_counts = mathtools.weight(counts)
        len_sequence = len(sequence)
        if weight_counts < len_sequence:
            counts = list(counts)
            counts.append(len(sequence) - weight_counts)

    for start, stop in mathtools.cumulative_sums_pairwise(counts):
        result.append(type(sequence)(sequence[start:stop]))

    return result