Skip to content

Commit

Permalink
Made matrix +/- operations multithreading
Browse files Browse the repository at this point in the history
  • Loading branch information
hosseinmoein committed Dec 4, 2024
1 parent baa0d0c commit 4ac76f4
Show file tree
Hide file tree
Showing 3 changed files with 204 additions and 56 deletions.
16 changes: 16 additions & 0 deletions include/DataFrame/DataFrameTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,22 @@ struct StationaryParams {

// ----------------------------------------------------------------------------

enum class stationary_test : unsigned char {

kpss = 1, // Kwiatkowski-Phillips-Schmidt–Shin test
adf = 2, // Augmented Dickey-Fuller test
};

struct StationaryTestParams {

// Only considered for ADF test
//
std::size_t adf_lag { 1 };
bool adf_with_trend { false };
};

// ----------------------------------------------------------------------------

template<typename T>
struct RandGenParams {

Expand Down
200 changes: 164 additions & 36 deletions include/DataFrame/Utils/Matrix.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,10 @@ class Matrix {

using storage_t = std::vector<value_type>;

size_type ppivot_(size_type pivot_row) noexcept;
inline size_type
ppivot_(size_type pivot_row,
size_type self_rows,
size_type self_cols) noexcept;

size_type rows_ { 0 };
size_type cols_ { 0 };
Expand Down Expand Up @@ -1014,20 +1017,51 @@ template<typename T, matrix_orient MO1, matrix_orient MO2>
static inline Matrix<T, MO1>
operator + (const Matrix<T, MO1> &lhs, const Matrix<T, MO2> &rhs) {

assert(lhs.rows() == rhs.rows() && lhs.cols() == rhs.cols());
const long lhs_rows = lhs.rows();
const long lhs_cols = lhs.cols();

auto result = lhs;
#ifdef HMDF_SANITY_EXCEPTIONS
assert(lhs_rows == rhs.rows() && lhs_cols == rhs.cols());
#endif // HMDF_SANITY_EXCEPTIONS

if constexpr (MO1 == matrix_orient::column_major) {
for (long c = 0; c < lhs.cols(); ++c)
for (long r = 0; r < lhs.rows(); ++r)
result(r, c) += rhs(r, c);
auto result = lhs;
auto col_lbd =
[lhs_rows, &result, &rhs = std::as_const(rhs)]
(auto begin, auto end) -> void {
for (long c = begin; c < end; ++c)
for (long r = 0; r < lhs_rows; ++r)
result(r, c) += rhs(r, c);
};
auto row_lbd =
[lhs_cols, &result, &rhs = std::as_const(rhs)]
(auto begin, auto end) -> void {
for (long r = begin; r < end; ++r)
for (long c = 0; c < lhs_cols; ++c)
result(r, c) += rhs(r, c);
};
const long thread_level =
(lhs_cols >= 20000L || lhs_rows >= 20000L)
? ThreadGranularity::get_thread_level() : 0;

if (thread_level > 2) {
std::vector<std::future<void>> futures;

if constexpr (MO1 == matrix_orient::column_major)
futures = ThreadGranularity::thr_pool_.parallel_loop(
0L, lhs_cols, std::move(col_lbd));
else // matrix_orient::row_major
futures = ThreadGranularity::thr_pool_.parallel_loop(
0L, lhs_rows, std::move(row_lbd));

for (auto &fut : futures) fut.get();
}
else {
for (long r = 0; r < lhs.rows(); ++r)
for (long c = 0; c < lhs.cols(); ++c)
result(r, c) += rhs(r, c);
if constexpr (MO1 == matrix_orient::column_major)
col_lbd(0L, lhs_cols);
else // matrix_orient::row_major
row_lbd(0L, lhs_rows);
}

return (result);
}

Expand All @@ -1037,20 +1071,51 @@ template<typename T, matrix_orient MO1, matrix_orient MO2>
static inline Matrix<T, MO1>
operator - (const Matrix<T, MO1> &lhs, const Matrix<T, MO2> &rhs) {

assert(lhs.rows() == rhs.rows() && lhs.cols() == rhs.cols());
const long lhs_rows = lhs.rows();
const long lhs_cols = lhs.cols();

#ifdef HMDF_SANITY_EXCEPTIONS
assert(lhs_rows == rhs.rows() && lhs_cols == rhs.cols());
#endif // HMDF_SANITY_EXCEPTIONS

auto result = lhs;
auto col_lbd =
[lhs_rows, &result, &rhs = std::as_const(rhs)]
(auto begin, auto end) -> void {
for (long c = begin; c < end; ++c)
for (long r = 0; r < lhs_rows; ++r)
result(r, c) -= rhs(r, c);
};
auto row_lbd =
[lhs_cols, &result, &rhs = std::as_const(rhs)]
(auto begin, auto end) -> void {
for (long r = begin; r < end; ++r)
for (long c = 0; c < lhs_cols; ++c)
result(r, c) -= rhs(r, c);
};
const long thread_level =
(lhs_cols >= 20000L || lhs_rows >= 20000L)
? ThreadGranularity::get_thread_level() : 0;

auto result = lhs;
if (thread_level > 2) {
std::vector<std::future<void>> futures;

if constexpr (MO1 == matrix_orient::column_major) {
for (long c = 0; c < lhs.cols(); ++c)
for (long r = 0; r < lhs.rows(); ++r)
result(r, c) -= rhs(r, c);
if constexpr (MO1 == matrix_orient::column_major)
futures = ThreadGranularity::thr_pool_.parallel_loop(
0L, lhs_cols, std::move(col_lbd));
else // matrix_orient::row_major
futures = ThreadGranularity::thr_pool_.parallel_loop(
0L, lhs_rows, std::move(row_lbd));

for (auto &fut : futures) fut.get();
}
else {
for (long r = 0; r < lhs.rows(); ++r)
for (long c = 0; c < lhs.cols(); ++c)
result(r, c) -= rhs(r, c);
if constexpr (MO1 == matrix_orient::column_major)
col_lbd(0L, lhs_cols);
else // matrix_orient::row_major
row_lbd(0L, lhs_rows);
}

return (result);
}

Expand All @@ -1060,18 +1125,50 @@ template<typename T, matrix_orient MO1, matrix_orient MO2>
static inline Matrix<T, MO1> &
operator += (Matrix<T, MO1> &lhs, const Matrix<T, MO2> &rhs) {

assert(lhs.rows() == rhs.rows() && lhs.cols() == rhs.cols());
const long lhs_rows = lhs.rows();
const long lhs_cols = lhs.cols();

if constexpr (MO1 == matrix_orient::column_major) {
for (long c = 0; c < lhs.cols(); ++c)
for (long r = 0; r < lhs.rows(); ++r)
lhs(r, c) += rhs(r, c);
#ifdef HMDF_SANITY_EXCEPTIONS
assert(lhs_rows == rhs.rows() && lhs_cols == rhs.cols());
#endif // HMDF_SANITY_EXCEPTIONS

auto col_lbd =
[lhs_rows, &lhs, &rhs = std::as_const(rhs)]
(auto begin, auto end) -> void {
for (long c = begin; c < end; ++c)
for (long r = 0; r < lhs_rows; ++r)
lhs(r, c) += rhs(r, c);
};
auto row_lbd =
[lhs_cols, &lhs, &rhs = std::as_const(rhs)]
(auto begin, auto end) -> void {
for (long r = begin; r < end; ++r)
for (long c = 0; c < lhs_cols; ++c)
lhs(r, c) += rhs(r, c);
};
const long thread_level =
(lhs_cols >= 20000L || lhs_rows >= 20000L)
? ThreadGranularity::get_thread_level() : 0;

if (thread_level > 2) {
std::vector<std::future<void>> futures;

if constexpr (MO1 == matrix_orient::column_major)
futures = ThreadGranularity::thr_pool_.parallel_loop(
0L, lhs_cols, std::move(col_lbd));
else // matrix_orient::row_major
futures = ThreadGranularity::thr_pool_.parallel_loop(
0L, lhs_rows, std::move(row_lbd));

for (auto &fut : futures) fut.get();
}
else {
for (long r = 0; r < lhs.rows(); ++r)
for (long c = 0; c < lhs.cols(); ++c)
lhs(r, c) += rhs(r, c);
if constexpr (MO1 == matrix_orient::column_major)
col_lbd(0L, lhs_cols);
else // matrix_orient::row_major
row_lbd(0L, lhs_rows);
}

return (lhs);
}

Expand All @@ -1081,18 +1178,50 @@ template<typename T, matrix_orient MO1, matrix_orient MO2>
static inline Matrix<T, MO1> &
operator -= (Matrix<T, MO1> &lhs, const Matrix<T, MO2> &rhs) {

assert(lhs.rows() == rhs.rows() && lhs.cols() == rhs.cols());
const long lhs_rows = lhs.rows();
const long lhs_cols = lhs.cols();

if constexpr (MO1 == matrix_orient::column_major) {
for (long c = 0; c < lhs.cols(); ++c)
for (long r = 0; r < lhs.rows(); ++r)
lhs(r, c) -= rhs(r, c);
#ifdef HMDF_SANITY_EXCEPTIONS
assert(lhs_rows == rhs.rows() && lhs_cols == rhs.cols());
#endif // HMDF_SANITY_EXCEPTIONS

auto col_lbd =
[lhs_rows, &lhs, &rhs = std::as_const(rhs)]
(auto begin, auto end) -> void {
for (long c = begin; c < end; ++c)
for (long r = 0; r < lhs_rows; ++r)
lhs(r, c) -= rhs(r, c);
};
auto row_lbd =
[lhs_cols, &lhs, &rhs = std::as_const(rhs)]
(auto begin, auto end) -> void {
for (long r = begin; r < end; ++r)
for (long c = 0; c < lhs_cols; ++c)
lhs(r, c) -= rhs(r, c);
};
const long thread_level =
(lhs_cols >= 20000L || lhs_rows >= 20000L)
? ThreadGranularity::get_thread_level() : 0;

if (thread_level > 2) {
std::vector<std::future<void>> futures;

if constexpr (MO1 == matrix_orient::column_major)
futures = ThreadGranularity::thr_pool_.parallel_loop(
0L, lhs_cols, std::move(col_lbd));
else // matrix_orient::row_major
futures = ThreadGranularity::thr_pool_.parallel_loop(
0L, lhs_rows, std::move(row_lbd));

for (auto &fut : futures) fut.get();
}
else {
for (long r = 0; r < lhs.rows(); ++r)
for (long c = 0; c < lhs.cols(); ++c)
lhs(r, c) -= rhs(r, c);
if constexpr (MO1 == matrix_orient::column_major)
col_lbd(0L, lhs_cols);
else // matrix_orient::row_major
row_lbd(0L, lhs_rows);
}

return (lhs);
}

Expand All @@ -1104,7 +1233,6 @@ template<typename T, matrix_orient MO1, matrix_orient MO2>
static Matrix<T, MO1>
operator * (const Matrix<T, MO1> &lhs, const Matrix<T, MO2> &rhs) {


const long lhs_rows { lhs.rows() };
const long lhs_cols { lhs.cols() };
const long rhs_cols { rhs.cols() };
Expand Down
44 changes: 24 additions & 20 deletions include/DataFrame/Utils/Matrix.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -221,13 +221,15 @@ Matrix<T, MO>::transpose2() const noexcept {
// ----------------------------------------------------------------------------

template<typename T, matrix_orient MO>
Matrix<T, MO>::size_type
Matrix<T, MO>::ppivot_(size_type pivot_row) noexcept {
inline Matrix<T, MO>::size_type
Matrix<T, MO>::ppivot_(size_type pivot_row,
size_type self_rows,
size_type self_cols) noexcept {

size_type max_row { pivot_row };
value_type max_value { value_type(std::fabs(at(pivot_row, pivot_row))) };

for (size_type r = pivot_row + 1; r < rows(); ++r) {
for (size_type r = pivot_row + 1; r < self_rows; ++r) {
const value_type tmp { value_type(std::fabs(at(r, pivot_row))) };

if (tmp > max_value && tmp != value_type(0)) {
Expand All @@ -240,7 +242,7 @@ Matrix<T, MO>::ppivot_(size_type pivot_row) noexcept {
return (NOPOS_);

if (max_row != pivot_row) {
for (size_type c = 0; c < cols(); ++c)
for (size_type c = 0; c < self_cols; ++c)
std::swap(at(pivot_row, c), at(max_row, c));
return (max_row);
}
Expand All @@ -257,38 +259,40 @@ Matrix<T, MO>::inverse() const {
if (rows() != cols())
throw DataFrameError("Matrix::inverse(): Matrix must be squared");

Matrix aux_mat = *this;
Matrix result { rows(), cols(), 0 };
const size_type self_rows = rows();
const size_type self_cols = cols();
Matrix aux_mat { *this };
Matrix result { self_rows, self_cols, 0 };

// First make identity matrix
//
for (size_type d = 0; d < result.cols(); ++d)
result(d, d) = value_type(1);
for (size_type d = 0; d < self_cols; ++d)
result.at(d, d) = value_type(1);

for (size_type r = 0; r < aux_mat.rows (); ++r) {
const size_type idx = aux_mat.ppivot_(r);
for (size_type r = 0; r < self_rows; ++r) {
const size_type idx = aux_mat.ppivot_(r, self_rows, self_cols);

if (idx == NOPOS_)
throw DataFrameError("Matrix::inverse(): Singular matrix");

if (idx != 0)
for (size_type c = 0; c < aux_mat.cols(); ++c)
std::swap(result(r, c), result(idx, c));
for (size_type c = 0; c < self_cols; ++c)
std::swap(result.at(r, c), result.at(idx, c));

const value_type diag = aux_mat.at(r, r);

for (size_type c = 0; c < aux_mat.cols(); ++c) {
for (size_type c = 0; c < self_cols; ++c) {
aux_mat.at(r, c) /= diag;
result(r, c) /= diag;
result.at(r, c) /= diag;
}

for (size_type rr = 0; rr < aux_mat.rows (); ++rr) {
if (rr != r) {
const value_type off_diag = aux_mat.at(rr, r);
for (size_type r2 = 0; r2 < self_rows; ++r2) {
if (r2 != r) {
const value_type off_diag = aux_mat.at(r2, r);

for (size_type c = 0; c < aux_mat.cols(); ++c) {
aux_mat.at(rr, c) -= off_diag * aux_mat.at(r, c);
result(rr, c) -= off_diag * result(r, c);
for (size_type c = 0; c < self_cols; ++c) {
aux_mat.at(r2, c) -= off_diag * aux_mat.at(r, c);
result.at(r2, c) -= off_diag * result.at(r, c);
}
}
}
Expand Down

0 comments on commit 4ac76f4

Please sign in to comment.