rust_tensors/
address_bound.rs1use crate::addressable::Addressable;
2
3#[derive(Clone, PartialEq, Debug)]
4pub struct AddressBound<A: Addressable> {
5 pub smallest_possible_position: A,
6 pub largest_possible_position: A,
7}
8
9impl<A: Addressable> AddressBound<A> {
10 pub fn contains_address(&self, address: &A) -> bool {
11 for d in 0..A::get_dimension_count() {
12 if address.get_item_at_dimension_index(d)
13 < self
14 .smallest_possible_position
15 .get_item_at_dimension_index(d)
16 || address.get_item_at_dimension_index(d)
17 > self
18 .largest_possible_position
19 .get_item_at_dimension_index(d)
20 {
21 return false;
22 }
23 }
24 true
25 }
26
27 pub fn iter(&self) -> AddressIterator<A> {
28 AddressIterator {
29 bounds: AddressBound::new(
30 self.smallest_possible_position,
31 self.largest_possible_position,
32 ),
33 abacus: Vec::new(),
34 }
35 }
36
37 pub fn new(smallest_possible_position: A, largest_possible_position: A) -> AddressBound<A> {
38 AddressBound {
39 smallest_possible_position,
40 largest_possible_position,
41 }
42 }
43
44 pub fn index_address(&self, address: &A) -> Option<usize> {
45 if !self.contains_address(&address) {
46 return None;
47 }
48 let mut out: usize = 0;
49
50 for d in (0..A::get_dimension_count()).rev() {
51 out *= (self
52 .largest_possible_position
53 .get_item_at_dimension_index(d)
54 - self
55 .smallest_possible_position
56 .get_item_at_dimension_index(d)
57 + 1) as usize;
58 out += (address.get_item_at_dimension_index(d)
59 - self
60 .smallest_possible_position
61 .get_item_at_dimension_index(d)) as usize;
62 }
63
64 Some(out)
65 }
66 pub fn get_address_from_index(&self, index: usize) -> Result<A, &str> {
67 let mut index = index;
68 let mut values: Vec<i64> = Vec::new();
69 for d in 0..A::get_dimension_count() {
70 let min_value = *(self
71 .smallest_possible_position
72 .get_item_at_dimension_index(d));
73 let max_value = *(self
74 .largest_possible_position
75 .get_item_at_dimension_index(d));
76 let breadth = (max_value - min_value + 1) as usize;
77 let value = (index % breadth) as i64 + min_value;
78 values.push(value);
79 index /= breadth;
80 }
81 if index != 0 {
82 return Err("Index is too large.");
83 }
84 Ok(A::new_from_value_vec(values))
85 }
86}
87
88pub struct AddressIterator<A: Addressable> {
89 bounds: AddressBound<A>,
90 abacus: Vec<i64>,
91}
92
93impl<A: Addressable> Iterator for AddressIterator<A> {
94 type Item = A;
95
96 fn next(&mut self) -> Option<Self::Item> {
97 if self.abacus.len() == 0 {
98 let dims = A::get_dimension_count();
99 self.abacus = vec![0; dims as usize];
100 for i in 0..dims {
101 self.abacus[i as usize] = *self
102 .bounds
103 .smallest_possible_position
104 .get_item_at_dimension_index(i);
105 }
106 return Some(A::new_from_value_vec(self.abacus.clone()));
107 }
108 for dimension in 0..A::get_dimension_count() {
109 if self.abacus[dimension as usize]
110 >= *self
111 .bounds
112 .largest_possible_position
113 .get_item_at_dimension_index(dimension)
114 {
115 if dimension == A::get_dimension_count() - 1 {
116 return None;
117 }
118 self.abacus[dimension as usize] = *self
119 .bounds
120 .smallest_possible_position
121 .get_item_at_dimension_index(dimension);
122 continue;
123 } else {
124 self.abacus[dimension as usize] += 1;
125 }
126 break;
127 }
128 Some(A::new_from_value_vec(self.abacus.clone()))
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135 use crate::matrix_address::MatrixAddress;
136 use proptest::proptest;
137
138 #[test]
139 fn iteration_visual_test() {
140 let bounds = AddressBound {
141 smallest_possible_position: MatrixAddress { x: 50, y: 50 },
142 largest_possible_position: MatrixAddress { x: 69, y: 100 },
143 };
144 assert!(bounds.iter().is_sorted());
145 }
146 proptest! {
147 #[test]
148 fn indexing_test(x1 in 0i64..1000, y1 in 0i64..1000, x2 in 0i64..1000, y2 in 0i64..1000) {
149 if x2 < x1 || y2 < y1 {
150 return Ok(());
151 }
152 let bounds = AddressBound {
153 smallest_possible_position: MatrixAddress { x: x1, y: y1 },
154 largest_possible_position: MatrixAddress { x: x2, y: y2 },
155 };
156 bounds.iter()
157 .enumerate()
158 .for_each(|(index, address)| {
159 assert_eq!(bounds.index_address(&address).unwrap(), ((address.y - y1) * (x2-x1 + 1) + (address.x - x1)) as usize);
160 assert_eq!(bounds.get_address_from_index(index).expect("Index out of bounds"), address);
161 });
162 }
163 #[test]
164 fn address_iteration_test(x1 in 0i64..1000, y1 in 0i64..1000, x2 in 0i64..1000, y2 in 0i64..1000) {
165 if x2 < x1 || y2 < y1 {
166 return Ok(());
167 }
168 let bounds = AddressBound {
169 smallest_possible_position: MatrixAddress { x: x1, y: y1 },
170 largest_possible_position: MatrixAddress { x: x2, y: y2 },
171 };
172 bounds.iter().for_each(|address| assert!(bounds.contains_address(&address)));
173 assert_eq!((x2 - x1 + 1) * (y2 - y1 + 1), bounds.iter().collect::<Vec<_>>().len().try_into().unwrap())
174 }
175 #[test]
176 fn contains_test(x1 in 0i64..1000, y1 in 0i64..1000, x2 in 0i64..1000, y2 in 0i64..1000, x3 in 0i64..1000, y3 in 0i64..1000) {
177 if x2 < x1 || y2 < y1 {
178 return Ok(());
179 }
180 let bounds = AddressBound {
181 smallest_possible_position: MatrixAddress { x: x1, y: y1 },
182 largest_possible_position: MatrixAddress { x: x2, y: y2 },
183 };
184 assert_eq!(bounds.contains_address(&MatrixAddress{x: x3,y: y3}), x3 >= x1 && x3 <= x2 && y3 >= y1 && y3 <= y2);
185 }
186 }
187}