1use core::{
4 cmp::Ordering,
5 fmt::{Display, Formatter},
6 hash::{Hash, Hasher},
7 marker::PhantomData,
8};
9
10use distances::Number;
11use serde::{
12 de::{MapAccess, SeqAccess, Visitor},
13 ser::SerializeStruct,
14 Deserialize, Deserializer, Serialize, Serializer,
15};
16
17use crate::{core::cluster::Children, utils, Cluster, Dataset, Instance, PartitionCriterion, UniBall};
18
19pub type Ratios = [f64; 6];
21
22#[derive(Debug, Clone)]
24pub struct Vertex<U: Number> {
25 uni_ball: UniBall<U>,
27 ratios: Ratios,
29 children: Option<Children<U, Self>>,
31}
32
33impl<I: Instance, U: Number, D: Dataset<I, U>> crate::Tree<I, U, D, Vertex<U>> {
34 #[must_use]
42 pub fn normalize_ratios(mut self) -> Self {
43 self.root = self.root.normalize_ratios();
44 self
45 }
46}
47
48impl<U: Number> Vertex<U> {
49 pub const fn new(uni_ball: UniBall<U>, ratios: Ratios, children: Option<Children<U, Self>>) -> Self {
51 Self {
52 uni_ball,
53 ratios,
54 children,
55 }
56 }
57
58 pub fn from_base_tree(root: UniBall<U>) -> Self {
60 Self::from_uni_ball(root).set_child_parent_ratios([1.0; 6])
61 }
62
63 fn from_uni_ball(mut uni_ball: UniBall<U>) -> Self {
65 match uni_ball.children {
66 Some(children) => {
67 uni_ball.children = None;
68 let left = Box::new(Self::from_uni_ball(*children.left));
69 let right = Box::new(Self::from_uni_ball(*children.right));
70 let children = Children {
71 left,
72 right,
73 arg_l: children.arg_l,
74 arg_r: children.arg_r,
75 polar_distance: children.polar_distance,
76 };
77 Self::new(uni_ball, [1.0; 6], Some(children))
78 }
79 None => Self::new(uni_ball, [1.0; 6], None),
80 }
81 }
82
83 #[must_use]
85 #[allow(clippy::similar_names)]
86 pub(crate) fn set_child_parent_ratios(mut self, parent_ratios: Ratios) -> Self {
87 let [pc, pr, pl, pc_, pr_, pl_] = parent_ratios;
88
89 let c = self.cardinality().as_f64() / pc;
90 let r = self.radius().as_f64() / pr;
91 let l = self.lfd() / pl;
92
93 let c_ = utils::next_ema(c, pc_);
94 let r_ = utils::next_ema(r, pr_);
95 let l_ = utils::next_ema(l, pl_);
96
97 let ratios = [c, r, l, c_, r_, l_];
98 self.ratios = ratios;
99
100 if let Some(Children {
101 left,
102 right,
103 arg_l,
104 arg_r,
105 polar_distance,
106 }) = self.children
107 {
108 let left = Box::new(left.set_child_parent_ratios(ratios));
109 let right = Box::new(right.set_child_parent_ratios(ratios));
110 let children = Children {
111 left,
112 right,
113 arg_l,
114 arg_r,
115 polar_distance,
116 };
117 self.children = Some(children);
118 }
119
120 self
121 }
122
123 #[must_use]
125 pub fn normalize_ratios(mut self) -> Self {
126 let all_ratios = self.subtree().into_iter().map(Self::ratios).collect::<Vec<_>>();
127
128 let all_ratios = utils::rows_to_cols(&all_ratios);
129
130 let means = utils::calc_row_means(&all_ratios);
132
133 let sds = utils::calc_row_sds(&all_ratios);
135
136 self.set_normalized_ratios(means, sds);
137
138 self
139 }
140
141 fn set_normalized_ratios(&mut self, means: Ratios, sds: Ratios) {
143 let normalized_ratios: Vec<_> = self
144 .ratios
145 .into_iter()
146 .zip(means)
147 .zip(sds)
148 .map(|((value, mean), std)| (value - mean) / std.mul_add(core::f64::consts::SQRT_2, f64::EPSILON))
149 .map(libm::erf)
150 .map(|v| (1. + v) / 2.)
151 .collect();
152
153 if let Ok(normalized_ratios) = normalized_ratios.try_into() {
154 self.ratios = normalized_ratios;
155 }
156
157 match &mut self.children {
158 Some(children) => {
159 children.left.set_normalized_ratios(means, sds);
160 children.right.set_normalized_ratios(means, sds);
161 }
162 None => (),
163 }
164 }
165
166 pub const fn uni_ball(&self) -> &UniBall<U> {
168 &self.uni_ball
169 }
170
171 pub const fn ratios(&self) -> Ratios {
173 self.ratios
174 }
175}
176
177impl<U: Number> Cluster<U> for Vertex<U> {
178 fn new_root<I: Instance, D: Dataset<I, U>>(data: &D, seed: Option<u64>) -> Self {
179 let uni_ball = UniBall::new_root(data, seed);
180 let ratios = [0.0; 6];
181 Self::new(uni_ball, ratios, None)
182 }
183
184 fn partition<I, D, P>(self, data: &mut D, criteria: &P, seed: Option<u64>) -> Self
185 where
186 I: Instance,
187 D: Dataset<I, U>,
188 P: PartitionCriterion<U>,
189 {
190 let uni_ball = self.uni_ball.partition(data, criteria, seed);
191 Self::from_base_tree(uni_ball)
192 }
193
194 fn offset(&self) -> usize {
195 self.uni_ball.offset()
196 }
197
198 fn cardinality(&self) -> usize {
199 self.uni_ball.cardinality()
200 }
201
202 fn depth(&self) -> usize {
203 self.uni_ball.depth()
204 }
205
206 fn arg_center(&self) -> usize {
207 self.uni_ball.arg_center()
208 }
209
210 fn radius(&self) -> U {
211 self.uni_ball.radius()
212 }
213
214 fn arg_radial(&self) -> usize {
215 self.uni_ball.arg_radial()
216 }
217
218 fn lfd(&self) -> f64 {
219 self.uni_ball.lfd()
220 }
221
222 fn children(&self) -> Option<[&Self; 2]> {
223 self.children.as_ref().map(|c| [c.left.as_ref(), c.right.as_ref()])
224 }
225
226 fn polar_distance(&self) -> Option<U> {
227 self.uni_ball.polar_distance()
228 }
229
230 fn arg_poles(&self) -> Option<[usize; 2]> {
231 self.uni_ball.arg_poles()
232 }
233}
234
235impl<U: Number> PartialEq for Vertex<U> {
236 fn eq(&self, other: &Self) -> bool {
237 self.uni_ball.eq(&other.uni_ball)
238 }
239}
240
241impl<U: Number> Eq for Vertex<U> {}
242
243impl<U: Number> PartialOrd for Vertex<U> {
244 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
245 Some(self.cmp(other))
246 }
247}
248
249impl<U: Number> Ord for Vertex<U> {
250 fn cmp(&self, other: &Self) -> Ordering {
251 self.uni_ball.cmp(&other.uni_ball)
252 }
253}
254
255impl<U: Number> Hash for Vertex<U> {
256 fn hash<H: Hasher>(&self, state: &mut H) {
257 self.uni_ball.hash(state);
258 }
259}
260
261impl<U: Number> Display for Vertex<U> {
262 fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
263 write!(f, "{}", self.uni_ball)
264 }
265}
266
267impl<U: Number> Serialize for Vertex<U> {
268 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
269 let mut state = serializer.serialize_struct("Vertex", 3)?;
270 state.serialize_field("uni_ball", &self.uni_ball)?;
271 state.serialize_field("ratios", &self.ratios)?;
272 state.serialize_field("children", &self.children)?;
273 state.end()
274 }
275}
276
277impl<'de, U: Number> Deserialize<'de> for Vertex<U> {
278 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
279 #[derive(Deserialize)]
281 #[serde(field_identifier, rename_all = "lowercase")]
282 enum Field {
283 UniBall,
285 Ratios,
287 Children,
289 }
290
291 struct VertexVisitor<U: Number>(PhantomData<U>);
293
294 impl<'de, U: Number> Visitor<'de> for VertexVisitor<U> {
295 type Value = Vertex<U>;
296
297 fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
298 formatter.write_str("struct Vertex")
299 }
300
301 fn visit_seq<V: SeqAccess<'de>>(self, mut seq: V) -> Result<Self::Value, V::Error> {
302 let uni_ball = seq
303 .next_element()?
304 .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
305 let ratios = seq
306 .next_element()?
307 .ok_or_else(|| serde::de::Error::invalid_length(1, &self))?;
308 let children = seq
309 .next_element()?
310 .ok_or_else(|| serde::de::Error::invalid_length(2, &self))?;
311 Ok(Vertex::new(uni_ball, ratios, children))
312 }
313
314 fn visit_map<V: MapAccess<'de>>(self, mut map: V) -> Result<Self::Value, V::Error> {
315 let mut uni_ball = None;
316 let mut ratios = None;
317 let mut children = None;
318
319 while let Some(key) = map.next_key()? {
320 match key {
321 Field::UniBall => {
322 if uni_ball.is_some() {
323 return Err(serde::de::Error::duplicate_field("uni_ball"));
324 }
325 uni_ball = Some(map.next_value()?);
326 }
327 Field::Ratios => {
328 if ratios.is_some() {
329 return Err(serde::de::Error::duplicate_field("ratios"));
330 }
331 ratios = Some(map.next_value()?);
332 }
333 Field::Children => {
334 if children.is_some() {
335 return Err(serde::de::Error::duplicate_field("children"));
336 }
337 children = Some(map.next_value()?);
338 }
339 }
340 }
341
342 let uni_ball = uni_ball.ok_or_else(|| serde::de::Error::missing_field("uni_ball"))?;
343 let ratios = ratios.ok_or_else(|| serde::de::Error::missing_field("ratios"))?;
344 let children = children.ok_or_else(|| serde::de::Error::missing_field("children"))?;
345
346 Ok(Vertex::new(uni_ball, ratios, children))
347 }
348 }
349
350 const FIELDS: &[&str] = &["uni_ball", "ratios", "children"];
352 deserializer.deserialize_struct("Vertex", FIELDS, VertexVisitor(PhantomData))
353 }
354}