Skip to content

API Reference ​

A map of the public API. Every type lives in namespace feature_elm, the CUDA entry points in feature_elm::cuda_backend. Matrices are std::vector<FloatT> in row-major order, and fallible calls return bool or std::optional instead of throwing. The headers are the source of truth; each heading links to one.

Common types — core/feature_map.hpp ​

SymbolPurpose
enum class Backend { kCpu, kGpu }Where transforms and solves run. kGpu returns false when no CUDA device is present
enum class ActivationKind { kSigmoid, kTanh, kRelu }Hidden-layer non-linearity used by feature maps
enum class ActivationFunction { kSigmoid, kTanh, kRelu }The same choice at model level; activationKind() converts it
template <class FloatT> class FeatureMapInterface: inputDim(), outputDim(), fit(data, n), transform(input, n, &out), setBackend(b)

Feature maps ​

ClassHeaderNotes
RandomAdditiveMap<FloatT>(inputDim, outputDim, activation, seed?, backend, weights?, biases?)core/random_additive_map.hppg(xW + b) with random W, b; fit is a no-op. Weights are inputDim × outputDim
RbfMap<FloatT>(inputDim, numCenters, width, RbfCenterInit, seed)core/rbf_map.hppGaussian RBF, exp(-‖x - c‖² / 2σ²); fit picks centres (kRandom or kKMeans)
ElmAutoEncoderLayer<FloatT>(inputDim, outputDim, activation, seed, ridgeAlpha)core/elm_ae.hppLearned encoder: fit solves an auto-encoder and reuses its output weights; reconstruct() for diagnostics
StackedFeatureMap<FloatT>(inputDim, layerDims, activation, seed, ridgeAlpha, backend)core/stacked_feature_map.hppGreedy layer-wise stack of auto-encoder layers; setBackend applies to every layer
IdentityMap<FloatT>(dim)core/identity_map.hppPass-through, for linear baselines

Lower-level RBF helpers (RbfParameters, computeRbfFeatures, initializeRbfCentersRandom, initializeRbfCentersKMeans) are in core/rbf_features.hpp.

Solvers ​

SymbolHeaderNotes
SolverOptions<FloatT>{ridgeAlpha, path, method}core/solver.hpppath: kAuto (dual when samples < features), kPrimal or kDual. method: kCholesky or kHouseholderQr
BatchRidgeSolver<FloatT>(options).solve(H, n, T, outputs, &β)sameSolves (HᵀH + αI)β = HᵀT. β is features × outputs
RlsOptions<FloatT>{regularization, forgettingFactor, constraint, constraintStrength}core/rls_solver.hppForgetting factor < 1 gives FOS-ELM; RlsConstraint::kClassDistance gives OS-CELM
RlsSolver<FloatT>(options, backend): initialize(H, n, T, outputs), update(H, n, T)sameRecursive least squares; weights() and covariance() expose the state. With Backend::kGpu, plain RLS (forgetting 1, no constraint) keeps its state on the GPU in information form (float64) and usesGpu() returns true; FOS/OS-CELM settings stay on the CPU

Models ​

All models share predict(x) and predictBatch(X, n), which return std::optional<std::vector<FloatT>>.

ClassHeaderTraining API
BatchElm<FloatT>(inputs, hidden, activation, backend, ridgeAlpha); an overload also takes explicit weights, biasescore/elm.hpptrain(X, T, n, outputs)
OsElm<FloatT>(inputs, hidden, activation, backend, rlsOptions); an overload also takes explicit weights, biasescore/os_elm.hppinitialize(X0, T0, n0, outputs), then update(X, T, n) per chunk
OsCelm<FloatT>(…)core/os_celm.hppSame as OS-ELM, with a class-distance constraint
MlElm<FloatT>(inputs, hiddenPerLayer, activation, backend, ridgeAlpha, seed)core/ml_elm.hpptrain(X, T, n, outputs): auto-encoder stack plus ridge read-out
HierarchicalOsElm<FloatT>(inputs, hiddenPerLayer, activation, backend, rlsOptions, ridgeAlpha, seed)core/h_os_elm.hppinitialize / update: the online version of ML-ELM

Model files ​

A trained BatchElm can be saved and reloaded, so a model can be trained once (for example on a GPU) and served anywhere:

cpp
BatchElm<float> model(64, 4096, ActivationFunction::kRelu, Backend::kGpu);
model.train(X, T, n, 10);
model.save("digits.felm");                                   // false if untrained or unwritable

auto served = BatchElm<float>::load("digits.felm", Backend::kCpu);  // std::nullopt on bad files

The file is binary and little-endian, with a small header followed by the raw weights:

FieldTypeNotes
magicchar[4]FELM
versionuint32currently 1
scalar widthuint324 (float) or 8 (double); must match the BatchElm<FloatT> that loads it
activationuint32ActivationFunction value
inputs, hidden, outputsuint64 × 3
ridge alphafloat64
hidden weightsscalar × inputs·hiddenrow-major, inputs × hidden
hidden biasesscalar × hidden
output weightsscalar × hidden·outputsrow-major, hidden × outputs

load rejects wrong magic, versions or widths, out-of-range sizes, non-finite values and truncated files. A reloaded model predicts bit-identically to the original.

felm-train ​

A command-line trainer built with the library (the felm_train target). It reads labelled CSV (label,f1,…,fN with a header), trains on the GPU when one is available, reports per-class test accuracy, and saves a model file:

bash
felm-train --train train.csv --test test.csv --inputs 64 --classes 10 \
           --hidden 4096 --activation relu --ridge 1 --input-scale 64 --out model.felm

--input-scale S divides the random hidden weights by S. That is equivalent to scaling the inputs down, but the saved model then works directly on raw features. data/models/handwriting_8x8.felm is built this way; see data/models/README.md.

Data ​

SymbolHeaderNotes
loadCsv(path, inputDim, labelColumn, labelColumnFirst)io/dataset.hppReturns DatasetLoadResult{optional<Dataset>, error}
preprocessDataset(data, labels, n, dim, trainFraction, seed)io/preprocess.hppDeterministic split, min-max scaling fitted on the training split, one-hot targets
minMaxNormalize(data, min, max), oneHotEncode(labels, classes)sameThe building blocks used above
DriftStream(Config{inputDim, numClasses, streamLength, driftPoint, seed}): next(), reset()io/drift_stream.hppSynthetic rotating-boundary stream with one concept drift
loadIdx(imagesPath, labelsPath)io/idx_dataset.hppUncompressed IDX pairs (MNIST, Fashion-MNIST) → IdxDataset with float pixels in 0..1; scripts/fetch_datasets.py downloads them

CUDA backend — cuda/ ​

You normally reach these through Backend::kGpu. They are public for benchmarks and advanced use.

SymbolNotes
isGpuAvailable(), gpuDeviceName()Device detection; the result is cached per process
transformRandomAdditiveGpu(...), transformElmAutoEncoderGpu(...)cuBLAS GEMM plus a fused bias and activation kernel
solveRidgeGpu(H, T, n, outputs, options, &β)Normal equations on the device (syrk + cuSOLVER Cholesky), falling back to Householder QR on the augmented system if the Cholesky fails
DeviceBuffer<T>RAII device allocation with bounds-checked host copies

CPU-only builds link stubs that return false from every GPU entry point (src/cuda/cuda_stubs.cpp).

Threading ​

CPU hot loops (hidden-layer transforms, the normal equations, Cholesky, RLS updates, batch prediction) are multithreaded with OpenMP when the library is built with FEATURE_ELM_OPENMP=ON (the default). Threads split output elements and each element keeps its summation order, so results are bit-identical to a serial run for any thread count. Use OMP_NUM_THREADS to limit threads; feature_elm::parallelThreads() (in core/parallel.hpp) reports the count in use.

Released under the MIT License.