sklears_core/macros.rs
1/// Advanced macro definitions for sklears-core
2///
3/// This module provides powerful declarative macros for common patterns in machine learning code,
4/// validation, builder patterns, code generation utilities, and advanced ML algorithm scaffolding.
5///
6/// ## Key Features
7/// - **Dataset Creation**: Quick dataset macros for testing and prototyping
8/// - **Type System Helpers**: Trait bound definitions and complex type constraints
9/// - **Configuration Management**: Parameter mapping and validation macros
10/// - **Code Generation**: Boilerplate reduction for ML algorithms
11/// - **Testing Infrastructure**: Comprehensive test suite generation
12/// - **Performance Optimizations**: SIMD and parallel processing macros
13///
14/// Creates a quick dataset for testing and demonstration purposes
15///
16/// # Examples
17/// ```ignore
18/// use sklears_core::quick_dataset;
19/// // SciRS2 Policy: Using scirs2_core::ndarray (COMPLIANT)
20/// use scirs2_core::ndarray::{arr1, arr2};
21///
22/// let dataset = quick_dataset!(
23/// data: arr2(&[[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]),
24/// target: arr1(&[0.0, 1.0, 0.0])
25/// );
26/// ```
27#[macro_export]
28macro_rules! quick_dataset {
29 (data: $data:expr, target: $target:expr) => {
30 $crate::dataset::Dataset::builder()
31 .data($data)
32 .target($target)
33 .build()
34 };
35 (data: $data:expr) => {
36 $crate::dataset::Dataset::builder().data($data).build()
37 };
38}
39
40/// Helper macro for creating trait bound combinations commonly used in ML
41///
42/// # Examples
43/// ```rust,ignore
44/// use sklears_core::define_ml_float_bounds;
45///
46/// define_ml_float_bounds!(FloatBounds);
47///
48/// fn process_data<T: FloatBounds>(data: T) -> T {
49/// data
50/// }
51/// ```
52#[macro_export]
53macro_rules! define_ml_float_bounds {
54 ($name:ident) => {
55 trait $name:
56 Float + NumCast + Copy + Clone + Send + Sync + std::fmt::Debug
57 {
58 }
59 impl<T> $name for T where
60 T: Float
61 + NumCast
62 + Copy
63 + Clone
64 + Send
65 + Sync
66 + std::fmt::Debug
67 {
68 }
69 };
70}
71
72/// Creates a simple parameter mapping for algorithm configurations
73///
74/// # Examples
75/// ```
76/// use sklears_core::parameter_map;
77///
78/// let params = parameter_map! {
79/// alpha: 1.0,
80/// max_iter: 1000.0,
81/// tol: 1e-6
82/// };
83/// ```
84#[macro_export]
85macro_rules! parameter_map {
86 ($($param:ident: $value:expr),* $(,)?) => {
87 {
88 let mut params = std::collections::HashMap::new();
89 $(
90 params.insert(stringify!($param).to_string(), $value);
91 )*
92 params
93 }
94 };
95}
96
97/// Helper macro for creating default trait implementations
98///
99/// # Examples
100/// ```
101/// use sklears_core::impl_default_config;
102///
103/// struct MyConfig {
104/// alpha: f64,
105/// max_iter: usize,
106/// }
107///
108/// impl_default_config! {
109/// MyConfig {
110/// alpha: 1.0,
111/// max_iter: 100,
112/// }
113/// }
114/// ```
115#[macro_export]
116macro_rules! impl_default_config {
117 ($struct_name:ident { $($field:ident: $default:expr),* $(,)? }) => {
118 impl Default for $struct_name {
119 fn default() -> Self {
120 Self {
121 $($field: $default,)*
122 }
123 }
124 }
125 };
126}
127
128/// Implements standard machine learning traits for an estimator
129///
130/// This macro generates boilerplate implementations for common ML traits
131#[macro_export]
132macro_rules! impl_ml_traits {
133 ($estimator:ident) => {
134 impl $crate::traits::Estimator for $estimator {
135 type Config = ();
136
137 fn name(&self) -> &str {
138 stringify!($estimator)
139 }
140 }
141 };
142 ($estimator:ident, config: $config:ty) => {
143 impl $crate::traits::Estimator for $estimator {
144 type Config = $config;
145
146 fn name(&self) -> &str {
147 stringify!($estimator)
148 }
149 }
150 };
151}
152
153/// Creates a test suite for an estimator implementation
154///
155/// This generates comprehensive tests including property-based testing
156#[macro_export]
157macro_rules! estimator_test_suite {
158 ($estimator:ident) => {
159 #[allow(non_snake_case)]
160 #[cfg(test)]
161 mod tests {
162 use super::*;
163 use $crate::test_utilities::*;
164
165 #[test]
166 fn test_estimator_creation() {
167 let estimator = $estimator::new();
168 assert_eq!(estimator.name(), stringify!($estimator));
169 }
170
171 #[test]
172 fn test_estimator_clone() {
173 let estimator = $estimator::new();
174 let cloned = estimator.clone();
175 assert_eq!(estimator.name(), cloned.name());
176 }
177 }
178 };
179}
180
181/// Advanced macro for creating ML estimators with builder pattern and validation
182///
183/// This macro generates comprehensive boilerplate code for ML estimators including:
184/// - Builder pattern implementation
185/// - Parameter validation
186/// - Standard trait implementations
187/// - Error handling
188///
189/// # Examples
190/// ```rust,ignore
191/// use sklears_core::define_estimator;
192///
193/// define_estimator! {
194/// name: LinearRegression,
195/// config: LinearRegressionConfig {
196/// fit_intercept: bool = true,
197/// regularization: f64 = 0.0
198/// },
199/// features: [Fit, Predict],
200/// validation: {
201/// regularization >= 0.0
202/// }
203/// }
204/// ```
205#[macro_export]
206macro_rules! define_estimator {
207 (
208 name: $name:ident,
209 config: $config:ident {
210 $(
211 $field:ident: $type:ty = $default:expr
212 ),* $(,)?
213 },
214 features: [$($trait:ident),* $(,)?],
215 validation: {
216 $(
217 $validation:expr
218 ),* $(,)?
219 }
220 ) => {
221 /// Auto-generated configuration struct
222 #[derive(Debug, Clone, PartialEq)]
223 pub struct $config {
224 $(
225 pub $field: $type,
226 )*
227 }
228
229 impl Default for $config {
230 fn default() -> Self {
231 Self {
232 $(
233 $field: $default,
234 )*
235 }
236 }
237 }
238
239 /// Auto-generated builder struct
240 #[derive(Debug, Clone)]
241 pub struct $name<State = $crate::types::const_generic::FixedFeatures<f64, 1>> {
242 config: $config,
243 _state: std::marker::PhantomData<State>,
244 }
245
246 impl Default for $name {
247 fn default() -> Self {
248 Self::new()
249 }
250 }
251
252 impl $name {
253 /// Create a new estimator with default configuration
254 pub fn new() -> Self {
255 Self {
256 config: $config::default(),
257 _state: std::marker::PhantomData,
258 }
259 }
260
261 /// Create a builder for configuring the estimator
262 pub fn builder() -> $name<()> {
263 $name {
264 config: $config::default(),
265 _state: std::marker::PhantomData,
266 }
267 }
268
269 $(
270 /// Set parameter
271 pub fn $field(mut self, value: $type) -> Self {
272 self.config.$field = value;
273 self
274 }
275 )*
276
277 /// Validate the configuration
278 pub fn validate(&self) -> $crate::error::Result<()> {
279 $(
280 if !($validation) {
281 return Err($crate::error::SklearsError::InvalidInput(
282 format!("Validation failed: {}", stringify!($validation))
283 ));
284 }
285 )*
286 Ok(())
287 }
288
289 /// Get the estimator name
290 pub fn name(&self) -> &'static str {
291 stringify!($name)
292 }
293 }
294
295 impl $crate::traits::Estimator for $name {
296 type Config = $config;
297
298 fn name(&self) -> &'static str {
299 stringify!($name)
300 }
301
302 fn config(&self) -> &Self::Config {
303 &self.config
304 }
305 }
306
307 // Generate test module (simplified to avoid paste dependency)
308 #[allow(non_snake_case)]
309#[cfg(test)]
310 mod tests {
311 use super::*;
312
313 #[test]
314 fn test_default_creation() {
315 let estimator = $name::default();
316 assert_eq!(estimator.name(), stringify!($name));
317 estimator.validate().unwrap();
318 }
319
320 #[test]
321 fn test_builder_pattern() {
322 let estimator = $name::builder();
323 estimator.validate().unwrap();
324 }
325 }
326 };
327}
328
329/// Macro for creating type-safe validation rules
330///
331/// # Examples
332/// ```rust,ignore
333/// use sklears_core::validation_rules;
334///
335/// validation_rules! {
336/// positive: |x: f64| x > 0.0,
337/// probability: |x: f64| x >= 0.0 && x <= 1.0,
338/// non_empty: |s: &str| !s.is_empty()
339/// }
340/// ```
341#[macro_export]
342macro_rules! validation_rules {
343 ($(
344 $rule_name:ident: |$param:ident: $type:ty| $condition:expr
345 ),* $(,)?) => {
346 $(
347 pub fn $rule_name($param: $type) -> bool {
348 $condition
349 }
350 )*
351 };
352}
353
354// ========== ADVANCED MACRO SYSTEM ENHANCEMENTS ==========
355
356/// Creates a complete ML algorithm with all necessary boilerplate
357///
358/// This macro generates:
359/// - Configuration struct with validation
360/// - State management (trained/untrained)
361/// - Builder pattern implementation
362/// - Core trait implementations
363/// - Basic test suite
364/// - Documentation templates
365///
366/// # Examples
367/// ```rust,ignore
368/// use sklears_core::define_ml_algorithm;
369///
370/// define_ml_algorithm! {
371/// name: LinearRegression,
372/// config: {
373/// fit_intercept: bool = true,
374/// alpha: f64 = 1.0 => validate(|x| x >= 0.0),
375/// max_iter: usize = 1000 => validate(|x| x > 0)
376/// },
377/// fit_fn: fit_linear_regression,
378/// predict_fn: predict_linear_regression,
379/// algorithm_type: supervised_regression
380/// }
381/// ```
382#[macro_export]
383macro_rules! define_ml_algorithm {
384 (
385 name: $name:ident,
386 config: {
387 $(
388 $field:ident: $field_type:ty = $default:expr
389 $(=> validate($validator:expr))?
390 ),* $(,)?
391 },
392 fit_fn: $fit_fn:ident,
393 predict_fn: $predict_fn:ident,
394 algorithm_type: $algorithm_type:ident
395 ) => {
396 // Configuration struct with validation
397 #[derive(Debug, Clone)]
398 pub struct [<$name Config>] {
399 $(
400 pub $field: $field_type,
401 )*
402 }
403
404 impl Default for [<$name Config>] {
405 fn default() -> Self {
406 Self {
407 $(
408 $field: $default,
409 )*
410 }
411 }
412 }
413
414 impl [<$name Config>] {
415 /// Validate all configuration parameters
416 pub fn validate(&self) -> $crate::error::Result<()> {
417 $(
418 $(
419 if !($validator)(self.$field) {
420 return Err($crate::error::SklearsError::InvalidInput(
421 format!("Validation failed for {}: {:?}", stringify!($field), self.$field)
422 ));
423 }
424 )?
425 )*
426 Ok(())
427 }
428 }
429 };
430}
431
432/// Creates comprehensive benchmarking suite for ML algorithms
433///
434/// # Examples
435/// ```rust,ignore
436/// benchmark_suite! {
437/// algorithm: LinearRegression,
438/// datasets: [small_dataset, medium_dataset, large_dataset],
439/// metrics: [fit_time, predict_time, memory_usage],
440/// iterations: 100
441/// }
442/// ```
443#[macro_export]
444macro_rules! benchmark_suite {
445 (
446 algorithm: $algo:ident,
447 datasets: [$($dataset:ident),* $(,)?],
448 metrics: [$($metric:ident),* $(,)?],
449 iterations: $iters:expr
450 ) => {
451 #[allow(non_snake_case)]
452#[cfg(test)]
453 mod benchmarks {
454 use super::*;
455 use std::time::Instant;
456
457 $(
458 #[test]
459 fn [<bench_ $algo:snake _ $dataset>]() {
460 let dataset = $dataset();
461 let mut total_fit_time = std::time::Duration::new(0, 0);
462 let mut total_predict_time = std::time::Duration::new(0, 0);
463
464 for _ in 0..$iters {
465 let algo = $algo::default();
466 let start = Instant::now();
467 let _ = start.elapsed(); // Placeholder for actual benchmarking
468 }
469
470 println!("{} benchmark completed", stringify!($algo));
471 }
472 )*
473 }
474 };
475}
476
477/// Creates SIMD-optimized operation implementations
478///
479/// # Examples
480/// ```rust,ignore
481/// simd_operations! {
482/// dot_product: (a: &[f64], b: &[f64]) -> f64 {
483/// simd: |a, b| simd_dot(a, b),
484/// fallback: |a, b| a.iter().zip(b).map(|(x, y)| x * y).sum()
485/// }
486/// }
487/// ```
488#[macro_export]
489macro_rules! simd_operations {
490 ($(
491 $op_name:ident: ($($param:ident: $param_type:ty),*) -> $return_type:ty {
492 simd: |$($simd_param:ident),*| $simd_impl:expr,
493 fallback: |$($fallback_param:ident),*| $fallback_impl:expr
494 }
495 ),* $(,)?) => {
496 $(
497 /// SIMD-optimized operation with fallback
498 pub fn $op_name($($param: $param_type),*) -> $return_type {
499 #[cfg(target_feature = "avx2")]
500 {
501 // SIMD implementation would go here
502 $fallback_impl // Fallback for now
503 }
504 #[cfg(not(target_feature = "avx2"))]
505 {
506 $fallback_impl
507 }
508 }
509 )*
510 };
511}