//
//package edu.berkeley.nlp.math;
//
//import Jama.Matrix;
//import Jama.EigenvalueDecomposition;
//import Jama.SingularValueDecomposition;
//import fig.basic.Pair;
//import fig.basic.NumUtils;
//
//import java.util.Arrays;
//
//import edu.berkeley.nlp.util.Logger;
//
///**
// * User: aria42
// * Date: Jan 13, 2009
// */
//public class MatrixTreeTheorem {
//
// /**
// * Computes sum over labeled trees. There is assumed to be a fixed
// * number of labels possible for each edge.
// *
// * logPotentials[i][j][l] represents the logPotential (i,j)
// * for the (i,j) attachment with label l. It's safe to have
// * -inf as a value in this array to disallow attachments
// * or labels
// *
// * Returns sum over labeled trees as well as posteriors
// * stored in result.getSecond()
// * @param logPotentials
// * @return
// */
// public static Pair<Double,double[][][]>
// computeLabeledMultiRoot(double[][][] logPotentials)
// {
// int n = logPotentials.length;
// int l = logPotentials[0][0].length;
// double[][] collapsedLogPotentials = new double[n][n];
// for (int i = 0; i < n; i++) {
// for (int j = 0; j < n; j++) {
// collapsedLogPotentials[i][j] = SloppyMath.logAdd(logPotentials[i][j]);
// }
// }
// Pair<Double,double[][]> result = computeMultiRoot(collapsedLogPotentials);
// double sumTrees = result.getFirst();
// double[][] collapsedPosteriors = result.getSecond();
// double[][][] posteriors = new double[n][n][l];
// for (int i = 0; i < n; i++) {
// for (int j = 0; j < n; j++) {
// double post = collapsedPosteriors[i][j];
// double attachSum = collapsedLogPotentials[i][j];
// for (int k = 0; k < l; k++) {
// double labelProb = Math.exp(logPotentials[i][j][k]-attachSum);
// posteriors[i][j][k] = labelProb * post;
// }
// }
// }
// return Pair.newPair(sumTrees,posteriors);
// }
//
// /**
// * logPotentials[i][j] is the logPotential of attaching (i,j) where
// * i \neq j. When i==j, this represents the root potentials. Note
// * that this version allows multiple roots so it's not suitable
// * for dependency parsing.
// *
// * Returns sum of weighted trees and posteriors over attachments
// * again root posteriors are stored on the diagonal
// * @param logPotentials
// * @return
// */
// public static Pair<Double,double[][]> computeMultiRoot(double[][] logPotentials)
// {
// int n = logPotentials.length;
// double[][] potentials = new double[n][];
//// double max = Double.NEGATIVE_INFINITY;
//// for (int i = 0; i < n; i++) {
//// for (int j = 0; j < n; j++) {
//// if (logPotentials[i][j] < Double.POSITIVE_INFINITY) {
//// max = Math.max(logPotentials[i][j],max);
//// }
//// }
//// }
//// for (int i = 0; i < n; i++) {
//// for (int j = 0; j < n; j++) {
//// logPotentials[i][j] -= max;
//// }
//// }
// for (int i = 0; i < n; i++) {
// potentials[i] = DoubleArrays.exponentiate(logPotentials[i]);
// DoubleArrays.checkValid(potentials[i]);
// DoubleArrays.checkNonNegative(potentials[i]);
// }
// double[][] laplacian = new double[n][n];
// for (int j = 0; j < n; j++) {
// double sum = 0.0;
// for (int i = 0; i < n; i++) {
// sum += potentials[i][j];
// }
// for (int i = 0; i < n; i++) {
// laplacian[i][j] = i == j ? sum : -potentials[i][j];
// }
// }
// DoubleArrays.checkValid(laplacian);
// Matrix L = new Matrix(laplacian);
// SingularValueDecomposition svd = new SingularValueDecomposition(L);
// Matrix U = svd.getU();
// Matrix Sigma = svd.getS();
// for (int i = 0; i < n; i++) {
// double s= Sigma.get(i,i);
// Sigma.set(i,i, s > 0.0 ? 1.0/s : s);
// }
// Matrix V = svd.getV();
// Matrix Linv = V.times(Sigma).times(U.transpose());
// EigenvalueDecomposition evd = L.eig();
// //Matrix Linv = L.inverse();
// double[][] posteriors = new double[n][n];
// for (int i = 0; i < n; i++) {
// for (int j = 0; j < n; j++) {
// if (i == j) {
// // Root Posterior
// posteriors[i][j] = potentials[i][i] * Linv.get(i,i);
// } else {
// // Non-root Posterior
// posteriors[i][j] = potentials[i][j] * (Linv.get(j,j) - Linv.get(j,i));
// }
// if (posteriors[i][j] < -1.0e-10) {
// throw new RuntimeException("Error in Matrix-Tree Posteriors");
// }
// posteriors[i][j] = Math.max(posteriors[i][j],1.0e-10);
// }
// }
// DoubleArrays.checkValid(posteriors);
// double logSumTree = 0.0;
// for (double ev : evd.getRealEigenvalues()) {
// logSumTree += Math.log(ev);
// }
// return Pair.makePair(logSumTree,posteriors);
// }
//
// public static void main(String[] args)
// {
// int n = 3;
// int l = 2;
// double[][] potentials = new double[n][n];
// for (double[] row: potentials) {
// Arrays.fill(row,Double.NEGATIVE_INFINITY);
// }
// for (int i=0; i < n; ++i) potentials[i][i] = 0.0;
// for (int i = 0; i+1 < n; i++) {
// potentials[i][i+1] = 0.0;
// }
// Pair<Double,double[][]> res = computeMultiRoot(potentials);
// System.out.println("sumTrees: " + Math.exp(res.getFirst()));
// }
//}