Skip to content

Commit

Permalink
Merge pull request #265 from sparcityeu/feature/min_degree_column
Browse files Browse the repository at this point in the history
Feature/min degree column
  • Loading branch information
kamerkaya authored Dec 20, 2023
2 parents d5187c2 + 3aff229 commit 3eafb24
Show file tree
Hide file tree
Showing 6 changed files with 305 additions and 1 deletion.
7 changes: 7 additions & 0 deletions src/class_instantiation_list.json
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,13 @@
"folder": null,
"exceptions": null
},
{
"template": "class MinDegreeColumn<$id_type, $nnz_type, $value_type>",
"filename": "min_degree_column.inc",
"ifdef": null,
"folder": null,
"exceptions": null
},
{
"template": "class MaxDegree<$id_type, $nnz_type, $value_type>",
"filename": "max_degree.inc",
Expand Down
109 changes: 109 additions & 0 deletions src/sparsebase/feature/min_degree_column.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#include "min_degree_column.h"

#include <memory>
#include <tuple>
#include <unordered_map>
#include <utility>
#include <vector>

#include "sparsebase/utils/parameterizable.h"

namespace sparsebase::feature {

template <typename IDType, typename NNZType, typename ValueType>
MinDegreeColumn<IDType, NNZType, ValueType>::MinDegreeColumn(ParamsType) {
MinDegreeColumn();
}
template <typename IDType, typename NNZType, typename ValueType>
MinDegreeColumn<IDType, NNZType, ValueType>::MinDegreeColumn() {
Register();
this->params_ = std::shared_ptr<ParamsType>(new ParamsType());
this->pmap_.insert({get_id_static(), this->params_});
}

template <typename IDType, typename NNZType, typename ValueType>
MinDegreeColumn<IDType, NNZType, ValueType>::MinDegreeColumn(
const MinDegreeColumn<IDType, NNZType, ValueType> &d) {
Register();
this->params_ = d.params_;
this->pmap_ = d.pmap_;
}

template <typename IDType, typename NNZType, typename ValueType>
MinDegreeColumn<IDType, NNZType, ValueType>::MinDegreeColumn(
const std::shared_ptr<ParamsType> r) {
Register();
this->params_ = r;
this->pmap_[get_id_static()] = r;
}

template <typename IDType, typename NNZType, typename ValueType>
MinDegreeColumn<IDType, NNZType, ValueType>::~MinDegreeColumn() = default;

template <typename IDType, typename NNZType, typename ValueType>
void MinDegreeColumn<IDType, NNZType, ValueType>::Register() {
this->RegisterFunction(
{format::CSC<IDType, NNZType, ValueType>::get_id_static()},
GetMinDegreeColumnCSC);
}

template <typename IDType, typename NNZType, typename ValueType>
std::vector<std::type_index>
MinDegreeColumn<IDType, NNZType, ValueType>::get_sub_ids() {
return {typeid(MinDegreeColumn<IDType, NNZType, ValueType>)};
}

template <typename IDType, typename NNZType, typename ValueType>
std::vector<utils::Extractable *>
MinDegreeColumn<IDType, NNZType, ValueType>::get_subs() {
return {new MinDegreeColumn<IDType, NNZType, ValueType>(*this)};
}

template <typename IDType, typename NNZType, typename ValueType>
std::type_index MinDegreeColumn<IDType, NNZType, ValueType>::get_id_static() {
return typeid(MinDegreeColumn<IDType, NNZType, ValueType>);
}

template <typename IDType, typename NNZType, typename ValueType>
std::unordered_map<std::type_index, std::any>
MinDegreeColumn<IDType, NNZType, ValueType>::Extract(format::Format *format,
std::vector<context::Context *> c,
bool convert_input) {
return {{this->get_id(),
std::forward<NNZType *>(GetMinDegreeColumn(format, c, convert_input))}};
};

template <typename IDType, typename NNZType, typename ValueType>
NNZType *MinDegreeColumn<IDType, NNZType, ValueType>::GetMinDegreeColumn(
format::Format *format, std::vector<context::Context *> c,
bool convert_input) {
return this->Execute(this->params_.get(), c, convert_input, format);
}

template <typename IDType, typename NNZType, typename ValueType>
std::tuple<std::vector<std::vector<format::Format *>>, NNZType *>
MinDegreeColumn<IDType, NNZType, ValueType>::GetMinDegreeColumnCached(
format::Format *format, std::vector<context::Context *> c,
bool convert_input) {
return this->CachedExecute(this->params_.get(), c, convert_input, false,
format);
}

template <typename IDType, typename NNZType, typename ValueType>
NNZType *MinDegreeColumn<IDType, NNZType, ValueType>::GetMinDegreeColumnCSC(
std::vector<format::Format *> formats, utils::Parameters *params) {
auto csc = formats[0]->AsAbsolute<format::CSC<IDType, NNZType, ValueType>>();
IDType num_col = csc->get_dimensions()[0];
auto *cols = csc->get_col_ptr();
NNZType *min_degree = new NNZType;
*min_degree = cols[1] - cols[0];
for (int i = 1; i < num_col; i++) {
*min_degree = std::min(*min_degree, cols[i + 1] - cols[i]);
}
return min_degree;
}

#if !defined(_HEADER_ONLY)
#include "init/min_degree_column.inc"
#endif
} // namespace sparsebase::feature
80 changes: 80 additions & 0 deletions src/sparsebase/feature/min_degree_column.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#include <vector>

#include "sparsebase/config.h"
#include "sparsebase/feature/feature_preprocess_type.h"
#include "sparsebase/format/csc.h"
#include "sparsebase/utils/parameterizable.h"

#ifndef SPARSEBASE_PROJECT_MIN_DEGREE_COLUMN_H
#define SPARSEBASE_PROJECT_MIN_DEGREE_COLUMN_H

namespace sparsebase::feature {
//! Find the min degree in the graph representation of a format object
template <typename IDType, typename NNZType, typename ValueType>
class MinDegreeColumn : public feature::FeaturePreprocessType<NNZType *> {
public:
//! An empty struct used for the parameters of Min Degree
typedef utils::Parameters ParamsType;
MinDegreeColumn();
MinDegreeColumn(ParamsType);
MinDegreeColumn(const MinDegreeColumn<IDType, NNZType, ValueType> &d);
MinDegreeColumn(std::shared_ptr<ParamsType>);
std::unordered_map<std::type_index, std::any> Extract(
format::Format *format, std::vector<context::Context *>,
bool convert_input) override;
std::vector<std::type_index> get_sub_ids() override;
std::vector<utils::Extractable *> get_subs() override;
static std::type_index get_id_static();

//! Min Degree executor function that carries out function matching
/*!
*
* @param format a single format pointer to any format
* @param contexts vector of contexts that can be used for extracting
* features.
* @param convert_input whether or not to convert the input format if that is
* needed.
* @return min degree in the graph representation of `format`
*/
NNZType *GetMinDegreeColumn(format::Format *format,
std::vector<context::Context *> contexts,
bool convert_input);
std::
tuple<std::vector<std::vector<format::Format *>>, NNZType *>
//! Min Degree executor function that carries out function
//! matching with cached output
/*!
*
* @param format a single format pointer to any format
* @param contexts vector of contexts that can be used for extracting
* features.
* @param convert_input whether or not to convert the input format if that
* is needed.
* @return min degree in the graph representation of `format`
*/
GetMinDegreeColumnCached(format::Format *format,
std::vector<context::Context *> contexts,
bool convert_input);
//! Min Degree implementation function for CSCs
/*!
*
* @param formats A vector containing a single format pointer that should
* point at a CSR object
* @param params a Parameters pointer, though it
* is not used in the function
* @return min degree in the graph representations of 'format[0]'
*/
static NNZType *GetMinDegreeColumnCSC(std::vector<format::Format *> formats,
utils::Parameters *params);
~MinDegreeColumn();

protected:
void Register();
};

} // namespace sparsebase::feature
#ifdef _HEADER_ONLY
#include "sparsebase/feature/min_degree_column.cc"
#endif

#endif // SPARSEBASE_PROJECT_MIN_DEGREE_COLUMN_H
9 changes: 9 additions & 0 deletions tests/suites/sparsebase/feature/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,15 @@ target_link_libraries(sparsebase_feature_triangle_count_tests.test gtest gtest_m

add_test(NAME sparsebase_feature_triangle_count_tests.test COMMAND sparsebase_feature_triangle_count_tests.test)

if(${USE_CUDA})
set_source_files_properties(min_degree_column_tests.cc PROPERTIES LANGUAGE CUDA)
endif()
add_executable(sparsebase_feature_min_degree_column_tests.test min_degree_column_tests.cc)
target_link_libraries(sparsebase_feature_min_degree_column_tests.test sparsebase)
target_link_libraries(sparsebase_feature_min_degree_column_tests.test gtest gtest_main)

add_test(NAME sparsebase_feature_min_degree_column_tests.test COMMAND sparsebase_feature_min_degree_column_tests.test)

if(${USE_CUDA})
set_source_files_properties(standard_deviation_degree_column_tests.cc PROPERTIES LANGUAGE CUDA)
endif()
Expand Down
99 changes: 99 additions & 0 deletions tests/suites/sparsebase/feature/min_degree_column_tests.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#include <memory>
#include <typeindex>
#include <typeinfo>
#include <utility>
#include <vector>

#include "gtest/gtest.h"
#include "sparsebase/bases/reorder_base.h"
#include "sparsebase/context/context.h"
#include "sparsebase/feature/min_degree_column.h"
#include "sparsebase/format/coo.h"
#include "sparsebase/format/csc.h"
#include "sparsebase/format/csr.h"
#include "sparsebase/format/format_order_one.h"
#include "sparsebase/format/format_order_two.h"
#include "sparsebase/reorder/degree_reorder.h"
#include "sparsebase/reorder/reorderer.h"
#include "sparsebase/utils/exception.h"

using namespace sparsebase;
using namespace sparsebase::reorder;
using namespace sparsebase::bases;
using namespace sparsebase::feature;
#include "../functionality_common.inc"

class MinDegreeColumnTest : public ::testing::Test {
protected:
feature::MinDegreeColumn<int, int, int> feature;

struct Params1 : sparsebase::utils::Parameters {};
struct Params2 : sparsebase::utils::Parameters {};
};

TEST_F(MinDegreeColumnTest, AllTests) {
// test get_sub_ids
EXPECT_EQ(feature.get_sub_ids().size(), 1);
EXPECT_EQ(feature.get_sub_ids()[0], std::type_index(typeid(feature)));

// Test get_subs
auto subs = feature.get_subs();
// a single sub-feature
EXPECT_EQ(subs.size(), 1);
// same type as feature but different address
auto &feat = *(subs[0]);
EXPECT_EQ(std::type_index(typeid(feat)), std::type_index(typeid(feature)));
EXPECT_NE(subs[0], &feature);

// Check GetMinDegreeColumnCSC implementation function
Params1 p1;
auto min_degree =
feature::MinDegreeColumn<int, int, int>::GetMinDegreeColumnCSC({&global_csc}, &p1);

auto min_in_degrees = (int)1e9;
for (int i = 0; i < n; ++i)
min_in_degrees = std::min(min_in_degrees, degrees[i]);
EXPECT_EQ(*min_degree, min_in_degrees);
delete min_degree;
// Check GetMinDegree
min_degree = feature.GetMinDegreeColumn(&global_csc, {&cpu_context}, true);
EXPECT_EQ(*min_degree, min_in_degrees);
delete min_degree;

min_degree = feature.GetMinDegreeColumn(&global_csc, {&cpu_context}, false);
EXPECT_EQ(*min_degree, min_in_degrees);
delete min_degree;

// Check GetMinDegree with conversion
min_degree = feature.GetMinDegreeColumn(&global_coo, {&cpu_context}, true);
EXPECT_EQ(*min_degree, min_in_degrees);

EXPECT_THROW(feature.GetMinDegreeColumn(&global_coo, {&cpu_context}, false),
utils::DirectExecutionNotAvailableException<
std::vector<std::type_index>>);
// Check Extract
auto feature_map = feature.Extract(&global_csc, {&cpu_context}, true);
// Check map size and type
EXPECT_EQ(feature_map.size(), 1);
for (auto feat : feature_map) {
EXPECT_EQ(feat.first, std::type_index(typeid(feature)));
}

EXPECT_EQ(*std::any_cast<int *>(feature_map[feature.get_id()]), min_in_degrees);

// Check Extract with conversion
feature_map = feature.Extract(&global_coo, {&cpu_context}, true);
// Check map size and type
EXPECT_EQ(feature_map.size(), 1);
for (auto feat : feature_map) {
EXPECT_EQ(feat.first, std::type_index(typeid(feature)));
}

EXPECT_EQ(*std::any_cast<int *>(feature_map[feature.get_id()]), min_in_degrees);

EXPECT_THROW(feature.Extract(&global_coo, {&cpu_context}, false),
utils::DirectExecutionNotAvailableException<
std::vector<std::type_index>>);
delete min_degree;
}

2 changes: 1 addition & 1 deletion tests/suites/sparsebase/functionality_common.inc
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ format::Array<float> inv_arr(n, reordered_array, format::kNotOwned);
format::CSR<int, int, int> global_csr(n, n, row_ptr, cols, vals,
format::kNotOwned);
format::CSC<int, int, int> global_csc(n, n, col_ptr, row_ind, vals_csr,
format::kNotOwned);
format::kNotOwned);
format::COO<int, int, int> global_coo(n, n, nnz, rows, cols, vals,
format::kNotOwned);
sparsebase::context::CPUContext cpu_context;
Expand Down

0 comments on commit 3eafb24

Please sign in to comment.