scirs2_interpolate/bspline_modules/
types.rs1use scirs2_core::ndarray::{Array1, Array2};
7use scirs2_core::numeric::{Float, FromPrimitive, Zero};
8use std::cell::RefCell;
9use std::fmt::{Debug, Display};
10use std::ops::{Add, Div, Mul, Sub};
11
12#[derive(Debug, Clone, Copy, PartialEq, Default)]
14pub enum ExtrapolateMode {
15 #[default]
17 Extrapolate,
18 Periodic,
20 Nan,
22 Error,
24}
25
26#[derive(Debug)]
29pub struct BSplineWorkspace<T> {
30 pub(crate) coeffs: RefCell<Array1<T>>,
32 pub(crate) poly_buf: RefCell<Array1<T>>,
34 pub(crate) basis_buf: RefCell<Array1<T>>,
36 pub(crate) matrix_buf: RefCell<Array2<T>>,
38 pub(crate) memory_stats: RefCell<WorkspaceMemoryStats>,
40}
41
42#[derive(Debug, Clone, Default)]
44pub struct WorkspaceMemoryStats {
45 pub peak_memory_bytes: usize,
47 pub current_memory_bytes: usize,
49 pub allocations_avoided: usize,
51 pub resize_count: usize,
53 pub evaluation_count: usize,
55}
56
57impl WorkspaceMemoryStats {
58 pub fn efficiency_ratio(&self) -> f64 {
60 if self.evaluation_count == 0 {
61 0.0
62 } else {
63 self.allocations_avoided as f64 / self.evaluation_count as f64
64 }
65 }
66
67 pub fn peak_memory_mb(&self) -> f64 {
69 self.peak_memory_bytes as f64 / (1024.0 * 1024.0)
70 }
71
72 pub fn update_memory_usage(&mut self, current_bytes: usize) {
74 self.current_memory_bytes = current_bytes;
75 if current_bytes > self.peak_memory_bytes {
76 self.peak_memory_bytes = current_bytes;
77 }
78 }
79
80 pub fn record_allocation_avoided(&mut self) {
82 self.allocations_avoided += 1;
83 }
84
85 pub fn record_resize(&mut self) {
87 self.resize_count += 1;
88 }
89
90 pub fn record_evaluation(&mut self) {
92 self.evaluation_count += 1;
93 }
94
95 pub fn reset(&mut self) {
97 self.peak_memory_bytes = 0;
98 self.current_memory_bytes = 0;
99 self.allocations_avoided = 0;
100 self.resize_count = 0;
101 self.evaluation_count = 0;
102 }
103
104 pub fn estimated_memory_saved_mb(&self, avg_allocation_size_bytes: usize) -> f64 {
106 (self.allocations_avoided * avg_allocation_size_bytes) as f64 / (1024.0 * 1024.0)
107 }
108}
109
110impl<T> BSplineWorkspace<T>
111where
112 T: Float + FromPrimitive + Zero + Clone,
113{
114 pub fn new() -> Self {
116 Self::with_capacity(16, 16)
117 }
118
119 pub fn with_capacity(array_capacity: usize, matrix_capacity: usize) -> Self {
121 Self {
122 coeffs: RefCell::new(Array1::zeros(array_capacity)),
123 poly_buf: RefCell::new(Array1::zeros(array_capacity)),
124 basis_buf: RefCell::new(Array1::zeros(array_capacity)),
125 matrix_buf: RefCell::new(Array2::zeros((matrix_capacity, matrix_capacity))),
126 memory_stats: RefCell::new(WorkspaceMemoryStats::default()),
127 }
128 }
129
130 pub fn current_memory_bytes(&self) -> usize {
132 self.memory_stats.borrow().current_memory_bytes
133 }
134
135 pub fn peak_memory_bytes(&self) -> usize {
137 self.memory_stats.borrow().peak_memory_bytes
138 }
139
140 pub fn efficiency_ratio(&self) -> f64 {
142 self.memory_stats.borrow().efficiency_ratio()
143 }
144
145 pub fn evaluation_count(&self) -> usize {
147 self.memory_stats.borrow().evaluation_count
148 }
149
150 pub fn allocations_avoided(&self) -> usize {
152 self.memory_stats.borrow().allocations_avoided
153 }
154
155 pub fn get_statistics(&self) -> WorkspaceMemoryStats {
157 self.memory_stats.borrow().clone()
158 }
159
160 pub fn reset_statistics(&self) {
162 self.memory_stats.borrow_mut().reset();
163 }
164
165 pub fn ensure_coeffs_capacity(&self, capacity: usize) {
167 let mut coeffs = self.coeffs.borrow_mut();
168 if coeffs.len() < capacity {
169 *coeffs = Array1::zeros(capacity);
170 self.memory_stats.borrow_mut().record_resize();
171 } else {
172 self.memory_stats.borrow_mut().record_allocation_avoided();
173 }
174 }
175
176 pub fn ensure_poly_capacity(&self, capacity: usize) {
178 let mut poly_buf = self.poly_buf.borrow_mut();
179 if poly_buf.len() < capacity {
180 *poly_buf = Array1::zeros(capacity);
181 self.memory_stats.borrow_mut().record_resize();
182 } else {
183 self.memory_stats.borrow_mut().record_allocation_avoided();
184 }
185 }
186
187 pub fn ensure_basis_capacity(&self, capacity: usize) {
189 let mut basis_buf = self.basis_buf.borrow_mut();
190 if basis_buf.len() < capacity {
191 *basis_buf = Array1::zeros(capacity);
192 self.memory_stats.borrow_mut().record_resize();
193 } else {
194 self.memory_stats.borrow_mut().record_allocation_avoided();
195 }
196 }
197
198 pub fn ensure_matrix_capacity(&self, rows: usize, cols: usize) {
200 let mut matrix_buf = self.matrix_buf.borrow_mut();
201 if matrix_buf.nrows() < rows || matrix_buf.ncols() < cols {
202 *matrix_buf = Array2::zeros((rows, cols));
203 self.memory_stats.borrow_mut().record_resize();
204 } else {
205 self.memory_stats.borrow_mut().record_allocation_avoided();
206 }
207 }
208
209 pub fn record_evaluation(&self) {
211 self.memory_stats.borrow_mut().record_evaluation();
212
213 let coeffs_size = self.coeffs.borrow().len() * std::mem::size_of::<T>();
215 let poly_size = self.poly_buf.borrow().len() * std::mem::size_of::<T>();
216 let basis_size = self.basis_buf.borrow().len() * std::mem::size_of::<T>();
217 let matrix_size = {
218 let matrix = self.matrix_buf.borrow();
219 matrix.nrows() * matrix.ncols() * std::mem::size_of::<T>()
220 };
221
222 let total_size = coeffs_size + poly_size + basis_size + matrix_size;
223 self.memory_stats
224 .borrow_mut()
225 .update_memory_usage(total_size);
226 }
227
228 pub fn clear(&self) {
230 *self.coeffs.borrow_mut() = Array1::zeros(1);
231 *self.poly_buf.borrow_mut() = Array1::zeros(1);
232 *self.basis_buf.borrow_mut() = Array1::zeros(1);
233 *self.matrix_buf.borrow_mut() = Array2::zeros((1, 1));
234 }
235
236 pub fn memory_report(&self) -> String {
238 let stats = self.get_statistics();
239 format!(
240 "BSpline Workspace Memory Report:\n\
241 Peak Memory: {:.2} MB\n\
242 Current Memory: {:.2} MB\n\
243 Evaluations: {}\n\
244 Allocations Avoided: {}\n\
245 Efficiency Ratio: {:.2}%\n\
246 Resizes: {}",
247 stats.peak_memory_mb(),
248 stats.current_memory_bytes as f64 / (1024.0 * 1024.0),
249 stats.evaluation_count,
250 stats.allocations_avoided,
251 stats.efficiency_ratio() * 100.0,
252 stats.resize_count
253 )
254 }
255}
256
257impl<T> Default for BSplineWorkspace<T>
258where
259 T: Float + FromPrimitive + Zero + Clone,
260{
261 fn default() -> Self {
262 Self::new()
263 }
264}
265
266impl<T> Clone for BSplineWorkspace<T>
267where
268 T: Float + FromPrimitive + Zero + Clone,
269{
270 fn clone(&self) -> Self {
271 Self {
272 coeffs: RefCell::new(self.coeffs.borrow().clone()),
273 poly_buf: RefCell::new(self.poly_buf.borrow().clone()),
274 basis_buf: RefCell::new(self.basis_buf.borrow().clone()),
275 matrix_buf: RefCell::new(self.matrix_buf.borrow().clone()),
276 memory_stats: RefCell::new(self.memory_stats.borrow().clone()),
277 }
278 }
279}
280
281pub struct BSplineWorkspaceBuilder<T> {
283 array_capacity: usize,
284 matrix_capacity: usize,
285 _phantom: std::marker::PhantomData<T>,
286}
287
288impl<T> Default for BSplineWorkspaceBuilder<T> {
289 fn default() -> Self {
290 Self {
291 array_capacity: 16,
292 matrix_capacity: 16,
293 _phantom: std::marker::PhantomData,
294 }
295 }
296}
297
298impl<T> BSplineWorkspaceBuilder<T>
299where
300 T: Float + FromPrimitive + Zero + Clone,
301{
302 pub fn new() -> Self {
304 Self::default()
305 }
306
307 pub fn with_array_capacity(mut self, capacity: usize) -> Self {
309 self.array_capacity = capacity;
310 self
311 }
312
313 pub fn with_matrix_capacity(mut self, capacity: usize) -> Self {
315 self.matrix_capacity = capacity;
316 self
317 }
318
319 pub fn build(self) -> BSplineWorkspace<T> {
321 BSplineWorkspace::with_capacity(self.array_capacity, self.matrix_capacity)
322 }
323}
324
325pub trait WorkspaceProvider<T> {
327 fn get_workspace(&self) -> &BSplineWorkspace<T>;
329
330 fn is_workspace_enabled(&self) -> bool;
332}
333
334#[derive(Debug, Clone)]
336pub struct WorkspaceConfig {
337 pub initial_array_capacity: usize,
339 pub initial_matrix_capacity: usize,
341 pub max_memory_mb: f64,
343 pub auto_memory_management: bool,
345}
346
347impl Default for WorkspaceConfig {
348 fn default() -> Self {
349 Self {
350 initial_array_capacity: 16,
351 initial_matrix_capacity: 16,
352 max_memory_mb: 100.0, auto_memory_management: true,
354 }
355 }
356}