/** 
* @file FullVector.cpp
* @brief non sparse vector
* @author Erik Rodner
* @date 05/11/2008

*/
#include <math.h>
#include <assert.h>
#include <string.h>


#include <iostream>
#include <algorithm>
#include <limits>

#include "vislearning/math/mathbase/FullVector.h"

#include <stdio.h>

#include "core/basics/StringTools.h"

// whether to throw a exception when we divide by zero
#undef FULLVECTOR_THROW_NORMALIZATION_EXCEPTION

using namespace OBJREC;
using namespace NICE;
using namespace std;


FullVector::FullVector ( const map<int, double> & mymap )
{
    length = 0;
    for ( map<int, double>::const_iterator i = mymap.begin();
		i != mymap.end(); i++ )
    {
	int k = i->first;
	if ( k+1 > length )
	    length = k+1;
    }

    data = new double[length];
    memset ( (void *)data, 0, sizeof(double)*length );
  
    for ( map<int, double>::const_iterator i = mymap.begin();
		i != mymap.end(); i++ )
    {
	int k = i->first;
	double v = i->second;
	data[k] = v;
    }
 
}

FullVector::FullVector ( const map<short, double> & mymap )
{
	length = 0;
	for ( map<short, double>::const_iterator i = mymap.begin();
		     i != mymap.end(); i++ )
	{
		int k = (int)i->first;
		if ( k+1 > length )
			length = k+1;
	}

	data = new double[length];
	memset ( (void *)data, 0, sizeof(double)*length );
  
	for ( map<short, double>::const_iterator i = mymap.begin();
		     i != mymap.end(); i++ )
	{
		int k = i->first;
		double v = i->second;
		data[k] = v;
	}
 
}

FullVector::FullVector ( const FullVector & v )
{
    length = v.length;

	if ( length == 0 )
		data = NULL;
	else {
		data = new double[length];
		memset ( (void *)data, 0, sizeof(double)*length );

		for ( int i = 0 ; i < length ; i++ )
			data[i] = v.data[i];
	}
}

FullVector::FullVector ()
{
    length = 0;
    data = NULL;
}

FullVector::FullVector (int _length) 
{
    length = _length;
    if ( length > 0 )
    {
		data = new double[length];
		memset ( (void *)data, 0, sizeof(double)*length );
    } else {
		data = NULL;
    }
}

FullVector::~FullVector ()
{
    if ( data != NULL )
		delete [] data;
}

void FullVector::set ( double val ) 
{
    for ( int i = 0 ; i < length ; i++  )
		data[i] = val;
}

void FullVector::reinit ( int _length )
{
    if ( data != NULL ) {
		delete [] data;
    }
    length = _length;
    data = new double [ length ];
    memset ( (void *)data, 0, sizeof(double)*length );
}

void FullVector::add ( const FullVector & v )
{
    add ( v, 1.0 );
}

double & FullVector::operator[] (int i)
{
	assert ( i < length );
    	return data[i];
}

const double & FullVector::operator[] (int i) const
{
    assert ( i < length );
    return data[i];
}

void FullVector::add ( const FullVector & v, double lambda )
{
    assert ( v.length >= length );
    for ( int i = 0 ; i < v.length ; i++  )
	data[i] += v.data[i] * lambda;
}

void FullVector::add ( double beta )
{
    for ( int i = 0 ; i < length; i++ )
		data[i] += beta;
}

void FullVector::divide ( const FullVector & v )
{
    assert ( v.length >= length );
    for ( int i = 0 ; i < length ; i++ )
    {
		if ( fabs(data[i]) < 10e-11 ) continue;

		double value = v.data[i];
		if ( fabs(value) < 10e-11 ) {
			fprintf (stderr, "FullVector::divide: Division by Zero !\n");
			exit(-1);
		} else {
			data[i] /= value;
		}
    }
}

void FullVector::multiply ( const FullVector & v )
{
    assert ( v.length >= length );
    for ( int i = 0 ; i < length ; i++ )
    {
		data[i] *= v.data[i];
    }
}

void FullVector::multiply ( double val )
{
    for ( int i = 0 ; i < length ; i++ )
		data[i] *= val;
}

void FullVector::restore (istream & is, int format)
{
	std::string tag;
	is >> tag;
	if ( tag != "SVECTOR" ) {
		fprintf (stderr, "FullVector: format error !\n");
	}
    
	const int bufsize = 1024*1024;
	char *buf = new char[bufsize];
	std::string buf_s;

	vector<string> elements;
	vector<string> pair;
	
	elements.clear();
	
	is.get ( buf, bufsize );
	buf_s = buf;

	if ( buf_s.size() <= 0 ) 
		return;

	StringTools::split ( buf_s, ' ', elements );

	if ( elements.size() <= 1 )
		return;

	reinit(elements.size()-1);

	size_t l = 0;
	// skip first element because of white space
	for ( vector<string>::const_iterator i  = elements.begin()+1; 
						 i != elements.end();
						 i++, l++ )
	{
		pair.clear();
		StringTools::split ( *i, ':', pair );
		if ( pair.size() == 2 ) 
		{
			double val = atof ( pair[1].c_str() );
			(*this)[l] = val;
		}
	}

    delete [] buf;
}

void FullVector::store (ostream & os, int format) const
{
    os << "SVECTOR ";
    for ( int i = 0 ; i < length ; i++ )
    {
		os << i << ":" << data[i] << " ";
    }
    os << "END" << endl;
}

void FullVector::clear ()
{
    if ( length != 0 ) 
		memset ( data, 0x0, sizeof(double)*length );
}

double FullVector::sum () const
{
    double sumv = 0.0;
    for ( int i = 0 ; i < length ; i++ )
		sumv += data[i];

    return sumv;
}

void FullVector::normalize ()
{
    double sum = 0;
    for ( int i = 0 ; i < length ; i++ )
		sum += data[i];

#ifdef FULLVECTOR_THROW_NORMALIZATION_EXCEPTION
    assert ( fabs(sum) > 1e-10 );
#endif
    if ( fabs(sum) < 1e-10 ) {
		//fprintf (stderr, "WARNING: normalization failed !\n");
		for ( int i = 0 ; i < length ; i++ )
			data[i] = 0.0;

    } else {
		for ( int i = 0 ; i < length ; i++ )
			data[i] /= sum;
    }
}

void FullVector::addMap ( const map<int, int> & v, double lambda )
{
    for ( map<int, int>::const_iterator v_it = v.begin();
				       v_it != v.end();
				       v_it++ )
    {
		int i = v_it->first;
		assert ( i < length );
		data[i] += v_it->second * lambda;
    }
}

void FullVector::addMap ( const map<int, double> & v, double lambda )
{
    for ( map<int, double>::const_iterator v_it = v.begin();
				       v_it != v.end();
				       v_it++ )
    {
		int i = v_it->first;
		assert ( i < length );
		data[i] += v_it->second * lambda;
    }
}

int FullVector::maxElement () const
{
    int maxindex = 0;
    double max = - numeric_limits<double>::max();
    for ( int i = 0 ; i < length ; i++ )
    {
		if ( data[i] > max )
		{
			maxindex = i;
			max = data[i];
		}
    }
    return maxindex;
}

int FullVector::maxElementExclusive ( int key ) const
{
    int maxindex = (key == 0) ? 1 : 0;
    double max = - numeric_limits<double>::max();
    for ( int i = 0 ; i < length ; i++ )
    {
		double val = data[i];
		if ( (i != key) && (val > max) )
		{
			maxindex = i;
			max = val;
		}
    }
    return maxindex;
}

double FullVector::entropy () const
{
    double entropy = 0.0;
    double sum = 0.0;
    for ( int i = 0 ; i < length ; i++ )
    {
		double val = data[i];
		if ( val <= 0.0 ) continue;
			entropy -= val*log(val);
		sum += val;
    }
    entropy /= sum;
    entropy += log(sum);
    return entropy;
}
	
void FullVector::getSortedIndices ( vector<int> & indizes ) const
{
    vector< pair<double, int> > tmp;
    for ( int i = 0 ; i < length ; i++ )
	if ( fabs(data[i]) > 10e-11 )
	    tmp.push_back ( pair<double, int> (  data[i], i  ) );

    sort ( tmp.begin(), tmp.end() );

    for ( vector<pair<double,int> >::const_iterator j = tmp.begin();
		j != tmp.end(); j++ )
	indizes.push_back ( j->second );
}
	
double FullVector::max () const
{
    double max = - numeric_limits<double>::max();
    for ( int i = 0 ; i < length ; i++ )
    {
		if ( data[i] > max )
			max = data[i];
    }
    return max;
}

double FullVector::min () const
{
    double min = numeric_limits<double>::max();
    for ( int i = 0 ; i < length ; i++ )
    {
		if ( data[i] < min )
			min = data[i];
    }
    return min;
}

double FullVector::get ( size_t i ) const
{
    assert ( (int)i < length );
    return data[i];
}
	
void FullVector::operator= ( const FullVector & v )
{
    if ( data != NULL )
		delete [] data;

    length = v.length;

	if ( length == 0 )
		data = NULL;
	else {
		data = new double[length];
		memset ( (void *)data, 0, sizeof(double)*length );

		for ( int i = 0 ; i < length ; i++ )
			data[i] = v.data[i];
	}
}