diff --git a/common/cuda_hip/matrix/csr_kernels.hpp.inc b/common/cuda_hip/matrix/csr_kernels.hpp.inc index 3f02337747e..ed4850654cf 100644 --- a/common/cuda_hip/matrix/csr_kernels.hpp.inc +++ b/common/cuda_hip/matrix/csr_kernels.hpp.inc @@ -764,6 +764,147 @@ __global__ __launch_bounds__(default_block_size) void inv_symm_permute( } +template +__global__ __launch_bounds__(default_block_size) void inv_nonsymm_permute( + size_type num_rows, const IndexType* __restrict__ row_permutation, + const IndexType* __restrict__ col_permutation, + const IndexType* __restrict__ in_row_ptrs, + const IndexType* __restrict__ in_cols, + const ValueType* __restrict__ in_vals, + const IndexType* __restrict__ out_row_ptrs, + IndexType* __restrict__ out_cols, ValueType* __restrict__ out_vals) +{ + auto tid = thread::get_subwarp_id_flat(); + if (tid >= num_rows) { + return; + } + auto lane = threadIdx.x % subwarp_size; + auto in_row = tid; + auto out_row = row_permutation[tid]; + auto in_begin = in_row_ptrs[in_row]; + auto in_size = in_row_ptrs[in_row + 1] - in_begin; + auto out_begin = out_row_ptrs[out_row]; + for (IndexType i = lane; i < in_size; i += subwarp_size) { + out_cols[out_begin + i] = col_permutation[in_cols[in_begin + i]]; + out_vals[out_begin + i] = in_vals[in_begin + i]; + } +} + + +template +__global__ __launch_bounds__(default_block_size) void row_scale_permute( + size_type num_rows, const ValueType* __restrict__ scale, + const IndexType* __restrict__ permutation, + const IndexType* __restrict__ in_row_ptrs, + const IndexType* __restrict__ in_cols, + const ValueType* __restrict__ in_vals, + const IndexType* __restrict__ out_row_ptrs, + IndexType* __restrict__ out_cols, ValueType* __restrict__ out_vals) +{ + auto tid = thread::get_subwarp_id_flat(); + if (tid >= num_rows) { + return; + } + auto lane = threadIdx.x % subwarp_size; + auto in_row = permutation[tid]; + auto out_row = tid; + auto in_begin = in_row_ptrs[in_row]; + auto in_size = in_row_ptrs[in_row + 1] - in_begin; + auto out_begin = out_row_ptrs[out_row]; + for (IndexType i = lane; i < in_size; i += subwarp_size) { + out_cols[out_begin + i] = in_cols[in_begin + i]; + out_vals[out_begin + i] = in_vals[in_begin + i] * scale[out_row]; + } +} + + +template +__global__ __launch_bounds__(default_block_size) void inv_row_scale_permute( + size_type num_rows, const ValueType* __restrict__ scale, + const IndexType* __restrict__ permutation, + const IndexType* __restrict__ in_row_ptrs, + const IndexType* __restrict__ in_cols, + const ValueType* __restrict__ in_vals, + const IndexType* __restrict__ out_row_ptrs, + IndexType* __restrict__ out_cols, ValueType* __restrict__ out_vals) +{ + auto tid = thread::get_subwarp_id_flat(); + if (tid >= num_rows) { + return; + } + auto lane = threadIdx.x % subwarp_size; + auto in_row = tid; + auto out_row = permutation[tid]; + auto in_begin = in_row_ptrs[in_row]; + auto in_size = in_row_ptrs[in_row + 1] - in_begin; + auto out_begin = out_row_ptrs[out_row]; + for (IndexType i = lane; i < in_size; i += subwarp_size) { + out_cols[out_begin + i] = in_cols[in_begin + i]; + out_vals[out_begin + i] = in_vals[in_begin + i] / scale[in_row]; + } +} + + +template +__global__ __launch_bounds__(default_block_size) void inv_symm_scale_permute( + size_type num_rows, const ValueType* __restrict__ scale, + const IndexType* __restrict__ permutation, + const IndexType* __restrict__ in_row_ptrs, + const IndexType* __restrict__ in_cols, + const ValueType* __restrict__ in_vals, + const IndexType* __restrict__ out_row_ptrs, + IndexType* __restrict__ out_cols, ValueType* __restrict__ out_vals) +{ + auto tid = thread::get_subwarp_id_flat(); + if (tid >= num_rows) { + return; + } + auto lane = threadIdx.x % subwarp_size; + auto in_row = tid; + auto out_row = permutation[tid]; + auto in_begin = in_row_ptrs[in_row]; + auto in_size = in_row_ptrs[in_row + 1] - in_begin; + auto out_begin = out_row_ptrs[out_row]; + for (IndexType i = lane; i < in_size; i += subwarp_size) { + const auto in_col = in_cols[in_begin + i]; + out_cols[out_begin + i] = permutation[in_col]; + out_vals[out_begin + i] = + in_vals[in_begin + i] / (scale[in_row] * scale[in_col]); + } +} + + +template +__global__ __launch_bounds__(default_block_size) void inv_nonsymm_scale_permute( + size_type num_rows, const ValueType* __restrict__ row_scale, + const IndexType* __restrict__ row_permutation, + const ValueType* __restrict__ col_scale, + const IndexType* __restrict__ col_permutation, + const IndexType* __restrict__ in_row_ptrs, + const IndexType* __restrict__ in_cols, + const ValueType* __restrict__ in_vals, + const IndexType* __restrict__ out_row_ptrs, + IndexType* __restrict__ out_cols, ValueType* __restrict__ out_vals) +{ + auto tid = thread::get_subwarp_id_flat(); + if (tid >= num_rows) { + return; + } + auto lane = threadIdx.x % subwarp_size; + auto in_row = tid; + auto out_row = row_permutation[tid]; + auto in_begin = in_row_ptrs[in_row]; + auto in_size = in_row_ptrs[in_row + 1] - in_begin; + auto out_begin = out_row_ptrs[out_row]; + for (IndexType i = lane; i < in_size; i += subwarp_size) { + const auto in_col = in_cols[in_begin + i]; + out_cols[out_begin + i] = col_permutation[in_col]; + out_vals[out_begin + i] = + in_vals[in_begin + i] / (row_scale[in_row] * col_scale[in_col]); + } +} + + template __global__ __launch_bounds__(default_block_size) void compute_submatrix_idxs_and_vals( @@ -1116,6 +1257,408 @@ void build_lookup(std::shared_ptr exec, } +namespace { + + +template +void spgeam(syn::value_list, + std::shared_ptr exec, const ValueType* alpha, + const IndexType* a_row_ptrs, const IndexType* a_col_idxs, + const ValueType* a_vals, const ValueType* beta, + const IndexType* b_row_ptrs, const IndexType* b_col_idxs, + const ValueType* b_vals, matrix::Csr* c) +{ + auto m = static_cast(c->get_size()[0]); + auto c_row_ptrs = c->get_row_ptrs(); + // count nnz for alpha * A + beta * B + auto subwarps_per_block = default_block_size / subwarp_size; + auto num_blocks = ceildiv(m, subwarps_per_block); + if (num_blocks > 0) { + kernel::spgeam_nnz + <<get_stream()>>>( + a_row_ptrs, a_col_idxs, b_row_ptrs, b_col_idxs, m, c_row_ptrs); + } + + // build row pointers + components::prefix_sum_nonnegative(exec, c_row_ptrs, m + 1); + + // accumulate non-zeros for alpha * A + beta * B + matrix::CsrBuilder c_builder{c}; + auto c_nnz = exec->copy_val_to_host(c_row_ptrs + m); + c_builder.get_col_idx_array().resize_and_reset(c_nnz); + c_builder.get_value_array().resize_and_reset(c_nnz); + auto c_col_idxs = c->get_col_idxs(); + auto c_vals = c->get_values(); + if (num_blocks > 0) { + kernel::spgeam + <<get_stream()>>>( + as_device_type(alpha), a_row_ptrs, a_col_idxs, + as_device_type(a_vals), as_device_type(beta), b_row_ptrs, + b_col_idxs, as_device_type(b_vals), m, c_row_ptrs, c_col_idxs, + as_device_type(c_vals)); + } +} + +GKO_ENABLE_IMPLEMENTATION_SELECTION(select_spgeam, spgeam); + + +} // namespace + + +template +void spgeam(std::shared_ptr exec, + const matrix::Dense* alpha, + const matrix::Csr* a, + const matrix::Dense* beta, + const matrix::Csr* b, + matrix::Csr* c) +{ + auto total_nnz = + a->get_num_stored_elements() + b->get_num_stored_elements(); + auto nnz_per_row = total_nnz / a->get_size()[0]; + select_spgeam( + spgeam_kernels(), + [&](int compiled_subwarp_size) { + return compiled_subwarp_size >= nnz_per_row || + compiled_subwarp_size == config::warp_size; + }, + syn::value_list(), syn::type_list<>(), exec, + alpha->get_const_values(), a->get_const_row_ptrs(), + a->get_const_col_idxs(), a->get_const_values(), + beta->get_const_values(), b->get_const_row_ptrs(), + b->get_const_col_idxs(), b->get_const_values(), c); +} + + +template +void fill_in_dense(std::shared_ptr exec, + const matrix::Csr* source, + matrix::Dense* result) +{ + const auto num_rows = result->get_size()[0]; + const auto num_cols = result->get_size()[1]; + const auto stride = result->get_stride(); + const auto row_ptrs = source->get_const_row_ptrs(); + const auto col_idxs = source->get_const_col_idxs(); + const auto vals = source->get_const_values(); + + auto grid_dim = ceildiv(num_rows, default_block_size); + if (grid_dim > 0) { + kernel::fill_in_dense<<get_stream()>>>( + num_rows, as_device_type(row_ptrs), as_device_type(col_idxs), + as_device_type(vals), stride, as_device_type(result->get_values())); + } +} + + +template +void inv_symm_permute(std::shared_ptr exec, + const IndexType* perm, + const matrix::Csr* orig, + matrix::Csr* permuted) +{ + auto num_rows = orig->get_size()[0]; + auto count_num_blocks = ceildiv(num_rows, default_block_size); + if (count_num_blocks > 0) { + kernel::inv_row_ptr_permute<<get_stream()>>>( + num_rows, perm, orig->get_const_row_ptrs(), + permuted->get_row_ptrs()); + } + components::prefix_sum_nonnegative(exec, permuted->get_row_ptrs(), + num_rows + 1); + auto copy_num_blocks = + ceildiv(num_rows, default_block_size / config::warp_size); + if (copy_num_blocks > 0) { + kernel::inv_symm_permute + <<get_stream()>>>( + num_rows, perm, orig->get_const_row_ptrs(), + orig->get_const_col_idxs(), + as_device_type(orig->get_const_values()), + permuted->get_row_ptrs(), permuted->get_col_idxs(), + as_device_type(permuted->get_values())); + } +} + + +template +void inv_nonsymm_permute(std::shared_ptr exec, + const IndexType* row_perm, const IndexType* col_perm, + const matrix::Csr* orig, + matrix::Csr* permuted) +{ + auto num_rows = orig->get_size()[0]; + auto count_num_blocks = ceildiv(num_rows, default_block_size); + if (count_num_blocks > 0) { + kernel::inv_row_ptr_permute<<get_stream()>>>( + num_rows, row_perm, orig->get_const_row_ptrs(), + permuted->get_row_ptrs()); + } + components::prefix_sum_nonnegative(exec, permuted->get_row_ptrs(), + num_rows + 1); + auto copy_num_blocks = + ceildiv(num_rows, default_block_size / config::warp_size); + if (copy_num_blocks > 0) { + kernel::inv_nonsymm_permute + <<get_stream()>>>( + num_rows, row_perm, col_perm, orig->get_const_row_ptrs(), + orig->get_const_col_idxs(), + as_device_type(orig->get_const_values()), + permuted->get_row_ptrs(), permuted->get_col_idxs(), + as_device_type(permuted->get_values())); + } +} + + +template +void row_permute(std::shared_ptr exec, + const IndexType* perm, + const matrix::Csr* orig, + matrix::Csr* row_permuted) +{ + auto num_rows = orig->get_size()[0]; + auto count_num_blocks = ceildiv(num_rows, default_block_size); + if (count_num_blocks > 0) { + kernel::row_ptr_permute<<get_stream()>>>( + num_rows, perm, orig->get_const_row_ptrs(), + row_permuted->get_row_ptrs()); + } + components::prefix_sum_nonnegative(exec, row_permuted->get_row_ptrs(), + num_rows + 1); + auto copy_num_blocks = + ceildiv(num_rows, default_block_size / config::warp_size); + if (copy_num_blocks > 0) { + kernel::row_permute + <<get_stream()>>>( + num_rows, perm, orig->get_const_row_ptrs(), + orig->get_const_col_idxs(), + as_device_type(orig->get_const_values()), + row_permuted->get_row_ptrs(), row_permuted->get_col_idxs(), + as_device_type(row_permuted->get_values())); + } +} + + +template +void inv_row_permute(std::shared_ptr exec, + const IndexType* perm, + const matrix::Csr* orig, + matrix::Csr* row_permuted) +{ + auto num_rows = orig->get_size()[0]; + auto count_num_blocks = ceildiv(num_rows, default_block_size); + if (count_num_blocks > 0) { + kernel::inv_row_ptr_permute<<get_stream()>>>( + num_rows, perm, orig->get_const_row_ptrs(), + row_permuted->get_row_ptrs()); + } + components::prefix_sum_nonnegative(exec, row_permuted->get_row_ptrs(), + num_rows + 1); + auto copy_num_blocks = + ceildiv(num_rows, default_block_size / config::warp_size); + if (copy_num_blocks > 0) { + kernel::inv_row_permute + <<get_stream()>>>( + num_rows, perm, orig->get_const_row_ptrs(), + orig->get_const_col_idxs(), + as_device_type(orig->get_const_values()), + row_permuted->get_row_ptrs(), row_permuted->get_col_idxs(), + as_device_type(row_permuted->get_values())); + } +} + + +template +void inv_symm_scale_permute(std::shared_ptr exec, + const ValueType* scale, const IndexType* perm, + const matrix::Csr* orig, + matrix::Csr* permuted) +{ + auto num_rows = orig->get_size()[0]; + auto count_num_blocks = ceildiv(num_rows, default_block_size); + if (count_num_blocks > 0) { + kernel::inv_row_ptr_permute<<get_stream()>>>( + num_rows, perm, orig->get_const_row_ptrs(), + permuted->get_row_ptrs()); + } + components::prefix_sum_nonnegative(exec, permuted->get_row_ptrs(), + num_rows + 1); + auto copy_num_blocks = + ceildiv(num_rows, default_block_size / config::warp_size); + if (copy_num_blocks > 0) { + kernel::inv_symm_scale_permute + <<get_stream()>>>( + num_rows, as_device_type(scale), perm, + orig->get_const_row_ptrs(), orig->get_const_col_idxs(), + as_device_type(orig->get_const_values()), + permuted->get_row_ptrs(), permuted->get_col_idxs(), + as_device_type(permuted->get_values())); + } +} + + +template +void inv_nonsymm_scale_permute(std::shared_ptr exec, + const ValueType* row_scale, + const IndexType* row_perm, + const ValueType* col_scale, + const IndexType* col_perm, + const matrix::Csr* orig, + matrix::Csr* permuted) +{ + auto num_rows = orig->get_size()[0]; + auto count_num_blocks = ceildiv(num_rows, default_block_size); + if (count_num_blocks > 0) { + kernel::inv_row_ptr_permute<<get_stream()>>>( + num_rows, row_perm, orig->get_const_row_ptrs(), + permuted->get_row_ptrs()); + } + components::prefix_sum_nonnegative(exec, permuted->get_row_ptrs(), + num_rows + 1); + auto copy_num_blocks = + ceildiv(num_rows, default_block_size / config::warp_size); + if (copy_num_blocks > 0) { + kernel::inv_nonsymm_scale_permute + <<get_stream()>>>( + num_rows, as_device_type(row_scale), row_perm, + as_device_type(col_scale), col_perm, orig->get_const_row_ptrs(), + orig->get_const_col_idxs(), + as_device_type(orig->get_const_values()), + permuted->get_row_ptrs(), permuted->get_col_idxs(), + as_device_type(permuted->get_values())); + } +} + + +template +void row_scale_permute(std::shared_ptr exec, + const ValueType* scale, const IndexType* perm, + const matrix::Csr* orig, + matrix::Csr* row_permuted) +{ + auto num_rows = orig->get_size()[0]; + auto count_num_blocks = ceildiv(num_rows, default_block_size); + if (count_num_blocks > 0) { + kernel::row_ptr_permute<<get_stream()>>>( + num_rows, perm, orig->get_const_row_ptrs(), + row_permuted->get_row_ptrs()); + } + components::prefix_sum_nonnegative(exec, row_permuted->get_row_ptrs(), + num_rows + 1); + auto copy_num_blocks = + ceildiv(num_rows, default_block_size / config::warp_size); + if (copy_num_blocks > 0) { + kernel::row_scale_permute + <<get_stream()>>>( + num_rows, as_device_type(scale), perm, + orig->get_const_row_ptrs(), orig->get_const_col_idxs(), + as_device_type(orig->get_const_values()), + row_permuted->get_row_ptrs(), row_permuted->get_col_idxs(), + as_device_type(row_permuted->get_values())); + } +} + + +template +void inv_row_scale_permute(std::shared_ptr exec, + const ValueType* scale, const IndexType* perm, + const matrix::Csr* orig, + matrix::Csr* row_permuted) +{ + auto num_rows = orig->get_size()[0]; + auto count_num_blocks = ceildiv(num_rows, default_block_size); + if (count_num_blocks > 0) { + kernel::inv_row_ptr_permute<<get_stream()>>>( + num_rows, perm, orig->get_const_row_ptrs(), + row_permuted->get_row_ptrs()); + } + components::prefix_sum_nonnegative(exec, row_permuted->get_row_ptrs(), + num_rows + 1); + auto copy_num_blocks = + ceildiv(num_rows, default_block_size / config::warp_size); + if (copy_num_blocks > 0) { + kernel::inv_row_scale_permute + <<get_stream()>>>( + num_rows, as_device_type(scale), perm, + orig->get_const_row_ptrs(), orig->get_const_col_idxs(), + as_device_type(orig->get_const_values()), + row_permuted->get_row_ptrs(), row_permuted->get_col_idxs(), + as_device_type(row_permuted->get_values())); + } +} + + +template +void calculate_nonzeros_per_row_in_span( + std::shared_ptr exec, + const matrix::Csr* source, const span& row_span, + const span& col_span, array* row_nnz) +{ + const auto num_rows = source->get_size()[0]; + auto row_ptrs = source->get_const_row_ptrs(); + auto col_idxs = source->get_const_col_idxs(); + auto grid_dim = ceildiv(row_span.length(), default_block_size); + if (grid_dim > 0) { + kernel::calculate_nnz_per_row_in_span<<get_stream()>>>( + row_span, col_span, as_device_type(row_ptrs), + as_device_type(col_idxs), as_device_type(row_nnz->get_data())); + } +} + + +template +void compute_submatrix(std::shared_ptr exec, + const matrix::Csr* source, + gko::span row_span, gko::span col_span, + matrix::Csr* result) +{ + auto row_offset = row_span.begin; + auto col_offset = col_span.begin; + auto num_rows = result->get_size()[0]; + auto num_cols = result->get_size()[1]; + auto row_ptrs = source->get_const_row_ptrs(); + auto grid_dim = ceildiv(num_rows, default_block_size); + if (grid_dim > 0) { + kernel::compute_submatrix_idxs_and_vals<<get_stream()>>>( + num_rows, num_cols, row_offset, col_offset, + as_device_type(source->get_const_row_ptrs()), + as_device_type(source->get_const_col_idxs()), + as_device_type(source->get_const_values()), + as_device_type(result->get_const_row_ptrs()), + as_device_type(result->get_col_idxs()), + as_device_type(result->get_values())); + } +} + + +template +void calculate_nonzeros_per_row_in_index_set( + std::shared_ptr exec, + const matrix::Csr* source, + const gko::index_set& row_index_set, + const gko::index_set& col_index_set, + IndexType* row_nnz) GKO_NOT_IMPLEMENTED; + + +template +void compute_submatrix_from_index_set( + std::shared_ptr exec, + const matrix::Csr* source, + const gko::index_set& row_index_set, + const gko::index_set& col_index_set, + matrix::Csr* result) GKO_NOT_IMPLEMENTED; + + template void fallback_transpose(std::shared_ptr exec, const matrix::Csr* input, @@ -1165,3 +1708,92 @@ void fallback_sort(std::shared_ptr exec, thrust::stable_sort_by_key(thrust_policy(exec), row_idxs, row_idxs + nnz, col_val_it); } + + +template +void is_sorted_by_column_index( + std::shared_ptr exec, + const matrix::Csr* to_check, bool* is_sorted) +{ + *is_sorted = true; + auto cpu_array = make_array_view(exec->get_master(), 1, is_sorted); + auto gpu_array = array{exec, cpu_array}; + auto block_size = default_block_size; + auto num_rows = static_cast(to_check->get_size()[0]); + auto num_blocks = ceildiv(num_rows, block_size); + if (num_blocks > 0) { + kernel:: + check_unsorted<<get_stream()>>>( + to_check->get_const_row_ptrs(), to_check->get_const_col_idxs(), + num_rows, gpu_array.get_data()); + } + cpu_array = gpu_array; +} + + +template +void extract_diagonal(std::shared_ptr exec, + const matrix::Csr* orig, + matrix::Diagonal* diag) +{ + const auto nnz = orig->get_num_stored_elements(); + const auto diag_size = diag->get_size()[0]; + const auto num_blocks = + ceildiv(config::warp_size * diag_size, default_block_size); + + const auto orig_values = orig->get_const_values(); + const auto orig_row_ptrs = orig->get_const_row_ptrs(); + const auto orig_col_idxs = orig->get_const_col_idxs(); + auto diag_values = diag->get_values(); + if (num_blocks > 0) { + kernel::extract_diagonal<<get_stream()>>>( + diag_size, nnz, as_device_type(orig_values), + as_device_type(orig_row_ptrs), as_device_type(orig_col_idxs), + as_device_type(diag_values)); + } +} + + +template +void check_diagonal_entries_exist( + std::shared_ptr exec, + const matrix::Csr* const mtx, bool& has_all_diags) +{ + const size_type num_warps = mtx->get_size()[0]; + if (num_warps > 0) { + const size_type num_blocks = + num_warps / (default_block_size / config::warp_size); + array has_diags(exec, {true}); + kernel::check_diagonal_entries<<get_stream()>>>( + static_cast( + std::min(mtx->get_size()[0], mtx->get_size()[1])), + mtx->get_const_row_ptrs(), mtx->get_const_col_idxs(), + has_diags.get_data()); + has_all_diags = exec->copy_val_to_host(has_diags.get_const_data()); + } else { + has_all_diags = true; + } +} + + +template +void add_scaled_identity(std::shared_ptr exec, + const matrix::Dense* const alpha, + const matrix::Dense* const beta, + matrix::Csr* const mtx) +{ + const auto nrows = mtx->get_size()[0]; + if (nrows == 0) { + return; + } + const auto nthreads = nrows * config::warp_size; + const auto nblocks = ceildiv(nthreads, default_block_size); + kernel::add_scaled_identity<<get_stream()>>>( + as_device_type(alpha->get_const_values()), + as_device_type(beta->get_const_values()), static_cast(nrows), + mtx->get_const_row_ptrs(), mtx->get_const_col_idxs(), + as_device_type(mtx->get_values())); +} diff --git a/common/unified/CMakeLists.txt b/common/unified/CMakeLists.txt index 67fc839d6a7..7ac6b3df40c 100644 --- a/common/unified/CMakeLists.txt +++ b/common/unified/CMakeLists.txt @@ -12,6 +12,8 @@ set(UNIFIED_SOURCES matrix/csr_kernels.cpp matrix/ell_kernels.cpp matrix/hybrid_kernels.cpp + matrix/permutation_kernels.cpp + matrix/scaled_permutation_kernels.cpp matrix/sellp_kernels.cpp matrix/sparsity_csr_kernels.cpp matrix/diagonal_kernels.cpp diff --git a/common/unified/matrix/csr_kernels.cpp b/common/unified/matrix/csr_kernels.cpp index 1704fdd1f9c..4746f88ddfe 100644 --- a/common/unified/matrix/csr_kernels.cpp +++ b/common/unified/matrix/csr_kernels.cpp @@ -54,53 +54,71 @@ namespace GKO_DEVICE_NAMESPACE { namespace csr { -template -void invert_permutation(std::shared_ptr exec, - size_type size, const IndexType* permutation_indices, - IndexType* inv_permutation) +template +void inv_col_permute(std::shared_ptr exec, + const IndexType* perm, + const matrix::Csr* orig, + matrix::Csr* col_permuted) { + auto num_rows = orig->get_size()[0]; + auto nnz = orig->get_num_stored_elements(); + auto size = std::max(num_rows, nnz); run_kernel( exec, - [] GKO_KERNEL(auto tid, auto permutation, auto inv_permutation) { - inv_permutation[permutation[tid]] = tid; + [] GKO_KERNEL(auto tid, auto num_rows, auto num_nonzeros, + auto permutation, auto in_row_ptrs, auto in_col_idxs, + auto in_vals, auto out_row_ptrs, auto out_col_idxs, + auto out_vals) { + if (tid < num_nonzeros) { + out_col_idxs[tid] = permutation[in_col_idxs[tid]]; + out_vals[tid] = in_vals[tid]; + } + if (tid <= num_rows) { + out_row_ptrs[tid] = in_row_ptrs[tid]; + } }, - size, permutation_indices, inv_permutation); + size, num_rows, nnz, perm, orig->get_const_row_ptrs(), + orig->get_const_col_idxs(), orig->get_const_values(), + col_permuted->get_row_ptrs(), col_permuted->get_col_idxs(), + col_permuted->get_values()); } -GKO_INSTANTIATE_FOR_EACH_INDEX_TYPE(GKO_DECLARE_INVERT_PERMUTATION_KERNEL); +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_CSR_INV_COL_PERMUTE_KERNEL); template -void inverse_column_permute(std::shared_ptr exec, - const IndexType* perm, - const matrix::Csr* orig, - matrix::Csr* column_permuted) +void inv_col_scale_permute(std::shared_ptr exec, + const ValueType* scale, const IndexType* perm, + const matrix::Csr* orig, + matrix::Csr* col_permuted) { auto num_rows = orig->get_size()[0]; auto nnz = orig->get_num_stored_elements(); auto size = std::max(num_rows, nnz); run_kernel( exec, - [] GKO_KERNEL(auto tid, auto num_rows, auto num_nonzeros, + [] GKO_KERNEL(auto tid, auto num_rows, auto num_nonzeros, auto scale, auto permutation, auto in_row_ptrs, auto in_col_idxs, auto in_vals, auto out_row_ptrs, auto out_col_idxs, auto out_vals) { if (tid < num_nonzeros) { - out_col_idxs[tid] = permutation[in_col_idxs[tid]]; - out_vals[tid] = in_vals[tid]; + const auto in_col = in_col_idxs[tid]; + out_col_idxs[tid] = permutation[in_col]; + out_vals[tid] = in_vals[tid] / scale[in_col]; } if (tid <= num_rows) { out_row_ptrs[tid] = in_row_ptrs[tid]; } }, - size, num_rows, nnz, perm, orig->get_const_row_ptrs(), + size, num_rows, nnz, scale, perm, orig->get_const_row_ptrs(), orig->get_const_col_idxs(), orig->get_const_values(), - column_permuted->get_row_ptrs(), column_permuted->get_col_idxs(), - column_permuted->get_values()); + col_permuted->get_row_ptrs(), col_permuted->get_col_idxs(), + col_permuted->get_values()); } GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( - GKO_DECLARE_CSR_INVERSE_COLUMN_PERMUTE_KERNEL); + GKO_DECLARE_CSR_INV_COL_SCALE_PERMUTE_KERNEL); template diff --git a/common/unified/matrix/dense_kernels.instantiate.cpp b/common/unified/matrix/dense_kernels.instantiate.cpp index bf20c8a19b6..d8a5cd7af2a 100644 --- a/common/unified/matrix/dense_kernels.instantiate.cpp +++ b/common/unified/matrix/dense_kernels.instantiate.cpp @@ -59,16 +59,36 @@ GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( GKO_DECLARE_DENSE_SYMM_PERMUTE_KERNEL); GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( GKO_DECLARE_DENSE_INV_SYMM_PERMUTE_KERNEL); +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_DENSE_NONSYMM_PERMUTE_KERNEL); +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_DENSE_INV_NONSYMM_PERMUTE_KERNEL); GKO_INSTANTIATE_FOR_EACH_MIXED_VALUE_AND_INDEX_TYPE_2( GKO_DECLARE_DENSE_ROW_GATHER_KERNEL); GKO_INSTANTIATE_FOR_EACH_MIXED_VALUE_AND_INDEX_TYPE_2( GKO_DECLARE_DENSE_ADVANCED_ROW_GATHER_KERNEL); GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( - GKO_DECLARE_DENSE_COLUMN_PERMUTE_KERNEL); + GKO_DECLARE_DENSE_COL_PERMUTE_KERNEL); GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( GKO_DECLARE_DENSE_INV_ROW_PERMUTE_KERNEL); GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( - GKO_DECLARE_DENSE_INV_COLUMN_PERMUTE_KERNEL); + GKO_DECLARE_DENSE_INV_COL_PERMUTE_KERNEL); +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_DENSE_SYMM_SCALE_PERMUTE_KERNEL); +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_DENSE_INV_SYMM_SCALE_PERMUTE_KERNEL); +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_DENSE_NONSYMM_SCALE_PERMUTE_KERNEL); +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_DENSE_INV_NONSYMM_SCALE_PERMUTE_KERNEL); +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_DENSE_ROW_SCALE_PERMUTE_KERNEL); +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_DENSE_INV_ROW_SCALE_PERMUTE_KERNEL); +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_DENSE_COL_SCALE_PERMUTE_KERNEL); +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_DENSE_INV_COL_SCALE_PERMUTE_KERNEL); GKO_INSTANTIATE_FOR_EACH_VALUE_TYPE(GKO_DECLARE_DENSE_EXTRACT_DIAGONAL_KERNEL); GKO_INSTANTIATE_FOR_EACH_VALUE_TYPE(GKO_DECLARE_INPLACE_ABSOLUTE_DENSE_KERNEL); GKO_INSTANTIATE_FOR_EACH_VALUE_TYPE(GKO_DECLARE_OUTPLACE_ABSOLUTE_DENSE_KERNEL); diff --git a/common/unified/matrix/dense_kernels.template.cpp b/common/unified/matrix/dense_kernels.template.cpp index b6ed5fb37e0..79ac8e5f9fd 100644 --- a/common/unified/matrix/dense_kernels.template.cpp +++ b/common/unified/matrix/dense_kernels.template.cpp @@ -367,7 +367,7 @@ void compute_sqrt(std::shared_ptr exec, template void symm_permute(std::shared_ptr exec, - const array* permutation_indices, + const IndexType* permutation_indices, const matrix::Dense* orig, matrix::Dense* permuted) { @@ -376,13 +376,13 @@ void symm_permute(std::shared_ptr exec, [] GKO_KERNEL(auto row, auto col, auto orig, auto perm, auto permuted) { permuted(row, col) = orig(perm[row], perm[col]); }, - orig->get_size(), orig, *permutation_indices, permuted); + orig->get_size(), orig, permutation_indices, permuted); } template void inv_symm_permute(std::shared_ptr exec, - const array* permutation_indices, + const IndexType* permutation_indices, const matrix::Dense* orig, matrix::Dense* permuted) { @@ -391,14 +391,49 @@ void inv_symm_permute(std::shared_ptr exec, [] GKO_KERNEL(auto row, auto col, auto orig, auto perm, auto permuted) { permuted(perm[row], perm[col]) = orig(row, col); }, - orig->get_size(), orig, *permutation_indices, permuted); + orig->get_size(), orig, permutation_indices, permuted); +} + + +template +void nonsymm_permute(std::shared_ptr exec, + const IndexType* row_permutation_indices, + const IndexType* column_permutation_indices, + const matrix::Dense* orig, + matrix::Dense* permuted) +{ + run_kernel( + exec, + [] GKO_KERNEL(auto row, auto col, auto orig, auto row_perm, + auto col_perm, auto permuted) { + permuted(row, col) = orig(row_perm[row], col_perm[col]); + }, + orig->get_size(), orig, row_permutation_indices, + column_permutation_indices, permuted); +} + + +template +void inv_nonsymm_permute(std::shared_ptr exec, + const IndexType* row_permutation_indices, + const IndexType* column_permutation_indices, + const matrix::Dense* orig, + matrix::Dense* permuted) +{ + run_kernel( + exec, + [] GKO_KERNEL(auto row, auto col, auto orig, auto row_perm, + auto col_perm, auto permuted) { + permuted(row_perm[row], col_perm[col]) = orig(row, col); + }, + orig->get_size(), orig, row_permutation_indices, + column_permutation_indices, permuted); } template void row_gather(std::shared_ptr exec, - const array* row_idxs, - const matrix::Dense* orig, + const IndexType* row_idxs, const matrix::Dense* orig, matrix::Dense* row_collection) { run_kernel( @@ -406,15 +441,14 @@ void row_gather(std::shared_ptr exec, [] GKO_KERNEL(auto row, auto col, auto orig, auto rows, auto gathered) { gathered(row, col) = orig(rows[row], col); }, - dim<2>{row_idxs->get_num_elems(), orig->get_size()[1]}, orig, *row_idxs, - row_collection); + row_collection->get_size(), orig, row_idxs, row_collection); } template void advanced_row_gather(std::shared_ptr exec, const matrix::Dense* alpha, - const array* row_idxs, + const IndexType* row_idxs, const matrix::Dense* orig, const matrix::Dense* beta, matrix::Dense* row_collection) @@ -429,54 +463,191 @@ void advanced_row_gather(std::shared_ptr exec, static_cast(beta[0]) * static_cast(gathered(row, col)); }, - dim<2>{row_idxs->get_num_elems(), orig->get_size()[1]}, - alpha->get_const_values(), orig, *row_idxs, beta->get_const_values(), - row_collection); + row_collection->get_size(), alpha->get_const_values(), orig, row_idxs, + beta->get_const_values(), row_collection); } template -void column_permute(std::shared_ptr exec, - const array* permutation_indices, - const matrix::Dense* orig, - matrix::Dense* column_permuted) +void col_permute(std::shared_ptr exec, + const IndexType* permutation_indices, + const matrix::Dense* orig, + matrix::Dense* col_permuted) { run_kernel( exec, [] GKO_KERNEL(auto row, auto col, auto orig, auto perm, auto permuted) { permuted(row, col) = orig(row, perm[col]); }, - orig->get_size(), orig, *permutation_indices, column_permuted); + orig->get_size(), orig, permutation_indices, col_permuted); } template -void inverse_row_permute(std::shared_ptr exec, - const array* permutation_indices, - const matrix::Dense* orig, - matrix::Dense* row_permuted) +void inv_row_permute(std::shared_ptr exec, + const IndexType* permutation_indices, + const matrix::Dense* orig, + matrix::Dense* row_permuted) { run_kernel( exec, [] GKO_KERNEL(auto row, auto col, auto orig, auto perm, auto permuted) { permuted(perm[row], col) = orig(row, col); }, - orig->get_size(), orig, *permutation_indices, row_permuted); + orig->get_size(), orig, permutation_indices, row_permuted); } template -void inverse_column_permute(std::shared_ptr exec, - const array* permutation_indices, - const matrix::Dense* orig, - matrix::Dense* column_permuted) +void inv_col_permute(std::shared_ptr exec, + const IndexType* permutation_indices, + const matrix::Dense* orig, + matrix::Dense* col_permuted) { run_kernel( exec, [] GKO_KERNEL(auto row, auto col, auto orig, auto perm, auto permuted) { permuted(row, perm[col]) = orig(row, col); }, - orig->get_size(), orig, *permutation_indices, column_permuted); + orig->get_size(), orig, permutation_indices, col_permuted); +} + + +template +void symm_scale_permute(std::shared_ptr exec, + const ValueType* scale, const IndexType* perm, + const matrix::Dense* orig, + matrix::Dense* permuted) +{ + run_kernel( + exec, + [] GKO_KERNEL(auto i, auto j, auto scale, auto perm, auto orig, + auto permuted) { + permuted(i, j) = scale[i] * scale[j] * orig(perm[i], perm[j]); + }, + orig->get_size(), scale, perm, orig, permuted); +} + + +template +void inv_symm_scale_permute(std::shared_ptr exec, + const ValueType* scale, const IndexType* perm, + const matrix::Dense* orig, + matrix::Dense* permuted) +{ + run_kernel( + exec, + [] GKO_KERNEL(auto i, auto j, auto scale, auto perm, auto orig, + auto permuted) { + permuted(perm[i], perm[j]) = orig(i, j) / (scale[i] * scale[j]); + }, + orig->get_size(), scale, perm, orig, permuted); +} + + +template +void nonsymm_scale_permute(std::shared_ptr exec, + const ValueType* row_scale, + const IndexType* row_perm, + const ValueType* col_scale, + const IndexType* col_perm, + const matrix::Dense* orig, + matrix::Dense* permuted) +{ + run_kernel( + exec, + [] GKO_KERNEL(auto i, auto j, auto row_scale, auto row_perm, + auto col_scale, auto col_perm, auto orig, auto permuted) { + permuted(i, j) = + row_scale[i] * col_scale[j] * orig(row_perm[i], col_perm[j]); + }, + orig->get_size(), row_scale, row_perm, col_scale, col_perm, orig, + permuted); +} + + +template +void inv_nonsymm_scale_permute(std::shared_ptr exec, + const ValueType* row_scale, + const IndexType* row_perm, + const ValueType* col_scale, + const IndexType* col_perm, + const matrix::Dense* orig, + matrix::Dense* permuted) +{ + run_kernel( + exec, + [] GKO_KERNEL(auto i, auto j, auto row_scale, auto row_perm, + auto col_scale, auto col_perm, auto orig, auto permuted) { + permuted(row_perm[i], row_perm[j]) = + orig(i, j) / (row_scale[i] * col_scale[j]); + }, + orig->get_size(), row_scale, row_perm, col_scale, col_perm, orig, + permuted); +} + + +template +void row_scale_permute(std::shared_ptr exec, + const ValueType* scale, const IndexType* perm, + const matrix::Dense* orig, + matrix::Dense* permuted) +{ + run_kernel( + exec, + [] GKO_KERNEL(auto i, auto j, auto scale, auto perm, auto orig, + auto permuted) { + permuted(i, j) = scale[i] * orig(perm[i], j); + }, + orig->get_size(), scale, perm, orig, permuted); +} + + +template +void inv_row_scale_permute(std::shared_ptr exec, + const ValueType* scale, const IndexType* perm, + const matrix::Dense* orig, + matrix::Dense* permuted) +{ + run_kernel( + exec, + [] GKO_KERNEL(auto i, auto j, auto scale, auto perm, auto orig, + auto permuted) { + permuted(perm[i], j) = orig(i, j) / scale[i]; + }, + orig->get_size(), scale, perm, orig, permuted); +} + + +template +void col_scale_permute(std::shared_ptr exec, + const ValueType* scale, const IndexType* perm, + const matrix::Dense* orig, + matrix::Dense* permuted) +{ + run_kernel( + exec, + [] GKO_KERNEL(auto i, auto j, auto scale, auto perm, auto orig, + auto permuted) { + permuted(i, j) = scale[j] * orig(i, perm[j]); + }, + orig->get_size(), scale, perm, orig, permuted); +} + + +template +void inv_col_scale_permute(std::shared_ptr exec, + const ValueType* scale, const IndexType* perm, + const matrix::Dense* orig, + matrix::Dense* permuted) +{ + run_kernel( + exec, + [] GKO_KERNEL(auto i, auto j, auto scale, auto perm, auto orig, + auto permuted) { + permuted(i, perm[j]) = orig(i, j) / scale[j]; + }, + orig->get_size(), scale, perm, orig, permuted); } diff --git a/common/unified/matrix/permutation_kernels.cpp b/common/unified/matrix/permutation_kernels.cpp new file mode 100644 index 00000000000..58b82c1602e --- /dev/null +++ b/common/unified/matrix/permutation_kernels.cpp @@ -0,0 +1,67 @@ +/************************************************************* +Copyright (c) 2017-2023, the Ginkgo authors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*************************************************************/ + +#include "core/matrix/permutation_kernels.hpp" + + +#include + + +#include "common/unified/base/kernel_launch.hpp" + + +namespace gko { +namespace kernels { +namespace GKO_DEVICE_NAMESPACE { +namespace permutation { + + +template +void invert(std::shared_ptr exec, + const IndexType* permutation_indices, size_type size, + IndexType* inv_permutation) +{ + run_kernel( + exec, + [] GKO_KERNEL(auto i, auto permutation, auto inv_permutation) { + inv_permutation[permutation[i]] = i; + }, + size, permutation_indices, inv_permutation); +} + +GKO_INSTANTIATE_FOR_EACH_INDEX_TYPE(GKO_DECLARE_PERMUTATION_INVERT_KERNEL); + + +} // namespace permutation +} // namespace GKO_DEVICE_NAMESPACE +} // namespace kernels +} // namespace gko diff --git a/common/unified/matrix/scaled_permutation_kernels.cpp b/common/unified/matrix/scaled_permutation_kernels.cpp new file mode 100644 index 00000000000..7bebe4c4778 --- /dev/null +++ b/common/unified/matrix/scaled_permutation_kernels.cpp @@ -0,0 +1,72 @@ +/************************************************************* +Copyright (c) 2017-2023, the Ginkgo authors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*************************************************************/ + +#include "core/matrix/scaled_permutation_kernels.hpp" + + +#include + + +#include "common/unified/base/kernel_launch.hpp" + + +namespace gko { +namespace kernels { +namespace GKO_DEVICE_NAMESPACE { +namespace scaled_permutation { + + +template +void invert(std::shared_ptr exec, + const IndexType* input_permutation, const ValueType* input_scale, + size_type size, IndexType* output_permutation, + ValueType* output_scale) +{ + run_kernel( + exec, + [] GKO_KERNEL(auto i, auto input_permutation, auto input_scale, + auto output_permutation, auto output_scale) { + output_permutation[input_permutation[i]] = i; + output_scale[input_permutation[i]] = + one(input_scale[i]) / input_scale[i]; + }, + size, input_permutation, input_scale, output_permutation, output_scale); +} + +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_SCALED_PERMUTATION_INVERT_KERNEL); + + +} // namespace scaled_permutation +} // namespace GKO_DEVICE_NAMESPACE +} // namespace kernels +} // namespace gko diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 7932976d6c9..34f96ff168d 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -49,9 +49,10 @@ target_sources(ginkgo matrix/hybrid.cpp matrix/identity.cpp matrix/permutation.cpp + matrix/row_gatherer.cpp + matrix/scaled_permutation.cpp matrix/sellp.cpp matrix/sparsity_csr.cpp - matrix/row_gatherer.cpp multigrid/pgm.cpp multigrid/fixed_coarsening.cpp preconditioner/isai.cpp diff --git a/core/device_hooks/common_kernels.inc.cpp b/core/device_hooks/common_kernels.inc.cpp index c8bbd2e0a31..84b36790865 100644 --- a/core/device_hooks/common_kernels.inc.cpp +++ b/core/device_hooks/common_kernels.inc.cpp @@ -65,6 +65,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "core/matrix/fbcsr_kernels.hpp" #include "core/matrix/fft_kernels.hpp" #include "core/matrix/hybrid_kernels.hpp" +#include "core/matrix/permutation_kernels.hpp" +#include "core/matrix/scaled_permutation_kernels.hpp" #include "core/matrix/sellp_kernels.hpp" #include "core/matrix/sparsity_csr_kernels.hpp" #include "core/multigrid/pgm_kernels.hpp" @@ -344,9 +346,20 @@ GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_DENSE_INV_SYMM_PERMUTE_KERNEL); GKO_STUB_MIXED_VALUE_AND_INDEX_TYPE_2(GKO_DECLARE_DENSE_ROW_GATHER_KERNEL); GKO_STUB_MIXED_VALUE_AND_INDEX_TYPE_2( GKO_DECLARE_DENSE_ADVANCED_ROW_GATHER_KERNEL); -GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_DENSE_COLUMN_PERMUTE_KERNEL); +GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_DENSE_COL_PERMUTE_KERNEL); GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_DENSE_INV_ROW_PERMUTE_KERNEL); -GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_DENSE_INV_COLUMN_PERMUTE_KERNEL); +GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_DENSE_INV_COL_PERMUTE_KERNEL); +GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_DENSE_NONSYMM_PERMUTE_KERNEL); +GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_DENSE_INV_NONSYMM_PERMUTE_KERNEL); +GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_DENSE_SYMM_SCALE_PERMUTE_KERNEL); +GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_DENSE_INV_SYMM_SCALE_PERMUTE_KERNEL); +GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_DENSE_ROW_SCALE_PERMUTE_KERNEL); +GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_DENSE_COL_SCALE_PERMUTE_KERNEL); +GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_DENSE_INV_ROW_SCALE_PERMUTE_KERNEL); +GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_DENSE_INV_COL_SCALE_PERMUTE_KERNEL); +GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_DENSE_NONSYMM_SCALE_PERMUTE_KERNEL); +GKO_STUB_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_DENSE_INV_NONSYMM_SCALE_PERMUTE_KERNEL); GKO_STUB_VALUE_TYPE(GKO_DECLARE_DENSE_EXTRACT_DIAGONAL_KERNEL); GKO_STUB_VALUE_TYPE(GKO_DECLARE_INPLACE_ABSOLUTE_DENSE_KERNEL); GKO_STUB_VALUE_TYPE(GKO_DECLARE_OUTPLACE_ABSOLUTE_DENSE_KERNEL); @@ -563,11 +576,16 @@ GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_CSR_CONVERT_TO_HYBRID_KERNEL); GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_CSR_CONVERT_TO_SELLP_KERNEL); GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_CSR_TRANSPOSE_KERNEL); GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_CSR_CONJ_TRANSPOSE_KERNEL); +GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_CSR_INV_NONSYMM_PERMUTE_KERNEL); GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_CSR_INV_SYMM_PERMUTE_KERNEL); GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_CSR_ROW_PERMUTE_KERNEL); -GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_CSR_INVERSE_COLUMN_PERMUTE_KERNEL); -GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_CSR_INVERSE_ROW_PERMUTE_KERNEL); -GKO_STUB_INDEX_TYPE(GKO_DECLARE_INVERT_PERMUTATION_KERNEL); +GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_CSR_INV_COL_PERMUTE_KERNEL); +GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_CSR_INV_ROW_PERMUTE_KERNEL); +GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_CSR_INV_NONSYMM_SCALE_PERMUTE_KERNEL); +GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_CSR_INV_SYMM_SCALE_PERMUTE_KERNEL); +GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_CSR_ROW_SCALE_PERMUTE_KERNEL); +GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_CSR_INV_COL_SCALE_PERMUTE_KERNEL); +GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_CSR_INV_ROW_SCALE_PERMUTE_KERNEL); GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_CSR_SORT_BY_COLUMN_INDEX); GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_CSR_IS_SORTED_BY_COLUMN_INDEX); GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_CSR_EXTRACT_DIAGONAL); @@ -680,6 +698,24 @@ GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_HYBRID_CONVERT_TO_CSR_KERNEL); } // namespace hybrid +namespace permutation { + + +GKO_STUB_INDEX_TYPE(GKO_DECLARE_PERMUTATION_INVERT_KERNEL); + + +} // namespace permutation + + +namespace scaled_permutation { + + +GKO_STUB_VALUE_AND_INDEX_TYPE(GKO_DECLARE_SCALED_PERMUTATION_INVERT_KERNEL); + + +} // namespace scaled_permutation + + namespace sellp { diff --git a/core/matrix/csr.cpp b/core/matrix/csr.cpp index 9a4697c1195..e669f4d4718 100644 --- a/core/matrix/csr.cpp +++ b/core/matrix/csr.cpp @@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include #include @@ -93,9 +94,15 @@ GKO_REGISTER_OPERATION(transpose, csr::transpose); GKO_REGISTER_OPERATION(conj_transpose, csr::conj_transpose); GKO_REGISTER_OPERATION(inv_symm_permute, csr::inv_symm_permute); GKO_REGISTER_OPERATION(row_permute, csr::row_permute); -GKO_REGISTER_OPERATION(inverse_row_permute, csr::inverse_row_permute); -GKO_REGISTER_OPERATION(inverse_column_permute, csr::inverse_column_permute); -GKO_REGISTER_OPERATION(invert_permutation, csr::invert_permutation); +GKO_REGISTER_OPERATION(inv_row_permute, csr::inv_row_permute); +GKO_REGISTER_OPERATION(inv_col_permute, csr::inv_col_permute); +GKO_REGISTER_OPERATION(inv_nonsymm_permute, csr::inv_nonsymm_permute); +GKO_REGISTER_OPERATION(inv_symm_scale_permute, csr::inv_symm_scale_permute); +GKO_REGISTER_OPERATION(row_scale_permute, csr::row_scale_permute); +GKO_REGISTER_OPERATION(inv_row_scale_permute, csr::inv_row_scale_permute); +GKO_REGISTER_OPERATION(inv_col_scale_permute, csr::inv_col_scale_permute); +GKO_REGISTER_OPERATION(inv_nonsymm_scale_permute, + csr::inv_nonsymm_scale_permute); GKO_REGISTER_OPERATION(convert_ptrs_to_sizes, components::convert_ptrs_to_sizes); GKO_REGISTER_OPERATION(sort_by_column_index, csr::sort_by_column_index); @@ -520,26 +527,226 @@ std::unique_ptr Csr::conj_transpose() const } +template +std::unique_ptr> Csr::permute( + ptr_param> permutation, + permute_mode mode) const +{ + const auto exec = this->get_executor(); + const auto size = this->get_size(); + const auto nnz = this->get_num_stored_elements(); + if ((mode & permute_mode::symmetric) == permute_mode::none) { + return this->clone(); + } + if ((mode & permute_mode::symmetric) == permute_mode::symmetric) { + GKO_ASSERT_IS_SQUARE_MATRIX(this); + } + if ((mode & permute_mode::rows) == permute_mode::rows) { + GKO_ASSERT_EQ(size[0], permutation->get_size()[0]); + } + if ((mode & permute_mode::columns) == permute_mode::columns) { + GKO_ASSERT_EQ(size[1], permutation->get_size()[0]); + } + auto result = Csr::create(exec, size, nnz, this->get_strategy()->copy()); + auto local_permutation = make_temporary_clone(exec, permutation); + std::unique_ptr> inv_permutation; + const auto perm_idxs = local_permutation->get_const_permutation(); + const IndexType* inv_perm_idxs{}; + // to permute columns, we need to know the inverse permutation + bool needs_inverse = + (mode & permute_mode::inverse_columns) == permute_mode::columns; + if (needs_inverse) { + inv_permutation = local_permutation->invert(); + inv_perm_idxs = inv_permutation->get_const_permutation(); + } + switch (mode) { + case permute_mode::rows: + exec->run(csr::make_row_permute(perm_idxs, this, result.get())); + break; + case permute_mode::columns: + exec->run(csr::make_inv_col_permute(inv_perm_idxs, this, result.get())); + break; + case permute_mode::inverse_rows: + exec->run(csr::make_inv_row_permute(perm_idxs, this, result.get())); + break; + case permute_mode::inverse_columns: + exec->run(csr::make_inv_col_permute(perm_idxs, this, result.get())); + break; + case permute_mode::symmetric: + exec->run( + csr::make_inv_symm_permute(inv_perm_idxs, this, result.get())); + break; + case permute_mode::inverse_symmetric: + exec->run(csr::make_inv_symm_permute(perm_idxs, this, result.get())); + break; + default: + GKO_ASSERT(false); + } + result->make_srow(); + if ((mode & permute_mode::columns) == permute_mode::columns) { + result->sort_by_column_index(); + } + return result; +} + + +template +std::unique_ptr> Csr::permute( + ptr_param> row_permutation, + ptr_param> col_permutation, bool invert) const +{ + const auto exec = this->get_executor(); + const auto size = this->get_size(); + const auto nnz = this->get_num_stored_elements(); + GKO_ASSERT_EQ(size[0], row_permutation->get_size()[0]); + GKO_ASSERT_EQ(size[1], col_permutation->get_size()[0]); + auto result = Csr::create(exec, size, nnz, this->get_strategy()->copy()); + auto local_row_permutation = make_temporary_clone(exec, row_permutation); + auto local_col_permutation = make_temporary_clone(exec, col_permutation); + if (invert) { + exec->run(csr::make_inv_nonsymm_permute( + local_row_permutation->get_const_permutation(), + local_col_permutation->get_const_permutation(), this, + result.get())); + } else { + const auto inv_row_perm = local_row_permutation->invert(); + const auto inv_col_perm = local_col_permutation->invert(); + exec->run(csr::make_inv_nonsymm_permute( + inv_row_perm->get_const_permutation(), + inv_col_perm->get_const_permutation(), this, result.get())); + } + result->make_srow(); + result->sort_by_column_index(); + return result; +} + + +template +std::unique_ptr> +Csr::scale_permute( + ptr_param> permutation, + permute_mode mode) const +{ + const auto exec = this->get_executor(); + const auto size = this->get_size(); + const auto nnz = this->get_num_stored_elements(); + if ((mode & permute_mode::symmetric) == permute_mode::none) { + return this->clone(); + } + if ((mode & permute_mode::symmetric) == permute_mode::symmetric) { + GKO_ASSERT_IS_SQUARE_MATRIX(this); + } + if ((mode & permute_mode::rows) == permute_mode::rows) { + GKO_ASSERT_EQ(size[0], permutation->get_size()[0]); + } + if ((mode & permute_mode::columns) == permute_mode::columns) { + GKO_ASSERT_EQ(size[1], permutation->get_size()[0]); + } + auto result = Csr::create(exec, size, nnz, this->get_strategy()->copy()); + auto local_permutation = make_temporary_clone(exec, permutation); + std::unique_ptr> + inv_permutation; + const auto perm_idxs = local_permutation->get_const_permutation(); + const auto scale_factors = local_permutation->get_const_scale(); + const ValueType* inv_scale_factors{}; + const IndexType* inv_perm_idxs{}; + // to permute columns, we need to know the inverse permutation + bool needs_inverse = + (mode & permute_mode::inverse_columns) == permute_mode::columns; + if (needs_inverse) { + inv_permutation = local_permutation->invert(); + inv_scale_factors = inv_permutation->get_const_scale(); + inv_perm_idxs = inv_permutation->get_const_permutation(); + } + switch (mode) { + case permute_mode::rows: + exec->run(csr::make_row_scale_permute(scale_factors, perm_idxs, this, + result.get())); + break; + case permute_mode::columns: + exec->run(csr::make_inv_col_scale_permute( + inv_scale_factors, inv_perm_idxs, this, result.get())); + break; + case permute_mode::inverse_rows: + exec->run(csr::make_inv_row_scale_permute(scale_factors, perm_idxs, + this, result.get())); + break; + case permute_mode::inverse_columns: + exec->run(csr::make_inv_col_scale_permute(scale_factors, perm_idxs, + this, result.get())); + break; + case permute_mode::symmetric: + exec->run(csr::make_inv_symm_scale_permute( + inv_scale_factors, inv_perm_idxs, this, result.get())); + break; + case permute_mode::inverse_symmetric: + exec->run(csr::make_inv_symm_scale_permute(scale_factors, perm_idxs, + this, result.get())); + break; + default: + GKO_ASSERT(false); + } + result->make_srow(); + if ((mode & permute_mode::columns) == permute_mode::columns) { + result->sort_by_column_index(); + } + return result; +} + + +template +std::unique_ptr> +Csr::scale_permute( + ptr_param> row_permutation, + ptr_param> col_permutation, + bool invert) const +{ + const auto exec = this->get_executor(); + const auto size = this->get_size(); + const auto nnz = this->get_num_stored_elements(); + GKO_ASSERT_EQ(size[0], row_permutation->get_size()[0]); + GKO_ASSERT_EQ(size[1], col_permutation->get_size()[0]); + auto result = Csr::create(exec, size, nnz, this->get_strategy()->copy()); + auto local_row_permutation = make_temporary_clone(exec, row_permutation); + auto local_col_permutation = make_temporary_clone(exec, col_permutation); + if (invert) { + exec->run(csr::make_inv_nonsymm_scale_permute( + local_row_permutation->get_const_scale(), + local_row_permutation->get_const_permutation(), + local_col_permutation->get_const_scale(), + local_col_permutation->get_const_permutation(), this, + result.get())); + } else { + const auto inv_row_perm = local_row_permutation->invert(); + const auto inv_col_perm = local_col_permutation->invert(); + exec->run(csr::make_inv_nonsymm_scale_permute( + inv_row_perm->get_const_scale(), + inv_row_perm->get_const_permutation(), + inv_col_perm->get_const_scale(), + inv_col_perm->get_const_permutation(), this, result.get())); + } + result->make_srow(); + result->sort_by_column_index(); + return result; +} + + +template +std::unique_ptr> create_permutation_view( + const array& indices) +{ + return Permutation::create_const(indices.get_executor(), + indices.get_num_elems(), + indices.as_const_view()); +} + + template std::unique_ptr Csr::permute( const array* permutation_indices) const { - GKO_ASSERT_IS_SQUARE_MATRIX(this); - GKO_ASSERT_EQ(permutation_indices->get_num_elems(), this->get_size()[0]); - auto exec = this->get_executor(); - auto permute_cpy = - Csr::create(exec, this->get_size(), this->get_num_stored_elements(), - this->get_strategy()); - array inv_permutation(exec, this->get_size()[1]); - - exec->run(csr::make_invert_permutation( - this->get_size()[1], - make_temporary_clone(exec, permutation_indices)->get_const_data(), - inv_permutation.get_data())); - exec->run(csr::make_inv_symm_permute(inv_permutation.get_const_data(), this, - permute_cpy.get())); - permute_cpy->make_srow(); - return std::move(permute_cpy); + return permute(create_permutation_view(*permutation_indices), + permute_mode::symmetric); } @@ -547,18 +754,8 @@ template std::unique_ptr Csr::inverse_permute( const array* permutation_indices) const { - GKO_ASSERT_IS_SQUARE_MATRIX(this); - GKO_ASSERT_EQ(permutation_indices->get_num_elems(), this->get_size()[0]); - auto exec = this->get_executor(); - auto permute_cpy = - Csr::create(exec, this->get_size(), this->get_num_stored_elements(), - this->get_strategy()); - - exec->run(csr::make_inv_symm_permute( - make_temporary_clone(exec, permutation_indices)->get_const_data(), this, - permute_cpy.get())); - permute_cpy->make_srow(); - return std::move(permute_cpy); + return permute(create_permutation_view(*permutation_indices), + permute_mode::inverse_symmetric); } @@ -566,17 +763,8 @@ template std::unique_ptr Csr::row_permute( const array* permutation_indices) const { - GKO_ASSERT_EQ(permutation_indices->get_num_elems(), this->get_size()[0]); - auto exec = this->get_executor(); - auto permute_cpy = - Csr::create(exec, this->get_size(), this->get_num_stored_elements(), - this->get_strategy()); - - exec->run(csr::make_row_permute( - make_temporary_clone(exec, permutation_indices)->get_const_data(), this, - permute_cpy.get())); - permute_cpy->make_srow(); - return std::move(permute_cpy); + return permute(create_permutation_view(*permutation_indices), + permute_mode::rows); } @@ -584,22 +772,8 @@ template std::unique_ptr Csr::column_permute( const array* permutation_indices) const { - GKO_ASSERT_EQ(permutation_indices->get_num_elems(), this->get_size()[1]); - auto exec = this->get_executor(); - auto permute_cpy = - Csr::create(exec, this->get_size(), this->get_num_stored_elements(), - this->get_strategy()); - array inv_permutation(exec, this->get_size()[1]); - - exec->run(csr::make_invert_permutation( - this->get_size()[1], - make_temporary_clone(exec, permutation_indices)->get_const_data(), - inv_permutation.get_data())); - exec->run(csr::make_inverse_column_permute(inv_permutation.get_const_data(), - this, permute_cpy.get())); - permute_cpy->make_srow(); - permute_cpy->sort_by_column_index(); - return std::move(permute_cpy); + return permute(create_permutation_view(*permutation_indices), + permute_mode::columns); } @@ -607,17 +781,8 @@ template std::unique_ptr Csr::inverse_row_permute( const array* permutation_indices) const { - GKO_ASSERT_EQ(permutation_indices->get_num_elems(), this->get_size()[0]); - auto exec = this->get_executor(); - auto inverse_permute_cpy = - Csr::create(exec, this->get_size(), this->get_num_stored_elements(), - this->get_strategy()); - - exec->run(csr::make_inverse_row_permute( - make_temporary_clone(exec, permutation_indices)->get_const_data(), this, - inverse_permute_cpy.get())); - inverse_permute_cpy->make_srow(); - return std::move(inverse_permute_cpy); + return permute(create_permutation_view(*permutation_indices), + permute_mode::inverse_rows); } @@ -625,18 +790,8 @@ template std::unique_ptr Csr::inverse_column_permute( const array* permutation_indices) const { - GKO_ASSERT_EQ(permutation_indices->get_num_elems(), this->get_size()[1]); - auto exec = this->get_executor(); - auto inverse_permute_cpy = - Csr::create(exec, this->get_size(), this->get_num_stored_elements(), - this->get_strategy()); - - exec->run(csr::make_inverse_column_permute( - make_temporary_clone(exec, permutation_indices)->get_const_data(), this, - inverse_permute_cpy.get())); - inverse_permute_cpy->make_srow(); - inverse_permute_cpy->sort_by_column_index(); - return std::move(inverse_permute_cpy); + return permute(create_permutation_view(*permutation_indices), + permute_mode::inverse_columns); } diff --git a/core/matrix/csr_kernels.hpp b/core/matrix/csr_kernels.hpp index 42a92ca1b84..26d80f93b8b 100644 --- a/core/matrix/csr_kernels.hpp +++ b/core/matrix/csr_kernels.hpp @@ -146,23 +146,61 @@ namespace kernels { const matrix::Csr* orig, \ matrix::Csr* row_permuted) -#define GKO_DECLARE_CSR_INVERSE_ROW_PERMUTE_KERNEL(ValueType, IndexType) \ - void inverse_row_permute(std::shared_ptr exec, \ - const IndexType* permutation_indices, \ +#define GKO_DECLARE_CSR_INV_ROW_PERMUTE_KERNEL(ValueType, IndexType) \ + void inv_row_permute(std::shared_ptr exec, \ + const IndexType* permutation_indices, \ + const matrix::Csr* orig, \ + matrix::Csr* row_permuted) + +#define GKO_DECLARE_CSR_INV_COL_PERMUTE_KERNEL(ValueType, IndexType) \ + void inv_col_permute(std::shared_ptr exec, \ + const IndexType* permutation_indices, \ + const matrix::Csr* orig, \ + matrix::Csr* col_permuted) + +#define GKO_DECLARE_CSR_INV_NONSYMM_PERMUTE_KERNEL(ValueType, IndexType) \ + void inv_nonsymm_permute(std::shared_ptr exec, \ + const IndexType* row_permutation_indices, \ + const IndexType* column_permutation_indices, \ const matrix::Csr* orig, \ - matrix::Csr* row_permuted) - -#define GKO_DECLARE_CSR_INVERSE_COLUMN_PERMUTE_KERNEL(ValueType, IndexType) \ - void inverse_column_permute( \ - std::shared_ptr exec, \ - const IndexType* permutation_indices, \ - const matrix::Csr* orig, \ - matrix::Csr* column_permuted) - -#define GKO_DECLARE_INVERT_PERMUTATION_KERNEL(IndexType) \ - void invert_permutation( \ - std::shared_ptr exec, size_type size, \ - const IndexType* permutation_indices, IndexType* inv_permutation) + matrix::Csr* permuted) + +#define GKO_DECLARE_CSR_INV_SYMM_SCALE_PERMUTE_KERNEL(ValueType, IndexType) \ + void inv_symm_scale_permute(std::shared_ptr exec, \ + const ValueType* scale, \ + const IndexType* permutation_indices, \ + const matrix::Csr* orig, \ + matrix::Csr* permuted) + +#define GKO_DECLARE_CSR_ROW_SCALE_PERMUTE_KERNEL(ValueType, IndexType) \ + void row_scale_permute(std::shared_ptr exec, \ + const ValueType* scale, \ + const IndexType* permutation_indices, \ + const matrix::Csr* orig, \ + matrix::Csr* row_permuted) + +#define GKO_DECLARE_CSR_INV_ROW_SCALE_PERMUTE_KERNEL(ValueType, IndexType) \ + void inv_row_scale_permute( \ + std::shared_ptr exec, const ValueType* scale, \ + const IndexType* permutation_indices, \ + const matrix::Csr* orig, \ + matrix::Csr* row_permuted) + +#define GKO_DECLARE_CSR_INV_COL_SCALE_PERMUTE_KERNEL(ValueType, IndexType) \ + void inv_col_scale_permute( \ + std::shared_ptr exec, const ValueType* scale, \ + const IndexType* permutation_indices, \ + const matrix::Csr* orig, \ + matrix::Csr* col_permuted) + +#define GKO_DECLARE_CSR_INV_NONSYMM_SCALE_PERMUTE_KERNEL(ValueType, IndexType) \ + void inv_nonsymm_scale_permute( \ + std::shared_ptr exec, \ + const ValueType* row_scale, const IndexType* row_permutation_indices, \ + const ValueType* column_scale, \ + const IndexType* column_permutation_indices, \ + const matrix::Csr* orig, \ + matrix::Csr* col_permuted) #define GKO_DECLARE_CSR_CALC_NNZ_PER_ROW_IN_SPAN_KERNEL(ValueType, IndexType) \ void calculate_nonzeros_per_row_in_span( \ @@ -251,74 +289,84 @@ namespace kernels { IndexType sample_size, IndexType* result) -#define GKO_DECLARE_ALL_AS_TEMPLATES \ - template \ - GKO_DECLARE_CSR_SPMV_KERNEL(MatrixValueType, InputValueType, \ - OutputValueType, IndexType); \ - template \ - GKO_DECLARE_CSR_ADVANCED_SPMV_KERNEL(MatrixValueType, InputValueType, \ - OutputValueType, IndexType); \ - template \ - GKO_DECLARE_CSR_SPGEMM_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_CSR_ADVANCED_SPGEMM_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_CSR_SPGEAM_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_CSR_FILL_IN_DENSE_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_CSR_CONVERT_TO_SELLP_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_CSR_CONVERT_TO_HYBRID_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_CSR_CONVERT_TO_ELL_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_CSR_CONVERT_TO_FBCSR_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_CSR_TRANSPOSE_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_CSR_CONJ_TRANSPOSE_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_CSR_INV_SYMM_PERMUTE_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_CSR_ROW_PERMUTE_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_CSR_INVERSE_ROW_PERMUTE_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_CSR_INVERSE_COLUMN_PERMUTE_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_INVERT_PERMUTATION_KERNEL(IndexType); \ - template \ - GKO_DECLARE_CSR_CALC_NNZ_PER_ROW_IN_SPAN_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_CSR_COMPUTE_SUB_MATRIX_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_CSR_CALC_NNZ_PER_ROW_IN_INDEX_SET_KERNEL(ValueType, \ - IndexType); \ - template \ - GKO_DECLARE_CSR_COMPUTE_SUB_MATRIX_FROM_INDEX_SET_KERNEL(ValueType, \ - IndexType); \ - template \ - GKO_DECLARE_CSR_SORT_BY_COLUMN_INDEX(ValueType, IndexType); \ - template \ - GKO_DECLARE_CSR_IS_SORTED_BY_COLUMN_INDEX(ValueType, IndexType); \ - template \ - GKO_DECLARE_CSR_EXTRACT_DIAGONAL(ValueType, IndexType); \ - template \ - GKO_DECLARE_CSR_SCALE_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_CSR_INV_SCALE_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_CSR_CHECK_DIAGONAL_ENTRIES_EXIST(ValueType, IndexType); \ - template \ - GKO_DECLARE_CSR_ADD_SCALED_IDENTITY_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_CSR_BUILD_LOOKUP_OFFSETS_KERNEL(IndexType); \ - template \ - GKO_DECLARE_CSR_BUILD_LOOKUP_KERNEL(IndexType); \ - template \ +#define GKO_DECLARE_ALL_AS_TEMPLATES \ + template \ + GKO_DECLARE_CSR_SPMV_KERNEL(MatrixValueType, InputValueType, \ + OutputValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_ADVANCED_SPMV_KERNEL(MatrixValueType, InputValueType, \ + OutputValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_SPGEMM_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_ADVANCED_SPGEMM_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_SPGEAM_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_FILL_IN_DENSE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_CONVERT_TO_SELLP_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_CONVERT_TO_HYBRID_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_CONVERT_TO_ELL_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_CONVERT_TO_FBCSR_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_TRANSPOSE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_CONJ_TRANSPOSE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_INV_SYMM_PERMUTE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_ROW_PERMUTE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_INV_ROW_PERMUTE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_INV_COL_PERMUTE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_INV_NONSYMM_PERMUTE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_INV_SYMM_SCALE_PERMUTE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_ROW_SCALE_PERMUTE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_INV_ROW_SCALE_PERMUTE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_INV_COL_SCALE_PERMUTE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_INV_NONSYMM_SCALE_PERMUTE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_CALC_NNZ_PER_ROW_IN_SPAN_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_COMPUTE_SUB_MATRIX_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_CALC_NNZ_PER_ROW_IN_INDEX_SET_KERNEL(ValueType, \ + IndexType); \ + template \ + GKO_DECLARE_CSR_COMPUTE_SUB_MATRIX_FROM_INDEX_SET_KERNEL(ValueType, \ + IndexType); \ + template \ + GKO_DECLARE_CSR_SORT_BY_COLUMN_INDEX(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_IS_SORTED_BY_COLUMN_INDEX(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_EXTRACT_DIAGONAL(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_SCALE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_INV_SCALE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_CHECK_DIAGONAL_ENTRIES_EXIST(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_ADD_SCALED_IDENTITY_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_CSR_BUILD_LOOKUP_OFFSETS_KERNEL(IndexType); \ + template \ + GKO_DECLARE_CSR_BUILD_LOOKUP_KERNEL(IndexType); \ + template \ GKO_DECLARE_CSR_BENCHMARK_LOOKUP_KERNEL(IndexType) diff --git a/core/matrix/dense.cpp b/core/matrix/dense.cpp index 17dec93c234..e5ad34a8294 100644 --- a/core/matrix/dense.cpp +++ b/core/matrix/dense.cpp @@ -50,6 +50,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include +#include #include #include @@ -58,6 +60,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "core/components/prefix_sum_kernels.hpp" #include "core/matrix/dense_kernels.hpp" #include "core/matrix/hybrid_kernels.hpp" +#include "ginkgo/core/base/temporary_clone.hpp" namespace gko { @@ -95,11 +98,22 @@ GKO_REGISTER_OPERATION(transpose, dense::transpose); GKO_REGISTER_OPERATION(conj_transpose, dense::conj_transpose); GKO_REGISTER_OPERATION(symm_permute, dense::symm_permute); GKO_REGISTER_OPERATION(inv_symm_permute, dense::inv_symm_permute); +GKO_REGISTER_OPERATION(nonsymm_permute, dense::nonsymm_permute); +GKO_REGISTER_OPERATION(inv_nonsymm_permute, dense::inv_nonsymm_permute); GKO_REGISTER_OPERATION(row_gather, dense::row_gather); GKO_REGISTER_OPERATION(advanced_row_gather, dense::advanced_row_gather); -GKO_REGISTER_OPERATION(column_permute, dense::column_permute); -GKO_REGISTER_OPERATION(inverse_row_permute, dense::inverse_row_permute); -GKO_REGISTER_OPERATION(inverse_column_permute, dense::inverse_column_permute); +GKO_REGISTER_OPERATION(col_permute, dense::col_permute); +GKO_REGISTER_OPERATION(inverse_row_permute, dense::inv_row_permute); +GKO_REGISTER_OPERATION(inverse_col_permute, dense::inv_col_permute); +GKO_REGISTER_OPERATION(symm_scale_permute, dense::symm_scale_permute); +GKO_REGISTER_OPERATION(inv_symm_scale_permute, dense::inv_symm_scale_permute); +GKO_REGISTER_OPERATION(nonsymm_scale_permute, dense::nonsymm_scale_permute); +GKO_REGISTER_OPERATION(inv_nonsymm_scale_permute, + dense::inv_nonsymm_scale_permute); +GKO_REGISTER_OPERATION(row_scale_permute, dense::row_scale_permute); +GKO_REGISTER_OPERATION(col_scale_permute, dense::col_scale_permute); +GKO_REGISTER_OPERATION(inv_row_scale_permute, dense::inv_row_scale_permute); +GKO_REGISTER_OPERATION(inv_col_scale_permute, dense::inv_col_scale_permute); GKO_REGISTER_OPERATION(fill_in_matrix_data, dense::fill_in_matrix_data); GKO_REGISTER_OPERATION(convert_to_coo, dense::convert_to_coo); GKO_REGISTER_OPERATION(convert_to_csr, dense::convert_to_csr); @@ -1080,48 +1094,174 @@ void Dense::conj_transpose(ptr_param> output) const template template -void Dense::permute_impl(const array* permutation_indices, - Dense* output) const +void Dense::permute_impl(const Permutation* permutation, + permute_mode mode, Dense* output) const { - GKO_ASSERT_IS_SQUARE_MATRIX(this); + const auto exec = this->get_executor(); + const auto size = this->get_size(); GKO_ASSERT_EQUAL_DIMENSIONS(this, output); - GKO_ASSERT_EQ(permutation_indices->get_num_elems(), this->get_size()[0]); - auto exec = this->get_executor(); - - exec->run(dense::make_symm_permute( - make_temporary_clone(exec, permutation_indices).get(), this, - make_temporary_output_clone(exec, output).get())); + if ((mode & permute_mode::symmetric) == permute_mode::none) { + output->copy_from(this); + return; + } + if ((mode & permute_mode::symmetric) == permute_mode::symmetric) { + GKO_ASSERT_IS_SQUARE_MATRIX(this); + } + if ((mode & permute_mode::rows) == permute_mode::rows) { + GKO_ASSERT_EQ(size[0], permutation->get_size()[0]); + } + if ((mode & permute_mode::columns) == permute_mode::columns) { + GKO_ASSERT_EQ(size[1], permutation->get_size()[0]); + } + auto local_output = make_temporary_output_clone(exec, output); + auto local_perm = make_temporary_clone(exec, permutation); + switch (mode) { + case permute_mode::rows: + exec->run(dense::make_row_gather(local_perm->get_const_permutation(), + this, local_output.get())); + break; + case permute_mode::columns: + exec->run(dense::make_col_permute(local_perm->get_const_permutation(), + this, local_output.get())); + break; + case permute_mode::symmetric: + exec->run(dense::make_symm_permute(local_perm->get_const_permutation(), + this, local_output.get())); + break; + case permute_mode::inverse_rows: + exec->run(dense::make_inverse_row_permute( + local_perm->get_const_permutation(), this, local_output.get())); + break; + case permute_mode::inverse_columns: + exec->run(dense::make_inverse_col_permute( + local_perm->get_const_permutation(), this, local_output.get())); + break; + case permute_mode::inverse_symmetric: + exec->run(dense::make_inv_symm_permute( + local_perm->get_const_permutation(), this, local_output.get())); + break; + default: + GKO_ASSERT(false); // cannot happen + } } template template -void Dense::inverse_permute_impl( - const array* permutation_indices, Dense* output) const +void Dense::permute_impl( + const Permutation* row_permutation, + const Permutation* col_permutation, bool invert, + Dense* output) const { - GKO_ASSERT_IS_SQUARE_MATRIX(this); - GKO_ASSERT_EQUAL_DIMENSIONS(this, output); - GKO_ASSERT_EQ(permutation_indices->get_num_elems(), this->get_size()[0]); auto exec = this->get_executor(); - - exec->run(dense::make_inv_symm_permute( - make_temporary_clone(exec, permutation_indices).get(), this, - make_temporary_output_clone(exec, output).get())); + auto size = this->get_size(); + GKO_ASSERT_EQUAL_DIMENSIONS(this, output); + GKO_ASSERT_EQ(size[0], row_permutation->get_size()[0]); + GKO_ASSERT_EQ(size[1], col_permutation->get_size()[0]); + auto local_output = make_temporary_output_clone(exec, output); + auto local_row_perm = make_temporary_clone(exec, row_permutation); + auto local_col_perm = make_temporary_clone(exec, col_permutation); + if (invert) { + exec->run(dense::make_inv_nonsymm_permute( + local_row_perm->get_const_permutation(), + local_col_perm->get_const_permutation(), this, local_output.get())); + } else { + exec->run(dense::make_nonsymm_permute( + local_row_perm->get_const_permutation(), + local_col_perm->get_const_permutation(), this, local_output.get())); + } } template template -void Dense::row_permute_impl( - const array* permutation_indices, Dense* output) const +void Dense::scale_permute_impl( + const ScaledPermutation* permutation, + permute_mode mode, Dense* output) const { - GKO_ASSERT_EQ(permutation_indices->get_num_elems(), this->get_size()[0]); + const auto exec = this->get_executor(); + const auto size = this->get_size(); GKO_ASSERT_EQUAL_DIMENSIONS(this, output); - auto exec = this->get_executor(); + if ((mode & permute_mode::symmetric) == permute_mode::none) { + output->copy_from(this); + return; + } + if ((mode & permute_mode::symmetric) == permute_mode::symmetric) { + GKO_ASSERT_IS_SQUARE_MATRIX(this); + } + if ((mode & permute_mode::rows) == permute_mode::rows) { + GKO_ASSERT_EQ(size[0], permutation->get_size()[0]); + } + if ((mode & permute_mode::columns) == permute_mode::columns) { + GKO_ASSERT_EQ(size[1], permutation->get_size()[0]); + } + auto local_output = make_temporary_output_clone(exec, output); + auto local_perm = make_temporary_clone(exec, permutation); + switch (mode) { + case permute_mode::rows: + exec->run(dense::make_row_scale_permute( + local_perm->get_const_scale(), local_perm->get_const_permutation(), + this, local_output.get())); + break; + case permute_mode::columns: + exec->run(dense::make_col_scale_permute( + local_perm->get_const_scale(), local_perm->get_const_permutation(), + this, local_output.get())); + break; + case permute_mode::symmetric: + exec->run(dense::make_symm_scale_permute( + local_perm->get_const_scale(), local_perm->get_const_permutation(), + this, local_output.get())); + break; + case permute_mode::inverse_rows: + exec->run(dense::make_inv_row_scale_permute( + local_perm->get_const_scale(), local_perm->get_const_permutation(), + this, local_output.get())); + break; + case permute_mode::inverse_columns: + exec->run(dense::make_inv_col_scale_permute( + local_perm->get_const_scale(), local_perm->get_const_permutation(), + this, local_output.get())); + break; + case permute_mode::inverse_symmetric: + exec->run(dense::make_inv_symm_scale_permute( + local_perm->get_const_scale(), local_perm->get_const_permutation(), + this, local_output.get())); + break; + default: + GKO_ASSERT(false); // cannot happen + } +} - exec->run(dense::make_row_gather( - make_temporary_clone(exec, permutation_indices).get(), this, - make_temporary_output_clone(exec, output).get())); + +template +template +void Dense::scale_permute_impl( + const ScaledPermutation* row_permutation, + const ScaledPermutation* col_permutation, bool invert, + Dense* output) const +{ + auto exec = this->get_executor(); + auto size = this->get_size(); + GKO_ASSERT_EQUAL_DIMENSIONS(this, output); + GKO_ASSERT_EQ(size[0], row_permutation->get_size()[0]); + GKO_ASSERT_EQ(size[1], col_permutation->get_size()[0]); + auto local_output = make_temporary_output_clone(exec, output); + auto local_row_perm = make_temporary_clone(exec, row_permutation); + auto local_col_perm = make_temporary_clone(exec, col_permutation); + if (invert) { + exec->run(dense::make_inv_nonsymm_scale_permute( + local_row_perm->get_const_scale(), + local_row_perm->get_const_permutation(), + local_col_perm->get_const_scale(), + local_col_perm->get_const_permutation(), this, local_output.get())); + } else { + exec->run(dense::make_nonsymm_scale_permute( + local_row_perm->get_const_scale(), + local_row_perm->get_const_permutation(), + local_col_perm->get_const_scale(), + local_col_perm->get_const_permutation(), this, local_output.get())); + } } @@ -1135,7 +1275,7 @@ void Dense::row_gather_impl(const array* row_idxs, GKO_ASSERT_EQUAL_DIMENSIONS(expected_dim, row_collection); exec->run(dense::make_row_gather( - make_temporary_clone(exec, row_idxs).get(), this, + make_temporary_clone(exec, row_idxs)->get_const_data(), this, make_temporary_output_clone(exec, row_collection).get())); } @@ -1152,82 +1292,130 @@ void Dense::row_gather_impl(const Dense* alpha, exec->run(dense::make_advanced_row_gather( make_temporary_clone(exec, alpha).get(), - make_temporary_clone(exec, row_idxs).get(), this, + make_temporary_clone(exec, row_idxs)->get_const_data(), this, make_temporary_clone(exec, beta).get(), make_temporary_clone(exec, row_collection).get())); } template -template -void Dense::column_permute_impl( - const array* permutation_indices, Dense* output) const +std::unique_ptr Dense::permute( + const array* permutation_indices) const { - GKO_ASSERT_EQ(permutation_indices->get_num_elems(), this->get_size()[1]); - GKO_ASSERT_EQUAL_DIMENSIONS(this, output); - auto exec = this->get_executor(); - - exec->run(dense::make_column_permute( - make_temporary_clone(exec, permutation_indices).get(), this, - make_temporary_output_clone(exec, output).get())); + auto result = Dense::create(this->get_executor(), this->get_size()); + this->permute(permutation_indices, result); + return result; } template -template -void Dense::inverse_row_permute_impl( - const array* permutation_indices, Dense* output) const +std::unique_ptr Dense::permute( + const array* permutation_indices) const { - GKO_ASSERT_EQ(permutation_indices->get_num_elems(), this->get_size()[0]); - GKO_ASSERT_EQUAL_DIMENSIONS(this, output); - auto exec = this->get_executor(); - - exec->run(dense::make_inverse_row_permute( - make_temporary_clone(exec, permutation_indices).get(), this, - make_temporary_output_clone(exec, output).get())); + auto result = Dense::create(this->get_executor(), this->get_size()); + this->permute(permutation_indices, result); + return result; } template -template -void Dense::inverse_column_permute_impl( - const array* permutation_indices, Dense* output) const +std::unique_ptr> Dense::permute( + ptr_param> permutation, permute_mode mode) const { - GKO_ASSERT_EQ(permutation_indices->get_num_elems(), this->get_size()[1]); - GKO_ASSERT_EQUAL_DIMENSIONS(this, output); - auto exec = this->get_executor(); + auto result = Dense::create(this->get_executor(), this->get_size()); + this->permute(permutation, result, mode); + return result; +} + - exec->run(dense::make_inverse_column_permute( - make_temporary_clone(exec, permutation_indices).get(), this, - make_temporary_output_clone(exec, output).get())); +template +std::unique_ptr> Dense::permute( + ptr_param> permutation, permute_mode mode) const +{ + auto result = Dense::create(this->get_executor(), this->get_size()); + this->permute(permutation, result, mode); + return result; } template -std::unique_ptr Dense::permute( - const array* permutation_indices) const +std::unique_ptr> Dense::permute( + ptr_param> row_permutation, + ptr_param> col_permutation, bool invert) const { auto result = Dense::create(this->get_executor(), this->get_size()); - this->permute(permutation_indices, result); + this->permute(row_permutation, col_permutation, result, invert); return result; } template -std::unique_ptr Dense::permute( - const array* permutation_indices) const +std::unique_ptr> Dense::permute( + ptr_param> row_permutation, + ptr_param> col_permutation, bool invert) const { auto result = Dense::create(this->get_executor(), this->get_size()); - this->permute(permutation_indices, result); + this->permute(row_permutation, col_permutation, result, invert); return result; } +template +void Dense::permute(ptr_param> permutation, + ptr_param> result, + permute_mode mode) const +{ + this->permute_impl(permutation.get(), mode, result.get()); +} + + +template +void Dense::permute(ptr_param> permutation, + ptr_param> result, + permute_mode mode) const +{ + this->permute_impl(permutation.get(), mode, result.get()); +} + + +template +void Dense::permute( + ptr_param> row_permutation, + ptr_param> col_permutation, + ptr_param> result, bool invert) const +{ + this->permute_impl(row_permutation.get(), col_permutation.get(), invert, + result.get()); +} + + +template +void Dense::permute( + ptr_param> row_permutation, + ptr_param> col_permutation, + ptr_param> result, bool invert) const +{ + this->permute_impl(row_permutation.get(), col_permutation.get(), invert, + result.get()); +} + + +template +std::unique_ptr> create_permutation_view( + const array& indices) +{ + return Permutation::create_const(indices.get_executor(), + indices.get_num_elems(), + indices.as_const_view()); +} + + template void Dense::permute(const array* permutation_indices, ptr_param> output) const { - this->permute_impl(permutation_indices, output.get()); + this->permute_impl(create_permutation_view(*permutation_indices).get(), + permute_mode::symmetric, output.get()); } @@ -1235,7 +1423,8 @@ template void Dense::permute(const array* permutation_indices, ptr_param> output) const { - this->permute_impl(permutation_indices, output.get()); + this->permute_impl(create_permutation_view(*permutation_indices).get(), + permute_mode::symmetric, output.get()); } @@ -1263,7 +1452,8 @@ template void Dense::inverse_permute(const array* permutation_indices, ptr_param> output) const { - this->inverse_permute_impl(permutation_indices, output.get()); + this->permute_impl(create_permutation_view(*permutation_indices).get(), + permute_mode::inverse_symmetric, output.get()); } @@ -1271,7 +1461,8 @@ template void Dense::inverse_permute(const array* permutation_indices, ptr_param> output) const { - this->inverse_permute_impl(permutation_indices, output.get()); + this->permute_impl(create_permutation_view(*permutation_indices).get(), + permute_mode::inverse_symmetric, output.get()); } @@ -1299,7 +1490,8 @@ template void Dense::row_permute(const array* permutation_indices, ptr_param> output) const { - this->row_permute_impl(permutation_indices, output.get()); + this->permute_impl(create_permutation_view(*permutation_indices).get(), + permute_mode::rows, output.get()); } @@ -1307,7 +1499,8 @@ template void Dense::row_permute(const array* permutation_indices, ptr_param> output) const { - this->row_permute_impl(permutation_indices, output.get()); + this->permute_impl(create_permutation_view(*permutation_indices).get(), + permute_mode::rows, output.get()); } @@ -1434,7 +1627,8 @@ template void Dense::column_permute(const array* permutation_indices, ptr_param> output) const { - this->column_permute_impl(permutation_indices, output.get()); + this->permute_impl(create_permutation_view(*permutation_indices).get(), + permute_mode::columns, output.get()); } @@ -1442,7 +1636,8 @@ template void Dense::column_permute(const array* permutation_indices, ptr_param> output) const { - this->column_permute_impl(permutation_indices, output.get()); + this->permute_impl(create_permutation_view(*permutation_indices).get(), + permute_mode::columns, output.get()); } @@ -1471,7 +1666,8 @@ void Dense::inverse_row_permute( const array* permutation_indices, ptr_param> output) const { - this->inverse_row_permute_impl(permutation_indices, output.get()); + this->permute_impl(create_permutation_view(*permutation_indices).get(), + permute_mode::inverse_rows, output.get()); } @@ -1480,7 +1676,8 @@ void Dense::inverse_row_permute( const array* permutation_indices, ptr_param> output) const { - this->inverse_row_permute_impl(permutation_indices, output.get()); + this->permute_impl(create_permutation_view(*permutation_indices).get(), + permute_mode::inverse_rows, output.get()); } @@ -1509,7 +1706,8 @@ void Dense::inverse_column_permute( const array* permutation_indices, ptr_param> output) const { - this->inverse_column_permute_impl(permutation_indices, output.get()); + this->permute_impl(create_permutation_view(*permutation_indices).get(), + permute_mode::inverse_columns, output.get()); } @@ -1518,7 +1716,94 @@ void Dense::inverse_column_permute( const array* permutation_indices, ptr_param> output) const { - this->inverse_column_permute_impl(permutation_indices, output.get()); + this->permute_impl(create_permutation_view(*permutation_indices).get(), + permute_mode::inverse_columns, output.get()); +} + + +template +std::unique_ptr> Dense::scale_permute( + ptr_param> permutation, + permute_mode mode) const +{ + auto result = Dense::create(this->get_executor(), this->get_size()); + this->scale_permute(permutation, result, mode); + return result; +} + + +template +std::unique_ptr> Dense::scale_permute( + ptr_param> permutation, + permute_mode mode) const +{ + auto result = Dense::create(this->get_executor(), this->get_size()); + this->scale_permute(permutation, result, mode); + return result; +} + + +template +void Dense::scale_permute( + ptr_param> permutation, + ptr_param output, permute_mode mode) const +{ + this->scale_permute_impl(permutation.get(), mode, output.get()); +} + + +template +void Dense::scale_permute( + ptr_param> permutation, + ptr_param output, permute_mode mode) const +{ + this->scale_permute_impl(permutation.get(), mode, output.get()); +} + + +template +std::unique_ptr> Dense::scale_permute( + ptr_param> row_permutation, + ptr_param> col_permutation, + bool invert) const +{ + auto result = Dense::create(this->get_executor(), this->get_size()); + this->scale_permute(row_permutation, col_permutation, result, invert); + return result; +} + + +template +std::unique_ptr> Dense::scale_permute( + ptr_param> row_permutation, + ptr_param> col_permutation, + bool invert) const +{ + auto result = Dense::create(this->get_executor(), this->get_size()); + this->scale_permute(row_permutation, col_permutation, result, invert); + return result; +} + + +template +void Dense::scale_permute( + ptr_param> row_permutation, + ptr_param> col_permutation, + ptr_param output, bool invert) const +{ + this->scale_permute_impl(row_permutation.get(), col_permutation.get(), + invert, output.get()); +} + + +template +void Dense::scale_permute( + ptr_param> row_permutation, + ptr_param> col_permutation, + ptr_param output, bool invert) const +{ + this->scale_permute_impl(row_permutation.get(), col_permutation.get(), + invert, output.get()); } diff --git a/core/matrix/dense_kernels.hpp b/core/matrix/dense_kernels.hpp index 9a487fadeda..77e5c677456 100644 --- a/core/matrix/dense_kernels.hpp +++ b/core/matrix/dense_kernels.hpp @@ -232,50 +232,112 @@ namespace kernels { const matrix::Dense<_type>* orig, \ matrix::Dense<_type>* trans) +#define GKO_DECLARE_DENSE_SYMM_SCALE_PERMUTE_KERNEL(_vtype, _itype) \ + void symm_scale_permute( \ + std::shared_ptr exec, const _vtype* scale, \ + const _itype* permutation_indices, const matrix::Dense<_vtype>* orig, \ + matrix::Dense<_vtype>* permuted) + +#define GKO_DECLARE_DENSE_ROW_SCALE_PERMUTE_KERNEL(_vtype, _itype) \ + void row_scale_permute( \ + std::shared_ptr exec, const _vtype* scale, \ + const _itype* permutation_indices, const matrix::Dense<_vtype>* orig, \ + matrix::Dense<_vtype>* permuted) + +#define GKO_DECLARE_DENSE_COL_SCALE_PERMUTE_KERNEL(_vtype, _itype) \ + void col_scale_permute( \ + std::shared_ptr exec, const _vtype* scale, \ + const _itype* permutation_indices, const matrix::Dense<_vtype>* orig, \ + matrix::Dense<_vtype>* permuted) + +#define GKO_DECLARE_DENSE_INV_SYMM_SCALE_PERMUTE_KERNEL(_vtype, _itype) \ + void inv_symm_scale_permute( \ + std::shared_ptr exec, const _vtype* scale, \ + const _itype* permutation_indices, const matrix::Dense<_vtype>* orig, \ + matrix::Dense<_vtype>* permuted) + +#define GKO_DECLARE_DENSE_INV_ROW_SCALE_PERMUTE_KERNEL(_vtype, _itype) \ + void inv_row_scale_permute( \ + std::shared_ptr exec, const _vtype* scale, \ + const _itype* permutation_indices, const matrix::Dense<_vtype>* orig, \ + matrix::Dense<_vtype>* permuted) + +#define GKO_DECLARE_DENSE_INV_COL_SCALE_PERMUTE_KERNEL(_vtype, _itype) \ + void inv_col_scale_permute( \ + std::shared_ptr exec, const _vtype* scale, \ + const _itype* permutation_indices, const matrix::Dense<_vtype>* orig, \ + matrix::Dense<_vtype>* permuted) + +#define GKO_DECLARE_DENSE_NONSYMM_SCALE_PERMUTE_KERNEL(_vtype, _itype) \ + void nonsymm_scale_permute( \ + std::shared_ptr exec, const _vtype* row_scale, \ + const _itype* row_permutation_indices, const _vtype* column_scale, \ + const _itype* column_permutation_indices, \ + const matrix::Dense<_vtype>* orig, matrix::Dense<_vtype>* permuted) + +#define GKO_DECLARE_DENSE_INV_NONSYMM_SCALE_PERMUTE_KERNEL(_vtype, _itype) \ + void inv_nonsymm_scale_permute( \ + std::shared_ptr exec, const _vtype* row_scale, \ + const _itype* row_permutation_indices, const _vtype* column_scale, \ + const _itype* column_permutation_indices, \ + const matrix::Dense<_vtype>* orig, matrix::Dense<_vtype>* permuted) + #define GKO_DECLARE_DENSE_SYMM_PERMUTE_KERNEL(_vtype, _itype) \ void symm_permute(std::shared_ptr exec, \ - const array<_itype>* permutation_indices, \ + const _itype* permutation_indices, \ const matrix::Dense<_vtype>* orig, \ matrix::Dense<_vtype>* permuted) #define GKO_DECLARE_DENSE_INV_SYMM_PERMUTE_KERNEL(_vtype, _itype) \ void inv_symm_permute(std::shared_ptr exec, \ - const array<_itype>* permutation_indices, \ + const _itype* permutation_indices, \ const matrix::Dense<_vtype>* orig, \ matrix::Dense<_vtype>* permuted) +#define GKO_DECLARE_DENSE_NONSYMM_PERMUTE_KERNEL(_vtype, _itype) \ + void nonsymm_permute(std::shared_ptr exec, \ + const _itype* row_permutation_indices, \ + const _itype* column_permutation_indices, \ + const matrix::Dense<_vtype>* orig, \ + matrix::Dense<_vtype>* permuted) + +#define GKO_DECLARE_DENSE_INV_NONSYMM_PERMUTE_KERNEL(_vtype, _itype) \ + void inv_nonsymm_permute(std::shared_ptr exec, \ + const _itype* row_permutation_indices, \ + const _itype* column_permutation_indices, \ + const matrix::Dense<_vtype>* orig, \ + matrix::Dense<_vtype>* permuted) + #define GKO_DECLARE_DENSE_ROW_GATHER_KERNEL(_vtype, _otype, _itype) \ void row_gather(std::shared_ptr exec, \ - const array<_itype>* gather_indices, \ + const _itype* gather_indices, \ const matrix::Dense<_vtype>* orig, \ matrix::Dense<_otype>* row_collection) - -#define GKO_DECLARE_DENSE_ADVANCED_ROW_GATHER_KERNEL(_vtype, _otype, _itype) \ - void advanced_row_gather(std::shared_ptr exec, \ - const matrix::Dense<_vtype>* alpha, \ - const array<_itype>* gather_indices, \ - const matrix::Dense<_vtype>* orig, \ - const matrix::Dense<_vtype>* beta, \ - matrix::Dense<_otype>* row_collection) - -#define GKO_DECLARE_DENSE_COLUMN_PERMUTE_KERNEL(_vtype, _itype) \ - void column_permute(std::shared_ptr exec, \ - const array<_itype>* permutation_indices, \ - const matrix::Dense<_vtype>* orig, \ - matrix::Dense<_vtype>* column_permuted) - -#define GKO_DECLARE_DENSE_INV_ROW_PERMUTE_KERNEL(_vtype, _itype) \ - void inverse_row_permute(std::shared_ptr exec, \ - const array<_itype>* permutation_indices, \ - const matrix::Dense<_vtype>* orig, \ - matrix::Dense<_vtype>* row_permuted) - -#define GKO_DECLARE_DENSE_INV_COLUMN_PERMUTE_KERNEL(_vtype, _itype) \ - void inverse_column_permute(std::shared_ptr exec, \ - const array<_itype>* permutation_indices, \ - const matrix::Dense<_vtype>* orig, \ - matrix::Dense<_vtype>* column_permuted) +#define GKO_DECLARE_DENSE_ADVANCED_ROW_GATHER_KERNEL(_vtype, _otype, _itype) \ + void advanced_row_gather( \ + std::shared_ptr exec, \ + const matrix::Dense<_vtype>* alpha, const _itype* gather_indices, \ + const matrix::Dense<_vtype>* orig, const matrix::Dense<_vtype>* beta, \ + matrix::Dense<_otype>* row_collection) + +#define GKO_DECLARE_DENSE_COL_PERMUTE_KERNEL(_vtype, _itype) \ + void col_permute(std::shared_ptr exec, \ + const _itype* permutation_indices, \ + const matrix::Dense<_vtype>* orig, \ + matrix::Dense<_vtype>* col_permuted) + +#define GKO_DECLARE_DENSE_INV_ROW_PERMUTE_KERNEL(_vtype, _itype) \ + void inv_row_permute(std::shared_ptr exec, \ + const _itype* permutation_indices, \ + const matrix::Dense<_vtype>* orig, \ + matrix::Dense<_vtype>* row_permuted) + +#define GKO_DECLARE_DENSE_INV_COL_PERMUTE_KERNEL(_vtype, _itype) \ + void inv_col_permute(std::shared_ptr exec, \ + const _itype* permutation_indices, \ + const matrix::Dense<_vtype>* orig, \ + matrix::Dense<_vtype>* col_permuted) #define GKO_DECLARE_DENSE_EXTRACT_DIAGONAL_KERNEL(_vtype) \ void extract_diagonal(std::shared_ptr exec, \ @@ -314,102 +376,122 @@ namespace kernels { matrix::Dense<_vtype>* mtx) -#define GKO_DECLARE_ALL_AS_TEMPLATES \ - template \ - GKO_DECLARE_DENSE_SIMPLE_APPLY_KERNEL(ValueType); \ - template \ - GKO_DECLARE_DENSE_APPLY_KERNEL(ValueType); \ - template \ - GKO_DECLARE_DENSE_COPY_KERNEL(InValueType, OutValueType); \ - template \ - GKO_DECLARE_DENSE_FILL_KERNEL(ValueType); \ - template \ - GKO_DECLARE_DENSE_SCALE_KERNEL(ValueType, ScalarType); \ - template \ - GKO_DECLARE_DENSE_INV_SCALE_KERNEL(ValueType, ScalarType); \ - template \ - GKO_DECLARE_DENSE_ADD_SCALED_KERNEL(ValueType, ScalarType); \ - template \ - GKO_DECLARE_DENSE_SUB_SCALED_KERNEL(ValueType, ScalarType); \ - template \ - GKO_DECLARE_DENSE_ADD_SCALED_DIAG_KERNEL(ValueType); \ - template \ - GKO_DECLARE_DENSE_SUB_SCALED_DIAG_KERNEL(ValueType); \ - template \ - GKO_DECLARE_DENSE_COMPUTE_DOT_KERNEL(ValueType); \ - template \ - GKO_DECLARE_DENSE_COMPUTE_DOT_DISPATCH_KERNEL(ValueType); \ - template \ - GKO_DECLARE_DENSE_COMPUTE_CONJ_DOT_KERNEL(ValueType); \ - template \ - GKO_DECLARE_DENSE_COMPUTE_CONJ_DOT_DISPATCH_KERNEL(ValueType); \ - template \ - GKO_DECLARE_DENSE_COMPUTE_NORM2_KERNEL(ValueType); \ - template \ - GKO_DECLARE_DENSE_COMPUTE_NORM2_DISPATCH_KERNEL(ValueType); \ - template \ - GKO_DECLARE_DENSE_COMPUTE_NORM1_KERNEL(ValueType); \ - template \ - GKO_DECLARE_DENSE_FILL_IN_MATRIX_DATA_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_DENSE_COMPUTE_SQUARED_NORM2_KERNEL(ValueType); \ - template \ - GKO_DECLARE_DENSE_COMPUTE_SQRT_KERNEL(ValueType); \ - template \ - GKO_DECLARE_DENSE_CONVERT_TO_COO_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_DENSE_CONVERT_TO_CSR_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_DENSE_CONVERT_TO_ELL_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_DENSE_CONVERT_TO_FBCSR_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_DENSE_CONVERT_TO_HYBRID_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_DENSE_CONVERT_TO_SELLP_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_DENSE_CONVERT_TO_SPARSITY_CSR_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_DENSE_COMPUTE_MAX_NNZ_PER_ROW_KERNEL(ValueType); \ - template \ - GKO_DECLARE_DENSE_COMPUTE_SLICE_SETS_KERNEL(ValueType); \ - template \ - GKO_DECLARE_DENSE_COUNT_NONZEROS_PER_ROW_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_DENSE_COUNT_NONZERO_BLOCKS_PER_ROW_KERNEL(ValueType, \ - IndexType); \ - template \ - GKO_DECLARE_DENSE_TRANSPOSE_KERNEL(ValueType); \ - template \ - GKO_DECLARE_DENSE_CONJ_TRANSPOSE_KERNEL(ValueType); \ - template \ - GKO_DECLARE_DENSE_SYMM_PERMUTE_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_DENSE_INV_SYMM_PERMUTE_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_DENSE_ROW_GATHER_KERNEL(ValueType, OutputType, IndexType); \ - template \ - GKO_DECLARE_DENSE_ADVANCED_ROW_GATHER_KERNEL(ValueType, OutputType, \ - IndexType); \ - template \ - GKO_DECLARE_DENSE_COLUMN_PERMUTE_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_DENSE_INV_ROW_PERMUTE_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_DENSE_INV_COLUMN_PERMUTE_KERNEL(ValueType, IndexType); \ - template \ - GKO_DECLARE_DENSE_EXTRACT_DIAGONAL_KERNEL(ValueType); \ - template \ - GKO_DECLARE_INPLACE_ABSOLUTE_DENSE_KERNEL(ValueType); \ - template \ - GKO_DECLARE_OUTPLACE_ABSOLUTE_DENSE_KERNEL(ValueType); \ - template \ - GKO_DECLARE_MAKE_COMPLEX_KERNEL(ValueType); \ - template \ - GKO_DECLARE_GET_REAL_KERNEL(ValueType); \ - template \ - GKO_DECLARE_GET_IMAG_KERNEL(ValueType); \ - template \ +#define GKO_DECLARE_ALL_AS_TEMPLATES \ + template \ + GKO_DECLARE_DENSE_SIMPLE_APPLY_KERNEL(ValueType); \ + template \ + GKO_DECLARE_DENSE_APPLY_KERNEL(ValueType); \ + template \ + GKO_DECLARE_DENSE_COPY_KERNEL(InValueType, OutValueType); \ + template \ + GKO_DECLARE_DENSE_FILL_KERNEL(ValueType); \ + template \ + GKO_DECLARE_DENSE_SCALE_KERNEL(ValueType, ScalarType); \ + template \ + GKO_DECLARE_DENSE_INV_SCALE_KERNEL(ValueType, ScalarType); \ + template \ + GKO_DECLARE_DENSE_ADD_SCALED_KERNEL(ValueType, ScalarType); \ + template \ + GKO_DECLARE_DENSE_SUB_SCALED_KERNEL(ValueType, ScalarType); \ + template \ + GKO_DECLARE_DENSE_ADD_SCALED_DIAG_KERNEL(ValueType); \ + template \ + GKO_DECLARE_DENSE_SUB_SCALED_DIAG_KERNEL(ValueType); \ + template \ + GKO_DECLARE_DENSE_COMPUTE_DOT_KERNEL(ValueType); \ + template \ + GKO_DECLARE_DENSE_COMPUTE_DOT_DISPATCH_KERNEL(ValueType); \ + template \ + GKO_DECLARE_DENSE_COMPUTE_CONJ_DOT_KERNEL(ValueType); \ + template \ + GKO_DECLARE_DENSE_COMPUTE_CONJ_DOT_DISPATCH_KERNEL(ValueType); \ + template \ + GKO_DECLARE_DENSE_COMPUTE_NORM2_KERNEL(ValueType); \ + template \ + GKO_DECLARE_DENSE_COMPUTE_NORM2_DISPATCH_KERNEL(ValueType); \ + template \ + GKO_DECLARE_DENSE_COMPUTE_NORM1_KERNEL(ValueType); \ + template \ + GKO_DECLARE_DENSE_FILL_IN_MATRIX_DATA_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_DENSE_COMPUTE_SQUARED_NORM2_KERNEL(ValueType); \ + template \ + GKO_DECLARE_DENSE_COMPUTE_SQRT_KERNEL(ValueType); \ + template \ + GKO_DECLARE_DENSE_CONVERT_TO_COO_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_DENSE_CONVERT_TO_CSR_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_DENSE_CONVERT_TO_ELL_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_DENSE_CONVERT_TO_FBCSR_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_DENSE_CONVERT_TO_HYBRID_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_DENSE_CONVERT_TO_SELLP_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_DENSE_CONVERT_TO_SPARSITY_CSR_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_DENSE_COMPUTE_MAX_NNZ_PER_ROW_KERNEL(ValueType); \ + template \ + GKO_DECLARE_DENSE_COMPUTE_SLICE_SETS_KERNEL(ValueType); \ + template \ + GKO_DECLARE_DENSE_COUNT_NONZEROS_PER_ROW_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_DENSE_COUNT_NONZERO_BLOCKS_PER_ROW_KERNEL(ValueType, \ + IndexType); \ + template \ + GKO_DECLARE_DENSE_TRANSPOSE_KERNEL(ValueType); \ + template \ + GKO_DECLARE_DENSE_CONJ_TRANSPOSE_KERNEL(ValueType); \ + template \ + GKO_DECLARE_DENSE_SYMM_PERMUTE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_DENSE_INV_SYMM_PERMUTE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_DENSE_NONSYMM_PERMUTE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_DENSE_INV_NONSYMM_PERMUTE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_DENSE_ROW_GATHER_KERNEL(ValueType, OutputType, IndexType); \ + template \ + GKO_DECLARE_DENSE_ADVANCED_ROW_GATHER_KERNEL(ValueType, OutputType, \ + IndexType); \ + template \ + GKO_DECLARE_DENSE_COL_PERMUTE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_DENSE_INV_ROW_PERMUTE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_DENSE_INV_COL_PERMUTE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_DENSE_SYMM_SCALE_PERMUTE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_DENSE_INV_SYMM_SCALE_PERMUTE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_DENSE_ROW_SCALE_PERMUTE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_DENSE_COL_SCALE_PERMUTE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_DENSE_INV_ROW_SCALE_PERMUTE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_DENSE_INV_COL_SCALE_PERMUTE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_DENSE_NONSYMM_SCALE_PERMUTE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_DENSE_INV_NONSYMM_SCALE_PERMUTE_KERNEL(ValueType, IndexType); \ + template \ + GKO_DECLARE_DENSE_EXTRACT_DIAGONAL_KERNEL(ValueType); \ + template \ + GKO_DECLARE_INPLACE_ABSOLUTE_DENSE_KERNEL(ValueType); \ + template \ + GKO_DECLARE_OUTPLACE_ABSOLUTE_DENSE_KERNEL(ValueType); \ + template \ + GKO_DECLARE_MAKE_COMPLEX_KERNEL(ValueType); \ + template \ + GKO_DECLARE_GET_REAL_KERNEL(ValueType); \ + template \ + GKO_DECLARE_GET_IMAG_KERNEL(ValueType); \ + template \ GKO_DECLARE_DENSE_ADD_SCALED_IDENTITY_KERNEL(ValueType, ScalarType) diff --git a/core/matrix/permutation.cpp b/core/matrix/permutation.cpp index a641834f12c..cc58ced53d2 100644 --- a/core/matrix/permutation.cpp +++ b/core/matrix/permutation.cpp @@ -31,10 +31,48 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *************************************************************/ #include +#include "core/matrix/permutation_kernels.hpp" +#include "ginkgo/core/base/executor.hpp" namespace gko { namespace matrix { +namespace permutation { + + +GKO_REGISTER_OPERATION(invert, permutation::invert); + + +} + + +template +std::unique_ptr> Permutation::invert() const +{ + const auto exec = this->get_executor(); + const auto size = this->get_size()[0]; + array inv_permutation{exec, size}; + exec->run(permutation::make_invert(this->get_const_permutation(), size, + inv_permutation.get_data())); + return Permutation::create(exec, dim<2>{size, size}, + std::move(inv_permutation)); +} + + +template +void Permutation::write( + gko::matrix_data& data) const +{ + const auto host_this = + make_temporary_clone(this->get_executor()->get_master(), this); + data.size = this->get_size(); + data.nonzeros.clear(); + data.nonzeros.reserve(data.size[0]); + for (IndexType row = 0; row < this->get_size()[0]; row++) { + data.nonzeros.emplace_back(row, host_this->get_const_permutation()[row], + 1.0); + } +} #define GKO_DECLARE_PERMUTATION_MATRIX(_type) class Permutation<_type> diff --git a/core/matrix/permutation_kernels.hpp b/core/matrix/permutation_kernels.hpp new file mode 100644 index 00000000000..a77e0c2f618 --- /dev/null +++ b/core/matrix/permutation_kernels.hpp @@ -0,0 +1,82 @@ +/************************************************************* +Copyright (c) 2017-2023, the Ginkgo authors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*************************************************************/ + +#ifndef GKO_CORE_MATRIX_PERMUTATION_KERNELS_HPP_ +#define GKO_CORE_MATRIX_PERMUTATION_KERNELS_HPP_ + + +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "core/base/kernel_declaration.hpp" +#include "core/matrix/csr_lookup.hpp" + + +namespace gko { +namespace kernels { + + +#define GKO_DECLARE_PERMUTATION_INVERT_KERNEL(IndexType) \ + void invert(std::shared_ptr exec, \ + const IndexType* permutation_indices, size_type size, \ + IndexType* inv_permutation) + + +#define GKO_DECLARE_ALL_AS_TEMPLATES \ + template \ + GKO_DECLARE_PERMUTATION_INVERT_KERNEL(IndexType) + + +GKO_DECLARE_FOR_ALL_EXECUTOR_NAMESPACES(permutation, + GKO_DECLARE_ALL_AS_TEMPLATES); + + +#undef GKO_DECLARE_ALL_AS_TEMPLATES + + +} // namespace kernels +} // namespace gko + + +#endif // GKO_CORE_MATRIX_PERMUTATION_KERNELS_HPP_ diff --git a/core/matrix/scaled_permutation.cpp b/core/matrix/scaled_permutation.cpp new file mode 100644 index 00000000000..d1ce00b521a --- /dev/null +++ b/core/matrix/scaled_permutation.cpp @@ -0,0 +1,142 @@ +/************************************************************* +Copyright (c) 2017-2023, the Ginkgo authors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*************************************************************/ + +#include +#include "core/matrix/scaled_permutation_kernels.hpp" +#include "ginkgo/core/base/executor.hpp" +#include "ginkgo/core/base/precision_dispatch.hpp" + + +namespace gko { +namespace matrix { +namespace scaled_permutation { +namespace { + + +GKO_REGISTER_OPERATION(invert, scaled_permutation::invert); + + +} // namespace +} // namespace scaled_permutation + + +template +ScaledPermutation::ScaledPermutation( + std::shared_ptr exec, size_type size) + : ScaledPermutation{exec, array{exec, size}, + array{exec, size}} +{} + + +template +ScaledPermutation::ScaledPermutation( + std::shared_ptr exec, array scaling_factors, + array permutation_indices) + : EnableLinOp(exec, + dim<2>{scaling_factors.get_num_elems(), + scaling_factors.get_num_elems()}), + scale_{exec, std::move(scaling_factors)}, + permutation_{exec, std::move(permutation_indices)} +{ + GKO_ASSERT_EQ(scale_.get_num_elems(), permutation_.get_num_elems()); +} + + +template +std::unique_ptr> +ScaledPermutation::invert() const +{ + const auto exec = this->get_executor(); + const auto size = this->get_size()[0]; + array inv_permutation{exec, size}; + array inv_scale{exec, size}; + exec->run(scaled_permutation::make_invert( + this->get_const_permutation(), this->get_const_scale(), size, + inv_permutation.get_data(), inv_scale.get_data())); + return ScaledPermutation::create(exec, std::move(inv_scale), + std::move(inv_permutation)); +} + + +template +void ScaledPermutation::apply_impl(const LinOp* b, + LinOp* x) const +{ + precision_dispatch_real_complex( + [this](auto dense_b, auto dense_x) { + dense_b->scale_permute(this, dense_x, permute_mode::rows); + }, + b, x); +} + + +template +void ScaledPermutation::apply_impl(const LinOp* alpha, + const LinOp* b, + const LinOp* beta, + LinOp* x) const +{ + precision_dispatch_real_complex( + [this](auto dense_alpha, auto dense_b, auto dense_beta, auto dense_x) { + auto x_clone = dense_x->clone(); + dense_b->scale_permute(this, x_clone, permute_mode::rows); + dense_x->scale(dense_beta); + dense_x->add_scaled(dense_alpha, x_clone); + }, + alpha, b, beta, x); +} + + +template +void ScaledPermutation::write( + gko::matrix_data& data) const +{ + const auto host_this = + make_temporary_clone(this->get_executor()->get_master(), this); + data.size = this->get_size(); + data.nonzeros.clear(); + data.nonzeros.reserve(data.size[0]); + for (IndexType row = 0; row < this->get_size()[0]; row++) { + data.nonzeros.emplace_back(row, host_this->get_const_permutation()[row], + host_this->get_const_scale()[row]); + } +} + + +#define GKO_DECLARE_SCALED_PERMUTATION_MATRIX(ValueType, IndexType) \ + class ScaledPermutation +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_SCALED_PERMUTATION_MATRIX); + + +} // namespace matrix +} // namespace gko diff --git a/core/matrix/scaled_permutation_kernels.hpp b/core/matrix/scaled_permutation_kernels.hpp new file mode 100644 index 00000000000..905321ea885 --- /dev/null +++ b/core/matrix/scaled_permutation_kernels.hpp @@ -0,0 +1,68 @@ +/************************************************************* +Copyright (c) 2017-2023, the Ginkgo authors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*************************************************************/ + +#ifndef GKO_CORE_MATRIX_SCALED_PERMUTATION_KERNELS_HPP_ +#define GKO_CORE_MATRIX_SCALED_PERMUTATION_KERNELS_HPP_ + +#include + + +#include "core/base/kernel_declaration.hpp" + + +namespace gko { +namespace kernels { + + +#define GKO_DECLARE_SCALED_PERMUTATION_INVERT_KERNEL(ValueType, IndexType) \ + void invert(std::shared_ptr exec, \ + const IndexType* input_permutation, \ + const ValueType* input_scale, size_type size, \ + IndexType* output_permutation, ValueType* output_scale) + +#define GKO_DECLARE_ALL_AS_TEMPLATES \ + template \ + GKO_DECLARE_SCALED_PERMUTATION_INVERT_KERNEL(ValueType, IndexType) + + +GKO_DECLARE_FOR_ALL_EXECUTOR_NAMESPACES(scaled_permutation, + GKO_DECLARE_ALL_AS_TEMPLATES); + + +#undef GKO_DECLARE_ALL_AS_TEMPLATES + + +} // namespace kernels +} // namespace gko + + +#endif // GKO_CORE_MATRIX_SCALED_PERMUTATION_KERNELS_HPP_ diff --git a/core/test/matrix/permutation.cpp b/core/test/matrix/permutation.cpp index 09ef5e4701a..166ff0cbcdb 100644 --- a/core/test/matrix/permutation.cpp +++ b/core/test/matrix/permutation.cpp @@ -51,39 +51,40 @@ namespace { template class Permutation : public ::testing::Test { protected: - using v_type = + using value_type = typename std::tuple_element<0, decltype(ValueIndexType())>::type; - using i_type = + using index_type = typename std::tuple_element<1, decltype(ValueIndexType())>::type; - using Vec = gko::matrix::Dense; - using Csr = gko::matrix::Csr; + using Vec = gko::matrix::Dense; + using Csr = gko::matrix::Csr; Permutation() : exec(gko::ReferenceExecutor::create()), - mtx(gko::matrix::Permutation::create( - exec, gko::dim<2>{4, 3}, gko::array{exec, {1, 0, 2, 3}})) + mtx(gko::matrix::Permutation::create( + exec, gko::dim<2>{4, 3}, + gko::array{exec, {1, 0, 2, 3}})) {} static void assert_equal_to_original_mtx( - gko::ptr_param> m) + gko::ptr_param> m) { auto perm = m->get_permutation(); ASSERT_EQ(m->get_size(), gko::dim<2>(4, 3)); - ASSERT_EQ(m->get_permutation_size(), 4); + ASSERT_EQ(m->get_size()[0], 4); ASSERT_EQ(perm[0], 1); ASSERT_EQ(perm[1], 0); ASSERT_EQ(perm[2], 2); ASSERT_EQ(perm[3], 3); } - static void assert_empty(gko::matrix::Permutation* m) + static void assert_empty(gko::matrix::Permutation* m) { ASSERT_EQ(m->get_size(), gko::dim<2>(0, 0)); - ASSERT_EQ(m->get_permutation_size(), 0); + ASSERT_EQ(m->get_size()[0], 0); } std::shared_ptr exec; - std::unique_ptr> mtx; + std::unique_ptr> mtx; }; TYPED_TEST_SUITE(Permutation, gko::test::ValueIndexTypes, @@ -92,8 +93,8 @@ TYPED_TEST_SUITE(Permutation, gko::test::ValueIndexTypes, TYPED_TEST(Permutation, CanBeEmpty) { - using i_type = typename TestFixture::i_type; - auto empty = gko::matrix::Permutation::create(this->exec); + using index_type = typename TestFixture::index_type; + auto empty = gko::matrix::Permutation::create(this->exec); this->assert_empty(empty.get()); } @@ -101,8 +102,8 @@ TYPED_TEST(Permutation, CanBeEmpty) TYPED_TEST(Permutation, ReturnsNullValuesArrayWhenEmpty) { - using i_type = typename TestFixture::i_type; - auto empty = gko::matrix::Permutation::create(this->exec); + using index_type = typename TestFixture::index_type; + auto empty = gko::matrix::Permutation::create(this->exec); ASSERT_EQ(empty->get_const_permutation(), nullptr); } @@ -110,19 +111,19 @@ TYPED_TEST(Permutation, ReturnsNullValuesArrayWhenEmpty) TYPED_TEST(Permutation, CanBeConstructedWithSize) { - using i_type = typename TestFixture::i_type; - auto m = - gko::matrix::Permutation::create(this->exec, gko::dim<2>{2, 3}); + using index_type = typename TestFixture::index_type; + auto m = gko::matrix::Permutation::create(this->exec, + gko::dim<2>{2, 3}); ASSERT_EQ(m->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(m->get_permutation_size(), 2); + ASSERT_EQ(m->get_size()[0], 2); } TYPED_TEST(Permutation, FactorySetsCorrectPermuteMask) { - using i_type = typename TestFixture::i_type; - auto m = gko::matrix::Permutation::create(this->exec); + using index_type = typename TestFixture::index_type; + auto m = gko::matrix::Permutation::create(this->exec); auto mask = m->get_permute_mask(); ASSERT_EQ(mask, gko::matrix::row_permute); @@ -131,10 +132,10 @@ TYPED_TEST(Permutation, FactorySetsCorrectPermuteMask) TYPED_TEST(Permutation, PermutationCanBeConstructedFromExistingData) { - using i_type = typename TestFixture::i_type; - i_type data[] = {1, 0, 2}; + using index_type = typename TestFixture::index_type; + index_type data[] = {1, 0, 2}; - auto m = gko::matrix::Permutation::create( + auto m = gko::matrix::Permutation::create( this->exec, gko::dim<2>{3, 5}, gko::make_array_view(this->exec, 3, data)); @@ -144,12 +145,12 @@ TYPED_TEST(Permutation, PermutationCanBeConstructedFromExistingData) TYPED_TEST(Permutation, PermutationCanBeConstructedFromExistingConstData) { - using i_type = typename TestFixture::i_type; - using i_type = typename TestFixture::i_type; - const i_type data[] = {1, 0, 2}; + using index_type = typename TestFixture::index_type; + using index_type = typename TestFixture::index_type; + const index_type data[] = {1, 0, 2}; - auto m = gko::matrix::Permutation::create_const( - this->exec, 3, gko::array::const_view(this->exec, 3, data)); + auto m = gko::matrix::Permutation::create_const( + this->exec, 3, gko::array::const_view(this->exec, 3, data)); ASSERT_EQ(m->get_const_permutation(), data); } @@ -157,20 +158,20 @@ TYPED_TEST(Permutation, PermutationCanBeConstructedFromExistingConstData) TYPED_TEST(Permutation, CanBeConstructedWithSizeAndMask) { - using i_type = typename TestFixture::i_type; - auto m = gko::matrix::Permutation::create( + using index_type = typename TestFixture::index_type; + auto m = gko::matrix::Permutation::create( this->exec, gko::dim<2>{2, 3}, gko::matrix::column_permute); ASSERT_EQ(m->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(m->get_permutation_size(), 2); + ASSERT_EQ(m->get_size()[0], 2); ASSERT_EQ(m->get_permute_mask(), gko::matrix::column_permute); } TYPED_TEST(Permutation, CanExplicitlyOverrideSetPermuteMask) { - using i_type = typename TestFixture::i_type; - auto m = gko::matrix::Permutation::create( + using index_type = typename TestFixture::index_type; + auto m = gko::matrix::Permutation::create( this->exec, gko::dim<2>{2, 3}, gko::matrix::column_permute); auto mask = m->get_permute_mask(); @@ -186,10 +187,10 @@ TYPED_TEST(Permutation, CanExplicitlyOverrideSetPermuteMask) TYPED_TEST(Permutation, PermutationThrowsforWrongRowPermDimensions) { - using i_type = typename TestFixture::i_type; - i_type data[] = {0, 2, 1}; + using index_type = typename TestFixture::index_type; + index_type data[] = {0, 2, 1}; - ASSERT_THROW(gko::matrix::Permutation::create( + ASSERT_THROW(gko::matrix::Permutation::create( this->exec, gko::dim<2>{4, 2}, gko::make_array_view(this->exec, 3, data)), gko::ValueMismatch); @@ -198,10 +199,10 @@ TYPED_TEST(Permutation, PermutationThrowsforWrongRowPermDimensions) TYPED_TEST(Permutation, SettingMaskDoesNotModifyData) { - using i_type = typename TestFixture::i_type; - i_type data[] = {1, 0, 2}; + using index_type = typename TestFixture::index_type; + index_type data[] = {1, 0, 2}; - auto m = gko::matrix::Permutation::create( + auto m = gko::matrix::Permutation::create( this->exec, gko::dim<2>{3, 5}, gko::make_array_view(this->exec, 3, data)); @@ -220,10 +221,10 @@ TYPED_TEST(Permutation, SettingMaskDoesNotModifyData) TYPED_TEST(Permutation, PermutationThrowsforWrongColPermDimensions) { - using i_type = typename TestFixture::i_type; - i_type data[] = {0, 2, 1}; + using index_type = typename TestFixture::index_type; + index_type data[] = {0, 2, 1}; - ASSERT_THROW(gko::matrix::Permutation::create( + ASSERT_THROW(gko::matrix::Permutation::create( this->exec, gko::dim<2>{3, 4}, gko::make_array_view(this->exec, 3, data), gko::matrix::column_permute), @@ -239,8 +240,8 @@ TYPED_TEST(Permutation, KnowsItsSizeAndValues) TYPED_TEST(Permutation, CanBeCopied) { - using i_type = typename TestFixture::i_type; - auto mtx_copy = gko::matrix::Permutation::create(this->exec); + using index_type = typename TestFixture::index_type; + auto mtx_copy = gko::matrix::Permutation::create(this->exec); mtx_copy->copy_from(this->mtx); @@ -252,8 +253,8 @@ TYPED_TEST(Permutation, CanBeCopied) TYPED_TEST(Permutation, CanBeMoved) { - using i_type = typename TestFixture::i_type; - auto mtx_copy = gko::matrix::Permutation::create(this->exec); + using index_type = typename TestFixture::index_type; + auto mtx_copy = gko::matrix::Permutation::create(this->exec); mtx_copy->move_from(this->mtx); @@ -263,8 +264,8 @@ TYPED_TEST(Permutation, CanBeMoved) TYPED_TEST(Permutation, CopyingPreservesMask) { - using i_type = typename TestFixture::i_type; - auto mtx_copy = gko::matrix::Permutation::create(this->exec); + using index_type = typename TestFixture::index_type; + auto mtx_copy = gko::matrix::Permutation::create(this->exec); mtx_copy->copy_from(this->mtx); diff --git a/cuda/matrix/csr_kernels.instantiate.cu b/cuda/matrix/csr_kernels.instantiate.cu index 75747bf074b..335d42d2ff9 100644 --- a/cuda/matrix/csr_kernels.instantiate.cu +++ b/cuda/matrix/csr_kernels.instantiate.cu @@ -69,12 +69,22 @@ GKO_INSTANTIATE_FOR_EACH_INDEX_TYPE(GKO_DECLARE_CSR_BUILD_LOOKUP_KERNEL); GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE(GKO_DECLARE_CSR_SPGEAM_KERNEL); GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( GKO_DECLARE_CSR_FILL_IN_DENSE_KERNEL); +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_CSR_INV_NONSYMM_PERMUTE_KERNEL); GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( GKO_DECLARE_CSR_INV_SYMM_PERMUTE_KERNEL); GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( GKO_DECLARE_CSR_ROW_PERMUTE_KERNEL); GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( - GKO_DECLARE_CSR_INVERSE_ROW_PERMUTE_KERNEL); + GKO_DECLARE_CSR_INV_ROW_PERMUTE_KERNEL); +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_CSR_INV_NONSYMM_SCALE_PERMUTE_KERNEL); +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_CSR_INV_SYMM_SCALE_PERMUTE_KERNEL); +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_CSR_ROW_SCALE_PERMUTE_KERNEL); +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_CSR_INV_ROW_SCALE_PERMUTE_KERNEL); GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( GKO_DECLARE_CSR_CALC_NNZ_PER_ROW_IN_SPAN_KERNEL); GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( diff --git a/cuda/matrix/csr_kernels.template.cu b/cuda/matrix/csr_kernels.template.cu index 1b4b20a1e75..d5b577a6068 100644 --- a/cuda/matrix/csr_kernels.template.cu +++ b/cuda/matrix/csr_kernels.template.cu @@ -124,7 +124,7 @@ namespace { template void merge_path_spmv(syn::value_list, - std::shared_ptr exec, + std::shared_ptr exec, const matrix::Csr* a, const matrix::Dense* b, matrix::Dense* c, @@ -204,7 +204,7 @@ GKO_ENABLE_IMPLEMENTATION_SELECTION(select_merge_path_spmv, merge_path_spmv); template -int compute_items_per_thread(std::shared_ptr exec) +int compute_items_per_thread(std::shared_ptr exec) { const int version = (exec->get_major_version() << 4) + exec->get_minor_version(); @@ -245,7 +245,7 @@ int compute_items_per_thread(std::shared_ptr exec) template void classical_spmv(syn::value_list, - std::shared_ptr exec, + std::shared_ptr exec, const matrix::Csr* a, const matrix::Dense* b, matrix::Dense* c, @@ -298,7 +298,7 @@ GKO_ENABLE_IMPLEMENTATION_SELECTION(select_classical_spmv, classical_spmv); template -void load_balance_spmv(std::shared_ptr exec, +void load_balance_spmv(std::shared_ptr exec, const matrix::Csr* a, const matrix::Dense* b, matrix::Dense* c, @@ -349,7 +349,7 @@ void load_balance_spmv(std::shared_ptr exec, template -bool try_general_sparselib_spmv(std::shared_ptr exec, +bool try_general_sparselib_spmv(std::shared_ptr exec, const ValueType* alpha, const matrix::Csr* a, const matrix::Dense* b, @@ -441,7 +441,7 @@ template ::value || !std::is_same::value>> -bool try_sparselib_spmv(std::shared_ptr exec, +bool try_sparselib_spmv(std::shared_ptr exec, const matrix::Csr* a, const matrix::Dense* b, matrix::Dense* c, @@ -453,7 +453,7 @@ bool try_sparselib_spmv(std::shared_ptr exec, } template -bool try_sparselib_spmv(std::shared_ptr exec, +bool try_sparselib_spmv(std::shared_ptr exec, const matrix::Csr* a, const matrix::Dense* b, matrix::Dense* c, @@ -479,7 +479,7 @@ bool try_sparselib_spmv(std::shared_ptr exec, template -void spmv(std::shared_ptr exec, +void spmv(std::shared_ptr exec, const matrix::Csr* a, const matrix::Dense* b, matrix::Dense* c) @@ -536,7 +536,7 @@ void spmv(std::shared_ptr exec, template -void advanced_spmv(std::shared_ptr exec, +void advanced_spmv(std::shared_ptr exec, const matrix::Dense* alpha, const matrix::Csr* a, const matrix::Dense* b, @@ -597,7 +597,7 @@ void advanced_spmv(std::shared_ptr exec, template -void spgemm(std::shared_ptr exec, +void spgemm(std::shared_ptr exec, const matrix::Csr* a, const matrix::Csr* b, matrix::Csr* c) @@ -719,56 +719,8 @@ void spgemm(std::shared_ptr exec, } -namespace { - - -template -void spgeam(syn::value_list, - std::shared_ptr exec, const ValueType* alpha, - const IndexType* a_row_ptrs, const IndexType* a_col_idxs, - const ValueType* a_vals, const ValueType* beta, - const IndexType* b_row_ptrs, const IndexType* b_col_idxs, - const ValueType* b_vals, matrix::Csr* c) -{ - auto m = static_cast(c->get_size()[0]); - auto c_row_ptrs = c->get_row_ptrs(); - // count nnz for alpha * A + beta * B - auto subwarps_per_block = default_block_size / subwarp_size; - auto num_blocks = ceildiv(m, subwarps_per_block); - if (num_blocks > 0) { - kernel::spgeam_nnz - <<get_stream()>>>( - a_row_ptrs, a_col_idxs, b_row_ptrs, b_col_idxs, m, c_row_ptrs); - } - - // build row pointers - components::prefix_sum_nonnegative(exec, c_row_ptrs, m + 1); - - // accumulate non-zeros for alpha * A + beta * B - matrix::CsrBuilder c_builder{c}; - auto c_nnz = exec->copy_val_to_host(c_row_ptrs + m); - c_builder.get_col_idx_array().resize_and_reset(c_nnz); - c_builder.get_value_array().resize_and_reset(c_nnz); - auto c_col_idxs = c->get_col_idxs(); - auto c_vals = c->get_values(); - if (num_blocks > 0) { - kernel::spgeam - <<get_stream()>>>( - as_device_type(alpha), a_row_ptrs, a_col_idxs, - as_device_type(a_vals), as_device_type(beta), b_row_ptrs, - b_col_idxs, as_device_type(b_vals), m, c_row_ptrs, c_col_idxs, - as_device_type(c_vals)); - } -} - -GKO_ENABLE_IMPLEMENTATION_SELECTION(select_spgeam, spgeam); - - -} // namespace - - template -void advanced_spgemm(std::shared_ptr exec, +void advanced_spgemm(std::shared_ptr exec, const matrix::Dense* alpha, const matrix::Csr* a, const matrix::Csr* b, @@ -914,54 +866,7 @@ void advanced_spgemm(std::shared_ptr exec, template -void spgeam(std::shared_ptr exec, - const matrix::Dense* alpha, - const matrix::Csr* a, - const matrix::Dense* beta, - const matrix::Csr* b, - matrix::Csr* c) -{ - auto total_nnz = - a->get_num_stored_elements() + b->get_num_stored_elements(); - auto nnz_per_row = total_nnz / a->get_size()[0]; - select_spgeam( - spgeam_kernels(), - [&](int compiled_subwarp_size) { - return compiled_subwarp_size >= nnz_per_row || - compiled_subwarp_size == config::warp_size; - }, - syn::value_list(), syn::type_list<>(), exec, - alpha->get_const_values(), a->get_const_row_ptrs(), - a->get_const_col_idxs(), a->get_const_values(), - beta->get_const_values(), b->get_const_row_ptrs(), - b->get_const_col_idxs(), b->get_const_values(), c); -} - - -template -void fill_in_dense(std::shared_ptr exec, - const matrix::Csr* source, - matrix::Dense* result) -{ - const auto num_rows = result->get_size()[0]; - const auto num_cols = result->get_size()[1]; - const auto stride = result->get_stride(); - const auto row_ptrs = source->get_const_row_ptrs(); - const auto col_idxs = source->get_const_col_idxs(); - const auto vals = source->get_const_values(); - - auto grid_dim = ceildiv(num_rows, default_block_size); - if (grid_dim > 0) { - kernel::fill_in_dense<<get_stream()>>>( - num_rows, as_device_type(row_ptrs), as_device_type(col_idxs), - as_device_type(vals), stride, as_device_type(result->get_values())); - } -} - - -template -void transpose(std::shared_ptr exec, +void transpose(std::shared_ptr exec, const matrix::Csr* orig, matrix::Csr* trans) { @@ -1010,7 +915,7 @@ void transpose(std::shared_ptr exec, template -void conj_transpose(std::shared_ptr exec, +void conj_transpose(std::shared_ptr exec, const matrix::Csr* orig, matrix::Csr* trans) { @@ -1067,160 +972,7 @@ void conj_transpose(std::shared_ptr exec, template -void inv_symm_permute(std::shared_ptr exec, - const IndexType* perm, - const matrix::Csr* orig, - matrix::Csr* permuted) -{ - auto num_rows = orig->get_size()[0]; - auto count_num_blocks = ceildiv(num_rows, default_block_size); - if (count_num_blocks > 0) { - kernel::inv_row_ptr_permute<<get_stream()>>>( - num_rows, perm, orig->get_const_row_ptrs(), - permuted->get_row_ptrs()); - } - components::prefix_sum_nonnegative(exec, permuted->get_row_ptrs(), - num_rows + 1); - auto copy_num_blocks = - ceildiv(num_rows, default_block_size / config::warp_size); - if (copy_num_blocks > 0) { - kernel::inv_symm_permute - <<get_stream()>>>( - num_rows, perm, orig->get_const_row_ptrs(), - orig->get_const_col_idxs(), - as_device_type(orig->get_const_values()), - permuted->get_row_ptrs(), permuted->get_col_idxs(), - as_device_type(permuted->get_values())); - } -} - - -template -void row_permute(std::shared_ptr exec, - const IndexType* perm, - const matrix::Csr* orig, - matrix::Csr* row_permuted) -{ - auto num_rows = orig->get_size()[0]; - auto count_num_blocks = ceildiv(num_rows, default_block_size); - if (count_num_blocks > 0) { - kernel::row_ptr_permute<<get_stream()>>>( - num_rows, perm, orig->get_const_row_ptrs(), - row_permuted->get_row_ptrs()); - } - components::prefix_sum_nonnegative(exec, row_permuted->get_row_ptrs(), - num_rows + 1); - auto copy_num_blocks = - ceildiv(num_rows, default_block_size / config::warp_size); - if (copy_num_blocks > 0) { - kernel::row_permute - <<get_stream()>>>( - num_rows, perm, orig->get_const_row_ptrs(), - orig->get_const_col_idxs(), - as_device_type(orig->get_const_values()), - row_permuted->get_row_ptrs(), row_permuted->get_col_idxs(), - as_device_type(row_permuted->get_values())); - } -} - - -template -void inverse_row_permute(std::shared_ptr exec, - const IndexType* perm, - const matrix::Csr* orig, - matrix::Csr* row_permuted) -{ - auto num_rows = orig->get_size()[0]; - auto count_num_blocks = ceildiv(num_rows, default_block_size); - if (count_num_blocks > 0) { - kernel::inv_row_ptr_permute<<get_stream()>>>( - num_rows, perm, orig->get_const_row_ptrs(), - row_permuted->get_row_ptrs()); - } - components::prefix_sum_nonnegative(exec, row_permuted->get_row_ptrs(), - num_rows + 1); - auto copy_num_blocks = - ceildiv(num_rows, default_block_size / config::warp_size); - if (copy_num_blocks > 0) { - kernel::inv_row_permute - <<get_stream()>>>( - num_rows, perm, orig->get_const_row_ptrs(), - orig->get_const_col_idxs(), - as_device_type(orig->get_const_values()), - row_permuted->get_row_ptrs(), row_permuted->get_col_idxs(), - as_device_type(row_permuted->get_values())); - } -} - - -template -void calculate_nonzeros_per_row_in_span( - std::shared_ptr exec, - const matrix::Csr* source, const span& row_span, - const span& col_span, array* row_nnz) -{ - const auto num_rows = source->get_size()[0]; - auto row_ptrs = source->get_const_row_ptrs(); - auto col_idxs = source->get_const_col_idxs(); - auto grid_dim = ceildiv(row_span.length(), default_block_size); - if (grid_dim > 0) { - kernel::calculate_nnz_per_row_in_span<<get_stream()>>>( - row_span, col_span, as_device_type(row_ptrs), - as_device_type(col_idxs), as_device_type(row_nnz->get_data())); - } -} - - -template -void compute_submatrix(std::shared_ptr exec, - const matrix::Csr* source, - gko::span row_span, gko::span col_span, - matrix::Csr* result) -{ - auto row_offset = row_span.begin; - auto col_offset = col_span.begin; - auto num_rows = result->get_size()[0]; - auto num_cols = result->get_size()[1]; - auto row_ptrs = source->get_const_row_ptrs(); - auto grid_dim = ceildiv(num_rows, default_block_size); - if (grid_dim > 0) { - kernel::compute_submatrix_idxs_and_vals<<get_stream()>>>( - num_rows, num_cols, row_offset, col_offset, - as_device_type(source->get_const_row_ptrs()), - as_device_type(source->get_const_col_idxs()), - as_device_type(source->get_const_values()), - as_device_type(result->get_const_row_ptrs()), - as_device_type(result->get_col_idxs()), - as_device_type(result->get_values())); - } -} - - -template -void calculate_nonzeros_per_row_in_index_set( - std::shared_ptr exec, - const matrix::Csr* source, - const gko::index_set& row_index_set, - const gko::index_set& col_index_set, - IndexType* row_nnz) GKO_NOT_IMPLEMENTED; - - -template -void compute_submatrix_from_index_set( - std::shared_ptr exec, - const matrix::Csr* source, - const gko::index_set& row_index_set, - const gko::index_set& col_index_set, - matrix::Csr* result) GKO_NOT_IMPLEMENTED; - - -template -void sort_by_column_index(std::shared_ptr exec, +void sort_by_column_index(std::shared_ptr exec, matrix::Csr* to_sort) { if (cusparse::is_supported::value) { @@ -1271,96 +1023,6 @@ void sort_by_column_index(std::shared_ptr exec, } -template -void is_sorted_by_column_index( - std::shared_ptr exec, - const matrix::Csr* to_check, bool* is_sorted) -{ - *is_sorted = true; - auto cpu_array = make_array_view(exec->get_master(), 1, is_sorted); - auto gpu_array = array{exec, cpu_array}; - auto block_size = default_block_size; - auto num_rows = static_cast(to_check->get_size()[0]); - auto num_blocks = ceildiv(num_rows, block_size); - if (num_blocks > 0) { - kernel:: - check_unsorted<<get_stream()>>>( - to_check->get_const_row_ptrs(), to_check->get_const_col_idxs(), - num_rows, gpu_array.get_data()); - } - cpu_array = gpu_array; -} - - -template -void extract_diagonal(std::shared_ptr exec, - const matrix::Csr* orig, - matrix::Diagonal* diag) -{ - const auto nnz = orig->get_num_stored_elements(); - const auto diag_size = diag->get_size()[0]; - const auto num_blocks = - ceildiv(config::warp_size * diag_size, default_block_size); - - const auto orig_values = orig->get_const_values(); - const auto orig_row_ptrs = orig->get_const_row_ptrs(); - const auto orig_col_idxs = orig->get_const_col_idxs(); - auto diag_values = diag->get_values(); - - if (num_blocks > 0) { - kernel::extract_diagonal<<get_stream()>>>( - diag_size, nnz, as_device_type(orig_values), - as_device_type(orig_row_ptrs), as_device_type(orig_col_idxs), - as_device_type(diag_values)); - } -} - - -template -void check_diagonal_entries_exist( - std::shared_ptr exec, - const matrix::Csr* const mtx, bool& has_all_diags) -{ - const size_type num_warps = mtx->get_size()[0]; - if (num_warps > 0) { - const size_type num_blocks = - num_warps / (default_block_size / config::warp_size); - array has_diags(exec, {true}); - kernel::check_diagonal_entries<<get_stream()>>>( - static_cast( - std::min(mtx->get_size()[0], mtx->get_size()[1])), - mtx->get_const_row_ptrs(), mtx->get_const_col_idxs(), - has_diags.get_data()); - has_all_diags = exec->copy_val_to_host(has_diags.get_const_data()); - } else { - has_all_diags = true; - } -} - - -template -void add_scaled_identity(std::shared_ptr exec, - const matrix::Dense* const alpha, - const matrix::Dense* const beta, - matrix::Csr* const mtx) -{ - const auto nrows = mtx->get_size()[0]; - if (nrows == 0) { - return; - } - const auto nthreads = nrows * config::warp_size; - const auto nblocks = ceildiv(nthreads, default_block_size); - kernel::add_scaled_identity<<get_stream()>>>( - as_device_type(alpha->get_const_values()), - as_device_type(beta->get_const_values()), static_cast(nrows), - mtx->get_const_row_ptrs(), mtx->get_const_col_idxs(), - as_device_type(mtx->get_values())); -} - - } // namespace csr } // namespace cuda } // namespace kernels diff --git a/dpcpp/matrix/csr_kernels.dp.cpp b/dpcpp/matrix/csr_kernels.dp.cpp index 11309b67b9b..5fa628612cf 100644 --- a/dpcpp/matrix/csr_kernels.dp.cpp +++ b/dpcpp/matrix/csr_kernels.dp.cpp @@ -1032,6 +1032,35 @@ void inv_symm_permute_kernel(size_type num_rows, } } + +template +void inv_nonsymm_permute_kernel(size_type num_rows, + const IndexType* __restrict__ row_permutation, + const IndexType* __restrict__ col_permutation, + const IndexType* __restrict__ in_row_ptrs, + const IndexType* __restrict__ in_cols, + const ValueType* __restrict__ in_vals, + const IndexType* __restrict__ out_row_ptrs, + IndexType* __restrict__ out_cols, + ValueType* __restrict__ out_vals, + sycl::nd_item<3> item_ct1) +{ + auto tid = thread::get_subwarp_id_flat(item_ct1); + if (tid >= num_rows) { + return; + } + auto lane = item_ct1.get_local_id(2) % subgroup_size; + auto in_row = tid; + auto out_row = row_permutation[tid]; + auto in_begin = in_row_ptrs[in_row]; + auto in_size = in_row_ptrs[in_row + 1] - in_begin; + auto out_begin = out_row_ptrs[out_row]; + for (IndexType i = lane; i < in_size; i += subgroup_size) { + out_cols[out_begin + i] = col_permutation[in_cols[in_begin + i]]; + out_vals[out_begin + i] = in_vals[in_begin + i]; + } +} + template void inv_symm_permute_kernel(dim3 grid, dim3 block, size_type dynamic_shared_memory, @@ -1052,6 +1081,25 @@ void inv_symm_permute_kernel(dim3 grid, dim3 block, }); } +template +void inv_nonsymm_permute_kernel( + dim3 grid, dim3 block, size_type dynamic_shared_memory, sycl::queue* queue, + size_type num_rows, const IndexType* row_permutation, + const IndexType* col_permutation, const IndexType* in_row_ptrs, + const IndexType* in_cols, const ValueType* in_vals, + const IndexType* out_row_ptrs, IndexType* out_cols, ValueType* out_vals) +{ + queue->submit([&](sycl::handler& cgh) { + cgh.parallel_for(sycl_nd_range(grid, block), + [=](sycl::nd_item<3> item_ct1) { + inv_nonsymm_permute_kernel( + num_rows, row_permutation, col_permutation, + in_row_ptrs, in_cols, in_vals, out_row_ptrs, + out_cols, out_vals, item_ct1); + }); + }); +} + namespace host_kernel { @@ -2196,6 +2244,33 @@ GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( GKO_DECLARE_CSR_INV_SYMM_PERMUTE_KERNEL); +template +void inv_nonsymm_permute(std::shared_ptr exec, + const IndexType* row_perm, const IndexType* col_perm, + const matrix::Csr* orig, + matrix::Csr* permuted) +{ + auto num_rows = orig->get_size()[0]; + auto count_num_blocks = ceildiv(num_rows, default_block_size); + inv_row_ptr_permute_kernel( + count_num_blocks, default_block_size, 0, exec->get_queue(), num_rows, + row_perm, orig->get_const_row_ptrs(), permuted->get_row_ptrs()); + components::prefix_sum_nonnegative(exec, permuted->get_row_ptrs(), + num_rows + 1); + auto copy_num_blocks = + ceildiv(num_rows, default_block_size / config::warp_size); + inv_symm_permute_kernel( + copy_num_blocks, default_block_size, 0, exec->get_queue(), num_rows, + row_perm, col_perm, orig->get_const_row_ptrs(), + orig->get_const_col_idxs(), orig->get_const_values(), + permuted->get_row_ptrs(), permuted->get_col_idxs(), + permuted->get_values()); +} + +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_CSR_INV_NONSYMM_PERMUTE_KERNEL); + + template void row_permute(std::shared_ptr exec, const IndexType* perm, @@ -2223,10 +2298,10 @@ GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( template -void inverse_row_permute(std::shared_ptr exec, - const IndexType* perm, - const matrix::Csr* orig, - matrix::Csr* row_permuted) +void inv_row_permute(std::shared_ptr exec, + const IndexType* perm, + const matrix::Csr* orig, + matrix::Csr* row_permuted) { auto num_rows = orig->get_size()[0]; auto count_num_blocks = ceildiv(num_rows, default_block_size); @@ -2245,7 +2320,7 @@ void inverse_row_permute(std::shared_ptr exec, } GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( - GKO_DECLARE_CSR_INVERSE_ROW_PERMUTE_KERNEL); + GKO_DECLARE_CSR_INV_ROW_PERMUTE_KERNEL); template diff --git a/examples/distributed-solver/distributed-solver.cpp b/examples/distributed-solver/distributed-solver.cpp index 123f93775f5..cd07b8a3c4e 100644 --- a/examples/distributed-solver/distributed-solver.cpp +++ b/examples/distributed-solver/distributed-solver.cpp @@ -119,15 +119,14 @@ int main(int argc, char* argv[]) int device_id = gko::experimental::mpi::map_rank_to_device_id( comm, gko::CudaExecutor::get_num_devices()); return gko::CudaExecutor::create( - device_id, gko::ReferenceExecutor::create(), false, - gko::allocation_mode::device); + device_id, gko::ReferenceExecutor::create()); }}, {"hip", [](MPI_Comm comm) { int device_id = gko::experimental::mpi::map_rank_to_device_id( comm, gko::HipExecutor::get_num_devices()); return gko::HipExecutor::create( - device_id, gko::ReferenceExecutor::create(), true); + device_id, gko::ReferenceExecutor::create()); }}, {"dpcpp", [](MPI_Comm comm) { int device_id = 0; diff --git a/hip/matrix/csr_kernels.instantiate.hip.cpp b/hip/matrix/csr_kernels.instantiate.hip.cpp index 9a6c29206de..156b170311f 100644 --- a/hip/matrix/csr_kernels.instantiate.hip.cpp +++ b/hip/matrix/csr_kernels.instantiate.hip.cpp @@ -117,12 +117,22 @@ GKO_INSTANTIATE_FOR_EACH_INDEX_TYPE(GKO_DECLARE_CSR_BUILD_LOOKUP_KERNEL); GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE(GKO_DECLARE_CSR_SPGEAM_KERNEL); GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( GKO_DECLARE_CSR_FILL_IN_DENSE_KERNEL); +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_CSR_INV_NONSYMM_PERMUTE_KERNEL); GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( GKO_DECLARE_CSR_INV_SYMM_PERMUTE_KERNEL); GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( GKO_DECLARE_CSR_ROW_PERMUTE_KERNEL); GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( - GKO_DECLARE_CSR_INVERSE_ROW_PERMUTE_KERNEL); + GKO_DECLARE_CSR_INV_ROW_PERMUTE_KERNEL); +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_CSR_INV_NONSYMM_SCALE_PERMUTE_KERNEL); +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_CSR_INV_SYMM_SCALE_PERMUTE_KERNEL); +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_CSR_ROW_SCALE_PERMUTE_KERNEL); +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_CSR_INV_ROW_SCALE_PERMUTE_KERNEL); GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( GKO_DECLARE_CSR_CALC_NNZ_PER_ROW_IN_SPAN_KERNEL); GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( diff --git a/hip/matrix/csr_kernels.template.hip.cpp b/hip/matrix/csr_kernels.template.hip.cpp index e6a4fb64041..52101385c92 100644 --- a/hip/matrix/csr_kernels.template.hip.cpp +++ b/hip/matrix/csr_kernels.template.hip.cpp @@ -629,54 +629,6 @@ void spgemm(std::shared_ptr exec, } -namespace { - - -template -void spgeam(syn::value_list, - std::shared_ptr exec, const ValueType* alpha, - const IndexType* a_row_ptrs, const IndexType* a_col_idxs, - const ValueType* a_vals, const ValueType* beta, - const IndexType* b_row_ptrs, const IndexType* b_col_idxs, - const ValueType* b_vals, matrix::Csr* c) -{ - auto m = static_cast(c->get_size()[0]); - auto c_row_ptrs = c->get_row_ptrs(); - // count nnz for alpha * A + beta * B - auto subwarps_per_block = default_block_size / subwarp_size; - auto num_blocks = ceildiv(m, subwarps_per_block); - if (num_blocks > 0) { - kernel::spgeam_nnz - <<get_stream()>>>( - a_row_ptrs, a_col_idxs, b_row_ptrs, b_col_idxs, m, c_row_ptrs); - } - - // build row pointers - components::prefix_sum_nonnegative(exec, c_row_ptrs, m + 1); - - // accumulate non-zeros for alpha * A + beta * B - matrix::CsrBuilder c_builder{c}; - auto c_nnz = exec->copy_val_to_host(c_row_ptrs + m); - c_builder.get_col_idx_array().resize_and_reset(c_nnz); - c_builder.get_value_array().resize_and_reset(c_nnz); - auto c_col_idxs = c->get_col_idxs(); - auto c_vals = c->get_values(); - if (num_blocks > 0) { - kernel::spgeam - <<get_stream()>>>( - as_device_type(alpha), a_row_ptrs, a_col_idxs, - as_device_type(a_vals), as_device_type(beta), b_row_ptrs, - b_col_idxs, as_device_type(b_vals), m, c_row_ptrs, c_col_idxs, - as_device_type(c_vals)); - } -} - -GKO_ENABLE_IMPLEMENTATION_SELECTION(select_spgeam, spgeam); - - -} // namespace - - template void advanced_spgemm(std::shared_ptr exec, const matrix::Dense* alpha, @@ -768,53 +720,6 @@ void advanced_spgemm(std::shared_ptr exec, } -template -void spgeam(std::shared_ptr exec, - const matrix::Dense* alpha, - const matrix::Csr* a, - const matrix::Dense* beta, - const matrix::Csr* b, - matrix::Csr* c) -{ - auto total_nnz = - a->get_num_stored_elements() + b->get_num_stored_elements(); - auto nnz_per_row = total_nnz / a->get_size()[0]; - select_spgeam( - spgeam_kernels(), - [&](int compiled_subwarp_size) { - return compiled_subwarp_size >= nnz_per_row || - compiled_subwarp_size == config::warp_size; - }, - syn::value_list(), syn::type_list<>(), exec, - alpha->get_const_values(), a->get_const_row_ptrs(), - a->get_const_col_idxs(), a->get_const_values(), - beta->get_const_values(), b->get_const_row_ptrs(), - b->get_const_col_idxs(), b->get_const_values(), c); -} - - -template -void fill_in_dense(std::shared_ptr exec, - const matrix::Csr* source, - matrix::Dense* result) -{ - const auto num_rows = result->get_size()[0]; - const auto num_cols = result->get_size()[1]; - const auto stride = result->get_stride(); - const auto row_ptrs = source->get_const_row_ptrs(); - const auto col_idxs = source->get_const_col_idxs(); - const auto vals = source->get_const_values(); - - auto grid_dim = ceildiv(num_rows, default_block_size); - if (grid_dim > 0) { - kernel::fill_in_dense<<get_stream()>>>( - num_rows, as_device_type(row_ptrs), as_device_type(col_idxs), - as_device_type(vals), stride, as_device_type(result->get_values())); - } -} - - template void transpose(std::shared_ptr exec, const matrix::Csr* orig, @@ -871,159 +776,6 @@ void conj_transpose(std::shared_ptr exec, } -template -void inv_symm_permute(std::shared_ptr exec, - const IndexType* perm, - const matrix::Csr* orig, - matrix::Csr* permuted) -{ - auto num_rows = orig->get_size()[0]; - auto count_num_blocks = ceildiv(num_rows, default_block_size); - if (count_num_blocks > 0) { - kernel::inv_row_ptr_permute<<get_stream()>>>( - num_rows, perm, orig->get_const_row_ptrs(), - permuted->get_row_ptrs()); - } - components::prefix_sum_nonnegative(exec, permuted->get_row_ptrs(), - num_rows + 1); - auto copy_num_blocks = - ceildiv(num_rows, default_block_size / config::warp_size); - if (copy_num_blocks > 0) { - kernel::inv_symm_permute - <<get_stream()>>>( - num_rows, perm, orig->get_const_row_ptrs(), - orig->get_const_col_idxs(), - as_device_type(orig->get_const_values()), - permuted->get_row_ptrs(), permuted->get_col_idxs(), - as_device_type(permuted->get_values())); - } -} - - -template -void row_permute(std::shared_ptr exec, const IndexType* perm, - const matrix::Csr* orig, - matrix::Csr* row_permuted) -{ - auto num_rows = orig->get_size()[0]; - auto count_num_blocks = ceildiv(num_rows, default_block_size); - if (count_num_blocks > 0) { - kernel::row_ptr_permute<<get_stream()>>>( - num_rows, perm, orig->get_const_row_ptrs(), - row_permuted->get_row_ptrs()); - } - components::prefix_sum_nonnegative(exec, row_permuted->get_row_ptrs(), - num_rows + 1); - auto copy_num_blocks = - ceildiv(num_rows, default_block_size / config::warp_size); - if (copy_num_blocks > 0) { - kernel::row_permute - <<get_stream()>>>( - num_rows, perm, orig->get_const_row_ptrs(), - orig->get_const_col_idxs(), - as_device_type(orig->get_const_values()), - row_permuted->get_row_ptrs(), row_permuted->get_col_idxs(), - as_device_type(row_permuted->get_values())); - } -} - - -template -void inverse_row_permute(std::shared_ptr exec, - const IndexType* perm, - const matrix::Csr* orig, - matrix::Csr* row_permuted) -{ - auto num_rows = orig->get_size()[0]; - auto count_num_blocks = ceildiv(num_rows, default_block_size); - if (count_num_blocks > 0) { - kernel::inv_row_ptr_permute<<get_stream()>>>( - num_rows, perm, orig->get_const_row_ptrs(), - row_permuted->get_row_ptrs()); - } - components::prefix_sum_nonnegative(exec, row_permuted->get_row_ptrs(), - num_rows + 1); - auto copy_num_blocks = - ceildiv(num_rows, default_block_size / config::warp_size); - if (copy_num_blocks > 0) { - kernel::inv_row_permute - <<get_stream()>>>( - num_rows, perm, orig->get_const_row_ptrs(), - orig->get_const_col_idxs(), - as_device_type(orig->get_const_values()), - row_permuted->get_row_ptrs(), row_permuted->get_col_idxs(), - as_device_type(row_permuted->get_values())); - } -} - - -template -void calculate_nonzeros_per_row_in_span( - std::shared_ptr exec, - const matrix::Csr* source, const span& row_span, - const span& col_span, array* row_nnz) -{ - const auto num_rows = source->get_size()[0]; - auto row_ptrs = source->get_const_row_ptrs(); - auto col_idxs = source->get_const_col_idxs(); - auto grid_dim = ceildiv(row_span.length(), default_block_size); - - if (grid_dim > 0) { - kernel::calculate_nnz_per_row_in_span<<get_stream()>>>( - row_span, col_span, as_device_type(row_ptrs), - as_device_type(col_idxs), as_device_type(row_nnz->get_data())); - } -} - - -template -void compute_submatrix(std::shared_ptr exec, - const matrix::Csr* source, - gko::span row_span, gko::span col_span, - matrix::Csr* result) -{ - auto row_offset = row_span.begin; - auto col_offset = col_span.begin; - auto num_rows = result->get_size()[0]; - auto num_cols = result->get_size()[1]; - auto row_ptrs = source->get_const_row_ptrs(); - auto grid_dim = ceildiv(num_rows, default_block_size); - if (grid_dim > 0) { - kernel::compute_submatrix_idxs_and_vals<<get_stream()>>>( - num_rows, num_cols, row_offset, col_offset, - as_device_type(source->get_const_row_ptrs()), - as_device_type(source->get_const_col_idxs()), - as_device_type(source->get_const_values()), - as_device_type(result->get_const_row_ptrs()), - as_device_type(result->get_col_idxs()), - as_device_type(result->get_values())); - } -} - - -template -void calculate_nonzeros_per_row_in_index_set( - std::shared_ptr exec, - const matrix::Csr* source, - const gko::index_set& row_index_set, - const gko::index_set& col_index_set, - IndexType* row_nnz) GKO_NOT_IMPLEMENTED; - - -template -void compute_submatrix_from_index_set( - std::shared_ptr exec, - const matrix::Csr* source, - const gko::index_set& row_index_set, - const gko::index_set& col_index_set, - matrix::Csr* result) GKO_NOT_IMPLEMENTED; - - template void sort_by_column_index(std::shared_ptr exec, matrix::Csr* to_sort) @@ -1069,95 +821,6 @@ void sort_by_column_index(std::shared_ptr exec, } -template -void is_sorted_by_column_index( - std::shared_ptr exec, - const matrix::Csr* to_check, bool* is_sorted) -{ - *is_sorted = true; - auto cpu_array = make_array_view(exec->get_master(), 1, is_sorted); - auto gpu_array = array{exec, cpu_array}; - auto block_size = default_block_size; - auto num_rows = static_cast(to_check->get_size()[0]); - auto num_blocks = ceildiv(num_rows, block_size); - if (num_blocks > 0) { - kernel:: - check_unsorted<<get_stream()>>>( - to_check->get_const_row_ptrs(), to_check->get_const_col_idxs(), - num_rows, gpu_array.get_data()); - } - cpu_array = gpu_array; -} - - -template -void extract_diagonal(std::shared_ptr exec, - const matrix::Csr* orig, - matrix::Diagonal* diag) -{ - const auto nnz = orig->get_num_stored_elements(); - const auto diag_size = diag->get_size()[0]; - const auto num_blocks = - ceildiv(config::warp_size * diag_size, default_block_size); - - const auto orig_values = orig->get_const_values(); - const auto orig_row_ptrs = orig->get_const_row_ptrs(); - const auto orig_col_idxs = orig->get_const_col_idxs(); - auto diag_values = diag->get_values(); - if (num_blocks > 0) { - kernel::extract_diagonal<<get_stream()>>>( - diag_size, nnz, as_device_type(orig_values), - as_device_type(orig_row_ptrs), as_device_type(orig_col_idxs), - as_device_type(diag_values)); - } -} - - -template -void check_diagonal_entries_exist( - std::shared_ptr exec, - const matrix::Csr* const mtx, bool& has_all_diags) -{ - const size_type num_warps = mtx->get_size()[0]; - if (num_warps > 0) { - const size_type num_blocks = - num_warps / (default_block_size / config::warp_size); - array has_diags(exec, {true}); - kernel::check_diagonal_entries<<get_stream()>>>( - static_cast( - std::min(mtx->get_size()[0], mtx->get_size()[1])), - mtx->get_const_row_ptrs(), mtx->get_const_col_idxs(), - has_diags.get_data()); - has_all_diags = exec->copy_val_to_host(has_diags.get_const_data()); - } else { - has_all_diags = true; - } -} - - -template -void add_scaled_identity(std::shared_ptr exec, - const matrix::Dense* const alpha, - const matrix::Dense* const beta, - matrix::Csr* const mtx) -{ - const auto nrows = mtx->get_size()[0]; - if (nrows == 0) { - return; - } - const auto nthreads = nrows * config::warp_size; - const auto nblocks = ceildiv(nthreads, default_block_size); - kernel::add_scaled_identity<<get_stream()>>>( - as_device_type(alpha->get_const_values()), - as_device_type(beta->get_const_values()), static_cast(nrows), - mtx->get_const_row_ptrs(), mtx->get_const_col_idxs(), - as_device_type(mtx->get_values())); -} - - } // namespace csr } // namespace hip } // namespace kernels diff --git a/include/ginkgo/core/base/exception.hpp b/include/ginkgo/core/base/exception.hpp index 8b270ed7a98..1a52b93c0bd 100644 --- a/include/ginkgo/core/base/exception.hpp +++ b/include/ginkgo/core/base/exception.hpp @@ -683,6 +683,7 @@ class UnsupportedMatrixProperty : public Error { }; +/** Exception thrown if an object is in an invalid state. */ class InvalidStateError : public Error { public: /** @@ -701,6 +702,25 @@ class InvalidStateError : public Error { }; +/** Exception thrown if an invalid valid was passed to a function. */ +class InvalidValueError : public Error { +public: + /** + * Initializes an invalid value error. + * + * @param file The name of the offending source file + * @param line The source code line number where the error occurred + * @param func The function name where the error occurred + * @param clarification A message describing the invalid value + */ + InvalidValueError(const std::string& file, int line, + const std::string& func, const std::string& clarification) + : Error(file, line, + func + ": Invalid value encountered : " + clarification) + {} +}; + + } // namespace gko diff --git a/include/ginkgo/core/matrix/csr.hpp b/include/ginkgo/core/matrix/csr.hpp index 834208c4322..b73459c1175 100644 --- a/include/ginkgo/core/matrix/csr.hpp +++ b/include/ginkgo/core/matrix/csr.hpp @@ -38,6 +38,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include namespace gko { @@ -59,9 +60,6 @@ class Ell; template class Hybrid; -template -class Permutation; - template class ScaledPermutation; diff --git a/include/ginkgo/core/matrix/dense.hpp b/include/ginkgo/core/matrix/dense.hpp index 4af7bac9432..3d54b780bb8 100644 --- a/include/ginkgo/core/matrix/dense.hpp +++ b/include/ginkgo/core/matrix/dense.hpp @@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include namespace gko { @@ -81,9 +82,6 @@ class Fbcsr; template class Hybrid; -template -class Permutation; - template class ScaledPermutation; @@ -492,7 +490,7 @@ class Dense */ void permute(ptr_param> row_permutation, ptr_param> column_permutation, - ptr_param output, bool invert) const; + ptr_param output, bool invert = false) const; /** * @copydoc permute(ptr_param>, ptr_param> row_permutation, ptr_param> column_permutation, - ptr_param output, bool invert) const; + ptr_param output, bool invert = false) const; /** * Creates a scaled and permuted copy of this matrix. @@ -537,7 +535,7 @@ class Dense * @copydoc scale_permute(ptr_param>, ptr_param, permute_mode) */ - std::unique_ptr scale_permute( + void scale_permute( ptr_param> permutation, ptr_param output, permute_mode mode) const; @@ -575,22 +573,22 @@ class Dense * that writes the permuted copy into an existing Dense matrix. * @param output the output matrix. */ - std::unique_ptr scale_permute( + void scale_permute( ptr_param> row_permutation, ptr_param> column_permutation, - ptr_param output, bool invert) const; + ptr_param output, bool invert = false) const; /** * @copydoc scale_permute(ptr_param>, ptr_param>, * ptr_param, bool) */ - std::unique_ptr scale_permute( + void scale_permute( ptr_param> row_permutation, ptr_param> column_permutation, - ptr_param output, bool invert) const; + ptr_param output, bool invert = false) const; std::unique_ptr permute( const array* permutation_indices) const override; @@ -1443,19 +1441,24 @@ class Dense } template - void permute_impl(const array* permutation, Dense* output) const; + void permute_impl(const Permutation* permutation, + permute_mode mode, Dense* output) const; template - void inverse_permute_impl(const array* permutation, - Dense* output) const; + void permute_impl(const Permutation* row_permutation, + const Permutation* col_permutation, + bool invert, Dense* output) const; template - void row_permute_impl(const array* permutation, - Dense* output) const; + void scale_permute_impl( + const ScaledPermutation* permutation, + permute_mode mode, Dense* output) const; template - void inverse_row_permute_impl(const array* permutation, - Dense* output) const; + void scale_permute_impl( + const ScaledPermutation* row_permutation, + const ScaledPermutation* column_permutation, + bool invert, Dense* output) const; template void row_gather_impl(const array* row_idxs, @@ -1467,14 +1470,6 @@ class Dense const Dense* beta, Dense* row_collection) const; - template - void column_permute_impl(const array* permutation, - Dense* output) const; - - template - void inverse_column_permute_impl(const array* permutation, - Dense* output) const; - private: array values_; size_type stride_; diff --git a/include/ginkgo/core/matrix/permutation.hpp b/include/ginkgo/core/matrix/permutation.hpp index 163160a2af6..b577481345b 100644 --- a/include/ginkgo/core/matrix/permutation.hpp +++ b/include/ginkgo/core/matrix/permutation.hpp @@ -52,6 +52,78 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace gko { namespace matrix { + +/** Specifies how a permutation will be applied to a matrix. */ +enum class permute_mode { + /** Neither rows nor columns will be permuted. */ + none = 0b0, + /** The rows will be permuted. */ + rows = 0b1, + /** The columns will be permuted. */ + columns = 0b10, + /** + * The rows and columns will be permuted. This is equivalent to + * `permute_mode::rows | permute_mode::columns`. + */ + symmetric = 0b11, + /** The permutation will be inverted before being applied. */ + inverse = 0b100, + /** + * The rows will be permuted using the inverse permutation. This is + * equivalent to `permute_mode::rows | permute_mode::inverse`. + */ + inverse_rows = 0b101, + /** + * The columns will be permuted using the inverse permutation. This is + * equivalent to `permute_mode::columns | permute_mode::inverse`. + */ + inverse_columns = 0b110, + /** + * The rows and columns will be permuted using the inverse permutation. This + * is equivalent to `permute_mode::symmetric | permute_mode::inverse`. + */ + inverse_symmetric = 0b111 +}; + + +/** Combines two permutation modes. */ +inline permute_mode operator|(permute_mode a, permute_mode b) +{ + return static_cast(static_cast(a) | static_cast(b)); +} + + +/** Computes the intersection of two permutation modes. */ +inline permute_mode operator&(permute_mode a, permute_mode b) +{ + return static_cast(static_cast(a) & static_cast(b)); +} + + +inline std::ostream& operator<<(std::ostream& stream, permute_mode mode) +{ + switch (mode) { + case permute_mode::none: + return stream << "none"; + case permute_mode::rows: + return stream << "rows"; + case permute_mode::columns: + return stream << "columns"; + case permute_mode::symmetric: + return stream << "symmetric"; + case permute_mode::inverse: + return stream << "inverse"; + case permute_mode::inverse_rows: + return stream << "inverse_rows"; + case permute_mode::inverse_columns: + return stream << "inverse_columns"; + case permute_mode::inverse_symmetric: + return stream << "inverse_symmetric"; + } + return stream; +} + + /** @internal std::bitset allows to store any number of bits */ using mask_type = gko::uint64; @@ -77,11 +149,14 @@ static constexpr mask_type inverse_permute = mask_type{1 << 3}; */ template class Permutation : public EnableLinOp>, - public EnableCreateMethod> { + public EnableCreateMethod>, + public WritableToMatrixData { friend class EnableCreateMethod; friend class EnablePolymorphicObject; public: + // value_type is only available to enable the usage of gko::write + using value_type = default_precision; using index_type = IndexType; /** @@ -110,7 +185,8 @@ class Permutation : public EnableLinOp>, * @return the number of elements explicitly stored in the permutation * array. */ - size_type get_permutation_size() const noexcept + [[deprecated("use get_size()[0] instead")]] size_type get_permutation_size() + const noexcept { return permutation_.get_num_elems(); } @@ -132,6 +208,16 @@ class Permutation : public EnableLinOp>, enabled_permute_ = permute_mask; } + /** + * Returns the inverse permutation. + * + * @return a newly created Permutation object storing the inverse + * permutation of this Permutation. + */ + std::unique_ptr invert() const; + + void write(gko::matrix_data& data) const override; + /** * Creates a constant (immutable) Permutation matrix from a constant array. * @@ -214,7 +300,7 @@ class Permutation : public EnableLinOp>, } } - void apply_impl(const LinOp* in, LinOp* out) const + void apply_impl(const LinOp* in, LinOp* out) const override { auto perm = as>(in); std::unique_ptr tmp{}; @@ -248,7 +334,7 @@ class Permutation : public EnableLinOp>, void apply_impl(const LinOp*, const LinOp* in, const LinOp*, - LinOp* out) const + LinOp* out) const override { // Ignores alpha and beta and just performs a normal permutation as an // advanced apply does not really make sense here. diff --git a/include/ginkgo/core/matrix/scaled_permutation.hpp b/include/ginkgo/core/matrix/scaled_permutation.hpp new file mode 100644 index 00000000000..0a5a2d781e7 --- /dev/null +++ b/include/ginkgo/core/matrix/scaled_permutation.hpp @@ -0,0 +1,177 @@ +/************************************************************* +Copyright (c) 2017-2023, the Ginkgo authors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*************************************************************/ + +#ifndef GKO_PUBLIC_CORE_MATRIX_SCALED_PERMUTATION_HPP_ +#define GKO_PUBLIC_CORE_MATRIX_SCALED_PERMUTATION_HPP_ + + +#include + + +#include +#include +#include +#include +#include + + +namespace gko { +namespace matrix { + + +/** + * ScaledPermutation is a matrix combining a permutation with scaling factors. + * It is a combination of Diagonal and Permutation, and can be read as + * $SP = S \cdot P$, i.e. the scaling gets applied after the permutation. + * + * @tparam IndexType index type of permutation indices + * @tparam ValueType value type of the scaling factors + * + * @ingroup permutation + * @ingroup mat_formats + * @ingroup LinOp + */ +template +class ScaledPermutation + : public EnableLinOp>, + public EnableCreateMethod>, + public WritableToMatrixData { + friend class EnableCreateMethod; + friend class EnablePolymorphicObject; + +public: + using value_type = ValueType; + using index_type = IndexType; + + /** + * Returns a pointer to the scaling factors. + * + * @return the pointer to the scaling factors. + */ + value_type* get_scale() noexcept { return scale_.get_data(); } + + /** + * @copydoc get_scale() + * + * @note This is the constant version of the function, which can be + * significantly more memory efficient than the non-constant version, + * so always prefer this version. + */ + const value_type* get_const_scale() const noexcept + { + return scale_.get_const_data(); + } + + /** + * Returns a pointer to the permutation indices. + * + * @return the pointer to the permutation indices. + */ + index_type* get_permutation() noexcept { return permutation_.get_data(); } + + /** + * @copydoc get_permutation() + * + * @note This is the constant version of the function, which can be + * significantly more memory efficient than the non-constant version, + * so always prefer this version. + */ + const index_type* get_const_permutation() const noexcept + { + return permutation_.get_const_data(); + } + + /** + * Returns the inverse scaled permutation. + * + * @return a newly created ScaledPermutation object storing the inverse + * permutation and scaling factors of this ScalingPermutation. + */ + std::unique_ptr invert() const; + + void write(gko::matrix_data& data) const override; + + /** + * Creates a constant (immutable) ScaledPermutation matrix from constant + * arrays. + * + * @param exec the executor to create the object on + * @param perm_idxs the permutation index array of the matrix + * @param scale the scaling factor array + * @returns A smart pointer to the constant matrix wrapping the input arrays + * (if it resides on the same executor as the matrix) or a copy of + * the arrays on the correct executor. + */ + static std::unique_ptr create_const( + std::shared_ptr exec, + gko::detail::const_array_view&& scale, + gko::detail::const_array_view&& perm_idxs); + +protected: + /** + * Creates an uninitialized ScaledPermutation matrix. + * + * @param exec Executor associated to the matrix + * @param size dimensions of the (square) scaled permutation matrix + */ + ScaledPermutation(std::shared_ptr exec, size_type size = 0); + + /** + * Creates a ScaledPermutation matrix from already allocated (and + * initialized) arrays. + * + * @param exec Executor associated to the matrix + * @param permutation_indices array of permutation indices + * @param scaling_factors array of scaling factors + */ + ScaledPermutation(std::shared_ptr exec, + array scaling_factors, + array permutation_indices); + + void apply_impl(const LinOp* in, LinOp* out) const override; + + + void apply_impl(const LinOp*, const LinOp* in, const LinOp*, + LinOp* out) const override; + + +private: + array scale_; + array permutation_; +}; + + +} // namespace matrix +} // namespace gko + + +#endif // GKO_PUBLIC_CORE_MATRIX_SCALED_PERMUTATION_HPP_ diff --git a/include/ginkgo/ginkgo.hpp b/include/ginkgo/ginkgo.hpp index bcdaa5d2d20..6a217251055 100644 --- a/include/ginkgo/ginkgo.hpp +++ b/include/ginkgo/ginkgo.hpp @@ -118,6 +118,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include #include diff --git a/omp/matrix/csr_kernels.cpp b/omp/matrix/csr_kernels.cpp index 7d4a5a7ebd1..96fb8354d96 100644 --- a/omp/matrix/csr_kernels.cpp +++ b/omp/matrix/csr_kernels.cpp @@ -909,6 +909,20 @@ void inv_symm_permute(std::shared_ptr exec, const IndexType* perm, const matrix::Csr* orig, matrix::Csr* permuted) +{ + inv_nonsymm_permute(exec, perm, perm, orig, permuted); +} + +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_CSR_INV_SYMM_PERMUTE_KERNEL); + + +template +void inv_nonsymm_permute(std::shared_ptr exec, + const IndexType* row_perm, + const IndexType* column_perm, + const matrix::Csr* orig, + matrix::Csr* permuted) { auto in_row_ptrs = orig->get_const_row_ptrs(); auto in_col_idxs = orig->get_const_col_idxs(); @@ -921,26 +935,26 @@ void inv_symm_permute(std::shared_ptr exec, #pragma omp parallel for for (size_type row = 0; row < num_rows; ++row) { auto src_row = row; - auto dst_row = perm[row]; + auto dst_row = row_perm[row]; p_row_ptrs[dst_row] = in_row_ptrs[src_row + 1] - in_row_ptrs[src_row]; } components::prefix_sum_nonnegative(exec, p_row_ptrs, num_rows + 1); #pragma omp parallel for for (size_type row = 0; row < num_rows; ++row) { auto src_row = row; - auto dst_row = perm[row]; + auto dst_row = row_perm[row]; auto src_begin = in_row_ptrs[src_row]; auto dst_begin = p_row_ptrs[dst_row]; auto row_size = in_row_ptrs[src_row + 1] - src_begin; for (IndexType i = 0; i < row_size; ++i) { - p_col_idxs[dst_begin + i] = perm[in_col_idxs[src_begin + i]]; + p_col_idxs[dst_begin + i] = column_perm[in_col_idxs[src_begin + i]]; p_vals[dst_begin + i] = in_vals[src_begin + i]; } } } GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( - GKO_DECLARE_CSR_INV_SYMM_PERMUTE_KERNEL); + GKO_DECLARE_CSR_INV_NONSYMM_PERMUTE_KERNEL); template @@ -982,10 +996,10 @@ GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( template -void inverse_row_permute(std::shared_ptr exec, - const IndexType* perm, - const matrix::Csr* orig, - matrix::Csr* row_permuted) +void inv_row_permute(std::shared_ptr exec, + const IndexType* perm, + const matrix::Csr* orig, + matrix::Csr* row_permuted) { auto orig_row_ptrs = orig->get_const_row_ptrs(); auto orig_col_idxs = orig->get_const_col_idxs(); @@ -1017,7 +1031,146 @@ void inverse_row_permute(std::shared_ptr exec, } GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( - GKO_DECLARE_CSR_INVERSE_ROW_PERMUTE_KERNEL); + GKO_DECLARE_CSR_INV_ROW_PERMUTE_KERNEL); + + +template +void inv_symm_scale_permute(std::shared_ptr exec, + const ValueType* scale, const IndexType* perm, + const matrix::Csr* orig, + matrix::Csr* permuted) +{ + inv_nonsymm_scale_permute(exec, scale, perm, scale, perm, orig, permuted); +} + +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_CSR_INV_SYMM_SCALE_PERMUTE_KERNEL); + + +template +void inv_nonsymm_scale_permute(std::shared_ptr exec, + const ValueType* row_scale, + const IndexType* row_perm, + const ValueType* col_scale, + const IndexType* col_perm, + const matrix::Csr* orig, + matrix::Csr* permuted) +{ + auto in_row_ptrs = orig->get_const_row_ptrs(); + auto in_col_idxs = orig->get_const_col_idxs(); + auto in_vals = orig->get_const_values(); + auto p_row_ptrs = permuted->get_row_ptrs(); + auto p_col_idxs = permuted->get_col_idxs(); + auto p_vals = permuted->get_values(); + size_type num_rows = orig->get_size()[0]; + +#pragma omp parallel for + for (size_type row = 0; row < num_rows; ++row) { + auto src_row = row; + auto dst_row = row_perm[row]; + p_row_ptrs[dst_row] = in_row_ptrs[src_row + 1] - in_row_ptrs[src_row]; + } + components::prefix_sum_nonnegative(exec, p_row_ptrs, num_rows + 1); +#pragma omp parallel for + for (size_type row = 0; row < num_rows; ++row) { + auto src_row = row; + auto dst_row = row_perm[row]; + auto src_begin = in_row_ptrs[src_row]; + auto dst_begin = p_row_ptrs[dst_row]; + auto row_size = in_row_ptrs[src_row + 1] - src_begin; + for (IndexType i = 0; i < row_size; ++i) { + const auto in_col = in_col_idxs[src_begin + i]; + p_col_idxs[dst_begin + i] = col_perm[in_col]; + p_vals[dst_begin + i] = in_vals[src_begin + i] / + (row_scale[src_row] * col_scale[in_col]); + } + } +} + +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_CSR_INV_NONSYMM_SCALE_PERMUTE_KERNEL); + + +template +void row_scale_permute(std::shared_ptr exec, + const ValueType* scale, const IndexType* perm, + const matrix::Csr* orig, + matrix::Csr* row_permuted) +{ + auto orig_row_ptrs = orig->get_const_row_ptrs(); + auto orig_col_idxs = orig->get_const_col_idxs(); + auto orig_vals = orig->get_const_values(); + auto rp_row_ptrs = row_permuted->get_row_ptrs(); + auto rp_col_idxs = row_permuted->get_col_idxs(); + auto rp_vals = row_permuted->get_values(); + size_type num_rows = orig->get_size()[0]; + +#pragma omp parallel for + for (size_type row = 0; row < num_rows; ++row) { + auto src_row = perm[row]; + auto dst_row = row; + rp_row_ptrs[dst_row] = + orig_row_ptrs[src_row + 1] - orig_row_ptrs[src_row]; + } + components::prefix_sum_nonnegative(exec, rp_row_ptrs, num_rows + 1); +#pragma omp parallel for + for (size_type row = 0; row < num_rows; ++row) { + auto src_row = perm[row]; + auto dst_row = row; + auto src_begin = orig_row_ptrs[src_row]; + auto dst_begin = rp_row_ptrs[dst_row]; + auto row_size = orig_row_ptrs[src_row + 1] - src_begin; + std::copy_n(orig_col_idxs + src_begin, row_size, + rp_col_idxs + dst_begin); + for (IndexType i = 0; i < row_size; i++) { + rp_vals[i + dst_begin] = orig_vals[i + src_begin] * scale[dst_row]; + } + } +} + +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_CSR_ROW_SCALE_PERMUTE_KERNEL); + + +template +void inv_row_scale_permute(std::shared_ptr exec, + const ValueType* scale, const IndexType* perm, + const matrix::Csr* orig, + matrix::Csr* row_permuted) +{ + auto orig_row_ptrs = orig->get_const_row_ptrs(); + auto orig_col_idxs = orig->get_const_col_idxs(); + auto orig_vals = orig->get_const_values(); + auto rp_row_ptrs = row_permuted->get_row_ptrs(); + auto rp_col_idxs = row_permuted->get_col_idxs(); + auto rp_vals = row_permuted->get_values(); + size_type num_rows = orig->get_size()[0]; + +#pragma omp parallel for + for (size_type row = 0; row < num_rows; ++row) { + auto src_row = row; + auto dst_row = perm[row]; + rp_row_ptrs[dst_row] = + orig_row_ptrs[src_row + 1] - orig_row_ptrs[src_row]; + } + components::prefix_sum_nonnegative(exec, rp_row_ptrs, num_rows + 1); +#pragma omp parallel for + for (size_type row = 0; row < num_rows; ++row) { + auto src_row = row; + auto dst_row = perm[row]; + auto src_begin = orig_row_ptrs[src_row]; + auto dst_begin = rp_row_ptrs[dst_row]; + auto row_size = orig_row_ptrs[src_row + 1] - src_begin; + std::copy_n(orig_col_idxs + src_begin, row_size, + rp_col_idxs + dst_begin); + for (IndexType i = 0; i < row_size; i++) { + rp_vals[i + dst_begin] = orig_vals[i + src_begin] / scale[src_row]; + } + } +} + +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_CSR_INV_ROW_SCALE_PERMUTE_KERNEL); template diff --git a/omp/test/reorder/rcm_kernels.cpp b/omp/test/reorder/rcm_kernels.cpp index d2996ffb319..48698ac1b49 100644 --- a/omp/test/reorder/rcm_kernels.cpp +++ b/omp/test/reorder/rcm_kernels.cpp @@ -118,8 +118,7 @@ class Rcm : public ::testing::Test { return false; } - const auto n = gko::as(reorder->get_permutation()) - ->get_permutation_size(); + const auto n = reorder->get_permutation()->get_size()[0]; auto degrees = std::vector(n); for (gko::size_type i = 0; i < n; ++i) { degrees[i] = @@ -198,8 +197,8 @@ class Rcm : public ::testing::Test { static bool is_rcm_ordered(std::shared_ptr mtx, std::shared_ptr reorder) { - const auto n = gko::as(reorder->get_permutation()) - ->get_permutation_size(); + const auto n = + gko::as(reorder->get_permutation())->get_size()[0]; const auto row_ptrs = mtx->get_const_row_ptrs(); const auto col_idxs = mtx->get_const_col_idxs(); auto degrees = std::vector(n); diff --git a/reference/CMakeLists.txt b/reference/CMakeLists.txt index dd54e3fb52f..d7546c45fcb 100644 --- a/reference/CMakeLists.txt +++ b/reference/CMakeLists.txt @@ -33,6 +33,8 @@ target_sources(ginkgo_reference matrix/fbcsr_kernels.cpp matrix/fft_kernels.cpp matrix/hybrid_kernels.cpp + matrix/permutation_kernels.cpp + matrix/scaled_permutation_kernels.cpp matrix/sellp_kernels.cpp matrix/sparsity_csr_kernels.cpp multigrid/pgm_kernels.cpp diff --git a/reference/matrix/csr_kernels.cpp b/reference/matrix/csr_kernels.cpp index 3a05a09cd45..d87e72bc5ab 100644 --- a/reference/matrix/csr_kernels.cpp +++ b/reference/matrix/csr_kernels.cpp @@ -834,24 +834,25 @@ GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( GKO_DECLARE_CSR_CONVERT_TO_HYBRID_KERNEL); -template -void invert_permutation(std::shared_ptr exec, - size_type size, const IndexType* permutation_indices, - IndexType* inv_permutation) +template +void inv_symm_permute(std::shared_ptr exec, + const IndexType* perm, + const matrix::Csr* orig, + matrix::Csr* permuted) { - for (IndexType i = 0; i < static_cast(size); ++i) { - inv_permutation[permutation_indices[i]] = i; - } + inv_nonsymm_permute(exec, perm, perm, orig, permuted); } -GKO_INSTANTIATE_FOR_EACH_INDEX_TYPE(GKO_DECLARE_INVERT_PERMUTATION_KERNEL); +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_CSR_INV_SYMM_PERMUTE_KERNEL); template -void inv_symm_permute(std::shared_ptr exec, - const IndexType* perm, - const matrix::Csr* orig, - matrix::Csr* permuted) +void inv_nonsymm_permute(std::shared_ptr exec, + const IndexType* row_perm, + const IndexType* column_perm, + const matrix::Csr* orig, + matrix::Csr* permuted) { auto in_row_ptrs = orig->get_const_row_ptrs(); auto in_col_idxs = orig->get_const_col_idxs(); @@ -863,25 +864,25 @@ void inv_symm_permute(std::shared_ptr exec, for (size_type row = 0; row < num_rows; ++row) { auto src_row = row; - auto dst_row = perm[row]; + auto dst_row = row_perm[row]; p_row_ptrs[dst_row] = in_row_ptrs[src_row + 1] - in_row_ptrs[src_row]; } components::prefix_sum_nonnegative(exec, p_row_ptrs, num_rows + 1); for (size_type row = 0; row < num_rows; ++row) { auto src_row = row; - auto dst_row = perm[row]; + auto dst_row = row_perm[row]; auto src_begin = in_row_ptrs[src_row]; auto dst_begin = p_row_ptrs[dst_row]; auto row_size = in_row_ptrs[src_row + 1] - src_begin; for (IndexType i = 0; i < row_size; ++i) { - p_col_idxs[dst_begin + i] = perm[in_col_idxs[src_begin + i]]; + p_col_idxs[dst_begin + i] = column_perm[in_col_idxs[src_begin + i]]; p_vals[dst_begin + i] = in_vals[src_begin + i]; } } } GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( - GKO_DECLARE_CSR_INV_SYMM_PERMUTE_KERNEL); + GKO_DECLARE_CSR_INV_NONSYMM_PERMUTE_KERNEL); template @@ -920,10 +921,10 @@ GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( template -void inverse_row_permute(std::shared_ptr exec, - const IndexType* perm, - const matrix::Csr* orig, - matrix::Csr* row_permuted) +void inv_row_permute(std::shared_ptr exec, + const IndexType* perm, + const matrix::Csr* orig, + matrix::Csr* row_permuted) { auto in_row_ptrs = orig->get_const_row_ptrs(); auto in_col_idxs = orig->get_const_col_idxs(); @@ -951,21 +952,21 @@ void inverse_row_permute(std::shared_ptr exec, } GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( - GKO_DECLARE_CSR_INVERSE_ROW_PERMUTE_KERNEL); + GKO_DECLARE_CSR_INV_ROW_PERMUTE_KERNEL); template -void inverse_column_permute(std::shared_ptr exec, - const IndexType* perm, - const matrix::Csr* orig, - matrix::Csr* column_permuted) +void inv_col_permute(std::shared_ptr exec, + const IndexType* perm, + const matrix::Csr* orig, + matrix::Csr* col_permuted) { auto in_row_ptrs = orig->get_const_row_ptrs(); auto in_col_idxs = orig->get_const_col_idxs(); auto in_vals = orig->get_const_values(); - auto cp_row_ptrs = column_permuted->get_row_ptrs(); - auto cp_col_idxs = column_permuted->get_col_idxs(); - auto cp_vals = column_permuted->get_values(); + auto cp_row_ptrs = col_permuted->get_row_ptrs(); + auto cp_col_idxs = col_permuted->get_col_idxs(); + auto cp_vals = col_permuted->get_values(); auto num_rows = orig->get_size()[0]; for (size_type row = 0; row < num_rows; ++row) { @@ -981,7 +982,167 @@ void inverse_column_permute(std::shared_ptr exec, } GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( - GKO_DECLARE_CSR_INVERSE_COLUMN_PERMUTE_KERNEL); + GKO_DECLARE_CSR_INV_COL_PERMUTE_KERNEL); + + +template +void inv_symm_scale_permute(std::shared_ptr exec, + const ValueType* scale, const IndexType* perm, + const matrix::Csr* orig, + matrix::Csr* permuted) +{ + inv_nonsymm_scale_permute(exec, scale, perm, scale, perm, orig, permuted); +} + +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_CSR_INV_SYMM_SCALE_PERMUTE_KERNEL); + + +template +void inv_nonsymm_scale_permute(std::shared_ptr exec, + const ValueType* row_scale, + const IndexType* row_perm, + const ValueType* col_scale, + const IndexType* col_perm, + const matrix::Csr* orig, + matrix::Csr* permuted) +{ + auto in_row_ptrs = orig->get_const_row_ptrs(); + auto in_col_idxs = orig->get_const_col_idxs(); + auto in_vals = orig->get_const_values(); + auto p_row_ptrs = permuted->get_row_ptrs(); + auto p_col_idxs = permuted->get_col_idxs(); + auto p_vals = permuted->get_values(); + size_type num_rows = orig->get_size()[0]; + + for (size_type row = 0; row < num_rows; ++row) { + auto src_row = row; + auto dst_row = row_perm[row]; + p_row_ptrs[dst_row] = in_row_ptrs[src_row + 1] - in_row_ptrs[src_row]; + } + components::prefix_sum_nonnegative(exec, p_row_ptrs, num_rows + 1); + for (size_type row = 0; row < num_rows; ++row) { + auto src_row = row; + auto dst_row = row_perm[row]; + auto src_begin = in_row_ptrs[src_row]; + auto dst_begin = p_row_ptrs[dst_row]; + auto row_size = in_row_ptrs[src_row + 1] - src_begin; + for (IndexType i = 0; i < row_size; ++i) { + const auto in_col = in_col_idxs[src_begin + i]; + p_col_idxs[dst_begin + i] = col_perm[in_col]; + p_vals[dst_begin + i] = in_vals[src_begin + i] / + (row_scale[src_row] * col_scale[in_col]); + } + } +} + +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_CSR_INV_NONSYMM_SCALE_PERMUTE_KERNEL); + + +template +void row_scale_permute(std::shared_ptr exec, + const ValueType* scale, const IndexType* perm, + const matrix::Csr* orig, + matrix::Csr* row_permuted) +{ + auto in_row_ptrs = orig->get_const_row_ptrs(); + auto in_col_idxs = orig->get_const_col_idxs(); + auto in_vals = orig->get_const_values(); + auto rp_row_ptrs = row_permuted->get_row_ptrs(); + auto rp_col_idxs = row_permuted->get_col_idxs(); + auto rp_vals = row_permuted->get_values(); + size_type num_rows = orig->get_size()[0]; + + for (size_type row = 0; row < num_rows; ++row) { + auto src_row = perm[row]; + auto dst_row = row; + rp_row_ptrs[dst_row] = in_row_ptrs[src_row + 1] - in_row_ptrs[src_row]; + } + components::prefix_sum_nonnegative(exec, rp_row_ptrs, num_rows + 1); + for (size_type row = 0; row < num_rows; ++row) { + const auto src_row = perm[row]; + const auto dst_row = row; + const auto src_begin = in_row_ptrs[src_row]; + const auto dst_begin = rp_row_ptrs[dst_row]; + const auto row_size = in_row_ptrs[src_row + 1] - src_begin; + std::copy_n(in_col_idxs + src_begin, row_size, rp_col_idxs + dst_begin); + for (IndexType i = 0; i < row_size; i++) { + rp_vals[i + dst_begin] = in_vals[i + src_begin] * scale[dst_row]; + } + } +} + +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_CSR_ROW_SCALE_PERMUTE_KERNEL); + + +template +void inv_row_scale_permute(std::shared_ptr exec, + const ValueType* scale, const IndexType* perm, + const matrix::Csr* orig, + matrix::Csr* row_permuted) +{ + auto in_row_ptrs = orig->get_const_row_ptrs(); + auto in_col_idxs = orig->get_const_col_idxs(); + auto in_vals = orig->get_const_values(); + auto rp_row_ptrs = row_permuted->get_row_ptrs(); + auto rp_col_idxs = row_permuted->get_col_idxs(); + auto rp_vals = row_permuted->get_values(); + size_type num_rows = orig->get_size()[0]; + + for (size_type row = 0; row < num_rows; ++row) { + auto src_row = row; + auto dst_row = perm[row]; + rp_row_ptrs[dst_row] = in_row_ptrs[src_row + 1] - in_row_ptrs[src_row]; + } + components::prefix_sum_nonnegative(exec, rp_row_ptrs, num_rows + 1); + for (size_type row = 0; row < num_rows; ++row) { + auto src_row = row; + auto dst_row = perm[row]; + auto src_begin = in_row_ptrs[src_row]; + auto dst_begin = rp_row_ptrs[dst_row]; + auto row_size = in_row_ptrs[src_row + 1] - src_begin; + std::copy_n(in_col_idxs + src_begin, row_size, rp_col_idxs + dst_begin); + for (IndexType i = 0; i < row_size; i++) { + rp_vals[i + dst_begin] = in_vals[i + src_begin] / scale[src_row]; + } + } +} + +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_CSR_INV_ROW_SCALE_PERMUTE_KERNEL); + + +template +void inv_col_scale_permute(std::shared_ptr exec, + const ValueType* scale, const IndexType* perm, + const matrix::Csr* orig, + matrix::Csr* col_permuted) +{ + auto in_row_ptrs = orig->get_const_row_ptrs(); + auto in_col_idxs = orig->get_const_col_idxs(); + auto in_vals = orig->get_const_values(); + auto cp_row_ptrs = col_permuted->get_row_ptrs(); + auto cp_col_idxs = col_permuted->get_col_idxs(); + auto cp_vals = col_permuted->get_values(); + auto num_rows = orig->get_size()[0]; + + for (size_type row = 0; row < num_rows; ++row) { + auto row_begin = in_row_ptrs[row]; + auto row_end = in_row_ptrs[row + 1]; + cp_row_ptrs[row] = in_row_ptrs[row]; + for (auto k = row_begin; k < row_end; ++k) { + const auto in_col = in_col_idxs[k]; + cp_col_idxs[k] = perm[in_col]; + cp_vals[k] = in_vals[k] / scale[in_col]; + } + } + cp_row_ptrs[num_rows] = in_row_ptrs[num_rows]; +} + +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_CSR_INV_COL_SCALE_PERMUTE_KERNEL); template diff --git a/reference/matrix/dense_kernels.cpp b/reference/matrix/dense_kernels.cpp index ba399b0f445..cec13d4b25a 100644 --- a/reference/matrix/dense_kernels.cpp +++ b/reference/matrix/dense_kernels.cpp @@ -841,11 +841,9 @@ GKO_INSTANTIATE_FOR_EACH_VALUE_TYPE(GKO_DECLARE_DENSE_CONJ_TRANSPOSE_KERNEL); template void symm_permute(std::shared_ptr exec, - const array* permutation_indices, - const matrix::Dense* orig, + const IndexType* perm, const matrix::Dense* orig, matrix::Dense* permuted) { - auto perm = permutation_indices->get_const_data(); auto size = orig->get_size()[0]; for (size_type i = 0; i < size; ++i) { for (size_type j = 0; j < size; ++j) { @@ -860,11 +858,10 @@ GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( template void inv_symm_permute(std::shared_ptr exec, - const array* permutation_indices, + const IndexType* perm, const matrix::Dense* orig, matrix::Dense* permuted) { - auto perm = permutation_indices->get_const_data(); auto size = orig->get_size()[0]; for (size_type i = 0; i < size; ++i) { for (size_type j = 0; j < size; ++j) { @@ -877,14 +874,46 @@ GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( GKO_DECLARE_DENSE_INV_SYMM_PERMUTE_KERNEL); +template +void nonsymm_permute(std::shared_ptr exec, + const IndexType* row_perm, const IndexType* col_perm, + const matrix::Dense* orig, + matrix::Dense* permuted) +{ + for (size_type i = 0; i < orig->get_size()[0]; ++i) { + for (size_type j = 0; j < orig->get_size()[1]; ++j) { + permuted->at(i, j) = orig->at(row_perm[i], col_perm[j]); + } + } +} + +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_DENSE_NONSYMM_PERMUTE_KERNEL); + + +template +void inv_nonsymm_permute(std::shared_ptr exec, + const IndexType* row_perm, const IndexType* col_perm, + const matrix::Dense* orig, + matrix::Dense* permuted) +{ + for (size_type i = 0; i < orig->get_size()[0]; ++i) { + for (size_type j = 0; j < orig->get_size()[1]; ++j) { + permuted->at(row_perm[i], col_perm[j]) = orig->at(i, j); + } + } +} + +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_DENSE_INV_NONSYMM_PERMUTE_KERNEL); + + template void row_gather(std::shared_ptr exec, - const array* row_idxs, - const matrix::Dense* orig, + const IndexType* rows, const matrix::Dense* orig, matrix::Dense* row_collection) { - auto rows = row_idxs->get_const_data(); - for (size_type i = 0; i < row_idxs->get_num_elems(); ++i) { + for (size_type i = 0; i < row_collection->get_size()[0]; ++i) { for (size_type j = 0; j < orig->get_size()[1]; ++j) { row_collection->at(i, j) = orig->at(rows[i], j); } @@ -898,16 +927,15 @@ GKO_INSTANTIATE_FOR_EACH_MIXED_VALUE_AND_INDEX_TYPE_2( template void advanced_row_gather(std::shared_ptr exec, const matrix::Dense* alpha, - const array* row_idxs, + const IndexType* rows, const matrix::Dense* orig, const matrix::Dense* beta, matrix::Dense* row_collection) { using type = highest_precision; - auto rows = row_idxs->get_const_data(); auto scalar_alpha = alpha->at(0, 0); auto scalar_beta = beta->at(0, 0); - for (size_type i = 0; i < row_idxs->get_num_elems(); ++i) { + for (size_type i = 0; i < row_collection->get_size()[0]; ++i) { for (size_type j = 0; j < orig->get_size()[1]; ++j) { row_collection->at(i, j) = static_cast(scalar_alpha * orig->at(rows[i], j)) + @@ -922,30 +950,27 @@ GKO_INSTANTIATE_FOR_EACH_MIXED_VALUE_AND_INDEX_TYPE_2( template -void column_permute(std::shared_ptr exec, - const array* permutation_indices, - const matrix::Dense* orig, - matrix::Dense* column_permuted) +void col_permute(std::shared_ptr exec, + const IndexType* perm, const matrix::Dense* orig, + matrix::Dense* col_permuted) { - auto perm = permutation_indices->get_const_data(); for (size_type j = 0; j < orig->get_size()[1]; ++j) { for (size_type i = 0; i < orig->get_size()[0]; ++i) { - column_permuted->at(i, j) = orig->at(i, perm[j]); + col_permuted->at(i, j) = orig->at(i, perm[j]); } } } GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( - GKO_DECLARE_DENSE_COLUMN_PERMUTE_KERNEL); + GKO_DECLARE_DENSE_COL_PERMUTE_KERNEL); template -void inverse_row_permute(std::shared_ptr exec, - const array* permutation_indices, - const matrix::Dense* orig, - matrix::Dense* row_permuted) +void inv_row_permute(std::shared_ptr exec, + const IndexType* perm, + const matrix::Dense* orig, + matrix::Dense* row_permuted) { - auto perm = permutation_indices->get_const_data(); for (size_type i = 0; i < orig->get_size()[0]; ++i) { for (size_type j = 0; j < orig->get_size()[1]; ++j) { row_permuted->at(perm[i], j) = orig->at(i, j); @@ -958,21 +983,166 @@ GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( template -void inverse_column_permute(std::shared_ptr exec, - const array* permutation_indices, +void inv_col_permute(std::shared_ptr exec, + const IndexType* perm, + const matrix::Dense* orig, + matrix::Dense* col_permuted) +{ + for (size_type j = 0; j < orig->get_size()[1]; ++j) { + for (size_type i = 0; i < orig->get_size()[0]; ++i) { + col_permuted->at(i, perm[j]) = orig->at(i, j); + } + } +} + +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_DENSE_INV_COL_PERMUTE_KERNEL); + + +template +void symm_scale_permute(std::shared_ptr exec, + const ValueType* scale, const IndexType* perm, + const matrix::Dense* orig, + matrix::Dense* permuted) +{ + for (size_type j = 0; j < orig->get_size()[1]; ++j) { + for (size_type i = 0; i < orig->get_size()[0]; ++i) { + permuted->at(i, j) = + scale[i] * scale[j] * orig->at(perm[i], perm[j]); + } + } +} + +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_DENSE_SYMM_SCALE_PERMUTE_KERNEL); + + +template +void inv_symm_scale_permute(std::shared_ptr exec, + const ValueType* scale, const IndexType* perm, const matrix::Dense* orig, - matrix::Dense* column_permuted) + matrix::Dense* permuted) +{ + for (size_type j = 0; j < orig->get_size()[1]; ++j) { + for (size_type i = 0; i < orig->get_size()[0]; ++i) { + permuted->at(perm[i], perm[j]) = + orig->at(i, j) / (scale[i] * scale[j]); + } + } +} + +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_DENSE_INV_SYMM_SCALE_PERMUTE_KERNEL); + + +template +void nonsymm_scale_permute(std::shared_ptr exec, + const ValueType* row_scale, + const IndexType* row_perm, + const ValueType* col_scale, + const IndexType* col_perm, + const matrix::Dense* orig, + matrix::Dense* permuted) +{ + for (size_type j = 0; j < orig->get_size()[1]; ++j) { + for (size_type i = 0; i < orig->get_size()[0]; ++i) { + permuted->at(i, j) = row_scale[i] * col_scale[j] * + orig->at(row_perm[i], col_perm[j]); + } + } +} + +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_DENSE_NONSYMM_SCALE_PERMUTE_KERNEL); + + +template +void inv_nonsymm_scale_permute(std::shared_ptr exec, + const ValueType* row_scale, + const IndexType* row_perm, + const ValueType* col_scale, + const IndexType* col_perm, + const matrix::Dense* orig, + matrix::Dense* permuted) +{ + for (size_type j = 0; j < orig->get_size()[1]; ++j) { + for (size_type i = 0; i < orig->get_size()[0]; ++i) { + permuted->at(row_perm[i], col_perm[j]) = + orig->at(i, j) / (row_scale[i] * col_scale[j]); + } + } +} + +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_DENSE_INV_NONSYMM_SCALE_PERMUTE_KERNEL); + + +template +void row_scale_permute(std::shared_ptr exec, + const ValueType* scale, const IndexType* perm, + const matrix::Dense* orig, + matrix::Dense* permuted) +{ + for (size_type j = 0; j < orig->get_size()[1]; ++j) { + for (size_type i = 0; i < orig->get_size()[0]; ++i) { + permuted->at(i, j) = scale[i] * orig->at(perm[i], j); + } + } +} + +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_DENSE_ROW_SCALE_PERMUTE_KERNEL); + + +template +void inv_row_scale_permute(std::shared_ptr exec, + const ValueType* scale, const IndexType* perm, + const matrix::Dense* orig, + matrix::Dense* permuted) +{ + for (size_type j = 0; j < orig->get_size()[1]; ++j) { + for (size_type i = 0; i < orig->get_size()[0]; ++i) { + permuted->at(perm[i], j) = orig->at(i, j) / scale[i]; + } + } +} + +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_DENSE_INV_ROW_SCALE_PERMUTE_KERNEL); + + +template +void col_scale_permute(std::shared_ptr exec, + const ValueType* scale, const IndexType* perm, + const matrix::Dense* orig, + matrix::Dense* permuted) +{ + for (size_type j = 0; j < orig->get_size()[1]; ++j) { + for (size_type i = 0; i < orig->get_size()[0]; ++i) { + permuted->at(i, j) = scale[j] * orig->at(i, perm[j]); + } + } +} + +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_DENSE_COL_SCALE_PERMUTE_KERNEL); + + +template +void inv_col_scale_permute(std::shared_ptr exec, + const ValueType* scale, const IndexType* perm, + const matrix::Dense* orig, + matrix::Dense* permuted) { - auto perm = permutation_indices->get_const_data(); for (size_type j = 0; j < orig->get_size()[1]; ++j) { for (size_type i = 0; i < orig->get_size()[0]; ++i) { - column_permuted->at(i, perm[j]) = orig->at(i, j); + permuted->at(i, perm[j]) = orig->at(i, j) / scale[j]; } } } GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( - GKO_DECLARE_DENSE_INV_COLUMN_PERMUTE_KERNEL); + GKO_DECLARE_DENSE_INV_COL_SCALE_PERMUTE_KERNEL); template diff --git a/reference/matrix/permutation_kernels.cpp b/reference/matrix/permutation_kernels.cpp new file mode 100644 index 00000000000..cc7a81a1044 --- /dev/null +++ b/reference/matrix/permutation_kernels.cpp @@ -0,0 +1,58 @@ +/************************************************************* +Copyright (c) 2017-2023, the Ginkgo authors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*************************************************************/ + +#include "core/matrix/permutation_kernels.hpp" + + +namespace gko { +namespace kernels { +namespace reference { +namespace permutation { + + +template +void invert(std::shared_ptr exec, + const IndexType* permutation, size_type size, + IndexType* output_permutation) +{ + for (size_type i = 0; i < size; i++) { + output_permutation[permutation[i]] = i; + } +} + +GKO_INSTANTIATE_FOR_EACH_INDEX_TYPE(GKO_DECLARE_PERMUTATION_INVERT_KERNEL); + + +} // namespace permutation +} // namespace reference +} // namespace kernels +} // namespace gko diff --git a/reference/matrix/scaled_permutation_kernels.cpp b/reference/matrix/scaled_permutation_kernels.cpp new file mode 100644 index 00000000000..54a68fbdf0a --- /dev/null +++ b/reference/matrix/scaled_permutation_kernels.cpp @@ -0,0 +1,64 @@ +/************************************************************* +Copyright (c) 2017-2023, the Ginkgo authors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*************************************************************/ + +#include "core/matrix/scaled_permutation_kernels.hpp" + + +#include + + +namespace gko { +namespace kernels { +namespace reference { +namespace scaled_permutation { + + +template +void invert(std::shared_ptr exec, + const IndexType* input_permutation, const ValueType* input_scale, + size_type size, IndexType* output_permutation, + ValueType* output_scale) +{ + for (size_type i = 0; i < size; i++) { + output_permutation[input_permutation[i]] = i; + output_scale[input_permutation[i]] = one() / input_scale[i]; + } +} + +GKO_INSTANTIATE_FOR_EACH_VALUE_AND_INDEX_TYPE( + GKO_DECLARE_SCALED_PERMUTATION_INVERT_KERNEL); + + +} // namespace scaled_permutation +} // namespace reference +} // namespace kernels +} // namespace gko diff --git a/reference/test/matrix/CMakeLists.txt b/reference/test/matrix/CMakeLists.txt index 9670a5df80c..734eb82485f 100644 --- a/reference/test/matrix/CMakeLists.txt +++ b/reference/test/matrix/CMakeLists.txt @@ -8,6 +8,7 @@ ginkgo_create_test(fft_kernels) ginkgo_create_test(hybrid_kernels) ginkgo_create_test(identity) ginkgo_create_test(permutation) +ginkgo_create_test(scaled_permutation) ginkgo_create_test(sellp_kernels) ginkgo_create_test(sparsity_csr) ginkgo_create_test(sparsity_csr_kernels) diff --git a/reference/test/matrix/csr_kernels.cpp b/reference/test/matrix/csr_kernels.cpp index d56201ade02..64fc26f0a67 100644 --- a/reference/test/matrix/csr_kernels.cpp +++ b/reference/test/matrix/csr_kernels.cpp @@ -49,6 +49,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include +#include #include #include @@ -76,6 +78,8 @@ class Csr : public ::testing::Test { using Hybrid = gko::matrix::Hybrid; using Vec = gko::matrix::Dense; using MixedVec = gko::matrix::Dense>; + using Perm = gko::matrix::Permutation; + using ScaledPerm = gko::matrix::ScaledPermutation; Csr() : exec(gko::ReferenceExecutor::create()), @@ -87,7 +91,21 @@ class Csr : public ::testing::Test { std::make_shared())), mtx3_unsorted( Mtx::create(exec, gko::dim<2>(3, 3), 7, - std::make_shared())) + std::make_shared())), + perm3(Perm::create(exec, 3, gko::array{exec, {1, 2, 0}})), + perm3_rev(perm3->invert()), + perm2(Perm::create(exec, 2, gko::array{exec, {1, 0}})), + perm0(Perm::create(exec)), + scale_perm3(ScaledPerm::create( + exec, gko::array{this->exec, {2.0, 3.0, 5.0}}, + gko::array{exec, {1, 2, 0}})), + scale_perm3_rev(ScaledPerm::create( + exec, gko::array{this->exec, {7.0, 11.0, 13.0}}, + gko::array{exec, {1, 2, 0}})), + scale_perm2(ScaledPerm::create( + exec, gko::array{this->exec, {17.0, 19.0}}, + gko::array{exec, {1, 0}})), + scale_perm0(ScaledPerm::create(exec)) { this->create_mtx(mtx.get()); this->create_mtx2(mtx2.get()); @@ -349,6 +367,14 @@ class Csr : public ::testing::Test { std::unique_ptr mtx2; std::unique_ptr mtx3_sorted; std::unique_ptr mtx3_unsorted; + std::unique_ptr perm3; + std::unique_ptr perm3_rev; + std::unique_ptr perm2; + std::unique_ptr perm0; + std::unique_ptr scale_perm3; + std::unique_ptr scale_perm3_rev; + std::unique_ptr scale_perm2; + std::unique_ptr scale_perm0; index_type invalid_index = gko::invalid_index(); }; @@ -1284,6 +1310,439 @@ TYPED_TEST(Csr, NonSquareMtxIsTransposable) } +template +std::unique_ptr> csr_from_permutation( + gko::matrix::Permutation* perm, bool invert) +{ + gko::matrix_data double_data; + if (invert) { + perm->invert()->write(double_data); + } else { + perm->write(double_data); + } + gko::matrix_data data; + data.size = double_data.size; + for (auto entry : double_data.nonzeros) { + data.nonzeros.emplace_back(entry.row, entry.column, 1.0); + } + auto mtx = + gko::matrix::Csr::create(perm->get_executor()); + mtx->read(data); + return mtx; +} + + +template +std::unique_ptr> csr_from_permutation( + gko::matrix::ScaledPermutation* perm, bool invert) +{ + gko::matrix_data data; + if (invert) { + perm->invert()->write(data); + } else { + perm->write(data); + } + auto mtx = + gko::matrix::Csr::create(perm->get_executor()); + mtx->read(data); + return mtx; +} + + +template +std::unique_ptr> ref_permute( + gko::matrix::Csr* input, Permutation* permutation, + gko::matrix::permute_mode mode) +{ + using gko::matrix::permute_mode; + using Csr = gko::matrix::Csr; + auto result = input->clone(); + auto permutation_csr = csr_from_permutation( + permutation, (mode & permute_mode::inverse) == permute_mode::inverse); + if ((mode & permute_mode::rows) == permute_mode::rows) { + // compute P * A + permutation_csr->apply(input, result); + } + if ((mode & permute_mode::columns) == permute_mode::columns) { + // compute A * P^T = (P * A^T)^T + auto tmp = result->transpose(); + auto tmp2 = gko::as(tmp->clone()); + permutation_csr->apply(tmp, tmp2); + result = gko::as(tmp2->transpose()); + } + return result; +} + + +template +std::unique_ptr> ref_permute( + gko::matrix::Csr* input, Permutation* row_permutation, + Permutation* col_permutation, bool invert) +{ + using gko::matrix::permute_mode; + using Csr = gko::matrix::Csr; + auto result = input->clone(); + auto row_permutation_csr = + csr_from_permutation(row_permutation, invert); + auto col_permutation_csr = + csr_from_permutation(col_permutation, invert); + row_permutation_csr->apply(input, result); + auto tmp = result->transpose(); + auto tmp2 = gko::as(tmp->clone()); + col_permutation_csr->apply(tmp, tmp2); + return gko::as(tmp2->transpose()); +} + + +TYPED_TEST(Csr, Permute) +{ + using gko::matrix::permute_mode; + + for (auto mode : + {permute_mode::none, permute_mode::rows, permute_mode::columns, + permute_mode::symmetric, permute_mode::inverse_rows, + permute_mode::inverse_columns, permute_mode::inverse_symmetric}) { + SCOPED_TRACE(mode); + + auto permuted = this->mtx3_sorted->permute(this->perm3, mode); + auto ref_permuted = + ref_permute(this->mtx3_sorted.get(), this->perm3.get(), mode); + + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); + GKO_ASSERT_MTX_EQ_SPARSITY(permuted, ref_permuted); + ASSERT_TRUE(permuted->is_sorted_by_column_index()); + } +} + + +TYPED_TEST(Csr, PermuteRoundtrip) +{ + using gko::matrix::permute_mode; + + for (auto mode : + {permute_mode::rows, permute_mode::columns, permute_mode::symmetric}) { + SCOPED_TRACE(mode); + + auto permuted = + this->mtx3_sorted->permute(this->perm3, mode) + ->permute(this->perm3, mode | permute_mode::inverse); + + GKO_ASSERT_MTX_NEAR(this->mtx3_sorted, permuted, 0.0); + GKO_ASSERT_MTX_EQ_SPARSITY(permuted, this->mtx3_sorted); + ASSERT_TRUE(permuted->is_sorted_by_column_index()); + } +} + + +TYPED_TEST(Csr, PermuteRectangular) +{ + using gko::matrix::permute_mode; + + auto rpermuted = this->mtx2->permute(this->perm2, permute_mode::rows); + auto irpermuted = + this->mtx2->permute(this->perm2, permute_mode::inverse_rows); + auto cpermuted = this->mtx2->permute(this->perm3, permute_mode::columns); + auto icpermuted = + this->mtx2->permute(this->perm3, permute_mode::inverse_columns); + auto ref_rpermuted = + ref_permute(this->mtx2.get(), this->perm2.get(), permute_mode::rows); + auto ref_irpermuted = ref_permute(this->mtx2.get(), this->perm2.get(), + permute_mode::inverse_rows); + auto ref_cpermuted = + ref_permute(this->mtx2.get(), this->perm3.get(), permute_mode::columns); + auto ref_icpermuted = ref_permute(this->mtx2.get(), this->perm3.get(), + permute_mode::inverse_columns); + + GKO_ASSERT_MTX_NEAR(rpermuted, ref_rpermuted, 0.0); + GKO_ASSERT_MTX_NEAR(irpermuted, ref_irpermuted, 0.0); + GKO_ASSERT_MTX_NEAR(cpermuted, ref_cpermuted, 0.0); + GKO_ASSERT_MTX_NEAR(icpermuted, ref_icpermuted, 0.0); + GKO_ASSERT_MTX_EQ_SPARSITY(rpermuted, ref_rpermuted); + GKO_ASSERT_MTX_EQ_SPARSITY(irpermuted, ref_irpermuted); + GKO_ASSERT_MTX_EQ_SPARSITY(cpermuted, ref_cpermuted); + GKO_ASSERT_MTX_EQ_SPARSITY(icpermuted, ref_icpermuted); + ASSERT_TRUE(rpermuted->is_sorted_by_column_index()); + ASSERT_TRUE(irpermuted->is_sorted_by_column_index()); + ASSERT_TRUE(cpermuted->is_sorted_by_column_index()); + ASSERT_TRUE(icpermuted->is_sorted_by_column_index()); +} + + +TYPED_TEST(Csr, PermuteFailsWithIncorrectPermutationSize) +{ + using gko::matrix::permute_mode; + + for (auto mode : + {/* no permute_mode::none */ permute_mode::rows, permute_mode::columns, + permute_mode::symmetric, permute_mode::inverse_rows, + permute_mode::inverse_columns, permute_mode::inverse_symmetric}) { + SCOPED_TRACE(mode); + + ASSERT_THROW(this->mtx3_sorted->permute(this->perm0, mode), + gko::ValueMismatch); + } +} + + +TYPED_TEST(Csr, NonsymmPermute) +{ + auto permuted = this->mtx3_sorted->permute(this->perm3, this->perm3_rev); + auto ref_permuted = ref_permute(this->mtx3_sorted.get(), this->perm3.get(), + this->perm3_rev.get(), false); + + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); + GKO_ASSERT_MTX_EQ_SPARSITY(permuted, ref_permuted); + ASSERT_TRUE(permuted->is_sorted_by_column_index()); +} + + +TYPED_TEST(Csr, NonsymmPermuteInverse) +{ + auto permuted = + this->mtx3_sorted->permute(this->perm3, this->perm3_rev, true); + auto ref_permuted = ref_permute(this->mtx3_sorted.get(), this->perm3.get(), + this->perm3_rev.get(), true); + + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); + GKO_ASSERT_MTX_EQ_SPARSITY(permuted, ref_permuted); + ASSERT_TRUE(permuted->is_sorted_by_column_index()); +} + + +TYPED_TEST(Csr, NonsymmPermuteRectangular) +{ + auto permuted = this->mtx2->permute(this->perm2, this->perm3); + auto ref_permuted = ref_permute(this->mtx2.get(), this->perm2.get(), + this->perm3.get(), false); + + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); + GKO_ASSERT_MTX_EQ_SPARSITY(permuted, ref_permuted); + ASSERT_TRUE(permuted->is_sorted_by_column_index()); +} + + +TYPED_TEST(Csr, NonsymmPermuteInverseRectangular) +{ + auto permuted = this->mtx2->permute(this->perm2, this->perm3, true); + auto ref_permuted = ref_permute(this->mtx2.get(), this->perm2.get(), + this->perm3.get(), true); + + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); + GKO_ASSERT_MTX_EQ_SPARSITY(permuted, ref_permuted); + ASSERT_TRUE(permuted->is_sorted_by_column_index()); +} + + +TYPED_TEST(Csr, NonsymmPermuteRoundtrip) +{ + auto permuted = this->mtx3_sorted->permute(this->perm3, this->perm3_rev) + ->permute(this->perm3, this->perm3_rev, true); + + GKO_ASSERT_MTX_NEAR(this->mtx3_sorted, permuted, 0.0); + GKO_ASSERT_MTX_EQ_SPARSITY(permuted, this->mtx3_sorted); + ASSERT_TRUE(permuted->is_sorted_by_column_index()); +} + + +TYPED_TEST(Csr, NonsymmPermuteFailsWithIncorrectPermutationSize) +{ + ASSERT_THROW(this->mtx3_sorted->permute(this->perm0, this->perm3_rev), + gko::ValueMismatch); + ASSERT_THROW(this->mtx3_sorted->permute(this->perm3_rev, this->perm0), + gko::ValueMismatch); + ASSERT_THROW(this->mtx3_sorted->permute(this->perm0, this->perm0), + gko::ValueMismatch); +} + + +TYPED_TEST(Csr, ScaledPermute) +{ + using gko::matrix::permute_mode; + using value_type = typename TestFixture::value_type; + + for (auto mode : + {permute_mode::none, permute_mode::rows, permute_mode::columns, + permute_mode::symmetric, permute_mode::inverse_rows, + permute_mode::inverse_columns, permute_mode::inverse_symmetric}) { + SCOPED_TRACE(mode); + + auto permuted = + this->mtx3_sorted->scale_permute(this->scale_perm3, mode); + auto ref_permuted = + ref_permute(this->mtx3_sorted.get(), this->scale_perm3.get(), mode); + + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, r::value); + GKO_ASSERT_MTX_EQ_SPARSITY(permuted, ref_permuted); + ASSERT_TRUE(permuted->is_sorted_by_column_index()); + } +} + + +TYPED_TEST(Csr, ScaledPermuteRoundtrip) +{ + using gko::matrix::permute_mode; + using value_type = typename TestFixture::value_type; + + for (auto mode : + {permute_mode::rows, permute_mode::columns, permute_mode::symmetric}) { + SCOPED_TRACE(mode); + + auto permuted = + this->mtx3_sorted->scale_permute(this->scale_perm3, mode) + ->scale_permute(this->scale_perm3, + mode | permute_mode::inverse); + + GKO_ASSERT_MTX_NEAR(this->mtx3_sorted, permuted, r::value); + GKO_ASSERT_MTX_EQ_SPARSITY(permuted, this->mtx3_sorted); + ASSERT_TRUE(permuted->is_sorted_by_column_index()); + } +} + + +TYPED_TEST(Csr, ScaledPermuteRectangular) +{ + using gko::matrix::permute_mode; + using value_type = typename TestFixture::value_type; + + auto rpermuted = + this->mtx2->scale_permute(this->scale_perm2, permute_mode::rows); + auto irpermuted = this->mtx2->scale_permute(this->scale_perm2, + permute_mode::inverse_rows); + auto cpermuted = + this->mtx2->scale_permute(this->scale_perm3, permute_mode::columns); + auto icpermuted = this->mtx2->scale_permute(this->scale_perm3, + permute_mode::inverse_columns); + auto ref_rpermuted = ref_permute(this->mtx2.get(), this->scale_perm2.get(), + permute_mode::rows); + auto ref_irpermuted = ref_permute(this->mtx2.get(), this->scale_perm2.get(), + permute_mode::inverse_rows); + auto ref_cpermuted = ref_permute(this->mtx2.get(), this->scale_perm3.get(), + permute_mode::columns); + auto ref_icpermuted = ref_permute(this->mtx2.get(), this->scale_perm3.get(), + permute_mode::inverse_columns); + + GKO_ASSERT_MTX_NEAR(rpermuted, ref_rpermuted, r::value); + GKO_ASSERT_MTX_NEAR(irpermuted, ref_irpermuted, r::value); + GKO_ASSERT_MTX_NEAR(cpermuted, ref_cpermuted, r::value); + GKO_ASSERT_MTX_NEAR(icpermuted, ref_icpermuted, r::value); + GKO_ASSERT_MTX_EQ_SPARSITY(rpermuted, ref_rpermuted); + GKO_ASSERT_MTX_EQ_SPARSITY(irpermuted, ref_irpermuted); + GKO_ASSERT_MTX_EQ_SPARSITY(cpermuted, ref_cpermuted); + GKO_ASSERT_MTX_EQ_SPARSITY(icpermuted, ref_icpermuted); + ASSERT_TRUE(rpermuted->is_sorted_by_column_index()); + ASSERT_TRUE(irpermuted->is_sorted_by_column_index()); + ASSERT_TRUE(cpermuted->is_sorted_by_column_index()); + ASSERT_TRUE(icpermuted->is_sorted_by_column_index()); +} + + +TYPED_TEST(Csr, ScaledPermuteFailsWithIncorrectPermutationSize) +{ + using gko::matrix::permute_mode; + + for (auto mode : + {/* no permute_mode::none */ permute_mode::rows, permute_mode::columns, + permute_mode::symmetric, permute_mode::inverse_rows, + permute_mode::inverse_columns, permute_mode::inverse_symmetric}) { + SCOPED_TRACE(mode); + + ASSERT_THROW(this->mtx3_sorted->scale_permute(this->scale_perm0, mode), + gko::ValueMismatch); + } +} + + +TYPED_TEST(Csr, NonsymmScaledPermute) +{ + using value_type = typename TestFixture::value_type; + + auto permuted = this->mtx3_sorted->scale_permute(this->scale_perm3, + this->scale_perm3_rev); + auto ref_permuted = + ref_permute(this->mtx3_sorted.get(), this->scale_perm3.get(), + this->scale_perm3_rev.get(), false); + + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, r::value); + GKO_ASSERT_MTX_EQ_SPARSITY(permuted, ref_permuted); + ASSERT_TRUE(permuted->is_sorted_by_column_index()); +} + + +TYPED_TEST(Csr, NonsymmScaledPermuteInverse) +{ + using value_type = typename TestFixture::value_type; + + auto permuted = this->mtx3_sorted->scale_permute( + this->scale_perm3, this->scale_perm3_rev, true); + auto ref_permuted = + ref_permute(this->mtx3_sorted.get(), this->scale_perm3.get(), + this->scale_perm3_rev.get(), true); + + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, r::value); + GKO_ASSERT_MTX_EQ_SPARSITY(permuted, ref_permuted); + ASSERT_TRUE(permuted->is_sorted_by_column_index()); +} + + +TYPED_TEST(Csr, NonsymmScaledPermuteRectangular) +{ + using value_type = typename TestFixture::value_type; + + auto permuted = + this->mtx2->scale_permute(this->scale_perm2, this->scale_perm3); + auto ref_permuted = ref_permute(this->mtx2.get(), this->scale_perm2.get(), + this->scale_perm3.get(), false); + + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, r::value); + GKO_ASSERT_MTX_EQ_SPARSITY(permuted, ref_permuted); + ASSERT_TRUE(permuted->is_sorted_by_column_index()); +} + + +TYPED_TEST(Csr, NonsymmScaledPermuteInverseRectangular) +{ + using value_type = typename TestFixture::value_type; + + auto permuted = + this->mtx2->scale_permute(this->scale_perm2, this->scale_perm3, true); + auto ref_permuted = ref_permute(this->mtx2.get(), this->scale_perm2.get(), + this->scale_perm3.get(), true); + + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, r::value); + GKO_ASSERT_MTX_EQ_SPARSITY(permuted, ref_permuted); + ASSERT_TRUE(permuted->is_sorted_by_column_index()); +} + + +TYPED_TEST(Csr, NonsymmScaledPermuteRoundtrip) +{ + using value_type = typename TestFixture::value_type; + + auto permuted = + this->mtx3_sorted + ->scale_permute(this->scale_perm3, this->scale_perm3_rev) + ->scale_permute(this->scale_perm3, this->scale_perm3_rev, true); + + GKO_ASSERT_MTX_NEAR(this->mtx3_sorted, permuted, r::value); + GKO_ASSERT_MTX_EQ_SPARSITY(permuted, this->mtx3_sorted); + ASSERT_TRUE(permuted->is_sorted_by_column_index()); +} + + +TYPED_TEST(Csr, NonsymmScaledPermuteFailsWithIncorrectPermutationSize) +{ + ASSERT_THROW(this->mtx3_sorted->scale_permute(this->scale_perm0, + this->scale_perm3_rev), + gko::ValueMismatch); + ASSERT_THROW(this->mtx3_sorted->scale_permute(this->scale_perm3_rev, + this->scale_perm0), + gko::ValueMismatch); + ASSERT_THROW( + this->mtx3_sorted->scale_permute(this->scale_perm0, this->scale_perm0), + gko::ValueMismatch); +} + + TYPED_TEST(Csr, SquareMatrixIsPermutable) { using Csr = typename TestFixture::Mtx; diff --git a/reference/test/matrix/dense_kernels.cpp b/reference/test/matrix/dense_kernels.cpp index 9edab89e382..7f614c4585e 100644 --- a/reference/test/matrix/dense_kernels.cpp +++ b/reference/test/matrix/dense_kernels.cpp @@ -50,12 +50,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include #include #include "core/matrix/dense_kernels.hpp" #include "core/test/utils.hpp" +#include "ginkgo/core/matrix/scaled_permutation.hpp" namespace { @@ -97,7 +99,6 @@ class Dense : public ::testing::Test { std::unique_ptr mtx6; std::unique_ptr mtx7; std::unique_ptr mtx8; - gko::int32 invalid_index = gko::invalid_index(); std::default_random_engine rand_engine; template @@ -780,3510 +781,2831 @@ TYPED_TEST(Dense, MovesToPrecision) } -TYPED_TEST(Dense, ConvertsToCoo32) +TYPED_TEST(Dense, ConvertsEmptyToPrecision) { + using Dense = typename TestFixture::Mtx; using T = typename TestFixture::value_type; - using Coo = typename gko::matrix::Coo; - auto coo_mtx = Coo::create(this->mtx4->get_executor()); + using OtherT = typename gko::next_precision; + using OtherDense = typename gko::matrix::Dense; + auto empty = OtherDense::create(this->exec); + auto res = Dense::create(this->exec); - this->mtx4->convert_to(coo_mtx); - auto v = coo_mtx->get_const_values(); - auto c = coo_mtx->get_const_col_idxs(); - auto r = coo_mtx->get_const_row_idxs(); + empty->convert_to(res); - ASSERT_EQ(coo_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(coo_mtx->get_num_stored_elements(), 4); - EXPECT_EQ(r[0], 0); - EXPECT_EQ(r[1], 0); - EXPECT_EQ(r[2], 0); - EXPECT_EQ(r[3], 1); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], 2); - EXPECT_EQ(c[3], 1); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{3.0}); - EXPECT_EQ(v[2], T{2.0}); - EXPECT_EQ(v[3], T{5.0}); + ASSERT_FALSE(res->get_size()); } -TYPED_TEST(Dense, MovesToCoo32) +TYPED_TEST(Dense, MovesEmptyToPrecision) { + using Dense = typename TestFixture::Mtx; using T = typename TestFixture::value_type; - using Coo = typename gko::matrix::Coo; - auto coo_mtx = Coo::create(this->mtx4->get_executor()); + using OtherT = typename gko::next_precision; + using OtherDense = typename gko::matrix::Dense; + auto empty = OtherDense::create(this->exec); + auto res = Dense::create(this->exec); - this->mtx4->move_to(coo_mtx); - auto v = coo_mtx->get_const_values(); - auto c = coo_mtx->get_const_col_idxs(); - auto r = coo_mtx->get_const_row_idxs(); + empty->move_to(res); - ASSERT_EQ(coo_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(coo_mtx->get_num_stored_elements(), 4); - EXPECT_EQ(r[0], 0); - EXPECT_EQ(r[1], 0); - EXPECT_EQ(r[2], 0); - EXPECT_EQ(r[3], 1); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], 2); - EXPECT_EQ(c[3], 1); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{3.0}); - EXPECT_EQ(v[2], T{2.0}); - EXPECT_EQ(v[3], T{5.0}); + ASSERT_FALSE(res->get_size()); } -TYPED_TEST(Dense, ConvertsToCoo64) +TYPED_TEST(Dense, SquareMatrixIsTransposable) { + using Mtx = typename TestFixture::Mtx; using T = typename TestFixture::value_type; - using Coo = typename gko::matrix::Coo; - auto coo_mtx = Coo::create(this->mtx4->get_executor()); - - this->mtx4->convert_to(coo_mtx); - auto v = coo_mtx->get_const_values(); - auto c = coo_mtx->get_const_col_idxs(); - auto r = coo_mtx->get_const_row_idxs(); + auto trans = gko::as(this->mtx5->transpose()); - ASSERT_EQ(coo_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(coo_mtx->get_num_stored_elements(), 4); - EXPECT_EQ(r[0], 0); - EXPECT_EQ(r[1], 0); - EXPECT_EQ(r[2], 0); - EXPECT_EQ(r[3], 1); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], 2); - EXPECT_EQ(c[3], 1); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{3.0}); - EXPECT_EQ(v[2], T{2.0}); - EXPECT_EQ(v[3], T{5.0}); + GKO_ASSERT_MTX_NEAR( + trans, l({{1.0, -2.0, 2.1}, {-1.0, 2.0, 3.4}, {-0.5, 4.5, 1.2}}), + 0.0); } -TYPED_TEST(Dense, MovesToCoo64) +TYPED_TEST(Dense, SquareMatrixIsTransposableIntoDense) { + using Mtx = typename TestFixture::Mtx; using T = typename TestFixture::value_type; - using Coo = typename gko::matrix::Coo; - auto coo_mtx = Coo::create(this->mtx4->get_executor()); + auto trans = Mtx::create(this->exec, this->mtx5->get_size()); - this->mtx4->move_to(coo_mtx); - auto v = coo_mtx->get_const_values(); - auto c = coo_mtx->get_const_col_idxs(); - auto r = coo_mtx->get_const_row_idxs(); + this->mtx5->transpose(trans); - ASSERT_EQ(coo_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(coo_mtx->get_num_stored_elements(), 4); - EXPECT_EQ(r[0], 0); - EXPECT_EQ(r[1], 0); - EXPECT_EQ(r[2], 0); - EXPECT_EQ(r[3], 1); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], 2); - EXPECT_EQ(c[3], 1); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{3.0}); - EXPECT_EQ(v[2], T{2.0}); - EXPECT_EQ(v[3], T{5.0}); + GKO_ASSERT_MTX_NEAR( + trans, l({{1.0, -2.0, 2.1}, {-1.0, 2.0, 3.4}, {-0.5, 4.5, 1.2}}), + 0.0); } -TYPED_TEST(Dense, ConvertsToCsr32) +TYPED_TEST(Dense, SquareSubmatrixIsTransposableIntoDense) { + using Mtx = typename TestFixture::Mtx; using T = typename TestFixture::value_type; - using Csr = typename gko::matrix::Csr; - auto csr_s_classical = std::make_shared(); - auto csr_s_merge = std::make_shared(); - auto csr_mtx_c = Csr::create(this->mtx4->get_executor(), csr_s_classical); - auto csr_mtx_m = Csr::create(this->mtx4->get_executor(), csr_s_merge); + auto trans = Mtx::create(this->exec, gko::dim<2>{2, 2}, 4); - this->mtx4->convert_to(csr_mtx_c); - this->mtx4->convert_to(csr_mtx_m); + this->mtx5->create_submatrix({0, 2}, {0, 2})->transpose(trans); - auto v = csr_mtx_c->get_const_values(); - auto c = csr_mtx_c->get_const_col_idxs(); - auto r = csr_mtx_c->get_const_row_ptrs(); - ASSERT_EQ(csr_mtx_c->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(csr_mtx_c->get_num_stored_elements(), 4); - EXPECT_EQ(r[0], 0); - EXPECT_EQ(r[1], 3); - EXPECT_EQ(r[2], 4); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], 2); - EXPECT_EQ(c[3], 1); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{3.0}); - EXPECT_EQ(v[2], T{2.0}); - EXPECT_EQ(v[3], T{5.0}); - ASSERT_EQ(csr_mtx_c->get_strategy()->get_name(), "classical"); - GKO_ASSERT_MTX_NEAR(csr_mtx_c, csr_mtx_m, 0.0); - ASSERT_EQ(csr_mtx_m->get_strategy()->get_name(), "merge_path"); + GKO_ASSERT_MTX_NEAR(trans, l({{1.0, -2.0}, {-1.0, 2.0}}), 0.0); + ASSERT_EQ(trans->get_stride(), 4); } -TYPED_TEST(Dense, MovesToCsr32) +TYPED_TEST(Dense, SquareMatrixIsTransposableIntoDenseFailsForWrongDimensions) { - using T = typename TestFixture::value_type; - using Csr = typename gko::matrix::Csr; - auto csr_s_classical = std::make_shared(); - auto csr_s_merge = std::make_shared(); - auto csr_mtx_c = Csr::create(this->mtx4->get_executor(), csr_s_classical); - auto csr_mtx_m = Csr::create(this->mtx4->get_executor(), csr_s_merge); - auto mtx_clone = this->mtx4->clone(); - - this->mtx4->move_to(csr_mtx_c); - mtx_clone->move_to(csr_mtx_m); + using Mtx = typename TestFixture::Mtx; - auto v = csr_mtx_c->get_const_values(); - auto c = csr_mtx_c->get_const_col_idxs(); - auto r = csr_mtx_c->get_const_row_ptrs(); - ASSERT_EQ(csr_mtx_c->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(csr_mtx_c->get_num_stored_elements(), 4); - EXPECT_EQ(r[0], 0); - EXPECT_EQ(r[1], 3); - EXPECT_EQ(r[2], 4); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], 2); - EXPECT_EQ(c[3], 1); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{3.0}); - EXPECT_EQ(v[2], T{2.0}); - EXPECT_EQ(v[3], T{5.0}); - ASSERT_EQ(csr_mtx_c->get_strategy()->get_name(), "classical"); - GKO_ASSERT_MTX_NEAR(csr_mtx_c, csr_mtx_m, 0.0); - ASSERT_EQ(csr_mtx_m->get_strategy()->get_name(), "merge_path"); + ASSERT_THROW(this->mtx5->transpose(Mtx::create(this->exec)), + gko::DimensionMismatch); } -TYPED_TEST(Dense, ConvertsToCsr64) +TYPED_TEST(Dense, NonSquareMatrixIsTransposable) { + using Mtx = typename TestFixture::Mtx; using T = typename TestFixture::value_type; - using Csr = typename gko::matrix::Csr; - auto csr_s_classical = std::make_shared(); - auto csr_s_merge = std::make_shared(); - auto csr_mtx_c = Csr::create(this->mtx4->get_executor(), csr_s_classical); - auto csr_mtx_m = Csr::create(this->mtx4->get_executor(), csr_s_merge); - - this->mtx4->convert_to(csr_mtx_c); - this->mtx4->convert_to(csr_mtx_m); + auto trans = gko::as(this->mtx4->transpose()); - auto v = csr_mtx_c->get_const_values(); - auto c = csr_mtx_c->get_const_col_idxs(); - auto r = csr_mtx_c->get_const_row_ptrs(); - ASSERT_EQ(csr_mtx_c->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(csr_mtx_c->get_num_stored_elements(), 4); - EXPECT_EQ(r[0], 0); - EXPECT_EQ(r[1], 3); - EXPECT_EQ(r[2], 4); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], 2); - EXPECT_EQ(c[3], 1); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{3.0}); - EXPECT_EQ(v[2], T{2.0}); - EXPECT_EQ(v[3], T{5.0}); - ASSERT_EQ(csr_mtx_c->get_strategy()->get_name(), "classical"); - GKO_ASSERT_MTX_NEAR(csr_mtx_c, csr_mtx_m, 0.0); - ASSERT_EQ(csr_mtx_m->get_strategy()->get_name(), "merge_path"); + GKO_ASSERT_MTX_NEAR(trans, l({{1.0, 0.0}, {3.0, 5.0}, {2.0, 0.0}}), 0.0); } -TYPED_TEST(Dense, MovesToCsr64) +TYPED_TEST(Dense, NonSquareMatrixIsTransposableIntoDense) { + using Mtx = typename TestFixture::Mtx; using T = typename TestFixture::value_type; - using Csr = typename gko::matrix::Csr; - auto csr_s_classical = std::make_shared(); - auto csr_s_merge = std::make_shared(); - auto csr_mtx_c = Csr::create(this->mtx4->get_executor(), csr_s_classical); - auto csr_mtx_m = Csr::create(this->mtx4->get_executor(), csr_s_merge); - auto mtx_clone = this->mtx4->clone(); + auto trans = + Mtx::create(this->exec, gko::transpose(this->mtx4->get_size())); - this->mtx4->move_to(csr_mtx_c); - mtx_clone->move_to(csr_mtx_m); + this->mtx4->transpose(trans); - auto v = csr_mtx_c->get_const_values(); - auto c = csr_mtx_c->get_const_col_idxs(); - auto r = csr_mtx_c->get_const_row_ptrs(); - ASSERT_EQ(csr_mtx_c->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(csr_mtx_c->get_num_stored_elements(), 4); - EXPECT_EQ(r[0], 0); - EXPECT_EQ(r[1], 3); - EXPECT_EQ(r[2], 4); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], 2); - EXPECT_EQ(c[3], 1); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{3.0}); - EXPECT_EQ(v[2], T{2.0}); - EXPECT_EQ(v[3], T{5.0}); - ASSERT_EQ(csr_mtx_c->get_strategy()->get_name(), "classical"); - GKO_ASSERT_MTX_NEAR(csr_mtx_c, csr_mtx_m, 0.0); - ASSERT_EQ(csr_mtx_m->get_strategy()->get_name(), "merge_path"); + GKO_ASSERT_MTX_NEAR(trans, l({{1.0, 0.0}, {3.0, 5.0}, {2.0, 0.0}}), 0.0); } -TYPED_TEST(Dense, ConvertsToSparsityCsr32) +TYPED_TEST(Dense, NonSquareSubmatrixIsTransposableIntoDense) { + using Mtx = typename TestFixture::Mtx; using T = typename TestFixture::value_type; - using SparsityCsr = typename gko::matrix::SparsityCsr; - auto sparsity_csr_mtx = SparsityCsr::create(this->mtx4->get_executor()); + auto trans = Mtx::create(this->exec, gko::dim<2>{2, 1}, 5); - this->mtx4->convert_to(sparsity_csr_mtx); - auto v = sparsity_csr_mtx->get_const_value(); - auto c = sparsity_csr_mtx->get_const_col_idxs(); - auto r = sparsity_csr_mtx->get_const_row_ptrs(); + this->mtx4->create_submatrix({0, 1}, {0, 2})->transpose(trans); - ASSERT_EQ(sparsity_csr_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(sparsity_csr_mtx->get_num_nonzeros(), 4); - EXPECT_EQ(r[0], 0); - EXPECT_EQ(r[1], 3); - EXPECT_EQ(r[2], 4); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], 2); - EXPECT_EQ(c[3], 1); - EXPECT_EQ(v[0], T{1.0}); + GKO_ASSERT_MTX_NEAR(trans, l({1.0, 3.0}), 0.0); + ASSERT_EQ(trans->get_stride(), 5); +} + + +TYPED_TEST(Dense, NonSquareMatrixIsTransposableIntoDenseFailsForWrongDimensions) +{ + using Mtx = typename TestFixture::Mtx; + + ASSERT_THROW(this->mtx4->transpose(Mtx::create(this->exec)), + gko::DimensionMismatch); } -TYPED_TEST(Dense, MovesToSparsityCsr32) +TYPED_TEST(Dense, ExtractsDiagonalFromSquareMatrix) { using T = typename TestFixture::value_type; - using SparsityCsr = typename gko::matrix::SparsityCsr; - auto sparsity_csr_mtx = SparsityCsr::create(this->mtx4->get_executor()); - this->mtx4->move_to(sparsity_csr_mtx); - auto v = sparsity_csr_mtx->get_const_value(); - auto c = sparsity_csr_mtx->get_const_col_idxs(); - auto r = sparsity_csr_mtx->get_const_row_ptrs(); + auto diag = this->mtx5->extract_diagonal(); - ASSERT_EQ(sparsity_csr_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(sparsity_csr_mtx->get_num_nonzeros(), 4); - EXPECT_EQ(r[0], 0); - EXPECT_EQ(r[1], 3); - EXPECT_EQ(r[2], 4); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], 2); - EXPECT_EQ(c[3], 1); - EXPECT_EQ(v[0], T{1.0}); + ASSERT_EQ(diag->get_size()[0], 3); + ASSERT_EQ(diag->get_size()[1], 3); + ASSERT_EQ(diag->get_values()[0], T{1.}); + ASSERT_EQ(diag->get_values()[1], T{2.}); + ASSERT_EQ(diag->get_values()[2], T{1.2}); } -TYPED_TEST(Dense, ConvertsToSparsityCsr64) +TYPED_TEST(Dense, ExtractsDiagonalFromTallSkinnyMatrix) { using T = typename TestFixture::value_type; - using SparsityCsr = typename gko::matrix::SparsityCsr; - auto sparsity_csr_mtx = SparsityCsr::create(this->mtx4->get_executor()); - this->mtx4->convert_to(sparsity_csr_mtx); - auto v = sparsity_csr_mtx->get_const_value(); - auto c = sparsity_csr_mtx->get_const_col_idxs(); - auto r = sparsity_csr_mtx->get_const_row_ptrs(); + auto diag = this->mtx4->extract_diagonal(); - ASSERT_EQ(sparsity_csr_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(sparsity_csr_mtx->get_num_nonzeros(), 4); - EXPECT_EQ(r[0], 0); - EXPECT_EQ(r[1], 3); - EXPECT_EQ(r[2], 4); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], 2); - EXPECT_EQ(c[3], 1); - EXPECT_EQ(v[0], T{1.0}); + ASSERT_EQ(diag->get_size()[0], 2); + ASSERT_EQ(diag->get_size()[1], 2); + ASSERT_EQ(diag->get_values()[0], T{1.}); + ASSERT_EQ(diag->get_values()[1], T{5.}); } -TYPED_TEST(Dense, MovesToSparsityCsr64) +TYPED_TEST(Dense, ExtractsDiagonalFromShortFatMatrix) { using T = typename TestFixture::value_type; - using SparsityCsr = typename gko::matrix::SparsityCsr; - auto sparsity_csr_mtx = SparsityCsr::create(this->mtx4->get_executor()); - this->mtx4->move_to(sparsity_csr_mtx); - auto v = sparsity_csr_mtx->get_const_value(); - auto c = sparsity_csr_mtx->get_const_col_idxs(); - auto r = sparsity_csr_mtx->get_const_row_ptrs(); + auto diag = this->mtx8->extract_diagonal(); - ASSERT_EQ(sparsity_csr_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(sparsity_csr_mtx->get_num_nonzeros(), 4); - EXPECT_EQ(r[0], 0); - EXPECT_EQ(r[1], 3); - EXPECT_EQ(r[2], 4); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], 2); - EXPECT_EQ(c[3], 1); - EXPECT_EQ(v[0], T{1.0}); + ASSERT_EQ(diag->get_size()[0], 2); + ASSERT_EQ(diag->get_size()[1], 2); + ASSERT_EQ(diag->get_values()[0], T{1.}); + ASSERT_EQ(diag->get_values()[1], T{2.}); } -TYPED_TEST(Dense, ConvertsToEll32) +TYPED_TEST(Dense, ExtractsDiagonalFromSquareMatrixIntoDiagonal) { using T = typename TestFixture::value_type; - using Ell = typename gko::matrix::Ell; - auto ell_mtx = Ell::create(this->mtx6->get_executor()); + auto diag = gko::matrix::Diagonal::create(this->exec, 3); - this->mtx6->convert_to(ell_mtx); - auto v = ell_mtx->get_const_values(); - auto c = ell_mtx->get_const_col_idxs(); + this->mtx5->extract_diagonal(diag); - ASSERT_EQ(ell_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(ell_mtx->get_num_stored_elements_per_row(), 2); - ASSERT_EQ(ell_mtx->get_num_stored_elements(), 4); - ASSERT_EQ(ell_mtx->get_stride(), 2); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], 1); - EXPECT_EQ(c[3], this->invalid_index); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{1.5}); - EXPECT_EQ(v[2], T{2.0}); - EXPECT_EQ(v[3], T{0.0}); + ASSERT_EQ(diag->get_size()[0], 3); + ASSERT_EQ(diag->get_size()[1], 3); + ASSERT_EQ(diag->get_values()[0], T{1.}); + ASSERT_EQ(diag->get_values()[1], T{2.}); + ASSERT_EQ(diag->get_values()[2], T{1.2}); } -TYPED_TEST(Dense, MovesToEll32) +TYPED_TEST(Dense, ExtractsDiagonalFromTallSkinnyMatrixIntoDiagonal) { using T = typename TestFixture::value_type; - using Ell = typename gko::matrix::Ell; - auto ell_mtx = Ell::create(this->mtx6->get_executor()); + auto diag = gko::matrix::Diagonal::create(this->exec, 2); - this->mtx6->move_to(ell_mtx); - auto v = ell_mtx->get_const_values(); - auto c = ell_mtx->get_const_col_idxs(); + this->mtx4->extract_diagonal(diag); - ASSERT_EQ(ell_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(ell_mtx->get_num_stored_elements_per_row(), 2); - ASSERT_EQ(ell_mtx->get_num_stored_elements(), 4); - ASSERT_EQ(ell_mtx->get_stride(), 2); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], 1); - EXPECT_EQ(c[3], this->invalid_index); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{1.5}); - EXPECT_EQ(v[2], T{2.0}); - EXPECT_EQ(v[3], T{0.0}); + ASSERT_EQ(diag->get_size()[0], 2); + ASSERT_EQ(diag->get_size()[1], 2); + ASSERT_EQ(diag->get_values()[0], T{1.}); + ASSERT_EQ(diag->get_values()[1], T{5.}); } -TYPED_TEST(Dense, ConvertsToEll64) +TYPED_TEST(Dense, ExtractsDiagonalFromShortFatMatrixIntoDiagonal) { using T = typename TestFixture::value_type; - using Ell = typename gko::matrix::Ell; - auto ell_mtx = Ell::create(this->mtx6->get_executor()); + auto diag = gko::matrix::Diagonal::create(this->exec, 2); - this->mtx6->convert_to(ell_mtx); - auto v = ell_mtx->get_const_values(); - auto c = ell_mtx->get_const_col_idxs(); + this->mtx8->extract_diagonal(diag); - ASSERT_EQ(ell_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(ell_mtx->get_num_stored_elements_per_row(), 2); - ASSERT_EQ(ell_mtx->get_num_stored_elements(), 4); - ASSERT_EQ(ell_mtx->get_stride(), 2); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], 1); - EXPECT_EQ(c[3], this->invalid_index); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{1.5}); - EXPECT_EQ(v[2], T{2.0}); - EXPECT_EQ(v[3], T{0.0}); + ASSERT_EQ(diag->get_size()[0], 2); + ASSERT_EQ(diag->get_size()[1], 2); + ASSERT_EQ(diag->get_values()[0], T{1.}); + ASSERT_EQ(diag->get_values()[1], T{2.}); } -TYPED_TEST(Dense, MovesToEll64) +TYPED_TEST(Dense, InplaceAbsolute) { using T = typename TestFixture::value_type; - using Ell = typename gko::matrix::Ell; - auto ell_mtx = Ell::create(this->mtx6->get_executor()); - this->mtx6->move_to(ell_mtx); - auto v = ell_mtx->get_const_values(); - auto c = ell_mtx->get_const_col_idxs(); + this->mtx5->compute_absolute_inplace(); - ASSERT_EQ(ell_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(ell_mtx->get_num_stored_elements_per_row(), 2); - ASSERT_EQ(ell_mtx->get_num_stored_elements(), 4); - ASSERT_EQ(ell_mtx->get_stride(), 2); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], 1); - EXPECT_EQ(c[3], this->invalid_index); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{1.5}); - EXPECT_EQ(v[2], T{2.0}); - EXPECT_EQ(v[3], T{0.0}); + GKO_ASSERT_MTX_NEAR( + this->mtx5, l({{1.0, 1.0, 0.5}, {2.0, 2.0, 4.5}, {2.1, 3.4, 1.2}}), + 0.0); } -TYPED_TEST(Dense, ConvertsToEllWithStride) +TYPED_TEST(Dense, InplaceAbsoluteSubMatrix) { using T = typename TestFixture::value_type; - using Ell = typename gko::matrix::Ell; - auto ell_mtx = - Ell::create(this->mtx6->get_executor(), gko::dim<2>{2, 3}, 2, 3); + auto mtx = this->mtx5->create_submatrix(gko::span{0, 2}, gko::span{0, 2}); - this->mtx6->convert_to(ell_mtx); - auto v = ell_mtx->get_const_values(); - auto c = ell_mtx->get_const_col_idxs(); + mtx->compute_absolute_inplace(); - ASSERT_EQ(ell_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(ell_mtx->get_num_stored_elements_per_row(), 2); - ASSERT_EQ(ell_mtx->get_num_stored_elements(), 6); - ASSERT_EQ(ell_mtx->get_stride(), 3); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], this->invalid_index); - EXPECT_EQ(c[3], 1); - EXPECT_EQ(c[4], this->invalid_index); - EXPECT_EQ(c[5], this->invalid_index); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{1.5}); - EXPECT_EQ(v[2], T{0.0}); - EXPECT_EQ(v[3], T{2.0}); - EXPECT_EQ(v[4], T{0.0}); - EXPECT_EQ(v[5], T{0.0}); + GKO_ASSERT_MTX_NEAR( + this->mtx5, l({{1.0, 1.0, -0.5}, {2.0, 2.0, 4.5}, {2.1, 3.4, 1.2}}), + 0.0); } -TYPED_TEST(Dense, MovesToEllWithStride) +TYPED_TEST(Dense, OutplaceAbsolute) { using T = typename TestFixture::value_type; - using Ell = typename gko::matrix::Ell; - auto ell_mtx = - Ell::create(this->mtx6->get_executor(), gko::dim<2>{2, 3}, 2, 3); - this->mtx6->move_to(ell_mtx); - auto v = ell_mtx->get_const_values(); - auto c = ell_mtx->get_const_col_idxs(); + auto abs_mtx = this->mtx5->compute_absolute(); - ASSERT_EQ(ell_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(ell_mtx->get_num_stored_elements_per_row(), 2); - ASSERT_EQ(ell_mtx->get_num_stored_elements(), 6); - ASSERT_EQ(ell_mtx->get_stride(), 3); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], this->invalid_index); - EXPECT_EQ(c[3], 1); - EXPECT_EQ(c[4], this->invalid_index); - EXPECT_EQ(c[5], this->invalid_index); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{1.5}); - EXPECT_EQ(v[2], T{0.0}); - EXPECT_EQ(v[3], T{2.0}); - EXPECT_EQ(v[4], T{0.0}); - EXPECT_EQ(v[5], T{0.0}); + GKO_ASSERT_MTX_NEAR( + abs_mtx, l({{1.0, 1.0, 0.5}, {2.0, 2.0, 4.5}, {2.1, 3.4, 1.2}}), + 0.0); } -TYPED_TEST(Dense, MovesToHybridAutomatically32) +TYPED_TEST(Dense, OutplaceAbsoluteIntoDense) { + using Mtx = typename TestFixture::Mtx; using T = typename TestFixture::value_type; - using Hybrid = typename gko::matrix::Hybrid; - auto hybrid_mtx = Hybrid::create(this->mtx4->get_executor()); + auto abs_mtx = + gko::remove_complex::create(this->exec, this->mtx5->get_size()); - this->mtx4->move_to(hybrid_mtx); - auto v = hybrid_mtx->get_const_coo_values(); - auto c = hybrid_mtx->get_const_coo_col_idxs(); - auto r = hybrid_mtx->get_const_coo_row_idxs(); - auto n = hybrid_mtx->get_ell_num_stored_elements_per_row(); - auto p = hybrid_mtx->get_ell_stride(); + this->mtx5->compute_absolute(abs_mtx); - ASSERT_EQ(hybrid_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(hybrid_mtx->get_ell_num_stored_elements(), 0); - ASSERT_EQ(hybrid_mtx->get_coo_num_stored_elements(), 4); - EXPECT_EQ(n, 0); - EXPECT_EQ(p, 2); - EXPECT_EQ(r[0], 0); - EXPECT_EQ(r[1], 0); - EXPECT_EQ(r[2], 0); - EXPECT_EQ(r[3], 1); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], 2); - EXPECT_EQ(c[3], 1); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{3.0}); - EXPECT_EQ(v[2], T{2.0}); - EXPECT_EQ(v[3], T{5.0}); + GKO_ASSERT_MTX_NEAR( + abs_mtx, l({{1.0, 1.0, 0.5}, {2.0, 2.0, 4.5}, {2.1, 3.4, 1.2}}), + 0.0); } -TYPED_TEST(Dense, ConvertsToHybridAutomatically32) +TYPED_TEST(Dense, OutplaceAbsoluteSubMatrix) { using T = typename TestFixture::value_type; - using Hybrid = typename gko::matrix::Hybrid; - auto hybrid_mtx = Hybrid::create(this->mtx4->get_executor()); + auto mtx = this->mtx5->create_submatrix(gko::span{0, 2}, gko::span{0, 2}); - this->mtx4->convert_to(hybrid_mtx); - auto v = hybrid_mtx->get_const_coo_values(); - auto c = hybrid_mtx->get_const_coo_col_idxs(); - auto r = hybrid_mtx->get_const_coo_row_idxs(); - auto n = hybrid_mtx->get_ell_num_stored_elements_per_row(); - auto p = hybrid_mtx->get_ell_stride(); + auto abs_mtx = mtx->compute_absolute(); - ASSERT_EQ(hybrid_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(hybrid_mtx->get_ell_num_stored_elements(), 0); - ASSERT_EQ(hybrid_mtx->get_coo_num_stored_elements(), 4); - EXPECT_EQ(n, 0); - EXPECT_EQ(p, 2); - EXPECT_EQ(r[0], 0); - EXPECT_EQ(r[1], 0); - EXPECT_EQ(r[2], 0); - EXPECT_EQ(r[3], 1); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], 2); - EXPECT_EQ(c[3], 1); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{3.0}); - EXPECT_EQ(v[2], T{2.0}); - EXPECT_EQ(v[3], T{5.0}); + GKO_ASSERT_MTX_NEAR(abs_mtx, l({{1.0, 1.0}, {2.0, 2.0}}), 0); + GKO_ASSERT_EQ(abs_mtx->get_stride(), 2); } -TYPED_TEST(Dense, MovesToHybridAutomatically64) +TYPED_TEST(Dense, OutplaceSubmatrixAbsoluteIntoDense) { + using Mtx = typename TestFixture::Mtx; using T = typename TestFixture::value_type; - using Hybrid = typename gko::matrix::Hybrid; - auto hybrid_mtx = Hybrid::create(this->mtx4->get_executor()); + auto mtx = this->mtx5->create_submatrix(gko::span{0, 2}, gko::span{0, 2}); + auto abs_mtx = + gko::remove_complex::create(this->exec, gko::dim<2>{2, 2}, 4); - this->mtx4->move_to(hybrid_mtx); - auto v = hybrid_mtx->get_const_coo_values(); - auto c = hybrid_mtx->get_const_coo_col_idxs(); - auto r = hybrid_mtx->get_const_coo_row_idxs(); - auto n = hybrid_mtx->get_ell_num_stored_elements_per_row(); - auto p = hybrid_mtx->get_ell_stride(); + mtx->compute_absolute(abs_mtx); - ASSERT_EQ(hybrid_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(hybrid_mtx->get_ell_num_stored_elements(), 0); - ASSERT_EQ(hybrid_mtx->get_coo_num_stored_elements(), 4); - EXPECT_EQ(n, 0); - EXPECT_EQ(p, 2); - EXPECT_EQ(r[0], 0); - EXPECT_EQ(r[1], 0); - EXPECT_EQ(r[2], 0); - EXPECT_EQ(r[3], 1); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], 2); - EXPECT_EQ(c[3], 1); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{3.0}); - EXPECT_EQ(v[2], T{2.0}); - EXPECT_EQ(v[3], T{5.0}); + GKO_ASSERT_MTX_NEAR(abs_mtx, l({{1.0, 1.0}, {2.0, 2.0}}), 0); + GKO_ASSERT_EQ(abs_mtx->get_stride(), 4); } -TYPED_TEST(Dense, ConvertsToHybridAutomatically64) +TYPED_TEST(Dense, AppliesToComplex) { - using T = typename TestFixture::value_type; - using Hybrid = typename gko::matrix::Hybrid; - auto hybrid_mtx = Hybrid::create(this->mtx4->get_executor()); + using value_type = typename TestFixture::value_type; + using complex_type = gko::to_complex; + using Vec = gko::matrix::Dense; + auto exec = gko::ReferenceExecutor::create(); + auto b = + gko::initialize({{complex_type{1.0, 0.0}, complex_type{2.0, 1.0}}, + {complex_type{2.0, 2.0}, complex_type{3.0, 3.0}}, + {complex_type{3.0, 4.0}, complex_type{4.0, 5.0}}}, + exec); + auto x = Vec::create(exec, gko::dim<2>{2, 2}); - this->mtx4->convert_to(hybrid_mtx); - auto v = hybrid_mtx->get_const_coo_values(); - auto c = hybrid_mtx->get_const_coo_col_idxs(); - auto r = hybrid_mtx->get_const_coo_row_idxs(); - auto n = hybrid_mtx->get_ell_num_stored_elements_per_row(); - auto p = hybrid_mtx->get_ell_stride(); + this->mtx1->apply(b, x); - ASSERT_EQ(hybrid_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(hybrid_mtx->get_ell_num_stored_elements(), 0); - ASSERT_EQ(hybrid_mtx->get_coo_num_stored_elements(), 4); - EXPECT_EQ(n, 0); - EXPECT_EQ(p, 2); - EXPECT_EQ(r[0], 0); - EXPECT_EQ(r[1], 0); - EXPECT_EQ(r[2], 0); - EXPECT_EQ(r[3], 1); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], 2); - EXPECT_EQ(c[3], 1); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{3.0}); - EXPECT_EQ(v[2], T{2.0}); - EXPECT_EQ(v[3], T{5.0}); + GKO_ASSERT_MTX_NEAR( + x, + l({{complex_type{14.0, 16.0}, complex_type{20.0, 22.0}}, + {complex_type{17.0, 19.0}, complex_type{24.5, 26.5}}}), + 0.0); } -TYPED_TEST(Dense, MovesToHybridWithStrideAutomatically) +TYPED_TEST(Dense, AppliesToMixedComplex) { - using T = typename TestFixture::value_type; - using Hybrid = typename gko::matrix::Hybrid; - auto hybrid_mtx = - Hybrid::create(this->mtx4->get_executor(), gko::dim<2>{2, 3}, 0, 3); + using mixed_value_type = + gko::next_precision; + using mixed_complex_type = gko::to_complex; + using Vec = gko::matrix::Dense; + auto exec = gko::ReferenceExecutor::create(); + auto b = gko::initialize( + {{mixed_complex_type{1.0, 0.0}, mixed_complex_type{2.0, 1.0}}, + {mixed_complex_type{2.0, 2.0}, mixed_complex_type{3.0, 3.0}}, + {mixed_complex_type{3.0, 4.0}, mixed_complex_type{4.0, 5.0}}}, + exec); + auto x = Vec::create(exec, gko::dim<2>{2, 2}); - this->mtx4->move_to(hybrid_mtx); - auto v = hybrid_mtx->get_const_coo_values(); - auto c = hybrid_mtx->get_const_coo_col_idxs(); - auto r = hybrid_mtx->get_const_coo_row_idxs(); - auto n = hybrid_mtx->get_ell_num_stored_elements_per_row(); - auto p = hybrid_mtx->get_ell_stride(); - - ASSERT_EQ(hybrid_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(hybrid_mtx->get_ell_num_stored_elements(), 0); - ASSERT_EQ(hybrid_mtx->get_coo_num_stored_elements(), 4); - EXPECT_EQ(n, 0); - EXPECT_EQ(p, 3); - EXPECT_EQ(r[0], 0); - EXPECT_EQ(r[1], 0); - EXPECT_EQ(r[2], 0); - EXPECT_EQ(r[3], 1); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], 2); - EXPECT_EQ(c[3], 1); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{3.0}); - EXPECT_EQ(v[2], T{2.0}); - EXPECT_EQ(v[3], T{5.0}); -} - - -TYPED_TEST(Dense, ConvertsToHybridWithStrideAutomatically) -{ - using T = typename TestFixture::value_type; - using Hybrid = typename gko::matrix::Hybrid; - auto hybrid_mtx = - Hybrid::create(this->mtx4->get_executor(), gko::dim<2>{2, 3}, 0, 3); - - this->mtx4->convert_to(hybrid_mtx); - auto v = hybrid_mtx->get_const_coo_values(); - auto c = hybrid_mtx->get_const_coo_col_idxs(); - auto r = hybrid_mtx->get_const_coo_row_idxs(); - auto n = hybrid_mtx->get_ell_num_stored_elements_per_row(); - auto p = hybrid_mtx->get_ell_stride(); - - ASSERT_EQ(hybrid_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(hybrid_mtx->get_ell_num_stored_elements(), 0); - ASSERT_EQ(hybrid_mtx->get_coo_num_stored_elements(), 4); - EXPECT_EQ(n, 0); - EXPECT_EQ(p, 3); - EXPECT_EQ(r[0], 0); - EXPECT_EQ(r[1], 0); - EXPECT_EQ(r[2], 0); - EXPECT_EQ(r[3], 1); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], 2); - EXPECT_EQ(c[3], 1); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{3.0}); - EXPECT_EQ(v[2], T{2.0}); - EXPECT_EQ(v[3], T{5.0}); -} - - -TYPED_TEST(Dense, MovesToHybridWithStrideAndCooLengthByColumns2) -{ - using T = typename TestFixture::value_type; - using Hybrid = typename gko::matrix::Hybrid; - auto hybrid_mtx = - Hybrid::create(this->mtx4->get_executor(), gko::dim<2>{2, 3}, 2, 3, 3, - std::make_shared(2)); - - this->mtx4->move_to(hybrid_mtx); - auto v = hybrid_mtx->get_const_ell_values(); - auto c = hybrid_mtx->get_const_ell_col_idxs(); - auto n = hybrid_mtx->get_ell_num_stored_elements_per_row(); - auto p = hybrid_mtx->get_ell_stride(); - - ASSERT_EQ(hybrid_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(hybrid_mtx->get_ell_num_stored_elements(), 6); - ASSERT_EQ(hybrid_mtx->get_coo_num_stored_elements(), 1); - EXPECT_EQ(n, 2); - EXPECT_EQ(p, 3); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], this->invalid_index); - EXPECT_EQ(c[3], 1); - EXPECT_EQ(c[4], this->invalid_index); - EXPECT_EQ(c[5], this->invalid_index); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{5.0}); - EXPECT_EQ(v[2], T{0.0}); - EXPECT_EQ(v[3], T{3.0}); - EXPECT_EQ(v[4], T{0.0}); - EXPECT_EQ(v[5], T{0.0}); - EXPECT_EQ(hybrid_mtx->get_const_coo_values()[0], T{2.0}); - EXPECT_EQ(hybrid_mtx->get_const_coo_row_idxs()[0], 0); - EXPECT_EQ(hybrid_mtx->get_const_coo_col_idxs()[0], 2); -} - - -TYPED_TEST(Dense, ConvertsToHybridWithStrideAndCooLengthByColumns2) -{ - using T = typename TestFixture::value_type; - using Hybrid = typename gko::matrix::Hybrid; - auto hybrid_mtx = - Hybrid::create(this->mtx4->get_executor(), gko::dim<2>{2, 3}, 2, 3, 3, - std::make_shared(2)); - - this->mtx4->convert_to(hybrid_mtx); - auto v = hybrid_mtx->get_const_ell_values(); - auto c = hybrid_mtx->get_const_ell_col_idxs(); - auto n = hybrid_mtx->get_ell_num_stored_elements_per_row(); - auto p = hybrid_mtx->get_ell_stride(); - - ASSERT_EQ(hybrid_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(hybrid_mtx->get_ell_num_stored_elements(), 6); - ASSERT_EQ(hybrid_mtx->get_coo_num_stored_elements(), 1); - EXPECT_EQ(n, 2); - EXPECT_EQ(p, 3); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], this->invalid_index); - EXPECT_EQ(c[3], 1); - EXPECT_EQ(c[4], this->invalid_index); - EXPECT_EQ(c[5], this->invalid_index); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{5.0}); - EXPECT_EQ(v[2], T{0.0}); - EXPECT_EQ(v[3], T{3.0}); - EXPECT_EQ(v[4], T{0.0}); - EXPECT_EQ(v[5], T{0.0}); - EXPECT_EQ(hybrid_mtx->get_const_coo_row_idxs()[0], 0); - EXPECT_EQ(hybrid_mtx->get_const_coo_col_idxs()[0], 2); - EXPECT_EQ(hybrid_mtx->get_const_coo_values()[0], T{2.0}); -} - - -TYPED_TEST(Dense, MovesToHybridWithStrideByPercent40) -{ - using T = typename TestFixture::value_type; - using Hybrid = typename gko::matrix::Hybrid; - auto hybrid_mtx = - Hybrid::create(this->mtx4->get_executor(), gko::dim<2>{2, 3}, 1, 3, - std::make_shared(0.4)); - - this->mtx4->move_to(hybrid_mtx); - auto v = hybrid_mtx->get_const_ell_values(); - auto c = hybrid_mtx->get_const_ell_col_idxs(); - auto n = hybrid_mtx->get_ell_num_stored_elements_per_row(); - auto p = hybrid_mtx->get_ell_stride(); - auto coo_v = hybrid_mtx->get_const_coo_values(); - auto coo_c = hybrid_mtx->get_const_coo_col_idxs(); - auto coo_r = hybrid_mtx->get_const_coo_row_idxs(); - - ASSERT_EQ(hybrid_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(hybrid_mtx->get_ell_num_stored_elements(), 3); - EXPECT_EQ(n, 1); - EXPECT_EQ(p, 3); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], this->invalid_index); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{5.0}); - EXPECT_EQ(v[2], T{0.0}); - ASSERT_EQ(hybrid_mtx->get_coo_num_stored_elements(), 2); - EXPECT_EQ(coo_v[0], T{3.0}); - EXPECT_EQ(coo_v[1], T{2.0}); - EXPECT_EQ(coo_c[0], 1); - EXPECT_EQ(coo_c[1], 2); - EXPECT_EQ(coo_r[0], 0); - EXPECT_EQ(coo_r[1], 0); -} - - -TYPED_TEST(Dense, ConvertsToHybridWithStrideByPercent40) -{ - using T = typename TestFixture::value_type; - using Hybrid = typename gko::matrix::Hybrid; - auto hybrid_mtx = - Hybrid::create(this->mtx4->get_executor(), gko::dim<2>{2, 3}, 1, 3, - std::make_shared(0.4)); - - this->mtx4->convert_to(hybrid_mtx); - auto v = hybrid_mtx->get_const_ell_values(); - auto c = hybrid_mtx->get_const_ell_col_idxs(); - auto n = hybrid_mtx->get_ell_num_stored_elements_per_row(); - auto p = hybrid_mtx->get_ell_stride(); - auto coo_v = hybrid_mtx->get_const_coo_values(); - auto coo_c = hybrid_mtx->get_const_coo_col_idxs(); - auto coo_r = hybrid_mtx->get_const_coo_row_idxs(); - - ASSERT_EQ(hybrid_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(hybrid_mtx->get_ell_num_stored_elements(), 3); - EXPECT_EQ(n, 1); - EXPECT_EQ(p, 3); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], this->invalid_index); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{5.0}); - EXPECT_EQ(v[2], T{0.0}); - ASSERT_EQ(hybrid_mtx->get_coo_num_stored_elements(), 2); - EXPECT_EQ(coo_v[0], T{3.0}); - EXPECT_EQ(coo_v[1], T{2.0}); - EXPECT_EQ(coo_c[0], 1); - EXPECT_EQ(coo_c[1], 2); - EXPECT_EQ(coo_r[0], 0); - EXPECT_EQ(coo_r[1], 0); -} - - -TYPED_TEST(Dense, ConvertsToSellp32) -{ - using T = typename TestFixture::value_type; - using Sellp = typename gko::matrix::Sellp; - auto sellp_mtx = Sellp::create(this->mtx7->get_executor()); - - this->mtx7->convert_to(sellp_mtx); - auto v = sellp_mtx->get_const_values(); - auto c = sellp_mtx->get_const_col_idxs(); - auto s = sellp_mtx->get_const_slice_sets(); - auto l = sellp_mtx->get_const_slice_lengths(); - - ASSERT_EQ(sellp_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(sellp_mtx->get_total_cols(), 3); - ASSERT_EQ(sellp_mtx->get_num_stored_elements(), - 3 * gko::matrix::default_slice_size); - ASSERT_EQ(sellp_mtx->get_slice_size(), gko::matrix::default_slice_size); - ASSERT_EQ(sellp_mtx->get_stride_factor(), - gko::matrix::default_stride_factor); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[gko::matrix::default_slice_size], 1); - EXPECT_EQ(c[gko::matrix::default_slice_size + 1], this->invalid_index); - EXPECT_EQ(c[2 * gko::matrix::default_slice_size], 2); - EXPECT_EQ(c[2 * gko::matrix::default_slice_size + 1], this->invalid_index); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{1.5}); - EXPECT_EQ(v[gko::matrix::default_slice_size], T{2.0}); - EXPECT_EQ(v[gko::matrix::default_slice_size + 1], T{0.0}); - EXPECT_EQ(v[2 * gko::matrix::default_slice_size], T{3.0}); - EXPECT_EQ(v[2 * gko::matrix::default_slice_size + 1], T{0.0}); - EXPECT_EQ(s[0], 0); - EXPECT_EQ(s[1], 3); - EXPECT_EQ(l[0], 3); -} - - -TYPED_TEST(Dense, MovesToSellp32) -{ - using T = typename TestFixture::value_type; - using Sellp = typename gko::matrix::Sellp; - auto sellp_mtx = Sellp::create(this->mtx7->get_executor()); - - this->mtx7->move_to(sellp_mtx); - auto v = sellp_mtx->get_const_values(); - auto c = sellp_mtx->get_const_col_idxs(); - auto s = sellp_mtx->get_const_slice_sets(); - auto l = sellp_mtx->get_const_slice_lengths(); - - ASSERT_EQ(sellp_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(sellp_mtx->get_total_cols(), 3); - ASSERT_EQ(sellp_mtx->get_num_stored_elements(), - 3 * gko::matrix::default_slice_size); - ASSERT_EQ(sellp_mtx->get_slice_size(), gko::matrix::default_slice_size); - ASSERT_EQ(sellp_mtx->get_stride_factor(), - gko::matrix::default_stride_factor); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[gko::matrix::default_slice_size], 1); - EXPECT_EQ(c[gko::matrix::default_slice_size + 1], this->invalid_index); - EXPECT_EQ(c[2 * gko::matrix::default_slice_size], 2); - EXPECT_EQ(c[2 * gko::matrix::default_slice_size + 1], this->invalid_index); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{1.5}); - EXPECT_EQ(v[gko::matrix::default_slice_size], T{2.0}); - EXPECT_EQ(v[gko::matrix::default_slice_size + 1], T{0.0}); - EXPECT_EQ(v[2 * gko::matrix::default_slice_size], T{3.0}); - EXPECT_EQ(v[2 * gko::matrix::default_slice_size + 1], T{0.0}); - EXPECT_EQ(s[0], 0); - EXPECT_EQ(s[1], 3); - EXPECT_EQ(l[0], 3); -} - - -TYPED_TEST(Dense, ConvertsToSellp64) -{ - using T = typename TestFixture::value_type; - using Sellp = typename gko::matrix::Sellp; - auto sellp_mtx = Sellp::create(this->mtx7->get_executor()); - - this->mtx7->convert_to(sellp_mtx); - auto v = sellp_mtx->get_const_values(); - auto c = sellp_mtx->get_const_col_idxs(); - auto s = sellp_mtx->get_const_slice_sets(); - auto l = sellp_mtx->get_const_slice_lengths(); - - ASSERT_EQ(sellp_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(sellp_mtx->get_total_cols(), 3); - ASSERT_EQ(sellp_mtx->get_num_stored_elements(), - 3 * gko::matrix::default_slice_size); - ASSERT_EQ(sellp_mtx->get_slice_size(), gko::matrix::default_slice_size); - ASSERT_EQ(sellp_mtx->get_stride_factor(), - gko::matrix::default_stride_factor); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[gko::matrix::default_slice_size], 1); - EXPECT_EQ(c[gko::matrix::default_slice_size + 1], this->invalid_index); - EXPECT_EQ(c[2 * gko::matrix::default_slice_size], 2); - EXPECT_EQ(c[2 * gko::matrix::default_slice_size + 1], this->invalid_index); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{1.5}); - EXPECT_EQ(v[gko::matrix::default_slice_size], T{2.0}); - EXPECT_EQ(v[gko::matrix::default_slice_size + 1], T{0.0}); - EXPECT_EQ(v[2 * gko::matrix::default_slice_size], T{3.0}); - EXPECT_EQ(v[2 * gko::matrix::default_slice_size + 1], T{0.0}); - EXPECT_EQ(s[0], 0); - EXPECT_EQ(s[1], 3); - EXPECT_EQ(l[0], 3); -} - - -TYPED_TEST(Dense, MovesToSellp64) -{ - using T = typename TestFixture::value_type; - using Sellp = typename gko::matrix::Sellp; - auto sellp_mtx = Sellp::create(this->mtx7->get_executor()); - - this->mtx7->move_to(sellp_mtx); - auto v = sellp_mtx->get_const_values(); - auto c = sellp_mtx->get_const_col_idxs(); - auto s = sellp_mtx->get_const_slice_sets(); - auto l = sellp_mtx->get_const_slice_lengths(); - - ASSERT_EQ(sellp_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(sellp_mtx->get_total_cols(), 3); - ASSERT_EQ(sellp_mtx->get_num_stored_elements(), - 3 * gko::matrix::default_slice_size); - ASSERT_EQ(sellp_mtx->get_slice_size(), gko::matrix::default_slice_size); - ASSERT_EQ(sellp_mtx->get_stride_factor(), - gko::matrix::default_stride_factor); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[gko::matrix::default_slice_size], 1); - EXPECT_EQ(c[gko::matrix::default_slice_size + 1], this->invalid_index); - EXPECT_EQ(c[2 * gko::matrix::default_slice_size], 2); - EXPECT_EQ(c[2 * gko::matrix::default_slice_size + 1], this->invalid_index); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{1.5}); - EXPECT_EQ(v[gko::matrix::default_slice_size], T{2.0}); - EXPECT_EQ(v[gko::matrix::default_slice_size + 1], T{0.0}); - EXPECT_EQ(v[2 * gko::matrix::default_slice_size], T{3.0}); - EXPECT_EQ(v[2 * gko::matrix::default_slice_size + 1], T{0.0}); - EXPECT_EQ(s[0], 0); - EXPECT_EQ(s[1], 3); - EXPECT_EQ(l[0], 3); -} - - -TYPED_TEST(Dense, ConvertsToSellpWithSliceSizeAndStrideFactor) -{ - using T = typename TestFixture::value_type; - using Sellp = typename gko::matrix::Sellp; - auto sellp_mtx = - Sellp::create(this->mtx7->get_executor(), gko::dim<2>{}, 2, 2, 0); - - this->mtx7->convert_to(sellp_mtx); - auto v = sellp_mtx->get_const_values(); - auto c = sellp_mtx->get_const_col_idxs(); - auto s = sellp_mtx->get_const_slice_sets(); - auto l = sellp_mtx->get_const_slice_lengths(); - - ASSERT_EQ(sellp_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(sellp_mtx->get_total_cols(), 4); - ASSERT_EQ(sellp_mtx->get_num_stored_elements(), 8); - ASSERT_EQ(sellp_mtx->get_slice_size(), 2); - ASSERT_EQ(sellp_mtx->get_stride_factor(), 2); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], 1); - EXPECT_EQ(c[3], this->invalid_index); - EXPECT_EQ(c[4], 2); - EXPECT_EQ(c[5], this->invalid_index); - EXPECT_EQ(c[6], this->invalid_index); - EXPECT_EQ(c[7], this->invalid_index); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{1.5}); - EXPECT_EQ(v[2], T{2.0}); - EXPECT_EQ(v[3], T{0.0}); - EXPECT_EQ(v[4], T{3.0}); - EXPECT_EQ(v[5], T{0.0}); - EXPECT_EQ(v[6], T{0.0}); - EXPECT_EQ(v[7], T{0.0}); - EXPECT_EQ(s[0], 0); - EXPECT_EQ(s[1], 4); - EXPECT_EQ(l[0], 4); -} - - -TYPED_TEST(Dense, MovesToSellpWithSliceSizeAndStrideFactor) -{ - using T = typename TestFixture::value_type; - using Sellp = typename gko::matrix::Sellp; - auto sellp_mtx = - Sellp::create(this->mtx7->get_executor(), gko::dim<2>{}, 2, 2, 0); - - this->mtx7->move_to(sellp_mtx); - auto v = sellp_mtx->get_const_values(); - auto c = sellp_mtx->get_const_col_idxs(); - auto s = sellp_mtx->get_const_slice_sets(); - auto l = sellp_mtx->get_const_slice_lengths(); - - ASSERT_EQ(sellp_mtx->get_size(), gko::dim<2>(2, 3)); - ASSERT_EQ(sellp_mtx->get_total_cols(), 4); - ASSERT_EQ(sellp_mtx->get_num_stored_elements(), 8); - ASSERT_EQ(sellp_mtx->get_slice_size(), 2); - ASSERT_EQ(sellp_mtx->get_stride_factor(), 2); - EXPECT_EQ(c[0], 0); - EXPECT_EQ(c[1], 1); - EXPECT_EQ(c[2], 1); - EXPECT_EQ(c[3], this->invalid_index); - EXPECT_EQ(c[4], 2); - EXPECT_EQ(c[5], this->invalid_index); - EXPECT_EQ(c[6], this->invalid_index); - EXPECT_EQ(c[7], this->invalid_index); - EXPECT_EQ(v[0], T{1.0}); - EXPECT_EQ(v[1], T{1.5}); - EXPECT_EQ(v[2], T{2.0}); - EXPECT_EQ(v[3], T{0.0}); - EXPECT_EQ(v[4], T{3.0}); - EXPECT_EQ(v[5], T{0.0}); - EXPECT_EQ(v[6], T{0.0}); - EXPECT_EQ(v[7], T{0.0}); - EXPECT_EQ(s[0], 0); - EXPECT_EQ(s[1], 4); - EXPECT_EQ(l[0], 4); -} - - -TYPED_TEST(Dense, ConvertsToAndFromSellpWithMoreThanOneSlice) -{ - using T = typename TestFixture::value_type; - using Mtx = typename TestFixture::Mtx; - using Sellp = typename gko::matrix::Sellp; - auto x = this->template gen_mtx(65, 25); - - auto sellp_mtx = Sellp::create(this->exec); - auto dense_mtx = Mtx::create(this->exec); - x->convert_to(sellp_mtx); - sellp_mtx->convert_to(dense_mtx); - - GKO_ASSERT_MTX_NEAR(dense_mtx, x, 0.0); -} - - -TYPED_TEST(Dense, ConvertsEmptyToPrecision) -{ - using Dense = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - using OtherT = typename gko::next_precision; - using OtherDense = typename gko::matrix::Dense; - auto empty = OtherDense::create(this->exec); - auto res = Dense::create(this->exec); - - empty->convert_to(res); - - ASSERT_FALSE(res->get_size()); -} - - -TYPED_TEST(Dense, MovesEmptyToPrecision) -{ - using Dense = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - using OtherT = typename gko::next_precision; - using OtherDense = typename gko::matrix::Dense; - auto empty = OtherDense::create(this->exec); - auto res = Dense::create(this->exec); - - empty->move_to(res); - - ASSERT_FALSE(res->get_size()); -} - - -TYPED_TEST(Dense, ConvertsEmptyToCoo) -{ - using Dense = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - using Coo = typename gko::matrix::Coo; - auto empty = Dense::create(this->exec); - auto res = Coo::create(this->exec); - - empty->convert_to(res); - - ASSERT_EQ(res->get_num_stored_elements(), 0); - ASSERT_FALSE(res->get_size()); -} - - -TYPED_TEST(Dense, MovesEmptyToCoo) -{ - using Dense = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - using Coo = typename gko::matrix::Coo; - auto empty = Dense::create(this->exec); - auto res = Coo::create(this->exec); - - empty->move_to(res); - - ASSERT_EQ(res->get_num_stored_elements(), 0); - ASSERT_FALSE(res->get_size()); -} - - -TYPED_TEST(Dense, ConvertsEmptyMatrixToCsr) -{ - using Dense = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - using Csr = typename gko::matrix::Csr; - auto empty = Dense::create(this->exec); - auto res = Csr::create(this->exec); - - empty->convert_to(res); - - ASSERT_EQ(res->get_num_stored_elements(), 0); - ASSERT_EQ(*res->get_const_row_ptrs(), 0); - ASSERT_FALSE(res->get_size()); -} - - -TYPED_TEST(Dense, MovesEmptyMatrixToCsr) -{ - using Dense = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - using Csr = typename gko::matrix::Csr; - auto empty = Dense::create(this->exec); - auto res = Csr::create(this->exec); - - empty->move_to(res); - - ASSERT_EQ(res->get_num_stored_elements(), 0); - ASSERT_EQ(*res->get_const_row_ptrs(), 0); - ASSERT_FALSE(res->get_size()); -} - - -TYPED_TEST(Dense, ConvertsEmptyToSparsityCsr) -{ - using Dense = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - using SparsityCsr = typename gko::matrix::SparsityCsr; - auto empty = Dense::create(this->exec); - auto res = SparsityCsr::create(this->exec); - - empty->convert_to(res); - - ASSERT_EQ(res->get_num_nonzeros(), 0); - ASSERT_EQ(*res->get_const_row_ptrs(), 0); - ASSERT_FALSE(res->get_size()); -} - - -TYPED_TEST(Dense, MovesEmptyToSparsityCsr) -{ - using Dense = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - using SparsityCsr = typename gko::matrix::SparsityCsr; - auto empty = Dense::create(this->exec); - auto res = SparsityCsr::create(this->exec); - - empty->move_to(res); - - ASSERT_EQ(res->get_num_nonzeros(), 0); - ASSERT_EQ(*res->get_const_row_ptrs(), 0); - ASSERT_FALSE(res->get_size()); -} - - -TYPED_TEST(Dense, ConvertsEmptyToEll) -{ - using Dense = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - using Ell = typename gko::matrix::Ell; - auto empty = Dense::create(this->exec); - auto res = Ell::create(this->exec); - - empty->convert_to(res); - - ASSERT_EQ(res->get_num_stored_elements(), 0); - ASSERT_FALSE(res->get_size()); -} - - -TYPED_TEST(Dense, MovesEmptyToEll) -{ - using Dense = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - using Ell = typename gko::matrix::Ell; - auto empty = Dense::create(this->exec); - auto res = Ell::create(this->exec); - - empty->move_to(res); - - ASSERT_EQ(res->get_num_stored_elements(), 0); - ASSERT_FALSE(res->get_size()); -} - - -TYPED_TEST(Dense, ConvertsEmptyToHybrid) -{ - using Dense = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - using Hybrid = typename gko::matrix::Hybrid; - auto empty = Dense::create(this->exec); - auto res = Hybrid::create(this->exec); - - empty->convert_to(res); - - ASSERT_EQ(res->get_num_stored_elements(), 0); - ASSERT_FALSE(res->get_size()); -} - - -TYPED_TEST(Dense, MovesEmptyToHybrid) -{ - using Dense = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - using Hybrid = typename gko::matrix::Hybrid; - auto empty = Dense::create(this->exec); - auto res = Hybrid::create(this->exec); - - empty->move_to(res); - - ASSERT_EQ(res->get_num_stored_elements(), 0); - ASSERT_FALSE(res->get_size()); -} - - -TYPED_TEST(Dense, ConvertsEmptyToSellp) -{ - using Dense = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - using Sellp = typename gko::matrix::Sellp; - auto empty = Dense::create(this->exec); - auto res = Sellp::create(this->exec); - - empty->convert_to(res); - - ASSERT_EQ(res->get_num_stored_elements(), 0); - ASSERT_EQ(*res->get_const_slice_sets(), 0); - ASSERT_FALSE(res->get_size()); -} - - -TYPED_TEST(Dense, MovesEmptyToSellp) -{ - using Dense = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - using Sellp = typename gko::matrix::Sellp; - auto empty = Dense::create(this->exec); - auto res = Sellp::create(this->exec); - - empty->move_to(res); - - ASSERT_EQ(res->get_num_stored_elements(), 0); - ASSERT_EQ(*res->get_const_slice_sets(), 0); - ASSERT_FALSE(res->get_size()); -} - - -TYPED_TEST(Dense, SquareMatrixIsTransposable) -{ - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto trans = gko::as(this->mtx5->transpose()); - - GKO_ASSERT_MTX_NEAR( - trans, l({{1.0, -2.0, 2.1}, {-1.0, 2.0, 3.4}, {-0.5, 4.5, 1.2}}), - 0.0); -} - - -TYPED_TEST(Dense, SquareMatrixIsTransposableIntoDense) -{ - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto trans = Mtx::create(this->exec, this->mtx5->get_size()); - - this->mtx5->transpose(trans); - - GKO_ASSERT_MTX_NEAR( - trans, l({{1.0, -2.0, 2.1}, {-1.0, 2.0, 3.4}, {-0.5, 4.5, 1.2}}), - 0.0); -} - - -TYPED_TEST(Dense, SquareSubmatrixIsTransposableIntoDense) -{ - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto trans = Mtx::create(this->exec, gko::dim<2>{2, 2}, 4); - - this->mtx5->create_submatrix({0, 2}, {0, 2})->transpose(trans); - - GKO_ASSERT_MTX_NEAR(trans, l({{1.0, -2.0}, {-1.0, 2.0}}), 0.0); - ASSERT_EQ(trans->get_stride(), 4); -} - - -TYPED_TEST(Dense, SquareMatrixIsTransposableIntoDenseFailsForWrongDimensions) -{ - using Mtx = typename TestFixture::Mtx; - - ASSERT_THROW(this->mtx5->transpose(Mtx::create(this->exec)), - gko::DimensionMismatch); -} - - -TYPED_TEST(Dense, NonSquareMatrixIsTransposable) -{ - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto trans = gko::as(this->mtx4->transpose()); - - GKO_ASSERT_MTX_NEAR(trans, l({{1.0, 0.0}, {3.0, 5.0}, {2.0, 0.0}}), 0.0); -} - - -TYPED_TEST(Dense, NonSquareMatrixIsTransposableIntoDense) -{ - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto trans = - Mtx::create(this->exec, gko::transpose(this->mtx4->get_size())); - - this->mtx4->transpose(trans); - - GKO_ASSERT_MTX_NEAR(trans, l({{1.0, 0.0}, {3.0, 5.0}, {2.0, 0.0}}), 0.0); -} - - -TYPED_TEST(Dense, NonSquareSubmatrixIsTransposableIntoDense) -{ - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto trans = Mtx::create(this->exec, gko::dim<2>{2, 1}, 5); - - this->mtx4->create_submatrix({0, 1}, {0, 2})->transpose(trans); - - GKO_ASSERT_MTX_NEAR(trans, l({1.0, 3.0}), 0.0); - ASSERT_EQ(trans->get_stride(), 5); -} - - -TYPED_TEST(Dense, NonSquareMatrixIsTransposableIntoDenseFailsForWrongDimensions) -{ - using Mtx = typename TestFixture::Mtx; - - ASSERT_THROW(this->mtx4->transpose(Mtx::create(this->exec)), - gko::DimensionMismatch); -} - - -TYPED_TEST(Dense, SquareMatrixCanGatherRows) -{ - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 0}}; - - auto row_collection = this->mtx5->row_gather(&permute_idxs); - - GKO_ASSERT_MTX_NEAR(row_collection, - l({{-2.0, 2.0, 4.5}, {1.0, -1.0, -0.5}}), 0.0); -} - - -TYPED_TEST(Dense, SquareMatrixCanGatherRowsIntoDense) -{ - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 0}}; - auto row_collection = Mtx::create(exec, gko::dim<2>{2, 3}); - - this->mtx5->row_gather(&permute_idxs, row_collection); + this->mtx1->apply(b, x); - GKO_ASSERT_MTX_NEAR(row_collection, - l({{-2.0, 2.0, 4.5}, {1.0, -1.0, -0.5}}), 0.0); + GKO_ASSERT_MTX_NEAR( + x, + l({{mixed_complex_type{14.0, 16.0}, mixed_complex_type{20.0, 22.0}}, + {mixed_complex_type{17.0, 19.0}, mixed_complex_type{24.5, 26.5}}}), + 0.0); } -TYPED_TEST(Dense, SquareSubmatrixCanGatherRowsIntoDense) +TYPED_TEST(Dense, AdvancedAppliesToComplex) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 0}}; - auto row_collection = Mtx::create(exec, gko::dim<2>{2, 2}, 4); - - this->mtx5->create_submatrix({0, 2}, {1, 3}) - ->row_gather(&permute_idxs, row_collection); - - GKO_ASSERT_MTX_NEAR(row_collection, l({{2.0, 4.5}, {-1.0, -0.5}}), 0.0); - ASSERT_EQ(row_collection->get_stride(), 4); -} - + using value_type = typename TestFixture::value_type; + using complex_type = gko::to_complex; + using Dense = gko::matrix::Dense; + using DenseComplex = gko::matrix::Dense; + auto exec = gko::ReferenceExecutor::create(); -TYPED_TEST(Dense, NonSquareSubmatrixCanGatherRowsIntoMixedDense) -{ - using Mtx = typename TestFixture::Mtx; - using MixedMtx = typename TestFixture::MixedMtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx4->get_executor(); - gko::array gather_index{exec, {1, 0, 1}}; - auto row_collection = MixedMtx::create(exec, gko::dim<2>{3, 3}, 4); + auto b = gko::initialize( + {{complex_type{1.0, 0.0}, complex_type{2.0, 1.0}}, + {complex_type{2.0, 2.0}, complex_type{3.0, 3.0}}, + {complex_type{3.0, 4.0}, complex_type{4.0, 5.0}}}, + exec); + auto x = gko::initialize( + {{complex_type{1.0, 0.0}, complex_type{2.0, 1.0}}, + {complex_type{2.0, 2.0}, complex_type{3.0, 3.0}}}, + exec); + auto alpha = gko::initialize({-1.0}, this->exec); + auto beta = gko::initialize({2.0}, this->exec); - this->mtx4->row_gather(&gather_index, row_collection); + this->mtx1->apply(alpha, b, beta, x); GKO_ASSERT_MTX_NEAR( - row_collection, - l( - {{0.0, 5.0, 0.0}, {1.0, 3.0, 2.0}, {0.0, 5.0, 0.0}}), + x, + l({{complex_type{-12.0, -16.0}, complex_type{-16.0, -20.0}}, + {complex_type{-13.0, -15.0}, complex_type{-18.5, -20.5}}}), 0.0); } -TYPED_TEST(Dense, NonSquareSubmatrixCanAdvancedGatherRowsIntoMixedDense) +TYPED_TEST(Dense, AdvancedAppliesToMixedComplex) { - using Mtx = typename TestFixture::Mtx; - using MixedMtx = typename TestFixture::MixedMtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx4->get_executor(); - gko::array gather_index{exec, {1, 0, 1}}; - auto row_collection = gko::initialize( - {{1.0, 0.5, -1.0}, {-1.5, 0.5, 1.0}, {2.0, -3.0, 1.0}}, exec); - auto alpha = gko::initialize({1.0}, exec); - auto beta = gko::initialize({2.0}, exec); + using mixed_value_type = + gko::next_precision; + using mixed_complex_type = gko::to_complex; + using MixedDense = gko::matrix::Dense; + using MixedDenseComplex = gko::matrix::Dense; + auto exec = gko::ReferenceExecutor::create(); - this->mtx4->row_gather(alpha, &gather_index, beta, row_collection); + auto b = gko::initialize( + {{mixed_complex_type{1.0, 0.0}, mixed_complex_type{2.0, 1.0}}, + {mixed_complex_type{2.0, 2.0}, mixed_complex_type{3.0, 3.0}}, + {mixed_complex_type{3.0, 4.0}, mixed_complex_type{4.0, 5.0}}}, + exec); + auto x = gko::initialize( + {{mixed_complex_type{1.0, 0.0}, mixed_complex_type{2.0, 1.0}}, + {mixed_complex_type{2.0, 2.0}, mixed_complex_type{3.0, 3.0}}}, + exec); + auto alpha = gko::initialize({-1.0}, this->exec); + auto beta = gko::initialize({2.0}, this->exec); + + this->mtx1->apply(alpha, b, beta, x); GKO_ASSERT_MTX_NEAR( - row_collection, - l( - {{2.0, 6.0, -2.0}, {-2.0, 4.0, 4.0}, {4.0, -1.0, 2.0}}), + x, + l({{mixed_complex_type{-12.0, -16.0}, mixed_complex_type{-16.0, -20.0}}, + {mixed_complex_type{-13.0, -15.0}, + mixed_complex_type{-18.5, -20.5}}}), 0.0); } -TYPED_TEST(Dense, SquareMatrixGatherRowsIntoDenseFailsForWrongDimensions) -{ - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 0}}; - - ASSERT_THROW(this->mtx5->row_gather(&permute_idxs, Mtx::create(exec)), - gko::DimensionMismatch); -} - - -TYPED_TEST(Dense, SquareMatrixCanGatherRows64) +TYPED_TEST(Dense, MakeComplex) { - using Mtx = typename TestFixture::Mtx; using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 0}}; - auto row_collection = this->mtx5->row_gather(&permute_idxs); + auto complex_mtx = this->mtx5->make_complex(); - GKO_ASSERT_MTX_NEAR(row_collection, - l({{-2.0, 2.0, 4.5}, {1.0, -1.0, -0.5}}), 0.0); + GKO_ASSERT_MTX_NEAR(complex_mtx, this->mtx5, 0.0); } -TYPED_TEST(Dense, SquareMatrixCanGatherRowsIntoDense64) +TYPED_TEST(Dense, MakeComplexIntoDense) { - using Mtx = typename TestFixture::Mtx; using T = typename TestFixture::value_type; + using ComplexMtx = typename TestFixture::ComplexMtx; auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 0}}; - auto row_collection = Mtx::create(exec, gko::dim<2>{2, 3}); - this->mtx5->row_gather(&permute_idxs, row_collection); + auto complex_mtx = ComplexMtx::create(exec, this->mtx5->get_size()); + this->mtx5->make_complex(complex_mtx); - GKO_ASSERT_MTX_NEAR(row_collection, - l({{-2.0, 2.0, 4.5}, {1.0, -1.0, -0.5}}), 0.0); + GKO_ASSERT_MTX_NEAR(complex_mtx, this->mtx5, 0.0); } -TYPED_TEST(Dense, SquareSubmatrixCanGatherRowsIntoDense64) +TYPED_TEST(Dense, MakeComplexIntoDenseFailsForWrongDimensions) { - using Mtx = typename TestFixture::Mtx; using T = typename TestFixture::value_type; + using ComplexMtx = typename TestFixture::ComplexMtx; auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 0}}; - auto row_collection = Mtx::create(exec, gko::dim<2>{2, 2}, 4); - this->mtx5->create_submatrix({0, 2}, {1, 3}) - ->row_gather(&permute_idxs, row_collection); + auto complex_mtx = ComplexMtx::create(exec); - GKO_ASSERT_MTX_NEAR(row_collection, l({{2.0, 4.5}, {-1.0, -0.5}}), 0.0); - ASSERT_EQ(row_collection->get_stride(), 4); + ASSERT_THROW(this->mtx5->make_complex(complex_mtx), gko::DimensionMismatch); } -TYPED_TEST(Dense, NonSquareSubmatrixCanGatherRowsIntoMixedDense64) +TYPED_TEST(Dense, GetReal) { - using Mtx = typename TestFixture::Mtx; - using MixedMtx = typename TestFixture::MixedMtx; using T = typename TestFixture::value_type; - auto exec = this->mtx4->get_executor(); - gko::array gather_index{exec, {1, 0, 1}}; - auto row_collection = MixedMtx::create(exec, gko::dim<2>{3, 3}, 4); - this->mtx4->row_gather(&gather_index, row_collection); + auto real_mtx = this->mtx5->get_real(); - GKO_ASSERT_MTX_NEAR( - row_collection, - l( - {{0.0, 5.0, 0.0}, {1.0, 3.0, 2.0}, {0.0, 5.0, 0.0}}), - 0.0); + GKO_ASSERT_MTX_NEAR(real_mtx, this->mtx5, 0.0); } -TYPED_TEST(Dense, SquareMatrixGatherRowsIntoDenseFailsForWrongDimensions64) +TYPED_TEST(Dense, GetRealIntoDense) { - using Mtx = typename TestFixture::Mtx; using T = typename TestFixture::value_type; + using RealMtx = typename TestFixture::RealMtx; auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 0}}; - - ASSERT_THROW(this->mtx5->row_gather(&permute_idxs, Mtx::create(exec)), - gko::DimensionMismatch); -} - - -TYPED_TEST(Dense, SquareMatrixIsPermutable) -{ - using Mtx = typename TestFixture::Mtx; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; - - auto ref_permuted = - gko::as(gko::as(this->mtx5->row_permute(&permute_idxs)) - ->column_permute(&permute_idxs)); - auto permuted = gko::as(this->mtx5->permute(&permute_idxs)); - - GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); -} - - -TYPED_TEST(Dense, SquareMatrixIsPermutableIntoDense) -{ - using Mtx = typename TestFixture::Mtx; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; - auto permuted = Mtx::create(exec, this->mtx5->get_size()); - auto ref_permuted = - gko::as(gko::as(this->mtx5->row_permute(&permute_idxs)) - ->column_permute(&permute_idxs)); - this->mtx5->permute(&permute_idxs, permuted); + auto real_mtx = RealMtx::create(exec, this->mtx5->get_size()); + this->mtx5->get_real(real_mtx); - GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); + GKO_ASSERT_MTX_NEAR(real_mtx, this->mtx5, 0.0); } -TYPED_TEST(Dense, SquareSubmatrixIsPermutableIntoDense) +TYPED_TEST(Dense, GetRealIntoDenseFailsForWrongDimensions) { - using Mtx = typename TestFixture::Mtx; + using T = typename TestFixture::value_type; + using RealMtx = typename TestFixture::RealMtx; auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 0}}; - auto permuted = Mtx::create(exec, gko::dim<2>{2, 2}, 4); - auto mtx = this->mtx5->create_submatrix({0, 2}, {1, 3}); - - auto ref_permuted = - gko::as(gko::as(mtx->row_permute(&permute_idxs)) - ->column_permute(&permute_idxs)); - mtx->permute(&permute_idxs, permuted); - - GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); - ASSERT_EQ(permuted->get_stride(), 4); -} - - -TYPED_TEST(Dense, NonSquareMatrixPermuteIntoDenseFails) -{ - using Mtx = typename TestFixture::Mtx; - auto exec = this->mtx4->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; - ASSERT_THROW(this->mtx4->permute(&permute_idxs, this->mtx4->clone()), - gko::DimensionMismatch); + auto real_mtx = RealMtx::create(exec); + ASSERT_THROW(this->mtx5->get_real(real_mtx), gko::DimensionMismatch); } -TYPED_TEST(Dense, SquareMatrixPermuteIntoDenseFailsForWrongPermutationSize) +TYPED_TEST(Dense, GetImag) { - using Mtx = typename TestFixture::Mtx; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2}}; - - ASSERT_THROW(this->mtx5->permute(&permute_idxs, this->mtx5->clone()), - gko::ValueMismatch); -} - + using T = typename TestFixture::value_type; -TYPED_TEST(Dense, SquareMatrixPermuteIntoDenseFailsForWrongDimensions) -{ - using Mtx = typename TestFixture::Mtx; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; + auto imag_mtx = this->mtx5->get_imag(); - ASSERT_THROW(this->mtx5->permute(&permute_idxs, Mtx::create(exec)), - gko::DimensionMismatch); + GKO_ASSERT_MTX_NEAR( + imag_mtx, l({{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}), + 0.0); } -TYPED_TEST(Dense, SquareMatrixIsInversePermutable) +TYPED_TEST(Dense, GetImagIntoDense) { - using Mtx = typename TestFixture::Mtx; + using T = typename TestFixture::value_type; + using RealMtx = typename TestFixture::RealMtx; auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; - auto ref_permuted = gko::as( - gko::as(this->mtx5->inverse_row_permute(&permute_idxs)) - ->inverse_column_permute(&permute_idxs)); - auto permuted = gko::as(this->mtx5->inverse_permute(&permute_idxs)); + auto imag_mtx = RealMtx::create(exec, this->mtx5->get_size()); + this->mtx5->get_imag(imag_mtx); - GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); + GKO_ASSERT_MTX_NEAR( + imag_mtx, l({{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}), + 0.0); } -TYPED_TEST(Dense, SquareMatrixIsInversePermutableIntoDense) +TYPED_TEST(Dense, GetImagIntoDenseFailsForWrongDimensions) { - using Mtx = typename TestFixture::Mtx; + using T = typename TestFixture::value_type; + using RealMtx = typename TestFixture::RealMtx; auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; - auto permuted = Mtx::create(exec, this->mtx5->get_size()); - auto ref_permuted = gko::as( - gko::as(this->mtx5->inverse_row_permute(&permute_idxs)) - ->inverse_column_permute(&permute_idxs)); - this->mtx5->inverse_permute(&permute_idxs, permuted); - - GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); + auto imag_mtx = RealMtx::create(exec); + ASSERT_THROW(this->mtx5->get_imag(imag_mtx), gko::DimensionMismatch); } -TYPED_TEST(Dense, SquareSubmatrixIsInversePermutableIntoDense) +TYPED_TEST(Dense, MakeTemporaryConversionDoesntConvertOnMatch) { using Mtx = typename TestFixture::Mtx; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 0}}; - auto permuted = Mtx::create(exec, gko::dim<2>{2, 2}, 4); - auto mtx = this->mtx5->create_submatrix({0, 2}, {1, 3}); - - auto ref_permuted = - gko::as(gko::as(mtx->inverse_row_permute(&permute_idxs)) - ->inverse_column_permute(&permute_idxs)); - mtx->inverse_permute(&permute_idxs, permuted); + using T = typename TestFixture::value_type; + auto alpha = gko::initialize({8.0}, this->exec); - GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); - ASSERT_EQ(permuted->get_stride(), 4); + ASSERT_EQ(gko::make_temporary_conversion(alpha).get(), alpha.get()); } -TYPED_TEST(Dense, NonSquareMatrixInversePermuteIntoDenseFails) +TYPED_TEST(Dense, MakeTemporaryConversionConvertsBack) { - using Mtx = typename TestFixture::Mtx; - auto exec = this->mtx4->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; + using MixedMtx = typename TestFixture::MixedMtx; + using T = typename TestFixture::value_type; + using MixedT = typename MixedMtx::value_type; + auto alpha = gko::initialize({8.0}, this->exec); - ASSERT_THROW( - this->mtx4->inverse_permute(&permute_idxs, this->mtx4->clone()), - gko::DimensionMismatch); + { + auto conversion = gko::make_temporary_conversion(alpha); + conversion->at(0, 0) = T{7.0}; + } + + ASSERT_EQ(alpha->at(0, 0), MixedT{7.0}); } -TYPED_TEST(Dense, - SquareMatrixInversePermuteIntoDenseFailsForWrongPermutationSize) +TYPED_TEST(Dense, MakeTemporaryConversionConstDoesntConvertBack) { - using Mtx = typename TestFixture::Mtx; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {0, 1}}; + using MixedMtx = typename TestFixture::MixedMtx; + using T = typename TestFixture::value_type; + using MixedT = typename MixedMtx::value_type; + auto alpha = gko::initialize({8.0}, this->exec); - ASSERT_THROW( - this->mtx5->inverse_permute(&permute_idxs, this->mtx5->clone()), - gko::ValueMismatch); + { + auto conversion = gko::make_temporary_conversion( + static_cast(alpha.get())); + alpha->at(0, 0) = MixedT{7.0}; + } + + ASSERT_EQ(alpha->at(0, 0), MixedT{7.0}); } -TYPED_TEST(Dense, SquareMatrixInversePermuteIntoDenseFailsForWrongDimensions) +TYPED_TEST(Dense, ScaleAddIdentityRectangular) { - using Mtx = typename TestFixture::Mtx; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; + using T = typename TestFixture::value_type; + using Vec = typename TestFixture::Mtx; + using MixedVec = typename TestFixture::MixedMtx; + auto alpha = gko::initialize({2.0}, this->exec); + auto beta = gko::initialize({-1.0}, this->exec); + auto b = gko::initialize( + {I{2.0, 0.0}, I{1.0, 2.5}, I{0.0, -4.0}}, this->exec); - ASSERT_THROW(this->mtx5->inverse_permute(&permute_idxs, Mtx::create(exec)), - gko::DimensionMismatch); + b->add_scaled_identity(alpha, beta); + + GKO_ASSERT_MTX_NEAR(b, l({{0.0, 0.0}, {-1.0, -0.5}, {0.0, 4.0}}), 0.0); } -TYPED_TEST(Dense, SquareMatrixIsPermutable64) -{ - using Mtx = typename TestFixture::Mtx; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; +template +class DenseComplex : public ::testing::Test { +protected: + using value_type = T; + using Mtx = gko::matrix::Dense; + using RealMtx = gko::matrix::Dense>; +}; - auto ref_permuted = - gko::as(gko::as(this->mtx5->row_permute(&permute_idxs)) - ->column_permute(&permute_idxs)); - auto permuted = gko::as(this->mtx5->permute(&permute_idxs)); - GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); -} +TYPED_TEST_SUITE(DenseComplex, gko::test::ComplexValueTypes, + TypenameNameGenerator); -TYPED_TEST(Dense, SquareMatrixIsPermutableIntoDense64) +TYPED_TEST(DenseComplex, ScalesWithRealScalar) { - using Mtx = typename TestFixture::Mtx; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; - auto permuted = Mtx::create(exec, this->mtx5->get_size()); + using Dense = typename TestFixture::Mtx; + using RealDense = gko::remove_complex; + using T = typename TestFixture::value_type; + auto exec = gko::ReferenceExecutor::create(); + auto mtx = gko::initialize({{T{1.0, 2.0}, T{-1.0, 2.25}}, + {T{-2.0, 1.5}, T{4.5, 0.0}}, + {T{1.0, 0.0}, T{0.0, 1.0}}}, + exec); + auto alpha = + gko::initialize({gko::remove_complex{-2.0}}, exec); - auto ref_permuted = - gko::as(gko::as(this->mtx5->row_permute(&permute_idxs)) - ->column_permute(&permute_idxs)); - this->mtx5->permute(&permute_idxs, permuted); + mtx->scale(alpha); - GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); + GKO_ASSERT_MTX_NEAR(mtx, + l({{T{-2.0, -4.0}, T{2.0, -4.5}}, + {T{4.0, -3.0}, T{-9.0, 0.0}}, + {T{-2.0, 0.0}, T{0.0, -2.0}}}), + 0.0); } -TYPED_TEST(Dense, SquareSubmatrixIsPermutableIntoDense64) +TYPED_TEST(DenseComplex, ScalesWithRealVector) { - using Mtx = typename TestFixture::Mtx; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 0}}; - auto permuted = Mtx::create(exec, gko::dim<2>{2, 2}, 4); - auto mtx = this->mtx5->create_submatrix({0, 2}, {1, 3}); + using Dense = typename TestFixture::Mtx; + using RealDense = gko::remove_complex; + using T = typename TestFixture::value_type; + using RealT = gko::remove_complex; + auto exec = gko::ReferenceExecutor::create(); + auto mtx = gko::initialize({{T{1.0, 2.0}, T{-1.0, 2.25}}, + {T{-2.0, 1.5}, T{4.5, 0.0}}, + {T{1.0, 0.0}, T{0.0, 1.0}}}, + exec); + auto alpha = gko::initialize({{RealT{-2.0}, RealT{4.0}}}, exec); - auto ref_permuted = - gko::as(gko::as(mtx->row_permute(&permute_idxs)) - ->column_permute(&permute_idxs)); - mtx->permute(&permute_idxs, permuted); + mtx->scale(alpha); - GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); - ASSERT_EQ(permuted->get_stride(), 4); + GKO_ASSERT_MTX_NEAR(mtx, + l({{T{-2.0, -4.0}, T{-4.0, 9.0}}, + {T{4.0, -3.0}, T{18.0, 0.0}}, + {T{-2.0, 0.0}, T{0.0, 4.0}}}), + 0.0); } -TYPED_TEST(Dense, NonSquareMatrixPermuteIntoDenseFails64) +TYPED_TEST(DenseComplex, InvScalesWithRealScalar) { - using Mtx = typename TestFixture::Mtx; - auto exec = this->mtx4->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; + using Dense = typename TestFixture::Mtx; + using RealDense = gko::remove_complex; + using T = typename TestFixture::value_type; + auto exec = gko::ReferenceExecutor::create(); + auto mtx = gko::initialize({{T{1.0, 2.0}, T{-1.0, 2.25}}, + {T{-2.0, 1.5}, T{4.5, 0.0}}, + {T{1.0, 0.0}, T{0.0, 1.0}}}, + exec); + auto alpha = + gko::initialize({gko::remove_complex{-0.5}}, exec); - ASSERT_THROW(this->mtx4->permute(&permute_idxs, this->mtx4->clone()), - gko::DimensionMismatch); + mtx->inv_scale(alpha); + + GKO_ASSERT_MTX_NEAR(mtx, + l({{T{-2.0, -4.0}, T{2.0, -4.5}}, + {T{4.0, -3.0}, T{-9.0, 0.0}}, + {T{-2.0, 0.0}, T{0.0, -2.0}}}), + 0.0); } -TYPED_TEST(Dense, SquareMatrixPermuteIntoDenseFailsForWrongPermutationSize64) +TYPED_TEST(DenseComplex, InvScalesWithRealVector) { - using Mtx = typename TestFixture::Mtx; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2}}; + using Dense = typename TestFixture::Mtx; + using RealDense = gko::remove_complex; + using T = typename TestFixture::value_type; + using RealT = gko::remove_complex; + auto exec = gko::ReferenceExecutor::create(); + auto mtx = gko::initialize({{T{1.0, 2.0}, T{-1.0, 2.25}}, + {T{-2.0, 1.5}, T{4.5, 0.0}}, + {T{1.0, 0.0}, T{0.0, 1.0}}}, + exec); + auto alpha = gko::initialize({{RealT{-0.5}, RealT{0.25}}}, exec); - ASSERT_THROW(this->mtx5->permute(&permute_idxs, this->mtx5->clone()), - gko::ValueMismatch); + mtx->inv_scale(alpha); + + GKO_ASSERT_MTX_NEAR(mtx, + l({{T{-2.0, -4.0}, T{-4.0, 9.0}}, + {T{4.0, -3.0}, T{18.0, 0.0}}, + {T{-2.0, 0.0}, T{0.0, 4.0}}}), + 0.0); } -TYPED_TEST(Dense, SquareMatrixPermuteIntoDenseFailsForWrongDimensions64) +TYPED_TEST(DenseComplex, AddsScaledWithRealScalar) { - using Mtx = typename TestFixture::Mtx; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; + using Dense = typename TestFixture::Mtx; + using RealDense = gko::remove_complex; + using T = typename TestFixture::value_type; + auto exec = gko::ReferenceExecutor::create(); + auto mtx = gko::initialize({{T{1.0, 2.0}, T{-1.0, 2.25}}, + {T{-2.0, 1.5}, T{4.5, 0.0}}, + {T{1.0, 0.0}, T{0.0, 1.0}}}, + exec); + auto mtx2 = gko::initialize({{T{4.0, -1.0}, T{5.0, 1.5}}, + {T{3.0, 1.0}, T{0.0, 2.0}}, + {T{-1.0, 1.0}, T{0.5, -2.0}}}, + exec); + auto alpha = + gko::initialize({gko::remove_complex{-2.0}}, exec); - ASSERT_THROW(this->mtx5->permute(&permute_idxs, Mtx::create(exec)), - gko::DimensionMismatch); + mtx->add_scaled(alpha, mtx2); + + GKO_ASSERT_MTX_NEAR(mtx, + l({{T{-7.0, 4.0}, T{-11.0, -0.75}}, + {T{-8.0, -0.5}, T{4.5, -4.0}}, + {T{3.0, -2.0}, T{-1.0, 5.0}}}), + 0.0); } -TYPED_TEST(Dense, SquareMatrixIsInversePermutable64) +TYPED_TEST(DenseComplex, AddsScaledWithRealVector) { - using Mtx = typename TestFixture::Mtx; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; + using Dense = typename TestFixture::Mtx; + using RealDense = gko::remove_complex; + using T = typename TestFixture::value_type; + using RealT = gko::remove_complex; + auto exec = gko::ReferenceExecutor::create(); + auto mtx = gko::initialize({{T{1.0, 2.0}, T{-1.0, 2.25}}, + {T{-2.0, 1.5}, T{4.5, 0.0}}, + {T{1.0, 0.0}, T{0.0, 1.0}}}, + exec); + auto mtx2 = gko::initialize({{T{4.0, -1.0}, T{5.0, 1.5}}, + {T{3.0, 1.0}, T{0.0, 2.0}}, + {T{-1.0, 1.0}, T{0.5, -2.0}}}, + exec); + auto alpha = gko::initialize({{RealT{-2.0}, RealT{4.0}}}, exec); - auto ref_permuted = gko::as( - gko::as(this->mtx5->inverse_row_permute(&permute_idxs)) - ->inverse_column_permute(&permute_idxs)); - auto permuted = gko::as(this->mtx5->inverse_permute(&permute_idxs)); + mtx->add_scaled(alpha, mtx2); - GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); + GKO_ASSERT_MTX_NEAR(mtx, + l({{T{-7.0, 4.0}, T{19.0, 8.25}}, + {T{-8.0, -0.5}, T{4.5, 8.0}}, + {T{3.0, -2.0}, T{2.0, -7.0}}}), + 0.0); } -TYPED_TEST(Dense, SquareMatrixIsInversePermutableIntoDense64) +TYPED_TEST(DenseComplex, SubtractsScaledWithRealScalar) { - using Mtx = typename TestFixture::Mtx; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; - auto permuted = Mtx::create(exec, this->mtx5->get_size()); + using Dense = typename TestFixture::Mtx; + using RealDense = gko::remove_complex; + using T = typename TestFixture::value_type; + auto exec = gko::ReferenceExecutor::create(); + auto mtx = gko::initialize({{T{1.0, 2.0}, T{-1.0, 2.25}}, + {T{-2.0, 1.5}, T{4.5, 0.0}}, + {T{1.0, 0.0}, T{0.0, 1.0}}}, + exec); + auto mtx2 = gko::initialize({{T{4.0, -1.0}, T{5.0, 1.5}}, + {T{3.0, 1.0}, T{0.0, 2.0}}, + {T{-1.0, 1.0}, T{0.5, -2.0}}}, + exec); + auto alpha = + gko::initialize({gko::remove_complex{2.0}}, exec); - auto ref_permuted = gko::as( - gko::as(this->mtx5->inverse_row_permute(&permute_idxs)) - ->inverse_column_permute(&permute_idxs)); - this->mtx5->inverse_permute(&permute_idxs, permuted); + mtx->sub_scaled(alpha, mtx2); - GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); + GKO_ASSERT_MTX_NEAR(mtx, + l({{T{-7.0, 4.0}, T{-11.0, -0.75}}, + {T{-8.0, -0.5}, T{4.5, -4.0}}, + {T{3.0, -2.0}, T{-1.0, 5.0}}}), + 0.0); } -TYPED_TEST(Dense, SquareSubmatrixIsInversePermutableIntoDense64) +TYPED_TEST(DenseComplex, SubtractsScaledWithRealVector) { - using Mtx = typename TestFixture::Mtx; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 0}}; - auto permuted = Mtx::create(exec, gko::dim<2>{2, 2}, 4); - auto mtx = this->mtx5->create_submatrix({0, 2}, {1, 3}); + using Dense = typename TestFixture::Mtx; + using RealDense = gko::remove_complex; + using T = typename TestFixture::value_type; + using RealT = gko::remove_complex; + auto exec = gko::ReferenceExecutor::create(); + auto mtx = gko::initialize({{T{1.0, 2.0}, T{-1.0, 2.25}}, + {T{-2.0, 1.5}, T{4.5, 0.0}}, + {T{1.0, 0.0}, T{0.0, 1.0}}}, + exec); + auto mtx2 = gko::initialize({{T{4.0, -1.0}, T{5.0, 1.5}}, + {T{3.0, 1.0}, T{0.0, 2.0}}, + {T{-1.0, 1.0}, T{0.5, -2.0}}}, + exec); + auto alpha = gko::initialize({{RealT{2.0}, RealT{-4.0}}}, exec); - auto ref_permuted = - gko::as(gko::as(mtx->inverse_row_permute(&permute_idxs)) - ->inverse_column_permute(&permute_idxs)); - mtx->inverse_permute(&permute_idxs, permuted); + mtx->sub_scaled(alpha, mtx2); - GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); - ASSERT_EQ(permuted->get_stride(), 4); + GKO_ASSERT_MTX_NEAR(mtx, + l({{T{-7.0, 4.0}, T{19.0, 8.25}}, + {T{-8.0, -0.5}, T{4.5, 8.0}}, + {T{3.0, -2.0}, T{2.0, -7.0}}}), + 0.0); } -TYPED_TEST(Dense, NonSquareMatrixInversePermuteIntoDenseFails64) +TYPED_TEST(DenseComplex, NonSquareMatrixIsConjugateTransposable) { - using Mtx = typename TestFixture::Mtx; - auto exec = this->mtx4->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; - - ASSERT_THROW( - this->mtx4->inverse_permute(&permute_idxs, this->mtx4->clone()), - gko::DimensionMismatch); -} - + using Dense = typename TestFixture::Mtx; + using T = typename TestFixture::value_type; + auto exec = gko::ReferenceExecutor::create(); + auto mtx = gko::initialize({{T{1.0, 2.0}, T{-1.0, 2.1}}, + {T{-2.0, 1.5}, T{4.5, 0.0}}, + {T{1.0, 0.0}, T{0.0, 1.0}}}, + exec); -TYPED_TEST(Dense, - SquareMatrixInversePermuteIntoDenseFailsForWrongPermutationSize64) -{ - using Mtx = typename TestFixture::Mtx; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2}}; + auto trans = gko::as(mtx->conj_transpose()); - ASSERT_THROW( - this->mtx5->inverse_permute(&permute_idxs, this->mtx5->clone()), - gko::ValueMismatch); + GKO_ASSERT_MTX_NEAR(trans, + l({{T{1.0, -2.0}, T{-2.0, -1.5}, T{1.0, 0.0}}, + {T{-1.0, -2.1}, T{4.5, 0.0}, T{0.0, -1.0}}}), + 0.0); } -TYPED_TEST(Dense, SquareMatrixInversePermuteIntoDenseFailsForWrongDimensions64) +TYPED_TEST(DenseComplex, NonSquareMatrixIsConjugateTransposableIntoDense) { - using Mtx = typename TestFixture::Mtx; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; + using Dense = typename TestFixture::Mtx; + using T = typename TestFixture::value_type; + auto exec = gko::ReferenceExecutor::create(); + auto mtx = gko::initialize({{T{1.0, 2.0}, T{-1.0, 2.1}}, + {T{-2.0, 1.5}, T{4.5, 0.0}}, + {T{1.0, 0.0}, T{0.0, 1.0}}}, + exec); + auto trans = Dense::create(exec, gko::transpose(mtx->get_size())); - ASSERT_THROW(this->mtx5->inverse_permute(&permute_idxs, Mtx::create(exec)), - gko::DimensionMismatch); + mtx->conj_transpose(trans); + + GKO_ASSERT_MTX_NEAR(trans, + l({{T{1.0, -2.0}, T{-2.0, -1.5}, T{1.0, 0.0}}, + {T{-1.0, -2.1}, T{4.5, 0.0}, T{0.0, -1.0}}}), + 0.0); } -TYPED_TEST(Dense, SquareMatrixIsRowPermutable) +TYPED_TEST(DenseComplex, InplaceAbsolute) { using Mtx = typename TestFixture::Mtx; using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; + auto exec = gko::ReferenceExecutor::create(); + auto mtx = gko::initialize({{T{1.0, 0.0}, T{3.0, 4.0}, T{0.0, 2.0}}, + {T{-4.0, -3.0}, T{-1.0, 0}, T{0.0, 0.0}}, + {T{0.0, 0.0}, T{0.0, -1.5}, T{2.0, 0.0}}}, + exec); - auto row_permute = gko::as(this->mtx5->row_permute(&permute_idxs)); + mtx->compute_absolute_inplace(); GKO_ASSERT_MTX_NEAR( - row_permute, - l({{-2.0, 2.0, 4.5}, {2.1, 3.4, 1.2}, {1.0, -1.0, -0.5}}), 0.0); + mtx, l({{1.0, 5.0, 2.0}, {5.0, 1.0, 0.0}, {0.0, 1.5, 2.0}}), 0.0); } -TYPED_TEST(Dense, NonSquareMatrixIsRowPermutable) +TYPED_TEST(DenseComplex, OutplaceAbsolute) { using Mtx = typename TestFixture::Mtx; using T = typename TestFixture::value_type; - auto exec = this->mtx4->get_executor(); - gko::array permute_idxs{exec, {1, 0}}; + auto exec = gko::ReferenceExecutor::create(); + auto mtx = gko::initialize({{T{1.0, 0.0}, T{3.0, 4.0}, T{0.0, 2.0}}, + {T{-4.0, -3.0}, T{-1.0, 0}, T{0.0, 0.0}}, + {T{0.0, 0.0}, T{0.0, -1.5}, T{2.0, 0.0}}}, + exec); - auto row_permute = gko::as(this->mtx4->row_permute(&permute_idxs)); + auto abs_mtx = mtx->compute_absolute(); - GKO_ASSERT_MTX_NEAR(row_permute, l({{0.0, 5.0, 0.0}, {1.0, 3.0, 2.0}}), - 0.0); + GKO_ASSERT_MTX_NEAR( + abs_mtx, l({{1.0, 5.0, 2.0}, {5.0, 1.0, 0.0}, {0.0, 1.5, 2.0}}), + 0.0); } -TYPED_TEST(Dense, SquareMatrixIsRowPermutableIntoDense) +TYPED_TEST(DenseComplex, OutplaceAbsoluteIntoDense) { using Mtx = typename TestFixture::Mtx; using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; - auto row_permute = Mtx::create(exec, this->mtx5->get_size()); + auto exec = gko::ReferenceExecutor::create(); + auto mtx = gko::initialize({{T{1.0, 0.0}, T{3.0, 4.0}, T{0.0, 2.0}}, + {T{-4.0, -3.0}, T{-1.0, 0}, T{0.0, 0.0}}, + {T{0.0, 0.0}, T{0.0, -1.5}, T{2.0, 0.0}}}, + exec); + auto abs_mtx = gko::remove_complex::create(exec, mtx->get_size()); - this->mtx5->row_permute(&permute_idxs, row_permute); + mtx->compute_absolute(abs_mtx); GKO_ASSERT_MTX_NEAR( - row_permute, - l({{-2.0, 2.0, 4.5}, {2.1, 3.4, 1.2}, {1.0, -1.0, -0.5}}), 0.0); + abs_mtx, l({{1.0, 5.0, 2.0}, {5.0, 1.0, 0.0}, {0.0, 1.5, 2.0}}), + 0.0); } -TYPED_TEST(Dense, SquareSubmatrixIsRowPermutableIntoDense) +TYPED_TEST(DenseComplex, MakeComplex) { using Mtx = typename TestFixture::Mtx; using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 0}}; - auto row_permute = Mtx::create(exec, gko::dim<2>{2, 2}, 4); + auto exec = gko::ReferenceExecutor::create(); + auto mtx = gko::initialize({{T{1.0, 0.0}, T{3.0, 4.0}, T{0.0, 2.0}}, + {T{-4.0, -3.0}, T{-1.0, 0}, T{0.0, 0.0}}, + {T{0.0, 0.0}, T{0.0, -1.5}, T{2.0, 0.0}}}, + exec); - this->mtx5->create_submatrix({0, 2}, {0, 2}) - ->row_permute(&permute_idxs, row_permute); + auto complex_mtx = mtx->make_complex(); - GKO_ASSERT_MTX_NEAR(row_permute, l({{-2.0, 2.0}, {1.0, -1.0}}), 0.0); - ASSERT_EQ(row_permute->get_stride(), 4); + GKO_ASSERT_MTX_NEAR(complex_mtx, mtx, 0.0); } -TYPED_TEST(Dense, SquareMatrixRowPermuteIntoDenseFailsForWrongPermutationSize) +TYPED_TEST(DenseComplex, MakeComplexIntoDense) { using Mtx = typename TestFixture::Mtx; using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2}}; - auto row_permute = Mtx::create(exec, this->mtx5->get_size()); + auto exec = gko::ReferenceExecutor::create(); + auto mtx = gko::initialize({{T{1.0, 0.0}, T{3.0, 4.0}, T{0.0, 2.0}}, + {T{-4.0, -3.0}, T{-1.0, 0}, T{0.0, 0.0}}, + {T{0.0, 0.0}, T{0.0, -1.5}, T{2.0, 0.0}}}, + exec); - ASSERT_THROW(this->mtx5->row_permute(&permute_idxs, row_permute), - gko::ValueMismatch); + auto complex_mtx = Mtx::create(exec, mtx->get_size()); + mtx->make_complex(complex_mtx); + + GKO_ASSERT_MTX_NEAR(complex_mtx, mtx, 0.0); } -TYPED_TEST(Dense, SquareMatrixRowPermuteIntoDenseFailsForWrongDimensions) +TYPED_TEST(DenseComplex, GetReal) { using Mtx = typename TestFixture::Mtx; using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; + auto exec = gko::ReferenceExecutor::create(); + auto mtx = gko::initialize({{T{1.0, 0.0}, T{3.0, 4.0}, T{0.0, 2.0}}, + {T{-4.0, -3.0}, T{-1.0, 0}, T{0.0, 0.0}}, + {T{0.0, 0.0}, T{0.0, -1.5}, T{2.0, 0.0}}}, + exec); - ASSERT_THROW(this->mtx5->row_permute(&permute_idxs, Mtx::create(exec)), - gko::DimensionMismatch); + auto real_mtx = mtx->get_real(); + + GKO_ASSERT_MTX_NEAR( + real_mtx, l({{1.0, 3.0, 0.0}, {-4.0, -1.0, 0.0}, {0.0, 0.0, 2.0}}), + 0.0); } -TYPED_TEST(Dense, SquareMatrixIsColPermutable) +TYPED_TEST(DenseComplex, GetRealIntoDense) { using Mtx = typename TestFixture::Mtx; + using RealMtx = typename TestFixture::RealMtx; using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; + auto exec = gko::ReferenceExecutor::create(); + auto mtx = gko::initialize({{T{1.0, 0.0}, T{3.0, 4.0}, T{0.0, 2.0}}, + {T{-4.0, -3.0}, T{-1.0, 0}, T{0.0, 0.0}}, + {T{0.0, 0.0}, T{0.0, -1.5}, T{2.0, 0.0}}}, + exec); - auto c_permute = gko::as(this->mtx5->column_permute(&permute_idxs)); + auto real_mtx = RealMtx::create(exec, mtx->get_size()); + mtx->get_real(real_mtx); GKO_ASSERT_MTX_NEAR( - c_permute, l({{-1.0, -0.5, 1.0}, {2.0, 4.5, -2.0}, {3.4, 1.2, 2.1}}), + real_mtx, l({{1.0, 3.0, 0.0}, {-4.0, -1.0, 0.0}, {0.0, 0.0, 2.0}}), 0.0); } -TYPED_TEST(Dense, NonSquareMatrixIsColPermutable) +TYPED_TEST(DenseComplex, GetImag) { using Mtx = typename TestFixture::Mtx; using T = typename TestFixture::value_type; - auto exec = this->mtx4->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; + auto exec = gko::ReferenceExecutor::create(); + auto mtx = gko::initialize({{T{1.0, 0.0}, T{3.0, 4.0}, T{0.0, 2.0}}, + {T{-4.0, -3.0}, T{-1.0, 0}, T{0.0, 0.0}}, + {T{0.0, 0.0}, T{0.0, -1.5}, T{2.0, 0.0}}}, + exec); - auto c_permute = gko::as(this->mtx4->column_permute(&permute_idxs)); + auto imag_mtx = mtx->get_imag(); - GKO_ASSERT_MTX_NEAR(c_permute, l({{3.0, 2.0, 1.0}, {5.0, 0.0, 0.0}}), - 0.0); + GKO_ASSERT_MTX_NEAR( + imag_mtx, l({{0.0, 4.0, 2.0}, {-3.0, 0.0, 0.0}, {0.0, -1.5, 0.0}}), + 0.0); } -TYPED_TEST(Dense, SquareMatrixIsColPermutableIntoDense) +TYPED_TEST(DenseComplex, GetImagIntoDense) { using Mtx = typename TestFixture::Mtx; + using RealMtx = typename TestFixture::RealMtx; using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; - auto c_permute = Mtx::create(exec, this->mtx5->get_size()); + auto exec = gko::ReferenceExecutor::create(); + auto mtx = gko::initialize({{T{1.0, 0.0}, T{3.0, 4.0}, T{0.0, 2.0}}, + {T{-4.0, -3.0}, T{-1.0, 0}, T{0.0, 0.0}}, + {T{0.0, 0.0}, T{0.0, -1.5}, T{2.0, 0.0}}}, + exec); - this->mtx5->column_permute(&permute_idxs, c_permute); + auto imag_mtx = RealMtx::create(exec, mtx->get_size()); + mtx->get_imag(imag_mtx); GKO_ASSERT_MTX_NEAR( - c_permute, l({{-1.0, -0.5, 1.0}, {2.0, 4.5, -2.0}, {3.4, 1.2, 2.1}}), + imag_mtx, l({{0.0, 4.0, 2.0}, {-3.0, 0.0, 0.0}, {0.0, -1.5, 0.0}}), 0.0); } -TYPED_TEST(Dense, SquareSubmatrixIsColPermutableIntoDense) +TYPED_TEST(DenseComplex, Dot) { using Mtx = typename TestFixture::Mtx; using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 0}}; - auto c_permute = Mtx::create(exec, gko::dim<2>{2, 2}, 4); + auto exec = gko::ReferenceExecutor::create(); + auto a = + gko::initialize({T{1.0, 0.0}, T{3.0, 4.0}, T{1.0, 2.0}}, exec); + auto b = + gko::initialize({T{1.0, -2.0}, T{5.0, 0.0}, T{0.0, -3.0}}, exec); + auto result = gko::initialize({T{0.0, 0.0}}, exec); - this->mtx5->create_submatrix({0, 2}, {0, 2}) - ->column_permute(&permute_idxs, c_permute); + a->compute_dot(b, result); - GKO_ASSERT_MTX_NEAR(c_permute, l({{-1.0, 1.0}, {2.0, -2.0}}), 0.0); - ASSERT_EQ(c_permute->get_stride(), 4); + GKO_ASSERT_MTX_NEAR(result, l({T{22.0, 15.0}}), 0.0); } -TYPED_TEST(Dense, SquareMatrixColPermuteIntoDenseFailsForWrongPermutationSize) +TYPED_TEST(DenseComplex, ConjDot) { using Mtx = typename TestFixture::Mtx; using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2}}; - auto row_permute = Mtx::create(exec, this->mtx5->get_size()); + auto exec = gko::ReferenceExecutor::create(); + auto a = + gko::initialize({T{1.0, 0.0}, T{3.0, 4.0}, T{1.0, 2.0}}, exec); + auto b = + gko::initialize({T{1.0, -2.0}, T{5.0, 0.0}, T{0.0, -3.0}}, exec); + auto result = gko::initialize({T{0.0, 0.0}}, exec); - ASSERT_THROW(this->mtx5->column_permute(&permute_idxs, row_permute), - gko::ValueMismatch); + a->compute_conj_dot(b, result); + + GKO_ASSERT_MTX_NEAR(result, l({T{10.0, -25.0}}), 0.0); } -TYPED_TEST(Dense, SquareMatrixColPermuteIntoDenseFailsForWrongDimensions) -{ - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; +template +class DenseWithIndexType + : public Dense< + typename std::tuple_element<0, decltype(ValueIndexType())>::type> { +public: + using value_type = + typename std::tuple_element<0, decltype(ValueIndexType())>::type; + using index_type = + typename std::tuple_element<1, decltype(ValueIndexType())>::type; + using Permutation = gko::matrix::Permutation; + using ScaledPermutation = + gko::matrix::ScaledPermutation; - ASSERT_THROW(this->mtx5->column_permute(&permute_idxs, Mtx::create(exec)), - gko::DimensionMismatch); -} + DenseWithIndexType() + { + perm2 = Permutation::create(this->exec, 2, + gko::array{this->exec, {1, 0}}); + perm3 = Permutation::create( + this->exec, 3, gko::array{this->exec, {1, 2, 0}}); + perm3_rev = Permutation::create( + this->exec, 3, gko::array{this->exec, {2, 0, 1}}); + perm0 = Permutation::create(this->exec, 0); + scale_perm2 = ScaledPermutation::create( + this->exec, gko::array{this->exec, {17.0, 19.0}}, + gko::array{this->exec, {1, 0}}); + scale_perm3 = ScaledPermutation::create( + this->exec, gko::array{this->exec, {2.0, 3.0, 5.0}}, + gko::array{this->exec, {1, 2, 0}}); + scale_perm3_rev = ScaledPermutation::create( + this->exec, gko::array{this->exec, {7.0, 11.0, 13.0}}, + gko::array{this->exec, {2, 0, 1}}); + scale_perm0 = ScaledPermutation::create(this->exec, 0); + } -TYPED_TEST(Dense, SquareMatrixIsInverseRowPermutable) -{ - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array inverse_permute_idxs{exec, {1, 2, 0}}; + std::unique_ptr perm2; + std::unique_ptr perm3; + std::unique_ptr perm3_rev; + std::unique_ptr perm0; + std::unique_ptr scale_perm2; + std::unique_ptr scale_perm3; + std::unique_ptr scale_perm3_rev; + std::unique_ptr scale_perm0; - auto inverse_row_permute = - gko::as(this->mtx5->inverse_row_permute(&inverse_permute_idxs)); + index_type invalid_index = gko::invalid_index(); +}; - GKO_ASSERT_MTX_NEAR( - inverse_row_permute, - l({{2.1, 3.4, 1.2}, {1.0, -1.0, -0.5}, {-2.0, 2.0, 4.5}}), 0.0); -} +TYPED_TEST_SUITE(DenseWithIndexType, gko::test::ValueIndexTypes, + PairTypenameNameGenerator); -TYPED_TEST(Dense, NonSquareMatrixIsInverseRowPermutable) +template +void assert_coo_eq_mtx4(const gko::matrix::Coo* coo_mtx) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx4->get_executor(); - gko::array inverse_permute_idxs{exec, {1, 0}}; - - auto inverse_row_permute = - gko::as(this->mtx4->inverse_row_permute(&inverse_permute_idxs)); + auto v = coo_mtx->get_const_values(); + auto c = coo_mtx->get_const_col_idxs(); + auto r = coo_mtx->get_const_row_idxs(); - GKO_ASSERT_MTX_NEAR(inverse_row_permute, - l({{0.0, 5.0, 0.0}, {1.0, 3.0, 2.0}}), 0.0); + ASSERT_EQ(coo_mtx->get_size(), gko::dim<2>(2, 3)); + ASSERT_EQ(coo_mtx->get_num_stored_elements(), 4); + EXPECT_EQ(r[0], 0); + EXPECT_EQ(r[1], 0); + EXPECT_EQ(r[2], 0); + EXPECT_EQ(r[3], 1); + EXPECT_EQ(c[0], 0); + EXPECT_EQ(c[1], 1); + EXPECT_EQ(c[2], 2); + EXPECT_EQ(c[3], 1); + EXPECT_EQ(v[0], ValueType{1.0}); + EXPECT_EQ(v[1], ValueType{3.0}); + EXPECT_EQ(v[2], ValueType{2.0}); + EXPECT_EQ(v[3], ValueType{5.0}); } -TYPED_TEST(Dense, SquareMatrixIsInverseRowPermutableIntoDense) +TYPED_TEST(DenseWithIndexType, ConvertsToCoo) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; - auto row_permute = Mtx::create(exec, this->mtx5->get_size()); + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Coo = typename gko::matrix::Coo; + auto coo_mtx = Coo::create(this->mtx4->get_executor()); - this->mtx5->inverse_row_permute(&permute_idxs, row_permute); + this->mtx4->convert_to(coo_mtx); - GKO_ASSERT_MTX_NEAR( - row_permute, - l({{2.1, 3.4, 1.2}, {1.0, -1.0, -0.5}, {-2.0, 2.0, 4.5}}), 0.0); + assert_coo_eq_mtx4(coo_mtx.get()); } -TYPED_TEST(Dense, SquareSubmatrixIsInverseRowPermutableIntoDense) +TYPED_TEST(DenseWithIndexType, MovesToCoo) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 0}}; - auto row_permute = Mtx::create(exec, gko::dim<2>{2, 2}, 4); + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Coo = typename gko::matrix::Coo; + auto coo_mtx = Coo::create(this->mtx4->get_executor()); - this->mtx5->create_submatrix({0, 2}, {0, 2}) - ->inverse_row_permute(&permute_idxs, row_permute); + this->mtx4->move_to(coo_mtx); - GKO_ASSERT_MTX_NEAR(row_permute, l({{-2.0, 2.0}, {1.0, -1.0}}), 0.0); - ASSERT_EQ(row_permute->get_stride(), 4); + assert_coo_eq_mtx4(coo_mtx.get()); } -TYPED_TEST(Dense, - SquareMatrixInverseRowPermuteIntoDenseFailsForWrongPermutationSize) +template +void assert_csr_eq_mtx4(const gko::matrix::Csr* csr_mtx) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2}}; - auto row_permute = Mtx::create(exec, this->mtx5->get_size()); - - ASSERT_THROW(this->mtx5->inverse_row_permute(&permute_idxs, row_permute), - gko::ValueMismatch); + auto v = csr_mtx->get_const_values(); + auto c = csr_mtx->get_const_col_idxs(); + auto r = csr_mtx->get_const_row_ptrs(); + ASSERT_EQ(csr_mtx->get_size(), gko::dim<2>(2, 3)); + ASSERT_EQ(csr_mtx->get_num_stored_elements(), 4); + EXPECT_EQ(r[0], 0); + EXPECT_EQ(r[1], 3); + EXPECT_EQ(r[2], 4); + EXPECT_EQ(c[0], 0); + EXPECT_EQ(c[1], 1); + EXPECT_EQ(c[2], 2); + EXPECT_EQ(c[3], 1); + EXPECT_EQ(v[0], ValueType{1.0}); + EXPECT_EQ(v[1], ValueType{3.0}); + EXPECT_EQ(v[2], ValueType{2.0}); + EXPECT_EQ(v[3], ValueType{5.0}); } -TYPED_TEST(Dense, SquareMatrixInverseRowPermuteIntoDenseFailsForWrongDimensions) +TYPED_TEST(DenseWithIndexType, ConvertsToCsr) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Csr = typename gko::matrix::Csr; + auto csr_s_classical = std::make_shared(); + auto csr_s_merge = std::make_shared(); + auto csr_mtx_c = Csr::create(this->mtx4->get_executor(), csr_s_classical); + auto csr_mtx_m = Csr::create(this->mtx4->get_executor(), csr_s_merge); - ASSERT_THROW( - this->mtx5->inverse_row_permute(&permute_idxs, Mtx::create(exec)), - gko::DimensionMismatch); + this->mtx4->convert_to(csr_mtx_c); + this->mtx4->convert_to(csr_mtx_m); + + assert_csr_eq_mtx4(csr_mtx_c.get()); + ASSERT_EQ(csr_mtx_c->get_strategy()->get_name(), "classical"); + GKO_ASSERT_MTX_NEAR(csr_mtx_c, csr_mtx_m, 0.0); + ASSERT_EQ(csr_mtx_m->get_strategy()->get_name(), "merge_path"); } -TYPED_TEST(Dense, SquareMatrixIsInverseColPermutable) +TYPED_TEST(DenseWithIndexType, MovesToCsr) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array inverse_permute_idxs{exec, {1, 2, 0}}; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Csr = typename gko::matrix::Csr; + auto csr_s_classical = std::make_shared(); + auto csr_s_merge = std::make_shared(); + auto csr_mtx_c = Csr::create(this->mtx4->get_executor(), csr_s_classical); + auto csr_mtx_m = Csr::create(this->mtx4->get_executor(), csr_s_merge); + auto mtx_clone = this->mtx4->clone(); - auto inverse_c_permute = - gko::as(this->mtx5->inverse_column_permute(&inverse_permute_idxs)); + this->mtx4->move_to(csr_mtx_c); + mtx_clone->move_to(csr_mtx_m); - GKO_ASSERT_MTX_NEAR( - inverse_c_permute, - l({{-0.5, 1.0, -1.0}, {4.5, -2.0, 2.0}, {1.2, 2.1, 3.4}}), 0.0); + assert_csr_eq_mtx4(csr_mtx_c.get()); + ASSERT_EQ(csr_mtx_c->get_strategy()->get_name(), "classical"); + GKO_ASSERT_MTX_NEAR(csr_mtx_c, csr_mtx_m, 0.0); + ASSERT_EQ(csr_mtx_m->get_strategy()->get_name(), "merge_path"); } -TYPED_TEST(Dense, NonSquareMatrixIsInverseColPermutable) +template +void assert_sparsity_csr_eq_mtx4( + const gko::matrix::SparsityCsr* sparsity_csr_mtx) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx4->get_executor(); - gko::array inverse_permute_idxs{exec, {1, 2, 0}}; - - auto inverse_c_permute = - gko::as(this->mtx4->inverse_column_permute(&inverse_permute_idxs)); + auto v = sparsity_csr_mtx->get_const_value(); + auto c = sparsity_csr_mtx->get_const_col_idxs(); + auto r = sparsity_csr_mtx->get_const_row_ptrs(); - GKO_ASSERT_MTX_NEAR(inverse_c_permute, - l({{2.0, 1.0, 3.0}, {0.0, 0.0, 5.0}}), 0.0); + ASSERT_EQ(sparsity_csr_mtx->get_size(), gko::dim<2>(2, 3)); + ASSERT_EQ(sparsity_csr_mtx->get_num_nonzeros(), 4); + EXPECT_EQ(r[0], 0); + EXPECT_EQ(r[1], 3); + EXPECT_EQ(r[2], 4); + EXPECT_EQ(c[0], 0); + EXPECT_EQ(c[1], 1); + EXPECT_EQ(c[2], 2); + EXPECT_EQ(c[3], 1); + EXPECT_EQ(v[0], ValueType{1.0}); } -TYPED_TEST(Dense, SquareMatrixIsInverseColPermutableIntoDense) +TYPED_TEST(DenseWithIndexType, ConvertsToSparsityCsr) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; - auto c_permute = Mtx::create(exec, this->mtx5->get_size()); + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using SparsityCsr = + typename gko::matrix::SparsityCsr; + auto sparsity_csr_mtx = SparsityCsr::create(this->mtx4->get_executor()); - this->mtx5->inverse_column_permute(&permute_idxs, c_permute); + this->mtx4->convert_to(sparsity_csr_mtx); - GKO_ASSERT_MTX_NEAR( - c_permute, l({{-0.5, 1.0, -1.0}, {4.5, -2.0, 2.0}, {1.2, 2.1, 3.4}}), - 0.0); + assert_sparsity_csr_eq_mtx4(sparsity_csr_mtx.get()); } -TYPED_TEST(Dense, SquareSubmatrixIsInverseColPermutableIntoDense) +TYPED_TEST(DenseWithIndexType, MovesToSparsityCsr) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 0}}; - auto c_permute = Mtx::create(exec, gko::dim<2>{2, 2}, 4); + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using SparsityCsr = + typename gko::matrix::SparsityCsr; + auto sparsity_csr_mtx = SparsityCsr::create(this->mtx4->get_executor()); - this->mtx5->create_submatrix({0, 2}, {0, 2}) - ->column_permute(&permute_idxs, c_permute); + this->mtx4->move_to(sparsity_csr_mtx); - GKO_ASSERT_MTX_NEAR(c_permute, l({{-1.0, 1.0}, {2.0, -2.0}}), 0.0); - ASSERT_EQ(c_permute->get_stride(), 4); + assert_sparsity_csr_eq_mtx4(sparsity_csr_mtx.get()); } -TYPED_TEST(Dense, - SquareMatrixInverseColPermuteIntoDenseFailsForWrongPermutationSize) +template +void assert_ell_eq_mtx6(const gko::matrix::Ell* ell_mtx) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2}}; - auto row_permute = Mtx::create(exec, this->mtx5->get_size()); + auto v = ell_mtx->get_const_values(); + auto c = ell_mtx->get_const_col_idxs(); - ASSERT_THROW(this->mtx5->inverse_column_permute(&permute_idxs, row_permute), - gko::ValueMismatch); + ASSERT_EQ(ell_mtx->get_size(), gko::dim<2>(2, 3)); + ASSERT_EQ(ell_mtx->get_num_stored_elements_per_row(), 2); + ASSERT_EQ(ell_mtx->get_num_stored_elements(), 4); + ASSERT_EQ(ell_mtx->get_stride(), 2); + EXPECT_EQ(c[0], 0); + EXPECT_EQ(c[1], 1); + EXPECT_EQ(c[2], 1); + EXPECT_EQ(c[3], gko::invalid_index()); + EXPECT_EQ(v[0], ValueType{1.0}); + EXPECT_EQ(v[1], ValueType{1.5}); + EXPECT_EQ(v[2], ValueType{2.0}); + EXPECT_EQ(v[3], ValueType{0.0}); } -TYPED_TEST(Dense, SquareMatrixInverseColPermuteIntoDenseFailsForWrongDimensions) +TYPED_TEST(DenseWithIndexType, ConvertsToEll) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Ell = typename gko::matrix::Ell; + auto ell_mtx = Ell::create(this->mtx6->get_executor()); - ASSERT_THROW( - this->mtx5->inverse_column_permute(&permute_idxs, Mtx::create(exec)), - gko::DimensionMismatch); + this->mtx6->convert_to(ell_mtx); + + assert_ell_eq_mtx6(ell_mtx.get()); } -TYPED_TEST(Dense, SquareMatrixIsRowPermutable64) +TYPED_TEST(DenseWithIndexType, MovesToEll) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Ell = typename gko::matrix::Ell; + auto ell_mtx = Ell::create(this->mtx6->get_executor()); - auto row_permute = gko::as(this->mtx5->row_permute(&permute_idxs)); + this->mtx6->move_to(ell_mtx); - GKO_ASSERT_MTX_NEAR( - row_permute, - l({{-2.0, 2.0, 4.5}, {2.1, 3.4, 1.2}, {1.0, -1.0, -0.5}}), 0.0); + assert_ell_eq_mtx6(ell_mtx.get()); } -TYPED_TEST(Dense, NonSquareMatrixIsRowPermutable64) +template +void assert_strided_ell_eq_mtx6( + const gko::matrix::Ell* ell_mtx) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx4->get_executor(); - gko::array permute_idxs{exec, {1, 0}}; - - auto row_permute = gko::as(this->mtx4->row_permute(&permute_idxs)); + constexpr auto invalid_index = gko::invalid_index(); + auto v = ell_mtx->get_const_values(); + auto c = ell_mtx->get_const_col_idxs(); - GKO_ASSERT_MTX_NEAR(row_permute, l({{0.0, 5.0, 0.0}, {1.0, 3.0, 2.0}}), - 0.0); + ASSERT_EQ(ell_mtx->get_size(), gko::dim<2>(2, 3)); + ASSERT_EQ(ell_mtx->get_num_stored_elements_per_row(), 2); + ASSERT_EQ(ell_mtx->get_num_stored_elements(), 6); + ASSERT_EQ(ell_mtx->get_stride(), 3); + EXPECT_EQ(c[0], 0); + EXPECT_EQ(c[1], 1); + EXPECT_EQ(c[2], invalid_index); + EXPECT_EQ(c[3], 1); + EXPECT_EQ(c[4], invalid_index); + EXPECT_EQ(c[5], invalid_index); + EXPECT_EQ(v[0], ValueType{1.0}); + EXPECT_EQ(v[1], ValueType{1.5}); + EXPECT_EQ(v[2], ValueType{0.0}); + EXPECT_EQ(v[3], ValueType{2.0}); + EXPECT_EQ(v[4], ValueType{0.0}); + EXPECT_EQ(v[5], ValueType{0.0}); } -TYPED_TEST(Dense, SquareMatrixIsRowPermutableIntoDense64) +TYPED_TEST(DenseWithIndexType, ConvertsToEllWithStride) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; - auto row_permute = Mtx::create(exec, this->mtx5->get_size()); + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Ell = typename gko::matrix::Ell; + auto ell_mtx = + Ell::create(this->mtx6->get_executor(), gko::dim<2>{2, 3}, 2, 3); - this->mtx5->row_permute(&permute_idxs, row_permute); + this->mtx6->convert_to(ell_mtx); - GKO_ASSERT_MTX_NEAR( - row_permute, - l({{-2.0, 2.0, 4.5}, {2.1, 3.4, 1.2}, {1.0, -1.0, -0.5}}), 0.0); + assert_strided_ell_eq_mtx6(ell_mtx.get()); } -TYPED_TEST(Dense, SquareSubmatrixIsRowPermutableIntoDense64) +TYPED_TEST(DenseWithIndexType, MovesToEllWithStride) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 0}}; - auto row_permute = Mtx::create(exec, gko::dim<2>{2, 2}, 4); + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Ell = typename gko::matrix::Ell; + auto ell_mtx = + Ell::create(this->mtx6->get_executor(), gko::dim<2>{2, 3}, 2, 3); - this->mtx5->create_submatrix({0, 2}, {0, 2}) - ->row_permute(&permute_idxs, row_permute); + this->mtx6->move_to(ell_mtx); - GKO_ASSERT_MTX_NEAR(row_permute, l({{-2.0, 2.0}, {1.0, -1.0}}), 0.0); - ASSERT_EQ(row_permute->get_stride(), 4); + assert_strided_ell_eq_mtx6(ell_mtx.get()); } -TYPED_TEST(Dense, SquareMatrixRowPermuteIntoDenseFailsForWrongPermutationSize64) +template +void assert_hybrid_auto_eq_mtx4( + const gko::matrix::Hybrid* hybrid_mtx) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2}}; - auto row_permute = Mtx::create(exec, this->mtx5->get_size()); + auto v = hybrid_mtx->get_const_coo_values(); + auto c = hybrid_mtx->get_const_coo_col_idxs(); + auto r = hybrid_mtx->get_const_coo_row_idxs(); + auto n = hybrid_mtx->get_ell_num_stored_elements_per_row(); + auto p = hybrid_mtx->get_ell_stride(); - ASSERT_THROW(this->mtx5->row_permute(&permute_idxs, row_permute), - gko::ValueMismatch); + ASSERT_EQ(hybrid_mtx->get_size(), gko::dim<2>(2, 3)); + ASSERT_EQ(hybrid_mtx->get_ell_num_stored_elements(), 0); + ASSERT_EQ(hybrid_mtx->get_coo_num_stored_elements(), 4); + EXPECT_EQ(n, 0); + EXPECT_EQ(p, 2); + EXPECT_EQ(r[0], 0); + EXPECT_EQ(r[1], 0); + EXPECT_EQ(r[2], 0); + EXPECT_EQ(r[3], 1); + EXPECT_EQ(c[0], 0); + EXPECT_EQ(c[1], 1); + EXPECT_EQ(c[2], 2); + EXPECT_EQ(c[3], 1); + EXPECT_EQ(v[0], ValueType{1.0}); + EXPECT_EQ(v[1], ValueType{3.0}); + EXPECT_EQ(v[2], ValueType{2.0}); + EXPECT_EQ(v[3], ValueType{5.0}); } -TYPED_TEST(Dense, SquareMatrixRowPermuteIntoDenseFailsForWrongDimensions64) +TYPED_TEST(DenseWithIndexType, MovesToHybridAutomatically) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Hybrid = typename gko::matrix::Hybrid; + auto hybrid_mtx = Hybrid::create(this->mtx4->get_executor()); - ASSERT_THROW(this->mtx5->row_permute(&permute_idxs, Mtx::create(exec)), - gko::DimensionMismatch); + this->mtx4->move_to(hybrid_mtx); + + assert_hybrid_auto_eq_mtx4(hybrid_mtx.get()); } -TYPED_TEST(Dense, SquareMatrixIsColPermutable64) +TYPED_TEST(DenseWithIndexType, ConvertsToHybridAutomatically) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Hybrid = typename gko::matrix::Hybrid; + auto hybrid_mtx = Hybrid::create(this->mtx4->get_executor()); - auto c_permute = gko::as(this->mtx5->column_permute(&permute_idxs)); + this->mtx4->convert_to(hybrid_mtx); - GKO_ASSERT_MTX_NEAR( - c_permute, l({{-1.0, -0.5, 1.0}, {2.0, 4.5, -2.0}, {3.4, 1.2, 2.1}}), - 0.0); + assert_hybrid_auto_eq_mtx4(hybrid_mtx.get()); } -TYPED_TEST(Dense, NonSquareMatrixIsColPermutable64) +template +void assert_hybrid_strided_eq_mtx4( + const gko::matrix::Hybrid* hybrid_mtx) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx4->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; - - auto c_permute = gko::as(this->mtx4->column_permute(&permute_idxs)); + auto v = hybrid_mtx->get_const_coo_values(); + auto c = hybrid_mtx->get_const_coo_col_idxs(); + auto r = hybrid_mtx->get_const_coo_row_idxs(); + auto n = hybrid_mtx->get_ell_num_stored_elements_per_row(); + auto p = hybrid_mtx->get_ell_stride(); - GKO_ASSERT_MTX_NEAR(c_permute, l({{3.0, 2.0, 1.0}, {5.0, 0.0, 0.0}}), - 0.0); + ASSERT_EQ(hybrid_mtx->get_size(), gko::dim<2>(2, 3)); + ASSERT_EQ(hybrid_mtx->get_ell_num_stored_elements(), 0); + ASSERT_EQ(hybrid_mtx->get_coo_num_stored_elements(), 4); + EXPECT_EQ(n, 0); + EXPECT_EQ(p, 3); + EXPECT_EQ(r[0], 0); + EXPECT_EQ(r[1], 0); + EXPECT_EQ(r[2], 0); + EXPECT_EQ(r[3], 1); + EXPECT_EQ(c[0], 0); + EXPECT_EQ(c[1], 1); + EXPECT_EQ(c[2], 2); + EXPECT_EQ(c[3], 1); + EXPECT_EQ(v[0], ValueType{1.0}); + EXPECT_EQ(v[1], ValueType{3.0}); + EXPECT_EQ(v[2], ValueType{2.0}); + EXPECT_EQ(v[3], ValueType{5.0}); } -TYPED_TEST(Dense, SquareMatrixIsColPermutableIntoDense64) +TYPED_TEST(DenseWithIndexType, MovesToHybridWithStrideAutomatically) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; - auto c_permute = Mtx::create(exec, this->mtx5->get_size()); + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Hybrid = typename gko::matrix::Hybrid; + auto hybrid_mtx = + Hybrid::create(this->mtx4->get_executor(), gko::dim<2>{2, 3}, 0, 3); - this->mtx5->column_permute(&permute_idxs, c_permute); + this->mtx4->move_to(hybrid_mtx); - GKO_ASSERT_MTX_NEAR( - c_permute, l({{-1.0, -0.5, 1.0}, {2.0, 4.5, -2.0}, {3.4, 1.2, 2.1}}), - 0.0); + assert_hybrid_strided_eq_mtx4(hybrid_mtx.get()); } -TYPED_TEST(Dense, SquareSubmatrixIsColPermutableIntoDense64) +TYPED_TEST(DenseWithIndexType, ConvertsToHybridWithStrideAutomatically) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 0}}; - auto c_permute = Mtx::create(exec, gko::dim<2>{2, 2}, 4); + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Hybrid = typename gko::matrix::Hybrid; + auto hybrid_mtx = + Hybrid::create(this->mtx4->get_executor(), gko::dim<2>{2, 3}, 0, 3); - this->mtx5->create_submatrix({0, 2}, {0, 2}) - ->column_permute(&permute_idxs, c_permute); + this->mtx4->convert_to(hybrid_mtx); - GKO_ASSERT_MTX_NEAR(c_permute, l({{-1.0, 1.0}, {2.0, -2.0}}), 0.0); - ASSERT_EQ(c_permute->get_stride(), 4); + assert_hybrid_strided_eq_mtx4(hybrid_mtx.get()); } -TYPED_TEST(Dense, SquareMatrixColPermuteIntoDenseFailsForWrongPermutationSize64) +template +void assert_hybrid_limited_eq_mtx4( + const gko::matrix::Hybrid* hybrid_mtx) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2}}; - auto row_permute = Mtx::create(exec, this->mtx5->get_size()); + constexpr auto invalid_index = gko::invalid_index(); + auto v = hybrid_mtx->get_const_ell_values(); + auto c = hybrid_mtx->get_const_ell_col_idxs(); + auto n = hybrid_mtx->get_ell_num_stored_elements_per_row(); + auto p = hybrid_mtx->get_ell_stride(); - ASSERT_THROW(this->mtx5->column_permute(&permute_idxs, row_permute), - gko::ValueMismatch); + ASSERT_EQ(hybrid_mtx->get_size(), gko::dim<2>(2, 3)); + ASSERT_EQ(hybrid_mtx->get_ell_num_stored_elements(), 6); + ASSERT_EQ(hybrid_mtx->get_coo_num_stored_elements(), 1); + EXPECT_EQ(n, 2); + EXPECT_EQ(p, 3); + EXPECT_EQ(c[0], 0); + EXPECT_EQ(c[1], 1); + EXPECT_EQ(c[2], invalid_index); + EXPECT_EQ(c[3], 1); + EXPECT_EQ(c[4], invalid_index); + EXPECT_EQ(c[5], invalid_index); + EXPECT_EQ(v[0], ValueType{1.0}); + EXPECT_EQ(v[1], ValueType{5.0}); + EXPECT_EQ(v[2], ValueType{0.0}); + EXPECT_EQ(v[3], ValueType{3.0}); + EXPECT_EQ(v[4], ValueType{0.0}); + EXPECT_EQ(v[5], ValueType{0.0}); + EXPECT_EQ(hybrid_mtx->get_const_coo_values()[0], ValueType{2.0}); + EXPECT_EQ(hybrid_mtx->get_const_coo_row_idxs()[0], 0); + EXPECT_EQ(hybrid_mtx->get_const_coo_col_idxs()[0], 2); } -TYPED_TEST(Dense, SquareMatrixColPermuteIntoDenseFailsForWrongDimensions64) +TYPED_TEST(DenseWithIndexType, MovesToHybridWithStrideAndCooLengthByColumns2) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Hybrid = typename gko::matrix::Hybrid; + auto hybrid_mtx = + Hybrid::create(this->mtx4->get_executor(), gko::dim<2>{2, 3}, 2, 3, 3, + std::make_shared(2)); - ASSERT_THROW(this->mtx5->column_permute(&permute_idxs, Mtx::create(exec)), - gko::DimensionMismatch); + this->mtx4->move_to(hybrid_mtx); + + assert_hybrid_limited_eq_mtx4(hybrid_mtx.get()); } -TYPED_TEST(Dense, SquareMatrixIsInverseRowPermutable64) +TYPED_TEST(DenseWithIndexType, ConvertsToHybridWithStrideAndCooLengthByColumns2) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array inverse_permute_idxs{exec, {1, 2, 0}}; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Hybrid = typename gko::matrix::Hybrid; + auto hybrid_mtx = + Hybrid::create(this->mtx4->get_executor(), gko::dim<2>{2, 3}, 2, 3, 3, + std::make_shared(2)); - auto inverse_row_permute = - gko::as(this->mtx5->inverse_row_permute(&inverse_permute_idxs)); + this->mtx4->convert_to(hybrid_mtx); - GKO_ASSERT_MTX_NEAR( - inverse_row_permute, - l({{2.1, 3.4, 1.2}, {1.0, -1.0, -0.5}, {-2.0, 2.0, 4.5}}), 0.0); + assert_hybrid_limited_eq_mtx4(hybrid_mtx.get()); } -TYPED_TEST(Dense, NonSquareMatrixIsInverseRowPermutable64) +template +void assert_hybrid_percent_eq_mtx4( + const gko::matrix::Hybrid* hybrid_mtx) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx4->get_executor(); - gko::array inverse_permute_idxs{exec, {1, 0}}; - - auto inverse_row_permute = - gko::as(this->mtx4->inverse_row_permute(&inverse_permute_idxs)); + auto v = hybrid_mtx->get_const_ell_values(); + auto c = hybrid_mtx->get_const_ell_col_idxs(); + auto n = hybrid_mtx->get_ell_num_stored_elements_per_row(); + auto p = hybrid_mtx->get_ell_stride(); + auto coo_v = hybrid_mtx->get_const_coo_values(); + auto coo_c = hybrid_mtx->get_const_coo_col_idxs(); + auto coo_r = hybrid_mtx->get_const_coo_row_idxs(); - GKO_ASSERT_MTX_NEAR(inverse_row_permute, - l({{0.0, 5.0, 0.0}, {1.0, 3.0, 2.0}}), 0.0); + ASSERT_EQ(hybrid_mtx->get_size(), gko::dim<2>(2, 3)); + ASSERT_EQ(hybrid_mtx->get_ell_num_stored_elements(), 3); + EXPECT_EQ(n, 1); + EXPECT_EQ(p, 3); + EXPECT_EQ(c[0], 0); + EXPECT_EQ(c[1], 1); + EXPECT_EQ(c[2], gko::invalid_index()); + EXPECT_EQ(v[0], ValueType{1.0}); + EXPECT_EQ(v[1], ValueType{5.0}); + EXPECT_EQ(v[2], ValueType{0.0}); + ASSERT_EQ(hybrid_mtx->get_coo_num_stored_elements(), 2); + EXPECT_EQ(coo_v[0], ValueType{3.0}); + EXPECT_EQ(coo_v[1], ValueType{2.0}); + EXPECT_EQ(coo_c[0], 1); + EXPECT_EQ(coo_c[1], 2); + EXPECT_EQ(coo_r[0], 0); + EXPECT_EQ(coo_r[1], 0); } -TYPED_TEST(Dense, SquareMatrixIsInverseRowPermutableIntoDense64) +TYPED_TEST(DenseWithIndexType, MovesToHybridWithStrideByPercent40) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; - auto row_permute = Mtx::create(exec, this->mtx5->get_size()); + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Hybrid = typename gko::matrix::Hybrid; + auto hybrid_mtx = + Hybrid::create(this->mtx4->get_executor(), gko::dim<2>{2, 3}, 1, 3, + std::make_shared(0.4)); - this->mtx5->inverse_row_permute(&permute_idxs, row_permute); + this->mtx4->move_to(hybrid_mtx); - GKO_ASSERT_MTX_NEAR( - row_permute, - l({{2.1, 3.4, 1.2}, {1.0, -1.0, -0.5}, {-2.0, 2.0, 4.5}}), 0.0); + assert_hybrid_percent_eq_mtx4(hybrid_mtx.get()); } -TYPED_TEST(Dense, SquareSubmatrixIsInverseRowPermutableIntoDense64) +TYPED_TEST(DenseWithIndexType, ConvertsToHybridWithStrideByPercent40) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 0}}; - auto row_permute = Mtx::create(exec, gko::dim<2>{2, 2}, 4); + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Hybrid = typename gko::matrix::Hybrid; + auto hybrid_mtx = + Hybrid::create(this->mtx4->get_executor(), gko::dim<2>{2, 3}, 1, 3, + std::make_shared(0.4)); - this->mtx5->create_submatrix({0, 2}, {0, 2}) - ->inverse_row_permute(&permute_idxs, row_permute); + this->mtx4->convert_to(hybrid_mtx); - GKO_ASSERT_MTX_NEAR(row_permute, l({{-2.0, 2.0}, {1.0, -1.0}}), 0.0); - ASSERT_EQ(row_permute->get_stride(), 4); + assert_hybrid_percent_eq_mtx4(hybrid_mtx.get()); } -TYPED_TEST(Dense, - SquareMatrixInverseRowPermuteIntoDenseFailsForWrongPermutationSize64) +template +void assert_sellp_eq_mtx7( + const gko::matrix::Sellp* sellp_mtx) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2}}; - auto row_permute = Mtx::create(exec, this->mtx5->get_size()); + constexpr auto invalid_index = gko::invalid_index(); + auto v = sellp_mtx->get_const_values(); + auto c = sellp_mtx->get_const_col_idxs(); + auto s = sellp_mtx->get_const_slice_sets(); + auto l = sellp_mtx->get_const_slice_lengths(); - ASSERT_THROW(this->mtx5->inverse_row_permute(&permute_idxs, row_permute), - gko::ValueMismatch); + ASSERT_EQ(sellp_mtx->get_size(), gko::dim<2>(2, 3)); + ASSERT_EQ(sellp_mtx->get_total_cols(), 3); + ASSERT_EQ(sellp_mtx->get_num_stored_elements(), + 3 * gko::matrix::default_slice_size); + ASSERT_EQ(sellp_mtx->get_slice_size(), gko::matrix::default_slice_size); + ASSERT_EQ(sellp_mtx->get_stride_factor(), + gko::matrix::default_stride_factor); + EXPECT_EQ(c[0], 0); + EXPECT_EQ(c[1], 1); + EXPECT_EQ(c[gko::matrix::default_slice_size], 1); + EXPECT_EQ(c[gko::matrix::default_slice_size + 1], invalid_index); + EXPECT_EQ(c[2 * gko::matrix::default_slice_size], 2); + EXPECT_EQ(c[2 * gko::matrix::default_slice_size + 1], invalid_index); + EXPECT_EQ(v[0], ValueType{1.0}); + EXPECT_EQ(v[1], ValueType{1.5}); + EXPECT_EQ(v[gko::matrix::default_slice_size], ValueType{2.0}); + EXPECT_EQ(v[gko::matrix::default_slice_size + 1], ValueType{0.0}); + EXPECT_EQ(v[2 * gko::matrix::default_slice_size], ValueType{3.0}); + EXPECT_EQ(v[2 * gko::matrix::default_slice_size + 1], ValueType{0.0}); + EXPECT_EQ(s[0], 0); + EXPECT_EQ(s[1], 3); + EXPECT_EQ(l[0], 3); } -TYPED_TEST(Dense, - SquareMatrixInverseRowPermuteIntoDenseFailsForWrongDimensions64) +TYPED_TEST(DenseWithIndexType, ConvertsToSellp) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Sellp = typename gko::matrix::Sellp; + auto sellp_mtx = Sellp::create(this->mtx7->get_executor()); - ASSERT_THROW( - this->mtx5->inverse_row_permute(&permute_idxs, Mtx::create(exec)), - gko::DimensionMismatch); + this->mtx7->convert_to(sellp_mtx); + + assert_sellp_eq_mtx7(sellp_mtx.get()); } -TYPED_TEST(Dense, SquareMatrixIsInverseColPermutable64) +TYPED_TEST(DenseWithIndexType, MovesToSellp) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array inverse_permute_idxs{exec, {1, 2, 0}}; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Sellp = typename gko::matrix::Sellp; + auto sellp_mtx = Sellp::create(this->mtx7->get_executor()); - auto inverse_c_permute = - gko::as(this->mtx5->inverse_column_permute(&inverse_permute_idxs)); + this->mtx7->move_to(sellp_mtx); - GKO_ASSERT_MTX_NEAR( - inverse_c_permute, - l({{-0.5, 1.0, -1.0}, {4.5, -2.0, 2.0}, {1.2, 2.1, 3.4}}), 0.0); + assert_sellp_eq_mtx7(sellp_mtx.get()); } -TYPED_TEST(Dense, NonSquareMatrixIsInverseColPermutable64) +template +void assert_sellp_strided_eq_mtx7( + const gko::matrix::Sellp* sellp_mtx) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx4->get_executor(); - gko::array inverse_permute_idxs{exec, {1, 2, 0}}; - - auto inverse_c_permute = - gko::as(this->mtx4->inverse_column_permute(&inverse_permute_idxs)); + constexpr auto invalid_index = gko::invalid_index(); + auto v = sellp_mtx->get_const_values(); + auto c = sellp_mtx->get_const_col_idxs(); + auto s = sellp_mtx->get_const_slice_sets(); + auto l = sellp_mtx->get_const_slice_lengths(); - GKO_ASSERT_MTX_NEAR(inverse_c_permute, - l({{2.0, 1.0, 3.0}, {0.0, 0.0, 5.0}}), 0.0); + ASSERT_EQ(sellp_mtx->get_size(), gko::dim<2>(2, 3)); + ASSERT_EQ(sellp_mtx->get_total_cols(), 4); + ASSERT_EQ(sellp_mtx->get_num_stored_elements(), 8); + ASSERT_EQ(sellp_mtx->get_slice_size(), 2); + ASSERT_EQ(sellp_mtx->get_stride_factor(), 2); + EXPECT_EQ(c[0], 0); + EXPECT_EQ(c[1], 1); + EXPECT_EQ(c[2], 1); + EXPECT_EQ(c[3], invalid_index); + EXPECT_EQ(c[4], 2); + EXPECT_EQ(c[5], invalid_index); + EXPECT_EQ(c[6], invalid_index); + EXPECT_EQ(c[7], invalid_index); + EXPECT_EQ(v[0], ValueType{1.0}); + EXPECT_EQ(v[1], ValueType{1.5}); + EXPECT_EQ(v[2], ValueType{2.0}); + EXPECT_EQ(v[3], ValueType{0.0}); + EXPECT_EQ(v[4], ValueType{3.0}); + EXPECT_EQ(v[5], ValueType{0.0}); + EXPECT_EQ(v[6], ValueType{0.0}); + EXPECT_EQ(v[7], ValueType{0.0}); + EXPECT_EQ(s[0], 0); + EXPECT_EQ(s[1], 4); + EXPECT_EQ(l[0], 4); } -TYPED_TEST(Dense, SquareMatrixIsInverseColPermutableIntoDense64) +TYPED_TEST(DenseWithIndexType, ConvertsToSellpWithSliceSizeAndStrideFactor) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; - auto c_permute = Mtx::create(exec, this->mtx5->get_size()); + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Sellp = typename gko::matrix::Sellp; + auto sellp_mtx = + Sellp::create(this->mtx7->get_executor(), gko::dim<2>{}, 2, 2, 0); - this->mtx5->inverse_column_permute(&permute_idxs, c_permute); + this->mtx7->convert_to(sellp_mtx); - GKO_ASSERT_MTX_NEAR( - c_permute, l({{-0.5, 1.0, -1.0}, {4.5, -2.0, 2.0}, {1.2, 2.1, 3.4}}), - 0.0); + assert_sellp_strided_eq_mtx7(sellp_mtx.get()); } -TYPED_TEST(Dense, SquareSubmatrixIsInverseColPermutableIntoDense64) +TYPED_TEST(DenseWithIndexType, MovesToSellpWithSliceSizeAndStrideFactor) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 0}}; - auto c_permute = Mtx::create(exec, gko::dim<2>{2, 2}, 4); + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Sellp = typename gko::matrix::Sellp; + auto sellp_mtx = + Sellp::create(this->mtx7->get_executor(), gko::dim<2>{}, 2, 2, 0); - this->mtx5->create_submatrix({0, 2}, {0, 2}) - ->column_permute(&permute_idxs, c_permute); + this->mtx7->move_to(sellp_mtx); - GKO_ASSERT_MTX_NEAR(c_permute, l({{-1.0, 1.0}, {2.0, -2.0}}), 0.0); - ASSERT_EQ(c_permute->get_stride(), 4); + assert_sellp_strided_eq_mtx7(sellp_mtx.get()); } -TYPED_TEST(Dense, - SquareMatrixInverseColPermuteIntoDenseFailsForWrongPermutationSize64) +TYPED_TEST(DenseWithIndexType, ConvertsToAndFromSellpWithMoreThanOneSlice) { + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2}}; - auto row_permute = Mtx::create(exec, this->mtx5->get_size()); - - ASSERT_THROW(this->mtx5->inverse_column_permute(&permute_idxs, row_permute), - gko::ValueMismatch); -} - + using Sellp = typename gko::matrix::Sellp; + auto x = this->template gen_mtx(65, 25); -TYPED_TEST(Dense, - SquareMatrixInverseColPermuteIntoDenseFailsForWrongDimensions64) -{ - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = this->mtx5->get_executor(); - gko::array permute_idxs{exec, {1, 2, 0}}; + auto sellp_mtx = Sellp::create(this->exec); + auto dense_mtx = Mtx::create(this->exec); + x->convert_to(sellp_mtx); + sellp_mtx->convert_to(dense_mtx); - ASSERT_THROW( - this->mtx5->inverse_column_permute(&permute_idxs, Mtx::create(exec)), - gko::DimensionMismatch); + GKO_ASSERT_MTX_NEAR(dense_mtx, x, 0.0); } -TYPED_TEST(Dense, ExtractsDiagonalFromSquareMatrix) +TYPED_TEST(DenseWithIndexType, ConvertsEmptyToCoo) { - using T = typename TestFixture::value_type; + using Dense = typename TestFixture::Mtx; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Coo = typename gko::matrix::Coo; + auto empty = Dense::create(this->exec); + auto res = Coo::create(this->exec); - auto diag = this->mtx5->extract_diagonal(); + empty->convert_to(res); - ASSERT_EQ(diag->get_size()[0], 3); - ASSERT_EQ(diag->get_size()[1], 3); - ASSERT_EQ(diag->get_values()[0], T{1.}); - ASSERT_EQ(diag->get_values()[1], T{2.}); - ASSERT_EQ(diag->get_values()[2], T{1.2}); + ASSERT_EQ(res->get_num_stored_elements(), 0); + ASSERT_FALSE(res->get_size()); } -TYPED_TEST(Dense, ExtractsDiagonalFromTallSkinnyMatrix) +TYPED_TEST(DenseWithIndexType, MovesEmptyToCoo) { - using T = typename TestFixture::value_type; + using Dense = typename TestFixture::Mtx; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Coo = typename gko::matrix::Coo; + auto empty = Dense::create(this->exec); + auto res = Coo::create(this->exec); - auto diag = this->mtx4->extract_diagonal(); + empty->move_to(res); - ASSERT_EQ(diag->get_size()[0], 2); - ASSERT_EQ(diag->get_size()[1], 2); - ASSERT_EQ(diag->get_values()[0], T{1.}); - ASSERT_EQ(diag->get_values()[1], T{5.}); + ASSERT_EQ(res->get_num_stored_elements(), 0); + ASSERT_FALSE(res->get_size()); } -TYPED_TEST(Dense, ExtractsDiagonalFromShortFatMatrix) +TYPED_TEST(DenseWithIndexType, ConvertsEmptyMatrixToCsr) { - using T = typename TestFixture::value_type; + using Dense = typename TestFixture::Mtx; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Csr = typename gko::matrix::Csr; + auto empty = Dense::create(this->exec); + auto res = Csr::create(this->exec); - auto diag = this->mtx8->extract_diagonal(); + empty->convert_to(res); - ASSERT_EQ(diag->get_size()[0], 2); - ASSERT_EQ(diag->get_size()[1], 2); - ASSERT_EQ(diag->get_values()[0], T{1.}); - ASSERT_EQ(diag->get_values()[1], T{2.}); + ASSERT_EQ(res->get_num_stored_elements(), 0); + ASSERT_EQ(*res->get_const_row_ptrs(), 0); + ASSERT_FALSE(res->get_size()); } -TYPED_TEST(Dense, ExtractsDiagonalFromSquareMatrixIntoDiagonal) +TYPED_TEST(DenseWithIndexType, MovesEmptyMatrixToCsr) { - using T = typename TestFixture::value_type; - auto diag = gko::matrix::Diagonal::create(this->exec, 3); + using Dense = typename TestFixture::Mtx; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Csr = typename gko::matrix::Csr; + auto empty = Dense::create(this->exec); + auto res = Csr::create(this->exec); - this->mtx5->extract_diagonal(diag); + empty->move_to(res); - ASSERT_EQ(diag->get_size()[0], 3); - ASSERT_EQ(diag->get_size()[1], 3); - ASSERT_EQ(diag->get_values()[0], T{1.}); - ASSERT_EQ(diag->get_values()[1], T{2.}); - ASSERT_EQ(diag->get_values()[2], T{1.2}); + ASSERT_EQ(res->get_num_stored_elements(), 0); + ASSERT_EQ(*res->get_const_row_ptrs(), 0); + ASSERT_FALSE(res->get_size()); } -TYPED_TEST(Dense, ExtractsDiagonalFromTallSkinnyMatrixIntoDiagonal) +TYPED_TEST(DenseWithIndexType, ConvertsEmptyToSparsityCsr) { - using T = typename TestFixture::value_type; - auto diag = gko::matrix::Diagonal::create(this->exec, 2); + using Dense = typename TestFixture::Mtx; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using SparsityCsr = + typename gko::matrix::SparsityCsr; + auto empty = Dense::create(this->exec); + auto res = SparsityCsr::create(this->exec); - this->mtx4->extract_diagonal(diag); + empty->convert_to(res); - ASSERT_EQ(diag->get_size()[0], 2); - ASSERT_EQ(diag->get_size()[1], 2); - ASSERT_EQ(diag->get_values()[0], T{1.}); - ASSERT_EQ(diag->get_values()[1], T{5.}); + ASSERT_EQ(res->get_num_nonzeros(), 0); + ASSERT_EQ(*res->get_const_row_ptrs(), 0); + ASSERT_FALSE(res->get_size()); } -TYPED_TEST(Dense, ExtractsDiagonalFromShortFatMatrixIntoDiagonal) +TYPED_TEST(DenseWithIndexType, MovesEmptyToSparsityCsr) { - using T = typename TestFixture::value_type; - auto diag = gko::matrix::Diagonal::create(this->exec, 2); + using Dense = typename TestFixture::Mtx; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using SparsityCsr = + typename gko::matrix::SparsityCsr; + auto empty = Dense::create(this->exec); + auto res = SparsityCsr::create(this->exec); - this->mtx8->extract_diagonal(diag); + empty->move_to(res); - ASSERT_EQ(diag->get_size()[0], 2); - ASSERT_EQ(diag->get_size()[1], 2); - ASSERT_EQ(diag->get_values()[0], T{1.}); - ASSERT_EQ(diag->get_values()[1], T{2.}); + ASSERT_EQ(res->get_num_nonzeros(), 0); + ASSERT_EQ(*res->get_const_row_ptrs(), 0); + ASSERT_FALSE(res->get_size()); } -TYPED_TEST(Dense, InplaceAbsolute) +TYPED_TEST(DenseWithIndexType, ConvertsEmptyToEll) { - using T = typename TestFixture::value_type; + using Dense = typename TestFixture::Mtx; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Ell = typename gko::matrix::Ell; + auto empty = Dense::create(this->exec); + auto res = Ell::create(this->exec); - this->mtx5->compute_absolute_inplace(); + empty->convert_to(res); - GKO_ASSERT_MTX_NEAR( - this->mtx5, l({{1.0, 1.0, 0.5}, {2.0, 2.0, 4.5}, {2.1, 3.4, 1.2}}), - 0.0); + ASSERT_EQ(res->get_num_stored_elements(), 0); + ASSERT_FALSE(res->get_size()); } -TYPED_TEST(Dense, InplaceAbsoluteSubMatrix) +TYPED_TEST(DenseWithIndexType, MovesEmptyToEll) { - using T = typename TestFixture::value_type; - auto mtx = this->mtx5->create_submatrix(gko::span{0, 2}, gko::span{0, 2}); + using Dense = typename TestFixture::Mtx; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Ell = typename gko::matrix::Ell; + auto empty = Dense::create(this->exec); + auto res = Ell::create(this->exec); - mtx->compute_absolute_inplace(); + empty->move_to(res); - GKO_ASSERT_MTX_NEAR( - this->mtx5, l({{1.0, 1.0, -0.5}, {2.0, 2.0, 4.5}, {2.1, 3.4, 1.2}}), - 0.0); + ASSERT_EQ(res->get_num_stored_elements(), 0); + ASSERT_FALSE(res->get_size()); } -TYPED_TEST(Dense, OutplaceAbsolute) +TYPED_TEST(DenseWithIndexType, ConvertsEmptyToHybrid) { - using T = typename TestFixture::value_type; - - auto abs_mtx = this->mtx5->compute_absolute(); + using Dense = typename TestFixture::Mtx; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Hybrid = typename gko::matrix::Hybrid; + auto empty = Dense::create(this->exec); + auto res = Hybrid::create(this->exec); - GKO_ASSERT_MTX_NEAR( - abs_mtx, l({{1.0, 1.0, 0.5}, {2.0, 2.0, 4.5}, {2.1, 3.4, 1.2}}), - 0.0); + empty->convert_to(res); + + ASSERT_EQ(res->get_num_stored_elements(), 0); + ASSERT_FALSE(res->get_size()); } -TYPED_TEST(Dense, OutplaceAbsoluteIntoDense) +TYPED_TEST(DenseWithIndexType, MovesEmptyToHybrid) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto abs_mtx = - gko::remove_complex::create(this->exec, this->mtx5->get_size()); + using Dense = typename TestFixture::Mtx; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Hybrid = typename gko::matrix::Hybrid; + auto empty = Dense::create(this->exec); + auto res = Hybrid::create(this->exec); - this->mtx5->compute_absolute(abs_mtx); + empty->move_to(res); - GKO_ASSERT_MTX_NEAR( - abs_mtx, l({{1.0, 1.0, 0.5}, {2.0, 2.0, 4.5}, {2.1, 3.4, 1.2}}), - 0.0); + ASSERT_EQ(res->get_num_stored_elements(), 0); + ASSERT_FALSE(res->get_size()); } -TYPED_TEST(Dense, OutplaceAbsoluteSubMatrix) +TYPED_TEST(DenseWithIndexType, ConvertsEmptyToSellp) { - using T = typename TestFixture::value_type; - auto mtx = this->mtx5->create_submatrix(gko::span{0, 2}, gko::span{0, 2}); + using Dense = typename TestFixture::Mtx; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Sellp = typename gko::matrix::Sellp; + auto empty = Dense::create(this->exec); + auto res = Sellp::create(this->exec); - auto abs_mtx = mtx->compute_absolute(); + empty->convert_to(res); - GKO_ASSERT_MTX_NEAR(abs_mtx, l({{1.0, 1.0}, {2.0, 2.0}}), 0); - GKO_ASSERT_EQ(abs_mtx->get_stride(), 2); + ASSERT_EQ(res->get_num_stored_elements(), 0); + ASSERT_EQ(*res->get_const_slice_sets(), 0); + ASSERT_FALSE(res->get_size()); } -TYPED_TEST(Dense, OutplaceSubmatrixAbsoluteIntoDense) +TYPED_TEST(DenseWithIndexType, MovesEmptyToSellp) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto mtx = this->mtx5->create_submatrix(gko::span{0, 2}, gko::span{0, 2}); - auto abs_mtx = - gko::remove_complex::create(this->exec, gko::dim<2>{2, 2}, 4); + using Dense = typename TestFixture::Mtx; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + using Sellp = typename gko::matrix::Sellp; + auto empty = Dense::create(this->exec); + auto res = Sellp::create(this->exec); - mtx->compute_absolute(abs_mtx); + empty->move_to(res); - GKO_ASSERT_MTX_NEAR(abs_mtx, l({{1.0, 1.0}, {2.0, 2.0}}), 0); - GKO_ASSERT_EQ(abs_mtx->get_stride(), 4); + ASSERT_EQ(res->get_num_stored_elements(), 0); + ASSERT_EQ(*res->get_const_slice_sets(), 0); + ASSERT_FALSE(res->get_size()); } -TYPED_TEST(Dense, AppliesToComplex) +template +std::unique_ptr> ref_permute( + gko::matrix::Dense* input, + gko::matrix::Permutation* permutation, + gko::matrix::permute_mode mode) { - using value_type = typename TestFixture::value_type; - using complex_type = gko::to_complex; - using Vec = gko::matrix::Dense; - auto exec = gko::ReferenceExecutor::create(); - auto b = - gko::initialize({{complex_type{1.0, 0.0}, complex_type{2.0, 1.0}}, - {complex_type{2.0, 2.0}, complex_type{3.0, 3.0}}, - {complex_type{3.0, 4.0}, complex_type{4.0, 5.0}}}, - exec); - auto x = Vec::create(exec, gko::dim<2>{2, 2}); - - this->mtx1->apply(b, x); - - GKO_ASSERT_MTX_NEAR( - x, - l({{complex_type{14.0, 16.0}, complex_type{20.0, 22.0}}, - {complex_type{17.0, 19.0}, complex_type{24.5, 26.5}}}), - 0.0); + using gko::matrix::permute_mode; + auto result = input->clone(); + auto permutation_dense = + gko::matrix::Dense::create(input->get_executor()); + gko::matrix_data permutation_data; + if ((mode & permute_mode::inverse) == permute_mode::inverse) { + permutation->invert()->write(permutation_data); + } else { + permutation->write(permutation_data); + } + permutation_dense->read(permutation_data); + if ((mode & permute_mode::rows) == permute_mode::rows) { + // compute P * A + permutation_dense->apply(input, result); + } + if ((mode & permute_mode::columns) == permute_mode::columns) { + // compute A * P^T = (P * A^T)^T + auto tmp = result->transpose(); + auto tmp2 = gko::as>(tmp->clone()); + permutation_dense->apply(tmp, tmp2); + tmp2->transpose(result); + } + return result; +} + + +template +std::unique_ptr> ref_permute( + gko::matrix::Dense* input, + gko::matrix::Permutation* row_permutation, + gko::matrix::Permutation* col_permutation, bool invert) +{ + using gko::matrix::permute_mode; + auto result = input->clone(); + auto row_permutation_dense = + gko::matrix::Dense::create(input->get_executor()); + auto col_permutation_dense = + gko::matrix::Dense::create(input->get_executor()); + gko::matrix_data row_permutation_data; + gko::matrix_data col_permutation_data; + if (invert) { + row_permutation->invert()->write(row_permutation_data); + col_permutation->invert()->write(col_permutation_data); + } else { + row_permutation->write(row_permutation_data); + col_permutation->write(col_permutation_data); + } + row_permutation_dense->read(row_permutation_data); + col_permutation_dense->read(col_permutation_data); + row_permutation_dense->apply(input, result); + auto tmp = result->transpose(); + auto tmp2 = gko::as>(tmp->clone()); + col_permutation_dense->apply(tmp, tmp2); + tmp2->transpose(result); + return result; } -TYPED_TEST(Dense, AppliesToMixedComplex) +TYPED_TEST(DenseWithIndexType, Permute) { - using mixed_value_type = - gko::next_precision; - using mixed_complex_type = gko::to_complex; - using Vec = gko::matrix::Dense; - auto exec = gko::ReferenceExecutor::create(); - auto b = gko::initialize( - {{mixed_complex_type{1.0, 0.0}, mixed_complex_type{2.0, 1.0}}, - {mixed_complex_type{2.0, 2.0}, mixed_complex_type{3.0, 3.0}}, - {mixed_complex_type{3.0, 4.0}, mixed_complex_type{4.0, 5.0}}}, - exec); - auto x = Vec::create(exec, gko::dim<2>{2, 2}); + using gko::matrix::permute_mode; - this->mtx1->apply(b, x); + for (auto mode : + {permute_mode::none, permute_mode::rows, permute_mode::columns, + permute_mode::symmetric, permute_mode::inverse_rows, + permute_mode::inverse_columns, permute_mode::inverse_symmetric}) { + SCOPED_TRACE(mode); - GKO_ASSERT_MTX_NEAR( - x, - l({{mixed_complex_type{14.0, 16.0}, mixed_complex_type{20.0, 22.0}}, - {mixed_complex_type{17.0, 19.0}, mixed_complex_type{24.5, 26.5}}}), - 0.0); + auto permuted = this->mtx5->permute(this->perm3, mode); + auto ref_permuted = + ref_permute(this->mtx5.get(), this->perm3.get(), mode); + + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); + } } -TYPED_TEST(Dense, AdvancedAppliesToComplex) +TYPED_TEST(DenseWithIndexType, PermuteRoundtrip) { - using value_type = typename TestFixture::value_type; - using complex_type = gko::to_complex; - using Dense = gko::matrix::Dense; - using DenseComplex = gko::matrix::Dense; - auto exec = gko::ReferenceExecutor::create(); + using gko::matrix::permute_mode; - auto b = gko::initialize( - {{complex_type{1.0, 0.0}, complex_type{2.0, 1.0}}, - {complex_type{2.0, 2.0}, complex_type{3.0, 3.0}}, - {complex_type{3.0, 4.0}, complex_type{4.0, 5.0}}}, - exec); - auto x = gko::initialize( - {{complex_type{1.0, 0.0}, complex_type{2.0, 1.0}}, - {complex_type{2.0, 2.0}, complex_type{3.0, 3.0}}}, - exec); - auto alpha = gko::initialize({-1.0}, this->exec); - auto beta = gko::initialize({2.0}, this->exec); + for (auto mode : + {permute_mode::rows, permute_mode::columns, permute_mode::symmetric}) { + SCOPED_TRACE(mode); - this->mtx1->apply(alpha, b, beta, x); + auto permuted = + this->mtx5->permute(this->perm3, mode) + ->permute(this->perm3, mode | permute_mode::inverse); - GKO_ASSERT_MTX_NEAR( - x, - l({{complex_type{-12.0, -16.0}, complex_type{-16.0, -20.0}}, - {complex_type{-13.0, -15.0}, complex_type{-18.5, -20.5}}}), - 0.0); + GKO_ASSERT_MTX_NEAR(this->mtx5, permuted, 0.0); + } } -TYPED_TEST(Dense, AdvancedAppliesToMixedComplex) +TYPED_TEST(DenseWithIndexType, PermuteStridedIntoDense) { - using mixed_value_type = - gko::next_precision; - using mixed_complex_type = gko::to_complex; - using MixedDense = gko::matrix::Dense; - using MixedDenseComplex = gko::matrix::Dense; - auto exec = gko::ReferenceExecutor::create(); + using gko::matrix::permute_mode; + using Mtx = typename TestFixture::Mtx; + auto mtx = Mtx::create(this->exec, this->mtx5->get_size(), + this->mtx5->get_size()[1] + 1); + mtx->copy_from(this->mtx5); - auto b = gko::initialize( - {{mixed_complex_type{1.0, 0.0}, mixed_complex_type{2.0, 1.0}}, - {mixed_complex_type{2.0, 2.0}, mixed_complex_type{3.0, 3.0}}, - {mixed_complex_type{3.0, 4.0}, mixed_complex_type{4.0, 5.0}}}, - exec); - auto x = gko::initialize( - {{mixed_complex_type{1.0, 0.0}, mixed_complex_type{2.0, 1.0}}, - {mixed_complex_type{2.0, 2.0}, mixed_complex_type{3.0, 3.0}}}, - exec); - auto alpha = gko::initialize({-1.0}, this->exec); - auto beta = gko::initialize({2.0}, this->exec); + for (auto mode : + {permute_mode::none, permute_mode::rows, permute_mode::columns, + permute_mode::symmetric, permute_mode::inverse, + permute_mode::inverse_rows, permute_mode::inverse_columns, + permute_mode::inverse_symmetric}) { + SCOPED_TRACE(mode); + auto permuted = Mtx::create(this->exec, this->mtx5->get_size(), + this->mtx5->get_size()[1] + 2); - this->mtx1->apply(alpha, b, beta, x); + this->mtx5->permute(this->perm3, permuted, mode); + auto ref_permuted = + ref_permute(this->mtx5.get(), this->perm3.get(), mode); - GKO_ASSERT_MTX_NEAR( - x, - l({{mixed_complex_type{-12.0, -16.0}, mixed_complex_type{-16.0, -20.0}}, - {mixed_complex_type{-13.0, -15.0}, - mixed_complex_type{-18.5, -20.5}}}), - 0.0); + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); + } } -TYPED_TEST(Dense, MakeComplex) +TYPED_TEST(DenseWithIndexType, PermuteRectangular) { - using T = typename TestFixture::value_type; + using gko::matrix::permute_mode; - auto complex_mtx = this->mtx5->make_complex(); + auto rpermuted = this->mtx1->permute(this->perm2, permute_mode::rows); + auto irpermuted = + this->mtx1->permute(this->perm2, permute_mode::inverse_rows); + auto cpermuted = this->mtx1->permute(this->perm3, permute_mode::columns); + auto icpermuted = + this->mtx1->permute(this->perm3, permute_mode::inverse_columns); + auto ref_rpermuted = + ref_permute(this->mtx1.get(), this->perm2.get(), permute_mode::rows); + auto ref_irpermuted = ref_permute(this->mtx1.get(), this->perm2.get(), + permute_mode::inverse_rows); + auto ref_cpermuted = + ref_permute(this->mtx1.get(), this->perm3.get(), permute_mode::columns); + auto ref_icpermuted = ref_permute(this->mtx1.get(), this->perm3.get(), + permute_mode::inverse_columns); - GKO_ASSERT_MTX_NEAR(complex_mtx, this->mtx5, 0.0); + GKO_ASSERT_MTX_NEAR(rpermuted, ref_rpermuted, 0.0); + GKO_ASSERT_MTX_NEAR(irpermuted, ref_irpermuted, 0.0); + GKO_ASSERT_MTX_NEAR(cpermuted, ref_cpermuted, 0.0); + GKO_ASSERT_MTX_NEAR(icpermuted, ref_icpermuted, 0.0); } -TYPED_TEST(Dense, MakeComplexIntoDense) +TYPED_TEST(DenseWithIndexType, PermuteFailsWithIncorrectPermutationSize) { - using T = typename TestFixture::value_type; - using ComplexMtx = typename TestFixture::ComplexMtx; - auto exec = this->mtx5->get_executor(); + using gko::matrix::permute_mode; - auto complex_mtx = ComplexMtx::create(exec, this->mtx5->get_size()); - this->mtx5->make_complex(complex_mtx); + for (auto mode : + {/* no permute_mode::none */ permute_mode::rows, permute_mode::columns, + permute_mode::symmetric, permute_mode::inverse_rows, + permute_mode::inverse_columns, permute_mode::inverse_symmetric}) { + SCOPED_TRACE(mode); - GKO_ASSERT_MTX_NEAR(complex_mtx, this->mtx5, 0.0); + ASSERT_THROW(this->mtx5->permute(this->perm0, mode), + gko::ValueMismatch); + } } -TYPED_TEST(Dense, MakeComplexIntoDenseFailsForWrongDimensions) +TYPED_TEST(DenseWithIndexType, PermuteFailsWithIncorrectOutputSize) { - using T = typename TestFixture::value_type; - using ComplexMtx = typename TestFixture::ComplexMtx; - auto exec = this->mtx5->get_executor(); + using gko::matrix::permute_mode; + using Mtx = typename TestFixture::Mtx; + auto output = Mtx::create(this->exec); - auto complex_mtx = ComplexMtx::create(exec); + for (auto mode : + {permute_mode::none, permute_mode::rows, permute_mode::columns, + permute_mode::symmetric, permute_mode::inverse_rows, + permute_mode::inverse_columns, permute_mode::inverse_symmetric}) { + SCOPED_TRACE(mode); - ASSERT_THROW(this->mtx5->make_complex(complex_mtx), gko::DimensionMismatch); + ASSERT_THROW(this->mtx5->permute(this->perm3, output, mode), + gko::DimensionMismatch); + } } -TYPED_TEST(Dense, GetReal) +TYPED_TEST(DenseWithIndexType, NonsymmPermute) { - using T = typename TestFixture::value_type; + auto permuted = this->mtx5->permute(this->perm3, this->perm3_rev); + auto ref_permuted = ref_permute(this->mtx5.get(), this->perm3.get(), + this->perm3_rev.get(), false); - auto real_mtx = this->mtx5->get_real(); + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); +} - GKO_ASSERT_MTX_NEAR(real_mtx, this->mtx5, 0.0); + +TYPED_TEST(DenseWithIndexType, NonsymmPermuteInverse) +{ + auto permuted = this->mtx5->permute(this->perm3, this->perm3_rev, true); + auto ref_permuted = ref_permute(this->mtx5.get(), this->perm3.get(), + this->perm3_rev.get(), true); + + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); } -TYPED_TEST(Dense, GetRealIntoDense) +TYPED_TEST(DenseWithIndexType, NonsymmPermuteRectangular) { - using T = typename TestFixture::value_type; - using RealMtx = typename TestFixture::RealMtx; - auto exec = this->mtx5->get_executor(); + auto permuted = this->mtx1->permute(this->perm2, this->perm3); + auto ref_permuted = ref_permute(this->mtx1.get(), this->perm2.get(), + this->perm3.get(), false); - auto real_mtx = RealMtx::create(exec, this->mtx5->get_size()); - this->mtx5->get_real(real_mtx); + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); +} - GKO_ASSERT_MTX_NEAR(real_mtx, this->mtx5, 0.0); + +TYPED_TEST(DenseWithIndexType, NonsymmPermuteInverseRectangular) +{ + auto permuted = this->mtx1->permute(this->perm2, this->perm3, true); + auto ref_permuted = ref_permute(this->mtx1.get(), this->perm2.get(), + this->perm3.get(), true); + + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); } -TYPED_TEST(Dense, GetRealIntoDenseFailsForWrongDimensions) +TYPED_TEST(DenseWithIndexType, NonsymmPermuteRoundtrip) { - using T = typename TestFixture::value_type; - using RealMtx = typename TestFixture::RealMtx; - auto exec = this->mtx5->get_executor(); + auto permuted = this->mtx5->permute(this->perm3, this->perm3_rev) + ->permute(this->perm3, this->perm3_rev, true); - auto real_mtx = RealMtx::create(exec); - ASSERT_THROW(this->mtx5->get_real(real_mtx), gko::DimensionMismatch); + GKO_ASSERT_MTX_NEAR(this->mtx5, permuted, 0.0); } -TYPED_TEST(Dense, GetImag) +TYPED_TEST(DenseWithIndexType, NonsymmPermuteStridedIntoDense) { - using T = typename TestFixture::value_type; + using Mtx = typename TestFixture::Mtx; + auto mtx = Mtx::create(this->exec, this->mtx5->get_size(), + this->mtx5->get_size()[1] + 1); + auto permuted = Mtx::create(this->exec, this->mtx5->get_size(), + this->mtx5->get_size()[1] + 2); + mtx->copy_from(this->mtx5); - auto imag_mtx = this->mtx5->get_imag(); + mtx->permute(this->perm3, this->perm3_rev, permuted); + auto ref_permuted = ref_permute(this->mtx5.get(), this->perm3.get(), + this->perm3_rev.get(), false); - GKO_ASSERT_MTX_NEAR( - imag_mtx, l({{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}), - 0.0); + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); } -TYPED_TEST(Dense, GetImagIntoDense) +TYPED_TEST(DenseWithIndexType, NonsymmPermuteInverseStridedIntoDense) { - using T = typename TestFixture::value_type; - using RealMtx = typename TestFixture::RealMtx; - auto exec = this->mtx5->get_executor(); + using Mtx = typename TestFixture::Mtx; + auto mtx = Mtx::create(this->exec, this->mtx5->get_size(), + this->mtx5->get_size()[1] + 1); + auto permuted = Mtx::create(this->exec, this->mtx5->get_size(), + this->mtx5->get_size()[1] + 2); + mtx->copy_from(this->mtx5); - auto imag_mtx = RealMtx::create(exec, this->mtx5->get_size()); - this->mtx5->get_imag(imag_mtx); + mtx->permute(this->perm3, this->perm3_rev, permuted, true); + auto ref_permuted = ref_permute(this->mtx5.get(), this->perm3.get(), + this->perm3_rev.get(), true); - GKO_ASSERT_MTX_NEAR( - imag_mtx, l({{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}), - 0.0); + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); } -TYPED_TEST(Dense, GetImagIntoDenseFailsForWrongDimensions) +TYPED_TEST(DenseWithIndexType, NonsymmPermuteFailsWithIncorrectPermutationSize) { - using T = typename TestFixture::value_type; - using RealMtx = typename TestFixture::RealMtx; - auto exec = this->mtx5->get_executor(); - - auto imag_mtx = RealMtx::create(exec); - ASSERT_THROW(this->mtx5->get_imag(imag_mtx), gko::DimensionMismatch); + ASSERT_THROW(this->mtx5->permute(this->perm0, this->perm3_rev), + gko::ValueMismatch); + ASSERT_THROW(this->mtx5->permute(this->perm3_rev, this->perm0), + gko::ValueMismatch); + ASSERT_THROW(this->mtx5->permute(this->perm0, this->perm0), + gko::ValueMismatch); } -TYPED_TEST(Dense, MakeTemporaryConversionDoesntConvertOnMatch) +TYPED_TEST(DenseWithIndexType, SquareMatrixCanGatherRows) { using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto alpha = gko::initialize({8.0}, this->exec); + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + auto exec = this->mtx5->get_executor(); + gko::array permute_idxs{exec, {1, 0}}; - ASSERT_EQ(gko::make_temporary_conversion(alpha).get(), alpha.get()); + auto row_collection = this->mtx5->row_gather(&permute_idxs); + + GKO_ASSERT_MTX_NEAR(row_collection, + l({{-2.0, 2.0, 4.5}, {1.0, -1.0, -0.5}}), + 0.0); } -TYPED_TEST(Dense, MakeTemporaryConversionConvertsBack) +TYPED_TEST(DenseWithIndexType, SquareMatrixCanGatherRowsIntoDense) { - using MixedMtx = typename TestFixture::MixedMtx; - using T = typename TestFixture::value_type; - using MixedT = typename MixedMtx::value_type; - auto alpha = gko::initialize({8.0}, this->exec); + using Mtx = typename TestFixture::Mtx; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + auto exec = this->mtx5->get_executor(); + gko::array permute_idxs{exec, {1, 0}}; + auto row_collection = Mtx::create(exec, gko::dim<2>{2, 3}); - { - auto conversion = gko::make_temporary_conversion(alpha); - conversion->at(0, 0) = T{7.0}; - } + this->mtx5->row_gather(&permute_idxs, row_collection); - ASSERT_EQ(alpha->at(0, 0), MixedT{7.0}); + GKO_ASSERT_MTX_NEAR(row_collection, + l({{-2.0, 2.0, 4.5}, {1.0, -1.0, -0.5}}), + 0.0); } -TYPED_TEST(Dense, MakeTemporaryConversionConstDoesntConvertBack) +TYPED_TEST(DenseWithIndexType, SquareSubmatrixCanGatherRowsIntoDense) { - using MixedMtx = typename TestFixture::MixedMtx; - using T = typename TestFixture::value_type; - using MixedT = typename MixedMtx::value_type; - auto alpha = gko::initialize({8.0}, this->exec); + using Mtx = typename TestFixture::Mtx; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + auto exec = this->mtx5->get_executor(); + gko::array permute_idxs{exec, {1, 0}}; + auto row_collection = Mtx::create(exec, gko::dim<2>{2, 2}, 4); - { - auto conversion = gko::make_temporary_conversion( - static_cast(alpha.get())); - alpha->at(0, 0) = MixedT{7.0}; - } + this->mtx5->create_submatrix({0, 2}, {1, 3}) + ->row_gather(&permute_idxs, row_collection); - ASSERT_EQ(alpha->at(0, 0), MixedT{7.0}); + GKO_ASSERT_MTX_NEAR(row_collection, + l({{2.0, 4.5}, {-1.0, -0.5}}), 0.0); + ASSERT_EQ(row_collection->get_stride(), 4); } -TYPED_TEST(Dense, ScaleAddIdentityRectangular) +TYPED_TEST(DenseWithIndexType, + SquareMatrixGatherRowsIntoDenseFailsForWrongDimensions) { - using T = typename TestFixture::value_type; - using Vec = typename TestFixture::Mtx; - using MixedVec = typename TestFixture::MixedMtx; - auto alpha = gko::initialize({2.0}, this->exec); - auto beta = gko::initialize({-1.0}, this->exec); - auto b = gko::initialize( - {I{2.0, 0.0}, I{1.0, 2.5}, I{0.0, -4.0}}, this->exec); - - b->add_scaled_identity(alpha, beta); + using Mtx = typename TestFixture::Mtx; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + auto exec = this->mtx5->get_executor(); + gko::array permute_idxs{exec, {1, 0}}; - GKO_ASSERT_MTX_NEAR(b, l({{0.0, 0.0}, {-1.0, -0.5}, {0.0, 4.0}}), 0.0); + ASSERT_THROW(this->mtx5->row_gather(&permute_idxs, Mtx::create(exec)), + gko::DimensionMismatch); } -template -class DenseComplex : public ::testing::Test { -protected: - using value_type = T; - using Mtx = gko::matrix::Dense; - using RealMtx = gko::matrix::Dense>; -}; +TYPED_TEST(DenseWithIndexType, NonSquareSubmatrixCanGatherRowsIntoMixedDense) +{ + using Mtx = typename TestFixture::Mtx; + using MixedMtx = typename TestFixture::MixedMtx; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + auto exec = this->mtx4->get_executor(); + gko::array gather_index{exec, {1, 0, 1}}; + auto row_collection = MixedMtx::create(exec, gko::dim<2>{3, 3}, 4); + this->mtx4->row_gather(&gather_index, row_collection); -TYPED_TEST_SUITE(DenseComplex, gko::test::ComplexValueTypes, - TypenameNameGenerator); + GKO_ASSERT_MTX_NEAR( + row_collection, + l( + {{0.0, 5.0, 0.0}, {1.0, 3.0, 2.0}, {0.0, 5.0, 0.0}}), + 0.0); +} -TYPED_TEST(DenseComplex, ScalesWithRealScalar) +TYPED_TEST(DenseWithIndexType, + NonSquareSubmatrixCanAdvancedGatherRowsIntoMixedDense) { - using Dense = typename TestFixture::Mtx; - using RealDense = gko::remove_complex; - using T = typename TestFixture::value_type; - auto exec = gko::ReferenceExecutor::create(); - auto mtx = gko::initialize({{T{1.0, 2.0}, T{-1.0, 2.25}}, - {T{-2.0, 1.5}, T{4.5, 0.0}}, - {T{1.0, 0.0}, T{0.0, 1.0}}}, - exec); - auto alpha = - gko::initialize({gko::remove_complex{-2.0}}, exec); + using Mtx = typename TestFixture::Mtx; + using MixedMtx = typename TestFixture::MixedMtx; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + auto exec = this->mtx4->get_executor(); + gko::array gather_index{exec, {1, 0, 1}}; + auto row_collection = gko::initialize( + {{1.0, 0.5, -1.0}, {-1.5, 0.5, 1.0}, {2.0, -3.0, 1.0}}, exec); + auto alpha = gko::initialize({1.0}, exec); + auto beta = gko::initialize({2.0}, exec); - mtx->scale(alpha); + this->mtx4->row_gather(alpha, &gather_index, beta, row_collection); - GKO_ASSERT_MTX_NEAR(mtx, - l({{T{-2.0, -4.0}, T{2.0, -4.5}}, - {T{4.0, -3.0}, T{-9.0, 0.0}}, - {T{-2.0, 0.0}, T{0.0, -2.0}}}), - 0.0); + GKO_ASSERT_MTX_NEAR( + row_collection, + l( + {{2.0, 6.0, -2.0}, {-2.0, 4.0, 4.0}, {4.0, -1.0, 2.0}}), + 0.0); } -TYPED_TEST(DenseComplex, ScalesWithRealVector) +TYPED_TEST(DenseWithIndexType, SquareMatrixIsPermutable) { - using Dense = typename TestFixture::Mtx; - using RealDense = gko::remove_complex; - using T = typename TestFixture::value_type; - using RealT = gko::remove_complex; - auto exec = gko::ReferenceExecutor::create(); - auto mtx = gko::initialize({{T{1.0, 2.0}, T{-1.0, 2.25}}, - {T{-2.0, 1.5}, T{4.5, 0.0}}, - {T{1.0, 0.0}, T{0.0, 1.0}}}, - exec); - auto alpha = gko::initialize({{RealT{-2.0}, RealT{4.0}}}, exec); + using Mtx = typename TestFixture::Mtx; + using index_type = typename TestFixture::index_type; + auto exec = this->mtx5->get_executor(); + gko::array permute_idxs{exec, {1, 2, 0}}; - mtx->scale(alpha); + auto ref_permuted = + gko::as(gko::as(this->mtx5->row_permute(&permute_idxs)) + ->column_permute(&permute_idxs)); + auto permuted = gko::as(this->mtx5->permute(&permute_idxs)); - GKO_ASSERT_MTX_NEAR(mtx, - l({{T{-2.0, -4.0}, T{-4.0, 9.0}}, - {T{4.0, -3.0}, T{18.0, 0.0}}, - {T{-2.0, 0.0}, T{0.0, 4.0}}}), - 0.0); + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); } -TYPED_TEST(DenseComplex, InvScalesWithRealScalar) +TYPED_TEST(DenseWithIndexType, SquareMatrixIsPermutableIntoDense) { - using Dense = typename TestFixture::Mtx; - using RealDense = gko::remove_complex; - using T = typename TestFixture::value_type; - auto exec = gko::ReferenceExecutor::create(); - auto mtx = gko::initialize({{T{1.0, 2.0}, T{-1.0, 2.25}}, - {T{-2.0, 1.5}, T{4.5, 0.0}}, - {T{1.0, 0.0}, T{0.0, 1.0}}}, - exec); - auto alpha = - gko::initialize({gko::remove_complex{-0.5}}, exec); + using Mtx = typename TestFixture::Mtx; + using index_type = typename TestFixture::index_type; + auto exec = this->mtx5->get_executor(); + gko::array permute_idxs{exec, {1, 2, 0}}; + auto permuted = Mtx::create(exec, this->mtx5->get_size()); - mtx->inv_scale(alpha); + auto ref_permuted = + gko::as(gko::as(this->mtx5->row_permute(&permute_idxs)) + ->column_permute(&permute_idxs)); + this->mtx5->permute(&permute_idxs, permuted); - GKO_ASSERT_MTX_NEAR(mtx, - l({{T{-2.0, -4.0}, T{2.0, -4.5}}, - {T{4.0, -3.0}, T{-9.0, 0.0}}, - {T{-2.0, 0.0}, T{0.0, -2.0}}}), - 0.0); + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); } -TYPED_TEST(DenseComplex, InvScalesWithRealVector) +TYPED_TEST(DenseWithIndexType, SquareMatrixIsInversePermutable) { - using Dense = typename TestFixture::Mtx; - using RealDense = gko::remove_complex; - using T = typename TestFixture::value_type; - using RealT = gko::remove_complex; - auto exec = gko::ReferenceExecutor::create(); - auto mtx = gko::initialize({{T{1.0, 2.0}, T{-1.0, 2.25}}, - {T{-2.0, 1.5}, T{4.5, 0.0}}, - {T{1.0, 0.0}, T{0.0, 1.0}}}, - exec); - auto alpha = gko::initialize({{RealT{-0.5}, RealT{0.25}}}, exec); + using Mtx = typename TestFixture::Mtx; + using index_type = typename TestFixture::index_type; + auto exec = this->mtx5->get_executor(); + gko::array permute_idxs{exec, {1, 2, 0}}; - mtx->inv_scale(alpha); + auto ref_permuted = gko::as( + gko::as(this->mtx5->inverse_row_permute(&permute_idxs)) + ->inverse_column_permute(&permute_idxs)); + auto permuted = gko::as(this->mtx5->inverse_permute(&permute_idxs)); - GKO_ASSERT_MTX_NEAR(mtx, - l({{T{-2.0, -4.0}, T{-4.0, 9.0}}, - {T{4.0, -3.0}, T{18.0, 0.0}}, - {T{-2.0, 0.0}, T{0.0, 4.0}}}), - 0.0); + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); } -TYPED_TEST(DenseComplex, AddsScaledWithRealScalar) +TYPED_TEST(DenseWithIndexType, SquareMatrixIsInversePermutableIntoDense) { - using Dense = typename TestFixture::Mtx; - using RealDense = gko::remove_complex; - using T = typename TestFixture::value_type; - auto exec = gko::ReferenceExecutor::create(); - auto mtx = gko::initialize({{T{1.0, 2.0}, T{-1.0, 2.25}}, - {T{-2.0, 1.5}, T{4.5, 0.0}}, - {T{1.0, 0.0}, T{0.0, 1.0}}}, - exec); - auto mtx2 = gko::initialize({{T{4.0, -1.0}, T{5.0, 1.5}}, - {T{3.0, 1.0}, T{0.0, 2.0}}, - {T{-1.0, 1.0}, T{0.5, -2.0}}}, - exec); - auto alpha = - gko::initialize({gko::remove_complex{-2.0}}, exec); + using Mtx = typename TestFixture::Mtx; + using index_type = typename TestFixture::index_type; + auto exec = this->mtx5->get_executor(); + gko::array permute_idxs{exec, {1, 2, 0}}; + auto permuted = Mtx::create(exec, this->mtx5->get_size()); - mtx->add_scaled(alpha, mtx2); + auto ref_permuted = gko::as( + gko::as(this->mtx5->inverse_row_permute(&permute_idxs)) + ->inverse_column_permute(&permute_idxs)); + this->mtx5->inverse_permute(&permute_idxs, permuted); - GKO_ASSERT_MTX_NEAR(mtx, - l({{T{-7.0, 4.0}, T{-11.0, -0.75}}, - {T{-8.0, -0.5}, T{4.5, -4.0}}, - {T{3.0, -2.0}, T{-1.0, 5.0}}}), - 0.0); + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, 0.0); } -TYPED_TEST(DenseComplex, AddsScaledWithRealVector) +TYPED_TEST(DenseWithIndexType, SquareMatrixIsRowPermutable) { - using Dense = typename TestFixture::Mtx; - using RealDense = gko::remove_complex; - using T = typename TestFixture::value_type; - using RealT = gko::remove_complex; - auto exec = gko::ReferenceExecutor::create(); - auto mtx = gko::initialize({{T{1.0, 2.0}, T{-1.0, 2.25}}, - {T{-2.0, 1.5}, T{4.5, 0.0}}, - {T{1.0, 0.0}, T{0.0, 1.0}}}, - exec); - auto mtx2 = gko::initialize({{T{4.0, -1.0}, T{5.0, 1.5}}, - {T{3.0, 1.0}, T{0.0, 2.0}}, - {T{-1.0, 1.0}, T{0.5, -2.0}}}, - exec); - auto alpha = gko::initialize({{RealT{-2.0}, RealT{4.0}}}, exec); + using Mtx = typename TestFixture::Mtx; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + auto exec = this->mtx5->get_executor(); + gko::array permute_idxs{exec, {1, 2, 0}}; - mtx->add_scaled(alpha, mtx2); + auto row_permute = gko::as(this->mtx5->row_permute(&permute_idxs)); - GKO_ASSERT_MTX_NEAR(mtx, - l({{T{-7.0, 4.0}, T{19.0, 8.25}}, - {T{-8.0, -0.5}, T{4.5, 8.0}}, - {T{3.0, -2.0}, T{2.0, -7.0}}}), - 0.0); + GKO_ASSERT_MTX_NEAR( + row_permute, + l({{-2.0, 2.0, 4.5}, {2.1, 3.4, 1.2}, {1.0, -1.0, -0.5}}), + 0.0); } -TYPED_TEST(DenseComplex, SubtractsScaledWithRealScalar) +TYPED_TEST(DenseWithIndexType, SquareMatrixIsRowPermutableIntoDense) { - using Dense = typename TestFixture::Mtx; - using RealDense = gko::remove_complex; - using T = typename TestFixture::value_type; - auto exec = gko::ReferenceExecutor::create(); - auto mtx = gko::initialize({{T{1.0, 2.0}, T{-1.0, 2.25}}, - {T{-2.0, 1.5}, T{4.5, 0.0}}, - {T{1.0, 0.0}, T{0.0, 1.0}}}, - exec); - auto mtx2 = gko::initialize({{T{4.0, -1.0}, T{5.0, 1.5}}, - {T{3.0, 1.0}, T{0.0, 2.0}}, - {T{-1.0, 1.0}, T{0.5, -2.0}}}, - exec); - auto alpha = - gko::initialize({gko::remove_complex{2.0}}, exec); + using Mtx = typename TestFixture::Mtx; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + auto exec = this->mtx5->get_executor(); + gko::array permute_idxs{exec, {1, 2, 0}}; + auto row_permute = Mtx::create(exec, this->mtx5->get_size()); - mtx->sub_scaled(alpha, mtx2); + this->mtx5->row_permute(&permute_idxs, row_permute); - GKO_ASSERT_MTX_NEAR(mtx, - l({{T{-7.0, 4.0}, T{-11.0, -0.75}}, - {T{-8.0, -0.5}, T{4.5, -4.0}}, - {T{3.0, -2.0}, T{-1.0, 5.0}}}), - 0.0); + GKO_ASSERT_MTX_NEAR( + row_permute, + l({{-2.0, 2.0, 4.5}, {2.1, 3.4, 1.2}, {1.0, -1.0, -0.5}}), + 0.0); } -TYPED_TEST(DenseComplex, SubtractsScaledWithRealVector) -{ - using Dense = typename TestFixture::Mtx; - using RealDense = gko::remove_complex; - using T = typename TestFixture::value_type; - using RealT = gko::remove_complex; - auto exec = gko::ReferenceExecutor::create(); - auto mtx = gko::initialize({{T{1.0, 2.0}, T{-1.0, 2.25}}, - {T{-2.0, 1.5}, T{4.5, 0.0}}, - {T{1.0, 0.0}, T{0.0, 1.0}}}, - exec); - auto mtx2 = gko::initialize({{T{4.0, -1.0}, T{5.0, 1.5}}, - {T{3.0, 1.0}, T{0.0, 2.0}}, - {T{-1.0, 1.0}, T{0.5, -2.0}}}, - exec); - auto alpha = gko::initialize({{RealT{2.0}, RealT{-4.0}}}, exec); +TYPED_TEST(DenseWithIndexType, SquareMatrixIsColPermutable) +{ + using Mtx = typename TestFixture::Mtx; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + auto exec = this->mtx5->get_executor(); + gko::array permute_idxs{exec, {1, 2, 0}}; - mtx->sub_scaled(alpha, mtx2); + auto c_permute = gko::as(this->mtx5->column_permute(&permute_idxs)); - GKO_ASSERT_MTX_NEAR(mtx, - l({{T{-7.0, 4.0}, T{19.0, 8.25}}, - {T{-8.0, -0.5}, T{4.5, 8.0}}, - {T{3.0, -2.0}, T{2.0, -7.0}}}), - 0.0); + GKO_ASSERT_MTX_NEAR( + c_permute, + l({{-1.0, -0.5, 1.0}, {2.0, 4.5, -2.0}, {3.4, 1.2, 2.1}}), + 0.0); } -TYPED_TEST(DenseComplex, NonSquareMatrixIsConjugateTransposable) +TYPED_TEST(DenseWithIndexType, SquareMatrixIsColPermutableIntoDense) { - using Dense = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = gko::ReferenceExecutor::create(); - auto mtx = gko::initialize({{T{1.0, 2.0}, T{-1.0, 2.1}}, - {T{-2.0, 1.5}, T{4.5, 0.0}}, - {T{1.0, 0.0}, T{0.0, 1.0}}}, - exec); + using Mtx = typename TestFixture::Mtx; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + auto exec = this->mtx5->get_executor(); + gko::array permute_idxs{exec, {1, 2, 0}}; + auto c_permute = Mtx::create(exec, this->mtx5->get_size()); - auto trans = gko::as(mtx->conj_transpose()); + this->mtx5->column_permute(&permute_idxs, c_permute); - GKO_ASSERT_MTX_NEAR(trans, - l({{T{1.0, -2.0}, T{-2.0, -1.5}, T{1.0, 0.0}}, - {T{-1.0, -2.1}, T{4.5, 0.0}, T{0.0, -1.0}}}), - 0.0); + GKO_ASSERT_MTX_NEAR( + c_permute, + l({{-1.0, -0.5, 1.0}, {2.0, 4.5, -2.0}, {3.4, 1.2, 2.1}}), + 0.0); } -TYPED_TEST(DenseComplex, NonSquareMatrixIsConjugateTransposableIntoDense) +TYPED_TEST(DenseWithIndexType, SquareMatrixIsInverseRowPermutable) { - using Dense = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = gko::ReferenceExecutor::create(); - auto mtx = gko::initialize({{T{1.0, 2.0}, T{-1.0, 2.1}}, - {T{-2.0, 1.5}, T{4.5, 0.0}}, - {T{1.0, 0.0}, T{0.0, 1.0}}}, - exec); - auto trans = Dense::create(exec, gko::transpose(mtx->get_size())); + using Mtx = typename TestFixture::Mtx; + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + auto exec = this->mtx5->get_executor(); + gko::array inverse_permute_idxs{exec, {1, 2, 0}}; - mtx->conj_transpose(trans); + auto inv_row_permute = + gko::as(this->mtx5->inverse_row_permute(&inverse_permute_idxs)); - GKO_ASSERT_MTX_NEAR(trans, - l({{T{1.0, -2.0}, T{-2.0, -1.5}, T{1.0, 0.0}}, - {T{-1.0, -2.1}, T{4.5, 0.0}, T{0.0, -1.0}}}), - 0.0); + GKO_ASSERT_MTX_NEAR( + inv_row_permute, + l({{2.1, 3.4, 1.2}, {1.0, -1.0, -0.5}, {-2.0, 2.0, 4.5}}), + 0.0); } -TYPED_TEST(DenseComplex, InplaceAbsolute) +TYPED_TEST(DenseWithIndexType, SquareMatrixIsInverseRowPermutableIntoDense) { using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = gko::ReferenceExecutor::create(); - auto mtx = gko::initialize({{T{1.0, 0.0}, T{3.0, 4.0}, T{0.0, 2.0}}, - {T{-4.0, -3.0}, T{-1.0, 0}, T{0.0, 0.0}}, - {T{0.0, 0.0}, T{0.0, -1.5}, T{2.0, 0.0}}}, - exec); + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + auto exec = this->mtx5->get_executor(); + gko::array permute_idxs{exec, {1, 2, 0}}; + auto row_permute = Mtx::create(exec, this->mtx5->get_size()); - mtx->compute_absolute_inplace(); + this->mtx5->inverse_row_permute(&permute_idxs, row_permute); GKO_ASSERT_MTX_NEAR( - mtx, l({{1.0, 5.0, 2.0}, {5.0, 1.0, 0.0}, {0.0, 1.5, 2.0}}), 0.0); + row_permute, + l({{2.1, 3.4, 1.2}, {1.0, -1.0, -0.5}, {-2.0, 2.0, 4.5}}), + 0.0); } -TYPED_TEST(DenseComplex, OutplaceAbsolute) +TYPED_TEST(DenseWithIndexType, SquareMatrixIsInverseColPermutable) { using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = gko::ReferenceExecutor::create(); - auto mtx = gko::initialize({{T{1.0, 0.0}, T{3.0, 4.0}, T{0.0, 2.0}}, - {T{-4.0, -3.0}, T{-1.0, 0}, T{0.0, 0.0}}, - {T{0.0, 0.0}, T{0.0, -1.5}, T{2.0, 0.0}}}, - exec); + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + auto exec = this->mtx5->get_executor(); + gko::array inverse_permute_idxs{exec, {1, 2, 0}}; - auto abs_mtx = mtx->compute_absolute(); + auto inv_c_permute = + gko::as(this->mtx5->inverse_column_permute(&inverse_permute_idxs)); GKO_ASSERT_MTX_NEAR( - abs_mtx, l({{1.0, 5.0, 2.0}, {5.0, 1.0, 0.0}, {0.0, 1.5, 2.0}}), + inv_c_permute, + l({{-0.5, 1.0, -1.0}, {4.5, -2.0, 2.0}, {1.2, 2.1, 3.4}}), 0.0); } -TYPED_TEST(DenseComplex, OutplaceAbsoluteIntoDense) +TYPED_TEST(DenseWithIndexType, SquareMatrixIsInverseColPermutableIntoDense) { using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = gko::ReferenceExecutor::create(); - auto mtx = gko::initialize({{T{1.0, 0.0}, T{3.0, 4.0}, T{0.0, 2.0}}, - {T{-4.0, -3.0}, T{-1.0, 0}, T{0.0, 0.0}}, - {T{0.0, 0.0}, T{0.0, -1.5}, T{2.0, 0.0}}}, - exec); - auto abs_mtx = gko::remove_complex::create(exec, mtx->get_size()); + using value_type = typename TestFixture::value_type; + using index_type = typename TestFixture::index_type; + auto exec = this->mtx5->get_executor(); + gko::array permute_idxs{exec, {1, 2, 0}}; + auto c_permute = Mtx::create(exec, this->mtx5->get_size()); - mtx->compute_absolute(abs_mtx); + this->mtx5->inverse_column_permute(&permute_idxs, c_permute); GKO_ASSERT_MTX_NEAR( - abs_mtx, l({{1.0, 5.0, 2.0}, {5.0, 1.0, 0.0}, {0.0, 1.5, 2.0}}), + c_permute, + l({{-0.5, 1.0, -1.0}, {4.5, -2.0, 2.0}, {1.2, 2.1, 3.4}}), 0.0); } -TYPED_TEST(DenseComplex, MakeComplex) +template +std::unique_ptr> ref_scaled_permute( + gko::matrix::Dense* input, + gko::matrix::ScaledPermutation* permutation, + gko::matrix::permute_mode mode) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = gko::ReferenceExecutor::create(); - auto mtx = gko::initialize({{T{1.0, 0.0}, T{3.0, 4.0}, T{0.0, 2.0}}, - {T{-4.0, -3.0}, T{-1.0, 0}, T{0.0, 0.0}}, - {T{0.0, 0.0}, T{0.0, -1.5}, T{2.0, 0.0}}}, - exec); + using gko::matrix::permute_mode; + auto result = input->clone(); + auto permutation_dense = + gko::matrix::Dense::create(input->get_executor()); + gko::matrix_data permutation_data; + if ((mode & permute_mode::inverse) == permute_mode::inverse) { + permutation->invert()->write(permutation_data); + } else { + permutation->write(permutation_data); + } + permutation_dense->read(permutation_data); + if ((mode & permute_mode::rows) == permute_mode::rows) { + // compute P * A + permutation_dense->apply(input, result); + } + if ((mode & permute_mode::columns) == permute_mode::columns) { + // compute A * P^T = (P * A^T)^T + auto tmp = result->transpose(); + auto tmp2 = gko::as>(tmp->clone()); + permutation_dense->apply(tmp, tmp2); + tmp2->transpose(result); + } + return result; +} + + +template +std::unique_ptr> ref_scaled_permute( + gko::matrix::Dense* input, + gko::matrix::ScaledPermutation* row_permutation, + gko::matrix::ScaledPermutation* col_permutation, + bool invert) +{ + using gko::matrix::permute_mode; + auto result = input->clone(); + auto row_permutation_dense = + gko::matrix::Dense::create(input->get_executor()); + auto col_permutation_dense = + gko::matrix::Dense::create(input->get_executor()); + gko::matrix_data row_permutation_data; + gko::matrix_data col_permutation_data; + if (invert) { + row_permutation->invert()->write(row_permutation_data); + col_permutation->invert()->write(col_permutation_data); + } else { + row_permutation->write(row_permutation_data); + col_permutation->write(col_permutation_data); + } + row_permutation_dense->read(row_permutation_data); + col_permutation_dense->read(col_permutation_data); + row_permutation_dense->apply(input, result); + auto tmp = result->transpose(); + auto tmp2 = gko::as>(tmp->clone()); + col_permutation_dense->apply(tmp, tmp2); + tmp2->transpose(result); + return result; +} - auto complex_mtx = mtx->make_complex(); - GKO_ASSERT_MTX_NEAR(complex_mtx, mtx, 0.0); +TYPED_TEST(DenseWithIndexType, ScaledPermute) +{ + using gko::matrix::permute_mode; + using value_type = typename TestFixture::value_type; + + for (auto mode : + {permute_mode::none, permute_mode::rows, permute_mode::columns, + permute_mode::symmetric, permute_mode::inverse_rows, + permute_mode::inverse_columns, permute_mode::inverse_symmetric}) { + SCOPED_TRACE(mode); + + auto permuted = this->mtx5->scale_permute(this->scale_perm3, mode); + auto ref_permuted = + ref_scaled_permute(this->mtx5.get(), this->scale_perm3.get(), mode); + + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, r::value); + } } -TYPED_TEST(DenseComplex, MakeComplexIntoDense) +TYPED_TEST(DenseWithIndexType, ScaledPermuteRoundtrip) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = gko::ReferenceExecutor::create(); - auto mtx = gko::initialize({{T{1.0, 0.0}, T{3.0, 4.0}, T{0.0, 2.0}}, - {T{-4.0, -3.0}, T{-1.0, 0}, T{0.0, 0.0}}, - {T{0.0, 0.0}, T{0.0, -1.5}, T{2.0, 0.0}}}, - exec); + using gko::matrix::permute_mode; + using value_type = typename TestFixture::value_type; - auto complex_mtx = Mtx::create(exec, mtx->get_size()); - mtx->make_complex(complex_mtx); + for (auto mode : + {permute_mode::rows, permute_mode::columns, permute_mode::symmetric}) { + SCOPED_TRACE(mode); - GKO_ASSERT_MTX_NEAR(complex_mtx, mtx, 0.0); + auto permuted = this->mtx5->scale_permute(this->scale_perm3, mode) + ->scale_permute(this->scale_perm3, + mode | permute_mode::inverse); + + GKO_ASSERT_MTX_NEAR(this->mtx5, permuted, r::value); + } } -TYPED_TEST(DenseComplex, GetReal) +TYPED_TEST(DenseWithIndexType, ScaledPermuteStridedIntoDense) { + using gko::matrix::permute_mode; + using value_type = typename TestFixture::value_type; using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = gko::ReferenceExecutor::create(); - auto mtx = gko::initialize({{T{1.0, 0.0}, T{3.0, 4.0}, T{0.0, 2.0}}, - {T{-4.0, -3.0}, T{-1.0, 0}, T{0.0, 0.0}}, - {T{0.0, 0.0}, T{0.0, -1.5}, T{2.0, 0.0}}}, - exec); + auto mtx = Mtx::create(this->exec, this->mtx5->get_size(), + this->mtx5->get_size()[1] + 1); + mtx->copy_from(this->mtx5); - auto real_mtx = mtx->get_real(); + for (auto mode : + {permute_mode::none, permute_mode::rows, permute_mode::columns, + permute_mode::symmetric, permute_mode::inverse, + permute_mode::inverse_rows, permute_mode::inverse_columns, + permute_mode::inverse_symmetric}) { + SCOPED_TRACE(mode); + auto permuted = Mtx::create(this->exec, this->mtx5->get_size(), + this->mtx5->get_size()[1] + 2); - GKO_ASSERT_MTX_NEAR( - real_mtx, l({{1.0, 3.0, 0.0}, {-4.0, -1.0, 0.0}, {0.0, 0.0, 2.0}}), - 0.0); + this->mtx5->scale_permute(this->scale_perm3, permuted, mode); + auto ref_permuted = + ref_scaled_permute(this->mtx5.get(), this->scale_perm3.get(), mode); + + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, r::value); + } } -TYPED_TEST(DenseComplex, GetRealIntoDense) +TYPED_TEST(DenseWithIndexType, ScaledPermuteRectangular) { + using gko::matrix::permute_mode; + using value_type = typename TestFixture::value_type; + + auto rpermuted = + this->mtx1->scale_permute(this->scale_perm2, permute_mode::rows); + auto irpermuted = this->mtx1->scale_permute(this->scale_perm2, + permute_mode::inverse_rows); + auto cpermuted = + this->mtx1->scale_permute(this->scale_perm3, permute_mode::columns); + auto icpermuted = this->mtx1->scale_permute(this->scale_perm3, + permute_mode::inverse_columns); + auto ref_rpermuted = ref_scaled_permute( + this->mtx1.get(), this->scale_perm2.get(), permute_mode::rows); + auto ref_irpermuted = ref_scaled_permute( + this->mtx1.get(), this->scale_perm2.get(), permute_mode::inverse_rows); + auto ref_cpermuted = ref_scaled_permute( + this->mtx1.get(), this->scale_perm3.get(), permute_mode::columns); + auto ref_icpermuted = + ref_scaled_permute(this->mtx1.get(), this->scale_perm3.get(), + permute_mode::inverse_columns); + + GKO_ASSERT_MTX_NEAR(rpermuted, ref_rpermuted, r::value); + GKO_ASSERT_MTX_NEAR(irpermuted, ref_irpermuted, r::value); + GKO_ASSERT_MTX_NEAR(cpermuted, ref_cpermuted, r::value); + GKO_ASSERT_MTX_NEAR(icpermuted, ref_icpermuted, r::value); +} + + +TYPED_TEST(DenseWithIndexType, ScaledPermuteFailsWithIncorrectPermutationSize) +{ + using gko::matrix::permute_mode; + + for (auto mode : + {/* no permute_mode::none */ permute_mode::rows, permute_mode::columns, + permute_mode::symmetric, permute_mode::inverse_rows, + permute_mode::inverse_columns, permute_mode::inverse_symmetric}) { + SCOPED_TRACE(mode); + + ASSERT_THROW(this->mtx5->scale_permute(this->scale_perm0, mode), + gko::ValueMismatch); + } +} + + +TYPED_TEST(DenseWithIndexType, ScaledPermuteFailsWithIncorrectOutputSize) +{ + using gko::matrix::permute_mode; using Mtx = typename TestFixture::Mtx; - using RealMtx = typename TestFixture::RealMtx; - using T = typename TestFixture::value_type; - auto exec = gko::ReferenceExecutor::create(); - auto mtx = gko::initialize({{T{1.0, 0.0}, T{3.0, 4.0}, T{0.0, 2.0}}, - {T{-4.0, -3.0}, T{-1.0, 0}, T{0.0, 0.0}}, - {T{0.0, 0.0}, T{0.0, -1.5}, T{2.0, 0.0}}}, - exec); + auto output = Mtx::create(this->exec); - auto real_mtx = RealMtx::create(exec, mtx->get_size()); - mtx->get_real(real_mtx); + for (auto mode : + {permute_mode::none, permute_mode::rows, permute_mode::columns, + permute_mode::symmetric, permute_mode::inverse_rows, + permute_mode::inverse_columns, permute_mode::inverse_symmetric}) { + SCOPED_TRACE(mode); - GKO_ASSERT_MTX_NEAR( - real_mtx, l({{1.0, 3.0, 0.0}, {-4.0, -1.0, 0.0}, {0.0, 0.0, 2.0}}), - 0.0); + ASSERT_THROW(this->mtx5->scale_permute(this->scale_perm3, output, mode), + gko::DimensionMismatch); + } } -TYPED_TEST(DenseComplex, GetImag) +TYPED_TEST(DenseWithIndexType, NonsymmScaledPermute) { - using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = gko::ReferenceExecutor::create(); - auto mtx = gko::initialize({{T{1.0, 0.0}, T{3.0, 4.0}, T{0.0, 2.0}}, - {T{-4.0, -3.0}, T{-1.0, 0}, T{0.0, 0.0}}, - {T{0.0, 0.0}, T{0.0, -1.5}, T{2.0, 0.0}}}, - exec); + using value_type = typename TestFixture::value_type; - auto imag_mtx = mtx->get_imag(); + auto permuted = + this->mtx5->scale_permute(this->scale_perm3, this->scale_perm3_rev); + auto ref_permuted = + ref_scaled_permute(this->mtx5.get(), this->scale_perm3.get(), + this->scale_perm3_rev.get(), false); - GKO_ASSERT_MTX_NEAR( - imag_mtx, l({{0.0, 4.0, 2.0}, {-3.0, 0.0, 0.0}, {0.0, -1.5, 0.0}}), - 0.0); + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, r::value); } -TYPED_TEST(DenseComplex, GetImagIntoDense) +TYPED_TEST(DenseWithIndexType, NonsymmScaledPermuteInverse) { - using Mtx = typename TestFixture::Mtx; - using RealMtx = typename TestFixture::RealMtx; - using T = typename TestFixture::value_type; - auto exec = gko::ReferenceExecutor::create(); - auto mtx = gko::initialize({{T{1.0, 0.0}, T{3.0, 4.0}, T{0.0, 2.0}}, - {T{-4.0, -3.0}, T{-1.0, 0}, T{0.0, 0.0}}, - {T{0.0, 0.0}, T{0.0, -1.5}, T{2.0, 0.0}}}, - exec); + using value_type = typename TestFixture::value_type; - auto imag_mtx = RealMtx::create(exec, mtx->get_size()); - mtx->get_imag(imag_mtx); + auto permuted = this->mtx5->scale_permute(this->scale_perm3, + this->scale_perm3_rev, true); + auto ref_permuted = + ref_scaled_permute(this->mtx5.get(), this->scale_perm3.get(), + this->scale_perm3_rev.get(), true); - GKO_ASSERT_MTX_NEAR( - imag_mtx, l({{0.0, 4.0, 2.0}, {-3.0, 0.0, 0.0}, {0.0, -1.5, 0.0}}), - 0.0); + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, r::value); } -TYPED_TEST(DenseComplex, Dot) +TYPED_TEST(DenseWithIndexType, NonsymmScaledPermuteRectangular) +{ + using value_type = typename TestFixture::value_type; + + auto permuted = + this->mtx1->scale_permute(this->scale_perm2, this->scale_perm3); + auto ref_permuted = + ref_scaled_permute(this->mtx1.get(), this->scale_perm2.get(), + this->scale_perm3.get(), false); + + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, r::value); +} + + +TYPED_TEST(DenseWithIndexType, NonsymmScaledPermuteInverseRectangular) +{ + using value_type = typename TestFixture::value_type; + + auto permuted = + this->mtx1->scale_permute(this->scale_perm2, this->scale_perm3, true); + auto ref_permuted = + ref_scaled_permute(this->mtx1.get(), this->scale_perm2.get(), + this->scale_perm3.get(), true); + + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, r::value); +} + + +TYPED_TEST(DenseWithIndexType, NonsymmScaledPermuteRoundtrip) +{ + using value_type = typename TestFixture::value_type; + + auto permuted = + this->mtx5->scale_permute(this->scale_perm3, this->scale_perm3_rev) + ->scale_permute(this->scale_perm3, this->scale_perm3_rev, true); + + GKO_ASSERT_MTX_NEAR(this->mtx5, permuted, r::value); +} + + +TYPED_TEST(DenseWithIndexType, NonsymmScaledPermuteStridedIntoDense) { using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = gko::ReferenceExecutor::create(); - auto a = - gko::initialize({T{1.0, 0.0}, T{3.0, 4.0}, T{1.0, 2.0}}, exec); - auto b = - gko::initialize({T{1.0, -2.0}, T{5.0, 0.0}, T{0.0, -3.0}}, exec); - auto result = gko::initialize({T{0.0, 0.0}}, exec); + using value_type = typename TestFixture::value_type; + auto mtx = Mtx::create(this->exec, this->mtx5->get_size(), + this->mtx5->get_size()[1] + 1); + auto permuted = Mtx::create(this->exec, this->mtx5->get_size(), + this->mtx5->get_size()[1] + 2); + mtx->copy_from(this->mtx5); - a->compute_dot(b, result); + mtx->scale_permute(this->scale_perm3, this->scale_perm3_rev, permuted); + auto ref_permuted = + ref_scaled_permute(this->mtx5.get(), this->scale_perm3.get(), + this->scale_perm3_rev.get(), false); - GKO_ASSERT_MTX_NEAR(result, l({T{22.0, 15.0}}), 0.0); + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, r::value); } -TYPED_TEST(DenseComplex, ConjDot) +TYPED_TEST(DenseWithIndexType, NonsymmScaledPermuteInverseStridedIntoDense) { using Mtx = typename TestFixture::Mtx; - using T = typename TestFixture::value_type; - auto exec = gko::ReferenceExecutor::create(); - auto a = - gko::initialize({T{1.0, 0.0}, T{3.0, 4.0}, T{1.0, 2.0}}, exec); - auto b = - gko::initialize({T{1.0, -2.0}, T{5.0, 0.0}, T{0.0, -3.0}}, exec); - auto result = gko::initialize({T{0.0, 0.0}}, exec); + using value_type = typename TestFixture::value_type; + auto mtx = Mtx::create(this->exec, this->mtx5->get_size(), + this->mtx5->get_size()[1] + 1); + auto permuted = Mtx::create(this->exec, this->mtx5->get_size(), + this->mtx5->get_size()[1] + 2); + mtx->copy_from(this->mtx5); + + mtx->scale_permute(this->scale_perm3, this->scale_perm3_rev, permuted, + true); + auto ref_permuted = + ref_scaled_permute(this->mtx5.get(), this->scale_perm3.get(), + this->scale_perm3_rev.get(), true); - a->compute_conj_dot(b, result); + GKO_ASSERT_MTX_NEAR(permuted, ref_permuted, r::value); +} - GKO_ASSERT_MTX_NEAR(result, l({T{10.0, -25.0}}), 0.0); + +TYPED_TEST(DenseWithIndexType, NonsymmScaledPermuteFailsWithIncorrectOutputSize) +{ + ASSERT_THROW( + this->mtx5->scale_permute(this->scale_perm3, this->scale_perm3, + TestFixture::Mtx::create(this->exec)), + gko::DimensionMismatch); +} + + +TYPED_TEST(DenseWithIndexType, + NonsymmScaledPermuteFailsWithIncorrectPermutationSize) +{ + ASSERT_THROW( + this->mtx5->scale_permute(this->scale_perm0, this->scale_perm3_rev), + gko::ValueMismatch); + ASSERT_THROW( + this->mtx5->scale_permute(this->scale_perm3_rev, this->scale_perm0), + gko::ValueMismatch); + ASSERT_THROW( + this->mtx5->scale_permute(this->scale_perm0, this->scale_perm0), + gko::ValueMismatch); } diff --git a/reference/test/matrix/permutation.cpp b/reference/test/matrix/permutation.cpp index 2bd2e3d9741..65e092dfcd5 100644 --- a/reference/test/matrix/permutation.cpp +++ b/reference/test/matrix/permutation.cpp @@ -37,8 +37,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -#include -#include #include @@ -51,12 +49,11 @@ namespace { template class Permutation : public ::testing::Test { protected: - using v_type = + using value_type = typename std::tuple_element<0, decltype(ValueIndexType())>::type; - using i_type = + using index_type = typename std::tuple_element<1, decltype(ValueIndexType())>::type; - using Vec = gko::matrix::Dense; - using Csr = gko::matrix::Csr; + using Vec = gko::matrix::Dense; Permutation() : exec(gko::ReferenceExecutor::create()) {} @@ -67,413 +64,53 @@ TYPED_TEST_SUITE(Permutation, gko::test::ValueIndexTypes, PairTypenameNameGenerator); -TYPED_TEST(Permutation, AppliesRowPermutationToDense) +TYPED_TEST(Permutation, Invert) { - using i_type = typename TestFixture::i_type; - using T = typename TestFixture::v_type; - using Vec = typename TestFixture::Vec; - // clang-format off - auto x = gko::initialize( - {I{2.0, 3.0}, - I{4.0, 2.5}}, this->exec); - // clang-format on - auto y = Vec::create(this->exec, gko::dim<2>{2}); - i_type rdata[] = {1, 0}; + using index_type = typename TestFixture::index_type; + auto perm = gko::matrix::Permutation::create( + this->exec, 3, gko::array{this->exec, {1, 2, 0}}); - auto perm = gko::matrix::Permutation::create( - this->exec, gko::dim<2>{2}, gko::make_array_view(this->exec, 2, rdata)); + auto inv = perm->invert(); - perm->apply(x, y); - // clang-format off - GKO_ASSERT_MTX_NEAR(y, - l({{4.0, 2.5}, - {2.0, 3.0}}), - 0.0); - // clang-format on + EXPECT_EQ(inv->get_const_permutation()[0], 2); + EXPECT_EQ(inv->get_const_permutation()[1], 0); + EXPECT_EQ(inv->get_const_permutation()[2], 1); } -TYPED_TEST(Permutation, AppliesColPermutationToDense) +TYPED_TEST(Permutation, Write) { - using i_type = typename TestFixture::i_type; - using T = typename TestFixture::v_type; - using Vec = typename TestFixture::Vec; - // clang-format off - auto x = gko::initialize( - {I{2.0, 3.0}, - I{4.0, 2.5}}, this->exec); - // clang-format on - auto y = Vec::create(this->exec, gko::dim<2>{2}); - i_type rdata[] = {1, 0}; + using index_type = typename TestFixture::index_type; + auto perm = gko::matrix::Permutation::create( + this->exec, 3, gko::array{this->exec, {1, 2, 0}}); - auto perm = gko::matrix::Permutation::create( - this->exec, gko::dim<2>{2}, gko::make_array_view(this->exec, 2, rdata), - gko::matrix::column_permute); - - perm->apply(x, y); - // clang-format off - GKO_ASSERT_MTX_NEAR(y, - l({{3.0, 2.0}, - {2.5, 4.0}}), - 0.0); - // clang-format on + GKO_ASSERT_MTX_NEAR( + perm, l({{0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}, {1.0, 0.0, 0.0}}), + 0.0); } -TYPED_TEST(Permutation, AppliesRowAndColPermutationToDense) +TYPED_TEST(Permutation, AppliesRowPermutationToDense) { - using i_type = typename TestFixture::i_type; - using T = typename TestFixture::v_type; + using index_type = typename TestFixture::index_type; + using T = typename TestFixture::value_type; using Vec = typename TestFixture::Vec; // clang-format off auto x = gko::initialize( {I{2.0, 3.0}, I{4.0, 2.5}}, this->exec); // clang-format on - auto y1 = Vec::create(this->exec, gko::dim<2>{2}); - auto y2 = Vec::create(this->exec, gko::dim<2>{2}); - i_type cdata[] = {1, 0}; - i_type rdata[] = {1, 0}; + auto y = Vec::create(this->exec, gko::dim<2>{2}); + index_type rdata[] = {1, 0}; - auto rperm = gko::matrix::Permutation::create( + auto perm = gko::matrix::Permutation::create( this->exec, gko::dim<2>{2}, gko::make_array_view(this->exec, 2, rdata)); - auto cperm = gko::matrix::Permutation::create( - this->exec, gko::dim<2>{2}, gko::make_array_view(this->exec, 2, cdata), - gko::matrix::column_permute); - - rperm->apply(x, y1); - cperm->apply(y1, y2); - // clang-format off - GKO_ASSERT_MTX_NEAR(y2, - l({{2.5, 4.0}, - {3.0, 2.0}}), - 0.0); - // clang-format on -} - - -TYPED_TEST(Permutation, AppliesRowAndColPermutationToDenseWithOneArray) -{ - using i_type = typename TestFixture::i_type; - using T = typename TestFixture::v_type; - using Vec = typename TestFixture::Vec; - // clang-format off - auto x = gko::initialize( - {I{2.0, 3.0}, - I{4.0, 2.5}}, this->exec); - // clang-format on - auto y1 = Vec::create(this->exec, gko::dim<2>{2}); - i_type data[] = {1, 0}; - - auto perm = gko::matrix::Permutation::create( - this->exec, gko::dim<2>{2}, gko::make_array_view(this->exec, 2, data), - gko::matrix::row_permute | gko::matrix::column_permute); - - perm->apply(x, y1); - // clang-format off - GKO_ASSERT_MTX_NEAR(y1, - l({{2.5, 4.0}, - {3.0, 2.0}}), - 0.0); - // clang-format on -} - - -TYPED_TEST(Permutation, AppliesInverseRowAndColPermutationToDense) -{ - using i_type = typename TestFixture::i_type; - using Vec = typename TestFixture::Vec; - // clang-format off - auto x = gko::initialize({{2.0, 3.0, 0.0}, - {0.0, 1.0, 0.0}, - {0.0, 4.0, 2.5}}, - this->exec); - // clang-format on - auto y1 = Vec::create(this->exec, gko::dim<2>{3}); - auto y2 = Vec::create(this->exec, gko::dim<2>{3}); - i_type cdata[] = {1, 2, 0}; - i_type rdata[] = {1, 2, 0}; - - auto rperm = gko::matrix::Permutation::create( - this->exec, gko::dim<2>{3}, gko::make_array_view(this->exec, 3, rdata), - gko::matrix::row_permute | gko::matrix::inverse_permute); - auto cperm = gko::matrix::Permutation::create( - this->exec, gko::dim<2>{3}, gko::make_array_view(this->exec, 3, cdata), - gko::matrix::inverse_permute | gko::matrix::column_permute); - - rperm->apply(x, y1); - cperm->apply(y1, y2); - // clang-format off - GKO_ASSERT_MTX_NEAR(y2, - l({{2.5, 0.0, 4.0}, - {0.0, 2.0, 3.0}, - {0.0, 0.0, 1.0}}), - 0.0); - // clang-format on -} - - -TYPED_TEST(Permutation, AppliesInverseRowAndColPermutationToDenseWithOneArray) -{ - using i_type = typename TestFixture::i_type; - using Vec = typename TestFixture::Vec; - // clang-format off - auto x = gko::initialize({{2.0, 3.0, 0.0}, - {0.0, 1.0, 0.0}, - {0.0, 4.0, 2.5}}, - this->exec); - // clang-format on - auto y1 = Vec::create(this->exec, gko::dim<2>{3}); - i_type data[] = {1, 2, 0}; - - auto perm = gko::matrix::Permutation::create( - this->exec, gko::dim<2>{3}, gko::make_array_view(this->exec, 3, data), - gko::matrix::column_permute | gko::matrix::row_permute | - gko::matrix::inverse_permute); - - perm->apply(x, y1); - // clang-format off - GKO_ASSERT_MTX_NEAR(y1, - l({{2.5, 0.0, 4.0}, - {0.0, 2.0, 3.0}, - {0.0, 0.0, 1.0}}), - 0.0); - // clang-format on -} - - -TYPED_TEST(Permutation, AppliesInverseRowPermutationToDense) -{ - using i_type = typename TestFixture::i_type; - using Vec = typename TestFixture::Vec; - // clang-format off - auto x = gko::initialize({{2.0, 3.0, 0.0}, - {0.0, 1.0, 0.0}, - {0.0, 4.0, 2.5}}, - this->exec); - // clang-format on - auto y = Vec::create(this->exec, gko::dim<2>{3}); - i_type rdata[] = {1, 2, 0}; - - auto rperm = gko::matrix::Permutation::create( - this->exec, gko::dim<2>{3}, gko::make_array_view(this->exec, 3, rdata), - gko::matrix::row_permute | gko::matrix::inverse_permute); - - rperm->apply(x, y); - // clang-format off - GKO_ASSERT_MTX_NEAR(y, - l({{0.0, 4.0, 2.5}, - {2.0, 3.0, 0.0}, - {0.0, 1.0, 0.0}}), - 0.0); - // clang-format on -} - - -TYPED_TEST(Permutation, AppliesInverseColPermutationToDense) -{ - using i_type = typename TestFixture::i_type; - using Vec = typename TestFixture::Vec; - // clang-format off - auto x = gko::initialize({{2.0, 3.0, 0.0}, - {0.0, 1.0, 0.0}, - {0.0, 4.0, 2.5}}, - this->exec); - // clang-format on - auto y = Vec::create(this->exec, gko::dim<2>{3}); - i_type cdata[] = {1, 2, 0}; - - auto cperm = gko::matrix::Permutation::create( - this->exec, gko::dim<2>{3}, gko::make_array_view(this->exec, 3, cdata), - gko::matrix::inverse_permute | gko::matrix::column_permute); - - cperm->apply(x, y); - // clang-format off - GKO_ASSERT_MTX_NEAR(y, - l({{0.0, 2.0, 3.0}, - {0.0, 0.0, 1.0}, - {2.5, 0.0, 4.0}}), - 0.0); - // clang-format on -} - - -TYPED_TEST(Permutation, AppliesRowPermutationToCsr) -{ - using i_type = typename TestFixture::i_type; - using Csr = typename TestFixture::Csr; - // clang-format off - auto x = gko::initialize( - {{2.0, 3.0, 0.0}, - {0.0, 1.0, 0.0}, - {0.0, 4.0, 2.5}}, - this->exec); - // clang-format on - auto y = Csr::create(this->exec, gko::dim<2>{3}); - i_type rdata[] = {1, 2, 0}; - - auto perm = gko::matrix::Permutation::create( - this->exec, gko::dim<2>{3}, gko::make_array_view(this->exec, 3, rdata)); perm->apply(x, y); // clang-format off GKO_ASSERT_MTX_NEAR(y, - l({{0.0, 1.0, 0.0}, - {0.0, 4.0, 2.5}, - {2.0, 3.0, 0.0}}), - 0.0); - // clang-format on -} - - -TYPED_TEST(Permutation, AppliesColPermutationToCsr) -{ - using i_type = typename TestFixture::i_type; - using Csr = typename TestFixture::Csr; - // clang-format off - auto x = gko::initialize( - {{2.0, 3.0, 0.0}, - {0.0, 1.0, 0.0}, - {0.0, 4.0, 2.5}}, - this->exec); - // clang-format on - auto y = Csr::create(this->exec, gko::dim<2>{3}); - i_type cdata[] = {1, 2, 0}; - - auto perm = gko::matrix::Permutation::create( - this->exec, gko::dim<2>{3}, gko::make_array_view(this->exec, 3, cdata), - gko::matrix::column_permute); - - perm->apply(x, y); - // clang-format off - GKO_ASSERT_MTX_NEAR(y, - l({{3.0, 0.0, 2.0}, - {1.0, 0.0, 0.0}, - {4.0, 2.5, 0.0}}), - 0.0); - // clang-format on -} - - -TYPED_TEST(Permutation, AppliesRowAndColPermutationToCsr) -{ - using i_type = typename TestFixture::i_type; - using Csr = typename TestFixture::Csr; - // clang-format off - auto x = gko::initialize( - {{2.0, 3.0, 0.0}, - {0.0, 1.0, 0.0}, - {0.0, 4.0, 2.5}}, - this->exec); - // clang-format on - auto y1 = Csr::create(this->exec, gko::dim<2>{3}); - auto y2 = Csr::create(this->exec, gko::dim<2>{3}); - i_type cdata[] = {1, 2, 0}; - i_type rdata[] = {1, 2, 0}; - - auto rperm = gko::matrix::Permutation::create( - this->exec, gko::dim<2>{3}, gko::make_array_view(this->exec, 3, rdata)); - auto cperm = gko::matrix::Permutation::create( - this->exec, gko::dim<2>{3}, gko::make_array_view(this->exec, 3, cdata), - gko::matrix::column_permute); - - rperm->apply(x, y1); - cperm->apply(y1, y2); - // clang-format off - GKO_ASSERT_MTX_NEAR(y2, - l({{1.0, 0.0, 0.0}, - {4.0, 2.5, 0.0}, - {3.0, 0.0, 2.0}}), - 0.0); - // clang-format on -} - - -TYPED_TEST(Permutation, AppliesInverseRowPermutationToCsr) -{ - using i_type = typename TestFixture::i_type; - using Csr = typename TestFixture::Csr; - // clang-format off - auto x = gko::initialize({{2.0, 3.0, 0.0}, - {0.0, 1.0, 0.0}, - {0.0, 4.0, 2.5}}, - this->exec); - // clang-format on - auto y = Csr::create(this->exec, gko::dim<2>{3}); - i_type rdata[] = {1, 2, 0}; - - auto rperm = gko::matrix::Permutation::create( - this->exec, gko::dim<2>{3}, gko::make_array_view(this->exec, 3, rdata), - gko::matrix::row_permute | gko::matrix::inverse_permute); - - rperm->apply(x, y); - // clang-format off - GKO_ASSERT_MTX_NEAR(y, - l({{0.0, 4.0, 2.5}, - {2.0, 3.0, 0.0}, - {0.0, 1.0, 0.0}}), - 0.0); - // clang-format on -} - - -TYPED_TEST(Permutation, AppliesInverseColPermutationToCsr) -{ - using i_type = typename TestFixture::i_type; - using Csr = typename TestFixture::Csr; - // clang-format off - auto x = gko::initialize({{2.0, 3.0, 0.0}, - {0.0, 1.0, 0.0}, - {0.0, 4.0, 2.5}}, - this->exec); - // clang-format on - auto y = Csr::create(this->exec, gko::dim<2>{3}); - i_type cdata[] = {1, 2, 0}; - - auto cperm = gko::matrix::Permutation::create( - this->exec, gko::dim<2>{3}, gko::make_array_view(this->exec, 3, cdata), - gko::matrix::inverse_permute | gko::matrix::column_permute); - - cperm->apply(x, y); - // clang-format off - GKO_ASSERT_MTX_NEAR(y, - l({{0.0, 2.0, 3.0}, - {0.0, 0.0, 1.0}, - {2.5, 0.0, 4.0}}), - 0.0); - // clang-format on -} - - -TYPED_TEST(Permutation, AppliesInverseRowAndColPermutationToCsr) -{ - using i_type = typename TestFixture::i_type; - using Csr = typename TestFixture::Csr; - // clang-format off - auto x = gko::initialize({{2.0, 3.0, 0.0}, - {0.0, 1.0, 0.0}, - {0.0, 4.0, 2.5}}, - this->exec); - // clang-format on - auto y1 = Csr::create(this->exec, gko::dim<2>{3}); - auto y2 = Csr::create(this->exec, gko::dim<2>{3}); - i_type cdata[] = {1, 2, 0}; - i_type rdata[] = {1, 2, 0}; - - auto rperm = gko::matrix::Permutation::create( - this->exec, gko::dim<2>{3}, gko::make_array_view(this->exec, 3, rdata), - gko::matrix::row_permute | gko::matrix::inverse_permute); - auto cperm = gko::matrix::Permutation::create( - this->exec, gko::dim<2>{3}, gko::make_array_view(this->exec, 3, cdata), - gko::matrix::inverse_permute | gko::matrix::column_permute); - - rperm->apply(x, y1); - cperm->apply(y1, y2); - // clang-format off - GKO_ASSERT_MTX_NEAR(y2, - l({{2.5, 0.0, 4.0}, - {0.0, 2.0, 3.0}, - {0.0, 0.0, 1.0}}), + l({{4.0, 2.5}, + {2.0, 3.0}}), 0.0); // clang-format on } diff --git a/reference/test/matrix/scaled_permutation.cpp b/reference/test/matrix/scaled_permutation.cpp new file mode 100644 index 00000000000..a15c0f09bbf --- /dev/null +++ b/reference/test/matrix/scaled_permutation.cpp @@ -0,0 +1,116 @@ +/************************************************************* +Copyright (c) 2017-2023, the Ginkgo authors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*************************************************************/ + +#include + + +#include + + +#include +#include +#include + + +#include "core/test/utils.hpp" + + +namespace { + + +template +class ScaledPermutation : public ::testing::Test { +protected: + using value_type = + typename std::tuple_element<0, decltype(ValueIndexType())>::type; + using index_type = + typename std::tuple_element<1, decltype(ValueIndexType())>::type; + using Vec = gko::matrix::Dense; + using Mtx = gko::matrix::ScaledPermutation; + + ScaledPermutation() : exec(gko::ReferenceExecutor::create()) + { + perm3 = Mtx::create(exec, + gko::array{this->exec, {1.0, 2.0, 4.0}}, + gko::array{this->exec, {1, 2, 0}}); + perm2 = + Mtx::create(exec, gko::array{this->exec, {3.0, 5.0}}, + gko::array{this->exec, {1, 0}}); + } + + std::shared_ptr exec; + std::unique_ptr perm3; + std::unique_ptr perm2; +}; + +TYPED_TEST_SUITE(ScaledPermutation, gko::test::ValueIndexTypes, + PairTypenameNameGenerator); + + +TYPED_TEST(ScaledPermutation, Invert) +{ + using T = typename TestFixture::value_type; + auto inv = this->perm3->invert(); + + EXPECT_EQ(inv->get_const_permutation()[0], 2); + EXPECT_EQ(inv->get_const_permutation()[1], 0); + EXPECT_EQ(inv->get_const_permutation()[2], 1); + EXPECT_EQ(inv->get_const_scale()[0], T{0.25}); + EXPECT_EQ(inv->get_const_scale()[1], T{1.0}); + EXPECT_EQ(inv->get_const_scale()[2], T{0.5}); +} + + +TYPED_TEST(ScaledPermutation, Write) +{ + using T = typename TestFixture::value_type; + + GKO_ASSERT_MTX_NEAR( + this->perm3, l({{0.0, 1.0, 0.0}, {0.0, 0.0, 2.0}, {4.0, 0.0, 0.0}}), + 0.0); +} + + +TYPED_TEST(ScaledPermutation, AppliesToDense) +{ + using T = typename TestFixture::value_type; + using Vec = typename TestFixture::Vec; + auto x = gko::initialize({I{2.0, 3.0}, I{4.0, 2.5}}, this->exec); + auto y = Vec::create(this->exec, gko::dim<2>{2}); + + this->perm2->apply(x, y); + + GKO_ASSERT_MTX_NEAR(y, l({{12.0, 7.5}, {10.0, 15.0}}), 0.0); +} + + +} // namespace diff --git a/reference/test/reorder/rcm_kernels.cpp b/reference/test/reorder/rcm_kernels.cpp index 4c79af9e73a..b23e8bec097 100644 --- a/reference/test/reorder/rcm_kernels.cpp +++ b/reference/test/reorder/rcm_kernels.cpp @@ -98,7 +98,7 @@ class Rcm : public ::testing::Test { static bool is_permutation(const perm_type* input_perm) { - const auto perm_size = input_perm->get_permutation_size(); + const auto perm_size = input_perm->get_size()[0]; auto perm_sorted = std::vector(perm_size); std::copy_n(input_perm->get_const_permutation(), perm_size, perm_sorted.begin()); diff --git a/test/matrix/CMakeLists.txt b/test/matrix/CMakeLists.txt index a9cf267a3c8..2c245a67a40 100644 --- a/test/matrix/CMakeLists.txt +++ b/test/matrix/CMakeLists.txt @@ -12,5 +12,7 @@ else() endif() ginkgo_create_common_test(hybrid_kernels) ginkgo_create_common_test(matrix) +ginkgo_create_common_test(permutation_kernels) +ginkgo_create_common_test(scaled_permutation_kernels) ginkgo_create_common_test(sellp_kernels) ginkgo_create_common_test(sparsity_csr_kernels) diff --git a/test/matrix/csr_kernels2.cpp b/test/matrix/csr_kernels2.cpp index 4d3ffa61323..6fa679f8a62 100644 --- a/test/matrix/csr_kernels2.cpp +++ b/test/matrix/csr_kernels2.cpp @@ -48,6 +48,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include +#include #include #include @@ -55,6 +57,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "core/components/prefix_sum_kernels.hpp" #include "core/matrix/csr_kernels.hpp" #include "core/test/utils.hpp" +#include "core/test/utils/assertions.hpp" #include "core/test/utils/unsort_matrix.hpp" #include "core/utils/matrix_utils.hpp" #include "test/utils/executor.hpp" @@ -68,6 +71,8 @@ class Csr : public CommonTestFixture { using Mtx = gko::matrix::Csr; using ComplexVec = gko::matrix::Dense>; using ComplexMtx = gko::matrix::Csr>; + using Perm = gko::matrix::Permutation; + using ScaledPerm = gko::matrix::ScaledPermutation; Csr() #ifdef GINKGO_FAST_TESTS @@ -162,8 +167,8 @@ class Csr : public CommonTestFixture { beta2 = gko::initialize({-1.0}, ref); dmtx = Mtx::create(exec, strategy); dmtx->copy_from(mtx); - square_dmtx = Mtx::create(exec, strategy); - square_dmtx->copy_from(square_mtx); + dsquare_mtx = Mtx::create(exec, strategy); + dsquare_mtx->copy_from(square_mtx); dresult = gko::clone(exec, expected); dresult2 = gko::clone(exec, expected2); dy = gko::clone(exec, y); @@ -180,8 +185,22 @@ class Csr : public CommonTestFixture { std::vector tmp2(mtx->get_size()[1], 0); std::iota(tmp2.begin(), tmp2.end(), 0); std::shuffle(tmp2.begin(), tmp2.end(), rng); + std::vector scale(mtx->get_size()[0]); + std::vector scale2(mtx->get_size()[1]); + std::uniform_real_distribution dist(1, 2); + auto gen = [&] { return dist(rng); }; + std::generate(scale.begin(), scale.end(), gen); + std::generate(scale2.begin(), scale2.end(), gen); rpermute_idxs = std::make_unique(ref, tmp.begin(), tmp.end()); cpermute_idxs = std::make_unique(ref, tmp2.begin(), tmp2.end()); + rpermutation = Perm::create(ref, tmp.size(), *rpermute_idxs); + cpermutation = Perm::create(ref, tmp2.size(), *cpermute_idxs); + srpermutation = ScaledPerm::create( + ref, gko::array(ref, scale.begin(), scale.end()), + *rpermute_idxs); + scpermutation = ScaledPerm::create( + ref, gko::array(ref, scale2.begin(), scale2.end()), + *cpermute_idxs); } template @@ -192,8 +211,8 @@ class Csr : public CommonTestFixture { complex_mtx = ComplexMtx::create(ref, strategy); complex_mtx->move_from( gen_mtx(mtx_size[0], mtx_size[1], 1)); - complex_dmtx = ComplexMtx::create(exec, strategy); - complex_dmtx->copy_from(complex_mtx); + dcomplex_mtx = ComplexMtx::create(exec, strategy); + dcomplex_mtx->copy_from(complex_mtx); } void unsort_mtx() @@ -220,8 +239,8 @@ class Csr : public CommonTestFixture { std::unique_ptr dmtx; std::unique_ptr dmtx2; - std::unique_ptr complex_dmtx; - std::unique_ptr square_dmtx; + std::unique_ptr dcomplex_mtx; + std::unique_ptr dsquare_mtx; std::unique_ptr dresult; std::unique_ptr dresult2; std::unique_ptr dy; @@ -232,6 +251,10 @@ class Csr : public CommonTestFixture { std::unique_ptr dbeta2; std::unique_ptr rpermute_idxs; std::unique_ptr cpermute_idxs; + std::unique_ptr rpermutation; + std::unique_ptr cpermutation; + std::unique_ptr srpermutation; + std::unique_ptr scpermutation; }; @@ -510,11 +533,11 @@ TEST_F(Csr, AdvancedApplyToCsrMatrixIsEquivalentToRef) auto d_trans = dmtx->transpose(); mtx->apply(alpha, trans, beta, square_mtx); - dmtx->apply(dalpha, d_trans, dbeta, square_dmtx); + dmtx->apply(dalpha, d_trans, dbeta, dsquare_mtx); - GKO_ASSERT_MTX_NEAR(square_dmtx, square_mtx, r::value); - GKO_ASSERT_MTX_EQ_SPARSITY(square_dmtx, square_mtx); - ASSERT_TRUE(square_dmtx->is_sorted_by_column_index()); + GKO_ASSERT_MTX_NEAR(dsquare_mtx, square_mtx, r::value); + GKO_ASSERT_MTX_EQ_SPARSITY(dsquare_mtx, square_mtx); + ASSERT_TRUE(dsquare_mtx->is_sorted_by_column_index()); } @@ -525,11 +548,11 @@ TEST_F(Csr, SimpleApplyToCsrMatrixIsEquivalentToRef) auto d_trans = dmtx->transpose(); mtx->apply(trans, square_mtx); - dmtx->apply(d_trans, square_dmtx); + dmtx->apply(d_trans, dsquare_mtx); - GKO_ASSERT_MTX_NEAR(square_dmtx, square_mtx, r::value); - GKO_ASSERT_MTX_EQ_SPARSITY(square_dmtx, square_mtx); - ASSERT_TRUE(square_dmtx->is_sorted_by_column_index()); + GKO_ASSERT_MTX_NEAR(dsquare_mtx, square_mtx, r::value); + GKO_ASSERT_MTX_EQ_SPARSITY(dsquare_mtx, square_mtx); + ASSERT_TRUE(dsquare_mtx->is_sorted_by_column_index()); } @@ -542,11 +565,11 @@ TEST_F(Csr, SimpleApplyToSparseCsrMatrixIsEquivalentToRef) dmtx2->copy_from(mtx2); mtx->apply(mtx2, square_mtx); - dmtx->apply(dmtx2, square_dmtx); + dmtx->apply(dmtx2, dsquare_mtx); - GKO_ASSERT_MTX_EQ_SPARSITY(square_dmtx, square_mtx); - GKO_ASSERT_MTX_NEAR(square_dmtx, square_mtx, r::value); - ASSERT_TRUE(square_dmtx->is_sorted_by_column_index()); + GKO_ASSERT_MTX_EQ_SPARSITY(dsquare_mtx, square_mtx); + GKO_ASSERT_MTX_NEAR(dsquare_mtx, square_mtx, r::value); + ASSERT_TRUE(dsquare_mtx->is_sorted_by_column_index()); } @@ -560,11 +583,11 @@ TEST_F(Csr, SimpleApplySparseToSparseCsrMatrixIsEquivalentToRef) auto dmtx2 = gko::clone(exec, mtx2); mtx1->apply(mtx2, square_mtx); - dmtx1->apply(dmtx2, square_dmtx); + dmtx1->apply(dmtx2, dsquare_mtx); - GKO_ASSERT_MTX_EQ_SPARSITY(square_dmtx, square_mtx); - GKO_ASSERT_MTX_NEAR(square_dmtx, square_mtx, r::value); - ASSERT_TRUE(square_dmtx->is_sorted_by_column_index()); + GKO_ASSERT_MTX_EQ_SPARSITY(dsquare_mtx, square_mtx); + GKO_ASSERT_MTX_NEAR(dsquare_mtx, square_mtx, r::value); + ASSERT_TRUE(dsquare_mtx->is_sorted_by_column_index()); } @@ -581,11 +604,11 @@ TEST_F(Csr, SimpleApplyToEmptyCsrMatrixIsEquivalentToRef) dmtx2->copy_from(mtx2); mtx->apply(mtx2, square_mtx); - dmtx->apply(dmtx2, square_dmtx); + dmtx->apply(dmtx2, dsquare_mtx); - GKO_ASSERT_MTX_EQ_SPARSITY(square_dmtx, square_mtx); - GKO_ASSERT_MTX_NEAR(square_dmtx, square_mtx, r::value); - ASSERT_TRUE(square_dmtx->is_sorted_by_column_index()); + GKO_ASSERT_MTX_EQ_SPARSITY(dsquare_mtx, square_mtx); + GKO_ASSERT_MTX_NEAR(dsquare_mtx, square_mtx, r::value); + ASSERT_TRUE(dsquare_mtx->is_sorted_by_column_index()); } @@ -673,7 +696,7 @@ TEST_F(Csr, ConjugateTransposeIsEquivalentToRef) set_up_apply_complex_data(); auto trans = gko::as(complex_mtx->conj_transpose()); - auto d_trans = gko::as(complex_dmtx->conj_transpose()); + auto d_trans = gko::as(dcomplex_mtx->conj_transpose()); GKO_ASSERT_MTX_NEAR(d_trans, trans, 0.0); ASSERT_TRUE(d_trans->is_sorted_by_column_index()); @@ -868,12 +891,152 @@ TEST_F(Csr, MoveToHybridIsEquivalentToRef) } +TEST_F(Csr, IsGenericPermutable) +{ + using gko::matrix::permute_mode; + set_up_apply_data(); + + for (auto mode : + {permute_mode::none, permute_mode::rows, permute_mode::columns, + permute_mode::symmetric, permute_mode::inverse_rows, + permute_mode::inverse_columns, permute_mode::inverse_symmetric}) { + SCOPED_TRACE(mode); + auto permuted = square_mtx->permute(rpermutation, mode); + auto dpermuted = dsquare_mtx->permute(rpermutation, mode); + + GKO_ASSERT_MTX_NEAR(permuted, dpermuted, 0); + GKO_ASSERT_MTX_EQ_SPARSITY(permuted, dpermuted); + ASSERT_TRUE(dpermuted->is_sorted_by_column_index()); + } +} + + +TEST_F(Csr, IsGenericPermutableRectangular) +{ + using gko::matrix::permute_mode; + set_up_apply_data(); + + auto rpermuted = mtx->permute(rpermutation, permute_mode::rows); + auto drpermuted = dmtx->permute(rpermutation, permute_mode::rows); + auto irpermuted = + mtx->permute(rpermutation, permute_mode::inverse_rows); + auto dirpermuted = + dmtx->permute(rpermutation, permute_mode::inverse_rows); + auto cpermuted = mtx->permute(cpermutation, permute_mode::columns); + auto dcpermuted = dmtx->permute(cpermutation, permute_mode::columns); + auto icpermuted = + mtx->permute(cpermutation, permute_mode::inverse_columns); + auto dicpermuted = + dmtx->permute(cpermutation, permute_mode::inverse_columns); + + GKO_EXPECT_MTX_NEAR(rpermuted, drpermuted, r::value); + GKO_EXPECT_MTX_NEAR(irpermuted, dirpermuted, r::value); + GKO_EXPECT_MTX_NEAR(cpermuted, dcpermuted, r::value); + GKO_EXPECT_MTX_NEAR(icpermuted, dicpermuted, r::value); + GKO_EXPECT_MTX_EQ_SPARSITY(rpermuted, drpermuted); + GKO_EXPECT_MTX_EQ_SPARSITY(irpermuted, dirpermuted); + GKO_EXPECT_MTX_EQ_SPARSITY(cpermuted, dcpermuted); + GKO_EXPECT_MTX_EQ_SPARSITY(icpermuted, dicpermuted); + EXPECT_TRUE(rpermuted->is_sorted_by_column_index()); + EXPECT_TRUE(irpermuted->is_sorted_by_column_index()); + EXPECT_TRUE(cpermuted->is_sorted_by_column_index()); + EXPECT_TRUE(icpermuted->is_sorted_by_column_index()); +} + + +TEST_F(Csr, IsNonsymmPermutable) +{ + using gko::matrix::permute_mode; + set_up_apply_data(); + + for (auto invert : {false, true}) { + SCOPED_TRACE(invert); + auto permuted = mtx->permute(rpermutation, cpermutation, invert); + auto dpermuted = dmtx->permute(rpermutation, cpermutation, invert); + + GKO_ASSERT_MTX_NEAR(permuted, dpermuted, 0); + GKO_ASSERT_MTX_EQ_SPARSITY(permuted, dpermuted); + ASSERT_TRUE(dpermuted->is_sorted_by_column_index()); + } +} + + +TEST_F(Csr, IsGenericScalePermutable) +{ + using gko::matrix::permute_mode; + set_up_apply_data(); + + for (auto mode : + {permute_mode::none, permute_mode::rows, permute_mode::columns, + permute_mode::symmetric, permute_mode::inverse_rows, + permute_mode::inverse_columns, permute_mode::inverse_symmetric}) { + SCOPED_TRACE(mode); + auto permuted = square_mtx->scale_permute(srpermutation, mode); + auto dpermuted = dsquare_mtx->scale_permute(srpermutation, mode); + + GKO_EXPECT_MTX_NEAR(permuted, dpermuted, r::value); + GKO_EXPECT_MTX_EQ_SPARSITY(permuted, dpermuted); + EXPECT_TRUE(dpermuted->is_sorted_by_column_index()); + } +} + + +TEST_F(Csr, IsGenericScalePermutableRectangular) +{ + using gko::matrix::permute_mode; + set_up_apply_data(); + + auto rpermuted = mtx->scale_permute(srpermutation, permute_mode::rows); + auto drpermuted = dmtx->scale_permute(srpermutation, permute_mode::rows); + auto irpermuted = + mtx->scale_permute(srpermutation, permute_mode::inverse_rows); + auto dirpermuted = + dmtx->scale_permute(srpermutation, permute_mode::inverse_rows); + auto cpermuted = mtx->scale_permute(scpermutation, permute_mode::columns); + auto dcpermuted = dmtx->scale_permute(scpermutation, permute_mode::columns); + auto icpermuted = + mtx->scale_permute(scpermutation, permute_mode::inverse_columns); + auto dicpermuted = + dmtx->scale_permute(scpermutation, permute_mode::inverse_columns); + + GKO_EXPECT_MTX_NEAR(rpermuted, drpermuted, r::value); + GKO_EXPECT_MTX_NEAR(irpermuted, dirpermuted, r::value); + GKO_EXPECT_MTX_NEAR(cpermuted, dcpermuted, r::value); + GKO_EXPECT_MTX_NEAR(icpermuted, dicpermuted, r::value); + GKO_EXPECT_MTX_EQ_SPARSITY(rpermuted, drpermuted); + GKO_EXPECT_MTX_EQ_SPARSITY(irpermuted, dirpermuted); + GKO_EXPECT_MTX_EQ_SPARSITY(cpermuted, dcpermuted); + GKO_EXPECT_MTX_EQ_SPARSITY(icpermuted, dicpermuted); + EXPECT_TRUE(rpermuted->is_sorted_by_column_index()); + EXPECT_TRUE(irpermuted->is_sorted_by_column_index()); + EXPECT_TRUE(cpermuted->is_sorted_by_column_index()); + EXPECT_TRUE(icpermuted->is_sorted_by_column_index()); +} + + +TEST_F(Csr, IsNonsymmScalePermutable) +{ + using gko::matrix::permute_mode; + set_up_apply_data(); + + for (auto invert : {false, true}) { + SCOPED_TRACE(invert); + auto permuted = mtx->scale_permute(srpermutation, scpermutation, invert); + auto dpermuted = dmtx->scale_permute(srpermutation, scpermutation, invert); + + GKO_EXPECT_MTX_NEAR(permuted, dpermuted, r::value); + GKO_EXPECT_MTX_EQ_SPARSITY(permuted, dpermuted); + EXPECT_TRUE(dpermuted->is_sorted_by_column_index()); + } +} + + TEST_F(Csr, IsPermutable) { set_up_apply_data(); auto permuted = gko::as(square_mtx->permute(rpermute_idxs.get())); - auto dpermuted = gko::as(square_dmtx->permute(rpermute_idxs.get())); + auto dpermuted = gko::as(dsquare_mtx->permute(rpermute_idxs.get())); GKO_ASSERT_MTX_EQ_SPARSITY(permuted, dpermuted); GKO_ASSERT_MTX_NEAR(permuted, dpermuted, 0); @@ -887,7 +1050,7 @@ TEST_F(Csr, IsInversePermutable) auto permuted = gko::as(square_mtx->inverse_permute(rpermute_idxs.get())); auto dpermuted = - gko::as(square_dmtx->inverse_permute(rpermute_idxs.get())); + gko::as(dsquare_mtx->inverse_permute(rpermute_idxs.get())); GKO_ASSERT_MTX_EQ_SPARSITY(permuted, dpermuted); GKO_ASSERT_MTX_NEAR(permuted, dpermuted, 0); @@ -1141,9 +1304,9 @@ TEST_F(Csr, InplaceAbsoluteComplexMatrixIsEquivalentToRef) set_up_apply_complex_data(); complex_mtx->compute_absolute_inplace(); - complex_dmtx->compute_absolute_inplace(); + dcomplex_mtx->compute_absolute_inplace(); - GKO_ASSERT_MTX_NEAR(complex_mtx, complex_dmtx, r::value); + GKO_ASSERT_MTX_NEAR(complex_mtx, dcomplex_mtx, r::value); } @@ -1152,7 +1315,7 @@ TEST_F(Csr, OutplaceAbsoluteComplexMatrixIsEquivalentToRef) set_up_apply_complex_data(); auto abs_mtx = complex_mtx->compute_absolute(); - auto dabs_mtx = complex_dmtx->compute_absolute(); + auto dabs_mtx = dcomplex_mtx->compute_absolute(); GKO_ASSERT_MTX_NEAR(abs_mtx, dabs_mtx, r::value); } diff --git a/test/matrix/dense_kernels.cpp b/test/matrix/dense_kernels.cpp index e9449ee9262..994283915c2 100644 --- a/test/matrix/dense_kernels.cpp +++ b/test/matrix/dense_kernels.cpp @@ -50,6 +50,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include +#include #include #include @@ -70,6 +72,9 @@ class Dense : public CommonTestFixture { using ComplexMtx = gko::matrix::Dense>; using Diagonal = gko::matrix::Diagonal; using MixedComplexMtx = gko::matrix::Dense>; + using Permutation = gko::matrix::Permutation; + using ScaledPermutation = + gko::matrix::ScaledPermutation; Dense() : rand_engine(15) {} @@ -145,16 +150,37 @@ class Dense : public CommonTestFixture { std::iota(tmp2.begin(), tmp2.end(), 0); std::shuffle(tmp2.begin(), tmp2.end(), rng); std::vector tmp3(x->get_size()[0] / 10); + std::vector scale_factors(tmp.size()); + std::vector scale_factors2(tmp2.size()); std::uniform_int_distribution row_dist(0, x->get_size()[0] - 1); + std::uniform_real_distribution scale_dist{1, 2}; for (auto& i : tmp3) { i = row_dist(rng); } + for (auto& s : scale_factors) { + s = scale_dist(rng); + } + for (auto& s : scale_factors2) { + s = scale_dist(rng); + } rpermute_idxs = std::unique_ptr(new Arr{ref, tmp.begin(), tmp.end()}); cpermute_idxs = std::unique_ptr(new Arr{ref, tmp2.begin(), tmp2.end()}); rgather_idxs = std::unique_ptr(new Arr{ref, tmp3.begin(), tmp3.end()}); + rpermutation = Permutation::create(ref, tmp.size(), *rpermute_idxs); + cpermutation = Permutation::create(ref, tmp2.size(), *cpermute_idxs); + rspermutation = ScaledPermutation::create( + ref, + gko::array{ref, scale_factors.begin(), + scale_factors.end()}, + *rpermute_idxs); + cspermutation = ScaledPermutation::create( + ref, + gko::array{ref, scale_factors2.begin(), + scale_factors2.end()}, + *cpermute_idxs); } template @@ -187,6 +213,10 @@ class Dense : public CommonTestFixture { std::unique_ptr dsquare; std::unique_ptr rpermute_idxs; std::unique_ptr cpermute_idxs; + std::unique_ptr rpermutation; + std::unique_ptr cpermutation; + std::unique_ptr rspermutation; + std::unique_ptr cspermutation; std::unique_ptr rgather_idxs; }; @@ -1278,6 +1308,192 @@ TEST_F(Dense, CanAdvancedGatherRowsIntoMixedDenseCrossExecutor) } +TEST_F(Dense, IsGenericPermutable) +{ + using gko::matrix::permute_mode; + set_up_apply_data(); + + for (auto mode : + {permute_mode::none, permute_mode::rows, permute_mode::columns, + permute_mode::symmetric, permute_mode::inverse_rows, + permute_mode::inverse_columns, permute_mode::inverse_symmetric}) { + SCOPED_TRACE(mode); + auto permuted = square->permute(rpermutation, mode); + auto dpermuted = dsquare->permute(rpermutation, mode); + + GKO_ASSERT_MTX_NEAR(permuted, dpermuted, 0); + } +} + + +TEST_F(Dense, IsGenericPermutableRectangular) +{ + using gko::matrix::permute_mode; + set_up_apply_data(); + + auto rpermuted = x->permute(rpermutation, permute_mode::rows); + auto drpermuted = dx->permute(rpermutation, permute_mode::rows); + auto irpermuted = x->permute(rpermutation, permute_mode::inverse_rows); + auto dirpermuted = dx->permute(rpermutation, permute_mode::inverse_rows); + auto cpermuted = x->permute(cpermutation, permute_mode::columns); + auto dcpermuted = dx->permute(cpermutation, permute_mode::columns); + auto icpermuted = x->permute(cpermutation, permute_mode::inverse_columns); + auto dicpermuted = dx->permute(cpermutation, permute_mode::inverse_columns); + + GKO_ASSERT_MTX_NEAR(rpermuted, drpermuted, 0); + GKO_ASSERT_MTX_NEAR(irpermuted, dirpermuted, 0); + GKO_ASSERT_MTX_NEAR(cpermuted, dcpermuted, 0); + GKO_ASSERT_MTX_NEAR(icpermuted, dicpermuted, 0); +} + + +TEST_F(Dense, IsGenericPermutableIntoDenseCrossExecutor) +{ + using gko::matrix::permute_mode; + set_up_apply_data(); + + for (auto mode : + {permute_mode::none, permute_mode::rows, permute_mode::columns, + permute_mode::symmetric, permute_mode::inverse_rows, + permute_mode::inverse_columns, permute_mode::inverse_symmetric}) { + SCOPED_TRACE(mode); + auto host_permuted = square->clone(); + + auto ref_permuted = square->permute(rpermutation, mode); + dsquare->permute(rpermutation, host_permuted, mode); + + GKO_ASSERT_MTX_NEAR(ref_permuted, host_permuted, 0); + } +} + + +TEST_F(Dense, IsNonsymmPermutable) +{ + using gko::matrix::permute_mode; + set_up_apply_data(); + + for (auto invert : {false, true}) { + SCOPED_TRACE(invert); + auto permuted = x->permute(rpermutation, cpermutation, invert); + auto dpermuted = dx->permute(rpermutation, cpermutation, invert); + + GKO_ASSERT_MTX_NEAR(permuted, dpermuted, 0); + } +} + + +TEST_F(Dense, IsNonsymmPermutableIntoDenseCrossExecutor) +{ + using gko::matrix::permute_mode; + set_up_apply_data(); + + for (auto invert : {false, true}) { + SCOPED_TRACE(invert); + auto host_permuted = dx->clone(); + + auto ref_permuted = x->permute(rpermutation, cpermutation, invert); + dx->permute(rpermutation, cpermutation, host_permuted, invert); + + GKO_ASSERT_MTX_NEAR(ref_permuted, host_permuted, 0); + } +} + + +TEST_F(Dense, IsGenericScalePermutable) +{ + using gko::matrix::permute_mode; + set_up_apply_data(); + + for (auto mode : + {permute_mode::none, permute_mode::rows, permute_mode::columns, + permute_mode::symmetric, permute_mode::inverse_rows, + permute_mode::inverse_columns, permute_mode::inverse_symmetric}) { + SCOPED_TRACE(mode); + auto permuted = square->scale_permute(rspermutation, mode); + auto dpermuted = dsquare->scale_permute(rspermutation, mode); + + GKO_ASSERT_MTX_NEAR(permuted, dpermuted, r::value); + } +} + + +TEST_F(Dense, IsGenericScalePermutableRectangular) +{ + using gko::matrix::permute_mode; + set_up_apply_data(); + + auto rpermuted = x->scale_permute(rspermutation, permute_mode::rows); + auto drpermuted = dx->scale_permute(rspermutation, permute_mode::rows); + auto irpermuted = + x->scale_permute(rspermutation, permute_mode::inverse_rows); + auto dirpermuted = + dx->scale_permute(rspermutation, permute_mode::inverse_rows); + auto cpermuted = x->scale_permute(cspermutation, permute_mode::columns); + auto dcpermuted = dx->scale_permute(cspermutation, permute_mode::columns); + auto icpermuted = + x->scale_permute(cspermutation, permute_mode::inverse_columns); + auto dicpermuted = + dx->scale_permute(cspermutation, permute_mode::inverse_columns); + + GKO_ASSERT_MTX_NEAR(rpermuted, drpermuted, r::value); + GKO_ASSERT_MTX_NEAR(irpermuted, dirpermuted, r::value); + GKO_ASSERT_MTX_NEAR(cpermuted, dcpermuted, r::value); + GKO_ASSERT_MTX_NEAR(icpermuted, dicpermuted, r::value); +} + + +TEST_F(Dense, IsGenericScalePermutableIntoDenseCrossExecutor) +{ + using gko::matrix::permute_mode; + set_up_apply_data(); + + for (auto mode : + {permute_mode::none, permute_mode::rows, permute_mode::columns, + permute_mode::symmetric, permute_mode::inverse_rows, + permute_mode::inverse_columns, permute_mode::inverse_symmetric}) { + SCOPED_TRACE(mode); + auto host_permuted = square->clone(); + + auto ref_permuted = square->permute(rpermutation, mode); + dsquare->permute(rpermutation, host_permuted, mode); + + GKO_ASSERT_MTX_NEAR(ref_permuted, host_permuted, r::value); + } +} + + +TEST_F(Dense, IsNonsymmScalePermutable) +{ + using gko::matrix::permute_mode; + set_up_apply_data(); + + for (auto invert : {false, true}) { + SCOPED_TRACE(invert); + auto permuted = x->permute(rpermutation, cpermutation, invert); + auto dpermuted = dx->permute(rpermutation, cpermutation, invert); + + GKO_ASSERT_MTX_NEAR(permuted, dpermuted, r::value); + } +} + + +TEST_F(Dense, IsNonsymmScalePermutableIntoDenseCrossExecutor) +{ + using gko::matrix::permute_mode; + set_up_apply_data(); + + for (auto invert : {false, true}) { + SCOPED_TRACE(invert); + auto host_permuted = dx->clone(); + + auto ref_permuted = x->permute(rpermutation, cpermutation, invert); + dx->permute(rpermutation, cpermutation, host_permuted, invert); + + GKO_ASSERT_MTX_NEAR(ref_permuted, host_permuted, r::value); + } +} + + TEST_F(Dense, IsPermutable) { set_up_apply_data(); diff --git a/test/matrix/permutation_kernels.cpp b/test/matrix/permutation_kernels.cpp new file mode 100644 index 00000000000..037040b8fd4 --- /dev/null +++ b/test/matrix/permutation_kernels.cpp @@ -0,0 +1,73 @@ +/************************************************************* +Copyright (c) 2017-2023, the Ginkgo authors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*************************************************************/ + +#include + + +#include +#include + + +#include + + +#include "core/test/utils.hpp" +#include "test/utils/executor.hpp" + + +class Permutation : public CommonTestFixture { +protected: + using Perm = gko::matrix::Permutation; + + Permutation() : rand_engine(42) + { + std::vector tmp(1000, 0); + std::iota(tmp.begin(), tmp.end(), 0); + std::shuffle(tmp.begin(), tmp.end(), rand_engine); + permutation = Perm::create(ref, tmp.size(), gko::array(ref, tmp.begin(), tmp.end())); + dpermutation = permutation->clone(exec); + } + + std::default_random_engine rand_engine; + + std::unique_ptr permutation; + std::unique_ptr dpermutation; +}; + + +TEST_F(Permutation, InvertIsEquivalentToRef) +{ + auto inv = permutation->invert(); + auto dinv = dpermutation->invert(); + + GKO_ASSERT_MTX_EQ_SPARSITY(inv, dinv); +} diff --git a/test/matrix/scaled_permutation_kernels.cpp b/test/matrix/scaled_permutation_kernels.cpp new file mode 100644 index 00000000000..d85b9735abc --- /dev/null +++ b/test/matrix/scaled_permutation_kernels.cpp @@ -0,0 +1,77 @@ +/************************************************************* +Copyright (c) 2017-2023, the Ginkgo authors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*************************************************************/ + +#include + + +#include +#include + + +#include + + +#include "core/test/utils.hpp" +#include "test/utils/executor.hpp" + + +class ScaledPermutation : public CommonTestFixture { +protected: + using ScaledPerm = gko::matrix::ScaledPermutation; + + ScaledPermutation() : rand_engine(42) + { + std::vector tmp(1000, 0); + std::iota(tmp.begin(), tmp.end(), 0); + std::shuffle(tmp.begin(), tmp.end(), rand_engine); + std::vector scale(tmp.size()); + std::uniform_real_distribution dist(1, 2); + auto gen = [&] { return dist(rand_engine); }; + std::generate(scale.begin(), scale.end(), gen); + permutation = ScaledPerm::create(ref, gko::array(ref, scale.begin(), scale.end()), gko::array(ref, tmp.begin(), tmp.end())); + dpermutation = permutation->clone(exec); + } + + std::default_random_engine rand_engine; + + std::unique_ptr permutation; + std::unique_ptr dpermutation; +}; + + +TEST_F(ScaledPermutation, InvertIsEquivalentToRef) +{ + auto inv = permutation->invert(); + auto dinv = dpermutation->invert(); + + GKO_ASSERT_MTX_NEAR(inv, dinv, r::value); +}