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 org.apache.commons.math4.legacy.exception.MathIllegalStateException;
20 import org.apache.commons.math4.legacy.exception.NullArgumentException;
21 import org.apache.commons.math4.legacy.exception.util.LocalizedFormats;
22 import org.apache.commons.math4.legacy.stat.descriptive.moment.GeometricMean;
23 import org.apache.commons.math4.legacy.stat.descriptive.moment.Mean;
24 import org.apache.commons.math4.legacy.stat.descriptive.moment.SecondMoment;
25 import org.apache.commons.math4.legacy.stat.descriptive.moment.Variance;
26 import org.apache.commons.math4.legacy.stat.descriptive.rank.Max;
27 import org.apache.commons.math4.legacy.stat.descriptive.rank.Min;
28 import org.apache.commons.math4.legacy.stat.descriptive.summary.Sum;
29 import org.apache.commons.math4.legacy.stat.descriptive.summary.SumOfLogs;
30 import org.apache.commons.math4.legacy.stat.descriptive.summary.SumOfSquares;
31 import org.apache.commons.math4.core.jdkmath.JdkMath;
32 import org.apache.commons.numbers.core.Precision;
33
34 /**
35 * <p>
36 * Computes summary statistics for a stream of data values added using the
37 * {@link #addValue(double) addValue} method. The data values are not stored in
38 * memory, so this class can be used to compute statistics for very large data
39 * streams.
40 * </p>
41 * <p>
42 * The {@link StorelessUnivariateStatistic} instances used to maintain summary
43 * state and compute statistics are configurable via setters. For example, the
44 * default implementation for the variance can be overridden by calling
45 * {@link #setVarianceImpl(StorelessUnivariateStatistic)}. Actual parameters to
46 * these methods must implement the {@link StorelessUnivariateStatistic}
47 * interface and configuration must be completed before <code>addValue</code>
48 * is called. No configuration is necessary to use the default, commons-math
49 * provided implementations.
50 * </p>
51 * <p>
52 * Note: This class is not thread-safe. Use
53 * {@link SynchronizedSummaryStatistics} if concurrent access from multiple
54 * threads is required.
55 * </p>
56 */
57 public class SummaryStatistics implements StatisticalSummary {
58 /** count of values that have been added. */
59 private long n;
60
61 /** SecondMoment is used to compute the mean and variance. */
62 private SecondMoment secondMoment = new SecondMoment();
63
64 /** sum of values that have been added. */
65 private Sum sum = new Sum();
66
67 /** sum of the square of each value that has been added. */
68 private SumOfSquares sumsq = new SumOfSquares();
69
70 /** min of values that have been added. */
71 private Min min = new Min();
72
73 /** max of values that have been added. */
74 private Max max = new Max();
75
76 /** sumLog of values that have been added. */
77 private SumOfLogs sumLog = new SumOfLogs();
78
79 /** geoMean of values that have been added. */
80 private GeometricMean geoMean = new GeometricMean(sumLog);
81
82 /** mean of values that have been added. */
83 private Mean mean = new Mean(secondMoment);
84
85 /** variance of values that have been added. */
86 private Variance variance = new Variance(secondMoment);
87
88 /** Sum statistic implementation - can be reset by setter. */
89 private StorelessUnivariateStatistic sumImpl = sum;
90
91 /** Sum of squares statistic implementation - can be reset by setter. */
92 private StorelessUnivariateStatistic sumsqImpl = sumsq;
93
94 /** Minimum statistic implementation - can be reset by setter. */
95 private StorelessUnivariateStatistic minImpl = min;
96
97 /** Maximum statistic implementation - can be reset by setter. */
98 private StorelessUnivariateStatistic maxImpl = max;
99
100 /** Sum of log statistic implementation - can be reset by setter. */
101 private StorelessUnivariateStatistic sumLogImpl = sumLog;
102
103 /** Geometric mean statistic implementation - can be reset by setter. */
104 private StorelessUnivariateStatistic geoMeanImpl = geoMean;
105
106 /** Mean statistic implementation - can be reset by setter. */
107 private StorelessUnivariateStatistic meanImpl = mean;
108
109 /** Variance statistic implementation - can be reset by setter. */
110 private StorelessUnivariateStatistic varianceImpl = variance;
111
112 /**
113 * Construct a SummaryStatistics instance.
114 */
115 public SummaryStatistics() {
116 }
117
118 /**
119 * A copy constructor. Creates a deep-copy of the {@code original}.
120 *
121 * @param original the {@code SummaryStatistics} instance to copy
122 * @throws NullArgumentException if original is null
123 */
124 public SummaryStatistics(SummaryStatistics original) throws NullArgumentException {
125 copy(original, this);
126 }
127
128 /**
129 * Return a {@link StatisticalSummaryValues} instance reporting current
130 * statistics.
131 * @return Current values of statistics
132 */
133 public StatisticalSummary getSummary() {
134 return new StatisticalSummaryValues(getMean(), getVariance(), getN(),
135 getMax(), getMin(), getSum());
136 }
137
138 /**
139 * Add a value to the data.
140 * @param value the value to add
141 */
142 public void addValue(double value) {
143 sumImpl.increment(value);
144 sumsqImpl.increment(value);
145 minImpl.increment(value);
146 maxImpl.increment(value);
147 sumLogImpl.increment(value);
148 secondMoment.increment(value);
149 // If mean, variance or geomean have been overridden,
150 // need to increment these
151 if (meanImpl != mean) {
152 meanImpl.increment(value);
153 }
154 if (varianceImpl != variance) {
155 varianceImpl.increment(value);
156 }
157 if (geoMeanImpl != geoMean) {
158 geoMeanImpl.increment(value);
159 }
160 n++;
161 }
162
163 /**
164 * Returns the number of available values.
165 * @return The number of available values
166 */
167 @Override
168 public long getN() {
169 return n;
170 }
171
172 /**
173 * Returns the sum of the values that have been added.
174 * @return The sum or <code>Double.NaN</code> if no values have been added
175 */
176 @Override
177 public double getSum() {
178 return sumImpl.getResult();
179 }
180
181 /**
182 * Returns the sum of the squares of the values that have been added.
183 * <p>
184 * Double.NaN is returned if no values have been added.
185 * </p>
186 * @return The sum of squares
187 */
188 public double getSumsq() {
189 return sumsqImpl.getResult();
190 }
191
192 /**
193 * Returns the mean of the values that have been added.
194 * <p>
195 * Double.NaN is returned if no values have been added.
196 * </p>
197 * @return the mean
198 */
199 @Override
200 public double getMean() {
201 return meanImpl.getResult();
202 }
203
204 /**
205 * Returns the standard deviation of the values that have been added.
206 * <p>
207 * Double.NaN is returned if no values have been added.
208 * </p>
209 * @return the standard deviation
210 */
211 @Override
212 public double getStandardDeviation() {
213 double stdDev = Double.NaN;
214 if (getN() > 0) {
215 if (getN() > 1) {
216 stdDev = JdkMath.sqrt(getVariance());
217 } else {
218 stdDev = 0.0;
219 }
220 }
221 return stdDev;
222 }
223
224 /**
225 * Returns the quadratic mean, a.k.a.
226 * <a href="http://mathworld.wolfram.com/Root-Mean-Square.html">
227 * root-mean-square</a> of the available values
228 * @return The quadratic mean or {@code Double.NaN} if no values
229 * have been added.
230 */
231 public double getQuadraticMean() {
232 final long size = getN();
233 return size > 0 ? JdkMath.sqrt(getSumsq() / size) : Double.NaN;
234 }
235
236 /**
237 * Returns the (sample) variance of the available values.
238 *
239 * <p>This method returns the bias-corrected sample variance (using {@code n - 1} in
240 * the denominator). Use {@link #getPopulationVariance()} for the non-bias-corrected
241 * population variance.</p>
242 *
243 * <p>Double.NaN is returned if no values have been added.</p>
244 *
245 * @return the variance
246 */
247 @Override
248 public double getVariance() {
249 return varianceImpl.getResult();
250 }
251
252 /**
253 * Returns the <a href="http://en.wikibooks.org/wiki/Statistics/Summary/Variance">
254 * population variance</a> of the values that have been added.
255 *
256 * <p>Double.NaN is returned if no values have been added.</p>
257 *
258 * @return the population variance
259 */
260 public double getPopulationVariance() {
261 Variance populationVariance = new Variance(secondMoment);
262 populationVariance.setBiasCorrected(false);
263 return populationVariance.getResult();
264 }
265
266 /**
267 * Returns the maximum of the values that have been added.
268 * <p>
269 * Double.NaN is returned if no values have been added.
270 * </p>
271 * @return the maximum
272 */
273 @Override
274 public double getMax() {
275 return maxImpl.getResult();
276 }
277
278 /**
279 * Returns the minimum of the values that have been added.
280 * <p>
281 * Double.NaN is returned if no values have been added.
282 * </p>
283 * @return the minimum
284 */
285 @Override
286 public double getMin() {
287 return minImpl.getResult();
288 }
289
290 /**
291 * Returns the geometric mean of the values that have been added.
292 * <p>
293 * Double.NaN is returned if no values have been added.
294 * </p>
295 * @return the geometric mean
296 */
297 public double getGeometricMean() {
298 return geoMeanImpl.getResult();
299 }
300
301 /**
302 * Returns the sum of the logs of the values that have been added.
303 * <p>
304 * Double.NaN is returned if no values have been added.
305 * </p>
306 * @return the sum of logs
307 * @since 1.2
308 */
309 public double getSumOfLogs() {
310 return sumLogImpl.getResult();
311 }
312
313 /**
314 * Returns a statistic related to the Second Central Moment. Specifically,
315 * what is returned is the sum of squared deviations from the sample mean
316 * among the values that have been added.
317 * <p>
318 * Returns <code>Double.NaN</code> if no data values have been added and
319 * returns <code>0</code> if there is just one value in the data set.
320 * </p>
321 * @return second central moment statistic
322 * @since 2.0
323 */
324 public double getSecondMoment() {
325 return secondMoment.getResult();
326 }
327
328 /**
329 * Generates a text report displaying summary statistics from values that
330 * have been added.
331 * @return String with line feeds displaying statistics
332 * @since 1.2
333 */
334 @Override
335 public String toString() {
336 StringBuilder outBuffer = new StringBuilder();
337 String endl = "\n";
338 outBuffer.append("SummaryStatistics:").append(endl);
339 outBuffer.append("n: ").append(getN()).append(endl);
340 outBuffer.append("min: ").append(getMin()).append(endl);
341 outBuffer.append("max: ").append(getMax()).append(endl);
342 outBuffer.append("sum: ").append(getSum()).append(endl);
343 outBuffer.append("mean: ").append(getMean()).append(endl);
344 outBuffer.append("geometric mean: ").append(getGeometricMean())
345 .append(endl);
346 outBuffer.append("variance: ").append(getVariance()).append(endl);
347 outBuffer.append("population variance: ").append(getPopulationVariance()).append(endl);
348 outBuffer.append("second moment: ").append(getSecondMoment()).append(endl);
349 outBuffer.append("sum of squares: ").append(getSumsq()).append(endl);
350 outBuffer.append("standard deviation: ").append(getStandardDeviation())
351 .append(endl);
352 outBuffer.append("sum of logs: ").append(getSumOfLogs()).append(endl);
353 return outBuffer.toString();
354 }
355
356 /**
357 * Resets all statistics and storage.
358 */
359 public void clear() {
360 this.n = 0;
361 minImpl.clear();
362 maxImpl.clear();
363 sumImpl.clear();
364 sumLogImpl.clear();
365 sumsqImpl.clear();
366 geoMeanImpl.clear();
367 secondMoment.clear();
368 if (meanImpl != mean) {
369 meanImpl.clear();
370 }
371 if (varianceImpl != variance) {
372 varianceImpl.clear();
373 }
374 }
375
376 /**
377 * Returns true iff <code>object</code> is a
378 * <code>SummaryStatistics</code> instance and all statistics have the
379 * same values as this.
380 * @param object the object to test equality against.
381 * @return true if object equals this
382 */
383 @Override
384 public boolean equals(Object object) {
385 if (object == this) {
386 return true;
387 }
388 if (!(object instanceof SummaryStatistics)) {
389 return false;
390 }
391 SummaryStatistics stat = (SummaryStatistics)object;
392 return Precision.equalsIncludingNaN(stat.getGeometricMean(), getGeometricMean()) &&
393 Precision.equalsIncludingNaN(stat.getMax(), getMax()) &&
394 Precision.equalsIncludingNaN(stat.getMean(), getMean()) &&
395 Precision.equalsIncludingNaN(stat.getMin(), getMin()) &&
396 Precision.equalsIncludingNaN(stat.getN(), getN()) &&
397 Precision.equalsIncludingNaN(stat.getSum(), getSum()) &&
398 Precision.equalsIncludingNaN(stat.getSumsq(), getSumsq()) &&
399 Precision.equalsIncludingNaN(stat.getVariance(), getVariance());
400 }
401
402 /**
403 * Returns hash code based on values of statistics.
404 * @return hash code
405 */
406 @Override
407 public int hashCode() {
408 int result = 31 + Double.hashCode(getGeometricMean());
409 result = result * 31 + Double.hashCode(getGeometricMean());
410 result = result * 31 + Double.hashCode(getMax());
411 result = result * 31 + Double.hashCode(getMean());
412 result = result * 31 + Double.hashCode(getMin());
413 result = result * 31 + Double.hashCode(getN());
414 result = result * 31 + Double.hashCode(getSum());
415 result = result * 31 + Double.hashCode(getSumsq());
416 result = result * 31 + Double.hashCode(getVariance());
417 return result;
418 }
419
420 // Getters and setters for statistics implementations
421 /**
422 * Returns the currently configured Sum implementation.
423 * @return the StorelessUnivariateStatistic implementing the sum
424 * @since 1.2
425 */
426 public StorelessUnivariateStatistic getSumImpl() {
427 return sumImpl;
428 }
429
430 /**
431 * <p>
432 * Sets the implementation for the Sum.
433 * </p>
434 * <p>
435 * This method cannot be activated after data has been added - i.e.,
436 * after {@link #addValue(double) addValue} has been used to add data.
437 * If it is activated after data has been added, an IllegalStateException
438 * will be thrown.
439 * </p>
440 * @param sumImpl the StorelessUnivariateStatistic instance to use for
441 * computing the Sum
442 * @throws MathIllegalStateException if data has already been added (i.e if n >0)
443 * @since 1.2
444 */
445 public void setSumImpl(StorelessUnivariateStatistic sumImpl)
446 throws MathIllegalStateException {
447 checkEmpty();
448 this.sumImpl = sumImpl;
449 }
450
451 /**
452 * Returns the currently configured sum of squares implementation.
453 * @return the StorelessUnivariateStatistic implementing the sum of squares
454 * @since 1.2
455 */
456 public StorelessUnivariateStatistic getSumsqImpl() {
457 return sumsqImpl;
458 }
459
460 /**
461 * <p>
462 * Sets the implementation for the sum of squares.
463 * </p>
464 * <p>
465 * This method cannot be activated after data has been added - i.e.,
466 * after {@link #addValue(double) addValue} has been used to add data.
467 * If it is activated after data has been added, an IllegalStateException
468 * will be thrown.
469 * </p>
470 * @param sumsqImpl the StorelessUnivariateStatistic instance to use for
471 * computing the sum of squares
472 * @throws MathIllegalStateException if data has already been added (i.e if n > 0)
473 * @since 1.2
474 */
475 public void setSumsqImpl(StorelessUnivariateStatistic sumsqImpl)
476 throws MathIllegalStateException {
477 checkEmpty();
478 this.sumsqImpl = sumsqImpl;
479 }
480
481 /**
482 * Returns the currently configured minimum implementation.
483 * @return the StorelessUnivariateStatistic implementing the minimum
484 * @since 1.2
485 */
486 public StorelessUnivariateStatistic getMinImpl() {
487 return minImpl;
488 }
489
490 /**
491 * <p>
492 * Sets the implementation for the minimum.
493 * </p>
494 * <p>
495 * This method cannot be activated after data has been added - i.e.,
496 * after {@link #addValue(double) addValue} has been used to add data.
497 * If it is activated after data has been added, an IllegalStateException
498 * will be thrown.
499 * </p>
500 * @param minImpl the StorelessUnivariateStatistic instance to use for
501 * computing the minimum
502 * @throws MathIllegalStateException if data has already been added (i.e if n > 0)
503 * @since 1.2
504 */
505 public void setMinImpl(StorelessUnivariateStatistic minImpl)
506 throws MathIllegalStateException {
507 checkEmpty();
508 this.minImpl = minImpl;
509 }
510
511 /**
512 * Returns the currently configured maximum implementation.
513 * @return the StorelessUnivariateStatistic implementing the maximum
514 * @since 1.2
515 */
516 public StorelessUnivariateStatistic getMaxImpl() {
517 return maxImpl;
518 }
519
520 /**
521 * <p>
522 * Sets the implementation for the maximum.
523 * </p>
524 * <p>
525 * This method cannot be activated after data has been added - i.e.,
526 * after {@link #addValue(double) addValue} has been used to add data.
527 * If it is activated after data has been added, an IllegalStateException
528 * will be thrown.
529 * </p>
530 * @param maxImpl the StorelessUnivariateStatistic instance to use for
531 * computing the maximum
532 * @throws MathIllegalStateException if data has already been added (i.e if n > 0)
533 * @since 1.2
534 */
535 public void setMaxImpl(StorelessUnivariateStatistic maxImpl)
536 throws MathIllegalStateException {
537 checkEmpty();
538 this.maxImpl = maxImpl;
539 }
540
541 /**
542 * Returns the currently configured sum of logs implementation.
543 * @return the StorelessUnivariateStatistic implementing the log sum
544 * @since 1.2
545 */
546 public StorelessUnivariateStatistic getSumLogImpl() {
547 return sumLogImpl;
548 }
549
550 /**
551 * <p>
552 * Sets the implementation for the sum of logs.
553 * </p>
554 * <p>
555 * This method cannot be activated after data has been added - i.e.,
556 * after {@link #addValue(double) addValue} has been used to add data.
557 * If it is activated after data has been added, an IllegalStateException
558 * will be thrown.
559 * </p>
560 * @param sumLogImpl the StorelessUnivariateStatistic instance to use for
561 * computing the log sum
562 * @throws MathIllegalStateException if data has already been added (i.e if n > 0)
563 * @since 1.2
564 */
565 public void setSumLogImpl(StorelessUnivariateStatistic sumLogImpl)
566 throws MathIllegalStateException {
567 checkEmpty();
568 this.sumLogImpl = sumLogImpl;
569 geoMean.setSumLogImpl(sumLogImpl);
570 }
571
572 /**
573 * Returns the currently configured geometric mean implementation.
574 * @return the StorelessUnivariateStatistic implementing the geometric mean
575 * @since 1.2
576 */
577 public StorelessUnivariateStatistic getGeoMeanImpl() {
578 return geoMeanImpl;
579 }
580
581 /**
582 * <p>
583 * Sets the implementation for the geometric mean.
584 * </p>
585 * <p>
586 * This method cannot be activated after data has been added - i.e.,
587 * after {@link #addValue(double) addValue} has been used to add data.
588 * If it is activated after data has been added, an IllegalStateException
589 * will be thrown.
590 * </p>
591 * @param geoMeanImpl the StorelessUnivariateStatistic instance to use for
592 * computing the geometric mean
593 * @throws MathIllegalStateException if data has already been added (i.e if n > 0)
594 * @since 1.2
595 */
596 public void setGeoMeanImpl(StorelessUnivariateStatistic geoMeanImpl)
597 throws MathIllegalStateException {
598 checkEmpty();
599 this.geoMeanImpl = geoMeanImpl;
600 }
601
602 /**
603 * Returns the currently configured mean implementation.
604 * @return the StorelessUnivariateStatistic implementing the mean
605 * @since 1.2
606 */
607 public StorelessUnivariateStatistic getMeanImpl() {
608 return meanImpl;
609 }
610
611 /**
612 * <p>
613 * Sets the implementation for the mean.
614 * </p>
615 * <p>
616 * This method cannot be activated after data has been added - i.e.,
617 * after {@link #addValue(double) addValue} has been used to add data.
618 * If it is activated after data has been added, an IllegalStateException
619 * will be thrown.
620 * </p>
621 * @param meanImpl the StorelessUnivariateStatistic instance to use for
622 * computing the mean
623 * @throws MathIllegalStateException if data has already been added (i.e if n > 0)
624 * @since 1.2
625 */
626 public void setMeanImpl(StorelessUnivariateStatistic meanImpl)
627 throws MathIllegalStateException {
628 checkEmpty();
629 this.meanImpl = meanImpl;
630 }
631
632 /**
633 * Returns the currently configured variance implementation.
634 * @return the StorelessUnivariateStatistic implementing the variance
635 * @since 1.2
636 */
637 public StorelessUnivariateStatistic getVarianceImpl() {
638 return varianceImpl;
639 }
640
641 /**
642 * <p>
643 * Sets the implementation for the variance.
644 * </p>
645 * <p>
646 * This method cannot be activated after data has been added - i.e.,
647 * after {@link #addValue(double) addValue} has been used to add data.
648 * If it is activated after data has been added, an IllegalStateException
649 * will be thrown.
650 * </p>
651 * @param varianceImpl the StorelessUnivariateStatistic instance to use for
652 * computing the variance
653 * @throws MathIllegalStateException if data has already been added (i.e if n > 0)
654 * @since 1.2
655 */
656 public void setVarianceImpl(StorelessUnivariateStatistic varianceImpl)
657 throws MathIllegalStateException {
658 checkEmpty();
659 this.varianceImpl = varianceImpl;
660 }
661
662 /**
663 * Throws IllegalStateException if n > 0.
664 * @throws MathIllegalStateException if data has been added
665 */
666 private void checkEmpty() throws MathIllegalStateException {
667 if (n > 0) {
668 throw new MathIllegalStateException(
669 LocalizedFormats.VALUES_ADDED_BEFORE_CONFIGURING_STATISTIC, n);
670 }
671 }
672
673 /**
674 * Returns a copy of this SummaryStatistics instance with the same internal state.
675 *
676 * @return a copy of this
677 */
678 public SummaryStatistics copy() {
679 SummaryStatistics result = new SummaryStatistics();
680 // No try-catch or advertised exception because arguments are guaranteed non-null
681 copy(this, result);
682 return result;
683 }
684
685 /**
686 * Copies source to dest.
687 * <p>Neither source nor dest can be null.</p>
688 *
689 * @param source SummaryStatistics to copy
690 * @param dest SummaryStatistics to copy to
691 * @throws NullArgumentException if either source or dest is null
692 */
693 public static void copy(SummaryStatistics source, SummaryStatistics dest)
694 throws NullArgumentException {
695 NullArgumentException.check(source);
696 NullArgumentException.check(dest);
697 dest.maxImpl = source.maxImpl.copy();
698 dest.minImpl = source.minImpl.copy();
699 dest.sumImpl = source.sumImpl.copy();
700 dest.sumLogImpl = source.sumLogImpl.copy();
701 dest.sumsqImpl = source.sumsqImpl.copy();
702 dest.secondMoment = source.secondMoment.copy();
703 dest.n = source.n;
704
705 // Keep commons-math supplied statistics with embedded moments in synch
706 if (source.getVarianceImpl() instanceof Variance) {
707 dest.varianceImpl = new Variance(dest.secondMoment);
708 } else {
709 dest.varianceImpl = source.varianceImpl.copy();
710 }
711 if (source.meanImpl instanceof Mean) {
712 dest.meanImpl = new Mean(dest.secondMoment);
713 } else {
714 dest.meanImpl = source.meanImpl.copy();
715 }
716 if (source.getGeoMeanImpl() instanceof GeometricMean) {
717 dest.geoMeanImpl = new GeometricMean((SumOfLogs) dest.sumLogImpl);
718 } else {
719 dest.geoMeanImpl = source.geoMeanImpl.copy();
720 }
721
722 // Make sure that if stat == statImpl in source, same
723 // holds in dest; otherwise copy stat
724 if (source.geoMean == source.geoMeanImpl) {
725 dest.geoMean = (GeometricMean) dest.geoMeanImpl;
726 } else {
727 GeometricMean.copy(source.geoMean, dest.geoMean);
728 }
729 if (source.max == source.maxImpl) {
730 dest.max = (Max) dest.maxImpl;
731 } else {
732 Max.copy(source.max, dest.max);
733 }
734 if (source.mean == source.meanImpl) {
735 dest.mean = (Mean) dest.meanImpl;
736 } else {
737 Mean.copy(source.mean, dest.mean);
738 }
739 if (source.min == source.minImpl) {
740 dest.min = (Min) dest.minImpl;
741 } else {
742 Min.copy(source.min, dest.min);
743 }
744 if (source.sum == source.sumImpl) {
745 dest.sum = (Sum) dest.sumImpl;
746 } else {
747 Sum.copy(source.sum, dest.sum);
748 }
749 if (source.variance == source.varianceImpl) {
750 dest.variance = (Variance) dest.varianceImpl;
751 } else {
752 Variance.copy(source.variance, dest.variance);
753 }
754 if (source.sumLog == source.sumLogImpl) {
755 dest.sumLog = (SumOfLogs) dest.sumLogImpl;
756 } else {
757 SumOfLogs.copy(source.sumLog, dest.sumLog);
758 }
759 if (source.sumsq == source.sumsqImpl) {
760 dest.sumsq = (SumOfSquares) dest.sumsqImpl;
761 } else {
762 SumOfSquares.copy(source.sumsq, dest.sumsq);
763 }
764 }
765 }