Skip to main content

radiate_core/objectives/
mod.rs

1pub mod front;
2pub mod optimize;
3pub mod pareto;
4pub mod score;
5
6pub use front::*;
7pub use optimize::*;
8pub use pareto::*;
9pub use score::*;
10
11// use crate::objectives::{Objective, Scored, pareto};
12// #[cfg(feature = "serde")]
13// use serde::{Deserialize, Serialize};
14// use std::{cmp::Ordering, hash::Hash, ops::Range, sync::Arc};
15
16// const DEFAULT_ENTROPY_BINS: usize = 20;
17
18// pub struct FrontAddResult {
19//     pub added_count: usize,
20//     pub removed_count: usize,
21//     pub comparisons: usize,
22//     pub filter_count: usize,
23//     pub size: usize,
24// }
25
26// /// A `Front<T>` is a collection of `T`'s that are non-dominated with respect to each other.
27// /// This is useful for multi-objective optimization problems where the goal is to find
28// /// the best solutions that are not dominated by any other solution.
29// /// This results in what is called the Pareto front.
30// #[derive(Clone)]
31// #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
32// pub struct Front<T>
33// where
34//     T: Scored,
35// {
36//     values: Vec<Arc<T>>,
37//     range: Range<usize>,
38//     objective: Objective,
39
40//     // ---- scratch / cache (not part of logical state) ----
41//     #[cfg_attr(feature = "serde", serde(skip))]
42//     scratch_remove: Vec<usize>,
43
44//     #[cfg_attr(feature = "serde", serde(skip))]
45//     scratch_keep_idx: Vec<usize>,
46
47//     // Flat score matrix: [n, m] row-major
48//     #[cfg_attr(feature = "serde", serde(skip))]
49//     scratch_scores: Vec<f32>,
50
51//     // Crowding distance per item (len = n)
52//     #[cfg_attr(feature = "serde", serde(skip))]
53//     scratch_dist: Vec<f32>,
54
55//     // Indices 0..n used for per-dimension sorts in crowding distance
56//     #[cfg_attr(feature = "serde", serde(skip))]
57//     scratch_order: Vec<usize>,
58// }
59
60// impl<T> Front<T>
61// where
62//     T: Scored,
63// {
64//     pub fn new(range: Range<usize>, objective: Objective) -> Self {
65//         Front {
66//             values: Vec::new(),
67//             range,
68//             objective: objective.clone(),
69//             scratch_remove: Vec::new(),
70//             scratch_keep_idx: Vec::new(),
71//             scratch_scores: Vec::new(),
72//             scratch_dist: Vec::new(),
73//             scratch_order: Vec::new(),
74//         }
75//     }
76
77//     pub fn range(&self) -> Range<usize> {
78//         self.range.clone()
79//     }
80
81//     pub fn objective(&self) -> Objective {
82//         self.objective.clone()
83//     }
84
85//     pub fn is_empty(&self) -> bool {
86//         self.values.is_empty()
87//     }
88
89//     pub fn values(&self) -> &[Arc<T>] {
90//         &self.values
91//     }
92
93//     pub fn crowding_distance(&self) -> Option<Vec<f32>> {
94//         let scores = self
95//             .values
96//             .iter()
97//             .filter_map(|s| s.score())
98//             .collect::<Vec<_>>();
99
100//         if scores.is_empty() {
101//             return None;
102//         }
103
104//         Some(pareto::crowding_distance(&scores))
105//     }
106
107//     pub fn entropy(&self) -> Option<f32> {
108//         let scores = self
109//             .values
110//             .iter()
111//             .filter_map(|s| s.score())
112//             .collect::<Vec<_>>();
113
114//         if scores.is_empty() {
115//             return None;
116//         }
117
118//         Some(pareto::entropy(&scores, DEFAULT_ENTROPY_BINS))
119//     }
120
121//     pub fn add_all(&mut self, items: Vec<T>) -> FrontAddResult
122//     where
123//         T: Eq + Hash + Clone + Send + Sync + 'static,
124//     {
125//         let mut updated = false;
126//         let mut to_remove = Vec::new();
127//         let mut added_count = 0;
128//         let mut removed_count = 0;
129//         let mut comparisons = 0;
130//         let mut filter_count = 0;
131
132//         for new_member in items.into_iter() {
133//             let mut is_dominated = true;
134
135//             for existing_val in self.values.iter() {
136//                 let equals = &new_member == existing_val.as_ref();
137//                 if self.dom_cmp(existing_val.as_ref(), &new_member) == Ordering::Greater || equals {
138//                     // If an existing value dominates the new value, return false
139//                     is_dominated = false;
140//                     comparisons += 1;
141//                     break;
142//                 } else if self.dom_cmp(&new_member, existing_val.as_ref()) == Ordering::Greater {
143//                     // If the new value dominates an existing value, continue checking
144//                     to_remove.push(Arc::clone(existing_val));
145//                     comparisons += 1;
146//                     continue;
147//                 }
148//             }
149
150//             if is_dominated {
151//                 updated = true;
152//                 self.values.push(Arc::new(new_member));
153//                 added_count += 1;
154//                 for rem in to_remove.drain(..) {
155//                     self.values.retain(|x| x.as_ref() != rem.as_ref());
156//                     removed_count += 1;
157//                 }
158//             }
159
160//             if updated && self.values.len() > self.range.end {
161//                 self.filter();
162//                 filter_count += 1;
163//             }
164
165//             to_remove.clear();
166//             updated = false;
167//         }
168
169//         FrontAddResult {
170//             added_count,
171//             removed_count,
172//             comparisons,
173//             filter_count,
174//             size: self.values.len(),
175//         }
176//     }
177
178//     fn dom_cmp(&self, one: &T, two: &T) -> Ordering {
179//         let one_score = one.score();
180//         let two_score = two.score();
181
182//         if one_score.is_none() || two_score.is_none() {
183//             return Ordering::Equal;
184//         }
185
186//         if let (Some(one), Some(two)) = (one_score, two_score) {
187//             if pareto::dominance(one, two, &self.objective) {
188//                 return Ordering::Greater;
189//             } else if pareto::dominance(two, one, &self.objective) {
190//                 return Ordering::Less;
191//             }
192//         }
193
194//         Ordering::Equal
195//     }
196
197//     fn filter(&mut self) {
198//         if let Some(crowding_distances) = self.crowding_distance() {
199//             let mut enumerated = crowding_distances.iter().enumerate().collect::<Vec<_>>();
200
201//             enumerated.sort_unstable_by(|a, b| b.1.partial_cmp(a.1).unwrap_or(Ordering::Equal));
202
203//             self.values = enumerated
204//                 .iter()
205//                 .take(self.range.start)
206//                 .map(|(i, _)| Arc::clone(&self.values[*i]))
207//                 .collect::<Vec<Arc<T>>>();
208//         }
209//     }
210// }
211
212// impl<T> Default for Front<T>
213// where
214//     T: Scored,
215// {
216//     fn default() -> Self {
217//         Front::new(0..0, Objective::default())
218//     }
219// }