File indexing completed on 2026-06-21 07:48:11
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/unit_test.hpp>
0010
0011 #include "ActsPlugins/Gnn/Stages.hpp"
0012
0013 #ifdef ACTS_GNN_WITH_CUDA
0014 #include <cuda_runtime_api.h>
0015 #endif
0016
0017 using namespace ActsPlugins;
0018
0019 namespace ActsTests {
0020
0021 namespace {
0022
0023 const ExecutionContext execContextCpu{Device::Cpu(), {}};
0024 #ifdef ACTS_GNN_WITH_CUDA
0025 const ExecutionContext execContextCuda{Device::Cuda(0), cudaStreamLegacy};
0026 #endif
0027
0028
0029 PipelineTensors makeTensors(std::size_t nNodes, std::size_t nFeatures,
0030 std::vector<std::int64_t> edges,
0031 const ExecutionContext &ctx) {
0032 const auto nEdges = edges.size() / 2;
0033
0034 auto nodeFeaturesCpu =
0035 Tensor<float>::Create({nNodes, nFeatures}, execContextCpu);
0036 for (std::size_t i = 0; i < nNodes * nFeatures; ++i) {
0037 nodeFeaturesCpu.data()[i] = static_cast<float>(i);
0038 }
0039
0040 auto edgeIndexCpu = Tensor<std::int64_t>::Create({2, nEdges}, execContextCpu);
0041 std::copy(edges.begin(), edges.end(), edgeIndexCpu.data());
0042
0043 return {std::move(nodeFeaturesCpu).clone(ctx),
0044 std::move(edgeIndexCpu).clone(ctx), std::nullopt, std::nullopt};
0045 }
0046
0047
0048 template <typename T>
0049 std::vector<T> toHost(const Tensor<T> &tensor, const ExecutionContext &srcCtx) {
0050 auto host = tensor.clone({Device::Cpu(), srcCtx.stream});
0051 return {host.data(), host.data() + host.size()};
0052 }
0053
0054 void testAllNodesUsed(const ExecutionContext &ctx) {
0055
0056 auto tensors = makeTensors(3, 4, {0, 1, 1, 2}, ctx);
0057 const auto originalNodeData = toHost(tensors.nodeFeatures, ctx);
0058
0059 std::vector<int> spIds = {10, 11, 12};
0060 auto result = removeUnusedNodes(std::move(tensors), spIds, ctx);
0061
0062 BOOST_CHECK_EQUAL(result.nodeFeatures.shape()[0], 3u);
0063 BOOST_CHECK_EQUAL(result.nodeFeatures.shape()[1], 4u);
0064 BOOST_CHECK_EQUAL(result.edgeIndex.shape()[1], 2u);
0065
0066 BOOST_REQUIRE_EQUAL(spIds.size(), 3u);
0067 BOOST_CHECK_EQUAL(spIds[0], 10);
0068 BOOST_CHECK_EQUAL(spIds[1], 11);
0069 BOOST_CHECK_EQUAL(spIds[2], 12);
0070
0071 const auto nodeData = toHost(result.nodeFeatures, ctx);
0072 BOOST_CHECK_EQUAL_COLLECTIONS(nodeData.begin(), nodeData.end(),
0073 originalNodeData.begin(),
0074 originalNodeData.end());
0075
0076 const auto edgeData = toHost(result.edgeIndex, ctx);
0077 BOOST_CHECK_EQUAL(edgeData[0], 0);
0078 BOOST_CHECK_EQUAL(edgeData[1], 1);
0079 BOOST_CHECK_EQUAL(edgeData[2], 1);
0080 BOOST_CHECK_EQUAL(edgeData[3], 2);
0081 }
0082
0083 void testUnusedNodesRemoved(const ExecutionContext &ctx) {
0084
0085
0086 auto tensors = makeTensors(5, 2, {0, 2, 2, 4}, ctx);
0087 std::vector<int> spIds = {100, 101, 102, 103, 104};
0088
0089 auto result = removeUnusedNodes(std::move(tensors), spIds, ctx);
0090
0091 BOOST_CHECK_EQUAL(result.nodeFeatures.shape()[0], 3u);
0092 BOOST_CHECK_EQUAL(result.nodeFeatures.shape()[1], 2u);
0093 BOOST_CHECK_EQUAL(result.edgeIndex.shape()[1], 2u);
0094
0095 BOOST_REQUIRE_EQUAL(spIds.size(), 3u);
0096 BOOST_CHECK_EQUAL(spIds[0], 100);
0097 BOOST_CHECK_EQUAL(spIds[1], 102);
0098 BOOST_CHECK_EQUAL(spIds[2], 104);
0099
0100 const auto edgeData = toHost(result.edgeIndex, ctx);
0101 BOOST_CHECK_EQUAL(edgeData[0], 0);
0102 BOOST_CHECK_EQUAL(edgeData[1], 1);
0103 BOOST_CHECK_EQUAL(edgeData[2], 1);
0104 BOOST_CHECK_EQUAL(edgeData[3], 2);
0105
0106
0107 const auto nodeData = toHost(result.nodeFeatures, ctx);
0108 BOOST_CHECK_EQUAL(nodeData[0], 0.f);
0109 BOOST_CHECK_EQUAL(nodeData[1], 1.f);
0110 BOOST_CHECK_EQUAL(nodeData[2], 4.f);
0111 BOOST_CHECK_EQUAL(nodeData[3], 5.f);
0112 BOOST_CHECK_EQUAL(nodeData[4], 8.f);
0113 BOOST_CHECK_EQUAL(nodeData[5], 9.f);
0114 }
0115
0116 void testEdgeAndScoreTensorsPreserved(const ExecutionContext &ctx) {
0117
0118 auto nodeFeaturesCpu = Tensor<float>::Create({4, 1}, execContextCpu);
0119 auto edgeIndexCpu = Tensor<std::int64_t>::Create({2, 1}, execContextCpu);
0120 edgeIndexCpu.data()[0] = 1;
0121 edgeIndexCpu.data()[1] = 2;
0122 auto edgeFeaturesCpu = Tensor<float>::Create({1, 3}, execContextCpu);
0123 edgeFeaturesCpu.data()[0] = 7.f;
0124 edgeFeaturesCpu.data()[1] = 8.f;
0125 edgeFeaturesCpu.data()[2] = 9.f;
0126 auto edgeScoresCpu = Tensor<float>::Create({1, 1}, execContextCpu);
0127 edgeScoresCpu.data()[0] = 0.99f;
0128
0129 PipelineTensors tensors{nodeFeaturesCpu.clone(ctx), edgeIndexCpu.clone(ctx),
0130 edgeFeaturesCpu.clone(ctx), edgeScoresCpu.clone(ctx)};
0131
0132 std::vector<int> spIds = {10, 11, 12, 13};
0133 auto result = removeUnusedNodes(std::move(tensors), spIds, ctx);
0134
0135 BOOST_CHECK_EQUAL(result.nodeFeatures.shape()[0], 2u);
0136 BOOST_REQUIRE_EQUAL(spIds.size(), 2u);
0137 BOOST_CHECK_EQUAL(spIds[0], 11);
0138 BOOST_CHECK_EQUAL(spIds[1], 12);
0139
0140 const auto edgeData = toHost(result.edgeIndex, ctx);
0141 BOOST_CHECK_EQUAL(edgeData[0], 0);
0142 BOOST_CHECK_EQUAL(edgeData[1], 1);
0143
0144 BOOST_REQUIRE(result.edgeFeatures.has_value());
0145 const auto featData = toHost(*result.edgeFeatures, ctx);
0146 BOOST_CHECK_EQUAL(featData[0], 7.f);
0147 BOOST_CHECK_EQUAL(featData[1], 8.f);
0148 BOOST_CHECK_EQUAL(featData[2], 9.f);
0149
0150 BOOST_REQUIRE(result.edgeScores.has_value());
0151 const auto scoreData = toHost(*result.edgeScores, ctx);
0152 BOOST_CHECK_EQUAL(scoreData[0], 0.99f);
0153 }
0154
0155 }
0156
0157 BOOST_AUTO_TEST_SUITE(GnnRemoveUnusedNodesSuite)
0158
0159 BOOST_AUTO_TEST_CASE(test_all_nodes_used_cpu) {
0160 testAllNodesUsed(execContextCpu);
0161 }
0162
0163 BOOST_AUTO_TEST_CASE(test_unused_nodes_removed_cpu) {
0164 testUnusedNodesRemoved(execContextCpu);
0165 }
0166
0167 BOOST_AUTO_TEST_CASE(test_zero_edges_throws) {
0168 auto nodeFeatures = Tensor<float>::Create({4, 2}, execContextCpu);
0169 auto edgeIndex = Tensor<std::int64_t>::Create({2, 0}, execContextCpu);
0170 PipelineTensors tensors{std::move(nodeFeatures), std::move(edgeIndex),
0171 std::nullopt, std::nullopt};
0172 std::vector<int> spIds = {0, 1, 2, 3};
0173 BOOST_CHECK_THROW(
0174 removeUnusedNodes(std::move(tensors), spIds, execContextCpu),
0175 NoEdgesError);
0176 }
0177
0178 BOOST_AUTO_TEST_CASE(test_edge_and_score_tensors_preserved_cpu) {
0179 testEdgeAndScoreTensorsPreserved(execContextCpu);
0180 }
0181
0182 #ifdef ACTS_GNN_WITH_CUDA
0183
0184 BOOST_AUTO_TEST_CASE(test_all_nodes_used_cuda) {
0185 testAllNodesUsed(execContextCuda);
0186 }
0187
0188 BOOST_AUTO_TEST_CASE(test_unused_nodes_removed_cuda) {
0189 testUnusedNodesRemoved(execContextCuda);
0190 }
0191
0192 BOOST_AUTO_TEST_CASE(test_edge_and_score_tensors_preserved_cuda) {
0193 testEdgeAndScoreTensorsPreserved(execContextCuda);
0194 }
0195
0196 #endif
0197
0198 BOOST_AUTO_TEST_SUITE_END()
0199
0200 }