SHOGUN  4.1.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Sum.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) The Shogun Machine Learning Toolbox
3  * Written (w) 2014 Soumyajit De
4  * Written (w) 2014 Khaled Nasr
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice, this
11  * list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  * The views and conclusions contained in the software and documentation are those
28  * of the authors and should not be interpreted as representing official policies,
29  * either expressed or implied, of the Shogun Development Team.
30  */
31 
32 #ifndef SUM_IMPL_H_
33 #define SUM_IMPL_H_
34 
35 #include <shogun/lib/config.h>
36 #include <shogun/lib/SGMatrix.h>
37 #include <shogun/lib/SGVector.h>
38 #include <shogun/io/SGIO.h>
40 
41 #ifdef HAVE_EIGEN3
43 #endif // HAVE_EIGEN3
44 
45 #ifdef HAVE_VIENNACL
47 #include <shogun/lib/GPUMatrix.h>
48 #include <shogun/lib/GPUVector.h>
49 #endif
50 
51 #include <string>
52 
53 namespace shogun
54 {
55 
56 namespace linalg
57 {
58 
62 namespace implementation
63 {
64 
70 template <enum Backend,class Matrix>
71 struct sum
72 {
74  typedef typename Matrix::Scalar T;
75 
83  static T compute(Matrix m, bool no_diag);
84 
92  static T compute(Block<Matrix> b, bool no_diag);
93 };
94 
100 template <enum Backend,class Matrix>
102 {
104  typedef typename Matrix::Scalar T;
105 
113  static T compute(Matrix m, bool no_diag);
114 
122  static T compute(Block<Matrix> b, bool no_diag);
123 };
124 
130 template <enum Backend,class Matrix>
132 {
134  typedef typename Matrix::Scalar T;
135 
143  static SGVector<T> compute(Matrix m, bool no_diag);
144 
152  static SGVector<T> compute(Block<Matrix> b, bool no_diag);
153 
161  static void compute(SGMatrix<T> m, SGVector<T> result, bool no_diag);
162 
171  static void compute(Block<SGMatrix<T> > b, SGVector<T> result, bool no_diag);
172 };
173 
179 template <enum Backend,class Matrix>
181 {
183  typedef typename Matrix::Scalar T;
184 
192  static SGVector<T> compute(Matrix m, bool no_diag);
193 
201  static SGVector<T> compute(Block<Matrix> b, bool no_diag);
202 
210  static void compute(SGMatrix<T> m, SGVector<T> result, bool no_diag);
211 
220  static void compute(Block<SGMatrix<T> > b, SGVector<T> result, bool no_diag);
221 };
222 
223 #ifdef HAVE_EIGEN3
224 
228 template <class Matrix>
229 struct sum<Backend::EIGEN3,Matrix>
230 {
232  typedef typename Matrix::Scalar T;
233 
236 
244  static T compute(SGMatrix<T> mat, bool no_diag)
245  {
246  Eigen::Map<MatrixXt> m = mat;
247 
248  T sum=m.sum();
249 
250  // remove the main diagonal elements if required
251  if (no_diag)
252  sum-=m.diagonal().sum();
253 
254  return sum;
255  }
256 
264  static T compute(Block<SGMatrix<T> > b, bool no_diag)
265  {
266  Eigen::Map<MatrixXt> map = b.m_matrix;
267 
268  Eigen::Block< Eigen::Map<MatrixXt> > b_eigen = map.block(
269  b.m_row_begin, b.m_col_begin,
270  b.m_row_size, b.m_col_size);
271 
272  T sum=b_eigen.sum();
273 
274  // remove the main diagonal elements if required
275  if (no_diag)
276  sum-=b_eigen.diagonal().sum();
277 
278  return sum;
279  }
280 };
281 
286 template <class Matrix>
287 struct sum_symmetric<Backend::EIGEN3,Matrix>
288 {
290  typedef typename Matrix::Scalar T;
291 
294 
302  static T compute(SGMatrix<T> mat, bool no_diag)
303  {
304  Eigen::Map<MatrixXt> m = mat;
305 
306  REQUIRE(m.rows()==m.cols(), "Matrix is not square!\n");
307 
308  // since the matrix is symmetric with main diagonal inside, we can save half
309  // the computation with using only the upper triangular part.
310  const MatrixXt& m_upper=m.template triangularView<Eigen::StrictlyUpper>();
311  T sum=m_upper.sum();
312 
313  // the actual sum would be twice of what we computed
314  sum*=2;
315 
316  // add the diagonal elements if required
317  if (!no_diag)
318  sum+=m.diagonal().sum();
319 
320  return sum;
321  }
322 
330  static T compute(Block<SGMatrix<T> > b, bool no_diag)
331  {
332  Eigen::Map<MatrixXt> map = b.m_matrix;
333 
334  const MatrixXt& m=map.template block(b.m_row_begin, b.m_col_begin,
335  b.m_row_size, b.m_col_size);
336 
337  REQUIRE(m.rows()==m.cols(), "Matrix is not square!\n");
338 
339  // since the matrix is symmetric with main diagonal inside, we can save half
340  // the computation with using only the upper triangular part.
341  const MatrixXt& m_upper=m.template triangularView<Eigen::StrictlyUpper>();
342  T sum=m_upper.sum();
343 
344  // the actual sum would be twice of what we computed
345  sum*=2;
346 
347  // add the diagonal elements if required
348  if (!no_diag)
349  sum+=m.diagonal().sum();
350 
351  return sum;
352  }
353 };
354 
359 template <class Matrix>
360 struct colwise_sum<Backend::EIGEN3,Matrix>
361 {
363  typedef typename Matrix::Scalar T;
364 
367 
370 
373 
381  static SGVector<T> compute(SGMatrix<T> m, bool no_diag)
382  {
383  SGVector<T> result(m.num_cols);
384  compute(m, result, no_diag);
385  return result;
386  }
387 
396  static SGVector<T> compute(Block<SGMatrix<T> > b, bool no_diag)
397  {
398  SGVector<T> result(b.m_col_size);
399  compute(b, result, no_diag);
400  return result;
401  }
402 
410  static void compute(SGMatrix<T> mat, SGVector<T> result, bool no_diag)
411  {
412  Eigen::Map<MatrixXt> m = mat;
413  Eigen::Map<VectorXt> r = result;
414 
415  r = m.colwise().sum();
416 
417  // remove the main diagonal elements if required
418  if (no_diag)
419  {
420  index_t len_major_diag=m.rows() < m.cols() ? m.rows() : m.cols();
421  for (index_t i=0; i<len_major_diag; ++i)
422  r[i]-=m(i,i);
423  }
424  }
425 
434  static void compute(Block<SGMatrix<T> > b, SGVector<T> result, bool no_diag)
435  {
436  Eigen::Map<MatrixXt> map = b.m_matrix;
437  Eigen::Map<VectorXt> r = result;
438 
439  Eigen::Block< Eigen::Map<MatrixXt> > m = map.block(
440  b.m_row_begin, b.m_col_begin,
441  b.m_row_size, b.m_col_size);
442 
443  r = m.colwise().sum();
444 
445  // remove the main diagonal elements if required
446  if (no_diag)
447  {
448  index_t len_major_diag=m.rows() < m.cols() ? m.rows() : m.cols();
449  for (index_t i=0; i<len_major_diag; ++i)
450  r[i]-=m(i,i);
451  }
452  }
453 };
454 
459 template <class Matrix>
460 struct rowwise_sum<Backend::EIGEN3,Matrix>
461 {
463  typedef typename Matrix::Scalar T;
464 
467 
470 
473 
481  static SGVector<T> compute(SGMatrix<T> m, bool no_diag)
482  {
483  SGVector<T> result(m.num_rows);
484  compute(m, result, no_diag);
485  return result;
486  }
487 
496  static SGVector<T> compute(Block<SGMatrix<T> > b, bool no_diag)
497  {
498  SGVector<T> result(b.m_row_size);
499  compute(b, result, no_diag);
500  return result;
501  }
502 
510  static void compute(SGMatrix<T> mat, SGVector<T> result, bool no_diag)
511  {
512  Eigen::Map<MatrixXt> m = mat;
513  Eigen::Map<VectorXt> r = result;
514 
515  r = m.rowwise().sum();
516 
517  // remove the main diagonal elements if required
518  if (no_diag)
519  {
520  index_t len_major_diag=m.rows() < m.cols() ? m.rows() : m.cols();
521  for (index_t i=0; i<len_major_diag; ++i)
522  r[i]-=m(i,i);
523  }
524  }
525 
534  static void compute(Block<SGMatrix<T> > b, SGVector<T> result, bool no_diag)
535  {
536  Eigen::Map<MatrixXt> map = b.m_matrix;
537  Eigen::Map<VectorXt> r = result;
538 
539  Eigen::Block< Eigen::Map<MatrixXt> > m = map.block(
540  b.m_row_begin, b.m_col_begin,
541  b.m_row_size, b.m_col_size);
542 
543  r = m.rowwise().sum();
544 
545  // remove the main diagonal elements if required
546  if (no_diag)
547  {
548  index_t len_major_diag=m.rows() < m.cols() ? m.rows() : m.cols();
549  for (index_t i=0; i<len_major_diag; ++i)
550  r[i]-=m(i,i);
551  }
552  }
553 };
554 
555 #endif // HAVE_EIGEN3
556 
557 #ifdef HAVE_VIENNACL
558 
562 template <class Matrix>
563 struct sum<Backend::VIENNACL,Matrix>
564 {
566  typedef typename Matrix::Scalar T;
567 
569  template <class T>
570  static viennacl::ocl::kernel& generate_kernel(bool no_diag)
571  {
572  std::string kernel_name = "sum_" + ocl::get_type_string<T>();
573  if (no_diag) kernel_name.append("_no_diag");
574 
575  if (ocl::kernel_exists(kernel_name))
576  return ocl::get_kernel(kernel_name);
577 
578  std::string source = ocl::generate_kernel_preamble<T>(kernel_name);
579  if (no_diag) source.append("#define NO_DIAG\n");
580 
581  source.append(
582  R"(
583  __kernel void KERNEL_NAME(
584  __global DATATYPE* mat, int nrows, int ncols, int offset,
585  __global DATATYPE* result)
586  {
587  __local DATATYPE buffer[WORK_GROUP_SIZE_1D];
588  int size = nrows*ncols;
589 
590  int local_id = get_local_id(0);
591 
592  DATATYPE thread_sum = 0;
593  for (int i=local_id; i<size; i+=WORK_GROUP_SIZE_1D)
594  {
595  #ifdef NO_DIAG
596  if (!(i/nrows == i%nrows))
597  #endif
598  thread_sum += mat[i+offset];
599  }
600 
601  buffer[local_id] = thread_sum;
602 
603  for (int j = WORK_GROUP_SIZE_1D/2; j > 0; j = j>>1)
604  {
605  barrier(CLK_LOCAL_MEM_FENCE);
606  if (local_id < j)
607  buffer[local_id] += buffer[local_id + j];
608  }
609 
610  barrier(CLK_LOCAL_MEM_FENCE);
611 
612  if (get_global_id(0)==0)
613  *result = buffer[0];
614  }
615  )"
616  );
617 
618  viennacl::ocl::kernel& kernel = ocl::compile_kernel(kernel_name, source);
619 
620  kernel.local_work_size(0, OCL_WORK_GROUP_SIZE_1D);
621  kernel.global_work_size(0, OCL_WORK_GROUP_SIZE_1D);
622 
623  return kernel;
624  }
625 
633  static T compute(CGPUMatrix<T> mat, bool no_diag)
634  {
635  viennacl::ocl::kernel& kernel = generate_kernel<T>(no_diag);
636 
637  CGPUVector<T> result(1);
638 
639  viennacl::ocl::enqueue(kernel(mat.vcl_matrix(),
640  cl_int(mat.num_rows), cl_int(mat.num_cols), cl_int(mat.offset),
641  result.vcl_vector()));
642 
643  return result[0];
644  }
645 
653  static T compute(Block<CGPUMatrix<T> > b, bool no_diag)
654  {
655  SG_SERROR("The operation sum() on a matrix block is currently not supported\n");
656  return 0;
657  }
658 };
659 
664 template <class Matrix>
665 struct sum_symmetric<Backend::VIENNACL,Matrix>
666 {
668  typedef typename Matrix::Scalar T;
669 
677  static T compute(CGPUMatrix<T> mat, bool no_diag)
678  {
679  return sum<Backend::VIENNACL, CGPUMatrix<T> >::compute(mat, no_diag);
680  }
681 
689  static T compute(Block<CGPUMatrix<T> > b, bool no_diag)
690  {
691  SG_SERROR("The operation sum_symmetric() on a matrix block is currently not supported\n");
692  return 0;
693  }
694 };
695 
700 template <class Matrix>
701 struct colwise_sum<Backend::VIENNACL,Matrix>
702 {
704  typedef typename Matrix::Scalar T;
705 
707  typedef CGPUVector<T> ReturnType;
708 
710  template <class T>
711  static viennacl::ocl::kernel& generate_kernel(bool no_diag)
712  {
713  std::string kernel_name = "colwise_sum_" + ocl::get_type_string<T>();
714  if (no_diag) kernel_name.append("_no_diag");
715 
716  if (ocl::kernel_exists(kernel_name))
717  return ocl::get_kernel(kernel_name);
718 
719  std::string source = ocl::generate_kernel_preamble<T>(kernel_name);
720  if (no_diag) source.append("#define NO_DIAG\n");
721 
722  source.append(
723  R"(
724  __kernel void KERNEL_NAME(
725  __global DATATYPE* mat, int nrows, int ncols, int offset,
726  __global DATATYPE* result, int result_offset)
727  {
728  int j = get_global_id(0);
729 
730  if (j>=ncols)
731  return;
732 
733  DATATYPE sum = 0;
734  for (int i=0; i<nrows; i++)
735  {
736  #ifdef NO_DIAG
737  if (i!=j)
738  #endif
739  sum += mat[offset+i+j*nrows];
740  }
741 
742  result[j+result_offset] = sum;
743  }
744  )"
745  );
746 
747  viennacl::ocl::kernel& kernel = ocl::compile_kernel(kernel_name, source);
748 
749  kernel.local_work_size(0, OCL_WORK_GROUP_SIZE_1D);
750 
751  return kernel;
752  }
753 
761  static CGPUVector<T> compute(CGPUMatrix<T> m, bool no_diag)
762  {
763  CGPUVector<T> result(m.num_cols);
764  compute(m, result, no_diag);
765  return result;
766  }
767 
776  static CGPUVector<T> compute(Block<CGPUMatrix<T> > b, bool no_diag)
777  {
778  SG_SERROR("The operation colwise_sum() on a matrix block is currently not supported\n");
779  return CGPUVector<T>();
780  }
781 
789  static void compute(CGPUMatrix<T> mat, CGPUVector<T> result, bool no_diag)
790  {
791  viennacl::ocl::kernel& kernel = generate_kernel<T>(no_diag);
792  kernel.global_work_size(0, ocl::align_to_multiple_1d(mat.num_cols));
793 
794  viennacl::ocl::enqueue(kernel(mat.vcl_matrix(),
795  cl_int(mat.num_rows), cl_int(mat.num_cols), cl_int(mat.offset),
796  result.vcl_vector(), cl_int(result.offset)));
797  }
798 
807  static void compute(Block<CGPUMatrix<T> > b, CGPUVector<T> result, bool no_diag)
808  {
809  SG_SERROR("The operation colwise_sum() on a matrix block is currently not supported\n");
810  }
811 };
812 
817 template <class Matrix>
818 struct rowwise_sum<Backend::VIENNACL,Matrix>
819 {
821  typedef typename Matrix::Scalar T;
822 
824  typedef CGPUVector<T> ReturnType;
825 
827  template <class T>
828  static viennacl::ocl::kernel& generate_kernel(bool no_diag)
829  {
830  std::string kernel_name = "rowwise_sum_" + ocl::get_type_string<T>();
831  if (no_diag) kernel_name.append("_no_diag");
832 
833  if (ocl::kernel_exists(kernel_name))
834  return ocl::get_kernel(kernel_name);
835 
836  std::string source = ocl::generate_kernel_preamble<T>(kernel_name);
837  if (no_diag) source.append("#define NO_DIAG\n");
838 
839  source.append(
840  R"(
841  __kernel void KERNEL_NAME(
842  __global DATATYPE* mat, int nrows, int ncols, int offset,
843  __global DATATYPE* result, int result_offset)
844  {
845  int i = get_global_id(0);
846 
847  if (i>=nrows)
848  return;
849 
850  DATATYPE sum = 0;
851  for (int j=0; j<ncols; j++)
852  {
853  #ifdef NO_DIAG
854  if (i!=j)
855  #endif
856  sum += mat[offset+i+j*nrows];
857  }
858 
859  result[i+result_offset] = sum;
860  }
861  )"
862  );
863 
864  viennacl::ocl::kernel& kernel = ocl::compile_kernel(kernel_name, source);
865 
866  kernel.local_work_size(0, OCL_WORK_GROUP_SIZE_1D);
867 
868  return kernel;
869  }
870 
878  static CGPUVector<T> compute(CGPUMatrix<T> m, bool no_diag)
879  {
880  CGPUVector<T> result(m.num_rows);
881  compute(m, result, no_diag);
882  return result;
883  }
884 
893  static CGPUVector<T> compute(Block<CGPUMatrix<T> > b, bool no_diag)
894  {
895  SG_SERROR("The operation rowwise_sum() on a matrix block is currently not supported\n");
896  return CGPUVector<T>();
897  }
898 
906  static void compute(CGPUMatrix<T> mat, CGPUVector<T> result, bool no_diag)
907  {
908  viennacl::ocl::kernel& kernel = generate_kernel<T>(no_diag);
909  kernel.global_work_size(0, ocl::align_to_multiple_1d(mat.num_rows));
910 
911  viennacl::ocl::enqueue(kernel(mat.vcl_matrix(),
912  cl_int(mat.num_rows), cl_int(mat.num_cols), cl_int(mat.offset),
913  result.vcl_vector(), cl_int(result.offset)));
914  }
915 
924  static void compute(Block<CGPUMatrix<T> > b, CGPUVector<T> result, bool no_diag)
925  {
926  SG_SERROR("The operation rowwise_sum() on a matrix block is currently not supported\n");
927  }
928 };
929 
930 #endif // HAVE_VIENNACL
931 
932 }
933 
934 }
935 
936 }
937 #endif // SUM_IMPL_H_
Generic class colwise_sum which provides a static compute method. This class is specialized for diffe...
Definition: Sum.h:131
static SGVector< T > compute(Matrix m, bool no_diag)
static SGVector< T > compute(SGMatrix< T > m, bool no_diag)
Definition: Sum.h:481
static void compute(SGMatrix< T > mat, SGVector< T > result, bool no_diag)
Definition: Sum.h:410
Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > MatrixXt
Definition: Sum.h:235
Generic class rowwise_sum which provides a static compute method. This class is specialized for diffe...
Definition: Sum.h:180
static T compute(Matrix m, bool no_diag)
static void compute(Block< SGMatrix< T > > b, SGVector< T > result, bool no_diag)
Definition: Sum.h:534
int32_t index_t
Definition: common.h:62
static T compute(SGMatrix< T > mat, bool no_diag)
Definition: Sum.h:244
static T compute(SGMatrix< T > mat, bool no_diag)
Definition: Sum.h:302
#define REQUIRE(x,...)
Definition: SGIO.h:206
index_t num_cols
Definition: SGMatrix.h:378
Generic class Block which wraps a matrix class and contains block specific information, providing a uniform way to deal with matrix blocks for all supported backend matrices.
Definition: Block.h:49
static void compute(SGMatrix< T > mat, SGVector< T > result, bool no_diag)
Definition: Sum.h:510
index_t num_rows
Definition: SGMatrix.h:376
Generic class sum which provides a static compute method. This class is specialized for different typ...
Definition: Sum.h:71
shogun matrix
static T compute(Matrix m, bool no_diag)
static SGVector< T > compute(Block< SGMatrix< T > > b, bool no_diag)
Definition: Sum.h:396
shogun vector
static SGVector< T > compute(Matrix m, bool no_diag)
all of classes and functions are contained in the shogun namespace
Definition: class_list.h:18
Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > MatrixXt
Definition: Sum.h:369
#define SG_SERROR(...)
Definition: SGIO.h:179
static T compute(Block< SGMatrix< T > > b, bool no_diag)
Definition: Sum.h:264
static SGVector< T > compute(SGMatrix< T > m, bool no_diag)
Definition: Sum.h:381
static T compute(Block< SGMatrix< T > > b, bool no_diag)
Definition: Sum.h:330
static void compute(Block< SGMatrix< T > > b, SGVector< T > result, bool no_diag)
Definition: Sum.h:434
static SGVector< T > compute(Block< SGMatrix< T > > b, bool no_diag)
Definition: Sum.h:496
Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > MatrixXt
Definition: Sum.h:469
Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > MatrixXt
Definition: Sum.h:293
Block< Matrix > block(Matrix matrix, index_t row_begin, index_t col_begin, index_t row_size, index_t col_size)
Definition: Block.h:102
Generic class sum symmetric which provides a static compute method. This class is specialized for dif...
Definition: Sum.h:101

SHOGUN Machine Learning Toolbox - Documentation