Cyclops Tensor Framework
parallel arithmetic on multidimensional arrays
mapping.cxx
Go to the documentation of this file.
1 /*Copyright (c) 2011, Edgar Solomonik, all rights reserved.*/
2 
3 #define MAX_PHASE 16384
4 
5 #include "mapping.h"
6 #include "../shared/util.h"
7 #include "../tensor/untyped_tensor.h"
8 #include "../summation/sum_tsr.h"
9 
10 namespace CTF_int {
12  type = NOT_MAPPED;
13  has_child = 0;
14  np = 1;
15  }
16 
18  clear();
19  }
20 
21  mapping::mapping(mapping const & other){
22  type = other.type;
23  has_child = other.has_child;
24  np = other.np;
25  cdt = other.cdt;
26  if (has_child) child = new mapping(*other.child);
27  }
28 
30  type = other.type;
31  has_child = other.has_child;
32  np = other.np;
33  cdt = other.cdt;
34  if (has_child) child = new mapping(*other.child);
35  return *this;
36  }
37 
38 
39  int mapping::calc_phase() const {
40  int phase;
41  if (this->type == NOT_MAPPED){
42  phase = 1;
43  } else{
44  phase = this->np;
45  #if DEBUG >1
46  if (phase == 0)
47  printf("phase should never be zero! map type = %d\n",this->type);
48  ASSERT(phase!=0);
49  #endif
50  if (this->has_child){
51  phase = phase*this->child->calc_phase();
52  }
53  }
54  return phase;
55  }
56 
58  int phase;
59  if (this->type == NOT_MAPPED){
60  phase = 1;
61  } else {
62  if (this->type == PHYSICAL_MAP)
63  phase = this->np;
64  else
65  phase = 1;
66  if (this->has_child){
67  phase = phase*this->child->calc_phys_phase();
68 
69  }
70  }
71  return phase;
72  }
73 
74  int mapping::calc_phys_rank(topology const * topo) const {
75  int rank, phase;
76  if (this->type == NOT_MAPPED){
77  rank = 0;
78  } else {
79  if (this->type == PHYSICAL_MAP) {
80  rank = topo->dim_comm[this->cdt].rank;
81  phase = this->np;
82  } else {
83  rank = 0;
84  phase = 1;
85  }
86  if (this->has_child){
87  /* WARNING: Assumes folding is ordered by lda */
88  rank = rank + phase*child->calc_phys_rank(topo);
89  }
90  }
91  return rank;
92  }
93 
95  if (this->type != NOT_MAPPED && this->has_child) {
96  this->child->clear();
97  delete this->child;
98  }
99  this->type = NOT_MAPPED;
100  this->np = 1;
101  this->has_child = 0;
102  }
103 
104  void mapping::aug_phys(topology const * topo, int idim){
105  mapping * map = NULL;
106  if (type != NOT_MAPPED)
107  map = new mapping(*this);
108  clear();
109  type = PHYSICAL_MAP;
110  cdt = idim;
111  np = topo->lens[idim];
112  has_child = (map != NULL);
113  child = map;
114  }
115 
116 
117  void mapping::aug_virt(int tot_phase){
118  mapping * map = this;
119  int my_phase = 1;
120  while (map->has_child){
121  my_phase *= map->np;
122  map = map->child;
123  }
124  if (map->type == NOT_MAPPED){
125  map->type = VIRTUAL_MAP;
126  map->np = tot_phase/(map->np*my_phase);
127  } else if (map->type == VIRTUAL_MAP){
128  ASSERT(tot_phase%my_phase == 0);
129  map->np = tot_phase/my_phase;
130  } else {
131  ASSERT(map->type == PHYSICAL_MAP);
132  map->has_child = 1;
133  map->child = new mapping();
134  my_phase *= map->np;
135  map = map->child;
136  map->np = tot_phase/my_phase;
137  map->type = VIRTUAL_MAP;
138  map->has_child = 0;
139  }
140  }
141 
142 
143  int comp_dim_map(mapping const * map_A,
144  mapping const * map_B){
145  if (map_A->type == NOT_MAPPED &&
146  map_B->type == NOT_MAPPED) return 1;
147  /* if (map_A->type == NOT_MAPPED ||
148  map_B->type == NOT_MAPPED) return 0;*/
149  if (map_A->type == NOT_MAPPED){
150  if (map_B->type == VIRTUAL_MAP && map_B->np == 1) return 1;
151  else return 0;
152  }
153  if (map_B->type == NOT_MAPPED){
154  if (map_A->type == VIRTUAL_MAP && map_A->np == 1) return 1;
155  else return 0;
156  }
157 
158  if (map_A->type == PHYSICAL_MAP){
159  if (map_B->type != PHYSICAL_MAP ||
160  map_B->cdt != map_A->cdt ||
161  map_B->np != map_A->np){
162  /* DEBUG_PRINTF("failed confirmation here [%d %d %d] != [%d] [%d] [%d]\n",
163  map_A->type, map_A->cdt, map_A->np,
164  map_B->type, map_B->cdt, map_B->np);*/
165  return 0;
166  }
167  if (map_A->has_child){
168  if (map_B->has_child != 1 ||
169  comp_dim_map(map_A->child, map_B->child) != 1){
170  DEBUG_PRINTF("failed confirmation here\n");
171  return 0;
172  }
173  } else {
174  if (map_B->has_child){
175  DEBUG_PRINTF("failed confirmation here\n");
176  return 0;
177  }
178  }
179  } else {
180  ASSERT(map_A->type == VIRTUAL_MAP);
181  if (map_B->type != VIRTUAL_MAP ||
182  map_B->np != map_A->np) {
183  DEBUG_PRINTF("failed confirmation here\n");
184  return 0;
185  }
186  }
187  return 1;
188  }
189 
190  void copy_mapping(int order,
191  mapping const * mapping_A,
192  mapping * mapping_B){
193  int i;
194  for (i=0; i<order; i++){
195  mapping_B[i].clear();
196  mapping_B[i] = mapping(mapping_A[i]);
197  }
198 /* memcpy(mapping_B, mapping_A, sizeof(mapping)*order);
199  for (i=0; i<order; i++){
200  if (mapping_A[i].has_child){
201  CTF_int::alloc_ptr(sizeof(mapping), (void**)&mapping_B[i].child);
202  mapping_B[i].child->has_child = 0;
203  mapping_B[i].child->np = 1;
204  mapping_B[i].child->type = NOT_MAPPED;
205  copy_mapping(1, mapping_A[i].child, mapping_B[i].child);
206  }
207  }*/
208  }
209 
210  int copy_mapping(int order_A,
211  int order_B,
212  int const * idx_A,
213  mapping const * mapping_A,
214  int const * idx_B,
215  mapping * mapping_B,
216  int make_virt){
217  int i, order_tot, iA, iB;
218  int * idx_arr;
219 
220 
221  inv_idx(order_A, idx_A,
222  order_B, idx_B,
223  &order_tot, &idx_arr);
224 
225  for (i=0; i<order_tot; i++){
226  iA = idx_arr[2*i];
227  iB = idx_arr[2*i+1];
228  if (iA == -1){
229  if (make_virt){
230  ASSERT(iB!=-1);
231  mapping_B[iB].type = VIRTUAL_MAP;
232  mapping_B[iB].np = 1;
233  mapping_B[iB].has_child = 0;
234  }
235  } else if (iB != -1){
236  mapping_B[iB].clear();
237  copy_mapping(1, mapping_A+iA, mapping_B+iB);
238  }
239  }
240  CTF_int::cdealloc(idx_arr);
241  return CTF_int::SUCCESS;
242  }
243 
244  int map_tensor(int num_phys_dims,
245  int tsr_order,
246  int const * tsr_edge_len,
247  int const * tsr_sym_table,
248  int * restricted,
249  CommData * phys_comm,
250  int const * comm_idx,
251  int fill,
252  mapping * tsr_edge_map){
253  int i,j,max_dim,max_len,phase,ret;
254  mapping * map;
255 
256  /* Make sure the starting mappings are consistent among symmetries */
257  ret = map_symtsr(tsr_order, tsr_sym_table, tsr_edge_map);
258  if (ret!=CTF_int::SUCCESS) return ret;
259 
260  /* Assign physical dimensions */
261  for (i=0; i<num_phys_dims; i++){
262  max_len = -1;
263  max_dim = -1;
264  for (j=0; j<tsr_order; j++){
265  if (tsr_edge_len[j]/tsr_edge_map[j].calc_phys_phase() > max_len) {
266  /* if tsr dimension can be mapped */
267  if (!restricted[j]){
268  /* if tensor dimension not mapped ot physical dimension or
269  mapped to a physical dimension that can be folded with
270  this one */
271  if (tsr_edge_map[j].type != PHYSICAL_MAP ||
272  (fill && ((comm_idx == NULL && tsr_edge_map[j].cdt == i-1) ||
273  (comm_idx != NULL && tsr_edge_map[j].cdt == comm_idx[i]-1)))){
274  max_dim = j;
275  max_len = tsr_edge_len[j]/tsr_edge_map[j].calc_phys_phase();
276  }
277  }
278  }
279  }
280  if (max_dim == -1){
281  if (fill){
282  return CTF_int::NEGATIVE;
283  }
284  break;
285  }
286  map = &(tsr_edge_map[max_dim]);
287  // FIXME: why?
288  // map->has_child = 0;
289  if (map->type != NOT_MAPPED){
290  while (map->has_child) map = map->child;
291  phase = phys_comm[i].np;
292  if (map->type == VIRTUAL_MAP){
293  if (phys_comm[i].np != map->np){
294  phase = lcm(map->np, phys_comm[i].np);
295  if ((phase < map->np || phase < phys_comm[i].np) || phase >= MAX_PHASE)
296  return CTF_int::NEGATIVE;
297  if (phase/phys_comm[i].np != 1){
298  map->has_child = 1;
299  map->child = new mapping();
300  map->child->type = VIRTUAL_MAP;
301  map->child->np = phase/phys_comm[i].np;
302  map->child->has_child = 0;
303  }
304  }
305  } else if (map->type == PHYSICAL_MAP){
306  if (map->has_child != 1)
307  map->child = new mapping();
308  map->has_child = 1;
309  map = map->child;
310  map->has_child = 0;
311  }
312  }
313  map->type = PHYSICAL_MAP;
314  map->np = phys_comm[i].np;
315  map->cdt = (comm_idx == NULL) ? i : comm_idx[i];
316  if (!fill)
317  restricted[max_dim] = 1;
318  ret = map_symtsr(tsr_order, tsr_sym_table, tsr_edge_map);
319  if (ret!=CTF_int::SUCCESS) return ret;
320  }
321  for (i=0; i<tsr_order; i++){
322  if (tsr_edge_map[i].type == NOT_MAPPED){
323  tsr_edge_map[i].type = VIRTUAL_MAP;
324  tsr_edge_map[i].np = 1;
325  tsr_edge_map[i].has_child = 0;
326  }
327  }
328  return CTF_int::SUCCESS;
329  }
330 
331 
333  int const * idx_map){
334  int i, j, pass, iR, max_idx;
335  int * idx_arr;
336  mapping * map1, * map2;
337 
338 
339  max_idx = -1;
340  for (i=0; i<tsr->order; i++){
341  if (idx_map[i] > max_idx) max_idx = idx_map[i];
342  }
343  max_idx++;
344 
345  CTF_int::alloc_ptr(sizeof(int)*max_idx, (void**)&idx_arr);
346  std::fill(idx_arr, idx_arr+max_idx, -1);
347 
348  pass = 1;
349  for (i=0; i<tsr->order; i++){
350  map1 = &tsr->edge_map[i];
351  while (map1->type == PHYSICAL_MAP) {
352  map2 = map1;
353  while (map2->has_child){
354  map2 = map2->child;
355  if (map2->type == PHYSICAL_MAP){
356  /*if (map1->cdt == map2->cdt) pass = 0;
357  if (!pass){
358  DPRINTF(3,"failed confirmation here i=%d\n",i);
359  break;
360  }*/
361  if (map2->cdt != map1->cdt+1)
362  pass = 0;
363  if (!pass){
364  DPRINTF(3,"failed confirmation here i=%d\n",i);
365  break;
366  }
367  }
368  }
369  for (j=i+1; j<tsr->order; j++){
370  map2 = &tsr->edge_map[j];
371  while (map2->type == PHYSICAL_MAP){
372  if (map1->cdt == map2->cdt) pass = 0;
373  if (!pass){
374  DPRINTF(3,"failed confirmation here i=%d j=%d\n",i,j);
375  break;
376  }
377  if (map2->has_child)
378  map2 = map2->child;
379  else break;
380  }
381  }
382  if (map1->has_child)
383  map1 = map1->child;
384  else break;
385  }
386  }
387  /* Go in reverse, since the first index of the diagonal set will be mapped */
388  if (pass){
389  for (i=tsr->order-1; i>=0; i--){
390  iR = idx_arr[idx_map[i]];
391  if (iR != -1){
392  if (tsr->edge_map[iR].has_child == 1)
393  pass = 0;
394  if (tsr->edge_map[i].has_child == 1)
395  pass = 0;
396  /* if (tsr->edge_map[i].type != VIRTUAL_MAP)
397  pass = 0;*/
398  /* if (tsr->edge_map[i].np != tsr->edge_map[iR].np)
399  pass = 0;*/
400  if (tsr->edge_map[i].type == PHYSICAL_MAP)
401  pass = 0;
402  // if (tsr->edge_map[iR].type == VIRTUAL_MAP){
403  if (tsr->edge_map[i].calc_phase()
404  != tsr->edge_map[iR].calc_phase()){
405  pass = 0;
406  }
407  /*if (tsr->edge_map[iR].has_child && tsr->edge_map[iR].child->type == PHYSICAL_MAP){
408  pass = 0;
409  }*/
410  if (!pass) {
411  DPRINTF(3,"failed confirmation here i=%d iR=%d\n",i,iR);
412  break;
413  }
414  continue;
415  }
416  idx_arr[idx_map[i]] = i;
417  }
418  }
419  CTF_int::cdealloc(idx_arr);
420  return pass;
421  }
422 
424  int const * idx_map){
425  int iR, max_idx, i, ret, npp;
426  int * idx_arr, * stable;
427 
428 
429  max_idx = -1;
430  for (i=0; i<tsr->order; i++){
431  if (idx_map[i] > max_idx) max_idx = idx_map[i];
432  }
433  max_idx++;
434 
435 
436  CTF_int::alloc_ptr(sizeof(int)*max_idx, (void**)&idx_arr);
437  CTF_int::alloc_ptr(sizeof(int)*tsr->order*tsr->order, (void**)&stable);
438  memcpy(stable, tsr->sym_table, sizeof(int)*tsr->order*tsr->order);
439 
440  std::fill(idx_arr, idx_arr+max_idx, -1);
441 
442  /* Go in reverse, since the first index of the diagonal set will be mapped */
443  npp = 0;
444  for (i=0; i<tsr->order; i++){
445  iR = idx_arr[idx_map[i]];
446  if (iR != -1){
447  stable[iR*tsr->order+i] = 1;
448  stable[i*tsr->order+iR] = 1;
449  // ASSERT(tsr->edge_map[iR].type != PHYSICAL_MAP);
450  if (tsr->edge_map[iR].type == NOT_MAPPED){
451  npp = 1;
452  tsr->edge_map[iR].type = VIRTUAL_MAP;
453  tsr->edge_map[iR].np = 1;
454  tsr->edge_map[iR].has_child = 0;
455  }
456  }
457  idx_arr[idx_map[i]] = i;
458  }
459 
460  if (!npp){
461  ret = map_symtsr(tsr->order, stable, tsr->edge_map);
462  if (ret!=CTF_int::SUCCESS) return ret;
463  }
464 
465  CTF_int::cdealloc(idx_arr);
466  CTF_int::cdealloc(stable);
467  return CTF_int::SUCCESS;
468  }
469 
470  int map_symtsr(int tsr_order,
471  int const * tsr_sym_table,
472  mapping * tsr_edge_map){
473  int i,j,phase,adj,loop,sym_phase,lcm_phase;
474  mapping * sym_map, * map;
475 
476  /* Make sure the starting mappings are consistent among symmetries */
477  adj = 1;
478  loop = 0;
479  while (adj){
480  adj = 0;
481  #ifndef MAXLOOP
482  #define MAXLOOP 20
483  #endif
484  if (loop >= MAXLOOP) return CTF_int::NEGATIVE;
485  loop++;
486  for (i=0; i<tsr_order; i++){
487  if (tsr_edge_map[i].type != NOT_MAPPED){
488  map = &tsr_edge_map[i];
489  phase = map->calc_phase();
490  for (j=0; j<tsr_order; j++){
491  if (i!=j && tsr_sym_table[i*tsr_order+j] == 1){
492  sym_map = &(tsr_edge_map[j]);
493  sym_phase = sym_map->calc_phase();
494  /* Check if symmetric phase inconsitent */
495  if (sym_phase != phase) adj = 1;
496  else continue;
497  lcm_phase = lcm(sym_phase, phase);
498  if ((lcm_phase < sym_phase || lcm_phase < phase) || lcm_phase >= MAX_PHASE)
499  return CTF_int::NEGATIVE;
500  /* Adjust phase of symmetric (j) dimension */
501  if (sym_map->type == NOT_MAPPED){
502  sym_map->type = VIRTUAL_MAP;
503  sym_map->np = lcm_phase;
504  sym_map->has_child = 0;
505  } else if (sym_phase != lcm_phase) {
506  while (sym_map->has_child) sym_map = sym_map->child;
507  if (sym_map->type == VIRTUAL_MAP){
508  sym_map->np = sym_map->np*(lcm_phase/sym_phase);
509  } else {
510  ASSERT(sym_map->type == PHYSICAL_MAP);
511  if (!sym_map->has_child)
512  sym_map->child = new mapping();
513  sym_map->has_child = 1;
514  sym_map->child->type = VIRTUAL_MAP;
515  sym_map->child->np = lcm_phase/sym_phase;
516  sym_map->child->has_child = 0;
517  }
518  }
519  /* Adjust phase of reference (i) dimension if also necessary */
520  if (lcm_phase > phase){
521  while (map->has_child) map = map->child;
522  if (map->type == VIRTUAL_MAP){
523  map->np = map->np*(lcm_phase/phase);
524  } else {
525  if (!map->has_child)
526  map->child = new mapping();
527  ASSERT(map->type == PHYSICAL_MAP);
528  map->has_child = 1;
529  map->child->type = VIRTUAL_MAP;
530  map->child->np = lcm_phase/phase;
531  map->child->has_child = 0;
532  }
533  }
534  }
535  }
536  }
537  }
538  }
539  return CTF_int::SUCCESS;
540  }
541 
542  int stretch_virt(int order,
543  int stretch_factor,
544  mapping * maps){
545  int i;
546  mapping * map;
547  for (i=0; i<order; i++){
548  map = &maps[i];
549  while (map->has_child) map = map->child;
550  if (map->type == PHYSICAL_MAP){
551  if (map->has_child){
552  map->has_child = 1;
553  map->child = new mapping();
554  map->child->type = VIRTUAL_MAP;
555  map->child->np = stretch_factor;
556  map->child->has_child = 0;
557  }
558  } else if (map->type == VIRTUAL_MAP){
559  map->np = map->np * stretch_factor;
560  } else {
561  map->type = VIRTUAL_MAP;
562  map->np = stretch_factor;
563  }
564  }
565  return CTF_int::SUCCESS;
566  }
567 
568 
569 
570 
571 }
int calc_phys_rank(topology const *topo) const
compute the physical rank of a mapping
Definition: mapping.cxx:74
int map_tensor(int num_phys_dims, int tsr_order, int const *tsr_edge_len, int const *tsr_sym_table, int *restricted, CommData *phys_comm, int const *comm_idx, int fill, mapping *tsr_edge_map)
map a tensor
Definition: mapping.cxx:244
map_type type
Definition: mapping.h:22
#define DPRINTF(...)
Definition: util.h:235
int calc_phase() const
compute the phase of a mapping
Definition: mapping.cxx:39
void aug_phys(topology const *topo, int idim)
adds a physical mapping to this mapping
Definition: mapping.cxx:104
def rank(self)
Definition: core.pyx:312
int calc_phys_phase() const
compute the physical phase of a mapping
Definition: mapping.cxx:57
void inv_idx(int order_A, int const *idx_A, int order_B, int const *idx_B, int order_C, int const *idx_C, int *order_tot, int **idx_arr)
invert index map
Definition: ctr_tsr.cxx:592
#define ASSERT(...)
Definition: util.h:88
#define DEBUG_PRINTF(...)
Definition: util.h:238
void copy_mapping(int order, mapping const *mapping_A, mapping *mapping_B)
copies mapping A to B
Definition: mapping.cxx:190
int order
number of tensor dimensions
#define MAX_PHASE
Definition: mapping.cxx:3
int alloc_ptr(int64_t len, void **const ptr)
alloc abstraction
Definition: memcontrol.cxx:320
int comp_dim_map(mapping const *map_A, mapping const *map_B)
compares two mappings
Definition: mapping.cxx:143
~mapping()
destructor
Definition: mapping.cxx:17
#define MAXLOOP
mapping * edge_map
mappings of each tensor dimension onto topology dimensions
CommData * dim_comm
Definition: topology.h:20
mapping * child
Definition: mapping.h:26
int * sym_table
order-by-order table of dimensional symmetry relations
int map_symtsr(int tsr_order, int const *tsr_sym_table, mapping *tsr_edge_map)
adjust a mapping to maintan symmetry
Definition: mapping.cxx:470
int check_self_mapping(tensor const *tsr, int const *idx_map)
checks mapping in preparation for tensors scale, summ or contract
Definition: mapping.cxx:332
int cdealloc(void *ptr)
free abstraction
Definition: memcontrol.cxx:480
internal distributed tensor class
int lcm(int a, int b)
Definition: util.h:340
mapping()
constructor
Definition: mapping.cxx:11
mapping & operator=(mapping const &other)
Definition: mapping.cxx:29
int map_self_indices(tensor const *tsr, int const *idx_map)
create virtual mapping for idx_maps that have repeating indices
Definition: mapping.cxx:423
void aug_virt(int tot_phase)
augments mapping to have sufficient virtualization so that the total phas is exactly tot_phase (assum...
Definition: mapping.cxx:117
int stretch_virt(int order, int stretch_factor, mapping *maps)
stretch virtualization by a factor
Definition: mapping.cxx:542
void clear()
resets mapping to NOT_MAPPED
Definition: mapping.cxx:94