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 */
017package org.apache.commons.math4.legacy.stat.descriptive.summary;
018
019import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException;
020import org.apache.commons.math4.legacy.exception.NullArgumentException;
021import org.apache.commons.math4.legacy.stat.descriptive.AbstractStorelessUnivariateStatistic;
022import org.apache.commons.math4.core.jdkmath.JdkMath;
023import org.apache.commons.math4.legacy.core.MathArrays;
024
025/**
026 * Returns the sum of the natural logs for this collection of values.
027 * <p>
028 * Uses {@link org.apache.commons.math4.core.jdkmath.JdkMath#log(double)} to compute the logs.
029 * Therefore,
030 * <ul>
031 * <li>If any of values are &lt; 0, the result is <code>NaN.</code></li>
032 * <li>If all values are non-negative and less than
033 * <code>Double.POSITIVE_INFINITY</code>,  but at least one value is 0, the
034 * result is <code>Double.NEGATIVE_INFINITY.</code></li>
035 * <li>If both <code>Double.POSITIVE_INFINITY</code> and
036 * <code>Double.NEGATIVE_INFINITY</code> are among the values, the result is
037 * <code>NaN.</code></li>
038 * </ul>
039 * <p>
040 * <strong>Note that this implementation is not synchronized.</strong> If
041 * multiple threads access an instance of this class concurrently, and at least
042 * one of the threads invokes the <code>increment()</code> or
043 * <code>clear()</code> method, it must be synchronized externally.</p>
044 */
045public class SumOfLogs extends AbstractStorelessUnivariateStatistic {
046    /** Number of values that have been added. */
047    private int n;
048
049    /**
050     * The currently running value.
051     */
052    private double value;
053
054    /**
055     * Create a SumOfLogs instance.
056     */
057    public SumOfLogs() {
058       value = 0d;
059       n = 0;
060    }
061
062    /**
063     * Copy constructor, creates a new {@code SumOfLogs} identical
064     * to the {@code original}.
065     *
066     * @param original the {@code SumOfLogs} instance to copy
067     * @throws NullArgumentException if original is null
068     */
069    public SumOfLogs(SumOfLogs original) throws NullArgumentException {
070        copy(original, this);
071    }
072
073    /**
074     * {@inheritDoc}
075     */
076    @Override
077    public void increment(final double d) {
078        value += JdkMath.log(d);
079        n++;
080    }
081
082    /**
083     * {@inheritDoc}
084     */
085    @Override
086    public double getResult() {
087        return value;
088    }
089
090    /**
091     * {@inheritDoc}
092     */
093    @Override
094    public long getN() {
095        return n;
096    }
097
098    /**
099     * {@inheritDoc}
100     */
101    @Override
102    public void clear() {
103        value = 0d;
104        n = 0;
105    }
106
107    /**
108     * Returns the sum of the natural logs of the entries in the specified portion of
109     * the input array, or <code>Double.NaN</code> if the designated subarray
110     * is empty.
111     * <p>
112     * Throws <code>MathIllegalArgumentException</code> if the array is null.</p>
113     * <p>
114     * See {@link SumOfLogs}.</p>
115     *
116     * @param values the input array
117     * @param begin index of the first array element to include
118     * @param length the number of elements to include
119     * @return the sum of the natural logs of the values or 0 if
120     * length = 0
121     * @throws MathIllegalArgumentException if the array is null or the array index
122     *  parameters are not valid
123     */
124    @Override
125    public double evaluate(final double[] values, final int begin, final int length)
126        throws MathIllegalArgumentException {
127
128        double sumLog = Double.NaN;
129        if (MathArrays.verifyValues(values, begin, length, true)) {
130            sumLog = 0.0;
131            for (int i = begin; i < begin + length; i++) {
132                sumLog += JdkMath.log(values[i]);
133            }
134        }
135        return sumLog;
136    }
137
138    /**
139     * {@inheritDoc}
140     */
141    @Override
142    public SumOfLogs copy() {
143        SumOfLogs result = new SumOfLogs();
144        // No try-catch or advertised exception here because args are valid
145        copy(this, result);
146        return result;
147    }
148
149    /**
150     * Copies source to dest.
151     * <p>Neither source nor dest can be null.</p>
152     *
153     * @param source SumOfLogs to copy
154     * @param dest SumOfLogs to copy to
155     * @throws NullArgumentException if either source or dest is null
156     */
157    public static void copy(SumOfLogs source, SumOfLogs dest)
158        throws NullArgumentException {
159        NullArgumentException.check(source);
160        NullArgumentException.check(dest);
161        dest.n = source.n;
162        dest.value = source.value;
163    }
164}