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

markrogoyski / math-php / 4804485735

pending completion
4804485735

push

github

GitHub
PHPdoc annotations added, phpstan works without errors now (#465)

53 of 53 new or added lines in 20 files covered. (100.0%)

7532 of 7538 relevant lines covered (99.92%)

185.08 hits per line

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

97.1
/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
        /** @var int $result */
80
        $result = self::baseArgMax($values);
40✔
81
        return $result;
40✔
82
    }
83

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

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

115
        /** @var int $result */
116
        $result = self::baseArgMax($valuesWithoutNans);
48✔
117
        return $result;
48✔
118
    }
119

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

139
        return null;
×
140
    }
141

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

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

178
        // Standard case: Find max and return index
179

180
        /** @var int $result */
181
        $result = self::baseArgMin($values);
40✔
182
        return $result;
40✔
183
    }
184

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

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

216
        /** @var int $result */
217
        $result = self::baseArgMin($valuesWithoutNans);
48✔
218
        return $result;
48✔
219
    }
220

221
    /**
222
     * Base argMin calculation
223
     * Find the array index of the minimum value.
224
     *
225
     * In case of the maximum value appearing multiple times, the index of the first occurrence is returned.
226
     *
227
     * @param float[]|int[] $values
228
     *
229
     * @return int|null Index of the first occurrence of the minimum value
230
     */
231
    private static function baseArgMin(array $values): ?int
232
    {
233
        $max = \min($values);
88✔
234
        foreach ($values as $i => $v) {
88✔
235
            if ($v === $max) {
88✔
236
                return $i;
88✔
237
            }
238
        }
239

240
        return null;
×
241
    }
242

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

271
        return $indices;
27✔
272
    }
273
}
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

© 2026 Coveralls, Inc