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