/*
 * MiningMart Version 1.0
 * 
 * Copyright (C) 2006 Martin Scholz, Timm Euler, 
 *                    Daniel Hakenjos, Katharina Morik
 *
 * Contact: miningmart@ls8.cs.uni-dortmund.de
 *
 * A list of contributing developers (other than the copyright 
 * holders) can be found at
 * http://mmart.cs.uni-dortmund.de/downloads/download.html
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program 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 this program, see the file MM_HOME/LICENSE; if not, write
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA 02110-1301, USA.
 */
package edu.udo.cs.miningmart.operator.uep;

import java.util.ArrayList;

import edu.udo.cs.miningmart.exception.M4CompilerError;
import edu.udo.cs.miningmart.exception.M4Exception;
import edu.udo.cs.miningmart.m4.BaseAttribute;
import edu.udo.cs.miningmart.m4.Column;
import edu.udo.cs.miningmart.m4.Feature;
import edu.udo.cs.miningmart.m4.Value;
import edu.udo.cs.miningmart.m4.utils.Print;

/**
 * <p>M4 Compiler</p>
 * <p>Copyright: Copyright (c) 2002</p>
 * <p>Company: University Dortmund</p>
 *
 * @author Felix Koschin
 * @version $Id: UepFeatureSelection.java,v 1.7 2006/04/11 14:10:18 euler Exp $
 */
public abstract class UepFeatureSelection extends edu.udo.cs.miningmart.operator.FeatureSelection
{
	protected Column theClassAttribute;
	String[] ClassAttrEl;
	
	public BaseAttribute getTheClassAttribute() throws M4CompilerError
	{
		return (BaseAttribute) this.getSingleParameter("TheClassAttribute");
	}

	public Value getNoOfAttributes() throws M4CompilerError
	{
		return (Value) this.getSingleParameter("NoOfAttributes");
	}

//	abstract public Feature[] computeListOfAttributes(Feature[] theSuperset) throws M4CompilerError;

	protected myData selectTheBestAttr(ArrayList selected, ArrayList removed) throws M4CompilerError
	{
		Feature[] tmpF = new Feature[selected.size() + 1];
		for (int i = 0; i < selected.size(); i++)
		{
			tmpF[i] = (Feature)selected.get(i);
		}
		
		double Max = -1;
		int MaxID = -1;
		for (int i = 0; i < removed.size(); i++)
		{
			tmpF[tmpF.length - 1] = (Feature)removed.get(i);
			double MI;
			MI = getMutualInforation(new myTable(this.getM4Db().getFrquencyTable(theClassAttribute, tmpF, ClassAttrEl)));
					
			if (MI > Max)
			{
				Max = MI;
				MaxID = i;
			}
		}
		return new myData(Max, MaxID);
	}

	protected myData selectTheWorstAttr(ArrayList selected) throws M4CompilerError
	{
		Feature[] tmpF = new Feature[selected.size() - 1];
		for (int i = 1; i < selected.size(); i++)
		{
			tmpF[i - 1] = (Feature)selected.get(i);
		}
			double Max = getMutualInforation(new myTable(this.getM4Db().getFrquencyTable(theClassAttribute, tmpF, ClassAttrEl)));
			int MaxID = 0;
			for (int i = 0; i < selected.size() - 1; i++)
			{	
				tmpF[i] = (Feature)selected.get(i);		
				double MI = getMutualInforation(new myTable(this.getM4Db().getFrquencyTable(theClassAttribute, tmpF, ClassAttrEl)));
				if (MI > Max)
				{
					Max = MI;
					MaxID = i + 1;
				}			
			}
			return new myData(Max, MaxID);
	}	
	
	protected double getMutualInforation(myTable tbl)
	{
		int rs = tbl.Rows();
		int cs = tbl.Columns();

		double x = 0;		
		for (int r = 0; r < rs - 1; r++)
			for (int c = 1; c < cs - 1; c++)
			{
				if (tbl.Cell(r, c) > 0)
				{
					double t1 = (tbl.Cell(r, c) / (double)tbl.Cell(rs - 1, cs - 1));
					double t2 = (tbl.Cell(rs - 1, cs - 1) * (double)tbl.Cell(r, c)) / ((double)tbl.Cell(r, cs - 1) * (double)tbl.Cell(rs - 1, c));
					double t3 = Math.log(t2);
					x = x + t1 * t3;
//*remove/					doPrint(100, t1 + " * log(" + t2 + ") = " + t1 + " * " + t3 + " = " + x);	
//					x = x + ((tbl.Cell(r, c) / tbl.Cell(rs - 1, cs - 1)) * Math.log((tbl.Cell(rs - 1, cs - 1) * tbl.Cell(r, c)) / (tbl.Cell(r, cs - 1) * tbl.Cell(rs - 1, c))));
//*remove*/			doPrint(100, "R" + r + "C" + c + ": " + x);
				}
//*remove*/				else
//*remove*/					doPrint(100, "R" + r + "C" + c + ": -");
			}
		return x;
	}
	
	protected class myTable
	{
		private ArrayList Rs = new ArrayList();
		private myColumn[] Cs;
		
		public myTable (long Columns)
		{
//			Rs = new myRows[rows];
			Cs = new myColumn[(int)Columns];
		}
		
		myTable (String[][] TableData)
		{
//*remove*/			doPrint(100, TableData[0][0].getValue());
//*remove*/			doPrint(100, "" + TableData.length);
//*remove*/			doPrint(100, "" + TableData[0].length);
			Cs = new myColumn[TableData[0].length - 1];
			for (int i = 0; i < TableData.length; i++)
			{
				long[] Vals = new long[TableData[0].length - 1];
				for (int n = 1; n < TableData[0].length; n++)
				{
					Vals[n - 1] = Long.parseLong(TableData[i][n]);
				}
				addRow(TableData[i][0], Vals);
			}
		}
		
		public boolean addRow(String Name, long[] Values)
		{
			if (Values.length == Cs.length)
			{
				myRow row = new myRow(Name, Values, Cs);
				Rs.add(row);
				for (int i = 0; i < Cs.length; i++)
				{
					myCell cell = row.cells[i];
					Cs[i] = new myColumn();
					Cs[i].cells.add(cell);
				}
				return true;
			}
			else
				return false;
		}
		
		public void print()
		{
			for (int i = 0; i < Rs.size(); i++)
			{
				myRow row = (myRow)Rs.get(i);
				String s = row.name;
				for (int n = 0; n < row.cells.length; n++)
				{
					s = s + "\t" + row.cells[n].value;
				}
				doPrint(Print.MAX, s);
			}
		}
		
		public int Rows()
		{
			return Rs.size();
		}
		
		public int Columns()
		{
			return Cs.length;
		}
				
		public long Cell(int Row, int Column)
		{
			return ((myRow)Rs.get(Row)).cells[Column].value;
		}		
		
		public long Cell(String Row, String Column)
		{
			int i = 0;
			myRow row = (myRow)Rs.get(i);
			while (!row.equals(Row))
			{
				row = (myRow)Rs.get(++i);
			}
			i = 0;
			while (!Cs[i].equals(Column))
			{
				i++;
			}
			return row.cells[i].value;
		}
		
		private class myCell
		{
			myRow row;
			myColumn col;
			long value;
		}

		private class myRow
		{
			myCell[] cells;
			String name;
			
			myRow (String Name, long[] Values, myColumn[] Cs)
			{
				name = Name;
				cells = new myCell[Values.length];
				for(int i = 0; i < Values.length; i++)
				{
					cells[i] = new myCell();
					cells[i].row = this;
					cells[i].col = Cs[i];
					cells[i].value = Values[i];
				}
			}			
		}
	
		private class myColumn
		{
			ArrayList cells = new ArrayList();
			String name;		
		}
	}
	
	protected class myData
	{
		public double MI;
		public int Index;
		
		public myData(double MutualInformation, int ID)
		{
			MI = MutualInformation;
			Index = ID;
		}		
	}
}
/*
 * $Log: UepFeatureSelection.java,v $
 * Revision 1.7  2006/04/11 14:10:18  euler
 * Updated license text.
 *
 * Revision 1.6  2006/04/06 16:31:17  euler
 * Prepended license remark.
 *
 * Revision 1.5  2006/03/30 16:07:14  scholz
 * fixed author tags for release
 *
 * Revision 1.4  2006/03/29 09:50:47  euler
 * Added installation robustness.
 *
 * Revision 1.3  2006/03/23 11:13:46  euler
 * Improved exception handling.
 *
 * Revision 1.2  2006/01/06 16:27:56  euler
 * Bugfixes
 *
 * Revision 1.1  2006/01/03 09:54:35  hakenjos
 * Initial version!
 *
 */
