
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <vector>
#include <math.h>
#include <float.h>
#include "defs.h"
#include "cover_tree.h"
#include "par_est.h"
#include "per_eval.h"
#include "svm.h"
#include "fast_lsvm.h"
#include "noise_reduction.h"



#define MAX_DISTS 70
NR::NR(struct lkm_parameter *par, struct problem *prob)
{
	this->par = par;
	this->prob = prob;

	parEst = new ParEst();
	coverTree = NULL;
}

NR::~NR()
{
	delete parEst;
	if( coverTree != NULL ) delete coverTree;
}


void NR::remove_noise()
{
	if( par->nr_strategy == LSVM_NR ) remove_noise_lsvm();
	if( par->nr_strategy == FALKNR ) remove_noise_falknr();
	if( par->nr_strategy == ENN ) remove_noise_enn();
	if( par->nr_strategy == ALLKNN ) remove_noise_aknn();

}

void NR::remove_noise_aknn()
{
	coverTree = new CoverTree(par->svm_par,par->base,false,0,par->silent);

	ct_prob = coverTree->addPoints(prob);

	int deleted = 0;
	bool *del = Malloc(bool,prob->l);

	for( int i = 0; i < ct_prob->l; i++ )
		{
			struct problem *p = coverTree->knn_p(ct_prob->x[i],par->k,true);
		del[i] = false;
		double tl = ct_prob->y[i];

		while( p->l > 0 )
			{
			if( !check_majority_rule(p,tl) )
				{
				del[i] = true;
				deleted++;
				break;
				}
			p->l--;
			}


		free(p);
		}
	
	print_tr(par->out_put_file,ct_prob,del);

	printf("deleted %d\n",deleted);

	free(del);
}



void NR::remove_noise_enn()
{
	coverTree = new CoverTree(par->svm_par,par->base,false,0,par->silent);

	ct_prob = coverTree->addPoints(prob);

	int deleted = 0;
	bool *del = Malloc(bool,prob->l);

	for( int i = 0; i < ct_prob->l; i++ )
		{
		struct problem *p = coverTree->knn_p(ct_prob->x[i],par->k,true);
 
		if( !check_majority_rule(p,ct_prob->y[i]) )
			{
			del[i] = true;
			deleted++;
			}
		else del[i] = false;

		free(p);
		}
	
	print_tr(par->out_put_file,ct_prob,del);

	printf("deleted %d\n",deleted);

	free(del);
}



bool NR::check_majority_rule(struct problem *p, double true_label )
{
	double *labels = Malloc(double,20);
	int *rep_labels = Malloc(int,20), n_labels = 0;
	bool ret = true;
	for( int i = 0; i < p->l; i++ )
		if( n_labels == 0 )
			{
			labels[0] = p->y[0];
			rep_labels[0] = 1;
			n_labels++;
			}
		else
			{
			double l =  p->y[i];
			int ind = -1;
			for( int j = 0; j < n_labels; j++ )
				if( labels[j] == l ) ind = j;
			if( ind >= 0 ) rep_labels[ind]++;
			else
				{	
				if( n_labels % 20 == 0 )
					{
					labels = Realloc(labels,double, n_labels + 20 );
					rep_labels = Realloc(rep_labels,int, n_labels + 20 );
					}
				labels[n_labels] = l;
				rep_labels[n_labels++] = 1;
				}
			}
	int max_rep = -1;
	for( int j = 0; j < n_labels; j++ )
		if( rep_labels[j] > max_rep )
			max_rep = rep_labels[j];


	if( !par->conservative_mr )
		{
		for( int j = 0; j < n_labels; j++ )
			if( rep_labels[j] == max_rep && labels[j] != true_label )
				{
				ret = false;
				break;
				}
		}
	else
		{
		bool br = false;
		for( int j = 0; j < n_labels; j++ )
			if( rep_labels[j] == max_rep && labels[j] == true_label )
				{
				br = true;
				break;
				}
		if( !br ) ret = false;
		}

	free(labels);
	free(rep_labels);

	return ret;

}


bool contains(int el, int *arr, int n)
{
	for( int i = 0; i < n; i++ )
		if( arr[i] == el )
			return true;
	return false;
}

void NR::remove_noise_falknr()
{
	int deleted = 0;
	sFastLSVM *flm = new sFastLSVM(par,prob);
	flm->train();

	bool *del = Malloc(bool,prob->l);
	for( int i = 0; i < prob->l; i++ )
		del[i] = false;

	CoverTree *ct = flm->get_cover_tree();

	struct problem **pbs = ct->get_trained_probs();
	struct svm_model **sms = ct->get_trained_models();

	int np = ct->get_n_local_probs();

	for( int i = 0; i < np; i++ )
		{
		struct svm_model *m = sms[i];
		struct problem *p = pbs[i];

		for( int j = 0; j < par->kp; j++ )
			{	
			struct node *nn = p->x[j];

			while( nn->index > 0 ) nn++;

			int ind = -nn->index;
			
			if( !del[ind] && p->y[j] != svm_predict(m,p->x[j]) )
				{
				deleted++;
				del[ind] = true;
				}
			}
		}


	printf("\nFaLKNR removed %d samples.\n",deleted);
	//print_tr_id(par->out_put_file,prob,del);
	print_tr(par->out_put_file,prob,del);

	free(del);
	delete flm;
}

void NR::remove_noise_lsvm()
{
	coverTree = new CoverTree(par->svm_par,par->base,false,0,par->silent);

	coverTree->setKs(par->k,1);
	ct_prob = coverTree->addPoints(prob);


	if( par->local_model_selection == LMS_INIT && ( par->svm_par->kernel_type == LINEAR ||  par->svm_par->kernel_type == RBF ) ) 
		{
		struct problem **nlp = NULL;
		nlp = coverTree->createNLocalProbs(par->n_loc_models,par->k,par->k/2,par->loc_prob_bil_th);
		
		
		if ( par->svm_par->kernel_type == LINEAR ) parEst->estC(nlp,par->n_loc_models,par,par->c_lms,par->n_c_lms,par->k/2,par->k);
		else parEst->estCG(nlp,par->n_loc_models,par,par->c_lms,par->n_c_lms,par->g_lms,par->n_g_lms,par->k/2,par->k);

		for( int i = 0; i < par->n_loc_models; i++ )
			free(nlp[i]);
		free(nlp);
		}

	double quant = -par->svm_par->gamma;
	int removed = 0;
	bool *del = Malloc(bool,ct_prob->l);
	for( int i = 0; i < ct_prob->l; i++ )
		{
		
		struct problem *lp = coverTree->knn_p(ct_prob->x[i],par->k,true);

		struct svm_parameter *parameter = copy_svm_parameter(par->svm_par);
		if( !par->silent)printf("train %d \t",i);
		if( par->svm_par->kernel_type == RBF && par->svm_par->gamma < 0.0 ) parameter->gamma = parEst->estG_quant(lp,quant);
		if( !par->silent)printf("%f %f\n",parameter->C,parameter->gamma);
		struct svm_model *m = svm_train(lp,parameter);
		double p = svm_predict(m,ct_prob->x[i]);
		del[i] = !( p == ct_prob->y[i]);
		if( del[i] ) 
			{
			if( !par->silent) printf("removed\n");
			removed++;
			}
		free(lp);
		svm_destroy_model(m);
		svm_destroy_param(parameter);
		}

	//delete pe;

	printf("\n%d samples removed\n",removed);
	print_tr_id(par->out_put_file,ct_prob,del);

	free(del);
}


void NR::print_tr(char *file_name,struct problem *p,bool *del)
{
	printf("%s\n",file_name);
	FILE *out = fopen(file_name,"w");
	for( int i = 0; i < p->l; i++ )
		if( !del[i] )
			{
			fprintf(out,"%f\t",p->y[i]);
			struct node *px = p->x[i];
			while( px->index > 0 )
				{
				fprintf(out,"%d:%g\t",px->index,px->value);
				++px;
				}
			fprintf(out,"#%d\t",px->index);
			fprintf(out,"\n");
			}

	fclose(out);
}


void NR::print_tr_id(char *file_name,struct problem *p,bool *del)
{
	printf("%s\n",file_name);
	FILE *out = fopen(file_name,"w");

	char ed_id_file[1024];

	sprintf(ed_id_file,"%s.id",file_name);

	FILE *out_ed = fopen(ed_id_file,"w");
	
	for( int i = 0; i < p->l; i++ )
		{
		if( !del[i] ) fprintf(out,"%f\t",p->y[i]);
		struct node *px = p->x[i];
		while( px->index > 0 )
			{
			if( !del[i] ) fprintf(out,"%d:%g\t",px->index,px->value);
			++px;
			}
		if( del[i] ) fprintf(out_ed,"1\n");
		else fprintf(out_ed,"0\n");
		if( !del[i] ) fprintf(out,"\n");
		}

	fclose(out);
	fclose(out_ed);

}



