Skip to main content

Skigen

High-performance machine learning for modern C++ and Eigen.

Skigen is a header-only C++ template library for machine learning. It brings the scikit-learn API — fit(), transform(), predict() — to the Eigen ecosystem.

Overview

  • Skigen is versatile.
    • Preprocessing, linear models, decomposition, clustering, trees, neighbors, pipelines, and metrics — covering the core scikit-learn surface with a consistent API.
    • All estimators are templatized on Scalar (default: double). Switch to float for 2× SIMD throughput on the same hardware.
  • Skigen is fast.
    • Eigen's expression templates eliminate temporaries and enable lazy evaluation.
    • Explicit SIMD vectorization via Eigen for SSE, AVX, AVX-512, and ARM NEON.
    • Compile-time polymorphism via CRTP — zero vtable overhead, zero runtime dispatch.
    • No interpreter, no garbage collector, no GIL.
  • Skigen is reliable.
    • Bit-level parity with scikit-learn for identical inputs and default parameters, verified via cross-language parity tests.
    • CI-tested on GCC, Clang, and MSVC across Linux, macOS, and Windows.
  • Skigen is elegant.
    • Header-only — drop Skigen/ next to Eigen/ and #include. No compiled libraries, no linker flags.
    • Include patterns mirror Eigen: #include <Skigen/Dense> feels like #include <Eigen/Dense>.
    • The same API you know from scikit-learn, native to C++.

Design

PrincipleImplementation
Eigen-nativeHeaders, namespaces, and include patterns mirror Eigen conventions.
Header-onlyNo compiled libraries, no link-time dependencies.
TemplatizedScalar template parameter — double default, float for dense SIMD.
Zero-copyInputs use Eigen::Ref<const MatrixType> — sub-blocks and memory-mapped data without copying.
CRTPStatic polymorphism via the Curiously Recurring Template Pattern.
Bit-level parityResults match scikit-learn for identical inputs and default parameters.

Quick Example

#include <Eigen/Dense>
#include <Skigen/Preprocessing>
#include <iostream>

int main() {
Eigen::MatrixXd X(4, 2);
X << 1, 10,
2, 20,
3, 30,
4, 40;

Skigen::StandardScaler scaler;
Eigen::MatrixXd Z = scaler.fit_transform(X);

std::cout << "Standardized:\n" << Z << "\n";
return 0;
}