Factor graph solver
Project description
tiny-solver-rs
Warning! This project is still under development.
Inspired by ceres-solver, tiny-solver, and minisam.
This is a general optimizer written in Rust, including bindings for Python. If you're familiar with ceres-solver or factor-graph optimizers, you'll find it very easy to use.
Installation
python
The python package can be installed directly from PyPI:
pip install tiny-solver
rust
cargo add tiny-solver
Current Features
- Automatic Derivatives using num-dual
-
Sparse QR, Sparse Cholesky using faer - GaussNewtonOptimizer
- Multithreading jacobian
- loss function (Huber)
- Define factor in python
TODO
- LevenbergMarquardtOptimizer
- information matrix
Benchmark
dataset | tiny-solver | gtsam | minisam |
---|---|---|---|
m3500 | 161.1ms | 130.7ms | 123.6 ms |
It's not extremely optimized, but it's easy to install and use.
Usage
Rust
// define your own Cost/Factor struct
// impl residual function
// and the jacobian will be auto generated
struct CustomFactor {}
impl tiny_solver::factors::Factor for CustomFactor {
fn residual_func(
&self,
params: &[nalgebra::DVector<num_dual::DualDVec64>],
) -> nalgebra::DVector<num_dual::DualDVec64> {
let x = ¶ms[0][0];
let y = ¶ms[1][0];
let z = ¶ms[1][1];
na::dvector![x + y.clone().mul(2.0) + z.clone().mul(4.0), y.mul(z)]
}
}
fn main() {
// init logger, `export RUST_LOG=trace` to see more log
env_logger::init();
// init problem (factor graph)
let mut problem = tiny_solver::Problem::new();
// add residual blocks (factors)
// add residual x needs to be close to 3.0
problem.add_residual_block(
1,
vec![("x".to_string(), 1)],
Box::new(tiny_solver::factors::PriorFactor {
v: na::dvector![3.0],
}),
None,
);
// add custom residual for x and yz
problem.add_residual_block(
2,
vec![("x".to_string(), 1), ("yz".to_string(), 2)],
Box::new(CustomFactor {}),
None,
);
// the initial values for x is 0.7 and yz is [-30.2, 123.4]
let initial_values = HashMap::<String, na::DVector<f64>>::from([
("x".to_string(), na::dvector![0.7]),
("yz".to_string(), na::dvector![-30.2, 123.4]),
]);
// initialize optimizer
let optimizer = tiny_solver::GaussNewtonOptimizer {};
// optimize
let result = optimizer.optimize(&problem, &initial_values, None);
// result
for (k, v) in result {
println!("{}: {}", k, v);
}
}
Python
import numpy as np
from tiny_solver import Problem, GaussNewtonOptimizer
from tiny_solver.factors import PriorFactor, PyFactor
# define custom cost function in python
# the trade off is the jacobian for the problem cannot be done in parallel
# because of gil
def cost(x: np.ndarray, yz: np.ndarray) -> np.ndarray:
r0 = x[0] + 2 * yz[0] + 4 * yz[1]
r1 = yz[0] * yz[0]
return np.array([r0, r1])
def main():
# initialize problem (factor graph)
problem = Problem()
# factor defined in python
custom_factor = PyFactor(cost)
problem.add_residual_block(
2,
[
("x", 1),
("yz", 2),
],
custom_factor,
None,
)
# prior factor import from rust
prior_factor = PriorFactor(np.array([3.0]))
problem.add_residual_block(1, [("x", 1)], prior_factor, None)
# initial values
init_values = {"x": np.array([0.7]), "yz": np.array([-30.2, 123.4])}
# optimizer
optimizer = GaussNewtonOptimizer()
result_values = optimizer.optimize(problem, init_values)
# result
for k, v in result_values.items():
print(f"{k}: {v}")
if __name__ == "__main__":
main()
Example
Basic example
cargo run -r --example small_problem
M3500 dataset
git clone https://github.com/powei-lin/tiny-solver-rs.git
cd tiny-solver-rs
# run rust version
cargo run -r --example m3500_benchmar
# run python version
pip install tiny-solver matplotlib
python3 examples/python/m3500.py
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
File details
Details for the file tiny_solver-0.7.0-cp37-abi3-manylinux_2_35_x86_64.whl
.
File metadata
- Download URL: tiny_solver-0.7.0-cp37-abi3-manylinux_2_35_x86_64.whl
- Upload date:
- Size: 3.6 MB
- Tags: CPython 3.7+, manylinux: glibc 2.35+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.0.0 CPython/3.10.12
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | bb3b4886e27eaa0dce79ab0f5c64577732f516b369737005aaa190918818ff2c |
|
MD5 | 2ca0e87f16794a3ee2fc3f503611d451 |
|
BLAKE2b-256 | a94ba1542c28dbaf84bb68dfb8e5272c806499f5a7c396be3b72a7a07161c8b6 |
File details
Details for the file tiny_solver-0.7.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
.
File metadata
- Download URL: tiny_solver-0.7.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 4.2 MB
- Tags: CPython 3.7+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.0.0 CPython/3.10.12
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | a1c491a74978307b2f74da3685a610a5aa6ac63c1a219d22ba3c6f716cf4a973 |
|
MD5 | 0e0b684ea96a32b3839ae99a47e30c81 |
|
BLAKE2b-256 | 4c128f50cf53e86c46b02d20ae0e9dddcf376e5d3babb3362e2427656bff477a |
File details
Details for the file tiny_solver-0.7.0-cp37-abi3-macosx_11_0_arm64.whl
.
File metadata
- Download URL: tiny_solver-0.7.0-cp37-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 2.9 MB
- Tags: CPython 3.7+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.1 CPython/3.12.6
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 9898dae2bdf83eec9958c2caacef1c49d0f1fd3582cbcb27185170f9e194b91b |
|
MD5 | 970de8609b90da0fee68ceb20ef7a63e |
|
BLAKE2b-256 | 431e387913676301a7efeb46af37ae62ef7139670e1095a3dcba037233613f58 |