// Copyright (C) 2010, Guy Barrand. All rights reserved. // See the file tools.license for terms. #ifndef tools_array #define tools_array #ifdef TOOLS_MEM #include "mem" #endif #include #include namespace tools { // array handles an hyperparallelepiped of cells of class T. template class array { public: static const std::string& s_class() { static const std::string s_v("tools::array"); return s_v; } public: typedef typename std::vector< std::pair > cut_t; typedef typename std::vector uints_t; typedef typename std::vector::iterator vec_it_t; typedef typename std::vector::const_iterator cons_vec_it_t; public: array() { #ifdef TOOLS_MEM mem::increment(s_class().c_str()); #endif } array(const uints_t& a_orders) { #ifdef TOOLS_MEM mem::increment(s_class().c_str()); #endif configure(a_orders); } array(unsigned int a_dimension,unsigned int a_order) { #ifdef TOOLS_MEM mem::increment(s_class().c_str()); #endif // A hypercube of dimension "a_dimension" and size "a_order". uints_t _orders(a_dimension); for(unsigned int index=0;index& vector() const { return m_vector;} std::vector& vector() { return m_vector;} bool fill(const std::vector& a_values,cut_t* a_cut = 0) { size_t dsize = a_values.size(); size_t di = 0; unsigned int index = 0; for(vec_it_t it=m_vector.begin();it!=m_vector.end();++it,index++) { if(!a_cut || (a_cut && accept(index,*a_cut)) ) { if(di>=dsize) return false; //a_values exhausted too early *it = a_values[di]; di++; } } return true; } bool fill(unsigned int a_sz,const T* a_data,cut_t* a_cut = 0) { unsigned int di = 0; unsigned int index = 0; for(vec_it_t it=m_vector.begin();it!=m_vector.end();++it,index++) { if(!a_cut || (a_cut && accept(index,*a_cut)) ) { if(di>=a_sz) return false; //a_values exhausted too early *it = a_data[di]; di++; } } return true; } // Related to other array : bool equal(const array& a_array) const { if(m_orders!=a_array.m_orders) return false; cons_vec_it_t it = m_vector.begin(); cons_vec_it_t ait = a_array.m_vector.begin(); for(;it!=m_vector.end();++it,++ait) { if((*it)!=(*ait)) return false; } return true; } bool equal(const array& a_array,T aEpsilon) const { if(m_orders!=a_array.m_orders) return false; cons_vec_it_t it = m_vector.begin(); cons_vec_it_t ait = a_array.m_vector.begin(); for(;it!=m_vector.end();++it,++ait) { T diff = (*it) - (*ait); if(diff<0) diff *= -1; if(diff>=aEpsilon) return false; } return true; } bool is_proportional(const array& a_array,T& a_factor) const { // If true, then : a_array = a_factor * this. a_factor = zero(); if(m_orders!=a_array.m_orders) return false; bool first = true; cons_vec_it_t it = m_vector.begin(); cons_vec_it_t ait = a_array.m_vector.begin(); for(;it!=m_vector.end();++it,++ait) { if( ((*it)==zero()) && ((*ait)==zero())) { continue; } else if( ((*it)!=zero()) && ((*ait)==zero())) { return false; } else if( ((*it)==zero()) && ((*ait)!=zero())) { return false; } else { if(first) { a_factor = (*ait)/(*it); first = false; } else { if((*ait)!=(*it)*a_factor) return false; } } } return true; } bool add(const array& a_array,cut_t* a_cut = 0) { if(m_orders!=a_array.m_orders) return false; vec_it_t it = m_vector.begin(); cons_vec_it_t ait = a_array.m_vector.begin(); unsigned int index = 0; for(;it!=m_vector.end();++it,++ait,index++) { if(!a_cut || (a_cut && accept(index,*a_cut)) ) { (*it) += (*ait); } } return true; } bool subtract(const array& a_array) { if(m_orders!=a_array.m_orders) return false; vec_it_t it = m_vector.begin(); cons_vec_it_t ait = a_array.m_vector.begin(); for(;it!=m_vector.end();++it,++ait) (*it) -= (*ait); return true; } bool multiply(const array& a_array) { if(m_orders!=a_array.m_orders) return false; vec_it_t it = m_vector.begin(); cons_vec_it_t ait = a_array.m_vector.begin(); for(;it!=m_vector.end();++it,++ait) (*it) *= (*ait); return true; } bool divide(const array& a_array) { if(m_orders!=a_array.m_orders) return false; bool status = true; vec_it_t it = m_vector.begin(); cons_vec_it_t ait = a_array.m_vector.begin(); for(;it!=m_vector.end();++it,++ait) { if((*ait)==zero()) { (*it) = zero(); //PAW convention. status = false; } else { (*it) /= (*ait); } } return status; } bool contract(const array& a_array,T& a_value) const { a_value = zero(); if(m_orders!=a_array.m_orders) return false; cons_vec_it_t it = m_vector.begin(); cons_vec_it_t ait = a_array.m_vector.begin(); for(;it!=m_vector.end();++it,++ait) a_value += (*it) * (*ait); return true; } //Else: void add(const T& a_T,cut_t* a_cut = 0) { unsigned int index = 0; for(vec_it_t it = m_vector.begin();it!=m_vector.end();++it,index++) { if(!a_cut || (a_cut && accept(index,*a_cut)) ) { (*it) += a_T; } } } void multiply(const T& a_T) { for(vec_it_t it = m_vector.begin();it!=m_vector.end();++it) (*it) *= a_T; } bool divide(const T& a_T) { if(a_T==zero()) return false; for(vec_it_t it = m_vector.begin();it!=m_vector.end();++it) (*it) /= a_T; return true; } bool invert() { bool status = true; T v_one = one(); for(vec_it_t it = m_vector.begin();it!=m_vector.end();++it) { if((*it)==zero()) { (*it) = zero(); //PAW convention. status = false; } else { T _value = (*it); (*it) = v_one/_value; } } return status; } bool offset(const uints_t& a_is,unsigned int& a_offset) const { size_t dim = m_orders.size(); a_offset = 0; if(a_is.size()!=dim) return false; if(dim==0) return false; for(size_t iaxis=0;iaxis=m_orders[iaxis]) { a_offset = 0; return false; } a_offset += i * m_offsets[iaxis]; } return true; } bool indices(unsigned int a_offset,uints_t& a_is) const { if(a_offset>=m_vector.size()) return false; size_t dim = m_orders.size(); unsigned int off = a_offset; for(int iaxis=int(dim)-1;iaxis>=0;iaxis--) { a_is[iaxis] = off/m_offsets[iaxis]; off -= a_is[iaxis] * m_offsets[iaxis]; } return true; } bool accept(unsigned int a_index,const cut_t& a_cut) const { size_t dim = m_orders.size(); if(a_cut.size()!=dim) return false; if(!indices(a_index,const_cast(m_is))) return false; bool good = true; for(size_t iaxis=0;iaxisa_cut[iaxis].second) {good = false;break;} } return good; } void set_constant(const T& a_v) { for(vec_it_t it = m_vector.begin();it!=m_vector.end();++it) (*it) = a_v; } void set_zero(){ set_constant(zero()); } public: static T zero() { //return (T)0; //return T(0); return T(); } static T one() { //return (T)1; return T(1); } static T minus_one() { //return (T)-1; return T(-1); } static T two() { //return (T)2; return T(2); } protected: uints_t m_orders; uints_t m_offsets; std::vector m_vector; uints_t m_is; }; } #include // Helpers array : namespace tools { template inline bool contract( const array& aA ,unsigned int aIA ,const array& aB ,unsigned int aIB ,array& aR ){ // Contract a tensor (aA) with a vector (aB) // on indice aIA of aA and aIB of aB. // aA.dimension must be > 1. // aB.dimension must be > 1. if(&aR==&aA) return false; if(&aR==&aB) return false; if(aA.dimension()==0) return false; if(aB.dimension()==0) return false; if(aIA>=aA.dimension()) return false; if(aIB>=aB.dimension()) return false; if(aA.orders()[aIA]!=aB.orders()[aIB]) return false; unsigned int rdima = aA.dimension()-1; unsigned int rdimb = aB.dimension()-1; if((rdima+rdimb)==0) { std::vector rorders(1); rorders[0] = 1; if(!aR.configure(rorders)) return false; const std::vector& vA = aA.vector(); const std::vector& vB = aB.vector(); T value = array::zero(); for(unsigned int index=0;index rorders(rdima+rdimb); unsigned int index; for(index=0;index ais(aA.dimension()); std::vector bis(aB.dimension()); std::vector ris(aR.dimension()); //FIXME : optimize the below. unsigned int order = aA.orders()[aIA]; unsigned int rsize = aR.size(); std::vector& rvec = aR.vector(); for(unsigned int roffset=0;roffset inline bool swap( const array& aV ,unsigned int aI1 ,unsigned int aI2 ,array& aR ){ if(&aR==&aV) return false; unsigned int dim = aV.dimension(); if(aI1>=dim) return false; if(aI2>=dim) return false; if(aI1==aI2) { aR.copy(aV); return true; } if(!aR.configure(aV.orders())) return false; std::vector vis(aV.dimension()); std::vector ris(aV.dimension()); const std::vector& vvec = aV.vector(); unsigned int size = aV.size(); for(unsigned int offset=0;offset inline void dump(std::ostream& a_out,const tools::array& a_array,const std::string& a_title){ if(a_title.size()) a_out << a_title << std::endl; const std::vector& vec = a_array.vector(); typedef typename std::vector::const_iterator cons_vec_it_t; for(cons_vec_it_t it = vec.begin();it!=vec.end();++it) { a_out << (*it) << std::endl; } } template inline void diff(std::ostream& a_out,const array& aA,const array& aB,T a_epsilon){ if(aA.orders()!=aB.orders()) { a_out << "tools::arrays::diff : not same orders" << std::endl; return; } bool header_done = false; unsigned int dim = aA.dimension(); std::vector is(dim); unsigned int vsize = aA.vector().size(); for(unsigned int index=0;index=a_epsilon) { aA.indices(index,is); if(!header_done) { a_out << "tools::arrays::diff :" << std::endl; header_done = true; } for(unsigned int i=0;i class kronecker : public array { public: kronecker(unsigned int a_order):array(a_order,a_order){ // epsilon(i1,i2,....in) with n = a_order and i in [0,n[. // Then an Array of a_order * a_order. unsigned int index = 0; typedef typename std::vector _uints_t; _uints_t is(a_order); std::vector& vec = array::vector(); typedef typename std::vector::iterator _vec_it_t; _vec_it_t it = vec.begin(); for(;it!=vec.end();++it,index++) { if(!array::indices(index,is)) return; //FIXME throw. bool good = true; {for(unsigned int iaxis=0;iaxis::one(); else (*it) = array::minus_one();} } } }; template inline array operator+(const array& a1,const array& a2) { array res(a1); if(!res.add(a2)) {} return res; } template inline array operator-(const array& a1,const array& a2) { array res(a1); if(!res.subtract(a2)) {} return res; } template inline array operator*(const T& a_fac,const array& a_m) { array res(a_m); res *= a_fac; return res; } } #endif