1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 /*
19 * This is not the original file distributed by the Apache Software Foundation
20 * It has been modified by the Hipparchus project
21 */
22 package org.hipparchus.stat.inference;
23
24 import org.hipparchus.distribution.continuous.ChiSquaredDistribution;
25 import org.hipparchus.exception.LocalizedCoreFormats;
26 import org.hipparchus.exception.MathIllegalArgumentException;
27 import org.hipparchus.exception.MathIllegalStateException;
28 import org.hipparchus.exception.NullArgumentException;
29 import org.hipparchus.stat.LocalizedStatFormats;
30 import org.hipparchus.util.FastMath;
31 import org.hipparchus.util.MathArrays;
32 import org.hipparchus.util.MathUtils;
33
34 /**
35 * Implements Chi-Square test statistics.
36 * <p>
37 * This implementation handles both known and unknown distributions.
38 * <p>
39 * Two samples tests can be used when the distribution is unknown <i>a priori</i>
40 * but provided by one sample, or when the hypothesis under test is that the two
41 * samples come from the same underlying distribution.
42 */
43 public class ChiSquareTest { // NOPMD - this is not a Junit test class, PMD false positive here
44
45 /** Empty constructor.
46 * <p>
47 * This constructor is not strictly necessary, but it prevents spurious
48 * javadoc warnings with JDK 18 and later.
49 * </p>
50 * @since 3.0
51 */
52 public ChiSquareTest() { // NOPMD - unnecessary constructor added intentionally to make javadoc happy
53 // nothing to do
54 }
55
56 /**
57 * Computes the <a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda35f.htm">
58 * Chi-Square statistic</a> comparing <code>observed</code> and <code>expected</code>
59 * frequency counts.
60 * <p>
61 * This statistic can be used to perform a Chi-Square test evaluating the null
62 * hypothesis that the observed counts follow the expected distribution.
63 * <p>
64 * <strong>Preconditions</strong>:
65 * <ul>
66 * <li>Expected counts must all be positive.</li>
67 * <li>Observed counts must all be ≥ 0.</li>
68 * <li>The observed and expected arrays must have the same length and
69 * their common length must be at least 2.</li>
70 * </ul>
71 * <p>
72 * If any of the preconditions are not met, an
73 * <code>IllegalArgumentException</code> is thrown.
74 * <p>
75 * <strong>Note: </strong>This implementation rescales the
76 * <code>expected</code> array if necessary to ensure that the sum of the
77 * expected and observed counts are equal.
78 *
79 * @param observed array of observed frequency counts
80 * @param expected array of expected frequency counts
81 * @return chiSquare test statistic
82 * @throws MathIllegalArgumentException if <code>observed</code> has negative entries
83 * @throws MathIllegalArgumentException if <code>expected</code> has entries that are
84 * not strictly positive
85 * @throws MathIllegalArgumentException if the arrays length is less than 2
86 */
87 public double chiSquare(final double[] expected, final long[] observed)
88 throws MathIllegalArgumentException {
89
90 if (expected.length < 2) {
91 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
92 expected.length, 2);
93 }
94 MathUtils.checkDimension(expected.length, observed.length);
95 MathArrays.checkPositive(expected);
96 MathArrays.checkNonNegative(observed);
97
98 double sumExpected = 0d;
99 double sumObserved = 0d;
100 for (int i = 0; i < observed.length; i++) {
101 sumExpected += expected[i];
102 sumObserved += observed[i];
103 }
104 double ratio = 1.0d;
105 boolean rescale = false;
106 if (FastMath.abs(sumExpected - sumObserved) > 10E-6) {
107 ratio = sumObserved / sumExpected;
108 rescale = true;
109 }
110 double sumSq = 0.0d;
111 for (int i = 0; i < observed.length; i++) {
112 if (rescale) {
113 final double dev = observed[i] - ratio * expected[i];
114 sumSq += dev * dev / (ratio * expected[i]);
115 } else {
116 final double dev = observed[i] - expected[i];
117 sumSq += dev * dev / expected[i];
118 }
119 }
120 return sumSq;
121 }
122
123 /**
124 * Returns the <i>observed significance level</i>, or <a href=
125 * "http://www.cas.lancs.ac.uk/glossary_v1.1/hyptest.html#pvalue">
126 * p-value</a>, associated with a
127 * <a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda35f.htm">
128 * Chi-square goodness of fit test</a> comparing the <code>observed</code>
129 * frequency counts to those in the <code>expected</code> array.
130 * <p>
131 * The number returned is the smallest significance level at which one can reject
132 * the null hypothesis that the observed counts conform to the frequency distribution
133 * described by the expected counts.
134 * <p>
135 * <strong>Preconditions</strong>:
136 * <ul>
137 * <li>Expected counts must all be positive.</li>
138 * <li>Observed counts must all be ≥ 0.</li>
139 * <li>The observed and expected arrays must have the same length and
140 * their common length must be at least 2.</li>
141 * </ul>
142 * <p>
143 * If any of the preconditions are not met, an
144 * <code>IllegalArgumentException</code> is thrown.
145 * <p>
146 * <strong>Note: </strong>This implementation rescales the
147 * <code>expected</code> array if necessary to ensure that the sum of the
148 * expected and observed counts are equal.
149 *
150 * @param observed array of observed frequency counts
151 * @param expected array of expected frequency counts
152 * @return p-value
153 * @throws MathIllegalArgumentException if <code>observed</code> has negative entries
154 * @throws MathIllegalArgumentException if <code>expected</code> has entries that are
155 * not strictly positive
156 * @throws MathIllegalArgumentException if the arrays length is less than 2
157 * @throws MathIllegalStateException if an error occurs computing the p-value
158 */
159 public double chiSquareTest(final double[] expected, final long[] observed)
160 throws MathIllegalArgumentException, MathIllegalStateException {
161
162 final ChiSquaredDistribution distribution = new ChiSquaredDistribution(expected.length - 1.0);
163 return 1.0 - distribution.cumulativeProbability(chiSquare(expected, observed));
164 }
165
166 /**
167 * Performs a <a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda35f.htm">
168 * Chi-square goodness of fit test</a> evaluating the null hypothesis that the
169 * observed counts conform to the frequency distribution described by the expected
170 * counts, with significance level <code>alpha</code>. Returns true iff the null
171 * hypothesis can be rejected with 100 * (1 - alpha) percent confidence.
172 * <p>
173 * <strong>Example:</strong><br>
174 * To test the hypothesis that <code>observed</code> follows
175 * <code>expected</code> at the 99% level, use
176 * <code>chiSquareTest(expected, observed, 0.01)</code>
177 * <p>
178 * <strong>Preconditions</strong>:
179 * <ul>
180 * <li>Expected counts must all be positive.</li>
181 * <li>Observed counts must all be ≥ 0.</li>
182 * <li>The observed and expected arrays must have the same length and
183 * their common length must be at least 2.</li>
184 * <li><code> 0 < alpha < 0.5</code></li>
185 * </ul>
186 * <p>
187 * If any of the preconditions are not met, an
188 * <code>IllegalArgumentException</code> is thrown.
189 * <p>
190 * <strong>Note: </strong>This implementation rescales the
191 * <code>expected</code> array if necessary to ensure that the sum of the
192 * expected and observed counts are equal.
193 *
194 * @param observed array of observed frequency counts
195 * @param expected array of expected frequency counts
196 * @param alpha significance level of the test
197 * @return true iff null hypothesis can be rejected with confidence
198 * 1 - alpha
199 * @throws MathIllegalArgumentException if <code>observed</code> has negative entries
200 * @throws MathIllegalArgumentException if <code>expected</code> has entries that are
201 * not strictly positive
202 * @throws MathIllegalArgumentException if the arrays length is less than 2
203 * @throws MathIllegalArgumentException if <code>alpha</code> is not in the range (0, 0.5]
204 * @throws MathIllegalStateException if an error occurs computing the p-value
205 */
206 public boolean chiSquareTest(final double[] expected, final long[] observed,
207 final double alpha)
208 throws MathIllegalArgumentException, MathIllegalStateException {
209
210 if ((alpha <= 0) || (alpha > 0.5)) {
211 throw new MathIllegalArgumentException(LocalizedStatFormats.OUT_OF_BOUND_SIGNIFICANCE_LEVEL,
212 alpha, 0, 0.5);
213 }
214 return chiSquareTest(expected, observed) < alpha;
215
216 }
217
218 /**
219 * Computes the Chi-Square statistic associated with a
220 * <a href="http://www.itl.nist.gov/div898/handbook/prc/section4/prc45.htm">
221 * chi-square test of independence</a> based on the input <code>counts</code>
222 * array, viewed as a two-way table.
223 * <p>
224 * The rows of the 2-way table are
225 * <code>count[0], ... , count[count.length - 1] </code>
226 * <p>
227 * <strong>Preconditions</strong>:
228 * <ul>
229 * <li>All counts must be ≥ 0.</li>
230 * <li>The count array must be rectangular (i.e. all count[i] subarrays
231 * must have the same length).</li>
232 * <li>The 2-way table represented by <code>counts</code> must have at
233 * least 2 columns and at least 2 rows.</li>
234 * </ul>
235 * <p>
236 * If any of the preconditions are not met, an
237 * <code>IllegalArgumentException</code> is thrown.
238 *
239 * @param counts array representation of 2-way table
240 * @return chiSquare test statistic
241 * @throws NullArgumentException if the array is null
242 * @throws MathIllegalArgumentException if the array is not rectangular
243 * @throws MathIllegalArgumentException if {@code counts} has negative entries
244 */
245 public double chiSquare(final long[][] counts)
246 throws MathIllegalArgumentException, NullArgumentException {
247
248 checkArray(counts);
249 int nRows = counts.length;
250 int nCols = counts[0].length;
251
252 // compute row, column and total sums
253 double[] rowSum = new double[nRows];
254 double[] colSum = new double[nCols];
255 double total = 0.0d;
256 for (int row = 0; row < nRows; row++) {
257 for (int col = 0; col < nCols; col++) {
258 rowSum[row] += counts[row][col];
259 colSum[col] += counts[row][col];
260 total += counts[row][col];
261 }
262 }
263
264 // compute expected counts and chi-square
265 double sumSq = 0.0d;
266 for (int row = 0; row < nRows; row++) {
267 for (int col = 0; col < nCols; col++) {
268 final double expected = (rowSum[row] * colSum[col]) / total;
269 sumSq += ((counts[row][col] - expected) *
270 (counts[row][col] - expected)) / expected;
271 }
272 }
273 return sumSq;
274 }
275
276 /**
277 * Returns the <i>observed significance level</i>, or <a href=
278 * "http://www.cas.lancs.ac.uk/glossary_v1.1/hyptest.html#pvalue">
279 * p-value</a>, associated with a
280 * <a href="http://www.itl.nist.gov/div898/handbook/prc/section4/prc45.htm">
281 * chi-square test of independence</a> based on the input <code>counts</code>
282 * array, viewed as a two-way table.
283 * <p>
284 * The rows of the 2-way table are
285 * <code>count[0], ... , count[count.length - 1] </code>
286 * <p>
287 * <strong>Preconditions</strong>:
288 * <ul>
289 * <li>All counts must be ≥ 0.</li>
290 * <li>The count array must be rectangular (i.e. all count[i] subarrays must have
291 * the same length).</li>
292 * <li>The 2-way table represented by <code>counts</code> must have at least 2
293 * columns and at least 2 rows.</li>
294 * </ul>
295 * <p>
296 * If any of the preconditions are not met, an
297 * <code>IllegalArgumentException</code> is thrown.
298 *
299 * @param counts array representation of 2-way table
300 * @return p-value
301 * @throws NullArgumentException if the array is null
302 * @throws MathIllegalArgumentException if the array is not rectangular
303 * @throws MathIllegalArgumentException if {@code counts} has negative entries
304 * @throws MathIllegalStateException if an error occurs computing the p-value
305 */
306 public double chiSquareTest(final long[][] counts)
307 throws MathIllegalArgumentException, NullArgumentException, MathIllegalStateException {
308
309 checkArray(counts);
310 double df = ((double) counts.length -1) * ((double) counts[0].length - 1);
311 final ChiSquaredDistribution distribution = new ChiSquaredDistribution(df);
312 return 1 - distribution.cumulativeProbability(chiSquare(counts));
313 }
314
315 /**
316 * Performs a <a href="http://www.itl.nist.gov/div898/handbook/prc/section4/prc45.htm">
317 * chi-square test of independence</a> evaluating the null hypothesis that the
318 * classifications represented by the counts in the columns of the input 2-way table
319 * are independent of the rows, with significance level <code>alpha</code>.
320 * Returns true iff the null hypothesis can be rejected with 100 * (1 - alpha) percent
321 * confidence.
322 * <p>
323 * The rows of the 2-way table are
324 * <code>count[0], ... , count[count.length - 1] </code>
325 * <p>
326 * <strong>Example:</strong><br>
327 * To test the null hypothesis that the counts in
328 * <code>count[0], ... , count[count.length - 1] </code>
329 * all correspond to the same underlying probability distribution at the 99% level,
330 * use <code>chiSquareTest(counts, 0.01)</code>.
331 * <p>
332 * <strong>Preconditions</strong>:
333 * <ul>
334 * <li>All counts must be ≥ 0.</li>
335 * <li>The count array must be rectangular (i.e. all count[i] subarrays must have the
336 * same length).</li>
337 * <li>The 2-way table represented by <code>counts</code> must have at least 2 columns and
338 * at least 2 rows.</li>
339 * </ul>
340 * <p>
341 * If any of the preconditions are not met, an
342 * <code>IllegalArgumentException</code> is thrown.
343 *
344 * @param counts array representation of 2-way table
345 * @param alpha significance level of the test
346 * @return true iff null hypothesis can be rejected with confidence
347 * 1 - alpha
348 * @throws NullArgumentException if the array is null
349 * @throws MathIllegalArgumentException if the array is not rectangular
350 * @throws MathIllegalArgumentException if {@code counts} has any negative entries
351 * @throws MathIllegalArgumentException if <code>alpha</code> is not in the range (0, 0.5]
352 * @throws MathIllegalStateException if an error occurs computing the p-value
353 */
354 public boolean chiSquareTest(final long[][] counts, final double alpha)
355 throws MathIllegalArgumentException, NullArgumentException, MathIllegalStateException {
356
357 if ((alpha <= 0) || (alpha > 0.5)) {
358 throw new MathIllegalArgumentException(LocalizedStatFormats.OUT_OF_BOUND_SIGNIFICANCE_LEVEL,
359 alpha, 0, 0.5);
360 }
361 return chiSquareTest(counts) < alpha;
362 }
363
364 /**
365 * Computes a
366 * <a href="http://www.itl.nist.gov/div898/software/dataplot/refman1/auxillar/chi2samp.htm">
367 * Chi-Square two sample test statistic</a> comparing bin frequency counts
368 * in <code>observed1</code> and <code>observed2</code>.
369 * <p>
370 * The sums of frequency counts in the two samples are not required to be the
371 * same. The formula used to compute the test statistic is
372 * </p>
373 * <code>
374 * ∑[(K * observed1[i] - observed2[i]/K)<sup>2</sup> / (observed1[i] + observed2[i])]
375 * </code>
376 * <p>
377 * where
378 * </p>
379 * <code>K = √[∑(observed2 / ∑(observed1)]</code>
380 * <p>
381 * This statistic can be used to perform a Chi-Square test evaluating the
382 * null hypothesis that both observed counts follow the same distribution.
383 * </p>
384 * <p><strong>Preconditions</strong>:</p>
385 * <ul>
386 * <li>Observed counts must be non-negative.</li>
387 * <li>Observed counts for a specific bin must not both be zero.</li>
388 * <li>Observed counts for a specific sample must not all be 0.</li>
389 * <li>The arrays <code>observed1</code> and <code>observed2</code> must have
390 * the same length and their common length must be at least 2.</li>
391 * </ul>
392 * <p>
393 * If any of the preconditions are not met, an
394 * <code>IllegalArgumentException</code> is thrown.
395 * </p>
396 *
397 * @param observed1 array of observed frequency counts of the first data set
398 * @param observed2 array of observed frequency counts of the second data set
399 * @return chiSquare test statistic
400 * @throws MathIllegalArgumentException the the length of the arrays does not match
401 * @throws MathIllegalArgumentException if any entries in <code>observed1</code> or
402 * <code>observed2</code> are negative
403 * @throws MathIllegalArgumentException if either all counts of <code>observed1</code> or
404 * <code>observed2</code> are zero, or if the count at some index is zero
405 * for both arrays
406 */
407 public double chiSquareDataSetsComparison(long[] observed1, long[] observed2)
408 throws MathIllegalArgumentException {
409
410 // Make sure lengths are same
411 if (observed1.length < 2) {
412 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
413 observed1.length, 2);
414 }
415 MathUtils.checkDimension(observed1.length, observed2.length);
416
417 // Ensure non-negative counts
418 MathArrays.checkNonNegative(observed1);
419 MathArrays.checkNonNegative(observed2);
420
421 // Compute and compare count sums
422 long countSum1 = 0;
423 long countSum2 = 0;
424 for (int i = 0; i < observed1.length; i++) {
425 countSum1 += observed1[i];
426 countSum2 += observed2[i];
427 }
428 // Ensure neither sample is uniformly 0
429 if (countSum1 == 0 || countSum2 == 0) {
430 throw new MathIllegalArgumentException(LocalizedCoreFormats.ZERO_NOT_ALLOWED);
431 }
432 // Compare and compute weight only if different
433 double weight = 0.0;
434 boolean unequalCounts = countSum1 != countSum2;
435 if (unequalCounts) {
436 weight = FastMath.sqrt(((double) countSum1) / countSum2);
437 }
438 // Compute ChiSquare statistic
439 double sumSq = 0.0d;
440 for (int i = 0; i < observed1.length; i++) {
441 if (observed1[i] == 0 && observed2[i] == 0) {
442 throw new MathIllegalArgumentException(LocalizedCoreFormats.OBSERVED_COUNTS_BOTTH_ZERO_FOR_ENTRY, i);
443 } else {
444 final double obs1 = observed1[i];
445 final double obs2 = observed2[i];
446 final double dev;
447 if (unequalCounts) { // apply weights
448 dev = obs1/weight - obs2 * weight;
449 } else {
450 dev = obs1 - obs2;
451 }
452 sumSq += (dev * dev) / (obs1 + obs2);
453 }
454 }
455 return sumSq;
456 }
457
458 /**
459 * Returns the <i>observed significance level</i>, or <a href=
460 * "http://www.cas.lancs.ac.uk/glossary_v1.1/hyptest.html#pvalue">
461 * p-value</a>, associated with a Chi-Square two sample test comparing
462 * bin frequency counts in <code>observed1</code> and
463 * <code>observed2</code>.
464 * <p>
465 * The number returned is the smallest significance level at which one
466 * can reject the null hypothesis that the observed counts conform to the
467 * same distribution.
468 * <p>
469 * See {@link #chiSquareDataSetsComparison(long[], long[])} for details
470 * on the formula used to compute the test statistic. The degrees of
471 * of freedom used to perform the test is one less than the common length
472 * of the input observed count arrays.
473 * <p>
474 * <strong>Preconditions</strong>:
475 * <ul>
476 * <li>Observed counts must be non-negative.</li>
477 * <li>Observed counts for a specific bin must not both be zero.</li>
478 * <li>Observed counts for a specific sample must not all be 0.</li>
479 * <li>The arrays <code>observed1</code> and <code>observed2</code> must
480 * have the same length and their common length must be at least 2.</li>
481 * </ul>
482 * <p>
483 * If any of the preconditions are not met, an
484 * <code>IllegalArgumentException</code> is thrown.
485 *
486 * @param observed1 array of observed frequency counts of the first data set
487 * @param observed2 array of observed frequency counts of the second data set
488 * @return p-value
489 * @throws MathIllegalArgumentException the the length of the arrays does not match
490 * @throws MathIllegalArgumentException if any entries in <code>observed1</code> or
491 * <code>observed2</code> are negative
492 * @throws MathIllegalArgumentException if either all counts of <code>observed1</code> or
493 * <code>observed2</code> are zero, or if the count at the same index is zero
494 * for both arrays
495 * @throws MathIllegalStateException if an error occurs computing the p-value
496 */
497 public double chiSquareTestDataSetsComparison(long[] observed1, long[] observed2)
498 throws MathIllegalArgumentException,
499 MathIllegalStateException {
500
501 final ChiSquaredDistribution distribution =
502 new ChiSquaredDistribution((double) observed1.length - 1);
503 return 1 - distribution.cumulativeProbability(
504 chiSquareDataSetsComparison(observed1, observed2));
505 }
506
507 /**
508 * Performs a Chi-Square two sample test comparing two binned data
509 * sets. The test evaluates the null hypothesis that the two lists of
510 * observed counts conform to the same frequency distribution, with
511 * significance level <code>alpha</code>. Returns true iff the null
512 * hypothesis can be rejected with 100 * (1 - alpha) percent confidence.
513 * <p>
514 * See {@link #chiSquareDataSetsComparison(long[], long[])} for
515 * details on the formula used to compute the Chisquare statistic used
516 * in the test. The degrees of of freedom used to perform the test is
517 * one less than the common length of the input observed count arrays.
518 * <p>
519 * <strong>Preconditions</strong>:
520 * <ul>
521 * <li>Observed counts must be non-negative.</li>
522 * <li>Observed counts for a specific bin must not both be zero.</li>
523 * <li>Observed counts for a specific sample must not all be 0.</li>
524 * <li>The arrays <code>observed1</code> and <code>observed2</code> must
525 * have the same length and their common length must be at least 2.</li>
526 * <li><code> 0 < alpha < 0.5</code></li>
527 * </ul>
528 * <p>
529 * If any of the preconditions are not met, an
530 * <code>IllegalArgumentException</code> is thrown.
531 *
532 * @param observed1 array of observed frequency counts of the first data set
533 * @param observed2 array of observed frequency counts of the second data set
534 * @param alpha significance level of the test
535 * @return true iff null hypothesis can be rejected with confidence
536 * 1 - alpha
537 * @throws MathIllegalArgumentException the the length of the arrays does not match
538 * @throws MathIllegalArgumentException if any entries in <code>observed1</code> or
539 * <code>observed2</code> are negative
540 * @throws MathIllegalArgumentException if either all counts of <code>observed1</code> or
541 * <code>observed2</code> are zero, or if the count at the same index is zero
542 * for both arrays
543 * @throws MathIllegalArgumentException if <code>alpha</code> is not in the range (0, 0.5]
544 * @throws MathIllegalStateException if an error occurs performing the test
545 */
546 public boolean chiSquareTestDataSetsComparison(final long[] observed1,
547 final long[] observed2,
548 final double alpha)
549 throws MathIllegalArgumentException, MathIllegalStateException {
550
551 if (alpha <= 0 ||
552 alpha > 0.5) {
553 throw new MathIllegalArgumentException(LocalizedStatFormats.OUT_OF_BOUND_SIGNIFICANCE_LEVEL,
554 alpha, 0, 0.5);
555 }
556 return chiSquareTestDataSetsComparison(observed1, observed2) < alpha;
557
558 }
559
560 /**
561 * Checks to make sure that the input long[][] array is rectangular,
562 * has at least 2 rows and 2 columns, and has all non-negative entries.
563 *
564 * @param in input 2-way table to check
565 * @throws NullArgumentException if the array is null
566 * @throws MathIllegalArgumentException if the array is not valid
567 * @throws MathIllegalArgumentException if the array contains any negative entries
568 */
569 private void checkArray(final long[][] in)
570 throws MathIllegalArgumentException, NullArgumentException {
571
572 if (in.length < 2) {
573 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
574 in.length, 2);
575 }
576
577 if (in[0].length < 2) {
578 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
579 in[0].length, 2);
580 }
581
582 MathArrays.checkRectangular(in);
583 MathArrays.checkNonNegative(in);
584 }
585
586 }