1use crate::geometry::{Boundary, Geometry};
4use crate::result::SolveResult;
5use crate::Result;
6
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
12#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
13pub enum Strategy {
14 #[default]
16 BottomLeftFill,
17 NfpGuided,
19 GeneticAlgorithm,
21 Brkga,
23 SimulatedAnnealing,
25 ExtremePoint,
27 Gdrr,
29 Alns,
31 MilpExact,
33 HybridExact,
35}
36
37#[derive(Debug, Clone)]
39#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
40pub struct Config {
41 pub strategy: Strategy,
43
44 pub spacing: f64,
46
47 pub margin: f64,
49
50 pub time_limit_ms: u64,
52
53 pub target_utilization: Option<f64>,
55
56 pub threads: usize,
58
59 pub population_size: usize,
62
63 pub max_generations: u32,
65
66 pub crossover_rate: f64,
68
69 pub mutation_rate: f64,
71
72 pub elite_count: usize,
74}
75
76impl Default for Config {
77 fn default() -> Self {
78 Self {
79 strategy: Strategy::default(),
80 spacing: 0.0,
81 margin: 0.0,
82 time_limit_ms: 30000,
83 target_utilization: None,
84 threads: 0,
85 population_size: 100,
86 max_generations: 500,
87 crossover_rate: 0.85,
88 mutation_rate: 0.05,
89 elite_count: 5,
90 }
91 }
92}
93
94impl Config {
95 pub fn new() -> Self {
97 Self::default()
98 }
99
100 pub fn with_strategy(mut self, strategy: Strategy) -> Self {
102 self.strategy = strategy;
103 self
104 }
105
106 pub fn with_spacing(mut self, spacing: f64) -> Self {
108 self.spacing = spacing;
109 self
110 }
111
112 pub fn with_margin(mut self, margin: f64) -> Self {
114 self.margin = margin;
115 self
116 }
117
118 pub fn with_time_limit(mut self, ms: u64) -> Self {
120 self.time_limit_ms = ms;
121 self
122 }
123
124 pub fn with_target_utilization(mut self, util: f64) -> Self {
126 self.target_utilization = Some(util.clamp(0.0, 1.0));
127 self
128 }
129}
130
131pub type ProgressCallback = Box<dyn Fn(ProgressInfo) + Send + Sync>;
133
134#[derive(Debug, Clone, Default)]
136pub struct ProgressInfo {
137 pub iteration: u32,
139 pub total_iterations: u32,
141 pub utilization: f64,
143 pub best_fitness: f64,
145 pub items_placed: usize,
147 pub total_items: usize,
149 pub elapsed_ms: u64,
151 pub phase: String,
153 pub running: bool,
155}
156
157impl ProgressInfo {
158 pub fn new() -> Self {
160 Self {
161 running: true,
162 ..Default::default()
163 }
164 }
165
166 pub fn with_iteration(mut self, current: u32, total: u32) -> Self {
168 self.iteration = current;
169 self.total_iterations = total;
170 self
171 }
172
173 pub fn with_utilization(mut self, utilization: f64) -> Self {
175 self.utilization = utilization;
176 self
177 }
178
179 pub fn with_fitness(mut self, fitness: f64) -> Self {
181 self.best_fitness = fitness;
182 self
183 }
184
185 pub fn with_items(mut self, placed: usize, total: usize) -> Self {
187 self.items_placed = placed;
188 self.total_items = total;
189 self
190 }
191
192 pub fn with_elapsed(mut self, elapsed_ms: u64) -> Self {
194 self.elapsed_ms = elapsed_ms;
195 self
196 }
197
198 pub fn with_phase(mut self, phase: impl Into<String>) -> Self {
200 self.phase = phase.into();
201 self
202 }
203
204 pub fn finished(mut self) -> Self {
206 self.running = false;
207 self
208 }
209
210 pub fn progress_percent(&self) -> f64 {
212 if self.total_iterations > 0 {
213 self.iteration as f64 / self.total_iterations as f64
214 } else {
215 0.0
216 }
217 }
218}
219
220pub trait Solver {
222 type Geometry: Geometry;
224 type Boundary: Boundary;
226 type Scalar;
228
229 fn solve(
231 &self,
232 geometries: &[Self::Geometry],
233 boundary: &Self::Boundary,
234 ) -> Result<SolveResult<Self::Scalar>>;
235
236 fn solve_with_progress(
238 &self,
239 geometries: &[Self::Geometry],
240 boundary: &Self::Boundary,
241 callback: ProgressCallback,
242 ) -> Result<SolveResult<Self::Scalar>>;
243
244 fn cancel(&self);
246}