| Crates.io | silva |
| lib.rs | silva |
| version | 0.1.0 |
| created_at | 2025-12-30 14:29:03.008572+00 |
| updated_at | 2025-12-30 14:29:03.008572+00 |
| description | A fast Rust inference engine for tree ensemble models supporting XGBoost, LightGBM, and native formats |
| homepage | |
| repository | https://github.com/lucidfrontier45/silva |
| max_upload_size | |
| id | 2012719 |
| size | 2,266,977 |
Silba is a tiny inference engine for tree ensemble models (a.k.a forest models) in Rust.
gbtree only (gblinear and dart are not supported)reg:squarederror (regression)binary:logistic (binary classification)multi:softmax (multiclass classification)multi:softprob (multiclass classification)cargo add silva
A container for multi-output models (e.g., multi-class classification). Holds a vector of Forest instances, one per output class. Returns a vector of predictions, one per output.
Single-output tree ensemble containing:
base_value: Bias/baseline score added to all predictionstrees: Vector of decision treesPrediction formula: base_value + Σ tree_predictions
Individual decision tree represented as:
node_map: Hash map of node ID → TreeNoderoot: Root node IDTraverses tree from root to leaf based on feature comparisons.
Single node with:
split_index: Feature index for splittingsplit_condition: Threshold value (NotNanleft/right: Child node IDs (None for leaves)value: Leaf value (NotNanLeaves have no children; internal nodes contain split logic.
{
"forests": [
{
"base_value": 0.5,
"trees": [
{
"nm": {
"0": {"id": 0, "si": 0, "sc": 2.5, "l": 1, "r": 2, "v": 0.0},
"1": {"id": 1, "si": 1, "sc": 1.5, "l": null, "r": null, "v": 3.0},
"2": {"id": 2, "si": 1, "sc": 3.5, "l": null, "r": null, "v": 5.0}
},
"root": 0
},
{
"nm": {
"0": {"id": 0, "si": 0, "sc": 5.0, "l": 1, "r": 2, "v": 0.0},
"1": {"id": 1, "si": 1, "sc": 2.0, "l": null, "r": null, "v": 10.0},
"2": {"id": 2, "si": 1, "sc": 3.0, "l": null, "r": null, "v": 20.0}
},
"root": 0
}
]
}
]
}
| Abbreviation | Full Name | Description |
|---|---|---|
nm |
node_map | Hash map mapping node ID to TreeNode |
si |
split_index | Feature index used for splitting at this node |
sc |
split_condition | Threshold value for the split comparison |
l |
left | ID of left child node (null for leaves) |
r |
right | ID of right child node (null for leaves) |
v |
value | Leaf prediction value (only used in leaf nodes) |
MultiOutputForest
└── forests: Forest[]
├── base_value: f64 (baseline score)
├── trees: Tree[]
│ ├── nm: {node_id: TreeNode}
│ │ ├── id: node ID
│ │ ├── si: feature index to split on
│ │ ├── sc: split threshold
│ │ ├── l: left child ID (or null)
│ │ ├── r: right child ID (or null)
│ │ └── v: leaf value
│ └── root: ID of the root node
Prediction Flow: Start at root → compare feature[si] with sc → follow l or r → repeat until leaf → sum all tree values → add base_value
The predict methods work with feature vectors (&[f64]) and return prediction values.
use silva::Tree;
let tree = Tree::new(node_map, root_id);
let prediction = tree.predict(&[1.5, 2.3, 0.8]); // returns NotNan<f64>
use silva::Forest;
let forest = Forest::new(base_value, trees);
let prediction = forest.predict(&[1.5, 2.3, 0.8]); // returns NotNan<f64>
use silva::MultiOutputForest;
let model = MultiOutputForest::new(forests);
let predictions = model.predict(&[1.5, 2.3, 0.8]); // returns Vec<NotNan<f64>>
use silva::MultiOutputForest;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Load model from file
let model = MultiOutputForest::from_file("model.json")?;
// Prepare feature data
let features = vec![vec![1.5, 2.3, 0.8], vec![0.5, 1.2, 3.4]];
// Make predictions
for x in &features {
let prediction = model.predict(x);
println!("Predictions: {:?}", prediction);
}
Ok(())
}
For more examples, see examples/prediction.rs.