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.math3.stat.descriptive;
018
019 import java.io.Serializable;
020 import java.lang.reflect.InvocationTargetException;
021 import java.util.Arrays;
022
023 import org.apache.commons.math3.exception.MathIllegalArgumentException;
024 import org.apache.commons.math3.exception.NullArgumentException;
025 import org.apache.commons.math3.exception.MathIllegalStateException;
026 import org.apache.commons.math3.exception.util.LocalizedFormats;
027 import org.apache.commons.math3.stat.descriptive.moment.GeometricMean;
028 import org.apache.commons.math3.stat.descriptive.moment.Kurtosis;
029 import org.apache.commons.math3.stat.descriptive.moment.Mean;
030 import org.apache.commons.math3.stat.descriptive.moment.Skewness;
031 import org.apache.commons.math3.stat.descriptive.moment.Variance;
032 import org.apache.commons.math3.stat.descriptive.rank.Max;
033 import org.apache.commons.math3.stat.descriptive.rank.Min;
034 import org.apache.commons.math3.stat.descriptive.rank.Percentile;
035 import org.apache.commons.math3.stat.descriptive.summary.Sum;
036 import org.apache.commons.math3.stat.descriptive.summary.SumOfSquares;
037 import org.apache.commons.math3.util.MathUtils;
038 import org.apache.commons.math3.util.ResizableDoubleArray;
039 import org.apache.commons.math3.util.FastMath;
040
041
042 /**
043 * Maintains a dataset of values of a single variable and computes descriptive
044 * statistics based on stored data. The {@link #getWindowSize() windowSize}
045 * property sets a limit on the number of values that can be stored in the
046 * dataset. The default value, INFINITE_WINDOW, puts no limit on the size of
047 * the dataset. This value should be used with caution, as the backing store
048 * will grow without bound in this case. For very large datasets,
049 * {@link SummaryStatistics}, which does not store the dataset, should be used
050 * instead of this class. If <code>windowSize</code> is not INFINITE_WINDOW and
051 * more values are added than can be stored in the dataset, new values are
052 * added in a "rolling" manner, with new values replacing the "oldest" values
053 * in the dataset.
054 *
055 * <p>Note: this class is not threadsafe. Use
056 * {@link SynchronizedDescriptiveStatistics} if concurrent access from multiple
057 * threads is required.</p>
058 *
059 * @version $Id: DescriptiveStatistics.java 1422354 2012-12-15 20:59:01Z psteitz $
060 */
061 public class DescriptiveStatistics implements StatisticalSummary, Serializable {
062
063 /**
064 * Represents an infinite window size. When the {@link #getWindowSize()}
065 * returns this value, there is no limit to the number of data values
066 * that can be stored in the dataset.
067 */
068 public static final int INFINITE_WINDOW = -1;
069
070 /** Serialization UID */
071 private static final long serialVersionUID = 4133067267405273064L;
072
073 /** Name of the setQuantile method. */
074 private static final String SET_QUANTILE_METHOD_NAME = "setQuantile";
075
076 /** hold the window size **/
077 protected int windowSize = INFINITE_WINDOW;
078
079 /**
080 * Stored data values
081 */
082 private ResizableDoubleArray eDA = new ResizableDoubleArray();
083
084 /** Mean statistic implementation - can be reset by setter. */
085 private UnivariateStatistic meanImpl = new Mean();
086
087 /** Geometric mean statistic implementation - can be reset by setter. */
088 private UnivariateStatistic geometricMeanImpl = new GeometricMean();
089
090 /** Kurtosis statistic implementation - can be reset by setter. */
091 private UnivariateStatistic kurtosisImpl = new Kurtosis();
092
093 /** Maximum statistic implementation - can be reset by setter. */
094 private UnivariateStatistic maxImpl = new Max();
095
096 /** Minimum statistic implementation - can be reset by setter. */
097 private UnivariateStatistic minImpl = new Min();
098
099 /** Percentile statistic implementation - can be reset by setter. */
100 private UnivariateStatistic percentileImpl = new Percentile();
101
102 /** Skewness statistic implementation - can be reset by setter. */
103 private UnivariateStatistic skewnessImpl = new Skewness();
104
105 /** Variance statistic implementation - can be reset by setter. */
106 private UnivariateStatistic varianceImpl = new Variance();
107
108 /** Sum of squares statistic implementation - can be reset by setter. */
109 private UnivariateStatistic sumsqImpl = new SumOfSquares();
110
111 /** Sum statistic implementation - can be reset by setter. */
112 private UnivariateStatistic sumImpl = new Sum();
113
114 /**
115 * Construct a DescriptiveStatistics instance with an infinite window
116 */
117 public DescriptiveStatistics() {
118 }
119
120 /**
121 * Construct a DescriptiveStatistics instance with the specified window
122 *
123 * @param window the window size.
124 * @throws MathIllegalArgumentException if window size is less than 1 but
125 * not equal to {@link #INFINITE_WINDOW}
126 */
127 public DescriptiveStatistics(int window) throws MathIllegalArgumentException {
128 setWindowSize(window);
129 }
130
131 /**
132 * Construct a DescriptiveStatistics instance with an infinite window
133 * and the initial data values in double[] initialDoubleArray.
134 * If initialDoubleArray is null, then this constructor corresponds to
135 * DescriptiveStatistics()
136 *
137 * @param initialDoubleArray the initial double[].
138 */
139 public DescriptiveStatistics(double[] initialDoubleArray) {
140 if (initialDoubleArray != null) {
141 eDA = new ResizableDoubleArray(initialDoubleArray);
142 }
143 }
144
145 /**
146 * Copy constructor. Construct a new DescriptiveStatistics instance that
147 * is a copy of original.
148 *
149 * @param original DescriptiveStatistics instance to copy
150 * @throws NullArgumentException if original is null
151 */
152 public DescriptiveStatistics(DescriptiveStatistics original) throws NullArgumentException {
153 copy(original, this);
154 }
155
156 /**
157 * Adds the value to the dataset. If the dataset is at the maximum size
158 * (i.e., the number of stored elements equals the currently configured
159 * windowSize), the first (oldest) element in the dataset is discarded
160 * to make room for the new value.
161 *
162 * @param v the value to be added
163 */
164 public void addValue(double v) {
165 if (windowSize != INFINITE_WINDOW) {
166 if (getN() == windowSize) {
167 eDA.addElementRolling(v);
168 } else if (getN() < windowSize) {
169 eDA.addElement(v);
170 }
171 } else {
172 eDA.addElement(v);
173 }
174 }
175
176 /**
177 * Removes the most recent value from the dataset.
178 *
179 * @throws MathIllegalStateException if there are no elements stored
180 */
181 public void removeMostRecentValue() throws MathIllegalStateException {
182 try {
183 eDA.discardMostRecentElements(1);
184 } catch (MathIllegalArgumentException ex) {
185 throw new MathIllegalStateException(LocalizedFormats.NO_DATA);
186 }
187 }
188
189 /**
190 * Replaces the most recently stored value with the given value.
191 * There must be at least one element stored to call this method.
192 *
193 * @param v the value to replace the most recent stored value
194 * @return replaced value
195 * @throws MathIllegalStateException if there are no elements stored
196 */
197 public double replaceMostRecentValue(double v) throws MathIllegalStateException {
198 return eDA.substituteMostRecentElement(v);
199 }
200
201 /**
202 * Returns the <a href="http://www.xycoon.com/arithmetic_mean.htm">
203 * arithmetic mean </a> of the available values
204 * @return The mean or Double.NaN if no values have been added.
205 */
206 public double getMean() {
207 return apply(meanImpl);
208 }
209
210 /**
211 * Returns the <a href="http://www.xycoon.com/geometric_mean.htm">
212 * geometric mean </a> of the available values
213 * @return The geometricMean, Double.NaN if no values have been added,
214 * or if the product of the available values is less than or equal to 0.
215 */
216 public double getGeometricMean() {
217 return apply(geometricMeanImpl);
218 }
219
220 /**
221 * Returns the (sample) variance of the available values.
222 *
223 * <p>This method returns the bias-corrected sample variance (using {@code n - 1} in
224 * the denominator). Use {@link #getPopulationVariance()} for the non-bias-corrected
225 * population variance.</p>
226 *
227 * @return The variance, Double.NaN if no values have been added
228 * or 0.0 for a single value set.
229 */
230 public double getVariance() {
231 return apply(varianceImpl);
232 }
233
234 /**
235 * Returns the <a href="http://en.wikibooks.org/wiki/Statistics/Summary/Variance">
236 * population variance</a> of the available values.
237 *
238 * @return The population variance, Double.NaN if no values have been added,
239 * or 0.0 for a single value set.
240 */
241 public double getPopulationVariance() {
242 return apply(new Variance(false));
243 }
244
245 /**
246 * Returns the standard deviation of the available values.
247 * @return The standard deviation, Double.NaN if no values have been added
248 * or 0.0 for a single value set.
249 */
250 public double getStandardDeviation() {
251 double stdDev = Double.NaN;
252 if (getN() > 0) {
253 if (getN() > 1) {
254 stdDev = FastMath.sqrt(getVariance());
255 } else {
256 stdDev = 0.0;
257 }
258 }
259 return stdDev;
260 }
261
262 /**
263 * Returns the skewness of the available values. Skewness is a
264 * measure of the asymmetry of a given distribution.
265 * @return The skewness, Double.NaN if no values have been added
266 * or 0.0 for a value set <=2.
267 */
268 public double getSkewness() {
269 return apply(skewnessImpl);
270 }
271
272 /**
273 * Returns the Kurtosis of the available values. Kurtosis is a
274 * measure of the "peakedness" of a distribution
275 * @return The kurtosis, Double.NaN if no values have been added, or 0.0
276 * for a value set <=3.
277 */
278 public double getKurtosis() {
279 return apply(kurtosisImpl);
280 }
281
282 /**
283 * Returns the maximum of the available values
284 * @return The max or Double.NaN if no values have been added.
285 */
286 public double getMax() {
287 return apply(maxImpl);
288 }
289
290 /**
291 * Returns the minimum of the available values
292 * @return The min or Double.NaN if no values have been added.
293 */
294 public double getMin() {
295 return apply(minImpl);
296 }
297
298 /**
299 * Returns the number of available values
300 * @return The number of available values
301 */
302 public long getN() {
303 return eDA.getNumElements();
304 }
305
306 /**
307 * Returns the sum of the values that have been added to Univariate.
308 * @return The sum or Double.NaN if no values have been added
309 */
310 public double getSum() {
311 return apply(sumImpl);
312 }
313
314 /**
315 * Returns the sum of the squares of the available values.
316 * @return The sum of the squares or Double.NaN if no
317 * values have been added.
318 */
319 public double getSumsq() {
320 return apply(sumsqImpl);
321 }
322
323 /**
324 * Resets all statistics and storage
325 */
326 public void clear() {
327 eDA.clear();
328 }
329
330
331 /**
332 * Returns the maximum number of values that can be stored in the
333 * dataset, or INFINITE_WINDOW (-1) if there is no limit.
334 *
335 * @return The current window size or -1 if its Infinite.
336 */
337 public int getWindowSize() {
338 return windowSize;
339 }
340
341 /**
342 * WindowSize controls the number of values that contribute to the
343 * reported statistics. For example, if windowSize is set to 3 and the
344 * values {1,2,3,4,5} have been added <strong> in that order</strong> then
345 * the <i>available values</i> are {3,4,5} and all reported statistics will
346 * be based on these values. If {@code windowSize} is decreased as a result
347 * of this call and there are more than the new value of elements in the
348 * current dataset, values from the front of the array are discarded to
349 * reduce the dataset to {@code windowSize} elements.
350 *
351 * @param windowSize sets the size of the window.
352 * @throws MathIllegalArgumentException if window size is less than 1 but
353 * not equal to {@link #INFINITE_WINDOW}
354 */
355 public void setWindowSize(int windowSize) throws MathIllegalArgumentException {
356 if (windowSize < 1 && windowSize != INFINITE_WINDOW) {
357 throw new MathIllegalArgumentException(
358 LocalizedFormats.NOT_POSITIVE_WINDOW_SIZE, windowSize);
359 }
360
361 this.windowSize = windowSize;
362
363 // We need to check to see if we need to discard elements
364 // from the front of the array. If the windowSize is less than
365 // the current number of elements.
366 if (windowSize != INFINITE_WINDOW && windowSize < eDA.getNumElements()) {
367 eDA.discardFrontElements(eDA.getNumElements() - windowSize);
368 }
369 }
370
371 /**
372 * Returns the current set of values in an array of double primitives.
373 * The order of addition is preserved. The returned array is a fresh
374 * copy of the underlying data -- i.e., it is not a reference to the
375 * stored data.
376 *
377 * @return returns the current set of numbers in the order in which they
378 * were added to this set
379 */
380 public double[] getValues() {
381 return eDA.getElements();
382 }
383
384 /**
385 * Returns the current set of values in an array of double primitives,
386 * sorted in ascending order. The returned array is a fresh
387 * copy of the underlying data -- i.e., it is not a reference to the
388 * stored data.
389 * @return returns the current set of
390 * numbers sorted in ascending order
391 */
392 public double[] getSortedValues() {
393 double[] sort = getValues();
394 Arrays.sort(sort);
395 return sort;
396 }
397
398 /**
399 * Returns the element at the specified index
400 * @param index The Index of the element
401 * @return return the element at the specified index
402 */
403 public double getElement(int index) {
404 return eDA.getElement(index);
405 }
406
407 /**
408 * Returns an estimate for the pth percentile of the stored values.
409 * <p>
410 * The implementation provided here follows the first estimation procedure presented
411 * <a href="http://www.itl.nist.gov/div898/handbook/prc/section2/prc252.htm">here.</a>
412 * </p><p>
413 * <strong>Preconditions</strong>:<ul>
414 * <li><code>0 < p ≤ 100</code> (otherwise an
415 * <code>MathIllegalArgumentException</code> is thrown)</li>
416 * <li>at least one value must be stored (returns <code>Double.NaN
417 * </code> otherwise)</li>
418 * </ul></p>
419 *
420 * @param p the requested percentile (scaled from 0 - 100)
421 * @return An estimate for the pth percentile of the stored data
422 * @throws MathIllegalStateException if percentile implementation has been
423 * overridden and the supplied implementation does not support setQuantile
424 * @throws MathIllegalArgumentException if p is not a valid quantile
425 */
426 public double getPercentile(double p) throws MathIllegalStateException, MathIllegalArgumentException {
427 if (percentileImpl instanceof Percentile) {
428 ((Percentile) percentileImpl).setQuantile(p);
429 } else {
430 try {
431 percentileImpl.getClass().getMethod(SET_QUANTILE_METHOD_NAME,
432 new Class[] {Double.TYPE}).invoke(percentileImpl,
433 new Object[] {Double.valueOf(p)});
434 } catch (NoSuchMethodException e1) { // Setter guard should prevent
435 throw new MathIllegalStateException(
436 LocalizedFormats.PERCENTILE_IMPLEMENTATION_UNSUPPORTED_METHOD,
437 percentileImpl.getClass().getName(), SET_QUANTILE_METHOD_NAME);
438 } catch (IllegalAccessException e2) {
439 throw new MathIllegalStateException(
440 LocalizedFormats.PERCENTILE_IMPLEMENTATION_CANNOT_ACCESS_METHOD,
441 SET_QUANTILE_METHOD_NAME, percentileImpl.getClass().getName());
442 } catch (InvocationTargetException e3) {
443 throw new IllegalStateException(e3.getCause());
444 }
445 }
446 return apply(percentileImpl);
447 }
448
449 /**
450 * Generates a text report displaying univariate statistics from values
451 * that have been added. Each statistic is displayed on a separate
452 * line.
453 *
454 * @return String with line feeds displaying statistics
455 */
456 @Override
457 public String toString() {
458 StringBuilder outBuffer = new StringBuilder();
459 String endl = "\n";
460 outBuffer.append("DescriptiveStatistics:").append(endl);
461 outBuffer.append("n: ").append(getN()).append(endl);
462 outBuffer.append("min: ").append(getMin()).append(endl);
463 outBuffer.append("max: ").append(getMax()).append(endl);
464 outBuffer.append("mean: ").append(getMean()).append(endl);
465 outBuffer.append("std dev: ").append(getStandardDeviation())
466 .append(endl);
467 try {
468 // No catch for MIAE because actual parameter is valid below
469 outBuffer.append("median: ").append(getPercentile(50)).append(endl);
470 } catch (MathIllegalStateException ex) {
471 outBuffer.append("median: unavailable").append(endl);
472 }
473 outBuffer.append("skewness: ").append(getSkewness()).append(endl);
474 outBuffer.append("kurtosis: ").append(getKurtosis()).append(endl);
475 return outBuffer.toString();
476 }
477
478 /**
479 * Apply the given statistic to the data associated with this set of statistics.
480 * @param stat the statistic to apply
481 * @return the computed value of the statistic.
482 */
483 public double apply(UnivariateStatistic stat) {
484 // No try-catch or advertised exception here because arguments are guaranteed valid
485 return eDA.compute(stat);
486 }
487
488 // Implementation getters and setter
489
490 /**
491 * Returns the currently configured mean implementation.
492 *
493 * @return the UnivariateStatistic implementing the mean
494 * @since 1.2
495 */
496 public synchronized UnivariateStatistic getMeanImpl() {
497 return meanImpl;
498 }
499
500 /**
501 * <p>Sets the implementation for the mean.</p>
502 *
503 * @param meanImpl the UnivariateStatistic instance to use
504 * for computing the mean
505 * @since 1.2
506 */
507 public synchronized void setMeanImpl(UnivariateStatistic meanImpl) {
508 this.meanImpl = meanImpl;
509 }
510
511 /**
512 * Returns the currently configured geometric mean implementation.
513 *
514 * @return the UnivariateStatistic implementing the geometric mean
515 * @since 1.2
516 */
517 public synchronized UnivariateStatistic getGeometricMeanImpl() {
518 return geometricMeanImpl;
519 }
520
521 /**
522 * <p>Sets the implementation for the gemoetric mean.</p>
523 *
524 * @param geometricMeanImpl the UnivariateStatistic instance to use
525 * for computing the geometric mean
526 * @since 1.2
527 */
528 public synchronized void setGeometricMeanImpl(
529 UnivariateStatistic geometricMeanImpl) {
530 this.geometricMeanImpl = geometricMeanImpl;
531 }
532
533 /**
534 * Returns the currently configured kurtosis implementation.
535 *
536 * @return the UnivariateStatistic implementing the kurtosis
537 * @since 1.2
538 */
539 public synchronized UnivariateStatistic getKurtosisImpl() {
540 return kurtosisImpl;
541 }
542
543 /**
544 * <p>Sets the implementation for the kurtosis.</p>
545 *
546 * @param kurtosisImpl the UnivariateStatistic instance to use
547 * for computing the kurtosis
548 * @since 1.2
549 */
550 public synchronized void setKurtosisImpl(UnivariateStatistic kurtosisImpl) {
551 this.kurtosisImpl = kurtosisImpl;
552 }
553
554 /**
555 * Returns the currently configured maximum implementation.
556 *
557 * @return the UnivariateStatistic implementing the maximum
558 * @since 1.2
559 */
560 public synchronized UnivariateStatistic getMaxImpl() {
561 return maxImpl;
562 }
563
564 /**
565 * <p>Sets the implementation for the maximum.</p>
566 *
567 * @param maxImpl the UnivariateStatistic instance to use
568 * for computing the maximum
569 * @since 1.2
570 */
571 public synchronized void setMaxImpl(UnivariateStatistic maxImpl) {
572 this.maxImpl = maxImpl;
573 }
574
575 /**
576 * Returns the currently configured minimum implementation.
577 *
578 * @return the UnivariateStatistic implementing the minimum
579 * @since 1.2
580 */
581 public synchronized UnivariateStatistic getMinImpl() {
582 return minImpl;
583 }
584
585 /**
586 * <p>Sets the implementation for the minimum.</p>
587 *
588 * @param minImpl the UnivariateStatistic instance to use
589 * for computing the minimum
590 * @since 1.2
591 */
592 public synchronized void setMinImpl(UnivariateStatistic minImpl) {
593 this.minImpl = minImpl;
594 }
595
596 /**
597 * Returns the currently configured percentile implementation.
598 *
599 * @return the UnivariateStatistic implementing the percentile
600 * @since 1.2
601 */
602 public synchronized UnivariateStatistic getPercentileImpl() {
603 return percentileImpl;
604 }
605
606 /**
607 * Sets the implementation to be used by {@link #getPercentile(double)}.
608 * The supplied <code>UnivariateStatistic</code> must provide a
609 * <code>setQuantile(double)</code> method; otherwise
610 * <code>IllegalArgumentException</code> is thrown.
611 *
612 * @param percentileImpl the percentileImpl to set
613 * @throws MathIllegalArgumentException if the supplied implementation does not
614 * provide a <code>setQuantile</code> method
615 * @since 1.2
616 */
617 public synchronized void setPercentileImpl(UnivariateStatistic percentileImpl)
618 throws MathIllegalArgumentException {
619 try {
620 percentileImpl.getClass().getMethod(SET_QUANTILE_METHOD_NAME,
621 new Class[] {Double.TYPE}).invoke(percentileImpl,
622 new Object[] {Double.valueOf(50.0d)});
623 } catch (NoSuchMethodException e1) {
624 throw new MathIllegalArgumentException(
625 LocalizedFormats.PERCENTILE_IMPLEMENTATION_UNSUPPORTED_METHOD,
626 percentileImpl.getClass().getName(), SET_QUANTILE_METHOD_NAME);
627 } catch (IllegalAccessException e2) {
628 throw new MathIllegalArgumentException(
629 LocalizedFormats.PERCENTILE_IMPLEMENTATION_CANNOT_ACCESS_METHOD,
630 SET_QUANTILE_METHOD_NAME, percentileImpl.getClass().getName());
631 } catch (InvocationTargetException e3) {
632 throw new IllegalArgumentException(e3.getCause());
633 }
634 this.percentileImpl = percentileImpl;
635 }
636
637 /**
638 * Returns the currently configured skewness implementation.
639 *
640 * @return the UnivariateStatistic implementing the skewness
641 * @since 1.2
642 */
643 public synchronized UnivariateStatistic getSkewnessImpl() {
644 return skewnessImpl;
645 }
646
647 /**
648 * <p>Sets the implementation for the skewness.</p>
649 *
650 * @param skewnessImpl the UnivariateStatistic instance to use
651 * for computing the skewness
652 * @since 1.2
653 */
654 public synchronized void setSkewnessImpl(
655 UnivariateStatistic skewnessImpl) {
656 this.skewnessImpl = skewnessImpl;
657 }
658
659 /**
660 * Returns the currently configured variance implementation.
661 *
662 * @return the UnivariateStatistic implementing the variance
663 * @since 1.2
664 */
665 public synchronized UnivariateStatistic getVarianceImpl() {
666 return varianceImpl;
667 }
668
669 /**
670 * <p>Sets the implementation for the variance.</p>
671 *
672 * @param varianceImpl the UnivariateStatistic instance to use
673 * for computing the variance
674 * @since 1.2
675 */
676 public synchronized void setVarianceImpl(
677 UnivariateStatistic varianceImpl) {
678 this.varianceImpl = varianceImpl;
679 }
680
681 /**
682 * Returns the currently configured sum of squares implementation.
683 *
684 * @return the UnivariateStatistic implementing the sum of squares
685 * @since 1.2
686 */
687 public synchronized UnivariateStatistic getSumsqImpl() {
688 return sumsqImpl;
689 }
690
691 /**
692 * <p>Sets the implementation for the sum of squares.</p>
693 *
694 * @param sumsqImpl the UnivariateStatistic instance to use
695 * for computing the sum of squares
696 * @since 1.2
697 */
698 public synchronized void setSumsqImpl(UnivariateStatistic sumsqImpl) {
699 this.sumsqImpl = sumsqImpl;
700 }
701
702 /**
703 * Returns the currently configured sum implementation.
704 *
705 * @return the UnivariateStatistic implementing the sum
706 * @since 1.2
707 */
708 public synchronized UnivariateStatistic getSumImpl() {
709 return sumImpl;
710 }
711
712 /**
713 * <p>Sets the implementation for the sum.</p>
714 *
715 * @param sumImpl the UnivariateStatistic instance to use
716 * for computing the sum
717 * @since 1.2
718 */
719 public synchronized void setSumImpl(UnivariateStatistic sumImpl) {
720 this.sumImpl = sumImpl;
721 }
722
723 /**
724 * Returns a copy of this DescriptiveStatistics instance with the same internal state.
725 *
726 * @return a copy of this
727 */
728 public DescriptiveStatistics copy() {
729 DescriptiveStatistics result = new DescriptiveStatistics();
730 // No try-catch or advertised exception because parms are guaranteed valid
731 copy(this, result);
732 return result;
733 }
734
735 /**
736 * Copies source to dest.
737 * <p>Neither source nor dest can be null.</p>
738 *
739 * @param source DescriptiveStatistics to copy
740 * @param dest DescriptiveStatistics to copy to
741 * @throws NullArgumentException if either source or dest is null
742 */
743 public static void copy(DescriptiveStatistics source, DescriptiveStatistics dest)
744 throws NullArgumentException {
745 MathUtils.checkNotNull(source);
746 MathUtils.checkNotNull(dest);
747 // Copy data and window size
748 dest.eDA = source.eDA.copy();
749 dest.windowSize = source.windowSize;
750
751 // Copy implementations
752 dest.maxImpl = source.maxImpl.copy();
753 dest.meanImpl = source.meanImpl.copy();
754 dest.minImpl = source.minImpl.copy();
755 dest.sumImpl = source.sumImpl.copy();
756 dest.varianceImpl = source.varianceImpl.copy();
757 dest.sumsqImpl = source.sumsqImpl.copy();
758 dest.geometricMeanImpl = source.geometricMeanImpl.copy();
759 dest.kurtosisImpl = source.kurtosisImpl;
760 dest.skewnessImpl = source.skewnessImpl;
761 dest.percentileImpl = source.percentileImpl;
762 }
763 }