https://github.com/wrenfold/wrenfold
Toolkit for generating code from symbolic math expressions.
https://github.com/wrenfold/wrenfold
code-generation computer-vision mathematics robotics symbolic-math
Last synced: 2 months ago
JSON representation
Toolkit for generating code from symbolic math expressions.
- Host: GitHub
- URL: https://github.com/wrenfold/wrenfold
- Owner: wrenfold
- License: mit
- Created: 2021-10-30T22:37:31.000Z (almost 4 years ago)
- Default Branch: main
- Last Pushed: 2025-07-20T16:36:19.000Z (3 months ago)
- Last Synced: 2025-07-22T22:06:27.097Z (2 months ago)
- Topics: code-generation, computer-vision, mathematics, robotics, symbolic-math
- Language: C++
- Homepage:
- Size: 3.15 MB
- Stars: 66
- Watchers: 5
- Forks: 1
- Open Issues: 21
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Citation: CITATION.cff
- Support: support/code_coverage.py
Awesome Lists containing this project
README
# wrenfold
![]()
---
`wrenfold` is a framework for converting symbolic mathematical expressions (written in Python) into generated numerical code in other languages (C++, Rust, Python). It aims to bridge the gap between prototyping of functions in expressive symbolic form, and performant production code. wrenfold is particularly relevant to domains where numerical optimization is employed to solve differentiable objective functions, such as robotics or computer vision.
Using wrenfold, mathematical functions can be expressed and composed succinctly in python:
```python
from wrenfold import code_generation, sym
from wrenfold.type_annotations import Vector3def angular_distance(a: Vector3, b: Vector3):
"""
A simple example function: We compute the angle between two vectors. The angle is returned, and
the Jacobian with respect to `a` is passed as an output argument. This might be a cost in an
optimization, for instance.
"""
dot = (a.T * b)[0]
cos_theta = dot / (a.norm() * b.norm())
theta = sym.acos(cos_theta)
theta_D_a = sym.jacobian([theta], a)# Our generated function will return `theta`, and pass `theta_D_a` as an output arg.
return (
code_generation.ReturnValue(theta),
code_generation.OutputArg(theta_D_a, "theta_D_a"),
)
```And corresponding compilable code can be obtained easily:
```python
# CppGenerator can be swapped out for RustGenerator to obtain Rust. You can implement your own
# custom generator to target a new language - or override methods on the provided generators in
# order to customize the output code to your liking.
cpp = code_generation.generate_function(angular_distance, code_generation.CppGenerator())
print(cpp)
```
```cpp
template
Scalar angular_distance(const T0& a, const T1& b, T2&& theta_D_a) {
auto _a = wf::make_input_span<3, 1>(a);
auto _b = wf::make_input_span<3, 1>(b);
auto _theta_D_a = wf::make_output_span<1, 3>(theta_D_a);const Scalar v007 = _b(2, 0);
const Scalar v006 = _a(2, 0);
const Scalar v004 = _b(1, 0);// ... Output code is truncated for brevity.
const Scalar v009 = v000 * v001 + v003 * v004 + v006 * v007;
const Scalar v021 = v001 * v001 + v004 * v004 + v007 * v007;// ...
_theta_D_a(0, 0) = (v000 * v072 + v001 * v017) * v073;
_theta_D_a(0, 1) = (v003 * v072 + v004 * v017) * v073;
_theta_D_a(0, 2) = (v006 * v072 + v007 * v017) * v073;
return std::acos(v009 * v017 * v023);
}
```wrenfold draws inspiration from [SymForce](https://symforce.org), but differs in a few key ways:
* **Improved flexibility**: Symbolic expressions can include conditional logic. This enables a broader range of functions to be generated.
* **Ease of integration**: wrenfold aims to make it straightforward to customize the code-generation step to suit your project. For example, you can [use existing types in your codebase in generated method signatures](https://wrenfold.org/reference/custom_types.html).
* **Faster code generation**: Faster code generation translates to quicker iteration on experiments. The generation cost should ideally be negligible compared to compile time for the code itself.
* **Narrower scope**: wrenfold does not implement a numerical optimizer. Rather we aim to make it simple to integrate generated code into your project's existing preferred optimizer (see the [extended examples](https://github.com/wrenfold/wrenfold-extra-examples)). It should be relatively straightforward to use wrenfold functions with GTSAM, Ceres, the SymForce optimizer, or your own custom implementation.wrenfold is primarily written in C++, and exposes a python API via [pybind11](https://pybind11.readthedocs.io). It can presently generate code in C++17, Rust, and Python (NumPy, PyTorch, and JAX are all supported).
## Motivation
Why use symbolic code generation for mathematical functions? The [SymForce paper](https://arxiv.org/abs/2204.07889) outlines some of the rationale. In our opinion, the two main arguments are:
* **Faster iteration**:
- Functions can be written quickly and expressively in python, enabling rapid prototyping. Over time, users acquire a library of composable expressions that can be combined easily to form new symbolic functions.
- Derivatives are obtained automatically, without spending time debugging manually chain-ruled Jacobians.
* **Improved runtime performance**:
- The performance of generated methods is [often competitive with handwritten implementations](https://wrenfold.org/performance.html), and can meaningfully exceed results obtained with runtime auto-diff.
- Generated methods are fast enough to deploy on a production robot, enabling a quicker pipeline from offline prototyping to real-world testing.
- **A prudent caveat for any performance related claim**: Your mileage may vary depending on expression complexity and the degree of effort exerted in optimizing different implementations.## Getting started
Install wrenfold from [PyPi](https://pypi.org/project/wrenfold/):
```bash
pip install wrenfold
```wrenfold is also available on [conda-forge](https://anaconda.org/conda-forge/wrenfold):
```bash
conda install -c conda-forge wrenfold
```To get started:
- Refer to the [quick start guide](https://wrenfold.org/quick_start.html) and [user guide](https://wrenfold.org/reference/index.html).
- Take a look at some of the examples:
- There are some examples of symbolic expressions [in this repository](examples). For instance, an implementation of [imu integration](examples/imu_integration/imu_integration.py) or the dynamics of a [cart-pole/double-pendulum](examples/cart_pole/cart_pole_dynamics.py) system.
- Each example includes a unit test that invokes the generated code.
- The [wrenfold-extra-examples](https://github.com/wrenfold/wrenfold-extra-examples) repository includes examples of integrating generated code into existing optimizers like [GTSAM](http://gtsam.org) and [Ceres](http://ceres-solver.org).## Building from source
See [Building from source](https://wrenfold.org/building.html).
## Project status
wrenfold was originally created by [me](https://github.com/gareth-cross) after determining there were opportunities to push the symbolic code-generation concept further (see motivations section).
The project began as a part-time hobby for fun, and has evolved into a more full-featured framework over time. wrenfold is in the early stages of receiving feedback from a wider audience. There will be rough edges and undoubtedly some bugs. If you find something broken or missing, please consider [filing a ticket](https://github.com/wrenfold/wrenfold/issues/new/choose). I aim to continue developing and expanding the framework. For details of upcoming work, see the [planned features list](https://github.com/wrenfold/wrenfold/issues?q=is%3Aissue+is%3Aopen+label%3Afeature).
If you are interested in collaboration opportunities or have general questions, please [reach out](mailto:gcross.code@icloud.com?subject=Wrenfold).
## License
wrenfold uses the [MIT License](./LICENSE).
## Citation
wrenfold is published in the [Journal of Open Source Software (JOSS)](https://joss.theoj.org). If you wish to cite this project, please use the following:
```bibtex
@article{Cross2025,
doi = {10.21105/joss.07303},
url = {https://doi.org/10.21105/joss.07303},
year = {2025},
publisher = {The Open Journal},
volume = {10},
number = {105},
pages = {7303},
author = {Gareth Cross},
title = {wrenfold: Symbolic code generation for robotics},
journal = {Journal of Open Source Software}
}
```