37 #ifndef BGEOT_TENSOR_H__ 
   38 #define BGEOT_TENSOR_H__ 
   53   class multi_index : 
public std::vector<size_type> {
 
   56     void incrementation(
const multi_index &m) {
 
   57       iterator it = begin(), ite = end();
 
   58       const_iterator itm = m.begin();
 
   61         while (*it >= *itm && it != (ite-1)) { *it = 0; ++it; ++itm; ++(*it); }
 
   65     void reset() { std::fill(begin(), end(), 0); }
 
   67     inline bool finished(
const multi_index &m) {
 
   71         return ((*
this)[size()-1] >= m[size()-1]);
 
   74     multi_index(
size_t n) : std::vector<
size_type>(n)
 
   75     { std::fill(begin(), end(), 
size_type(0)); }
 
   78     { (*this)[0] = i; (*this)[1] = j; }
 
   81     { (*this)[0] = i; (*this)[1] = j; (*this)[2] = k; }
 
   84     { (*this)[0] = i; (*this)[1] = j; (*this)[2] = k; (*this)[3] = l; }
 
   88     bool is_equal(
const multi_index &m)
 const {
 
   89       if (this->size() != m.size()) 
return false;
 
   91         if (m[i] != (*
this)[i]) 
return false;
 
   97       for (
size_type k = 0; k < this->size(); ++k) s *= (*
this)[k];
 
  102       return std::vector<size_type>::capacity()*
sizeof(
size_type) +
 
  108                                    const multi_index& mi) { 
 
  109     multi_index::const_iterator it = mi.begin(), ite = mi.end();
 
  112     for ( ; it != ite; ++it)
 
  113       { 
if (!f) o << 
", "; o << *it; f = 
false; }
 
  118   template<
class T> 
class tensor : 
public std::vector<T> {
 
  127     typedef typename std::vector<T>::iterator iterator;
 
  128     typedef typename std::vector<T>::const_iterator const_iterator;
 
  130     template<
class CONT> 
inline const T& operator ()(
const CONT &c)
 const {
 
  131       typename CONT::const_iterator it = c.begin();
 
  132       multi_index::const_iterator q = coeff_.begin(), e = coeff_.end();
 
  133       multi_index::const_iterator qv = sizes_.begin();
 
  135       for ( ; q != e; ++q, ++it) {
 
  137         GMM_ASSERT2(*it < *qv++, 
"Index out of range.");
 
  139       return *(this->begin() + d);
 
  144       GMM_ASSERT2(order() == 4, 
"Bad tensor order.");
 
  145       size_type d = coeff_[0]*i + coeff_[1]*j + coeff_[2]*k + coeff_[3]*l;
 
  146       GMM_ASSERT2(d < size(), 
"Index out of range.");
 
  147       return *(this->begin() + d);
 
  151       GMM_ASSERT2(order() == 3, 
"Bad tensor order.");
 
  152       size_type d = coeff_[0]*i + coeff_[1]*j + coeff_[2]*k;
 
  153       GMM_ASSERT2(d < size(), 
"Index out of range.");
 
  154       return *(this->begin() + d);
 
  158       GMM_ASSERT2(order() == 2, 
"Bad tensor order");
 
  160         GMM_ASSERT2(d < size(), 
"Index out of range.");
 
  161         return *(this->begin() + d);
 
  166       GMM_ASSERT2(order() == 4, 
"Bad tensor order.");
 
  167       size_type d = coeff_[0]*i + coeff_[1]*j + coeff_[2]*k + coeff_[3]*l;
 
  168       GMM_ASSERT2(d < size(), 
"Index out of range.");
 
  169       return *(this->begin() + d);
 
  174       GMM_ASSERT2(order() == 3, 
"Bad tensor order.");
 
  175       size_type d = coeff_[0]*i + coeff_[1]*j + coeff_[2]*k;
 
  176       GMM_ASSERT2(d < size(), 
"Index out of range.");
 
  177       return *(this->begin() + d);
 
  181       GMM_ASSERT2(order() == 2, 
"Bad tensor order.");
 
  183       GMM_ASSERT2(d < size(), 
"Index out of range.");
 
  184       return *(this->begin() + d);
 
  187     template<
class CONT> 
inline T& operator ()(
const CONT &c) {
 
  188       typename CONT::const_iterator it = c.begin();
 
  189       multi_index::iterator q = coeff_.begin(), e = coeff_.end();
 
  191       for ( ; q != e; ++q, ++it) d += (*q) * (*it);
 
  192       GMM_ASSERT2(d < size(), 
"Index out of range.");
 
  193       return *(this->begin() + d);
 
  196     inline size_type size()
 const { 
return std::vector<T>::size(); }
 
  198     inline const multi_index &sizes()
 const { 
return sizes_; }
 
  199     inline size_type order()
 const { 
return sizes_.size(); }
 
  201     void init(
const multi_index &c) {
 
  204       sizes_ = c; coeff_.resize(c.size());
 
  205       auto p = coeff_.begin(), pe = coeff_.end();
 
  206       for ( ; p != pe; ++p, ++it) { *p = d; d *= *it; }
 
  210     inline void init() { sizes_.resize(0); coeff_.resize(0); this->
resize(1); }
 
  213       sizes_.resize(1); sizes_[0] = i; coeff_.resize(1); coeff_[0] = 1;
 
  218       sizes_.resize(2); sizes_[0] = i; sizes_[1] = j;
 
  219       coeff_.resize(2); coeff_[0] = 1; coeff_[1] = i;
 
  224       sizes_.resize(3); sizes_[0] = i; sizes_[1] = j; sizes_[2] = k; 
 
  225       coeff_.resize(3); coeff_[0] = 1; coeff_[1] = i; coeff_[2] = i*j;
 
  231       sizes_[0] = i; sizes_[1] = j; sizes_[2] = k; sizes_[3] = k; 
 
  233       coeff_[0] = 1; coeff_[1] = i; coeff_[2] = i*j; coeff_[3] = i*j*k;
 
  237     inline void adjust_sizes(
const multi_index &mi) { init(mi); }
 
  238     inline void adjust_sizes() { init(); }
 
  239     inline void adjust_sizes(
size_type i) { init(i); }
 
  244     { init(i, j, k, l); }
 
  247       const multi_index &mi = t.sizes_; 
size_type d = mi.size();
 
  248       sizes_.resize(d); coeff_.resize(d);
 
  250         std::copy(mi.begin(), mi.end(), sizes_.begin());
 
  251         std::copy(t.coeff_.begin(), t.coeff_.end(), coeff_.begin());
 
  262     inline void remove_unit_dim() {
 
  265         for (; i < sizes_.size(); ++i)
 
  266           if (sizes_[i] != 1) { sizes_[j]=sizes_[i]; coeff_[j]=coeff_[i]; ++j; }
 
  276     void mat_reduction(
const tensor &t, 
const gmm::dense_matrix<T> &m, 
int ni);
 
  277     void mat_transp_reduction(
const tensor &t, 
const gmm::dense_matrix<T> &m,
 
  280     void mat_mult(
const gmm::dense_matrix<T> &m, gmm::dense_matrix<T> &mm);
 
  283     void product(
const tensor &t2, tensor &tt);
 
  285     void dot_product(
const tensor &t2, tensor &tt);
 
  286     void dot_product(
const gmm::dense_matrix<T> &m, tensor &tt);
 
  288     void double_dot_product(
const tensor &t2, tensor &tt);
 
  289     void double_dot_product(
const gmm::dense_matrix<T> &m, tensor &tt);
 
  292       return sizeof(T) * this->size()
 
  293         + 
sizeof(*this) + sizes_.memsize() + coeff_.memsize();
 
  296     std::vector<T> &as_vector() { 
return *
this; }
 
  297     const std::vector<T> &as_vector()
 const { 
return *
this; }
 
  300     tensor<T>& operator +=(
const tensor<T>& w)
 
  301     { 
gmm::add(w.as_vector(), this->as_vector()); 
return *
this; }
 
  303     tensor<T>& operator -=(
const tensor<T>& w) {
 
  304       gmm::add(gmm::scaled(w.as_vector(), T(-1)), this->as_vector());
 
  308     tensor<T>& operator *=(
const scalar_type w)
 
  309     { gmm::scale(this->as_vector(), w); 
return *
this; }
 
  311     tensor<T>& operator /=(
const scalar_type w)
 
  312     { gmm::scale(this->as_vector(), scalar_type(1)/w); 
return *
this; }
 
  314     tensor &operator =(
const tensor &t) {
 
  315       if (this->size() != t.size()) this->
resize(t.size());
 
  316       std::copy(t.begin(), t.end(), this->begin());
 
  317       if (sizes_.size() != t.sizes_.size()) sizes_.resize(t.sizes_.size());
 
  318       std::copy(t.sizes_.begin(), t.sizes_.end(), sizes_.begin());
 
  319       if (coeff_.size() != t.coeff_.size()) coeff_.resize(t.coeff_.size());
 
  320       std::copy(t.coeff_.begin(), t.coeff_.end(), coeff_.begin());
 
  324     tensor(
const tensor &t)
 
  325       : std::vector<T>(t), sizes_(t.sizes_), coeff_(t.coeff_) { }
 
  326     tensor(
const multi_index &c) { init(c); }
 
  331     { init(i, j, k, l); }
 
  335   template<
class T> 
void tensor<T>::mat_transp_reduction
 
  336   (
const tensor &t, 
const gmm::dense_matrix<T> &m, 
int ni) {
 
  339     THREAD_SAFE_STATIC std::vector<T> tmp;
 
  340     THREAD_SAFE_STATIC multi_index mi;
 
  343     size_type dimt = mi[ni], dim = m.nrows();
 
  345     GMM_ASSERT2(dimt, 
"Inconsistent dimension.");
 
  346     GMM_ASSERT2(dimt == m.ncols(), 
"Dimensions mismatch.");
 
  347     GMM_ASSERT2(&t != 
this, 
"Does not work when t and *this are the same.");
 
  350     if (tmp.size() < dimt) tmp.resize(dimt);
 
  353     const_iterator pft = t.begin();
 
  354     iterator pf = this->begin();
 
  355     size_type dd  =   coeff_[ni]*(  sizes()[ni]-1)-1, co  =   coeff_[ni];
 
  356     size_type ddt = t.coeff_[ni]*(t.sizes()[ni]-1)-1, cot = t.coeff_[ni];
 
  357     std::fill(mi.begin(), mi.end(), 0);
 
  358     for (;!mi.finished(sizes()); mi.incrementation(sizes()), ++pf, ++pft) {
 
  362         pf += dd; pft += ddt;
 
  364         const_iterator pl = pft; iterator pt = tmp.begin();
 
  366         for(
size_type k = 1; k < dimt; ++k, ++pt) { pl += cot; *pt = *pl;}
 
  371           *pff = T(0); pt = tmp.begin(); pl = m.begin() + k;
 
  372           *pff += (*pl) * (*pt); ++pt;
 
  373           for (
size_type l = 1; l < dimt; ++l, ++pt) {
 
  375             *pff += (*pl) * (*pt);
 
  382   template<
class T> 
void tensor<T>::mat_mult(
const gmm::dense_matrix<T> &m,
 
  383                                              gmm::dense_matrix<T> &mm) {
 
  384     GMM_ASSERT2(order() == 4,
 
  385                 "This operation is for order four tensors only.");
 
  386     GMM_ASSERT2(sizes_[2] == gmm::mat_nrows(m) &&
 
  387                 sizes_[3] == gmm::mat_ncols(m), 
"Dimensions mismatch.");
 
  388     mm.base_resize(sizes_[0], sizes_[1]);
 
  391     const_iterator pt = this->begin();
 
  392     const_iterator pm = m.begin();
 
  393     for (
size_type l = 0; l < sizes_[3]; ++l)
 
  394       for (
size_type k = 0; k < sizes_[2]; ++k) {
 
  395         iterator pmm = mm.begin();
 
  396         for (
size_type j = 0; j < sizes_[1]; ++j)
 
  397           for (
size_type i = 0; i < sizes_[0]; ++i)
 
  398             *pmm++ += *pt++ * (*pm);
 
  403   template<
class T> 
void tensor<T>::mat_reduction
 
  404   (
const tensor &t, 
const gmm::dense_matrix<T> &m, 
int ni) {
 
  406     THREAD_SAFE_STATIC std::vector<T> tmp;
 
  407     THREAD_SAFE_STATIC multi_index mi;
 
  410     size_type dimt = mi[ni], dim = m.ncols();
 
  411     GMM_ASSERT2(dimt, 
"Inconsistent dimension.");
 
  412     GMM_ASSERT2(dimt == m.nrows(), 
"Dimensions mismatch.");
 
  413     GMM_ASSERT2(&t != 
this, 
"Does not work when t and *this are the same.");
 
  416     if (tmp.size() < dimt) tmp.resize(dimt);
 
  418     const_iterator pft = t.begin();
 
  419     iterator pf = this->begin();
 
  420     size_type dd  =   coeff_[ni]*(  sizes()[ni]-1)-1, co  =   coeff_[ni];
 
  421     size_type ddt = t.coeff_[ni]*(t.sizes()[ni]-1)-1, cot = t.coeff_[ni];
 
  422     std::fill(mi.begin(), mi.end(), 0);
 
  423     for (;!mi.finished(sizes()); mi.incrementation(sizes()), ++pf, ++pft) {
 
  427         pf += dd; pft += ddt;
 
  430         const_iterator pl = pft; iterator pt = tmp.begin();
 
  432         for(
size_type k = 1; k < dimt; ++k, ++pt) { pl += cot; *pt = *pl; }
 
  434         iterator pff = pf; pl = m.begin();
 
  437           *pff = T(0); pt = tmp.begin();
 
  438           for (
size_type l = 0; l < dimt; ++l, ++pt, ++pl)
 
  439             *pff += (*pl) * (*pt);
 
  446   template<
class T> 
void tensor<T>::product(
const tensor<T> &t2,
 
  448     size_type res_order = order() + t2.order();
 
  449     multi_index res_size(res_order);
 
  450     for (
size_type i = 0 ; i < this->order(); ++i) res_size[i] = this->size(i);
 
  451     for (
size_type i = 0 ; i < t2.order(); ++i) res_size[order() + i] = t2.size(i);
 
  452     tt.adjust_sizes(res_size);
 
  457     const_iterator pt2 = t2.begin();
 
  458     iterator ptt = tt.begin();
 
  459     for (
size_type j = 0; j < size2; ++j, ++pt2) {
 
  460       const_iterator pt1 = this->begin();
 
  461       for (
size_type i = 0; i < size1; ++i, ++pt1, ++ptt)
 
  462         *ptt += *pt1 * (*pt2);
 
  467   template<
class T> 
void tensor<T>::dot_product(
const tensor<T> &t2,
 
  469     GMM_ASSERT2(size(order()-1) == t2.size(0),
 
  470                 "Dimensions mismatch between last dimension of first tensor " 
  471                 "and first dimension of second tensor.");
 
  472     size_type res_order = order() + t2.order() - 2;
 
  473     multi_index res_size(res_order);
 
  474     for (
size_type i = 0 ; i < this->order() - 1; ++i) res_size[i] = this->size(i);
 
  475     for (
size_type i = 0 ; i < t2.order() - 1; ++i) res_size[order() - 1 + i] = t2.size(i);
 
  476     tt.adjust_sizes(res_size);
 
  482     const_iterator pt2 = t2.begin();
 
  483     iterator ptt = tt.begin();
 
  485       const_iterator pt1 = this->begin();
 
  487       for (
size_type q = 0; q < size0; ++q, ++pt2) {
 
  489         for (
size_type i = 0; i < size1; ++i, ++pt1, ++ptt)
 
  490           *ptt += *pt1 * (*pt2);
 
  495   template<
class T> 
void tensor<T>::dot_product(
const gmm::dense_matrix<T> &m,
 
  497     GMM_ASSERT2(size(order()-1) == gmm::mat_nrows(m),
 
  498                 "Dimensions mismatch between last dimensions of tensor " 
  499                 "and rows of the matrix.");
 
  500     tensor<T> t2(multi_index(gmm::mat_nrows(m),gmm::mat_ncols(m)));
 
  501     gmm::copy(m.as_vector(), t2.as_vector());
 
  506   template<
class T> 
void tensor<T>::double_dot_product(
const tensor<T> &t2,
 
  508     GMM_ASSERT2(order() >= 2 && t2.order() >= 2,
 
  509                 "Tensors of wrong size. Tensors of order two or higher are required.");
 
  510     GMM_ASSERT2(size(order()-2) == t2.size(0) && size(order()-1) == t2.size(1),
 
  511                 "Dimensions mismatch between last two dimensions of first tensor " 
  512                 "and first two dimensions of second tensor.");
 
  513     size_type res_order = order() + t2.order() - 4;
 
  514     multi_index res_size(res_order);
 
  515     for (
size_type i = 0 ; i < this->order() - 2; ++i) res_size[i] = this->size(i);
 
  516     for (
size_type i = 0 ; i < t2.order() - 2; ++i) res_size[order() - 2 + i] = t2.size(i);
 
  517     tt.adjust_sizes(res_size);
 
  523     const_iterator pt2 = t2.begin();
 
  524     iterator ptt = tt.begin();
 
  526       const_iterator pt1 = this->begin();
 
  528       for (
size_type q = 0; q < size0; ++q, ++pt2) {
 
  530         for (
size_type i = 0; i < size1; ++i, ++pt1, ++ptt)
 
  531           *ptt += *pt1 * (*pt2);
 
  536   template<
class T> 
void tensor<T>::double_dot_product(
const gmm::dense_matrix<T> &m,
 
  538     GMM_ASSERT2(order() >= 2,
 
  539                 "Tensor of wrong size. Tensor of order two or higher is required.");
 
  540     GMM_ASSERT2(size(order()-2) == gmm::mat_nrows(m) &&
 
  541                 size(order()-1) == gmm::mat_ncols(m),
 
  542                 "Dimensions mismatch between last two dimensions of tensor " 
  543                 "and dimensions of the matrix.");
 
  544     tensor<T> t2(multi_index(gmm::mat_nrows(m),gmm::mat_ncols(m)));
 
  545     gmm::copy(m.as_vector(), t2.as_vector());
 
  546     double_dot_product(t2, tt);
 
  550   template<
class T> std::ostream &
operator <<
 
  551     (std::ostream &o, 
const tensor<T>& t) {
 
  552     o << 
"sizes " << t.sizes() << 
" " << vref(t.as_vector());
 
  556   typedef tensor<scalar_type> base_tensor;
 
  557   typedef tensor<complex_type> base_complex_tensor;
 
Tools for multithreaded, OpenMP and Boost based parallelization.
void copy(const L1 &l1, L2 &l2)
*/
void clear(L &l)
clear (fill with zeros) a vector or matrix.
void resize(V &v, size_type n)
*/
void add(const L1 &l1, L2 &l2)
*/
gmm::uint16_type short_type
used as the common short type integer in the library
std::ostream & operator<<(std::ostream &o, const convex_structure &cv)
Print the details of the convex structure cvs to the output stream o.
size_t size_type
used as the common size type in the library