1use std::collections::HashMap;
9use std::sync::{Arc, RwLock};
10
11use crate::architecture_simulator::{
12 Architecture, ArchitectureSimulator, Component, ComponentType, Connection, SimulationConfig,
13 SimulationMetrics,
14};
15use crate::knowledge_base::{KnowledgeBase, KnowledgeEntryType};
16
17#[derive(Debug, Clone, PartialEq)]
21pub enum GenerationStrategy {
22 Hybrid,
24 Optimize,
26 Novel,
28 Evolutionary,
30}
31
32#[derive(Debug, Clone)]
34pub struct GenerationParams {
35 pub min_components: usize,
37 pub max_components: usize,
38 pub min_connections: usize,
40 pub max_connections: usize,
41 pub target_latency_ms: f64,
43 pub target_throughput: f64,
45 pub reliability_requirement: f64,
47 pub strategy: GenerationStrategy,
49 pub generations: u32,
51 pub mutation_rate: f64,
53}
54
55impl Default for GenerationParams {
56 fn default() -> Self {
57 Self {
58 min_components: 3,
59 max_components: 10,
60 min_connections: 2,
61 max_connections: 15,
62 target_latency_ms: 50.0,
63 target_throughput: 1000.0,
64 reliability_requirement: 0.95,
65 strategy: GenerationStrategy::Hybrid,
66 generations: 5,
67 mutation_rate: 0.1,
68 }
69 }
70}
71
72#[derive(Debug, Clone)]
74pub struct ArchitectureProposal {
75 pub architecture: Architecture,
76 pub generation_score: f64,
77 pub inspiration_sources: Vec<String>,
78 pub improvements: Vec<String>,
79 pub predicted_metrics: Option<SimulationMetrics>,
80}
81
82pub struct ArchitectureGenerator {
86 knowledge_base: Arc<KnowledgeBase>,
87 simulator: Arc<ArchitectureSimulator>,
88 params: Arc<RwLock<GenerationParams>>,
89 generation_history: Arc<RwLock<Vec<ArchitectureProposal>>>,
91}
92
93impl ArchitectureGenerator {
94 pub fn new(knowledge_base: Arc<KnowledgeBase>, simulator: Arc<ArchitectureSimulator>) -> Self {
96 Self {
97 knowledge_base,
98 simulator,
99 params: Arc::new(RwLock::new(GenerationParams::default())),
100 generation_history: Arc::new(RwLock::new(Vec::new())),
101 }
102 }
103
104 pub fn set_params(&self, params: GenerationParams) {
106 *crate::sync_guard::write_lock(&self.params) = params;
107 }
108
109 pub fn generate(&self, requirements: &str) -> Vec<ArchitectureProposal> {
111 let params = crate::sync_guard::read_lock(&self.params).clone();
112
113 match params.strategy {
114 GenerationStrategy::Hybrid => self.generate_hybrid(requirements, ¶ms),
115 GenerationStrategy::Optimize => self.generate_optimized(requirements, ¶ms),
116 GenerationStrategy::Novel => self.generate_novel(requirements, ¶ms),
117 GenerationStrategy::Evolutionary => self.generate_evolutionary(requirements, ¶ms),
118 }
119 }
120
121 fn generate_hybrid(
123 &self,
124 requirements: &str,
125 params: &GenerationParams,
126 ) -> Vec<ArchitectureProposal> {
127 let mut proposals = Vec::new();
128
129 let relevant_entries = self.knowledge_base.search(requirements, 20);
131
132 let mut component_type_weights: HashMap<ComponentType, f64> = HashMap::new();
134 let mut _connection_patterns: Vec<(String, String, f64)> = Vec::new();
135
136 for result in &relevant_entries {
137 let entry = &result.entry;
138 match entry.entry_type {
139 KnowledgeEntryType::BestPractice => {
140 if entry.tags.contains(&"microservices".to_string()) {
142 *component_type_weights
143 .entry(ComponentType::Software)
144 .or_insert(0.0) += 0.3;
145 }
146 if entry.tags.contains(&"scalability".to_string()) {
147 *component_type_weights
148 .entry(ComponentType::Network)
149 .or_insert(0.0) += 0.2;
150 }
151 }
152 KnowledgeEntryType::SimulationResult
153 if entry.confidence > 0.8 => {
155 *component_type_weights
156 .entry(ComponentType::Software)
157 .or_insert(0.0) += 0.2;
158 *component_type_weights
159 .entry(ComponentType::Storage)
160 .or_insert(0.0) += 0.1;
161 }
162 KnowledgeEntryType::KnownPitfall
163 if entry.tags.contains(&"bottleneck".to_string()) => {
165 *component_type_weights
166 .entry(ComponentType::Storage)
167 .or_insert(0.0) -= 0.1;
168 }
169 _ => {}
170 }
171 }
172
173 for variant in 0..3 {
175 let comp_count = params.min_components + variant * 2;
176 let conn_count = params.min_connections + variant;
177
178 let mut components = HashMap::new();
179 let mut connections = Vec::new();
180
181 for i in 0..comp_count.min(params.max_components) {
183 let comp_type = self.select_weighted_type(&component_type_weights, i);
184 let comp_id = format!("comp_{}", i);
185 let latency = 5.0 + (i as f64 * 2.0) + rand::random::<f64>() * 5.0;
186 let error_rate = 0.005 + rand::random::<f64>() * 0.02;
187
188 components.insert(
189 comp_id.clone(),
190 Component {
191 id: comp_id,
192 name: format!("{}_{}", Self::type_name(&comp_type), i),
193 component_type: comp_type,
194 capacity: HashMap::new(),
195 load: 0.0,
196 error_rate,
197 latency_ms: latency,
198 },
199 );
200 }
201
202 let comp_ids: Vec<String> = components.keys().cloned().collect();
204 for i in 0..conn_count
205 .min(params.max_connections)
206 .min(comp_ids.len().saturating_sub(1))
207 {
208 let from = &comp_ids[i % comp_ids.len()];
209 let to = &comp_ids[(i + 1) % comp_ids.len()];
210 let bandwidth = 1000.0 + rand::random::<f64>() * 9000.0;
211 let protocol = if i.is_multiple_of(2) {
212 "HTTP/2"
213 } else {
214 "gRPC"
215 };
216
217 connections.push(Connection {
218 from: from.clone(),
219 to: to.clone(),
220 bandwidth,
221 protocol: protocol.to_string(),
222 latency_ms: 1.0 + rand::random::<f64>() * 2.0,
223 packet_loss: 0.001,
224 });
225 }
226
227 let arch = Architecture {
228 id: format!("generated_{}", rand::random::<u32>()),
229 name: format!("Hybrid Architecture v{}", variant + 1),
230 description: format!(
231 "Generated from knowledge base patterns. Requirements: {}",
232 requirements
233 ),
234 components,
235 connections,
236 version: 1,
237 cohesion_score: 0.5 + rand::random::<f64>() * 0.3,
238 };
239
240 let config = SimulationConfig {
242 duration_secs: 30.0,
243 time_step_ms: 100.0,
244 max_concurrent_requests: 500,
245 load_pattern: "sine".to_string(),
246 peak_load: 0.7,
247 enable_fault_injection: true,
248 fault_rate: 0.01,
249 };
250
251 let sim_result = self.simulator.run_simulation(&arch.id, &config);
252
253 let score = self.calculate_proposal_score(&arch, &sim_result, params);
255
256 let sources: Vec<String> = relevant_entries
258 .iter()
259 .take(3)
260 .map(|r| r.entry.title.clone())
261 .collect();
262
263 let improvements = self.suggest_improvements(&arch, &sim_result);
265
266 proposals.push(ArchitectureProposal {
267 architecture: arch,
268 generation_score: score,
269 inspiration_sources: sources,
270 improvements,
271 predicted_metrics: sim_result,
272 });
273 }
274
275 proposals.sort_by(|a, b| b.generation_score.total_cmp(&a.generation_score));
277
278 crate::sync_guard::write_lock(&self.generation_history).extend(proposals.clone());
280
281 proposals
282 }
283
284 fn generate_optimized(
286 &self,
287 requirements: &str,
288 params: &GenerationParams,
289 ) -> Vec<ArchitectureProposal> {
290 let mut proposals = Vec::new();
291
292 let existing = self.simulator.list_architectures();
294 if existing.is_empty() {
295 return self.generate_hybrid(requirements, params);
296 }
297
298 for arch in existing.iter().take(2) {
299 let mut optimized = arch.clone();
300 optimized.id = format!("optimized_{}", rand::random::<u32>());
301 optimized.name = format!("Optimized {}", arch.name);
302 optimized.version = arch.version + 1;
303
304 let mut to_remove = Vec::new();
307 for (comp_id, comp) in &optimized.components {
308 if comp.latency_ms > params.target_latency_ms * 2.0 {
309 to_remove.push(comp_id.clone());
310 }
311 }
312 for comp_id in &to_remove {
313 optimized.components.remove(comp_id);
314 optimized
315 .connections
316 .retain(|c| c.from != *comp_id && c.to != *comp_id);
317 }
318
319 if !optimized
321 .components
322 .values()
323 .any(|c| c.component_type == ComponentType::Storage)
324 {
325 let cache_id = "cache_0".to_string();
326 optimized.components.insert(
327 cache_id.clone(),
328 Component {
329 id: cache_id.clone(),
330 name: "Cache Layer".to_string(),
331 component_type: ComponentType::Storage,
332 capacity: {
333 let mut cap = HashMap::new();
334 cap.insert("memory_mb".to_string(), 8192.0);
335 cap
336 },
337 load: 0.0,
338 error_rate: 0.001,
339 latency_ms: 1.0,
340 },
341 );
342
343 if let Some(first_comp) = optimized.components.keys().next() {
345 optimized.connections.push(Connection {
346 from: first_comp.clone(),
347 to: cache_id,
348 bandwidth: 10000.0,
349 protocol: "Redis".to_string(),
350 latency_ms: 0.5,
351 packet_loss: 0.0001,
352 });
353 }
354 }
355
356 let config = SimulationConfig {
358 duration_secs: 30.0,
359 time_step_ms: 100.0,
360 max_concurrent_requests: 500,
361 load_pattern: "sine".to_string(),
362 peak_load: 0.7,
363 enable_fault_injection: true,
364 fault_rate: 0.01,
365 };
366
367 let sim_result = self.simulator.run_simulation(&optimized.id, &config);
368 let score = self.calculate_proposal_score(&optimized, &sim_result, params);
369
370 proposals.push(ArchitectureProposal {
371 architecture: optimized,
372 generation_score: score,
373 inspiration_sources: vec![format!("Optimized from: {}", arch.name)],
374 improvements: vec![
375 "Added cache layer for reduced latency".to_string(),
376 format!("Removed {} high-latency components", to_remove.len()),
377 ],
378 predicted_metrics: sim_result,
379 });
380 }
381
382 proposals.sort_by(|a, b| b.generation_score.total_cmp(&a.generation_score));
383 crate::sync_guard::write_lock(&self.generation_history).extend(proposals.clone());
384 proposals
385 }
386
387 fn generate_novel(
389 &self,
390 requirements: &str,
391 params: &GenerationParams,
392 ) -> Vec<ArchitectureProposal> {
393 let mut proposals = Vec::new();
394
395 for variant in 0..3 {
396 let comp_count = params.min_components + variant;
397 let mut components = HashMap::new();
398
399 let types = [
401 ComponentType::Software,
402 ComponentType::Storage,
403 ComponentType::Network,
404 ComponentType::Hardware,
405 ];
406
407 for i in 0..comp_count {
408 let comp_type = types[i % types.len()].clone();
409 let comp_id = format!("novel_comp_{}", i);
410 let latency = 1.0 + rand::random::<f64>() * 20.0;
411 let error_rate = rand::random::<f64>() * 0.01;
412
413 components.insert(
414 comp_id.clone(),
415 Component {
416 id: comp_id,
417 name: format!("Novel_{}_{}", Self::type_name(&comp_type), i),
418 component_type: comp_type,
419 capacity: HashMap::new(),
420 load: 0.0,
421 error_rate,
422 latency_ms: latency,
423 },
424 );
425 }
426
427 let comp_ids: Vec<String> = components.keys().cloned().collect();
429 let mut connections = Vec::new();
430 for i in 0..comp_ids.len() {
431 for j in (i + 1)..comp_ids.len() {
432 if rand::random::<f64>() < 0.3 {
433 connections.push(Connection {
435 from: comp_ids[i].clone(),
436 to: comp_ids[j].clone(),
437 bandwidth: 1000.0 + rand::random::<f64>() * 9000.0,
438 protocol: if rand::random() {
439 "HTTP/2".to_string()
440 } else {
441 "gRPC".to_string()
442 },
443 latency_ms: rand::random::<f64>() * 5.0,
444 packet_loss: rand::random::<f64>() * 0.01,
445 });
446 }
447 }
448 }
449
450 let arch = Architecture {
451 id: format!("novel_{}", rand::random::<u32>()),
452 name: format!("Novel Architecture v{}", variant + 1),
453 description: format!("Novel architecture for: {}", requirements),
454 components,
455 connections,
456 version: 1,
457 cohesion_score: rand::random::<f64>() * 0.5 + 0.3,
458 };
459
460 let config = SimulationConfig {
461 duration_secs: 30.0,
462 time_step_ms: 100.0,
463 max_concurrent_requests: 500,
464 load_pattern: "sine".to_string(),
465 peak_load: 0.7,
466 enable_fault_injection: true,
467 fault_rate: 0.01,
468 };
469
470 let sim_result = self.simulator.run_simulation(&arch.id, &config);
471 let score = self.calculate_proposal_score(&arch, &sim_result, params);
472
473 proposals.push(ArchitectureProposal {
474 architecture: arch,
475 generation_score: score,
476 inspiration_sources: vec!["Novel generation from scratch".to_string()],
477 improvements: vec!["Novel architecture — no prior patterns used".to_string()],
478 predicted_metrics: sim_result,
479 });
480 }
481
482 proposals.sort_by(|a, b| b.generation_score.total_cmp(&a.generation_score));
483 crate::sync_guard::write_lock(&self.generation_history).extend(proposals.clone());
484 proposals
485 }
486
487 fn generate_evolutionary(
489 &self,
490 requirements: &str,
491 params: &GenerationParams,
492 ) -> Vec<ArchitectureProposal> {
493 let mut population = Vec::new();
494
495 for _ in 0..10 {
497 let comp_count = params.min_components
498 + (rand::random::<usize>() % (params.max_components - params.min_components + 1));
499 let mut components = HashMap::new();
500
501 for i in 0..comp_count {
502 let comp_type = match rand::random::<u8>() % 4 {
503 0 => ComponentType::Software,
504 1 => ComponentType::Storage,
505 2 => ComponentType::Network,
506 _ => ComponentType::Hardware,
507 };
508 let comp_id = format!("evo_comp_{}", i);
509 components.insert(
510 comp_id.clone(),
511 Component {
512 id: comp_id,
513 name: format!("Evo_{}_{}", Self::type_name(&comp_type), i),
514 component_type: comp_type,
515 capacity: HashMap::new(),
516 load: 0.0,
517 error_rate: rand::random::<f64>() * 0.02,
518 latency_ms: rand::random::<f64>() * 30.0 + 1.0,
519 },
520 );
521 }
522
523 let comp_ids: Vec<String> = components.keys().cloned().collect();
524 let mut connections = Vec::new();
525 for i in 0..comp_ids.len().saturating_sub(1) {
526 if rand::random::<f64>() < 0.5 {
527 connections.push(Connection {
528 from: comp_ids[i].clone(),
529 to: comp_ids[i + 1].clone(),
530 bandwidth: 1000.0 + rand::random::<f64>() * 9000.0,
531 protocol: if rand::random() {
532 "HTTP/2".to_string()
533 } else {
534 "gRPC".to_string()
535 },
536 latency_ms: rand::random::<f64>() * 3.0,
537 packet_loss: rand::random::<f64>() * 0.01,
538 });
539 }
540 }
541
542 let arch = Architecture {
543 id: format!("evo_{}", rand::random::<u32>()),
544 name: format!("Evolutionary v{}", population.len() + 1),
545 description: format!("Evolutionary architecture for: {}", requirements),
546 components,
547 connections,
548 version: 1,
549 cohesion_score: rand::random::<f64>() * 0.5,
550 };
551
552 self.simulator.register_architecture(arch.clone());
553 population.push(arch);
554 }
555
556 for gen in 0..params.generations {
558 let mut new_population = Vec::new();
559
560 for arch in &population {
561 let config = SimulationConfig {
563 duration_secs: 20.0,
564 time_step_ms: 100.0,
565 max_concurrent_requests: 500,
566 load_pattern: "sine".to_string(),
567 peak_load: 0.7,
568 enable_fault_injection: true,
569 fault_rate: 0.01,
570 };
571
572 let sim_result = self.simulator.run_simulation(&arch.id, &config);
573 let score = self.calculate_proposal_score(arch, &sim_result, params);
574
575 if score > 0.5 {
577 new_population.push(arch.clone());
578
579 if rand::random::<f64>() < params.mutation_rate {
581 let mut mutated = arch.clone();
582 mutated.id = format!("evo_mut_{}_{}", gen, rand::random::<u32>());
583 mutated.name = format!("Mutated Gen{}", gen + 1);
584 mutated.version = gen + 1;
585
586 if !mutated.components.is_empty() {
588 let keys: Vec<String> = mutated.components.keys().cloned().collect();
589 if let Some(key) = keys.get(rand::random::<usize>() % keys.len()) {
590 if let Some(comp) = mutated.components.get_mut(key) {
591 comp.latency_ms *= 0.5 + rand::random::<f64>(); comp.error_rate *= 0.5 + rand::random::<f64>();
593 }
594 }
595 }
596
597 self.simulator.register_architecture(mutated.clone());
598 new_population.push(mutated);
599 }
600 }
601 }
602
603 population = new_population;
604 if population.is_empty() {
605 break;
606 }
607 }
608
609 let mut proposals = Vec::new();
611 for arch in population.iter().take(3) {
612 let config = SimulationConfig {
613 duration_secs: 30.0,
614 time_step_ms: 100.0,
615 max_concurrent_requests: 500,
616 load_pattern: "sine".to_string(),
617 peak_load: 0.7,
618 enable_fault_injection: true,
619 fault_rate: 0.01,
620 };
621
622 let sim_result = self.simulator.run_simulation(&arch.id, &config);
623 let score = self.calculate_proposal_score(arch, &sim_result, params);
624
625 proposals.push(ArchitectureProposal {
626 architecture: arch.clone(),
627 generation_score: score,
628 inspiration_sources: vec![format!(
629 "Evolutionary generation ({} generations)",
630 params.generations
631 )],
632 improvements: vec!["Evolved through natural selection".to_string()],
633 predicted_metrics: sim_result,
634 });
635 }
636
637 proposals.sort_by(|a, b| b.generation_score.total_cmp(&a.generation_score));
638 crate::sync_guard::write_lock(&self.generation_history).extend(proposals.clone());
639 proposals
640 }
641
642 fn calculate_proposal_score(
644 &self,
645 arch: &Architecture,
646 sim_result: &Option<SimulationMetrics>,
647 params: &GenerationParams,
648 ) -> f64 {
649 let mut score = 0.0;
650
651 score += arch.cohesion_score * 0.2;
653
654 if let Some(ref metrics) = sim_result {
655 let latency_score = if metrics.avg_latency_ms <= params.target_latency_ms {
657 1.0
658 } else {
659 (params.target_latency_ms / metrics.avg_latency_ms).min(1.0)
660 };
661 score += latency_score * 0.2;
662
663 let throughput_score =
665 (metrics.throughput_req_per_sec / params.target_throughput).min(1.0);
666 score += throughput_score * 0.15;
667
668 score += metrics.stability_score * 0.15;
670
671 score += metrics.resilience_score * 0.1;
673
674 score -= metrics.error_rate * 0.1;
676
677 score -= metrics.bottleneck_components.len() as f64 * 0.05;
679 }
680
681 let comp_ratio = arch.components.len() as f64 / params.max_components as f64;
683 if comp_ratio > 0.3 && comp_ratio < 0.8 {
684 score += 0.1; }
686
687 let max_connections = arch.components.len() * (arch.components.len() - 1) / 2;
689 if max_connections > 0 {
690 let density = arch.connections.len() as f64 / max_connections as f64;
691 if density > 0.2 && density < 0.6 {
692 score += 0.05; }
694 }
695
696 score.clamp(0.0, 1.0)
697 }
698
699 fn suggest_improvements(
701 &self,
702 arch: &Architecture,
703 sim_result: &Option<SimulationMetrics>,
704 ) -> Vec<String> {
705 let mut improvements = Vec::new();
706
707 if let Some(ref metrics) = sim_result {
708 if metrics.avg_latency_ms > 100.0 {
709 improvements.push("Consider adding a cache layer to reduce latency".to_string());
710 }
711 if metrics.error_rate > 0.05 {
712 improvements.push(
713 "Implement retry logic and circuit breakers for error resilience".to_string(),
714 );
715 }
716 if !metrics.bottleneck_components.is_empty() {
717 improvements.push(format!(
718 "Scale or optimize bottleneck components: {}",
719 metrics.bottleneck_components.join(", ")
720 ));
721 }
722 if metrics.stability_score < 0.7 {
723 improvements
724 .push("Add load balancing and auto-scaling for better stability".to_string());
725 }
726 if metrics.resilience_score < 0.7 {
727 improvements
728 .push("Implement bulkhead isolation to prevent cascade failures".to_string());
729 }
730 }
731
732 if arch.connections.len() < arch.components.len() {
733 improvements
734 .push("Consider adding redundant connections for fault tolerance".to_string());
735 }
736
737 improvements
738 }
739
740 fn select_weighted_type(
742 &self,
743 weights: &HashMap<ComponentType, f64>,
744 index: usize,
745 ) -> ComponentType {
746 if weights.is_empty() {
747 return match index % 4 {
748 0 => ComponentType::Software,
749 1 => ComponentType::Storage,
750 2 => ComponentType::Network,
751 _ => ComponentType::Hardware,
752 };
753 }
754
755 let total: f64 = weights.values().sum();
756 if total <= 0.0 {
757 return ComponentType::Software;
758 }
759
760 let mut r = rand::random::<f64>() * total;
761 for (comp_type, weight) in weights {
762 r -= weight.max(0.0);
763 if r <= 0.0 {
764 return comp_type.clone();
765 }
766 }
767
768 ComponentType::Software
769 }
770
771 fn type_name(comp_type: &ComponentType) -> String {
773 match comp_type {
774 ComponentType::Software => "Service".to_string(),
775 ComponentType::Hardware => "Hardware".to_string(),
776 ComponentType::Network => "Network".to_string(),
777 ComponentType::Storage => "Storage".to_string(),
778 ComponentType::Custom(s) => s.clone(),
779 }
780 }
781
782 pub fn get_history(&self) -> Vec<ArchitectureProposal> {
784 crate::sync_guard::read_lock(&self.generation_history).clone()
785 }
786
787 pub fn clear_history(&self) {
789 crate::sync_guard::write_lock(&self.generation_history).clear();
790 }
791}
792
793#[cfg(test)]
794mod tests {
795 use super::*;
796
797 fn create_test_generator() -> ArchitectureGenerator {
798 let kb = Arc::new(KnowledgeBase::new());
799 let sim = Arc::new(ArchitectureSimulator::new());
800 ArchitectureGenerator::new(kb, sim)
801 }
802
803 #[test]
804 fn test_generate_hybrid() {
805 let gen = create_test_generator();
806 let proposals = gen.generate("scalable microservices");
807 assert!(!proposals.is_empty());
808 assert!(proposals[0].generation_score > 0.0);
809 }
810
811 #[test]
812 fn test_generate_novel() {
813 let gen = create_test_generator();
814 gen.set_params(GenerationParams {
815 strategy: GenerationStrategy::Novel,
816 ..Default::default()
817 });
818 let proposals = gen.generate("test requirements");
819 assert!(!proposals.is_empty());
820 }
821
822 #[test]
823 fn test_generate_evolutionary() {
824 let gen = create_test_generator();
825 gen.set_params(GenerationParams {
826 strategy: GenerationStrategy::Evolutionary,
827 generations: 3,
828 min_components: 3,
829 max_components: 5,
830 mutation_rate: 1.0,
831 target_latency_ms: 1000.0,
832 target_throughput: 1.0,
833 ..Default::default()
834 });
835 let proposals = gen.generate("test");
836 assert!(!proposals.is_empty());
837 }
838}