1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//! [![Latest Version]][crates.io]
//! [![Rust](https://github.com/ralfbiedert/ffsvm-rust/actions/workflows/rust.yml/badge.svg?branch=master)](https://github.com/ralfbiedert/ffsvm-rust/actions/workflows/rust.yml)
//! [![deps.svg]][deps]
//! [![docs]][docs.rs]
//! ![MIT]
//!
//! # In One Sentence
//!
//! You trained a SVM using [libSVM](https://github.com/cjlin1/libsvm), now you want the highest possible performance during (real-time) classification, like games or VR.
//!
//!
//! # Highlights
//!
//! * loads almost all [libSVM](https://github.com/cjlin1/libsvm) types (C-SVC, ν-SVC, ε-SVR,  ν-SVR) and kernels (linear, poly, RBF and sigmoid)
//! * produces practically same classification results as libSVM
//! * optimized for [SIMD](https://github.com/rust-lang/rfcs/pull/2366) and can be mixed seamlessly with [Rayon](https://github.com/rayon-rs/rayon)
//! * written in 100% Rust
//! * allocation-free during classification for dense SVMs
//! * **2.5x - 14x faster than libSVM for dense SVMs**
//! * extremely low classification times for small models (e.g., 128 SV, 16 dense attributes, linear ~ 500ns)
//! * successfully used in **Unity and VR** projects (Windows & Android)
//!
//!
//! Note: Currently **requires Rust nightly** (March 2019 and later), because we depend on RFC 2366 (portable SIMD). Once that stabilizes we'll also go stable.
//!
//!
//! # Usage
//!
//! Train with [libSVM](https://github.com/cjlin1/libsvm) (e.g., using the tool `svm-train`), then classify with `ffsvm-rust`.
//!
//! From Rust:
//!
//! ```rust
//! # use std::convert::TryFrom;
//! # use ffsvm::{DenseSVM, Predict, Problem, SAMPLE_MODEL, Solution};
//! # fn main() -> Result<(), ffsvm::Error> {
//! // Replace `SAMPLE_MODEL` with a `&str` to your model.
//! let svm = DenseSVM::try_from(SAMPLE_MODEL)?;
//!
//! let mut problem = Problem::from(&svm);
//! let features = problem.features();
//!
//! features[0] = 0.55838;
//! features[1] = -0.157895;
//! features[2] = 0.581292;
//! features[3] = -0.221184;
//!
//! svm.predict_value(&mut problem)?;
//!
//! assert_eq!(problem.solution(), Solution::Label(42));
//! # Ok(())
//! # }
//!
//! ```
//!
//! # Status
//! * **March 10, 2023**: Reactivated for latest Rust nightly.
//! * **June 7, 2019**: Gave up on 'no `unsafe`', but gained runtime SIMD selection.
//! * **March 10, 2019**: As soon as we can move away from nightly we'll go beta.
//! * **Aug 5, 2018**: Still in alpha, but finally on crates.io.
//! * **May 27, 2018**: We're in alpha. Successfully used internally on Windows, Mac, Android and Linux
//! on various machines and devices. Once SIMD stabilizes and we can cross-compile to WASM
//! we'll move to beta.
//! * **December 16, 2017**: We're in pre-alpha. It will probably not even work on your machine.
//!
//!
//! # Performance
//!
//! ![performance](https://raw.githubusercontent.com/ralfbiedert/ffsvm-rust/master/docs/performance_relative.v3.png)
//!
//! All performance numbers reported for the `DenseSVM`. We also have support for `SparseSVM`s, which are slower for "mostly dense" models, and faster for "mostly sparse" models (and generally on the performance level of libSVM).
//!
//! [See here for details.](https://github.com/ralfbiedert/ffsvm-rust/blob/master/docs/performance.md)
//!
//!
//! ### Tips
//!
//! * For an x-fold performance increase, create a number of `Problem` structures, and process them with [Rayon's](https://docs.rs/rayon/1.0.3/rayon/) `par_iter`.
//!
//!
//! # FAQ
//!
//! [See here for details.](https://github.com/ralfbiedert/ffsvm-rust/blob/master/docs/FAQ.md)
//!
//! [Latest Version]: https://img.shields.io/crates/v/ffsvm.svg
//! [crates.io]: https://crates.io/crates/ffsvm
//! [MIT]: https://img.shields.io/badge/license-MIT-blue.svg
//! [docs]: https://docs.rs/ffsvm/badge.svg
//! [docs.rs]: https://docs.rs/ffsvm/
//! [deps]: https://deps.rs/repo/github/ralfbiedert/ffsvm-rust
//! [deps.svg]: https://deps.rs/repo/github/ralfbiedert/ffsvm-rust/status.svg

#![feature(portable_simd)]
#![warn(clippy::all)] // Enable ALL the warnings ...
#![warn(clippy::nursery)]
#![warn(clippy::pedantic)]
#![warn(clippy::cargo)]
#![allow(clippy::cast_possible_truncation)] // All our casts are in a range where this doesn't matter.
#![allow(clippy::cast_precision_loss)]
#![allow(clippy::cast_possible_wrap)]
#![allow(clippy::module_name_repetitions)] // We do that way too often
#![allow(clippy::doc_markdown)] // Mainly for `libSVM` in the docs.

mod errors;
mod parser;
mod sparse;
mod svm;
mod util;
mod vectors;

// Set float types to largest width we support instructions sets
// (important to make sure we get max alignment of target_feature) when selecting
// dynamically.
#[allow(non_camel_case_types)]
#[doc(hidden)]
pub type f32s = simd_aligned::arch::x256::f32s;
#[doc(hidden)]
#[allow(non_camel_case_types)]
pub type f64s = simd_aligned::arch::x256::f64s;

#[doc(hidden)]
pub static SAMPLE_MODEL: &str = include_str!("sample.model");

pub use crate::{
    errors::Error,
    parser::{Attribute, Header, ModelFile, SupportVector},
    svm::{
        kernel::{KernelDense, KernelSparse, Linear, Poly, Rbf, Sigmoid},
        predict::Predict,
        problem::{DenseProblem, Problem, Solution, SparseProblem},
        DenseSVM, SVMType, SparseSVM,
    },
};