Skip to content

Commit e043274

Browse files
authored
Merge pull request #264 from sparcityeu/feature/max_degree_column
Feature/max degree column for sparse matrix features
2 parents b63a0e3 + 79c2285 commit e043274

6 files changed

Lines changed: 305 additions & 34 deletions

File tree

.github/workflows/testing.yml

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -17,40 +17,6 @@ env:
1717

1818
jobs:
1919

20-
test_win:
21-
runs-on: windows-latest
22-
defaults:
23-
run:
24-
shell: msys2 {0}
25-
26-
steps:
27-
- uses: actions/checkout@v3
28-
with:
29-
submodules: recursive
30-
31-
- name: MSYS2 Setup
32-
uses: msys2/setup-msys2@v2
33-
with:
34-
msystem: MINGW64
35-
update: false
36-
install: mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-python mingw-w64-x86_64-ninja mingw-w64-x86_64-lld
37-
38-
- name: Configure CMake
39-
working-directory: ${{github.workspace}}
40-
run: cmake -B build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_CXX_COMPILER=g++ -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_FLAGS="-fuse-ld=lld" -DRUN_TESTS=ON
41-
42-
- name: Build
43-
working-directory: ${{github.workspace}}
44-
run: cmake --build build --config ${{env.BUILD_TYPE}} -j 2
45-
46-
- name: Run Examples
47-
working-directory: ${{github.workspace}}/build/examples
48-
run: python3 run_all_examples.py
49-
50-
- name: Run Tests
51-
working-directory: ${{github.workspace}}/build
52-
run: ctest -V
53-
5420
test_mac:
5521
runs-on: macos-latest
5622

src/class_instantiation_list.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,13 @@
546546
"folder": null,
547547
"exceptions": null
548548
},
549+
{
550+
"template": "class MaxDegreeColumn<$id_type, $nnz_type, $value_type>",
551+
"filename": "max_degree_column.inc",
552+
"ifdef": null,
553+
"folder": null,
554+
"exceptions": null
555+
},
549556
{
550557
"template": "class AvgDegree<$id_type, $nnz_type, $value_type, $float_type>",
551558
"filename": "avg_degree.inc",
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
#include "max_degree_column.h"
2+
3+
#include <memory>
4+
#include <tuple>
5+
#include <unordered_map>
6+
#include <utility>
7+
#include <vector>
8+
9+
#include "sparsebase/utils/parameterizable.h"
10+
11+
namespace sparsebase::feature {
12+
13+
template <typename IDType, typename NNZType, typename ValueType>
14+
MaxDegreeColumn<IDType, NNZType, ValueType>::MaxDegreeColumn(ParamsType) {
15+
MaxDegreeColumn();
16+
}
17+
template <typename IDType, typename NNZType, typename ValueType>
18+
MaxDegreeColumn<IDType, NNZType, ValueType>::MaxDegreeColumn() {
19+
Register();
20+
this->params_ = std::shared_ptr<ParamsType>(new ParamsType());
21+
this->pmap_.insert({get_id_static(), this->params_});
22+
}
23+
24+
template <typename IDType, typename NNZType, typename ValueType>
25+
MaxDegreeColumn<IDType, NNZType, ValueType>::MaxDegreeColumn(
26+
const MaxDegreeColumn<IDType, NNZType, ValueType> &d) {
27+
Register();
28+
this->params_ = d.params_;
29+
this->pmap_ = d.pmap_;
30+
}
31+
32+
template <typename IDType, typename NNZType, typename ValueType>
33+
MaxDegreeColumn<IDType, NNZType, ValueType>::MaxDegreeColumn(
34+
const std::shared_ptr<ParamsType> r) {
35+
Register();
36+
this->params_ = r;
37+
this->pmap_[get_id_static()] = r;
38+
}
39+
40+
template <typename IDType, typename NNZType, typename ValueType>
41+
MaxDegreeColumn<IDType, NNZType, ValueType>::~MaxDegreeColumn() = default;
42+
43+
template <typename IDType, typename NNZType, typename ValueType>
44+
void MaxDegreeColumn<IDType, NNZType, ValueType>::Register() {
45+
this->RegisterFunction(
46+
{format::CSC<IDType, NNZType, ValueType>::get_id_static()},
47+
GetMaxDegreeColumnCSC);
48+
}
49+
50+
template <typename IDType, typename NNZType, typename ValueType>
51+
std::vector<std::type_index>
52+
MaxDegreeColumn<IDType, NNZType, ValueType>::get_sub_ids() {
53+
return {typeid(MaxDegreeColumn<IDType, NNZType, ValueType>)};
54+
}
55+
56+
template <typename IDType, typename NNZType, typename ValueType>
57+
std::vector<utils::Extractable *>
58+
MaxDegreeColumn<IDType, NNZType, ValueType>::get_subs() {
59+
return {new MaxDegreeColumn<IDType, NNZType, ValueType>(*this)};
60+
}
61+
62+
template <typename IDType, typename NNZType, typename ValueType>
63+
std::type_index MaxDegreeColumn<IDType, NNZType, ValueType>::get_id_static() {
64+
return typeid(MaxDegreeColumn<IDType, NNZType, ValueType>);
65+
}
66+
67+
template <typename IDType, typename NNZType, typename ValueType>
68+
std::unordered_map<std::type_index, std::any>
69+
MaxDegreeColumn<IDType, NNZType, ValueType>::Extract(format::Format *format,
70+
std::vector<context::Context *> c,
71+
bool convert_input) {
72+
return {{this->get_id(),
73+
std::forward<NNZType *>(GetMaxDegreeColumn(format, c, convert_input))}};
74+
};
75+
76+
template <typename IDType, typename NNZType, typename ValueType>
77+
NNZType *MaxDegreeColumn<IDType, NNZType, ValueType>::GetMaxDegreeColumn(
78+
format::Format *format, std::vector<context::Context *> c,
79+
bool convert_input) {
80+
return this->Execute(this->params_.get(), c, convert_input, format);
81+
}
82+
83+
template <typename IDType, typename NNZType, typename ValueType>
84+
std::tuple<std::vector<std::vector<format::Format *>>, NNZType *>
85+
MaxDegreeColumn<IDType, NNZType, ValueType>::GetMaxDegreeColumnCached(
86+
format::Format *format, std::vector<context::Context *> c,
87+
bool convert_input) {
88+
return this->CachedExecute(this->params_.get(), c, convert_input, false,
89+
format);
90+
}
91+
92+
template <typename IDType, typename NNZType, typename ValueType>
93+
NNZType *MaxDegreeColumn<IDType, NNZType, ValueType>::GetMaxDegreeColumnCSC(
94+
std::vector<format::Format *> formats, utils::Parameters *params) {
95+
auto csc = formats[0]->AsAbsolute<format::CSC<IDType, NNZType, ValueType>>();
96+
IDType num_col = csc->get_dimensions()[0];
97+
auto *cols = csc->get_col_ptr();
98+
NNZType *max_degree = new NNZType;
99+
*max_degree = cols[1] - cols[0];
100+
for (int i = 1; i < num_col; i++) {
101+
*max_degree = std::max(*max_degree, cols[i + 1] - cols[i]);
102+
}
103+
return max_degree;
104+
}
105+
106+
#if !defined(_HEADER_ONLY)
107+
#include "init/max_degree_column.inc"
108+
#endif
109+
} // namespace sparsebase::feature
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#include <vector>
2+
3+
#include "sparsebase/config.h"
4+
#include "sparsebase/feature/feature_preprocess_type.h"
5+
#include "sparsebase/format/csc.h"
6+
#include "sparsebase/utils/parameterizable.h"
7+
8+
#ifndef SPARSEBASE_PROJECT_MAX_DEGREE_COLUMN_H
9+
#define SPARSEBASE_PROJECT_MAX_DEGREE_COLUMN_H
10+
11+
namespace sparsebase::feature {
12+
//! Find the max degree in the graph representation of a format object
13+
template <typename IDType, typename NNZType, typename ValueType>
14+
class MaxDegreeColumn : public feature::FeaturePreprocessType<NNZType *> {
15+
public:
16+
//! An empty struct used for the parameters of Max Degree
17+
typedef utils::Parameters ParamsType;
18+
MaxDegreeColumn();
19+
MaxDegreeColumn(ParamsType);
20+
MaxDegreeColumn(const MaxDegreeColumn<IDType, NNZType, ValueType> &d);
21+
MaxDegreeColumn(std::shared_ptr<ParamsType>);
22+
std::unordered_map<std::type_index, std::any> Extract(
23+
format::Format *format, std::vector<context::Context *>,
24+
bool convert_input) override;
25+
std::vector<std::type_index> get_sub_ids() override;
26+
std::vector<utils::Extractable *> get_subs() override;
27+
static std::type_index get_id_static();
28+
29+
//! Max Degree Column executor function that carries out function matching
30+
/*!
31+
*
32+
* @param format a single format pointer to any format
33+
* @param contexts vector of contexts that can be used for extracting
34+
* features.
35+
* @param convert_input whether or not to convert the input format if that is
36+
* needed.
37+
* @return max degree column in the graph representation of `format`
38+
*/
39+
NNZType *GetMaxDegreeColumn(format::Format *format,
40+
std::vector<context::Context *> contexts,
41+
bool convert_input);
42+
std::
43+
tuple<std::vector<std::vector<format::Format *>>, NNZType *>
44+
//! Max Degree Column executor function that carries out function
45+
//! matching with cached output
46+
/*!
47+
*
48+
* @param format a single format pointer to any format
49+
* @param contexts vector of contexts that can be used for extracting
50+
* features.
51+
* @param convert_input whether or not to convert the input format if that
52+
* is needed.
53+
* @return max degree in the graph representation of `format`
54+
*/
55+
GetMaxDegreeColumnCached(format::Format *format,
56+
std::vector<context::Context *> contexts,
57+
bool convert_input);
58+
//! Max Degree Column implementation function for CSCs
59+
/*!
60+
*
61+
* @param formats A vector containing a single format pointer that should
62+
* point at a CSR object
63+
* @param params a Parameters pointer, though it
64+
* is not used in the function
65+
* @return max degree in the graph representations of 'format[0]'
66+
*/
67+
static NNZType *GetMaxDegreeColumnCSC(std::vector<format::Format *> formats,
68+
utils::Parameters *params);
69+
~MaxDegreeColumn();
70+
71+
protected:
72+
void Register();
73+
};
74+
75+
} // namespace sparsebase::feature
76+
#ifdef _HEADER_ONLY
77+
#include "sparsebase/feature/max_degree_column.cc"
78+
#endif
79+
80+
#endif // SPARSEBASE_PROJECT_MAX_DEGREE_COLUMN_H

tests/suites/sparsebase/feature/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,15 @@ target_link_libraries(sparsebase_feature_triangle_count_tests.test gtest gtest_m
124124

125125
add_test(NAME sparsebase_feature_triangle_count_tests.test COMMAND sparsebase_feature_triangle_count_tests.test)
126126

127+
if(${USE_CUDA})
128+
set_source_files_properties(max_degree_column_tests.cc PROPERTIES LANGUAGE CUDA)
129+
endif()
130+
add_executable(sparsebase_feature_max_degree_column_tests.test max_degree_column_tests.cc)
131+
target_link_libraries(sparsebase_feature_max_degree_column_tests.test sparsebase)
132+
target_link_libraries(sparsebase_feature_max_degree_column_tests.test gtest gtest_main)
133+
134+
add_test(NAME sparsebase_feature_max_degree_column_tests.test COMMAND sparsebase_feature_max_degree_column_tests.test)
135+
127136
if(${USE_CUDA})
128137
set_source_files_properties(median_degree_column_tests.cc PROPERTIES LANGUAGE CUDA)
129138
endif()
@@ -177,3 +186,4 @@ target_link_libraries(sparsebase_feature_geometric_avg_degree_column_tests.test
177186
target_link_libraries(sparsebase_feature_geometric_avg_degree_column_tests.test gtest gtest_main)
178187

179188
add_test(NAME sparsebase_feature_geometric_avg_degree_column_tests.test COMMAND sparsebase_feature_geometric_avg_degree_column_tests.test)
189+
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#include <memory>
2+
#include <typeindex>
3+
#include <typeinfo>
4+
#include <utility>
5+
#include <vector>
6+
7+
#include "gtest/gtest.h"
8+
#include "sparsebase/bases/reorder_base.h"
9+
#include "sparsebase/context/context.h"
10+
#include "sparsebase/feature/max_degree_column.h"
11+
#include "sparsebase/format/coo.h"
12+
#include "sparsebase/format/csc.h"
13+
#include "sparsebase/format/csr.h"
14+
#include "sparsebase/format/format_order_one.h"
15+
#include "sparsebase/format/format_order_two.h"
16+
#include "sparsebase/reorder/degree_reorder.h"
17+
#include "sparsebase/reorder/reorderer.h"
18+
#include "sparsebase/utils/exception.h"
19+
20+
using namespace sparsebase;
21+
22+
using namespace sparsebase::reorder;
23+
using namespace sparsebase::bases;
24+
using namespace sparsebase::feature;
25+
#include "../functionality_common.inc"
26+
27+
class MaxDegreeColumnTest : public ::testing::Test {
28+
protected:
29+
feature::MaxDegreeColumn<int, int, int> feature;
30+
31+
struct Params1 : sparsebase::utils::Parameters {};
32+
struct Params2 : sparsebase::utils::Parameters {};
33+
};
34+
35+
TEST_F(MaxDegreeColumnTest, AllTests) {
36+
// test get_sub_ids
37+
EXPECT_EQ(feature.get_sub_ids().size(), 1);
38+
EXPECT_EQ(feature.get_sub_ids()[0], std::type_index(typeid(feature)));
39+
40+
// Test get_subs
41+
auto subs = feature.get_subs();
42+
// a single sub-feature
43+
EXPECT_EQ(subs.size(), 1);
44+
// same type as feature but different address
45+
auto &feat = *(subs[0]);
46+
EXPECT_EQ(std::type_index(typeid(feat)), std::type_index(typeid(feature)));
47+
EXPECT_NE(subs[0], &feature);
48+
49+
// Check GetMaxDegreeCSR implementation function
50+
Params1 p1;
51+
auto max_degree =
52+
feature::MaxDegreeColumn<int, int, int>::GetMaxDegreeColumnCSC({&global_csc}, &p1);
53+
54+
auto max_in_degrees = 0;
55+
for (int i = 0; i < n; ++i)
56+
max_in_degrees = std::max(max_in_degrees, degrees[i]);
57+
EXPECT_EQ(*max_degree, max_in_degrees);
58+
delete max_degree;
59+
// Check GetMaxDegree
60+
max_degree = feature.GetMaxDegreeColumn(&global_csc, {&cpu_context}, true);
61+
EXPECT_EQ(*max_degree, max_in_degrees);
62+
delete max_degree;
63+
64+
max_degree = feature.GetMaxDegreeColumn(&global_csc, {&cpu_context}, false);
65+
EXPECT_EQ(*max_degree, max_in_degrees);
66+
delete max_degree;
67+
68+
// Check GetMaxDegree with conversion
69+
max_degree = feature.GetMaxDegreeColumn(&global_coo, {&cpu_context}, true);
70+
EXPECT_EQ(*max_degree, max_in_degrees);
71+
72+
EXPECT_THROW(feature.GetMaxDegreeColumn(&global_coo, {&cpu_context}, false),
73+
utils::DirectExecutionNotAvailableException<
74+
std::vector<std::type_index>>);
75+
// Check Extract
76+
auto feature_map = feature.Extract(&global_csc, {&cpu_context}, true);
77+
// Check map size and type
78+
EXPECT_EQ(feature_map.size(), 1);
79+
for (auto feat : feature_map) {
80+
EXPECT_EQ(feat.first, std::type_index(typeid(feature)));
81+
}
82+
83+
EXPECT_EQ(*std::any_cast<int *>(feature_map[feature.get_id()]), max_in_degrees);
84+
85+
// Check Extract with conversion
86+
feature_map = feature.Extract(&global_coo, {&cpu_context}, true);
87+
// Check map size and type
88+
EXPECT_EQ(feature_map.size(), 1);
89+
for (auto feat : feature_map) {
90+
EXPECT_EQ(feat.first, std::type_index(typeid(feature)));
91+
}
92+
93+
EXPECT_EQ(*std::any_cast<int *>(feature_map[feature.get_id()]), max_in_degrees);
94+
95+
EXPECT_THROW(feature.Extract(&global_coo, {&cpu_context}, false),
96+
utils::DirectExecutionNotAvailableException<
97+
std::vector<std::type_index>>);
98+
delete max_degree;
99+
}

0 commit comments

Comments
 (0)