planc
Parallel Lowrank Approximation with Non-negativity Constraints
dimtrees.hpp
Go to the documentation of this file.
1 /* Copyright Koby Hayashi 2018 */
2 
3 #ifndef DIMTREE_DIMTREES_HPP_
4 #define DIMTREE_DIMTREES_HPP_
5 
6 #include "dimtree/ddttensor.hpp"
7 #include "dimtree/dimtrees.h"
8 
31 void partial_MTTKRP(Output_Layout OL, long int s, direction D, tensor *T,
32  double *A, long int r, double *C, long int num_threads) {
33  // mkl_set_num_threads(num_threads);
34  // openblas_set_num_threads(num_threads);
35 
36  CBLAS_ORDER dgemm_layout; // layout for dgemm calls
37  // CBLAS_TRANSPOSE trans_tensor, trans_A;
38  // dgemm related variables.
39  char trans_tensor, trans_A;
40 
41  int i, m, n, k, output_stride, tensor_stride, right_dims_product,
42  left_dims_product, i_r;
43  double alpha, beta;
44 
45  alpha = 1.0;
46  beta = 0.0;
47 
48  if (s < 0 || s >= T->nmodes - 1) { // s cannot be negative or be equal to N-1
49  // or be greater than N-1
50  printf("Invalid value of s in partial_MTTKRP(), s = %ld\nExit\n", s);
51  exit(-1);
52  }
53  if (T == NULL) {
54  printf("T == NULL in partial_MTTKRP()\nExit\n");
55  exit(-1);
56  }
57  if (A == NULL) {
58  printf("A == NULL in partial_MTTKRP()\nExit\n");
59  exit(-1);
60  }
61  if (C == NULL) {
62  printf("C == NULL in partial_MTTKRP()\nExit\n");
63  exit(-1);
64  }
65 
66  right_dims_product = 1;
67  left_dims_product = 1; // the left dimension product always includes s
68 
69  for (i = 0; i < s + 1; i++) left_dims_product *= T->dims[i];
70  for (i = s + 1; i < T->nmodes; i++) right_dims_product *= T->dims[i];
71 
72  if (D == ::direction::left) {
73  // m = right_dims_product; // Tensor->data is m x k, A is k x n
74  // // n = r;
75  // k = left_dims_product;
76  // tensor_stride = left_dims_product;
77  if (OL == RowMajor) {
78  dgemm_layout = CblasRowMajor;
79  // trans_tensor = CblasNoTrans;
80  // trans_A = CblasNoTrans;
81  trans_tensor = 'N';
82  trans_A = 'N';
83  m = r;
84  n = right_dims_product;
85  k = left_dims_product;
86  tensor_stride = left_dims_product;
87  output_stride = r;
88  dgemm_(&trans_A, &trans_tensor, &m, &n, &k, &alpha, A, &m, T->data, &tensor_stride,
89  &beta, C, &output_stride);
90  // assuming dgemm. comment if not neccessary
91  } else {
92  // trans_tensor = CblasTrans;
93  // trans_A = CblasTrans;
94  dgemm_layout = CblasColMajor;
95  trans_tensor = 'T';
96  trans_A = 'T';
97  output_stride = right_dims_product;
98  m = right_dims_product; // Tensor->data is m x k, A is k x n
99  // n = r;
100  k = left_dims_product;
101  i_r = r;
102  tensor_stride = left_dims_product;
103  dgemm_(&trans_tensor, &trans_A, &m, &i_r, &k, &alpha, T->data,
104  &tensor_stride, A, &i_r, &beta, C, &output_stride);
105  }
106  } else { // D == right
107  // m = left_dims_product;
108  // // n = r;
109  // k = right_dims_product;
110  tensor_stride = left_dims_product;
111  if (OL == RowMajor) {
112  dgemm_layout = CblasRowMajor;
113  // trans_tensor = CblasTrans;
114  trans_tensor = 'T';
115  // trans_A = CblasNoTrans;
116  trans_A = 'N';
117  m = r;
118  n = left_dims_product;
119  k = right_dims_product;
120  output_stride = r;
121  tensor_stride = left_dims_product;
122  dgemm_(&trans_A, &trans_tensor, &m, &n, &k, &alpha, A,
123  &m, T->data, &tensor_stride, &beta, C, &output_stride);
124  } else {
125  dgemm_layout = CblasColMajor;
126  // trans_tensor = CblasNoTrans;
127  trans_tensor = 'N';
128  // trans_A = CblasTrans;
129  trans_A = 'T';
130  output_stride = left_dims_product;
131  m = left_dims_product;
132  // n = r;
133  k = right_dims_product;
134  i_r = r;
135  tensor_stride = left_dims_product;
136  dgemm_(&trans_tensor, &trans_A, &m, &i_r, &k, &alpha, T->data,
137  &tensor_stride, A, &i_r, &beta, C, &output_stride);
138  }
139  }
153  // cblas_dgemm(dgemm_layout, trans_tensor, trans_A, m, r, k, alpha, T->data,
154  // tensor_stride, A, r, beta, C, output_stride);
155  // dgemm_(char *transa, char *transb, integer *m, integer *
156  // n, integer *k, doublereal *alpha, doublereal *a, integer *lda,
157  // doublereal *b, integer *ldb, doublereal *beta, doublereal *c, integer
158  // *ldc)
159  // dgemm_(&trans_tensor, &trans_A, &m, &i_r, &k, &alpha, T->data,
160  // &tensor_stride,
161  // A, &i_r, &beta, C, &output_stride);
162 }
163 
176 void partial_MTTKRP_with_KRP(Output_Layout OL, long int s, direction D,
177  ktensor *Y, tensor *T, double *C,
178  long int num_threads) {
179  // mkl_set_num_threads(num_threads);
180  // openblas_set_num_threads(num_threads);
181 
182  if ((s < 0) || (s >= T->nmodes - 1)) { // s cannot be negative or be equal to
183  // N-1 or be greater than N-1
184  printf("Invalid value of s in partial_MTTKRP_with_KRP(), s = %ld\nExit\n",
185  s);
186  exit(-1);
187  }
188  if (T == NULL) {
189  printf("T == NULL in partial_MTTKRP_with_KRP()\nExit\n");
190  exit(-1);
191  }
192  if (Y == NULL) {
193  printf("Y == NULL in partial_MTTKRP_with_KRP()\nExit\n");
194  exit(-1);
195  }
196 
197  long int i, right_dims_product, left_dims_product, free_KRP;
198  double *KRP;
199  ktensor tempY;
200 
201  right_dims_product = 1;
202  left_dims_product = 1; // the left dimension product always includes s
203 
204  for (i = 0; i < s + 1; i++) left_dims_product *= T->dims[i];
205  for (i = s + 1; i < T->nmodes; i++) right_dims_product *= T->dims[i];
206 
207  if (D == ::direction::left) { // s+1 because left includes s by convention
208  LR_Ktensor_Reordering_newY(Y, &tempY, s + 1, D);
209  } else {
210  LR_Ktensor_Reordering_newY(Y, &tempY, s, D);
211  }
212 
213  if (tempY.nmodes == 1) { // no KRP needs to be formed
214  KRP = tempY.factors[0];
215  free_KRP = 0;
216  } else {
217  KRP = reinterpret_cast<double *>(
218  malloc(sizeof(double) * Y->rank * tempY.dims_product));
219  wrapper_Parallel_Multi_revKRP(&tempY, num_threads, KRP);
220  destruct_Ktensor(&tempY, 0);
221  free_KRP = 1;
222  }
223 
234  partial_MTTKRP(OL, s, D, T, KRP, Y->rank, C, num_threads);
235 
236  if (free_KRP == 1) free(KRP);
237 }
238 
250 void partial_MTTKRP_with_KRP_output_FM(direction D, ktensor *Y, tensor *T,
251  long int num_threads) {
252  long int s, n;
253 
254  if (D == ::direction::left) {
255  s = T->nmodes - 2;
256  n = s + 1;
257  } else { // D == right
258  s = 0;
259  n = s;
260  }
261 
270  partial_MTTKRP_with_KRP(RowMajor, s, D, Y, T, Y->factors[n], num_threads);
271 }
272 
281 void partial_MTTKRP_with_KRP_output_T(long int s, direction D,
282  ktensor *input_ktensor,
283  tensor *input_tensor,
284  tensor *output_tensor,
285  long int num_threads) {
286  Output_Layout output_layout = ColMajor;
287  long int new_s; // new_s is the split point for the new tensor
288 
289  partial_MTTKRP_with_KRP(output_layout, s, D, input_ktensor, input_tensor,
290  output_tensor->data, num_threads);
291 
292  if (D == ::direction::left) {
293  new_s = s;
294  } else {
295  new_s = s + 1; // the LR_tensor_Reduction does not include the given split
296  }
297 
298  // Adjust the tensor in the opposite direction of D
299  LR_tensor_Reduction(input_tensor, output_tensor, new_s,
300  opposite_direction(D));
301 
302  // Ddd in the rank dimension
303  output_tensor->nmodes += 1;
304  output_tensor->dims[output_tensor->nmodes - 1] = input_ktensor->rank;
305  output_tensor->dims_product *= input_ktensor->rank;
306 }
307 
315 void multi_TTV(Output_Layout OL, long int s, direction D, tensor *T, double *A,
316  long int r, double *C, long int num_threads) {
317  if (s < 0 || s >= T->nmodes - 1) { // s cannot be negative or be equal to N-1
318  // or be greater than N-1
319  printf("Invalid value of s in multi_TTV(), s = %ld\nExit\n", s);
320  exit(-1);
321  }
322  if (T == NULL) {
323  printf("T == NULL in multi_TTV()\nExit\n");
324  exit(-1);
325  }
326  if (A == NULL) {
327  printf("A == NULL in multi_TTV()\nExit\n");
328  exit(-1);
329  }
330  if (C == NULL) {
331  printf("C == NULL in multi_TTV()\nExit\n");
332  exit(-1);
333  }
334  if (r != T->dims[T->nmodes - 1]) { // the last mode of T must be of length r
335  printf(
336  "r and the last mode of the tensor T must be equal, r = %ld, "
337  "T->dims[T->nmodes-1] = %ld\nmulti_TTV()\n\nExit\n",
338  r, T->dims[T->nmodes - 1]);
339  exit(-1);
340  }
341 
342  CBLAS_ORDER dgemv_layout;
343  CBLAS_TRANSPOSE trans_tensor;
344  long int right_dims_product, left_dims_product, i, m, n, tensor_stride,
345  output_stride, output_col_stride;
346  double alpha, beta;
347 
348  alpha = 1.0;
349  beta = 0.0;
350 
351  left_dims_product = 1;
352  right_dims_product = 1;
353 
354  for (i = 0; i < s + 1; i++) // by convenction left product includes s
355  left_dims_product *= T->dims[i];
356  for (i = s + 1; i < T->nmodes - 1;
357  i++) // -1 because we do not want to include the rank dimension
358  right_dims_product *= T->dims[i];
359 
360  trans_tensor = CblasNoTrans; // alwyas NoTrans because dgemv_layout is based
361  // on left and right
362  if (D == ::direction::left) {
363  dgemv_layout = CblasRowMajor;
364  m = right_dims_product;
365  n = left_dims_product;
366  tensor_stride = n;
367  if (OL == RowMajor) {
368  output_stride = r;
369  output_col_stride = 1;
370  } else {
371  output_stride = 1;
372  output_col_stride = m;
373  }
374  } else { // D == right
375  dgemv_layout = CblasColMajor;
376  m = left_dims_product;
377  n = right_dims_product;
378  tensor_stride = m;
379  if (OL == RowMajor) {
380  output_stride = r;
381  output_col_stride = 1;
382  } else {
383  output_stride = 1;
384  output_col_stride = m;
385  }
386  }
387 
388  // openblas_set_num_threads(num_threads);
389  for (i = 0; i < r; i++) {
406  cblas_dgemv(dgemv_layout, trans_tensor, m, n, alpha, T->data + i * m * n,
407  tensor_stride, A + i, r, beta, &C[i * output_col_stride],
408  output_stride);
409  }
410 }
411 
418 void multi_TTV_with_KRP(Output_Layout OL, long int s, direction D, tensor *T,
419  ktensor *Y, double *C, long int num_threads) {
420  ktensor tempY;
421  double *KRP;
422  long int free_KRP;
423 
424  // the tensour should have 1 more mode than the ktensor
425  if (T->nmodes != Y->nmodes + 1) {
426  printf(
427  "In multi_TTV_with_KRP(), T->nmodes = %ld and Y->nmodes = %ld\nThe "
428  "tensor should have 1 more mode than the ktensor.\nExit\n",
429  T->nmodes, Y->nmodes);
430  exit(-1);
431  }
432 
433  // form the needed tempY, multi ttv goes the same way as PM now
434  if (D == ::direction::left) {
435  LR_Ktensor_Reordering_newY(Y, &tempY, s + 1, D);
436  } else { // D == right
437  LR_Ktensor_Reordering_newY(Y, &tempY, s, D);
438  }
439 
440  if (tempY.nmodes == 1) {
441  KRP = tempY.factors[0];
442  free_KRP = 0;
443  } else {
444  KRP = reinterpret_cast<double *>(
445  malloc(sizeof(double) * Y->rank * tempY.dims_product));
446 
447  wrapper_Parallel_Multi_revKRP(&tempY, num_threads, KRP);
448  destruct_Ktensor(&tempY, 0);
449  free_KRP = 1;
450  }
451 
452  multi_TTV(OL, s, D, T, KRP, Y->rank, C, num_threads);
453 
454  if (free_KRP == 1) free(KRP);
455 }
456 
464 void multi_TTV_with_KRP_output_FM(direction D, tensor *input_tensor,
465  ktensor *input_ktensor,
466  long int num_threads) {
467  long int s, n;
468 
469  if (D == ::direction::left) {
470  s = input_ktensor->nmodes - 2;
471  n = s + 1;
472  } else { // D == right
473  s = 0;
474  n = s;
475  }
476 
477  multi_TTV_with_KRP(RowMajor, s, D, input_tensor, input_ktensor,
478  input_ktensor->factors[n], num_threads);
479 }
480 
481 void multi_TTV_with_KRP_output_T(long int s, direction D, tensor *input_tensor,
482  ktensor *input_ktensor, tensor *output_tensor,
483  long int num_threads) {
484  long int x;
485  direction op_D;
486 
487  multi_TTV_with_KRP(ColMajor, s, D, input_tensor, input_ktensor,
488  output_tensor->data, num_threads);
489 
490  if (D == ::direction::left) {
491  op_D = ::direction::right;
492  x = s;
493  } else { // D == right
494  op_D = ::direction::left;
495  x = s + 1;
496  }
497 
498  // adjust the tensor in the op_D
499  LR_tensor_Reduction(input_tensor, output_tensor, x, op_D);
500 
501  if (op_D ==
502  ::direction::left) { // if we went left we didn't get the rank dimension
503  output_tensor->nmodes += 1;
504  output_tensor->dims[output_tensor->nmodes - 1] = input_ktensor->rank;
505  output_tensor->dims_product *= input_ktensor->rank;
506  }
507 }
508 
509 #endif // DIMTREE_DIMTREES_HPP_
void partial_MTTKRP(Output_Layout OL, long int s, direction D, tensor *T, double *A, long int r, double *C, long int num_threads)
Performs a tensor times a matrix based on some split of dimensions.
Definition: dimtrees.hpp:31
void multi_TTV_with_KRP(Output_Layout OL, long int s, direction D, tensor *T, ktensor *Y, double *C, long int num_threads)
multi_TTV_with_KRP(); KRP wrapper for the general multi_TTV function.
Definition: dimtrees.hpp:418
void multi_TTV(Output_Layout OL, long int s, direction D, tensor *T, double *A, long int r, double *C, long int num_threads)
multi_TTV(); performs a multi_ttv with between subtensors of T->data and the column of the matrix ...
Definition: dimtrees.hpp:315
void multi_TTV_with_KRP_output_FM(direction D, tensor *input_tensor, ktensor *input_ktensor, long int num_threads)
multi_TTV_with_KRP_output_FM(); Wrapper function for performing a multi_TTV with a KRP and outputin...
Definition: dimtrees.hpp:464
void LR_tensor_Reduction(tensor *T, tensor *nT, long int n, direction D)
Definition: ddttensor.hpp:1388
void multi_TTV_with_KRP_output_T(long int s, direction D, tensor *input_tensor, ktensor *input_ktensor, tensor *output_tensor, long int num_threads)
Definition: dimtrees.hpp:481
void destruct_Ktensor(ktensor *Y, long int clear_factors)
Definition: ddttensor.hpp:1348
direction opposite_direction(direction D)
Definition: ddttensor.hpp:1434
void partial_MTTKRP_with_KRP(Output_Layout OL, long int s, direction D, ktensor *Y, tensor *T, double *C, long int num_threads)
Wrapper function for partial_MTTKRP() Forms a desired KRP, manages all the memory for the KRP Passes ...
Definition: dimtrees.hpp:176
void partial_MTTKRP_with_KRP_output_FM(direction D, ktensor *Y, tensor *T, long int num_threads)
partial_MTTKRP_with_KRP_output_FM(); Wrapper function for computing a partial_MTTKRP with KRP and o...
Definition: dimtrees.hpp:250
Output_Layout
This .h file contains all the functions need to construct dimension trees for fast_CP_ALS algorithms...
Definition: dimtrees.h:16
void wrapper_Parallel_Multi_revKRP(ktensor *Y, long int num_threads, double *KRP)
Wrapper function for the reverse KRP of a ktensor Y 1) Ktensor object 2) number of threads to use 3)...
Definition: ddttensor.hpp:872
void LR_Ktensor_Reordering_newY(ktensor *Y, ktensor *nY, long int n, direction D)
Definition: ddttensor.hpp:1264
void partial_MTTKRP_with_KRP_output_T(long int s, direction D, ktensor *input_ktensor, tensor *input_tensor, tensor *output_tensor, long int num_threads)
partial_MTTKRP_with_KRP_output_T() Wrapper function for computing partial_MTTKRP with KRP and outpu...
Definition: dimtrees.hpp:281