| 386 | // temporary space. |
| 387 | template <typename T> |
| 388 | void SparseTensor::Reorder(const VarDimArray& order) { |
| 389 | DCHECK_EQ(DataTypeToEnum<T>::v(), dtype()) |
| 390 | << "Reorder requested with the wrong datatype"; |
| 391 | DCHECK_EQ(order.size(), dims_) << "Order length must be SparseTensor rank"; |
| 392 | auto ix_t = ix_.matrix<int64>(); |
| 393 | auto vals_t = vals_.vec<T>(); |
| 394 | |
| 395 | std::vector<int64> reorder(num_entries()); |
| 396 | std::iota(reorder.begin(), reorder.end(), 0); |
| 397 | |
| 398 | // Sort to get order of indices |
| 399 | switch (order.size()) { |
| 400 | #define CASE_SORT(ORDER_SIZE) \ |
| 401 | case ORDER_SIZE: { \ |
| 402 | FixedDimComparator<ORDER_SIZE> sorter(ix_t, order, shape()); \ |
| 403 | std::sort(reorder.begin(), reorder.end(), sorter); \ |
| 404 | break; \ |
| 405 | } |
| 406 | CASE_SORT(0); |
| 407 | CASE_SORT(1); |
| 408 | CASE_SORT(2); |
| 409 | CASE_SORT(3); |
| 410 | CASE_SORT(4); |
| 411 | CASE_SORT(5); |
| 412 | #undef CASE_SORT |
| 413 | default: { |
| 414 | DimComparator sorter(ix_t, order, shape()); |
| 415 | std::sort(reorder.begin(), reorder.end(), sorter); |
| 416 | } |
| 417 | } |
| 418 | |
| 419 | // We have a forward reordering, but what we'll need is a |
| 420 | // permutation (the inverse). This can be calculated with O(1) |
| 421 | // additional |
| 422 | // and O(n) time (INVPERM) but we just do the simple thing here. |
| 423 | std::vector<size_t> permutation(reorder.size()); |
| 424 | for (std::size_t n = 0; n < reorder.size(); ++n) { |
| 425 | permutation[reorder[n]] = n; |
| 426 | } |
| 427 | |
| 428 | // Update indices & values by converting the permutations to |
| 429 | // a product of transpositions. Iterate over the cycles in the |
| 430 | // permutation, and convert each of those into a product of |
| 431 | // transpositions (swaps): |
| 432 | // https://en.wikipedia.org/wiki/Cyclic_permutation |
| 433 | // This is N swaps, 2*N comparisons. |
| 434 | for (std::size_t n = 0; n + 1 < permutation.size(); ++n) { |
| 435 | while (n != permutation[n]) { |
| 436 | std::size_t r = permutation[n]; |
| 437 | std::swap_ranges(&(ix_t(n, 0)), &(ix_t(n + 1, 0)), &(ix_t(r, 0))); |
| 438 | std::swap(vals_t(n), vals_t(r)); |
| 439 | std::swap(permutation[n], permutation[r]); |
| 440 | } |
| 441 | } |
| 442 | |
| 443 | order_ = ShapeArray(order.begin(), order.end()); |
| 444 | } |
| 445 | |