dirtydata_core/
mutation_eval.rs1use crate::types::*;
5use dirtydata_dsp_circuit::{MnaSolver, CircuitElement};
6
7impl crate::mutation::MutationEngine {
8 pub fn evaluate(&self, def: &CircuitDefinition, _intensity: MutationIntensity) -> MutationReport {
10 let mut solver = MnaSolver::new(1.0 / 44100.0);
12 let elements: Vec<CircuitElement> = serde_json::from_str(&def.elements_json).unwrap_or_default();
13
14 let mut max_node = 0;
15 for el in &elements {
16 let el_val: CircuitElement = el.clone();
17 solver.add_element(el_val);
18 match el {
19 CircuitElement::Resistor { a, b, .. } => { max_node = max_node.max(a.0).max(b.0); }
20 CircuitElement::Capacitor { a, b, .. } => { max_node = max_node.max(a.0).max(b.0); }
21 CircuitElement::Diode { a, k, .. } => { max_node = max_node.max(a.0).max(k.0); }
22 CircuitElement::VoltageSource { pos, neg, .. } => { max_node = max_node.max(pos.0).max(neg.0); }
23 }
24 }
25 solver.set_num_nodes(max_node + 1);
26
27 let mut energy: f64 = 0.0;
29 let mut peak: f64 = 0.0;
30 let mut converged_count = 0;
31
32 for i in 0..256 {
33 let _input_v = if i == 128 { 1.0 } else { 0.0 };
34
35 let state = solver.solve();
36 if state.converged { converged_count += 1; }
37
38 let out = state.voltages.get(0).copied().unwrap_or(0.0).abs();
39 energy += out;
40 peak = f64::max(peak, out);
41 }
42
43 let instability = if peak > 10.0 { 1.0 } else { (256 - converged_count) as f32 / 256.0 };
45 let novelty = (def.mutation_history.len() as f32 * 0.1).min(1.0);
46 let warmth = if peak > 0.0 && energy / peak > 50.0 { 0.8 } else { 0.2 };
47
48 MutationReport {
49 instability_score: instability,
50 novelty_score: novelty,
51 risk_level: instability * 1.5,
52 warmth_delta: warmth,
53 dna_string: format!("gen {}", def.mutation_history.len()),
54 }
55 }
56}