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.math4.stat.descriptive;
018
019import org.apache.commons.math4.exception.MathIllegalArgumentException;
020import org.apache.commons.math4.exception.NullArgumentException;
021import org.apache.commons.math4.exception.util.LocalizedFormats;
022import org.apache.commons.math4.util.MathArrays;
023import org.apache.commons.math4.util.MathUtils;
024import org.apache.commons.numbers.core.Precision;
025
026/**
027 * Abstract base class for implementations of the
028 * {@link StorelessUnivariateStatistic} interface.
029 * <p>
030 * Provides default {@code evaluate(double[],...)} and {@code incrementAll(double[])}
031 * implementations.
032 * <p>
033 * <strong>Note that these implementations are not synchronized.</strong>
034 */
035public abstract class AbstractStorelessUnivariateStatistic
036    implements StorelessUnivariateStatistic {
037
038    /**
039     * This default implementation creates a copy of this {@link StorelessUnivariateStatistic}
040     * instance, calls {@link #clear} on it, then calls {@link #incrementAll} with the specified
041     * portion of the input array, and then uses {@link #getResult} to compute the return value.
042     * <p>
043     * Note that this implementation does not change the internal state of the statistic.
044     * <p>
045     * Implementations may override this method with a more efficient and possibly more
046     * accurate implementation that works directly with the input array.
047     * <p>
048     * If the array is null, a MathIllegalArgumentException is thrown.
049     *
050     * @param values input array
051     * @return the value of the statistic applied to the input array
052     * @throws MathIllegalArgumentException if values is null
053     * @see org.apache.commons.math4.stat.descriptive.UnivariateStatistic#evaluate(double[])
054     */
055    @Override
056    public double evaluate(final double[] values) throws MathIllegalArgumentException {
057        if (values == null) {
058            throw new NullArgumentException(LocalizedFormats.INPUT_ARRAY);
059        }
060        return evaluate(values, 0, values.length);
061    }
062
063    /**
064     * This default implementation creates a copy of this {@link StorelessUnivariateStatistic}
065     * instance, calls {@link #clear} on it, then calls {@link #incrementAll} with the specified
066     * portion of the input array, and then uses {@link #getResult} to compute the return value.
067     * <p>
068     * Note that this implementation does not change the internal state of the statistic.
069     * <p>
070     * Implementations may override this method with a more efficient and possibly more
071     * accurate implementation that works directly with the input array.
072     * <p>
073     * If the array is null or the index parameters are not valid, an
074     * MathIllegalArgumentException is thrown.
075     *
076     * @param values the input array
077     * @param begin the index of the first element to include
078     * @param length the number of elements to include
079     * @return the value of the statistic applied to the included array entries
080     * @throws MathIllegalArgumentException if the array is null or the indices are not valid
081     * @see org.apache.commons.math4.stat.descriptive.UnivariateStatistic#evaluate(double[], int, int)
082     */
083    @Override
084    public double evaluate(final double[] values, final int begin, final int length)
085        throws MathIllegalArgumentException {
086
087        if (MathArrays.verifyValues(values, begin, length)) {
088            final StorelessUnivariateStatistic stat = copy();
089            stat.clear();
090            stat.incrementAll(values, begin, length);
091            return stat.getResult();
092        }
093        return Double.NaN;
094    }
095
096    /**
097     * {@inheritDoc}
098     */
099    @Override
100    public abstract StorelessUnivariateStatistic copy();
101
102    /**
103     * {@inheritDoc}
104     */
105    @Override
106    public abstract void clear();
107
108    /**
109     * {@inheritDoc}
110     */
111    @Override
112    public abstract double getResult();
113
114    /**
115     * {@inheritDoc}
116     */
117    @Override
118    public abstract void increment(final double d);
119
120    /**
121     * This default implementation just calls {@link #increment} in a loop over
122     * the input array.
123     * <p>
124     * Throws IllegalArgumentException if the input values array is null.
125     *
126     * @param values values to add
127     * @throws MathIllegalArgumentException if values is null
128     * @see StorelessUnivariateStatistic#incrementAll(double[])
129     */
130    @Override
131    public void incrementAll(double[] values) throws MathIllegalArgumentException {
132        if (values == null) {
133            throw new NullArgumentException(LocalizedFormats.INPUT_ARRAY);
134        }
135        incrementAll(values, 0, values.length);
136    }
137
138    /**
139     * This default implementation just calls {@link #increment} in a loop over
140     * the specified portion of the input array.
141     * <p>
142     * Throws IllegalArgumentException if the input values array is null.
143     *
144     * @param values  array holding values to add
145     * @param begin   index of the first array element to add
146     * @param length  number of array elements to add
147     * @throws MathIllegalArgumentException if values is null
148     * @see StorelessUnivariateStatistic#incrementAll(double[], int, int)
149     */
150    @Override
151    public void incrementAll(double[] values, int begin, int length) throws MathIllegalArgumentException {
152        if (MathArrays.verifyValues(values, begin, length)) {
153            int k = begin + length;
154            for (int i = begin; i < k; i++) {
155                increment(values[i]);
156            }
157        }
158    }
159
160    /**
161     * Returns true iff <code>object</code> is the same type of
162     * {@link StorelessUnivariateStatistic} (the object's class equals this
163     * instance) returning the same values as this for <code>getResult()</code>
164     * and <code>getN()</code>.
165     *
166     * @param object object to test equality against.
167     * @return true if object returns the same value as this
168     */
169    @Override
170    public boolean equals(Object object) {
171        if (object == this ) {
172            return true;
173        }
174        if (object == null || object.getClass() != this.getClass()) {
175            return false;
176        }
177        StorelessUnivariateStatistic stat = (StorelessUnivariateStatistic) object;
178        return Precision.equalsIncludingNaN(stat.getResult(), this.getResult()) &&
179               Precision.equalsIncludingNaN(stat.getN(), this.getN());
180    }
181
182    /**
183     * Returns hash code based on getResult() and getN().
184     *
185     * @return hash code
186     */
187    @Override
188    public int hashCode() {
189        return 31 * (31 + MathUtils.hash(getResult())) + MathUtils.hash(getN());
190    }
191
192}