1use serde::{Deserialize, Serialize};
7use thiserror::Error;
8
9#[derive(Error, Debug, Clone, PartialEq)]
11pub enum ExperimentError {
12 #[error("Invalid compute device configuration: {0}")]
13 InvalidComputeDevice(String),
14
15 #[error("Metrics collection failed: {0}")]
16 MetricsCollectionFailed(String),
17
18 #[error("Pareto frontier calculation failed: {0}")]
19 ParetoFrontierFailed(String),
20
21 #[error("Invalid ORCID format: {0}")]
22 InvalidOrcid(String),
23
24 #[error("Citation generation failed: {0}")]
25 CitationGenerationFailed(String),
26
27 #[error("Sovereign distribution validation failed: {0}")]
28 SovereignValidationFailed(String),
29
30 #[error("Experiment storage error: {0}")]
31 StorageError(String),
32}
33
34#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
36pub enum ComputeDevice {
37 Cpu { cores: u32, threads_per_core: u32, architecture: CpuArchitecture },
39 Gpu { name: String, memory_gb: f32, compute_capability: Option<String>, vendor: GpuVendor },
41 Tpu { version: TpuVersion, cores: u32 },
43 AppleSilicon { chip: AppleChip, neural_engine_cores: u32, gpu_cores: u32, memory_gb: u32 },
45 Edge { name: String, power_budget_watts: f32 },
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
51pub enum CpuArchitecture {
52 X86_64,
53 Aarch64,
54 Riscv64,
55 Wasm32,
56}
57
58#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
60pub enum GpuVendor {
61 Nvidia,
62 Amd,
63 Intel,
64 Apple,
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
69pub enum TpuVersion {
70 V2,
71 V3,
72 V4,
73 V5e,
74 V5p,
75}
76
77#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
79pub enum AppleChip {
80 M1,
81 M1Pro,
82 M1Max,
83 M1Ultra,
84 M2,
85 M2Pro,
86 M2Max,
87 M2Ultra,
88 M3,
89 M3Pro,
90 M3Max,
91 M4,
92 M4Pro,
93 M4Max,
94}
95
96impl ComputeDevice {
97 pub fn theoretical_flops(&self) -> f64 {
99 match self {
100 ComputeDevice::Cpu { cores, threads_per_core, architecture } => {
101 let base_flops = match architecture {
102 CpuArchitecture::X86_64 => 32.0, CpuArchitecture::Aarch64 => 16.0, CpuArchitecture::Riscv64 => 8.0,
105 CpuArchitecture::Wasm32 => 4.0,
106 };
107 (*cores as f64) * (*threads_per_core as f64) * base_flops * 1e9
108 }
109 ComputeDevice::Gpu { memory_gb, vendor, .. } => {
110 let bandwidth_factor = match vendor {
112 GpuVendor::Nvidia => 15.0,
113 GpuVendor::Amd => 12.0,
114 GpuVendor::Intel => 8.0,
115 GpuVendor::Apple => 10.0,
116 };
117 (*memory_gb as f64) * bandwidth_factor * 1e12
118 }
119 ComputeDevice::Tpu { version, cores } => {
120 let flops_per_core = match version {
121 TpuVersion::V2 => 45e12,
122 TpuVersion::V3 => 90e12,
123 TpuVersion::V4 => 275e12,
124 TpuVersion::V5e => 197e12,
125 TpuVersion::V5p => 459e12,
126 };
127 (*cores as f64) * flops_per_core
128 }
129 ComputeDevice::AppleSilicon { chip, gpu_cores, .. } => {
130 let flops_per_gpu_core = match chip {
131 AppleChip::M1 | AppleChip::M1Pro | AppleChip::M1Max | AppleChip::M1Ultra => {
132 128e9
133 }
134 AppleChip::M2 | AppleChip::M2Pro | AppleChip::M2Max | AppleChip::M2Ultra => {
135 150e9
136 }
137 AppleChip::M3 | AppleChip::M3Pro | AppleChip::M3Max => 180e9,
138 AppleChip::M4 | AppleChip::M4Pro | AppleChip::M4Max => 200e9,
139 };
140 (*gpu_cores as f64) * flops_per_gpu_core
141 }
142 ComputeDevice::Edge { power_budget_watts, .. } => {
143 (*power_budget_watts as f64) * 10e9
145 }
146 }
147 }
148
149 pub fn estimated_power_watts(&self) -> f32 {
151 match self {
152 ComputeDevice::Cpu { cores, .. } => (*cores as f32) * 15.0,
153 ComputeDevice::Gpu { memory_gb, vendor, .. } => {
154 let base = match vendor {
155 GpuVendor::Nvidia => 30.0,
156 GpuVendor::Amd => 35.0,
157 GpuVendor::Intel => 25.0,
158 GpuVendor::Apple => 20.0,
159 };
160 *memory_gb * base
161 }
162 ComputeDevice::Tpu { version, cores } => {
163 let per_core = match version {
164 TpuVersion::V2 => 40.0,
165 TpuVersion::V3 => 50.0,
166 TpuVersion::V4 => 60.0,
167 TpuVersion::V5e => 45.0,
168 TpuVersion::V5p => 70.0,
169 };
170 (*cores as f32) * per_core
171 }
172 ComputeDevice::AppleSilicon { chip, .. } => match chip {
173 AppleChip::M1 => 20.0,
174 AppleChip::M1Pro => 30.0,
175 AppleChip::M1Max => 40.0,
176 AppleChip::M1Ultra => 60.0,
177 AppleChip::M2 => 22.0,
178 AppleChip::M2Pro => 32.0,
179 AppleChip::M2Max => 45.0,
180 AppleChip::M2Ultra => 65.0,
181 AppleChip::M3 => 24.0,
182 AppleChip::M3Pro => 35.0,
183 AppleChip::M3Max => 50.0,
184 AppleChip::M4 => 25.0,
185 AppleChip::M4Pro => 38.0,
186 AppleChip::M4Max => 55.0,
187 },
188 ComputeDevice::Edge { power_budget_watts, .. } => *power_budget_watts,
189 }
190 }
191}
192
193#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
195pub enum ModelParadigm {
196 TraditionalML,
198 DeepLearning,
200 FineTuning,
202 Distillation,
204 MoE,
206 ReinforcementLearning,
208 FederatedLearning,
210 Nas,
212 ContinualLearning,
214 MetaLearning,
216}
217
218impl ModelParadigm {
219 pub fn compute_intensity(&self) -> ComputeIntensity {
221 match self {
222 ModelParadigm::TraditionalML => ComputeIntensity::Low,
223 ModelParadigm::DeepLearning => ComputeIntensity::High,
224 ModelParadigm::FineTuning => ComputeIntensity::Medium,
225 ModelParadigm::Distillation => ComputeIntensity::Medium,
226 ModelParadigm::MoE => ComputeIntensity::VeryHigh,
227 ModelParadigm::ReinforcementLearning => ComputeIntensity::High,
228 ModelParadigm::FederatedLearning => ComputeIntensity::Medium,
229 ModelParadigm::Nas => ComputeIntensity::VeryHigh,
230 ModelParadigm::ContinualLearning => ComputeIntensity::Medium,
231 ModelParadigm::MetaLearning => ComputeIntensity::High,
232 }
233 }
234
235 pub fn benefits_from_gpu(&self) -> bool {
237 matches!(
238 self,
239 ModelParadigm::DeepLearning
240 | ModelParadigm::FineTuning
241 | ModelParadigm::MoE
242 | ModelParadigm::ReinforcementLearning
243 | ModelParadigm::Nas
244 )
245 }
246}
247
248#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
250pub enum ComputeIntensity {
251 Low,
252 Medium,
253 High,
254 VeryHigh,
255}
256
257#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
259pub enum PlatformEfficiency {
260 Server,
262 Workstation,
264 Laptop,
266 Edge,
268 Mobile,
270 Embedded,
272}
273
274impl PlatformEfficiency {
275 pub fn typical_power_budget_watts(&self) -> f32 {
277 match self {
278 PlatformEfficiency::Server => 500.0,
279 PlatformEfficiency::Workstation => 350.0,
280 PlatformEfficiency::Laptop => 65.0,
281 PlatformEfficiency::Edge => 15.0,
282 PlatformEfficiency::Mobile => 5.0,
283 PlatformEfficiency::Embedded => 1.0,
284 }
285 }
286}
287
288#[cfg(test)]
289mod tests {
290 use super::*;
291
292 #[test]
297 fn test_experiment_error_display() {
298 let err = ExperimentError::InvalidComputeDevice("test".into());
299 assert!(err.to_string().contains("Invalid compute device"));
300
301 let err = ExperimentError::MetricsCollectionFailed("test".into());
302 assert!(err.to_string().contains("Metrics collection failed"));
303
304 let err = ExperimentError::ParetoFrontierFailed("test".into());
305 assert!(err.to_string().contains("Pareto frontier"));
306
307 let err = ExperimentError::InvalidOrcid("test".into());
308 assert!(err.to_string().contains("Invalid ORCID"));
309
310 let err = ExperimentError::CitationGenerationFailed("test".into());
311 assert!(err.to_string().contains("Citation generation"));
312
313 let err = ExperimentError::SovereignValidationFailed("test".into());
314 assert!(err.to_string().contains("Sovereign distribution"));
315
316 let err = ExperimentError::StorageError("test".into());
317 assert!(err.to_string().contains("storage error"));
318 }
319
320 #[test]
321 fn test_experiment_error_equality() {
322 let err1 = ExperimentError::InvalidComputeDevice("a".into());
323 let err2 = ExperimentError::InvalidComputeDevice("a".into());
324 assert_eq!(err1, err2);
325 }
326
327 #[test]
332 fn test_cpu_theoretical_flops_x86() {
333 let cpu = ComputeDevice::Cpu {
334 cores: 8,
335 threads_per_core: 2,
336 architecture: CpuArchitecture::X86_64,
337 };
338 let flops = cpu.theoretical_flops();
339 assert!(flops > 0.0);
340 assert_eq!(flops, 8.0 * 2.0 * 32.0 * 1e9);
341 }
342
343 #[test]
344 fn test_cpu_theoretical_flops_aarch64() {
345 let cpu = ComputeDevice::Cpu {
346 cores: 8,
347 threads_per_core: 1,
348 architecture: CpuArchitecture::Aarch64,
349 };
350 let flops = cpu.theoretical_flops();
351 assert_eq!(flops, 8.0 * 1.0 * 16.0 * 1e9);
352 }
353
354 #[test]
355 fn test_cpu_theoretical_flops_riscv() {
356 let cpu = ComputeDevice::Cpu {
357 cores: 4,
358 threads_per_core: 1,
359 architecture: CpuArchitecture::Riscv64,
360 };
361 let flops = cpu.theoretical_flops();
362 assert_eq!(flops, 4.0 * 1.0 * 8.0 * 1e9);
363 }
364
365 #[test]
366 fn test_cpu_theoretical_flops_wasm() {
367 let cpu = ComputeDevice::Cpu {
368 cores: 1,
369 threads_per_core: 1,
370 architecture: CpuArchitecture::Wasm32,
371 };
372 let flops = cpu.theoretical_flops();
373 assert_eq!(flops, 1.0 * 1.0 * 4.0 * 1e9);
374 }
375
376 #[test]
377 fn test_gpu_theoretical_flops_nvidia() {
378 let gpu = ComputeDevice::Gpu {
379 name: "RTX 4090".into(),
380 memory_gb: 24.0,
381 compute_capability: Some("8.9".into()),
382 vendor: GpuVendor::Nvidia,
383 };
384 let flops = gpu.theoretical_flops();
385 assert_eq!(flops, 24.0 * 15.0 * 1e12);
386 }
387
388 #[test]
389 fn test_gpu_theoretical_flops_amd() {
390 let gpu = ComputeDevice::Gpu {
391 name: "RX 7900".into(),
392 memory_gb: 20.0,
393 compute_capability: None,
394 vendor: GpuVendor::Amd,
395 };
396 let flops = gpu.theoretical_flops();
397 assert_eq!(flops, 20.0 * 12.0 * 1e12);
398 }
399
400 #[test]
401 fn test_gpu_theoretical_flops_intel() {
402 let gpu = ComputeDevice::Gpu {
403 name: "Arc A770".into(),
404 memory_gb: 16.0,
405 compute_capability: None,
406 vendor: GpuVendor::Intel,
407 };
408 let flops = gpu.theoretical_flops();
409 assert_eq!(flops, 16.0 * 8.0 * 1e12);
410 }
411
412 #[test]
413 fn test_gpu_theoretical_flops_apple() {
414 let gpu = ComputeDevice::Gpu {
415 name: "Apple GPU".into(),
416 memory_gb: 32.0,
417 compute_capability: None,
418 vendor: GpuVendor::Apple,
419 };
420 let flops = gpu.theoretical_flops();
421 assert_eq!(flops, 32.0 * 10.0 * 1e12);
422 }
423
424 #[test]
425 fn test_tpu_theoretical_flops() {
426 let tpu_v2 = ComputeDevice::Tpu { version: TpuVersion::V2, cores: 1 };
427 assert_eq!(tpu_v2.theoretical_flops(), 45e12);
428
429 let tpu_v3 = ComputeDevice::Tpu { version: TpuVersion::V3, cores: 2 };
430 assert_eq!(tpu_v3.theoretical_flops(), 2.0 * 90e12);
431
432 let tpu_v4 = ComputeDevice::Tpu { version: TpuVersion::V4, cores: 1 };
433 assert_eq!(tpu_v4.theoretical_flops(), 275e12);
434
435 let tpu_v5e = ComputeDevice::Tpu { version: TpuVersion::V5e, cores: 1 };
436 assert_eq!(tpu_v5e.theoretical_flops(), 197e12);
437
438 let tpu_v5p = ComputeDevice::Tpu { version: TpuVersion::V5p, cores: 1 };
439 assert_eq!(tpu_v5p.theoretical_flops(), 459e12);
440 }
441
442 #[test]
443 fn test_apple_silicon_theoretical_flops() {
444 let m1 = ComputeDevice::AppleSilicon {
445 chip: AppleChip::M1,
446 neural_engine_cores: 16,
447 gpu_cores: 8,
448 memory_gb: 16,
449 };
450 assert_eq!(m1.theoretical_flops(), 8.0 * 128e9);
451
452 let m2_max = ComputeDevice::AppleSilicon {
453 chip: AppleChip::M2Max,
454 neural_engine_cores: 16,
455 gpu_cores: 38,
456 memory_gb: 96,
457 };
458 assert_eq!(m2_max.theoretical_flops(), 38.0 * 150e9);
459
460 let m3_pro = ComputeDevice::AppleSilicon {
461 chip: AppleChip::M3Pro,
462 neural_engine_cores: 16,
463 gpu_cores: 18,
464 memory_gb: 36,
465 };
466 assert_eq!(m3_pro.theoretical_flops(), 18.0 * 180e9);
467
468 let m4_max = ComputeDevice::AppleSilicon {
469 chip: AppleChip::M4Max,
470 neural_engine_cores: 16,
471 gpu_cores: 40,
472 memory_gb: 128,
473 };
474 assert_eq!(m4_max.theoretical_flops(), 40.0 * 200e9);
475 }
476
477 #[test]
478 fn test_edge_device_theoretical_flops() {
479 let edge = ComputeDevice::Edge { name: "Jetson Nano".into(), power_budget_watts: 10.0 };
480 assert_eq!(edge.theoretical_flops(), 10.0 * 10e9);
481 }
482
483 #[test]
484 fn test_cpu_estimated_power() {
485 let cpu = ComputeDevice::Cpu {
486 cores: 8,
487 threads_per_core: 2,
488 architecture: CpuArchitecture::X86_64,
489 };
490 assert_eq!(cpu.estimated_power_watts(), 8.0 * 15.0);
491 }
492
493 #[test]
494 fn test_gpu_estimated_power() {
495 let nvidia = ComputeDevice::Gpu {
496 name: "RTX".into(),
497 memory_gb: 24.0,
498 compute_capability: None,
499 vendor: GpuVendor::Nvidia,
500 };
501 assert_eq!(nvidia.estimated_power_watts(), 24.0 * 30.0);
502
503 let amd = ComputeDevice::Gpu {
504 name: "RX".into(),
505 memory_gb: 16.0,
506 compute_capability: None,
507 vendor: GpuVendor::Amd,
508 };
509 assert_eq!(amd.estimated_power_watts(), 16.0 * 35.0);
510 }
511
512 #[test]
513 fn test_tpu_estimated_power() {
514 let tpu = ComputeDevice::Tpu { version: TpuVersion::V4, cores: 4 };
515 assert_eq!(tpu.estimated_power_watts(), 4.0 * 60.0);
516 }
517
518 #[test]
519 fn test_apple_silicon_estimated_power() {
520 let m1 = ComputeDevice::AppleSilicon {
521 chip: AppleChip::M1,
522 neural_engine_cores: 16,
523 gpu_cores: 8,
524 memory_gb: 16,
525 };
526 assert_eq!(m1.estimated_power_watts(), 20.0);
527
528 let m2_ultra = ComputeDevice::AppleSilicon {
529 chip: AppleChip::M2Ultra,
530 neural_engine_cores: 32,
531 gpu_cores: 76,
532 memory_gb: 192,
533 };
534 assert_eq!(m2_ultra.estimated_power_watts(), 65.0);
535
536 let m4 = ComputeDevice::AppleSilicon {
537 chip: AppleChip::M4,
538 neural_engine_cores: 16,
539 gpu_cores: 10,
540 memory_gb: 24,
541 };
542 assert_eq!(m4.estimated_power_watts(), 25.0);
543 }
544
545 #[test]
546 fn test_edge_device_estimated_power() {
547 let edge = ComputeDevice::Edge { name: "Pi".into(), power_budget_watts: 5.0 };
548 assert_eq!(edge.estimated_power_watts(), 5.0);
549 }
550
551 #[test]
556 fn test_model_paradigm_compute_intensity() {
557 assert_eq!(ModelParadigm::TraditionalML.compute_intensity(), ComputeIntensity::Low);
558 assert_eq!(ModelParadigm::DeepLearning.compute_intensity(), ComputeIntensity::High);
559 assert_eq!(ModelParadigm::FineTuning.compute_intensity(), ComputeIntensity::Medium);
560 assert_eq!(ModelParadigm::Distillation.compute_intensity(), ComputeIntensity::Medium);
561 assert_eq!(ModelParadigm::MoE.compute_intensity(), ComputeIntensity::VeryHigh);
562 assert_eq!(
563 ModelParadigm::ReinforcementLearning.compute_intensity(),
564 ComputeIntensity::High
565 );
566 assert_eq!(ModelParadigm::FederatedLearning.compute_intensity(), ComputeIntensity::Medium);
567 assert_eq!(ModelParadigm::Nas.compute_intensity(), ComputeIntensity::VeryHigh);
568 assert_eq!(ModelParadigm::ContinualLearning.compute_intensity(), ComputeIntensity::Medium);
569 assert_eq!(ModelParadigm::MetaLearning.compute_intensity(), ComputeIntensity::High);
570 }
571
572 #[test]
573 fn test_model_paradigm_benefits_from_gpu() {
574 assert!(ModelParadigm::DeepLearning.benefits_from_gpu());
575 assert!(ModelParadigm::FineTuning.benefits_from_gpu());
576 assert!(ModelParadigm::MoE.benefits_from_gpu());
577 assert!(ModelParadigm::ReinforcementLearning.benefits_from_gpu());
578 assert!(ModelParadigm::Nas.benefits_from_gpu());
579
580 assert!(!ModelParadigm::TraditionalML.benefits_from_gpu());
581 assert!(!ModelParadigm::Distillation.benefits_from_gpu());
582 assert!(!ModelParadigm::FederatedLearning.benefits_from_gpu());
583 assert!(!ModelParadigm::ContinualLearning.benefits_from_gpu());
584 assert!(!ModelParadigm::MetaLearning.benefits_from_gpu());
585 }
586
587 #[test]
592 fn test_platform_efficiency_power_budget() {
593 assert_eq!(PlatformEfficiency::Server.typical_power_budget_watts(), 500.0);
594 assert_eq!(PlatformEfficiency::Workstation.typical_power_budget_watts(), 350.0);
595 assert_eq!(PlatformEfficiency::Laptop.typical_power_budget_watts(), 65.0);
596 assert_eq!(PlatformEfficiency::Edge.typical_power_budget_watts(), 15.0);
597 assert_eq!(PlatformEfficiency::Mobile.typical_power_budget_watts(), 5.0);
598 assert_eq!(PlatformEfficiency::Embedded.typical_power_budget_watts(), 1.0);
599 }
600
601 #[test]
606 fn test_compute_device_serialization() {
607 let cpu = ComputeDevice::Cpu {
608 cores: 8,
609 threads_per_core: 2,
610 architecture: CpuArchitecture::X86_64,
611 };
612 let json = serde_json::to_string(&cpu).expect("json serialize failed");
613 let deserialized: ComputeDevice =
614 serde_json::from_str(&json).expect("json deserialize failed");
615 assert_eq!(cpu, deserialized);
616 }
617
618 #[test]
619 fn test_model_paradigm_serialization() {
620 let paradigm = ModelParadigm::DeepLearning;
621 let json = serde_json::to_string(¶digm).expect("json serialize failed");
622 let deserialized: ModelParadigm =
623 serde_json::from_str(&json).expect("json deserialize failed");
624 assert_eq!(paradigm, deserialized);
625 }
626}