rlevo_evolution/genome.rs
1//! Genome category trait and its zero-sized marker types.
2//!
3//! [`GenomeKind`] tags genome representations at the type level so operators
4//! can specialize on the element semantics (real-valued, binary, integer,
5//! or tree). Strategies take a marker type as a const generic to pick the
6//! right operator set.
7//!
8//! The markers themselves carry no data — they exist purely to discriminate
9//! trait impls.
10
11use std::fmt::Debug;
12
13/// Shape-erased genome kind.
14///
15/// `GenomeKind` is a zero-sized marker that strategies parameterize on to
16/// pick operators. Concrete kinds (`Real`, `Binary`, `Integer`, `Tree`,
17/// `Permutation`) live below; new kinds can be added by implementing this
18/// trait on a fresh marker type.
19///
20/// The associated constant [`GENOME_LEN`](GenomeKind::GENOME_LEN) records the
21/// genome length (number of genes) at the type level when it is compile-time
22/// known (for variable-length representations like trees, impls set it to `0`).
23pub trait GenomeKind: Debug + Copy + Send + Sync + 'static {
24 /// Compile-time genome length (number of genes), or `0` for
25 /// variable-length kinds.
26 const GENOME_LEN: usize;
27
28 /// Element type of the genome (typically `f32`, `i32`, or `bool`).
29 type Element: Copy + Debug + Send + Sync + 'static;
30}
31
32/// Real-valued genome (each gene is an `f32`).
33///
34/// Populations are stored as `Tensor<B, 2>` of shape `(pop_size, dim)`.
35/// All classical ES variants, real-coded GA, EP, and DE use this kind.
36#[derive(Debug, Clone, Copy, Default)]
37pub struct Real;
38
39impl GenomeKind for Real {
40 const GENOME_LEN: usize = 0;
41 type Element = f32;
42}
43
44/// Binary genome (each gene is a bit, stored as `i32` 0/1 on device).
45///
46/// Populations are stored as `Tensor<B, 2, Int>` of shape
47/// `(pop_size, dim)`. Binary-coded GA uses this kind.
48#[derive(Debug, Clone, Copy, Default)]
49pub struct Binary;
50
51impl GenomeKind for Binary {
52 const GENOME_LEN: usize = 0;
53 type Element = i32;
54}
55
56/// Integer-valued genome (each gene is a non-negative integer index).
57///
58/// Populations are stored as `Tensor<B, 2, Int>` of shape
59/// `(pop_size, dim)`. Cartesian GP (node indices), discrete parameter
60/// search, and other problems where genes are bounded integer values use
61/// this kind. For ordered-sequence problems (TSP, QAP) use [`Permutation`]
62/// instead.
63#[derive(Debug, Clone, Copy, Default)]
64pub struct Integer;
65
66/// Tree-based genome (variable-length AST, stored host-side).
67///
68/// Reserved for classical Koza-style GP in a future release. Tree
69/// genomes cannot be batched on a GPU and therefore have no tensor
70/// representation in this crate. The associated `Element` type is `i32`
71/// as a placeholder (structural node IDs); the actual in-memory
72/// representation will be defined when this kind is fully implemented.
73#[derive(Debug, Clone, Copy, Default)]
74pub struct Tree;
75
76/// Permutation genome (each row is a permutation of `0..n_nodes`).
77///
78/// Populations are stored as `Tensor<B, 2, Int>` of shape
79/// `(pop_size, n_nodes)` where every row is a valid permutation. Used by
80/// Ant Colony Optimization over combinatorial domains (TSP, QAP, …);
81/// only a stubbed consumer ships in this release — a full implementation
82/// is planned for a future release.
83#[derive(Debug, Clone, Copy, Default)]
84pub struct Permutation;
85
86impl GenomeKind for Integer {
87 const GENOME_LEN: usize = 0;
88 type Element = i32;
89}
90
91impl GenomeKind for Tree {
92 const GENOME_LEN: usize = 0;
93 type Element = i32;
94}
95
96impl GenomeKind for Permutation {
97 const GENOME_LEN: usize = 0;
98 type Element = i32;
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104
105 #[test]
106 fn real_has_f32_element() {
107 let _: <Real as GenomeKind>::Element = 0.0_f32;
108 }
109
110 #[test]
111 fn binary_has_i32_element() {
112 let _: <Binary as GenomeKind>::Element = 1_i32;
113 }
114
115 #[test]
116 fn integer_has_i32_element() {
117 let _: <Integer as GenomeKind>::Element = 5_i32;
118 }
119
120 #[test]
121 fn permutation_has_i32_element() {
122 let _: <Permutation as GenomeKind>::Element = 7_i32;
123 }
124
125 #[test]
126 fn markers_are_debug() {
127 let _ = format!(
128 "{Real:?} {Binary:?} {Integer:?} {Tree:?} {Permutation:?}"
129 );
130 }
131}