NICE
Northeastern Interactive Clustering Engine
cpu_operations.h
Go to the documentation of this file.
1 // The MIT License (MIT)
2 //
3 // Copyright (c) 2016 Northeastern University
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 // SOFTWARE.
22 
23 #ifndef CPP_INCLUDE_CPU_OPERATIONS_H_
24 #define CPP_INCLUDE_CPU_OPERATIONS_H_
25 
26 #include <string>
27 #include <iostream>
28 #include <cmath>
29 #include "include/matrix.h"
30 #include "include/vector.h"
31 #include "include/kernel_types.h"
32 #include "Eigen/SVD"
33 #include "include/svd_solver.h"
34 #include "include/util.h"
35 
36 namespace Nice {
37 
38 // Abstract class of common matrix operation interface
39 template<typename T>
41  public:
49  static Matrix<T> Transpose(const Matrix<T> &a) {
50  return a.transpose(); // Return transpose
51  }
52 
60  static Vector<T> Transpose(const Vector<T> &a) {
61  return a.transpose();
62  }
63 
74  static Matrix<T> Multiply(const Matrix<T> &a, const T &scalar) {
75  // Scalar-matrix multiplication
76  return scalar * a;
77  }
78 
89  static Matrix<T> Multiply(const Matrix<T> &a, const Matrix<T> &b) {
90  // Matrix-matrix multiplication
91  return a * b;
92  }
107  static Matrix<T> Add(const Matrix<T> &a, const T &scalar) {
108  // Does not work if matrix is empty.
109  if (a.rows() == 0) {
110  std::cerr << "MATRICIES ARE EMPTY";
111  exit(1);
112 
113  // Otherwise, code will run fine.
114  } else {
115  return (a.array() + scalar);
116  }
117  }
132  static Matrix<T> Add(const Matrix<T> &a, const Matrix<T> &b) {
133  // Does not work if matricies are not the same size.
134  if ((a.rows() != b.rows()) || (a.cols() != b.cols())) {
135  std::cerr << "MATRICIES ARE NOT THE SAME SIZE";
136  exit(1);
137 
138  // Does not work if matricies are empty.
139  } else if (a.rows() == 0) {
140  std::cerr << "MATRICIES ARE EMPTY";
141  exit(1);
142 
143  // Otherwise, code will run fine.
144  } else {
145  return a + b;
146  }
147  }
148  static Matrix<T> Subtract(const Matrix<T> &a, const T &scalar) {
149  // Matrix-scalar subtraction
150  if (a.rows() == 0 || a.cols() == 0) {
151  std::cerr << "EMPTY MATRIX AS ARGUEMENT!";
152  exit(1);
153  }
154  return (a.array() - scalar);
155  }
156  static Matrix<T> Subtract(const Matrix<T> &a, const Matrix<T> &b) {
157  // Matrix-matrix subtraction
158  if ((a.rows() != b.rows()) || (a.cols() != b.cols())) {
159  std::cerr << "MATRICES ARE NOT THE SAME SIZE!";
160  exit(1); // Exits the program
161  } else if (b.rows() == 0 || b.cols() == 0 || a.rows() == 0
162  || a.cols() == 0) {
163  std::cerr << "EMPTY MATRIX AS ARGUMENT!";
164  exit(1); // Exits the program
165  }
166  return a - b;
167  }
168 
179  static Matrix<bool> LogicalOr(const Matrix<bool> &a, const Matrix<bool> &b) {
180  // Returns the resulting matrix that is created by running a logical or
181  // operation on the two input matrices
182  if ((a.rows() != b.rows()) || (a.cols() != b.cols())) {
183  std::cerr << "MATRICES ARE NOT THE SAME SIZE!";
184  exit(1); // Exits the program
185  } else if (b.rows() == 0 || b.cols() == 0 || a.rows() == 0
186  || a.cols() == 0) {
187  std::cerr << "EMPTY MATRIX AS ARGUMENT!";
188  exit(1); // Exits the program
189  }
190  return (a.array() || b.array());
191  }
192 
201  Matrix<bool> b = a.replicate(1, 1);
202  int r;
203  // Iterate through the copied matrix
204  for (r = 0; r < b.rows(); ++r) {
205  for (int c = 0; c < b.cols(); ++c) {
206  b(r, c) = !b(r, c);
207  }
208  }
209  if (b.rows() == 0 || b.cols() == 0) {
210  std::cerr << "EMPTY MATRIX AS ARGUMENT!";
211  exit(1); // Exits the program
212  }
213  return b;
214  }
215 
226  static Matrix<bool> LogicalAnd(const Matrix<bool> &a, const Matrix<bool> &b) {
227  // Checks to see that the number of rows and columns are the same
228  if ((a.rows() != b.rows()) || (a.cols() != b.cols())) {
229  std::cerr << "MATRICES ARE NOT THE SAME SIZE!";
230  exit(1); // Exits the program
231  }
232  return (a.array() && b.array());
233  // Will return a matrix due to implicit conversion
234  }
235 
243  static Matrix<T> Inverse(const Matrix<T> &a) {
244  // If the matrix is empty, it should not check for inverse.
245  if (a.cols() == 0) {
246  std::cerr << "MATRIX IS EMPTY";
247  exit(1);
248  // If the matrix is not sqaure it will not produce an inverse.
249  } else if (a.cols() != a.rows()) {
250  std::cerr << "MATRIX IS NOT A SQUARE MATRIX!";
251  exit(1);
252 
253  // If the determinant of a matrix is 0, it does not have an inverse.
254  } else if (a.determinant() == 0) {
255  std::cerr << "MATRIX DOES NOT HAVE AN INVERSE (DETERMINANT IS ZERO)!";
256  exit(1);
257 
258  // If this point is reached then an inverse of the matrix exists.
259  } else {
260  return a.inverse();
261  }
262  }
263 
282  static Vector<T> Norm(const Matrix<T> &a,
283  const int &p = 2,
284  const int &axis = 0) {
285  int num_rows = a.rows();
286  int num_cols = a.cols();
287  float norm_value = 0;
288  if (axis == 0) {
289  Vector<T> norm(num_cols);
290  for (int j = 0; j < num_cols; j++) {
291  for (int i = 0; i < num_rows; i++)
292  norm_value += pow(a(i, j), p);
293  norm(j) = pow(norm_value, (1.0/p));
294  norm_value = 0;
295  }
296  return norm;
297  } else if (axis == 1) {
298  Vector<T> norm(num_rows);
299  for (int i = 0; i < num_rows; i++) {
300  for (int j = 0; j < num_cols; j++)
301  norm_value += pow(a(i, j), p);
302  norm(i) = pow(norm_value, (1.0/p));
303  norm_value = 0;
304  }
305  return norm;
306  } else {
307  std::cerr << "Axis must be zero or one!";
308  exit(1);
309  }
310 }
311 
312  static T Determinant(const Matrix<T> &a);
320 
321  static int Rank(const Matrix<T> &a) {
322  // Rank of a matrix
323  SvdSolver<T> svd;
324  return svd.Rank(a);
325  }
326 
333  static T FrobeniusNorm(const Matrix<T> &a) {
334  if (a.rows() == 0 || a.cols() == 0) {
335  std::cerr << "EMPTY MATRIX AS ARGUMENT!";
336  exit(-1); // Exits the program
337  } else {
338  return a.norm();
339  }
340  }
341 
350 
351  static T Trace(const Matrix<T> &a) {
352  // Trace of a matrix
353  return a.trace();
354  }
355 
366  static T DotProduct(const Vector<T> &a, const Vector<T> &b) {
367  // Checks to see if the size of the two vectors are not the same
368  if (a.size() != b.size()) {
369  std::cerr << "VECTORS ARE NOT THE SAME SIZE!";
370  exit(1);
371 
372  // Checks to see if both vectors contain at least one element
373  // Only one vector is checked because it is known that both
374  // vectors are the same size
375  } else if (a.size() == 0) {
376  std::cerr << "VECTORS ARE EMPTY!";
377  exit(1);
378 
379  // If this point is reached then calculating the dot product
380  // of the two vectors is valid
381  } else {
382  return (a.dot(b));
383  }
384  }
394  static Matrix<T> OuterProduct(const Vector<T> &a, const Vector<T> &b) {
395  // This function returns the outer product of he two passed in vectors
396  if (a.size() == 0 || b.size() == 0) {
397  std::cerr << "EMPTY VECTOR AS ARGUMENT!";
398  exit(1);
399  }
400  return a * b.transpose();
401  }
402 
413  static Vector<bool> LogicalAnd(const Vector<T> &a, const Vector<T> &b) {
414  if ((a.rows() != b.rows()) || (a.cols() != b.cols())) {
415  std::cerr << "MATRICES ARE NOT THE SAME SIZE!";
416  exit(1); // Exits the program
417  }
418  return (a.array() && b.array());
419  }
430  static Vector<bool> LogicalOr(const Vector<bool> &a, const Vector<bool> &b) {
431  // Returns the resulting vector that is created by running a logical or
432  // operation on the two input vectors
433  if (a.size() != b.size()) {
434  std::cerr << "VECTORS ARE NOT THE SAME SIZE!";
435  exit(1); // Exits the program
436  } else if (a.size() == 0 || b.size() == 0) {
437  std::cerr << "EMPTY VECTOR AS ARGUMENT!";
438  exit(1); // Exits the program
439  }
440  return (a.array() || b.array());
441  }
442 
451  Vector<bool> b = a.replicate(1, 1);
452  int i;
453  // Iterate through vector
454  for (i = 0; i < b.size(); ++i) {
455  b(i) = !b(i);
456  }
457  if (a.size() == 0) {
458  std::cerr << "EMPTY VECTOR AS ARGUMENT!";
459  exit(1); // Exits the program
460  }
461  return b;
462  }
477  static Matrix<T> Normalize(const Matrix<T> &a, const int &p = 2,
478  const int &axis = 0) {
479  int num_rows = a.rows();
480  int num_cols = a.cols();
481  Matrix<T> b(num_rows, num_cols);
482  if (axis == 0) {
483  b = a.transpose().array().colwise() / Norm(a, p, axis).array();
484  return b.transpose();
485  } else if (axis == 1) {
486  b = a.array().colwise() / Norm(a, p, axis).array();
487  return b;
488  } else {
489  std::cerr << "Axis must be zero or one!";
490  exit(1);
491  }
492  }
505  const Matrix<T> &data_matrix,
506  const KernelType kernel_type = kGaussianKernel,
507  const float constant = 1.0) {
508  int num_samples = data_matrix.rows();
509  // An n x n kernel matrix
510  Matrix<T> kernel_matrix(num_samples, num_samples);
511  if (kernel_type == kGaussianKernel) {
512  float sigma = constant;
513  // This for loop generates the kernel matrix using Gaussian kernel
514  for (int i = 0; i < num_samples; i++)
515  for (int j = 0; j < num_samples; j++) {
516  // Calculate the the norm of (x_i - x_j) for all (i, j) pairs
517  float i_j_dist = (data_matrix.row(i) - data_matrix.row(j)).norm();
518  kernel_matrix(i, j) = exp(-i_j_dist / (2 * sigma * sigma));
519  }
520  }
521  return kernel_matrix;
522  }
523 
532  static void GenDegreeMatrix(
533  const Matrix<T> &kernel_matrix,
534  Matrix<T> &degree_matrix,
535  Matrix<T> &degree_matrix_to_the_minus_half) {
536  // Generate the diagonal vector d_i and degree matrix D
537  Vector<T> d_i = kernel_matrix.rowwise().sum();
538  degree_matrix = d_i.asDiagonal();
539  // Generate matrix D^(-1/2)
540  degree_matrix_to_the_minus_half = d_i.array().sqrt().unaryExpr(
541  std::ptr_fun(util::reciprocal<T>)).matrix().asDiagonal();
542  }
543 };
544 } // namespace Nice
545 #endif // CPP_INCLUDE_CPU_OPERATIONS_H_
static Vector< T > Transpose(const Vector< T > &a)
Definition: cpu_operations.h:60
KernelType
Definition: kernel_types.h:27
static T Determinant(const Matrix< T > &a)
static void GenDegreeMatrix(const Matrix< T > &kernel_matrix, Matrix< T > &degree_matrix, Matrix< T > &degree_matrix_to_the_minus_half)
Definition: cpu_operations.h:532
static Matrix< T > Multiply(const Matrix< T > &a, const T &scalar)
Definition: cpu_operations.h:74
static Vector< bool > LogicalOr(const Vector< bool > &a, const Vector< bool > &b)
Definition: cpu_operations.h:430
static Matrix< bool > LogicalAnd(const Matrix< bool > &a, const Matrix< bool > &b)
Definition: cpu_operations.h:226
static Matrix< T > Add(const Matrix< T > &a, const T &scalar)
Definition: cpu_operations.h:107
Definition: cpu_operations.h:36
Definition: kernel_types.h:28
static Matrix< T > Subtract(const Matrix< T > &a, const T &scalar)
Definition: cpu_operations.h:148
int Rank(const Matrix< T > &a)
Definition: svd_solver.h:96
Definition: svd_solver.h:36
static T FrobeniusNorm(const Matrix< T > &a)
Definition: cpu_operations.h:333
static Matrix< T > OuterProduct(const Vector< T > &a, const Vector< T > &b)
Definition: cpu_operations.h:394
static Matrix< bool > LogicalOr(const Matrix< bool > &a, const Matrix< bool > &b)
Definition: cpu_operations.h:179
static Matrix< T > Transpose(const Matrix< T > &a)
Definition: cpu_operations.h:49
static Matrix< bool > LogicalNot(const Matrix< bool > &a)
Definition: cpu_operations.h:200
static T DotProduct(const Vector< T > &a, const Vector< T > &b)
Definition: cpu_operations.h:366
Definition: cpu_operations.h:40
static T Trace(const Matrix< T > &a)
Definition: cpu_operations.h:351
Eigen::Matrix< T, Eigen::Dynamic, 1 > Vector
Definition: vector.h:31
static Matrix< T > Normalize(const Matrix< T > &a, const int &p=2, const int &axis=0)
Definition: cpu_operations.h:477
static Matrix< T > GenKernelMatrix(const Matrix< T > &data_matrix, const KernelType kernel_type=kGaussianKernel, const float constant=1.0)
Definition: cpu_operations.h:504
static Vector< T > Norm(const Matrix< T > &a, const int &p=2, const int &axis=0)
Definition: cpu_operations.h:282
Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > Matrix
Definition: matrix.h:31
static Matrix< T > Add(const Matrix< T > &a, const Matrix< T > &b)
Definition: cpu_operations.h:132
static Vector< bool > LogicalAnd(const Vector< T > &a, const Vector< T > &b)
Definition: cpu_operations.h:413
static Matrix< T > Subtract(const Matrix< T > &a, const Matrix< T > &b)
Definition: cpu_operations.h:156
static int Rank(const Matrix< T > &a)
Definition: cpu_operations.h:321
static Matrix< T > Multiply(const Matrix< T > &a, const Matrix< T > &b)
Definition: cpu_operations.h:89
static Vector< bool > LogicalNot(const Vector< bool > &a)
Definition: cpu_operations.h:450
static Matrix< T > Inverse(const Matrix< T > &a)
Definition: cpu_operations.h:243