pub trait ParamType: Copy + Default + 'static {
const SIZE: usize;
const SUFFIXES: &'static [&'static str];
fn write_to32(&self, dst: &mut [f32]);
fn read_from32(src: &[f32]) -> Self;
fn write_to64(&self, dst: &mut [f64]);
fn read_from64(src: &[f64]) -> Self;
}
impl ParamType for f32 {
const SIZE: usize = 1;
const SUFFIXES: &'static [&'static str] = &[""];
fn write_to32(&self, dst: &mut [f32]) { dst[0] = *self; }
fn read_from32(src: &[f32]) -> Self { src[0] }
fn write_to64(&self, dst: &mut [f64]) { dst[0] = *self as f64; }
fn read_from64(src: &[f64]) -> Self { src[0] as f32 }
}
impl ParamType for f64 {
const SIZE: usize = 1;
const SUFFIXES: &'static [&'static str] = &[""];
fn write_to32(&self, dst: &mut [f32]) { dst[0] = *self as f32; }
fn read_from32(src: &[f32]) -> Self { src[0] as f64 }
fn write_to64(&self, dst: &mut [f64]) { dst[0] = *self; }
fn read_from64(src: &[f64]) -> Self { src[0] }
}
impl ParamType for crate::vect::vect2<f64> {
const SIZE: usize = 2;
const SUFFIXES: &'static [&'static str] = &[".x", ".y"];
fn write_to32(&self, dst: &mut [f32]) { dst[0] = self.x as f32; dst[1] = self.y as f32; }
fn read_from32(src: &[f32]) -> Self { Self::new(src[0] as f64, src[1] as f64) }
fn write_to64(&self, dst: &mut [f64]) { dst[0] = self.x; dst[1] = self.y; }
fn read_from64(src: &[f64]) -> Self { Self::new(src[0], src[1]) }
}
impl ParamType for crate::vect::vect2<f32> {
const SIZE: usize = 2;
const SUFFIXES: &'static [&'static str] = &[".x", ".y"];
fn write_to32(&self, dst: &mut [f32]) { dst[0] = self.x; dst[1] = self.y; }
fn read_from32(src: &[f32]) -> Self { Self::new(src[0], src[1]) }
fn write_to64(&self, dst: &mut [f64]) { dst[0] = self.x as f64; dst[1] = self.y as f64; }
fn read_from64(src: &[f64]) -> Self { Self::new(src[0] as f32, src[1] as f32) }
}
impl ParamType for crate::vect::vect3<f32> {
const SIZE: usize = 3;
const SUFFIXES: &'static [&'static str] = &[".x", ".y", ".z"];
fn write_to32(&self, dst: &mut [f32]) { dst[0] = self.x; dst[1] = self.y; dst[2] = self.z; }
fn read_from32(src: &[f32]) -> Self { Self::new(src[0], src[1], src[2]) }
fn write_to64(&self, dst: &mut [f64]) { dst[0] = self.x as f64; dst[1] = self.y as f64; dst[2] = self.z as f64; }
fn read_from64(src: &[f64]) -> Self { Self::new(src[0] as f32, src[1] as f32, src[2] as f32) }
}
#[derive(serde::Serialize, serde::Deserialize)]
pub struct Param<T: ParamType> {
pub optimize: bool,
pub value: T,
#[serde(skip)]
work: T,
#[serde(skip)]
index: u32,
}
impl<T: ParamType> Param<T> {
pub fn new(value: T) -> Self {
Param { optimize: true, value, work: T::default(), index: u32::MAX }
}
pub fn fixed(value: T) -> Self {
Param { optimize: false, value, work: T::default(), index: u32::MAX }
}
pub fn work(&self) -> T { self.work }
pub fn work_ref(&self) -> &T { &self.work }
pub fn work_mut(&mut self) -> &mut T { &mut self.work }
pub fn index(&self) -> u32 { self.index }
pub fn write_indices(&self, out: &mut [u32]) {
if self.index == u32::MAX {
for o in out.iter_mut() { *o = u32::MAX; }
} else {
for (k, o) in out.iter_mut().enumerate() {
*o = self.index + k as u32;
}
}
}
}
impl<T: ParamType + std::fmt::Debug> std::fmt::Debug for Param<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
if self.optimize {
write!(f, "Param({:?}, idx={})", self.value, self.index)
} else {
write!(f, "Param({:?}, fixed)", self.value)
}
}
}
pub trait Model {
fn serialize_params32(&mut self, data: &mut std::vec::Vec<f32>);
fn deserialize_params32(&mut self, data: &[f32]);
fn update32(&mut self,data: &[f32]);
fn update_self(&mut self);
fn serialize_params64(&mut self, data: &mut std::vec::Vec<f64>);
fn deserialize_params64(&mut self, data: &[f64]);
fn update64(&mut self, data: &[f64]);
const PARAM_COUNT: u32 = 0;
fn serialize_size(&self) -> u32 { 0 }
fn param_symbols(_base: &str, _out: &mut std::vec::Vec<String>) {}
fn zero_blocks(&mut self) {}
fn accumulate_hessian32(&self, _hessian: &mut [f32]) {}
fn accumulate_hessian64(&self, _hessian: &mut [f64]) {}
fn accumulate_hessian_band32(&self, _band: &mut [f32], _kd: usize) -> Result<(), crate::simple_lm::BandError> { Ok(()) }
fn accumulate_hessian_band64(&self, _band: &mut [f64], _kd: usize) -> Result<(), crate::simple_lm::BandError> { Ok(()) }
fn accumulate_hessian_sparse32(&self, _coo: &mut crate::simple_lm::CooMatrix<f32>) {}
fn accumulate_hessian_sparse64(&self, _coo: &mut crate::simple_lm::CooMatrix<f64>) {}
fn accumulate_hessian_sparse_direct32(&self, _csc: &mut crate::simple_lm::CscMatrix<f32>) {}
fn accumulate_hessian_sparse_direct64(&self, _csc: &mut crate::simple_lm::CscMatrix<f64>) {}
fn accumulate_hessian_sparse_indexed32(&self, _vals: &mut [f32], _positions: &[usize], _cursor: &mut usize) {}
fn accumulate_hessian_sparse_indexed64(&self, _vals: &mut [f64], _positions: &[usize], _cursor: &mut usize) {}
}
pub trait ExtendedModel {
fn extended_deserialize64(&mut self) {}
fn extended_deserialize32(&mut self) {}
fn extended_update64(&mut self, _params: &[f64]) {}
fn extended_update32(&mut self, _params: &[f32]) {}
fn extended_cost64(&self, _params: &[f64]) -> f64 { 0.0 }
fn extended_cost32(&self, _params: &[f32]) -> f32 { 0.0 }
fn extended_compute64(&mut self, _params: &[f64], _grad: &mut [f64]) {}
fn extended_compute32(&mut self, _params: &[f32], _grad: &mut [f32]) {}
fn extended_jacobian64(&mut self, _params: &[f64], _rows: &mut std::vec::Vec<JacobianRow<f64>>, _cid: &mut u32) {}
fn extended_jacobian32(&mut self, _params: &[f32], _rows: &mut std::vec::Vec<JacobianRow<f32>>, _cid: &mut u32) {}
}
impl<T: ParamType> Model for Param<T> {
fn serialize_params32(&mut self, data: &mut std::vec::Vec<f32>) {
if self.optimize {
self.index = data.len() as u32;
let start = data.len();
data.resize(start + T::SIZE, 0.0);
self.value.write_to32(&mut data[start..start + T::SIZE]);
} else {
self.index = u32::MAX;
}
}
fn deserialize_params32(&mut self, data: &[f32]) {
if self.index != u32::MAX {
let i = self.index as usize;
self.value = T::read_from32(&data[i..i + T::SIZE]);
}
}
fn update32(&mut self,data: &[f32]) {
if self.index != u32::MAX {
let i = self.index as usize;
self.work = T::read_from32(&data[i..i + T::SIZE]);
} else {
self.work = self.value;
}
}
fn update_self(&mut self) {
self.work = self.value;
}
fn serialize_params64(&mut self, data: &mut std::vec::Vec<f64>) {
if self.optimize {
self.index = data.len() as u32;
let start = data.len();
data.resize(start + T::SIZE, 0.0);
self.value.write_to64(&mut data[start..start + T::SIZE]);
} else {
self.index = u32::MAX;
}
}
fn deserialize_params64(&mut self, data: &[f64]) {
if self.index != u32::MAX {
let i = self.index as usize;
self.value = T::read_from64(&data[i..i + T::SIZE]);
}
}
fn update64(&mut self, data: &[f64]) {
if self.index != u32::MAX {
let i = self.index as usize;
self.work = T::read_from64(&data[i..i + T::SIZE]);
} else {
self.work = self.value;
}
}
const PARAM_COUNT: u32 = T::SIZE as u32;
fn serialize_size(&self) -> u32 { if self.optimize { T::SIZE as u32 } else { 0 } }
fn param_symbols(base: &str, out: &mut std::vec::Vec<String>) {
for suffix in T::SUFFIXES {
out.push(format!("{}{}", base, suffix));
}
}
}
use crate::vect::vect3;
use crate::matrix::matrix3;
#[derive(Clone, Copy)]
pub struct SimpleEulerAngleParam<T: crate::utils::Float> {
pub optimize: bool,
pub value: vect3<T>,
work: vect3<T>,
index: u32,
#[doc(hidden)] pub sincos: (vect3<T>, vect3<T>),
#[doc(hidden)] pub rotation_matrix: matrix3<T>,
}
impl<T: crate::utils::Float> Default for SimpleEulerAngleParam<T> {
fn default() -> Self {
Self {
optimize: true,
value: vect3::<T>::default(),
work: vect3::<T>::default(),
index: u32::MAX,
sincos: (vect3::<T>::default(), vect3::<T>::default()),
rotation_matrix: matrix3::<T>::identity(),
}
}
}
impl<T: crate::utils::Float> SimpleEulerAngleParam<T> {
pub fn new(value: vect3<T>) -> Self {
Self { optimize: true, value, work: vect3::<T>::default(), index: u32::MAX,
sincos: (vect3::<T>::default(), vect3::<T>::default()),
rotation_matrix: matrix3::<T>::identity() }
}
pub fn fixed(value: vect3<T>) -> Self {
Self { optimize: false, value, work: vect3::<T>::default(), index: u32::MAX,
sincos: (vect3::<T>::default(), vect3::<T>::default()),
rotation_matrix: matrix3::<T>::identity() }
}
pub fn work(&self) -> vect3<T> { self.work }
pub fn index(&self) -> u32 { self.index }
pub fn write_indices(&self, out: &mut [u32]) {
if self.index == u32::MAX {
for o in out.iter_mut() { *o = u32::MAX; }
} else {
for (k, o) in out.iter_mut().enumerate() { *o = self.index + k as u32; }
}
}
#[doc(hidden)]
pub fn __precompute(&mut self) {
self.sincos = self.work.sincos();
self.rotation_matrix = matrix3::<T>::rotation_from_euler_angles_sincos(
self.sincos.0, self.sincos.1);
}
}
impl<T: crate::utils::Float> serde::Serialize for SimpleEulerAngleParam<T> where T: serde::Serialize {
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeStruct;
let mut st = s.serialize_struct("SimpleEulerAngleParam", 2)?;
st.serialize_field("optimize", &self.optimize)?;
st.serialize_field("value", &self.value)?;
st.end()
}
}
impl<'de, T: crate::utils::Float + serde::Deserialize<'de>> serde::Deserialize<'de> for SimpleEulerAngleParam<T> {
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
use serde::de::{self, MapAccess, Visitor};
struct V<U>(std::marker::PhantomData<U>);
impl<'de2, U: crate::utils::Float + serde::Deserialize<'de2>> Visitor<'de2> for V<U> {
type Value = SimpleEulerAngleParam<U>;
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.write_str("SimpleEulerAngleParam")
}
fn visit_map<A: MapAccess<'de2>>(self, mut map: A) -> Result<Self::Value, A::Error> {
let mut opt = None; let mut val = None;
while let Some(key) = map.next_key::<String>()? {
match key.as_str() {
"optimize" => opt = Some(map.next_value()?),
"value" => val = Some(map.next_value()?),
_ => { let _ = map.next_value::<de::IgnoredAny>()?; }
}
}
Ok(SimpleEulerAngleParam {
optimize: opt.unwrap_or(true),
value: val.unwrap_or_default(),
..Default::default()
})
}
}
d.deserialize_map(V::<T>(std::marker::PhantomData))
}
}
impl<T: crate::utils::Float> Model for SimpleEulerAngleParam<T> where vect3<T>: ParamType {
fn serialize_params32(&mut self, data: &mut std::vec::Vec<f32>) {
if self.optimize {
self.index = data.len() as u32;
let start = data.len();
data.resize(start + 3, 0.0);
self.value.write_to32(&mut data[start..start + 3]);
} else { self.index = u32::MAX; }
}
fn deserialize_params32(&mut self, data: &[f32]) {
if self.index != u32::MAX {
let i = self.index as usize;
self.value = <vect3<T> as ParamType>::read_from32(&data[i..i + 3]);
}
}
fn update32(&mut self, data: &[f32]) {
if self.index != u32::MAX {
let i = self.index as usize;
self.work = <vect3<T> as ParamType>::read_from32(&data[i..i + 3]);
} else { self.work = self.value; }
}
fn update_self(&mut self) {
self.work = self.value;
self.__precompute();
}
fn serialize_params64(&mut self, data: &mut std::vec::Vec<f64>) {
if self.optimize {
self.index = data.len() as u32;
let start = data.len();
data.resize(start + 3, 0.0);
self.value.write_to64(&mut data[start..start + 3]);
} else { self.index = u32::MAX; }
}
fn deserialize_params64(&mut self, data: &[f64]) {
if self.index != u32::MAX {
let i = self.index as usize;
self.value = <vect3<T> as ParamType>::read_from64(&data[i..i + 3]);
}
}
fn update64(&mut self, data: &[f64]) {
if self.index != u32::MAX {
let i = self.index as usize;
self.work = <vect3<T> as ParamType>::read_from64(&data[i..i + 3]);
} else { self.work = self.value; }
}
const PARAM_COUNT: u32 = 3;
fn serialize_size(&self) -> u32 { if self.optimize { 3 } else { 0 } }
fn param_symbols(base: &str, out: &mut std::vec::Vec<String>) {
for suffix in <vect3<T> as ParamType>::SUFFIXES {
out.push(format!("{}{}", base, suffix));
}
}
}
#[derive(Clone, Copy)]
pub struct EulerAngleParam<T: crate::utils::Float> {
pub optimize: bool,
pub value: vect3<T>,
work: vect3<T>,
index: u32,
#[doc(hidden)] pub ref_rotation: matrix3<T>,
#[doc(hidden)] pub delta: vect3<T>,
#[doc(hidden)] pub sincos: (vect3<T>, vect3<T>),
#[doc(hidden)] pub rotation_matrix: matrix3<T>,
#[doc(hidden)] pub delta_sincos: (vect3<T>, vect3<T>),
}
impl<T: crate::utils::Float> Default for EulerAngleParam<T> {
fn default() -> Self {
Self {
optimize: true,
value: vect3::<T>::default(),
work: vect3::<T>::default(),
index: u32::MAX,
ref_rotation: matrix3::<T>::identity(),
delta: vect3::<T>::default(),
sincos: (vect3::<T>::default(), vect3::<T>::default()),
rotation_matrix: matrix3::<T>::identity(),
delta_sincos: (vect3::<T>::default(), vect3::<T>::default()),
}
}
}
impl<T: crate::utils::Float> EulerAngleParam<T> {
pub fn new(value: vect3<T>) -> Self {
Self { value, ..Default::default() }
}
pub fn fixed(value: vect3<T>) -> Self {
Self { optimize: false, value, ..Default::default() }
}
pub fn work(&self) -> vect3<T> { self.work }
pub fn index(&self) -> u32 { self.index }
pub fn write_indices(&self, out: &mut [u32]) {
if self.index == u32::MAX {
for o in out.iter_mut() { *o = u32::MAX; }
} else {
for (k, o) in out.iter_mut().enumerate() { *o = self.index + k as u32; }
}
}
pub fn advance(&mut self) {
self.ref_rotation = self.ref_rotation
* matrix3::<T>::rotation_from_euler_angles(self.delta);
self.delta = vect3::<T>::default();
}
#[doc(hidden)]
pub fn __precompute(&mut self) {
self.delta_sincos = self.delta.sincos();
let dea_rot = matrix3::<T>::rotation_from_euler_angles_sincos(
self.delta_sincos.0, self.delta_sincos.1);
self.rotation_matrix = self.ref_rotation * dea_rot;
self.work = self.rotation_matrix.get_euler_angles();
self.sincos = self.work.sincos();
}
}
impl<T: crate::utils::Float> serde::Serialize for EulerAngleParam<T> where T: serde::Serialize {
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeStruct;
let mut st = s.serialize_struct("EulerAngleParam", 2)?;
st.serialize_field("optimize", &self.optimize)?;
st.serialize_field("value", &self.value)?;
st.end()
}
}
impl<'de, T: crate::utils::Float + serde::Deserialize<'de>> serde::Deserialize<'de> for EulerAngleParam<T> {
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
use serde::de::{self, MapAccess, Visitor};
struct V<U>(std::marker::PhantomData<U>);
impl<'de2, U: crate::utils::Float + serde::Deserialize<'de2>> Visitor<'de2> for V<U> {
type Value = EulerAngleParam<U>;
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.write_str("EulerAngleParam")
}
fn visit_map<A: MapAccess<'de2>>(self, mut map: A) -> Result<Self::Value, A::Error> {
let mut opt = None; let mut val = None;
while let Some(key) = map.next_key::<String>()? {
match key.as_str() {
"optimize" => opt = Some(map.next_value()?),
"value" => val = Some(map.next_value()?),
_ => { let _ = map.next_value::<de::IgnoredAny>()?; }
}
}
Ok(EulerAngleParam {
optimize: opt.unwrap_or(true),
value: val.unwrap_or_default(),
..Default::default()
})
}
}
d.deserialize_map(V::<T>(std::marker::PhantomData))
}
}
impl<T: crate::utils::Float> Model for EulerAngleParam<T> where vect3<T>: ParamType {
fn serialize_params32(&mut self, data: &mut std::vec::Vec<f32>) {
if self.optimize {
self.ref_rotation = matrix3::<T>::rotation_from_euler_angles(self.value);
self.index = data.len() as u32;
data.push(0.0); data.push(0.0); data.push(0.0);
} else { self.index = u32::MAX; }
}
fn deserialize_params32(&mut self, data: &[f32]) {
if self.index != u32::MAX {
let i = self.index as usize;
let dea = <vect3<T> as ParamType>::read_from32(&data[i..i + 3]);
self.ref_rotation = self.ref_rotation
* matrix3::<T>::rotation_from_euler_angles(dea);
self.value = self.ref_rotation.get_euler_angles();
self.delta = vect3::<T>::default();
}
}
fn update32(&mut self, data: &[f32]) {
if self.index != u32::MAX {
let i = self.index as usize;
self.delta = <vect3<T> as ParamType>::read_from32(&data[i..i + 3]);
} else { self.delta = vect3::<T>::default(); }
}
fn update_self(&mut self) {
self.delta = vect3::<T>::default();
self.__precompute();
}
fn serialize_params64(&mut self, data: &mut std::vec::Vec<f64>) {
if self.optimize {
self.ref_rotation = matrix3::<T>::rotation_from_euler_angles(self.value);
self.index = data.len() as u32;
data.push(0.0); data.push(0.0); data.push(0.0);
} else { self.index = u32::MAX; }
}
fn deserialize_params64(&mut self, data: &[f64]) {
if self.index != u32::MAX {
let i = self.index as usize;
let dea = <vect3<T> as ParamType>::read_from64(&data[i..i + 3]);
self.ref_rotation = self.ref_rotation
* matrix3::<T>::rotation_from_euler_angles(dea);
self.value = self.ref_rotation.get_euler_angles();
self.delta = vect3::<T>::default();
}
}
fn update64(&mut self, data: &[f64]) {
if self.index != u32::MAX {
let i = self.index as usize;
self.delta = <vect3<T> as ParamType>::read_from64(&data[i..i + 3]);
} else { self.delta = vect3::<T>::default(); }
}
const PARAM_COUNT: u32 = 3;
fn serialize_size(&self) -> u32 { if self.optimize { 3 } else { 0 } }
fn param_symbols(base: &str, out: &mut std::vec::Vec<String>) {
for suffix in <vect3<T> as ParamType>::SUFFIXES {
out.push(format!("{}{}", base, suffix));
}
}
}
macro_rules! impl_model_noop {
($($ty:ty),* $(,)?) => {
$(
impl Model for $ty {
fn serialize_params32(&mut self, _data: &mut std::vec::Vec<f32>) {}
fn deserialize_params32(&mut self, _data: &[f32]) {}
fn update32(&mut self,_data: &[f32]) {}
fn update_self(&mut self) {}
fn serialize_params64(&mut self, _data: &mut std::vec::Vec<f64>) {}
fn deserialize_params64(&mut self, _data: &[f64]) {}
fn update64(&mut self, _data: &[f64]) {}
}
)*
};
}
impl_model_noop!(f32, f64, u32, i32, bool, usize, String);
macro_rules! impl_model_noop_generic {
($($ty:ty),* $(,)?) => {
$(
impl Model for $ty {
fn serialize_params32(&mut self, _data: &mut std::vec::Vec<f32>) {}
fn deserialize_params32(&mut self, _data: &[f32]) {}
fn update32(&mut self,_data: &[f32]) {}
fn update_self(&mut self) {}
fn serialize_params64(&mut self, _data: &mut std::vec::Vec<f64>) {}
fn deserialize_params64(&mut self, _data: &[f64]) {}
fn update64(&mut self, _data: &[f64]) {}
}
)*
};
}
impl_model_noop_generic!(
crate::vect::vect3f, crate::vect::vect3d,
crate::vect::vect2f, crate::vect::vect2d,
crate::matrix::matrix3f, crate::matrix::matrix3d,
crate::matrix::matrix2f, crate::matrix::matrix2d,
crate::quatern::quaternf, crate::quatern::quaternd,
);
impl<T> Model for crate::refs::Ref<T> {
fn serialize_params32(&mut self, _data: &mut std::vec::Vec<f32>) {}
fn deserialize_params32(&mut self, _data: &[f32]) {}
fn update32(&mut self,_data: &[f32]) {}
fn update_self(&mut self) {}
fn serialize_params64(&mut self, _data: &mut std::vec::Vec<f64>) {}
fn deserialize_params64(&mut self, _data: &[f64]) {}
fn update64(&mut self, _data: &[f64]) {}
}
macro_rules! impl_model_collection {
($ty:ty, $iter_mut:ident) => {
impl<T: Model> Model for $ty {
fn serialize_params32(&mut self, data: &mut std::vec::Vec<f32>) {
for item in self.$iter_mut() { item.serialize_params32(data); }
}
fn deserialize_params32(&mut self, data: &[f32]) {
for item in self.$iter_mut() { item.deserialize_params32(data); }
}
fn update32(&mut self,data: &[f32]) {
for item in self.$iter_mut() { item.update32(data); }
}
fn update_self(&mut self) {
for item in self.$iter_mut() { item.update_self(); }
}
fn serialize_params64(&mut self, data: &mut std::vec::Vec<f64>) {
for item in self.$iter_mut() { item.serialize_params64(data); }
}
fn deserialize_params64(&mut self, data: &[f64]) {
for item in self.$iter_mut() { item.deserialize_params64(data); }
}
fn update64(&mut self, data: &[f64]) {
for item in self.$iter_mut() { item.update64(data); }
}
fn zero_blocks(&mut self) {
for item in self.$iter_mut() { item.zero_blocks(); }
}
fn serialize_size(&self) -> u32 {
self.iter().map(|item| item.serialize_size()).sum()
}
fn accumulate_hessian32(&self, hessian: &mut [f32]) {
for item in self.iter() { item.accumulate_hessian32(hessian); }
}
fn accumulate_hessian64(&self, hessian: &mut [f64]) {
for item in self.iter() { item.accumulate_hessian64(hessian); }
}
fn accumulate_hessian_band32(&self, band: &mut [f32], kd: usize) -> Result<(), crate::simple_lm::BandError> {
for item in self.iter() { item.accumulate_hessian_band32(band, kd)?; }
Ok(())
}
fn accumulate_hessian_band64(&self, band: &mut [f64], kd: usize) -> Result<(), crate::simple_lm::BandError> {
for item in self.iter() { item.accumulate_hessian_band64(band, kd)?; }
Ok(())
}
fn accumulate_hessian_sparse32(&self, coo: &mut crate::simple_lm::CooMatrix<f32>) {
for item in self.iter() { item.accumulate_hessian_sparse32(coo); }
}
fn accumulate_hessian_sparse64(&self, coo: &mut crate::simple_lm::CooMatrix<f64>) {
for item in self.iter() { item.accumulate_hessian_sparse64(coo); }
}
fn accumulate_hessian_sparse_direct32(&self, csc: &mut crate::simple_lm::CscMatrix<f32>) {
for item in self.iter() { item.accumulate_hessian_sparse_direct32(csc); }
}
fn accumulate_hessian_sparse_direct64(&self, csc: &mut crate::simple_lm::CscMatrix<f64>) {
for item in self.iter() { item.accumulate_hessian_sparse_direct64(csc); }
}
fn accumulate_hessian_sparse_indexed32(&self, vals: &mut [f32], positions: &[usize], cursor: &mut usize) {
for item in self.iter() { item.accumulate_hessian_sparse_indexed32(vals, positions, cursor); }
}
fn accumulate_hessian_sparse_indexed64(&self, vals: &mut [f64], positions: &[usize], cursor: &mut usize) {
for item in self.iter() { item.accumulate_hessian_sparse_indexed64(vals, positions, cursor); }
}
}
};
}
impl_model_collection!(std::vec::Vec<T>, iter_mut);
impl_model_collection!(crate::refs::Vec<T>, iter_mut);
impl_model_collection!(crate::refs::Deque<T>, iter_mut);
impl<T: Model> Model for crate::refs::Arena<T> {
fn serialize_params32(&mut self, data: &mut std::vec::Vec<f32>) {
for item in self.iter_mut() { item.serialize_params32(data); }
}
fn deserialize_params32(&mut self, data: &[f32]) {
for item in self.iter_mut() { item.deserialize_params32(data); }
}
fn update32(&mut self,data: &[f32]) {
for item in self.iter_mut() { item.update32(data); }
}
fn update_self(&mut self) {
for item in self.iter_mut() { item.update_self(); }
}
fn serialize_params64(&mut self, data: &mut std::vec::Vec<f64>) {
for item in self.iter_mut() { item.serialize_params64(data); }
}
fn deserialize_params64(&mut self, data: &[f64]) {
for item in self.iter_mut() { item.deserialize_params64(data); }
}
fn update64(&mut self, data: &[f64]) {
for item in self.iter_mut() { item.update64(data); }
}
fn zero_blocks(&mut self) {
for item in self.iter_mut() { item.zero_blocks(); }
}
fn serialize_size(&self) -> u32 {
self.iter().map(|item| item.serialize_size()).sum()
}
fn accumulate_hessian32(&self, hessian: &mut [f32]) {
for item in self.iter() { item.accumulate_hessian32(hessian); }
}
fn accumulate_hessian64(&self, hessian: &mut [f64]) {
for item in self.iter() { item.accumulate_hessian64(hessian); }
}
fn accumulate_hessian_band32(&self, band: &mut [f32], kd: usize) -> Result<(), crate::simple_lm::BandError> {
for item in self.iter() { item.accumulate_hessian_band32(band, kd)?; }
Ok(())
}
fn accumulate_hessian_band64(&self, band: &mut [f64], kd: usize) -> Result<(), crate::simple_lm::BandError> {
for item in self.iter() { item.accumulate_hessian_band64(band, kd)?; }
Ok(())
}
fn accumulate_hessian_sparse32(&self, coo: &mut crate::simple_lm::CooMatrix<f32>) {
for item in self.iter() { item.accumulate_hessian_sparse32(coo); }
}
fn accumulate_hessian_sparse64(&self, coo: &mut crate::simple_lm::CooMatrix<f64>) {
for item in self.iter() { item.accumulate_hessian_sparse64(coo); }
}
fn accumulate_hessian_sparse_direct32(&self, csc: &mut crate::simple_lm::CscMatrix<f32>) {
for item in self.iter() { item.accumulate_hessian_sparse_direct32(csc); }
}
fn accumulate_hessian_sparse_direct64(&self, csc: &mut crate::simple_lm::CscMatrix<f64>) {
for item in self.iter() { item.accumulate_hessian_sparse_direct64(csc); }
}
fn accumulate_hessian_sparse_indexed32(&self, vals: &mut [f32], positions: &[usize], cursor: &mut usize) {
for item in self.iter() { item.accumulate_hessian_sparse_indexed32(vals, positions, cursor); }
}
fn accumulate_hessian_sparse_indexed64(&self, vals: &mut [f64], positions: &[usize], cursor: &mut usize) {
for item in self.iter() { item.accumulate_hessian_sparse_indexed64(vals, positions, cursor); }
}
}
impl<T: Model> Model for Option<T> {
fn serialize_params32(&mut self, data: &mut std::vec::Vec<f32>) {
if let Some(inner) = self { inner.serialize_params32(data); }
}
fn deserialize_params32(&mut self, data: &[f32]) {
if let Some(inner) = self { inner.deserialize_params32(data); }
}
fn update32(&mut self,data: &[f32]) {
if let Some(inner) = self { inner.update32(data); }
}
fn update_self(&mut self) {
if let Some(inner) = self { inner.update_self(); }
}
fn serialize_params64(&mut self, data: &mut std::vec::Vec<f64>) {
if let Some(inner) = self { inner.serialize_params64(data); }
}
fn deserialize_params64(&mut self, data: &[f64]) {
if let Some(inner) = self { inner.deserialize_params64(data); }
}
fn update64(&mut self, data: &[f64]) {
if let Some(inner) = self { inner.update64(data); }
}
fn serialize_size(&self) -> u32 {
if let Some(inner) = self { inner.serialize_size() } else { 0 }
}
fn zero_blocks(&mut self) {
if let Some(inner) = self { inner.zero_blocks(); }
}
fn accumulate_hessian32(&self, hessian: &mut [f32]) {
if let Some(inner) = self { inner.accumulate_hessian32(hessian); }
}
fn accumulate_hessian64(&self, hessian: &mut [f64]) {
if let Some(inner) = self { inner.accumulate_hessian64(hessian); }
}
fn accumulate_hessian_band32(&self, band: &mut [f32], kd: usize) -> Result<(), crate::simple_lm::BandError> {
if let Some(inner) = self { inner.accumulate_hessian_band32(band, kd)?; }
Ok(())
}
fn accumulate_hessian_band64(&self, band: &mut [f64], kd: usize) -> Result<(), crate::simple_lm::BandError> {
if let Some(inner) = self { inner.accumulate_hessian_band64(band, kd)?; }
Ok(())
}
fn accumulate_hessian_sparse32(&self, coo: &mut crate::simple_lm::CooMatrix<f32>) {
if let Some(inner) = self { inner.accumulate_hessian_sparse32(coo); }
}
fn accumulate_hessian_sparse64(&self, coo: &mut crate::simple_lm::CooMatrix<f64>) {
if let Some(inner) = self { inner.accumulate_hessian_sparse64(coo); }
}
fn accumulate_hessian_sparse_direct32(&self, csc: &mut crate::simple_lm::CscMatrix<f32>) {
if let Some(inner) = self { inner.accumulate_hessian_sparse_direct32(csc); }
}
fn accumulate_hessian_sparse_direct64(&self, csc: &mut crate::simple_lm::CscMatrix<f64>) {
if let Some(inner) = self { inner.accumulate_hessian_sparse_direct64(csc); }
}
fn accumulate_hessian_sparse_indexed32(&self, vals: &mut [f32], positions: &[usize], cursor: &mut usize) {
if let Some(inner) = self { inner.accumulate_hessian_sparse_indexed32(vals, positions, cursor); }
}
fn accumulate_hessian_sparse_indexed64(&self, vals: &mut [f64], positions: &[usize], cursor: &mut usize) {
if let Some(inner) = self { inner.accumulate_hessian_sparse_indexed64(vals, positions, cursor); }
}
}
#[inline]
fn tri_idx(n: usize, i: usize, j: usize) -> usize {
i * (2 * n - i - 1) / 2 + j
}
pub struct SelfBlock<A: Model, const N: usize, T: crate::utils::Float = f64> {
indices: [u32; N],
hessian: std::vec::Vec<T>,
_marker: std::marker::PhantomData<(A, T)>,
}
impl<A: Model, const N: usize, T: crate::utils::Float> Default for SelfBlock<A, N, T> {
fn default() -> Self { Self::new() }
}
impl<A: Model, const N: usize, T: crate::utils::Float> SelfBlock<A, N, T> {
pub fn new() -> Self {
SelfBlock {
indices: [u32::MAX; N],
hessian: vec![T::zero(); N * (N + 1) / 2],
_marker: std::marker::PhantomData,
}
}
pub fn set_indices(&mut self, indices: &[u32; N]) {
self.indices = *indices;
}
pub fn zero(&mut self) {
self.hessian.fill(T::zero());
}
pub fn is_active(&self) -> bool {
self.indices.iter().any(|&i| i != u32::MAX)
}
pub fn add_residual(&mut self, r: T, dr: &[T; N], grad: &mut [T]) {
let two = T::two();
for i in 0..N {
let gi = self.indices[i];
if gi != u32::MAX {
grad[gi as usize] += two * r * dr[i];
}
for j in i..N {
self.hessian[tri_idx(N, i, j)] += two * dr[i] * dr[j];
}
}
}
pub fn accumulate_hessian(&self, hessian: &mut [T]) {
let n_total = (hessian.len() as f64).sqrt() as usize;
for i in 0..N {
let gi = self.indices[i];
if gi == u32::MAX { continue; }
let gi = gi as usize;
for j in i..N {
let gj = self.indices[j];
if gj == u32::MAX { continue; }
let gj = gj as usize;
let val = self.hessian[tri_idx(N, i, j)];
hessian[gi * n_total + gj] += val;
if gi != gj {
hessian[gj * n_total + gi] += val;
}
}
}
}
pub fn accumulate_hessian_band(&self, band: &mut [T], kd: usize)
-> Result<(), crate::simple_lm::BandError>
{
let ldab = kd + 1;
for i in 0..N {
let gi = self.indices[i];
if gi == u32::MAX { continue; }
let gi = gi as usize;
for j in i..N {
let gj = self.indices[j];
if gj == u32::MAX { continue; }
let gj = gj as usize;
let (lo, hi) = if gi <= gj { (gi, gj) } else { (gj, gi) };
if hi - lo > kd {
return Err(crate::simple_lm::BandError { row: lo, col: hi, kd });
}
let val = self.hessian[tri_idx(N, i, j)];
band[(kd + lo - hi) + hi * ldab] += val;
}
}
Ok(())
}
pub fn accumulate_hessian_sparse(&self, coo: &mut crate::simple_lm::CooMatrix<T>) {
for i in 0..N {
let gi = self.indices[i];
if gi == u32::MAX { continue; }
for j in i..N {
let gj = self.indices[j];
if gj == u32::MAX { continue; }
let (lo, hi) = if gi <= gj { (gi, gj) } else { (gj, gi) };
let val = self.hessian[tri_idx(N, i, j)];
coo.push(lo, hi, val);
}
}
}
pub fn accumulate_hessian_sparse_direct(&self, csc: &mut crate::simple_lm::CscMatrix<T>) {
for i in 0..N {
let gi = self.indices[i];
if gi == u32::MAX { continue; }
for j in i..N {
let gj = self.indices[j];
if gj == u32::MAX { continue; }
let (lo, hi) = if gi <= gj { (gi, gj) } else { (gj, gi) };
let val = self.hessian[tri_idx(N, i, j)];
if let Some(pos) = csc.find_pos(lo as usize, hi as usize) {
csc.vals[pos] += val;
}
}
}
}
pub fn accumulate_hessian_sparse_indexed(&self, vals: &mut [T], positions: &[usize], cursor: &mut usize) {
for i in 0..N {
let gi = self.indices[i];
if gi == u32::MAX { continue; }
for j in i..N {
let gj = self.indices[j];
if gj == u32::MAX { continue; }
let val = self.hessian[tri_idx(N, i, j)];
vals[positions[*cursor]] += val;
*cursor += 1;
}
}
}
}
pub struct CrossBlock<A: Model, B: Model, const NA: usize, const NB: usize, T: crate::utils::Float = f64> {
indices_a: [u32; NA],
indices_b: [u32; NB],
cross_hessian: std::vec::Vec<T>, _marker: std::marker::PhantomData<(A, B, T)>,
}
impl<A: Model, B: Model, const NA: usize, const NB: usize, T: crate::utils::Float> Default for CrossBlock<A, B, NA, NB, T> {
fn default() -> Self { Self::new() }
}
impl<A: Model, B: Model, const NA: usize, const NB: usize, T: crate::utils::Float> CrossBlock<A, B, NA, NB, T> {
pub fn new() -> Self {
CrossBlock {
indices_a: [u32::MAX; NA],
indices_b: [u32::MAX; NB],
cross_hessian: vec![T::zero(); NA * NB],
_marker: std::marker::PhantomData,
}
}
pub fn na(&self) -> usize { NA }
pub fn nb(&self) -> usize { NB }
pub fn set_indices(&mut self, a_indices: &[u32], b_indices: &[u32]) {
debug_assert_eq!(a_indices.len(), NA);
debug_assert_eq!(b_indices.len(), NB);
self.indices_a.copy_from_slice(a_indices);
self.indices_b.copy_from_slice(b_indices);
}
pub fn zero(&mut self) {
self.cross_hessian.fill(T::zero());
}
pub fn is_active(&self) -> bool {
self.indices_a.iter().any(|&i| i != u32::MAX)
|| self.indices_b.iter().any(|&i| i != u32::MAX)
}
pub fn add_residual_cross(&mut self, _r: T, dr_a: &[T; NA], dr_b: &[T; NB]) {
let two = T::two();
for i in 0..NA {
let dai = dr_a[i];
if dai == T::zero() { continue; }
let row = i * NB;
for j in 0..NB {
self.cross_hessian[row + j] += two * dai * dr_b[j];
}
}
}
pub fn accumulate_hessian(&self, hessian: &mut [T]) {
let n_total = (hessian.len() as f64).sqrt() as usize;
for i in 0..NA {
let gi = self.indices_a[i];
if gi == u32::MAX { continue; }
let gi = gi as usize;
let row = i * NB;
for j in 0..NB {
let gj = self.indices_b[j];
if gj == u32::MAX { continue; }
let gj = gj as usize;
let val = self.cross_hessian[row + j];
if gi == gj { continue; }
hessian[gi * n_total + gj] += val;
hessian[gj * n_total + gi] += val;
}
}
}
pub fn accumulate_hessian_band(&self, band: &mut [T], kd: usize)
-> Result<(), crate::simple_lm::BandError>
{
let ldab = kd + 1;
for i in 0..NA {
let gi = self.indices_a[i];
if gi == u32::MAX { continue; }
let gi = gi as usize;
let row = i * NB;
for j in 0..NB {
let gj = self.indices_b[j];
if gj == u32::MAX { continue; }
let gj = gj as usize;
if gi == gj { continue; }
let (lo, hi) = if gi <= gj { (gi, gj) } else { (gj, gi) };
if hi - lo > kd {
return Err(crate::simple_lm::BandError { row: lo, col: hi, kd });
}
let val = self.cross_hessian[row + j];
band[(kd + lo - hi) + hi * ldab] += val;
}
}
Ok(())
}
pub fn accumulate_hessian_sparse(&self, coo: &mut crate::simple_lm::CooMatrix<T>) {
for i in 0..NA {
let gi = self.indices_a[i];
if gi == u32::MAX { continue; }
let row = i * NB;
for j in 0..NB {
let gj = self.indices_b[j];
if gj == u32::MAX { continue; }
if gi == gj { continue; }
let (lo, hi) = if gi <= gj { (gi, gj) } else { (gj, gi) };
let val = self.cross_hessian[row + j];
coo.push(lo, hi, val);
}
}
}
pub fn accumulate_hessian_sparse_direct(&self, csc: &mut crate::simple_lm::CscMatrix<T>) {
for i in 0..NA {
let gi = self.indices_a[i];
if gi == u32::MAX { continue; }
let row = i * NB;
for j in 0..NB {
let gj = self.indices_b[j];
if gj == u32::MAX { continue; }
if gi == gj { continue; }
let (lo, hi) = if gi <= gj { (gi, gj) } else { (gj, gi) };
let val = self.cross_hessian[row + j];
if let Some(pos) = csc.find_pos(lo as usize, hi as usize) {
csc.vals[pos] += val;
}
}
}
}
pub fn accumulate_hessian_sparse_indexed(&self, vals: &mut [T], positions: &[usize], cursor: &mut usize) {
for i in 0..NA {
let gi = self.indices_a[i];
if gi == u32::MAX { continue; }
let row = i * NB;
for j in 0..NB {
let gj = self.indices_b[j];
if gj == u32::MAX { continue; }
if gi == gj { continue; }
let val = self.cross_hessian[row + j];
vals[positions[*cursor]] += val;
*cursor += 1;
}
}
}
}
pub struct TripletBlock<T: crate::utils::Float = f64> {
pub hessian: std::vec::Vec<(u32, u32, T)>,
}
impl<T: crate::utils::Float> Default for TripletBlock<T> {
fn default() -> Self { Self::new() }
}
impl<T: crate::utils::Float> TripletBlock<T> {
pub fn new() -> Self {
TripletBlock { hessian: std::vec::Vec::new() }
}
pub fn zero(&mut self) {
self.hessian.clear();
}
pub fn add_residual(&mut self, r: T, indices: &[u32], dr: &[T], grad: &mut [T]) {
let two = T::two();
let n = indices.len();
for i in 0..n {
if indices[i] == u32::MAX { continue; }
let gi = indices[i] as usize;
grad[gi] += two * r * dr[i];
for j in i..n {
if indices[j] == u32::MAX { continue; }
let (lo, hi) = if indices[i] <= indices[j] {
(indices[i], indices[j])
} else {
(indices[j], indices[i])
};
self.hessian.push((lo, hi, two * dr[i] * dr[j]));
}
}
}
pub fn add_residual_cross(&mut self, _r: T, indices: &[u32], dr: &[T], entity_offsets: &[u32]) {
let two = T::two();
let n = indices.len();
let span_of = |i: u32| -> u32 {
let mut k = 0u32;
for (idx, &off) in entity_offsets.iter().enumerate() {
if off <= i { k = idx as u32; } else { break; }
}
k
};
for i in 0..n {
if indices[i] == u32::MAX { continue; }
let span_i = span_of(i as u32);
for j in (i + 1)..n {
if indices[j] == u32::MAX { continue; }
let span_j = span_of(j as u32);
if span_i == span_j { continue; }
let (lo, hi) = if indices[i] <= indices[j] {
(indices[i], indices[j])
} else {
(indices[j], indices[i])
};
self.hessian.push((lo, hi, two * dr[i] * dr[j]));
}
}
}
pub fn accumulate_hessian(&self, hessian: &mut [T]) {
let n_total = (hessian.len() as f64).sqrt() as usize;
for &(i, j, v) in &self.hessian {
let (i, j) = (i as usize, j as usize);
hessian[i * n_total + j] += v;
if i != j {
hessian[j * n_total + i] += v;
}
}
}
pub fn accumulate_hessian_band(&self, band: &mut [T], kd: usize)
-> Result<(), crate::simple_lm::BandError>
{
let ldab = kd + 1;
for &(row, col, v) in &self.hessian {
let (r, c) = (row as usize, col as usize);
if c < r || c - r > kd {
return Err(crate::simple_lm::BandError { row: r, col: c, kd });
}
band[(c - r) + r * ldab] += v;
}
Ok(())
}
pub fn accumulate_hessian_sparse(&self, coo: &mut crate::simple_lm::CooMatrix<T>) {
for &(i, j, v) in &self.hessian {
coo.push(i, j, v);
}
}
pub fn accumulate_hessian_sparse_direct(&self, csc: &mut crate::simple_lm::CscMatrix<T>) {
for &(row, col, v) in &self.hessian {
if let Some(pos) = csc.find_pos(row as usize, col as usize) {
csc.vals[pos] += v;
}
}
}
pub fn accumulate_hessian_sparse_indexed(&self, vals: &mut [T], positions: &[usize], cursor: &mut usize) {
for &(_, _, v) in &self.hessian {
vals[positions[*cursor]] += v;
*cursor += 1;
}
}
}
pub struct Jacobian<T: crate::utils::Float = f64> {
pub num_params: usize,
pub rows: std::vec::Vec<JacobianRow<T>>,
}
pub struct JacobianRow<T> {
pub constraint: u32,
pub label: &'static str,
pub residual: T,
pub entries: std::vec::Vec<(u32, T)>,
}
impl<T: crate::utils::Float> Jacobian<T> {
pub fn num_residuals(&self) -> usize { self.rows.len() }
pub fn residuals(&self) -> std::vec::Vec<T> {
self.rows.iter().map(|r| r.residual).collect()
}
pub fn to_dense(&self) -> std::vec::Vec<T> {
let m = self.rows.len();
let n = self.num_params;
let mut data = vec![T::zero(); m * n];
for (i, row) in self.rows.iter().enumerate() {
for &(j, v) in &row.entries {
data[i * n + j as usize] = v;
}
}
data
}
fn to_dense_f64(&self) -> std::vec::Vec<f64> {
let m = self.rows.len();
let n = self.num_params;
let mut data = vec![0.0f64; m * n];
for (i, row) in self.rows.iter().enumerate() {
for &(j, v) in &row.entries {
data[i * n + j as usize] = <f64 as num::NumCast>::from(v).unwrap_or(0.0);
}
}
data
}
pub fn singular_values(&self) -> std::vec::Vec<f64> {
let m = self.num_residuals();
let n = self.num_params;
if m == 0 || n == 0 { return std::vec::Vec::new(); }
let dense = self.to_dense_f64();
if n < 32 {
let j = nalgebra::DMatrix::from_row_slice(m, n, &dense);
j.singular_values().iter().cloned().collect()
} else {
let faer_j = faer::Mat::from_fn(m, n, |i, k| dense[i * n + k]);
match faer_j.thin_svd() {
Ok(svd) => {
let s = svd.S().column_vector();
(0..s.nrows()).map(|i| s[i]).collect()
}
Err(_) => std::vec::Vec::new(),
}
}
}
pub fn svd(&self) -> SvdResult {
let m = self.num_residuals();
let n = self.num_params;
let dense = self.to_dense_f64();
svd_dense_f64(m, n, &dense)
}
pub fn column_l2_norms(&self) -> std::vec::Vec<f64> {
let n = self.num_params;
let mut sum_sq = vec![0.0f64; n];
for row in &self.rows {
for &(j, v) in &row.entries {
let vf: f64 = <f64 as num::NumCast>::from(v).unwrap_or(0.0);
sum_sq[j as usize] += vf * vf;
}
}
sum_sq.into_iter().map(|s| s.sqrt()).collect()
}
pub fn singular_values_column_normalised(&self) -> std::vec::Vec<f64> {
let m = self.num_residuals();
let n = self.num_params;
if m == 0 || n == 0 { return std::vec::Vec::new(); }
let col_norms = self.column_l2_norms();
let mut dense = self.to_dense_f64();
for r in 0..m {
for c in 0..n {
dense[r * n + c] /= col_norms[c].max(1e-15);
}
}
if n < 32 {
let j = nalgebra::DMatrix::from_row_slice(m, n, &dense);
j.singular_values().iter().cloned().collect()
} else {
let faer_j = faer::Mat::from_fn(m, n, |i, k| dense[i * n + k]);
match faer_j.thin_svd() {
Ok(svd) => {
let s = svd.S().column_vector();
(0..s.nrows()).map(|i| s[i]).collect()
}
Err(_) => std::vec::Vec::new(),
}
}
}
pub fn svd_column_normalised(&self) -> (SvdResult, std::vec::Vec<f64>) {
let m = self.num_residuals();
let n = self.num_params;
if m == 0 || n == 0 {
return (SvdResult {
singular_values: std::vec::Vec::new(),
u: std::vec::Vec::new(),
v: std::vec::Vec::new(),
m, n,
}, std::vec::Vec::new());
}
let col_norms = self.column_l2_norms();
let mut dense = self.to_dense_f64();
for r in 0..m {
for c in 0..n {
dense[r * n + c] /= col_norms[c].max(1e-15);
}
}
(svd_dense_f64(m, n, &dense), col_norms)
}
}
fn svd_dense_f64(m: usize, n: usize, dense: &[f64]) -> SvdResult {
if m == 0 || n == 0 {
return SvdResult {
singular_values: std::vec::Vec::new(),
u: std::vec::Vec::new(),
v: std::vec::Vec::new(),
m, n,
};
}
let k = m.min(n);
if n < 32 {
let j = nalgebra::DMatrix::from_row_slice(m, n, dense);
let svd = j.svd(true, true);
let singular_values: std::vec::Vec<f64> = svd.singular_values.iter().cloned().collect();
let u_mat = svd.u.as_ref().expect("U requested");
let vt_mat = svd.v_t.as_ref().expect("V^t requested");
let mut u = vec![0.0f64; m * k];
let mut v = vec![0.0f64; n * k];
let kk = singular_values.len().min(k);
for i in 0..m {
for j in 0..kk {
u[i * k + j] = u_mat[(i, j)];
}
}
for i in 0..n {
for j in 0..kk {
v[i * k + j] = vt_mat[(j, i)];
}
}
SvdResult { singular_values, u, v, m, n }
} else {
let faer_j = faer::Mat::from_fn(m, n, |i, k| dense[i * n + k]);
match faer_j.thin_svd() {
Ok(svd) => {
let s = svd.S().column_vector();
let singular_values: std::vec::Vec<f64> = (0..s.nrows()).map(|i| s[i]).collect();
let u_mat = svd.U();
let v_mat = svd.V();
let mut u = vec![0.0f64; m * k];
let mut v = vec![0.0f64; n * k];
let kk = singular_values.len().min(k);
for i in 0..m {
for j in 0..kk {
u[i * k + j] = u_mat[(i, j)];
}
}
for i in 0..n {
for j in 0..kk {
v[i * k + j] = v_mat[(i, j)];
}
}
SvdResult { singular_values, u, v, m, n }
}
Err(_) => SvdResult {
singular_values: std::vec::Vec::new(),
u: std::vec::Vec::new(),
v: std::vec::Vec::new(),
m, n,
},
}
}
}
pub struct SvdResult {
pub singular_values: std::vec::Vec<f64>,
pub u: std::vec::Vec<f64>,
pub v: std::vec::Vec<f64>,
pub m: usize,
pub n: usize,
}
pub trait JacobianModel<T: crate::utils::Float> {
fn calc_jacobian(&mut self, params: &[T]) -> Jacobian<T>;
fn calc_cost_table(&mut self, params: &[T]) -> std::collections::HashMap<&'static str, T> {
let j = self.calc_jacobian(params);
let mut out = std::collections::HashMap::new();
for row in &j.rows {
let e = out.entry(row.label).or_insert(T::zero());
*e += row.residual * row.residual;
}
out
}
}
pub fn jacobian_entries<T: crate::utils::Float>(indices: &[u32], derivatives: &[T]) -> std::vec::Vec<(u32, T)> {
indices.iter().zip(derivatives.iter())
.filter(|&(&idx, _)| idx != u32::MAX)
.map(|(&idx, &d)| (idx, d))
.collect()
}
pub trait ModelSym {
type Sym;
fn sym(base: &str) -> Self::Sym;
}
use arael_sym::E;
impl ModelSym for bool {
type Sym = E;
fn sym(base: &str) -> E { arael_sym::symbol(base) }
}
impl ModelSym for u32 {
type Sym = E;
fn sym(base: &str) -> E { arael_sym::symbol(base) }
}
impl ModelSym for f32 {
type Sym = E;
fn sym(base: &str) -> E { arael_sym::symbol(base) }
}
impl ModelSym for f64 {
type Sym = E;
fn sym(base: &str) -> E { arael_sym::symbol(base) }
}
impl ModelSym for String {
type Sym = E;
fn sym(base: &str) -> E { arael_sym::symbol(base) }
}
impl ModelSym for crate::vect::vect3f {
type Sym = crate::vect::vect3sym;
fn sym(base: &str) -> Self::Sym { crate::vect::vect3sym::new(base) }
}
impl ModelSym for crate::vect::vect3d {
type Sym = crate::vect::vect3sym;
fn sym(base: &str) -> Self::Sym { crate::vect::vect3sym::new(base) }
}
impl ModelSym for crate::vect::vect2f {
type Sym = crate::vect::vect2sym;
fn sym(base: &str) -> Self::Sym { crate::vect::vect2sym::new(base) }
}
impl ModelSym for crate::vect::vect2d {
type Sym = crate::vect::vect2sym;
fn sym(base: &str) -> Self::Sym { crate::vect::vect2sym::new(base) }
}
impl ModelSym for crate::matrix::matrix3f {
type Sym = crate::matrix::matrix3sym;
fn sym(base: &str) -> Self::Sym { crate::matrix::matrix3sym::new(base) }
}
impl ModelSym for crate::matrix::matrix3d {
type Sym = crate::matrix::matrix3sym;
fn sym(base: &str) -> Self::Sym { crate::matrix::matrix3sym::new(base) }
}
impl ModelSym for crate::matrix::matrix2f {
type Sym = crate::matrix::matrix2sym;
fn sym(base: &str) -> Self::Sym { crate::matrix::matrix2sym::new(base) }
}
impl ModelSym for crate::matrix::matrix2d {
type Sym = crate::matrix::matrix2sym;
fn sym(base: &str) -> Self::Sym { crate::matrix::matrix2sym::new(base) }
}
impl ModelSym for crate::quatern::quaternf {
type Sym = crate::quatern::quaternsym;
fn sym(base: &str) -> Self::Sym { crate::quatern::quaternsym::new(base) }
}
impl ModelSym for crate::quatern::quaternd {
type Sym = crate::quatern::quaternsym;
fn sym(base: &str) -> Self::Sym { crate::quatern::quaternsym::new(base) }
}
impl<T: ParamType + ModelSym> ModelSym for Param<T> {
type Sym = T::Sym;
fn sym(base: &str) -> Self::Sym { T::sym(base) }
}
impl<T: crate::utils::Float> ModelSym for SimpleEulerAngleParam<T>
where vect3<T>: ModelSym
{
type Sym = <vect3<T> as ModelSym>::Sym;
fn sym(base: &str) -> Self::Sym { <vect3<T> as ModelSym>::sym(base) }
}
impl<T: crate::utils::Float> ModelSym for EulerAngleParam<T>
where vect3<T>: ModelSym
{
type Sym = <vect3<T> as ModelSym>::Sym;
fn sym(base: &str) -> Self::Sym { <vect3<T> as ModelSym>::sym(base) }
}
#[cfg(test)]
mod tests {
use super::*;
use crate::vect::{vect3f, vect2f};
#[test]
fn test_param_f32_serialize_deserialize() {
let mut a = Param::new(3.0f32);
let mut b = Param::new(7.0f32);
let mut c = Param::fixed(99.0f32);
let mut data = Vec::new();
a.serialize_params32(&mut data);
b.serialize_params32(&mut data);
c.serialize_params32(&mut data);
assert_eq!(data, vec![3.0, 7.0]);
assert_eq!(a.index, 0);
assert_eq!(b.index, 1);
assert_eq!(c.index, u32::MAX);
data[0] = 10.0;
data[1] = 20.0;
a.deserialize_params32(&data);
b.deserialize_params32(&data);
c.deserialize_params32(&data);
assert_eq!(a.value, 10.0);
assert_eq!(b.value, 20.0);
assert_eq!(c.value, 99.0); }
#[test]
fn test_param_vect3f_serialize() {
let mut p = Param::new(vect3f::new(1.0, 2.0, 3.0));
let mut data = Vec::new();
p.serialize_params32(&mut data);
assert_eq!(data, vec![1.0, 2.0, 3.0]);
assert_eq!(p.index, 0);
}
#[test]
fn test_param_update() {
let mut p = Param::new(5.0f32);
let mut data = Vec::new();
p.serialize_params32(&mut data);
data[0] = 42.0;
p.update32(&data);
assert_eq!(p.work(), 42.0);
assert_eq!(p.value, 5.0);
p.update_self();
assert_eq!(p.work(), 5.0); }
#[test]
fn test_param_fixed_update() {
let mut p = Param::fixed(5.0f32);
let mut data = Vec::new();
p.serialize_params32(&mut data);
assert!(data.is_empty());
p.update32(&data);
assert_eq!(p.work(), 5.0); }
#[test]
fn test_param_vect2f() {
let mut p = Param::new(vect2f::new(1.0, 2.0));
let mut data = Vec::new();
p.serialize_params32(&mut data);
assert_eq!(data, vec![1.0, 2.0]);
data[0] = 10.0;
data[1] = 20.0;
p.update32(&data);
assert_eq!(p.work().x, 10.0);
assert_eq!(p.work().y, 20.0);
}
#[test]
fn test_param_f32_serialize64_roundtrip() {
let mut a = Param::new(3.0f32);
let mut b = Param::new(7.0f32);
let mut c = Param::fixed(99.0f32);
let mut data: std::vec::Vec<f64> = Vec::new();
a.serialize_params64(&mut data);
b.serialize_params64(&mut data);
c.serialize_params64(&mut data);
assert_eq!(data, vec![3.0f64, 7.0]);
assert_eq!(a.index, 0);
assert_eq!(b.index, 1);
assert_eq!(c.index, u32::MAX);
data[0] = 10.0;
data[1] = 20.0;
a.deserialize_params64(&data);
b.deserialize_params64(&data);
c.deserialize_params64(&data);
assert_eq!(a.value, 10.0f32);
assert_eq!(b.value, 20.0f32);
assert_eq!(c.value, 99.0f32);
}
#[test]
fn test_param_vect3f_serialize64_roundtrip() {
let mut p = Param::new(vect3f::new(1.0, 2.0, 3.0));
let mut data: std::vec::Vec<f64> = Vec::new();
p.serialize_params64(&mut data);
assert_eq!(data, vec![1.0f64, 2.0, 3.0]);
data[0] = 10.5;
data[1] = 20.5;
data[2] = 30.5;
p.update64(&data);
assert_eq!(p.work().x, 10.5f32);
assert_eq!(p.work().y, 20.5f32);
assert_eq!(p.work().z, 30.5f32);
}
#[test]
fn test_param_fixed_update64() {
let mut p = Param::fixed(5.0f32);
let mut data: std::vec::Vec<f64> = Vec::new();
p.serialize_params64(&mut data);
assert!(data.is_empty());
p.update64(&data);
assert_eq!(p.work(), 5.0f32);
}
#[test]
fn test_param_count() {
assert_eq!(Param::<f32>::PARAM_COUNT, 1);
assert_eq!(Param::<vect2f>::PARAM_COUNT, 2);
assert_eq!(Param::<vect3f>::PARAM_COUNT, 3);
}
#[test]
fn test_serialize_size() {
let a = Param::new(1.0f32);
let b = Param::fixed(2.0f32);
let c = Param::new(vect3f::new(1.0, 2.0, 3.0));
assert_eq!(a.serialize_size(), 1);
assert_eq!(b.serialize_size(), 0);
assert_eq!(c.serialize_size(), 3);
}
#[test]
fn test_leaf_param_count_and_serialize_size() {
assert_eq!(f32::PARAM_COUNT, 0);
assert_eq!(0.0f32.serialize_size(), 0);
assert_eq!(vect3f::PARAM_COUNT, 0);
assert_eq!(vect3f::new(1.0, 2.0, 3.0).serialize_size(), 0);
}
#[test]
fn test_collection_serialize_size() {
let mut v = vec![Param::new(1.0f32), Param::new(2.0f32), Param::fixed(3.0f32)];
let mut data = Vec::new();
v.serialize_params32(&mut data);
assert_eq!(v.serialize_size(), 2);
let none: Option<Param<f32>> = None;
assert_eq!(none.serialize_size(), 0);
let some = Some(Param::new(1.0f32));
assert_eq!(some.serialize_size(), 1);
}
}