jagua_rs/probs/spp/entities/
problem.rs1use crate::entities::{Instance, Layout, PItemKey};
2use crate::geometry::DTransformation;
3use crate::probs::spp::entities::strip::Strip;
4use crate::probs::spp::entities::{SPInstance, SPSolution};
5use crate::probs::spp::util::assertions::problem_matches_solution;
6use itertools::Itertools;
7use std::time::Instant;
8
9#[derive(Clone)]
11pub struct SPProblem {
12 pub instance: SPInstance,
13 pub strip: Strip,
14 pub layout: Layout,
15 pub item_demand_qtys: Vec<usize>,
16}
17
18impl SPProblem {
19 pub fn new(instance: SPInstance) -> Self {
20 let item_demand_qtys = instance.items.iter().map(|(_, qty)| *qty).collect_vec();
21 let strip = instance.base_strip;
22 let layout = Layout::new(strip.into());
23
24 Self {
25 instance,
26 strip,
27 layout,
28 item_demand_qtys,
29 }
30 }
31
32 pub fn change_strip_width(&mut self, new_width: f32) {
34 self.strip.set_width(new_width);
35 self.layout.swap_container(self.strip.into());
36 }
37
38 pub fn fit_strip(&mut self) {
40 let feasible_before = self.layout.is_feasible();
41
42 let item_x_max = self
44 .layout
45 .placed_items
46 .values()
47 .map(|pi| pi.shape.bbox.x_max)
48 .max_by(|a, b| a.partial_cmp(b).unwrap())
49 .unwrap()
50 * 1.00001;
51
52 let fitted_width = item_x_max + self.strip.shape_modify_config.offset.unwrap_or(0.0);
54
55 self.change_strip_width(fitted_width);
56 debug_assert!(feasible_before == self.layout.is_feasible());
57 }
58
59 pub fn place_item(&mut self, placement: SPPlacement) -> PItemKey {
61 self.register_included_item(placement.item_id);
62 let item = self.instance.item(placement.item_id);
63
64 self.layout.place_item(item, placement.d_transf)
65 }
66
67 pub fn remove_item(&mut self, pkey: PItemKey, commit_instant: bool) -> SPPlacement {
70 let pi = self.layout.remove_item(pkey, commit_instant);
71 self.deregister_included_item(pi.item_id);
72
73 SPPlacement {
74 item_id: pi.item_id,
75 d_transf: pi.d_transf,
76 }
77 }
78
79 pub fn save(&mut self) -> SPSolution {
81 let solution = SPSolution {
82 layout_snapshot: self.layout.save(),
83 strip: self.strip,
84 time_stamp: Instant::now(),
85 };
86
87 debug_assert!(problem_matches_solution(self, &solution));
88
89 solution
90 }
91
92 pub fn restore(&mut self, solution: &SPSolution) {
94 if self.strip == solution.strip {
95 self.layout.restore(&solution.layout_snapshot);
97 } else {
98 self.layout = Layout::from_snapshot(&solution.layout_snapshot);
100 self.strip = solution.strip;
101 }
102
103 {
105 self.item_demand_qtys
106 .iter_mut()
107 .enumerate()
108 .for_each(|(id, qty)| *qty = self.instance.item_qty(id));
109
110 self.layout
111 .placed_items()
112 .iter()
113 .for_each(|(_, pi)| self.item_demand_qtys[pi.item_id] -= 1);
114 }
115 debug_assert!(problem_matches_solution(self, solution));
116 }
117
118 fn register_included_item(&mut self, item_id: usize) {
119 self.item_demand_qtys[item_id] -= 1;
120 }
121
122 fn deregister_included_item(&mut self, item_id: usize) {
123 self.item_demand_qtys[item_id] += 1;
124 }
125
126 pub fn density(&self) -> f32 {
127 self.layout.density(&self.instance)
128 }
129
130 pub fn strip_width(&self) -> f32 {
131 self.strip.width
132 }
133}
134
135#[derive(Debug, Clone, Copy)]
137pub struct SPPlacement {
138 pub item_id: usize,
139 pub d_transf: DTransformation,
140}