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 */
017package org.apache.commons.math3.stat.descriptive;
018
019import org.apache.commons.math3.exception.NotPositiveException;
020import org.apache.commons.math3.exception.NullArgumentException;
021import org.apache.commons.math3.exception.NumberIsTooLargeException;
022import org.apache.commons.math3.exception.MathIllegalArgumentException;
023import org.apache.commons.math3.exception.util.LocalizedFormats;
024import org.apache.commons.math3.util.MathArrays;
025
026/**
027 * Abstract base class for all implementations of the
028 * {@link UnivariateStatistic} interface.
029 * <p>
030 * Provides a default implementation of <code>evaluate(double[]),</code>
031 * delegating to <code>evaluate(double[], int, int)</code> in the natural way.
032 * </p>
033 * <p>
034 * Also includes a <code>test</code> method that performs generic parameter
035 * validation for the <code>evaluate</code> methods.</p>
036 *
037 * @version $Id: AbstractUnivariateStatistic.java 1537714 2013-10-31 21:54:21Z tn $
038 */
039public abstract class AbstractUnivariateStatistic
040    implements UnivariateStatistic {
041
042    /** Stored data. */
043    private double[] storedData;
044
045    /**
046     * Set the data array.
047     * <p>
048     * The stored value is a copy of the parameter array, not the array itself.
049     * </p>
050     * @param values data array to store (may be null to remove stored data)
051     * @see #evaluate()
052     */
053    public void setData(final double[] values) {
054        storedData = (values == null) ? null : values.clone();
055    }
056
057    /**
058     * Get a copy of the stored data array.
059     * @return copy of the stored data array (may be null)
060     */
061    public double[] getData() {
062        return (storedData == null) ? null : storedData.clone();
063    }
064
065    /**
066     * Get a reference to the stored data array.
067     * @return reference to the stored data array (may be null)
068     */
069    protected double[] getDataRef() {
070        return storedData;
071    }
072
073    /**
074     * Set the data array.  The input array is copied, not referenced.
075     *
076     * @param values data array to store
077     * @param begin the index of the first element to include
078     * @param length the number of elements to include
079     * @throws MathIllegalArgumentException if values is null or the indices
080     * are not valid
081     * @see #evaluate()
082     */
083    public void setData(final double[] values, final int begin, final int length)
084    throws MathIllegalArgumentException {
085        if (values == null) {
086            throw new NullArgumentException(LocalizedFormats.INPUT_ARRAY);
087        }
088
089        if (begin < 0) {
090            throw new NotPositiveException(LocalizedFormats.START_POSITION, begin);
091        }
092
093        if (length < 0) {
094            throw new NotPositiveException(LocalizedFormats.LENGTH, length);
095        }
096
097        if (begin + length > values.length) {
098            throw new NumberIsTooLargeException(LocalizedFormats.SUBARRAY_ENDS_AFTER_ARRAY_END,
099                                                begin + length, values.length, true);
100        }
101        storedData = new double[length];
102        System.arraycopy(values, begin, storedData, 0, length);
103    }
104
105    /**
106     * Returns the result of evaluating the statistic over the stored data.
107     * <p>
108     * The stored array is the one which was set by previous calls to {@link #setData(double[])}.
109     * </p>
110     * @return the value of the statistic applied to the stored data
111     * @throws MathIllegalArgumentException if the stored data array is null
112     */
113    public double evaluate() throws MathIllegalArgumentException {
114        return evaluate(storedData);
115    }
116
117    /**
118     * {@inheritDoc}
119     */
120    public double evaluate(final double[] values) throws MathIllegalArgumentException {
121        test(values, 0, 0);
122        return evaluate(values, 0, values.length);
123    }
124
125    /**
126     * {@inheritDoc}
127     */
128    public abstract double evaluate(final double[] values, final int begin, final int length)
129    throws MathIllegalArgumentException;
130
131    /**
132     * {@inheritDoc}
133     */
134    public abstract UnivariateStatistic copy();
135
136    /**
137     * This method is used by <code>evaluate(double[], int, int)</code> methods
138     * to verify that the input parameters designate a subarray of positive length.
139     * <p>
140     * <ul>
141     * <li>returns <code>true</code> iff the parameters designate a subarray of
142     * positive length</li>
143     * <li>throws <code>MathIllegalArgumentException</code> if the array is null or
144     * or the indices are invalid</li>
145     * <li>returns <code>false</li> if the array is non-null, but
146     * <code>length</code> is 0.
147     * </ul></p>
148     *
149     * @param values the input array
150     * @param begin index of the first array element to include
151     * @param length the number of elements to include
152     * @return true if the parameters are valid and designate a subarray of positive length
153     * @throws MathIllegalArgumentException if the indices are invalid or the array is null
154     * @deprecated 3.3 Use {@link MathArrays#test(double[], int, int)} instead
155     */
156    @Deprecated
157    protected boolean test(
158        final double[] values,
159        final int begin,
160        final int length) throws MathIllegalArgumentException {
161        return MathArrays.verifyValues(values, begin, length, false);
162    }
163
164    /**
165     * This method is used by <code>evaluate(double[], int, int)</code> methods
166     * to verify that the input parameters designate a subarray of positive length.
167     * <p>
168     * <ul>
169     * <li>returns <code>true</code> iff the parameters designate a subarray of
170     * non-negative length</li>
171     * <li>throws <code>IllegalArgumentException</code> if the array is null or
172     * or the indices are invalid</li>
173     * <li>returns <code>false</li> if the array is non-null, but
174     * <code>length</code> is 0 unless <code>allowEmpty</code> is <code>true</code>
175     * </ul></p>
176     *
177     * @param values the input array
178     * @param begin index of the first array element to include
179     * @param length the number of elements to include
180     * @param allowEmpty if <code>true</code> then zero length arrays are allowed
181     * @return true if the parameters are valid
182     * @throws MathIllegalArgumentException if the indices are invalid or the array is null
183     * @since 3.0
184     * @deprecated 3.3 Use {@link MathArrays#test(double[], int, int, boolean)} instead
185     */
186    @Deprecated
187    protected boolean test(final double[] values, final int begin,
188            final int length, final boolean allowEmpty) throws MathIllegalArgumentException {
189        return MathArrays.verifyValues(values, begin, length, allowEmpty);
190    }
191
192    /**
193     * This method is used by <code>evaluate(double[], double[], int, int)</code> methods
194     * to verify that the begin and length parameters designate a subarray of positive length
195     * and the weights are all non-negative, non-NaN, finite, and not all zero.
196     * <p>
197     * <ul>
198     * <li>returns <code>true</code> iff the parameters designate a subarray of
199     * positive length and the weights array contains legitimate values.</li>
200     * <li>throws <code>IllegalArgumentException</code> if any of the following are true:
201     * <ul><li>the values array is null</li>
202     *     <li>the weights array is null</li>
203     *     <li>the weights array does not have the same length as the values array</li>
204     *     <li>the weights array contains one or more infinite values</li>
205     *     <li>the weights array contains one or more NaN values</li>
206     *     <li>the weights array contains negative values</li>
207     *     <li>the start and length arguments do not determine a valid array</li></ul>
208     * </li>
209     * <li>returns <code>false</li> if the array is non-null, but
210     * <code>length</code> is 0.
211     * </ul></p>
212     *
213     * @param values the input array
214     * @param weights the weights array
215     * @param begin index of the first array element to include
216     * @param length the number of elements to include
217     * @return true if the parameters are valid and designate a subarray of positive length
218     * @throws MathIllegalArgumentException if the indices are invalid or the array is null
219     * @since 2.1
220     * @deprecated 3.3 Use {@link MathArrays#test(double[], double[], int, int)} instead
221     */
222    @Deprecated
223    protected boolean test(
224        final double[] values,
225        final double[] weights,
226        final int begin,
227        final int length) throws MathIllegalArgumentException {
228        return MathArrays.verifyValues(values, weights, begin, length, false);
229    }
230
231    /**
232     * This method is used by <code>evaluate(double[], double[], int, int)</code> methods
233     * to verify that the begin and length parameters designate a subarray of positive length
234     * and the weights are all non-negative, non-NaN, finite, and not all zero.
235     * <p>
236     * <ul>
237     * <li>returns <code>true</code> iff the parameters designate a subarray of
238     * non-negative length and the weights array contains legitimate values.</li>
239     * <li>throws <code>MathIllegalArgumentException</code> if any of the following are true:
240     * <ul><li>the values array is null</li>
241     *     <li>the weights array is null</li>
242     *     <li>the weights array does not have the same length as the values array</li>
243     *     <li>the weights array contains one or more infinite values</li>
244     *     <li>the weights array contains one or more NaN values</li>
245     *     <li>the weights array contains negative values</li>
246     *     <li>the start and length arguments do not determine a valid array</li></ul>
247     * </li>
248     * <li>returns <code>false</li> if the array is non-null, but
249     * <code>length</code> is 0 unless <code>allowEmpty</code> is <code>true</code>.
250     * </ul></p>
251     *
252     * @param values the input array.
253     * @param weights the weights array.
254     * @param begin index of the first array element to include.
255     * @param length the number of elements to include.
256     * @param allowEmpty if {@code true} than allow zero length arrays to pass.
257     * @return {@code true} if the parameters are valid.
258     * @throws NullArgumentException if either of the arrays are null
259     * @throws MathIllegalArgumentException if the array indices are not valid,
260     * the weights array contains NaN, infinite or negative elements, or there
261     * are no positive weights.
262     * @since 3.0
263     * @deprecated 3.3 Use {@link MathArrays#test(double[], double[], int, int, boolean)} instead
264     */
265    @Deprecated
266    protected boolean test(final double[] values, final double[] weights,
267            final int begin, final int length, final boolean allowEmpty) throws MathIllegalArgumentException {
268
269        return MathArrays.verifyValues(values, weights, begin, length, allowEmpty);
270    }
271}
272