1use super::{
4 ApplicationError, ApplicationResult, Duration, ExpectedMetrics, HashMap, PlatformAvailability,
5 PlatformConfig, PlatformType, ProblemSpecification, ProblemType, TestExecutionResult,
6};
7
8#[derive(Debug)]
10pub struct CrossPlatformValidator {
11 pub platforms: Vec<Platform>,
13 pub test_suites: HashMap<String, CrossPlatformTestSuite>,
15 pub compatibility_matrix: CompatibilityMatrix,
17 pub platform_configs: HashMap<String, PlatformConfig>,
19}
20
21#[derive(Debug, Clone)]
23pub struct Platform {
24 pub id: String,
26 pub platform_type: PlatformType,
28 pub availability: PlatformAvailability,
30 pub capabilities: PlatformCapabilities,
32 pub performance: PlatformPerformance,
34}
35
36#[derive(Debug, Clone)]
38pub struct PlatformCapabilities {
39 pub max_problem_size: usize,
41 pub supported_types: Vec<ProblemType>,
43 pub native_constraints: bool,
45 pub requires_embedding: bool,
47}
48
49#[derive(Debug, Clone)]
51pub struct PlatformPerformance {
52 pub runtime_range: (Duration, Duration),
54 pub quality_range: (f64, f64),
56 pub reliability: f64,
58 pub cost_per_problem: Option<f64>,
60}
61
62#[derive(Debug)]
64pub struct CrossPlatformTestSuite {
65 pub id: String,
67 pub test_cases: Vec<CrossPlatformTestCase>,
69 pub comparison_criteria: Vec<ComparisonCriterion>,
71 pub expected_differences: HashMap<String, ExpectedDifference>,
73}
74
75#[derive(Debug, Clone)]
77pub struct CrossPlatformTestCase {
78 pub id: String,
80 pub problem: ProblemSpecification,
82 pub platform_params: HashMap<String, PlatformSpecificParams>,
84 pub expected_results: HashMap<String, ExpectedMetrics>,
86}
87
88#[derive(Debug, Clone)]
90pub struct PlatformSpecificParams {
91 pub annealing_params: HashMap<String, f64>,
93 pub solver_settings: HashMap<String, String>,
95 pub resource_limits: HashMap<String, f64>,
97}
98
99#[derive(Debug, Clone)]
101pub struct ComparisonCriterion {
102 pub id: String,
104 pub metric: String,
106 pub comparison_type: ComparisonType,
108 pub tolerance: f64,
110 pub critical: bool,
112}
113
114#[derive(Debug, Clone, PartialEq, Eq)]
116pub enum ComparisonType {
117 AbsoluteDifference,
119 RelativeDifference,
121 StatisticalEquivalence,
123 Ranking,
125}
126
127#[derive(Debug, Clone)]
129pub struct ExpectedDifference {
130 pub platform_pair: (String, String),
132 pub difference_range: (f64, f64),
134 pub reason: String,
136 pub acceptable: bool,
138}
139
140#[derive(Debug)]
142pub struct CompatibilityMatrix {
143 pub feature_compatibility: HashMap<String, HashMap<String, CompatibilityLevel>>,
145 pub performance_compatibility: HashMap<String, HashMap<String, f64>>,
147 pub known_issues: HashMap<String, Vec<CompatibilityIssue>>,
149}
150
151#[derive(Debug, Clone, PartialEq, Eq)]
153pub enum CompatibilityLevel {
154 Full,
156 Partial,
158 Incompatible,
160 Unknown,
162}
163
164#[derive(Debug, Clone)]
166pub struct CompatibilityIssue {
167 pub id: String,
169 pub description: String,
171 pub severity: IssueSeverity,
173 pub workaround: Option<String>,
175 pub affected_features: Vec<String>,
177}
178
179#[derive(Debug, Clone, PartialEq, Eq)]
181pub enum IssueSeverity {
182 Critical,
184 Major,
186 Minor,
188 Cosmetic,
190}
191
192impl CrossPlatformValidator {
193 #[must_use]
194 pub fn new() -> Self {
195 Self {
196 platforms: Self::create_default_platforms(),
197 test_suites: HashMap::new(),
198 compatibility_matrix: CompatibilityMatrix {
199 feature_compatibility: HashMap::new(),
200 performance_compatibility: HashMap::new(),
201 known_issues: HashMap::new(),
202 },
203 platform_configs: HashMap::new(),
204 }
205 }
206
207 fn create_default_platforms() -> Vec<Platform> {
209 vec![
210 Platform {
211 id: "classical_simulator".to_string(),
212 platform_type: PlatformType::Classical,
213 availability: PlatformAvailability::Available,
214 capabilities: PlatformCapabilities {
215 max_problem_size: 10_000,
216 supported_types: vec![
217 ProblemType::RandomIsing,
218 ProblemType::MaxCut,
219 ProblemType::VertexCover,
220 ProblemType::TSP,
221 ProblemType::Portfolio,
222 ],
223 native_constraints: true,
224 requires_embedding: false,
225 },
226 performance: PlatformPerformance {
227 runtime_range: (Duration::from_millis(1), Duration::from_secs(3600)),
228 quality_range: (0.8, 1.0),
229 reliability: 0.99,
230 cost_per_problem: Some(0.0),
231 },
232 },
233 Platform {
234 id: "dwave_simulator".to_string(),
235 platform_type: PlatformType::DWave,
236 availability: PlatformAvailability::RequiresAuth,
237 capabilities: PlatformCapabilities {
238 max_problem_size: 5000,
239 supported_types: vec![ProblemType::RandomIsing, ProblemType::MaxCut],
240 native_constraints: false,
241 requires_embedding: true,
242 },
243 performance: PlatformPerformance {
244 runtime_range: (Duration::from_millis(20), Duration::from_secs(20)),
245 quality_range: (0.7, 0.95),
246 reliability: 0.95,
247 cost_per_problem: Some(0.00_037),
248 },
249 },
250 Platform {
251 id: "aws_braket".to_string(),
252 platform_type: PlatformType::AWSBraket,
253 availability: PlatformAvailability::RequiresAuth,
254 capabilities: PlatformCapabilities {
255 max_problem_size: 2000,
256 supported_types: vec![ProblemType::RandomIsing, ProblemType::MaxCut],
257 native_constraints: false,
258 requires_embedding: true,
259 },
260 performance: PlatformPerformance {
261 runtime_range: (Duration::from_secs(1), Duration::from_secs(300)),
262 quality_range: (0.6, 0.9),
263 reliability: 0.92,
264 cost_per_problem: Some(0.001),
265 },
266 },
267 ]
268 }
269
270 pub fn add_platform(&mut self, platform: Platform) {
272 self.platforms.push(platform);
273 }
274
275 #[must_use]
277 pub fn get_platform(&self, platform_id: &str) -> Option<&Platform> {
278 self.platforms.iter().find(|p| p.id == platform_id)
279 }
280
281 pub fn add_test_suite(&mut self, suite: CrossPlatformTestSuite) {
283 self.test_suites.insert(suite.id.clone(), suite);
284 }
285
286 pub fn run_validation(
288 &self,
289 suite_id: &str,
290 ) -> ApplicationResult<CrossPlatformValidationResult> {
291 let suite = self.test_suites.get(suite_id).ok_or_else(|| {
292 ApplicationError::ConfigurationError(format!("Test suite not found: {suite_id}"))
293 })?;
294
295 let mut platform_results = HashMap::new();
296 let mut comparison_results = Vec::new();
297
298 for platform in &self.platforms {
300 if platform.availability == PlatformAvailability::Available {
301 let results = self.run_suite_on_platform(suite, platform)?;
302 platform_results.insert(platform.id.clone(), results);
303 }
304 }
305
306 for criterion in &suite.comparison_criteria {
308 let comparison = self.compare_platforms(&platform_results, criterion)?;
309 comparison_results.push(comparison);
310 }
311
312 let compatibility_score = self.calculate_compatibility_score(&comparison_results);
314
315 Ok(CrossPlatformValidationResult {
316 suite_id: suite_id.to_string(),
317 platform_results,
318 comparison_results,
319 compatibility_score,
320 validation_time: Duration::from_secs(60), })
322 }
323
324 fn run_suite_on_platform(
326 &self,
327 suite: &CrossPlatformTestSuite,
328 platform: &Platform,
329 ) -> ApplicationResult<PlatformTestResults> {
330 let mut test_results = HashMap::new();
331
332 for test_case in &suite.test_cases {
333 if !self.is_test_supported(test_case, platform) {
335 continue;
336 }
337
338 let result = self.run_test_case_on_platform(test_case, platform)?;
339 test_results.insert(test_case.id.clone(), result);
340 }
341
342 Ok(PlatformTestResults {
343 platform_id: platform.id.clone(),
344 test_results,
345 platform_info: platform.clone(),
346 execution_time: Duration::from_secs(30), })
348 }
349
350 fn is_test_supported(&self, test_case: &CrossPlatformTestCase, platform: &Platform) -> bool {
352 platform
353 .capabilities
354 .supported_types
355 .contains(&test_case.problem.problem_type)
356 }
357
358 fn run_test_case_on_platform(
360 &self,
361 test_case: &CrossPlatformTestCase,
362 platform: &Platform,
363 ) -> ApplicationResult<TestExecutionResult> {
364 let base_quality = match platform.platform_type {
366 PlatformType::Classical => 0.95,
367 PlatformType::DWave => 0.85,
368 PlatformType::AWSBraket => 0.80,
369 PlatformType::FujitsuDA => 0.88,
370 PlatformType::Custom(_) => 0.75,
371 };
372
373 let problem_size = usize::midpoint(
374 test_case.problem.size_range.0,
375 test_case.problem.size_range.1,
376 );
377 let size_factor = (problem_size as f64 / 1000.0).min(1.0);
378 let quality = base_quality * (1.0 - size_factor * 0.2);
379
380 Ok(TestExecutionResult {
381 solution_quality: quality,
382 execution_time: Duration::from_millis((problem_size as u64).min(5000)),
383 final_energy: -quality * problem_size as f64,
384 best_solution: vec![1; problem_size],
385 convergence_achieved: true,
386 memory_used: problem_size * 8,
387 })
388 }
389
390 fn compare_platforms(
392 &self,
393 platform_results: &HashMap<String, PlatformTestResults>,
394 criterion: &ComparisonCriterion,
395 ) -> ApplicationResult<ComparisonResult> {
396 let mut metric_values = HashMap::new();
397
398 for (platform_id, results) in platform_results {
400 let values: Vec<f64> = results
401 .test_results
402 .values()
403 .map(|result| self.extract_metric_value(result, &criterion.metric))
404 .collect();
405
406 if !values.is_empty() {
407 let mean_value = values.iter().sum::<f64>() / values.len() as f64;
408 metric_values.insert(platform_id.clone(), mean_value);
409 }
410 }
411
412 let mut differences = HashMap::new();
414 let platforms: Vec<_> = metric_values.keys().collect();
415
416 for i in 0..platforms.len() {
417 for j in (i + 1)..platforms.len() {
418 let platform1 = platforms[i];
419 let platform2 = platforms[j];
420 let value1 = metric_values[platform1];
421 let value2 = metric_values[platform2];
422
423 let difference = match criterion.comparison_type {
424 ComparisonType::AbsoluteDifference => (value1 - value2).abs(),
425 ComparisonType::RelativeDifference => {
426 ((value1 - value2) / value1.max(value2)).abs()
427 }
428 _ => (value1 - value2).abs(), };
430
431 let pair_key = format!("{platform1}_{platform2}");
432 differences.insert(pair_key, difference);
433 }
434 }
435
436 let max_difference = differences
438 .values()
439 .fold(0.0f64, |max, &diff| max.max(diff));
440 let within_tolerance = max_difference <= criterion.tolerance;
441
442 Ok(ComparisonResult {
443 criterion_id: criterion.id.clone(),
444 metric: criterion.metric.clone(),
445 platform_values: metric_values,
446 differences,
447 max_difference,
448 within_tolerance,
449 critical: criterion.critical,
450 })
451 }
452
453 fn extract_metric_value(&self, result: &TestExecutionResult, metric: &str) -> f64 {
455 match metric {
456 "solution_quality" => result.solution_quality,
457 "execution_time" => result.execution_time.as_secs_f64(),
458 "final_energy" => result.final_energy,
459 "memory_used" => result.memory_used as f64,
460 _ => 0.0,
461 }
462 }
463
464 fn calculate_compatibility_score(&self, comparison_results: &[ComparisonResult]) -> f64 {
466 if comparison_results.is_empty() {
467 return 1.0;
468 }
469
470 let total_weight: f64 = comparison_results
471 .iter()
472 .map(|r| if r.critical { 2.0 } else { 1.0 })
473 .sum();
474
475 let weighted_score: f64 = comparison_results
476 .iter()
477 .map(|r| {
478 let score = if r.within_tolerance { 1.0 } else { 0.0 };
479 let weight = if r.critical { 2.0 } else { 1.0 };
480 score * weight
481 })
482 .sum();
483
484 weighted_score / total_weight
485 }
486
487 #[must_use]
489 pub fn get_compatibility(&self, platform1: &str, platform2: &str) -> CompatibilityInfo {
490 let feature_compat = self
491 .compatibility_matrix
492 .feature_compatibility
493 .get(platform1)
494 .and_then(|map| map.get(platform2))
495 .unwrap_or(&CompatibilityLevel::Unknown);
496
497 let performance_compat = self
498 .compatibility_matrix
499 .performance_compatibility
500 .get(platform1)
501 .and_then(|map| map.get(platform2))
502 .unwrap_or(&0.5);
503
504 let default_issues = Vec::new();
505 let issues = self
506 .compatibility_matrix
507 .known_issues
508 .get(&format!("{platform1}_{platform2}"))
509 .unwrap_or(&default_issues);
510
511 CompatibilityInfo {
512 platform_pair: (platform1.to_string(), platform2.to_string()),
513 feature_compatibility: feature_compat.clone(),
514 performance_compatibility: *performance_compat,
515 known_issues: issues.clone(),
516 }
517 }
518}
519
520#[derive(Debug)]
522pub struct CrossPlatformValidationResult {
523 pub suite_id: String,
525 pub platform_results: HashMap<String, PlatformTestResults>,
527 pub comparison_results: Vec<ComparisonResult>,
529 pub compatibility_score: f64,
531 pub validation_time: Duration,
533}
534
535#[derive(Debug)]
537pub struct PlatformTestResults {
538 pub platform_id: String,
540 pub test_results: HashMap<String, TestExecutionResult>,
542 pub platform_info: Platform,
544 pub execution_time: Duration,
546}
547
548#[derive(Debug)]
550pub struct ComparisonResult {
551 pub criterion_id: String,
553 pub metric: String,
555 pub platform_values: HashMap<String, f64>,
557 pub differences: HashMap<String, f64>,
559 pub max_difference: f64,
561 pub within_tolerance: bool,
563 pub critical: bool,
565}
566
567#[derive(Debug, Clone)]
569pub struct CompatibilityInfo {
570 pub platform_pair: (String, String),
572 pub feature_compatibility: CompatibilityLevel,
574 pub performance_compatibility: f64,
576 pub known_issues: Vec<CompatibilityIssue>,
578}