/*1:*/
#line 48 "./t_container.hweb"

#ifndef T_CONTAINER_H
#define T_CONTAINER_H

#include "symmetry.h"
#include "gs_tensor.h"
#include "tl_exception.h"
#include "tl_static.h"
#include "sparse_tensor.h"
#include "equivalence.h"
#include "rfs_tensor.h"
#include "Vector.h"

#include <map> 
#include <string> 
#include <sstream> 

#include <matio.h> 

/*2:*/
#line 75 "./t_container.hweb"

struct ltsym{
bool operator()(const Symmetry&s1,const Symmetry&s2)const
{return s1<s2;}
};

/*:2*/
#line 67 "./t_container.hweb"
;
/*3:*/
#line 101 "./t_container.hweb"

template<class _Ttype> class TensorContainer{
protected:
typedef const _Ttype*_const_ptr;
typedef _Ttype*_ptr;
typedef map<Symmetry,_ptr,ltsym> _Map;
typedef typename _Map::value_type _mvtype;
public:
typedef typename _Map::iterator iterator;
typedef typename _Map::const_iterator const_iterator;
private:
int n;
_Map m;
protected:
const EquivalenceBundle&ebundle;
public:
TensorContainer(int nn)
:n(nn),ebundle(*(tls.ebundle)){}
/*5:*/
#line 155 "./t_container.hweb"

TensorContainer(const TensorContainer<_Ttype> &c)
:n(c.n),m(),ebundle(c.ebundle)
{
for(const_iterator it= c.m.begin();it!=c.m.end();++it){
_Ttype*ten= new _Ttype(*((*it).second));
insert(ten);
}
}

/*:5*/
#line 119 "./t_container.hweb"
;
/*6:*/
#line 168 "./t_container.hweb"

TensorContainer(int first_row,int num,TensorContainer<_Ttype> &c)
:n(c.n),ebundle(*(tls.ebundle))
{
for(iterator it= c.m.begin();it!=c.m.end();++it){
_Ttype*t= new _Ttype(first_row,num,*((*it).second));
insert(t);
}
}


/*:6*/
#line 120 "./t_container.hweb"
;
/*7:*/
#line 180 "./t_container.hweb"

_const_ptr get(const Symmetry&s)const
{
TL_RAISE_IF(s.num()!=num(),
"Incompatible symmetry lookup in TensorContainer::get");
const_iterator it= m.find(s);
if(it==m.end()){
TL_RAISE("Symmetry not found in TensorContainer::get");
return NULL;
}else{
return(*it).second;
}
}


_ptr get(const Symmetry&s)
{
TL_RAISE_IF(s.num()!=num(),
"Incompatible symmetry lookup in TensorContainer::get");
iterator it= m.find(s);
if(it==m.end()){
TL_RAISE("Symmetry not found in TensorContainer::get");
return NULL;
}else{
return(*it).second;
}
}

/*:7*/
#line 121 "./t_container.hweb"
;
/*8:*/
#line 209 "./t_container.hweb"

bool check(const Symmetry&s)const
{
TL_RAISE_IF(s.num()!=num(),
"Incompatible symmetry lookup in TensorContainer::check");
const_iterator it= m.find(s);
return it!=m.end();
}

/*:8*/
#line 122 "./t_container.hweb"
;
/*9:*/
#line 219 "./t_container.hweb"

void insert(_ptr t)
{
TL_RAISE_IF(t->getSym().num()!=num(),
"Incompatible symmetry insertion in TensorContainer::insert");
TL_RAISE_IF(check(t->getSym()),
"Tensor already in container in TensorContainer::insert");
m.insert(_mvtype(t->getSym(),t));
if(!t->isFinite()){
throw TLException(__FILE__,__LINE__,"NaN or Inf asserted in TensorContainer::insert");
}
}

/*:9*/
#line 123 "./t_container.hweb"
;
/*10:*/
#line 233 "./t_container.hweb"

void remove(const Symmetry&s)
{
iterator it= m.find(s);
if(it!=m.end()){
_ptr t= (*it).second;
m.erase(it);
delete t;
}
}


/*:10*/
#line 124 "./t_container.hweb"
;
/*11:*/
#line 246 "./t_container.hweb"

void clear()
{
while(!m.empty()){
delete(*(m.begin())).second;
m.erase(m.begin());
}
}

/*:11*/
#line 125 "./t_container.hweb"
;
/*16:*/
#line 318 "./t_container.hweb"

vector<_const_ptr> 
fetchTensors(const Symmetry&rsym,const Equivalence&e)const
{
vector<_const_ptr> res(e.numClasses());
int i= 0;
for(Equivalence::const_seqit it= e.begin();
it!=e.end();++it,i++){
Symmetry s(rsym,*it);
res[i]= get(s);
}
return res;
}

/*:16*/
#line 126 "./t_container.hweb"
;
/*12:*/
#line 256 "./t_container.hweb"

int getMaxDim()const
{
int res= -1;
for(const_iterator run= m.begin();run!=m.end();++run){
int dim= (*run).first.dimen();
if(dim> res)
res= dim;
}
return res;
}


/*:12*/
#line 127 "./t_container.hweb"
;
/*13:*/
#line 270 "./t_container.hweb"

void print()const
{
printf("Tensor container: nvars=%d, tensors=%D\n",n,m.size());
for(const_iterator it= m.begin();it!=m.end();++it){
printf("Symmetry: ");
(*it).first.print();
((*it).second)->print();
}
}

/*:13*/
#line 128 "./t_container.hweb"
;
/*14:*/
#line 282 "./t_container.hweb"

void writeMat(mat_t*fd,const char*prefix)const
{
for(const_iterator it= begin();it!=end();++it){
char lname[100];
sprintf(lname,"%s_g",prefix);
const Symmetry&sym= (*it).first;
for(int i= 0;i<sym.num();i++){
char tmp[10];
sprintf(tmp,"_%d",sym[i]);
strcat(lname,tmp);
}
ConstTwoDMatrix m(*((*it).second));
m.writeMat(fd,lname);
}
}

/*:14*/
#line 129 "./t_container.hweb"
;
/*15:*/
#line 300 "./t_container.hweb"

void writeMMap(map<string,ConstTwoDMatrix> &mm,const string&prefix)const
{
ostringstream lname;
for(const_iterator it= begin();it!=end();++it){
lname.str(prefix);
lname<<"_g";
const Symmetry&sym= (*it).first;
for(int i= 0;i<sym.num();i++)
lname<<"_"<<sym[i];
mm.insert(make_pair(lname.str(),ConstTwoDMatrix(*((*it).second))));
}
}

/*:15*/
#line 130 "./t_container.hweb"
;

virtual~TensorContainer()
{clear();}

/*4:*/
#line 139 "./t_container.hweb"

int num()const
{return n;}
const EquivalenceBundle&getEqBundle()const
{return ebundle;}

const_iterator begin()const
{return m.begin();}
const_iterator end()const
{return m.end();}
iterator begin()
{return m.begin();}
iterator end()
{return m.end();}

/*:4*/
#line 135 "./t_container.hweb"
;
};

/*:3*/
#line 68 "./t_container.hweb"
;
/*17:*/
#line 334 "./t_container.hweb"

class FGSContainer;
class UGSContainer:public TensorContainer<UGSTensor> {
public:
UGSContainer(int nn)
:TensorContainer<UGSTensor> (nn){}
UGSContainer(const UGSContainer&uc)
:TensorContainer<UGSTensor> (uc){}
UGSContainer(const FGSContainer&c);
void multAndAdd(const UGSTensor&t,UGSTensor&out)const;
};


/*:17*/
#line 69 "./t_container.hweb"
;
/*18:*/
#line 361 "./t_container.hweb"

class FGSContainer:public TensorContainer<FGSTensor> {
static const int num_one_time;
public:
FGSContainer(int nn)
:TensorContainer<FGSTensor> (nn){}
FGSContainer(const FGSContainer&fc)
:TensorContainer<FGSTensor> (fc){}
FGSContainer(const UGSContainer&c);
void multAndAdd(const FGSTensor&t,FGSTensor&out)const;
void multAndAdd(const UGSTensor&t,FGSTensor&out)const;
private:
static Tensor::index
getIndices(int num,vector<IntSequence> &out,
const Tensor::index&start,
const Tensor::index&end);
};


/*:18*/
#line 70 "./t_container.hweb"
;

#endif

/*:1*/
