Skip to main content

tiny-solver-rs

Warning! This project is still under development.

crate PyPI - Version PyPI - Python Version

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 = &params[0][0];
        let y = &params[1][0];
        let z = &params[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

m3500 dataset rust result.
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

Metadata

Release files for tiny-solver 0.7.0

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

Built distributions (wheels)

Table of built distributions (wheels) for tiny-solver 0.7.0
File Interpreter ABI Platform Actions
tiny_solver-0.7.0-cp37-abi3-manylinux_2_35_x86_64.whl CPython 3.7 abi3 Linux glibc 2.35+ x86-64 Details for tiny_solver-0.7.0-cp37-abi3-manylinux_2_35_x86_64.whl
tiny_solver-0.7.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.7 abi3 Linux glibc 2.17+ ARM64 Details for tiny_solver-0.7.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
tiny_solver-0.7.0-cp37-abi3-macosx_11_0_arm64.whl CPython 3.7 abi3 macOS 11.0+ ARM64 Details for tiny_solver-0.7.0-cp37-abi3-macosx_11_0_arm64.whl

Total release size: 10.7 MB

Release files / tiny_solver-0.7.0-cp37-abi3-manylinux_2_35_x86_64.whl

Download URL tiny_solver-0.7.0-cp37-abi3-manylinux_2_35_x86_64.whl
Size 3.6 MB
Tags CPython 3.7 Linux glibc 2.35+ x86-64 abi3
SHA-256 checksum
How to use checksums
bb3b4886e27eaa0dce79ab0f5c64577732f516b369737005aaa190918818ff2c
BLAKE2b-256 checksum
How to use checksums
a94ba1542c28dbaf84bb68dfb8e5272c806499f5a7c396be3b72a7a07161c8b6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/5.0.0 CPython/3.10.12

Release files / tiny_solver-0.7.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL tiny_solver-0.7.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 4.2 MB
Tags CPython 3.7 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
a1c491a74978307b2f74da3685a610a5aa6ac63c1a219d22ba3c6f716cf4a973
BLAKE2b-256 checksum
How to use checksums
4c128f50cf53e86c46b02d20ae0e9dddcf376e5d3babb3362e2427656bff477a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/5.0.0 CPython/3.10.12

Release files / tiny_solver-0.7.0-cp37-abi3-macosx_11_0_arm64.whl

Download URL tiny_solver-0.7.0-cp37-abi3-macosx_11_0_arm64.whl
Size 2.9 MB
Tags CPython 3.7 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
9898dae2bdf83eec9958c2caacef1c49d0f1fd3582cbcb27185170f9e194b91b
BLAKE2b-256 checksum
How to use checksums
431e387913676301a7efeb46af37ae62ef7139670e1095a3dcba037233613f58
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/5.1.1 CPython/3.12.6

Security for tiny-solver 0.7.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.

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