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