GetFEM  5.5
bgeot_tensor.h
Go to the documentation of this file.
1 /* -*- c++ -*- (enables emacs c++ mode) */
2 /*===========================================================================
3 
4  Copyright (C) 2000-2026 Yves Renard
5 
6  This file is a part of GetFEM
7 
8  GetFEM is free software; you can redistribute it and/or modify it
9  under the terms of the GNU Lesser General Public License as published
10  by the Free Software Foundation; either version 3 of the License, or
11  (at your option) any later version along with the GCC Runtime Library
12  Exception either version 3.1 or (at your option) any later version.
13  This program is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16  License and GCC Runtime Library Exception for more details.
17  You should have received a copy of the GNU Lesser General Public License
18  along with this program. If not, see https://www.gnu.org/licenses/.
19 
20  As a special exception, you may use this file as it is a part of a free
21  software library without restriction. Specifically, if other files
22  instantiate templates or use macros or inline functions from this file,
23  or you compile this file and link it with other files to produce an
24  executable, this file does not by itself cause the resulting executable
25  to be covered by the GNU Lesser General Public License. This exception
26  does not however invalidate any other reasons why the executable file
27  might be covered by the GNU Lesser General Public License.
28 
29 ===========================================================================*/
30 
31 /**@file bgeot_tensor.h
32  @author Yves Renard <Yves.Renard@insa-lyon.fr>
33  @date October 09, 2000.
34  @brief tensor class, used in mat_elem computations.
35 */
36 #ifndef BGEOT_TENSOR_H__
37 #define BGEOT_TENSOR_H__
38 
39 #include "bgeot_small_vector.h"
40 #include "getfem/getfem_omp.h"
41 
42 
43 namespace bgeot {
44 
45  /* ********************************************************************* */
46  /* Class tensor<T>. */
47  /* ********************************************************************* */
48 
49  typedef size_t size_type;
50  typedef gmm::uint16_type short_type;
51 
52  class multi_index : public std::vector<size_type> {
53  public :
54 
55  void incrementation(const multi_index &m) {
56  iterator it = begin(), ite = end();
57  const_iterator itm = m.begin();
58  if (it != ite) {
59  ++(*it);
60  while (*it >= *itm && it != (ite-1)) { *it = 0; ++it; ++itm; ++(*it); }
61  } else resize(1);
62  }
63 
64  void reset() { std::fill(begin(), end(), 0); }
65 
66  inline bool finished(const multi_index &m) {
67  if (m.size() == 0)
68  return (size() == 1);
69  else
70  return ((*this)[size()-1] >= m[size()-1]);
71  }
72 
73  multi_index(size_t n) : std::vector<size_type>(n)
74  { std::fill(begin(), end(), size_type(0)); }
75  multi_index(size_type i, size_type j)
76  : std::vector<size_type>(2)
77  { (*this)[0] = i; (*this)[1] = j; }
78  multi_index(size_type i, size_type j, size_type k)
79  : std::vector<size_type>(3)
80  { (*this)[0] = i; (*this)[1] = j; (*this)[2] = k; }
81  multi_index(size_type i, size_type j, size_type k, size_type l)
82  : std::vector<size_type>(4)
83  { (*this)[0] = i; (*this)[1] = j; (*this)[2] = k; (*this)[3] = l; }
84 
85  multi_index() {}
86 
87  bool is_equal(const multi_index &m) const {
88  if (this->size() != m.size()) return false;
89  for (size_type i = 0; i < m.size(); ++i)
90  if (m[i] != (*this)[i]) return false;
91  return true;
92  }
93 
94  size_type total_size() const {
95  size_type s = 1;
96  for (size_type k = 0; k < this->size(); ++k) s *= (*this)[k];
97  return s;
98  }
99 
100  size_type memsize() const {
101  return std::vector<size_type>::capacity()*sizeof(size_type) +
102  sizeof(multi_index);
103  }
104  };
105 
106  inline std::ostream &operator <<(std::ostream &o,
107  const multi_index& mi) { /* a compiler ...*/
108  multi_index::const_iterator it = mi.begin(), ite = mi.end();
109  bool f = true;
110  o << "(";
111  for ( ; it != ite; ++it)
112  { if (!f) o << ", "; o << *it; f = false; }
113  o << ")";
114  return o;
115  }
116 
117  template<class T> class tensor : public std::vector<T> {
118  protected:
119 
120  multi_index sizes_;
121  multi_index coeff_;
122 
123  public:
124 
125  typedef typename std::vector<T>::size_type size_type;
126  typedef typename std::vector<T>::iterator iterator;
127  typedef typename std::vector<T>::const_iterator const_iterator;
128 
129  template<class CONT> inline const T& operator ()(const CONT &c) const {
130  typename CONT::const_iterator it = c.begin();
131  multi_index::const_iterator q = coeff_.begin(), e = coeff_.end();
132  multi_index::const_iterator qv = sizes_.begin();
133  size_type d = 0;
134  for ( ; q != e; ++q, ++it) {
135  d += (*q) * (*it);
136  GMM_ASSERT2(*it < *qv++, "Index out of range.");
137  }
138  return *(this->begin() + d);
139  }
140 
141  inline T& operator ()(size_type i, size_type j, size_type k,
142  size_type l) {
143  GMM_ASSERT2(order() == 4, "Bad tensor order.");
144  size_type d = coeff_[0]*i + coeff_[1]*j + coeff_[2]*k + coeff_[3]*l;
145  GMM_ASSERT2(d < size(), "Index out of range.");
146  return *(this->begin() + d);
147  }
148 
149  inline T& operator ()(size_type i, size_type j, size_type k) {
150  GMM_ASSERT2(order() == 3, "Bad tensor order.");
151  size_type d = coeff_[0]*i + coeff_[1]*j + coeff_[2]*k;
152  GMM_ASSERT2(d < size(), "Index out of range.");
153  return *(this->begin() + d);
154  }
155 
156  inline T& operator ()(size_type i, size_type j) {
157  GMM_ASSERT2(order() == 2, "Bad tensor order");
158  size_type d = coeff_[0]*i + coeff_[1]*j;
159  GMM_ASSERT2(d < size(), "Index out of range.");
160  return *(this->begin() + d);
161  }
162 
163  inline const T& operator ()(size_type i, size_type j, size_type k,
164  size_type l) const {
165  GMM_ASSERT2(order() == 4, "Bad tensor order.");
166  size_type d = coeff_[0]*i + coeff_[1]*j + coeff_[2]*k + coeff_[3]*l;
167  GMM_ASSERT2(d < size(), "Index out of range.");
168  return *(this->begin() + d);
169  }
170 
171  inline const T& operator ()(size_type i, size_type j,
172  size_type k) const {
173  GMM_ASSERT2(order() == 3, "Bad tensor order.");
174  size_type d = coeff_[0]*i + coeff_[1]*j + coeff_[2]*k;
175  GMM_ASSERT2(d < size(), "Index out of range.");
176  return *(this->begin() + d);
177  }
178 
179  inline const T& operator ()(size_type i, size_type j) const {
180  GMM_ASSERT2(order() == 2, "Bad tensor order.");
181  size_type d = coeff_[0]*i + coeff_[1]*j;
182  GMM_ASSERT2(d < size(), "Index out of range.");
183  return *(this->begin() + d);
184  }
185 
186  template<class CONT> inline T& operator ()(const CONT &c) {
187  typename CONT::const_iterator it = c.begin();
188  multi_index::iterator q = coeff_.begin(), e = coeff_.end();
189  size_type d = 0;
190  for ( ; q != e; ++q, ++it) d += (*q) * (*it);
191  GMM_ASSERT2(d < size(), "Index out of range.");
192  return *(this->begin() + d);
193  }
194 
195  inline size_type size() const { return std::vector<T>::size(); }
196  inline size_type size(size_type i) const { return sizes_[i]; }
197  inline const multi_index &sizes() const { return sizes_; }
198  inline size_type order() const { return sizes_.size(); }
199 
200  void init(const multi_index &c) {
201  auto it = c.begin();
202  size_type d = 1;
203  sizes_ = c; coeff_.resize(c.size());
204  auto p = coeff_.begin(), pe = coeff_.end();
205  for ( ; p != pe; ++p, ++it) { *p = d; d *= *it; }
206  this->resize(d);
207  }
208 
209  inline void init() { sizes_.resize(0); coeff_.resize(0); this->resize(1); }
210 
211  inline void init(size_type i) {
212  sizes_.resize(1); sizes_[0] = i; coeff_.resize(1); coeff_[0] = 1;
213  this->resize(i);
214  }
215 
216  inline void init(size_type i, size_type j) {
217  sizes_.resize(2); sizes_[0] = i; sizes_[1] = j;
218  coeff_.resize(2); coeff_[0] = 1; coeff_[1] = i;
219  this->resize(i*j);
220  }
221 
222  inline void init(size_type i, size_type j, size_type k) {
223  sizes_.resize(3); sizes_[0] = i; sizes_[1] = j; sizes_[2] = k;
224  coeff_.resize(3); coeff_[0] = 1; coeff_[1] = i; coeff_[2] = i*j;
225  this->resize(i*j*k);
226  }
227 
228  inline void init(size_type i, size_type j, size_type k, size_type l) {
229  sizes_.resize(4);
230  sizes_[0] = i; sizes_[1] = j; sizes_[2] = k; sizes_[3] = k;
231  coeff_.resize(4);
232  coeff_[0] = 1; coeff_[1] = i; coeff_[2] = i*j; coeff_[3] = i*j*k;
233  this->resize(i*j*k*l);
234  }
235 
236  inline void adjust_sizes(const multi_index &mi) { init(mi); }
237  inline void adjust_sizes() { init(); }
238  inline void adjust_sizes(size_type i) { init(i); }
239  inline void adjust_sizes(size_type i, size_type j) { init(i, j); }
240  inline void adjust_sizes(size_type i, size_type j, size_type k)
241  { init(i, j, k); }
242  inline void adjust_sizes(size_type i, size_type j, size_type k, size_type l)
243  { init(i, j, k, l); }
244 
245  inline size_type adjust_sizes_changing_last(const tensor &t, size_type P) {
246  const multi_index &mi = t.sizes_; size_type d = mi.size();
247  sizes_.resize(d); coeff_.resize(d);
248  if (d) {
249  std::copy(mi.begin(), mi.end(), sizes_.begin());
250  std::copy(t.coeff_.begin(), t.coeff_.end(), coeff_.begin());
251  size_type e = coeff_.back();
252  sizes_.back() = P;
253  this->resize(e*P);
254  return e;
255  } else {
256  this->resize(1);
257  return 1;
258  }
259  }
260 
261  inline void remove_unit_dim() {
262  if (sizes_.size()) {
263  size_type i = 0, j = 0;
264  for (; i < sizes_.size(); ++i)
265  if (sizes_[i] != 1) { sizes_[j]=sizes_[i]; coeff_[j]=coeff_[i]; ++j; }
266  if (!j) ++j;
267  sizes_.resize(j);
268  coeff_.resize(j);
269  }
270  }
271 
272  /** reduction of tensor t with respect to index ni with matrix m:
273  * t(...,j,...) <-- t(...,i,..) m(i, j)
274  */
275  void mat_reduction(const tensor &t, const gmm::dense_matrix<T> &m, int ni);
276  void mat_transp_reduction(const tensor &t, const gmm::dense_matrix<T> &m,
277  int ni);
278  /** mm(i,j) = t(i,j,k,l) * m(k,l); For order four tensor. */
279  void mat_mult(const gmm::dense_matrix<T> &m, gmm::dense_matrix<T> &mm);
280 
281  /** tt = t(...) * t2(...) */
282  void product(const tensor &t2, tensor &tt);
283  /** tt = t(...,k) * t2(k,...) */
284  void dot_product(const tensor &t2, tensor &tt);
285  void dot_product(const gmm::dense_matrix<T> &m, tensor &tt);
286  /** tt = t(...,k,l) * t2(k,l,...) */
287  void double_dot_product(const tensor &t2, tensor &tt);
288  void double_dot_product(const gmm::dense_matrix<T> &m, tensor &tt);
289 
290  size_type memsize() const {
291  return sizeof(T) * this->size()
292  + sizeof(*this) + sizes_.memsize() + coeff_.memsize();
293  }
294 
295  std::vector<T> &as_vector() { return *this; }
296  const std::vector<T> &as_vector() const { return *this; }
297 
298 
299  tensor<T>& operator +=(const tensor<T>& w)
300  { gmm::add(w.as_vector(), this->as_vector()); return *this; }
301 
302  tensor<T>& operator -=(const tensor<T>& w) {
303  gmm::add(gmm::scaled(w.as_vector(), T(-1)), this->as_vector());
304  return *this;
305  }
306 
307  tensor<T>& operator *=(const scalar_type w)
308  { gmm::scale(this->as_vector(), w); return *this; }
309 
310  tensor<T>& operator /=(const scalar_type w)
311  { gmm::scale(this->as_vector(), scalar_type(1)/w); return *this; }
312 
313  tensor &operator =(const tensor &t) {
314  if (this->size() != t.size()) this->resize(t.size());
315  std::copy(t.begin(), t.end(), this->begin());
316  if (sizes_.size() != t.sizes_.size()) sizes_.resize(t.sizes_.size());
317  std::copy(t.sizes_.begin(), t.sizes_.end(), sizes_.begin());
318  if (coeff_.size() != t.coeff_.size()) coeff_.resize(t.coeff_.size());
319  std::copy(t.coeff_.begin(), t.coeff_.end(), coeff_.begin());
320  return *this;
321  }
322 
323  tensor(const tensor &t)
324  : std::vector<T>(t), sizes_(t.sizes_), coeff_(t.coeff_) { }
325  tensor(const multi_index &c) { init(c); }
326  tensor(size_type i) = delete; // { init(i); }
327  tensor(size_type i, size_type j) { init(i, j); }
328  tensor(size_type i, size_type j, size_type k) { init(i, j, k); }
329  tensor(size_type i, size_type j, size_type k, size_type l)
330  { init(i, j, k, l); }
331  tensor() {}
332  };
333 
334 
335  template<class T> void tensor<T>::mat_transp_reduction
336  (const tensor &t, const gmm::dense_matrix<T> &m, int ni) {
337  /* contraction of tensor t by its index ni and the transpose of matrix m. */
338 
339  THREAD_SAFE_STATIC std::vector<T> tmp;
340  THREAD_SAFE_STATIC multi_index mi;
341 
342  mi = t.sizes();
343  size_type dimt = mi[ni], dim = m.nrows();
344 
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.");
348 
349  mi[ni] = dim;
350  if (tmp.size() < dimt) tmp.resize(dimt);
351  adjust_sizes(mi);
352 
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) {
359  if (mi[ni] != 0) {
360  for (size_type k = 0; k <= size_type(ni); ++k)
361  mi[k] = size_type(sizes()[k] - 1);
362  pf += dd; pft += ddt;
363  } else {
364  const_iterator pl = pft; iterator pt = tmp.begin();
365  *pt++ = *pl;
366  for(size_type k = 1; k < dimt; ++k, ++pt) { pl += cot; *pt = *pl;}
367 
368  iterator pff = pf;
369  for (size_type k = 0; k < dim; ++k) {
370  if (k) pff += co;
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) {
374  pl += dim;
375  *pff += (*pl) * (*pt);
376  }
377  }
378  }
379  }
380  }
381 
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]);
389  gmm::clear(mm);
390 
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);
399  ++pm;
400  }
401  }
402 
403  template<class T> void tensor<T>::mat_reduction
404  (const tensor &t, const gmm::dense_matrix<T> &m, int ni) {
405  /* contraction of tensor t by its index ni and the matrix m. */
406  THREAD_SAFE_STATIC std::vector<T> tmp;
407  THREAD_SAFE_STATIC multi_index mi;
408 
409  mi = t.sizes();
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.");
414 
415  mi[ni] = dim;
416  if (tmp.size() < dimt) tmp.resize(dimt);
417  adjust_sizes(mi);
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) {
424  if (mi[ni] != 0) {
425  for (size_type k = 0; k <= size_type(ni); ++k)
426  mi[k] = size_type(sizes()[k] - 1);
427  pf += dd; pft += ddt;
428  }
429  else {
430  const_iterator pl = pft; iterator pt = tmp.begin();
431  *pt++ = *pl;
432  for(size_type k = 1; k < dimt; ++k, ++pt) { pl += cot; *pt = *pl; }
433 
434  iterator pff = pf; pl = m.begin();
435  for (size_type k = 0; k < dim; ++k) {
436  if (k) pff += co;
437  *pff = T(0); pt = tmp.begin();
438  for (size_type l = 0; l < dimt; ++l, ++pt, ++pl)
439  *pff += (*pl) * (*pt);
440  }
441  }
442  }
443  }
444 
445 
446  template<class T> void tensor<T>::product(const tensor<T> &t2,
447  tensor<T> &tt) {
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);
453  gmm::clear(tt.as_vector());
454 
455  size_type size1 = this->size();
456  size_type size2 = t2.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);
463  }
464  }
465 
466 
467  template<class T> void tensor<T>::dot_product(const tensor<T> &t2,
468  tensor<T> &tt) {
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);
477  gmm::clear(tt.as_vector());
478 
479  size_type size0 = t2.size(0);
480  size_type size1 = this->size()/size0;
481  size_type size2 = t2.size()/size0;
482  const_iterator pt2 = t2.begin();
483  iterator ptt = tt.begin();
484  for (size_type j = 0; j < size2; ++j) {
485  const_iterator pt1 = this->begin();
486  iterator ptt0 = ptt;
487  for (size_type q = 0; q < size0; ++q, ++pt2) {
488  ptt = ptt0;
489  for (size_type i = 0; i < size1; ++i, ++pt1, ++ptt)
490  *ptt += *pt1 * (*pt2);
491  }
492  }
493  }
494 
495  template<class T> void tensor<T>::dot_product(const gmm::dense_matrix<T> &m,
496  tensor<T> &tt) {
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());
502  dot_product(t2, tt);
503  }
504 
505 
506  template<class T> void tensor<T>::double_dot_product(const tensor<T> &t2,
507  tensor<T> &tt) {
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);
518  gmm::clear(tt.as_vector());
519 
520  size_type size0 = t2.size(0)*t2.size(1);
521  size_type size1 = this->size()/size0;
522  size_type size2 = t2.size()/size0;
523  const_iterator pt2 = t2.begin();
524  iterator ptt = tt.begin();
525  for (size_type j = 0; j < size2; ++j) {
526  const_iterator pt1 = this->begin();
527  iterator ptt0 = ptt;
528  for (size_type q = 0; q < size0; ++q, ++pt2) {
529  ptt = ptt0;
530  for (size_type i = 0; i < size1; ++i, ++pt1, ++ptt)
531  *ptt += *pt1 * (*pt2);
532  }
533  }
534  }
535 
536  template<class T> void tensor<T>::double_dot_product(const gmm::dense_matrix<T> &m,
537  tensor<T> &tt) {
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);
547  }
548 
549 
550  template<class T> std::ostream &operator <<
551  (std::ostream &o, const tensor<T>& t) {
552  o << "sizes " << t.sizes() << " " << vref(t.as_vector());
553  return o;
554  }
555 
556  typedef tensor<scalar_type> base_tensor;
557  typedef tensor<complex_type> base_complex_tensor;
558 
559 
560 } /* end of namespace bgeot. */
561 
562 
563 #endif /* BGEOT_TENSOR_H */
Small (dim < 8) vectors.
Tools for multithreaded, OpenMP and Boost based parallelization.
void copy(const L1 &l1, L2 &l2)
*‍/
Definition: gmm_blas.h:976
void clear(L &l)
clear (fill with zeros) a vector or matrix.
Definition: gmm_blas.h:58
void resize(V &v, size_type n)
*‍/
Definition: gmm_blas.h:209
void add(const L1 &l1, L2 &l2)
*‍/
Definition: gmm_blas.h:1275
Basic Geometric Tools.
gmm::uint16_type short_type
used as the common short type integer in the library
Definition: bgeot_config.h:72
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
Definition: bgeot_poly.h:48