1
1
#ifndef TACHYON_MATH_MATRIX_MATRIX_UTILS_H_
2
2
#define TACHYON_MATH_MATRIX_MATRIX_UTILS_H_
3
3
4
+ #include < utility>
4
5
#include < vector>
5
6
6
7
#include " third_party/eigen3/Eigen/Core"
7
8
9
+ #include " tachyon/base/bits.h"
8
10
#include " tachyon/base/containers/container_util.h"
11
+ #include " tachyon/base/openmp_util.h"
9
12
#include " tachyon/math/finite_fields/packed_prime_field_traits_forward.h"
10
13
11
14
namespace tachyon ::math {
@@ -45,22 +48,25 @@ MakeCirculant(const Eigen::MatrixBase<ArgType>& arg) {
45
48
CirculantFunctor<ArgType>(arg.derived ()));
46
49
}
47
50
51
+ // NOTE(ashjeong): Important! |matrix| should carry the same amount of rows as
52
+ // the parent matrix it is a block from. |PackRowHorizontally| currently only
53
+ // supports row-major matrices.
48
54
template <typename PackedPrimeField, typename Derived, typename PrimeField>
49
- std::vector<PackedPrimeField> PackRowHorizontally (
50
- const Eigen::MatrixBase<Derived>& matrix, size_t row,
51
- std::vector<PrimeField>& remaining_values) {
55
+ std::vector<PackedPrimeField*> PackRowHorizontally (
56
+ Eigen::Block<Derived>& matrix, size_t row,
57
+ std::vector<PrimeField*>& remaining_values) {
58
+ static_assert (Derived::Options & Eigen::RowMajorBit);
52
59
size_t num_packed = matrix.cols () / PackedPrimeField::N;
53
60
size_t remaining_start_idx = num_packed * PackedPrimeField::N;
54
- remaining_values =
55
- base::CreateVector ( matrix.cols () - remaining_start_idx,
56
- [row, remaining_start_idx, &matrix](size_t col) {
57
- return matrix (row, remaining_start_idx + col);
58
- } );
59
-
61
+ remaining_values = base::CreateVector (
62
+ matrix.cols () - remaining_start_idx,
63
+ [row, remaining_start_idx, &matrix](size_t col) {
64
+ return reinterpret_cast <PrimeField*>(
65
+ matrix. data () + row * matrix. cols () + remaining_start_idx + col );
66
+ });
60
67
return base::CreateVector (num_packed, [row, &matrix](size_t col) {
61
- return PackedPrimeField::From ([row, col, &matrix](size_t i) {
62
- return matrix (row, PackedPrimeField::N * col + i);
63
- });
68
+ return reinterpret_cast <PackedPrimeField*>(
69
+ matrix.data () + row * matrix.cols () + PackedPrimeField::N * col);
64
70
});
65
71
}
66
72
@@ -74,6 +80,50 @@ std::vector<PackedPrimeField> PackRowVertically(
74
80
});
75
81
}
76
82
83
+ // Expands a |Eigen::MatrixBase|'s rows from |rows| to |rows|^(|added_bits|),
84
+ // moving values from row |i| to row |i|^(|added_bits|). All new entries are set
85
+ // to |F::Zero()|.
86
+ template <typename Derived>
87
+ void ExpandInPlaceWithZeroPad (Eigen::MatrixBase<Derived>& mat,
88
+ size_t added_bits) {
89
+ if (added_bits == 0 ) {
90
+ return ;
91
+ }
92
+
93
+ Eigen::Index original_rows = mat.rows ();
94
+ Eigen::Index new_rows = mat.rows () << added_bits;
95
+ Eigen::Index cols = mat.cols ();
96
+
97
+ Derived padded = Derived::Zero (new_rows, cols);
98
+
99
+ OPENMP_PARALLEL_FOR (Eigen::Index row = 0 ; row < original_rows; ++row) {
100
+ Eigen::Index padded_row_index = row << added_bits;
101
+ // TODO(ashjeong): Check if moved properly
102
+ padded.row (padded_row_index) = std::move (mat.row (row));
103
+ }
104
+ mat = std::move (padded);
105
+ }
106
+
107
+ // Swaps rows of a |Eigen::MatrixBase| such that each row is changed to the row
108
+ // accessed with the reversed bits of the current index. Crashes if the number
109
+ // of rows is not a power of two.
110
+ template <typename Derived>
111
+ void ReverseMatrixIndexBits (Eigen::MatrixBase<Derived>& mat) {
112
+ size_t rows = static_cast <size_t >(mat.rows ());
113
+ if (rows == 0 ) {
114
+ return ;
115
+ }
116
+ CHECK (base::bits::IsPowerOfTwo (rows));
117
+ size_t log_n = base::bits::Log2Ceiling (rows);
118
+
119
+ OPENMP_PARALLEL_FOR (size_t row = 1 ; row < rows; ++row) {
120
+ size_t ridx = base::bits::BitRev (row) >> (sizeof (size_t ) * 8 - log_n);
121
+ if (row < ridx) {
122
+ mat.row (row).swap (mat.row (ridx));
123
+ }
124
+ }
125
+ }
126
+
77
127
} // namespace tachyon::math
78
128
79
129
#endif // TACHYON_MATH_MATRIX_MATRIX_UTILS_H_
0 commit comments