Skip to main content

basis

Basis-function models in C11: extreme learning machines (ELM), random vector functional-link models (RVFL), random Fourier features (RFF), and Nyström RBF features. Regression uses a regularized linear readout; classification offers multinomial logistic or one-hot ridge readouts.

The C engine requires only libc/libm. JavaScript uses @wlearn/core for matrix normalization, errors, WLRN artifacts, metrics and loader registration. Python uses NumPy plus wlearn for artifacts, errors and registration. No Polygrad, BLAS, LAPACK or external neural runtime is required.

Requires @wlearn/core 0.3 in JavaScript or wlearn>=0.3,<0.4 in Python.

JavaScript

const { BasisRegressor } = require('@wlearn/basis')
const { load } = require('@wlearn/core')

const X = [[-1, 0], [0, 1], [1, 0], [2, 1]]
const model = await BasisRegressor.create({ method: 'rvfl', nComponents: 64 })
model.fit(X, [-1, 1, 3, 5])
const predictions = model.predict([[0.5, 0]])
const restored = await load(model.save())

Use BasisClassifier for classification, with predictProba(X), decisionFunction(X) and the classes property. Probabilities and decisions are flat row-major arrays of rows * classes.length. Predictions retain sorted original int32 class labels. Dense {data, rows, cols} matrices and rectangular numeric arrays are accepted; sparse and missing inputs are unsupported.

Construction/loading is asynchronous. fit, prediction, scoring, save and dispose are synchronous. fit(X, y, {sampleWeight}) accepts nonnegative weights with positive total and positive weight in every observed class.

dist/basis.js exposes the basis browser global. dist/basis.mjs provides named ESM exports. Both embed single-threaded WASM and work without special cross-origin isolation headers. TypeScript declarations implement the shared wlearn Estimator/Classifier contract.

Python

from wlearn_basis import BasisRegressor
from wlearn import load

model = BasisRegressor(method="rvfl", n_components=64)
model.fit([[-1, 0], [0, 1], [1, 0], [2, 1]], [-1, 1, 3, 5])
predictions = model.predict([[0.5, 0]])
model.save("model.wlrn")
restored = load("model.wlrn")

Python names use snake_case: n_components, max_iter, get_params, set_params, default_search_space, predict_proba, decision_function, feature_map, fit_info, classes_, n_features_in_, n_components_. fit(X, y, sample_weight=None) accepts NumPy arrays or numeric lists. predict_proba and decision_function return (rows, classes) arrays, including two columns for binary classification. save(path=None) returns WLRN bytes; load(bytes_or_path) accepts those bytes or a filesystem path.

Models and parameters

Parameter (JS / Python) Default Meaning
method rff elm, rvfl, rff, nystrom
sampling gaussian gaussian or supervised swim, for ELM/RVFL
nComponents / n_components 128 Requested map width, 1–4096
activation tanh tanh or relu, for ELM/RVFL
readout ridge / logistic Regression / classification default
alpha 1 Positive readout regularization
gamma 0.1 Positive RBF inverse length scale, RFF/Nyström
scale 1 Positive weight/bias scale, or SWIM transition scale
seed 42 Integer 0–2³²−1
maxIter / max_iter 300 Logistic iteration cap
tol 1e-6 Logistic mean-objective gradient infinity-norm threshold

Scale numeric inputs using training rows only, through preprocessing outside the model (for wlearn pipelines, use @wlearn/preprocess / wlearn.preprocess). Map width, regularization and kernel width affect quality. These defaults are starting points, not selected configurations for every dataset.

  • ELM defaults to fixed Gaussian weights scaled by scale / sqrt(input width), uniform biases in [-scale, scale], then tanh or ReLU.
  • RVFL appends the original numeric inputs to those ELM features.
  • RFF uses sqrt(2/m) * cos(Wx + b), Gaussian weights of variance 2*gamma and uniform phase. It approximates exp(-gamma * ||x-z||²).
  • Nyström samples distinct training row indices and whitens their RBF kernel using a symmetric eigendecomposition. Effective width is min(nComponents,n); duplicate rows are allowed. Eigenvalues at most 1e-12 * max(1, largest) are truncated. Feature coordinates are not uniquely determined across numerical implementations; their kernel and predictions are the meaningful comparison.

SWIM sampling

Set sampling: 'swim' in JS or sampling="swim" in Python with method='elm' or 'rvfl'. SWIM samples a supervised map once; it uses the same readout and has the same prediction cost as the corresponding Gaussian map.

The implementation follows Bolager et al., NeurIPS 2023. Pair mass is proportional to abs(y2-y1) / ||x2-x1||; classification uses one-hot target distance (one for different classes, zero otherwise), so class numbers carry no ordering. Positive sample weights define the endpoint measure. All ordered pairs are considered if they fit within max(4096, 8*nComponents); otherwise that many pairs are sampled with replacement from the endpoint measure. The hidden units are resampled from this pool using the supervised masses. This is a bounded approximation, not exhaustive pair search on large datasets.

For endpoints a,b, hidden weights are s1*(b-a)/||b-a||² and bias is -dot(weights,a)-s2. Tanh uses (s1,s2)=scale*(log(3),log(3)/2); ReLU uses (scale,0). At scale one, the two endpoints map to (-.5,.5) for tanh or (0,1) for ReLU. Pairs within 1e-12 input units are excluded. If all target differences in the pool vanish, sampling uses endpoint masses alone. If no usable pair remains, hidden weights are zero, retaining the readout intercept and RVFL direct inputs. No preprocessing or target data is stored for inference.

SWIM must be fitted inside every CV training fold, after training-only scaling. Do not construct its map from validation targets. Tune alpha, width, activation and scale; supervised sampling does not guarantee better predictions.

Ridge minimizes sum(w * residual²) + alpha * ||coefficients||² via incremental Givens QR. Logistic minimizes sum(w * cross_entropy) + alpha/2 * ||coefficients||² via L-BFGS. Both leave the intercept unpenalized. Classification ridge fits one-hot targets and softmaxes its scores; those probabilities are uncalibrated.

fitInfo / fit_info reports iterations and convergence. Ridge reports one direct solve. A logistic iteration cap or unsuccessful line search retains a finite fitted model with converged=false; inspect this diagnostic when tuning. Ridge uses O(q² + qk) workspace, while logistic additionally holds the n×q feature matrix; Nyström has O(m²) storage and an O(m³) eigensolve. Individual arrays and the model payload are limited to 256 MiB, not total process memory. WASM memory may grow to 1 GiB. Large input magnitudes may be rejected when feature/readout arithmetic cannot remain finite.

Lifecycle and composition

BasisTransformer fits only a feature map and emits a host-owned dense matrix. It shares map construction with the fused estimators and can precede GAM, RF, XGBoost or another compatible estimator:

const { BasisTransformer } = require('@wlearn/basis')
const { RFModel } = require('@wlearn/rf')
const { Pipeline } = require('@wlearn/core')

const map = await BasisTransformer.create({ method: 'rvfl', sampling: 'swim', nComponents: 64 })
const forest = await RFModel.create({ task: 'regression', nEstimators: 100 })
const pipeline = new Pipeline([['map', map], ['forest', forest]])
pipeline.fit(X, y)
const predictions = pipeline.predict(Xtest)
const bytes = pipeline.save()

Python exposes the same BasisTransformer, with fit_transform, transform, save(path=None) and load(bytes_or_path). Map parameters exclude readout, alpha, maxIter and tol; task defaults to 'regression'. Set task: 'classification' when SWIM should use label equality rather than numerical target distance. Only SWIM requires y. Weights affect SWIM sampling; other maps retain seeded sampling. Pipeline forwards weights to steps declaring support and rejects a weighted fit if the final estimator cannot consume them.

Map persistence uses wlearn.basis.transformer@1 with a BAM1 payload inside WLRN. There is no readout state. Keep SWIM fitting inside each CV training fold; AutoML can search a caller-provided estimator factory owning this Pipeline. Its Tranfi templates continue to cover ordinary tabular preparation.

Materializing a map allocates rows * outputCols * 8 bytes before the next estimator copies input into its own runtime. Fused ridge avoids this training matrix through streaming QR. Tree composition is available, but its accuracy and cost need validation for the intended dataset.

getParams/setParams expose validated parameters. A changed parameter invalidates fitted state. Invalid parameters and failed refits preserve the previous fitted model. Returned predictions/features/coefficients are owned copies. featureMap / feature_map inspects the fitted map; it is not a pipeline Transformer. coefficients() includes the intercept in its last row.

Call dispose() when replacing models or completing loops, CV and worker jobs. Each model owns native allocations; disposal is idempotent. Finalizers are a fallback. Python instances and the singleton WASM module are intended for serial calls; use separate workers/processes for parallel training.

Both estimator classes expose model-provided search spaces and stable AutoML class IDs. They compose with existing core Pipeline, VotingEnsemble and AutoML without model-specific engine code. The SDK re-exports both estimators and the Transformer. defaultPortfolio() / default_portfolio() supplies four initial configurations; callers can override these through the model spec's portfolio. The shared search IR currently supports equality conditions. The default space therefore searches sampling, activation and scale when method='elm'; RVFL uses defaults for those fields. To tune SWIM RVFL, supply a space with method fixed to rvfl and those parameters unconditional.

Gaussian persistence retains wlearn.basis.classifier@1 and wlearn.basis.regressor@1. SWIM uses the corresponding @2 type IDs and BAS2 payload, with the sampling flag in header word 52. Old readers reject this version; current readers accept both. Existing Gaussian bundles and Gaussian RNG sequences are unchanged. The core WLRN container holds a validated application/vnd.wlearn.basis payload with BAS1 magic, a 96-byte little-endian header, feature parameters, Nyström whitening matrix, readout coefficients and original labels. Payload bytes survive Python/JS round trips exactly; fresh native/WASM training is compared within numerical tolerance. There is no pickle or alternative public artifact format.

Build and test

Canonical C sources live in src/. js/csrc/ and py/csrc/ are generated distribution copies, following the RF/GAM layout. Native CMake builds a shared library; Python wheels compile the same sources into a ctypes-loadable extension.

make test-c JOBS=4
make build-js                 # Emscripten, Node, esbuild and local core required
make test-js test-types test-browser
make test-py PYTHON=python3    # install Python test extras first
make wheel PYTHON=python3

Use process affinity and numerical thread limits appropriate to the host. Browser tests reuse the ecosystem Playwright install and Chromium cache. BASIS_LIB_PATH selects a native development library explicitly. The native build and wheels have been exercised on Linux x86-64; other native platforms require their own build checks.

bench/composition.py --output RUN compares fused ridge with a separately fitted map plus matched sklearn ridge, and raw/map-based RF and XGBoost. It uses four small IID datasets and three fixed outer splits, without tuning. The shared repository's bench/basis-composition.mjs RUN WASM_RUN consumes those exact prepared splits for a separate WASM Pipeline comparison.

bench/benchmark.py compares fixed settings against native linear/logistic, wlearn RF, XGBoost and LightGBM on six datasets and three held-out splits. Install its optional reference dependencies first. It writes the protocol before fitting, hashes implementation inputs and reports metrics, fit/predict times, bundle sizes and cumulative process RSS. bench/benchmark.js consumes the same prepared splits for a separate WASM comparison. Timings are single warm-process measurements, not controlled performance regression gates.

bench/tune.py --output RUN --energy-csv DATA.csv runs the separate small tuning study: 12 candidates per family, three inner folds and two outer split seeds. Gaussian/SWIM ELM and RVFL share candidates; RFF/Nyström, ridge/logistic, XGBoost and LightGBM are tuned too. Six original datasets are retained, with iris and UCI energy heating load added. The latter is a building simulation dataset: Tsanas & Xifara (2012), UCI, CC BY 4.0. Download its CSV separately; it is not shipped in the package. Protocol, splits, source hashes, trial failures, warnings, convergence, selected parameters and test predictions are saved.

License

Original implementation: Apache-2.0. No GPL model dependency is included. The npm package carries Emscripten, musl, compiler-rt and bundled wlearn core notices under licenses/; browser distributions embed those license texts.

Metadata

Release files for wlearn-basis 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for wlearn-basis 0.1.0
File Size Uploaded Provenance Actions
wlearn_basis-0.1.0.tar.gz 36.1 kB Without provenance Details for wlearn_basis-0.1.0.tar.gz

Release files / wlearn_basis-0.1.0.tar.gz

Download URL wlearn_basis-0.1.0.tar.gz
Size 36.1 kB
Tags Source
SHA-256 checksum
How to use checksums
1bf5daad4e66c6864c0bc7ed056a0e38670cb65c6918720c8ee2e02effa288da
BLAKE2b-256 checksum
How to use checksums
113499148516e1781eb52d19486810b6796a95de3036871735bf6dfba2314acb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.12

Security for wlearn-basis 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

1 release file No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page