npm package: @millcrest/libsvmts
Description: Modern TypeScript wrapper for libsvm with WebAssembly support and sklearn-like API
Latest version: 0.0.6

# libsvm-ts

[![npm version](https://badge.fury.io/js/libsvm-ts.svg)](https://badge.fury.io/js/libsvm-ts)
[![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.3-blue)](https://www.typescriptlang.org/)

Modern TypeScript wrapper for [libsvm](https://github.com/cjlin1/libsvm) with WebAssembly support and an sklearn-like API. This library brings powerful Support Vector Machine capabilities to TypeScript/JavaScript with a familiar, Pythonic interface inspired by [scikit-learn](https://scikit-learn.org/).

## 🚀 Quick Start

### Installation

```bash
npm install @millcrest/libsvmts
```

### Basic Classification Example

```typescript
import { SVC } from "@millcrest/libsvmts";

// Create and configure classifier
const clf = new SVC({
  kernel: 'rbf',
  C: 1.0,
  gamma: 'scale',
});

// Prepare data
const x_train = [[0, 0], [1, 1], [1, 0], [0, 1]];
const y_train = [0, 0, 1, 1];

// Train model
await clf.fit(x_train, y_train);

// Make predictions
const predictions = clf.predict([[0.5, 0.5]]);
console.log(predictions); // [0]

// Get accuracy
const accuracy = clf.score(x_train, y_train);
console.log(`Accuracy: ${(accuracy * 100).toFixed(2)}%`);

// Clean up
clf.free();
```

### Basic Regression Example

```typescript
import { SVR } from "@millcrest/libsvmts";

// Create regressor
const regressor = new SVR({
  kernel: 'rbf',
  C: 1.0,
  epsilon: 0.1,
});

// Prepare data
const x_train = [[0], [1], [2], [3], [4]];
const y_train = [0, 1, 4, 9, 16]; // y = x^2

// Train model
await regressor.fit(x_train, y_train);

// Make predictions
const predictions = regressor.predict([[2.5]]);
console.log(predictions); // ~6.25

// Get R² score
const r2 = regressor.score(x_train, y_train);
console.log(`R² Score: ${r2.toFixed(4)}`);

// Clean up
regressor.free();
```

## 📖 Documentation

### API Reference

#### SVC (Support Vector Classification)

Mimics [sklearn.svm.SVC](https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html)

**Constructor Parameters:**

```typescript
interface SVCParams {
  C?: number;                        // Regularization parameter (default: 1.0)
  kernel?: 'linear' | 'poly' | 'rbf' | 'sigmoid' | 'precomputed';  // default: 'rbf'
  degree?: number;                   // Degree for poly kernel (default: 3)
  gamma?: number | 'scale' | 'auto'; // Kernel coefficient (default: 'scale')
  coef0?: number;                    // Independent term in kernel (default: 0.0)
  tol?: number;                      // Tolerance for stopping (default: 1e-3)
  shrinking?: boolean;               // Use shrinking heuristic (default: true)
  probability?: boolean;             // Enable probability estimates (default: false)
  cacheSize?: number;                // Kernel cache size in MB (default: 200)
  classWeight?: 'balanced' | Record<number, number> | null;  // Class weights
  verbose?: boolean;                 // Verbose output (default: false)
  maxIter?: number;                  // Max iterations, -1 for no limit (default: -1)
  decisionFunctionShape?: 'ovr' | 'ovo';  // Decision function shape (default: 'ovr')
  breakTies?: boolean;               // Break ties by confidence (default: false)
  randomState?: number | null;       // Random seed (default: null)
}
```

**Methods:**

- `async fit(X: Matrix, y: Vector): Promise<this>` - Fit the SVM model
- `predict(X: Matrix): Vector` - Predict class labels
- `predictProba(X: Matrix): PredictionWithProba[]` - Predict class probabilities (requires `probability: true`)
- `decisionFunction(X: Matrix): Matrix` - Compute decision function values
- `score(X: Matrix, y: Vector): number` - Return mean accuracy
- `getModelInfo(): ModelInfo | null` - Get model information
- `free(): void` - Free model memory

#### SVR (Support Vector Regression)

Mimics [sklearn.svm.SVR](https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVR.html)

**Constructor Parameters:**

```typescript
interface SVRParams {
  C?: number;                        // Regularization parameter (default: 1.0)
  kernel?: 'linear' | 'poly' | 'rbf' | 'sigmoid' | 'precomputed';  // default: 'rbf'
  degree?: number;                   // Degree for poly kernel (default: 3)
  gamma?: number | 'scale' | 'auto'; // Kernel coefficient (default: 'scale')
  coef0?: number;                    // Independent term in kernel (default: 0.0)
  epsilon?: number;                  // Epsilon in epsilon-SVR (default: 0.1)
  tol?: number;                      // Tolerance for stopping (default: 1e-3)
  shrinking?: boolean;               // Use shrinking heuristic (default: true)
  cacheSize?: number;                // Kernel cache size in MB (default: 200)
  verbose?: boolean;                 // Verbose output (default: false)
  maxIter?: number;                  // Max iterations, -1 for no limit (default: -1)
}
```

**Methods:**

- `async fit(X: Matrix, y: Vector): Promise<this>` - Fit the SVM model
- `predict(X: Matrix): Vector` - Predict target values
- `score(X: Matrix, y: Vector): number` - Return R² score
- `getModelInfo(): ModelInfo | null` - Get model information
- `free(): void` - Free model memory

### Types

```typescript
type Matrix = number[][];  // 2D array for features
type Vector = number[];    // 1D array for labels/targets

interface PredictionWithProba {
  label: number;
  probabilities: Record<number, number>;
}

interface ModelInfo {
  nClasses: number;
  classes?: number[];
  nSupportPerClass?: number[];
  nSupport: number;
  supportVectorIndices: number[];
  isFitted: boolean;
}
```

## 🏗️ Building from Source

### Prerequisites

- Node.js 16+
- [Emscripten](https://emscripten.org/docs/getting_started/downloads.html) (for building WASM)

### Setup

```bash
# Clone with submodules
git clone --recursive git@github.com:millcrest/libsvmts.git
cd libsvmts

# Or if already cloned
git submodule update --init --recursive

# Install dependencies
npm install

# Build everything
npm run build
```

**Note**: The first `npm install` will warn that WASM isn't built yet - that's expected.

### Installing Emscripten

Choose one of these methods:

**Option 1: System-wide (recommended)**
```bash
# Follow official guide: https://emscripten.org/docs/getting_started/downloads.html
```

**Option 2: Using Docker**
```bash
docker run -v $(pwd):/src -w /src emscripten/emsdk make build
```

**Option 3: Local emsdk (if you prefer)**
```bash
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install latest
./emsdk activate latest
source ./emsdk_env.sh
cd ..
```

### Build Commands

```bash
npm run build        # Build WASM + TypeScript
make build           # Build WASM only (requires emcc in PATH)
npm run build:ts     # Build TypeScript only
```
npm run build:ts
```

### Development Commands

```bash
npm run dev          # Watch mode for TypeScript
npm run build        # Build everything (WASM + TS)
npm run build:wasm   # Build WASM only
npm run build:ts     # Build TypeScript only
npm run test         # Run tests
npm run test:watch   # Watch mode for tests
npm run lint         # Lint code
npm run format       # Format code
npm run typecheck    # Type check without building
```

## 🔬 Advanced Usage

### Probability Estimates

```typescript
const clf = new SVC({
  kernel: 'rbf',
  probability: true,  // Enable probability estimates
});

await clf.fit(x_train, y_train);

// Get predictions with probabilities
const predictions = clf.predictProba(X_test);
predictions.forEach(pred => {
  console.log(`Predicted: ${pred.label}`);
  console.log(`Probabilities:`, pred.probabilities);
});
```

### Class Weights

```typescript
// Balanced class weights
const clf = new SVC({
  classWeight: 'balanced'
});

// Manual class weights
const clf = new SVC({
  classWeight: {
    0: 1.0,
    1: 2.0  // Give class 1 twice the weight
  }
});
```

### Decision Function

```typescript
const clf = new SVC({
  decisionFunctionShape: 'ovr'  // One-vs-Rest
});

await clf.fit(x_train, y_train);

// Get decision function values
const decisionValues = clf.decisionFunction(X_test);
```

### Model Persistence

```typescript
// Get model information
const modelInfo = clf.getModelInfo();
console.log('Support vectors:', modelInfo.nSupport);
console.log('Classes:', modelInfo.classes);

// Serialize model (TODO: implementation pending)
// const serialized = clf.serializeModel();
```

## 🧪 Testing

This project uses [Vitest](https://vitest.dev/) for both unit and integration tests.

```bash
# Run all tests (unit + integration)
npm test

# Run tests in watch mode
npm run test:watch

# Run tests with UI
npm run test:ui

# Run with coverage
npm run test:coverage
```

## 📝 License

This project is licensed under the BSD 3-Clause License - see the [LICENSE](./LICENSE) file for details.

libsvm is also licensed under the BSD 3-Clause License. See the [libsvm license](https://github.com/cjlin1/libsvm/blob/master/COPYRIGHT) for details.

## 🙏 Acknowledgments

- [libsvm](https://github.com/cjlin1/libsvm) by Chih-Chung Chang and Chih-Jen Lin
- [scikit-learn](https://scikit-learn.org/) for API inspiration
- [libsvm-ts](https://github.com/machinelearnjs/libsvm-ts) (original implementation) for initial inspiration

## 📚 References

- Chih-Chung Chang and Chih-Jen Lin, LIBSVM: a library for support vector machines. ACM Transactions on Intelligent Systems and Technology, 2:27:1--27:27, 2011.
- [libsvm website](https://www.csie.ntu.edu.tw/~cjlin/libsvm/)
- [Support Vector Machines on Wikipedia](https://en.wikipedia.org/wiki/Support_vector_machine)