lumen_dataset/transform/
selection.rs1use std::sync::Arc;
2use rand::seq::SliceRandom;
3use crate::Dataset;
4
5pub struct SubsetDataset<D>
6where
7 D: Dataset,
8{
9 pub wrapped: Arc<D>,
10 pub indices: Vec<usize>,
11}
12
13impl<D: Dataset> SubsetDataset<D> {
14 pub fn new(dataset: impl Into<Arc<D>>, indices: Vec<usize>) -> Self {
21 Self { wrapped: dataset.into(), indices }
22 }
23
24 pub fn from_indices(dataset: impl Into<Arc<D>>, indices: Vec<usize>) -> SubsetDatasetResult<Self> {
34 let dataset = dataset.into();
35
36 let size = dataset.len();
38 if let Some(&idx) = indices.iter().find(|&i| *i >= size) {
39 Err(SubsetDatasetError::IndexOutOfRangeWhenSelectDataset(idx, size, "from indices"))?;
40 }
41
42 Ok(Self::new(dataset, indices))
43 }
44
45 pub fn select_all(dataset: impl Into<Arc<D>>) -> Self {
59 let dataset = dataset.into();
60 let size = dataset.len();
61 Self::new(dataset, iota(size))
62 }
63
64 pub fn slice(&self, start: usize, end: usize) -> SubsetDatasetResult<Self> {
75 if start >= self.len() {
76 Err(SubsetDatasetError::IndexOutOfRangeWhenSelectDataset(start, self.len(), "slice"))?;
77 }
78 if end >= self.len() {
79 Err(SubsetDatasetError::IndexOutOfRangeWhenSelectDataset(end, self.len(), "slice"))?;
80 }
81 Ok(Self::new(self.wrapped.clone(), self.indices[start..end].to_vec()))
82 }
83
84 pub fn split(&self, num: usize) -> SubsetDatasetResult<Vec<Self>> {
98 if num == 0 {
99 Err(SubsetDatasetError::NumSplitZeroWhenSelectDataset)?;
100 }
101
102 let n = self.indices.len();
103 let mut datasets = Vec::with_capacity(num);
104
105 let base_size = n / num;
106 let remainder = n % num;
107
108 let mut start = 0;
109 for i in 0..num {
110 let size = base_size + (if i < remainder { 1 } else { 0 });
111 let end = start + size;
112
113 datasets.push(self.slice(start, end)?);
114
115 start = end;
116 }
117
118 Ok(datasets)
119 }
120}
121
122impl<D: Dataset> Dataset for SubsetDataset<D> {
123 type Item = D::Item;
124 type Error = D::Error;
125
126 fn get(&self, index: usize) -> Result<Option<Self::Item>, Self::Error> {
127 let index = match self.indices.get(index) {
128 Some(index) => index.clone(),
129 None => return Ok(None),
130 };
131 self.wrapped.get(index)
132 }
133
134 fn len(&self) -> usize {
135 self.indices.len()
136 }
137}
138
139pub fn random_split<D: Dataset>(dataset: D, ratio: f64) -> (SubsetDataset<D>, SubsetDataset<D>) {
140 let length = dataset.len();
141 let mut indices = iota(length);
142
143 let mut rng = rand::rng();
144 indices.shuffle(&mut rng);
145
146 let split_idx = (length as f64 * ratio).floor() as usize;
147 let (indices1, indices2) = indices.split_at(split_idx);
148
149 let dataset = Arc::new(dataset);
150 let subset1 = SubsetDataset::new(dataset.clone(), indices1.to_vec());
151 let subset2 = SubsetDataset::new(dataset.clone(), indices2.to_vec());
152
153 (subset1, subset2)
154}
155
156#[inline(always)]
157fn iota(size: usize) -> Vec<usize> {
158 (0..size).collect()
159}
160
161#[derive(Debug, thiserror::Error)]
162pub enum SubsetDatasetError {
163 #[error("Index out of bounds for wrapped dataset size: {0} >= {1} when {2}")]
164 IndexOutOfRangeWhenSelectDataset(usize, usize, &'static str),
165
166 #[error("Use 0 to split dataset")]
167 NumSplitZeroWhenSelectDataset,
168}
169
170pub type SubsetDatasetResult<T> = std::result::Result<T, SubsetDatasetError>;