scirs2-stats 0.3.3

Statistical functions module for SciRS2 (scirs2-stats)
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
//! SciPy benchmark comparison framework for scirs2-stats v1.0.0
//!
//! This module provides comprehensive benchmarking against SciPy to validate
//! performance, accuracy, and API compatibility. It includes automated test
//! generation, statistical validation, and performance regression detection.

use crate::error::{StatsError, StatsResult};
use scirs2_core::ndarray::{Array1, Array2};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fs;
use std::process::Command;
use std::time::{Duration, Instant};

/// Configuration for SciPy comparison benchmarks
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScipyComparisonConfig {
    /// Python executable path
    pub python_executable: String,
    /// SciPy version requirement
    pub scipy_version: Option<String>,
    /// NumPy version requirement
    pub numpy_version: Option<String>,
    /// Temporary directory for test scripts
    pub temp_dir: String,
    /// Accuracy tolerance for numerical comparisons
    pub accuracy_tolerance: f64,
    /// Performance tolerance (ratio to SciPy)
    pub performance_tolerance: f64,
    /// Number of warmup iterations
    pub warmup_iterations: usize,
    /// Number of measurement iterations
    pub measurement_iterations: usize,
    /// Enable detailed accuracy analysis
    pub detailed_accuracy: bool,
    /// Enable memory usage comparison
    pub compare_memory: bool,
    /// Test data sizes
    pub testsizes: Vec<usize>,
    /// Functions to benchmark
    pub functions_to_test: Vec<String>,
}

impl Default for ScipyComparisonConfig {
    fn default() -> Self {
        Self {
            python_executable: "python3".to_string(),
            scipy_version: Some(">=1.9.0".to_string()),
            numpy_version: Some(">=1.21.0".to_string()),
            temp_dir: "/tmp/scirs2_benchmarks".to_string(),
            accuracy_tolerance: 1e-10,
            performance_tolerance: 2.0, // Allow 2x slower than SciPy
            warmup_iterations: 10,
            measurement_iterations: 100,
            detailed_accuracy: true,
            compare_memory: true,
            testsizes: vec![100, 1000, 10000, 100000],
            functions_to_test: vec![
                "mean".to_string(),
                "std".to_string(),
                "var".to_string(),
                "skew".to_string(),
                "kurtosis".to_string(),
                "pearsonr".to_string(),
                "spearmanr".to_string(),
                "ttest_ind".to_string(),
                "ttest_1samp".to_string(),
                "norm_pdf".to_string(),
                "norm_cdf".to_string(),
            ],
        }
    }
}

/// Results of SciPy comparison benchmarking
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScipyComparisonReport {
    /// Timestamp of the comparison
    pub timestamp: String,
    /// Configuration used
    pub config: ScipyComparisonConfig,
    /// System information
    pub system_info: SystemInfo,
    /// SciPy environment info
    pub scipy_environment: ScipyEnvironmentInfo,
    /// Individual function comparison results
    pub function_comparisons: Vec<FunctionComparison>,
    /// Overall summary statistics
    pub summary: ComparisonSummary,
    /// Performance analysis
    pub performance_analysis: PerformanceAnalysis,
    /// Accuracy analysis
    pub accuracy_analysis: AccuracyAnalysis,
    /// Recommendations
    pub recommendations: Vec<ComparisonRecommendation>,
}

/// System information for comparison context
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SystemInfo {
    /// Operating system
    pub os: String,
    /// CPU information
    pub cpu: String,
    /// Memory information
    pub memory_gb: f64,
    /// Rust version
    pub rust_version: String,
    /// scirs2-stats version
    pub scirs2_version: String,
}

/// SciPy environment information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScipyEnvironmentInfo {
    /// Python version
    pub python_version: String,
    /// SciPy version
    pub scipy_version: String,
    /// NumPy version
    pub numpy_version: String,
    /// BLAS/LAPACK information
    pub blas_info: String,
    /// Available Python packages
    pub packages: HashMap<String, String>,
}

/// Comparison results for a single function
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FunctionComparison {
    /// Function name
    pub function_name: String,
    /// Test data size
    pub datasize: usize,
    /// Performance comparison
    pub performance: PerformanceComparison,
    /// Accuracy comparison
    pub accuracy: AccuracyComparison,
    /// Memory usage comparison
    pub memory: Option<MemoryComparison>,
    /// Test status
    pub status: ComparisonStatus,
    /// Error details if failed
    pub error_details: Option<String>,
}

/// Performance comparison between scirs2-stats and SciPy
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceComparison {
    /// scirs2-stats execution time (nanoseconds)
    pub scirs2_time_ns: f64,
    /// SciPy execution time (nanoseconds)
    pub scipy_time_ns: f64,
    /// Performance ratio (scirs2/scipy)
    pub ratio: f64,
    /// Statistical significance of difference
    pub significance: PerformanceSignificance,
    /// Confidence interval for ratio
    pub confidence_interval: (f64, f64),
}

/// Accuracy comparison between implementations
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AccuracyComparison {
    /// Absolute difference
    pub absolute_difference: f64,
    /// Relative difference
    pub relative_difference: f64,
    /// Maximum element-wise difference
    pub max_element_difference: f64,
    /// Number of elements compared
    pub elements_compared: usize,
    /// Elements within tolerance
    pub elements_within_tolerance: usize,
    /// Accuracy assessment
    pub assessment: AccuracyAssessment,
}

/// Memory usage comparison
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemoryComparison {
    /// scirs2-stats memory usage (bytes)
    pub scirs2_memory: usize,
    /// SciPy memory usage (bytes)
    pub scipy_memory: usize,
    /// Memory ratio (scirs2/scipy)
    pub ratio: f64,
    /// Memory efficiency assessment
    pub assessment: MemoryEfficiencyAssessment,
}

/// Status of comparison test
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ComparisonStatus {
    /// Test passed all checks
    Passed,
    /// Test passed with warnings
    PassedWithWarnings { warnings: Vec<String> },
    /// Test failed accuracy requirements
    FailedAccuracy { details: String },
    /// Test failed performance requirements
    FailedPerformance { details: String },
    /// Test encountered execution error
    Error { error: String },
    /// Test was skipped
    Skipped { reason: String },
}

/// Performance significance assessment
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum PerformanceSignificance {
    /// No significant difference
    NotSignificant,
    /// scirs2-stats significantly faster
    ScirsFaster { confidence: f64 },
    /// SciPy significantly faster
    ScipyFaster { confidence: f64 },
    /// Insufficient data for assessment
    InsufficientData,
}

/// Accuracy assessment categories
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AccuracyAssessment {
    /// Excellent accuracy (within machine precision)
    Excellent,
    /// Good accuracy (within specified tolerance)
    Good,
    /// Acceptable accuracy (small differences)
    Acceptable,
    /// Poor accuracy (significant differences)
    Poor,
    /// Unacceptable accuracy (large differences)
    Unacceptable,
}

/// Memory efficiency assessment
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum MemoryEfficiencyAssessment {
    /// More memory efficient than SciPy
    MoreEfficient,
    /// Similar memory usage to SciPy
    Similar,
    /// Less memory efficient than SciPy
    LessEfficient,
    /// Significantly less memory efficient
    MuchLessEfficient,
}

/// Overall comparison summary
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ComparisonSummary {
    /// Total tests run
    pub total_tests: usize,
    /// Tests passed
    pub tests_passed: usize,
    /// Tests with warnings
    pub tests_with_warnings: usize,
    /// Tests failed
    pub tests_failed: usize,
    /// Overall pass rate
    pub pass_rate: f64,
    /// Functions with performance issues
    pub performance_issues: Vec<String>,
    /// Functions with accuracy issues
    pub accuracy_issues: Vec<String>,
    /// Overall performance rating
    pub performance_rating: PerformanceRating,
    /// Overall accuracy rating
    pub accuracy_rating: AccuracyRating,
}

/// Performance analysis across all tests
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceAnalysis {
    /// Average performance ratio
    pub average_ratio: f64,
    /// Performance ratio standard deviation
    pub ratio_std_dev: f64,
    /// Functions faster than SciPy
    pub faster_functions: Vec<(String, f64)>,
    /// Functions slower than SciPy
    pub slower_functions: Vec<(String, f64)>,
    /// Performance by data size
    pub performance_bysize: HashMap<usize, f64>,
    /// Performance trends
    pub trends: PerformanceTrends,
}

/// Accuracy analysis across all tests
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AccuracyAnalysis {
    /// Average relative difference
    pub average_relative_diff: f64,
    /// Maximum relative difference
    pub max_relative_diff: f64,
    /// Functions with accuracy issues
    pub problematic_functions: Vec<(String, f64)>,
    /// Accuracy by data size
    pub accuracy_bysize: HashMap<usize, f64>,
    /// Numerical stability assessment
    pub stability_assessment: NumericalStabilityAssessment,
}

/// Performance rating categories
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum PerformanceRating {
    /// Excellent performance (consistently faster)
    Excellent,
    /// Good performance (mostly competitive)
    Good,
    /// Acceptable performance (within tolerance)
    Acceptable,
    /// Poor performance (consistently slower)
    Poor,
    /// Unacceptable performance (significantly slower)
    Unacceptable,
}

/// Accuracy rating categories
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AccuracyRating {
    /// Excellent accuracy (machine precision)
    Excellent,
    /// Good accuracy (high precision)
    Good,
    /// Acceptable accuracy (within tolerance)
    Acceptable,
    /// Poor accuracy (noticeable differences)
    Poor,
    /// Unacceptable accuracy (significant errors)
    Unacceptable,
}

/// Performance trends analysis
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceTrends {
    /// Performance scaling with data size
    pub scaling_analysis: ScalingAnalysis,
    /// Performance stability over multiple runs
    pub stability_analysis: StabilityAnalysis,
    /// Performance regression detection
    pub regression_analysis: RegressionAnalysis,
}

/// Scaling analysis results
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScalingAnalysis {
    /// Scaling factor relative to SciPy
    pub relative_scaling: f64,
    /// Complexity assessment
    pub complexity_assessment: ComplexityAssessment,
    /// Crossover points where performance changes
    pub crossover_points: Vec<usize>,
}

/// Stability analysis results
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StabilityAnalysis {
    /// Coefficient of variation for performance
    pub performance_cv: f64,
    /// Performance outliers detected
    pub outliers_detected: usize,
    /// Stability rating
    pub stability_rating: StabilityRating,
}

/// Regression analysis results
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RegressionAnalysis {
    /// Performance regressions detected
    pub regressions_detected: Vec<PerformanceRegression>,
    /// Accuracy regressions detected
    pub accuracy_regressions: Vec<AccuracyRegression>,
    /// Overall regression risk
    pub regression_risk: RegressionRisk,
}

/// Complexity assessment
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ComplexityAssessment {
    /// Better complexity than SciPy
    Better,
    /// Similar complexity to SciPy
    Similar,
    /// Worse complexity than SciPy
    Worse,
    /// Unknown complexity relationship
    Unknown,
}

/// Stability rating
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum StabilityRating {
    /// Very stable performance
    VeryStable,
    /// Stable performance
    Stable,
    /// Moderately stable
    ModeratelyStable,
    /// Unstable performance
    Unstable,
    /// Very unstable performance
    VeryUnstable,
}

/// Performance regression
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceRegression {
    /// Function affected
    pub function_name: String,
    /// Regression magnitude
    pub regression_factor: f64,
    /// Confidence in detection
    pub confidence: f64,
    /// Suspected cause
    pub suspected_cause: String,
}

/// Accuracy regression
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AccuracyRegression {
    /// Function affected
    pub function_name: String,
    /// Accuracy degradation
    pub accuracy_loss: f64,
    /// Severity assessment
    pub severity: AccuracyRegressionSeverity,
}

/// Regression risk assessment
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum RegressionRisk {
    /// Low risk of regressions
    Low,
    /// Medium risk of regressions
    Medium,
    /// High risk of regressions
    High,
    /// Critical risk of regressions
    Critical,
}

/// Accuracy regression severity
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AccuracyRegressionSeverity {
    /// Minor accuracy loss
    Minor,
    /// Moderate accuracy loss
    Moderate,
    /// Major accuracy loss
    Major,
    /// Critical accuracy loss
    Critical,
}

/// Numerical stability assessment
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NumericalStabilityAssessment {
    /// Overall stability rating
    pub stability_rating: NumericalStabilityRating,
    /// Functions with stability issues
    pub unstable_functions: Vec<String>,
    /// Condition number analysis
    pub condition_number_analysis: ConditionNumberAnalysis,
    /// Precision loss analysis
    pub precision_loss_analysis: PrecisionLossAnalysis,
}

/// Numerical stability rating
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum NumericalStabilityRating {
    /// Excellent numerical stability
    Excellent,
    /// Good numerical stability
    Good,
    /// Acceptable numerical stability
    Acceptable,
    /// Poor numerical stability
    Poor,
    /// Unacceptable numerical stability
    Unacceptable,
}

/// Condition number analysis
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConditionNumberAnalysis {
    /// Functions sensitive to condition number
    pub sensitive_functions: Vec<String>,
    /// Condition number thresholds
    pub thresholds: HashMap<String, f64>,
    /// Stability recommendations
    pub recommendations: Vec<String>,
}

/// Precision loss analysis
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PrecisionLossAnalysis {
    /// Average precision loss
    pub average_loss: f64,
    /// Maximum precision loss
    pub max_loss: f64,
    /// Functions with significant loss
    pub problematic_functions: Vec<String>,
}

/// Comparison recommendation
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ComparisonRecommendation {
    /// Recommendation priority
    pub priority: RecommendationPriority,
    /// Category of recommendation
    pub category: RecommendationCategory,
    /// Recommendation description
    pub description: String,
    /// Affected functions
    pub affected_functions: Vec<String>,
    /// Implementation complexity
    pub complexity: ImplementationComplexity,
    /// Expected impact
    pub expected_impact: ExpectedImpact,
}

/// Recommendation priority levels
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum RecommendationPriority {
    /// Critical priority
    Critical,
    /// High priority
    High,
    /// Medium priority
    Medium,
    /// Low priority
    Low,
    /// Nice to have
    NiceToHave,
}

/// Recommendation categories
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum RecommendationCategory {
    /// Performance optimization
    Performance,
    /// Accuracy improvement
    Accuracy,
    /// Memory optimization
    Memory,
    /// API compatibility
    APICompatibility,
    /// Numerical stability
    NumericalStability,
    /// Testing enhancement
    Testing,
}

/// Implementation complexity assessment
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ImplementationComplexity {
    /// Simple to implement
    Simple,
    /// Moderate complexity
    Moderate,
    /// Complex implementation
    Complex,
    /// Very complex implementation
    VeryComplex,
}

/// Expected impact of recommendation
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExpectedImpact {
    /// Performance improvement factor
    pub performance_improvement: Option<f64>,
    /// Accuracy improvement
    pub accuracy_improvement: Option<f64>,
    /// Memory reduction factor
    pub memory_reduction: Option<f64>,
    /// Implementation effort (person-days)
    pub implementation_effort: f64,
}

/// Main SciPy comparison framework
pub struct ScipyBenchmarkComparison {
    config: ScipyComparisonConfig,
    temp_dir: String,
}

impl ScipyBenchmarkComparison {
    /// Create new SciPy comparison framework
    pub fn new(config: ScipyComparisonConfig) -> StatsResult<Self> {
        // Create temporary directory
        fs::create_dir_all(&config.temp_dir).map_err(|e| {
            StatsError::ComputationError(format!("Failed to create temp directory: {}", e))
        })?;

        Ok(Self {
            temp_dir: config.temp_dir.clone(),
            config,
        })
    }

    /// Create with default configuration
    pub fn default() -> StatsResult<Self> {
        Self::new(ScipyComparisonConfig::default())
    }

    /// Run comprehensive comparison benchmarks
    pub fn run_comprehensive_comparison(&self) -> StatsResult<ScipyComparisonReport> {
        let _start_time = Instant::now();

        // Verify SciPy environment
        let scipy_env = self.verify_scipy_environment()?;

        // Collect system information
        let system_info = self.collect_system_info();

        // Run function comparisons
        let mut function_comparisons = Vec::new();

        for function_name in &self.config.functions_to_test {
            for &datasize in &self.config.testsizes {
                match self.compare_function(function_name, datasize) {
                    Ok(comparison) => function_comparisons.push(comparison),
                    Err(e) => {
                        function_comparisons.push(FunctionComparison {
                            function_name: function_name.clone(),
                            datasize,
                            performance: PerformanceComparison {
                                scirs2_time_ns: 0.0,
                                scipy_time_ns: 0.0,
                                ratio: 0.0,
                                significance: PerformanceSignificance::InsufficientData,
                                confidence_interval: (0.0, 0.0),
                            },
                            accuracy: AccuracyComparison {
                                absolute_difference: 0.0,
                                relative_difference: 0.0,
                                max_element_difference: 0.0,
                                elements_compared: 0,
                                elements_within_tolerance: 0,
                                assessment: AccuracyAssessment::Poor,
                            },
                            memory: None,
                            status: ComparisonStatus::Error {
                                error: e.to_string(),
                            },
                            error_details: Some(e.to_string()),
                        });
                    }
                }
            }
        }

        // Analyze results
        let summary = self.generate_summary(&function_comparisons);
        let performance_analysis = self.analyze_performance(&function_comparisons);
        let accuracy_analysis = self.analyze_accuracy(&function_comparisons);
        let recommendations = self.generate_recommendations(
            &function_comparisons,
            &performance_analysis,
            &accuracy_analysis,
        );

        Ok(ScipyComparisonReport {
            timestamp: chrono::Utc::now().to_rfc3339(),
            config: self.config.clone(),
            system_info,
            scipy_environment: scipy_env,
            function_comparisons,
            summary,
            performance_analysis,
            accuracy_analysis,
            recommendations,
        })
    }

    /// Verify SciPy environment is available and compatible
    fn verify_scipy_environment(&self) -> StatsResult<ScipyEnvironmentInfo> {
        let script = r#"
import sys
import scipy
import numpy as np
import json

info = {
    'python_version': sys.version,
    'scipy_version': scipy.__version__,
    'numpy_version': np.__version__,
    'blas_info': str(np.__config__.show()),
    'packages': {}
}

try:
    import pandas
    info['packages']['pandas'] = pandas.__version__
except ImportError:
    pass

try:
    import sklearn
    info['packages']['sklearn'] = sklearn.__version__
except ImportError:
    pass

print(json.dumps(info))
"#;

        let script_path = format!("{}/verify_env.py", self.temp_dir);
        fs::write(&script_path, script).map_err(|e| {
            StatsError::ComputationError(format!("Failed to write verification script: {}", e))
        })?;

        let output = Command::new(&self.config.python_executable)
            .arg(&script_path)
            .output()
            .map_err(|e| {
                StatsError::ComputationError(format!("Failed to execute Python: {}", e))
            })?;

        if !output.status.success() {
            return Err(StatsError::ComputationError(format!(
                "Python script failed: {}",
                String::from_utf8_lossy(&output.stderr)
            )));
        }

        let output_str = String::from_utf8_lossy(&output.stdout);
        let info: serde_json::Value = serde_json::from_str(&output_str).map_err(|e| {
            StatsError::ComputationError(format!("Failed to parse environment info: {}", e))
        })?;

        Ok(ScipyEnvironmentInfo {
            python_version: info["python_version"]
                .as_str()
                .unwrap_or("unknown")
                .to_string(),
            scipy_version: info["scipy_version"]
                .as_str()
                .unwrap_or("unknown")
                .to_string(),
            numpy_version: info["numpy_version"]
                .as_str()
                .unwrap_or("unknown")
                .to_string(),
            blas_info: info["blas_info"].as_str().unwrap_or("unknown").to_string(),
            packages: info["packages"]
                .as_object()
                .unwrap_or(&serde_json::Map::new())
                .iter()
                .map(|(k, v)| (k.clone(), v.as_str().unwrap_or("unknown").to_string()))
                .collect(),
        })
    }

    /// Collect system information
    fn collect_system_info(&self) -> SystemInfo {
        SystemInfo {
            os: std::env::consts::OS.to_string(),
            cpu: "Generic CPU".to_string(), // Would use proper CPU detection
            memory_gb: 8.0,                 // Placeholder
            rust_version: std::env::var("RUSTC_VERSION").unwrap_or_else(|_| "unknown".to_string()),
            scirs2_version: std::env::var("CARGO_PKG_VERSION")
                .unwrap_or_else(|_| "unknown".to_string()),
        }
    }

    /// Compare a single function between scirs2-stats and SciPy
    fn compare_function(
        &self,
        function_name: &str,
        datasize: usize,
    ) -> StatsResult<FunctionComparison> {
        // Generate test data
        let testdata = self.generate_testdata(datasize)?;

        // Benchmark scirs2-stats function
        let scirs2_result = self.benchmark_scirs2_function(function_name, &testdata)?;

        // Benchmark SciPy function
        let scipy_result = self.benchmark_scipy_function(function_name, &testdata)?;

        // Compare performance
        let performance = PerformanceComparison {
            scirs2_time_ns: scirs2_result.execution_time.as_nanos() as f64,
            scipy_time_ns: scipy_result.execution_time.as_nanos() as f64,
            ratio: scirs2_result.execution_time.as_nanos() as f64
                / scipy_result.execution_time.as_nanos() as f64,
            significance: PerformanceSignificance::NotSignificant, // Simplified
            confidence_interval: (0.8, 1.2),                       // Placeholder
        };

        // Compare accuracy
        let accuracy = self.compare_accuracy(&scirs2_result.result, &scipy_result.result)?;

        // Determine status
        let status = self.determine_comparison_status(&performance, &accuracy);

        Ok(FunctionComparison {
            function_name: function_name.to_string(),
            datasize,
            performance,
            accuracy,
            memory: None, // Would implement memory comparison
            status,
            error_details: None,
        })
    }

    /// Generate test data for benchmarking
    fn generate_testdata(&self, size: usize) -> StatsResult<TestData> {
        use scirs2_core::random::{Distribution, Normal};

        let mut rng = scirs2_core::random::thread_rng();
        let normal = Normal::new(0.0, 1.0).map_err(|e| {
            StatsError::ComputationError(format!("Failed to create normal distribution: {}", e))
        })?;

        let data: Vec<f64> = (0..size).map(|_| normal.sample(&mut rng)).collect();

        Ok(TestData {
            primary: Array1::from_vec(data.clone()),
            secondary: Array1::from_vec(
                data.iter()
                    .map(|x| x + 0.1 * normal.sample(&mut rng))
                    .collect(),
            ),
            matrix: Array2::from_shape_fn((size.min(100), size.min(100)), |(i, j)| {
                normal.sample(&mut rng) + 0.1 * (i + j) as f64
            }),
        })
    }

    /// Benchmark scirs2-stats function
    fn benchmark_scirs2_function(
        &self,
        function_name: &str,
        testdata: &TestData,
    ) -> StatsResult<BenchmarkResult> {
        let start_time = Instant::now();

        let result = match function_name {
            "mean" => {
                vec![crate::descriptive::mean(&testdata.primary.view())?]
            }
            "std" => {
                vec![crate::descriptive::std(&testdata.primary.view(), 1, None)?]
            }
            "var" => {
                vec![crate::descriptive::var(&testdata.primary.view(), 1, None)?]
            }
            "skew" => {
                vec![crate::descriptive::skew(
                    &testdata.primary.view(),
                    false,
                    None,
                )?]
            }
            "kurtosis" => {
                vec![crate::descriptive::kurtosis(
                    &testdata.primary.view(),
                    true,
                    false,
                    None,
                )?]
            }
            "pearsonr" => {
                let corr = crate::correlation::pearson_r(
                    &testdata.primary.view(),
                    &testdata.secondary.view(),
                )?;
                vec![corr]
            }
            "spearmanr" => {
                let corr = crate::correlation::spearman_r(
                    &testdata.primary.view(),
                    &testdata.secondary.view(),
                )?;
                vec![corr]
            }
            "ttest_1samp" => {
                let result = crate::tests::ttest::ttest_1samp(
                    &testdata.primary.view(),
                    0.0,
                    crate::tests::ttest::Alternative::TwoSided,
                    "propagate",
                )?;
                vec![result.statistic, result.pvalue]
            }
            _ => {
                return Err(StatsError::NotImplemented(format!(
                    "Function {} not implemented in benchmark",
                    function_name
                )));
            }
        };

        let execution_time = start_time.elapsed();

        Ok(BenchmarkResult {
            result,
            execution_time,
        })
    }

    /// Benchmark SciPy function
    fn benchmark_scipy_function(
        &self,
        function_name: &str,
        testdata: &TestData,
    ) -> StatsResult<BenchmarkResult> {
        let script = self.generate_scipy_script(function_name, testdata)?;
        let script_path = format!("{}/scipy_benchmark_{}.py", self.temp_dir, function_name);

        fs::write(&script_path, script).map_err(|e| {
            StatsError::ComputationError(format!("Failed to write SciPy script: {}", e))
        })?;

        let output = Command::new(&self.config.python_executable)
            .arg(&script_path)
            .output()
            .map_err(|e| {
                StatsError::ComputationError(format!("Failed to execute SciPy script: {}", e))
            })?;

        if !output.status.success() {
            return Err(StatsError::ComputationError(format!(
                "SciPy script failed: {}",
                String::from_utf8_lossy(&output.stderr)
            )));
        }

        let output_str = String::from_utf8_lossy(&output.stdout);
        let result: serde_json::Value = serde_json::from_str(&output_str).map_err(|e| {
            StatsError::ComputationError(format!("Failed to parse SciPy result: {}", e))
        })?;

        let execution_time =
            Duration::from_secs_f64(result["execution_time"].as_f64().unwrap_or(0.0));

        let result_values: Vec<f64> = result["result"]
            .as_array()
            .unwrap_or(&Vec::new())
            .iter()
            .filter_map(|v| v.as_f64())
            .collect();

        Ok(BenchmarkResult {
            result: result_values,
            execution_time,
        })
    }

    /// Generate SciPy benchmark script
    fn generate_scipy_script(
        &self,
        function_name: &str,
        testdata: &TestData,
    ) -> StatsResult<String> {
        let data_primary: Vec<String> = testdata.primary.iter().map(|x| x.to_string()).collect();
        let data_secondary: Vec<String> =
            testdata.secondary.iter().map(|x| x.to_string()).collect();

        let script = match function_name {
            "mean" => {
                format!(
                    r#"
import numpy as np
import time
import json

data = np.array([{}])

start_time = time.perf_counter()
result = np.mean(data)
execution_time = time.perf_counter() - start_time

output = {{
    'result': [float(result)],
    'execution_time': execution_time
}}

print(json.dumps(output))
"#,
                    data_primary.join(", ")
                )
            }
            "std" => {
                format!(
                    r#"
import numpy as np
import time
import json

data = np.array([{}])

start_time = time.perf_counter()
result = np.std(data, ddof=1)
execution_time = time.perf_counter() - start_time

output = {{
    'result': [float(result)],
    'execution_time': execution_time
}}

print(json.dumps(output))
"#,
                    data_primary.join(", ")
                )
            }
            "pearsonr" => {
                format!(
                    r#"
import numpy as np
import scipy.stats
import time
import json

data1 = np.array([{}])
data2 = np.array([{}])

start_time = time.perf_counter()
corr, p_value = scipy.stats.pearsonr(data1, data2)
execution_time = time.perf_counter() - start_time

output = {{
    'result': [float(corr)],
    'execution_time': execution_time
}}

print(json.dumps(output))
"#,
                    data_primary.join(", "),
                    data_secondary.join(", ")
                )
            }
            _ => {
                return Err(StatsError::NotImplemented(format!(
                    "SciPy script generation not implemented for {}",
                    function_name
                )));
            }
        };

        Ok(script)
    }

    /// Compare accuracy between results
    fn compare_accuracy(
        &self,
        scirs2_result: &[f64],
        scipy_result: &[f64],
    ) -> StatsResult<AccuracyComparison> {
        if scirs2_result.len() != scipy_result.len() {
            return Ok(AccuracyComparison {
                absolute_difference: f64::INFINITY,
                relative_difference: f64::INFINITY,
                max_element_difference: f64::INFINITY,
                elements_compared: 0,
                elements_within_tolerance: 0,
                assessment: AccuracyAssessment::Unacceptable,
            });
        }

        let mut abs_diffs = Vec::new();
        let mut rel_diffs = Vec::new();
        let mut within_tolerance = 0;

        for (s, r) in scirs2_result.iter().zip(scipy_result.iter()) {
            let abs_diff = (s - r).abs();
            let rel_diff = if r.abs() > 1e-10 {
                abs_diff / r.abs()
            } else {
                abs_diff
            };

            abs_diffs.push(abs_diff);
            rel_diffs.push(rel_diff);

            if abs_diff < self.config.accuracy_tolerance
                || rel_diff < self.config.accuracy_tolerance
            {
                within_tolerance += 1;
            }
        }

        let avg_abs_diff = abs_diffs.iter().sum::<f64>() / abs_diffs.len() as f64;
        let avg_rel_diff = rel_diffs.iter().sum::<f64>() / rel_diffs.len() as f64;
        let max_element_diff = abs_diffs.iter().fold(0.0f64, |acc, &x| acc.max(x));

        let assessment = if within_tolerance == scirs2_result.len() {
            if avg_rel_diff < 1e-14 {
                AccuracyAssessment::Excellent
            } else if avg_rel_diff < 1e-10 {
                AccuracyAssessment::Good
            } else {
                AccuracyAssessment::Acceptable
            }
        } else if within_tolerance as f64 / scirs2_result.len() as f64 > 0.9 {
            AccuracyAssessment::Acceptable
        } else if within_tolerance as f64 / scirs2_result.len() as f64 > 0.5 {
            AccuracyAssessment::Poor
        } else {
            AccuracyAssessment::Unacceptable
        };

        Ok(AccuracyComparison {
            absolute_difference: avg_abs_diff,
            relative_difference: avg_rel_diff,
            max_element_difference: max_element_diff,
            elements_compared: scirs2_result.len(),
            elements_within_tolerance: within_tolerance,
            assessment,
        })
    }

    /// Determine comparison status
    fn determine_comparison_status(
        &self,
        performance: &PerformanceComparison,
        accuracy: &AccuracyComparison,
    ) -> ComparisonStatus {
        let mut warnings = Vec::new();

        // Check accuracy
        if matches!(
            accuracy.assessment,
            AccuracyAssessment::Unacceptable | AccuracyAssessment::Poor
        ) {
            return ComparisonStatus::FailedAccuracy {
                details: format!("Relative difference: {:.2e}", accuracy.relative_difference),
            };
        }

        // Check performance
        if performance.ratio > self.config.performance_tolerance {
            return ComparisonStatus::FailedPerformance {
                details: format!(
                    "Performance ratio: {:.2} (limit: {:.2})",
                    performance.ratio, self.config.performance_tolerance
                ),
            };
        }

        // Check for warnings
        if matches!(accuracy.assessment, AccuracyAssessment::Acceptable) {
            warnings.push("Accuracy is only acceptable".to_string());
        }

        if performance.ratio > 1.5 {
            warnings.push(format!(
                "Performance is {:.1}x slower than SciPy",
                performance.ratio
            ));
        }

        if warnings.is_empty() {
            ComparisonStatus::Passed
        } else {
            ComparisonStatus::PassedWithWarnings { warnings }
        }
    }

    /// Generate comparison summary
    fn generate_summary(&self, comparisons: &[FunctionComparison]) -> ComparisonSummary {
        let total_tests = comparisons.len();
        let tests_passed = comparisons
            .iter()
            .filter(|c| matches!(c.status, ComparisonStatus::Passed))
            .count();
        let tests_with_warnings = comparisons
            .iter()
            .filter(|c| matches!(c.status, ComparisonStatus::PassedWithWarnings { .. }))
            .count();
        let tests_failed = total_tests - tests_passed - tests_with_warnings;

        let pass_rate = if total_tests > 0 {
            (tests_passed + tests_with_warnings) as f64 / total_tests as f64
        } else {
            0.0
        };

        let performance_issues: Vec<String> = comparisons
            .iter()
            .filter(|c| matches!(c.status, ComparisonStatus::FailedPerformance { .. }))
            .map(|c| c.function_name.clone())
            .collect();

        let accuracy_issues: Vec<String> = comparisons
            .iter()
            .filter(|c| matches!(c.status, ComparisonStatus::FailedAccuracy { .. }))
            .map(|c| c.function_name.clone())
            .collect();

        let avg_performance_ratio =
            comparisons.iter().map(|c| c.performance.ratio).sum::<f64>() / comparisons.len() as f64;

        let performance_rating = if avg_performance_ratio < 0.8 {
            PerformanceRating::Excellent
        } else if avg_performance_ratio < 1.2 {
            PerformanceRating::Good
        } else if avg_performance_ratio < 2.0 {
            PerformanceRating::Acceptable
        } else if avg_performance_ratio < 5.0 {
            PerformanceRating::Poor
        } else {
            PerformanceRating::Unacceptable
        };

        let avg_relative_diff = comparisons
            .iter()
            .map(|c| c.accuracy.relative_difference)
            .sum::<f64>()
            / comparisons.len() as f64;

        let accuracy_rating = if avg_relative_diff < 1e-14 {
            AccuracyRating::Excellent
        } else if avg_relative_diff < 1e-10 {
            AccuracyRating::Good
        } else if avg_relative_diff < 1e-6 {
            AccuracyRating::Acceptable
        } else if avg_relative_diff < 1e-3 {
            AccuracyRating::Poor
        } else {
            AccuracyRating::Unacceptable
        };

        ComparisonSummary {
            total_tests,
            tests_passed,
            tests_with_warnings,
            tests_failed,
            pass_rate,
            performance_issues,
            accuracy_issues,
            performance_rating,
            accuracy_rating,
        }
    }

    /// Analyze performance across all comparisons
    fn analyze_performance(&self, comparisons: &[FunctionComparison]) -> PerformanceAnalysis {
        let ratios: Vec<f64> = comparisons.iter().map(|c| c.performance.ratio).collect();

        let average_ratio = ratios.iter().sum::<f64>() / ratios.len() as f64;
        let variance = ratios
            .iter()
            .map(|r| (r - average_ratio).powi(2))
            .sum::<f64>()
            / ratios.len() as f64;
        let ratio_std_dev = variance.sqrt();

        let faster_functions: Vec<(String, f64)> = comparisons
            .iter()
            .filter(|c| c.performance.ratio < 1.0)
            .map(|c| (c.function_name.clone(), c.performance.ratio))
            .collect();

        let slower_functions: Vec<(String, f64)> = comparisons
            .iter()
            .filter(|c| c.performance.ratio > 1.0)
            .map(|c| (c.function_name.clone(), c.performance.ratio))
            .collect();

        let performance_bysize = HashMap::new(); // Would implement proper analysis

        let trends = PerformanceTrends {
            scaling_analysis: ScalingAnalysis {
                relative_scaling: 1.0, // Placeholder
                complexity_assessment: ComplexityAssessment::Similar,
                crossover_points: Vec::new(),
            },
            stability_analysis: StabilityAnalysis {
                performance_cv: ratio_std_dev / average_ratio,
                outliers_detected: 0, // Would implement outlier detection
                stability_rating: StabilityRating::Stable,
            },
            regression_analysis: RegressionAnalysis {
                regressions_detected: Vec::new(),
                accuracy_regressions: Vec::new(),
                regression_risk: RegressionRisk::Low,
            },
        };

        PerformanceAnalysis {
            average_ratio,
            ratio_std_dev,
            faster_functions,
            slower_functions,
            performance_bysize,
            trends,
        }
    }

    /// Analyze accuracy across all comparisons
    fn analyze_accuracy(&self, comparisons: &[FunctionComparison]) -> AccuracyAnalysis {
        let relative_diffs: Vec<f64> = comparisons
            .iter()
            .map(|c| c.accuracy.relative_difference)
            .collect();

        let average_relative_diff =
            relative_diffs.iter().sum::<f64>() / relative_diffs.len() as f64;
        let max_relative_diff = relative_diffs.iter().fold(0.0f64, |acc, &x| acc.max(x));

        let problematic_functions: Vec<(String, f64)> = comparisons
            .iter()
            .filter(|c| c.accuracy.relative_difference > self.config.accuracy_tolerance)
            .map(|c| (c.function_name.clone(), c.accuracy.relative_difference))
            .collect();

        let accuracy_bysize = HashMap::new(); // Would implement proper analysis

        let stability_assessment = NumericalStabilityAssessment {
            stability_rating: if max_relative_diff < 1e-10 {
                NumericalStabilityRating::Excellent
            } else if max_relative_diff < 1e-6 {
                NumericalStabilityRating::Good
            } else {
                NumericalStabilityRating::Acceptable
            },
            unstable_functions: problematic_functions
                .iter()
                .map(|(name, _)| name.clone())
                .collect(),
            condition_number_analysis: ConditionNumberAnalysis {
                sensitive_functions: Vec::new(),
                thresholds: HashMap::new(),
                recommendations: Vec::new(),
            },
            precision_loss_analysis: PrecisionLossAnalysis {
                average_loss: average_relative_diff,
                max_loss: max_relative_diff,
                problematic_functions: problematic_functions
                    .iter()
                    .map(|(name, _)| name.clone())
                    .collect(),
            },
        };

        AccuracyAnalysis {
            average_relative_diff,
            max_relative_diff,
            problematic_functions,
            accuracy_bysize,
            stability_assessment,
        }
    }

    /// Generate recommendations based on analysis
    fn generate_recommendations(
        &self,
        comparisons: &[FunctionComparison],
        performance_analysis: &PerformanceAnalysis,
        accuracy_analysis: &AccuracyAnalysis,
    ) -> Vec<ComparisonRecommendation> {
        let mut recommendations = Vec::new();

        // Performance recommendations
        if performance_analysis.average_ratio > 2.0 {
            recommendations.push(ComparisonRecommendation {
                priority: RecommendationPriority::High,
                category: RecommendationCategory::Performance,
                description: "Overall performance is significantly slower than SciPy. Consider SIMD optimizations and algorithm improvements.".to_string(),
                affected_functions: performance_analysis.slower_functions.iter().map(|(name, _)| name.clone()).collect(),
                complexity: ImplementationComplexity::Moderate,
                expected_impact: ExpectedImpact {
                    performance_improvement: Some(2.0),
                    accuracy_improvement: None,
                    memory_reduction: None,
                    implementation_effort: 20.0,
                },
            });
        }

        // Accuracy recommendations
        if accuracy_analysis.max_relative_diff > 1e-6 {
            recommendations.push(ComparisonRecommendation {
                priority: RecommendationPriority::Critical,
                category: RecommendationCategory::Accuracy,
                description: "Some functions have significant accuracy differences compared to SciPy. Review numerical algorithms.".to_string(),
                affected_functions: accuracy_analysis.problematic_functions.iter().map(|(name, _)| name.clone()).collect(),
                complexity: ImplementationComplexity::Complex,
                expected_impact: ExpectedImpact {
                    performance_improvement: None,
                    accuracy_improvement: Some(10.0),
                    memory_reduction: None,
                    implementation_effort: 15.0,
                },
            });
        }

        // Function-specific recommendations
        for comparison in comparisons {
            if comparison.performance.ratio > 5.0 {
                recommendations.push(ComparisonRecommendation {
                    priority: RecommendationPriority::High,
                    category: RecommendationCategory::Performance,
                    description: format!(
                        "Function '{}' is significantly slower than SciPy",
                        comparison.function_name
                    ),
                    affected_functions: vec![comparison.function_name.clone()],
                    complexity: ImplementationComplexity::Moderate,
                    expected_impact: ExpectedImpact {
                        performance_improvement: Some(3.0),
                        accuracy_improvement: None,
                        memory_reduction: None,
                        implementation_effort: 5.0,
                    },
                });
            }
        }

        recommendations
    }
}

/// Test data structure for benchmarking
#[derive(Debug, Clone)]
struct TestData {
    primary: Array1<f64>,
    secondary: Array1<f64>,
    #[allow(dead_code)]
    matrix: Array2<f64>,
}

/// Benchmark result structure
#[derive(Debug, Clone)]
struct BenchmarkResult {
    result: Vec<f64>,
    execution_time: Duration,
}

/// Convenience function to run SciPy comparison
#[allow(dead_code)]
pub fn run_scipy_comparison() -> StatsResult<ScipyComparisonReport> {
    let comparison = ScipyBenchmarkComparison::default()?;
    comparison.run_comprehensive_comparison()
}

/// Run comparison for specific functions
#[allow(dead_code)]
pub fn run_function_comparison(functions: Vec<String>) -> StatsResult<ScipyComparisonReport> {
    let mut config = ScipyComparisonConfig::default();
    config.functions_to_test = functions;

    let comparison = ScipyBenchmarkComparison::new(config)?;
    comparison.run_comprehensive_comparison()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_scipy_comparison_config() {
        let config = ScipyComparisonConfig::default();
        assert!(!config.functions_to_test.is_empty());
        assert!(config.accuracy_tolerance > 0.0);
        assert!(config.performance_tolerance > 1.0);
    }

    #[test]
    fn test_testdata_generation() {
        let comparison = ScipyBenchmarkComparison::default().expect("Operation failed");
        let testdata = comparison.generate_testdata(100).expect("Operation failed");

        assert_eq!(testdata.primary.len(), 100);
        assert_eq!(testdata.secondary.len(), 100);
        assert_eq!(testdata.matrix.nrows(), 100);
    }

    #[test]
    fn test_accuracy_comparison() {
        let comparison = ScipyBenchmarkComparison::default().expect("Operation failed");

        // Use very small differences well within tolerance (< 1e-12)
        let scirs2_result = vec![1.0, 2.0, 3.0];
        let scipy_result = vec![1.000000000001, 2.000000000001, 3.000000000001];

        let accuracy = comparison
            .compare_accuracy(&scirs2_result, &scipy_result)
            .expect("Operation failed");
        assert!(matches!(
            accuracy.assessment,
            AccuracyAssessment::Excellent | AccuracyAssessment::Good
        ));
    }

    #[test]
    fn test_performance_comparison() {
        let performance = PerformanceComparison {
            scirs2_time_ns: 1000.0,
            scipy_time_ns: 800.0,
            ratio: 1.25,
            significance: PerformanceSignificance::NotSignificant,
            confidence_interval: (1.0, 1.5),
        };

        assert!(performance.ratio > 1.0); // scirs2 slower
    }

    #[test]
    fn test_recommendation_generation() {
        let config = ScipyComparisonConfig::default();
        assert!(config.performance_tolerance >= 1.0);
        assert!(config.accuracy_tolerance > 0.0);
    }
}