Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add transpose flags to element_prod #4183

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 23 additions & 7 deletions src/shogun/mathematics/linalg/LinalgBackendBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -308,20 +308,36 @@ namespace shogun
#undef BACKEND_GENERIC_EIGEN_SOLVER_SYMMETRIC

/**
* Wrapper method of in-place matrix/vector elementwise product.
* Wrapper method of in-place vector elementwise product.
*
* @see linalg::element_prod
*/
#define BACKEND_GENERIC_IN_PLACE_ELEMENT_PROD(Type, Container) \
#define BACKEND_GENERIC_IN_PLACE_VECTOR_ELEMENT_PROD(Type, Container) \
virtual void element_prod( \
const Container<Type>& a, const Container<Type>& b, \
Container<Type>& result) const \
{ \
SG_SNOTIMPLEMENTED; \
}
DEFINE_FOR_ALL_PTYPE(BACKEND_GENERIC_IN_PLACE_ELEMENT_PROD, SGMatrix)
DEFINE_FOR_ALL_PTYPE(BACKEND_GENERIC_IN_PLACE_ELEMENT_PROD, SGVector)
#undef BACKEND_GENERIC_IN_PLACE_ELEMENT_PROD
DEFINE_FOR_ALL_PTYPE(
BACKEND_GENERIC_IN_PLACE_VECTOR_ELEMENT_PROD, SGVector)
#undef BACKEND_GENERIC_IN_PLACE_VECTOR_ELEMENT_PROD

/**
* Wrapper method of in-place matrix elementwise product.
*
* @see linalg::element_prod
*/
#define BACKEND_GENERIC_IN_PLACE_MATRIX_ELEMENT_PROD(Type, Container) \
virtual void element_prod( \
const Container<Type>& a, const Container<Type>& b, \
Container<Type>& result, bool transpose_A, bool transpose_B) const \
{ \
SG_SNOTIMPLEMENTED; \
}
DEFINE_FOR_ALL_PTYPE(
BACKEND_GENERIC_IN_PLACE_MATRIX_ELEMENT_PROD, SGMatrix)
#undef BACKEND_GENERIC_IN_PLACE_MATRIX_ELEMENT_PROD

/**
* Wrapper method of in-place matrix block elementwise product.
Expand All @@ -331,8 +347,8 @@ namespace shogun
#define BACKEND_GENERIC_IN_PLACE_BLOCK_ELEMENT_PROD(Type, Container) \
virtual void element_prod( \
const linalg::Block<Container<Type>>& a, \
const linalg::Block<Container<Type>>& b, Container<Type>& result) \
const \
const linalg::Block<Container<Type>>& b, Container<Type>& result, \
bool transpose_A, bool transpose_B) const \
{ \
SG_SNOTIMPLEMENTED; \
}
Expand Down
28 changes: 19 additions & 9 deletions src/shogun/mathematics/linalg/LinalgBackendEigen.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,20 +158,29 @@ namespace shogun
#undef BACKEND_GENERIC_EIGEN_SOLVER_SYMMETRIC

/** Implementation of @see LinalgBackendBase::element_prod */
#define BACKEND_GENERIC_IN_PLACE_ELEMENT_PROD(Type, Container) \
#define BACKEND_GENERIC_IN_PLACE_VECTOR_ELEMENT_PROD(Type, Container) \
virtual void element_prod( \
const Container<Type>& a, const Container<Type>& b, \
Container<Type>& result) const;
DEFINE_FOR_ALL_PTYPE(BACKEND_GENERIC_IN_PLACE_ELEMENT_PROD, SGMatrix)
DEFINE_FOR_ALL_PTYPE(BACKEND_GENERIC_IN_PLACE_ELEMENT_PROD, SGVector)
#undef BACKEND_GENERIC_IN_PLACE_ELEMENT_PROD
DEFINE_FOR_ALL_PTYPE(
BACKEND_GENERIC_IN_PLACE_VECTOR_ELEMENT_PROD, SGVector)
#undef BACKEND_GENERIC_IN_PLACE_VECTOR_ELEMENT_PROD

/** Implementation of @see LinalgBackendBase::element_prod */
#define BACKEND_GENERIC_IN_PLACE_MATRIX_ELEMENT_PROD(Type, Container) \
virtual void element_prod( \
const Container<Type>& a, const Container<Type>& b, \
Container<Type>& result, bool transpose_A, bool transpose_B) const;
DEFINE_FOR_ALL_PTYPE(
BACKEND_GENERIC_IN_PLACE_MATRIX_ELEMENT_PROD, SGMatrix)
#undef BACKEND_GENERIC_IN_PLACE_MATRIX_ELEMENT_PROD

/** Implementation of @see LinalgBackendBase::element_prod */
#define BACKEND_GENERIC_IN_PLACE_BLOCK_ELEMENT_PROD(Type, Container) \
virtual void element_prod( \
const linalg::Block<Container<Type>>& a, \
const linalg::Block<Container<Type>>& b, Container<Type>& result) \
const;
const linalg::Block<Container<Type>>& b, Container<Type>& result, \
bool transpose_A, bool transpose_B) const;
DEFINE_FOR_ALL_PTYPE(
BACKEND_GENERIC_IN_PLACE_BLOCK_ELEMENT_PROD, SGMatrix)
#undef BACKEND_GENERIC_IN_PLACE_BLOCK_ELEMENT_PROD
Expand Down Expand Up @@ -498,14 +507,15 @@ namespace shogun
/** Eigen3 matrix in-place elementwise product method */
template <typename T>
void element_prod_impl(
const SGMatrix<T>& a, const SGMatrix<T>& b,
SGMatrix<T>& result) const;
const SGMatrix<T>& a, const SGMatrix<T>& b, SGMatrix<T>& result,
bool transpose_A, bool transpose_B) const;

/** Eigen3 matrix block in-place elementwise product method */
template <typename T>
void element_prod_impl(
const linalg::Block<SGMatrix<T>>& a,
const linalg::Block<SGMatrix<T>>& b, SGMatrix<T>& result) const;
const linalg::Block<SGMatrix<T>>& b, SGMatrix<T>& result,
bool transpose_A, bool transpose_B) const;

/** Eigen3 vector in-place elementwise product method */
template <typename T>
Expand Down
44 changes: 34 additions & 10 deletions src/shogun/mathematics/linalg/LinalgBackendViennaCL.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,14 @@ namespace shogun
#undef BACKEND_GENERIC_DOT

/** Implementation of @see LinalgBackendBase::element_prod */
#define BACKEND_GENERIC_IN_PLACE_ELEMENT_PROD(Type, Container) \
#define BACKEND_GENERIC_IN_PLACE_MATRIX_ELEMENT_PROD(Type, Container) \
virtual void element_prod(const Container<Type>& a, const Container<Type>& b,\
Container<Type>& result) const \
Container<Type>& result, bool transpose_A, bool transpose_B) const \
{ \
element_prod_impl(a, b, result); \
element_prod_impl(a, b, result, transpose_A, transpose_B); \
}
DEFINE_FOR_ALL_PTYPE(BACKEND_GENERIC_IN_PLACE_ELEMENT_PROD, SGMatrix)
#undef BACKEND_GENERIC_IN_PLACE_ELEMENT_PROD
DEFINE_FOR_ALL_PTYPE(BACKEND_GENERIC_IN_PLACE_MATRIX_ELEMENT_PROD, SGMatrix)
#undef BACKEND_GENERIC_IN_PLACE_MATRIX_ELEMENT_PROD

/** Implementation of @see LinalgBackendBase::logistic */
#define BACKEND_GENERIC_LOGISTIC(Type, Container) \
Expand Down Expand Up @@ -364,16 +364,40 @@ namespace shogun
/** ViennaCL matrix in-place elementwise product method */
template <typename T>
void element_prod_impl(
const SGMatrix<T>& a, const SGMatrix<T>& b, SGMatrix<T>& result) const
const SGMatrix<T>& a, const SGMatrix<T>& b, SGMatrix<T>& result,
bool transpose_A, bool transpose_B) const
{
GPUMemoryViennaCL<T>* a_gpu = cast_to_viennacl(a);
GPUMemoryViennaCL<T>* b_gpu = cast_to_viennacl(b);
GPUMemoryViennaCL<T>* result_gpu = cast_to_viennacl(result);

result_gpu->data_matrix(a.num_rows, a.num_cols) =
viennacl::linalg::element_prod(
a_gpu->data_matrix(a.num_rows, a.num_cols),
b_gpu->data_matrix(a.num_rows, a.num_cols));
if (transpose_A && transpose_B)
result_gpu->data_matrix(result.num_rows, result.num_cols) =
viennacl::linalg::element_prod(
viennacl::trans(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cant we store the "trans" in a varialbe and then use that in the if-then-else. Then we don't copy the whole code block 3 times ...

a_gpu->data_matrix(a.num_rows, a.num_cols)),
viennacl::trans(
b_gpu->data_matrix(b.num_rows, b.num_cols)));

else if (transpose_A)
result_gpu->data_matrix(result.num_rows, result.num_cols) =
viennacl::linalg::element_prod(
viennacl::trans(
a_gpu->data_matrix(a.num_rows, a.num_cols)),
b_gpu->data_matrix(b.num_rows, b.num_cols));

else if (transpose_B)
result_gpu->data_matrix(result.num_rows, result.num_cols) =
viennacl::linalg::element_prod(
a_gpu->data_matrix(a.num_rows, a.num_cols),
viennacl::trans(
b_gpu->data_matrix(b.num_rows, b.num_cols)));

else
result_gpu->data_matrix(result.num_rows, result.num_cols) =
viennacl::linalg::element_prod(
a_gpu->data_matrix(a.num_rows, a.num_cols),
b_gpu->data_matrix(b.num_rows, b.num_cols));
}

/** ViennaCL logistic method. Calculates f(x) = 1/(1+exp(-x)) */
Expand Down
105 changes: 57 additions & 48 deletions src/shogun/mathematics/linalg/LinalgNamespace.h
Original file line number Diff line number Diff line change
Expand Up @@ -812,32 +812,40 @@ namespace shogun
*
* This operation works with CPU backends only.
*
* @param a First matrix block
* @param b Second matrix block
* @param A First matrix block
* @param B Second matrix block
* @param result Result matrix
* @param transpose_A whether to transpose matrix A
* @param transpose_B whether to transpose matrix B
*/
template <typename T>
void element_prod(
const Block<SGMatrix<T>>& a, const Block<SGMatrix<T>>& b,
SGMatrix<T>& result)
const Block<SGMatrix<T>>& A, const Block<SGMatrix<T>>& B,
SGMatrix<T>& result, bool transpose_A = false,
bool transpose_B = false)
{
auto num_rows = transpose_A ? A.m_col_size : A.m_row_size;
auto num_cols = transpose_A ? A.m_row_size : A.m_col_size;

REQUIRE(
a.m_row_size == b.m_row_size && a.m_col_size == b.m_col_size,
"Dimension mismatch! A(%d x %d) vs B(%d x %d)\n", a.m_row_size,
a.m_col_size, b.m_row_size, b.m_col_size);
(num_rows == transpose_B ? B.m_col_size : B.m_row_size) &&
(num_cols == transpose_B ? B.m_row_size : B.m_col_size),
"Dimension mismatch! A(%d x %d) vs B(%d x %d)\n", A.m_row_size,
A.m_col_size, B.m_row_size, B.m_col_size);

REQUIRE(
a.m_row_size == result.num_rows &&
a.m_col_size == result.num_cols,
num_rows == result.num_rows && num_cols == result.num_cols,
"Dimension mismatch! A(%d x %d) vs result(%d x %d)\n",
a.m_row_size, a.m_col_size, result.num_rows, result.num_cols);
A.m_row_size, A.m_col_size, result.num_rows, result.num_cols);

REQUIRE(
!result.on_gpu(),
"Cannot operate with matrix result on_gpu (%d) \
as matrix blocks are on CPU.\n",
result.on_gpu());

sg_linalg->get_cpu_backend()->element_prod(a, b, result);
sg_linalg->get_cpu_backend()->element_prod(
A, B, result, transpose_A, transpose_B);
}

/** Performs the operation C = A .* B where ".*" denotes elementwise
Expand All @@ -848,21 +856,21 @@ namespace shogun
*
* @param A First matrix block
* @param B Second matrix block
* @param transpose_A whether to transpose matrix A
* @param transpose_B whether to transpose matrix B
* @return The result of the operation
*/
template <typename T>
SGMatrix<T>
element_prod(const Block<SGMatrix<T>>& a, const Block<SGMatrix<T>>& b)
SGMatrix<T> element_prod(
const Block<SGMatrix<T>>& A, const Block<SGMatrix<T>>& B,
bool transpose_A = false, bool transpose_B = false)
{
REQUIRE(
a.m_row_size == b.m_row_size && a.m_col_size == b.m_col_size,
"Dimension mismatch! A(%d x %d) vs B(%d x %d)\n", a.m_row_size,
a.m_col_size, b.m_row_size, b.m_col_size);
auto num_rows = transpose_A ? A.m_col_size : A.m_row_size;
auto num_cols = transpose_A ? A.m_row_size : A.m_col_size;

SGMatrix<T> result(a.m_row_size, a.m_col_size);
result.zero();
SGMatrix<T> result(num_rows, num_cols);

element_prod(a, b, result);
element_prod(A, B, result, transpose_A, transpose_B);

return result;
}
Expand All @@ -877,55 +885,56 @@ namespace shogun
* @param a First matrix
* @param b Second matrix
* @param result Result matrix
* @param transpose_A whether to transpose matrix A
* @param transpose_B whether to transpose matrix B
*/
template <typename T>
void element_prod(
const SGMatrix<T>& a, const SGMatrix<T>& b, SGMatrix<T>& result)
const SGMatrix<T>& A, const SGMatrix<T>& B, SGMatrix<T>& result,
bool transpose_A = false, bool transpose_B = false)
{
REQUIRE(
a.num_rows == b.num_rows && a.num_cols == b.num_cols,
"Dimension mismatch! A(%d x %d) vs B(%d x %d)\n", a.num_rows,
a.num_cols, b.num_rows, b.num_cols);
REQUIRE(
a.num_rows == result.num_rows && a.num_cols == result.num_cols,
"Dimension mismatch! A(%d x %d) vs result(%d x %d)\n",
a.num_rows, a.num_cols, result.num_rows, result.num_cols);
auto num_rows = transpose_A ? A.num_cols : A.num_rows;
auto num_cols = transpose_A ? A.num_rows : A.num_cols;

REQUIRE(
!(result.on_gpu() ^ a.on_gpu()),
"Cannot operate with matrix result on_gpu (%d) and \
matrix A on_gpu (%d).\n",
result.on_gpu(), a.on_gpu());
(num_rows == transpose_B ? B.num_cols : B.num_rows) &&
(num_cols == transpose_B ? B.num_rows : B.num_cols),
"Dimension mismatch! A(%d x %d) vs B(%d x %d)\n", A.num_rows,
A.num_cols, B.num_rows, B.num_cols);

REQUIRE(
!(result.on_gpu() ^ b.on_gpu()),
"Cannot operate with matrix result on_gpu (%d) and \
matrix B on_gpu (%d).\n",
result.on_gpu(), b.on_gpu());
num_rows == result.num_rows && num_cols == result.num_cols,
"Dimension mismatch! A(%d x %d) vs result(%d x %d)\n",
A.num_rows, A.num_cols, result.num_rows, result.num_cols);

infer_backend(a, b)->element_prod(a, b, result);
infer_backend(A, B, result)
->element_prod(A, B, result, transpose_A, transpose_B);
}

/** Performs the operation C = A .* B where ".*" denotes elementwise
* multiplication.
*
* This version returns the result in a newly created matrix.
*
* @param a First matrix
* @param b Second matrix
* @param A First matrix
* @param B Second matrix
* @param transpose_A whether to transpose matrix A
* @param transpose_B whether to transpose matrix B
* @return The result of the operation
*/
template <typename T>
SGMatrix<T> element_prod(const SGMatrix<T>& a, const SGMatrix<T>& b)
SGMatrix<T> element_prod(
const SGMatrix<T>& A, const SGMatrix<T>& B,
bool transpose_A = false, bool transpose_B = false)
{
REQUIRE(
a.num_rows == b.num_rows && a.num_cols == b.num_cols,
"Dimension mismatch! A(%d x %d) vs B(%d x %d)\n", a.num_rows,
a.num_cols, b.num_rows, b.num_cols);
auto num_rows = transpose_A ? A.num_cols : A.num_rows;
auto num_cols = transpose_A ? A.num_rows : A.num_cols;

SGMatrix<T> result;
result = a.clone();
SGMatrix<T> result(num_rows, num_cols);

element_prod(a, b, result);
if (A.on_gpu())
to_gpu(result);
element_prod(A, B, result, transpose_A, transpose_B);

return result;
}
Expand Down