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