Skip to content

Commit be25f60

Browse files
authored
Merge pull request #26 from rpl-cmu/split-gaussian
Added split gaussian option to fac!
2 parents eeac240 + 300a2e7 commit be25f60

File tree

7 files changed

+97
-53
lines changed

7 files changed

+97
-53
lines changed

README.md

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ Additionally, we recommend checking out the [tests](/tests/) folder for more exa
4242

4343
```rust
4444
use factrs::{
45-
core::{
46-
assign_symbols, fac, BetweenResidual, GaussNewton, Graph, Huber, PriorResidual, Values, SO2,
47-
},
45+
assign_symbols,
46+
core::{BetweenResidual, GaussNewton, Graph, Huber, PriorResidual, Values, SO2},
47+
fac,
4848
traits::*,
4949
};
5050

@@ -67,13 +67,12 @@ fn main() {
6767
graph.add_factor(factor);
6868

6969
let res = BetweenResidual::new(y.minus(&x));
70-
let robust = Huber::default();
71-
let factor = fac![res, (X(0), X(1)), 0.1 as std, robust];
70+
let factor = fac![res, (X(0), X(1)), 0.1 as std, Huber::default()];
7271
// fac! is syntactic sugar for the following
7372
// let noise = GaussianNoise::from_scalar_sigma(0.1);
7473
// let factor = FactorBuilder::new2(res, X(0), X(1))
75-
// .noise(noise)
76-
// .robust(robust)
74+
// .noise(GaussianNoise::from_scalar_sigma(0.1))
75+
// .robust(Huber::default())
7776
// .build();
7877
graph.add_factor(factor);
7978

examples/gps.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ A simple 2D pose slam example with "GPS" measurements
1515
use factrs::variables::{VectorVar2, SE2};
1616
use factrs::{
1717
assign_symbols,
18-
core::{BetweenResidual, GaussNewton, GaussianNoise, Graph, Values},
18+
core::{BetweenResidual, GaussNewton, Graph, Values},
1919
dtype, fac,
2020
linalg::{Const, ForwardProp, Numeric, NumericalDiff, VectorX},
2121
residuals::Residual1,
@@ -87,10 +87,9 @@ fn main() {
8787
let mut graph = Graph::new();
8888

8989
// Add odometry factors
90-
let noise = GaussianNoise::<3>::from_diag_covs(0.1, 0.2, 0.2);
9190
let res = BetweenResidual::new(SE2::new(0.0, 2.0, 0.0));
92-
let odometry_01 = fac![res.clone(), (X(0), X(1)), noise.clone()];
93-
let odometry_12 = fac![res, (X(1), X(2)), noise];
91+
let odometry_01 = fac![res.clone(), (X(0), X(1)), (0.1, 0.2) as cov];
92+
let odometry_12 = fac![res, (X(1), X(2)), (0.1, 0.2) as cov];
9493
graph.add_factor(odometry_01);
9594
graph.add_factor(odometry_12);
9695

examples/readme.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use factrs::{
2-
core::{
3-
assign_symbols, fac, BetweenResidual, GaussNewton, Graph, Huber, PriorResidual, Values, SO2,
4-
},
2+
assign_symbols,
3+
core::{BetweenResidual, GaussNewton, Graph, Huber, PriorResidual, Values, SO2},
4+
fac,
55
traits::*,
66
};
77

@@ -24,13 +24,12 @@ fn main() {
2424
graph.add_factor(factor);
2525

2626
let res = BetweenResidual::new(y.minus(&x));
27-
let robust = Huber::default();
28-
let factor = fac![res, (X(0), X(1)), 0.1 as std, robust];
27+
let factor = fac![res, (X(0), X(1)), 0.1 as std, Huber::default()];
2928
// fac! is syntactic sugar for the following
3029
// let noise = GaussianNoise::from_scalar_sigma(0.1);
3130
// let factor = FactorBuilder::new2(res, X(0), X(1))
32-
// .noise(noise)
33-
// .robust(robust)
31+
// .noise(GaussianNoise::from_scalar_sigma(0.1))
32+
// .robust(Huber::default())
3433
// .build();
3534
graph.add_factor(factor);
3635

factrs-proc/src/fac.rs

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
use proc_macro2::Span;
2-
use proc_macro2::TokenStream as TokenStream2;
3-
use quote::quote;
4-
use quote::ToTokens;
5-
use syn::parse_quote;
6-
use syn::ExprCast;
7-
use syn::{parse::Parse, punctuated::Punctuated, Expr, Ident, Token};
1+
use proc_macro2::{Span, TokenStream as TokenStream2};
2+
use quote::{format_ident, quote, ToTokens};
3+
use syn::{
4+
parse::Parse, parse_quote, punctuated::Punctuated, spanned::Spanned, Expr, ExprCast, Ident,
5+
Token,
6+
};
87

98
pub struct Factor {
109
residual: Expr,
@@ -81,10 +80,30 @@ impl Parse for Factor {
8180
let m = quote!(factrs::noise);
8281
match &input[2] {
8382
Expr::Cast(ExprCast { expr, ty, .. }) => {
84-
match ty.to_token_stream().to_string().as_str() {
85-
"std" => Some(parse_quote!(#m::GaussianNoise::from_scalar_sigma(#expr))),
86-
"cov" => Some(parse_quote!(#m::GaussianNoise::from_scalar_cov(#expr))),
83+
// Make sure it's a cov or std cast
84+
let ty = match ty.to_token_stream().to_string().as_str() {
85+
"cov" => Ident::new("cov", ty.span()),
86+
"std" | "sigma" | "sig" => Ident::new("sigma", ty.span()),
8787
_ => return Err(syn::Error::new_spanned(ty, "Unknown cast for noise")),
88+
};
89+
90+
// Check if it's a tuple or a single variable
91+
match expr.as_ref() {
92+
Expr::Tuple(t) => {
93+
if t.elems.len() != 2 {
94+
return Err(syn::Error::new_spanned(
95+
t,
96+
"Expected tuple with two elements for split std/cov",
97+
));
98+
}
99+
let (a, b) = (&t.elems[0], &t.elems[1]);
100+
let func = format_ident!("from_split_{}", ty);
101+
Some(parse_quote!(#m::GaussianNoise::#func(#a, #b)))
102+
}
103+
_ => {
104+
let func = format_ident!("from_scalar_{}", ty);
105+
Some(parse_quote!(#m::GaussianNoise::#func(#expr)))
106+
}
88107
}
89108
}
90109
Expr::Infer(_) => Some(parse_quote!(#m::UnitNoise)),

src/containers/factor.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ impl<const DIM_OUT: usize> FactorBuilder<DIM_OUT> {
274274
#[cfg(test)]
275275
mod tests {
276276

277+
use factrs_proc::fac;
277278
use matrixcompare::assert_matrix_eq;
278279

279280
use super::*;
@@ -307,10 +308,7 @@ mod tests {
307308
let noise = GaussianNoise::<3>::from_diag_sigmas(1e-1, 2e-1, 3e-1);
308309
let robust = GemanMcClure::default();
309310

310-
let factor = FactorBuilder::new1(residual, X(0))
311-
.noise(noise)
312-
.robust(robust)
313-
.build();
311+
let factor: Factor = fac![residual, X(0), noise, robust];
314312

315313
let f = |x: VectorVar3| {
316314
let mut values = Values::new();
@@ -340,10 +338,7 @@ mod tests {
340338
let noise = GaussianNoise::<3>::from_diag_sigmas(1e-1, 2e-1, 3e-1);
341339
let robust = GemanMcClure::default();
342340

343-
let factor = FactorBuilder::new2(residual, X(0), X(1))
344-
.noise(noise)
345-
.robust(robust)
346-
.build();
341+
let factor: Factor = fac![residual, (X(0), X(1)), noise, robust];
347342

348343
let mut values = Values::new();
349344
values.insert_unchecked(X(0), x.clone());

src/lib.rs

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,10 @@
3737
//! # Example
3838
//! ```
3939
//! use factrs::{
40-
//! assign_symbols,
41-
//! containers::{FactorBuilder, Graph, Values},
42-
//! noise::GaussianNoise,
43-
//! optimizers::GaussNewton,
44-
//! residuals::{BetweenResidual, PriorResidual},
45-
//! robust::Huber,
46-
//! traits::*,
47-
//! variables::SO2,
40+
//! assign_symbols,
41+
//! core::{BetweenResidual, GaussNewton, Graph, Huber, PriorResidual, Values, SO2},
42+
//! fac,
43+
//! traits::*,
4844
//! };
4945
//!
5046
//! // Assign symbols to variable types
@@ -60,23 +56,24 @@
6056
//!
6157
//! // Make the factors & insert into graph
6258
//! let mut graph = Graph::new();
63-
//!
6459
//! let res = PriorResidual::new(x.clone());
65-
//! let factor = FactorBuilder::new1(res, X(0)).build();
60+
//! let factor = fac![res, X(0)];
6661
//! graph.add_factor(factor);
6762
//!
6863
//! let res = BetweenResidual::new(y.minus(&x));
69-
//! let noise = GaussianNoise::from_scalar_sigma(0.1);
70-
//! let robust = Huber::default();
71-
//! let factor = FactorBuilder::new2(res, X(0), X(1))
72-
//! .noise(noise)
73-
//! .robust(robust)
74-
//! .build();
64+
//! let factor = fac![res, (X(0), X(1)), 0.1 as std, Huber::default()];
65+
//! // fac! is syntactic sugar for the following
66+
//! // let noise = GaussianNoise::from_scalar_sigma(0.1);
67+
//! // let factor = FactorBuilder::new2(res, X(0), X(1))
68+
//! // .noise(GaussianNoise::from_scalar_sigma(0.1))
69+
//! // .robust(Huber::default())
70+
//! // .build();
7571
//! graph.add_factor(factor);
7672
//!
7773
//! // Optimize!
7874
//! let mut opt: GaussNewton = GaussNewton::new(graph);
79-
//! let result = opt.optimize(values);
75+
//! let result = opt.optimize(values).unwrap();
76+
//! println!("Results {:#}", result);
8077
//! ```
8178
8279
#![warn(clippy::unwrap_used)]

src/noise/gaussian.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,42 @@ impl<const N: usize> GaussianNoise<N> {
5151
Self { sqrt_inf }
5252
}
5353

54+
/// Create from split scalar sigmas.
55+
///
56+
/// Will apply the first scalar to the first N/2 elements and the second
57+
/// scalar to the last N/2 elements. In the case of an odd N, the first N/2
58+
/// elements will have one less element than the last N/2 elements.
59+
pub fn from_split_sigma(sigma1: dtype, sigma2: dtype) -> Self {
60+
let mut sqrt_inf = Matrix::<N, N>::zeros();
61+
let inf1 = 1.0 / sigma1;
62+
let inf2 = 1.0 / sigma2;
63+
for i in 0..N / 2 {
64+
sqrt_inf[(i, i)] = inf1;
65+
}
66+
for i in N / 2..N {
67+
sqrt_inf[(i, i)] = inf2;
68+
}
69+
Self { sqrt_inf }
70+
}
71+
72+
/// Create from split scalar covariances.
73+
///
74+
/// Will apply the first scalar to the first N/2 elements and the second
75+
/// scalar to the last N/2 elements. In the case of an odd N, the first N/2
76+
/// elements will have one less element than the last N/2 elements.
77+
pub fn from_split_cov(cov1: dtype, cov2: dtype) -> Self {
78+
let mut sqrt_inf = Matrix::<N, N>::zeros();
79+
let inf1 = 1.0 / cov1.sqrt();
80+
let inf2 = 1.0 / cov2.sqrt();
81+
for i in 0..N / 2 {
82+
sqrt_inf[(i, i)] = inf1;
83+
}
84+
for i in N / 2..N {
85+
sqrt_inf[(i, i)] = inf2;
86+
}
87+
Self { sqrt_inf }
88+
}
89+
5490
/// Create a diagonal Gaussian noise from a vector of sigmas.
5591
pub fn from_vec_sigma(sigma: VectorView<N>) -> Self {
5692
let sqrt_inf = Matrix::<N, N>::from_diagonal(&sigma.map(|x| 1.0 / x));

0 commit comments

Comments
 (0)