1
use std::fmt;
2

            
3
use itertools::Itertools;
4
use log::trace;
5

            
6
use crate::BlockIndex;
7
use crate::IndexedPartition;
8

            
9
/// A partition that explicitly stores a list of blocks and their indexing into
10
/// the list of elements.
11
#[derive(Debug)]
12
pub struct BlockPartition<A: Clone + fmt::Debug = ()> {
13
    elements: Vec<usize>,
14
    blocks: Vec<Block<A>>,
15
}
16

            
17
impl<A: Clone + fmt::Debug + Default> BlockPartition<A> {
18
    /// Create an initial partition where all the states are in a single block
19
    /// 0. And all the elements in the block are marked.
20
1502
    pub fn new(num_of_elements: usize) -> Self {
21
1502
        debug_assert!(num_of_elements > 0, "Cannot partition the empty set");
22

            
23
1502
        let blocks = vec![Block::new(0, num_of_elements)];
24
1502
        let elements = (0..num_of_elements).collect();
25

            
26
1502
        Self { elements, blocks }
27
1502
    }
28
}
29

            
30
impl<A: Clone + fmt::Debug + Default> BlockPartition<A> {
31
    /// Create a block partition from an indexed partition.
32
    ///
33
    /// This function creates a new partition that is dense, i.e. it does not
34
    /// contain empty blocks, and the blocks are indexed from 0 to n-1 even if the
35
    /// indexed partition is sparse.
36
1303
    pub fn from_indexed_partition(partition: &IndexedPartition) -> Self {
37
1303
        let mut blocks = vec![Block::new_empty(); partition.num_of_blocks()];
38
1303
        let num_of_elements = partition.iter_elements().count();
39

            
40
        // Figure out the number of elements per block.
41
86514
        for (_, block_index) in partition.iter_elements() {
42
86514
            blocks[block_index].end += 1;
43
86514
        }
44

            
45
        // Compute the start index for each block.
46
1303
        let mut start = 0;
47
84249
        for block in &mut blocks {
48
84247
            let end = block.end;
49
84247
            block.begin = start;
50
84247
            block.end = start; // This will be updated when adding elements.
51
84247
            start += end;
52
84247
        }
53

            
54
        // Create the elements vector.
55
1303
        let mut elements = vec![0; num_of_elements];
56
86514
        for (element_index, block_index) in partition.iter_elements() {
57
86514
            // Add the element to the block, and update the end index.
58
86514
            let block = &mut blocks[block_index];
59
86514
            let pos = block.end;
60
86514
            elements[pos] = element_index;
61
86514
            block.end = pos + 1;
62
86514
        }
63

            
64
        // Remove empty blocks.
65
84249
        blocks.retain(|block| !block.is_empty());
66

            
67
1303
        Self { elements, blocks }
68
1303
    }
69

            
70
    /// Return a reference to the given block.
71
580790
    pub fn block(&self, block_index: BlockIndex) -> &Block<A> {
72
580790
        &self.blocks[block_index]
73
580790
    }
74

            
75
    /// Return a mutable reference to the block's annotation.
76
355362
    pub fn block_annotation(&mut self, block_index: BlockIndex) -> &mut A {
77
355362
        self.blocks[block_index].annotation_mut()
78
355362
    }
79

            
80
    /// Splits a block into two blocks according to the given predicate. If the
81
    /// predicate holds for all or none of the elements, no split occurs.
82
39399053
    pub fn split_block<F>(&mut self, block_index: BlockIndex, predicate: F) -> Option<BlockIndex>
83
39399053
    where
84
39399053
        F: Fn(usize) -> bool,
85
    {
86
        // Swaps elements in the block so that the elements for which the
87
        // predicate holds are at the beginning of the block.
88
39399053
        let mut size = 0usize;
89

            
90
156089348
        for state in self.blocks[block_index].begin..self.blocks[block_index].end {
91
156089348
            if predicate(self.elements[state]) {
92
1415951
                self.elements.swap(self.blocks[block_index].begin + size, state);
93
1415951
                size += 1;
94
154673397
            }
95
        }
96

            
97
        // The original block are now the first [begin, begin + size) elements
98
39399053
        if size == 0 || size == self.blocks[block_index].len() {
99
            // No split occurred
100
39288842
            return None;
101
110211
        }
102

            
103
        // Create a new block for the remaining elements
104
110211
        let new_block = Block::new(self.blocks[block_index].begin + size, self.blocks[block_index].end);
105
110211
        let last_block = self.blocks.len();
106
110211
        self.blocks.push(new_block);
107

            
108
        // Update the original block
109
110211
        let new_end = self.blocks[block_index].begin + size;
110
110211
        self.blocks[block_index].end = new_end;
111

            
112
110211
        trace!(
113
            "Split block {:?} into blocks {:?} and {:?}",
114
            block_index,
115
            block_index,
116
            BlockIndex::new(last_block)
117
        );
118
110211
        Some(BlockIndex::new(last_block))
119
39399053
    }
120

            
121
    /// Returns the number of blocks in the partition.
122
1566473
    pub fn num_of_blocks(&self) -> usize {
123
1566473
        self.blocks.len()
124
1566473
    }
125

            
126
    /// Returns an iterator over the elements of a given block.
127
119283929
    pub fn iter_block(&self, block_index: BlockIndex) -> BlockIter<'_> {
128
119283929
        BlockIter {
129
119283929
            elements: &self.elements,
130
119283929
            index: self.blocks[block_index].begin,
131
119283929
            end: self.blocks[block_index].end,
132
119283929
        }
133
119283929
    }
134

            
135
    /// Returns an iterator over all blocks in the partition.
136
    pub fn iter(&self) -> impl Iterator<Item = &Block<A>> {
137
        self.blocks.iter()
138
    }
139

            
140
    /// Returns an iterator over all blocks in the partition.
141
    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Block<A>> {
142
        self.blocks.iter_mut()
143
    }
144

            
145
    /// Returns the number of elements in the partition.
146
103
    pub fn len(&self) -> usize {
147
103
        self.elements.len()
148
103
    }
149

            
150
    /// Returns true iff the partition is empty.
151
    pub fn is_empty(&self) -> bool {
152
        self.elements.is_empty()
153
    }
154
}
155

            
156
impl<B: Clone + fmt::Debug> fmt::Display for BlockPartition<B> {
157
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158
        let format = self
159
            .blocks
160
            .iter()
161
            .map(|block| format!("{{{}}}", block.iter(&self.elements).format(", ")))
162
            .format(", ");
163

            
164
        write!(f, "{{{}}}", format)
165
    }
166
}
167
/// A block that stores a subset of the elements in a partition.
168
///
169
/// # Details
170
///
171
/// It uses `start` and `end` to indicate a range start..end of elements in the
172
/// partition.
173
#[derive(Clone, Copy, Debug)]
174
pub struct Block<A: Clone + fmt::Debug> {
175
    begin: usize,
176
    end: usize,
177
    annotation: A,
178
}
179

            
180
impl<A: Clone + fmt::Debug + Default> Block<A> {
181
111713
    pub fn new(begin: usize, end: usize) -> Self {
182
111713
        debug_assert!(begin < end, "The range of this block is incorrect {begin}..{end}");
183
111713
        Block {
184
111713
            begin,
185
111713
            end,
186
111713
            annotation: Default::default(),
187
111713
        }
188
111713
    }
189

            
190
    /// Create an empty block at the given position.
191
1303
    fn new_empty() -> Self {
192
1303
        Block {
193
1303
            begin: 0,
194
1303
            end: 0,
195
1303
            annotation: Default::default(),
196
1303
        }
197
1303
    }
198
}
199

            
200
impl<A: Clone + fmt::Debug> Block<A> {
201
    /// Returns an iterator over the elements in this block.
202
    pub fn iter<'a>(&self, elements: &'a [usize]) -> impl Iterator<Item = usize> + 'a {
203
        BlockIter {
204
            elements,
205
            index: self.begin,
206
            end: self.end,
207
        }
208
    }
209

            
210
    /// Returns the underlying annotation of this block.
211
580783
    pub fn annotation(&self) -> &A {
212
580783
        &self.annotation
213
580783
    }
214

            
215
    /// Returns the underlying annotation of this block.
216
355362
    pub fn annotation_mut(&mut self) -> &mut A {
217
355362
        &mut self.annotation
218
355362
    }
219

            
220
    /// Returns the number of elements in the block.
221
400189
    pub fn len(&self) -> usize {
222
400189
        self.assert_consistent();
223
400189
        self.end - self.begin
224
400189
    }
225

            
226
    /// Returns true iff the block is empty.
227
84247
    pub fn is_empty(&self) -> bool {
228
84247
        self.begin == self.end
229
84247
    }
230

            
231
    /// Returns true iff the block is consistent.
232
400189
    fn assert_consistent(&self) {
233
400189
        debug_assert!(self.begin <= self.end, "The range of block {self:?} is incorrect");
234
400189
    }
235
}
236

            
237
pub struct BlockIter<'a> {
238
    elements: &'a [usize],
239
    index: usize,
240
    end: usize,
241
}
242

            
243
impl Iterator for BlockIter<'_> {
244
    type Item = usize;
245

            
246
14002110800
    fn next(&mut self) -> Option<Self::Item> {
247
14002110800
        if self.index < self.end {
248
11235921320
            let element = self.elements[self.index];
249
11235921320
            self.index += 1;
250
11235921320
            Some(element)
251
        } else {
252
2766189480
            None
253
        }
254
14002110800
    }
255

            
256
24
    fn size_hint(&self) -> (usize, Option<usize>) {
257
24
        let remaining = self.end - self.index;
258
24
        (remaining, Some(remaining))
259
24
    }
260
}
261

            
262
impl ExactSizeIterator for BlockIter<'_> {}
263

            
264
#[cfg(test)]
265
mod tests {
266
    use log::trace;
267
    use merc_utilities::random_test;
268
    use rand::RngExt;
269
    use rand::seq::IteratorRandom;
270

            
271
    use crate::BlockIndex;
272
    use crate::IndexedPartition;
273

            
274
    use super::BlockPartition;
275

            
276
    #[test]
277
1
    fn test_simple_block_partition() {
278
1
        let mut partition: BlockPartition<()> = BlockPartition::new(10);
279

            
280
1
        assert_eq!(partition.num_of_blocks(), 1);
281

            
282
1
        let initial_block = BlockIndex::new(0);
283
1
        assert_eq!(partition.block(initial_block).len(), 10);
284

            
285
10
        let block_index = partition.split_block(BlockIndex::new(0), |state| state < 5).unwrap();
286

            
287
1
        assert_eq!(partition.num_of_blocks(), 2);
288
1
        assert_eq!(partition.block(initial_block).len(), 5);
289
1
        assert_eq!(partition.block(block_index).len(), 5);
290
1
    }
291

            
292
    #[test]
293
1
    fn test_random_from_indexed_partition() {
294
100
        random_test(100, |rng| {
295
100
            let subset = (0..100).sample(rng, 25);
296
100
            let mut partition = IndexedPartition::with_subset(100, subset.iter().copied());
297

            
298
2500
            for element in subset {
299
2500
                partition.set_block(element, BlockIndex::new(rng.random_range(0..10)));
300
2500
            }
301
100
            trace!("Input partition {partition}");
302

            
303
100
            let block_partition: BlockPartition<()> = BlockPartition::from_indexed_partition(&partition);
304
100
            trace!("Output partition {block_partition}");
305

            
306
            // The block partition must contain exactly the same number of
307
            // elements as the indexed partition (regression: was sized by
308
            // num_of_blocks instead of num_of_elements).
309
100
            assert_eq!(
310
100
                block_partition.len(),
311
100
                partition.iter_elements().count(),
312
                "block_partition.len() does not match the number of elements in the indexed partition"
313
            );
314

            
315
            // Every element in the indexed partition must appear in the block
316
            // partition exactly once.
317
100
            let mut seen = [false; 100];
318
936
            for block in 0..block_partition.num_of_blocks() {
319
2500
                for element in block_partition.iter_block(BlockIndex::new(block)) {
320
2500
                    assert!(
321
2500
                        !seen[element],
322
                        "Element {element} appears more than once in block partition"
323
                    );
324
2500
                    seen[element] = true;
325
                }
326
            }
327
2500
            for (element, _) in partition.iter_elements() {
328
2500
                assert!(seen[element], "Element {element} is missing from block partition");
329
            }
330

            
331
            // Check that each block in the block partition contains only
332
            // elements from the same indexed-partition block.
333
936
            for block in 0..block_partition.num_of_blocks() {
334
936
                let mut elements = block_partition.iter_block(BlockIndex::new(block));
335
936
                let first = elements.next().unwrap();
336
936
                let expected_block = partition.block(first);
337

            
338
1564
                for element in elements {
339
1564
                    assert_eq!(
340
1564
                        partition.block(element),
341
                        expected_block,
342
                        "Block {block} contains elements from different indexed-partition blocks"
343
                    );
344
1564
                    assert_eq!(
345
1564
                        partition.block(element),
346
                        expected_block,
347
                        "Block {block} contains elements from different indexed-partition blocks"
348
                    );
349
                }
350
            }
351
100
        })
352
1
    }
353
}