001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.math.stat.descriptive; 018 019 import org.apache.commons.math.MathRuntimeException; 020 import org.apache.commons.math.exception.DimensionMismatchException; 021 import org.apache.commons.math.exception.NotPositiveException; 022 import org.apache.commons.math.exception.NullArgumentException; 023 import org.apache.commons.math.exception.util.LocalizedFormats; 024 025 /** 026 * Abstract base class for all implementations of the 027 * {@link UnivariateStatistic} interface. 028 * <p> 029 * Provides a default implementation of <code>evaluate(double[]),</code> 030 * delegating to <code>evaluate(double[], int, int)</code> in the natural way. 031 * </p> 032 * <p> 033 * Also includes a <code>test</code> method that performs generic parameter 034 * validation for the <code>evaluate</code> methods.</p> 035 * 036 * @version $Revision: 1006299 $ $Date: 2010-10-10 16:47:17 +0200 (dim. 10 oct. 2010) $ 037 */ 038 public abstract class AbstractUnivariateStatistic 039 implements UnivariateStatistic { 040 041 /** Stored data. */ 042 private double[] storedData; 043 044 /** 045 * Set the data array. 046 * <p> 047 * The stored value is a copy of the parameter array, not the array itself 048 * </p> 049 * @param values data array to store (may be null to remove stored data) 050 * @see #evaluate() 051 */ 052 public void setData(final double[] values) { 053 storedData = (values == null) ? null : values.clone(); 054 } 055 056 /** 057 * Get a copy of the stored data array. 058 * @return copy of the stored data array (may be null) 059 */ 060 public double[] getData() { 061 return (storedData == null) ? null : storedData.clone(); 062 } 063 064 /** 065 * Get a reference to the stored data array. 066 * @return reference to the stored data array (may be null) 067 */ 068 protected double[] getDataRef() { 069 return storedData; 070 } 071 072 /** 073 * Set the data array. 074 * @param values data array to store 075 * @param begin the index of the first element to include 076 * @param length the number of elements to include 077 * @see #evaluate() 078 */ 079 public void setData(final double[] values, final int begin, final int length) { 080 storedData = new double[length]; 081 System.arraycopy(values, begin, storedData, 0, length); 082 } 083 084 /** 085 * Returns the result of evaluating the statistic over the stored data. 086 * <p> 087 * The stored array is the one which was set by previous calls to 088 * </p> 089 * @return the value of the statistic applied to the stored data 090 */ 091 public double evaluate() { 092 return evaluate(storedData); 093 } 094 095 /** 096 * {@inheritDoc} 097 */ 098 public double evaluate(final double[] values) { 099 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