Arguments.java

  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.statistics.inference;

  18. import java.util.Set;

  19. /**
  20.  * Argument validation methods.
  21.  *
  22.  * @since 1.1
  23.  */
  24. final class Arguments {
  25.     /** Two. */
  26.     private static final int TWO = 2;

  27.     /** No instances. */
  28.     private Arguments() {}

  29.     /**
  30.      * Check the significance level is in the correct range.
  31.      *
  32.      * @param alpha Significance level of the test.
  33.      * @throws IllegalArgumentException if {@code alpha} is not in the range
  34.      * {@code (0, 0.5]}
  35.      */
  36.     static void checkSignificance(double alpha) {
  37.         if (alpha > 0 && alpha <= 0.5) {
  38.             return;
  39.         }
  40.         // Not in (0, 0.5], or NaN
  41.         throw new InferenceException(InferenceException.INVALID_SIGNIFICANCE, alpha);
  42.     }

  43.     /**
  44.      * Check that the value is {@code >= 0}.
  45.      *
  46.      * @param v Value to be tested.
  47.      * @return the value
  48.      * @throws IllegalArgumentException if the value is less than 0.
  49.      */
  50.     static int checkNonNegative(int v) {
  51.         if (v < 0) {
  52.             throw new InferenceException(InferenceException.NEGATIVE, v);
  53.         }
  54.         return v;
  55.     }

  56.     /**
  57.      * Check that the value is {@code >= 0}.
  58.      *
  59.      * @param v Value to be tested.
  60.      * @throws IllegalArgumentException if the value is less than 0.
  61.      */
  62.     static void checkNonNegative(double v) {
  63.         if (v >= 0) {
  64.             return;
  65.         }
  66.         // Negative, or NaN
  67.         throw new InferenceException(InferenceException.NEGATIVE, v);
  68.     }

  69.     /**
  70.      * Check that all values are {@code >= 0}.
  71.      *
  72.      * @param values Values to be tested.
  73.      * @throws IllegalArgumentException if any values are less than 0.
  74.      */
  75.     static void checkNonNegative(long[] values) {
  76.         for (final long v : values) {
  77.             if (v < 0) {
  78.                 throw new InferenceException(InferenceException.NEGATIVE, v);
  79.             }
  80.         }
  81.     }

  82.     /**
  83.      * Check that all values are {@code >= 0}.
  84.      *
  85.      * @param values Values to be tested.
  86.      * @throws IllegalArgumentException if any values are less than 0.
  87.      */
  88.     static void checkNonNegative(long[][] values) {
  89.         for (final long[] v : values) {
  90.             checkNonNegative(v);
  91.         }
  92.     }

  93.     /**
  94.      * Check that value is {@code > 0}.
  95.      *
  96.      * @param v Value to be tested.
  97.      * @return the value
  98.      * @throws IllegalArgumentException if the value is not strictly positive.
  99.      */
  100.     static int checkStrictlyPositive(int v) {
  101.         if (v <= 0) {
  102.             throw new InferenceException(InferenceException.NOT_STRICTLY_POSITIVE, v);
  103.         }
  104.         return v;
  105.     }

  106.     /**
  107.      * Check that value is {@code > 0}.
  108.      *
  109.      * @param v Value to be tested.
  110.      * @return the value
  111.      * @throws IllegalArgumentException if the value is not strictly positive.
  112.      */
  113.     static double checkStrictlyPositive(double v) {
  114.         if (v > 0) {
  115.             return v;
  116.         }
  117.         // not positive or NaN
  118.         throw new InferenceException(InferenceException.NOT_STRICTLY_POSITIVE, v);
  119.     }

  120.     /**
  121.      * Check that all values are {@code > 0}.
  122.      *
  123.      * @param values Values to be tested.
  124.      * @throws IllegalArgumentException if any values are not strictly positive.
  125.      */
  126.     static void checkStrictlyPositive(double[] values) {
  127.         for (final double v : values) {
  128.             // Logic negation detects NaN
  129.             if (!(v > 0)) {
  130.                 throw new InferenceException(InferenceException.NOT_STRICTLY_POSITIVE, v);
  131.             }
  132.         }
  133.     }

  134.     /**
  135.      * Check that the value is finite.
  136.      *
  137.      * @param v Value to be tested.
  138.      * @return the value
  139.      * @throws IllegalArgumentException if the value is not finite.
  140.      */
  141.     static double checkFinite(double v) {
  142.         if (!Double.isFinite(v)) {
  143.             throw new InferenceException("Non-finite input value: " + v);
  144.         }
  145.         return v;
  146.     }

  147.     /**
  148.      * Check that all values are not {@link Double#NaN}.
  149.      *
  150.      * @param values Values to be tested.
  151.      * @throws IllegalArgumentException if any values are NaN.
  152.      */
  153.     static void checkNonNaN(double[] values) {
  154.         for (final double v : values) {
  155.             if (Double.isNaN(v)) {
  156.                 throw new InferenceException("NaN input value");
  157.             }
  158.         }
  159.     }

  160.     /**
  161.      * Checks if the input array is rectangular. It is assumed the array is non-null
  162.      * and has a non-zero length.
  163.      *
  164.      * @param array Array to be tested.
  165.      * @throws NullPointerException if input array is null
  166.      * @throws IndexOutOfBoundsException if input array is zero length
  167.      * @throws IllegalArgumentException if input array is not rectangular
  168.      */
  169.     static void checkRectangular(long[][] array) {
  170.         final int first = array[0].length;
  171.         for (int i = 1; i < array.length; i++) {
  172.             if (array[i].length != first) {
  173.                 throw new InferenceException(InferenceException.NOT_RECTANGULAR, array[i].length, first);
  174.             }
  175.         }
  176.     }

  177.     /**
  178.      * Check the values size is the minimum required, {@code size >= required}.
  179.      *
  180.      * @param size Values size.
  181.      * @param required Required size.
  182.      * @throws IllegalArgumentException if {@code size < required}
  183.      */
  184.     static void checkValuesRequiredSize(int size, int required) {
  185.         if (size < required) {
  186.             throw new InferenceException(InferenceException.VALUES_REQUIRED, size, required);
  187.         }
  188.     }

  189.     /**
  190.      * Check the categories size is the minimum required, {@code size >= required}.
  191.      *
  192.      * @param size Values size.
  193.      * @param required Required size.
  194.      * @throws IllegalArgumentException if {@code size < required}
  195.      */
  196.     static void checkCategoriesRequiredSize(int size, int required) {
  197.         if (size < required) {
  198.             throw new InferenceException(InferenceException.CATEGORIES_REQUIRED, size, required);
  199.         }
  200.     }

  201.     /**
  202.      * Check the values sizes are equal, {@code size1 == size2}.
  203.      *
  204.      * @param size1 First size.
  205.      * @param size2 Second size.
  206.      * @throws IllegalArgumentException if {@code size1 != size2}
  207.      */
  208.     static void checkValuesSizeMatch(int size1, int size2) {
  209.         if (size1 != size2) {
  210.             throw new InferenceException(InferenceException.VALUES_MISMATCH, size1, size2);
  211.         }
  212.     }

  213.     /**
  214.      * Check the option is allowed.
  215.      *
  216.      * @param <E> Option type.
  217.      * @param v Option value.
  218.      * @param allowed Allowed options.
  219.      * @return the value
  220.      * @throws IllegalArgumentException if the value is not in the allowed options or is null
  221.      */
  222.     static <E extends Enum<E>> E checkOption(E v, Set<E> allowed) {
  223.         if (!allowed.contains(v)) {
  224.             throw new InferenceException("Invalid option: " + v);
  225.         }
  226.         return v;
  227.     }

  228.     /**
  229.      * Check the input is a 2-by-2 contingency table.
  230.      *
  231.      * @param table Table.
  232.      * @throws IllegalArgumentException if the {@code table} is not a 2-by-2 table; any
  233.      * table entry is negative; or the sum is zero or is not an integer
  234.      */
  235.     static void checkTable(int[][] table) {
  236.         if (table.length != TWO || table[0].length != TWO || table[1].length != TWO) {
  237.             throw new InferenceException("Require a 2-by-2 contingency table");
  238.         }
  239.         // Must all be positive
  240.         final int a = table[0][0];
  241.         final int b = table[0][1];
  242.         final int c = table[1][0];
  243.         final int d = table[1][1];
  244.         // Bitwise OR combines the sign bit from all values
  245.         checkNonNegative(a | b | c | d);
  246.         // Sum must be an integer
  247.         final long sum = (long) a + b + c + d;
  248.         if (sum > Integer.MAX_VALUE) {
  249.             throw new InferenceException(InferenceException.X_GT_Y, sum, Integer.MAX_VALUE);
  250.         }
  251.         checkStrictlyPositive((int) sum);
  252.     }
  253. }