abd-clam 0.25.3

Clustering, Learning and Approximation with Manifolds
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
use std::collections::HashMap;
use std::hash::Hash;

use crate::core::cluster::Cluster;
use crate::core::graph::Graph;
use distances::Number;

/// Type alias for cluster scores associated with clusters in a graph.
pub type ClusterScores<'a, U> = HashMap<&'a Cluster<U>, f64>;
/// Type alias for scores associated with individual instances or elements.
pub type InstanceScores = HashMap<usize, f64>;

/// A trait for scoring graphs.
pub trait GraphScorer<'a, U: Number>: Hash {
    /// Computes scores for the given graph and returns cluster scores and an array of scores.
    ///
    /// This function is responsible for calculating scores based on the input graph.
    ///
    /// # Arguments
    ///
    /// * `_graph`: A reference to the input graph from which scores are calculated.
    ///
    /// # Returns
    ///
    /// A tuple containing cluster scores and an array of scores.
    ///
    /// * `ClusterScores`: A structure that holds scores associated with individual clusters in the graph.
    /// * `Vec<f64>`: An array of scores, where each element corresponds to a specific aspect or metric.
    ///
    fn call(&self, _graph: &'a Graph<'a, U>) -> (ClusterScores<'a, U>, Vec<f64>) {
        todo!()
        // let cluster_scores = {
        //     let mut cluster_scores = self.score_graph(graph);
        //     if self.normalize_on_clusters() {
        //         let (clusters, scores): (Vec<_>, Vec<_>) = cluster_scores.into_iter().unzip();
        //         cluster_scores = clusters
        //             .into_iter()
        //             .zip(crate::utils::normalize_1d(&scores,statistical::mean(&scores),statistical::population_standard_deviation(&scores, None)).into_iter())
        //             .collect();
        //     }
        //     cluster_scores
        // };
        //
        // let instance_scores = {
        //     let mut instance_scores = self.inherit_scores(&cluster_scores);
        //     if !self.normalize_on_clusters() {
        //         let (indices, scores): (Vec<_>, Vec<_>) = instance_scores.into_iter().unzip();
        //         instance_scores = indices
        //             .into_iter()
        //             .zip(crate::utils::normalize_1d(&scores,statistical::mean(&scores),statistical::population_standard_deviation(&scores, None)).into_iter())
        //             .collect();
        //     }
        //     instance_scores
        // };
        //
        // let scores_array = self.ordered_scores(&instance_scores);
        //
        // (cluster_scores, scores_array)
    }

    /// Returns the name of the graph scorer.
    fn name(&self) -> &str;

    /// Returns the short name of the graph scorer.
    fn short_name(&self) -> &str;

    /// Indicates whether normalization should be performed based on clusters.
    fn normalize_on_clusters(&self) -> bool;

    /// Computes and returns cluster scores for clusters in the input graph.
    ///
    /// This function calculates cluster scores based on the characteristics of clusters in the input graph.
    /// Cluster scores are represented as a `ClusterScores` mapping clusters to their associated scores.
    ///
    /// # Arguments
    ///
    /// * `graph`: The input graph for which cluster scores are computed.
    ///
    /// # Returns
    ///
    /// A `ClusterScores` mapping clusters in the input graph to their associated scores.
    fn score_graph(&self, graph: &'a Graph<'a, U>) -> ClusterScores<'a, U>;

    /// Inherits cluster scores and computes scores for individual instances.
    ///
    /// This function inherits cluster scores and uses them to calculate scores for individual instances.
    /// It takes a `ClusterScores` as input, which maps clusters to their associated scores,
    /// and returns an `InstanceScores` mapping instances to their computed scores.
    ///
    /// # Arguments
    ///
    /// * `scores`: A `ClusterScores` mapping clusters to their associated scores.
    ///
    /// # Returns
    ///
    /// An `InstanceScores` mapping instances to their computed scores.
    fn inherit_scores(&self, _scores: &ClusterScores<U>) -> InstanceScores {
        todo!()

        // scores
        //     .iter()
        //     .flat_map(|(&c, &s)| c.indices().into_iter().map(move |i| (i, s)))
        //     .collect()
    }

    /// Orders the scores for individual instances.
    ///
    /// This function takes an `InstanceScores` mapping instances to their associated scores
    /// and returns a sorted vector of scores for instances. The vector contains the scores
    /// in ascending order based on the instance indices.
    ///
    /// # Arguments
    ///
    /// * `scores`: An `InstanceScores` mapping instances to their associated scores.
    ///
    /// # Returns
    ///
    /// A sorted vector of scores for instances in ascending order.
    fn ordered_scores(&self, _scores: &InstanceScores) -> Vec<f64> {
        todo!()

        // let mut scores: Vec<_> = scores.iter().map(|(&i, &s)| (i, s)).collect();
        // scores.sort_by_key(|(i, _)| *i);
        // let (_, scores): (Vec<_>, Vec<f64>) = scores.into_iter().unzip();
        // scores
    }
}

/// A graph scorer that calculates scores based on cluster cardinality.
pub struct ClusterCardinality;

impl Hash for ClusterCardinality {
    /// Generates a hash for the `ClusterCardinality` instance.
    ///
    /// This function hashes the string "`cluster_cardinality`" to uniquely identify this scorer.
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        "cluster_cardinality".hash(state);
    }
}

impl<'a, U: Number> GraphScorer<'a, U> for ClusterCardinality {
    /// Returns the name of the `ClusterCardinality` graph scorer.
    ///
    /// The name is "`cluster_cardinality`."
    fn name(&self) -> &str {
        "cluster_cardinality"
    }

    /// Returns the short name of the `ClusterCardinality` graph scorer.
    ///
    /// The short name is "cc."
    fn short_name(&self) -> &str {
        "cc"
    }

    /// Indicates whether normalization should be performed based on clusters for `ClusterCardinality`.
    ///
    /// TODO!
    fn normalize_on_clusters(&self) -> bool {
        todo!()
        //true
    }

    /// Computes and returns cluster scores based on cluster cardinality.
    ///
    /// This function calculates the scores for clusters based on their cardinality and returns them
    /// as a map of cluster references to their respective scores as floating-point values. The scores
    /// are calculated based on the cluster's cardinality, which represents the number of elements
    /// in the cluster.
    ///
    /// # Arguments
    ///
    /// * `_graph`: A reference to the input graph from which cluster scores are calculated.
    ///
    /// # Returns
    ///
    /// A `ClusterScores` mapping clusters to their calculated scores based on their cardinality.
    fn score_graph(&self, _graph: &'a Graph<'a, U>) -> ClusterScores<'a, U> {
        todo!()

        // graph
        //     .ordered_clusters()
        //     .iter()
        //     .map(|&c| (c, c.cardinality() as f64))
        //     .collect()
    }
}

/// A graph scorer that calculates scores based on component cardinality.
pub struct ComponentCardinality;

impl Hash for ComponentCardinality {
    /// Generates a hash for the `ComponentCardinality` instance.
    ///
    /// This function hashes the string "`component_cardinality`" to uniquely identify this scorer.
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        "component_cardinality".hash(state);
    }
}

impl<'a, U: Number> GraphScorer<'a, U> for ComponentCardinality {
    /// Returns the name of the `ComponentCardinality` graph scorer.
    ///
    /// The name is "`component_cardinality`."
    fn name(&self) -> &str {
        "component_cardinality"
    }

    /// Returns the short name of the `ComponentCardinality` graph scorer.
    ///
    /// The short name is "sc."
    fn short_name(&self) -> &str {
        "sc"
    }

    /// Indicates whether normalization should be performed based on clusters for `ComponentCardinality`.
    ///
    /// TODO!
    fn normalize_on_clusters(&self) -> bool {
        todo!()
        //true
    }

    /// Computes and returns cluster scores based on component cardinality.
    ///
    /// This function calculates the scores for clusters based on the cardinality of components they belong to
    /// and returns them as a map of cluster references to their respective scores as floating-point values.
    /// The scores are calculated based on the cardinality of the components that each cluster belongs to.
    ///
    /// # Arguments
    ///
    /// * `_graph`: A reference to the input graph from which cluster scores are calculated.
    ///
    /// # Returns
    ///
    /// A `ClusterScores` mapping clusters to their calculated scores based on the cardinality of their components.
    fn score_graph(&self, _graph: &'a Graph<'a, U>) -> ClusterScores<'a, U> {
        todo!()

        // graph
        //     .find_component_clusters()
        //     .iter()
        //     .flat_map(|clusters| {
        //         let score = clusters.len() as f64;
        //         clusters.iter().map(move |&c| (c, score))
        //     })
        //     .collect()
    }
}

/// A graph scorer that calculates scores based on vertex degree.
pub struct VertexDegree;

impl Hash for VertexDegree {
    /// Generates a hash for the `VertexDegree` instance.
    ///
    /// This function hashes the string "`vertex_degree`" to uniquely identify this scorer.
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        "vertex_degree".hash(state);
    }
}

impl<'a, U: Number> GraphScorer<'a, U> for VertexDegree {
    /// Returns the name of the `VertexDegree` graph scorer.
    ///
    /// The name is "`vertex_degree`."
    fn name(&self) -> &str {
        "vertex_degree"
    }

    /// Returns the short name of the `VertexDegree` graph scorer.
    ///
    /// The short name is "vd."
    fn short_name(&self) -> &str {
        "vd"
    }

    /// Indicates whether normalization should be performed based on clusters for `VertexDegree`.
    ///
    /// TODO!
    fn normalize_on_clusters(&self) -> bool {
        todo!()
        //true
    }

    /// Computes and returns cluster scores based on vertex degree.
    ///
    /// This function calculates the scores for clusters based on the vertex degrees of their vertices
    /// and returns them as a map of cluster references to their respective scores as floating-point values.
    /// The scores are calculated based on the vertex degrees of the clusters' vertices within the input graph.
    ///
    /// # Arguments
    ///
    /// * `_graph`: A reference to the input graph from which cluster scores are calculated.
    ///
    /// # Returns
    ///
    /// A `ClusterScores` mapping clusters to their calculated scores based on the vertex degrees of their vertices.
    fn score_graph(&self, _graph: &'a Graph<'a, U>) -> ClusterScores<'a, U> {
        todo!()

        // graph
        //     .ordered_clusters()
        //     .iter()
        //     .map(|&c| (c, graph.unchecked_vertex_degree(c) as f64))
        //     .collect()
    }
}

/// A graph scorer that calculates scores based on parent-child cluster relationships and cardinality.
///
/// This scorer assigns scores to clusters based on the cardinality of a cluster relative to its parent
/// cluster in a hierarchical structure. It uses a user-defined weight function to assign weights to
/// different levels of the hierarchy.
pub struct ParentCardinality<'a, U: Number> {
    /// The root cluster in the hierarchical structure.
    #[allow(dead_code)]
    root: &'a Cluster<U>,
    /// User-defined weight function for hierarchy levels.
    #[allow(dead_code)]
    weight: Box<dyn (Fn(usize) -> f64) + Send + Sync>,
}

impl<'a, U: Number> ParentCardinality<'a, U> {
    /// Creates a new instance of the `ParentCardinality` scorer.
    ///
    /// The `root` parameter specifies the root cluster of the hierarchy. The weight function is used
    /// to assign weights to different levels of the hierarchy.
    ///
    /// # Arguments
    ///
    /// * `_root`: The root cluster of the hierarchical structure.
    ///
    /// # Returns
    ///
    /// A new instance of the `ParentCardinality` scorer with the specified root cluster and weight function.
    pub fn new(_root: &'a Cluster<U>) -> Self {
        todo!()
        // let weight = Box::new(|d: usize| 1. / (d as f64).sqrt());
        // Self { root, weight }
    }

    /// Computes the ancestry of a given cluster.
    ///
    /// The ancestry of a cluster is a list of clusters starting from the root and ending at the given
    /// cluster. The list represents the hierarchical relationship between clusters in the structure.
    ///
    /// # Arguments
    ///
    /// * `_c`: The cluster for which the ancestry is to be computed.
    ///
    /// # Returns
    ///
    /// A vector of references to clusters representing the ancestry of the specified cluster.
    ///
    /// This method computes the ancestry of a cluster by traversing the hierarchical structure, starting from
    /// the root cluster and following parent-child relationships until the given cluster is reached.
    /// The resulting vector contains references to clusters that form the ancestry of the specified cluster.
    pub fn ancestry(&self, _c: &'a Cluster<U>) -> Vec<&'a Cluster<U>> {
        todo!()

        // c.history().into_iter().fold(vec![self.root], |mut ancestors, turn| {
        //     let last = ancestors.last().unwrap();
        //     let [left, right] = last.children().unwrap();
        //     let child = if *turn { right } else { left };
        //     ancestors.push(child);
        //     ancestors
        // })
    }
}

impl<'a, U: Number> Hash for ParentCardinality<'a, U> {
    /// Generates a hash for the `ParentCardinality` instance.
    ///
    /// This function hashes the string "`parent_cardinality`" to uniquely identify this scorer.
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        "parent_cardinality".hash(state);
    }
}

impl<'a, U: Number> GraphScorer<'a, U> for ParentCardinality<'a, U> {
    /// Returns the name of the `ParentCardinality` graph scorer.
    ///
    /// The name is "`parent_cardinality`."
    fn name(&self) -> &str {
        "parent_cardinality"
    }

    /// Returns the short name of the `ParentCardinality` graph scorer.
    ///
    /// The short name is "pc."
    fn short_name(&self) -> &str {
        "pc"
    }

    /// Indicates whether normalization should be performed based on clusters for `ParentCardinality`.
    ///
    /// TODO!
    fn normalize_on_clusters(&self) -> bool {
        todo!()
        //true
    }

    /// Computes and returns cluster scores based on parent-child cluster relationships and cardinality.
    ///
    /// This function calculates the scores for clusters based on their hierarchical relationships and
    /// cardinality, using the weight function to assign weights to different hierarchy levels.
    ///
    /// # Arguments
    ///
    /// * `_graph`: The input graph for which cluster scores are to be computed.
    ///
    /// # Returns
    ///
    /// A map of cluster indices to their respective scores as floating-point values.
    fn score_graph(&self, _graph: &'a Graph<'a, U>) -> ClusterScores<'a, U> {
        todo!()

        // graph
        //     .ordered_clusters()
        //     .iter()
        //     .map(|&c| {
        //         let ancestry = self.ancestry(c);
        //         let score: f64 = ancestry
        //             .iter()
        //             .skip(1)
        //             .zip(ancestry.iter())
        //             .enumerate()
        //             .map(|(i, (child, parent))| {
        //                 (self.weight)(i + 1) * parent.cardinality() as f64 / child.cardinality() as f64
        //             })
        //             .sum();
        //         (c, -score)
        //     })
        //     .collect()
    }
}

/// A graph scorer that calculates scores based on the neighborhood of clusters in a graph.
pub struct GraphNeighborhood {
    /// Fraction used to determine neighborhood size.
    #[allow(dead_code)]
    eccentricity_fraction: f64,
}

impl GraphNeighborhood {
    /// Creates a new instance of the `GraphNeighborhood` scorer.
    ///
    /// The `eccentricity_fraction` parameter specifies a factor that influences the number of steps taken
    /// in the neighborhood computation.
    ///
    #[must_use]
    pub const fn new(eccentricity_fraction: f64) -> Self {
        Self { eccentricity_fraction }
    }

    /// Calculates the number of steps for neighborhood computation in the graph.
    ///
    /// This function computes the number of steps based on the eccentricity of the given cluster
    /// and the eccentricity fraction specified during initialization.
    ///
    /// # Arguments
    ///
    /// * `_graph`: The input graph for which the number of steps is calculated.
    /// * `_c`: The cluster for which the number of steps is determined.
    ///
    /// # Returns
    ///
    /// The number of steps for neighborhood computation as a `usize` value.
    #[allow(dead_code)]
    fn num_steps<'a, U: Number>(&self, _graph: &'a Graph<'a, U>, _c: &'a Cluster<U>) -> usize {
        todo!()

        // let steps = graph.unchecked_eccentricity(c) as f64 * self.eccentricity_fraction;
        // 1 + steps as usize
    }
}

impl Hash for GraphNeighborhood {
    /// Generates a hash for the `GraphNeighborhood` instance.
    ///
    /// This function hashes the string "`graph_neighborhood`" to uniquely identify this scorer.
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        "graph_neighborhood".hash(state);
    }
}

impl<'a, U: Number> GraphScorer<'a, U> for GraphNeighborhood {
    /// Returns the name of the `GraphNeighborhood` graph scorer.
    ///
    /// The name is "`graph_neighborhood`."
    fn name(&self) -> &str {
        "graph_neighborhood"
    }

    /// Returns the short name of the `GraphNeighborhood` graph scorer.
    ///
    /// The short name is "gn."
    fn short_name(&self) -> &str {
        "gn"
    }

    /// Indicates whether normalization should be performed based on clusters for `GraphNeighborhood`.
    ///
    /// TODO!
    fn normalize_on_clusters(&self) -> bool {
        todo!()
        //true
    }

    /// Computes and returns cluster scores based on the neighborhood of clusters in the graph.
    ///
    /// This function calculates the scores for clusters based on their neighborhood in the graph,
    /// considering the number of steps and the size of the clusters within the neighborhood.
    ///
    /// # Arguments
    ///
    /// * `_graph`: The input graph for which cluster scores are to be computed.
    ///
    /// # Returns
    ///
    /// A map of cluster indices to their respective scores as floating-point values.
    fn score_graph(&self, _graph: &'a Graph<'a, U>) -> ClusterScores<'a, U> {
        todo!()

        // graph
        //     .ordered_clusters()
        //     .iter()
        //     .map(|&c| {
        //         let steps = self.num_steps(graph, c);
        //         // TODO: Do we need +1?
        //         let score = (0..steps + 1)
        //             .zip(graph.unchecked_frontier_sizes(c).iter())
        //             .fold(0, |score, (_, &size)| score + size);
        //         (c, -(score as f64))
        //     })
        //     .collect()
    }
}

/// A graph scorer that calculates stationary probabilities of clusters after a specified number of steps.
pub struct StationaryProbabilities {
    /// Number of steps for stationary probability calculation.
    #[allow(dead_code)]
    num_steps: usize,
}

impl Hash for StationaryProbabilities {
    /// Generates a hash for the `StationaryProbabilities` instance.
    ///
    /// This function hashes the string "`stationary_probabilities`" to uniquely identify this scorer.
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        "stationary_probabilities".hash(state);
    }
}

impl StationaryProbabilities {
    /// Creates a new instance of the `StationaryProbabilities` scorer.
    ///
    /// The `num_steps` parameter specifies the number of steps for which stationary probabilities will be computed.
    ///
    #[must_use]
    pub const fn new(num_steps: usize) -> Self {
        Self { num_steps }
    }
}

impl<'a, U: Number> GraphScorer<'a, U> for StationaryProbabilities {
    /// Returns the name of the `StationaryProbabilities` graph scorer.
    ///
    /// The name is "`stationary_probabilities`."
    fn name(&self) -> &str {
        "stationary_probabilities"
    }

    /// Returns the short name of the `StationaryProbabilities` graph scorer.
    ///
    /// The short name is "sp."
    fn short_name(&self) -> &str {
        "sp"
    }

    /// Indicates whether normalization should be performed based on clusters for `StationaryProbabilities`.
    ///
    /// TODO!
    fn normalize_on_clusters(&self) -> bool {
        todo!()
        //true
    }

    #[allow(unused_variables)]

    /// Computes and returns cluster scores based on stationary probabilities after a specified number of steps.
    ///
    /// This function calculates the scores for clusters based on their stationary probabilities in the graph
    /// after a fixed number of steps. The `num_steps` parameter specified during initialization determines
    /// the number of steps.
    ///
    /// # Arguments
    ///
    /// * `graph`: The input graph for which cluster scores are to be computed.
    ///
    /// # Returns
    ///
    /// A map of cluster indices to their respective scores as floating-point values.
    fn score_graph(&self, graph: &'a Graph<U>) -> ClusterScores<'a, U> {
        todo!()
    }
}