Files
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

1434 lines
40 KiB
C++

/* ************************************************************************
* 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 <gtest/gtest.h>
#include <rocalution/rocalution.hpp>
using namespace rocalution;
template <typename T>
void testing_local_vector_bad_args(void)
{
int safe_size = 100;
// Initialize rocALUTION
set_device_rocalution(device);
init_rocalution();
// LocalVector object
LocalVector<T> 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 <typename T>
LocalVector<T> getTestVector(int size = 10)
{
// Create a LocalVector
LocalVector<T> vec;
vec.Allocate("TestVector", size);
// Fill the source vector with some values
for(int i = 0; i < size; ++i)
{
vec[i] = static_cast<T>(i + 1);
}
return vec;
}
template <typename T>
void testing_get_interior(const Arguments& argus)
{
// Get a LocalVector with size from argus
LocalVector<T> vec = getTestVector<T>(argus.size);
// Call GetInterior
LocalVector<T>& 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 <typename T>
void testing_const_get_interior(const Arguments& argus)
{
// Get a LocalVector with size from argus
const LocalVector<T> vec = getTestVector<T>(argus.size);
// Call GetInterior
const LocalVector<T>& 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 <typename T>
void testing_check(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(argus.size);
// Check the vector
EXPECT_NO_THROW(vec.Check());
}
template <typename T>
void testing_zeros(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(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<T>(0.0));
}
}
template <typename T>
void testing_ones(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(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<T>(1.0));
}
}
template <typename T>
void testing_set_values(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(argus.size);
// Set values in the vector
T value = static_cast<T>(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 <typename T>
void testing_set_random_uniform(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(argus.size);
// Set random values in the vector
T min = static_cast<T>(0.0);
T max = static_cast<T>(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 <typename T>
void testing_set_random_normal(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(argus.size > 0 ? argus.size : 1000);
// Set random values in the vector
T mean = static_cast<T>(0.0);
T std = static_cast<T>(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 <typename T>
void testing_copy_from(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(argus.size);
// Create another LocalVector to copy from
LocalVector<T> src_vec = getTestVector<T>(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 <typename T>
void testing_clone_from(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(argus.size);
// Clone the vector
LocalVector<T> 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 <typename T>
void testing_binary(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(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<T> 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 <typename T>
void testing_add_scale(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> v = getTestVector<T>(argus.size);
LocalVector<T> x = getTestVector<T>(argus.size);
// Define a scaling factor
T alpha = static_cast<T>(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<T>((i + 1) * (1 + alpha)));
}
}
template <typename T>
void testing_scale_add(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> v = getTestVector<T>(argus.size);
LocalVector<T> x = getTestVector<T>(argus.size);
// Define a scaling factor
T alpha = static_cast<T>(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 <typename T>
void testing_scale_add_2(const Arguments& argus)
{
LocalVector<T> v = getTestVector<T>(argus.size);
LocalVector<T> x = getTestVector<T>(argus.size);
LocalVector<T> y = getTestVector<T>(argus.size);
// Fill x and y with test values
if(argus.size >= 3)
{
x[0] = static_cast<T>(1);
x[1] = static_cast<T>(2);
x[2] = static_cast<T>(3);
y[0] = static_cast<T>(4);
y[1] = static_cast<T>(5);
y[2] = static_cast<T>(6);
}
// v = 1 initially
v.Ones();
// v.ScaleAdd2(alpha, x, beta, y, gamma)
T alpha = static_cast<T>(2);
T beta = static_cast<T>(3);
T gamma = static_cast<T>(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 <typename T>
void testing_scale(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(argus.size);
// Define a scaling factor
T alpha = static_cast<T>(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<T>((i + 1) * alpha));
}
}
template <typename T>
void testing_dot(const Arguments& argus)
{
// Create two LocalVectors and allocate some size
LocalVector<T> vec1 = getTestVector<T>(argus.size);
LocalVector<T> vec2 = getTestVector<T>(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 <typename T>
void testing_dot_non_conj(const Arguments& argus)
{
// Create two LocalVectors and allocate some size
LocalVector<T> vec1 = getTestVector<T>(argus.size);
LocalVector<T> vec2 = getTestVector<T>(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 <typename T>
void testing_norm(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(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 <typename T>
void testing_reduce(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(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 <typename T>
void testing_point_wise_mult(const Arguments& argus)
{
// Create two LocalVectors and allocate some size
LocalVector<T> vec1 = getTestVector<T>(argus.size);
LocalVector<T> vec2 = getTestVector<T>(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<T>((i + 1) * (i + 1)));
}
}
template <typename T>
void testing_point_wise_mult_2(const Arguments& argus)
{
// Create two LocalVectors and allocate some size
LocalVector<T> vec1 = getTestVector<T>(argus.size);
LocalVector<T> vec2 = getTestVector<T>(argus.size);
LocalVector<T> vec3 = getTestVector<T>(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<T>((i + 1) * (i + 1)));
}
}
template <typename T>
void testing_leave_data_ptr(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(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 <typename T>
void testing_sync(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(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<T>(i + 1));
}
}
template <typename T>
void testing_copy_from_data(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(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<T>(0.0));
EXPECT_EQ(vec[1], static_cast<T>(2.0));
EXPECT_EQ(vec[2], static_cast<T>(4.0));
EXPECT_EQ(vec[3], static_cast<T>(8.0));
EXPECT_EQ(vec[4], static_cast<T>(16.0));
}
}
template <typename T>
void testing_copy_to_host_data(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(argus.size);
// Pointer to host data
std::vector<T> 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<T>(i + 1));
}
}
template <typename T>
void testing_restriction()
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(5);
// Create a mapping vector (map fine indices to coarse indices)
LocalVector<int> 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<T> restricted_vec = getTestVector<T>(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<T>(vec[0] + vec[1])); // sum of fine indices 0 and 1
EXPECT_EQ(restricted_vec[1], static_cast<T>(vec[2] + vec[3])); // sum of fine indices 2 and 3
EXPECT_EQ(restricted_vec[2], static_cast<T>(vec[4])); // fine index 4
}
template <typename T>
void testing_copy_from_with_offsets(const Arguments& argus)
{
// Create a source LocalVector and allocate some size
LocalVector<T> src_vec = getTestVector<T>(argus.size);
// Create a destination LocalVector and allocate some size
LocalVector<T> 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<T>(0));
EXPECT_EQ(dst_vec[1], static_cast<T>(0));
EXPECT_EQ(dst_vec[2], static_cast<T>(2));
EXPECT_EQ(dst_vec[3], static_cast<T>(3));
EXPECT_EQ(dst_vec[4], static_cast<T>(4));
}
}
template <typename T>
void testing_set_data_ptr_null(const Arguments& argus)
{
// Create a LocalVector
LocalVector<T> 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 <typename T>
void testing_info(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> 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 <typename T>
void testing_sort()
{
// Create a LocalVector and allocate some size
LocalVector<T> vec;
vec.Allocate("TestVector", 5);
LocalVector<T> sorted_vec;
sorted_vec.Allocate("TestVector", 5);
// Fill the vector with unsorted values
vec[0] = static_cast<T>(3.0);
vec[1] = static_cast<T>(1.0);
vec[2] = static_cast<T>(5.0);
vec[3] = static_cast<T>(2.0);
vec[4] = static_cast<T>(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<T>(1.0));
EXPECT_EQ(sorted_vec[1], static_cast<T>(2.0));
EXPECT_EQ(sorted_vec[2], static_cast<T>(3.0));
EXPECT_EQ(sorted_vec[3], static_cast<T>(4.0));
EXPECT_EQ(sorted_vec[4], static_cast<T>(5.0));
}
template <typename T>
void testing_permute_backward(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(argus.size);
// Create a permutation vector
LocalVector<int> 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<T>(5.0)); // Element at index 4
EXPECT_EQ(vec[1], static_cast<T>(3.0)); // Element at index 2
EXPECT_EQ(vec[2], static_cast<T>(1.0)); // Element at index 0
EXPECT_EQ(vec[3], static_cast<T>(4.0)); // Element at index 3
EXPECT_EQ(vec[4], static_cast<T>(2.0)); // Element at index 1
}
}
template <typename T>
void testing_inclusive_sum(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> 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<T>(i + 1);
}
// Create a LocalVector to store the result
LocalVector<T> 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<T>(i + 1);
EXPECT_EQ(result_vec[i], sum);
}
}
template <typename T>
void testing_power(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(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<T>((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<T>(i + 1)); // Original values restored
}
}
template <typename T>
void testing_scale_add_scale(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(argus.size);
// Create another LocalVector for the operation
LocalVector<T> x;
x.Allocate("XVector", argus.size);
// Fill the second vector with values
for(int i = 0; i < argus.size; ++i)
{
x[i] = static_cast<T>(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<T>(alpha * (i + 1) + beta * (argus.size - i)));
}
}
template <typename T>
void testing_operator_index_const(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(argus.size);
// Create a const reference to the vector
const LocalVector<T>& 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<T>(i + 1));
}
}
template <typename T>
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<double>(i + 1) << "\n";
}
file.close();
// Create a LocalVector to read the data into
LocalVector<T> 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<T>(i + 1));
}
// Clean up the temporary file
std::remove(filename.c_str());
}
template <typename T>
void testing_copy_from_async(const Arguments& argus)
{
// Create a source LocalVector and allocate some size
LocalVector<T> src_vec = getTestVector<T>(argus.size);
// Create a destination LocalVector
LocalVector<T> 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<T>(i + 1));
}
}
template <typename T>
void testing_move_to_accelerator_async(const Arguments& argus)
{
// Create a source LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(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<T>(i + 1));
}
}
template <typename T>
void testing_copy_from_host_data(const Arguments& argus)
{
// clang-format off
// Create a host array with test data
std::vector<T> host_data(argus.size);
for(int i = 0; i < argus.size; ++i)
{
host_data[i] = static_cast<T>(i + 1);
}
// clang-format on
// Create a LocalVector and allocate the same size
LocalVector<T> 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<T>(i + 1));
}
}
template <typename T>
void testing_copy_to_data(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(argus.size);
// Create a host array to store the copied data
std::vector<T> host_data(argus.size, static_cast<T>(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<T>(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 <typename T>
void testing_write_file_ascii()
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(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 <typename T>
void testing_scale_add_scale_with_offsets()
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(10);
// Create another LocalVector for the operation
LocalVector<T> x;
x.Allocate("XVector", 10);
// Fill the second vector with values
for(int i = 0; i < 10; ++i)
{
x[i] = static_cast<T>(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<T>(alpha * 5.0 + beta * 8.0)); // 2 * 5 + 3 * 8 = 34
EXPECT_EQ(vec[5], static_cast<T>(alpha * 6.0 + beta * 7.0)); // 2 * 6 + 3 * 7 = 33
EXPECT_EQ(vec[6], static_cast<T>(alpha * 7.0 + beta * 6.0)); // 2 * 7 + 3 * 6 = 32
// Ensure other elements remain unchanged
EXPECT_EQ(vec[0], static_cast<T>(1.0));
EXPECT_EQ(vec[1], static_cast<T>(2.0));
EXPECT_EQ(vec[2], static_cast<T>(3.0));
EXPECT_EQ(vec[3], static_cast<T>(4.0));
EXPECT_EQ(vec[7], static_cast<T>(8.0));
EXPECT_EQ(vec[8], static_cast<T>(9.0));
EXPECT_EQ(vec[9], static_cast<T>(10.0));
}
template <typename T>
void testing_inclusive_sum_void(const Arguments& argus)
{
LocalVector<T> vec = getTestVector<T>(argus.size);
T expected_sum = 0;
for(int i = 0; i < argus.size; ++i)
{
expected_sum += static_cast<T>(i + 1);
}
EXPECT_EQ(vec.InclusiveSum(), expected_sum);
}
template <typename T>
void testing_inclusive_sum_with_input(const Arguments& argus)
{
LocalVector<T> input_vec = getTestVector<T>(argus.size);
LocalVector<T> 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<T>(i + 1);
EXPECT_EQ(result_vec[i], sum);
}
}
template <typename T>
void testing_exclusive_sum_void(const Arguments& argus)
{
LocalVector<T> vec = getTestVector<T>(argus.size);
T expected_sum = 0;
for(int i = 0; i < argus.size - 1; ++i)
{
expected_sum += static_cast<T>(i + 1);
}
EXPECT_EQ(vec.ExclusiveSum(), expected_sum);
}
template <typename T>
void testing_exclusive_sum_with_input(const Arguments& argus)
{
LocalVector<T> input_vec = getTestVector<T>(argus.size);
LocalVector<T> 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<T>(i + 1);
}
}
template <typename T>
void testing_asum(const Arguments& argus)
{
LocalVector<T> vec = getTestVector<T>(argus.size);
T expected_sum = 0;
for(int i = 0; i < argus.size; ++i)
{
expected_sum += std::abs(static_cast<T>(i + 1));
}
EXPECT_EQ(vec.Asum(), expected_sum);
}
template <typename T>
void testing_amax(const Arguments& argus)
{
LocalVector<T> vec = getTestVector<T>(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<T>(argus.size));
}
// Helper function to read binary file contents into a vector
template <typename ValueType>
std::vector<ValueType> 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<char*>(&size), sizeof(size_t));
size_out = size;
// Read the vector data
std::vector<ValueType> data(size);
file.read(reinterpret_cast<char*>(data.data()), size * sizeof(ValueType));
file.close();
return data;
}
template <typename T>
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<T> 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<T>(i + 1);
}
// Create a mapping vector
LocalVector<int> 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<T> 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 <typename T>
void testing_get_index_values(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(argus.size);
// Create an index vector
int num_indices = std::min(3, argus.size);
LocalVector<int> 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<T> 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<T>(index[i] + 1));
}
}
template <typename T>
void testing_set_index_values(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> vec;
vec.Allocate("TestVector", argus.size);
// Create an index vector
int num_indices = std::min(3, argus.size);
LocalVector<int> 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<T> values;
values.Allocate("ValuesVector", num_indices);
for(int i = 0; i < num_indices; ++i)
{
values[i] = static_cast<T>(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<T>(100.0 * (i + 1)));
}
}
template <typename T>
void testing_add_index_values(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> vec;
vec.Allocate("TestVector", argus.size);
// Fill the vector with initial values
for(int i = 0; i < argus.size; ++i)
{
vec[i] = static_cast<T>(10.0 * (i + 1));
}
// Create an index vector
int num_indices = std::min(3, argus.size);
LocalVector<int> 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<T> values;
values.Allocate("ValuesVector", num_indices);
for(int i = 0; i < num_indices; ++i)
{
values[i] = static_cast<T>(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<T>(10.0 * (index[i] + 1) + 5.0 * (i + 1)));
}
}
template <typename T>
void testing_get_continuous_values(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(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<T> 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<T>(i + 2));
}
}
}
template <typename T>
void testing_set_continuous_values(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> 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<T> values(num_values);
for(int i = 0; i < num_values; ++i)
{
values[i] = static_cast<T>(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<T>(100.0 * (i + 1)));
}
}
}
template <typename T>
void testing_extract_coarse_mapping()
{
// Create a LocalVector and allocate some size
LocalVector<T> 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 <typename T>
void testing_move_to_host_async(const Arguments& argus)
{
// Create a LocalVector and allocate some size
LocalVector<T> vec = getTestVector<T>(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<T>(i + 1));
}
}
#endif // TESTING_LOCAL_VECTOR_HPP