IntStatistics.java

  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.statistics.descriptive;

  18. import java.math.BigInteger;
  19. import java.util.Objects;
  20. import java.util.Set;
  21. import java.util.function.DoubleConsumer;
  22. import java.util.function.Function;
  23. import java.util.function.IntConsumer;

  24. /**
  25.  * Statistics for {@code int} values.
  26.  *
  27.  * <p>This class provides combinations of individual statistic implementations in the
  28.  * {@code org.apache.commons.statistics.descriptive} package.
  29.  *
  30.  * <p>Supports up to 2<sup>63</sup> (exclusive) observations.
  31.  * This implementation does not check for overflow of the count.
  32.  *
  33.  * @since 1.1
  34.  */
  35. public final class IntStatistics implements IntConsumer {
  36.     /** Error message for non configured statistics. */
  37.     private static final String NO_CONFIGURED_STATISTICS = "No configured statistics";
  38.     /** Error message for an unsupported statistic. */
  39.     private static final String UNSUPPORTED_STATISTIC = "Unsupported statistic: ";

  40.     /** Count of values recorded. */
  41.     private long count;
  42.     /** The consumer of values. */
  43.     private final IntConsumer consumer;
  44.     /** The {@link IntMin} implementation. */
  45.     private final IntMin min;
  46.     /** The {@link IntMax} implementation. */
  47.     private final IntMax max;
  48.     /** The moment implementation. May be any instance of {@link FirstMoment}.
  49.      * This implementation uses only the third and fourth moments. */
  50.     private final FirstMoment moment;
  51.     /** The {@link IntSum} implementation. */
  52.     private final IntSum sum;
  53.     /** The {@link Product} implementation. */
  54.     private final Product product;
  55.     /** The {@link IntSumOfSquares} implementation. */
  56.     private final IntSumOfSquares sumOfSquares;
  57.     /** The {@link SumOfLogs} implementation. */
  58.     private final SumOfLogs sumOfLogs;
  59.     /** Configuration options for computation of statistics. */
  60.     private StatisticsConfiguration config;

  61.     /**
  62.      * A builder for {@link IntStatistics}.
  63.      */
  64.     public static final class Builder {
  65.         /** An empty double array. */
  66.         private static final int[] NO_VALUES = {};

  67.         /** The {@link IntMin} constructor. */
  68.         private Function<int[], IntMin> min;
  69.         /** The {@link IntMax} constructor. */
  70.         private Function<int[], IntMax> max;
  71.         /** The moment constructor. May return any instance of {@link FirstMoment}. */
  72.         private Function<int[], FirstMoment> moment;
  73.         /** The {@link IntSum} constructor. */
  74.         private Function<int[], IntSum> sum;
  75.         /** The {@link Product} constructor. */
  76.         private Function<int[], Product> product;
  77.         /** The {@link IntSumOfSquares} constructor. */
  78.         private Function<int[], IntSumOfSquares> sumOfSquares;
  79.         /** The {@link SumOfLogs} constructor. */
  80.         private Function<int[], SumOfLogs> sumOfLogs;
  81.         /** The order of the moment. It corresponds to the power computed by the {@link FirstMoment}
  82.          * instance constructed by {@link #moment}. This should only be increased from the default
  83.          * of zero (corresponding to no moment computation). */
  84.         private int momentOrder;
  85.         /** Configuration options for computation of statistics. */
  86.         private StatisticsConfiguration config = StatisticsConfiguration.withDefaults();

  87.         /**
  88.          * Create an instance.
  89.          */
  90.         Builder() {
  91.             // Do nothing
  92.         }

  93.         /**
  94.          * Add the statistic to the statistics to compute.
  95.          *
  96.          * @param statistic Statistic to compute.
  97.          * @return {@code this} instance
  98.          */
  99.         Builder add(Statistic statistic) {
  100.             switch (statistic) {
  101.             case GEOMETRIC_MEAN:
  102.             case SUM_OF_LOGS:
  103.                 sumOfLogs = SumOfLogs::of;
  104.                 break;
  105.             case KURTOSIS:
  106.                 createMoment(4);
  107.                 break;
  108.             case MAX:
  109.                 max = IntMax::of;
  110.                 break;
  111.             case MIN:
  112.                 min = IntMin::of;
  113.                 break;
  114.             case PRODUCT:
  115.                 product = Product::of;
  116.                 break;
  117.             case SKEWNESS:
  118.                 createMoment(3);
  119.                 break;
  120.             case STANDARD_DEVIATION:
  121.             case VARIANCE:
  122.                 sum = IntSum::of;
  123.                 sumOfSquares = IntSumOfSquares::of;
  124.                 break;
  125.             case MEAN:
  126.             case SUM:
  127.                 sum = IntSum::of;
  128.                 break;
  129.             case SUM_OF_SQUARES:
  130.                 sumOfSquares = IntSumOfSquares::of;
  131.                 break;
  132.             default:
  133.                 throw new IllegalArgumentException(UNSUPPORTED_STATISTIC + statistic);
  134.             }
  135.             return this;
  136.         }

  137.         /**
  138.          * Creates the moment constructor for the specified {@code order},
  139.          * e.g. order=3 is sum of cubed deviations.
  140.          *
  141.          * @param order Order.
  142.          */
  143.         private void createMoment(int order) {
  144.             if (order > momentOrder) {
  145.                 momentOrder = order;
  146.                 if (order == 4) {
  147.                     moment = SumOfFourthDeviations::of;
  148.                 } else {
  149.                     // Assume order == 3
  150.                     moment = SumOfCubedDeviations::of;
  151.                 }
  152.             }
  153.         }

  154.         /**
  155.          * Sets the statistics configuration options for computation of statistics.
  156.          *
  157.          * @param v Value.
  158.          * @return the builder
  159.          * @throws NullPointerException if the value is null
  160.          */
  161.         public Builder setConfiguration(StatisticsConfiguration v) {
  162.             config = Objects.requireNonNull(v);
  163.             return this;
  164.         }

  165.         /**
  166.          * Builds a {@code IntStatistics} instance.
  167.          *
  168.          * @return {@code IntStatistics} instance.
  169.          */
  170.         public IntStatistics build() {
  171.             return build(NO_VALUES);
  172.         }

  173.         /**
  174.          * Builds a {@code IntStatistics} instance using the input {@code values}.
  175.          *
  176.          * <p>Note: {@code IntStatistics} computed using
  177.          * {@link IntStatistics#accept(int) accept} may be
  178.          * different from this instance.
  179.          *
  180.          * @param values Values.
  181.          * @return {@code IntStatistics} instance.
  182.          */
  183.         public IntStatistics build(int... values) {
  184.             Objects.requireNonNull(values, "values");
  185.             return new IntStatistics(
  186.                 values.length,
  187.                 create(min, values),
  188.                 create(max, values),
  189.                 create(moment, values),
  190.                 create(sum, values),
  191.                 create(product, values),
  192.                 create(sumOfSquares, values),
  193.                 create(sumOfLogs, values),
  194.                 config);
  195.         }

  196.         /**
  197.          * Creates the object from the {@code values}.
  198.          *
  199.          * @param <T> object type
  200.          * @param constructor Constructor.
  201.          * @param values Values
  202.          * @return the instance
  203.          */
  204.         private static <T> T create(Function<int[], T> constructor, int[] values) {
  205.             if (constructor != null) {
  206.                 return constructor.apply(values);
  207.             }
  208.             return null;
  209.         }
  210.     }

  211.     /**
  212.      * Create an instance.
  213.      *
  214.      * @param count Count of values.
  215.      * @param min IntMin implementation.
  216.      * @param max IntMax implementation.
  217.      * @param moment Moment implementation.
  218.      * @param sum IntSum implementation.
  219.      * @param product Product implementation.
  220.      * @param sumOfSquares Sum of squares implementation.
  221.      * @param sumOfLogs Sum of logs implementation.
  222.      * @param config Statistics configuration.
  223.      */
  224.     IntStatistics(long count, IntMin min, IntMax max, FirstMoment moment, IntSum sum,
  225.                   Product product, IntSumOfSquares sumOfSquares, SumOfLogs sumOfLogs,
  226.                   StatisticsConfiguration config) {
  227.         this.count = count;
  228.         this.min = min;
  229.         this.max = max;
  230.         this.moment = moment;
  231.         this.sum = sum;
  232.         this.product = product;
  233.         this.sumOfSquares = sumOfSquares;
  234.         this.sumOfLogs = sumOfLogs;
  235.         this.config = config;
  236.         // The final consumer should never be null as the builder is created
  237.         // with at least one statistic.
  238.         consumer = Statistics.compose(min, max, sum, sumOfSquares,
  239.                                       composeAsInt(moment, product, sumOfLogs));
  240.     }

  241.     /**
  242.      * Chain the {@code consumers} into a single composite {@code IntConsumer}.
  243.      * Ignore any {@code null} consumer.
  244.      *
  245.      * @param consumers Consumers.
  246.      * @return a composed consumer (or null)
  247.      */
  248.     private static IntConsumer composeAsInt(DoubleConsumer... consumers) {
  249.         final DoubleConsumer c = Statistics.compose(consumers);
  250.         if (c != null) {
  251.             return c::accept;
  252.         }
  253.         return null;
  254.     }

  255.     /**
  256.      * Returns a new instance configured to compute the specified {@code statistics}.
  257.      *
  258.      * <p>The statistics will be empty and so will return the default values for each
  259.      * computed statistic.
  260.      *
  261.      * @param statistics Statistics to compute.
  262.      * @return the instance
  263.      * @throws IllegalArgumentException if there are no {@code statistics} to compute.
  264.      */
  265.     public static IntStatistics of(Statistic... statistics) {
  266.         return builder(statistics).build();
  267.     }

  268.     /**
  269.      * Returns a new instance configured to compute the specified {@code statistics}
  270.      * populated using the input {@code values}.
  271.      *
  272.      * <p>Use this method to create an instance populated with a (variable) array of
  273.      * {@code int[]} data:
  274.      *
  275.      * <pre>
  276.      * IntStatistics stats = IntStatistics.of(
  277.      *     EnumSet.of(Statistic.MIN, Statistic.MAX),
  278.      *     1, 1, 2, 3, 5, 8, 13);
  279.      * </pre>
  280.      *
  281.      * @param statistics Statistics to compute.
  282.      * @param values Values.
  283.      * @return the instance
  284.      * @throws IllegalArgumentException if there are no {@code statistics} to compute.
  285.      */
  286.     public static IntStatistics of(Set<Statistic> statistics, int... values) {
  287.         if (statistics.isEmpty()) {
  288.             throw new IllegalArgumentException(NO_CONFIGURED_STATISTICS);
  289.         }
  290.         final Builder b = new Builder();
  291.         statistics.forEach(b::add);
  292.         return b.build(values);
  293.     }

  294.     /**
  295.      * Returns a new builder configured to create instances to compute the specified
  296.      * {@code statistics}.
  297.      *
  298.      * <p>Use this method to create an instance populated with an array of {@code int[]}
  299.      * data using the {@link Builder#build(int...)} method:
  300.      *
  301.      * <pre>
  302.      * int[] data = ...
  303.      * IntStatistics stats = IntStatistics.builder(
  304.      *     Statistic.MIN, Statistic.MAX, Statistic.VARIANCE)
  305.      *     .build(data);
  306.      * </pre>
  307.      *
  308.      * <p>The builder can be used to create multiple instances of {@link IntStatistics}
  309.      * to be used in parallel, or on separate arrays of {@code int[]} data. These may
  310.      * be {@link #combine(IntStatistics) combined}. For example:
  311.      *
  312.      * <pre>
  313.      * int[][] data = ...
  314.      * IntStatistics.Builder builder = IntStatistics.builder(
  315.      *     Statistic.MIN, Statistic.MAX, Statistic.VARIANCE);
  316.      * IntStatistics stats = Arrays.stream(data)
  317.      *     .parallel()
  318.      *     .map(builder::build)
  319.      *     .reduce(IntStatistics::combine)
  320.      *     .get();
  321.      * </pre>
  322.      *
  323.      * <p>The builder can be used to create a {@link java.util.stream.Collector} for repeat
  324.      * use on multiple data:
  325.      *
  326.      * <pre>{@code
  327.      * IntStatistics.Builder builder = IntStatistics.builder(
  328.      *     Statistic.MIN, Statistic.MAX, Statistic.VARIANCE);
  329.      * Collector<int[], IntStatistics, IntStatistics> collector =
  330.      *     Collector.of(builder::build,
  331.      *                  (s, d) -> s.combine(builder.build(d)),
  332.      *                  IntStatistics::combine);
  333.      *
  334.      * // Repeated
  335.      * int[][] data = ...
  336.      * IntStatistics stats = Arrays.stream(data).collect(collector);
  337.      * }</pre>
  338.      *
  339.      * @param statistics Statistics to compute.
  340.      * @return the builder
  341.      * @throws IllegalArgumentException if there are no {@code statistics} to compute.
  342.      */
  343.     public static Builder builder(Statistic... statistics) {
  344.         if (statistics.length == 0) {
  345.             throw new IllegalArgumentException(NO_CONFIGURED_STATISTICS);
  346.         }
  347.         final Builder b = new Builder();
  348.         for (final Statistic s : statistics) {
  349.             b.add(s);
  350.         }
  351.         return b;
  352.     }

  353.     /**
  354.      * Updates the state of the statistics to reflect the addition of {@code value}.
  355.      *
  356.      * @param value Value.
  357.      */
  358.     @Override
  359.     public void accept(int value) {
  360.         count++;
  361.         consumer.accept(value);
  362.     }

  363.     /**
  364.      * Return the count of values recorded.
  365.      *
  366.      * @return the count of values
  367.      */
  368.     public long getCount() {
  369.         return count;
  370.     }

  371.     /**
  372.      * Check if the specified {@code statistic} is supported.
  373.      *
  374.      * <p>Note: This method will not return {@code false} if the argument is {@code null}.
  375.      *
  376.      * @param statistic Statistic.
  377.      * @return {@code true} if supported
  378.      * @throws NullPointerException if the {@code statistic} is {@code null}
  379.      * @see #getResult(Statistic)
  380.      */
  381.     public boolean isSupported(Statistic statistic) {
  382.         // Check for the appropriate underlying implementation
  383.         switch (statistic) {
  384.         case GEOMETRIC_MEAN:
  385.         case SUM_OF_LOGS:
  386.             return sumOfLogs != null;
  387.         case KURTOSIS:
  388.             return moment instanceof SumOfFourthDeviations;
  389.         case MAX:
  390.             return max != null;
  391.         case MIN:
  392.             return min != null;
  393.         case PRODUCT:
  394.             return product != null;
  395.         case SKEWNESS:
  396.             return moment instanceof SumOfCubedDeviations;
  397.         case STANDARD_DEVIATION:
  398.         case VARIANCE:
  399.             return sum != null && sumOfSquares != null;
  400.         case MEAN:
  401.         case SUM:
  402.             return sum != null;
  403.         case SUM_OF_SQUARES:
  404.             return sumOfSquares != null;
  405.         default:
  406.             return false;
  407.         }
  408.     }

  409.     /**
  410.      * Gets the value of the specified {@code statistic} as a {@code double}.
  411.      *
  412.      * @param statistic Statistic.
  413.      * @return the value
  414.      * @throws IllegalArgumentException if the {@code statistic} is not supported
  415.      * @see #isSupported(Statistic)
  416.      * @see #getResult(Statistic)
  417.      */
  418.     public double getAsDouble(Statistic statistic) {
  419.         return getResult(statistic).getAsDouble();
  420.     }

  421.     /**
  422.      * Gets the value of the specified {@code statistic} as an {@code int}.
  423.      *
  424.      * <p>Use this method to access the {@code int} result for exact integer statistics,
  425.      * for example {@link Statistic#MIN}.
  426.      *
  427.      * <p>Note: This method may throw an {@link ArithmeticException} if the result
  428.      * overflows an {@code int}.
  429.      *
  430.      * @param statistic Statistic.
  431.      * @return the value
  432.      * @throws IllegalArgumentException if the {@code statistic} is not supported
  433.      * @throws ArithmeticException if the {@code result} overflows an {@code int} or is not
  434.      * finite
  435.      * @see #isSupported(Statistic)
  436.      * @see #getResult(Statistic)
  437.      */
  438.     public int getAsInt(Statistic statistic) {
  439.         return getResult(statistic).getAsInt();
  440.     }

  441.     /**
  442.      * Gets the value of the specified {@code statistic} as a {@code long}.
  443.      *
  444.      * <p>Use this method to access the {@code long} result for exact integer statistics,
  445.      * for example {@link Statistic#SUM} for a {@link #getCount() count} less than or equal to
  446.      *2<sup>32</sup>.
  447.      *
  448.      * <p>Note: This method may throw an {@link ArithmeticException} if the result
  449.      * overflows an {@code long}.
  450.      *
  451.      * @param statistic Statistic.
  452.      * @return the value
  453.      * @throws IllegalArgumentException if the {@code statistic} is not supported
  454.      * @throws ArithmeticException if the {@code result} overflows an {@code long} or is not
  455.      * finite
  456.      * @see #isSupported(Statistic)
  457.      * @see #getResult(Statistic)
  458.      */
  459.     public long getAsLong(Statistic statistic) {
  460.         return getResult(statistic).getAsLong();
  461.     }

  462.     /**
  463.      * Gets the value of the specified {@code statistic} as a {@code BigInteger}.
  464.      *
  465.      * <p>Use this method to access the {@code BigInteger} result for exact integer statistics,
  466.      * for example {@link Statistic#SUM_OF_SQUARES}.
  467.      *
  468.      * <p>Note: This method may throw an {@link ArithmeticException} if the result
  469.      * is not finite.
  470.      *
  471.      * @param statistic Statistic.
  472.      * @return the value
  473.      * @throws IllegalArgumentException if the {@code statistic} is not supported
  474.      * @throws ArithmeticException if the {@code result} is not finite
  475.      * @see #isSupported(Statistic)
  476.      * @see #getResult(Statistic)
  477.      */
  478.     public BigInteger getAsBigInteger(Statistic statistic) {
  479.         return getResult(statistic).getAsBigInteger();
  480.     }

  481.     /**
  482.      * Gets a supplier for the value of the specified {@code statistic}.
  483.      *
  484.      * <p>The returned function will supply the correct result after
  485.      * calls to {@link #accept(int) accept} or
  486.      * {@link #combine(IntStatistics) combine} further values into
  487.      * {@code this} instance.
  488.      *
  489.      * <p>This method can be used to perform a one-time look-up of the statistic
  490.      * function to compute statistics as values are dynamically added.
  491.      *
  492.      * @param statistic Statistic.
  493.      * @return the supplier
  494.      * @throws IllegalArgumentException if the {@code statistic} is not supported
  495.      * @see #isSupported(Statistic)
  496.      * @see #getAsDouble(Statistic)
  497.      */
  498.     public StatisticResult getResult(Statistic statistic) {
  499.         // Locate the implementation.
  500.         // Statistics that wrap an underlying implementation are created in methods.
  501.         // The return argument should be an interface reference and not an instance
  502.         // of IntStatistic. This ensures the statistic implementation cannot
  503.         // be updated with new values by casting the result and calling accept(int).
  504.         StatisticResult stat = null;
  505.         switch (statistic) {
  506.         case GEOMETRIC_MEAN:
  507.             stat = getGeometricMean();
  508.             break;
  509.         case KURTOSIS:
  510.             stat = getKurtosis();
  511.             break;
  512.         case MAX:
  513.             stat = Statistics.getResultAsIntOrNull(max);
  514.             break;
  515.         case MEAN:
  516.             stat = getMean();
  517.             break;
  518.         case MIN:
  519.             stat = Statistics.getResultAsIntOrNull(min);
  520.             break;
  521.         case PRODUCT:
  522.             stat = Statistics.getResultAsDoubleOrNull(product);
  523.             break;
  524.         case SKEWNESS:
  525.             stat = getSkewness();
  526.             break;
  527.         case STANDARD_DEVIATION:
  528.             stat = getStandardDeviation();
  529.             break;
  530.         case SUM:
  531.             stat = Statistics.getResultAsBigIntegerOrNull(sum);
  532.             break;
  533.         case SUM_OF_LOGS:
  534.             stat = Statistics.getResultAsDoubleOrNull(sumOfLogs);
  535.             break;
  536.         case SUM_OF_SQUARES:
  537.             stat = Statistics.getResultAsBigIntegerOrNull(sumOfSquares);
  538.             break;
  539.         case VARIANCE:
  540.             stat = getVariance();
  541.             break;
  542.         default:
  543.             break;
  544.         }
  545.         if (stat != null) {
  546.             return stat;
  547.         }
  548.         throw new IllegalArgumentException(UNSUPPORTED_STATISTIC + statistic);
  549.     }

  550.     /**
  551.      * Gets the geometric mean.
  552.      *
  553.      * @return a geometric mean supplier (or null if unsupported)
  554.      */
  555.     private StatisticResult getGeometricMean() {
  556.         if (sumOfLogs != null) {
  557.             // Return a function that has access to the count and sumOfLogs
  558.             return () -> GeometricMean.computeGeometricMean(count, sumOfLogs);
  559.         }
  560.         return null;
  561.     }

  562.     /**
  563.      * Gets the kurtosis.
  564.      *
  565.      * @return a kurtosis supplier (or null if unsupported)
  566.      */
  567.     private StatisticResult getKurtosis() {
  568.         if (moment instanceof SumOfFourthDeviations) {
  569.             return new Kurtosis((SumOfFourthDeviations) moment)
  570.                 .setBiased(config.isBiased())::getAsDouble;
  571.         }
  572.         return null;
  573.     }

  574.     /**
  575.      * Gets the mean.
  576.      *
  577.      * @return a mean supplier (or null if unsupported)
  578.      */
  579.     private StatisticResult getMean() {
  580.         if (sum != null) {
  581.             // Return a function that has access to the count and sum
  582.             final Int128 s = sum.getSum();
  583.             return () -> IntMean.computeMean(s, count);
  584.         }
  585.         return null;
  586.     }

  587.     /**
  588.      * Gets the skewness.
  589.      *
  590.      * @return a skewness supplier (or null if unsupported)
  591.      */
  592.     private StatisticResult getSkewness() {
  593.         if (moment instanceof SumOfCubedDeviations) {
  594.             return new Skewness((SumOfCubedDeviations) moment)
  595.                 .setBiased(config.isBiased())::getAsDouble;
  596.         }
  597.         return null;
  598.     }

  599.     /**
  600.      * Gets the standard deviation.
  601.      *
  602.      * @return a standard deviation supplier (or null if unsupported)
  603.      */
  604.     private StatisticResult getStandardDeviation() {
  605.         return getVarianceOrStd(true);
  606.     }

  607.     /**
  608.      * Gets the variance.
  609.      *
  610.      * @return a variance supplier (or null if unsupported)
  611.      */
  612.     private StatisticResult getVariance() {
  613.         return getVarianceOrStd(false);
  614.     }

  615.     /**
  616.      * Gets the variance or standard deviation.
  617.      *
  618.      * @param std Flag to control if the statistic is the standard deviation.
  619.      * @return a variance/standard deviation supplier (or null if unsupported)
  620.      */
  621.     private StatisticResult getVarianceOrStd(boolean std) {
  622.         if (sum != null && sumOfSquares != null) {
  623.             // Return a function that has access to the count, sum and sum of squares
  624.             final Int128 s = sum.getSum();
  625.             final UInt128 ss = sumOfSquares.getSumOfSquares();
  626.             final boolean biased = config.isBiased();
  627.             return () -> IntVariance.computeVarianceOrStd(ss, s, count, biased, std);
  628.         }
  629.         return null;
  630.     }

  631.     /**
  632.      * Combines the state of the {@code other} statistics into this one.
  633.      * Only {@code this} instance is modified by the {@code combine} operation.
  634.      *
  635.      * <p>The {@code other} instance must be <em>compatible</em>. This is {@code true} if the
  636.      * {@code other} instance returns {@code true} for {@link #isSupported(Statistic)} for
  637.      * all values of the {@link Statistic} enum which are supported by {@code this}
  638.      * instance.
  639.      *
  640.      * <p>Note that this operation is <em>not symmetric</em>. It may be possible to perform
  641.      * {@code a.combine(b)} but not {@code b.combine(a)}. In the event that the {@code other}
  642.      * instance is not compatible then an exception is raised before any state is modified.
  643.      *
  644.      * @param other Another set of statistics to be combined.
  645.      * @return {@code this} instance after combining {@code other}.
  646.      * @throws IllegalArgumentException if the {@code other} is not compatible
  647.      */
  648.     public IntStatistics combine(IntStatistics other) {
  649.         // Check compatibility
  650.         Statistics.checkCombineCompatible(min, other.min);
  651.         Statistics.checkCombineCompatible(max, other.max);
  652.         Statistics.checkCombineCompatible(sum, other.sum);
  653.         Statistics.checkCombineCompatible(product, other.product);
  654.         Statistics.checkCombineCompatible(sumOfSquares, other.sumOfSquares);
  655.         Statistics.checkCombineCompatible(sumOfLogs, other.sumOfLogs);
  656.         Statistics.checkCombineAssignable(moment, other.moment);
  657.         // Combine
  658.         count += other.count;
  659.         Statistics.combine(min, other.min);
  660.         Statistics.combine(max, other.max);
  661.         Statistics.combine(sum, other.sum);
  662.         Statistics.combine(product, other.product);
  663.         Statistics.combine(sumOfSquares, other.sumOfSquares);
  664.         Statistics.combine(sumOfLogs, other.sumOfLogs);
  665.         Statistics.combineMoment(moment, other.moment);
  666.         return this;
  667.     }

  668.     /**
  669.      * Sets the statistics configuration.
  670.      *
  671.      * <p>These options only control the final computation of statistics. The configuration
  672.      * will not affect compatibility between instances during a
  673.      * {@link #combine(IntStatistics) combine} operation.
  674.      *
  675.      * <p>Note: These options will affect any future computation of statistics. Supplier functions
  676.      * that have been previously created will not be updated with the new configuration.
  677.      *
  678.      * @param v Value.
  679.      * @return {@code this} instance
  680.      * @throws NullPointerException if the value is null
  681.      * @see #getResult(Statistic)
  682.      */
  683.     public IntStatistics setConfiguration(StatisticsConfiguration v) {
  684.         config = Objects.requireNonNull(v);
  685.         return this;
  686.     }
  687. }