nale/align/bounded/structs/
bound.rs1use crate::util::PrintMe;
2use std::fmt::{Display, Formatter};
3use std::iter::{Rev, Zip};
4use std::ops::RangeInclusive;
5
6#[derive(Clone)]
7pub struct CloudBound {
8 pub left_target_idx: usize,
9 pub left_profile_idx: usize,
10 pub right_target_idx: usize,
11 pub right_profile_idx: usize,
12}
13
14impl Default for CloudBound {
15 fn default() -> Self {
16 CloudBound {
19 left_target_idx: 0,
20 left_profile_idx: 1,
21 right_target_idx: 1,
22 right_profile_idx: 0,
23 }
24 }
25}
26
27impl Display for CloudBound {
28 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
29 write!(
30 f,
31 "{},{} : {},{}",
32 self.left_target_idx,
33 self.left_profile_idx,
34 self.right_target_idx,
35 self.right_profile_idx
36 )
37 }
38}
39
40impl PrintMe for CloudBound {
41 fn print(&self) {
42 println!("{}", self);
43 }
44}
45
46impl CloudBound {
47 pub fn was_pruned(&self) -> bool {
48 self.left_target_idx < self.right_target_idx
49 }
50
51 pub fn anti_diagonal_idx(&self) -> usize {
52 self.left_target_idx + self.left_profile_idx
53 }
54
55 pub fn anti_diagonal_cell_zip(&self) -> Zip<Rev<RangeInclusive<usize>>, RangeInclusive<usize>> {
56 let target_range = (self.right_target_idx..=self.left_target_idx).rev();
57 let profile_range = self.left_profile_idx..=self.right_profile_idx;
58 target_range.zip(profile_range)
59 }
60}
61
62#[derive(Default, Clone)]
63pub struct CloudBoundGroup {
64 pub bounds: Vec<CloudBound>,
65 pub target_length: usize,
66 pub profile_length: usize,
67 pub size: usize,
68 pub min_anti_diagonal_idx: usize,
69 pub max_anti_diagonal_idx: usize,
70}
71
72impl CloudBoundGroup {
73 pub fn new(target_length: usize, profile_length: usize) -> Self {
74 let size = target_length + profile_length + 1;
75 Self {
76 bounds: vec![CloudBound::default(); size],
77 target_length,
78 profile_length,
79 size,
80 min_anti_diagonal_idx: size,
81 max_anti_diagonal_idx: 0,
82 }
83 }
84
85 pub fn resize(&mut self, new_size: usize) {
86 self.bounds.resize(new_size, CloudBound::default());
87 self.size = new_size;
88 }
89
90 pub fn reuse(&mut self, target_length: usize, profile_length: usize) {
91 let new_size = target_length + profile_length + 1;
92 if new_size > self.size {
93 self.resize(new_size);
94 }
95
96 self.min_anti_diagonal_idx = new_size;
97 self.max_anti_diagonal_idx = 0;
98
99 self.target_length = target_length;
100 self.profile_length = profile_length;
101
102 for bound in self.bounds.iter_mut() {
104 bound.left_target_idx = 0;
105 bound.left_profile_idx = 1;
106 bound.right_target_idx = 1;
107 bound.right_profile_idx = 0;
108 }
109 }
110
111 pub fn set(
112 &mut self,
113 anti_diagonal_idx: usize,
115 left_target_idx: usize,
116 left_profile_idx: usize,
117 right_target_idx: usize,
118 right_profile_idx: usize,
119 ) {
120 self.min_anti_diagonal_idx = self.min_anti_diagonal_idx.min(anti_diagonal_idx);
122 self.max_anti_diagonal_idx = self.max_anti_diagonal_idx.max(anti_diagonal_idx);
123
124 debug_assert_eq!(
125 left_target_idx + left_profile_idx,
126 right_target_idx + right_profile_idx
127 );
128
129 let bound = &mut self.bounds[anti_diagonal_idx];
130 bound.left_target_idx = left_target_idx;
131 bound.left_profile_idx = left_profile_idx;
132 bound.right_target_idx = right_target_idx;
133 bound.right_profile_idx = right_profile_idx;
134 }
135
136 pub fn get(&self, idx: usize) -> &CloudBound {
137 &self.bounds[idx]
138 }
139
140 pub fn get_mut(&mut self, idx: usize) -> &mut CloudBound {
141 &mut self.bounds[idx]
142 }
143
144 pub fn get_first(&self) -> &CloudBound {
145 self.get(self.min_anti_diagonal_idx)
146 }
147
148 pub fn get_last(&self) -> &CloudBound {
149 self.get(self.max_anti_diagonal_idx)
150 }
151
152 pub fn valid(&self) -> bool {
153 for idx in self.min_anti_diagonal_idx..=self.max_anti_diagonal_idx {
154 let bound = &self.bounds[idx];
155 if bound.was_pruned() {
156 return false;
157 }
158 }
159 true
160 }
161
162 pub fn cloud_size(&self) -> usize {
164 let mut cloud_size = 0usize;
165 for bound in self.bounds[self.min_anti_diagonal_idx..=self.max_anti_diagonal_idx].iter() {
166 cloud_size += bound.left_target_idx - bound.right_target_idx;
167 }
168 cloud_size
169 }
170
171 pub fn num_anti_diagonals(&self) -> usize {
173 self.max_anti_diagonal_idx - self.min_anti_diagonal_idx + 1
174 }
175
176 pub fn trim_wings(&mut self) {
180 for anti_diagonal_idx in self.min_anti_diagonal_idx + 1..=self.max_anti_diagonal_idx {
181 let previous_bound = self.get(anti_diagonal_idx - 1);
182 let current_bound = self.get(anti_diagonal_idx);
183
184 let right_distance = previous_bound
193 .right_target_idx
194 .saturating_sub(current_bound.right_target_idx);
195
196 let left_distance =
205 (previous_bound.left_profile_idx).saturating_sub(current_bound.left_profile_idx);
206
207 self.set(
208 anti_diagonal_idx,
209 current_bound.left_target_idx - left_distance,
210 current_bound.left_profile_idx + left_distance,
211 current_bound.right_target_idx + right_distance,
212 current_bound.right_profile_idx - right_distance,
213 )
214 }
215
216 for anti_diagonal_idx in (self.min_anti_diagonal_idx..self.max_anti_diagonal_idx).rev() {
217 let previous_bound = self.get(anti_diagonal_idx + 1);
218 let current_bound = self.get(anti_diagonal_idx);
219
220 let right_distance = current_bound
229 .right_profile_idx
230 .saturating_sub(previous_bound.right_profile_idx);
231
232 let left_distance =
241 (current_bound.left_target_idx).saturating_sub(previous_bound.left_target_idx);
242
243 self.set(
244 anti_diagonal_idx,
245 current_bound.left_target_idx - left_distance,
246 current_bound.left_profile_idx + left_distance,
247 current_bound.right_target_idx + right_distance,
248 current_bound.right_profile_idx - right_distance,
249 )
250 }
251 }
252
253 pub fn bound_block(&mut self, target_start: usize, profile_start: usize, size: usize) {
257 let idx = target_start + profile_start;
258 for i in 0..size {
259 self.set(
260 idx + i,
261 target_start + i,
262 profile_start,
263 target_start,
264 profile_start + i,
265 );
266 }
267 let idx = target_start + profile_start + size;
268 for i in 0..=size {
269 self.set(
270 idx + i,
271 target_start + size,
272 profile_start + i,
273 target_start + i,
274 profile_start + size,
275 );
276 }
277 }
278
279 pub fn bounds(&self) -> &[CloudBound] {
280 &self.bounds[self.min_anti_diagonal_idx..=self.max_anti_diagonal_idx]
281 }
282
283 pub fn join_bounds(forward_bounds: &mut CloudBoundGroup, backward_bounds: &CloudBoundGroup) {
284 if forward_bounds.max_anti_diagonal_idx < backward_bounds.min_anti_diagonal_idx {
286 let last_forward = forward_bounds.get_last();
305 let forward_x = ((last_forward.right_profile_idx as f32
306 + last_forward.left_profile_idx as f32)
307 / 2.0)
308 .floor();
309 let forward_y = last_forward.anti_diagonal_idx() as f32 - forward_x;
310
311 let first_backward = backward_bounds.get_first();
312 let backward_x = ((first_backward.right_profile_idx as f32
313 + first_backward.left_profile_idx as f32)
314 / 2.0)
315 .ceil();
316 let backward_y = first_backward.anti_diagonal_idx() as f32 - backward_x;
317
318 let slope = (backward_y - forward_y) / (backward_x - forward_x);
319 let intercept = forward_y - slope * forward_x;
320 let line_equation = |x: f32| slope * x + intercept;
321
322 let cloud_size_sum = forward_bounds.cloud_size() + backward_bounds.cloud_size();
323 let num_anti_diagonals =
324 forward_bounds.num_anti_diagonals() + backward_bounds.num_anti_diagonals();
325 let avg_anti_diagonal_length = cloud_size_sum / num_anti_diagonals;
327
328 let bound_fn = |center_profile_idx: usize| {
332 let center_target_idx = line_equation(center_profile_idx as f32).round() as usize;
333 let anti_diagonal_idx = center_profile_idx + center_target_idx;
334
335 let left_profile_idx = center_profile_idx - avg_anti_diagonal_length / 2;
338 let right_profile_idx = center_profile_idx + avg_anti_diagonal_length / 2;
339 let left_target_idx = anti_diagonal_idx - left_profile_idx;
340 let right_target_idx = anti_diagonal_idx - right_profile_idx;
341 CloudBound {
342 left_target_idx,
343 left_profile_idx,
344 right_target_idx,
345 right_profile_idx,
346 }
347 };
348
349 let first_bound = bound_fn(forward_x as usize);
350 forward_bounds.set(
351 first_bound.anti_diagonal_idx() + 1,
352 first_bound.left_target_idx,
353 first_bound.left_profile_idx + 1,
354 first_bound.right_target_idx + 1,
355 first_bound.right_profile_idx,
356 );
357
358 let profile_start = forward_x as usize + 1;
368 let profile_end = backward_x as usize - 1;
369 for center_profile_idx in profile_start..=profile_end {
370 let bound = bound_fn(center_profile_idx);
371
372 forward_bounds.set(
373 bound.anti_diagonal_idx(),
374 bound.left_target_idx,
375 bound.left_profile_idx,
376 bound.right_target_idx,
377 bound.right_profile_idx,
378 );
379
380 forward_bounds.set(
381 bound.anti_diagonal_idx() + 1,
382 bound.left_target_idx,
383 bound.left_profile_idx + 1,
384 bound.right_target_idx + 1,
385 bound.right_profile_idx,
386 );
387 }
388
389 for anti_diagonal_idx in
391 backward_bounds.min_anti_diagonal_idx..=backward_bounds.max_anti_diagonal_idx
392 {
393 let bound = backward_bounds.get(anti_diagonal_idx);
394 forward_bounds.set(
395 anti_diagonal_idx,
396 bound.left_target_idx,
397 bound.left_profile_idx,
398 bound.right_target_idx,
399 bound.right_profile_idx,
400 )
401 }
402 } else {
403 let start_idx = forward_bounds
406 .min_anti_diagonal_idx
407 .min(backward_bounds.min_anti_diagonal_idx);
408
409 let end_idx = forward_bounds
410 .max_anti_diagonal_idx
411 .max(backward_bounds.max_anti_diagonal_idx);
412
413 forward_bounds.min_anti_diagonal_idx = start_idx;
414 forward_bounds.max_anti_diagonal_idx = end_idx;
415 let forward_slice = &mut forward_bounds.bounds[start_idx..=end_idx];
416 let backward_slice = &backward_bounds.bounds[start_idx..=end_idx];
417
418 for (forward_bound, backward_bound) in forward_slice.iter_mut().zip(backward_slice) {
419 if forward_bound.was_pruned() {
420 forward_bound.left_target_idx = backward_bound.left_target_idx;
422 forward_bound.left_profile_idx = backward_bound.left_profile_idx;
423 forward_bound.right_target_idx = backward_bound.right_target_idx;
424 forward_bound.right_profile_idx = backward_bound.right_profile_idx;
425 } else if backward_bound.was_pruned() {
426 continue;
429 }
430
431 debug_assert_eq!(
432 forward_bound.anti_diagonal_idx(),
433 backward_bound.anti_diagonal_idx()
434 );
435
436 forward_bound.left_target_idx = forward_bound
438 .left_target_idx
439 .max(backward_bound.left_target_idx);
440
441 forward_bound.left_profile_idx = forward_bound
442 .left_profile_idx
443 .min(backward_bound.left_profile_idx);
444
445 forward_bound.right_target_idx = forward_bound
446 .right_target_idx
447 .min(backward_bound.right_target_idx);
448
449 forward_bound.right_profile_idx = forward_bound
450 .right_profile_idx
451 .max(backward_bound.right_profile_idx);
452 }
453 }
454 }
455}