/*
    Copyright (C) 2012 Bartosz Broda, Jacek Bochenek, Łukasz Biłeńkij, 
    Damian Jaworski, Wojciech Mazur, Dominik Piasecki, Maciej Piasecki, 
    Radosław Ramocki
    
    This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the Free
Software Foundation; either version 3 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 LICENSE and COPYING files for more details.
*/

/*
 * vector_definitions.cpp
 *
 *  Created on: Apr 19, 2009
 *      Author: boban
 */

#include "vector_definitions.h"

#include <boost/foreach.hpp>
#define foreach         BOOST_FOREACH

using namespace boost::numeric::ublas;

/////////////////////// base vector /////////////////////

BaseVector::~BaseVector() {
	// nothing
}

void BaseVector::Weight() {
	double len = Length();
	DivByValue(len);
}
/////////////////////// map vector /////////////////////
void MapVector::SetValues(std::map<size_t, double> & vals) {
	values = vals;
}
double MapVector::Length() {
	double len = 0.0;
	for (std::map<size_t, double>::iterator iter = values.begin(); iter != values.end(); iter++)
		len += (iter->second) * (iter->second);

	return sqrt(len);
}
void MapVector::DivByValue(double val) {
	for (std::map<size_t, double>::iterator iter = values.begin(); iter != values.end(); iter++)
		iter->second /= val;

}
double MapVector::Cosine(BaseVector* other) {
	MapVector * other_cast = (MapVector*) other;
	std::map<size_t, double> &other_vals = other_cast->values;
	double len1 = Length();
	double len2 = other_cast->Length();
	if (len1 == 0 || len2 == 0)
		return 0;
	/*
	 double scalar = 0.0;
	 for(std::map<size_t, double>::iterator iter = values.begin(); iter != values.end(); iter++)
	 {
	 std::map<size_t, double>::iterator find_other = other_vals.find(iter->first);
	 if( find_other != other_vals.end() )
	 scalar += (iter->second) * (find_other->second);
	 }*/

	std::map<size_t, double>::iterator i1 = values.begin(), i2 = other_vals.begin(), last1 = values.end(), last2 =
			other_vals.end();

	double scalar = 0.0;
	while (i1 != last1 && i2 != last2) {
		size_t index1 = i1->first;
		size_t index2 = i2->first;
		if (index1 == index2) {
			scalar += (i1->second) * (i2->second);
			i1++;
			i2++;
			continue;
		}

		if (index1 < index2)
			i1++;
		else
			i2++;
	}
	return scalar / (len1 * len2);
}

void MapVector::Print() {
	for (std::map<size_t, double>::iterator iter = values.begin(); iter != values.end(); iter++)
		std::cout << "(" << iter->first << ", " << iter->second << ") ";
	std::cout << std::endl;
}

/////////////////////// double array vector /////////////////////
DoubleArrayVector::DoubleArrayVector() {
	m_pValues = NULL;
	m_pIndices = NULL;
	m_stArraysLength = 0;
}

DoubleArrayVector::~DoubleArrayVector() {
	if (m_pValues) {
		delete[] m_pValues;
		m_pValues = NULL;
	}
	if (m_pIndices) {
		delete[] m_pIndices;
		m_pIndices = NULL;
	}
	m_stArraysLength = 0;
}

void DoubleArrayVector::SetValues(std::map<size_t, double> & vals) {
	m_stArraysLength = vals.size();
	m_pValues = new double[m_stArraysLength];
	m_pIndices = new size_t[m_stArraysLength];
	size_t id = 0;
	for (std::map<size_t, double>::iterator iter = vals.begin(); iter != vals.end(); iter++) {
		m_pValues[id] = iter->second;
		m_pIndices[id] = iter->first;
		id++;
	}
}

double DoubleArrayVector::Length() {
	double len = 0.0;
	for (size_t i = 0; i < m_stArraysLength; i++)
		len += m_pValues[i] * m_pValues[i];
	return sqrt(len);
}

void DoubleArrayVector::DivByValue(double val) {
	for (size_t i = 0; i < m_stArraysLength; i++)
		m_pValues[i] /= val;
}

double DoubleArrayVector::Cosine(BaseVector* other) {
	DoubleArrayVector * other_cast = (DoubleArrayVector*) other;
	double * other_vals = other_cast->m_pValues;
	size_t * other_indices = other_cast->m_pIndices;
	double len1 = Length();
	double len2 = other_cast->Length();

	if (len1 == 0 || len2 == 0)
		return 0;

	double scalar = 0.0;
	size_t i1 = 0, i2 = 0, last1 = m_stArraysLength, last2 = other_cast->m_stArraysLength;

	while (i1 != last1 && i2 != last2) {
		size_t index1 = m_pIndices[i1];
		size_t index2 = other_indices[i2];
		if (index1 == index2) {
			scalar += m_pValues[i1] * other_vals[i2];
			i1++;
			i2++;
			continue;
		}

		if (index1 < index2)
			i1++;
		else
			i2++;
	}

	return scalar / (len1 * len2);
}

void DoubleArrayVector::Print() {
	for (size_t i = 0; i < m_stArraysLength; i++)
		std::cout << "(" << m_pIndices[i] << ", " << m_pValues[i] << ") ";
	std::cout << std::endl;
}

///////////////////BoostMappedVector///////////////////////////////

template<class T>
void BoostMappedVector<T>::SetValues(std::map<size_t, double> & vals) {
	//vector.resize(vals.size());
	if (vals.size() == 0)
		return;
	//std::cout << "SIZE: " << vals.rbegin()->first +1 << ", " << vector.size()<< std::endl;
	//vector.resize(vals.rbegin()->first + 1);
	vector = mapped_vector<double, T>(vals.rbegin()->first + 1, vals.size());
	//std::cout << "SIZE: " << vals.rbegin()->first +1 << ", " << vector.size()<< std::endl;
	for (std::map<size_t, double>::iterator iter = vals.begin(); iter != vals.end(); iter++) {
		//std::cout << iter->first << std::endl;
		vector[iter->first] = iter->second;
	}
}

template<class T>
double BoostMappedVector<T>::Length() {
	double len = 0;
	BOOST_FOREACH (double d, vector)
		len	+= d*d;

	return sqrt(len);
}

template<class T>
void BoostMappedVector<T>::DivByValue(double val) {
	vector /= val;
}

template<class T>
double BoostMappedVector<T>::Cosine(BaseVector* other) {
	BoostMappedVector *v2 = (BoostMappedVector*) other;
	double len1 = Length();
	double len2 = v2->Length();

	if (len1 == 0 || len2 == 0)
		return 0;

	typename mapped_vector<double, T>::const_iterator i1 = vector.begin(), i2 = v2->vector.begin(), last1 = vector.end(), last2 =
			v2->vector.end();

	double scalar = 0.0;
	while (i1 != last1 && i2 != last2) {
		size_t index1 = i1.index();
		size_t index2 = i2.index();
		if (index1 == index2) {
			scalar += (*i1) * (*i2);
			i1++;
			i2++;
			continue;
		}

		if (index1 < index2)
			i1++;
		else
			i2++;
	}

	return scalar / (len1 * len2);
}
template<class T>
void BoostMappedVector<T>::Print() {
	for (typename mapped_vector<double, T>::iterator iter = vector.begin(); iter != vector.end(); iter++)
		std::cout << "(" << iter.index() << ", " << *iter << ") ";
	std::cout << std::endl;
}

template class BoostMappedVector<map_array<size_t, double> > ;
template class BoostMappedVector<map_std<size_t, double> > ;

///////////////////BoostCompressedVector////////////////////////////////

void BoostCompressedVector::SetValues(std::map<size_t, double> & vals) {
	//vector = compressed_vector<double>(vals.rbegin()->first, vals.size());
	if (vals.size() == 0)
		return;
	//vector.resize(vals.rbegin()->first + 1);
	vector = compressed_vector<double>(vals.rbegin()->first + 1, vals.size());
	//std::cout << "SIZE: " << vals.rbegin()->first +1 << ", " << vector.size()<< std::endl;
	for (std::map<size_t, double>::iterator iter = vals.begin(); iter != vals.end(); iter++) {
		//std::cout << iter->first << std::endl;
		vector[iter->first] = iter->second;
	}

	//vector[iter->first] = iter->second;
}

double BoostCompressedVector::Length() {
	double len = 0;
	BOOST_FOREACH (double d, vector)
		len += d*d;

	return sqrt(len);
}

void BoostCompressedVector::DivByValue(double val) {
	vector /= val;
}

double BoostCompressedVector::Cosine(BaseVector* other) {
	BoostCompressedVector *v2 = (BoostCompressedVector*) other;
	double len1 = Length();
	double len2 = v2->Length();

	if (len1 == 0 || len2 == 0)
		return 0;

	compressed_vector<double>::const_iterator i1 = vector.begin(), i2 = v2->vector.begin(), last1 = vector.end(), last2 =
			v2->vector.end();

	double scalar = 0.0;
	while (i1 != last1 && i2 != last2) {
		size_t index1 = i1.index();
		size_t index2 = i2.index();
		if (index1 == index2) {
			scalar += (*i1) * (*i2);
			i1++;
			i2++;
			continue;
		}

		if (index1 < index2)
			i1++;
		else
			i2++;
	}

	return scalar / (len1 * len2);
}

void BoostCompressedVector::Print() {
	std::cout << vector.size() << std::endl;
	for (compressed_vector<double>::iterator iter = vector.begin(); iter != vector.end(); iter++)
		std::cout << "(" << iter.index() << ", " << *iter << ") ";
	std::cout << std::endl;
}

