1use fugue::{addr, ChoiceValue, Trace};
7use rand::Rng;
8use serde::{Deserialize, Serialize};
9
10use crate::error::GenomeError;
11use crate::genome::bounds::MultiBounds;
12use crate::genome::traits::{EvolutionaryGenome, RealValuedGenome};
13
14#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
22pub struct DynamicRealVector {
23 genes: Vec<f64>,
25 min_length: usize,
27 max_length: usize,
29}
30
31impl DynamicRealVector {
32 pub fn new(genes: Vec<f64>, min_length: usize, max_length: usize) -> Result<Self, GenomeError> {
34 if genes.len() < min_length || genes.len() > max_length {
35 return Err(GenomeError::InvalidStructure(format!(
36 "Gene length {} outside bounds [{}, {}]",
37 genes.len(),
38 min_length,
39 max_length
40 )));
41 }
42 if min_length > max_length {
43 return Err(GenomeError::InvalidStructure(format!(
44 "min_length ({}) > max_length ({})",
45 min_length, max_length
46 )));
47 }
48 Ok(Self {
49 genes,
50 min_length,
51 max_length,
52 })
53 }
54
55 pub fn with_defaults(genes: Vec<f64>) -> Self {
57 Self {
58 genes,
59 min_length: 1,
60 max_length: usize::MAX,
61 }
62 }
63
64 pub fn zeros(
66 dimension: usize,
67 min_length: usize,
68 max_length: usize,
69 ) -> Result<Self, GenomeError> {
70 Self::new(vec![0.0; dimension], min_length, max_length)
71 }
72
73 pub fn min_length(&self) -> usize {
75 self.min_length
76 }
77
78 pub fn max_length(&self) -> usize {
80 self.max_length
81 }
82
83 pub fn into_inner(self) -> Vec<f64> {
85 self.genes
86 }
87
88 pub fn as_vec(&self) -> &Vec<f64> {
90 &self.genes
91 }
92
93 pub fn norm(&self) -> f64 {
95 self.genes.iter().map(|x| x * x).sum::<f64>().sqrt()
96 }
97
98 pub fn norm_squared(&self) -> f64 {
100 self.genes.iter().map(|x| x * x).sum::<f64>()
101 }
102
103 pub fn push(&mut self, gene: f64) -> Result<(), GenomeError> {
105 if self.genes.len() >= self.max_length {
106 return Err(GenomeError::ConstraintViolation(format!(
107 "Cannot add gene: would exceed max_length {}",
108 self.max_length
109 )));
110 }
111 self.genes.push(gene);
112 Ok(())
113 }
114
115 pub fn pop(&mut self) -> Result<f64, GenomeError> {
117 if self.genes.len() <= self.min_length {
118 return Err(GenomeError::ConstraintViolation(format!(
119 "Cannot remove gene: would go below min_length {}",
120 self.min_length
121 )));
122 }
123 Ok(self.genes.pop().unwrap())
124 }
125
126 pub fn insert(&mut self, index: usize, gene: f64) -> Result<(), GenomeError> {
128 if self.genes.len() >= self.max_length {
129 return Err(GenomeError::ConstraintViolation(format!(
130 "Cannot insert gene: would exceed max_length {}",
131 self.max_length
132 )));
133 }
134 if index > self.genes.len() {
135 return Err(GenomeError::InvalidStructure(format!(
136 "Insert index {} out of bounds for length {}",
137 index,
138 self.genes.len()
139 )));
140 }
141 self.genes.insert(index, gene);
142 Ok(())
143 }
144
145 pub fn remove(&mut self, index: usize) -> Result<f64, GenomeError> {
147 if self.genes.len() <= self.min_length {
148 return Err(GenomeError::ConstraintViolation(format!(
149 "Cannot remove gene: would go below min_length {}",
150 self.min_length
151 )));
152 }
153 if index >= self.genes.len() {
154 return Err(GenomeError::InvalidStructure(format!(
155 "Remove index {} out of bounds for length {}",
156 index,
157 self.genes.len()
158 )));
159 }
160 Ok(self.genes.remove(index))
161 }
162
163 pub fn can_grow(&self) -> bool {
165 self.genes.len() < self.max_length
166 }
167
168 pub fn can_shrink(&self) -> bool {
170 self.genes.len() > self.min_length
171 }
172
173 pub fn add(&self, other: &Self) -> Result<Self, GenomeError> {
175 if self.genes.len() != other.genes.len() {
176 return Err(GenomeError::DimensionMismatch {
177 expected: self.genes.len(),
178 actual: other.genes.len(),
179 });
180 }
181 Self::new(
182 self.genes
183 .iter()
184 .zip(other.genes.iter())
185 .map(|(a, b)| a + b)
186 .collect(),
187 self.min_length,
188 self.max_length,
189 )
190 }
191
192 pub fn sub(&self, other: &Self) -> Result<Self, GenomeError> {
194 if self.genes.len() != other.genes.len() {
195 return Err(GenomeError::DimensionMismatch {
196 expected: self.genes.len(),
197 actual: other.genes.len(),
198 });
199 }
200 Self::new(
201 self.genes
202 .iter()
203 .zip(other.genes.iter())
204 .map(|(a, b)| a - b)
205 .collect(),
206 self.min_length,
207 self.max_length,
208 )
209 }
210
211 pub fn scale(&self, scalar: f64) -> Self {
213 Self {
214 genes: self.genes.iter().map(|x| x * scalar).collect(),
215 min_length: self.min_length,
216 max_length: self.max_length,
217 }
218 }
219}
220
221impl EvolutionaryGenome for DynamicRealVector {
222 type Allele = f64;
223 type Phenotype = Vec<f64>;
224
225 fn to_trace(&self) -> Trace {
229 let mut trace = Trace::default();
230 for (i, &gene) in self.genes.iter().enumerate() {
231 trace.insert_choice(addr!("gene", i), ChoiceValue::F64(gene), 0.0);
232 }
233 trace.insert_choice(
235 addr!("meta", "min_length"),
236 ChoiceValue::I64(self.min_length as i64),
237 0.0,
238 );
239 trace.insert_choice(
240 addr!("meta", "max_length"),
241 ChoiceValue::I64(self.max_length as i64),
242 0.0,
243 );
244 trace.insert_choice(
245 addr!("meta", "length"),
246 ChoiceValue::I64(self.genes.len() as i64),
247 0.0,
248 );
249 trace
250 }
251
252 fn from_trace(trace: &Trace) -> Result<Self, GenomeError> {
254 let min_length = trace
255 .get_i64(&addr!("meta", "min_length"))
256 .map(|v| v as usize)
257 .unwrap_or(1);
258 let max_length = trace
259 .get_i64(&addr!("meta", "max_length"))
260 .map(|v| v as usize)
261 .unwrap_or(usize::MAX);
262 let expected_length = trace.get_i64(&addr!("meta", "length")).map(|v| v as usize);
263
264 let mut genes = Vec::new();
265 let mut i = 0;
266 while let Some(val) = trace.get_f64(&addr!("gene", i)) {
267 genes.push(val);
268 i += 1;
269 if let Some(len) = expected_length {
271 if i >= len {
272 break;
273 }
274 }
275 }
276
277 if genes.is_empty() {
278 return Err(GenomeError::InvalidStructure(
279 "No genes found in trace".to_string(),
280 ));
281 }
282
283 Self::new(genes, min_length, max_length)
284 }
285
286 fn decode(&self) -> Self::Phenotype {
287 self.genes.clone()
288 }
289
290 fn dimension(&self) -> usize {
291 self.genes.len()
292 }
293
294 fn generate<R: Rng>(rng: &mut R, bounds: &MultiBounds) -> Self {
295 let min_len = 1;
297 let max_len = bounds.dimension();
298 let length = if min_len == max_len {
299 min_len
300 } else {
301 rng.gen_range(min_len..=max_len)
302 };
303
304 let genes: Vec<f64> = (0..length)
305 .map(|i| {
306 let b = if i < bounds.dimension() {
307 bounds.get(i).unwrap()
308 } else {
309 bounds.get(0).unwrap()
311 };
312 rng.gen_range(b.min..=b.max)
313 })
314 .collect();
315
316 Self {
317 genes,
318 min_length: min_len,
319 max_length: max_len,
320 }
321 }
322
323 fn distance(&self, other: &Self) -> f64 {
324 let common_len = self.genes.len().min(other.genes.len());
326 let mut dist_sq = 0.0;
327
328 for i in 0..common_len {
329 let diff = self.genes[i] - other.genes[i];
330 dist_sq += diff * diff;
331 }
332
333 let length_penalty = (self.genes.len() as f64 - other.genes.len() as f64).abs();
335 dist_sq.sqrt() + length_penalty
336 }
337
338 fn trace_prefix() -> &'static str {
339 "dyn_gene"
340 }
341}
342
343impl RealValuedGenome for DynamicRealVector {
344 fn genes(&self) -> &[f64] {
345 &self.genes
346 }
347
348 fn genes_mut(&mut self) -> &mut [f64] {
349 &mut self.genes
350 }
351
352 fn from_genes(genes: Vec<f64>) -> Result<Self, GenomeError> {
353 if genes.is_empty() {
354 return Err(GenomeError::InvalidStructure(
355 "Cannot create DynamicRealVector with empty genes".to_string(),
356 ));
357 }
358 Ok(Self::with_defaults(genes))
359 }
360
361 fn apply_bounds(&mut self, bounds: &MultiBounds) {
362 for (i, gene) in self.genes.iter_mut().enumerate() {
363 if let Some(b) = bounds.get(i) {
364 *gene = gene.clamp(b.min, b.max);
365 }
366 }
367 }
368}
369
370#[cfg(test)]
371mod tests {
372 use super::*;
373
374 #[test]
375 fn test_dynamic_real_vector_creation() {
376 let genes = vec![1.0, 2.0, 3.0];
377 let genome = DynamicRealVector::new(genes.clone(), 1, 10).unwrap();
378 assert_eq!(genome.genes(), &genes[..]);
379 assert_eq!(genome.dimension(), 3);
380 }
381
382 #[test]
383 fn test_dynamic_real_vector_length_constraints() {
384 let result = DynamicRealVector::new(vec![1.0], 2, 10);
386 assert!(result.is_err());
387
388 let result = DynamicRealVector::new(vec![1.0, 2.0, 3.0], 1, 2);
390 assert!(result.is_err());
391
392 let result = DynamicRealVector::new(vec![1.0, 2.0], 5, 3);
394 assert!(result.is_err());
395 }
396
397 #[test]
398 fn test_push_pop() {
399 let mut genome = DynamicRealVector::new(vec![1.0, 2.0], 1, 5).unwrap();
400
401 genome.push(3.0).unwrap();
403 assert_eq!(genome.dimension(), 3);
404 assert_eq!(genome.genes()[2], 3.0);
405
406 let val = genome.pop().unwrap();
408 assert_eq!(val, 3.0);
409 assert_eq!(genome.dimension(), 2);
410 }
411
412 #[test]
413 fn test_push_pop_bounds() {
414 let mut genome = DynamicRealVector::new(vec![1.0, 2.0, 3.0], 3, 3).unwrap();
415
416 assert!(genome.push(4.0).is_err());
418
419 assert!(genome.pop().is_err());
421 }
422
423 #[test]
424 fn test_insert_remove() {
425 let mut genome = DynamicRealVector::new(vec![1.0, 3.0], 1, 5).unwrap();
426
427 genome.insert(1, 2.0).unwrap();
429 assert_eq!(genome.genes(), &[1.0, 2.0, 3.0]);
430
431 let val = genome.remove(1).unwrap();
433 assert_eq!(val, 2.0);
434 assert_eq!(genome.genes(), &[1.0, 3.0]);
435 }
436
437 #[test]
438 fn test_can_grow_shrink() {
439 let genome = DynamicRealVector::new(vec![1.0, 2.0], 1, 3).unwrap();
440 assert!(genome.can_grow());
441 assert!(genome.can_shrink());
442
443 let genome_at_max = DynamicRealVector::new(vec![1.0, 2.0, 3.0], 1, 3).unwrap();
444 assert!(!genome_at_max.can_grow());
445 assert!(genome_at_max.can_shrink());
446
447 let genome_at_min = DynamicRealVector::new(vec![1.0], 1, 3).unwrap();
448 assert!(genome_at_min.can_grow());
449 assert!(!genome_at_min.can_shrink());
450 }
451
452 #[test]
453 fn test_trace_roundtrip() {
454 let genome = DynamicRealVector::new(vec![1.0, 2.0, 3.0], 2, 5).unwrap();
455 let trace = genome.to_trace();
456 let restored = DynamicRealVector::from_trace(&trace).unwrap();
457
458 assert_eq!(genome.genes(), restored.genes());
459 assert_eq!(genome.min_length(), restored.min_length());
460 assert_eq!(genome.max_length(), restored.max_length());
461 }
462
463 #[test]
464 fn test_distance() {
465 let g1 = DynamicRealVector::new(vec![0.0, 0.0], 1, 10).unwrap();
466 let g2 = DynamicRealVector::new(vec![3.0, 4.0], 1, 10).unwrap();
467
468 let dist = g1.distance(&g2);
470 assert!((dist - 5.0).abs() < 0.001);
471
472 let g3 = DynamicRealVector::new(vec![0.0, 0.0, 0.0], 1, 10).unwrap();
474 let dist_with_penalty = g1.distance(&g3);
475 assert!(dist_with_penalty > 0.0);
476 }
477
478 #[test]
479 fn test_generate_random() {
480 let bounds = MultiBounds::symmetric(5.0, 5);
481 let mut rng = rand::thread_rng();
482
483 let genome = DynamicRealVector::generate(&mut rng, &bounds);
484
485 assert!(genome.dimension() >= 1);
486 assert!(genome.dimension() <= 5);
487 for gene in genome.genes() {
488 assert!(*gene >= -5.0 && *gene <= 5.0);
489 }
490 }
491
492 #[test]
493 fn test_arithmetic_operations() {
494 let g1 = DynamicRealVector::new(vec![1.0, 2.0, 3.0], 1, 10).unwrap();
495 let g2 = DynamicRealVector::new(vec![4.0, 5.0, 6.0], 1, 10).unwrap();
496
497 let sum = g1.add(&g2).unwrap();
498 assert_eq!(sum.genes(), &[5.0, 7.0, 9.0]);
499
500 let diff = g2.sub(&g1).unwrap();
501 assert_eq!(diff.genes(), &[3.0, 3.0, 3.0]);
502
503 let scaled = g1.scale(2.0);
504 assert_eq!(scaled.genes(), &[2.0, 4.0, 6.0]);
505 }
506
507 #[test]
508 fn test_norm() {
509 let genome = DynamicRealVector::new(vec![3.0, 4.0], 1, 10).unwrap();
510 assert!((genome.norm() - 5.0).abs() < 0.001);
511 assert!((genome.norm_squared() - 25.0).abs() < 0.001);
512 }
513}