/*
 *  Copyright 2006-2007 Columbia University.
 *
 *  This file is part of MEAPsoft.
 *
 *  MEAPsoft is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 *
 *  MEAPsoft is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with MEAPsoft; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 *  02110-1301 USA
 *
 *  See the file "COPYING" for the text of the license.
 */

package com.meapsoft.featextractors;

import java.util.Arrays;

import com.meapsoft.DSP;
import com.meapsoft.STFT;

/**
 * Computes the entropy of each chunk.
 *
 * @author Victor Adan (vga2102@columbia.edu)
 */

public class Entropy extends FeatureExtractor 
{
	
    public double[] features(STFT stft, long startFrame, int length) 
    {

        double[] currFrame;
        double[] workFrame;
        double dist;
        double[][] distMat = new double[length][length];
        double V;
        double px;
        double currFrameSum = 0;
        double[] entropy = new double[1];
		entropy[0] = 0;
        int k = (int)Math.round(Math.sqrt(length))+1;
		
		// normalization factor
		for (int frame=0; frame<length; frame++)
		{
			currFrame = stft.getFrame(startFrame+frame);
			// normalization factor currFrame
			currFrameSum += DSP.sum(currFrame)/length;
		}
        for(int frame=0; frame<length; frame++) 
        {
            currFrame = stft.getFrame(startFrame+frame) ;
			for(int w_frame=frame; w_frame<length; w_frame++) 
			{
					workFrame = stft.getFrame(startFrame+w_frame);
					dist = 0;
					// get distances
					for(int i=0; i< stft.getRows(); i++)
					{
						dist += Math.pow((currFrame[i]/currFrameSum - workFrame[i]/currFrameSum), 2 );
					}
					dist = Math.sqrt(dist) ;
					distMat[frame][w_frame] = dist;
					distMat[w_frame][frame] = dist;
			}
			Arrays.sort(distMat[frame]);
			if (distMat[frame][k] <	0.001)
			{
       			System.out.println("Found distance < 0.001");
				distMat[frame][k] = 	0.001;
			}
			//V = Math.pow(distances[k], stft.getRows());
			V = Math.pow(1000*distMat[frame][k], 3.);
			px = ((float)k/length) / V;
			entropy[0] += px * Math.log(1.0/px);
		}
		//System.out.println(entropy[0]);
        return entropy;
    }

	public String description()
	{
		return "Computes the entropy of each chunk.";
	}
}
