Skip to main content

factrs/linear/
values.rs

1use std::collections::hash_map::Iter as HashMapIter;
2
3use crate::{
4    containers::{Idx, Key, Symbol, Values, ValuesOrder},
5    linalg::{VectorViewX, VectorX},
6};
7
8/// Structure to store linear (aka all vector) values
9///
10/// This structure is the linear equivalent of [Values]. It stores all values in
11/// a single vector, along with indices and dimensions of each variable. Ideally
12/// *shouldn't* ever be needed in practice.
13pub struct LinearValues {
14    values: VectorX,
15    order: ValuesOrder,
16}
17
18impl LinearValues {
19    /// Create a zero/identity LinearValues from a [ValuesOrder]
20    pub fn zero_from_order(order: ValuesOrder) -> Self {
21        let values = VectorX::zeros(order.dim());
22        Self { values, order }
23    }
24
25    /// Create a zero/identity LinearValues from a [Values]
26    ///
27    /// The order is inferred from the values
28    pub fn zero_from_values(values: &Values) -> Self {
29        let order = ValuesOrder::from_values(values);
30        let values = VectorX::zeros(order.dim());
31        Self { values, order }
32    }
33
34    /// Create a LinearValues from a [ValuesOrder] and a vector
35    pub fn from_order_and_vector(order: ValuesOrder, values: VectorX) -> Self {
36        assert!(
37            values.len() == order.dim(),
38            "Vector and order must have the same dimension when creating LinearValues"
39        );
40        Self { values, order }
41    }
42
43    /// Create a LinearValues from a [Values] and a vector
44    ///
45    /// The order is inferred from the values
46    pub fn from_values_and_vector(values: &Values, vector: VectorX) -> Self {
47        let order = ValuesOrder::from_values(values);
48        assert!(
49            vector.len() == order.dim(),
50            "Vector and values must have the same dimension when creating LinearValues"
51        );
52        Self::from_order_and_vector(order, vector)
53    }
54
55    pub fn len(&self) -> usize {
56        self.order.len()
57    }
58
59    pub fn is_empty(&self) -> bool {
60        self.order.is_empty()
61    }
62
63    pub fn dim(&self) -> usize {
64        self.values.len()
65    }
66
67    fn get_idx(&self, idx: &Idx) -> VectorViewX<'_> {
68        self.values.rows(idx.idx, idx.dim)
69    }
70
71    /// Retrieve a vector from the LinearValues
72    pub fn get(&self, key: impl Symbol) -> Option<VectorViewX<'_>> {
73        let idx = self.order.get(key)?;
74        self.get_idx(idx).into()
75    }
76
77    pub fn iter(&self) -> Iter<'_> {
78        Iter {
79            values: self,
80            idx: self.order.iter(),
81        }
82    }
83}
84
85pub struct Iter<'a> {
86    values: &'a LinearValues,
87    idx: HashMapIter<'a, Key, Idx>,
88}
89
90impl<'a> Iterator for Iter<'a> {
91    type Item = (&'a Key, VectorViewX<'a>);
92
93    fn next(&mut self) -> Option<Self::Item> {
94        let n = self.idx.next()?;
95        Some((n.0, self.values.get_idx(n.1)))
96    }
97}
98
99#[cfg(test)]
100mod test {
101    use super::*;
102    use crate::{
103        dtype,
104        symbols::X,
105        variables::{Variable, VectorVar2, VectorVar3, VectorVar6},
106    };
107
108    fn make_order_vector() -> (ValuesOrder, VectorX) {
109        // Create some form of values
110        let mut v = Values::new();
111        v.insert_unchecked(X(0), VectorVar2::identity());
112        v.insert_unchecked(X(1), VectorVar6::identity());
113        v.insert_unchecked(X(2), VectorVar3::identity());
114
115        // Create an order
116        let order = ValuesOrder::from_values(&v);
117        let vector = VectorX::from_fn(order.dim(), |i, _| i as dtype);
118        (order, vector)
119    }
120
121    #[test]
122    fn from_order_and_vector() {
123        let (order, vector) = make_order_vector();
124
125        // Create LinearValues
126        let linear_values = LinearValues::from_order_and_vector(order, vector);
127        assert!(linear_values.len() == 3);
128        assert!(linear_values.dim() == 11);
129        assert!(linear_values.get(X(0)).expect("Key was missing").len() == 2);
130        assert!(linear_values.get(X(1)).expect("Key was missing").len() == 6);
131        assert!(linear_values.get(X(2)).expect("Key was missing").len() == 3);
132        assert!(linear_values.get(X(3)).is_none());
133    }
134
135    #[test]
136    #[should_panic]
137    fn mismatched_size() {
138        let (order, vector) = make_order_vector();
139        let vector = vector.push(0.0);
140        LinearValues::from_order_and_vector(order, vector);
141    }
142}