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