Cyclops Tensor Framework
parallel arithmetic on multidimensional arrays
term.cxx
Go to the documentation of this file.
1 /*Copyright (c) 2013, Edgar Solomonik, all rights reserved.*/
2 
3 #include "common.h"
4 #include "idx_tensor.h"
5 #include "../tensor/algstrct.h"
6 #include "../summation/summation.h"
7 #include "../contraction/contraction.h"
8 
9 using namespace CTF;
10 
11 
12 namespace CTF_int {
13  algstrct const * get_double_ring();
14  algstrct const * get_float_ring();
15  algstrct const * get_int64_t_ring();
16  algstrct const * get_int_ring();
17 }
18 
19 namespace CTF_int {
20 /*
21  Idx_Tensor * get_full_intm(Idx_Tensor& A,
22  Idx_Tensor& B){
23  int * len_C, * sym_C;
24  char * idx_C;
25  int order_C, i, j, idx;
26 
27  order_C = 0;
28  for (i=0; i<A.parent->order; i++){
29  order_C++;
30  for (j=0; j<i; j++){
31  if (A.idx_map[i] == A.idx_map[j]){
32  order_C--;
33  break;
34  }
35  }
36  }
37  for (j=0; j<B.parent->order; j++){
38  order_C++;
39  for (i=0; i<std::max(A.parent->order, B.parent->order); i++){
40  if (i<j && B.idx_map[i] == B.idx_map[j]){
41  order_C--;
42  break;
43  }
44  if (i<A.parent->order && A.idx_map[i] == B.idx_map[j]){
45  order_C--;
46  break;
47  }
48  }
49  }
50 
51 
52  idx_C = (char*)alloc(sizeof(char)*order_C);
53  sym_C = (int*)alloc(sizeof(int)*order_C);
54  len_C = (int*)alloc(sizeof(int)*order_C);
55  idx = 0;
56  for (i=0; i<A.parent->order; i++){
57  for (j=0; j<i && A.idx_map[i] != A.idx_map[j]; j++){}
58  if (j!=i) continue;
59  idx_C[idx] = A.idx_map[i];
60  len_C[idx] = A.parent->lens[i];
61  if (idx >= 1 && i >= 1 && idx_C[idx-1] == A.idx_map[i-1] && A.parent->sym[i-1] != NS){
62  sym_C[idx-1] = A.parent->sym[i-1];
63  }
64  sym_C[idx] = NS;
65  idx++;
66  }
67  int order_AC = idx;
68  for (j=0; j<B.parent->order; j++){
69  for (i=0; i<j && B.idx_map[i] != B.idx_map[j]; i++){}
70  if (i!=j) continue;
71  for (i=0; i<order_AC && idx_C[i] != B.idx_map[j]; i++){}
72  if (i!=order_AC){
73  if (sym_C[i] != NS) {
74  if (i==0){
75  if (B.parent->sym[i] != sym_C[j]){
76  sym_C[j] = NS;
77  }
78  } else if (j>0 && idx_C[i+1] == B.idx_map[j-1]){
79  if (B.parent->sym[j-1] == NS)
80  sym_C[j] = NS;
81  } else if (B.parent->sym[j] != sym_C[j]){
82  sym_C[j] = NS;
83  } else if (idx_C[i+1] != B.idx_map[j+1]){
84  sym_C[j] = NS;
85  }
86  }
87  continue;
88  }
89  idx_C[idx] = B.idx_map[j];
90  len_C[idx] = B.parent->lens[j];
91  if (idx >= 1 && j >= 1 && idx_C[idx-1] == B.idx_map[j-1] && B.parent->sym[j-1] != NS){
92  sym_C[idx-1] = B.parent->sym[j-1];
93  }
94  sym_C[idx] = NS;
95  idx++;
96  }
97  bool is_sparse_C = A.parent->is_sparse && B.parent->is_sparse;
98  tensor * tsr_C = new tensor(A.parent->sr, order_C, len_C, sym_C, A.parent->wrld, true, NULL, 1, is_sparse_C);
99  Idx_Tensor * out = new Idx_Tensor(tsr_C, idx_C);
100  //printf("A_inds =");
101  //for (int i=0; i<A.parent->order; i++){
102  // printf("%c",A.idx_map[i]);
103  //}
104  //printf("B_inds =");
105  //for (int i=0; i<B.parent->order; i++){
106  // printf("%c",B.idx_map[i]);
107  //}
108  //printf("C_inds =");
109  //for (int i=0; i<order_C; i++){
110  // printf("%c",idx_C[i]);
111  //}
112  //printf("\n");
113  out->is_intm = 1;
114  cdealloc(sym_C);
115  cdealloc(len_C);
116  cdealloc(idx_C);
117  return out;
118 
119  }*/
120 
122  Idx_Tensor& B,
123  std::vector<char> out_inds,
124  bool create_dummy=false){
125 
126  int * len_C, * sym_C;
127  char * idx_C;
128  int order_C, i, j;
129  int num_out_inds = (int)out_inds.size();
130  idx_C = (char*)alloc(sizeof(char)*num_out_inds);
131  sym_C = (int*)alloc(sizeof(int)*num_out_inds);
132  len_C = (int*)alloc(sizeof(int)*num_out_inds);
133  order_C = 0;
134  //FIXME: symmetry logic is incorrect here, setting all intermediates to fully nonsymmetric for now
135  for (j=0; j<num_out_inds; j++){
136  bool found = false;
137  int len = -1;
138  int sym_prev = -1;
139  for (i=0; i<A.parent->order; i++){
140  if (A.idx_map[i] == out_inds[j]){
141  found = true;
142  len = A.parent->lens[i];
143  if (sym_prev != -1) sym_prev = NS;
144  else if (i>0 && order_C>0 && A.idx_map[i-1] == idx_C[order_C-1]) sym_prev = A.parent->sym[i-1];
145  else sym_prev = NS;
146  }
147  }
148  if (!found){
149  for (i=0; i<B.parent->order; i++){
150  if (B.idx_map[i] == out_inds[j]){
151  found = true;
152  len = B.parent->lens[i];
153  if (sym_prev != NS && i>0 && order_C>0 && B.idx_map[i-1] == idx_C[order_C-1]) sym_prev = B.parent->sym[i-1];
154  else sym_prev = NS;
155 
156  }
157  }
158  }
159  if (found){
160  idx_C[order_C] = out_inds[j];
161  len_C[order_C] = len;
162  //if (sym_prev > 0)
163  // sym_C[order_C-1] = sym_prev;
164  sym_C[order_C] = NS;
165  order_C++;
166  }
167  }
168  bool is_sparse_C = A.parent->is_sparse && B.parent->is_sparse;
169  tensor * tsr_C = new tensor(A.parent->sr, order_C, len_C, sym_C, A.parent->wrld, true, NULL, !create_dummy, is_sparse_C);
170  Idx_Tensor * out = new Idx_Tensor(tsr_C, idx_C);
171  out->is_intm = 1;
172  cdealloc(sym_C);
173  cdealloc(len_C);
174  cdealloc(idx_C);
175  return out;
176  }
177 
178  //general Term functions, see ../../include/ctf.hpp for doxygen comments
179 
180  /*Term::operator dtype() const {
181  assert(where_am_i() != NULL);
182  Scalar sc(*where_am_i());
183  Idx_Tensor isc(&sc,"");
184  execute(isc);
185  // delete isc;
186  return sc.get_val();
187  }*/
188 
189  //
190  //void Term::execute(Idx_Tensor output){
191  // ABORT; //I don't see why this part of the code should ever be reached
193  //}
194  //
195  //
196  //Idx_Tensor Term::execute(){
197  // ABORT; //I don't see why this part of the code should ever be reached
198  // return Idx_Tensor();
199  //}
200 
201 
202  Term::Term(algstrct const * sr_){
203  sr = sr_->clone();
204  scale = NULL; // (char*)alloc(sr->el_size);
205  sr->safecopy(scale,sr->mulid());
206  }
207 
208  Term::~Term(){
209  delete sr;
210  if (scale != NULL){
211  cdealloc(scale);
212  scale = NULL;
213  }
214  }
215 
216  void Term::mult_scl(char const * mulscl){
217  sr->safemul(scale,mulscl,scale);
218  }
219 
220  Contract_Term Term::operator*(Term const & A) const {
221  Contract_Term trm(this->clone(),A.clone());
222  return trm;
223  }
224 
225 
226  Sum_Term Term::operator+(Term const & A) const {
227  Sum_Term trm(this->clone(),A.clone());
228  return trm;
229  }
230 
231 
232  Sum_Term Term::operator-(Term const & A) const {
233  Sum_Term trm(this->clone(),A.clone());
234 
235  if (trm.operands[1]->scale == NULL)
236  trm.operands[1]->scale = (char*)alloc(sr->el_size);
237  sr->safeaddinv(A.scale, trm.operands[1]->scale);
238  return trm;
239  }
240 
241  void Term::operator=(CTF::Idx_Tensor const & B){ this->execute(this->get_uniq_inds()) = B; }
242  void Term::operator=(Term const & B){ this->execute(this->get_uniq_inds()) = B; }
243  void Term::operator+=(Term const & B){ this->execute(this->get_uniq_inds()) += B; }
244  void Term::operator-=(Term const & B){ this->execute(this->get_uniq_inds()) -= B; }
245  void Term::operator*=(Term const & B){ this->execute(this->get_uniq_inds()) *= B; }
246 
247  void Term::operator=(double scl){ this->execute(this->get_uniq_inds()) = Idx_Tensor(sr,scl); }
248  void Term::operator+=(double scl){ this->execute(this->get_uniq_inds()) += Idx_Tensor(sr,scl); }
249  void Term::operator-=(double scl){ this->execute(this->get_uniq_inds()) -= Idx_Tensor(sr,scl); }
250  void Term::operator*=(double scl){ this->execute(this->get_uniq_inds()) *= Idx_Tensor(sr,scl); }
251 
252  void Term::operator=(int64_t scl){ this->execute(this->get_uniq_inds()) = Idx_Tensor(sr,scl); }
253  void Term::operator+=(int64_t scl){ this->execute(this->get_uniq_inds()) += Idx_Tensor(sr,scl); }
254  void Term::operator-=(int64_t scl){ this->execute(this->get_uniq_inds()) -= Idx_Tensor(sr,scl); }
255  void Term::operator*=(int64_t scl){ this->execute(this->get_uniq_inds()) *= Idx_Tensor(sr,scl); }
256  void Term::operator=(int scl){ this->execute(this->get_uniq_inds()) = Idx_Tensor(sr,(int64_t)scl); }
257  void Term::operator+=(int scl){ this->execute(this->get_uniq_inds()) += Idx_Tensor(sr,(int64_t)scl); }
258  void Term::operator-=(int scl){ this->execute(this->get_uniq_inds()) -= Idx_Tensor(sr,(int64_t)scl); }
259  void Term::operator*=(int scl){ this->execute(this->get_uniq_inds()) *= Idx_Tensor(sr,(int64_t)scl); }
260 
261 
262 
263  Term & Term::operator-(){
264  sr->safeaddinv(scale,scale);
265  return *this;
266  }
267 /*
268  Contract_Term Contract_Term::operator-() const {
269  Contract_Term trm(*this);
270  sr->safeaddinv(trm.scale,trm.scale);
271  return trm;
272  }*/
273 
275  Idx_Tensor iscl(sr, scl);
276  Contract_Term trm(this->clone(),iscl.clone());
277  return trm;
278  }
279 
281  Idx_Tensor iscl(sr, scl);
282  Contract_Term trm(this->clone(),iscl.clone());
283  return trm;
284  }
285 
286  Term::operator float () const {
287  CTF_int::tensor ts(get_float_ring(), 0, NULL, NULL, this->where_am_i(), true, NULL, 0);
288  ts[""] += *this;
289  float dbl = ((float*)ts.data)[0];
290  ts.wrld->cdt.bcast(&dbl, 1, MPI_DOUBLE, 0);
291  return dbl;
292 
293  }
294 
295  Term::operator double () const {
296  //return 0.0 += *this;
297  CTF_int::tensor ts(get_double_ring(), 0, NULL, NULL, this->where_am_i(), true, NULL, 0);
298  ts[""] += *this;
299  double dbl = ((double*)ts.data)[0];
300  ts.wrld->cdt.bcast(&dbl, 1, MPI_DOUBLE, 0);
301  return dbl;
302  /*int64_t s;
303  CTF_int::tensor ts(sr, 0, NULL, NULL, where_am_i(), true, NULL, 0);
304  Idx_Tensor iscl(&ts,"");
305  execute(iscl);
306  char val[sr->el_size];
307  char * datap;
308  iscl.parent->get_raw_data(&datap,&s);
309  memcpy(val, datap, sr->el_size);
310  MPI_Bcast(val, sr->el_size, MPI_CHAR, 0, where_am_i()->comm);
311  return sr->cast_to_double(val);*/
312  }
313 
314  Term::operator int () const {
315  CTF_int::tensor ts(get_int_ring(), 0, NULL, NULL, this->where_am_i(), true, NULL, 0);
316  ts[""] += *this;
317  int dbl = ((int*)ts.data)[0];
318  ts.wrld->cdt.bcast(&dbl, 1, MPI_INT64_T, 0);
319  return dbl;
320 
321  }
322 
323  Term::operator int64_t () const {
324  CTF_int::tensor ts(get_int64_t_ring(), 0, NULL, NULL, this->where_am_i(), true, NULL, 0);
325  ts[""] += *this;
326  int64_t dbl = ((int64_t*)ts.data)[0];
327  ts.wrld->cdt.bcast(&dbl, 1, MPI_INT64_T, 0);
328  return dbl;
329 
330  //int64_t s;
331  //CTF_int::tensor ts(sr, 0, NULL, NULL, where_am_i(), true, NULL, 0);
332  //Idx_Tensor iscl(&ts,"");
333  //execute(iscl);
334  //char val[sr->el_size];
335  //char * datap;
336  //iscl.parent->get_raw_data(&datap,&s);
337  //memcpy(val, datap, sr->el_size);
338  //MPI_Bcast(val, sr->el_size, MPI_CHAR, 0, where_am_i()->comm);
339  //return sr->cast_to_int(val);
340  }
341 
342 
343 
344  //functions spectific to Sum_Term
345 
346  Sum_Term::Sum_Term(Term * B, Term * A) : Term(A->sr) {
347  operands.push_back(B);
348  operands.push_back(A);
349  }
350 
352  for (int i=0; i<(int)operands.size(); i++){
353  delete operands[i];
354  }
355  operands.clear();
356  }
357 
358 
360  Sum_Term const & other,
361  std::map<tensor*, tensor*>* remap) : Term(other.sr) {
362  sr->safecopy(this->scale, other.scale);
363  for (int i=0; i<(int)other.operands.size(); i++){
364  this->operands.push_back(other.operands[i]->clone(remap));
365  }
366  }
367 
368 
369  Term * Sum_Term::clone(std::map<tensor*, tensor*>* remap) const{
370  return new Sum_Term(*this, remap);
371  }
372 
373 
374  Sum_Term Sum_Term::operator+(Term const & A) const {
375  Sum_Term st(*this);
376  st.operands.push_back(A.clone());
377  return st;
378  }
379 /*
380  Sum_Term Sum_Term::operator-() const {
381  Sum_Term trm(*this);
382  sr->safeaddinv(trm.scale,trm.scale);
383  return trm;
384  }*/
385 
386  Sum_Term Sum_Term::operator-(Term const & A) const {
387  Sum_Term st(*this);
388  st.operands.push_back(A.clone());
389  sr->safeaddinv(A.scale, st.operands.back()->scale);
390  return st;
391  }
392 
393  Idx_Tensor Sum_Term::estimate_time(double & cost, std::vector<char> out_inds) const {
394  std::vector< Term* > tmp_ops;
395  for (int i=0; i<(int)operands.size(); i++){
396  tmp_ops.push_back(operands[i]->clone());
397  }
398  while (tmp_ops.size() > 1){
399  Term * pop_A = tmp_ops.back();
400  tmp_ops.pop_back();
401  Term * pop_B = tmp_ops.back();
402  tmp_ops.pop_back();
403  Idx_Tensor op_A = pop_A->estimate_time(cost, out_inds);
404  Idx_Tensor op_B = pop_B->estimate_time(cost, out_inds);
405  Idx_Tensor * intm = get_full_intm(op_A, op_B, out_inds, true);
406  summation s1(op_A.parent, op_A.idx_map, op_A.scale,
407  intm->parent, intm->idx_map, intm->scale);
408  cost += s1.estimate_time();
409  summation s2(op_B.parent, op_B.idx_map, op_B.scale,
410  intm->parent, intm->idx_map, intm->scale);
411  cost += s2.estimate_time();
412  tmp_ops.push_back(intm);
413  delete pop_A;
414  delete pop_B;
415  }
416  Idx_Tensor ans = tmp_ops[0]->estimate_time(cost, out_inds);
417  delete tmp_ops[0];
418  tmp_ops.clear();
419  return ans;
420  }
421 
422  std::vector<char> det_uniq_inds(std::vector< Term* > const operands, std::vector<char> const out_inds){
423  std::set<char> uniq_inds;
424  std::set<Idx_Tensor*, tensor_name_less > inputs;
425  for (int j=0; j<(int)operands.size(); j++){
426  operands[j]->get_inputs(&inputs);
427  }
428  for (std::set<Idx_Tensor*>::iterator j=inputs.begin(); j!=inputs.end(); j++){
429  if ((*j)->parent != NULL){
430  for (int k=0; k<(*j)->parent->order; k++){
431  uniq_inds.insert((*j)->idx_map[k]);
432  }
433  }
434  }
435  for (int j=0; j<(int)out_inds.size(); j++){
436  uniq_inds.insert(out_inds[j]);
437  }
438  return std::vector<char>(uniq_inds.begin(), uniq_inds.end());
439  }
440 
441 
442  double Sum_Term::estimate_time(Idx_Tensor output) const{
443  double cost = 0.0;
444  this->estimate_time(cost, output.get_uniq_inds());
445  return cost;
446  }
447 
448  Idx_Tensor Sum_Term::execute(std::vector<char> out_inds) const {
449  std::vector< Term* > tmp_ops;
450  for (int i=0; i<(int)operands.size(); i++){
451  tmp_ops.push_back(operands[i]->clone());
452  }
453  while (tmp_ops.size() > 1){
454  Term * pop_A = tmp_ops.back();
455  tmp_ops.pop_back();
456  Term * pop_B = tmp_ops.back();
457  tmp_ops.pop_back();
458  Idx_Tensor op_A = pop_A->execute(out_inds);
459  Idx_Tensor op_B = pop_B->execute(out_inds);
460  Idx_Tensor * intm = get_full_intm(op_A, op_B, out_inds);
461  summation s1(op_A.parent, op_A.idx_map, op_A.scale,
462  intm->parent, intm->idx_map, intm->scale);
463  s1.execute();
464  //a little sloopy but intm->scale should always be 1 here
465  summation s2(op_B.parent, op_B.idx_map, op_B.scale,
466  intm->parent, intm->idx_map, intm->scale);
467  s2.execute();
468  tmp_ops.push_back(intm);
469  delete pop_A;
470  delete pop_B;
471  }
472  sr->safemul(tmp_ops[0]->scale, this->scale, tmp_ops[0]->scale);
473  Idx_Tensor ans = tmp_ops[0]->execute(out_inds);
474  delete tmp_ops[0];
475  tmp_ops.clear();
476  return ans;
477  }
478 
479 
480  void Sum_Term::execute(Idx_Tensor output) const{
481  //below commented method can be faster but is unsatisfactory, because output may be an operand in a later term
482  /*std::vector< Term* > tmp_ops = operands;
483  for (int i=0; i<((int)tmp_ops.size())-1; i++){
484  tmp_ops[i]->execute(output);
485  sr->safecopy(output.scale, sr->mulid());
486  }*/
487  Idx_Tensor itsr = this->execute(output.get_uniq_inds());
488  summation s(itsr.parent, itsr.idx_map, itsr.scale, output.parent, output.idx_map, output.scale);
489  s.execute();
490  }
491 
492  std::vector<char> Sum_Term::get_uniq_inds() const{
493  return det_uniq_inds(operands, std::vector<char>());
494  }
495 
496  void Sum_Term::get_inputs(std::set<Idx_Tensor*, tensor_name_less >* inputs_set) const {
497  for (int i=0; i<(int)operands.size(); i++){
498  operands[i]->get_inputs(inputs_set);
499  }
500  }
501 
502 
504  World * w = NULL;
505  for (int i=0; i<(int)operands.size(); i++){
506  if (operands[i]->where_am_i() != NULL) {
507  w = operands[i]->where_am_i();
508  }
509  }
510  return w;
511  }
512 
513 
514  //functions spectific to Contract_Term
515 
517  for (int i=0; i<(int)operands.size(); i++){
518  delete operands[i];
519  }
520  operands.clear();
521  }
522 
523 
525  World * w = NULL;
526  for (int i=0; i<(int)operands.size(); i++){
527  if (operands[i]->where_am_i() != NULL) {
528  w = operands[i]->where_am_i();
529  }
530  }
531  return w;
532  }
533 
534 
536  operands.push_back(B);
537  operands.push_back(A);
538  }
539 
540 
542  Contract_Term const & other,
543  std::map<tensor*, tensor*>* remap) : Term(other.sr) {
544  sr->safecopy(this->scale, other.scale);
545  for (int i=0; i<(int)other.operands.size(); i++){
546  Term * t = other.operands[i]->clone(remap);
547  operands.push_back(t);
548  }
549  }
550 
551 
552  Term * Contract_Term::clone(std::map<tensor*, tensor*>* remap) const {
553  return new Contract_Term(*this, remap);
554  }
555 
556 
558  Contract_Term ct(*this);
559  ct.operands.push_back(A.clone());
560  return ct;
561  }
562 
563  std::vector< Term* > contract_down_terms(algstrct * sr, char * tscale, std::vector< Term* > operands, std::vector<char> out_inds, int terms_to_leave, bool est_time=false, double * cost=NULL){
564  std::vector< Term* > tmp_ops;
565  for (int i=0; i<(int)operands.size(); i++){
566  tmp_ops.push_back(operands[i]->clone());
567  }
568  while (tmp_ops.size() > terms_to_leave){
569  Term * pop_A = tmp_ops.back();
570  tmp_ops.pop_back();
571  //include all terms except the one to execute to determine out_inds for executing that term
572  std::vector<char> out_inds_A = det_uniq_inds(tmp_ops, out_inds);
573  Term * pop_B = tmp_ops.back();
574  tmp_ops.pop_back();
575  tmp_ops.push_back(pop_A);
576  std::vector<char> out_inds_B = det_uniq_inds(tmp_ops, out_inds);
577  tmp_ops.pop_back();
578  Idx_Tensor * op_A;
579  Idx_Tensor * op_B;
580  if (est_time){
581  op_A = new Idx_Tensor(pop_A->estimate_time(*cost,out_inds_A));
582  op_B = new Idx_Tensor(pop_B->estimate_time(*cost,out_inds_B));
583  } else {
584  op_A = new Idx_Tensor(pop_A->execute(out_inds_A));
585  op_B = new Idx_Tensor(pop_B->execute(out_inds_B));
586  }
587  if (op_A->parent == NULL) {
588  sr->safemul(op_A->scale, op_B->scale, op_B->scale);
589  tmp_ops.push_back(op_B->clone());
590  } else if (op_B->parent == NULL) {
591  sr->safemul(op_A->scale, op_B->scale, op_A->scale);
592  tmp_ops.push_back(op_A->clone());
593  } else {
594  Idx_Tensor * intm = get_full_intm(*op_A, *op_B, det_uniq_inds(tmp_ops, out_inds), !est_time);
595  sr->safemul(tscale, op_A->scale, tscale);
596  sr->safemul(tscale, op_B->scale, tscale);
597  contraction c(op_A->parent, op_A->idx_map,
598  op_B->parent, op_B->idx_map, tscale,
599  intm->parent, intm->idx_map, intm->scale);
600  if (est_time){
601  *cost += c.estimate_time();
602  } else {
603  c.execute();
604  }
605  sr->safecopy(tscale, sr->mulid());
606  tmp_ops.push_back(intm);
607  }
608  delete op_A;
609  delete op_B;
610  delete pop_A;
611  delete pop_B;
612  }
613  return tmp_ops;
614  }
615 
616  void Contract_Term::execute(Idx_Tensor output) const {
617  std::vector<char> out_inds = output.get_uniq_inds();
618  char * tscale = NULL;
619  sr->safecopy(tscale, scale);
620  std::vector< Term* > tmp_ops = contract_down_terms(sr, tscale, operands, out_inds, 2);
621  {
622  assert(tmp_ops.size() == 2);
623  Term * pop_B = tmp_ops.back();
624  tmp_ops.pop_back();
625  //include all terms except the one to execute to determine out_inds for executing that term
626  std::vector<char> out_inds_B = det_uniq_inds(tmp_ops, out_inds);
627  Term * pop_A = tmp_ops.back();
628  tmp_ops.pop_back();
629  tmp_ops.push_back(pop_B);
630  std::vector<char> out_inds_A = det_uniq_inds(tmp_ops, out_inds);
631  tmp_ops.pop_back();
632  Idx_Tensor op_A = pop_A->execute(out_inds_A);
633  Idx_Tensor op_B = pop_B->execute(out_inds_B);
634  /*if (tscale != NULL) cdealloc(tscale);
635  tscale = NULL;
636  sr->safecopy(tscale, this->scale);*/
637  sr->safemul(tscale, op_A.scale, tscale);
638  sr->safemul(tscale, op_B.scale, tscale);
639 
640  if (op_A.parent == NULL && op_B.parent == NULL){
641  assert(0); //FIXME write scalar to whole tensor
642  } else if (op_A.parent == NULL){
643  summation s(op_B.parent, op_B.idx_map, tscale,
644  output.parent, output.idx_map, output.scale);
645  s.execute();
646  } else if (op_B.parent == NULL){
647  summation s(op_A.parent, op_A.idx_map, tscale,
648  output.parent, output.idx_map, output.scale);
649  s.execute();
650  } else {
651  contraction c(op_A.parent, op_A.idx_map,
652  op_B.parent, op_B.idx_map, tscale,
653  output.parent, output.idx_map, output.scale);
654  c.execute();
655  }
656  if (tscale != NULL) cdealloc(tscale);
657  tscale = NULL;
658  delete pop_A;
659  delete pop_B;
660  }
661  }
662 
663 
664  Idx_Tensor Contract_Term::execute(std::vector<char> out_inds) const {
665  char * tscale = NULL;
666  sr->safecopy(tscale, scale);
667  std::vector< Term* > tmp_ops = contract_down_terms(sr, scale, operands, out_inds, 1);
668  Idx_Tensor rtsr = tmp_ops[0]->execute(out_inds);
669  delete tmp_ops[0];
670  tmp_ops.clear();
671  if (tscale != NULL) cdealloc(tscale);
672  tscale = NULL;
673  return rtsr;
674  }
675 
676 
678  double cost = 0.0;
679  std::vector<char> out_inds = output.get_uniq_inds();
680  std::vector< Term* > tmp_ops = contract_down_terms(sr, scale, operands, out_inds, 2, true, &cost);
681  {
682  assert(tmp_ops.size() == 2);
683  Term * pop_B = tmp_ops.back();
684  tmp_ops.pop_back();
685  //include all terms except the one to execute to determine out_inds for executing that term
686  std::vector<char> out_inds_B = det_uniq_inds(tmp_ops, out_inds);
687  Term * pop_A = tmp_ops.back();
688  tmp_ops.pop_back();
689  tmp_ops.push_back(pop_B);
690  std::vector<char> out_inds_A = det_uniq_inds(tmp_ops, out_inds);
691  tmp_ops.pop_back();
692  Idx_Tensor op_A = pop_A->estimate_time(cost,out_inds);
693  Idx_Tensor op_B = pop_B->estimate_time(cost,out_inds);
694 
695  if (op_A.parent == NULL && op_B.parent == NULL){
696  assert(0); //FIXME write scalar to whole tensor
697  } else if (op_A.parent == NULL){
698  summation s(op_B.parent, op_B.idx_map, this->scale,
699  output.parent, output.idx_map, output.scale);
700  cost += s.estimate_time();
701  } else if (op_B.parent == NULL){
702  summation s(op_A.parent, op_A.idx_map, this->scale,
703  output.parent, output.idx_map, output.scale);
704  cost += s.estimate_time();
705  } else {
706  contraction c(op_A.parent, op_A.idx_map,
707  op_B.parent, op_B.idx_map, this->scale,
708  output.parent, output.idx_map, output.scale);
709  cost += c.estimate_time();
710  }
711  delete pop_A;
712  delete pop_B;
713  }
714  return cost;
715  }
716 
717 
718  Idx_Tensor Contract_Term::estimate_time(double & cost, std::vector<char> out_inds) const {
719  std::vector< Term* > tmp_ops = contract_down_terms(sr, scale, operands, out_inds, 1, true, &cost);
720  return tmp_ops[0]->estimate_time(cost, out_inds);
721  }
722 
723  std::vector<char> Contract_Term::get_uniq_inds() const{
724  return det_uniq_inds(operands, std::vector<char>());
725  }
726 
727  void Contract_Term::get_inputs(std::set<Idx_Tensor*, tensor_name_less >* inputs_set) const {
728  for (int i=0; i<(int)operands.size(); i++){
729  operands[i]->get_inputs(inputs_set);
730  }
731  }
732 
733  void operator-=(double & d, CTF_int::Term const & tsr){
734  d -= (double)tsr;
735  }
736 
737  void Term::operator<<(Term const & B){
738  B.execute(this->execute(this->get_uniq_inds()));
739  sr->safecopy(scale,sr->mulid());
740  }
741  void Term::operator<<(double scl){ this->execute(this->get_uniq_inds()) += Idx_Tensor(sr,scl); }
742 
743 
744  void operator+=(double & d, CTF_int::Term const & tsr){
745  d += (double)tsr;
746  }
747  void operator-=(int64_t & d, CTF_int::Term const & tsr){
748  d -= (int64_t)tsr;
749  }
750 
751  void operator+=(int64_t & d, CTF_int::Term const & tsr){
752  d += (int64_t)tsr;
753  }
754 }
755 
756 
757 namespace CTF_int {
759  if (A == NULL && B != NULL) {
760  return true;
761  } else if (A == NULL || B == NULL) {
762  return false;
763  }
764  if (A->parent == NULL && B->parent != NULL) {
765  return true;
766  } else if (A->parent == NULL || B->parent == NULL) {
767  return false;
768  }
769  int d = strcmp(A->parent->name, B->parent->name);
770  if (d>0) return d;
771  else return 1;
772  /*assert(0);//FIXME
773  //return A->tid < B->tid;
774  return -1;*/
775  }
776 }
777 
778 
779 
780 
a term is an abstract object representing some expression of tensors
Definition: term.h:33
CTF_int::algstrct const * get_double_ring()
Definition: ring.cxx:10
algstrct * sr
Definition: term.h:36
void operator-=(Term const &B)
Definition: term.cxx:244
Sum_Term operator+(Term const &A) const
constructs a new term by addition of two terms
Definition: term.cxx:374
void get_inputs(std::set< CTF::Idx_Tensor *, tensor_name_less > *inputs_set) const
appends the tensors this depends on to the input set
Definition: term.cxx:727
CTF_int::CommData cdt
communicator data for MPI comm defining this world
Definition: world.h:32
virtual void execute(CTF::Idx_Tensor output) const =0
evalues the expression, which just scales by default
int * sym
symmetries among tensor dimensions
void execute()
run contraction
Definition: contraction.cxx:99
virtual algstrct * clone() const =0
&#39;&#39;copy constructor&#39;&#39;
void get_inputs(std::set< CTF::Idx_Tensor *, tensor_name_less > *inputs_set) const
appends the tensors this depends on to the input set
Definition: term.cxx:496
Term & operator-()
Definition: term.cxx:263
double estimate_time(CTF::Idx_Tensor output) const
estimates the cost of a sum term
Definition: term.cxx:442
Contract_Term operator*(Term const &A) const
override contraction to grow vector rather than create recursive terms
Definition: term.cxx:557
void safecopy(char *&a, char const *b) const
copies element b to element a, , with checks for NULL and alloc as necessary
Definition: algstrct.cxx:529
CTF::World * where_am_i() const
negates term
Definition: term.cxx:503
void execute(bool run_diag=false)
run summation
Definition: summation.cxx:119
char * idx_map
Definition: idx_tensor.h:18
Sum_Term(Term *B, Term *A)
creates sum term for B+A
Definition: term.cxx:346
std::vector< char > get_uniq_inds() const
find list of unique indices that are involved in this term
Definition: term.cxx:492
void * alloc(int64_t len)
alloc abstraction
Definition: memcontrol.cxx:365
Definition: common.h:37
void operator<<(CTF_int::Term const &B)
Definition: term.cxx:737
Term * clone(std::map< tensor *, tensor * > *remap=NULL) const
base classes must implement this copy function to retrieve pointer
Definition: term.cxx:552
an instance of the CTF library (world) on a MPI communicator
Definition: world.h:19
virtual void safemul(char const *a, char const *b, char *&c) const
c = a*b, with NULL treated as mulid
Definition: algstrct.cxx:126
bool is_sparse
whether only the non-zero elements of the tensor are stored
int order
number of tensor dimensions
void operator-=(int64_t &d, CTF_int::Term const &tsr)
Definition: term.cxx:747
CTF::World * where_am_i() const
negates term
Definition: term.cxx:524
double estimate_time()
predicts execution time in seconds using performance models
Definition: summation.cxx:132
CTF::World * wrld
distributed processor context on which tensor is defined
std::vector< Term * > operands
Definition: term.h:277
double estimate_time(CTF::Idx_Tensor output) const
estimates the cost of a contract term
Definition: term.cxx:677
std::vector< char > get_uniq_inds() const
find list of unique indices that are involved in this term
Definition: term.cxx:723
def scale(self, scl)
Definition: core.pyx:325
class for execution distributed contraction of tensors
Definition: contraction.h:16
int * lens
unpadded tensor edge lengths
virtual Term * clone(std::map< tensor *, tensor * > *remap=NULL) const =0
base classes must implement this copy function to retrieve pointer
Contract_Term(Term *B, Term *A)
creates sum term for B+A
Definition: term.cxx:535
CTF_int::algstrct const * get_int_ring()
Definition: ring.cxx:14
void execute(CTF::Idx_Tensor output) const
evalues the expression by summing operands into output
Definition: term.cxx:480
algstrct * sr
algstrct on which tensor elements and operations are defined
CTF_int::Term * clone(std::map< CTF_int::tensor *, CTF_int::tensor * > *remap=NULL) const
base classes must implement this copy function to retrieve pointer
Definition: idx_tensor.cxx:168
double estimate_time()
predicts execution time in seconds using performance models
CTF_int::algstrct const * get_int64_t_ring()
Definition: ring.cxx:18
void bcast(void *buf, int64_t count, MPI_Datatype mdtype, int root)
broadcast, same interface as MPI_Bcast, but excluding the comm
Definition: common.cxx:336
std::vector< char > det_uniq_inds(std::vector< Term * > const operands, std::vector< char > const out_inds)
Definition: term.cxx:422
virtual double estimate_time(CTF::Idx_Tensor output) const =0
estimates the cost of a contraction/sum/.. term
CTF_int::algstrct const * get_float_ring()
Definition: ring.cxx:6
CTF_int::Contract_Term operator*(double const &d, CTF_int::Term const &tsr)
Definition: term.h:358
double estimate_time(Idx_Tensor output) const
estimates the cost of a contraction
Definition: idx_tensor.cxx:294
std::vector< char > get_uniq_inds() const
find list of unique indices that are involved in this term
Definition: idx_tensor.cxx:311
void operator+=(Term const &B)
Definition: term.cxx:243
int cdealloc(void *ptr)
free abstraction
Definition: memcontrol.cxx:480
Idx_Tensor execute(std::vector< char > out_inds) const
evalues the expression to produce an intermediate with all expression indices remaining ...
Definition: idx_tensor.cxx:290
Term * clone(std::map< tensor *, tensor * > *remap=NULL) const
base classes must implement this copy function to retrieve pointer
Definition: term.cxx:369
algstrct (algebraic structure) defines the elementwise operations computed in each tensor contraction...
Definition: algstrct.h:34
Definition: apsp.cxx:17
char * data
tensor data, either the data or the key-value pairs should exist at any given time ...
internal distributed tensor class
void operator+=(int64_t &d, CTF_int::Term const &tsr)
Definition: term.cxx:751
std::vector< Term * > contract_down_terms(algstrct *sr, char *tscale, std::vector< Term * > operands, std::vector< char > out_inds, int terms_to_leave, bool est_time=false, double *cost=NULL)
Definition: term.cxx:563
bool operator()(CTF::Idx_Tensor *A, CTF::Idx_Tensor *B)
Definition: term.cxx:758
char * scale
Definition: term.h:35
class for execution distributed summation of tensors
Definition: summation.h:15
An experession representing a contraction of a set of tensors contained in operands.
Definition: term.h:275
virtual void safeaddinv(char const *a, char *&b) const
b = -a, with checks for NULL and alloc as necessary
Definition: algstrct.cxx:97
virtual char const * mulid() const
identity element for multiplication i.e. 1
Definition: algstrct.cxx:93
a tensor with an index map associated with it (necessary for overloaded operators) ...
Definition: idx_tensor.h:15
void execute(CTF::Idx_Tensor output) const
override execution to to contract operands and add them to output
Definition: term.cxx:616
std::vector< Term * > operands
Definition: term.h:183
char * name
name given to tensor
Idx_Tensor * get_full_intm(Idx_Tensor &A, Idx_Tensor &B, std::vector< char > out_inds, bool create_dummy=false)
Definition: term.cxx:121
CTF_int::tensor * parent
Definition: idx_tensor.h:17