Source code for EvaluateFitness.EvalVarMaxFitness
1"""Variance-based (signal activity) fitness evaluator.
2
3Fitness equals the mean absolute difference between consecutive waveform
4samples, rewarding circuits that produce high-activity signals. Used with
5:class:`~EvaluateFitness.EvaluateFitness.EvaluateFitness` via the
6:class:`~EvaluateFitness.EvaluateFitness.FitnessEvaluator` protocol::
7
8 evaluator = EvalVarMaxFitness(plot_data_recorder=recorder)
9 EvaluateFitness(evaluator)
10"""
11
12from PlotDataRecorder import PlotDataRecorder
13
14
[docs]
15class EvalVarMaxFitness:
16 """Evaluate fitness by measuring sequential voltage variance in a waveform.
17
18 Tracks the best waveform per generation for heatmap recording.
19 """
20
[docs]
21 def __init__(self, plot_data_recorder: PlotDataRecorder):
22 """Create an evaluator that records live data to *plot_data_recorder*."""
23 self.__plot_data_recorder = plot_data_recorder
24 self.__best_waveform = []
25 self.__best_waveform_fit = 0
26 self.__epoch = 0
27
[docs]
28 def start_eval(self):
29 """Reset per-generation best waveform tracking."""
30 self.__best_waveform = []
31 self.__best_waveform_fit = 0
32
[docs]
33 def end_eval(self):
34 """Record the best waveform of this generation and advance the epoch counter."""
35 self.__plot_data_recorder.record_waveform_heatmap(self.__epoch, self.__best_waveform)
36 self.__epoch += 1
37
[docs]
38 def calculate_success(self, data: list[int], index: int, src_pop: str) -> float:
39 """Compute variance-based fitness from a waveform in *data*."""
40 waveform = data
41 variance_sum = 0
42 total_samples = len(waveform)
43 for i in range(len(waveform)-1):
44 # NOTE Signal Variance is calculated by summing the absolute difference of
45 # sequential voltage samples from the microcontroller.
46 # Capture the next point in the data file to a variable
47 initial1 = waveform[i]
48 # Capture the next point + 1 in the data file to a variable
49 initial2 = waveform[i+1]
50 # Take the absolute difference of the two points and store to a variable
51 variance = abs(initial2 - initial1)
52
53 if initial1 != None and initial1 < 1000:
54 variance_sum += variance
55
56 fitness = variance_sum / total_samples
57
58 if fitness > self.__best_waveform_fit:
59 self.__best_waveform_fit = fitness
60 self.__best_waveform = waveform
61
62 self.__plot_data_recorder.record_waveform(waveform)
63 self.__plot_data_recorder.record_all_live_data(index, fitness, src_pop)
64
65 return fitness
66
[docs]
67 def calculate_error(self, err: Exception, index: int, src_pop: str) -> float:
68 """Return zero fitness when measurement fails."""
69 self.__plot_data_recorder.record_all_live_data(index, 0, src_pop)
70 return 0