<commit_before>/*
 * Copyright 1999-2002 Carnegie Mellon University.  
 * Portions Copyright 2002 Sun Microsystems, Inc.  
 * Portions Copyright 2002 Mitsubishi Electronic Research Laboratories.
 * All Rights Reserved.  Use is subject to license terms.
 * 
 * See the file "license.terms" for information on usage and
 * redistribution of this file, and for a DISCLAIMER OF ALL 
 * WARRANTIES.
 *
 */

package edu.cmu.sphinx.util;

import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import java.util.logging.Level;

import java.io.Serializable;
import java.io.ObjectInputStream;
import java.io.IOException;


/**
 * Provides a set of methods for performing simple math in
 * the log domain.  The logarithmic base can be set by the
 * SphinxProperty:
 * <br><code>
 * edu.cmu.sphinx.util.LogMath.logBase
 * </code><br>
 * 
 */
public final class LogMath implements Serializable {

    static Map contextMap = new HashMap();

    /**
     * The logger for this class
     */
    private static Logger logger = 
	    Logger.getLogger("edu.cmu.sphinx.util.LogMath");

    /**
     * Sphinx property to get the Log base
     */

    public final static String PROP_LOG_BASE 
	= "edu.cmu.sphinx.util.LogMath.logBase";

    /**
     * Sphinx property that controls whether we use the old, slow (but
     * correct) method of performing the LogMath.add by doing the actual
     * computation.
     */

    public final static String PROP_USE_ADD_TABLE
	= "edu.cmu.sphinx.util.LogMath.useAddTable";

    private double logBase = 1.0001;
    private boolean useAddTable;
    private transient double naturalLogBase;
    private transient double inverseNaturalLogBase;
    private transient double logZero;
    private transient double logOne;
    private transient double theAddTable[];
    private transient double maxLogValue;
    private transient double minLogValue;

     /**
      * Creates a log math with the given base
      *
      * @param base the base for the log math
      *
      * @param useTable use the addTable (true) or do computation (false)
      */
     public static  LogMath getLogMath(double base, boolean useTable) {
	 return new LogMath(base, useTable);
     }

     /**
      * Gets a  LogMath for the given context
      *
      * @param context the context of interest
      *
      * @return the LogMath for the context
      */
     public static LogMath getLogMath(String  context) {
	 LogMath logMath = (LogMath) contextMap.get(context);
	 if (logMath == null) {
	    SphinxProperties props = 
		    SphinxProperties.getSphinxProperties(context);
	    double base = props.getDouble(PROP_LOG_BASE, Math.E);
	    boolean useTable = props.getBoolean(PROP_USE_ADD_TABLE, true);
	    logMath = new LogMath(base, useTable);
	    contextMap.put(context, logMath);
	 } 
	 return logMath;
     }

     /**
      * Create a log math class. Also create the addTable table, which
      * depends on the log base.
      *
      * @param base the log base
      *
      * @param useTable use the addTable (true) or do computation (false)
      */
     private LogMath(double base, boolean useTable) {
	 logBase = base;
	 useAddTable = useTable;
	 init();
     }

    /**
     * De-serializes the non-transient fields to the given stream
     *
     * @param s the stream to read the object from
     *
     * @throws IOException if an error occurs during the read.
     */
    private void readObject(ObjectInputStream s) 
	throws IOException, ClassNotFoundException {
	s.defaultReadObject();
	init();
    }

     /**
      * Initializes this log math
      */
     private void init() {

	 logger.info("Log base is " + logBase);
	 if (useAddTable) {
	     logger.info("Using AddTable when adding logs");
	 } else {
	     logger.info("Performing actual computation when adding logs");
	 }
	 naturalLogBase = Math.log(logBase);
	 inverseNaturalLogBase = 1.0/naturalLogBase;

	 // [[[ TODO: probably not right way to get logZero ]]]
	 // EBG: Probably the right way is just to assign 
	 // -MAX_VALUE to logZero

	 // logZero = Math.log(Double.MIN_VALUE);
	 logZero = -Double.MAX_VALUE;
         logOne = 0.0;

	 // System.out.println("Logz is " + logZero);

	 // When converting a number from/to linear, we need to make
	 // sure it's within certain limits to prevent it from
	 // underflowing/overflowing.

	 // We compute the max value by computing the log of the max
	 // value that a double can contain.
	 maxLogValue = linearToLog(Double.MAX_VALUE);

	 // We compute the min value by computing the log of the min
	 // (absolute) value that a double can hold.
	 minLogValue = linearToLog(Double.MIN_VALUE);

	 if (useAddTable) {
	     // Now create the addTable table.

	     // summation needed in the loop
	     double innerSummation;

	     // First decide number of elements.
	     int entriesInTheAddTable;
	     final int veryLargeNumberOfEntries = 150000;
	     final int verySmallNumberOfEntries = 0;

	     // To decide size of table, take into account that a base
	     // of 1.0001 or 1.0003 converts probabilities, which are
	     // numbers less than 1, into integers.  Therefore, a good
	     // approximation for the smallest number in the table,
	     // therefore the value with the highest index, is an
	     // index that maps into 0.5: indices higher than that, if
	     // they were present, would map to less values less than
	     // 0.5, therefore they would be mapped to 0 as
	     // integers. Since the table implements the expression:
	     //
	     // log(1.0 + base^(-index)))
	     //
	     // then the highest index would be:
	     //
	     // topIndex = - log(logBase^(0.5) - 1)
	     //
	     // where log is the log in the appropriate base.

	     // TODO: PBL changed this to get it to compile, also
	     // added -Math.rint(...) to round to nearest
	     // integer. Added the negation to match the preceeding
	     // documentation

	     entriesInTheAddTable = 
		 (int) -Math.rint(linearToLog(logToLinear(0.5) - 1));

	     // We reach this max if the log base is 1.00007. The
	     // closer you get to 1, the higher the number of entries
	     // in the table.

	     if (entriesInTheAddTable > veryLargeNumberOfEntries) {
		 entriesInTheAddTable = veryLargeNumberOfEntries;
	     }

	     if (entriesInTheAddTable <= verySmallNumberOfEntries) {
		 throw new IllegalArgumentException("The log base "
		      + logBase + " yields a very small addTable. "
		      + "Either choose not to use the addTable, "
                      + "or choose a logBase closer to 1.0");
	     }

	     // PBL added this just to see how many entries really are
	     // in the table

	     if (false)  {
		 System.out.println("LogAdd table has " + entriesInTheAddTable
				    + " entries.");
	     }

	     theAddTable = new double[entriesInTheAddTable];
	     for (int index = 0; index < entriesInTheAddTable; index++) {
		 // This loop implements the expression:
		 //
		 // log( 1.0 + power(base, index))
		 //
		 // needed to add two numbers in the log domain.

		 innerSummation = logToLinear(-index);
		 innerSummation += 1.0f;
		 theAddTable[index] = linearToLog(innerSummation);
	     }
	 }
     }



    /**
     * Returns the base raised to the power, when the result and the
     * base are in log.
     *
     * <p>Will check for underflow and report.</p>
     *
     * <p>Will check for overflow on the lowest bound and constrain
     * values to be no lower than -Double.MAX_VALUE.</p>
     *
     * <p>Will check for overflow on the highest bound and constrain
     * values to be no higher than Double.MAX_VALUE.</p>
     *
     *
     * @param logOfbase base, in log, to be raised
     * @param exponent power of the exponentiation
     *
     * @return base raised to exponent, in log
     *
     */
    public final double powerAsLinear(double logOfBase, double exponent) {
	double returnValue = logOfBase * exponent;
	boolean overflowOccurred = false;

	// if abs(exponent) is > 1, the product may result larger than max
	if (Math.abs(exponent) > 1) {
	    if (Math.abs(logOfBase) > (Double.MAX_VALUE / Math.abs(exponent))) {
		overflowOccurred = true;
		// logOfBase/exponent will have the same sign as their
		// product, but will not overflow.
		if ((logOfBase / exponent > 0)) {
		    returnValue = Double.MAX_VALUE;
		} else {
		    returnValue = -Double.MAX_VALUE;
		}
	    }
	} else if (Math.abs(exponent) < 1) {
	    // Underflow may occur if exponent is less than one (the
	    // power will be less than the logOfBase in absolute terms.
	    if (Math.abs(logOfBase) < ( Double.MIN_VALUE / Math.abs(exponent))) {
		overflowOccurred = true;
		returnValue = 0.0;
	    }
	}
	if (overflowOccurred) {
	    logger.info("********Overflow or underflow occurred "
			+ "while trying to LogMath.powerAsLinear "
			+  logOfBase + " raised to " + exponent);
	}
	return returnValue;
    }


    /**
     * Returns the product of two values, when the result and the two
     * values are in log.
     *
     * <p>In other words, it returns log(a * b) given log(a) and log(b).</p>
     *
     * <p>Will check for overflow on the lowest bound and constrain
     * values to be no lower than -Double.MAX_VALUE.</p>
     *
     * <p>Will check for overflow on the highest bound and constrain
     * values to be no higher than Double.MAX_VALUE.</p>
     *
     *
     * @param logVal1 value in log domain (i.e. log(val1)) to multiply
     * @param logVal2 value in log domain (i.e. log(val2)) to multiply
     *
     * @return product of val1 and val2 in the log domain
     *
     */
    public final double multiplyAsLinear(double logVal1, double logVal2) {
	double returnValue = logVal1 + logVal2;
	boolean overflowOccurred = false;

	// [ EBG: alternative... test the sign of each of logVal1 and
	// logVal2 and, if needed, the result. If logVal1 and logVal2 have
	// different signs, then overflow isn't an issue. If they have
	// the same sign and the result also has the same sign, then
	// operation was successful. if not, then an overflow occured,
	// in which case we can signal or just return MAX_VALUE ]

	if (logVal1 > 0) {
	    if (logVal2 > (Double.MAX_VALUE - logVal1)) {
		overflowOccurred = true;
		returnValue = Double.MAX_VALUE;
	    }
	} else if (logVal1 < 0) {
	    if (logVal2 < ( -Double.MAX_VALUE - logVal1)) {
		overflowOccurred = true;
		returnValue = -Double.MAX_VALUE;
	    }
	}
	if (overflowOccurred) {
	    logger.info("********Overflow or underflow occurred "
			+ "while trying to LogMath.multiplyAsLinear "
			+ logVal1 + " and " + logVal2);
	}
	return returnValue;
    }

    /**
     * Returns the ratio of two numbers when the arguments and the
     * result are in log.
     *
     * <p>That is, it returns log(a / b) given log(a) and log(b).</p>
     *
     * @param logVal1 dividend in log domain (i.e. log(val1))
     * @param logVal2 divisor in log domain (i.e. log(val2))
     *
     * @return division of val1 and val2 in the log domain
     *
     * TODO: Add check for underflow
     */
    public final double divideAsLinear(double logVal1, double logVal2) {
	// Since this is log, -logVal2 is log(1/Val2), therefore the
	// multiply, which already contains overflow check.
	double returnValue = multiplyAsLinear(logVal1, -logVal2);
	return returnValue;
    }


    /**
     * Returns the summation of two numbers when the arguments and the
     * result are in log.
     *
     * <p>That is, it returns log(a + b) given log(a) and log(b)</p>
     *
     * <p>This method makes use of the equality:</p>
     *
     * <p><b>log(a + b) = log(a) + log (1 + exp(log(b) - log(a)))</b></p>
     *
     * <p>which is derived from:</p>
     *
     * <p><b>a + b = a * (1 + (b / a))</b></p>
     *
     * <p>which in turns makes use of:</p>
     *
     * <p><b>b / a = exp (log(b) - log(a))</b></p>
     *
     * <p>Important to notice that <code>subtractAsLinear(a, b)</code>
     * is *not* the same as <code>addAsLinear(a, -b)</code>, since
     * we're in the log domain, and -b is in fact the inverse.</p>
     *
     * <p>Will check for underflow and constrain values to be no lower
     * than Double.MIN_VALUE.</p>
     *
     * <p>Will check for overflow and constrain values to be no higher
     * than Double.MAX_VALUE.</p>
     *
     * <p>Both underflow and overflow checks are actually performed by
     * the multiplyAsLinear method.</p>
     *
     * @param logVal1 value in log domain (i.e. log(val1)) to add
     * @param logVal2 value in log domain (i.e. log(val2)) to add
     *
     * @return sum of val1 and val2 in the log domain
     *
     * <br>[[[ TODO: This is a very slow way to do this ]]]
     * [[[ TODO: need to have some overflow underflow checks ]]]
     * [ EBG: maybe we should also have a function to add many numbers,
     * say, return the summation of all terms in a given vector, if 
     * efficiency becomes an issue.
     */
    public final double addAsLinear(double logVal1, double logVal2) {
	double highestValue;
	double difference;
	double returnValue;

	// difference is always a positive number
	if (logVal1 > logVal2) {
	    highestValue = logVal1;
	    difference = logVal1 - logVal2;
	} else {
	    highestValue = logVal2;
	    difference = logVal2 - logVal1;
	}
	return multiplyAsLinear(highestValue, addTable(difference));
    }
<commit_msg>Eliminated the power, multiply and divide methods from LogMath, and changed files that used these methods to the corresponding +, -, and * operations in log scale.<commit_after>/*
 * Copyright 1999-2002 Car<NAME> University.  
 * Portions Copyright 2002 Sun Microsystems, Inc.  
 * Portions Copyright 2002 Mitsubishi Electronic Research Laboratories.
 * All Rights Reserved.  Use is subject to license terms.
 * 
 * See the file "license.terms" for information on usage and
 * redistribution of this file, and for a DISCLAIMER OF ALL 
 * WARRANTIES.
 *
 */

package edu.cmu.sphinx.util;

import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import java.util.logging.Level;

import java.io.Serializable;
import java.io.ObjectInputStream;
import java.io.IOException;


/**
 * Provides a set of methods for performing simple math in
 * the log domain.  The logarithmic base can be set by the
 * SphinxProperty:
 * <br><code>
 * edu.cmu.sphinx.util.LogMath.logBase
 * </code><br>
 * 
 */
public final class LogMath implements Serializable {

    static Map contextMap = new HashMap();

    /**
     * The logger for this class
     */
    private static Logger logger = 
	    Logger.getLogger("edu.cmu.sphinx.util.LogMath");

    /**
     * Sphinx property to get the Log base
     */

    public final static String PROP_LOG_BASE 
	= "edu.cmu.sphinx.util.LogMath.logBase";

    /**
     * Sphinx property that controls whether we use the old, slow (but
     * correct) method of performing the LogMath.add by doing the actual
     * computation.
     */

    public final static String PROP_USE_ADD_TABLE
	= "edu.cmu.sphinx.util.LogMath.useAddTable";

    private double logBase;
    private boolean useAddTable;
    private transient double naturalLogBase;
    private transient double inverseNaturalLogBase;
    private transient double logZero;
    private transient double logOne;
    private transient double theAddTable[];
    private transient double maxLogValue;
    private transient double minLogValue;

     /**
      * Creates a log math with the given base
      *
      * @param base the base for the log math
      *
      * @param useTable use the addTable (true) or do computation (false)
      */
     public static  LogMath getLogMath(double base, boolean useTable) {
	 return new LogMath(base, useTable);
     }

     /**
      * Gets a  LogMath for the given context
      *
      * @param context the context of interest
      *
      * @return the LogMath for the context
      */
     public static LogMath getLogMath(String  context) {
	 LogMath logMath = (LogMath) contextMap.get(context);
	 if (logMath == null) {
	    SphinxProperties props = 
		    SphinxProperties.getSphinxProperties(context);
	    double base = props.getDouble(PROP_LOG_BASE, Math.E);
	    boolean useTable = props.getBoolean(PROP_USE_ADD_TABLE, true);
	    logMath = new LogMath(base, useTable);
	    contextMap.put(context, logMath);
	 } 
	 return logMath;
     }

     /**
      * Create a log math class. Also create the addTable table, which
      * depends on the log base.
      *
      * @param base the log base
      *
      * @param useTable use the addTable (true) or do computation (false)
      */
     private LogMath(double base, boolean useTable) {
	 logBase = base;
	 useAddTable = useTable;
	 init();
     }

    /**
     * De-serializes the non-transient fields to the given stream
     *
     * @param s the stream to read the object from
     *
     * @throws IOException if an error occurs during the read.
     */
    private void readObject(ObjectInputStream s) 
	throws IOException, ClassNotFoundException {
	s.defaultReadObject();
	init();
    }

     /**
      * Initializes this log math
      */
     private void init() {

	 logger.info("Log base is " + logBase);
	 if (useAddTable) {
	     logger.info("Using AddTable when adding logs");
	 } else {
	     logger.info("Performing actual computation when adding logs");
	 }
	 naturalLogBase = Math.log(logBase);
	 inverseNaturalLogBase = 1.0/naturalLogBase;

	 // [[[ TODO: probably not right way to get logZero ]]]
	 // EBG: Probably the right way is just to assign 
	 // -MAX_VALUE to logZero

	 // logZero = Math.log(Double.MIN_VALUE);
	 logZero = -Double.MAX_VALUE;
         logOne = 0.0;

	 // System.out.println("Logz is " + logZero);

	 // When converting a number from/to linear, we need to make
	 // sure it's within certain limits to prevent it from
	 // underflowing/overflowing.

	 // We compute the max value by computing the log of the max
	 // value that a double can contain.
	 maxLogValue = linearToLog(Double.MAX_VALUE);

	 // We compute the min value by computing the log of the min
	 // (absolute) value that a double can hold.
	 minLogValue = linearToLog(Double.MIN_VALUE);

	 if (useAddTable) {
	     // Now create the addTable table.

	     // summation needed in the loop
	     double innerSummation;

	     // First decide number of elements.
	     int entriesInTheAddTable;
	     final int veryLargeNumberOfEntries = 150000;
	     final int verySmallNumberOfEntries = 0;

	     // To decide size of table, take into account that a base
	     // of 1.0001 or 1.0003 converts probabilities, which are
	     // numbers less than 1, into integers.  Therefore, a good
	     // approximation for the smallest number in the table,
	     // therefore the value with the highest index, is an
	     // index that maps into 0.5: indices higher than that, if
	     // they were present, would map to less values less than
	     // 0.5, therefore they would be mapped to 0 as
	     // integers. Since the table implements the expression:
	     //
	     // log(1.0 + base^(-index)))
	     //
	     // then the highest index would be:
	     //
	     // topIndex = - log(logBase^(0.5) - 1)
	     //
	     // where log is the log in the appropriate base.

	     // TODO: PBL changed this to get it to compile, also
	     // added -Math.rint(...) to round to nearest
	     // integer. Added the negation to match the preceeding
	     // documentation

	     entriesInTheAddTable = 
		 (int) -Math.rint(linearToLog(logToLinear(0.5) - 1));

	     // We reach this max if the log base is 1.00007. The
	     // closer you get to 1, the higher the number of entries
	     // in the table.

	     if (entriesInTheAddTable > veryLargeNumberOfEntries) {
		 entriesInTheAddTable = veryLargeNumberOfEntries;
	     }

	     if (entriesInTheAddTable <= verySmallNumberOfEntries) {
		 throw new IllegalArgumentException("The log base "
		      + logBase + " yields a very small addTable. "
		      + "Either choose not to use the addTable, "
                      + "or choose a logBase closer to 1.0");
	     }

	     // PBL added this just to see how many entries really are
	     // in the table

	     if (false)  {
		 System.out.println("LogAdd table has " + entriesInTheAddTable
				    + " entries.");
	     }

	     theAddTable = new double[entriesInTheAddTable];
	     for (int index = 0; index < entriesInTheAddTable; index++) {
		 // This loop implements the expression:
		 //
		 // log( 1.0 + power(base, index))
		 //
		 // needed to add two numbers in the log domain.

		 innerSummation = logToLinear(-index);
		 innerSummation += 1.0f;
		 theAddTable[index] = linearToLog(innerSummation);
	     }
	 }
     }


    /**
     * Returns the summation of two numbers when the arguments and the
     * result are in log.
     *
     * <p>That is, it returns log(a + b) given log(a) and log(b)</p>
     *
     * <p>This method makes use of the equality:</p>
     *
     * <p><b>log(a + b) = log(a) + log (1 + exp(log(b) - log(a)))</b></p>
     *
     * <p>which is derived from:</p>
     *
     * <p><b>a + b = a * (1 + (b / a))</b></p>
     *
     * <p>which in turns makes use of:</p>
     *
     * <p><b>b / a = exp (log(b) - log(a))</b></p>
     *
     * <p>Important to notice that <code>subtractAsLinear(a, b)</code>
     * is *not* the same as <code>addAsLinear(a, -b)</code>, since
     * we're in the log domain, and -b is in fact the inverse.</p>
     *
     * <p>No underflow/overflow check is performed.</p>
     *
     * @param logVal1 value in log domain (i.e. log(val1)) to add
     * @param logVal2 value in log domain (i.e. log(val2)) to add
     *
     * @return sum of val1 and val2 in the log domain
     */
    public final double addAsLinear(double logVal1, double logVal2) {
	double logHighestValue;
	double logDifference;
	double returnValue;

	/*
	 * [ EBG: maybe we should also have a function to add many
	 * numbers, * say, return the summation of all terms in a
	 * given vector, if * efficiency becomes an issue.
	 */

	// difference is always a positive number
	if (logVal1 > logVal2) {
	    logHighestValue = logVal1;
	    logDifference = logVal1 - logVal2;
	} else {
	    logHighestValue = logVal2;
	    logDifference = logVal2 - logVal1;
	}
	return logHighestValue + addTable(logDifference);
    }

{'fraction_non_alphanumeric': 0.09911933860531992, 'fraction_numerical': 0.009615384615384616, 'mean_word_length': 2.5216772151898734, 'pattern_counts': {'":': 0, '<': 95, '<?xml version=': 0, '>': 97, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4206051', 'n_tokens_mistral': 7117, 'n_tokens_neox': 6515, 'n_words': 2393}