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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
//! fact.rs (pronounced factors) is a nonlinear least squares optimization
//! library over factor graphs written in Rust.
//!
//! It is specifically geared toward sensor fusion in robotics. It aims to be
//! fast, easy to use, and safe. The fact.rs API takes heavy inspiration from
//! the [gtsam library](https://gtsam.org/).
//!
//! Currently, it supports the following features
//! - Gauss-Newton & Levenberg-Marquadt Optimizers
//! - Common Lie Groups supported (SO2, SO3, SE2, SE3) with optimization in Lie
//! Algebras
//! - Automatic differentiation via dual numbers
//! - Serialization of graphs & variables via optional serde support
//! - Easy conversion to rerun types for straightforward visualization
//!
//! # Background
//!
//! Specifically, we solve the following problem,
//!
//! $$
//! \blue{\Theta^*} = \red{\argmin_{\Theta}}
//! \sum_{i} \green{\rho_i(||r_i(\Theta)||_{\Sigma_i} )}
//! $$
//!
//! The fact.rs API takes heavy inspiration from the [gtsam library](https://gtsam.org/),
//! and is loosely structured as follows,
//! - <blue>Variables</blue>: These are the unknowns in the optimization
//! problem. They are all lie-group based (even if trivially so). See the
//! [variable](crate::variables) module for details on custom implementations.
//! A collection of variables is stored in a
//! [Values](crate::containers::Values) container.
//! - <red>Optimizers</red>: The optimizer is responsible for finding the
//! optimal variables that minimize the factors. More info on factor graph
//! optimizers in [Optimizers](crate::optimizers).
//! - <green>Factors</green>: Each factor represents a probabilistic constraint
//! in the optimization. More info in [Factor](crate::containers::Factor). A
//! collection of factors is stored in a [Graph](crate::containers::Graph)
//! container.
//!
//! # Example
//! ```
//! use factrs::{
//! assign_symbols,
//! core::{BetweenResidual, GaussNewton, Graph, Huber, PriorResidual, Values, SO2},
//! fac,
//! traits::*,
//! };
//!
//! // Assign symbols to variable types
//! assign_symbols!(X: SO2);
//!
//! // Make all the values
//! let mut values = Values::new();
//!
//! let x = SO2::from_theta(1.0);
//! let y = SO2::from_theta(2.0);
//! values.insert(X(0), SO2::identity());
//! values.insert(X(1), SO2::identity());
//!
//! // Make the factors & insert into graph
//! let mut graph = Graph::new();
//! let res = PriorResidual::new(x.clone());
//! let factor = fac![res, X(0)];
//! graph.add_factor(factor);
//!
//! let res = BetweenResidual::new(y.minus(&x));
//! let factor = fac![res, (X(0), X(1)), 0.1 as std, Huber::default()];
//! graph.add_factor(factor);
//!
//! // Optimize!
//! let mut opt: GaussNewton = GaussNewton::new_default(graph);
//! let result = opt.optimize(values).unwrap();
//! println!("Results {:#}", result);
//! ```
/// The default floating point type used in the library
pub type dtype = f64;
pub type dtype = f32;
// Hack to be able to use our proc macro inside and out of our crate
// https://users.rust-lang.org/t/how-to-express-crate-path-in-procedural-macros/91274/10
extern crate self as factrs;
/// Easiest way to create a factor
///
/// Similar to `vec!` in the std library, this is a macro to create a factor
/// from a residual, keys, and alternatively noise and robust kernel. A simple
/// usage would be
/// ```
/// # use factrs::{assign_symbols, fac, core::{SO2, PriorResidual, BetweenResidual}, traits::*};
/// # let prior = PriorResidual::new(SO2::identity());
/// # let between = BetweenResidual::new(SO2::identity());
/// # assign_symbols!(X: SO2);
/// let prior_factor = fac![prior, X(0)];
/// let between_factor = fac![between, (X(0), X(1))];
/// ```
/// Additionally, there is a number of helper options for specifying a noise
/// model,
/// ```
/// # use factrs::{assign_symbols, fac, core::{SO2, PriorResidual, GaussianNoise}, traits::*};
/// # let prior = PriorResidual::new(SO2::identity());
/// # assign_symbols!(X: SO2);
/// let noise = GaussianNoise::from_scalar_sigma(0.1);
/// let f1a = fac![prior, X(0), noise];
/// # let prior = PriorResidual::new(SO2::identity());
/// let f1b = fac![prior, X(0), 0.1 as std];
/// # let prior = PriorResidual::new(SO2::identity());
/// let f2 = fac![prior, X(0), 0.1 as cov];
/// # let prior = PriorResidual::new(SO2::identity());
/// let f3 = fac![prior, X(0), (0.1, 0.3) as std];
/// ```
/// where `f1a` and `f1b` are identical, and where `f3` uses
/// [from_split_sigma](factrs::noise::GaussianNoise::from_split_sigma)
/// to specify the rotation and translation noise separately. (where rotation is
/// ALWAYS first in factrs)
///
/// Finally, a robust kernel can be specified as well,
/// ```
/// # use factrs::{assign_symbols, fac, core::{SO2, PriorResidual, Huber}, traits::*};
/// # let prior = PriorResidual::new(SO2::identity());
/// # assign_symbols!(X: SO2);
/// let f1 = fac![prior, X(0), 0.1 as std, Huber::default()];
/// # let prior = PriorResidual::new(SO2::identity());
/// let f2 = fac![prior, X(0), _, Huber::default()];
/// ```
/// where `f2` uses [UnitNoise](factrs::noise::UnitNoise) as the noise model.
pub use fac;
/// Mark an implementation of [Variable](factrs::traits::Variable),
/// [Residual](factrs::traits::Residual), [Noise](factrs::traits::NoiseModel),
/// or [Robust](factrs::traits::RobustCost).
///
/// This is mostly to aid in serialization when the `serde` feature is enabled.
/// Since these items are boxed inside [Factor](factrs::core::Factor), we use
/// `typetag` for serialization which requires a little bit of manual work.
///
/// For examples of usage, check out the [tests](https://github.com/rpl-cmu/factrs/tree/dev/tests) folder.
///
/// Specifically, it does the following for each trait:
///
/// ### [Variable](factrs::traits::Variable)
/// If serde is disabled, does nothing. Otherwise, it does the following:
/// - Checks there is a single generic for the datatype
/// - Add tag for serialization
/// - Add tag for serializing
/// [PriorResidual\<Type\>](factrs::core::PriorResidual) and
/// [BetweenResidual\<Type\>](factrs::core::BetweenResidual) as well.
///
/// ### [Residual](factrs::traits::Residual)
/// This should be applied on a numbered residual such as
/// [Residual2](factrs::residuals::Residual2) and will automatically derive
/// [Residual](factrs::traits::Residual). Additionally, if serde is
/// enabled, it will add a tag for serialization.
///
/// ### [Noise](factrs::traits::NoiseModel)
/// If serde is disabled, does nothing. Otherwise, it will tag the noise model
/// for serialization, up to size 32.
///
/// ### [Robust](factrs::traits::RobustCost)
/// If serde is disabled, does nothing. Otherwise, it will tag the robust
/// kernel.
pub use mark;
/// Untagged symbols if `unchecked` API is desired.
///
/// We strongly recommend using [assign_symbols] to
/// create and tag symbols with the appropriate types. However, we provide a
/// number of pre-defined symbols if desired. Note these objects can't be tagged
/// due to the orphan rules.
/// Helper module to import common traits
///
/// This module is meant to be glob imported to make it easier to use the traits
/// and functionality in the library.
/// ```
/// use factrs::traits::*;
/// ```
/// Helper module to group together most commonly used types
///
/// Specifically, this contains everything that would be needed to implement a
/// simple pose graph. While we recommend against it, for quick usage it can be
/// glob imported as
/// ```
/// use factrs::core::*;
/// ```
/// Conversion from fact.rs types to rerun types
///
/// Most the fact.rs types can be converted into rerun types for visualization
/// purposes. The following conversions are supported,
/// - VectorVar2 -> Vec2D, Points2D
/// - VectorVar3 -> Vec3D, Points3D
/// - SO2 -> Arrows2D
/// - SE2 -> Arrows2D, Points2D
/// - SO3 -> Rotation3D, Arrows3D
/// - SE3 -> Transform3D, Arrows3D, Points3D
///
/// Furthermore, we can also convert iterators of these types into the
/// corresponding rerun types. This is useful for visualizing multiple objects
/// at once.
/// - Iterator of VectorVar2 -> Points2D
/// - Iterator of VectorVar3 -> Points3D
/// - Iterator of SE2 -> Arrows2D, Points2D
/// - Iterator of SE3 -> Arrows3D, Points3D
/// Macros to help with serde serialization
///
/// In case you are using a [marked](crate::mark) custom implementation along
/// with serialization, you'll have to manually "tag" each type for
/// serialization. This module provides a number of helper functions to do so.