• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

markrogoyski / math-php / 4908566749

pending completion
4908566749

push

github

Mark Rogoyski
Github actions changes for static analysis.

7538 of 7544 relevant lines covered (99.92%)

184.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.92
/src/Search.php
1
<?php
2

3
namespace MathPHP;
4

5
use MathPHP\Exception;
6

7
/**
8
 * Search
9
 * Various functions to find specific indices in an array.
10
 */
11
class Search
12
{
13
    /**
14
     * Search Sorted
15
     * Find the array indices where items should be inserted to maintain sorted order.
16
     *
17
     * Inspired by and similar to Python NumPy's searchsorted
18
     *
19
     * @param float[]|int[] $haystack Sorted array with standard increasing numerical array keys
20
     * @param float         $needle   Item wanting to insert
21
     *
22
     * @return int Index of where you would insert the needle and maintain sorted order
23
     */
24
    public static function sorted(array $haystack, float $needle): int
25
    {
26
        if (empty($haystack)) {
96✔
27
            return 0;
1✔
28
        }
29

30
        $index = 0;
95✔
31
        foreach ($haystack as $i => $val) {
95✔
32
            if ($needle > $val) {
95✔
33
                $index++;
81✔
34
            } else {
35
                return $index;
87✔
36
            }
37
        }
38

39
        return $index;
10✔
40
    }
41

42
    /**
43
     * ArgMax
44
     * Find the array index of the maximum value.
45
     *
46
     * In case of the maximum value appearing multiple times, the index of the first occurrence is returned.
47
     * In the case NAN is present, the index of the first NAN is returned.
48
     *
49
     * Inspired by and similar to Python NumPy's argmax
50
     *
51
     * @param float[]|int[] $values
52
     *
53
     * @return int Index of the first occurrence of the maximum value
54
     *
55
     * @throws Exception\BadDataException if the array of values is empty
56
     */
57
    public static function argMax(array $values): int
58
    {
59
        if (empty($values)) {
49✔
60
            throw new Exception\BadDataException('Cannot find the argMax of an empty array');
1✔
61
        }
62

63
        // Special case: NAN wins if present
64
        $nanPresent = \array_filter(
48✔
65
            $values,
48✔
66
            function ($value) {
67
                return \is_float($value) && \is_nan($value);
48✔
68
            }
48✔
69
        );
70
        if (\count($nanPresent) > 0) {
48✔
71
            foreach ($values as $i => $v) {
8✔
72
                if (\is_nan($v)) {
8✔
73
                    return $i;
8✔
74
                }
75
            }
76
        }
77

78
        // Standard case: Find max and return index
79
        return self::baseArgMax($values);
40✔
80
    }
81

82
    /**
83
     * NanArgMax
84
     * Find the array index of the maximum value, ignoring NANs
85
     *
86
     * In case of the maximum value appearing multiple times, the index of the first occurrence is returned.
87
     *
88
     * Inspired by and similar to Python NumPy's nanargmax
89
     *
90
     * @param float[]|int[] $values
91
     *
92
     * @return int Index of the first occurrence of the maximum value
93
     *
94
     * @throws Exception\BadDataException if the array of values is empty
95
     * @throws Exception\BadDataException if the array only contains NANs
96
     */
97
    public static function nanArgMax(array $values): int
98
    {
99
        if (empty($values)) {
50✔
100
            throw new Exception\BadDataException('Cannot find the argMax of an empty array');
1✔
101
        }
102

103
        $valuesWithoutNans = \array_filter(
49✔
104
            $values,
49✔
105
            function ($value) {
106
                return !\is_nan($value);
49✔
107
            }
49✔
108
        );
109
        if (\count($valuesWithoutNans) === 0) {
49✔
110
            throw new Exception\BadDataException('Array of all NANs has no nanArgMax');
1✔
111
        }
112

113
        return self::baseArgMax($valuesWithoutNans);
48✔
114
    }
115

116
    /**
117
     * Base argMax calculation
118
     * Find the array index of the maximum value.
119
     *
120
     * In case of the maximum value appearing multiple times, the index of the first occurrence is returned.
121
     *
122
     * @param float[]|int[] $values
123
     *
124
     * @return int Index of the first occurrence of the maximum value
125
     *
126
     * @throws \LogicException if the array of values is empty - should never happen
127
     */
128
    private static function baseArgMax(array $values): int
129
    {
130
        $max = \max($values);
88✔
131
        foreach ($values as $i => $v) {
88✔
132
            if ($v === $max) {
88✔
133
                return $i;
88✔
134
            }
135
        }
136

137
        throw new \LogicException('argMax values is empty--should not happen');
×
138
    }
139

140
    /**
141
     * ArgMin
142
     * Find the array index of the minimum value.
143
     *
144
     * In case of the minimum value appearing multiple times, the index of the first occurrence is returned.
145
     * In the case NAN is present, the index of the first NAN is returned.
146
     *
147
     * Inspired by and similar to Python NumPy's argmin
148
     *
149
     * @param float[]|int[] $values
150
     *
151
     * @return int Index of the first occurrence of the minimum value
152
     *
153
     * @throws Exception\BadDataException if the array of values is empty
154
     */
155
    public static function argMin(array $values): int
156
    {
157
        if (empty($values)) {
49✔
158
            throw new Exception\BadDataException('Cannot find the argMin of an empty array');
1✔
159
        }
160

161
        // Special case: NAN wins if present
162
        $nanPresent = \array_filter(
48✔
163
            $values,
48✔
164
            function ($value) {
165
                return \is_float($value) && \is_nan($value);
48✔
166
            }
48✔
167
        );
168
        if (\count($nanPresent) > 0) {
48✔
169
            foreach ($values as $i => $v) {
8✔
170
                if (\is_nan($v)) {
8✔
171
                    return $i;
8✔
172
                }
173
            }
174
        }
175

176
        // Standard case: Find max and return index
177
        return self::baseArgMin($values);
40✔
178
    }
179

180
    /**
181
     * NanArgMin
182
     * Find the array index of the minimum value, ignoring NANs
183
     *
184
     * In case of the minimum value appearing multiple times, the index of the first occurrence is returned.
185
     *
186
     * Inspired by and similar to Python NumPy's nanargin
187
     *
188
     * @param float[]|int[] $values
189
     *
190
     * @return int Index of the first occurrence of the minimum value
191
     *
192
     * @throws Exception\BadDataException if the array of values is empty
193
     * @throws Exception\BadDataException if the array only contains NANs
194
     */
195
    public static function nanArgMin(array $values): int
196
    {
197
        if (empty($values)) {
50✔
198
            throw new Exception\BadDataException('Cannot find the nanArgMin of an empty array');
1✔
199
        }
200

201
        $valuesWithoutNans = \array_filter(
49✔
202
            $values,
49✔
203
            function ($value) {
204
                return !\is_nan($value);
49✔
205
            }
49✔
206
        );
207
        if (\count($valuesWithoutNans) === 0) {
49✔
208
            throw new Exception\BadDataException('Array of all NANs has no nanArgMax');
1✔
209
        }
210

211
        return self::baseArgMin($valuesWithoutNans);
48✔
212
    }
213

214
    /**
215
     * Base argMin calculation
216
     * Find the array index of the minimum value.
217
     *
218
     * In case of the maximum value appearing multiple times, the index of the first occurrence is returned.
219
     *
220
     * @param float[]|int[] $values
221
     *
222
     * @return int Index of the first occurrence of the minimum value
223
     *
224
     * @throws \LogicException if the array of values is empty - should never happen
225
     */
226
    private static function baseArgMin(array $values): int
227
    {
228
        $max = \min($values);
88✔
229
        foreach ($values as $i => $v) {
88✔
230
            if ($v === $max) {
88✔
231
                return $i;
88✔
232
            }
233
        }
234

235
        throw new \LogicException('argMin values is empty--should not happen');
×
236
    }
237

238
    /**
239
     * NonZero
240
     * Find the array indices of the scalar values that are non-zero.
241
     *
242
     * Considered 0:
243
     *  int 0, -0
244
     *  float 0.0, -0.0
245
     *  string 0, -0, 0.0, -0.0
246
     *  bool false
247
     *
248
     * Inspired by Python NumPy's nonzero
249
     *
250
     * @param float[]|int[] $values
251
     *
252
     * @return int[]
253
     */
254
    public static function nonZero(array $values): array
255
    {
256
        $indices = [];
27✔
257
        foreach ($values as $i => $v) {
27✔
258
            if (!\is_scalar($v)) {
26✔
259
                continue;
1✔
260
            }
261
            if ($v != 0) {
26✔
262
                $indices[] = $i;
21✔
263
            }
264
        }
265

266
        return $indices;
27✔
267
    }
268
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc