#include #include #include "./common.h" using namespace dgl; using namespace dgl::runtime; namespace { template aten::CSRMatrix CSR1(DLContext ctx = CTX) { // [[0, 1, 1, 0, 0], // [1, 0, 0, 0, 0], // [0, 0, 1, 1, 0], // [0, 0, 0, 0, 0]] // data: [0, 2, 3, 1, 4] return aten::CSRMatrix( 4, 5, aten::VecToIdArray(std::vector({0, 2, 3, 5, 5}), sizeof(IDX)*8, ctx), aten::VecToIdArray(std::vector({1, 2, 0, 3, 2}), sizeof(IDX)*8, ctx), aten::VecToIdArray(std::vector({0, 2, 3, 4, 1}), sizeof(IDX)*8, ctx), false); } template aten::CSRMatrix CSR2(DLContext ctx = CTX) { // has duplicate entries // [[0, 1, 2, 0, 0], // [1, 0, 0, 0, 0], // [0, 0, 1, 1, 0], // [0, 0, 0, 0, 0]] // data: [0, 2, 5, 3, 1, 4] return aten::CSRMatrix( 4, 5, aten::VecToIdArray(std::vector({0, 3, 4, 6, 6}), sizeof(IDX)*8, ctx), aten::VecToIdArray(std::vector({1, 2, 2, 0, 2, 3}), sizeof(IDX)*8, ctx), aten::VecToIdArray(std::vector({0, 2, 5, 3, 1, 4}), sizeof(IDX)*8, ctx), false); } template aten::COOMatrix COO1(DLContext ctx = CTX) { // [[0, 1, 1, 0, 0], // [1, 0, 0, 0, 0], // [0, 0, 1, 1, 0], // [0, 0, 0, 0, 0]] // data: [0, 2, 3, 1, 4] // row : [0, 2, 0, 1, 2] // col : [1, 2, 2, 0, 3] return aten::COOMatrix( 4, 5, aten::VecToIdArray(std::vector({0, 2, 0, 1, 2}), sizeof(IDX)*8, ctx), aten::VecToIdArray(std::vector({1, 2, 2, 0, 3}), sizeof(IDX)*8, ctx)); } template aten::COOMatrix COO2(DLContext ctx = CTX) { // has duplicate entries // [[0, 1, 2, 0, 0], // [1, 0, 0, 0, 0], // [0, 0, 1, 1, 0], // [0, 0, 0, 0, 0]] // data: [0, 2, 5, 3, 1, 4] // row : [0, 2, 0, 1, 2, 0] // col : [1, 2, 2, 0, 3, 2] return aten::COOMatrix( 4, 5, aten::VecToIdArray(std::vector({0, 2, 0, 1, 2, 0}), sizeof(IDX)*8, ctx), aten::VecToIdArray(std::vector({1, 2, 2, 0, 3, 2}), sizeof(IDX)*8, ctx)); } template aten::CSRMatrix SR_CSR3(DLContext ctx) { // [[0, 1, 2, 0, 0], // [1, 0, 0, 0, 0], // [0, 0, 1, 1, 0], // [0, 0, 0, 0, 0]] return aten::CSRMatrix( 4, 5, aten::VecToIdArray(std::vector({0, 3, 4, 6, 6}), sizeof(IDX)*8, ctx), aten::VecToIdArray(std::vector({2, 1, 2, 0, 2, 3}), sizeof(IDX)*8, ctx), aten::VecToIdArray(std::vector({0, 2, 5, 3, 1, 4}), sizeof(IDX)*8, ctx), false); } template aten::CSRMatrix SRC_CSR3(DLContext ctx) { // [[0, 1, 2, 0, 0], // [1, 0, 0, 0, 0], // [0, 0, 1, 1, 0], // [0, 0, 0, 0, 0]] return aten::CSRMatrix( 4, 5, aten::VecToIdArray(std::vector({0, 3, 4, 6, 6}), sizeof(IDX)*8, ctx), aten::VecToIdArray(std::vector({1, 2, 2, 0, 2, 3}), sizeof(IDX)*8, ctx), aten::VecToIdArray(std::vector({2, 0, 5, 3, 1, 4}), sizeof(IDX)*8, ctx), false); } template aten::COOMatrix COO3(DLContext ctx) { // has duplicate entries // [[0, 1, 2, 0, 0], // [1, 0, 0, 0, 0], // [0, 0, 1, 1, 0], // [0, 0, 0, 0, 0]] // row : [0, 2, 0, 1, 2, 0] // col : [2, 2, 1, 0, 3, 2] return aten::COOMatrix( 4, 5, aten::VecToIdArray(std::vector({0, 2, 0, 1, 2, 0}), sizeof(IDX)*8, ctx), aten::VecToIdArray(std::vector({2, 2, 1, 0, 3, 2}), sizeof(IDX)*8, ctx)); } } // namespace template void _TestCSRIsNonZero(DLContext ctx) { auto csr = CSR1(ctx); ASSERT_TRUE(aten::CSRIsNonZero(csr, 0, 1)); ASSERT_FALSE(aten::CSRIsNonZero(csr, 0, 0)); IdArray r = aten::VecToIdArray(std::vector({2, 2, 0, 0}), sizeof(IDX)*8, ctx); IdArray c = aten::VecToIdArray(std::vector({1, 1, 1, 3}), sizeof(IDX)*8, ctx); IdArray x = aten::CSRIsNonZero(csr, r, c); IdArray tx = aten::VecToIdArray(std::vector({0, 0, 1, 0}), sizeof(IDX)*8, ctx); ASSERT_TRUE(ArrayEQ(x, tx)); } TEST(SpmatTest, TestCSRIsNonZero) { _TestCSRIsNonZero(CPU); _TestCSRIsNonZero(CPU); #ifdef DGL_USE_CUDA _TestCSRIsNonZero(GPU); _TestCSRIsNonZero(GPU); #endif } template void _TestCSRGetRowNNZ(DLContext ctx) { auto csr = CSR2(ctx); ASSERT_EQ(aten::CSRGetRowNNZ(csr, 0), 3); ASSERT_EQ(aten::CSRGetRowNNZ(csr, 3), 0); IdArray r = aten::VecToIdArray(std::vector({0, 3}), sizeof(IDX)*8, ctx); IdArray x = aten::CSRGetRowNNZ(csr, r); IdArray tx = aten::VecToIdArray(std::vector({3, 0}), sizeof(IDX)*8, ctx); ASSERT_TRUE(ArrayEQ(x, tx)); } TEST(SpmatTest, TestCSRGetRowNNZ) { _TestCSRGetRowNNZ(CPU); _TestCSRGetRowNNZ(CPU); #ifdef DGL_USE_CUDA _TestCSRGetRowNNZ(GPU); _TestCSRGetRowNNZ(GPU); #endif } template void _TestCSRGetRowColumnIndices(DLContext ctx) { auto csr = CSR2(ctx); auto x = aten::CSRGetRowColumnIndices(csr, 0); auto tx = aten::VecToIdArray(std::vector({1, 2, 2}), sizeof(IDX)*8, ctx); ASSERT_TRUE(ArrayEQ(x, tx)); x = aten::CSRGetRowColumnIndices(csr, 1); tx = aten::VecToIdArray(std::vector({0}), sizeof(IDX)*8, ctx); ASSERT_TRUE(ArrayEQ(x, tx)); x = aten::CSRGetRowColumnIndices(csr, 3); tx = aten::VecToIdArray(std::vector({}), sizeof(IDX)*8, ctx); ASSERT_TRUE(ArrayEQ(x, tx)); } TEST(SpmatTest, TestCSRGetRowColumnIndices) { _TestCSRGetRowColumnIndices(CPU); _TestCSRGetRowColumnIndices(CPU); #ifdef DGL_USE_CUDA _TestCSRGetRowColumnIndices(GPU); _TestCSRGetRowColumnIndices(GPU); #endif } template void _TestCSRGetRowData(DLContext ctx) { auto csr = CSR2(ctx); auto x = aten::CSRGetRowData(csr, 0); auto tx = aten::VecToIdArray(std::vector({0, 2, 5}), sizeof(IDX)*8, ctx); ASSERT_TRUE(ArrayEQ(x, tx)); x = aten::CSRGetRowData(csr, 1); tx = aten::VecToIdArray(std::vector({3}), sizeof(IDX)*8, ctx); ASSERT_TRUE(ArrayEQ(x, tx)); x = aten::CSRGetRowData(csr, 3); tx = aten::VecToIdArray(std::vector({}), sizeof(IDX)*8, ctx); ASSERT_TRUE(ArrayEQ(x, tx)); } TEST(SpmatTest, TestCSRGetRowData) { _TestCSRGetRowData(CPU); _TestCSRGetRowData(CPU); #ifdef DGL_USE_CUDA _TestCSRGetRowData(GPU); _TestCSRGetRowData(GPU); #endif } template void _TestCSRGetData(DLContext ctx) { auto csr = CSR2(ctx); // test get all data auto x = aten::CSRGetAllData(csr, 0, 0); auto tx = aten::VecToIdArray(std::vector({}), sizeof(IDX)*8, ctx); ASSERT_TRUE(ArrayEQ(x, tx)); x = aten::CSRGetAllData(csr, 0, 2); tx = aten::VecToIdArray(std::vector({2, 5}), sizeof(IDX)*8, ctx); ASSERT_TRUE(ArrayEQ(x, tx)); // test get data auto r = aten::VecToIdArray(std::vector({0, 0, 0}), sizeof(IDX)*8, ctx); auto c = aten::VecToIdArray(std::vector({0, 1, 2}), sizeof(IDX)*8, ctx); x = aten::CSRGetData(csr, r, c); tx = aten::VecToIdArray(std::vector({-1, 0, 2}), sizeof(IDX)*8, ctx); ASSERT_TRUE(ArrayEQ(x, tx)); // test get data on sorted csr = aten::CSRSort(csr); r = aten::VecToIdArray(std::vector({0, 0, 0}), sizeof(IDX)*8, ctx); c = aten::VecToIdArray(std::vector({0, 1, 2}), sizeof(IDX)*8, ctx); x = aten::CSRGetData(csr, r, c); tx = aten::VecToIdArray(std::vector({-1, 0, 2}), sizeof(IDX)*8, ctx); ASSERT_TRUE(ArrayEQ(x, tx)); // test get data w/ broadcasting r = aten::VecToIdArray(std::vector({0}), sizeof(IDX)*8, ctx); c = aten::VecToIdArray(std::vector({0, 1, 2}), sizeof(IDX)*8, ctx); x = aten::CSRGetData(csr, r, c); tx = aten::VecToIdArray(std::vector({-1, 0, 2}), sizeof(IDX)*8, ctx); ASSERT_TRUE(ArrayEQ(x, tx)); } TEST(SpmatTest, CSRGetData) { _TestCSRGetData(CPU); _TestCSRGetData(CPU); #ifdef DGL_USE_CUDA _TestCSRGetData(GPU); _TestCSRGetData(GPU); #endif } template void _TestCSRGetDataAndIndices(DLContext ctx) { auto csr = CSR2(ctx); auto r = aten::VecToIdArray(std::vector({0, 0, 0}), sizeof(IDX)*8, ctx); auto c = aten::VecToIdArray(std::vector({0, 1, 2}), sizeof(IDX)*8, ctx); auto x = aten::CSRGetDataAndIndices(csr, r, c); auto tr = aten::VecToIdArray(std::vector({0, 0, 0}), sizeof(IDX)*8, ctx); auto tc = aten::VecToIdArray(std::vector({1, 2, 2}), sizeof(IDX)*8, ctx); auto td = aten::VecToIdArray(std::vector({0, 2, 5}), sizeof(IDX)*8, ctx); ASSERT_TRUE(ArrayEQ(x[0], tr)); ASSERT_TRUE(ArrayEQ(x[1], tc)); ASSERT_TRUE(ArrayEQ(x[2], td)); } TEST(SpmatTest, CSRGetDataAndIndices) { _TestCSRGetDataAndIndices(CPU); _TestCSRGetDataAndIndices(CPU); #ifdef DGL_USE_CUDA _TestCSRGetDataAndIndices(GPU); _TestCSRGetDataAndIndices(GPU); #endif } template void _TestCSRTranspose(DLContext ctx) { auto csr = CSR2(ctx); auto csr_t = aten::CSRTranspose(csr); // [[0, 1, 0, 0], // [1, 0, 0, 0], // [2, 0, 1, 0], // [0, 0, 1, 0], // [0, 0, 0, 0]] // data: [3, 0, 2, 5, 1, 4] ASSERT_EQ(csr_t.num_rows, 5); ASSERT_EQ(csr_t.num_cols, 4); auto tp = aten::VecToIdArray(std::vector({0, 1, 2, 5, 6, 6}), sizeof(IDX)*8, ctx); auto ti = aten::VecToIdArray(std::vector({1, 0, 0, 0, 2, 2}), sizeof(IDX)*8, ctx); auto td = aten::VecToIdArray(std::vector({3, 0, 2, 5, 1, 4}), sizeof(IDX)*8, ctx); ASSERT_TRUE(ArrayEQ(csr_t.indptr, tp)); ASSERT_TRUE(ArrayEQ(csr_t.indices, ti)); ASSERT_TRUE(ArrayEQ(csr_t.data, td)); } TEST(SpmatTest, CSRTranspose) { _TestCSRTranspose(CPU); _TestCSRTranspose(CPU); #ifdef DGL_USE_CUDA _TestCSRTranspose(GPU); _TestCSRTranspose(GPU); #endif } template void _TestCSRToCOO(DLContext ctx) { auto csr = CSR2(ctx); { auto coo = CSRToCOO(csr, false); ASSERT_EQ(coo.num_rows, 4); ASSERT_EQ(coo.num_cols, 5); ASSERT_TRUE(coo.row_sorted); auto tr = aten::VecToIdArray(std::vector({0, 0, 0, 1, 2, 2}), sizeof(IDX)*8, ctx); ASSERT_TRUE(ArrayEQ(coo.row, tr)); ASSERT_TRUE(ArrayEQ(coo.col, csr.indices)); ASSERT_TRUE(ArrayEQ(coo.data, csr.data)); // convert from sorted csr auto s_csr = CSRSort(csr); coo = CSRToCOO(s_csr, false); ASSERT_EQ(coo.num_rows, 4); ASSERT_EQ(coo.num_cols, 5); ASSERT_TRUE(coo.row_sorted); ASSERT_TRUE(coo.col_sorted); tr = aten::VecToIdArray(std::vector({0, 0, 0, 1, 2, 2}), sizeof(IDX)*8, ctx); ASSERT_TRUE(ArrayEQ(coo.row, tr)); ASSERT_TRUE(ArrayEQ(coo.col, s_csr.indices)); ASSERT_TRUE(ArrayEQ(coo.data, s_csr.data)); } { auto coo = CSRToCOO(csr, true); ASSERT_EQ(coo.num_rows, 4); ASSERT_EQ(coo.num_cols, 5); auto tcoo = COO2(ctx); ASSERT_TRUE(ArrayEQ(coo.row, tcoo.row)); ASSERT_TRUE(ArrayEQ(coo.col, tcoo.col)); } } TEST(SpmatTest, CSRToCOO) { _TestCSRToCOO(CPU); _TestCSRToCOO(CPU); #if DGL_USE_CUDA _TestCSRToCOO(GPU); _TestCSRToCOO(GPU); #endif } template void _TestCSRSliceRows(DLContext ctx) { auto csr = CSR2(ctx); auto x = aten::CSRSliceRows(csr, 1, 4); // [1, 0, 0, 0, 0], // [0, 0, 1, 1, 0], // [0, 0, 0, 0, 0]] // data: [3, 1, 4] ASSERT_EQ(x.num_rows, 3); ASSERT_EQ(x.num_cols, 5); auto tp = aten::VecToIdArray(std::vector({0, 1, 3, 3}), sizeof(IDX)*8, ctx); auto ti = aten::VecToIdArray(std::vector({0, 2, 3}), sizeof(IDX)*8, ctx); auto td = aten::VecToIdArray(std::vector({3, 1, 4}), sizeof(IDX)*8, ctx); ASSERT_TRUE(ArrayEQ(x.indptr, tp)); ASSERT_TRUE(ArrayEQ(x.indices, ti)); ASSERT_TRUE(ArrayEQ(x.data, td)); auto r = aten::VecToIdArray(std::vector({0, 1, 3}), sizeof(IDX)*8, ctx); x = aten::CSRSliceRows(csr, r); // [[0, 1, 2, 0, 0], // [1, 0, 0, 0, 0], // [0, 0, 0, 0, 0]] // data: [0, 2, 5, 3] tp = aten::VecToIdArray(std::vector({0, 3, 4, 4}), sizeof(IDX)*8, ctx); ti = aten::VecToIdArray(std::vector({1, 2, 2, 0}), sizeof(IDX)*8, ctx); td = aten::VecToIdArray(std::vector({0, 2, 5, 3}), sizeof(IDX)*8, ctx); ASSERT_TRUE(ArrayEQ(x.indptr, tp)); ASSERT_TRUE(ArrayEQ(x.indices, ti)); ASSERT_TRUE(ArrayEQ(x.data, td)); } TEST(SpmatTest, TestCSRSliceRows) { _TestCSRSliceRows(CPU); _TestCSRSliceRows(CPU); #ifdef DGL_USE_CUDA _TestCSRSliceRows(GPU); _TestCSRSliceRows(GPU); #endif } template void _TestCSRSliceMatrix(DLContext ctx) { auto csr = CSR2(ctx); { // square auto r = aten::VecToIdArray(std::vector({0, 1, 3}), sizeof(IDX)*8, ctx); auto c = aten::VecToIdArray(std::vector({1, 2, 3}), sizeof(IDX)*8, ctx); auto x = aten::CSRSliceMatrix(csr, r, c); // [[1, 2, 0], // [0, 0, 0], // [0, 0, 0]] // data: [0, 2, 5] ASSERT_EQ(x.num_rows, 3); ASSERT_EQ(x.num_cols, 3); auto tp = aten::VecToIdArray(std::vector({0, 3, 3, 3}), sizeof(IDX)*8, ctx); auto ti = aten::VecToIdArray(std::vector({0, 1, 1}), sizeof(IDX)*8, ctx); auto td = aten::VecToIdArray(std::vector({0, 2, 5}), sizeof(IDX)*8, ctx); ASSERT_TRUE(ArrayEQ(x.indptr, tp)); ASSERT_TRUE(ArrayEQ(x.indices, ti)); ASSERT_TRUE(ArrayEQ(x.data, td)); } { // non-square auto r = aten::VecToIdArray(std::vector({0, 1, 2}), sizeof(IDX)*8, ctx); auto c = aten::VecToIdArray(std::vector({0, 1}), sizeof(IDX)*8, ctx); auto x = aten::CSRSliceMatrix(csr, r, c); // [[0, 1], // [1, 0], // [0, 0]] // data: [0, 3] ASSERT_EQ(x.num_rows, 3); ASSERT_EQ(x.num_cols, 2); auto tp = aten::VecToIdArray(std::vector({0, 1, 2, 2}), sizeof(IDX)*8, ctx); auto ti = aten::VecToIdArray(std::vector({1, 0}), sizeof(IDX)*8, ctx); auto td = aten::VecToIdArray(std::vector({0, 3}), sizeof(IDX)*8, ctx); ASSERT_TRUE(ArrayEQ(x.indptr, tp)); ASSERT_TRUE(ArrayEQ(x.indices, ti)); ASSERT_TRUE(ArrayEQ(x.data, td)); } { // empty slice auto r = aten::VecToIdArray(std::vector({2, 3}), sizeof(IDX)*8, ctx); auto c = aten::VecToIdArray(std::vector({0, 1}), sizeof(IDX)*8, ctx); auto x = aten::CSRSliceMatrix(csr, r, c); // [[0, 0], // [0, 0]] // data: [] ASSERT_EQ(x.num_rows, 2); ASSERT_EQ(x.num_cols, 2); auto tp = aten::VecToIdArray(std::vector({0, 0, 0}), sizeof(IDX)*8, ctx); auto ti = aten::VecToIdArray(std::vector({}), sizeof(IDX)*8, ctx); auto td = aten::VecToIdArray(std::vector({}), sizeof(IDX)*8, ctx); ASSERT_TRUE(ArrayEQ(x.indptr, tp)); ASSERT_TRUE(ArrayEQ(x.indices, ti)); ASSERT_TRUE(ArrayEQ(x.data, td)); } } TEST(SpmatTest, CSRSliceMatrix) { _TestCSRSliceMatrix(CPU); _TestCSRSliceMatrix(CPU); #ifdef DGL_USE_CUDA _TestCSRSliceMatrix(GPU); _TestCSRSliceMatrix(GPU); #endif } template void _TestCSRHasDuplicate(DLContext ctx) { auto csr = CSR1(ctx); ASSERT_FALSE(aten::CSRHasDuplicate(csr)); csr = CSR2(ctx); ASSERT_TRUE(aten::CSRHasDuplicate(csr)); } TEST(SpmatTest, CSRHasDuplicate) { _TestCSRHasDuplicate(CPU); _TestCSRHasDuplicate(CPU); #ifdef DGL_USE_CUDA _TestCSRHasDuplicate(GPU); _TestCSRHasDuplicate(GPU); #endif } template void _TestCSRSort(DLContext ctx) { auto csr = CSR1(ctx); ASSERT_FALSE(aten::CSRIsSorted(csr)); auto csr1 = aten::CSRSort(csr); ASSERT_FALSE(aten::CSRIsSorted(csr)); ASSERT_TRUE(aten::CSRIsSorted(csr1)); ASSERT_TRUE(csr1.sorted); aten::CSRSort_(&csr); ASSERT_TRUE(aten::CSRIsSorted(csr)); ASSERT_TRUE(csr.sorted); csr = CSR2(ctx); ASSERT_TRUE(aten::CSRIsSorted(csr)); } TEST(SpmatTest, CSRSort) { _TestCSRSort(CPU); _TestCSRSort(CPU); #ifdef DGL_USE_CUDA _TestCSRSort(GPU); _TestCSRSort(GPU); #endif } template void _TestCSRReorder() { auto csr = CSR2(); auto new_row = aten::VecToIdArray( std::vector({2, 0, 3, 1}), sizeof(IDX)*8, CTX); auto new_col = aten::VecToIdArray( std::vector({2, 0, 4, 3, 1}), sizeof(IDX)*8, CTX); auto new_csr = CSRReorder(csr, new_row, new_col); ASSERT_EQ(new_csr.num_rows, csr.num_rows); ASSERT_EQ(new_csr.num_cols, csr.num_cols); } TEST(SpmatTest, TestCSRReorder) { _TestCSRReorder(); _TestCSRReorder(); }