From 32f699206c60475ee3d61299171759e84a4e69e1 Mon Sep 17 00:00:00 2001 From: barisyakar Date: Mon, 24 Jul 2023 20:29:44 +0300 Subject: [PATCH 1/2] Added the following features for degrees: median, standard deviation, coefficient of variation, and geometric average. --- src/class_instantiation_list.json | 28 ++++ .../coefficient_of_variation_degree.cc | 147 +++++++++++++++++ .../feature/coefficient_of_variation_degree.h | 105 ++++++++++++ .../feature/geometric_avg_degree.cc | 144 +++++++++++++++++ src/sparsebase/feature/geometric_avg_degree.h | 105 ++++++++++++ src/sparsebase/feature/median_degree.cc | 152 ++++++++++++++++++ src/sparsebase/feature/median_degree.h | 105 ++++++++++++ .../feature/standard_deviation_degree.cc | 147 +++++++++++++++++ .../feature/standard_deviation_degree.h | 105 ++++++++++++ 9 files changed, 1038 insertions(+) create mode 100644 src/sparsebase/feature/coefficient_of_variation_degree.cc create mode 100644 src/sparsebase/feature/coefficient_of_variation_degree.h create mode 100644 src/sparsebase/feature/geometric_avg_degree.cc create mode 100644 src/sparsebase/feature/geometric_avg_degree.h create mode 100644 src/sparsebase/feature/median_degree.cc create mode 100644 src/sparsebase/feature/median_degree.h create mode 100644 src/sparsebase/feature/standard_deviation_degree.cc create mode 100644 src/sparsebase/feature/standard_deviation_degree.h diff --git a/src/class_instantiation_list.json b/src/class_instantiation_list.json index 83222b78..e277f6cd 100644 --- a/src/class_instantiation_list.json +++ b/src/class_instantiation_list.json @@ -532,6 +532,34 @@ "folder": null, "exceptions": null }, + { + "template": "class MedianDegree<$id_type, $nnz_type, $value_type, $float_type>", + "filename": "median_degree.inc", + "ifdef": null, + "folder": null, + "exceptions": null + }, + { + "template": "class StandardDeviationDegree<$id_type, $nnz_type, $value_type, $float_type>", + "filename": "standard_deviation_degree.inc", + "ifdef": null, + "folder": null, + "exceptions": null + }, + { + "template": "class CoefficientOfVariationDegree<$id_type, $nnz_type, $value_type, $float_type>", + "filename": "coefficient_of_variation_degree.inc", + "ifdef": null, + "folder": null, + "exceptions": null + }, + { + "template": "class GeometricAvgDegree<$id_type, $nnz_type, $value_type, $float_type>", + "filename": "geometric_avg_degree.inc", + "ifdef": null, + "folder": null, + "exceptions": null + }, { "template": "class MinMaxAvgDegree<$id_type, $nnz_type, $value_type, $float_type>", "filename": "min_max_avg_degree.inc", diff --git a/src/sparsebase/feature/coefficient_of_variation_degree.cc b/src/sparsebase/feature/coefficient_of_variation_degree.cc new file mode 100644 index 00000000..fab9c9e0 --- /dev/null +++ b/src/sparsebase/feature/coefficient_of_variation_degree.cc @@ -0,0 +1,147 @@ +#include "sparsebase/feature/coefficient_of_variation_degree.h" + +#include +#include +#include +#include +#include +#include + +#include "sparsebase/utils/parameterizable.h" + +namespace sparsebase::feature { + +template +CoefficientOfVariationDegree::CoefficientOfVariationDegree() { + Register(); + this->params_ = + std::shared_ptr(new CoefficientOfVariationDegreeParams()); + this->pmap_.insert({get_id_static(), this->params_}); +} +template +CoefficientOfVariationDegree::CoefficientOfVariationDegree( + CoefficientOfVariationDegreeParams params) { + CoefficientOfVariationDegree(); +} + +template +CoefficientOfVariationDegree::CoefficientOfVariationDegree( + const CoefficientOfVariationDegree &d) { + Register(); + this->params_ = d.params_; + this->pmap_ = d.pmap_; +} + +template +CoefficientOfVariationDegree::CoefficientOfVariationDegree( + const std::shared_ptr p) { + Register(); + this->params_ = p; + this->pmap_[get_id_static()] = p; +} + +template +void CoefficientOfVariationDegree::Register() { + this->RegisterFunction( + {format::CSR::get_id_static()}, + GetCoefficientOfVariationDegreeCSR); +} + +template +std::unordered_map +CoefficientOfVariationDegree::Extract( + format::Format *format, std::vector c, + bool convert_input) { + return {{this->get_id(), std::forward( + GetCoefficientOfVariationDegree(format, c, convert_input))}}; +}; + +template +std::vector +CoefficientOfVariationDegree::get_sub_ids() { + return {typeid(CoefficientOfVariationDegree)}; +} + +template +std::vector +CoefficientOfVariationDegree::get_subs() { + return { + new CoefficientOfVariationDegree(*this)}; +} + +template +std::type_index +CoefficientOfVariationDegree::get_id_static() { + return typeid(CoefficientOfVariationDegree); +} + +template +CoefficientOfVariationDegree::~CoefficientOfVariationDegree() = default; + +template +std::tuple>, FeatureType *> +CoefficientOfVariationDegree:: + GetCoefficientOfVariationDegreeCached(format::Format *format, + std::vector contexts, + bool convert_input) { + CoefficientOfVariationDegreeParams params; + return this->CachedExecute(¶ms, contexts, convert_input, false, + format); // func(sfs, this->params_.get()); +} +template +FeatureType * +CoefficientOfVariationDegree::GetCoefficientOfVariationDegree( + format::Format *format, std::vector contexts, + bool convert_input) { + CoefficientOfVariationDegreeParams params; + return this->Execute(¶ms, contexts, convert_input, + format); // func(sfs, this->params_.get()); +} + +template +FeatureType * +CoefficientOfVariationDegree::GetCoefficientOfVariationDegree( + object::Graph *obj, + std::vector contexts, bool convert_input) { + format::Format *format = obj->get_connectivity(); + return this->Execute(this->params_.get(), contexts, convert_input, + format); // func(sfs, this->params_.get()); +} + +template +FeatureType *CoefficientOfVariationDegree:: + GetCoefficientOfVariationDegreeCSR(std::vector formats, + utils::Parameters *params) { + auto csr = formats[0]->AsAbsolute>(); + IDType num_vertices = csr->get_dimensions()[0]; + FeatureType avg_degree; + auto *rows = csr->get_row_ptr(); + NNZType degree_sum = rows[num_vertices] - rows[0]; + avg_degree = degree_sum / (FeatureType)num_vertices; + FeatureType standard_deviation_degree = 0; + for (int i = 0; i < num_vertices; i++) { + standard_deviation_degree += (rows[i + 1] - rows[i] - avg_degree)*(rows[i + 1] - rows[i] - avg_degree); + } + return new FeatureType(sqrt(standard_deviation_degree)/avg_degree); +} + +#if !defined(_HEADER_ONLY) +#include "init/coefficient_of_variation_degree.inc" +#endif +} // namespace sparsebase::feature diff --git a/src/sparsebase/feature/coefficient_of_variation_degree.h b/src/sparsebase/feature/coefficient_of_variation_degree.h new file mode 100644 index 00000000..22499f7a --- /dev/null +++ b/src/sparsebase/feature/coefficient_of_variation_degree.h @@ -0,0 +1,105 @@ +#include + +#include "sparsebase/config.h" +#include "sparsebase/feature/feature_preprocess_type.h" +#include "sparsebase/format/csr.h" +#include "sparsebase/object/object.h" +#include "sparsebase/utils/parameterizable.h" + +#ifndef SPARSEBASE_PROJECT_COEFFICIENT_OF_VARIATION_DEGREE_DISTRIBUTION_H +#define SPARSEBASE_PROJECT_COEFFICIENT_OF_VARIATION_DEGREE_DISTRIBUTION_H +namespace sparsebase::feature { + +//! An empty struct used for the parameters of CoefficientOfVariationDegree +struct CoefficientOfVariationDegreeParams : utils::Parameters {}; +//! Find the coefficient of variation degree of the graph representation of a format object +/*! + * + * @tparam FeatureType the type in which the distribution value are returned -- + * should be a floating type + */ +template +class CoefficientOfVariationDegree + : public feature::FeaturePreprocessType { + public: + //! An empty struct used for the parameters of CoefficientOfVariationDegree + typedef CoefficientOfVariationDegreeParams ParamsType; + CoefficientOfVariationDegree(); + CoefficientOfVariationDegree(CoefficientOfVariationDegreeParams); + CoefficientOfVariationDegree(const CoefficientOfVariationDegree &); + CoefficientOfVariationDegree(std::shared_ptr); + virtual std::unordered_map Extract( + format::Format *format, std::vector, + bool convert_input); + virtual std::vector get_sub_ids(); + virtual std::vector get_subs(); + static std::type_index get_id_static(); + + //! Coefficient of variation degree generation 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 + * @param convert_input whether or not to convert the input format if that is + * needed. + * @return coefficient of variation degree in the graph representation of `format` + */ + FeatureType *GetCoefficientOfVariationDegree(format::Format *format, + std::vector contexts, + bool convert_input); + //! Coefficient of variation degree generation executor function that carries out function + //! matching on a Graph + /*! + * + * @param object a single format pointer to any format + * @param contexts vector of contexts that can be used for extracting + * @param convert_input whether or not to convert the input format if that is + * needed. + * @return coefficient of variation degree in the graph + */ + FeatureType *GetCoefficientOfVariationDegree( + object::Graph *object, + std::vector contexts, bool convert_input); + //! Coefficient of variation degree generation executor function that carries out function + //! matching with cached outputs + /*! + * Generates the coefficient of variation degree of the passed format. If the input format + * was converted to other format types, the converting results are also + * returned with the 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 A tuple with the first element being a vector of Format* + * where each pointer in the output points at the format that the corresponds + * Format object from the the input was converted to. If an input Format + * wasn't converted, the output pointer will point at nullptr. The second + * element is a pointer pointing to coefficient of variation degree + */ + std::tuple>, FeatureType *> + GetCoefficientOfVariationDegreeCached(format::Format *format, + std::vector contexts, + bool convert_input); + + static FeatureType + * + //! Coefficient of variation degree generation implementation function for CSRs + /*! + * + * @param format a single format pointer to any format + * @return coefficient of variation degree in the graph representation of `formats[0]` + */ + GetCoefficientOfVariationDegreeCSR(std::vector formats, + utils::Parameters *params); + ~CoefficientOfVariationDegree(); + + protected: + void Register(); +}; +} // namespace sparsebase::feature +#ifdef _HEADER_ONLY +#include "sparsebase/feature/coefficient_of_variation_degree.cc" +#endif +#endif // SPARSEBASE_PROJECT_COEFFICIENT_OF_VARIATION_DEGREE_DISTRIBUTION_H diff --git a/src/sparsebase/feature/geometric_avg_degree.cc b/src/sparsebase/feature/geometric_avg_degree.cc new file mode 100644 index 00000000..ed543b1c --- /dev/null +++ b/src/sparsebase/feature/geometric_avg_degree.cc @@ -0,0 +1,144 @@ +#include "sparsebase/feature/geometric_avg_degree.h" + +#include +#include +#include +#include +#include +#include + +#include "sparsebase/utils/parameterizable.h" + +namespace sparsebase::feature { + +template +GeometricAvgDegree::GeometricAvgDegree() { + Register(); + this->params_ = + std::shared_ptr(new GeometricAvgDegreeParams()); + this->pmap_.insert({get_id_static(), this->params_}); +} +template +GeometricAvgDegree::GeometricAvgDegree( + GeometricAvgDegreeParams params) { + GeometricAvgDegree(); +} + +template +GeometricAvgDegree::GeometricAvgDegree( + const GeometricAvgDegree &d) { + Register(); + this->params_ = d.params_; + this->pmap_ = d.pmap_; +} + +template +GeometricAvgDegree::GeometricAvgDegree( + const std::shared_ptr p) { + Register(); + this->params_ = p; + this->pmap_[get_id_static()] = p; +} + +template +void GeometricAvgDegree::Register() { + this->RegisterFunction( + {format::CSR::get_id_static()}, + GetGeometricAvgDegreeCSR); +} + +template +std::unordered_map +GeometricAvgDegree::Extract( + format::Format *format, std::vector c, + bool convert_input) { + return {{this->get_id(), std::forward( + GetGeometricAvgDegree(format, c, convert_input))}}; +}; + +template +std::vector +GeometricAvgDegree::get_sub_ids() { + return {typeid(GeometricAvgDegree)}; +} + +template +std::vector +GeometricAvgDegree::get_subs() { + return { + new GeometricAvgDegree(*this)}; +} + +template +std::type_index +GeometricAvgDegree::get_id_static() { + return typeid(GeometricAvgDegree); +} + +template +GeometricAvgDegree::~GeometricAvgDegree() = default; + +template +std::tuple>, FeatureType *> +GeometricAvgDegree:: + GetGeometricAvgDegreeCached(format::Format *format, + std::vector contexts, + bool convert_input) { + GeometricAvgDegreeParams params; + return this->CachedExecute(¶ms, contexts, convert_input, false, + format); // func(sfs, this->params_.get()); +} +template +FeatureType * +GeometricAvgDegree::GetGeometricAvgDegree( + format::Format *format, std::vector contexts, + bool convert_input) { + GeometricAvgDegreeParams params; + return this->Execute(¶ms, contexts, convert_input, + format); // func(sfs, this->params_.get()); +} + +template +FeatureType * +GeometricAvgDegree::GetGeometricAvgDegree( + object::Graph *obj, + std::vector contexts, bool convert_input) { + format::Format *format = obj->get_connectivity(); + return this->Execute(this->params_.get(), contexts, convert_input, + format); // func(sfs, this->params_.get()); +} + +template +FeatureType *GeometricAvgDegree:: + GetGeometricAvgDegreeCSR(std::vector formats, + utils::Parameters *params) { + auto csr = formats[0]->AsAbsolute>(); + IDType num_vertices = csr->get_dimensions()[0]; + auto *rows = csr->get_row_ptr(); + FeatureType sum = 0.0; + for (int i = 0; i < num_vertices; i++) { + sum += log(rows[i + 1] - rows[i]); + } + return new FeatureType(exp(sum/num_vertices)); +} + +#if !defined(_HEADER_ONLY) +#include "init/geometric_avg_degree.inc" +#endif +} // namespace sparsebase::feature diff --git a/src/sparsebase/feature/geometric_avg_degree.h b/src/sparsebase/feature/geometric_avg_degree.h new file mode 100644 index 00000000..57cbb449 --- /dev/null +++ b/src/sparsebase/feature/geometric_avg_degree.h @@ -0,0 +1,105 @@ +#include + +#include "sparsebase/config.h" +#include "sparsebase/feature/feature_preprocess_type.h" +#include "sparsebase/format/csr.h" +#include "sparsebase/object/object.h" +#include "sparsebase/utils/parameterizable.h" + +#ifndef SPARSEBASE_PROJECT_GEOMETRIC_AVG_DEGREE_DISTRIBUTION_H +#define SPARSEBASE_PROJECT_GEOMETRIC_AVG_DEGREE_DISTRIBUTION_H +namespace sparsebase::feature { + +//! An empty struct used for the parameters of GeometricAvgDegree +struct GeometricAvgDegreeParams : utils::Parameters {}; +//! Find the geometric average degree of the graph representation of a format object +/*! + * + * @tparam FeatureType the type in which the distribution value are returned -- + * should be a floating type + */ +template +class GeometricAvgDegree + : public feature::FeaturePreprocessType { + public: + //! An empty struct used for the parameters of GeometricAvgDegree + typedef GeometricAvgDegreeParams ParamsType; + GeometricAvgDegree(); + GeometricAvgDegree(GeometricAvgDegreeParams); + GeometricAvgDegree(const GeometricAvgDegree &); + GeometricAvgDegree(std::shared_ptr); + virtual std::unordered_map Extract( + format::Format *format, std::vector, + bool convert_input); + virtual std::vector get_sub_ids(); + virtual std::vector get_subs(); + static std::type_index get_id_static(); + + //! Geometric average degree generation 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 + * @param convert_input whether or not to convert the input format if that is + * needed. + * @return geometric average degree in the graph representation of `format` + */ + FeatureType *GetGeometricAvgDegree(format::Format *format, + std::vector contexts, + bool convert_input); + //! Geometric average degree generation executor function that carries out function + //! matching on a Graph + /*! + * + * @param object a single format pointer to any format + * @param contexts vector of contexts that can be used for extracting + * @param convert_input whether or not to convert the input format if that is + * needed. + * @return geometric average degree in the graph + */ + FeatureType *GetGeometricAvgDegree( + object::Graph *object, + std::vector contexts, bool convert_input); + //! Geometric average degree generation executor function that carries out function + //! matching with cached outputs + /*! + * Generates the geometric average degree of the passed format. If the input format + * was converted to other format types, the converting results are also + * returned with the 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 A tuple with the first element being a vector of Format* + * where each pointer in the output points at the format that the corresponds + * Format object from the the input was converted to. If an input Format + * wasn't converted, the output pointer will point at nullptr. The second + * element is a pointer pointing to geometric average degree + */ + std::tuple>, FeatureType *> + GetGeometricAvgDegreeCached(format::Format *format, + std::vector contexts, + bool convert_input); + + static FeatureType + * + //! Geometric average degree generation implementation function for CSRs + /*! + * + * @param format a single format pointer to any format + * @return geometric average degree in the graph representation of `formats[0]` + */ + GetGeometricAvgDegreeCSR(std::vector formats, + utils::Parameters *params); + ~GeometricAvgDegree(); + + protected: + void Register(); +}; +} // namespace sparsebase::feature +#ifdef _HEADER_ONLY +#include "sparsebase/feature/geometric_avg_degree.cc" +#endif +#endif // SPARSEBASE_PROJECT_COEFFICIENT_OF_VARIATION_DEGREE_DISTRIBUTION_H diff --git a/src/sparsebase/feature/median_degree.cc b/src/sparsebase/feature/median_degree.cc new file mode 100644 index 00000000..83c32c3f --- /dev/null +++ b/src/sparsebase/feature/median_degree.cc @@ -0,0 +1,152 @@ +#include "sparsebase/feature/median_degree.h" + +#include +#include +#include +#include +#include + +#include "sparsebase/utils/parameterizable.h" + +namespace sparsebase::feature { + +template +MedianDegree::MedianDegree() { + Register(); + this->params_ = + std::shared_ptr(new MedianDegreeParams()); + this->pmap_.insert({get_id_static(), this->params_}); +} +template +MedianDegree::MedianDegree( + MedianDegreeParams params) { + MedianDegree(); +} + +template +MedianDegree::MedianDegree( + const MedianDegree &d) { + Register(); + this->params_ = d.params_; + this->pmap_ = d.pmap_; +} + +template +MedianDegree::MedianDegree( + const std::shared_ptr p) { + Register(); + this->params_ = p; + this->pmap_[get_id_static()] = p; +} + +template +void MedianDegree::Register() { + this->RegisterFunction( + {format::CSR::get_id_static()}, + GetMedianDegreeCSR); +} + +template +std::unordered_map +MedianDegree::Extract( + format::Format *format, std::vector c, + bool convert_input) { + return {{this->get_id(), std::forward( + GetMedianDegree(format, c, convert_input))}}; +}; + +template +std::vector +MedianDegree::get_sub_ids() { + return {typeid(MedianDegree)}; +} + +template +std::vector +MedianDegree::get_subs() { + return { + new MedianDegree(*this)}; +} + +template +std::type_index +MedianDegree::get_id_static() { + return typeid(MedianDegree); +} + +template +MedianDegree::~MedianDegree() = default; + +template +std::tuple>, FeatureType *> +MedianDegree:: + GetMedianDegreeCached(format::Format *format, + std::vector contexts, + bool convert_input) { + MedianDegreeParams params; + return this->CachedExecute(¶ms, contexts, convert_input, false, + format); // func(sfs, this->params_.get()); +} +template +FeatureType * +MedianDegree::GetMedianDegree( + format::Format *format, std::vector contexts, + bool convert_input) { + MedianDegreeParams params; + return this->Execute(¶ms, contexts, convert_input, + format); // func(sfs, this->params_.get()); +} + +template +FeatureType * +MedianDegree::GetMedianDegree( + object::Graph *obj, + std::vector contexts, bool convert_input) { + format::Format *format = obj->get_connectivity(); + return this->Execute(this->params_.get(), contexts, convert_input, + format); // func(sfs, this->params_.get()); +} + +template +FeatureType *MedianDegree:: + GetMedianDegreeCSR(std::vector formats, + utils::Parameters *params) { + auto csr = formats[0]->AsAbsolute>(); + IDType num_vertices = csr->get_dimensions()[0]; + auto *rows = csr->get_row_ptr(); + + std::vector degrees; + degrees.reserve(num_vertices); + for (IDType i = 0; i < num_vertices; i++) { + NNZType degree = rows[i + 1] - rows[i]; + degrees.push_back(degree); + } + std::sort(degrees.begin(), degrees.end()); + if (num_vertices % 2 == 0) { + return new FeatureType((FeatureType)(degrees[num_vertices / 2 - 1] + degrees[num_vertices / 2]) / 2.0); + } + else { + return new FeatureType(degrees[num_vertices / 2]); + } +} + +#if !defined(_HEADER_ONLY) +#include "init/median_degree.inc" +#endif +} // namespace sparsebase::feature \ No newline at end of file diff --git a/src/sparsebase/feature/median_degree.h b/src/sparsebase/feature/median_degree.h new file mode 100644 index 00000000..35271bc1 --- /dev/null +++ b/src/sparsebase/feature/median_degree.h @@ -0,0 +1,105 @@ +#include + +#include "sparsebase/config.h" +#include "sparsebase/feature/feature_preprocess_type.h" +#include "sparsebase/format/csr.h" +#include "sparsebase/object/object.h" +#include "sparsebase/utils/parameterizable.h" + +#ifndef SPARSEBASE_PROJECT_MEDIAN_DEGREE_DISTRIBUTION_H +#define SPARSEBASE_PROJECT_MEDIAN_DEGREE_DISTRIBUTION_H +namespace sparsebase::feature { + +//! An empty struct used for the parameters of MedianDegree +struct MedianDegreeParams : utils::Parameters {}; +//! Find the median degree of the graph representation of a format object +/*! + * + * @tparam FeatureType the type in which the distribution value are returned -- + * should be a floating type + */ +template +class MedianDegree + : public feature::FeaturePreprocessType { + public: + //! An empty struct used for the parameters of MedianDegree + typedef MedianDegreeParams ParamsType; + MedianDegree(); + MedianDegree(MedianDegreeParams); + MedianDegree(const MedianDegree &); + MedianDegree(std::shared_ptr); + virtual std::unordered_map Extract( + format::Format *format, std::vector, + bool convert_input); + virtual std::vector get_sub_ids(); + virtual std::vector get_subs(); + static std::type_index get_id_static(); + + //! Median degree generation 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 + * @param convert_input whether or not to convert the input format if that is + * needed. + * @return median degree in the graph representation of `format` + */ + FeatureType *GetMedianDegree(format::Format *format, + std::vector contexts, + bool convert_input); + //! Median degree generation executor function that carries out function + //! matching on a Graph + /*! + * + * @param object a single format pointer to any format + * @param contexts vector of contexts that can be used for extracting + * @param convert_input whether or not to convert the input format if that is + * needed. + * @return median degree in the graph + */ + FeatureType *GetMedianDegree( + object::Graph *object, + std::vector contexts, bool convert_input); + //! Median degree generation executor function that carries out function + //! matching with cached outputs + /*! + * Generates the median degree of the passed format. If the input format + * was converted to other format types, the converting results are also + * returned with the 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 A tuple with the first element being a vector of Format* + * where each pointer in the output points at the format that the corresponds + * Format object from the the input was converted to. If an input Format + * wasn't converted, the output pointer will point at nullptr. The second + * element is a pointer pointing to median degree + */ + std::tuple>, FeatureType *> + GetMedianDegreeCached(format::Format *format, + std::vector contexts, + bool convert_input); + + static FeatureType + * + //! Median degree generation implementation function for CSRs + /*! + * + * @param format a single format pointer to any format + * @return median degree in the graph representation of `formats[0]` + */ + GetMedianDegreeCSR(std::vector formats, + utils::Parameters *params); + ~MedianDegree(); + + protected: + void Register(); +}; +} // namespace sparsebase::feature +#ifdef _HEADER_ONLY +#include "sparsebase/feature/median_degree.cc" +#endif +#endif // SPARSEBASE_PROJECT_MEDIAN_DEGREE_DISTRIBUTION_H diff --git a/src/sparsebase/feature/standard_deviation_degree.cc b/src/sparsebase/feature/standard_deviation_degree.cc new file mode 100644 index 00000000..450818db --- /dev/null +++ b/src/sparsebase/feature/standard_deviation_degree.cc @@ -0,0 +1,147 @@ +#include "sparsebase/feature/standard_deviation_degree.h" + +#include +#include +#include +#include +#include +#include + +#include "sparsebase/utils/parameterizable.h" + +namespace sparsebase::feature { + +template +StandardDeviationDegree::StandardDeviationDegree() { + Register(); + this->params_ = + std::shared_ptr(new StandardDeviationDegreeParams()); + this->pmap_.insert({get_id_static(), this->params_}); +} +template +StandardDeviationDegree::StandardDeviationDegree( + StandardDeviationDegreeParams params) { + StandardDeviationDegree(); +} + +template +StandardDeviationDegree::StandardDeviationDegree( + const StandardDeviationDegree &d) { + Register(); + this->params_ = d.params_; + this->pmap_ = d.pmap_; +} + +template +StandardDeviationDegree::StandardDeviationDegree( + const std::shared_ptr p) { + Register(); + this->params_ = p; + this->pmap_[get_id_static()] = p; +} + +template +void StandardDeviationDegree::Register() { + this->RegisterFunction( + {format::CSR::get_id_static()}, + GetStandardDeviationDegreeCSR); +} + +template +std::unordered_map +StandardDeviationDegree::Extract( + format::Format *format, std::vector c, + bool convert_input) { + return {{this->get_id(), std::forward( + GetStandardDeviationDegree(format, c, convert_input))}}; +}; + +template +std::vector +StandardDeviationDegree::get_sub_ids() { + return {typeid(StandardDeviationDegree)}; +} + +template +std::vector +StandardDeviationDegree::get_subs() { + return { + new StandardDeviationDegree(*this)}; +} + +template +std::type_index +StandardDeviationDegree::get_id_static() { + return typeid(StandardDeviationDegree); +} + +template +StandardDeviationDegree::~StandardDeviationDegree() = default; + +template +std::tuple>, FeatureType *> +StandardDeviationDegree:: + GetStandardDeviationDegreeCached(format::Format *format, + std::vector contexts, + bool convert_input) { + StandardDeviationDegreeParams params; + return this->CachedExecute(¶ms, contexts, convert_input, false, + format); // func(sfs, this->params_.get()); +} +template +FeatureType * +StandardDeviationDegree::GetStandardDeviationDegree( + format::Format *format, std::vector contexts, + bool convert_input) { + StandardDeviationDegreeParams params; + return this->Execute(¶ms, contexts, convert_input, + format); // func(sfs, this->params_.get()); +} + +template +FeatureType * +StandardDeviationDegree::GetStandardDeviationDegree( + object::Graph *obj, + std::vector contexts, bool convert_input) { + format::Format *format = obj->get_connectivity(); + return this->Execute(this->params_.get(), contexts, convert_input, + format); // func(sfs, this->params_.get()); +} + +template +FeatureType *StandardDeviationDegree:: + GetStandardDeviationDegreeCSR(std::vector formats, + utils::Parameters *params) { + auto csr = formats[0]->AsAbsolute>(); + IDType num_vertices = csr->get_dimensions()[0]; + FeatureType avg_degree; + auto *rows = csr->get_row_ptr(); + NNZType degree_sum = rows[num_vertices] - rows[0]; + avg_degree = degree_sum / (FeatureType)num_vertices; + FeatureType standard_deviation_degree = 0; + for (int i = 0; i < num_vertices; i++) { + standard_deviation_degree += (rows[i + 1] - rows[i] - avg_degree)*(rows[i + 1] - rows[i] - avg_degree); + } + return new FeatureType(sqrt(standard_deviation_degree)); +} + +#if !defined(_HEADER_ONLY) +#include "init/standard_deviation_degree.inc" +#endif +} // namespace sparsebase::feature diff --git a/src/sparsebase/feature/standard_deviation_degree.h b/src/sparsebase/feature/standard_deviation_degree.h new file mode 100644 index 00000000..23f3d873 --- /dev/null +++ b/src/sparsebase/feature/standard_deviation_degree.h @@ -0,0 +1,105 @@ +#include + +#include "sparsebase/config.h" +#include "sparsebase/feature/feature_preprocess_type.h" +#include "sparsebase/format/csr.h" +#include "sparsebase/object/object.h" +#include "sparsebase/utils/parameterizable.h" + +#ifndef SPARSEBASE_PROJECT_STANDARD_DEVIATION_DEGREE_DISTRIBUTION_H +#define SPARSEBASE_PROJECT_STANDARD_DEVIATION_DEGREE_DISTRIBUTION_H +namespace sparsebase::feature { + +//! An empty struct used for the parameters of StandardDeviationDegree +struct StandardDeviationDegreeParams : utils::Parameters {}; +//! Find the standard deviation degree of the graph representation of a format object +/*! + * + * @tparam FeatureType the type in which the distribution value are returned -- + * should be a floating type + */ +template +class StandardDeviationDegree + : public feature::FeaturePreprocessType { + public: + //! An empty struct used for the parameters of StandardDeviationDegree + typedef StandardDeviationDegreeParams ParamsType; + StandardDeviationDegree(); + StandardDeviationDegree(StandardDeviationDegreeParams); + StandardDeviationDegree(const StandardDeviationDegree &); + StandardDeviationDegree(std::shared_ptr); + virtual std::unordered_map Extract( + format::Format *format, std::vector, + bool convert_input); + virtual std::vector get_sub_ids(); + virtual std::vector get_subs(); + static std::type_index get_id_static(); + + //! Standard deviation degree generation 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 + * @param convert_input whether or not to convert the input format if that is + * needed. + * @return standard deviation degree in the graph representation of `format` + */ + FeatureType *GetStandardDeviationDegree(format::Format *format, + std::vector contexts, + bool convert_input); + //! Standard deviation degree generation executor function that carries out function + //! matching on a Graph + /*! + * + * @param object a single format pointer to any format + * @param contexts vector of contexts that can be used for extracting + * @param convert_input whether or not to convert the input format if that is + * needed. + * @return standard deviation degree in the graph + */ + FeatureType *GetStandardDeviationDegree( + object::Graph *object, + std::vector contexts, bool convert_input); + //! Standard deviation degree generation executor function that carries out function + //! matching with cached outputs + /*! + * Generates the standard deviation degree of the passed format. If the input format + * was converted to other format types, the converting results are also + * returned with the 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 A tuple with the first element being a vector of Format* + * where each pointer in the output points at the format that the corresponds + * Format object from the the input was converted to. If an input Format + * wasn't converted, the output pointer will point at nullptr. The second + * element is a pointer pointing to standard deviation degree + */ + std::tuple>, FeatureType *> + GetStandardDeviationDegreeCached(format::Format *format, + std::vector contexts, + bool convert_input); + + static FeatureType + * + //! Standard deviation degree generation implementation function for CSRs + /*! + * + * @param format a single format pointer to any format + * @return standard deviation degree in the graph representation of `formats[0]` + */ + GetStandardDeviationDegreeCSR(std::vector formats, + utils::Parameters *params); + ~StandardDeviationDegree(); + + protected: + void Register(); +}; +} // namespace sparsebase::feature +#ifdef _HEADER_ONLY +#include "sparsebase/feature/standard_deviation_degree.cc" +#endif +#endif // SPARSEBASE_PROJECT_STANDARD_DEVIATION_DEGREE_DISTRIBUTION_H From 8323c75cc6273c77ce25c461820288a50cf37665 Mon Sep 17 00:00:00 2001 From: barisyakar Date: Tue, 25 Jul 2023 02:58:20 +0300 Subject: [PATCH 2/2] Implemented tests for features in this branch. --- .../suites/sparsebase/feature/CMakeLists.txt | 36 +++++ .../coefficient_of_variation_degree_tests.cc | 116 ++++++++++++++++ .../feature/geometric_avg_degree_tests.cc | 115 ++++++++++++++++ .../sparsebase/feature/median_degree_tests.cc | 124 ++++++++++++++++++ .../standard_deviation_degree_tests.cc | 116 ++++++++++++++++ 5 files changed, 507 insertions(+) create mode 100644 tests/suites/sparsebase/feature/coefficient_of_variation_degree_tests.cc create mode 100644 tests/suites/sparsebase/feature/geometric_avg_degree_tests.cc create mode 100644 tests/suites/sparsebase/feature/median_degree_tests.cc create mode 100644 tests/suites/sparsebase/feature/standard_deviation_degree_tests.cc diff --git a/tests/suites/sparsebase/feature/CMakeLists.txt b/tests/suites/sparsebase/feature/CMakeLists.txt index ee15ccbe..8427602f 100644 --- a/tests/suites/sparsebase/feature/CMakeLists.txt +++ b/tests/suites/sparsebase/feature/CMakeLists.txt @@ -79,6 +79,42 @@ target_link_libraries(sparsebase_feature_avg_degree_tests.test gtest gtest_main) add_test(NAME sparsebase_feature_avg_degree_tests.test COMMAND sparsebase_feature_avg_degree_tests.test) +if(${USE_CUDA}) + set_source_files_properties(standard_deviation_degree_tests.cc PROPERTIES LANGUAGE CUDA) +endif() +add_executable(sparsebase_feature_standard_deviation_degree_tests.test standard_deviation_degree_tests.cc) +target_link_libraries(sparsebase_feature_standard_deviation_degree_tests.test sparsebase) +target_link_libraries(sparsebase_feature_standard_deviation_degree_tests.test gtest gtest_main) + +add_test(NAME sparsebase_feature_standard_deviation_degree_tests.test COMMAND sparsebase_feature_standard_deviation_degree_tests.test) + +if(${USE_CUDA}) + set_source_files_properties(median_degree_tests.cc PROPERTIES LANGUAGE CUDA) +endif() +add_executable(sparsebase_feature_median_degree_tests.test median_degree_tests.cc) +target_link_libraries(sparsebase_feature_median_degree_tests.test sparsebase) +target_link_libraries(sparsebase_feature_median_degree_tests.test gtest gtest_main) + +add_test(NAME sparsebase_feature_median_degree_tests.test COMMAND sparsebase_feature_median_degree_tests.test) + +if(${USE_CUDA}) + set_source_files_properties(coefficient_of_variation_degree.cc PROPERTIES LANGUAGE CUDA) +endif() +add_executable(sparsebase_feature_coefficient_of_variation_degree_tests.test coefficient_of_variation_degree_tests.cc) +target_link_libraries(sparsebase_feature_coefficient_of_variation_degree_tests.test sparsebase) +target_link_libraries(sparsebase_feature_coefficient_of_variation_degree_tests.test gtest gtest_main) + +if(${USE_CUDA}) + set_source_files_properties(geometric_avg_degree_tests.cc PROPERTIES LANGUAGE CUDA) +endif() +add_executable(sparsebase_feature_geometric_avg_degree_tests.test geometric_avg_degree_tests.cc) +target_link_libraries(sparsebase_feature_geometric_avg_degree_tests.test sparsebase) +target_link_libraries(sparsebase_feature_geometric_avg_degree_tests.test gtest gtest_main) + +add_test(NAME sparsebase_feature_geometric_avg_degree_tests.test COMMAND sparsebase_feature_geometric_avg_degree_tests.test) + +add_test(NAME sparsebase_feature_coefficient_of_variation_degree_tests.test COMMAND sparsebase_feature_coefficient_of_variation_degree_tests.test) + if(${USE_CUDA}) set_source_files_properties(min_max_avg_degree_tests.cc PROPERTIES LANGUAGE CUDA) endif() diff --git a/tests/suites/sparsebase/feature/coefficient_of_variation_degree_tests.cc b/tests/suites/sparsebase/feature/coefficient_of_variation_degree_tests.cc new file mode 100644 index 00000000..7788b579 --- /dev/null +++ b/tests/suites/sparsebase/feature/coefficient_of_variation_degree_tests.cc @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include +#include + +#include "gtest/gtest.h" +#include "sparsebase/bases/reorder_base.h" +#include "sparsebase/context/context.h" +#include "sparsebase/feature/coefficient_of_variation_degree.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 CoefficientOfVariationDegreeTest : public ::testing::Test { + protected: + CoefficientOfVariationDegree feature; + + struct Params1 : sparsebase::utils::Parameters {}; + struct Params2 : sparsebase::utils::Parameters {}; +}; + +TEST_F(CoefficientOfVariationDegreeTest, 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 GetCoefficientOfVariationDegreeCSR implementation function + Params1 p1; + auto coefficient_of_variation_degree = + CoefficientOfVariationDegree::GetCoefficientOfVariationDegreeCSR( + {&global_csr}, &p1); + + int degree_sum = row_ptr[n] - row_ptr[0]; + auto avg_in_degrees = degree_sum / (float) n; + auto standard_deviation_in_degrees = 0.0; + for (int i = 0; i < n; i++) { + standard_deviation_in_degrees += (row_ptr[i + 1] - row_ptr[i] - avg_in_degrees)*(row_ptr[i + 1] - row_ptr[i] - avg_in_degrees); + } + auto coefficient_of_variation_in_degrees = sqrt(standard_deviation_in_degrees) / avg_in_degrees; + + EXPECT_NEAR(*coefficient_of_variation_degree, coefficient_of_variation_in_degrees, 0.000001); + + delete coefficient_of_variation_degree; + //// Check GetCoefficientOfVariationDegree (function matcher) + coefficient_of_variation_degree = + feature.GetCoefficientOfVariationDegree(&global_csr, {&cpu_context}, true); + EXPECT_NEAR(*coefficient_of_variation_degree, coefficient_of_variation_in_degrees, 0.000001); + delete coefficient_of_variation_degree; + + coefficient_of_variation_degree = + feature.GetCoefficientOfVariationDegree(&global_csr, {&cpu_context}, false); + EXPECT_NEAR(*coefficient_of_variation_degree, coefficient_of_variation_in_degrees, 0.000001); + delete coefficient_of_variation_degree; + + // Check GetCoefficientOfVariationDegree with conversion + coefficient_of_variation_degree = + feature.GetCoefficientOfVariationDegree(&global_coo, {&cpu_context}, true); + EXPECT_NEAR(*coefficient_of_variation_degree, coefficient_of_variation_in_degrees, 0.000001); + delete coefficient_of_variation_degree; + EXPECT_THROW(feature.GetCoefficientOfVariationDegree(&global_coo, {&cpu_context}, false), + utils::DirectExecutionNotAvailableException< + std::vector>); + // Check GetCoefficientOfVariationDegree with conversion and cached + auto coefficient_of_variation_degree_format = + feature.GetCoefficientOfVariationDegreeCached(&global_coo, {&cpu_context}, true); + EXPECT_NEAR(*std::get<1>(coefficient_of_variation_degree_format), coefficient_of_variation_in_degrees, 0.000001); + delete std::get<1>(coefficient_of_variation_degree_format); + + auto cached_data = std::get<0>(coefficient_of_variation_degree_format); + ASSERT_EQ(cached_data.size(), 1); + ASSERT_EQ(cached_data[0][0]->get_id(), std::type_index(typeid(global_csr))); + auto converted_csr = + cached_data[0][0]->AsAbsolute>(); + compare_csr(&global_csr, converted_csr); + // Check Extract + auto feature_map = feature.Extract(&global_csr, {&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_NEAR(*std::any_cast(feature_map[feature.get_id()]), + coefficient_of_variation_in_degrees, 0.000001); + + // 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_NEAR(*std::any_cast(feature_map[feature.get_id()]), + coefficient_of_variation_in_degrees, 0.000001); +} diff --git a/tests/suites/sparsebase/feature/geometric_avg_degree_tests.cc b/tests/suites/sparsebase/feature/geometric_avg_degree_tests.cc new file mode 100644 index 00000000..1344b56d --- /dev/null +++ b/tests/suites/sparsebase/feature/geometric_avg_degree_tests.cc @@ -0,0 +1,115 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "gtest/gtest.h" +#include "sparsebase/bases/reorder_base.h" +#include "sparsebase/context/context.h" +#include "sparsebase/feature/geometric_avg_degree.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 GeometricAvgDegreeTest : public ::testing::Test { + protected: + GeometricAvgDegree feature; + + struct Params1 : sparsebase::utils::Parameters {}; + struct Params2 : sparsebase::utils::Parameters {}; +}; + +TEST_F(GeometricAvgDegreeTest, 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 GetGeometricAvgDegreeCSR implementation function + Params1 p1; + auto geometric_avg_degree = + GeometricAvgDegree::GetGeometricAvgDegreeCSR( + {&global_csr}, &p1); + + auto geometric_avg_in_degrees = 0.0; + for (int i = 0; i < n; i++) { + geometric_avg_in_degrees += log(row_ptr[i + 1] - row_ptr[i]); + } + geometric_avg_in_degrees = exp(geometric_avg_in_degrees / n); + + EXPECT_NEAR(*geometric_avg_degree, geometric_avg_in_degrees, 0.000001); + + delete geometric_avg_degree; + //// Check GetGeometricAvgDegree (function matcher) + geometric_avg_degree = + feature.GetGeometricAvgDegree(&global_csr, {&cpu_context}, true); + EXPECT_NEAR(*geometric_avg_degree, geometric_avg_in_degrees, 0.000001); + delete geometric_avg_degree; + + geometric_avg_degree = + feature.GetGeometricAvgDegree(&global_csr, {&cpu_context}, false); + EXPECT_NEAR(*geometric_avg_degree, geometric_avg_in_degrees, 0.000001); + delete geometric_avg_degree; + + // Check GetGeometricAvgDegree with conversion + geometric_avg_degree = + feature.GetGeometricAvgDegree(&global_coo, {&cpu_context}, true); + EXPECT_NEAR(*geometric_avg_degree, geometric_avg_in_degrees, 0.000001); + delete geometric_avg_degree; + EXPECT_THROW(feature.GetGeometricAvgDegree(&global_coo, {&cpu_context}, false), + utils::DirectExecutionNotAvailableException< + std::vector>); + // Check GetGeometricAvgDegree with conversion and cached + auto geometric_avg_degree_format = + feature.GetGeometricAvgDegreeCached(&global_coo, {&cpu_context}, true); + EXPECT_NEAR(*std::get<1>(geometric_avg_degree_format), geometric_avg_in_degrees, 0.000001); + delete std::get<1>(geometric_avg_degree_format); + + auto cached_data = std::get<0>(geometric_avg_degree_format); + ASSERT_EQ(cached_data.size(), 1); + ASSERT_EQ(cached_data[0][0]->get_id(), std::type_index(typeid(global_csr))); + auto converted_csr = + cached_data[0][0]->AsAbsolute>(); + compare_csr(&global_csr, converted_csr); + // Check Extract + auto feature_map = feature.Extract(&global_csr, {&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_NEAR(*std::any_cast(feature_map[feature.get_id()]), + geometric_avg_in_degrees, 0.000001); + + // 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_NEAR(*std::any_cast(feature_map[feature.get_id()]), + geometric_avg_in_degrees, 0.000001); +} diff --git a/tests/suites/sparsebase/feature/median_degree_tests.cc b/tests/suites/sparsebase/feature/median_degree_tests.cc new file mode 100644 index 00000000..5e45b491 --- /dev/null +++ b/tests/suites/sparsebase/feature/median_degree_tests.cc @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include +#include + +#include "gtest/gtest.h" +#include "sparsebase/bases/reorder_base.h" +#include "sparsebase/context/context.h" +#include "sparsebase/feature/median_degree.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 MedianDegreeTest : public ::testing::Test { + protected: + MedianDegree feature; + + struct Params1 : sparsebase::utils::Parameters {}; + struct Params2 : sparsebase::utils::Parameters {}; +}; + +TEST_F(MedianDegreeTest, 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 GetMedianDegreeCSR implementation function + Params1 p1; + auto median_degree = + MedianDegree::GetMedianDegreeCSR( + {&global_csr}, &p1); + + std::vector test_degrees; + test_degrees.reserve(n); + for (int i = 0; i < n; i++) { + int current_degree = rows[i + 1] - rows[i]; + test_degrees.push_back(current_degree); + } + std::sort(test_degrees.begin(), test_degrees.end()); + + auto median_in_degrees = 0.0; + if (n % 2 == 0) { + median_in_degrees = (test_degrees[n / 2 - 1] + test_degrees[n / 2]) / 2.0; + } + else { + median_in_degrees = test_degrees[n / 2]; + } + + EXPECT_NEAR(*median_degree, median_in_degrees, 0.000001); + + delete median_degree; + //// Check GetMedianDegree (function matcher) + median_degree = + feature.GetMedianDegree(&global_csr, {&cpu_context}, true); + EXPECT_NEAR(*median_degree, median_in_degrees, 0.000001); + delete median_degree; + + median_degree = + feature.GetMedianDegree(&global_csr, {&cpu_context}, false); + EXPECT_NEAR(*median_degree, median_in_degrees, 0.000001); + delete median_degree; + + // Check GetMedianDegree with conversion + median_degree = + feature.GetMedianDegree(&global_coo, {&cpu_context}, true); + EXPECT_NEAR(*median_degree, median_in_degrees, 0.000001); + delete median_degree; + EXPECT_THROW(feature.GetMedianDegree(&global_coo, {&cpu_context}, false), + utils::DirectExecutionNotAvailableException< + std::vector>); + // Check GetMedianDegree with conversion and cached + auto median_degree_format = + feature.GetMedianDegreeCached(&global_coo, {&cpu_context}, true); + EXPECT_NEAR(*std::get<1>(median_degree_format), median_in_degrees, 0.000001); + delete std::get<1>(median_degree_format); + + auto cached_data = std::get<0>(median_degree_format); + ASSERT_EQ(cached_data.size(), 1); + ASSERT_EQ(cached_data[0][0]->get_id(), std::type_index(typeid(global_csr))); + auto converted_csr = + cached_data[0][0]->AsAbsolute>(); + compare_csr(&global_csr, converted_csr); + // Check Extract + auto feature_map = feature.Extract(&global_csr, {&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_NEAR(*std::any_cast(feature_map[feature.get_id()]), + median_in_degrees, 0.000001); + + // 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_NEAR(*std::any_cast(feature_map[feature.get_id()]), + median_in_degrees, 0.000001); +} diff --git a/tests/suites/sparsebase/feature/standard_deviation_degree_tests.cc b/tests/suites/sparsebase/feature/standard_deviation_degree_tests.cc new file mode 100644 index 00000000..f3084c1c --- /dev/null +++ b/tests/suites/sparsebase/feature/standard_deviation_degree_tests.cc @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include +#include + +#include "gtest/gtest.h" +#include "sparsebase/bases/reorder_base.h" +#include "sparsebase/context/context.h" +#include "sparsebase/feature/standard_deviation_degree.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 StandardDeviationDegreeTest : public ::testing::Test { + protected: + StandardDeviationDegree feature; + + struct Params1 : sparsebase::utils::Parameters {}; + struct Params2 : sparsebase::utils::Parameters {}; +}; + +TEST_F(StandardDeviationDegreeTest, 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 GetStandardDeviationDegreeCSR implementation function + Params1 p1; + auto standard_deviation_degree = + StandardDeviationDegree::GetStandardDeviationDegreeCSR( + {&global_csr}, &p1); + + int degree_sum = row_ptr[n] - row_ptr[0]; + auto avg_in_degrees = degree_sum / (float) n; + auto standard_deviation_in_degrees = 0.0; + for (int i = 0; i < n; i++) { + standard_deviation_in_degrees += (row_ptr[i + 1] - row_ptr[i] - avg_in_degrees)*(row_ptr[i + 1] - row_ptr[i] - avg_in_degrees); + } + standard_deviation_in_degrees = sqrt(standard_deviation_in_degrees); + + EXPECT_NEAR(*standard_deviation_degree, standard_deviation_in_degrees, 0.000001); + + delete standard_deviation_degree; + //// Check GetStandardDeviationDegree (function matcher) + standard_deviation_degree = + feature.GetStandardDeviationDegree(&global_csr, {&cpu_context}, true); + EXPECT_NEAR(*standard_deviation_degree, standard_deviation_in_degrees, 0.000001); + delete standard_deviation_degree; + + standard_deviation_degree = + feature.GetStandardDeviationDegree(&global_csr, {&cpu_context}, false); + EXPECT_NEAR(*standard_deviation_degree, standard_deviation_in_degrees, 0.000001); + delete standard_deviation_degree; + + // Check GetStandardDeviationDegree with conversion + standard_deviation_degree = + feature.GetStandardDeviationDegree(&global_coo, {&cpu_context}, true); + EXPECT_NEAR(*standard_deviation_degree, standard_deviation_in_degrees, 0.000001); + delete standard_deviation_degree; + EXPECT_THROW(feature.GetStandardDeviationDegree(&global_coo, {&cpu_context}, false), + utils::DirectExecutionNotAvailableException< + std::vector>); + // Check GetStandardDeviationDegree with conversion and cached + auto standard_deviation_degree_format = + feature.GetStandardDeviationDegreeCached(&global_coo, {&cpu_context}, true); + EXPECT_NEAR(*std::get<1>(standard_deviation_degree_format), standard_deviation_in_degrees, 0.000001); + delete std::get<1>(standard_deviation_degree_format); + + auto cached_data = std::get<0>(standard_deviation_degree_format); + ASSERT_EQ(cached_data.size(), 1); + ASSERT_EQ(cached_data[0][0]->get_id(), std::type_index(typeid(global_csr))); + auto converted_csr = + cached_data[0][0]->AsAbsolute>(); + compare_csr(&global_csr, converted_csr); + // Check Extract + auto feature_map = feature.Extract(&global_csr, {&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_NEAR(*std::any_cast(feature_map[feature.get_id()]), + standard_deviation_in_degrees, 0.000001); + + // 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_NEAR(*std::any_cast(feature_map[feature.get_id()]), + standard_deviation_in_degrees, 0.000001); +}