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
287 lines
7.8 KiB
C++
287 lines
7.8 KiB
C++
// Copyright © Advanced Micro Devices, Inc., or its affiliates.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
#include <algorithm>
|
|
#include <gtest/gtest.h>
|
|
#include <hipdnn_frontend/node/detail/TopologicalSortingUtils.hpp>
|
|
|
|
using namespace hipdnn_frontend;
|
|
using namespace hipdnn_frontend::detail;
|
|
|
|
class TestTopologicalSortingUtils : public ::testing::Test
|
|
{
|
|
protected:
|
|
static bool isValidTopologicalOrder(const std::vector<size_t>& order,
|
|
const GraphStructure& structure)
|
|
{
|
|
if(order.size() != structure.adjacencyList.size())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
std::vector<size_t> position(structure.adjacencyList.size());
|
|
for(size_t i = 0; i < order.size(); ++i)
|
|
{
|
|
position[order[i]] = i;
|
|
}
|
|
|
|
for(size_t node = 0; node < structure.adjacencyList.size(); ++node)
|
|
{
|
|
for(auto neighbor : structure.adjacencyList[node])
|
|
{
|
|
if(position[node] >= position[neighbor])
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
TEST_F(TestTopologicalSortingUtils, ComputesInDegreesCorrectly)
|
|
{
|
|
{
|
|
GraphStructure structure;
|
|
structure.adjacencyList = {};
|
|
const std::vector<int> inDegreesExpected = {};
|
|
EXPECT_EQ(computeInDegrees(structure), inDegreesExpected);
|
|
}
|
|
{
|
|
GraphStructure structure;
|
|
structure.adjacencyList = {{}};
|
|
const std::vector<int> inDegreesExpected = {0};
|
|
EXPECT_EQ(computeInDegrees(structure), inDegreesExpected);
|
|
}
|
|
{
|
|
GraphStructure structure;
|
|
structure.adjacencyList = {{1}, {2}, {}};
|
|
const std::vector<int> inDegreesExpected = {0, 1, 1};
|
|
EXPECT_EQ(computeInDegrees(structure), inDegreesExpected);
|
|
}
|
|
{
|
|
GraphStructure structure;
|
|
structure.adjacencyList = {
|
|
{1, 2}, // 0
|
|
{3, 4}, // 1
|
|
{4, 5}, // 2
|
|
{6}, // 3
|
|
{6, 7}, // 4
|
|
{8}, // 5
|
|
{9}, // 6
|
|
{9}, // 7
|
|
{9}, // 8
|
|
{} // 9
|
|
};
|
|
const std::vector<int> inDegreesExpected = {0, 1, 1, 1, 2, 1, 2, 1, 1, 3};
|
|
// Graph structure:
|
|
// 0
|
|
// / \
|
|
// 1 2
|
|
// / \ / \
|
|
// 3 4 5
|
|
// | / \ \
|
|
// 6 7 8
|
|
// \ | /
|
|
// 9
|
|
|
|
EXPECT_EQ(computeInDegrees(structure), inDegreesExpected);
|
|
}
|
|
}
|
|
|
|
TEST_F(TestTopologicalSortingUtils, EmptyGraph)
|
|
{
|
|
GraphStructure structure;
|
|
structure.adjacencyList = {};
|
|
|
|
auto result = performTopologicalSortWithComponentDetection(structure);
|
|
|
|
EXPECT_TRUE(result.order.empty());
|
|
EXPECT_FALSE(result.hasCycle);
|
|
EXPECT_EQ(result.componentCount, 0);
|
|
}
|
|
|
|
TEST_F(TestTopologicalSortingUtils, SingleNode)
|
|
{
|
|
GraphStructure structure;
|
|
structure.adjacencyList = {{}};
|
|
|
|
auto result = performTopologicalSortWithComponentDetection(structure);
|
|
|
|
ASSERT_EQ(result.order.size(), 1);
|
|
EXPECT_EQ(result.order[0], 0);
|
|
EXPECT_FALSE(result.hasCycle);
|
|
EXPECT_EQ(result.componentCount, 1);
|
|
}
|
|
|
|
TEST_F(TestTopologicalSortingUtils, LinearChain)
|
|
{
|
|
// Graph: 0 -> 1 -> 2 -> 3
|
|
GraphStructure structure;
|
|
structure.adjacencyList = {{1}, {2}, {3}, {}};
|
|
|
|
auto result = performTopologicalSortWithComponentDetection(structure);
|
|
|
|
ASSERT_EQ(result.order.size(), 4);
|
|
EXPECT_EQ(result.order[0], 0);
|
|
EXPECT_EQ(result.order[1], 1);
|
|
EXPECT_EQ(result.order[2], 2);
|
|
EXPECT_EQ(result.order[3], 3);
|
|
EXPECT_TRUE(isValidTopologicalOrder(result.order, structure));
|
|
EXPECT_FALSE(result.hasCycle);
|
|
EXPECT_EQ(result.componentCount, 1);
|
|
}
|
|
|
|
TEST_F(TestTopologicalSortingUtils, DiamondGraph)
|
|
{
|
|
// Graph: 0
|
|
// / \
|
|
// 1 2
|
|
// \ /
|
|
// 3
|
|
GraphStructure structure;
|
|
structure.adjacencyList = {{1, 2}, {3}, {3}, {}};
|
|
|
|
auto result = performTopologicalSortWithComponentDetection(structure);
|
|
|
|
ASSERT_EQ(result.order.size(), 4);
|
|
EXPECT_EQ(result.order[0], 0);
|
|
EXPECT_EQ(result.order[3], 3);
|
|
EXPECT_TRUE(isValidTopologicalOrder(result.order, structure));
|
|
EXPECT_FALSE(result.hasCycle);
|
|
EXPECT_EQ(result.componentCount, 1);
|
|
}
|
|
|
|
TEST_F(TestTopologicalSortingUtils, MultipleSourcesAndSinks)
|
|
{
|
|
// Graph:
|
|
// 0 1
|
|
// / \ / \
|
|
// 3 2 3 <-- 3 is the same as the other 3, just cant draw it in ascii
|
|
|
|
// Both 0 and 1 point to 2 and 3. 2 and 3 are sinks.
|
|
GraphStructure structure;
|
|
structure.adjacencyList = {{2, 3}, {2, 3}, {}, {}};
|
|
|
|
auto result = performTopologicalSortWithComponentDetection(structure);
|
|
|
|
ASSERT_EQ(result.order.size(), 4);
|
|
EXPECT_TRUE(isValidTopologicalOrder(result.order, structure));
|
|
EXPECT_FALSE(result.hasCycle);
|
|
EXPECT_EQ(result.componentCount, 1);
|
|
}
|
|
|
|
TEST_F(TestTopologicalSortingUtils, ComplexDag)
|
|
{
|
|
// Graph: 0 -> 1 -> 3 -> 4
|
|
// 0 -> 2 -> 3
|
|
// 2 -> 4
|
|
GraphStructure structure;
|
|
structure.adjacencyList = {{1, 2}, {3}, {3, 4}, {4}, {}};
|
|
|
|
auto result = performTopologicalSortWithComponentDetection(structure);
|
|
|
|
ASSERT_EQ(result.order.size(), 5);
|
|
EXPECT_EQ(result.order[0], 0);
|
|
EXPECT_EQ(result.order[4], 4);
|
|
EXPECT_TRUE(isValidTopologicalOrder(result.order, structure));
|
|
EXPECT_FALSE(result.hasCycle);
|
|
EXPECT_EQ(result.componentCount, 1);
|
|
}
|
|
|
|
TEST_F(TestTopologicalSortingUtils, DisconnectedNodes)
|
|
{
|
|
{
|
|
// Graph: 0 -> 1 2 (disconnected)
|
|
GraphStructure structure;
|
|
structure.adjacencyList = {{1}, {}, {}};
|
|
|
|
auto result = performTopologicalSortWithComponentDetection(structure);
|
|
|
|
EXPECT_FALSE(result.hasCycle);
|
|
EXPECT_EQ(result.componentCount, 2);
|
|
}
|
|
|
|
{
|
|
// Graph: 0 -> 1 2 -> 3 (two disconnected components)
|
|
GraphStructure structure;
|
|
structure.adjacencyList = {{1}, {}, {3}, {}};
|
|
|
|
auto result = performTopologicalSortWithComponentDetection(structure);
|
|
|
|
EXPECT_FALSE(result.hasCycle);
|
|
EXPECT_EQ(result.componentCount, 2);
|
|
}
|
|
|
|
{
|
|
// Graph: 0 -> 1 2 -> 3 4 (three disconnected components)
|
|
GraphStructure structure;
|
|
structure.adjacencyList = {{1}, {}, {3}, {}, {}};
|
|
|
|
auto result = performTopologicalSortWithComponentDetection(structure);
|
|
|
|
EXPECT_FALSE(result.hasCycle);
|
|
EXPECT_EQ(result.componentCount, 3);
|
|
}
|
|
|
|
{
|
|
// Graph: 0 -> 1 , 0-> 2, 1->3, 2->3. 4->5, 6, 7->8, 8->9
|
|
GraphStructure structure;
|
|
structure.adjacencyList = {{1, 2}, {3}, {3}, {}, {5}, {}, {}, {8}, {9}, {}};
|
|
|
|
auto result = performTopologicalSortWithComponentDetection(structure);
|
|
|
|
EXPECT_FALSE(result.hasCycle);
|
|
EXPECT_EQ(result.componentCount, 4);
|
|
}
|
|
}
|
|
|
|
TEST_F(TestTopologicalSortingUtils, LargerGraph)
|
|
{
|
|
// Graph with 10 nodes forming a complex DAG
|
|
|
|
GraphStructure structure;
|
|
structure.adjacencyList = {
|
|
{1, 2}, // 0
|
|
{3, 4}, // 1
|
|
{4, 5}, // 2
|
|
{6}, // 3
|
|
{6, 7}, // 4
|
|
{8}, // 5
|
|
{9}, // 6
|
|
{9}, // 7
|
|
{9}, // 8
|
|
{} // 9
|
|
};
|
|
// Graph structure:
|
|
// 0
|
|
// / \
|
|
// 1 2
|
|
// / \ / \
|
|
// 3 4 5
|
|
// | / \ \
|
|
// 6 7 8
|
|
// \ | /
|
|
// 9
|
|
|
|
auto result = performTopologicalSortWithComponentDetection(structure);
|
|
|
|
ASSERT_EQ(result.order.size(), 10);
|
|
EXPECT_EQ(result.order[0], 0);
|
|
EXPECT_EQ(result.order[9], 9);
|
|
EXPECT_TRUE(isValidTopologicalOrder(result.order, structure));
|
|
EXPECT_FALSE(result.hasCycle);
|
|
EXPECT_EQ(result.componentCount, 1);
|
|
}
|
|
|
|
TEST_F(TestTopologicalSortingUtils, CyclicGraph)
|
|
{
|
|
// Graph: 0 -> 1 -> 2 -> 1 (cycle)
|
|
GraphStructure structure;
|
|
structure.adjacencyList = {{1}, {2}, {1}};
|
|
auto sortResult = performTopologicalSortWithComponentDetection(structure);
|
|
|
|
EXPECT_TRUE(sortResult.hasCycle);
|
|
}
|