001/*
002 * Java Genetic Algorithm Library (jenetics-8.1.0).
003 * Copyright (c) 2007-2024 Franz Wilhelmstötter
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * 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 * Author:
018 *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
019 */
020package io.jenetics.stat;
021
022import static java.util.Objects.requireNonNull;
023
024import java.io.Serial;
025import java.io.Serializable;
026import java.util.function.ToLongFunction;
027import java.util.stream.Collector;
028
029/**
030 * <i>Value</i> objects which contains statistical moments.
031 *
032 * @see io.jenetics.stat.LongMomentStatistics
033 *
034 * @param count the count of values recorded
035 * @param min the minimum value recorded, or {@link Long#MAX_VALUE} if no
036 *            values have been recorded
037 * @param max the maximum value recorded, or {@link Long#MIN_VALUE} if no
038 *            values have been recorded
039 * @param sum the sum of values recorded, or zero if no values have been recorded
040 * @param mean the arithmetic mean of values recorded, or zero if no values have
041 *            been recorded
042 * @param variance the variance of values recorded, or {@link Double#NaN} if no
043 *            values have been recorded
044 * @param skewness the <a href="https://en.wikipedia.org/wiki/Skewness">Skewness</a>
045 *        of values recorded, or {@link Double#NaN} if less than two values have
046 *        been recorded
047 * @param kurtosis the <a href="https://en.wikipedia.org/wiki/Kurtosis">Kurtosis</a>
048 *        of values recorded, or {@link Double#NaN} if less than four values
049 *        have been recorded
050 *
051 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
052 * @since 3.0
053 * @version 7.0
054 */
055public record LongMoments(
056        long count,
057        long min,
058        long max,
059        long sum,
060        double mean,
061        double variance,
062        double skewness,
063        double kurtosis
064)
065        implements Serializable
066{
067
068        @Serial
069        private static final long serialVersionUID = 2;
070
071        @Override
072        public String toString() {
073                return String.format(
074                        "LongMoments[N=%d, ∧=%s, ∨=%s, Σ=%s, μ=%s, s²=%s, S=%s, K=%s]",
075                        count(), min(), max(), sum(),
076                        mean(), variance(), skewness(), kurtosis()
077                );
078        }
079
080        /**
081         * Return a new value object of the statistical moments, currently
082         * represented by the {@code statistics} object.
083         *
084         * @param statistics the creating (mutable) statistics class
085         * @return the statistical moments
086         */
087        public static LongMoments of(final LongMomentStatistics statistics) {
088                return new LongMoments(
089                        statistics.count(),
090                        statistics.min(),
091                        statistics.max(),
092                        statistics.sum(),
093                        statistics.mean(),
094                        statistics.variance(),
095                        statistics.skewness(),
096                        statistics.kurtosis()
097                );
098        }
099
100        /**
101         * Return a {@code Collector} which returns moments-statistics for the
102         * resulting values.
103         * {@snippet lang="java":
104         * final Stream<Long> stream = null; // @replace substring='null' replacement="..."
105         * final LongMoments moments = stream.collect(toLongMoments());
106         * }
107         *
108         * @since 4.1
109         *
110         * @param <N> the type of the input elements
111         * @return a {@code Collector} implementing the moments-statistics reduction
112         */
113        public static <N extends Number> Collector<N, ?, LongMoments>
114        toLongMoments() {
115                return toLongMoments(Number::longValue);
116        }
117
118        /**
119         * Return a {@code Collector} which applies a long-producing mapping
120         * function to each input element, and returns moments-statistics for the
121         * resulting values.
122         * {@snippet lang="java":
123         * final Stream<SomeObject> stream = null; // @replace substring='null' replacement="..."
124         * final LongMoments moments = stream
125         *     .collect(toLongMoments(v -> v.longValue()));
126         * }
127         *
128         * @param mapper a mapping function to apply to each element
129         * @param <T> the type of the input elements
130         * @return a {@code Collector} implementing the moments-statistics reduction
131         * @throws java.lang.NullPointerException if the given {@code mapper} is
132         *         {@code null}
133         */
134        public static <T> Collector<T, ?, LongMoments>
135        toLongMoments(final ToLongFunction<? super T> mapper) {
136                requireNonNull(mapper);
137                return Collector.of(
138                        LongMomentStatistics::new,
139                        (a, b) -> a.accept(mapper.applyAsLong(b)),
140                        LongMomentStatistics::combine,
141                        LongMoments::of
142                );
143        }
144
145}