// Path: src/utils/NumericalFunctions.java
// public class NumericalFunctions {
// 	public static double addLogs(double x, double y) {
// 		if (y <= x) {
// 			return x + Math.log1p(Math.exp(y - x));
// 		} else {
// 			return y + Math.log1p(Math.exp(x - y));
// 		}
// 	}
// 
// 	/*
// 	 * e^x + e^y = e^z - need to solve for z
// 	 * 
// 	 * z = log(e^x + e^y) = log(e^x.(e^x + e^y)/e^x) = x + log(1 + e^(y-x))
// 	 * 
// 	 * useful since e^(y-x) is presumably easier to calculate than either e^x or
// 	 * e^y
// 	 */
// 
// 	public static double adaGradUpdate(double gradient, double sumGradSquared, double learningRate) {
// 		double eps = 0.001;
// 
// 		return learningRate * gradient / (Math.sqrt(sumGradSquared) + eps);
// 	}
// }


import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import utils.NumericalFunctions;

				// System.out.println("root score: " + score + " gold: " +
				// root.goldMarker());

				if (score > maxScore) {
					maxScore = score;
					maxRoot = root;
				}
			}
		}

		// System.out.println("viterbi max value: " + maxScore);

		return maxRoot;
	}

	public double calcInside(boolean gold) {
		for (int i = 0; i < disjNodes.length; i++) {
			disjNodes[i].calcInside(gold);
		}

		// sum up the values for the roots:
		Iterator<DisjNode> it = rootNodes.iterator();
		if (!gold) {
			logZ = 0.0;
			while (it.hasNext()) {
				DisjNode root = it.next();
				if (logZ == 0.0) {
					logZ = root.score;
				} else {
// Path: src/utils/NumericalFunctions.java
// public class NumericalFunctions {
// 	public static double addLogs(double x, double y) {
// 		if (y <= x) {
// 			return x + Math.log1p(Math.exp(y - x));
// 		} else {
// 			return y + Math.log1p(Math.exp(x - y));
// 		}
// 	}
// 
// 	/*
// 	 * e^x + e^y = e^z - need to solve for z
// 	 * 
// 	 * z = log(e^x + e^y) = log(e^x.(e^x + e^y)/e^x) = x + log(1 + e^(y-x))
// 	 * 
// 	 * useful since e^(y-x) is presumably easier to calculate than either e^x or
// 	 * e^y
// 	 */
// 
// 	public static double adaGradUpdate(double gradient, double sumGradSquared, double learningRate) {
// 		double eps = 0.001;
// 
// 		return learningRate * gradient / (Math.sqrt(sumGradSquared) + eps);
// 	}
// }


// Path: src/training/Forest.java
import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import utils.NumericalFunctions;


				// System.out.println("root score: " + score + " gold: " +
				// root.goldMarker());

				if (score > maxScore) {
					maxScore = score;
					maxRoot = root;
				}
			}
		}

		// System.out.println("viterbi max value: " + maxScore);

		return maxRoot;
	}

	public double calcInside(boolean gold) {
		for (int i = 0; i < disjNodes.length; i++) {
			disjNodes[i].calcInside(gold);
		}

		// sum up the values for the roots:
		Iterator<DisjNode> it = rootNodes.iterator();
		if (!gold) {
			logZ = 0.0;
			while (it.hasNext()) {
				DisjNode root = it.next();
				if (logZ == 0.0) {
					logZ = root.score;
				} else {
					logZ = NumericalFunctions.addLogs(logZ, root.score);