1use std::collections::hash_map::Iter as HashMapIter;
2
3use crate::{
4 containers::{Idx, Key, Symbol, Values, ValuesOrder},
5 linalg::{VectorViewX, VectorX},
6};
7
8pub struct LinearValues {
14 values: VectorX,
15 order: ValuesOrder,
16}
17
18impl LinearValues {
19 pub fn zero_from_order(order: ValuesOrder) -> Self {
21 let values = VectorX::zeros(order.dim());
22 Self { values, order }
23 }
24
25 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 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 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 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 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 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 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}