All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gov.sandia.cognition.math.LogMath Maven / Gradle / Ivy

There is a newer version: 4.0.1
Show newest version
/*
 * File:                LogMath.java
 * Authors:             Justin Basilico
 * Company:             Sandia National Laboratories
 * Project:             Cognitive Foundry
 * 
 * Copyright June 13, 2011, Sandia Corporation.
 * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
 * license for use of this work by or on behalf of the U.S. Government. Export
 * of this program may require a license from the United States Government.
 * See CopyrightHistory.txt for complete details.
 * 
 */

package gov.sandia.cognition.math;

/**
 * A utility class for doing math with numbers represented as logarithms. Thus,
 * the number x is instead represented as log(x). This can be useful when
 * doing computation involving many products, such as with probabilities.
 * 
 * @author  Justin Basilico
 * @since   3.3.0
 */
public class LogMath
{

    /** The natural logarithm of 0 (log(0)), which is negative infinity. */
    public static final double LOG_0 = Double.NEGATIVE_INFINITY;

    /** The natural logarithm of 1 (log(1)), which is 0. */
    public static final double LOG_1 = 0.0;

    /** The natural logarithm of 2 (log(2)). */
    public static final double LOG_2 = Math.log(2.0);

    /** The natural logarithm of e (log(e)), which is 1. */
    public static final double LOG_E = 1.0;

    /** The natural logarithm of 10 (log(10)). */
    public static final double LOG_10 = Math.log(10.0);

    /**
     * Converts a number to its log-domain representation (log(x)). Negative
     * values will result in NaN.
     *
     * @param   x
     *      The number. Should not be negative.
     * @return
     *      The logarithm of x (log(x)).
     */
    public static double toLog(
        final double x)
    {
        return Math.log(x);
    }

    /**
     * Converts a number from log-domain representation (x = exp(logX)).
     *
     * @param   logX
     *      The log-domain representation of the number x (log(x)).
     * @return
     *      The value of x, which is exp(logX) = exp(log(x)).
     */
    public static double fromLog(
        final double logX)
    {
        return Math.exp(logX);
    }
    
    /**
     * Adds two log-domain values. It uses a trick to prevent numerical
     * overflow and underflow.
     *
     * @param   logX
     *      The first log-domain value (log(x)).
     *      Must be the same basis as logY.
     * @param   logY
     *      The second log-domain value (log(y)).
     *      Must be the same basis as logX.
     * @return
     *      The log of x plus y (log(x + y)).
     */
    public static double add(
        final double logX,
        final double logY)
    {
        if (logX > logY)
        {
            return MathUtil.log1PlusExp(logY - logX) + logX;
        }
        else if (logY > logX)
        {
            return MathUtil.log1PlusExp(logX - logY) + logY;
        }
        else
        {
            // Since x == y, we have log(x + y) = log(x * 2) = log(x) + log(2).
            return logX + LOG_2;
        }
    }

    /**
     * Subtracts two log-domain values. It uses a trick to prevent numerical
     * overflow and underflow.
     *
     * @param   logX
     *      The first log-domain value (log(x)).
     *      Must be the same basis as logY.
     * @param   logY
     *      The second log-domain value (log(y)).
     *      Must be the same basis as logX.
     * @return
     *      The log of x minus y (log(x - y)).
     */
    public static double subtract(
        final double logX,
        final double logY)
    {
        if (logX > logY)
        {
            return MathUtil.log1MinusExp(logY - logX) + logX;
        }
        else if (logY > logX)
        {
            // Since y > x, we will have a log of a negative number, which
            // does not exist.
            return Double.NaN;
        }
        else if (logX == Double.POSITIVE_INFINITY)
        {
            // Infinity minus infinity is normally a NaN.
            return Double.NaN;
        }
        else
        {
            // Since x == y, we have log(x - y) = log(0), which is negative
            // infinity.
            return LOG_0;
        }
    }

    /**
     * Multiplies two log-domain values. It uses the identity:
     *     log(x * y) = log(x) + log(y)
     *
     * @param   logX
     *      The first log-domain value (log(x)).
     *      Must be the same basis as logY.
     * @param   logY
     *      The second log-domain value (log(y)).
     *      Must be the same basis as logX.
     * @return
     *      The log of x divided by y (log(x * y)).
     */
    public static double multiply(
        final double logX,
        final double logY)
    {
        return logX + logY;
    }

    /**
     * Divides two log-domain values. It uses the identity:
     *     log(x / y) = log(x) - log(y)
     *
     * @param   logX
     *      The first log-domain value (log(x)) used in the numerator.
     *      Must be the same basis as logY.
     * @param   logY
     *      The second log-domain value (log(y)) used in the denominator.
     *      Must be the same basis as logX.
     * @return
     *      The log of x times y (log(x / y)).
     */
    public static double divide(
        final double logX,
        final double logY)
    {
        return logX - logY;
    }

    /**
     * Takes the inverse of a log-domain value. Using the same identity as
     * the division one and that log(1) = 0 to be:
     *    log(x^-1) = log(1 / x) = log(1) - log(x) = -log(x)
     *
     * @param   logX
     *      The log-domain value (log(x)) to invert.
     * @return
     *      The log of x^-1 = 1 / x (log(1/x)).
     */
    public static double inverse(
        final double logX)
    {
        return -logX;
    }
    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy