/**
* @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];
  }
}
