1use crate::api_standardization::{NullHandling, ResultMetadata, StandardizedConfig};
8use crate::error::StatsResult;
9use scirs2_core::numeric::{Float, NumCast};
11use std::collections::HashMap;
12use std::marker::PhantomData;
13use std::sync::Arc;
14use std::time::{Duration, Instant};
15
16#[derive(Debug, Clone)]
18pub struct FluentStatsConfig {
19 pub base_config: StandardizedConfig,
21 pub enable_fluent_api: bool,
23 pub enable_result_caching: bool,
25 pub enable_streaming: bool,
27 pub enable_async: bool,
29 pub auto_optimization_level: AutoOptimizationLevel,
31 pub result_format: ResultFormat,
33 pub enable_performance_monitoring: bool,
35 pub memory_strategy: MemoryStrategy,
37}
38
39impl Default for FluentStatsConfig {
40 fn default() -> Self {
41 Self {
42 base_config: StandardizedConfig::default(),
43 enable_fluent_api: true,
44 enable_result_caching: true,
45 enable_streaming: true,
46 enable_async: false, auto_optimization_level: AutoOptimizationLevel::Intelligent,
48 result_format: ResultFormat::Comprehensive,
49 enable_performance_monitoring: true,
50 memory_strategy: MemoryStrategy::Adaptive,
51 }
52 }
53}
54
55#[derive(Debug, Clone, Copy, PartialEq)]
57pub enum AutoOptimizationLevel {
58 None, Basic, Intelligent, Aggressive, }
63
64#[derive(Debug, Clone, Copy, PartialEq)]
66pub enum ResultFormat {
67 Minimal, Standard, Comprehensive, Custom, }
72
73#[derive(Debug, Clone, Copy, PartialEq)]
75pub enum MemoryStrategy {
76 Conservative, Balanced, Performance, Adaptive, }
81
82pub struct FluentStats<F>
84where
85 F: Float + NumCast + Send + Sync + 'static + std::fmt::Display,
86{
87 config: FluentStatsConfig,
88 operation_chain: Vec<StatisticalOperation>,
89 result_cache: Arc<std::sync::RwLock<HashMap<String, CachedResult<F>>>>,
90 performance_monitor: Option<PerformanceMonitor>,
91 _phantom: PhantomData<F>,
92}
93
94impl<F> Default for FluentStats<F>
95where
96 F: Float + NumCast + Send + Sync + 'static + std::fmt::Display,
97{
98 fn default() -> Self {
99 Self::new()
100 }
101}
102
103impl<F> FluentStats<F>
104where
105 F: Float + NumCast + Send + Sync + 'static + std::fmt::Display,
106{
107 pub fn new() -> Self {
109 Self::with_config(FluentStatsConfig::default())
110 }
111
112 pub fn with_config(config: FluentStatsConfig) -> Self {
114 let performance_monitor = if config.enable_performance_monitoring {
115 Some(PerformanceMonitor::new())
116 } else {
117 None
118 };
119
120 Self {
121 config,
122 operation_chain: Vec::new(),
123 result_cache: Arc::new(std::sync::RwLock::new(HashMap::new())),
124 performance_monitor,
125 _phantom: PhantomData,
126 }
127 }
128
129 pub fn parallel(mut self, enable: bool) -> Self {
131 self.config.base_config.parallel = enable;
132 self
133 }
134
135 pub fn simd(mut self, enable: bool) -> Self {
137 self.config.base_config.simd = enable;
138 self
139 }
140
141 pub fn confidence(mut self, level: f64) -> Self {
143 self.config.base_config.confidence_level = level;
144 self
145 }
146
147 pub fn null_handling(mut self, strategy: NullHandling) -> Self {
149 self.config.base_config.null_handling = strategy;
150 self
151 }
152
153 pub fn memory_limit(mut self, limit: usize) -> Self {
155 self.config.base_config.memory_limit = Some(limit);
156 self
157 }
158
159 pub fn optimization(mut self, level: AutoOptimizationLevel) -> Self {
161 self.config.auto_optimization_level = level;
162 self
163 }
164
165 pub fn streaming(mut self, enable: bool) -> Self {
167 self.config.enable_streaming = enable;
168 self
169 }
170
171 pub fn format(mut self, format: ResultFormat) -> Self {
173 self.config.result_format = format;
174 self
175 }
176
177 pub fn descriptive(self) -> FluentDescriptive<F> {
179 FluentDescriptive::new(self)
180 }
181
182 pub fn correlation(self) -> FluentCorrelation<F> {
184 FluentCorrelation::new(self)
185 }
186
187 pub fn test(self) -> FluentTesting<F> {
189 FluentTesting::new(self)
190 }
191
192 pub fn regression(self) -> FluentRegression<F> {
194 FluentRegression::new(self)
195 }
196
197 pub fn execute(&mut self) -> StatsResult<ChainedResults<F>> {
199 let start_time = Instant::now();
200 let mut results = ChainedResults::new();
201
202 if self.config.auto_optimization_level != AutoOptimizationLevel::None {
204 self.optimize_operation_chain()?;
205 }
206
207 for operation in &self.operation_chain {
209 let result = self.execute_operation(operation)?;
210 results.add_result(operation.name.clone(), result);
211 }
212
213 if let Some(ref mut monitor) = self.performance_monitor {
215 monitor.record_execution(start_time.elapsed(), self.operation_chain.len());
216 }
217
218 Ok(results)
219 }
220
221 fn optimize_operation_chain(&mut self) -> StatsResult<()> {
223 match self.config.auto_optimization_level {
224 AutoOptimizationLevel::Basic => {
225 self.operation_chain
227 .sort_by_key(|op| op.memory_access_pattern());
228 }
229 AutoOptimizationLevel::Intelligent => {
230 self.apply_intelligent_optimization()?;
232 }
233 AutoOptimizationLevel::Aggressive => {
234 self.fuse_operations()?;
236 }
237 AutoOptimizationLevel::None => {}
238 }
239 Ok(())
240 }
241
242 fn apply_intelligent_optimization(&mut self) -> StatsResult<()> {
244 self.operation_chain
247 .sort_by_key(|op| op.estimated_complexity());
248 Ok(())
249 }
250
251 fn fuse_operations(&mut self) -> StatsResult<()> {
253 Ok(())
256 }
257
258 fn execute_operation(
260 &self,
261 operation: &StatisticalOperation,
262 ) -> StatsResult<OperationResult<F>> {
263 if self.config.enable_result_caching {
265 let cache_key = operation.cache_key();
266 if let Ok(cache) = self.result_cache.read() {
267 if let Some(cached) = cache.get(&cache_key) {
268 if !cached.is_expired() {
269 return Ok(cached.result.clone());
270 }
271 }
272 }
273 }
274
275 let result = match &operation.operation_type {
277 OperationType::Mean => self.execute_mean_operation(operation),
278 OperationType::Variance => self.execute_variance_operation(operation),
279 OperationType::Correlation => self.execute_correlation_operation(operation),
280 OperationType::TTest => self.execute_ttest_operation(operation),
281 OperationType::Regression => self.execute_regression_operation(operation),
282 }?;
283
284 if self.config.enable_result_caching {
286 let cache_key = operation.cache_key();
287 if let Ok(mut cache) = self.result_cache.write() {
288 cache.insert(cache_key, CachedResult::new(result.clone()));
289 }
290 }
291
292 Ok(result)
293 }
294
295 fn execute_mean_operation(
297 &self,
298 _operation: &StatisticalOperation,
299 ) -> StatsResult<OperationResult<F>> {
300 Ok(OperationResult {
302 value: Box::new(F::zero()),
303 metadata: ResultMetadata {
304 samplesize: 0,
305 degrees_of_freedom: None,
306 confidence_level: None,
307 method: "mean".to_string(),
308 computation_time_ms: 0.0,
309 memory_usage_bytes: None,
310 optimized: true,
311 extra: HashMap::new(),
312 },
313 operation_type: OperationType::Mean,
314 })
315 }
316
317 fn execute_variance_operation(
319 &self,
320 _operation: &StatisticalOperation,
321 ) -> StatsResult<OperationResult<F>> {
322 Ok(OperationResult {
324 value: Box::new(F::one()),
325 metadata: ResultMetadata {
326 samplesize: 0,
327 degrees_of_freedom: Some(0),
328 confidence_level: None,
329 method: "variance".to_string(),
330 computation_time_ms: 0.0,
331 memory_usage_bytes: None,
332 optimized: true,
333 extra: HashMap::new(),
334 },
335 operation_type: OperationType::Variance,
336 })
337 }
338
339 fn execute_correlation_operation(
341 &self,
342 _operation: &StatisticalOperation,
343 ) -> StatsResult<OperationResult<F>> {
344 Ok(OperationResult {
346 value: Box::new(F::zero()),
347 metadata: ResultMetadata {
348 samplesize: 0,
349 degrees_of_freedom: None,
350 confidence_level: Some(0.95),
351 method: "pearson_correlation".to_string(),
352 computation_time_ms: 0.0,
353 memory_usage_bytes: None,
354 optimized: true,
355 extra: HashMap::new(),
356 },
357 operation_type: OperationType::Correlation,
358 })
359 }
360
361 fn execute_ttest_operation(
363 &self,
364 _operation: &StatisticalOperation,
365 ) -> StatsResult<OperationResult<F>> {
366 Ok(OperationResult {
368 value: Box::new(F::zero()),
369 metadata: ResultMetadata {
370 samplesize: 0,
371 degrees_of_freedom: Some(0),
372 confidence_level: Some(0.95),
373 method: "t_test".to_string(),
374 computation_time_ms: 0.0,
375 memory_usage_bytes: None,
376 optimized: true,
377 extra: HashMap::new(),
378 },
379 operation_type: OperationType::TTest,
380 })
381 }
382
383 fn execute_regression_operation(
385 &self,
386 _operation: &StatisticalOperation,
387 ) -> StatsResult<OperationResult<F>> {
388 Ok(OperationResult {
390 value: Box::new(F::zero()),
391 metadata: ResultMetadata {
392 samplesize: 0,
393 degrees_of_freedom: Some(0),
394 confidence_level: Some(0.95),
395 method: "linear_regression".to_string(),
396 computation_time_ms: 0.0,
397 memory_usage_bytes: None,
398 optimized: true,
399 extra: HashMap::new(),
400 },
401 operation_type: OperationType::Regression,
402 })
403 }
404}
405
406pub struct FluentDescriptive<F>
408where
409 F: Float + NumCast + Send + Sync + 'static + std::fmt::Display,
410{
411 parent: FluentStats<F>,
412 operations: Vec<DescriptiveOperation>,
413}
414
415impl<F> FluentDescriptive<F>
416where
417 F: Float + NumCast + Send + Sync + 'static + std::fmt::Display,
418{
419 fn new(parent: FluentStats<F>) -> Self {
420 Self {
421 parent,
422 operations: Vec::new(),
423 }
424 }
425
426 pub fn mean(mut self) -> Self {
428 self.operations.push(DescriptiveOperation::Mean);
429 self
430 }
431
432 pub fn variance(mut self, ddof: usize) -> Self {
434 self.operations.push(DescriptiveOperation::Variance(ddof));
435 self
436 }
437
438 pub fn std_dev(mut self, ddof: usize) -> Self {
440 self.operations.push(DescriptiveOperation::StdDev(ddof));
441 self
442 }
443
444 pub fn skewness(mut self) -> Self {
446 self.operations.push(DescriptiveOperation::Skewness);
447 self
448 }
449
450 pub fn kurtosis(mut self) -> Self {
452 self.operations.push(DescriptiveOperation::Kurtosis);
453 self
454 }
455
456 pub fn all_basic(mut self) -> Self {
458 self.operations.extend(vec![
459 DescriptiveOperation::Mean,
460 DescriptiveOperation::Variance(1),
461 DescriptiveOperation::StdDev(1),
462 DescriptiveOperation::Skewness,
463 DescriptiveOperation::Kurtosis,
464 ]);
465 self
466 }
467
468 pub fn and(mut self) -> FluentStats<F> {
470 for desc_op in self.operations {
472 let stat_op = StatisticalOperation {
473 name: format!("{:?}", desc_op),
474 operation_type: OperationType::from_descriptive(desc_op),
475 parameters: HashMap::new(),
476 data_requirements: DataRequirements::single_array(),
477 };
478 self.parent.operation_chain.push(stat_op);
479 }
480 self.parent
481 }
482}
483
484pub struct FluentCorrelation<F>
486where
487 F: Float + NumCast + Send + Sync + 'static + std::fmt::Display,
488{
489 parent: FluentStats<F>,
490 correlation_type: CorrelationType,
491 method: CorrelationMethod,
492}
493
494impl<F> FluentCorrelation<F>
495where
496 F: Float + NumCast + Send + Sync + 'static + std::fmt::Display,
497{
498 fn new(parent: FluentStats<F>) -> Self {
499 Self {
500 parent,
501 correlation_type: CorrelationType::Pairwise,
502 method: CorrelationMethod::Pearson,
503 }
504 }
505
506 pub fn method(mut self, method: CorrelationMethod) -> Self {
508 self.method = method;
509 self
510 }
511
512 pub fn pearson(mut self) -> Self {
514 self.method = CorrelationMethod::Pearson;
515 self
516 }
517
518 pub fn spearman(mut self) -> Self {
520 self.method = CorrelationMethod::Spearman;
521 self
522 }
523
524 pub fn kendall(mut self) -> Self {
526 self.method = CorrelationMethod::Kendall;
527 self
528 }
529
530 pub fn matrix(mut self) -> Self {
532 self.correlation_type = CorrelationType::Matrix;
533 self
534 }
535
536 pub fn and(mut self) -> FluentStats<F> {
538 let stat_op = StatisticalOperation {
539 name: format!("{:?}_{:?}", self.method, self.correlation_type),
540 operation_type: OperationType::Correlation,
541 parameters: HashMap::from([
542 ("method".to_string(), format!("{:?}", self.method)),
543 ("type".to_string(), format!("{:?}", self.correlation_type)),
544 ]),
545 data_requirements: DataRequirements::multi_array(),
546 };
547 self.parent.operation_chain.push(stat_op);
548 self.parent
549 }
550}
551
552pub struct FluentTesting<F>
554where
555 F: Float + NumCast + Send + Sync + 'static + std::fmt::Display,
556{
557 parent: FluentStats<F>,
558 test_type: TestType,
559}
560
561impl<F> FluentTesting<F>
562where
563 F: Float + NumCast + Send + Sync + 'static + std::fmt::Display,
564{
565 fn new(parent: FluentStats<F>) -> Self {
566 Self {
567 parent,
568 test_type: TestType::TTest,
569 }
570 }
571
572 pub fn t_test_one_sample(mut self, mu: F) -> Self {
574 self.test_type = TestType::TTestOneSample(mu.to_f64().unwrap_or(0.0));
575 self
576 }
577
578 pub fn t_test_independent(mut self) -> Self {
580 self.test_type = TestType::TTestIndependent;
581 self
582 }
583
584 pub fn t_test_paired(mut self) -> Self {
586 self.test_type = TestType::TTestPaired;
587 self
588 }
589
590 pub fn and(mut self) -> FluentStats<F> {
592 let stat_op = StatisticalOperation {
593 name: format!("{:?}", self.test_type),
594 operation_type: OperationType::TTest,
595 parameters: HashMap::new(),
596 data_requirements: DataRequirements::single_array(),
597 };
598 self.parent.operation_chain.push(stat_op);
599 self.parent
600 }
601}
602
603pub struct FluentRegression<F>
605where
606 F: Float + NumCast + Send + Sync + 'static + std::fmt::Display,
607{
608 parent: FluentStats<F>,
609 regression_type: RegressionType,
610}
611
612impl<F> FluentRegression<F>
613where
614 F: Float + NumCast + Send + Sync + 'static + std::fmt::Display,
615{
616 fn new(parent: FluentStats<F>) -> Self {
617 Self {
618 parent,
619 regression_type: RegressionType::Linear,
620 }
621 }
622
623 pub fn linear(mut self) -> Self {
625 self.regression_type = RegressionType::Linear;
626 self
627 }
628
629 pub fn polynomial(mut self, degree: usize) -> Self {
631 self.regression_type = RegressionType::Polynomial(degree);
632 self
633 }
634
635 pub fn ridge(mut self, alpha: F) -> Self {
637 self.regression_type = RegressionType::Ridge(alpha.to_f64().unwrap_or(0.0));
638 self
639 }
640
641 pub fn and(mut self) -> FluentStats<F> {
643 let stat_op = StatisticalOperation {
644 name: format!("{:?}", self.regression_type),
645 operation_type: OperationType::Regression,
646 parameters: HashMap::new(),
647 data_requirements: DataRequirements::xy_arrays(),
648 };
649 self.parent.operation_chain.push(stat_op);
650 self.parent
651 }
652}
653
654#[derive(Debug, Clone)]
656pub struct StatisticalOperation {
657 pub name: String,
658 pub operation_type: OperationType,
659 pub parameters: HashMap<String, String>,
660 pub data_requirements: DataRequirements,
661}
662
663impl StatisticalOperation {
664 pub fn cache_key(&self) -> String {
666 format!(
667 "{}_{:?}_{:?}",
668 self.name, self.operation_type, self.parameters
669 )
670 }
671
672 pub fn memory_access_pattern(&self) -> u32 {
674 match self.operation_type {
675 OperationType::Mean => 1,
676 OperationType::Variance => 2,
677 OperationType::Correlation => 3,
678 OperationType::TTest => 2,
679 OperationType::Regression => 4,
680 }
681 }
682
683 pub fn estimated_complexity(&self) -> u32 {
685 match self.operation_type {
686 OperationType::Mean => 1,
687 OperationType::Variance => 2,
688 OperationType::Correlation => 4,
689 OperationType::TTest => 3,
690 OperationType::Regression => 5,
691 }
692 }
693}
694
695#[derive(Debug, Clone, Copy, PartialEq)]
697pub enum OperationType {
698 Mean,
699 Variance,
700 Correlation,
701 TTest,
702 Regression,
703}
704
705impl OperationType {
706 fn from_descriptive(_descop: DescriptiveOperation) -> Self {
707 match _descop {
708 DescriptiveOperation::Mean => OperationType::Mean,
709 DescriptiveOperation::Variance(_) => OperationType::Variance,
710 DescriptiveOperation::StdDev(_) => OperationType::Variance,
711 DescriptiveOperation::Skewness => OperationType::Mean, DescriptiveOperation::Kurtosis => OperationType::Mean, }
714 }
715}
716
717#[derive(Debug, Clone)]
719pub struct DataRequirements {
720 pub arrays_needed: usize,
721 pub minsize: usize,
722 pub requires_numeric: bool,
723}
724
725impl DataRequirements {
726 pub fn single_array() -> Self {
727 Self {
728 arrays_needed: 1,
729 minsize: 1,
730 requires_numeric: true,
731 }
732 }
733
734 pub fn multi_array() -> Self {
735 Self {
736 arrays_needed: 2,
737 minsize: 1,
738 requires_numeric: true,
739 }
740 }
741
742 pub fn xy_arrays() -> Self {
743 Self {
744 arrays_needed: 2,
745 minsize: 2,
746 requires_numeric: true,
747 }
748 }
749}
750
751#[derive(Debug, Clone, Copy)]
753pub enum DescriptiveOperation {
754 Mean,
755 Variance(usize), StdDev(usize), Skewness,
758 Kurtosis,
759}
760
761#[derive(Debug, Clone, Copy)]
763pub enum CorrelationType {
764 Pairwise,
765 Matrix,
766 Partial,
767}
768
769#[derive(Debug, Clone, Copy)]
771pub enum CorrelationMethod {
772 Pearson,
773 Spearman,
774 Kendall,
775}
776
777#[derive(Debug, Clone)]
779pub enum TestType {
780 TTest,
781 TTestOneSample(f64),
782 TTestIndependent,
783 TTestPaired,
784 ChiSquare,
785 ANOVA,
786}
787
788#[derive(Debug, Clone)]
790pub enum RegressionType {
791 Linear,
792 Polynomial(usize), Ridge(f64), Lasso(f64), }
796
797#[derive(Debug, Clone)]
799pub struct OperationResult<F> {
800 pub value: Box<F>,
801 pub metadata: ResultMetadata,
802 pub operation_type: OperationType,
803}
804
805#[derive(Debug)]
807pub struct ChainedResults<F> {
808 results: HashMap<String, OperationResult<F>>,
809 execution_order: Vec<String>,
810}
811
812impl<F> ChainedResults<F> {
813 fn new() -> Self {
814 Self {
815 results: HashMap::new(),
816 execution_order: Vec::new(),
817 }
818 }
819
820 fn add_result(&mut self, name: String, result: OperationResult<F>) {
821 self.execution_order.push(name.clone());
822 self.results.insert(name, result);
823 }
824
825 pub fn get(&self, name: &str) -> Option<&OperationResult<F>> {
827 self.results.get(name)
828 }
829
830 pub fn iter(&self) -> impl Iterator<Item = (&String, &OperationResult<F>)> {
832 self.execution_order
833 .iter()
834 .filter_map(|name| self.results.get(name).map(|result| (name, result)))
835 }
836}
837
838#[derive(Debug, Clone)]
840struct CachedResult<F> {
841 result: OperationResult<F>,
842 created_at: Instant,
843 ttl: Duration,
844}
845
846impl<F> CachedResult<F> {
847 fn new(result: OperationResult<F>) -> Self {
848 Self {
849 result,
850 created_at: Instant::now(),
851 ttl: Duration::from_secs(300), }
853 }
854
855 fn is_expired(&self) -> bool {
856 self.created_at.elapsed() > self.ttl
857 }
858}
859
860#[derive(Debug)]
862struct PerformanceMonitor {
863 executions: Vec<ExecutionMetrics>,
864}
865
866impl PerformanceMonitor {
867 fn new() -> Self {
868 Self {
869 executions: Vec::new(),
870 }
871 }
872
873 fn record_execution(&mut self, duration: Duration, operationcount: usize) {
874 self.executions.push(ExecutionMetrics {
875 duration,
876 operation_count: operationcount,
877 timestamp: Instant::now(),
878 });
879 }
880
881 #[allow(dead_code)]
882 fn average_execution_time(&self) -> Option<Duration> {
883 if self.executions.is_empty() {
884 None
885 } else {
886 let total: Duration = self.executions.iter().map(|e| e.duration).sum();
887 Some(total / self.executions.len() as u32)
888 }
889 }
890}
891
892#[derive(Debug)]
894struct ExecutionMetrics {
895 duration: Duration,
896 #[allow(dead_code)]
897 operation_count: usize,
898 #[allow(dead_code)]
899 timestamp: Instant,
900}
901
902#[allow(dead_code)]
904pub fn stats<F>() -> FluentStats<F>
905where
906 F: Float + NumCast + Send + Sync + 'static + std::fmt::Display,
907{
908 FluentStats::new()
909}
910
911#[allow(dead_code)]
912pub fn stats_with<F>(config: FluentStatsConfig) -> FluentStats<F>
913where
914 F: Float + NumCast + Send + Sync + 'static + std::fmt::Display,
915{
916 FluentStats::with_config(config)
917}
918
919#[allow(dead_code)]
921pub fn quick_descriptive<F>() -> FluentDescriptive<F>
922where
923 F: Float + NumCast + Send + Sync + 'static + std::fmt::Display,
924{
925 FluentStats::new().descriptive()
926}
927
928#[allow(dead_code)]
930pub fn quick_correlation<F>() -> FluentCorrelation<F>
931where
932 F: Float + NumCast + Send + Sync + 'static + std::fmt::Display,
933{
934 FluentStats::new().correlation()
935}
936
937#[cfg(test)]
938mod tests {
939 use super::*;
940
941 #[test]
942 fn test_fluent_stats_creation() {
943 let _stats: FluentStats<f64> = stats();
944 assert!(true); }
946
947 #[test]
948 fn test_fluent_configuration() {
949 let config = FluentStatsConfig {
950 enable_fluent_api: true,
951 auto_optimization_level: AutoOptimizationLevel::Intelligent,
952 ..Default::default()
953 };
954
955 let _stats: FluentStats<f64> = stats_with(config);
956 assert!(true); }
958
959 #[test]
960 fn test_method_chaining() {
961 let _chain: FluentStats<f64> = stats()
962 .parallel(true)
963 .simd(true)
964 .confidence(0.99)
965 .optimization(AutoOptimizationLevel::Aggressive);
966
967 assert!(true); }
969
970 #[test]
971 fn test_descriptive_operations() {
972 let _desc = quick_descriptive::<f64>()
973 .mean()
974 .variance(1)
975 .std_dev(1)
976 .skewness()
977 .kurtosis();
978
979 assert!(true); }
981}