Initial commit as Claude developed it
Some checks failed
CI/CD Pipeline / Code Linting (push) Failing after 22s
CI/CD Pipeline / Build and Test (Debug, clang, ubuntu-latest) (push) Failing after 5m44s
CI/CD Pipeline / Build and Test (Debug, gcc, ubuntu-latest) (push) Failing after 5m33s
CI/CD Pipeline / Build and Test (Release, clang, ubuntu-20.04) (push) Failing after 6m12s
CI/CD Pipeline / Build and Test (Release, clang, ubuntu-latest) (push) Failing after 5m13s
CI/CD Pipeline / Build and Test (Release, gcc, ubuntu-20.04) (push) Failing after 5m30s
CI/CD Pipeline / Build and Test (Release, gcc, ubuntu-latest) (push) Failing after 5m33s
CI/CD Pipeline / Docker Build Test (push) Failing after 13s
CI/CD Pipeline / Performance Benchmarks (push) Has been skipped
CI/CD Pipeline / Build Documentation (push) Successful in 31s
CI/CD Pipeline / Create Release Package (push) Has been skipped
Some checks failed
CI/CD Pipeline / Code Linting (push) Failing after 22s
CI/CD Pipeline / Build and Test (Debug, clang, ubuntu-latest) (push) Failing after 5m44s
CI/CD Pipeline / Build and Test (Debug, gcc, ubuntu-latest) (push) Failing after 5m33s
CI/CD Pipeline / Build and Test (Release, clang, ubuntu-20.04) (push) Failing after 6m12s
CI/CD Pipeline / Build and Test (Release, clang, ubuntu-latest) (push) Failing after 5m13s
CI/CD Pipeline / Build and Test (Release, gcc, ubuntu-20.04) (push) Failing after 5m30s
CI/CD Pipeline / Build and Test (Release, gcc, ubuntu-latest) (push) Failing after 5m33s
CI/CD Pipeline / Docker Build Test (push) Failing after 13s
CI/CD Pipeline / Performance Benchmarks (push) Has been skipped
CI/CD Pipeline / Build Documentation (push) Successful in 31s
CI/CD Pipeline / Create Release Package (push) Has been skipped
This commit is contained in:
348
src/kernel_parameters.cpp
Normal file
348
src/kernel_parameters.cpp
Normal file
@@ -0,0 +1,348 @@
|
||||
#include "svm_classifier/kernel_parameters.hpp"
|
||||
#include <stdexcept>
|
||||
#include <cmath>
|
||||
|
||||
namespace svm_classifier {
|
||||
|
||||
KernelParameters::KernelParameters()
|
||||
: kernel_type_(KernelType::LINEAR)
|
||||
, multiclass_strategy_(MulticlassStrategy::ONE_VS_REST)
|
||||
, C_(1.0)
|
||||
, tolerance_(1e-3)
|
||||
, max_iterations_(-1)
|
||||
, probability_(false)
|
||||
, gamma_(-1.0) // Auto gamma
|
||||
, degree_(3)
|
||||
, coef0_(0.0)
|
||||
, cache_size_(200.0)
|
||||
{
|
||||
}
|
||||
|
||||
KernelParameters::KernelParameters(const nlohmann::json& config) : KernelParameters()
|
||||
{
|
||||
set_parameters(config);
|
||||
}
|
||||
|
||||
void KernelParameters::set_parameters(const nlohmann::json& config)
|
||||
{
|
||||
// Set kernel type first as it affects validation
|
||||
if (config.contains("kernel")) {
|
||||
if (config["kernel"].is_string()) {
|
||||
set_kernel_type(string_to_kernel_type(config["kernel"]));
|
||||
} else {
|
||||
throw std::invalid_argument("Kernel must be a string");
|
||||
}
|
||||
}
|
||||
|
||||
// Set multiclass strategy
|
||||
if (config.contains("multiclass_strategy")) {
|
||||
if (config["multiclass_strategy"].is_string()) {
|
||||
set_multiclass_strategy(string_to_multiclass_strategy(config["multiclass_strategy"]));
|
||||
} else {
|
||||
throw std::invalid_argument("Multiclass strategy must be a string");
|
||||
}
|
||||
}
|
||||
|
||||
// Set common parameters
|
||||
if (config.contains("C")) {
|
||||
if (config["C"].is_number()) {
|
||||
set_C(config["C"]);
|
||||
} else {
|
||||
throw std::invalid_argument("C must be a number");
|
||||
}
|
||||
}
|
||||
|
||||
if (config.contains("tolerance")) {
|
||||
if (config["tolerance"].is_number()) {
|
||||
set_tolerance(config["tolerance"]);
|
||||
} else {
|
||||
throw std::invalid_argument("Tolerance must be a number");
|
||||
}
|
||||
}
|
||||
|
||||
if (config.contains("max_iterations")) {
|
||||
if (config["max_iterations"].is_number_integer()) {
|
||||
set_max_iterations(config["max_iterations"]);
|
||||
} else {
|
||||
throw std::invalid_argument("Max iterations must be an integer");
|
||||
}
|
||||
}
|
||||
|
||||
if (config.contains("probability")) {
|
||||
if (config["probability"].is_boolean()) {
|
||||
set_probability(config["probability"]);
|
||||
} else {
|
||||
throw std::invalid_argument("Probability must be a boolean");
|
||||
}
|
||||
}
|
||||
|
||||
// Set kernel-specific parameters
|
||||
if (config.contains("gamma")) {
|
||||
if (config["gamma"].is_number()) {
|
||||
set_gamma(config["gamma"]);
|
||||
} else if (config["gamma"].is_string() && config["gamma"] == "auto") {
|
||||
set_gamma(-1.0); // Auto gamma
|
||||
} else {
|
||||
throw std::invalid_argument("Gamma must be a number or 'auto'");
|
||||
}
|
||||
}
|
||||
|
||||
if (config.contains("degree")) {
|
||||
if (config["degree"].is_number_integer()) {
|
||||
set_degree(config["degree"]);
|
||||
} else {
|
||||
throw std::invalid_argument("Degree must be an integer");
|
||||
}
|
||||
}
|
||||
|
||||
if (config.contains("coef0")) {
|
||||
if (config["coef0"].is_number()) {
|
||||
set_coef0(config["coef0"]);
|
||||
} else {
|
||||
throw std::invalid_argument("Coef0 must be a number");
|
||||
}
|
||||
}
|
||||
|
||||
if (config.contains("cache_size")) {
|
||||
if (config["cache_size"].is_number()) {
|
||||
set_cache_size(config["cache_size"]);
|
||||
} else {
|
||||
throw std::invalid_argument("Cache size must be a number");
|
||||
}
|
||||
}
|
||||
|
||||
// Validate all parameters
|
||||
validate();
|
||||
}
|
||||
|
||||
nlohmann::json KernelParameters::get_parameters() const
|
||||
{
|
||||
nlohmann::json params = {
|
||||
{"kernel", kernel_type_to_string(kernel_type_)},
|
||||
{"multiclass_strategy", multiclass_strategy_to_string(multiclass_strategy_)},
|
||||
{"C", C_},
|
||||
{"tolerance", tolerance_},
|
||||
{"max_iterations", max_iterations_},
|
||||
{"probability", probability_},
|
||||
{"cache_size", cache_size_}
|
||||
};
|
||||
|
||||
// Add kernel-specific parameters
|
||||
switch (kernel_type_) {
|
||||
case KernelType::LINEAR:
|
||||
// No additional parameters for linear kernel
|
||||
break;
|
||||
|
||||
case KernelType::RBF:
|
||||
params["gamma"] = is_gamma_auto() ? "auto" : gamma_;
|
||||
break;
|
||||
|
||||
case KernelType::POLYNOMIAL:
|
||||
params["degree"] = degree_;
|
||||
params["gamma"] = is_gamma_auto() ? "auto" : gamma_;
|
||||
params["coef0"] = coef0_;
|
||||
break;
|
||||
|
||||
case KernelType::SIGMOID:
|
||||
params["gamma"] = is_gamma_auto() ? "auto" : gamma_;
|
||||
params["coef0"] = coef0_;
|
||||
break;
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
void KernelParameters::set_kernel_type(KernelType kernel)
|
||||
{
|
||||
kernel_type_ = kernel;
|
||||
|
||||
// Reset kernel-specific parameters to defaults when kernel changes
|
||||
auto defaults = get_default_parameters(kernel);
|
||||
|
||||
if (defaults.contains("gamma")) {
|
||||
gamma_ = defaults["gamma"];
|
||||
}
|
||||
if (defaults.contains("degree")) {
|
||||
degree_ = defaults["degree"];
|
||||
}
|
||||
if (defaults.contains("coef0")) {
|
||||
coef0_ = defaults["coef0"];
|
||||
}
|
||||
}
|
||||
|
||||
void KernelParameters::set_C(double c)
|
||||
{
|
||||
if (c <= 0.0) {
|
||||
throw std::invalid_argument("C must be positive (C > 0)");
|
||||
}
|
||||
C_ = c;
|
||||
}
|
||||
|
||||
void KernelParameters::set_gamma(double gamma)
|
||||
{
|
||||
// Allow negative values for auto gamma (-1.0)
|
||||
if (gamma > 0.0 || gamma == -1.0) {
|
||||
gamma_ = gamma;
|
||||
} else {
|
||||
throw std::invalid_argument("Gamma must be positive or -1 for auto");
|
||||
}
|
||||
}
|
||||
|
||||
void KernelParameters::set_degree(int degree)
|
||||
{
|
||||
if (degree < 1) {
|
||||
throw std::invalid_argument("Degree must be >= 1");
|
||||
}
|
||||
degree_ = degree;
|
||||
}
|
||||
|
||||
void KernelParameters::set_coef0(double coef0)
|
||||
{
|
||||
coef0_ = coef0;
|
||||
}
|
||||
|
||||
void KernelParameters::set_tolerance(double tol)
|
||||
{
|
||||
if (tol <= 0.0) {
|
||||
throw std::invalid_argument("Tolerance must be positive (tolerance > 0)");
|
||||
}
|
||||
tolerance_ = tol;
|
||||
}
|
||||
|
||||
void KernelParameters::set_max_iterations(int max_iter)
|
||||
{
|
||||
if (max_iter <= 0 && max_iter != -1) {
|
||||
throw std::invalid_argument("Max iterations must be positive or -1 for no limit");
|
||||
}
|
||||
max_iterations_ = max_iter;
|
||||
}
|
||||
|
||||
void KernelParameters::set_cache_size(double cache_size)
|
||||
{
|
||||
if (cache_size < 0.0) {
|
||||
throw std::invalid_argument("Cache size must be non-negative");
|
||||
}
|
||||
cache_size_ = cache_size;
|
||||
}
|
||||
|
||||
void KernelParameters::set_probability(bool probability)
|
||||
{
|
||||
probability_ = probability;
|
||||
}
|
||||
|
||||
void KernelParameters::set_multiclass_strategy(MulticlassStrategy strategy)
|
||||
{
|
||||
multiclass_strategy_ = strategy;
|
||||
}
|
||||
|
||||
void KernelParameters::validate() const
|
||||
{
|
||||
// Validate common parameters
|
||||
if (C_ <= 0.0) {
|
||||
throw std::invalid_argument("C must be positive");
|
||||
}
|
||||
|
||||
if (tolerance_ <= 0.0) {
|
||||
throw std::invalid_argument("Tolerance must be positive");
|
||||
}
|
||||
|
||||
if (max_iterations_ <= 0 && max_iterations_ != -1) {
|
||||
throw std::invalid_argument("Max iterations must be positive or -1");
|
||||
}
|
||||
|
||||
if (cache_size_ < 0.0) {
|
||||
throw std::invalid_argument("Cache size must be non-negative");
|
||||
}
|
||||
|
||||
// Validate kernel-specific parameters
|
||||
validate_kernel_parameters();
|
||||
}
|
||||
|
||||
void KernelParameters::validate_kernel_parameters() const
|
||||
{
|
||||
switch (kernel_type_) {
|
||||
case KernelType::LINEAR:
|
||||
// Linear kernel has no additional parameters to validate
|
||||
break;
|
||||
|
||||
case KernelType::RBF:
|
||||
if (gamma_ > 0.0 || gamma_ == -1.0) {
|
||||
// Valid gamma (positive or auto)
|
||||
} else {
|
||||
throw std::invalid_argument("RBF kernel gamma must be positive or auto (-1)");
|
||||
}
|
||||
break;
|
||||
|
||||
case KernelType::POLYNOMIAL:
|
||||
if (degree_ < 1) {
|
||||
throw std::invalid_argument("Polynomial degree must be >= 1");
|
||||
}
|
||||
if (gamma_ > 0.0 || gamma_ == -1.0) {
|
||||
// Valid gamma
|
||||
} else {
|
||||
throw std::invalid_argument("Polynomial kernel gamma must be positive or auto (-1)");
|
||||
}
|
||||
// coef0 can be any real number
|
||||
break;
|
||||
|
||||
case KernelType::SIGMOID:
|
||||
if (gamma_ > 0.0 || gamma_ == -1.0) {
|
||||
// Valid gamma
|
||||
} else {
|
||||
throw std::invalid_argument("Sigmoid kernel gamma must be positive or auto (-1)");
|
||||
}
|
||||
// coef0 can be any real number
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nlohmann::json KernelParameters::get_default_parameters(KernelType kernel)
|
||||
{
|
||||
nlohmann::json defaults = {
|
||||
{"C", 1.0},
|
||||
{"tolerance", 1e-3},
|
||||
{"max_iterations", -1},
|
||||
{"probability", false},
|
||||
{"multiclass_strategy", "ovr"},
|
||||
{"cache_size", 200.0}
|
||||
};
|
||||
|
||||
switch (kernel) {
|
||||
case KernelType::LINEAR:
|
||||
defaults["kernel"] = "linear";
|
||||
break;
|
||||
|
||||
case KernelType::RBF:
|
||||
defaults["kernel"] = "rbf";
|
||||
defaults["gamma"] = -1.0; // Auto gamma
|
||||
break;
|
||||
|
||||
case KernelType::POLYNOMIAL:
|
||||
defaults["kernel"] = "polynomial";
|
||||
defaults["degree"] = 3;
|
||||
defaults["gamma"] = -1.0; // Auto gamma
|
||||
defaults["coef0"] = 0.0;
|
||||
break;
|
||||
|
||||
case KernelType::SIGMOID:
|
||||
defaults["kernel"] = "sigmoid";
|
||||
defaults["gamma"] = -1.0; // Auto gamma
|
||||
defaults["coef0"] = 0.0;
|
||||
break;
|
||||
}
|
||||
|
||||
return defaults;
|
||||
}
|
||||
|
||||
void KernelParameters::reset_to_defaults()
|
||||
{
|
||||
auto defaults = get_default_parameters(kernel_type_);
|
||||
set_parameters(defaults);
|
||||
}
|
||||
|
||||
void KernelParameters::set_gamma_auto()
|
||||
{
|
||||
gamma_ = -1.0;
|
||||
}
|
||||
|
||||
} // namespace svm_classifier
|
Reference in New Issue
Block a user