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.math.stat.descriptive; 18 19 import org.apache.commons.math.MathRuntimeException; 20 import org.apache.commons.math.exception.DimensionMismatchException; 21 import org.apache.commons.math.exception.NotPositiveException; 22 import org.apache.commons.math.exception.NullArgumentException; 23 import org.apache.commons.math.exception.util.LocalizedFormats; 24 25 /** 26 * Abstract base class for all implementations of the 27 * {@link UnivariateStatistic} interface. 28 * <p> 29 * Provides a default implementation of <code>evaluate(double[]),</code> 30 * delegating to <code>evaluate(double[], int, int)</code> in the natural way. 31 * </p> 32 * <p> 33 * Also includes a <code>test</code> method that performs generic parameter 34 * validation for the <code>evaluate</code> methods.</p> 35 * 36 * @version $Revision: 1006299 $ $Date: 2010-10-10 16:47:17 +0200 (dim. 10 oct. 2010) $ 37 */ 38 public abstract class AbstractUnivariateStatistic 39 implements UnivariateStatistic { 40 41 /** Stored data. */ 42 private double[] storedData; 43 44 /** 45 * Set the data array. 46 * <p> 47 * The stored value is a copy of the parameter array, not the array itself 48 * </p> 49 * @param values data array to store (may be null to remove stored data) 50 * @see #evaluate() 51 */ 52 public void setData(final double[] values) { 53 storedData = (values == null) ? null : values.clone(); 54 } 55 56 /** 57 * Get a copy of the stored data array. 58 * @return copy of the stored data array (may be null) 59 */ 60 public double[] getData() { 61 return (storedData == null) ? null : storedData.clone(); 62 } 63 64 /** 65 * Get a reference to the stored data array. 66 * @return reference to the stored data array (may be null) 67 */ 68 protected double[] getDataRef() { 69 return storedData; 70 } 71 72 /** 73 * Set the data array. 74 * @param values data array to store 75 * @param begin the index of the first element to include 76 * @param length the number of elements to include 77 * @see #evaluate() 78 */ 79 public void setData(final double[] values, final int begin, final int length) { 80 storedData = new double[length]; 81 System.arraycopy(values, begin, storedData, 0, length); 82 } 83 84 /** 85 * Returns the result of evaluating the statistic over the stored data. 86 * <p> 87 * The stored array is the one which was set by previous calls to 88 * </p> 89 * @return the value of the statistic applied to the stored data 90 */ 91 public double evaluate() { 92 return evaluate(storedData); 93 } 94 95 /** 96 * {@inheritDoc} 97 */ 98 public double evaluate(final double[] values) { 99 test(values, 0, 0); 100 return evaluate(values, 0, values.length); 101 } 102 103 /** 104 * {@inheritDoc} 105 */ 106 public abstract double evaluate(final double[] values, final int begin, final int length); 107 108 /** 109 * {@inheritDoc} 110 */ 111 public abstract UnivariateStatistic copy(); 112 113 /** 114 * This method is used by <code>evaluate(double[], int, int)</code> methods 115 * to verify that the input parameters designate a subarray of positive length. 116 * <p> 117 * <ul> 118 * <li>returns <code>true</code> iff the parameters designate a subarray of 119 * positive length</li> 120 * <li>throws <code>IllegalArgumentException</code> if the array is null or 121 * or the indices are invalid</li> 122 * <li>returns <code>false</li> if the array is non-null, but 123 * <code>length</code> is 0. 124 * </ul></p> 125 * 126 * @param values the input array 127 * @param begin index of the first array element to include 128 * @param length the number of elements to include 129 * @return true if the parameters are valid and designate a subarray of positive length 130 * @throws IllegalArgumentException if the indices are invalid or the array is null 131 */ 132 protected boolean test( 133 final double[] values, 134 final int begin, 135 final int length) { 136 137 if (values == null) { 138 throw new NullArgumentException(LocalizedFormats.INPUT_ARRAY); 139 } 140 141 if (begin < 0) { 142 throw new NotPositiveException(LocalizedFormats.START_POSITION, begin); 143 } 144 145 if (length < 0) { 146 throw new NotPositiveException(LocalizedFormats.LENGTH, length); 147 } 148 149 if (begin + length > values.length) { 150 throw MathRuntimeException.createIllegalArgumentException( 151 LocalizedFormats.SUBARRAY_ENDS_AFTER_ARRAY_END); 152 } 153 154 if (length == 0) { 155 return false; 156 } 157 158 return true; 159 160 } 161 162 /** 163 * This method is used by <code>evaluate(double[], double[], int, int)</code> methods 164 * to verify that the begin and length parameters designate a subarray of positive length 165 * and the weights are all non-negative, non-NaN, finite, and not all zero. 166 * <p> 167 * <ul> 168 * <li>returns <code>true</code> iff the parameters designate a subarray of 169 * positive length and the weights array contains legitimate values.</li> 170 * <li>throws <code>IllegalArgumentException</code> if any of the following are true: 171 * <ul><li>the values array is null</li> 172 * <li>the weights array is null</li> 173 * <li>the weights array does not have the same length as the values array</li> 174 * <li>the weights array contains one or more infinite values</li> 175 * <li>the weights array contains one or more NaN values</li> 176 * <li>the weights array contains negative values</li> 177 * <li>the start and length arguments do not determine a valid array</li></ul> 178 * </li> 179 * <li>returns <code>false</li> if the array is non-null, but 180 * <code>length</code> is 0. 181 * </ul></p> 182 * 183 * @param values the input array 184 * @param weights the weights array 185 * @param begin index of the first array element to include 186 * @param length the number of elements to include 187 * @return true if the parameters are valid and designate a subarray of positive length 188 * @throws IllegalArgumentException if the indices are invalid or the array is null 189 * @since 2.1 190 */ 191 protected boolean test( 192 final double[] values, 193 final double[] weights, 194 final int begin, 195 final int length) { 196 197 if (weights == null) { 198 throw new NullArgumentException(LocalizedFormats.INPUT_ARRAY); 199 } 200 201 if (weights.length != values.length) { 202 throw new DimensionMismatchException(weights.length, values.length); 203 } 204 205 boolean containsPositiveWeight = false; 206 for (int i = begin; i < begin + length; i++) { 207 if (Double.isNaN(weights[i])) { 208 throw MathRuntimeException.createIllegalArgumentException( 209 LocalizedFormats.NAN_ELEMENT_AT_INDEX, i); 210 } 211 if (Double.isInfinite(weights[i])) { 212 throw MathRuntimeException.createIllegalArgumentException( 213 LocalizedFormats.INFINITE_ARRAY_ELEMENT, weights[i], i); 214 } 215 if (weights[i] < 0) { 216 throw MathRuntimeException.createIllegalArgumentException( 217 LocalizedFormats.NEGATIVE_ELEMENT_AT_INDEX, i, weights[i]); 218 } 219 if (!containsPositiveWeight && weights[i] > 0.0) { 220 containsPositiveWeight = true; 221 } 222 } 223 224 if (!containsPositiveWeight) { 225 throw MathRuntimeException.createIllegalArgumentException( 226 LocalizedFormats.WEIGHT_AT_LEAST_ONE_NON_ZERO); 227 } 228 229 return test(values, begin, length); 230 } 231 } 232 233