1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.math4.legacy.stat.descriptive;
18
19 import java.lang.reflect.InvocationTargetException;
20 import java.util.Arrays;
21
22 import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException;
23 import org.apache.commons.math4.legacy.exception.MathIllegalStateException;
24 import org.apache.commons.math4.legacy.exception.NullArgumentException;
25 import org.apache.commons.math4.legacy.exception.util.LocalizedFormats;
26 import org.apache.commons.math4.legacy.stat.descriptive.moment.GeometricMean;
27 import org.apache.commons.math4.legacy.stat.descriptive.moment.Kurtosis;
28 import org.apache.commons.math4.legacy.stat.descriptive.moment.Mean;
29 import org.apache.commons.math4.legacy.stat.descriptive.moment.Skewness;
30 import org.apache.commons.math4.legacy.stat.descriptive.moment.Variance;
31 import org.apache.commons.math4.legacy.stat.descriptive.rank.Max;
32 import org.apache.commons.math4.legacy.stat.descriptive.rank.Min;
33 import org.apache.commons.math4.legacy.stat.descriptive.rank.Percentile;
34 import org.apache.commons.math4.legacy.stat.descriptive.summary.Sum;
35 import org.apache.commons.math4.legacy.stat.descriptive.summary.SumOfSquares;
36 import org.apache.commons.math4.core.jdkmath.JdkMath;
37
38
39 /**
40 * Maintains a dataset of values of a single variable and computes descriptive
41 * statistics based on stored data.
42 * <p>
43 * The {@link #getWindowSize() windowSize}
44 * property sets a limit on the number of values that can be stored in the
45 * dataset. The default value, INFINITE_WINDOW, puts no limit on the size of
46 * the dataset. This value should be used with caution, as the backing store
47 * will grow without bound in this case. For very large datasets,
48 * {@link SummaryStatistics}, which does not store the dataset, should be used
49 * instead of this class. If <code>windowSize</code> is not INFINITE_WINDOW and
50 * more values are added than can be stored in the dataset, new values are
51 * added in a "rolling" manner, with new values replacing the "oldest" values
52 * in the dataset.
53 * <p>
54 * Note: this class is not threadsafe. Use
55 * {@link SynchronizedDescriptiveStatistics} if concurrent access from multiple
56 * threads is required.
57 */
58 public class DescriptiveStatistics implements StatisticalSummary {
59
60 /**
61 * Represents an infinite window size. When the {@link #getWindowSize()}
62 * returns this value, there is no limit to the number of data values
63 * that can be stored in the dataset.
64 */
65 public static final int INFINITE_WINDOW = -1;
66
67 /** Name of the setQuantile method. */
68 private static final String SET_QUANTILE_METHOD_NAME = "setQuantile";
69
70 /** hold the window size. */
71 private int windowSize = INFINITE_WINDOW;
72
73 /** Stored data values. */
74 private ResizableDoubleArray eDA = new ResizableDoubleArray();
75
76 /** Mean statistic implementation - can be reset by setter. */
77 private UnivariateStatistic meanImpl = new Mean();
78
79 /** Geometric mean statistic implementation - can be reset by setter. */
80 private UnivariateStatistic geometricMeanImpl = new GeometricMean();
81
82 /** Kurtosis statistic implementation - can be reset by setter. */
83 private UnivariateStatistic kurtosisImpl = new Kurtosis();
84
85 /** Maximum statistic implementation - can be reset by setter. */
86 private UnivariateStatistic maxImpl = new Max();
87
88 /** Minimum statistic implementation - can be reset by setter. */
89 private UnivariateStatistic minImpl = new Min();
90
91 /** Percentile statistic implementation - can be reset by setter. */
92 private UnivariateStatistic percentileImpl = new Percentile();
93
94 /** Skewness statistic implementation - can be reset by setter. */
95 private UnivariateStatistic skewnessImpl = new Skewness();
96
97 /** Variance statistic implementation - can be reset by setter. */
98 private UnivariateStatistic varianceImpl = new Variance();
99
100 /** Sum of squares statistic implementation - can be reset by setter. */
101 private UnivariateStatistic sumsqImpl = new SumOfSquares();
102
103 /** Sum statistic implementation - can be reset by setter. */
104 private UnivariateStatistic sumImpl = new Sum();
105
106 /**
107 * Construct a {@code DescriptiveStatistics} instance with an infinite
108 * window.
109 */
110 public DescriptiveStatistics() {
111 }
112
113 /**
114 * Construct a {@code DescriptiveStatistics} instance with the specified
115 * window.
116 *
117 * @param window the window size.
118 * @throws MathIllegalArgumentException if window size is less than 1 but
119 * not equal to {@link #INFINITE_WINDOW}
120 */
121 public DescriptiveStatistics(int window) throws MathIllegalArgumentException {
122 setWindowSize(window);
123 }
124
125 /**
126 * Construct a {@code DescriptiveStatistics} instance with an infinite
127 * window and the initial data values in {@code initialDoubleArray}.
128 * If {@code initialDoubleArray} is {@code null}, then this constructor
129 * corresponds to the {@link #DescriptiveStatistics() default constructor}.
130 *
131 * @param initialDoubleArray the initial double[].
132 */
133 public DescriptiveStatistics(double[] initialDoubleArray) {
134 if (initialDoubleArray != null) {
135 eDA = new ResizableDoubleArray(initialDoubleArray);
136 }
137 }
138
139 /**
140 * Construct a DescriptiveStatistics instance with an infinite window
141 * and the initial data values in {@code initialDoubleArray}.
142 * If {@code initialDoubleArray} is {@code null}, then this constructor
143 * corresponds to {@link #DescriptiveStatistics() }.
144 *
145 * @param initialDoubleArray the initial Double[].
146 */
147 public DescriptiveStatistics(Double[] initialDoubleArray) {
148 if (initialDoubleArray != null) {
149 eDA = new ResizableDoubleArray(initialDoubleArray.length);
150 for(double initialValue : initialDoubleArray) {
151 eDA.addElement(initialValue);
152 }
153 }
154 }
155
156 /**
157 * Copy constructor. Construct a new {@code DescriptiveStatistics} instance
158 * that is a copy of {@code original}.
159 *
160 * @param original DescriptiveStatistics instance to copy
161 * @throws NullArgumentException if original is null
162 */
163 public DescriptiveStatistics(DescriptiveStatistics original) throws NullArgumentException {
164 copy(original, this);
165 }
166
167 /**
168 * Adds the value to the dataset. If the dataset is at the maximum size
169 * (i.e., the number of stored elements equals the currently configured
170 * windowSize), the first (oldest) element in the dataset is discarded
171 * to make room for the new value.
172 *
173 * @param v the value to be added
174 */
175 public void addValue(double v) {
176 if (windowSize != INFINITE_WINDOW) {
177 if (getN() == windowSize) {
178 eDA.addElementRolling(v);
179 } else if (getN() < windowSize) {
180 eDA.addElement(v);
181 }
182 } else {
183 eDA.addElement(v);
184 }
185 }
186
187 /**
188 * Removes the most recent value from the dataset.
189 *
190 * @throws MathIllegalStateException if there are no elements stored
191 */
192 public void removeMostRecentValue() throws MathIllegalStateException {
193 try {
194 eDA.discardMostRecentElements(1);
195 } catch (MathIllegalArgumentException ex) {
196 throw new MathIllegalStateException(LocalizedFormats.NO_DATA);
197 }
198 }
199
200 /**
201 * Replaces the most recently stored value with the given value.
202 * There must be at least one element stored to call this method.
203 *
204 * @param v the value to replace the most recent stored value
205 * @return replaced value
206 * @throws MathIllegalStateException if there are no elements stored
207 */
208 public double replaceMostRecentValue(double v) throws MathIllegalStateException {
209 return eDA.substituteMostRecentElement(v);
210 }
211
212 /**
213 * Returns the <a href="http://www.xycoon.com/arithmetic_mean.htm">
214 * arithmetic mean </a> of the available values.
215 * @return The mean or Double.NaN if no values have been added.
216 */
217 @Override
218 public double getMean() {
219 return apply(meanImpl);
220 }
221
222 /**
223 * Returns the <a href="http://www.xycoon.com/geometric_mean.htm">
224 * geometric mean </a> of the available values.
225 * <p>
226 * See {@link GeometricMean} for details on the computing algorithm.</p>
227 *
228 * @return The geometricMean, Double.NaN if no values have been added,
229 * or if any negative values have been added.
230 */
231 public double getGeometricMean() {
232 return apply(geometricMeanImpl);
233 }
234
235 /**
236 * Returns the (sample) variance of the available values.
237 *
238 * <p>This method returns the bias-corrected sample variance (using {@code n - 1} in
239 * the denominator). Use {@link #getPopulationVariance()} for the non-bias-corrected
240 * population variance.</p>
241 *
242 * @return The variance, Double.NaN if no values have been added
243 * or 0.0 for a single value set.
244 */
245 @Override
246 public double getVariance() {
247 return apply(varianceImpl);
248 }
249
250 /**
251 * Returns the <a href="http://en.wikibooks.org/wiki/Statistics/Summary/Variance">
252 * population variance</a> of the available values.
253 *
254 * @return The population variance, Double.NaN if no values have been added,
255 * or 0.0 for a single value set.
256 */
257 public double getPopulationVariance() {
258 return apply(new Variance(false));
259 }
260
261 /**
262 * Returns the standard deviation of the available values.
263 * @return The standard deviation, Double.NaN if no values have been added
264 * or 0.0 for a single value set.
265 */
266 @Override
267 public double getStandardDeviation() {
268 double stdDev = Double.NaN;
269 if (getN() > 0) {
270 if (getN() > 1) {
271 stdDev = JdkMath.sqrt(getVariance());
272 } else {
273 stdDev = 0.0;
274 }
275 }
276 return stdDev;
277 }
278
279 /**
280 * Returns the quadratic mean, a.k.a.
281 * <a href="http://mathworld.wolfram.com/Root-Mean-Square.html">
282 * root-mean-square</a> of the available values
283 * @return The quadratic mean or {@code Double.NaN} if no values
284 * have been added.
285 */
286 public double getQuadraticMean() {
287 final long n = getN();
288 return n > 0 ? JdkMath.sqrt(getSumsq() / n) : Double.NaN;
289 }
290
291 /**
292 * Returns the skewness of the available values. Skewness is a
293 * measure of the asymmetry of a given distribution.
294 *
295 * @return The skewness, Double.NaN if less than 3 values have been added.
296 */
297 public double getSkewness() {
298 return apply(skewnessImpl);
299 }
300
301 /**
302 * Returns the Kurtosis of the available values. Kurtosis is a
303 * measure of the "peakedness" of a distribution.
304 *
305 * @return The kurtosis, Double.NaN if less than 4 values have been added.
306 */
307 public double getKurtosis() {
308 return apply(kurtosisImpl);
309 }
310
311 /**
312 * Returns the maximum of the available values.
313 * @return The max or Double.NaN if no values have been added.
314 */
315 @Override
316 public double getMax() {
317 return apply(maxImpl);
318 }
319
320 /**
321 * Returns the minimum of the available values.
322 * @return The min or Double.NaN if no values have been added.
323 */
324 @Override
325 public double getMin() {
326 return apply(minImpl);
327 }
328
329 /**
330 * Returns the number of available values.
331 * @return The number of available values
332 */
333 @Override
334 public long getN() {
335 return eDA.getNumElements();
336 }
337
338 /**
339 * Returns the sum of the values that have been added to Univariate.
340 * @return The sum or Double.NaN if no values have been added
341 */
342 @Override
343 public double getSum() {
344 return apply(sumImpl);
345 }
346
347 /**
348 * Returns the sum of the squares of the available values.
349 * @return The sum of the squares or Double.NaN if no
350 * values have been added.
351 */
352 public double getSumsq() {
353 return apply(sumsqImpl);
354 }
355
356 /**
357 * Resets all statistics and storage.
358 */
359 public void clear() {
360 eDA.clear();
361 }
362
363
364 /**
365 * Returns the maximum number of values that can be stored in the
366 * dataset, or INFINITE_WINDOW (-1) if there is no limit.
367 *
368 * @return The current window size or -1 if its Infinite.
369 */
370 public int getWindowSize() {
371 return windowSize;
372 }
373
374 /**
375 * WindowSize controls the number of values that contribute to the
376 * reported statistics. For example, if windowSize is set to 3 and the
377 * values {1,2,3,4,5} have been added <strong> in that order</strong> then
378 * the <i>available values</i> are {3,4,5} and all reported statistics will
379 * be based on these values. If {@code windowSize} is decreased as a result
380 * of this call and there are more than the new value of elements in the
381 * current dataset, values from the front of the array are discarded to
382 * reduce the dataset to {@code windowSize} elements.
383 *
384 * @param windowSize sets the size of the window.
385 * @throws MathIllegalArgumentException if window size is less than 1 but
386 * not equal to {@link #INFINITE_WINDOW}
387 */
388 public void setWindowSize(int windowSize) throws MathIllegalArgumentException {
389 if (windowSize < 1 && windowSize != INFINITE_WINDOW) {
390 throw new MathIllegalArgumentException(
391 LocalizedFormats.NOT_POSITIVE_WINDOW_SIZE, windowSize);
392 }
393
394 this.windowSize = windowSize;
395
396 // We need to check to see if we need to discard elements
397 // from the front of the array. If the windowSize is less than
398 // the current number of elements.
399 if (windowSize != INFINITE_WINDOW && windowSize < eDA.getNumElements()) {
400 eDA.discardFrontElements(eDA.getNumElements() - windowSize);
401 }
402 }
403
404 /**
405 * Returns the current set of values in an array of double primitives.
406 * The order of addition is preserved. The returned array is a fresh
407 * copy of the underlying data -- i.e., it is not a reference to the
408 * stored data.
409 *
410 * @return returns the current set of numbers in the order in which they
411 * were added to this set
412 */
413 public double[] getValues() {
414 return eDA.getElements();
415 }
416
417 /**
418 * Returns the current set of values in an array of double primitives,
419 * sorted in ascending order. The returned array is a fresh
420 * copy of the underlying data -- i.e., it is not a reference to the
421 * stored data.
422 * @return returns the current set of
423 * numbers sorted in ascending order
424 */
425 public double[] getSortedValues() {
426 double[] sort = getValues();
427 Arrays.sort(sort);
428 return sort;
429 }
430
431 /**
432 * Returns the element at the specified index.
433 * @param index The Index of the element
434 * @return return the element at the specified index
435 */
436 public double getElement(int index) {
437 return eDA.getElement(index);
438 }
439
440 /**
441 * Returns an estimate for the pth percentile of the stored values.
442 * <p>
443 * The implementation provided here follows the first estimation procedure presented
444 * <a href="http://www.itl.nist.gov/div898/handbook/prc/section2/prc252.htm">here.</a>
445 * </p><p>
446 * <strong>Preconditions</strong>:<ul>
447 * <li><code>0 < p ≤ 100</code> (otherwise an
448 * <code>MathIllegalArgumentException</code> is thrown)</li>
449 * <li>at least one value must be stored (returns <code>Double.NaN
450 * </code> otherwise)</li>
451 * </ul>
452 *
453 * @param p the requested percentile (scaled from 0 - 100)
454 * @return An estimate for the pth percentile of the stored data
455 * @throws MathIllegalStateException if percentile implementation has been
456 * overridden and the supplied implementation does not support setQuantile
457 * @throws MathIllegalArgumentException if p is not a valid quantile
458 */
459 public double getPercentile(double p) throws MathIllegalStateException, MathIllegalArgumentException {
460 if (percentileImpl instanceof Percentile) {
461 ((Percentile) percentileImpl).setQuantile(p);
462 } else {
463 try {
464 percentileImpl.getClass().getMethod(SET_QUANTILE_METHOD_NAME,
465 new Class[] {Double.TYPE}).invoke(percentileImpl,
466 new Object[] {Double.valueOf(p)});
467 } catch (NoSuchMethodException e1) { // Setter guard should prevent
468 throw new MathIllegalStateException(
469 LocalizedFormats.PERCENTILE_IMPLEMENTATION_UNSUPPORTED_METHOD,
470 percentileImpl.getClass().getName(), SET_QUANTILE_METHOD_NAME);
471 } catch (IllegalAccessException e2) {
472 throw new MathIllegalStateException(
473 LocalizedFormats.PERCENTILE_IMPLEMENTATION_CANNOT_ACCESS_METHOD,
474 SET_QUANTILE_METHOD_NAME, percentileImpl.getClass().getName());
475 } catch (InvocationTargetException e3) {
476 throw new IllegalStateException(e3.getCause());
477 }
478 }
479 return apply(percentileImpl);
480 }
481
482 /**
483 * Generates a text report displaying univariate statistics from values
484 * that have been added. Each statistic is displayed on a separate
485 * line.
486 *
487 * @return String with line feeds displaying statistics
488 */
489 @Override
490 public String toString() {
491 StringBuilder outBuffer = new StringBuilder();
492 String endl = "\n";
493 outBuffer.append("DescriptiveStatistics:").append(endl);
494 outBuffer.append("n: ").append(getN()).append(endl);
495 outBuffer.append("min: ").append(getMin()).append(endl);
496 outBuffer.append("max: ").append(getMax()).append(endl);
497 outBuffer.append("mean: ").append(getMean()).append(endl);
498 outBuffer.append("std dev: ").append(getStandardDeviation())
499 .append(endl);
500 try {
501 // No catch for MIAE because actual parameter is valid below
502 outBuffer.append("median: ").append(getPercentile(50)).append(endl);
503 } catch (MathIllegalStateException ex) {
504 outBuffer.append("median: unavailable").append(endl);
505 }
506 outBuffer.append("skewness: ").append(getSkewness()).append(endl);
507 outBuffer.append("kurtosis: ").append(getKurtosis()).append(endl);
508 return outBuffer.toString();
509 }
510
511 /**
512 * Apply the given statistic to the data associated with this set of statistics.
513 * @param stat the statistic to apply
514 * @return the computed value of the statistic.
515 */
516 public double apply(UnivariateStatistic stat) {
517 // No try-catch or advertised exception here because arguments are guaranteed valid
518 return eDA.compute(stat);
519 }
520
521 // Implementation getters and setter
522
523 /**
524 * Returns the currently configured mean implementation.
525 *
526 * @return the UnivariateStatistic implementing the mean
527 * @since 1.2
528 */
529 public synchronized UnivariateStatistic getMeanImpl() {
530 return meanImpl;
531 }
532
533 /**
534 * <p>Sets the implementation for the mean.</p>
535 *
536 * @param meanImpl the UnivariateStatistic instance to use
537 * for computing the mean
538 * @since 1.2
539 */
540 public synchronized void setMeanImpl(UnivariateStatistic meanImpl) {
541 this.meanImpl = meanImpl;
542 }
543
544 /**
545 * Returns the currently configured geometric mean implementation.
546 *
547 * @return the UnivariateStatistic implementing the geometric mean
548 * @since 1.2
549 */
550 public synchronized UnivariateStatistic getGeometricMeanImpl() {
551 return geometricMeanImpl;
552 }
553
554 /**
555 * Sets the implementation for the geometric mean.
556 *
557 * @param geometricMeanImpl the UnivariateStatistic instance to use
558 * for computing the geometric mean
559 * @since 1.2
560 */
561 public synchronized void setGeometricMeanImpl(
562 UnivariateStatistic geometricMeanImpl) {
563 this.geometricMeanImpl = geometricMeanImpl;
564 }
565
566 /**
567 * Returns the currently configured kurtosis implementation.
568 *
569 * @return the UnivariateStatistic implementing the kurtosis
570 * @since 1.2
571 */
572 public synchronized UnivariateStatistic getKurtosisImpl() {
573 return kurtosisImpl;
574 }
575
576 /**
577 * Sets the implementation for the kurtosis.
578 *
579 * @param kurtosisImpl the UnivariateStatistic instance to use
580 * for computing the kurtosis
581 * @since 1.2
582 */
583 public synchronized void setKurtosisImpl(UnivariateStatistic kurtosisImpl) {
584 this.kurtosisImpl = kurtosisImpl;
585 }
586
587 /**
588 * Returns the currently configured maximum implementation.
589 *
590 * @return the UnivariateStatistic implementing the maximum
591 * @since 1.2
592 */
593 public synchronized UnivariateStatistic getMaxImpl() {
594 return maxImpl;
595 }
596
597 /**
598 * Sets the implementation for the maximum.
599 *
600 * @param maxImpl the UnivariateStatistic instance to use
601 * for computing the maximum
602 * @since 1.2
603 */
604 public synchronized void setMaxImpl(UnivariateStatistic maxImpl) {
605 this.maxImpl = maxImpl;
606 }
607
608 /**
609 * Returns the currently configured minimum implementation.
610 *
611 * @return the UnivariateStatistic implementing the minimum
612 * @since 1.2
613 */
614 public synchronized UnivariateStatistic getMinImpl() {
615 return minImpl;
616 }
617
618 /**
619 * Sets the implementation for the minimum.
620 *
621 * @param minImpl the UnivariateStatistic instance to use
622 * for computing the minimum
623 * @since 1.2
624 */
625 public synchronized void setMinImpl(UnivariateStatistic minImpl) {
626 this.minImpl = minImpl;
627 }
628
629 /**
630 * Returns the currently configured percentile implementation.
631 *
632 * @return the UnivariateStatistic implementing the percentile
633 * @since 1.2
634 */
635 public synchronized UnivariateStatistic getPercentileImpl() {
636 return percentileImpl;
637 }
638
639 /**
640 * Sets the implementation to be used by {@link #getPercentile(double)}.
641 * The supplied <code>UnivariateStatistic</code> must provide a
642 * <code>setQuantile(double)</code> method; otherwise
643 * <code>IllegalArgumentException</code> is thrown.
644 *
645 * @param percentileImpl the percentileImpl to set
646 * @throws MathIllegalArgumentException if the supplied implementation does not
647 * provide a <code>setQuantile</code> method
648 * @since 1.2
649 */
650 public synchronized void setPercentileImpl(UnivariateStatistic percentileImpl)
651 throws MathIllegalArgumentException {
652 try {
653 percentileImpl.getClass().getMethod(SET_QUANTILE_METHOD_NAME,
654 new Class[] {Double.TYPE}).invoke(percentileImpl,
655 new Object[] {Double.valueOf(50.0d)});
656 } catch (NoSuchMethodException e1) {
657 throw new MathIllegalArgumentException(
658 LocalizedFormats.PERCENTILE_IMPLEMENTATION_UNSUPPORTED_METHOD,
659 percentileImpl.getClass().getName(), SET_QUANTILE_METHOD_NAME);
660 } catch (IllegalAccessException e2) {
661 throw new MathIllegalArgumentException(
662 LocalizedFormats.PERCENTILE_IMPLEMENTATION_CANNOT_ACCESS_METHOD,
663 SET_QUANTILE_METHOD_NAME, percentileImpl.getClass().getName());
664 } catch (InvocationTargetException e3) {
665 throw new IllegalArgumentException(e3.getCause());
666 }
667 this.percentileImpl = percentileImpl;
668 }
669
670 /**
671 * Returns the currently configured skewness implementation.
672 *
673 * @return the UnivariateStatistic implementing the skewness
674 * @since 1.2
675 */
676 public synchronized UnivariateStatistic getSkewnessImpl() {
677 return skewnessImpl;
678 }
679
680 /**
681 * Sets the implementation for the skewness.
682 *
683 * @param skewnessImpl the UnivariateStatistic instance to use
684 * for computing the skewness
685 * @since 1.2
686 */
687 public synchronized void setSkewnessImpl(
688 UnivariateStatistic skewnessImpl) {
689 this.skewnessImpl = skewnessImpl;
690 }
691
692 /**
693 * Returns the currently configured variance implementation.
694 *
695 * @return the UnivariateStatistic implementing the variance
696 * @since 1.2
697 */
698 public synchronized UnivariateStatistic getVarianceImpl() {
699 return varianceImpl;
700 }
701
702 /**
703 * Sets the implementation for the variance.
704 *
705 * @param varianceImpl the UnivariateStatistic instance to use
706 * for computing the variance
707 * @since 1.2
708 */
709 public synchronized void setVarianceImpl(
710 UnivariateStatistic varianceImpl) {
711 this.varianceImpl = varianceImpl;
712 }
713
714 /**
715 * Returns the currently configured sum of squares implementation.
716 *
717 * @return the UnivariateStatistic implementing the sum of squares
718 * @since 1.2
719 */
720 public synchronized UnivariateStatistic getSumsqImpl() {
721 return sumsqImpl;
722 }
723
724 /**
725 * Sets the implementation for the sum of squares.
726 *
727 * @param sumsqImpl the UnivariateStatistic instance to use
728 * for computing the sum of squares
729 * @since 1.2
730 */
731 public synchronized void setSumsqImpl(UnivariateStatistic sumsqImpl) {
732 this.sumsqImpl = sumsqImpl;
733 }
734
735 /**
736 * Returns the currently configured sum implementation.
737 *
738 * @return the UnivariateStatistic implementing the sum
739 * @since 1.2
740 */
741 public synchronized UnivariateStatistic getSumImpl() {
742 return sumImpl;
743 }
744
745 /**
746 * Sets the implementation for the sum.
747 *
748 * @param sumImpl the UnivariateStatistic instance to use
749 * for computing the sum
750 * @since 1.2
751 */
752 public synchronized void setSumImpl(UnivariateStatistic sumImpl) {
753 this.sumImpl = sumImpl;
754 }
755
756 /**
757 * Returns a copy of this DescriptiveStatistics instance with the same internal state.
758 *
759 * @return a copy of this
760 */
761 public DescriptiveStatistics copy() {
762 DescriptiveStatistics result = new DescriptiveStatistics();
763 // No try-catch or advertised exception because parms are guaranteed valid
764 copy(this, result);
765 return result;
766 }
767
768 /**
769 * Copies source to dest.
770 * <p>Neither source nor dest can be null.</p>
771 *
772 * @param source DescriptiveStatistics to copy
773 * @param dest DescriptiveStatistics to copy to
774 * @throws NullArgumentException if either source or dest is null
775 */
776 public static void copy(DescriptiveStatistics source, DescriptiveStatistics dest)
777 throws NullArgumentException {
778 NullArgumentException.check(source);
779 NullArgumentException.check(dest);
780 // Copy data and window size
781 dest.eDA = source.eDA.copy();
782 dest.windowSize = source.windowSize;
783
784 // Copy implementations
785 dest.maxImpl = source.maxImpl.copy();
786 dest.meanImpl = source.meanImpl.copy();
787 dest.minImpl = source.minImpl.copy();
788 dest.sumImpl = source.sumImpl.copy();
789 dest.varianceImpl = source.varianceImpl.copy();
790 dest.sumsqImpl = source.sumsqImpl.copy();
791 dest.geometricMeanImpl = source.geometricMeanImpl.copy();
792 dest.kurtosisImpl = source.kurtosisImpl;
793 dest.skewnessImpl = source.skewnessImpl;
794 dest.percentileImpl = source.percentileImpl;
795 }
796 }