diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a945d7..4689358 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,6 +61,19 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${GraphMLIR_BINARY_DIR}) set(GraphMLIR_EXAMPLES OFF CACHE BOOL "Build examples") +#------------------------------------------------------------------------------- +# GoogleTest +#------------------------------------------------------------------------------- +set(BUILD_TESTS ON CACHE BOOL "Build tests") +if (BUILD_TESTS) + include(FetchContent) + FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip + ) + FetchContent_MakeAvailable(googletest) +endif() + # Add MLIR and LLVM headers to the include path include_directories(${LLVM_INCLUDE_DIRS}) include_directories(${MLIR_INCLUDE_DIRS}) @@ -80,6 +93,7 @@ include_directories(${GraphMLIR_SOURCE_DIR}/lib) add_subdirectory(include) add_subdirectory(lib) add_subdirectory(tools) +add_subdirectory(tests/unittests) if(GraphMLIR_EXAMPLES) add_subdirectory(examples) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index ec97a1d..40e5b52 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -11,8 +11,6 @@ BFS PROPERTIES LINKER_LANGUAGE C) - - add_executable(bfsExample bfsExample.cpp) add_dependencies(bfsExample graph-opt) target_link_libraries(bfsExample BFS) diff --git a/include/Interface/Container.h b/include/Interface/Container.h index e674642..3e3c64f 100644 --- a/include/Interface/Container.h +++ b/include/Interface/Container.h @@ -31,6 +31,8 @@ // - The storage order is NCHW. template class MemRef { public: + // Default constructor. + MemRef(){}; // Constructor from shape. MemRef(intptr_t sizes[N], T init = T(0)); // Constructor from data. @@ -62,10 +64,10 @@ template class MemRef { T &operator[](size_t index); // release the pointer T *release(); + //comparision operator + bool operator==(const MemRef &other); protected: - // Default constructor. - MemRef(){}; // Set the strides. // Computes the strides of the transposed tensor for transpose=true. void setStrides(); diff --git a/lib/Interface/CMakeLists.txt b/lib/Interface/CMakeLists.txt index 381bd6a..a4b9fc1 100644 --- a/lib/Interface/CMakeLists.txt +++ b/lib/Interface/CMakeLists.txt @@ -1 +1,2 @@ add_library(Container Container.cpp) +add_library(GraphContainer GraphContainer.cpp) diff --git a/lib/Interface/Container.cpp b/lib/Interface/Container.cpp index bb9d6a1..c4c5752 100644 --- a/lib/Interface/Container.cpp +++ b/lib/Interface/Container.cpp @@ -23,6 +23,8 @@ #include #include +#include +#include #include #include #include @@ -177,8 +179,16 @@ template MemRef &MemRef::operator=(MemRef &&other) noexcept { // Free the original aligned and allocated space. delete[] allocated; - // Copy members of the original object. - MemRef::MemRef(other); + // Steal members of the original object. + std::swap(strides, other.strides); + std::swap(offset, other.offset); + std::swap(sizes, other.sizes); + std::swap(size, other.size); + std::swap(allocated, other.allocated); + std::swap(aligned, other.aligned); + // Assign the NULL pointer to the original aligned and allocated members to + // avoid the double free error. + other.allocated = other.aligned = nullptr; return *this; } @@ -277,4 +287,33 @@ template T *MemRef::release() { return temp; } +template +bool MemRef::operator==(const MemRef &other) { + intptr_t x1 = this->sizes[0]; + intptr_t y1 = this->sizes[1]; + intptr_t x2 = other.sizes[0]; + intptr_t y2 = other.sizes[1]; + + // compare the sizes array and size + if (x1 != x2 || y1 != y2 || this->size != other.size) { + return false; + } + + // compare the strides + if (this->strides[0] != this->strides[0] || + other.strides[1] != other.strides[1]) { + return false; + } + + for (intptr_t i = 0; i < x1; i++) { + for (intptr_t j = 0; j < y1; j++) { + if (this->aligned[i * x1 + y1] != other.aligned[i * x1 + y1]) { + return false; + } + } + } + + return true; +} + #endif // CORE_CONTAINER_DEF diff --git a/lib/Interface/GraphContainer.cpp b/lib/Interface/GraphContainer.cpp index f2d7beb..fd6a652 100644 --- a/lib/Interface/GraphContainer.cpp +++ b/lib/Interface/GraphContainer.cpp @@ -209,7 +209,7 @@ void Graph::addEdge(T Node1, T Node2, T EdgeWeight) { this->incMat[Node2][edgeCount] = EdgeWeight; break; case graph::detail::GRAPH_INC_MATRIX_DIRECTED_WEIGHTED: - EdgeWeight = std::abs(sqrt(EdgeWeight)); + EdgeWeight = EdgeWeight; this->incMat[Node1][edgeCount] = EdgeWeight; this->incMat[Node2][edgeCount] = -EdgeWeight; this->edgeCount += 1; @@ -461,9 +461,9 @@ template void Graph::graph_to_MemRef_descriptor() { for (k = flag + 1; k < this->incMat.size() && flag != -2; k++) { if ((this->incMat[k][j] != 0) && flag != -1) { if (this->incMat[k][j] < this->incMat[int(flag)][j]) - linear[int(flag) * x + k] = pow(incMat[k][j], 2); + linear[int(flag) * x + k] = incMat[k][j]; else - linear[k * x + int(flag)] = pow(incMat[k][j], 2); + linear[k * x + int(flag)] = incMat[k][j]; flag = -1; } } diff --git a/tests/unittests/CMakeLists.txt b/tests/unittests/CMakeLists.txt new file mode 100644 index 0000000..4dc828d --- /dev/null +++ b/tests/unittests/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(Interface) diff --git a/tests/unittests/Interface/CMakeLists.txt b/tests/unittests/Interface/CMakeLists.txt new file mode 100644 index 0000000..34c8779 --- /dev/null +++ b/tests/unittests/Interface/CMakeLists.txt @@ -0,0 +1,12 @@ +add_executable( + InterfaceTests + GraphContainerTest.cpp + ContainerTest.cpp +) + +target_link_libraries(InterfaceTests gtest gtest_main pthread BFS) + +add_dependencies(InterfaceTests Container GraphContainer) + +include(GoogleTest) +gtest_discover_tests(InterfaceTests) diff --git a/tests/unittests/Interface/ContainerTest.cpp b/tests/unittests/Interface/ContainerTest.cpp new file mode 100644 index 0000000..278703f --- /dev/null +++ b/tests/unittests/Interface/ContainerTest.cpp @@ -0,0 +1,80 @@ +#include "Interface/Container.h" +#include + +template +void ASSERT_ARRAY_EQ(const T *x, const T *y, const size_t n) { + if (std::is_integral::value) { + for (size_t i = 0; i < n; i++) { + ASSERT_EQ(x[i], y[i]); + } + } else if (std::is_same::value) { + for (size_t i = 0; i < n; i++) { + ASSERT_FLOAT_EQ(x[i], y[i]); + } + } else if (std::is_same::value) { + for (size_t i = 0; i < n; i++) { + ASSERT_DOUBLE_EQ(x[i], y[i]); + } + } +} + +class MemRefTest : public ::testing::Test { +protected: + void SetUp() override {} + void TearDown() override {} +}; + +// Copy constructor. +TEST_F(MemRefTest, CopyConstructor2DMemref) { + // new hard codede MemRef object. + float aligned[] = {0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, + 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0}; + intptr_t sizes[2] = {6, 6}; + MemRef m(aligned, sizes, 0); + MemRef copy(m); + EXPECT_EQ(m == copy, true); +} + +// Copy assignment operator. +TEST_F(MemRefTest, CopyAssignment2DMemref) { + // new hard codede MemRef object. + float aligned[] = {0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, + 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0}; + intptr_t sizes[2] = {6, 6}; + MemRef m(aligned, sizes, 0); + MemRef copy = m; + EXPECT_EQ(m == copy, true); +} + +// Move constructor. +TEST_F(MemRefTest, MoveConstructor2DMemref) { + // new hard codede MemRef object. + float aligned[] = {0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, + 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0}; + intptr_t sizes[2] = {6, 6}; + MemRef m1(aligned, sizes, 0); + MemRef m2(aligned, sizes, 0); + + // Construct using move constructor. + MemRef move = std::move(m1); + + // test + EXPECT_EQ(m2 == move, true); +} + +// Move assignment operator. +TEST_F(MemRefTest, MoveAssignment2DMemref) { + // new hard codede MemRef object. + float aligned[] = {0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, + 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0}; + intptr_t sizes[2] = {6, 6}; + MemRef m1(aligned, sizes, 0); + MemRef m2(aligned, sizes, 0); + + MemRef move; + // Assignment using the move assignment operator. + move = std::move(m1); + + // test + EXPECT_EQ(m2 == move, true); +} diff --git a/tests/unittests/Interface/GraphContainerTest.cpp b/tests/unittests/Interface/GraphContainerTest.cpp new file mode 100644 index 0000000..d12a976 --- /dev/null +++ b/tests/unittests/Interface/GraphContainerTest.cpp @@ -0,0 +1,291 @@ +#include "Interface/GraphContainer.h" +#include + +class GraphContainerTest : public ::testing::Test { +protected: + void SetUp() override {} + void TearDown() override {} +}; + +TEST_F(GraphContainerTest, adjListUndirectedUnweighted) { + + // Create object of the Graph class and add edges. + Graph graph(graph::detail::GRAPH_ADJ_LIST_UNDIRECTED_UNWEIGHTED, 6); + graph.addEdge(0, 1); + graph.addEdge(1, 3); + graph.addEdge(1, 5); + graph.addEdge(1, 4); + graph.addEdge(2, 4); + + // convert the graph to MemRef using the functions in GraphContainer.cpp + auto memref2 = graph.get_Memref(); + + // new hard coded MemRef object. + float aligned[] = {0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, + 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0}; + intptr_t sizes[2] = {6, 6}; + MemRef memref1(aligned, sizes, 0); + + // Test + EXPECT_EQ(memref1 == memref2, true); +} + +TEST_F(GraphContainerTest, adjListDirectedUnweighted) { + + // Create object of the Graph class and add edges. + Graph graph(graph::detail::GRAPH_ADJ_LIST_DIRECTED_UNWEIGHTED, 6); + graph.addEdge(1, 0); + graph.addEdge(3, 1); + graph.addEdge(4, 1); + graph.addEdge(4, 2); + graph.addEdge(5, 1); + + // convert the graph to MemRef using the functions in GraphContainer.cpp + auto memref2 = graph.get_Memref(); + + // new hard coded MemRef object. + float aligned[] = {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0}; + intptr_t sizes[2] = {6, 6}; + MemRef memref1(aligned, sizes, 0); + + // Test + EXPECT_EQ(memref1 == memref2, true); +} + +TEST_F(GraphContainerTest, adjListUndirectedWeighted) { + + // Create object of the Graph class and add edges. + Graph graph(graph::detail::GRAPH_ADJ_LIST_UNDIRECTED_WEIGHTED, 6); + graph.addEdge(1, 0, 2); + graph.addEdge(3, 1, 3); + graph.addEdge(4, 1, 4); + graph.addEdge(4, 2, 5); + graph.addEdge(5, 1, 6); + + // convert the graph to MemRef using the functions in GraphContainer.cpp + auto memref2 = graph.get_Memref(); + + // new hard coded MemRef object. + float aligned[] = {0, 2, 0, 0, 0, 0, 2, 0, 0, 3, 4, 6, 0, 0, 0, 0, 5, 0, + 0, 3, 0, 0, 0, 0, 0, 4, 5, 0, 0, 0, 0, 6, 0, 0, 0, 0}; + intptr_t sizes[2] = {6, 6}; + MemRef memref1(aligned, sizes, 0); + + // Test + EXPECT_EQ(memref1 == memref2, true); +} + +TEST_F(GraphContainerTest, adjListDirectedWeighted) { + + // Create object of the Graph class and add edges. + Graph graph(graph::detail::GRAPH_ADJ_LIST_DIRECTED_WEIGHTED, 6); + graph.addEdge(1, 0, 2); + graph.addEdge(3, 1, 3); + graph.addEdge(4, 1, 4); + graph.addEdge(4, 2, 5); + graph.addEdge(5, 1, 6); + + // convert the graph to MemRef using the functions in GraphContainer.cpp + auto memref2 = graph.get_Memref(); + + // new hard coded MemRef object. + int aligned[] = {0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3, 0, 0, 0, 0, 0, 4, 5, 0, 0, 0, 0, 6, 0, 0, 0, 0}; + intptr_t sizes[2] = {6, 6}; + MemRef memref1(aligned, sizes, 0); + + // Test + EXPECT_EQ(memref1 == memref2, true); +} + +TEST_F(GraphContainerTest, adjMatrixUndirectedUnweighted) { + + // Create object of the Graph class and add edges. + Graph graph(graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_UNWEIGHTED, + 6); + graph.addEdge(0, 1); + graph.addEdge(1, 3); + graph.addEdge(1, 5); + graph.addEdge(1, 4); + graph.addEdge(2, 4); + + // convert the graph to MemRef using the functions in GraphContainer.cpp and + auto memref2 = graph.get_Memref(); + + // new hard coded MemRef object. + float aligned[] = {0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, + 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0}; + intptr_t sizes[2] = {6, 6}; + MemRef memref1(aligned, sizes, 0); + + // Test + EXPECT_EQ(memref1 == memref2, true); +} + +TEST_F(GraphContainerTest, adjMatrixDirectedUnweighted) { + + // Create object of the Graph class and add edges. + Graph graph(graph::detail::GRAPH_ADJ_MATRIX_DIRECTED_UNWEIGHTED, 6); + graph.addEdge(1, 0); + graph.addEdge(3, 1); + graph.addEdge(4, 1); + graph.addEdge(4, 2); + graph.addEdge(5, 1); + + // convert the graph to MemRef using the functions in GraphContainer.cpp + auto memref2 = graph.get_Memref(); + + // new hard coded MemRef object. + float aligned[] = {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0}; + intptr_t sizes[2] = {6, 6}; + MemRef memref1(aligned, sizes, 0); + + // Test + EXPECT_EQ(memref1 == memref2, true); +} + +TEST_F(GraphContainerTest, adjMatrixUndirectedWeighted) { + + // Create object of the Graph class and add edges. + Graph graph(graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_WEIGHTED, 6); + graph.addEdge(1, 0, 2); + graph.addEdge(3, 1, 3); + graph.addEdge(4, 1, 4); + graph.addEdge(4, 2, 5); + graph.addEdge(5, 1, 6); + + // convert the graph to MemRef using the functions in GraphContainer.cpp + auto memref2 = graph.get_Memref(); + + // new hard coded MemRef object. + float aligned[] = {0, 2, 0, 0, 0, 0, 2, 0, 0, 3, 4, 6, 0, 0, 0, 0, 5, 0, + 0, 3, 0, 0, 0, 0, 0, 4, 5, 0, 0, 0, 0, 6, 0, 0, 0, 0}; + intptr_t sizes[2] = {6, 6}; + MemRef memref1(aligned, sizes, 0); + + // Test + EXPECT_EQ(memref1 == memref2, true); +} + +TEST_F(GraphContainerTest, adjMatrixDirectedWeighted) { + + // Create object of the Graph class and add edges. + Graph graph(graph::detail::GRAPH_ADJ_MATRIX_DIRECTED_WEIGHTED, 6); + graph.addEdge(1, 0, 2); + graph.addEdge(3, 1, 3); + graph.addEdge(4, 1, 4); + graph.addEdge(4, 2, 5); + graph.addEdge(5, 1, 6); + + // convert the graph to MemRef using the functions in GraphContainer.cpp + auto memref2 = graph.get_Memref(); + + // new hard coded MemRef object. + float aligned[] = {0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3, 0, 0, 0, 0, 0, 4, 5, 0, 0, 0, 0, 6, 0, 0, 0, 0}; + intptr_t sizes[2] = {6, 6}; + MemRef memref1(aligned, sizes, 0); + + // Test + EXPECT_EQ(memref1 == memref2, true); +} + +TEST_F(GraphContainerTest, incMatrixUndirectedUnweighted) { + + // Create object of the Graph class and add edges. + Graph graph(graph::detail::GRAPH_INC_MATRIX_UNDIRECTED_UNWEIGHTED, + 6); + graph.addEdge(0, 1); + graph.addEdge(1, 3); + graph.addEdge(1, 5); + graph.addEdge(1, 4); + graph.addEdge(2, 4); + + // convert the graph to MemRef using the functions in GraphContainer.cpp + auto memref2 = graph.get_Memref(); + + // new hard coded MemRef object. + float aligned[] = {0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, + 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0}; + intptr_t sizes[2] = {6, 6}; + MemRef memref1(aligned, sizes, 0); + + // Test + EXPECT_EQ(memref1 == memref2, true); +} + +TEST_F(GraphContainerTest, incMatrixDirectedUnweighted) { + + // Create object of the Graph class and add edges. + Graph graph(graph::detail::GRAPH_INC_MATRIX_DIRECTED_UNWEIGHTED, 6); + graph.addEdge(1, 0); + graph.addEdge(3, 1); + graph.addEdge(4, 1); + graph.addEdge(4, 2); + graph.addEdge(5, 1); + + // convert the graph to MemRef using the functions in GraphContainer.cpp + auto memref2 = graph.get_Memref(); + + // new hard coded MemRef object. + float aligned[] = {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0}; + intptr_t sizes[2] = {6, 6}; + MemRef memref1(aligned, sizes, 0); + + // Test + EXPECT_EQ(memref1 == memref2, true); +} + +TEST_F(GraphContainerTest, incMatrixUndirectedWeighted) { + + // Create object of the Graph class and add edges. + Graph graph(graph::detail::GRAPH_INC_MATRIX_UNDIRECTED_WEIGHTED, 6); + graph.addEdge(1, 0, 2); + graph.addEdge(3, 1, 3); + graph.addEdge(4, 1, 4); + graph.addEdge(4, 2, 5); + graph.addEdge(5, 1, 6); + + // convert the graph to MemRef using the functions in GraphContainer.cpp + auto memref2 = graph.get_Memref(); + + // new hard coded MemRef object. + float aligned[] = {0, 2, 0, 0, 0, 0, 2, 0, 0, 3, 4, 6, 0, 0, 0, 0, 5, 0, + 0, 3, 0, 0, 0, 0, 0, 4, 5, 0, 0, 0, 0, 6, 0, 0, 0, 0}; + intptr_t sizes[2] = {6, 6}; + MemRef memref1(aligned, sizes, 0); + + // Test + EXPECT_EQ(memref1 == memref2, true); +} + +TEST_F(GraphContainerTest, incMatrixDirectedWeighted) { + + // Create object of the Graph class and add edges. + Graph graph(graph::detail::GRAPH_INC_MATRIX_DIRECTED_WEIGHTED, 6); + graph.addEdge(1, 0, 2); + graph.addEdge(3, 1, 3); + graph.addEdge(4, 1, 4); + graph.addEdge(4, 2, 5); + graph.addEdge(5, 1, 6); + + // convert the graph to MemRef using the functions in GraphContainer.cpp + auto memref2 = graph.get_Memref(); + + // new hard coded MemRef object. + int aligned[] = {0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3, 0, 0, 0, 0, 0, 4, 5, 0, 0, 0, 0, 6, 0, 0, 0, 0}; + intptr_t sizes[2] = {6, 6}; + MemRef memref1(aligned, sizes, 0); + + // Test + EXPECT_EQ(memref1 == memref2, true); +} + +int main(int argc, char **argv) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +}