<commit_before># cython: language_level=3

# Copyright (c) 2014, Dr <NAME>, Raysect Project
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#     1. Redistributions of source code must retain the above copyright notice,
#        this list of conditions and the following disclaimer.
#
#     2. Redistributions in binary form must reproduce the above copyright
#        notice, this list of conditions and the following disclaimer in the
#        documentation and/or other materials provided with the distribution.
#
#     3. Neither the name of the Raysect Project nor the names of its
#        contributors may be used to endorse or promote products derived from
#        this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

cimport cython

@cython.cdivision(True)
@cython.boundscheck(False)
@cython.wraparound(False)
cdef inline int find_index(ndarray x, double v):
    """
    Locates the lower index or the range that contains the specified value.

    This function performs a fast bisection search to identify the index range
    (bin) that encloses the specified value. The lower index of the range is
    returned. This function expects a monotonically increasing ndarray for x.
    The array type must be double and may not be empty.

    Each array bin has the defined range [x[i], x[i+1]) where i is the index of
    the bin.

    If the value lies below the range of the array this function will return an
    index of -1. If the value lies above the range of the array then the last
    index of the array will be returned.

    .. WARNING:: For speed, this function does not perform any type or bounds
       checking. Supplying malformed data may result in data corruption or a
       segmentation fault.

    :param ndarray x: An array containing monotonically increasing values.
    :param double v: The value to search for.
    :return: The lower index f the bin containing the search value.
    :rtype: int
    """

    cdef:
        double[::1] x_view
        int bottom_index
        int top_index
        int bisection_index

    x_view = x

    # check array ends before doing a costly bisection search
    if v < x_view[0]:

        # value is lower than the lowest value in the array
        return -1

    top_index = len(x) - 1
    if v >= x_view[top_index]:

        # value is above or equal to the highest value in the array
        return top_index

    # bisection search inside array range
    bottom_index = 0
    bisection_index = top_index / 2
    while (top_index - bottom_index) != 1:

        if v >= x_view[bisection_index]:

            bottom_index = bisection_index

        else:

            top_index = bisection_index

        bisection_index = (top_index + bottom_index) / 2

    return bottom_index


@cython.cdivision(True)
@cython.boundscheck(False)
@cython.wraparound(False)
cdef inline double integrate(ndarray x, ndarray y, double x0, double x1):
    """
    Integrates a linearly interpolated function between two points.

    This function performs a trapezium rule integration of the sampled function
    between point x0 and point x1. Outside the bounds of the array the function
    value is taken to be the end value of the array closest to the requested
    point (nearest-neighbour extrapolation).

    If x1 < x0 the integral range is treated as null and zero is returned.

    .. WARNING:: For speed, this function does not perform any type or bounds
       checking. Supplying malformed data may result in data corruption or a
       segmentation fault.

    :param ndarray x: An array containing monotonically increasing values.
    :param ndarray y: An array of sample values corresponding to the x array points.
    :param double x0: Start point of integration.
    :param double x1: End point of integration.
    :return: Integral between x0 and x1
    :rtype: double
    """

    cdef:
        double[::1] x_view, y_view
        double integral_sum
        int top_index
        int lower_index
        int upper_index
        int index
        double y0, y1, m

    # invalid range
    if x1 <= x0:

        return 0.0

    # identify array indices that lie between requested values
    lower_index = find_index(x, x0) + 1
    upper_index = find_index(x, x1)

    # are both points below the bottom of the array?
    if upper_index == 0:

        # extrapolate from first array value (nearest-neighbour)
        return y[0] * (x1 - x0)

    # are both points beyond the top of the array?
    top_index = len(x) - 1
    if lower_index > top_index:

        # extrapolate from last array value (nearest-neighbour)
        return y[top_index] * (x1 - x0)

    # fast memoryview access to numpy arrays
    x_view = x
    y_view = y

    # numerically integrate array
    if lower_index > upper_index:

        # both values lie inside the same array segment
        # the names lower_index and upper_index are now misnomers, they are swapped!
        m = (y_view[lower_index] - y_view[upper_index]) / (x_view[lower_index] - x_view[upper_index])
        y0 = m * (x0 - x_view[upper_index]) + y_view[upper_index]
        y1 = m * (x1 - x_view[upper_index]) + y_view[upper_index]

        # trapezium rule integration
        return 0.5 * (y0 + y1) * (x1 - x0)<commit_msg>Fix off by one indexing error in integrate()<commit_after># cython: language_level=3

# Copyright (c) 2014, Dr <NAME>, Raysect Project
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#     1. Redistributions of source code must retain the above copyright notice,
#        this list of conditions and the following disclaimer.
#
#     2. Redistributions in binary form must reproduce the above copyright
#        notice, this list of conditions and the following disclaimer in the
#        documentation and/or other materials provided with the distribution.
#
#     3. Neither the name of the Raysect Project nor the names of its
#        contributors may be used to endorse or promote products derived from
#        this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

cimport cython

@cython.cdivision(True)
@cython.boundscheck(False)
@cython.wraparound(False)
cdef inline int find_index(ndarray x, double v):
    """
    Locates the lower index or the range that contains the specified value.

    This function performs a fast bisection search to identify the index range
    (bin) that encloses the specified value. The lower index of the range is
    returned. This function expects a monotonically increasing ndarray for x.
    The array type must be double and may not be empty.

    Each array bin has the defined range [x[i], x[i+1]) where i is the index of
    the bin.

    If the value lies below the range of the array this function will return an
    index of -1. If the value lies above the range of the array then the last
    index of the array will be returned.

    .. WARNING:: For speed, this function does not perform any type or bounds
       checking. Supplying malformed data may result in data corruption or a
       segmentation fault.

    :param ndarray x: An array containing monotonically increasing values.
    :param double v: The value to search for.
    :return: The lower index f the bin containing the search value.
    :rtype: int
    """

    cdef:
        double[::1] x_view
        int bottom_index
        int top_index
        int bisection_index

    x_view = x

    # check array ends before doing a costly bisection search
    if v < x_view[0]:

        # value is lower than the lowest value in the array
        return -1

    top_index = len(x) - 1
    if v >= x_view[top_index]:

        # value is above or equal to the highest value in the array
        return top_index

    # bisection search inside array range
    bottom_index = 0
    bisection_index = top_index / 2
    while (top_index - bottom_index) != 1:

        if v >= x_view[bisection_index]:

            bottom_index = bisection_index

        else:

            top_index = bisection_index

        bisection_index = (top_index + bottom_index) / 2

    return bottom_index


@cython.cdivision(True)
@cython.boundscheck(False)
@cython.wraparound(False)
cdef inline double integrate(ndarray x, ndarray y, double x0, double x1):
    """
    Integrates a linearly interpolated function between two points.

    This function performs a trapezium rule integration of the sampled function
    between point x0 and point x1. Outside the bounds of the array the function
    value is taken to be the end value of the array closest to the requested
    point (nearest-neighbour extrapolation).

    If x1 < x0 the integral range is treated as null and zero is returned.

    .. WARNING:: For speed, this function does not perform any type or bounds
       checking. Supplying malformed data may result in data corruption or a
       segmentation fault.

    :param ndarray x: An array containing monotonically increasing values.
    :param ndarray y: An array of sample values corresponding to the x array points.
    :param double x0: Start point of integration.
    :param double x1: End point of integration.
    :return: Integral between x0 and x1
    :rtype: double
    """

    cdef:
        double[::1] x_view, y_view
        double integral_sum
        int top_index
        int lower_index
        int upper_index
        int index
        double y0, y1, m

    # invalid range
    if x1 <= x0:

        return 0.0

    # identify array indices that lie between requested values
    lower_index = find_index(x, x0) + 1
    upper_index = find_index(x, x1)

    # are both points below the bottom of the array?
    if upper_index == -1:

        # extrapolate from first array value (nearest-neighbour)
        return y[0] * (x1 - x0)

    # are both points beyond the top of the array?
    top_index = len(x) - 1
    if lower_index > top_index:

        # extrapolate from last array value (nearest-neighbour)
        return y[top_index] * (x1 - x0)

    # fast memoryview access to numpy arrays
    x_view = x
    y_view = y

    # numerically integrate array
    if lower_index > upper_index:

        # both values lie inside the same array segment
        # the names lower_index and upper_index are now misnomers, they are swapped!
        m = (y_view[lower_index] - y_view[upper_index]) / (x_view[lower_index] - x_view[upper_index])
        y0 = m * (x0 - x_view[upper_index]) + y_view[upper_index]
        y1 = m * (x1 - x_view[upper_index]) + y_view[upper_index]

        # trapezium rule integration
        return 0.5 * (y0 + y1) * (x1 - x0)
{'fraction_non_alphanumeric': 0.05718689162881246, 'fraction_numerical': 0.008922777417261519, 'mean_word_length': 2.940236497283477, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 13, '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': '3195604', 'n_tokens_mistral': 3530, 'n_tokens_neox': 3318, 'n_words': 1580}