/* ************************************************************************ * Copyright (C) 2018-2025 Advanced Micro Devices, Inc. All rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * * ************************************************************************ */ #pragma once #ifndef TESTING_LOCAL_VECTOR_HPP #define TESTING_LOCAL_VECTOR_HPP #include "utility.hpp" #include #include using namespace rocalution; template void testing_local_vector_bad_args(void) { int safe_size = 100; // Initialize rocALUTION set_device_rocalution(device); init_rocalution(); // LocalVector object LocalVector vec; // SetDataPtr { T* null_ptr = nullptr; ASSERT_DEATH(vec.SetDataPtr(nullptr, "", safe_size), ".*Assertion.*ptr != (NULL|__null)*"); ASSERT_DEATH(vec.SetDataPtr(&null_ptr, "", safe_size), ".*Assertion.*ptr != (NULL|__null)*"); } // LeaveDataPtr { T* vdata = nullptr; allocate_host(safe_size, &vdata); ASSERT_DEATH(vec.LeaveDataPtr(&vdata), ".*Assertion.*ptr == (NULL|__null)*"); free_host(&vdata); } // CopyFromData { T* null_ptr = nullptr; ASSERT_DEATH(vec.CopyFromData(null_ptr), ".*Assertion.*data != (NULL|__null)*"); } // CopyToData { T* null_ptr = nullptr; ASSERT_DEATH(vec.CopyToData(null_ptr), ".*Assertion.*data != (NULL|__null)*"); } // GetContinuousValues { vec.Allocate("", safe_size); T* null_T = nullptr; ASSERT_DEATH(vec.GetContinuousValues(0, safe_size, null_T), ".*Assertion.*values != (NULL|__null)*"); } // ExtractCoarseMapping { int* null_int = nullptr; int* vint = nullptr; allocate_host(safe_size, &vint); ASSERT_DEATH(vec.ExtractCoarseMapping(0, 0, null_int, 0, vint, vint), ".*Assertion.*index != (NULL|__null)*"); ASSERT_DEATH(vec.ExtractCoarseMapping(0, 0, vint, 0, null_int, vint), ".*Assertion.*size != (NULL|__null)*"); ASSERT_DEATH(vec.ExtractCoarseMapping(0, 0, vint, 0, vint, null_int), ".*Assertion.*map != (NULL|__null)*"); free_host(&vint); } // ExtractCoarseBoundary { int* null_int = nullptr; int* vint = nullptr; allocate_host(safe_size, &vint); ASSERT_DEATH(vec.ExtractCoarseBoundary(0, 0, null_int, 0, vint, vint), ".*Assertion.*index != (NULL|__null)*"); ASSERT_DEATH(vec.ExtractCoarseBoundary(0, 0, vint, 0, null_int, vint), ".*Assertion.*size != (NULL|__null)*"); ASSERT_DEATH(vec.ExtractCoarseBoundary(0, 0, vint, 0, vint, null_int), ".*Assertion.*boundary != (NULL|__null)*"); free_host(&vint); } // Stop rocALUTION stop_rocalution(); } template LocalVector getTestVector(int size = 10) { // Create a LocalVector LocalVector vec; vec.Allocate("TestVector", size); // Fill the source vector with some values for(int i = 0; i < size; ++i) { vec[i] = static_cast(i + 1); } return vec; } template void testing_get_interior(const Arguments& argus) { // Get a LocalVector with size from argus LocalVector vec = getTestVector(argus.size); // Call GetInterior LocalVector& interior = vec.GetInterior(); // Validate that the returned reference is the same as the original object EXPECT_EQ(&interior, &vec); // Validate that the size and properties of the vector remain unchanged EXPECT_EQ(interior.GetSize(), vec.GetSize()); for(int i = 0; i < vec.GetSize(); ++i) { EXPECT_EQ(vec[i], interior[i]); } } template void testing_const_get_interior(const Arguments& argus) { // Get a LocalVector with size from argus const LocalVector vec = getTestVector(argus.size); // Call GetInterior const LocalVector& interior = vec.GetInterior(); // Validate that the returned reference is the same as the original object EXPECT_EQ(&interior, &vec); // Validate that the size and properties of the vector remain unchanged EXPECT_EQ(interior.GetSize(), vec.GetSize()); for(int i = 0; i < vec.GetSize(); ++i) { EXPECT_EQ(vec[i], interior[i]); } } template void testing_check(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(argus.size); // Check the vector EXPECT_NO_THROW(vec.Check()); } template void testing_zeros(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(argus.size); vec.Zeros(); // Validate that all elements are set to zero for(int i = 0; i < vec.GetSize(); ++i) { EXPECT_EQ(vec[i], static_cast(0.0)); } } template void testing_ones(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(argus.size); vec.Ones(); // Validate that all elements are set to one for(int i = 0; i < vec.GetSize(); ++i) { EXPECT_EQ(vec[i], static_cast(1.0)); } } template void testing_set_values(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(argus.size); // Set values in the vector T value = static_cast(5.0); vec.SetValues(value); // Validate that all elements are set to the specified value for(int i = 0; i < vec.GetSize(); ++i) { EXPECT_EQ(vec[i], value); } } template void testing_set_random_uniform(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(argus.size); // Set random values in the vector T min = static_cast(0.0); T max = static_cast(1.0); vec.SetRandomUniform(min, max); // Validate that all elements are within the specified range for(int i = 0; i < vec.GetSize(); ++i) { EXPECT_GE(vec[i], min); EXPECT_LE(vec[i], max); } } template void testing_set_random_normal(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(argus.size > 0 ? argus.size : 1000); // Set random values in the vector T mean = static_cast(0.0); T std = static_cast(1.0); vec.SetRandomNormal(mean, std); // Validate that the mean of all elements is close to the specified mean T sum = 0.0; for(int i = 0; i < vec.GetSize(); ++i) { sum += vec[i]; } T calculated_mean = sum / vec.GetSize(); EXPECT_NEAR(calculated_mean, mean, 3 * std); // Validate that the standard deviation of all elements is close to the specified std T sum_sq = 0.0; for(int i = 0; i < vec.GetSize(); ++i) { sum_sq += (vec[i] - calculated_mean) * (vec[i] - calculated_mean); } T calculated_std = std::sqrt(sum_sq / vec.GetSize()); EXPECT_NEAR(calculated_std, std, 3 * std); } template void testing_copy_from(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(argus.size); // Create another LocalVector to copy from LocalVector src_vec = getTestVector(argus.size); // Copy values from the source vector EXPECT_NO_THROW(vec.CopyFrom(src_vec)); // Validate the copied values for(int i = 0; i < vec.GetSize(); ++i) { EXPECT_EQ(vec[i], src_vec[i]); } } template void testing_clone_from(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(argus.size); // Clone the vector LocalVector cloned_vec; EXPECT_NO_THROW(cloned_vec.CloneFrom(vec)); // Validate the cloned values for(int i = 0; i < cloned_vec.GetSize(); ++i) { EXPECT_EQ(cloned_vec[i], vec[i]); } } template void testing_binary(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(argus.size); // Define the filename for the test const std::string filename = get_temp_dir() + "test_vector.bin"; // Write the vector to a binary file EXPECT_NO_THROW(vec.WriteFileBinary(filename)); // Read the vector from the binary file LocalVector read_vec; EXPECT_NO_THROW(read_vec.ReadFileBinary(filename)); // Validate the read values for(int i = 0; i < read_vec.GetSize(); ++i) { EXPECT_EQ(read_vec[i], vec[i]); } // Clean up the temporary file std::remove(filename.c_str()); } template void testing_add_scale(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector v = getTestVector(argus.size); LocalVector x = getTestVector(argus.size); // Define a scaling factor T alpha = static_cast(2.0); // Perform the AddScale operation EXPECT_NO_THROW(v.AddScale(x, alpha)); // Validate the result for(int i = 0; i < v.GetSize(); ++i) { EXPECT_EQ(v[i], static_cast((i + 1) * (1 + alpha))); } } template void testing_scale_add(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector v = getTestVector(argus.size); LocalVector x = getTestVector(argus.size); // Define a scaling factor T alpha = static_cast(2.0); // v = 1 initially v.Ones(); // Perform the v = alpha * v + x EXPECT_NO_THROW(v.ScaleAdd(alpha, x)); // Validate the result for(int i = 0; i < v.GetSize(); ++i) { EXPECT_EQ(v[i], alpha + x[i]); } } template void testing_scale_add_2(const Arguments& argus) { LocalVector v = getTestVector(argus.size); LocalVector x = getTestVector(argus.size); LocalVector y = getTestVector(argus.size); // Fill x and y with test values if(argus.size >= 3) { x[0] = static_cast(1); x[1] = static_cast(2); x[2] = static_cast(3); y[0] = static_cast(4); y[1] = static_cast(5); y[2] = static_cast(6); } // v = 1 initially v.Ones(); // v.ScaleAdd2(alpha, x, beta, y, gamma) T alpha = static_cast(2); T beta = static_cast(3); T gamma = static_cast(3); v.ScaleAdd2(alpha, x, beta, y, gamma); // v[i] = alpha * v[i] + beta * x[i] + gamma * y[i] for(int i = 0; i < v.GetSize(); ++i) { EXPECT_EQ(v[i], alpha + beta * x[i] + gamma * y[i]); } } template void testing_scale(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(argus.size); // Define a scaling factor T alpha = static_cast(2.0); // Perform the Scale operation EXPECT_NO_THROW(vec.Scale(alpha)); // Validate the result for(int i = 0; i < vec.GetSize(); ++i) { EXPECT_EQ(vec[i], static_cast((i + 1) * alpha)); } } template void testing_dot(const Arguments& argus) { // Create two LocalVectors and allocate some size LocalVector vec1 = getTestVector(argus.size); LocalVector vec2 = getTestVector(argus.size); // Perform the Dot product T result = 0.0; EXPECT_NO_THROW(result = vec1.Dot(vec2)); // Validate the result T result2 = 0.0; for(int i = 0; i < vec1.GetSize(); ++i) { result2 += vec1[i] * vec2[i]; } EXPECT_EQ(result, result2); } template void testing_dot_non_conj(const Arguments& argus) { // Create two LocalVectors and allocate some size LocalVector vec1 = getTestVector(argus.size); LocalVector vec2 = getTestVector(argus.size); // Perform the Dot product without conjugation T result = 0.0; EXPECT_NO_THROW(result = vec1.DotNonConj(vec2)); // Validate the result T result2 = 0.0; for(int i = 0; i < vec1.GetSize(); ++i) { result2 += vec1[i] * vec2[i]; } EXPECT_EQ(result, result2); } template void testing_norm(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(argus.size); // Perform the Norm operation T result = 0.0; EXPECT_NO_THROW(result = vec.Norm()); // Validate the result T result2 = 0.0; for(int i = 0; i < vec.GetSize(); ++i) { result2 += vec[i] * vec[i]; } EXPECT_NEAR(result * result, result2, 1e-6 * std::abs(result2)); } template void testing_reduce(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(argus.size); // Perform the Reduce operation T result = 0.0; EXPECT_NO_THROW(result = vec.Reduce()); // Validate the result T result2 = 0.0; for(int i = 0; i < vec.GetSize(); ++i) { result2 += vec[i]; } EXPECT_EQ(result, result2); } template void testing_point_wise_mult(const Arguments& argus) { // Create two LocalVectors and allocate some size LocalVector vec1 = getTestVector(argus.size); LocalVector vec2 = getTestVector(argus.size); // Perform the PointwiseMult operation EXPECT_NO_THROW(vec1.PointWiseMult(vec2)); // Validate the result for(int i = 0; i < vec1.GetSize(); ++i) { EXPECT_EQ(vec1[i], static_cast((i + 1) * (i + 1))); } } template void testing_point_wise_mult_2(const Arguments& argus) { // Create two LocalVectors and allocate some size LocalVector vec1 = getTestVector(argus.size); LocalVector vec2 = getTestVector(argus.size); LocalVector vec3 = getTestVector(argus.size); // Perform the PointwiseMult operation EXPECT_NO_THROW(vec1.PointWiseMult(vec2, vec3)); // Validate the result for(int i = 0; i < vec1.GetSize(); ++i) { EXPECT_EQ(vec1[i], static_cast((i + 1) * (i + 1))); } } template void testing_leave_data_ptr(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(argus.size); // Pointer to data (initialized to NULL) T* data_ptr = nullptr; // Attempt to leave the data pointer EXPECT_NO_THROW(vec.LeaveDataPtr(&data_ptr)); // Ensure the pointer is not NULL after the call EXPECT_NE(data_ptr, nullptr); // Ensure the vector is cleared EXPECT_EQ(vec.GetSize(), 0); } template void testing_sync(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(argus.size); // Perform a synchronization operation EXPECT_NO_THROW(vec.Sync()); // Validate that the vector is still accessible and contains the correct values EXPECT_EQ(vec.GetSize(), argus.size); for(int i = 0; i < vec.GetSize(); ++i) { EXPECT_EQ(vec[i], static_cast(i + 1)); } } template void testing_copy_from_data(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(argus.size); // Pointer to data T data_ptr[5] = {0, 2, 4, 8, 16}; // Attempt to copy from the data pointer EXPECT_NO_THROW(vec.CopyFromData(data_ptr)); EXPECT_EQ(vec.GetSize(), argus.size); if(argus.size >= 5) { EXPECT_EQ(vec[0], static_cast(0.0)); EXPECT_EQ(vec[1], static_cast(2.0)); EXPECT_EQ(vec[2], static_cast(4.0)); EXPECT_EQ(vec[3], static_cast(8.0)); EXPECT_EQ(vec[4], static_cast(16.0)); } } template void testing_copy_to_host_data(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(argus.size); // Pointer to host data std::vector host_data(argus.size); // Attempt to copy to the host data pointer EXPECT_NO_THROW(vec.CopyToHostData(host_data.data())); for(int i = 0; i < argus.size; ++i) { EXPECT_EQ(host_data[i], static_cast(i + 1)); } } template void testing_restriction() { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(5); // Create a mapping vector (map fine indices to coarse indices) LocalVector map; map.Allocate("MappingVector", 5); map[0] = 0; map[1] = 0; map[2] = 1; map[3] = 1; map[4] = 2; // Create a LocalVector to store the restriction LocalVector restricted_vec = getTestVector(5); // Perform the Restriction operation EXPECT_NO_THROW(restricted_vec.Restriction(vec, map)); // Validate the result size (should match the number of unique coarse indices, here 3) EXPECT_EQ(restricted_vec.GetSize(), 5); // Optionally, check the restricted values EXPECT_EQ(restricted_vec[0], static_cast(vec[0] + vec[1])); // sum of fine indices 0 and 1 EXPECT_EQ(restricted_vec[1], static_cast(vec[2] + vec[3])); // sum of fine indices 2 and 3 EXPECT_EQ(restricted_vec[2], static_cast(vec[4])); // fine index 4 } template void testing_copy_from_with_offsets(const Arguments& argus) { // Create a source LocalVector and allocate some size LocalVector src_vec = getTestVector(argus.size); // Create a destination LocalVector and allocate some size LocalVector dst_vec; dst_vec.Allocate("DstVector", argus.size); // Fill destination with zeros dst_vec.Zeros(); // Copy 3 elements from src_vec[1..3] to dst_vec[2..4] int64_t src_offset = 1; int64_t dst_offset = 2; int64_t size = 3; if(argus.size >= 5) { EXPECT_NO_THROW(dst_vec.CopyFrom(src_vec, src_offset, dst_offset, size)); // Validate the copied values // dst_vec should now be [0, 0, 2, 3, 4] EXPECT_EQ(dst_vec[0], static_cast(0)); EXPECT_EQ(dst_vec[1], static_cast(0)); EXPECT_EQ(dst_vec[2], static_cast(2)); EXPECT_EQ(dst_vec[3], static_cast(3)); EXPECT_EQ(dst_vec[4], static_cast(4)); } } template void testing_set_data_ptr_null(const Arguments& argus) { // Create a LocalVector LocalVector vec; // Pointer to data (initialized to NULL) T* data_ptr = NULL; // Attempt to set the data pointer EXPECT_NO_THROW(vec.SetDataPtr(&data_ptr, "TestVector", 0)); // Ensure the pointer is still NULL after the call EXPECT_EQ(data_ptr, nullptr); // Ensure the vector is cleared EXPECT_EQ(vec.GetSize(), 0); } template void testing_info(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec; vec.Allocate("TestVector", argus.size); // Redirect standard output to a stringstream to capture the Info output std::stringstream output_stream; std::streambuf* original_cout_buffer = std::cout.rdbuf(); std::cout.rdbuf(output_stream.rdbuf()); // Call the Info method vec.Info(); // Restore the original standard output buffer std::cout.rdbuf(original_cout_buffer); // Get the captured output std::string output = output_stream.str(); // Validate the output contains expected information EXPECT_NE(output.find("name=TestVector"), std::string::npos); // Check vector name EXPECT_NE(output.find("size=" + std::to_string(argus.size)), std::string::npos); // Check vector size EXPECT_NE(output.find("prec=" + std::to_string(sizeof(T) * 8) + "bit"), std::string::npos); // Check data type } template void testing_sort() { // Create a LocalVector and allocate some size LocalVector vec; vec.Allocate("TestVector", 5); LocalVector sorted_vec; sorted_vec.Allocate("TestVector", 5); // Fill the vector with unsorted values vec[0] = static_cast(3.0); vec[1] = static_cast(1.0); vec[2] = static_cast(5.0); vec[3] = static_cast(2.0); vec[4] = static_cast(4.0); // Call the Sort method EXPECT_NO_THROW(vec.Sort(&sorted_vec, nullptr)); // Validate that the vector is sorted in ascending order EXPECT_EQ(sorted_vec[0], static_cast(1.0)); EXPECT_EQ(sorted_vec[1], static_cast(2.0)); EXPECT_EQ(sorted_vec[2], static_cast(3.0)); EXPECT_EQ(sorted_vec[3], static_cast(4.0)); EXPECT_EQ(sorted_vec[4], static_cast(5.0)); } template void testing_permute_backward(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(argus.size); // Create a permutation vector LocalVector permutation; permutation.Allocate("PermutationVector", argus.size); if(argus.size >= 5) { permutation[0] = 4; // Move element at index 4 to index 0 permutation[1] = 2; // Move element at index 2 to index 1 permutation[2] = 0; // Move element at index 0 to index 2 permutation[3] = 3; // Keep element at index 3 in place permutation[4] = 1; // Move element at index 1 to index 4 // Call the PermuteBackward method EXPECT_NO_THROW(vec.PermuteBackward(permutation)); // Validate the permuted vector EXPECT_EQ(vec[0], static_cast(5.0)); // Element at index 4 EXPECT_EQ(vec[1], static_cast(3.0)); // Element at index 2 EXPECT_EQ(vec[2], static_cast(1.0)); // Element at index 0 EXPECT_EQ(vec[3], static_cast(4.0)); // Element at index 3 EXPECT_EQ(vec[4], static_cast(2.0)); // Element at index 1 } } template void testing_inclusive_sum(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector input_vec; input_vec.Allocate("InputVector", argus.size); // Fill the input vector with values for(int i = 0; i < argus.size; ++i) { input_vec[i] = static_cast(i + 1); } // Create a LocalVector to store the result LocalVector result_vec; result_vec.Allocate("ResultVector", argus.size); // Call the InclusiveSum method EXPECT_NO_THROW(result_vec.InclusiveSum(input_vec)); // Validate the result T sum = 0; for(int i = 0; i < argus.size; ++i) { sum += static_cast(i + 1); EXPECT_EQ(result_vec[i], sum); } } template void testing_power(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(argus.size); // Apply the Power method with power = 2.0 EXPECT_NO_THROW(vec.Power(2.0)); // Validate the results for(int i = 0; i < argus.size; ++i) { EXPECT_EQ(vec[i], static_cast((i + 1) * (i + 1))); // Squared values } // Apply the Power method with power = 0.5 (square root) EXPECT_NO_THROW(vec.Power(0.5)); // Validate the results for(int i = 0; i < argus.size; ++i) { EXPECT_EQ(vec[i], static_cast(i + 1)); // Original values restored } } template void testing_scale_add_scale(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(argus.size); // Create another LocalVector for the operation LocalVector x; x.Allocate("XVector", argus.size); // Fill the second vector with values for(int i = 0; i < argus.size; ++i) { x[i] = static_cast(argus.size - i); } // Define scaling factors T alpha = 2.0f; T beta = 3.0f; // Perform the ScaleAddScale operation EXPECT_NO_THROW(vec.ScaleAddScale(alpha, x, beta)); // Validate the result for(int i = 0; i < argus.size; ++i) { EXPECT_EQ(vec[i], static_cast(alpha * (i + 1) + beta * (argus.size - i))); } } template void testing_operator_index_const(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(argus.size); // Create a const reference to the vector const LocalVector& const_vec = vec; // Validate access to elements using the const operator[] for(int i = 0; i < argus.size; ++i) { EXPECT_EQ(const_vec[i], static_cast(i + 1)); } } template void testing_read_file_ascii(const Arguments& argus) { // Create a temporary ASCII file with test data std::string filename = get_temp_dir() + "test_vector.txt"; std::ofstream file(filename); ASSERT_TRUE(file.is_open()); for(int i = 0; i < argus.size; ++i) { file << static_cast(i + 1) << "\n"; } file.close(); // Create a LocalVector to read the data into LocalVector vec; // Call the ReadFileASCII method EXPECT_NO_THROW(vec.ReadFileASCII(filename)); // Validate the vector size EXPECT_EQ(vec.GetSize(), argus.size); // Validate the values in the vector for(int i = 0; i < argus.size; ++i) { EXPECT_EQ(vec[i], static_cast(i + 1)); } // Clean up the temporary file std::remove(filename.c_str()); } template void testing_copy_from_async(const Arguments& argus) { // Create a source LocalVector and allocate some size LocalVector src_vec = getTestVector(argus.size); // Create a destination LocalVector LocalVector dest_vec; // Perform the asynchronous copy EXPECT_NO_THROW(dest_vec.CopyFromAsync(src_vec)); // Synchronize to ensure the copy is complete EXPECT_NO_THROW(_rocalution_sync()); // Validate the copied values EXPECT_EQ(dest_vec.GetSize(), src_vec.GetSize()); for(int i = 0; i < argus.size; ++i) { EXPECT_EQ(dest_vec[i], static_cast(i + 1)); } } template void testing_move_to_accelerator_async(const Arguments& argus) { // Create a source LocalVector and allocate some size LocalVector vec = getTestVector(argus.size); // Perform the asynchronous move to the accelerator EXPECT_NO_THROW(vec.MoveToAcceleratorAsync()); // Synchronize to ensure the move is complete EXPECT_NO_THROW(_rocalution_sync()); // Validate that the vector is still accessible and contains the correct values EXPECT_EQ(vec.GetSize(), argus.size); for(int i = 0; i < argus.size; ++i) { EXPECT_EQ(vec[i], static_cast(i + 1)); } } template void testing_copy_from_host_data(const Arguments& argus) { // clang-format off // Create a host array with test data std::vector host_data(argus.size); for(int i = 0; i < argus.size; ++i) { host_data[i] = static_cast(i + 1); } // clang-format on // Create a LocalVector and allocate the same size LocalVector vec; vec.Allocate("TestVector", argus.size); // Copy data from the host array to the LocalVector EXPECT_NO_THROW(vec.CopyFromHostData(host_data.data())); // Validate the vector size EXPECT_EQ(vec.GetSize(), argus.size); // Validate the copied values for(int i = 0; i < argus.size; ++i) { EXPECT_EQ(vec[i], static_cast(i + 1)); } } template void testing_copy_to_data(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(argus.size); // Create a host array to store the copied data std::vector host_data(argus.size, static_cast(0.0)); // Copy data from the LocalVector to the host array EXPECT_NO_THROW(vec.CopyToData(host_data.data())); // Validate the copied values for(int i = 0; i < argus.size; ++i) { EXPECT_EQ(host_data[i], static_cast(i + 1)); } } // Helper function to read the contents of a file into a string std::string ReadFileContents(const std::string& filename) { std::ifstream file(filename); std::stringstream buffer; buffer << file.rdbuf(); return buffer.str(); } template void testing_write_file_ascii() { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(5); // Define the filename for the test const std::string filename = get_temp_dir() + "test_vector.txt"; // Write the vector to the file EXPECT_NO_THROW(vec.WriteFileASCII(filename)); // Read the contents of the file std::string file_contents = ReadFileContents(filename); // Define the expected output std::string expected_output = "1.000000e+00\n2.000000e+00\n3.000000e+00\n4.000000e+00\n5.000000e+00\n"; // Validate the file contents EXPECT_EQ(file_contents, expected_output); // Clean up the temporary file std::remove(filename.c_str()); } template void testing_scale_add_scale_with_offsets() { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(10); // Create another LocalVector for the operation LocalVector x; x.Allocate("XVector", 10); // Fill the second vector with values for(int i = 0; i < 10; ++i) { x[i] = static_cast(10 - i); // Values: 10.0, 9.0, ..., 1.0 } // Define scaling factors and offsets T alpha = 2.0f; T beta = 3.0f; int64_t src_offset = 2; // Start from index 2 in x int64_t dst_offset = 4; // Start from index 4 in vec int64_t size = 3; // Operate on 3 elements // Perform the ScaleAddScale operation EXPECT_NO_THROW(vec.ScaleAddScale(alpha, x, beta, src_offset, dst_offset, size)); // Validate the results EXPECT_EQ(vec[4], static_cast(alpha * 5.0 + beta * 8.0)); // 2 * 5 + 3 * 8 = 34 EXPECT_EQ(vec[5], static_cast(alpha * 6.0 + beta * 7.0)); // 2 * 6 + 3 * 7 = 33 EXPECT_EQ(vec[6], static_cast(alpha * 7.0 + beta * 6.0)); // 2 * 7 + 3 * 6 = 32 // Ensure other elements remain unchanged EXPECT_EQ(vec[0], static_cast(1.0)); EXPECT_EQ(vec[1], static_cast(2.0)); EXPECT_EQ(vec[2], static_cast(3.0)); EXPECT_EQ(vec[3], static_cast(4.0)); EXPECT_EQ(vec[7], static_cast(8.0)); EXPECT_EQ(vec[8], static_cast(9.0)); EXPECT_EQ(vec[9], static_cast(10.0)); } template void testing_inclusive_sum_void(const Arguments& argus) { LocalVector vec = getTestVector(argus.size); T expected_sum = 0; for(int i = 0; i < argus.size; ++i) { expected_sum += static_cast(i + 1); } EXPECT_EQ(vec.InclusiveSum(), expected_sum); } template void testing_inclusive_sum_with_input(const Arguments& argus) { LocalVector input_vec = getTestVector(argus.size); LocalVector result_vec; result_vec.Allocate("ResultVector", argus.size); EXPECT_NO_THROW(result_vec.InclusiveSum(input_vec)); T sum = 0; for(int i = 0; i < argus.size; ++i) { sum += static_cast(i + 1); EXPECT_EQ(result_vec[i], sum); } } template void testing_exclusive_sum_void(const Arguments& argus) { LocalVector vec = getTestVector(argus.size); T expected_sum = 0; for(int i = 0; i < argus.size - 1; ++i) { expected_sum += static_cast(i + 1); } EXPECT_EQ(vec.ExclusiveSum(), expected_sum); } template void testing_exclusive_sum_with_input(const Arguments& argus) { LocalVector input_vec = getTestVector(argus.size); LocalVector result_vec; result_vec.Allocate("ResultVector", argus.size); EXPECT_NO_THROW(result_vec.ExclusiveSum(input_vec)); T sum = 0; for(int i = 0; i < argus.size; ++i) { EXPECT_EQ(result_vec[i], sum); sum += static_cast(i + 1); } } template void testing_asum(const Arguments& argus) { LocalVector vec = getTestVector(argus.size); T expected_sum = 0; for(int i = 0; i < argus.size; ++i) { expected_sum += std::abs(static_cast(i + 1)); } EXPECT_EQ(vec.Asum(), expected_sum); } template void testing_amax(const Arguments& argus) { LocalVector vec = getTestVector(argus.size); T max_value = 0.0; int max_index = vec.Amax(max_value); EXPECT_EQ(max_index, argus.size - 1); EXPECT_EQ(max_value, static_cast(argus.size)); } // Helper function to read binary file contents into a vector template std::vector ReadBinaryFile(const std::string& filename, size_t& size_out) { std::ifstream file(filename, std::ios::binary); // Read the size of the vector size_t size = 0; file.read(reinterpret_cast(&size), sizeof(size_t)); size_out = size; // Read the vector data std::vector data(size); file.read(reinterpret_cast(data.data()), size * sizeof(ValueType)); file.close(); return data; } template void testing_prolongation(const Arguments& argus) { // Create a coarse-level LocalVector and allocate some size int coarse_size = argus.size > 2 ? argus.size / 2 : 2; int fine_size = coarse_size * 2; LocalVector vec_coarse; vec_coarse.Allocate("CoarseVector", coarse_size); // Fill the coarse-level vector with values for(int i = 0; i < coarse_size; ++i) { vec_coarse[i] = static_cast(i + 1); } // Create a mapping vector LocalVector map; map.Allocate("MappingVector", fine_size); // Define the mapping (fine indices map to coarse indices) for(int i = 0; i < fine_size; ++i) { map[i] = i / 2; } // Create a fine-level LocalVector to store the result LocalVector vec_fine; vec_fine.Allocate("FineVector", fine_size); // Perform the prolongation operation EXPECT_NO_THROW(vec_fine.Prolongation(vec_coarse, map)); // Validate the prolonged values for(int i = 0; i < fine_size; ++i) { EXPECT_EQ(vec_fine[i], vec_coarse[map[i]]); } } template void testing_get_index_values(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(argus.size); // Create an index vector int num_indices = std::min(3, argus.size); LocalVector index; index.Allocate("IndexVector", num_indices); for(int i = 0; i < num_indices; ++i) { index[i] = i * 2; } // Create a LocalVector to store the values LocalVector values; values.Allocate("ValuesVector", num_indices); // Call the GetIndexValues method EXPECT_NO_THROW(vec.GetIndexValues(index, &values)); // Validate the retrieved values for(int i = 0; i < num_indices; ++i) { EXPECT_EQ(values[i], static_cast(index[i] + 1)); } } template void testing_set_index_values(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec; vec.Allocate("TestVector", argus.size); // Create an index vector int num_indices = std::min(3, argus.size); LocalVector index; index.Allocate("IndexVector", num_indices); for(int i = 0; i < num_indices; ++i) { index[i] = i * 2; } // Create a LocalVector to store the values LocalVector values; values.Allocate("ValuesVector", num_indices); for(int i = 0; i < num_indices; ++i) { values[i] = static_cast(100.0 * (i + 1)); } // Call the SetIndexValues method EXPECT_NO_THROW(vec.SetIndexValues(index, values)); // Validate the set values for(int i = 0; i < num_indices; ++i) { EXPECT_EQ(vec[index[i]], static_cast(100.0 * (i + 1))); } } template void testing_add_index_values(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec; vec.Allocate("TestVector", argus.size); // Fill the vector with initial values for(int i = 0; i < argus.size; ++i) { vec[i] = static_cast(10.0 * (i + 1)); } // Create an index vector int num_indices = std::min(3, argus.size); LocalVector index; index.Allocate("IndexVector", num_indices); for(int i = 0; i < num_indices; ++i) { index[i] = i * 2; } // Create a LocalVector to store the values to be added LocalVector values; values.Allocate("ValuesVector", num_indices); for(int i = 0; i < num_indices; ++i) { values[i] = static_cast(5.0 * (i + 1)); } // Call the AddIndexValues method EXPECT_NO_THROW(vec.AddIndexValues(index, values)); // Validate the updated values for(int i = 0; i < num_indices; ++i) { EXPECT_EQ(vec[index[i]], static_cast(10.0 * (index[i] + 1) + 5.0 * (i + 1))); } } template void testing_get_continuous_values(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(argus.size); int num_values = std::min(3, argus.size - 1); if(num_values > 0) { // Create an array to store the continuous values std::vector values(num_values); // Call the GetContinuousValues method EXPECT_NO_THROW(vec.GetContinuousValues(1, 1 + num_values, values.data())); // Validate the retrieved values for(int i = 0; i < num_values; ++i) { EXPECT_EQ(values[i], static_cast(i + 2)); } } } template void testing_set_continuous_values(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec; vec.Allocate("TestVector", argus.size); int num_values = std::min(3, argus.size - 1); if(num_values > 0) { // Create an array of values to set std::vector values(num_values); for(int i = 0; i < num_values; ++i) { values[i] = static_cast(100.0 * (i + 1)); } // Call the SetContinuousValues method EXPECT_NO_THROW(vec.SetContinuousValues(1, 1 + num_values, values.data())); // Validate the set values for(int i = 0; i < num_values; ++i) { EXPECT_EQ(vec[1 + i], static_cast(100.0 * (i + 1))); } } } template void testing_extract_coarse_mapping() { // Create a LocalVector and allocate some size LocalVector vec; vec.Allocate("TestVector", 5); // Create an index vector int index[3] = {0, 2, 4}; int size = 0; int map[3]; // Call the ExtractCoarseMapping method EXPECT_NO_THROW(vec.ExtractCoarseMapping(0, 5, index, 3, &size, map)); // Validate the extracted mapping EXPECT_EQ(size, 5); EXPECT_EQ(map[0], 0); } template void testing_move_to_host_async(const Arguments& argus) { // Create a LocalVector and allocate some size LocalVector vec = getTestVector(argus.size); // Move the vector to the accelerator EXPECT_NO_THROW(vec.MoveToAccelerator()); // Perform the asynchronous move to the host EXPECT_NO_THROW(vec.MoveToHostAsync()); // Synchronize to ensure the move is complete EXPECT_NO_THROW(_rocalution_sync()); // Validate that the vector is still accessible and contains the correct values EXPECT_EQ(vec.GetSize(), argus.size); for(int i = 0; i < argus.size; ++i) { EXPECT_EQ(vec[i], static_cast(i + 1)); } } #endif // TESTING_LOCAL_VECTOR_HPP