Skip to main content

dirtydata_core/
mutation_eval.rs

1//! Circuit Mutation Engine — Evaluation Logic
2//! "美しさは、秩序と混沌の境界にある。"
3
4use crate::types::*;
5use dirtydata_dsp_circuit::{MnaSolver, CircuitElement};
6
7impl crate::mutation::MutationEngine {
8    /// Evaluates a mutated circuit by running a micro-simulation.
9    pub fn evaluate(&self, def: &CircuitDefinition, _intensity: MutationIntensity) -> MutationReport {
10        // 1. Setup a micro-solver (Impulse Response test)
11        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        // 2. Probing: Run 256 samples of silence and 128 samples of impulse
28        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        // 3. Compute Metrics
44        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}