/*---------------------------------------------------------------------------*
*                                   IT++			             *
*---------------------------------------------------------------------------*
* Copyright (c) 1995-2004 by Tony Ottosson, Thomas Eriksson, Pål Frenger,   *
* Tobias Ringström, and Jonas Samuelsson.                                   *
*                                                                           *
* Permission to use, copy, modify, and distribute this software and its     *
* documentation under the terms of the GNU General Public License is hereby *
* granted. No representations are made about the suitability of this        *
* software for any purpose. It is provided "as is" without expressed or     *
* implied warranty. See the GNU General Public License for more details.    *
*---------------------------------------------------------------------------*/

/*! 
\file 
\brief Vector quantizer class (unconstrained)
\author Thomas Eriksson

1.14

2004/09/29 12:28:06
*/

#include "srccode/vq.h"
#include "base/matfunc.h"
#include <fstream>
#include <string>

using std::ifstream;
using std::ofstream;
using std::cout;
using std::endl;

namespace itpp {

//--------------------------------------------------------------------
//    class VQ
//--------------------------------------------------------------------

VQ::VQ() : CodeBook()
{
	LatestDist=0;
	Size=0;
	Dim=0;
}

VQ::VQ(const char *Name) : CodeBook()
{
	LatestDist=0;
	Size=0;
	Dim=0;
	load(Name);
}


int VQ::encode(const vec &x)
{
	int	i;
	double	S,MinS=1.0E30F;
	int	MinIndex=0;
	int	j,pos=0;
	double	a;

	for (i=0;i<Size;i++) {
		S=0;
		for (j=0;j<Dim;j++) {
			a=x._elem(j)-CodeBook._elem(pos+j);
			S+=a*a;
			if (S>=MinS) goto sune;
		}
		MinS=S;
		MinIndex=i;
sune:   pos+=Dim;
	}
	LatestDist=MinS;
	return MinIndex;
}

ivec VQ::encode(const vec &x, int num)
{
	double	S,a;
	vec		MinS(num);
	ivec	MinIndex(num);
	int	i,j,index,pos=0;

	MinS.clear();MinS+=1.0E30F;
	MinIndex.clear();
	for (i=0;i<Size;i++) {
		S=0;
		for (j=0;j<Dim;j++) {
			a=x._elem(j)-CodeBook._elem(pos+j);
			S+=a*a;
			if (S>=MinS[num-1]) goto sune;
		}
		for (index=num-2;(index>=0) && (S<MinS[index]);index--); 
		for (j=MinS.length()-2;j>index;j--) {
			MinS[j+1]=MinS[j];// memcpy, memmov
			MinIndex[j+1]=MinIndex[j];
		}
		MinS[index+1]=S;
		MinIndex[index+1]=i;
sune:   pos+=Dim;
	}
	LatestDist=MinS[0];
	return MinIndex;
}

Array<vec> VQ::decode(const ivec &Index) const
{
	Array<vec>	Temp(Index.length());

	for (int i=0;i<Temp.length();i++) {
		Temp(i)=get_codevector(Index(i));
	}
	return Temp;
}


#ifndef DOXYGEN_SHOULD_SKIP_THIS

ifstream &operator>>( ifstream &ifs, vec &v)
{
	int    i;
	char    str[2000];
	char    *ptr,*ptr_old;
	bool flag;
	if (length(v)!=0) {
		for (i=0;i<length(v);i++) {
			ifs.operator>>(v[i]) ;
		}
	} else {
		v.set_length(50);
		ifs.getline(str,2000);
		if (strlen(str)==0) ifs.getline(str,2000);
		i=0;
		v[i++]=atof(str);
		ptr=str;
		ptr_old=ptr;
		ptr=strchr(ptr,' ');
		while (ptr==ptr_old) {
			ptr++;
			ptr_old=ptr;
			ptr=strchr(ptr,' ');
		}
		while (ptr) {
			if (i>=v.length()) v.set_length(2*v.length(),true);
			v[i++]=atof(ptr);

			ptr_old=ptr;
			ptr=strchr(ptr,' ');
			while (ptr==ptr_old) {
				ptr++;
				ptr_old=ptr;
				ptr=strchr(ptr,' ');
			}
		}
		flag=true;
		flag=false;
		v.set_length(i,true);
	}
	return ifs;
}

#endif //DOXYGEN_SHOULD_SKIP_THIS

void VQ::load(const char *Name)
{
	mat			Temp;
	ifstream	CodeBookFile(Name);
	vec			v;
	int		n;

	it_error_if(!CodeBookFile,std::string("VQ::load : cannot open file ")+Name);
	cout << "Reading the codebook " << Name ; cout.flush() ;
	CodeBookFile >> v ;
	Temp.set_size(16,length(v));
	n=0;
	while (!CodeBookFile.eof()) {
		if (n>=Temp.rows()) Temp.set_size(2*Temp.rows(),Temp.cols(),true);
		Temp.set_row(n++,v);
		CodeBookFile >> v ;
	}
	Temp.set_size(n,Temp.cols(),true);
	set_codebook(Temp);
	cout << "  size:" << size() << "  dim:" << dim() << endl ;
}

void VQ::save(const char *Name) const
{
	ofstream	CodeBookFile(Name);

	cout << "Saving the codebook " << Name << endl ;
	for (int i=0;i<Size;i++) {
		vec v=CodeBook.mid(i*Dim,Dim);
		for (int j=0;j<v.length();j++) {
			CodeBookFile.operator<<(v[j]);
			if (j<v.length()-1) CodeBookFile.put(' ') ;
		}
		CodeBookFile << endl ;
	}
	CodeBookFile.close();
}

void VQ::modify_codevector(int no, double mul, const vec &add)
{
	int    pos=Dim*no;

	for (int i=0;i<Dim;i++) {
		CodeBook._elem(pos+i)*=mul;
		CodeBook._elem(pos+i)+=add[i];
	}	
}

vec VQ::get_codevector(int Index) const
{
	return CodeBook.mid(Index*Dim,Dim);
}

void VQ::set_codevector(int Index, const vec &v)
{
	it_error_if(Dim!=length(v),"VQ::set_codevector : Wrong dimension");
	for (int i=0;i<length(v);i++) {
		CodeBook._elem(Index*Dim+i)=v._elem(i);
	}
}

void VQ::set_codebook(const mat &CB)
{
	Size=CB.cols();
	Dim=CB.rows();
	CodeBook.set_length(Size*Dim);
	for (int i=0;i<Size;i++) {
		for (int j=0;j<Dim;j++) {
			CodeBook(i*Dim+j)=CB(j,i);
		}
	}
}

mat VQ::get_codebook() const
{
	mat	CB(Dim,Size);

	for (int i=0;i<Size;i++) {
		for (int j=0;i<Dim;i++) {
			CB(j,i)=CodeBook(i*Dim+j);
		}
	}
	return CB;
}

} //namespace itpp


syntax highlighted by Code2HTML, v. 0.9.1