jetty/cluster/
mod.rs

1//!
2//! In general, it is recommended to use the general-purpose
3//! [ClusterHistory]. It chooses dynamically between the following
4//! specialised algorithms:
5//!
6//! * [ClusterNaive](crate::cluster::naive::ClusterNaive): choose this
7//!   algorithm if you know that the number of partons is not too big,
8//!   at most about 25. Also use this algorithm for custom distances
9//!   where the actual nearest neighbours are not always the nearest
10//!   neighbours in ΔR.
11//!
12//! * [ClusterGeom](crate::cluster::geom::ClusterGeom): the fastest
13//!   implemented algorithm for a number of partons roughly between 25
14//!   and 50.
15//!
16//! * [ClusterGeomTile](crate::cluster::geom_tile::ClusterGeomTile):
17//!   the fastest implemented algorithm for a large number of partons
18//!   starting at about 50.
19//!
20/// Naive clustering
21pub mod naive;
22/// Clustering using the geometric O(N^2) approach of [arXiv:0512210](https://arxiv.org/abs/hep-ph/0512210)
23pub mod geom;
24/// Clustering using the geometric O(N^2) approach of [arXiv:0512210](https://arxiv.org/abs/hep-ph/0512210) with tiling
25pub mod geom_tile;
26
27use crate::distance::Distance;
28use crate::pseudojet::PseudoJet;
29
30use std::cmp::Ord;
31use std::hash::Hash;
32
33use log::debug;
34
35use self::{naive::ClusterNaive, geom::ClusterGeom, geom_tile::ClusterGeomTile};
36
37/// Cluster `partons` into jets using the distance measure `d`
38#[deprecated = "Use `Cluster::cluster` instead"]
39pub fn cluster<D: Distance>(partons: Vec<PseudoJet>, d: &D) -> Vec<PseudoJet> {
40    partons.cluster_if(d, |_| true)
41}
42
43/// Cluster `partons` into jets using the distance measure `d`
44/// Only jets for which `accept` is true are returned
45#[deprecated = "Use `Cluster::cluster_if` instead"]
46pub fn cluster_if<D, F>(
47    partons: Vec<PseudoJet>,
48    d: &D,
49    accept: F,
50) -> Vec<PseudoJet>
51where
52    D: Distance,
53    F: FnMut(PseudoJet) -> bool,
54{
55    partons.cluster_if(d, accept)
56}
57
58/// Objects that can be clustered into jets
59pub trait Cluster {
60    /// Cluster into jets using the distance measure `d`
61    fn cluster<D: Distance>(self, d: D) -> Vec<PseudoJet>;
62
63    /// Cluster into jets using the distance measure `d`
64    /// Only jets for which `accept` is true are returned
65    fn cluster_if<D, F>(self, d: D, accept: F) -> Vec<PseudoJet>
66    where
67        D: Distance,
68        F: FnMut(PseudoJet) -> bool;
69}
70
71impl Cluster for Vec<PseudoJet> {
72    fn cluster_if<D, F>(self, d: D, mut accept: F) -> Vec<PseudoJet>
73    where
74        D: Distance,
75        F: FnMut(PseudoJet) -> bool
76    {
77        debug!("clustering partons: {self:#?}");
78        let clustering = ClusterHistory::new(self, d);
79
80        clustering
81            .filter_map(|s| match s {
82                ClusterStep::Jet(jet) if accept(jet) => Some(jet),
83                _ => None,
84            })
85            .collect()
86    }
87
88    fn cluster<D: Distance>(self, d: D) -> Vec<PseudoJet> {
89        self.cluster_if(d, |_| true)
90    }
91}
92
93impl<'a, T> Cluster for &'a [T]
94where &'a T: Into<PseudoJet>
95{
96    fn cluster_if<D, F>(self, d: D, accept: F) -> Vec<PseudoJet>
97    where
98        D: Distance,
99        F: FnMut(PseudoJet) -> bool
100    {
101        let partons = Vec::from_iter(self.iter().map(|p| p.into()));
102        partons.cluster_if(d, accept)
103    }
104
105    fn cluster<D: Distance>(self, d: D) -> Vec<PseudoJet> {
106        self.cluster_if(d, |_| true)
107    }
108}
109
110/// Result of a clustering step
111#[derive(Clone, Debug, Ord, PartialOrd)]
112pub enum ClusterStep {
113    /// Two pseudojets were combined into a new pseudojet
114    Combine([PseudoJet; 2]),
115    /// A jet was found
116    Jet(PseudoJet),
117}
118
119impl From<[PseudoJet; 2]> for ClusterStep {
120    fn from(source: [PseudoJet; 2]) -> Self {
121        Self::Combine(source)
122    }
123}
124
125impl From<PseudoJet> for ClusterStep {
126    fn from(jet: PseudoJet) -> Self {
127        Self::Jet(jet)
128    }
129}
130
131impl PartialEq for ClusterStep {
132    fn eq(&self, other: &Self) -> bool {
133        match (self, other) {
134            (Self::Combine(left), Self::Combine(right)) => left == right || (
135                (left[0] == right[1]) && (left[1] == right[0])
136            ),
137            (Self::Jet(l0), Self::Jet(r0)) => l0 == r0,
138            _ => false,
139        }
140    }
141}
142
143impl Eq for ClusterStep { }
144
145impl Hash for ClusterStep {
146    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
147        match self {
148            ClusterStep::Combine([p1, p2]) => {
149                if p1 < p2 {
150                    [p1, p2].hash(state)
151                } else {
152                    [p2, p1].hash(state)
153                }
154            },
155            ClusterStep::Jet(p1) => p1.hash(state),
156        }
157    }
158}
159
160/// Trait marking a clustering algorithm
161pub trait ClusterHist: Iterator<Item = ClusterStep>{}
162
163impl<T> ClusterHist for T where T: Iterator<Item = ClusterStep> { }
164
165/// General-purpose cluster history
166pub struct ClusterHistory<'a> (
167    Box<dyn ClusterHist + 'a>
168);
169
170impl<'a> ClusterHistory<'a> {
171    const START_GEOM_THRESHOLD: usize = 25;
172    const END_GEOM_THRESHOLD: usize = 49;
173    const START_TILE_THRESHOLD: usize = Self::END_GEOM_THRESHOLD + 1;
174
175    /// Initialise clustering for the given `partons` and `distance`
176    pub fn new<D: Distance + 'a>(partons: Vec<PseudoJet>, distance: D) -> Self {
177        let hist: Box<dyn ClusterHist> = match partons.len() {
178            Self::START_TILE_THRESHOLD.. =>
179                Box::new(ClusterGeomTile::new(partons, distance)),
180            Self::START_GEOM_THRESHOLD..=Self::END_GEOM_THRESHOLD =>
181                Box::new(ClusterGeom::new(partons, distance)),
182            _ => Box::new(ClusterNaive::new(partons, distance))
183        };
184        Self(hist)
185    }
186}
187
188impl<'a> Iterator for ClusterHistory<'a> {
189    type Item = ClusterStep;
190
191    /// Perform the next clustering step
192    fn next(&mut self) -> Option<Self::Item> {
193        self.0.next()
194    }
195}