66 #ifndef BGEOT_SPARSE_TENSORS
67 #define BGEOT_SPARSE_TENSORS
77 typedef gmm::uint32_type index_type;
78 typedef gmm::int32_type stride_type;
81 class tensor_ranges :
public std::vector<index_type> {
83 tensor_ranges() : std::vector<index_type>() {}
84 tensor_ranges(
size_type n) : std::vector<index_type>(n) {}
85 tensor_ranges(
size_type n, index_type V) : std::vector<index_type>(n,V) {}
86 bool is_zero_size()
const
88 for (dim_type i=0; i < this->size(); ++i)
94 typedef std::vector<stride_type> tensor_strides;
95 typedef std::vector<dim_type> index_set;
97 typedef scalar_type * TDIter;
99 std::ostream&
operator<<(std::ostream& o,
const tensor_ranges& r);
102 struct tensor_ranges_loop {
107 tensor_ranges_loop(
const tensor_ranges& t) : sz(t), cnt(t.size()), finished_(t.size() == 0) {
108 std::fill(cnt.begin(), cnt.end(), 0);
110 index_type index(dim_type i) {
return cnt[i]; }
111 bool finished()
const {
return finished_; }
114 while (++cnt[i] >= sz[i]) {
115 cnt[i] = 0; i++;
if (i >= sz.size()) { finished_ =
true;
break; }
127 mutable index_type card_;
128 mutable bool card_uptodate;
130 tensor_mask() { set_card(0); }
131 explicit tensor_mask(
const tensor_ranges& r_,
const index_set& idxs_) {
135 explicit tensor_mask(
const tensor_mask& tm1,
const tensor_mask& tm2,
bool and_op);
136 explicit tensor_mask(
const std::vector<const tensor_mask*>& tm);
137 explicit tensor_mask(
const std::vector<const tensor_mask*> tm1,
138 const std::vector<const tensor_mask*> tm2,
bool and_op);
139 void swap(tensor_mask &tm) {
140 r.swap(tm.r); idxs.swap(tm.idxs);
141 m.swap(tm.m); s.swap(tm.s);
142 std::swap(card_, tm.card_);
143 std::swap(card_uptodate, tm.card_uptodate);
145 void assign(
const tensor_ranges& r_,
const index_set& idxs_) {
146 r = r_; idxs = idxs_; eval_strides(); m.assign(size(),
false);
149 void assign(
const tensor_mask& tm) {
154 card_ = tm.card_; card_uptodate = tm.card_uptodate;
156 void assign(
const std::vector<const tensor_mask* >& tm);
157 void assign(
const tensor_mask& tm1,
const tensor_mask& tm2,
bool and_op);
159 void clear() { r.resize(0); idxs.resize(0); m.clear(); s.resize(0); set_card(0); }
160 const tensor_ranges& ranges()
const {
return r; }
161 const index_set& indexes()
const {
return idxs; }
162 const tensor_strides& strides()
const {
return s; }
163 index_set& indexes() {
return idxs; }
164 void eval_strides() {
165 s.resize(r.size()+1); s[0]=1;
166 for (index_type i=0; i < r.size(); ++i) {
170 index_type ndim()
const {
return index_type(r.size()); }
171 index_type size()
const {
return s[r.size()]; }
172 void set_card(index_type c)
const { card_ = c; card_uptodate =
true; }
173 void unset_card()
const { card_uptodate =
false; }
174 index_type card(
bool just_look=
false)
const {
175 if (!card_uptodate || just_look) {
176 index_type c = index_type(std::count_if(m.begin(), m.end(),
177 [](
const auto &x) {return x == true;}));
178 if (just_look)
return c;
183 index_type pos(tensor_ranges& global_r)
const {
185 for (index_type i=0; i < r.size(); ++i)
186 p+= s[i]*global_r[idxs[i]];
189 index_type lpos(tensor_ranges& local_r)
const {
191 for (index_type i=0; i < r.size(); ++i)
195 bool operator()(tensor_ranges& global_r)
const {
196 return m[pos(global_r)];
198 bool operator()(stride_type p)
const {
return m[p]; }
199 void set_mask_val(stride_type p,
bool v) { m[p]=v; card_uptodate =
false; }
203 Slice(dim_type d, index_type i0_) : dim(d), i0(i0_) {}
207 void set_slice(index_type dim, index_type range, index_type islice) {
208 r.resize(1); r[0] = range;
209 idxs.resize(1); idxs[0] = dim_type(dim);
210 m.clear(); m.assign(range,
false); m[islice] = 1; set_card(1);
213 explicit tensor_mask(index_type range, Slice slice) {
214 set_slice(slice.dim, range, slice.i0);
219 Diagonal(dim_type i0_, dim_type i1_) : i0(i0_), i1(i1_) {}
223 void set_diagonal(index_type n, index_type i0, index_type i1) {
225 r.resize(2); r[0] = r[1] = n;
226 idxs.resize(2); idxs[0] = dim_type(i0); idxs[1] = dim_type(i1);
227 m.assign(n*n,
false);
228 for (index_type i=0; i < n; ++i) m[n*i+i]=
true;
232 explicit tensor_mask(index_type n, Diagonal diag) {
233 set_diagonal(n, diag.i0, diag.i1);
235 void set_triangular(index_type n, index_type i0, index_type i1) {
237 r.resize(2); r[0] = r[1] = n;
238 idxs.resize(2); idxs[0] = dim_type(i0); idxs[1] = dim_type(i1);
239 m.assign(n*n,
false); unset_card();
240 for (index_type i=0; i < n; ++i)
241 for (index_type j=i; j < n; ++j) m[i*n+j]=
true;
244 void set_full(index_type dim, index_type range) {
246 r.resize(1); r[0] = range;
247 idxs.resize(1); idxs[0] = dim_type(dim);
248 m.assign(range,
true); set_card(range);
251 void set_empty(index_type dim, index_type range) {
253 r.resize(1); r[0] = range;
254 idxs.resize(1); idxs[0] = dim_type(dim);
255 m.assign(range,
false); set_card(0);
258 explicit tensor_mask(index_type dim, index_type range) {
259 set_full(dim, range);
262 m.assign(size(),
false); set_card(0);
264 void shift_dim_num_ge(dim_type dim,
int shift) {
265 for (dim_type i=0; i < idxs.size(); ++i) {
266 if (idxs[i] >= dim) idxs[i] = dim_type(idxs[i] + shift);
270 void gen_mask_pos(tensor_strides& p)
const {
274 for (tensor_ranges_loop l(r); !l.finished(); l.next()) {
275 if (m[lpos(l.cnt)]) p[i++] = lpos(l.cnt);
279 void unpack_strides(
const tensor_strides& packed, tensor_strides& unpacked)
const;
283 int max_dim()
const {
284 index_set::const_iterator it = std::max_element(idxs.begin(),idxs.end());
285 return (it == idxs.end() ? -1 : *it);
287 void check_assertions()
const;
288 void print(std::ostream &o)
const;
289 void print_()
const { print(cerr); }
294 typedef std::vector<tensor_mask> tensor_mask_container;
296 struct tensor_index_to_mask {
299 tensor_index_to_mask() : mask_num(
short_type(-1)),
301 bool is_valid() {
return mask_num !=
short_type(-1) &&
311 mutable std::vector<tensor_index_to_mask> idx2mask;
312 tensor_mask_container masks_;
317 void check_empty_mask() {
319 for (dim_type i=0; i < masks_.size(); ++i) {
320 masks_[i].set_zero();
325 static void find_linked_masks(dim_type mnum,
const tensor_shape &ts1,
const tensor_shape &ts2,
326 dal::bit_vector& treated1, dal::bit_vector& treated2,
327 std::vector<const tensor_mask*>& lstA,
328 std::vector<const tensor_mask*>& lstB) {
330 assert(mnum < ts1.masks().size());
331 assert(!treated1[mnum]);
333 lstA.push_back(&ts1.mask(mnum));
334 for (dim_type i=0; i < ts1.mask(mnum).indexes().size(); ++i) {
335 dim_type ii = ts1.mask(mnum).indexes()[i];
336 if (ts2.index_is_valid(ii) && !treated2[ts2.index_to_mask_num(ii)])
337 find_linked_masks(ts2.index_to_mask_num(ii),ts2,ts1,treated2,treated1,lstB,lstA);
342 dim_type index_to_mask_num(dim_type ii)
const {
343 if (index_is_valid(ii))
344 return dim_type(idx2mask[ii].mask_num);
else return dim_type(-1);
347 void clear() { masks_.resize(0); idx2mask.resize(0); }
348 void swap(tensor_shape& ts) {
349 idx2mask.swap(ts.idx2mask);
350 masks_.swap(ts.masks_);
352 dim_type ndim()
const {
return dim_type(idx2mask.size()); }
353 bool index_is_valid(dim_type ii)
const {
354 assert(ii < idx2mask.size());
return idx2mask[ii].is_valid();
356 const tensor_mask& index_to_mask(dim_type ii)
const {
357 assert(index_is_valid(ii));
return masks_[idx2mask[ii].mask_num];
359 dim_type index_to_mask_dim(dim_type ii)
const {
360 assert(index_is_valid(ii));
return dim_type(idx2mask[ii].mask_dim);
362 index_type dim(dim_type ii)
const
363 { assert(index_is_valid(ii));
return index_to_mask(ii).ranges()[index_to_mask_dim(ii)];
365 tensor_mask_container& masks() {
return masks_; }
366 const tensor_mask_container& masks()
const {
return masks_; }
367 const tensor_mask& mask(dim_type i)
const { assert(i<masks_.size());
return masks_[i]; }
368 stride_type card(
bool just_look=
false)
const {
370 for (dim_type i=0; i < masks().size(); ++i)
371 n *= masks()[i].card(just_look);
374 void push_mask(
const tensor_mask& m) { masks_.push_back(m); update_idx2mask(); }
375 void remove_mask(dim_type mdim) {
377 masks_.erase(masks_.begin()+mdim);
380 void remove_unused_dimensions() {
382 for (dim_type i=0; i < ndim(); ++i) {
383 if (index_is_valid(i))
384 masks_[idx2mask[i].mask_num].indexes()[idx2mask[i].mask_dim] = nd++;
386 set_ndim_noclean(nd);
390 void update_idx2mask()
const {
398 std::fill(idx2mask.begin(), idx2mask.end(), tensor_index_to_mask());
399 for (dim_type i=0; i < masks_.size(); ++i) {
400 for (dim_type j=0; j < masks_[i].indexes().size(); ++j) {
401 dim_type k = masks_[i].indexes()[j];
402 GMM_ASSERT3(k < idx2mask.size() && !idx2mask[k].is_valid(),
"");
403 idx2mask[k].mask_num = i; idx2mask[k].mask_dim = j;
407 void assign_shape(
const tensor_shape& other) {
408 masks_ = other.masks_;
409 idx2mask = other.idx2mask;
412 void set_ndim(dim_type n) {
414 idx2mask.resize(n); update_idx2mask();
416 void set_ndim_noclean(dim_type n) {idx2mask.resize(n);}
421 explicit tensor_shape(dim_type nd) : idx2mask(nd,tensor_index_to_mask()) {
424 explicit tensor_shape(
const tensor_ranges& r) {
428 void set_full(
const tensor_ranges& r) {
429 idx2mask.resize(r.size());
430 masks_.resize(r.size());
431 for (dim_type i=0; i < r.size(); ++i) masks_[i].set_full(i,r[i]);
435 void set_empty(
const tensor_ranges& r) {
436 idx2mask.resize(r.size());
437 masks_.resize(r.size());
438 for (dim_type i=0; i < r.size(); ++i) masks_[i].set_empty(i,r[i]);
444 void merge(
const tensor_shape &ts2,
bool and_op =
true) {
446 GMM_ASSERT3(ts2.ndim() == ndim(),
"");
447 if (ts2.ndim()==0)
return;
448 for (dim_type i = 0; i < ndim(); ++i)
449 if (index_is_valid(i) && ts2.index_is_valid(i))
450 GMM_ASSERT3(ts2.dim(i) == dim(i),
"");
452 tensor_mask_container new_mask;
453 dal::bit_vector mask_treated1; mask_treated1.sup(0,masks().size());
454 dal::bit_vector mask_treated2; mask_treated2.sup(0,ts2.masks().size());
455 std::vector<const tensor_mask*> lstA, lstB; lstA.reserve(10); lstB.reserve(10);
456 for (dim_type i = 0; i < ndim(); ++i) {
457 dim_type i1 = dim_type(index_to_mask_num(i));
458 dim_type i2 = dim_type(ts2.index_to_mask_num(i));
459 lstA.clear(); lstB.clear();
460 if (index_is_valid(i) && !mask_treated1[i1])
461 find_linked_masks(i1, *
this, ts2, mask_treated1, mask_treated2,
463 else if (ts2.index_is_valid(i) && !mask_treated2[i2])
464 find_linked_masks(i2, ts2, *
this, mask_treated2, mask_treated1,
467 GMM_ASSERT3(lstA.size() || lstB.size(),
"");
468 new_mask.push_back(tensor_mask(lstA,lstB,and_op));
475 void shift_dim_num_ge(dim_type dim_num,
int shift) {
476 for (dim_type m = 0; m < masks().size(); ++m)
477 masks()[m].shift_dim_num_ge(dim_num,shift);
482 void permute(
const std::vector<dim_type> p,
bool revert=
false) {
483 std::vector<dim_type> invp(ndim()); std::fill(invp.begin(), invp.end(), dim_type(-1));
486 for (dim_type i=0; i < p.size(); ++i) {
487 if (p[i] != dim_type(-1)) {
488 assert(invp[p[i]] == dim_type(-1));
492 for (dim_type i=0; i < invp.size(); ++i) assert(invp[i] != dim_type(-1));
495 for (dim_type m=0; m < masks().size(); ++m) {
496 for (dim_type i=0; i < masks()[m].indexes().size(); ++i) {
498 masks()[m].indexes()[i] = invp[masks()[m].indexes()[i]];
500 masks()[m].indexes()[i] = p[masks()[m].indexes()[i]];
503 set_ndim_noclean(dim_type(p.size()));
509 tensor_shape slice_shape(tensor_mask::Slice slice)
const {
510 assert(slice.dim < ndim() && slice.i0 < dim(slice.dim));
511 tensor_shape ts(ndim());
512 ts.push_mask(tensor_mask(dim(slice.dim), slice));
517 tensor_shape diag_shape(tensor_mask::Diagonal diag)
const {
518 assert(diag.i1 != diag.i0 && diag.i0 < ndim() && diag.i1 < ndim());
519 assert(dim(diag.i0) == dim(diag.i1));
520 tensor_shape ts(ndim());
521 ts.push_mask(tensor_mask(dim(diag.i0), diag));
538 void print(std::ostream& o)
const;
539 void print_()
const { print(cerr); }
548 class tensor_ref :
public tensor_shape {
549 std::vector< tensor_strides > strides_;
554 stride_type base_shift_;
556 void remove_mask(dim_type mdim) {
557 tensor_shape::remove_mask(mdim);
558 assert(strides_[mdim].size() == 0 ||
559 (strides_[mdim].size() == 1 && strides_[mdim][0] == 0));
560 strides_.erase(strides_.begin()+mdim);
563 void swap(tensor_ref& tr) {
564 tensor_shape::swap(tr);
565 strides_.swap(tr.strides_);
566 std::swap(pbase_, tr.pbase_);
567 std::swap(base_shift_, tr.base_shift_);
569 const std::vector< tensor_strides >& strides()
const {
return strides_; }
570 std::vector< tensor_strides >& strides() {
return strides_; }
571 TDIter base()
const {
return (pbase_ ? (*pbase_) : 0); }
572 TDIter *pbase()
const {
return pbase_; }
573 stride_type base_shift()
const {
return base_shift_; }
574 void set_base(TDIter &new_base) { pbase_ = &new_base; base_shift_ = 0; }
576 void clear() { strides_.resize(0); pbase_ = 0; base_shift_ = 0; tensor_shape::clear(); }
581 void ensure_0_stride() {
582 for (index_type i=0; i < strides_.size(); ++i) {
583 if (strides_[i].size() >= 1 && strides_[i][0] != 0) {
584 stride_type s = strides_[i][0];
586 for (index_type j=0; j < strides_[i].size(); ++j)
594 explicit tensor_ref(
const tensor_shape& ts) : tensor_shape(ts), pbase_(0), base_shift_(0) {
595 strides_.reserve(16);
598 explicit tensor_ref(
const tensor_ranges& r, TDIter *pbase__=0)
599 : tensor_shape(r), pbase_(pbase__), base_shift_(0) {
600 strides_.reserve(16);
603 void init_strides() {
604 strides_.resize(masks().size());
606 for (dim_type i = 0; i < strides_.size(); ++i) {
607 index_type n = mask(i).card();
608 strides_[i].resize(n);
609 for (index_type j=0;j<n;++j)
610 strides_[i][j] = j*s;
614 tensor_ref() : pbase_(0), base_shift_(0) { strides_.reserve(16); }
616 void set_sub_tensor(
const tensor_ref& tr,
const tensor_shape& sub);
621 explicit tensor_ref(
const tensor_ref& tr,
const tensor_shape& sub) {
622 set_sub_tensor(tr,sub);
628 explicit tensor_ref(
const tensor_ref& tr, tensor_mask::Slice slice);
631 explicit tensor_ref(
const tensor_ref& tr, tensor_mask::Diagonal diag) {
632 set_sub_tensor(tr, tr.diag_shape(diag));
636 void print(std::ostream& o)
const;
638 void print_()
const { print(cerr); }
641 std::ostream&
operator<<(std::ostream& o,
const tensor_mask& m);
642 std::ostream&
operator<<(std::ostream& o,
const tensor_shape& ts);
643 std::ostream&
operator<<(std::ostream& o,
const tensor_ref& tr);
646 struct packed_range {
647 const stride_type *pinc;
648 const stride_type *begin, *end;
653 struct packed_range_info {
655 dim_type original_masknum;
657 std::vector<stride_type> mask_pos;
658 bool operator<(
const packed_range_info& pi)
const {
659 if (n < pi.n)
return true;
662 stride_type mean_increm;
667 std::bitset<32> have_regular_strides;
671 class multi_tensor_iterator {
673 std::vector<packed_range> pr;
674 std::vector<packed_range_info> pri;
676 std::vector<index_type> bloc_rank;
677 std::vector<index_type> bloc_nelt;
679 std::vector<TDIter> it;
680 std::vector<TDIter*> pit0;
681 tensor_strides itbase;
682 struct index_value_data {
684 const stride_type **ppinc;
688 const stride_type *pincbase;
689 const stride_type *pposbase;
691 index_type div, mod, nn;
695 std::vector<index_value_data> idxval;
696 std::vector<stride_type> vectorized_strides_;
697 index_type vectorized_size_;
698 index_type vectorized_pr_dim;
701 N = 0; pr.clear(); pri.clear(); bloc_rank.clear(); bloc_nelt.clear();
702 it.clear(); pit0.clear(); itbase.clear(); idxval.clear();
704 void swap(multi_tensor_iterator& m) {
705 std::swap(N,m.N); pr.swap(m.pr); pri.swap(m.pri);
706 bloc_rank.swap(m.bloc_rank); bloc_nelt.swap(m.bloc_nelt);
707 it.swap(m.it); pit0.swap(m.pit0); itbase.swap(m.itbase);
708 idxval.swap(m.idxval);
711 for (dim_type i=0; i < pr.size(); ++i) {
712 pr[i].pinc = pr[i].begin = &pri[i].inc[0];
713 pr[i].end = pr[i].begin+pri[i].inc.size();
715 for (dim_type n=0; n < N; ++n)
716 it[n] = *(pit0[n]) + itbase[n];
717 for (dim_type i=0; i < idxval.size(); ++i) {
718 if (idxval[i].cnt_num != dim_type(-1)) {
719 idxval[i].ppinc = &pr[idxval[i].cnt_num].pinc;
720 idxval[i].pincbase = &pri[idxval[i].cnt_num].inc[0];
721 idxval[i].pposbase = &pri[idxval[i].cnt_num].mask_pos[0];
722 idxval[i].nn = (N-pri[idxval[i].cnt_num].n);
724 static const stride_type *
null=0;
725 idxval[i].ppinc = &
null;
726 idxval[i].pincbase = 0;
727 idxval[i].pposbase = &idxval[i].pos_;
732 dim_type ndim()
const {
return dim_type(idxval.size()); }
734 index_type index(dim_type ii) {
735 index_value_data& iv = idxval[ii];
736 index_type cnt = index_type((*iv.ppinc - iv.pincbase)/iv.nn);
737 return ((iv.pposbase[cnt]) % iv.mod)/ iv.div;
739 index_type vectorized_size()
const {
return vectorized_size_; }
740 const std::vector<stride_type>& vectorized_strides()
const {
return vectorized_strides_; }
741 bool next(
unsigned i_stop =
unsigned(-1),
unsigned i0_ =
unsigned(-2)) {
742 unsigned i0 = unsigned(i0_ ==
unsigned(-2) ? pr.size()-1 : i0_);
743 while (i0 != i_stop) {
744 for (
unsigned n = pr[i0].n; n < N; ++n) {
746 it[n] += *pr[i0].pinc; pr[i0].pinc++;
748 if (pr[i0].pinc != pr[i0].end) {
751 pr[i0].pinc = pr[i0].begin;
757 bool vnext() {
return next(
unsigned(-1), vectorized_pr_dim); }
758 bool bnext(dim_type b) {
return next(bloc_rank[b]-1, bloc_rank[b+1]-1); }
759 bool bnext_useful(dim_type b) {
return bloc_rank[b] != bloc_rank[b+1]; }
763 if (pr.size() == 0)
return false;
764 std::vector<packed_range>::reverse_iterator p_ = pr.rbegin();
765 while (p_!=pr.rend()) {
766 it[0] += *(p_->pinc++);
767 if (p_->pinc != p_->end) {
770 p_->pinc = p_->begin;
778 if (pr.size() == 0)
return false;
779 std::vector<packed_range>::reverse_iterator p_ = pr.rbegin();
780 while (p_!=pr.rend()) {
781 it[0] += *(p_->pinc++);
782 it[1] += *(p_->pinc++);
783 if (p_->pinc != p_->end) {
786 p_->pinc = p_->begin;
793 scalar_type& p(dim_type n) {
return *it[n]; }
795 multi_tensor_iterator() {}
796 multi_tensor_iterator(std::vector<tensor_ref> trtab,
bool with_index_values) {
797 init(trtab, with_index_values);
799 void assign(std::vector<tensor_ref> trtab,
bool with_index_values) {
800 multi_tensor_iterator m(trtab, with_index_values);
803 multi_tensor_iterator(
const tensor_ref& tr0,
bool with_index_values) {
804 std::vector<tensor_ref> trtab(1); trtab[0] = tr0;
805 init(trtab, with_index_values);
807 void assign(
const tensor_ref& tr0,
bool with_index_values) {
808 multi_tensor_iterator m(tr0, with_index_values);
811 multi_tensor_iterator(
const tensor_ref& tr0,
812 const tensor_ref& tr1,
bool with_index_values) {
813 std::vector<tensor_ref> trtab(2); trtab[0] = tr0; trtab[1] = tr1;
814 init(trtab, with_index_values);
816 void assign(
const tensor_ref& tr0,
const tensor_ref& tr1,
bool with_index_values) {
817 multi_tensor_iterator m(tr0, tr1, with_index_values);
820 multi_tensor_iterator(
const tensor_ref& tr0,
821 const tensor_ref& tr1,
822 const tensor_ref& tr2,
bool with_index_values) {
823 std::vector<tensor_ref> trtab(3); trtab[0] = tr0; trtab[1] = tr1; trtab[2] = tr2;
824 init(trtab, with_index_values);
826 void assign(
const tensor_ref& tr0,
const tensor_ref& tr1,
const tensor_ref& tr2,
bool with_index_values) {
827 multi_tensor_iterator m(tr0, tr1, tr2, with_index_values);
830 void init(std::vector<tensor_ref> trtab,
bool with_index_values);
841 struct tensor_reduction {
842 struct tref_or_reduction {
844 std::shared_ptr<tensor_reduction> reduction;
845 tensor_ref &tr() {
return tr_; }
846 const tensor_ref &tr()
const {
return tr_; }
847 explicit tref_or_reduction(
const tensor_ref &tr__,
const std::string& s)
848 : tr_(tr__), ridx(s) {}
849 explicit tref_or_reduction(
const std::shared_ptr<tensor_reduction> &p,
const std::string& s)
850 : reduction(p), ridx(s) {
851 reduction->result(tr_);
853 bool is_reduction()
const {
return reduction != 0; }
854 void swap(tref_or_reduction &other) { tr_.swap(other.tr_); std::swap(reduction, other.reduction); }
857 std::vector<dim_type> gdim;
861 std::vector<dim_type> rdim;
866 tensor_ranges reduced_range;
867 std::string reduction_chars;
869 typedef std::vector<tref_or_reduction>::iterator trtab_iterator;
870 std::vector<tref_or_reduction> trtab;
871 multi_tensor_iterator mti;
872 std::vector<scalar_type> out_data;
875 tensor_reduction() {
clear(); }
876 virtual ~tensor_reduction() {
clear(); }
884 static void diag_shape(tensor_shape& ts,
const std::string& s) {
885 for (index_type i=0; i < s.length(); ++i) {
887 if (s[i] !=
' ' && pos != i)
888 ts = ts.diag_shape(tensor_mask::Diagonal(dim_type(pos),dim_type(i)));
892 void insert(
const tensor_ref& tr_,
const std::string& s);
893 void prepare(
const tensor_ref* tr_out = NULL);
895 void result(tensor_ref& res)
const {
897 res.remove_unused_dimensions();
900 void insert(
const tref_or_reduction& tr_,
const std::string& s);
901 void update_reduction_chars();
903 void make_sub_reductions();
904 size_type find_best_sub_reduction(dal::bit_vector &best_lst, std::string &best_idxset);
defines and typedefs for namespace bgeot
Provide a dynamic bit container.
void clear(L &l)
clear (fill with zeros) a vector or matrix.
Definition of basic exceptions.
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