File size: 3,297 Bytes
7885a28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
"""A small collection of auxiliary functions that operate on arrays."""

from cython cimport floating
from cython.parallel cimport prange
from libc.math cimport fabs
from libc.float cimport DBL_MAX, FLT_MAX

from ._cython_blas cimport _copy, _rotg, _rot
from ._typedefs cimport float64_t


ctypedef fused real_numeric:
    short
    int
    long
    long long
    float
    double


def min_pos(const floating[:] X):
    """Find the minimum value of an array over positive values.

    Returns the maximum representable value of the input dtype if none of the
    values are positive.

    Parameters
    ----------
    X : ndarray of shape (n,)
        Input array.

    Returns
    -------
    min_val : float
        The smallest positive value in the array, or the maximum representable value
         of the input dtype if no positive values are found.

    Examples
    --------
    >>> import numpy as np
    >>> from sklearn.utils.arrayfuncs import min_pos
    >>> X = np.array([0, -1, 2, 3, -4, 5])
    >>> min_pos(X)
    2.0
    """
    cdef Py_ssize_t i
    cdef floating min_val = FLT_MAX if floating is float else DBL_MAX
    for i in range(X.size):
        if 0. < X[i] < min_val:
            min_val = X[i]
    return min_val


def _all_with_any_reduction_axis_1(real_numeric[:, :] array, real_numeric value):
    """Check whether any row contains all values equal to `value`.

    It is equivalent to `np.any(np.all(X == value, axis=1))`, but it avoids to
    materialize the temporary boolean matrices in memory.

    Parameters
    ----------
    array: array-like
        The array to be checked.
    value: short, int, long, float, or double
        The value to use for the comparison.

    Returns
    -------
    any_all_equal: bool
        Whether or not any rows contains all values equal to `value`.
    """
    cdef Py_ssize_t i, j

    for i in range(array.shape[0]):
        for j in range(array.shape[1]):
            if array[i, j] != value:
                break
        else:  # no break
            return True
    return False


# General Cholesky Delete.
# Remove an element from the cholesky factorization
# m = columns
# n = rows
#
# TODO: put transpose as an option
def cholesky_delete(floating[:, :] L, int go_out):
    cdef:
        int n = L.shape[0]
        int m = L.strides[0]
        floating c, s
        floating *L1
        int i

    if floating is float:
        m /= sizeof(float)
    else:
        m /= sizeof(double)

    # delete row go_out
    L1 = &L[0, 0] + (go_out * m)
    for i in range(go_out, n-1):
        _copy(i + 2, L1 + m, 1, L1, 1)
        L1 += m

    L1 = &L[0, 0] + (go_out * m)
    for i in range(go_out, n-1):
        _rotg(L1 + i, L1 + i + 1, &c, &s)
        if L1[i] < 0:
            # Diagonals cannot be negative
            L1[i] = fabs(L1[i])
            c = -c
            s = -s

        L1[i + 1] = 0.  # just for cleanup
        L1 += m

        _rot(n - i - 2, L1 + i, m, L1 + i + 1, m, c, s)


def sum_parallel(const floating [:] array, int n_threads):
    """Parallel sum, always using float64 internally."""
    cdef:
        float64_t out = 0.
        int i = 0

    for i in prange(
        array.shape[0], schedule='static', nogil=True, num_threads=n_threads
    ):
        out += array[i]

    return out