Skip to content

Commit a18a400

Browse files
authored
Using Eigen matrix multiplication (#4361)
Using Eigen matrix multiplication in complex_matrix::operator*=. The 3 layer for-loop in `operator*=` was the dominat cost in `sum_op::to_matrix()` for multi-qubits operator chains. Using Eigen matrix drops the execution time on my machine from **87 seconds to 2 seconds**, speedup of **~40x**. Fixes #3626 Signed-off-by: Sachin Pisal <spisal@nvidia.com>
1 parent 0299a12 commit a18a400

1 file changed

Lines changed: 34 additions & 9 deletions

File tree

runtime/cudaq/operators/matrix.cpp

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -168,15 +168,40 @@ cudaq::complex_matrix::operator*=(const cudaq::complex_matrix &right) {
168168
if (cols() != right.rows())
169169
throw std::runtime_error("matrix dimensions mismatch in operator*=");
170170

171-
auto new_data =
172-
new cudaq::complex_matrix::value_type[rows() * right.cols()]();
173-
cudaq::complex_matrix::Dimensions new_dims = {rows(), right.cols()};
174-
for (std::size_t i = 0; i < rows(); i++)
175-
for (std::size_t j = 0; j < right.cols(); j++)
176-
for (std::size_t k = 0; k < cols(); k++)
177-
access(new_data, new_dims, i, j, this->internal_order) +=
178-
access(data, dimensions, i, k, this->internal_order) *
179-
access(right.data, right.dimensions, k, j, right.internal_order);
171+
const std::size_t new_rows = rows();
172+
const std::size_t new_cols = right.cols();
173+
auto *new_data = new cudaq::complex_matrix::value_type[new_rows * new_cols];
174+
cudaq::complex_matrix::Dimensions new_dims = {new_rows, new_cols};
175+
176+
using RowMat = Eigen::Matrix<value_type, -1, -1, Eigen::RowMajor, -1, -1>;
177+
using ColMat = Eigen::Matrix<value_type, -1, -1, Eigen::ColMajor, -1, -1>;
178+
179+
auto assign_product = [&](auto &&lhs_map, auto &&rhs_map) {
180+
if (this->internal_order == cudaq::complex_matrix::order::row_major)
181+
Eigen::Map<RowMat>(new_data, new_rows, new_cols).noalias() =
182+
lhs_map * rhs_map;
183+
else
184+
Eigen::Map<ColMat>(new_data, new_rows, new_cols).noalias() =
185+
lhs_map * rhs_map;
186+
};
187+
188+
const bool l_row =
189+
this->internal_order == cudaq::complex_matrix::order::row_major;
190+
const bool r_row =
191+
right.internal_order == cudaq::complex_matrix::order::row_major;
192+
Eigen::Map<const RowMat> l_row_map(this->data, this->rows(), this->cols());
193+
Eigen::Map<const ColMat> l_col_map(this->data, this->rows(), this->cols());
194+
Eigen::Map<const RowMat> r_row_map(right.data, right.rows(), right.cols());
195+
Eigen::Map<const ColMat> r_col_map(right.data, right.rows(), right.cols());
196+
if (l_row && r_row)
197+
assign_product(l_row_map, r_row_map);
198+
else if (l_row && !r_row)
199+
assign_product(l_row_map, r_col_map);
200+
else if (!l_row && r_row)
201+
assign_product(l_col_map, r_row_map);
202+
else
203+
assign_product(l_col_map, r_col_map);
204+
180205
swap(new_data);
181206
dimensions = new_dims;
182207
return *this;

0 commit comments

Comments
 (0)