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