1#![forbid(unsafe_code)]
2
3use std::collections::HashMap;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
17pub enum Ternary {
18 Negative,
19 Zero,
20 Positive,
21}
22
23impl Ternary {
24 pub fn to_i8(self) -> i8 {
26 match self {
27 Ternary::Negative => -1,
28 Ternary::Zero => 0,
29 Ternary::Positive => 1,
30 }
31 }
32
33 pub fn from_i8(v: i8) -> Self {
35 match v {
36 ..=-1 => Ternary::Negative,
37 0 => Ternary::Zero,
38 1.. => Ternary::Positive,
39 }
40 }
41
42 pub fn negate(self) -> Self {
44 match self {
45 Ternary::Negative => Ternary::Positive,
46 Ternary::Zero => Ternary::Zero,
47 Ternary::Positive => Ternary::Negative,
48 }
49 }
50}
51
52#[derive(Debug, Clone, PartialEq, Eq)]
56pub struct Pattern {
57 pub values: Vec<Ternary>,
58}
59
60impl Pattern {
61 pub fn new(values: Vec<Ternary>) -> Self {
62 Self { values }
63 }
64
65 pub fn len(&self) -> usize {
67 self.values.len()
68 }
69
70 pub fn is_empty(&self) -> bool {
72 self.values.is_empty()
73 }
74
75 pub fn to_i8_vec(&self) -> Vec<i8> {
77 self.values.iter().map(|t| t.to_i8()).collect()
78 }
79
80 pub fn symmetry(&self) -> f64 {
83 if self.values.len() < 2 {
84 return 1.0;
85 }
86 let n = self.values.len();
87 let matches = (0..n / 2)
88 .filter(|&i| self.values[i] == self.values[n - 1 - i])
89 .count();
90 matches as f64 / (n / 2) as f64
91 }
92
93 pub fn balance(&self) -> f64 {
95 if self.values.is_empty() {
96 return 1.0;
97 }
98 let zeros = self.values.iter().filter(|&&t| t == Ternary::Zero).count();
99 zeros as f64 / self.values.len() as f64
100 }
101
102 pub fn complexity(&self) -> f64 {
104 if self.values.len() < 2 {
105 return 0.0;
106 }
107 let transitions = self
108 .values
109 .windows(2)
110 .filter(|w| w[0] != w[1])
111 .count();
112 transitions as f64 / (self.values.len() - 1) as f64
113 }
114}
115
116#[derive(Debug, Clone)]
123pub struct AestheticScorer {
124 pub symmetry_weight: f64,
125 pub complexity_weight: f64,
126 pub balance_weight: f64,
127}
128
129impl Default for AestheticScorer {
130 fn default() -> Self {
131 Self {
132 symmetry_weight: 0.4,
133 complexity_weight: 0.35,
134 balance_weight: 0.25,
135 }
136 }
137}
138
139impl AestheticScorer {
140 pub fn new(symmetry_weight: f64, complexity_weight: f64, balance_weight: f64) -> Self {
141 Self {
142 symmetry_weight,
143 complexity_weight,
144 balance_weight,
145 }
146 }
147
148 pub fn score(&self, pattern: &Pattern) -> f64 {
150 let total_weight = self.symmetry_weight + self.complexity_weight + self.balance_weight;
151 if total_weight == 0.0 {
152 return 0.0;
153 }
154 let raw = self.symmetry_weight * pattern.symmetry()
155 + self.complexity_weight * pattern.complexity()
156 + self.balance_weight * pattern.balance();
157 raw / total_weight
158 }
159}
160
161#[derive(Debug, Clone)]
168pub struct MutationEngine {
169 pub mutation_rate: f64,
171}
172
173impl MutationEngine {
174 pub fn new(mutation_rate: f64) -> Self {
175 Self {
176 mutation_rate: mutation_rate.clamp(0.0, 1.0),
177 }
178 }
179
180 pub fn flip_mutate(&self, pattern: &Pattern, seed: usize) -> Pattern {
182 let values: Vec<Ternary> = pattern
183 .values
184 .iter()
185 .enumerate()
186 .map(|(i, &v)| {
187 if self.should_mutate(i, seed) {
188 v.negate()
189 } else {
190 v
191 }
192 })
193 .collect();
194 Pattern::new(values)
195 }
196
197 pub fn rotate(&self, pattern: &Pattern, shift: usize) -> Pattern {
199 if pattern.values.is_empty() {
200 return pattern.clone();
201 }
202 let n = pattern.values.len();
203 let s = shift % n;
204 let mut values = pattern.values.clone();
205 values.rotate_right(s);
206 Pattern::new(values)
207 }
208
209 pub fn reverse(&self, pattern: &Pattern) -> Pattern {
211 let mut values = pattern.values.clone();
212 values.reverse();
213 Pattern::new(values)
214 }
215
216 pub fn insert_mutate(&self, pattern: &Pattern, value: Ternary, seed: usize) -> Pattern {
218 let mut values = pattern.values.clone();
219 if !values.is_empty() {
220 let pos = seed % values.len();
221 values.insert(pos, value);
222 } else {
223 values.push(value);
224 }
225 Pattern::new(values)
226 }
227
228 pub fn delete_mutate(&self, pattern: &Pattern, seed: usize) -> Pattern {
230 let mut values = pattern.values.clone();
231 if !values.is_empty() {
232 let pos = seed % values.len();
233 values.remove(pos);
234 }
235 Pattern::new(values)
236 }
237
238 fn should_mutate(&self, index: usize, seed: usize) -> bool {
240 let hash = (index.wrapping_mul(31)).wrapping_add(seed).wrapping_mul(2654435761);
242 let normalized = (hash % 1000) as f64 / 1000.0;
244 normalized < self.mutation_rate
245 }
246}
247
248#[derive(Debug, Clone)]
252pub struct PatternGenerator {
253 pub seed: usize,
255}
256
257impl PatternGenerator {
258 pub fn new(seed: usize) -> Self {
259 Self { seed }
260 }
261
262 pub fn generate(&self, length: usize) -> Pattern {
264 let values: Vec<Ternary> = (0..length)
265 .map(|i| {
266 let hash = (i.wrapping_mul(7919)).wrapping_add(self.seed).wrapping_mul(1103515245);
267 match hash % 3 {
268 0 => Ternary::Negative,
269 1 => Ternary::Zero,
270 _ => Ternary::Positive,
271 }
272 })
273 .collect();
274 Pattern::new(values)
275 }
276
277 pub fn generate_symmetric(&self, half_length: usize) -> Pattern {
279 let half: Vec<Ternary> = (0..half_length)
280 .map(|i| {
281 let hash = (i.wrapping_mul(6271)).wrapping_add(self.seed).wrapping_mul(2147483647);
282 match hash % 3 {
283 0 => Ternary::Negative,
284 1 => Ternary::Zero,
285 _ => Ternary::Positive,
286 }
287 })
288 .collect();
289 let mut values = half.clone();
290 values.extend(half.iter().rev());
291 Pattern::new(values)
292 }
293
294 pub fn generate_weighted(&self, length: usize, neg_weight: f64, zero_weight: f64, pos_weight: f64) -> Pattern {
296 let total = neg_weight + zero_weight + pos_weight;
297 if total == 0.0 {
298 return Pattern::new(vec![Ternary::Zero; length]);
299 }
300 let neg_thresh = neg_weight / total;
301 let zero_thresh = neg_thresh + zero_weight / total;
302 let values: Vec<Ternary> = (0..length)
303 .map(|i| {
304 let hash = (i.wrapping_mul(3571)).wrapping_add(self.seed).wrapping_mul(48271);
305 let normalized = (hash % 1000) as f64 / 1000.0;
306 if normalized < neg_thresh {
307 Ternary::Negative
308 } else if normalized < zero_thresh {
309 Ternary::Zero
310 } else {
311 Ternary::Positive
312 }
313 })
314 .collect();
315 Pattern::new(values)
316 }
317}
318
319#[derive(Debug, Clone)]
323pub struct StyleTransfer {
324 rules: HashMap<String, Ternary>,
326}
327
328impl StyleTransfer {
329 pub fn new() -> Self {
330 Self {
331 rules: HashMap::new(),
332 }
333 }
334
335 pub fn add_rule(&mut self, source: &str, target: Ternary) {
337 self.rules.insert(source.to_string(), target);
338 }
339
340 pub fn apply(&self, pattern: &Pattern) -> Pattern {
342 let values: Vec<Ternary> = pattern
343 .values
344 .iter()
345 .map(|&v| {
346 let key = format!("{:?}", v);
347 match self.rules.get(&key) {
348 Some(&replacement) => replacement,
349 None => v,
350 }
351 })
352 .collect();
353 Pattern::new(values)
354 }
355
356 pub fn blend(a: &Pattern, b: &Pattern) -> Pattern {
358 let len = a.len().min(b.len());
359 let values: Vec<Ternary> = (0..len)
360 .map(|i| {
361 let avg = (a.values[i].to_i8() as i16 + b.values[i].to_i8() as i16) / 2;
362 Ternary::from_i8(avg as i8)
363 })
364 .collect();
365 Pattern::new(values)
366 }
367
368 pub fn overlay(a: &Pattern, b: &Pattern, offset: usize) -> Pattern {
370 let mut values = a.values.clone();
371 for (i, &v) in b.values.iter().enumerate() {
372 let pos = offset + i;
373 if pos < values.len() {
374 values[pos] = v;
375 }
376 }
377 Pattern::new(values)
378 }
379}
380
381#[derive(Debug, Clone)]
388pub struct CrossDomainMapper {
389 domains: HashMap<String, DomainMapping>,
391}
392
393#[derive(Debug, Clone)]
395pub struct DomainMapping {
396 pub negative_label: String,
397 pub zero_label: String,
398 pub positive_label: String,
399}
400
401impl CrossDomainMapper {
402 pub fn new() -> Self {
403 Self {
404 domains: HashMap::new(),
405 }
406 }
407
408 pub fn register_domain(
410 &mut self,
411 name: &str,
412 negative_label: &str,
413 zero_label: &str,
414 positive_label: &str,
415 ) {
416 self.domains.insert(
417 name.to_string(),
418 DomainMapping {
419 negative_label: negative_label.to_string(),
420 zero_label: zero_label.to_string(),
421 positive_label: positive_label.to_string(),
422 },
423 );
424 }
425
426 pub fn translate(&self, pattern: &Pattern, from_domain: &str, to_domain: &str) -> Option<Vec<String>> {
429 let _from = self.domains.get(from_domain)?;
430 let to = self.domains.get(to_domain)?;
431 Some(
432 pattern
433 .values
434 .iter()
435 .map(|&v| match v {
436 Ternary::Negative => to.negative_label.clone(),
437 Ternary::Zero => to.zero_label.clone(),
438 Ternary::Positive => to.positive_label.clone(),
439 })
440 .collect(),
441 )
442 }
443
444 pub fn label_for(&self, domain: &str, value: Ternary) -> Option<&str> {
446 let mapping = self.domains.get(domain)?;
447 Some(match value {
448 Ternary::Negative => &mapping.negative_label,
449 Ternary::Zero => &mapping.zero_label,
450 Ternary::Positive => &mapping.positive_label,
451 })
452 }
453
454 pub fn domain_names(&self) -> Vec<&str> {
456 self.domains.keys().map(|s| s.as_str()).collect()
457 }
458}
459
460#[derive(Debug, Clone)]
467pub struct Muse {
468 pub generator: PatternGenerator,
469 pub mutator: MutationEngine,
470 pub scorer: AestheticScorer,
471 pub style: StyleTransfer,
472}
473
474impl Muse {
475 pub fn new(seed: usize, mutation_rate: f64) -> Self {
476 Self {
477 generator: PatternGenerator::new(seed),
478 mutator: MutationEngine::new(mutation_rate),
479 scorer: AestheticScorer::default(),
480 style: StyleTransfer::new(),
481 }
482 }
483
484 pub fn with_scoring(seed: usize, mutation_rate: f64, sym_w: f64, comp_w: f64, bal_w: f64) -> Self {
486 Self {
487 generator: PatternGenerator::new(seed),
488 mutator: MutationEngine::new(mutation_rate),
489 scorer: AestheticScorer::new(sym_w, comp_w, bal_w),
490 style: StyleTransfer::new(),
491 }
492 }
493
494 pub fn create_and_evolve(&self, length: usize, generations: usize) -> Pattern {
497 let base = self.generator.generate(length);
498 let mut best = base.clone();
499 let mut best_score = self.scorer.score(&best);
500
501 for gen in 0..generations {
502 let candidate = self.mutator.flip_mutate(&best, gen);
503 let candidate_score = self.scorer.score(&candidate);
504 if candidate_score > best_score {
505 best = candidate;
506 best_score = candidate_score;
507 }
508 }
509 best
510 }
511
512 pub fn variants(&self, base: &Pattern, count: usize) -> Vec<Pattern> {
514 (0..count)
515 .map(|i| {
516 let rotated = self.mutator.rotate(base, i);
517 self.mutator.flip_mutate(&rotated, i)
518 })
519 .collect()
520 }
521
522 pub fn score(&self, pattern: &Pattern) -> f64 {
524 self.scorer.score(pattern)
525 }
526}
527
528#[cfg(test)]
531mod tests {
532 use super::*;
533
534 #[test]
535 fn test_ternary_to_i8() {
536 assert_eq!(Ternary::Negative.to_i8(), -1);
537 assert_eq!(Ternary::Zero.to_i8(), 0);
538 assert_eq!(Ternary::Positive.to_i8(), 1);
539 }
540
541 #[test]
542 fn test_ternary_from_i8() {
543 assert_eq!(Ternary::from_i8(-5), Ternary::Negative);
544 assert_eq!(Ternary::from_i8(0), Ternary::Zero);
545 assert_eq!(Ternary::from_i8(3), Ternary::Positive);
546 }
547
548 #[test]
549 fn test_ternary_negate() {
550 assert_eq!(Ternary::Negative.negate(), Ternary::Positive);
551 assert_eq!(Ternary::Zero.negate(), Ternary::Zero);
552 assert_eq!(Ternary::Positive.negate(), Ternary::Negative);
553 }
554
555 #[test]
556 fn test_pattern_symmetry_perfect() {
557 let p = Pattern::new(vec![Ternary::Positive, Ternary::Zero, Ternary::Positive]);
558 assert!((p.symmetry() - 1.0).abs() < 1e-9);
559 }
560
561 #[test]
562 fn test_pattern_symmetry_none() {
563 let p = Pattern::new(vec![Ternary::Positive, Ternary::Negative]);
564 assert!((p.symmetry() - 0.0).abs() < 1e-9);
565 }
566
567 #[test]
568 fn test_pattern_balance() {
569 let p = Pattern::new(vec![Ternary::Zero, Ternary::Positive, Ternary::Zero, Ternary::Negative]);
570 assert!((p.balance() - 0.5).abs() < 1e-9);
571 }
572
573 #[test]
574 fn test_pattern_complexity_max() {
575 let p = Pattern::new(vec![Ternary::Positive, Ternary::Negative, Ternary::Positive, Ternary::Negative]);
576 assert!((p.complexity() - 1.0).abs() < 1e-9);
577 }
578
579 #[test]
580 fn test_aesthetic_scorer() {
581 let scorer = AestheticScorer::default();
582 let p = Pattern::new(vec![Ternary::Positive, Ternary::Zero, Ternary::Positive]);
583 let score = scorer.score(&p);
584 assert!(score > 0.0 && score <= 1.0);
585 }
586
587 #[test]
588 fn test_aesthetic_scorer_custom_weights() {
589 let scorer = AestheticScorer::new(1.0, 0.0, 0.0);
590 let p = Pattern::new(vec![Ternary::Positive, Ternary::Zero, Ternary::Positive]);
591 assert!((scorer.score(&p) - 1.0).abs() < 1e-9);
592 }
593
594 #[test]
595 fn test_mutation_flip() {
596 let engine = MutationEngine::new(1.0); let p = Pattern::new(vec![Ternary::Positive, Ternary::Zero]);
598 let mutated = engine.flip_mutate(&p, 42);
599 assert_eq!(mutated.values[0], Ternary::Negative); }
601
602 #[test]
603 fn test_mutation_rotate() {
604 let engine = MutationEngine::new(0.5);
605 let p = Pattern::new(vec![Ternary::Positive, Ternary::Zero, Ternary::Negative]);
606 let rotated = engine.rotate(&p, 1);
607 assert_eq!(rotated.values[0], Ternary::Negative);
608 assert_eq!(rotated.values[1], Ternary::Positive);
609 }
610
611 #[test]
612 fn test_mutation_reverse() {
613 let engine = MutationEngine::new(0.5);
614 let p = Pattern::new(vec![Ternary::Positive, Ternary::Zero, Ternary::Negative]);
615 let reversed = engine.reverse(&p);
616 assert_eq!(reversed.values[0], Ternary::Negative);
617 assert_eq!(reversed.values[2], Ternary::Positive);
618 }
619
620 #[test]
621 fn test_mutation_insert() {
622 let engine = MutationEngine::new(0.5);
623 let p = Pattern::new(vec![Ternary::Positive, Ternary::Negative]);
624 let inserted = engine.insert_mutate(&p, Ternary::Zero, 0);
625 assert_eq!(inserted.len(), 3);
626 }
627
628 #[test]
629 fn test_mutation_delete() {
630 let engine = MutationEngine::new(0.5);
631 let p = Pattern::new(vec![Ternary::Positive, Ternary::Negative]);
632 let deleted = engine.delete_mutate(&p, 0);
633 assert_eq!(deleted.len(), 1);
634 }
635
636 #[test]
637 fn test_pattern_generator_deterministic() {
638 let gen = PatternGenerator::new(42);
639 let a = gen.generate(10);
640 let b = gen.generate(10);
641 assert_eq!(a, b);
642 }
643
644 #[test]
645 fn test_pattern_generator_symmetric() {
646 let gen = PatternGenerator::new(7);
647 let p = gen.generate_symmetric(3);
648 assert_eq!(p.len(), 6);
649 assert!((p.symmetry() - 1.0).abs() < 1e-9);
650 }
651
652 #[test]
653 fn test_pattern_generator_weighted() {
654 let gen = PatternGenerator::new(99);
655 let p = gen.generate_weighted(20, 1.0, 0.0, 0.0);
656 assert!(p.values.iter().all(|&v| v == Ternary::Negative));
657 }
658
659 #[test]
660 fn test_style_transfer_blend() {
661 let a = Pattern::new(vec![Ternary::Positive, Ternary::Negative]);
662 let b = Pattern::new(vec![Ternary::Negative, Ternary::Positive]);
663 let blended = StyleTransfer::blend(&a, &b);
664 assert_eq!(blended.values[0], Ternary::Zero);
665 assert_eq!(blended.values[1], Ternary::Zero);
666 }
667
668 #[test]
669 fn test_style_transfer_overlay() {
670 let a = Pattern::new(vec![Ternary::Zero, Ternary::Zero, Ternary::Zero, Ternary::Zero]);
671 let b = Pattern::new(vec![Ternary::Positive, Ternary::Negative]);
672 let overlaid = StyleTransfer::overlay(&a, &b, 1);
673 assert_eq!(overlaid.values[0], Ternary::Zero);
674 assert_eq!(overlaid.values[1], Ternary::Positive);
675 assert_eq!(overlaid.values[2], Ternary::Negative);
676 }
677
678 #[test]
679 fn test_cross_domain_mapper() {
680 let mut mapper = CrossDomainMapper::new();
681 mapper.register_domain("music", "flat", "natural", "sharp");
682 mapper.register_domain("visual", "dark", "neutral", "bright");
683 let p = Pattern::new(vec![Ternary::Positive, Ternary::Zero, Ternary::Negative]);
684 let translated = mapper.translate(&p, "music", "visual").unwrap();
685 assert_eq!(translated, vec!["bright", "neutral", "dark"]);
686 }
687
688 #[test]
689 fn test_cross_domain_mapper_label_for() {
690 let mut mapper = CrossDomainMapper::new();
691 mapper.register_domain("spatial", "left", "center", "right");
692 assert_eq!(mapper.label_for("spatial", Ternary::Positive), Some("right"));
693 assert_eq!(mapper.label_for("nonexistent", Ternary::Positive), None);
694 }
695
696 #[test]
697 fn test_muse_create_and_evolve() {
698 let muse = Muse::new(42, 0.3);
699 let result = muse.create_and_evolve(8, 10);
700 assert_eq!(result.len(), 8);
701 }
702
703 #[test]
704 fn test_muse_variants() {
705 let muse = Muse::new(42, 0.5);
706 let base = Pattern::new(vec![Ternary::Positive, Ternary::Zero, Ternary::Negative]);
707 let variants = muse.variants(&base, 5);
708 assert_eq!(variants.len(), 5);
709 for v in &variants {
710 assert_eq!(v.len(), 3);
711 }
712 }
713
714 #[test]
715 fn test_muse_scoring_integration() {
716 let muse = Muse::new(1, 0.2);
717 let p = muse.generator.generate(6);
718 let score = muse.score(&p);
719 assert!(score >= 0.0 && score <= 1.0);
720 }
721
722 #[test]
723 fn test_empty_pattern_metrics() {
724 let p = Pattern::new(vec![]);
725 assert!(p.is_empty());
726 assert!((p.symmetry() - 1.0).abs() < 1e-9);
727 assert!((p.balance() - 1.0).abs() < 1e-9);
728 assert!((p.complexity() - 0.0).abs() < 1e-9);
729 }
730}