/* KFNN的消融对象  只保留标记分布增强  不要K值寻优
 * */
package ceka.KFNN;

import ceka.core.Dataset;
import ceka.core.Example;
import ceka.core.Label;
import ceka.core.MultiNoisyLabelSet;
import weka.core.Utils;

public class KFNN_noKF {

	public static final String NAME = "G";
	
	private int numExample = 0;
	private int numCategory = 0;
	
	public void doInference(Dataset dataset) throws Exception {
		// 先定义几个变量
		numCategory = dataset.getCategorySize();
		numExample = dataset.getExampleSize();
		
		double[][] probs = new double[numExample][numCategory];
		double[] count = new double[numCategory];
		for(int i=0; i<numExample; i++) {
			// 计算概率分布
			MultiNoisyLabelSet multipleNoisyLabelSet = dataset.getExampleByIndex(i).getMultipleNoisyLabelSet(0);
			int labelSize = multipleNoisyLabelSet.getLabelSetSize();
			for(int k=0; k<labelSize; k++) {
				probs[i][multipleNoisyLabelSet.getLabel(k).getValue()] += 1.0 / labelSize;
			}
			int tempIndex = Utils.maxIndex(probs[i]);
			count[tempIndex] += 1;
			Label label = new Label(null, String.valueOf(tempIndex), dataset.getExampleByIndex(i).getId(), NAME);
			dataset.getExampleByIndex(i).setIntegratedLabel(label);
		}
		
		// 稳定性设置，防止数据集太不平衡或者出现为0类别
		boolean mark = false;
		
		if(count[Utils.minIndex(count)] < 10) {
			mark = true;
		}
		
		// 划分簇
		Dataset[] subDatasets = new Dataset[numCategory];
		for(int k=0; k<numCategory; k++) {
			subDatasets[k] = new Dataset(dataset,0);
		}
		for(int i=0; i<dataset.getExampleSize(); i++) {
			int label = dataset.getExampleByIndex(i).getIntegratedLabel().getValue();
			subDatasets[label].addExample(dataset.getExampleByIndex(i));
		}
		
		// 构建马氏距离的计算方案
		Mdistance[] tempMdistances = new Mdistance[numCategory];
		for(int k=0; k<numCategory; k++) {
			tempMdistances[k] = new Mdistance(subDatasets[k]);
		}
		
		// 计算概率
		double[][] distances = new double[numExample][numExample];
		double[][] tempDis = new double[numExample][numCategory];
		double[][] probs2 = new double[numExample][numCategory];
		for(int i=0; i<numExample; i++) {
			Example e1 = dataset.getExampleByIndex(i);
			// 先求实例到各个分布的距离
			double tempMin = Double.MAX_VALUE;
			double tempMax = Double.MIN_VALUE;
			for(int k=0; k<numCategory; k++) {
				if(subDatasets[k].getExampleSize() > 0) {
					tempDis[i][k] = tempMdistances[k].calMDistance(e1);
					if(tempDis[i][k] > tempMax)
						tempMax = tempDis[i][k];
					if(tempDis[i][k] < tempMin)
						tempMin = tempDis[i][k];
				}
				else
					tempDis[i][k] = 0;
			}
			for(int k=0; k<numCategory; k++) {
				if(tempDis[i][k] > 0)
					probs2[i][k] = (tempMax - tempDis[i][k]) / (tempMax - tempMin);
				else
					tempDis[i][k] = Double.MAX_VALUE;
			}
			
			for(int j=i+1; j<numExample; j++) {
				Example e2 = dataset.getExampleByIndex(j);
				double temp = 0;
				for(int k=0; k<numCategory; k++) {
					temp += tempMdistances[k].calMDistance(e1, e2);
				}
				distances[i][j] = temp;
				distances[j][i] = temp;
			}
		}
		
		// 标记增强
		if(!mark) {
			for(int i=0; i<numExample; i++) {
				for(int k=0; k<numCategory; k++) {
					probs[i][k] += probs2[i][k];
				}
				Utils.normalize(probs[i]);
			}
		}
				
		// 推断
		for(int i=0; i<numExample; i++) {
			Example example = dataset.getExampleByIndex(i);
			
			Label integratedL = new Label(null, String.valueOf(Utils.maxIndex(probs[i])), example.getId(), NAME);
			example.setIntegratedLabel(integratedL);
		}

		// this is important
		dataset.assignIntegeratedLabel2WekaInstanceClassValue();
	}
}
