sim_lib_serial_core/
permutation.rs1use crate::{BlockPartitionError, OrdinalMapError};
4
5#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
10pub struct OrdinalMap {
11 output_to_input: Vec<usize>,
12}
13
14impl OrdinalMap {
15 pub fn try_new(output_to_input: Vec<usize>) -> Result<Self, OrdinalMapError> {
17 let cardinality = output_to_input.len();
18 let mut first_outputs = vec![None; cardinality];
19 for (output, &input) in output_to_input.iter().enumerate() {
20 if input >= cardinality {
21 return Err(OrdinalMapError::OutOfRange {
22 output,
23 input,
24 cardinality,
25 });
26 }
27 if let Some(first_output) = first_outputs[input].replace(output) {
28 return Err(OrdinalMapError::DuplicateInput {
29 input,
30 first_output,
31 duplicate_output: output,
32 });
33 }
34 }
35 Ok(Self { output_to_input })
36 }
37
38 pub fn identity(cardinality: usize) -> Self {
40 Self {
41 output_to_input: (0..cardinality).collect(),
42 }
43 }
44
45 pub fn retrograde(cardinality: usize) -> Self {
47 Self {
48 output_to_input: (0..cardinality).rev().collect(),
49 }
50 }
51
52 pub fn rotation(cardinality: usize, steps: usize) -> Self {
54 if cardinality == 0 {
55 return Self::identity(0);
56 }
57 let shift = steps % cardinality;
58 Self {
59 output_to_input: (0..cardinality)
60 .map(|output| (output + shift) % cardinality)
61 .collect(),
62 }
63 }
64
65 pub fn cardinality(&self) -> usize {
67 self.output_to_input.len()
68 }
69
70 pub fn output_to_input(&self) -> &[usize] {
72 &self.output_to_input
73 }
74
75 pub fn is_identity(&self) -> bool {
77 self.output_to_input
78 .iter()
79 .enumerate()
80 .all(|(position, &input)| position == input)
81 }
82
83 pub fn apply<T: Clone>(&self, source: &[T]) -> Result<Vec<T>, OrdinalMapError> {
85 if source.len() != self.cardinality() {
86 return Err(OrdinalMapError::CardinalityMismatch {
87 expected: self.cardinality(),
88 found: source.len(),
89 });
90 }
91 self.output_to_input
92 .iter()
93 .enumerate()
94 .map(|(output, &input)| {
95 source
96 .get(input)
97 .cloned()
98 .ok_or(OrdinalMapError::OutOfRange {
99 output,
100 input,
101 cardinality: source.len(),
102 })
103 })
104 .collect()
105 }
106
107 pub fn inverse(&self) -> Result<Self, OrdinalMapError> {
109 let mut inverse = vec![0; self.cardinality()];
110 for (output, &input) in self.output_to_input.iter().enumerate() {
111 let Some(slot) = inverse.get_mut(input) else {
112 return Err(OrdinalMapError::OutOfRange {
113 output,
114 input,
115 cardinality: self.cardinality(),
116 });
117 };
118 *slot = output;
119 }
120 Self::try_new(inverse)
121 }
122
123 pub fn compose(&self, next: &Self) -> Result<Self, OrdinalMapError> {
125 if self.cardinality() != next.cardinality() {
126 return Err(OrdinalMapError::CompositionCardinalityMismatch {
127 first: self.cardinality(),
128 second: next.cardinality(),
129 });
130 }
131 let mut composed = Vec::with_capacity(self.cardinality());
132 for (output, &intermediate) in next.output_to_input.iter().enumerate() {
133 let Some(&input) = self.output_to_input.get(intermediate) else {
134 return Err(OrdinalMapError::OutOfRange {
135 output,
136 input: intermediate,
137 cardinality: self.cardinality(),
138 });
139 };
140 composed.push(input);
141 }
142 Self::try_new(composed)
143 }
144
145 pub fn canonical_form(&self) -> String {
147 let ordinals = self
148 .output_to_input
149 .iter()
150 .map(usize::to_string)
151 .collect::<Vec<_>>()
152 .join(",");
153 format!("ordinal-map/v1:[{ordinals}]")
154 }
155}
156
157pub type OrdinalPermutation = OrdinalMap;
159
160#[derive(Clone, Debug, PartialEq, Eq)]
166pub struct BlockPartition {
167 cardinality: usize,
168 blocks: Vec<Vec<usize>>,
169 order_map: OrdinalMap,
170}
171
172impl BlockPartition {
173 pub fn try_new(
175 cardinality: usize,
176 blocks: Vec<Vec<usize>>,
177 ) -> Result<Self, BlockPartitionError> {
178 let mut flattened = Vec::with_capacity(cardinality);
179 for (block, positions) in blocks.iter().enumerate() {
180 if positions.is_empty() {
181 return Err(BlockPartitionError::EmptyBlock { block });
182 }
183 flattened.extend(positions.iter().copied());
184 }
185 if flattened.len() != cardinality {
186 return Err(BlockPartitionError::CardinalityMismatch {
187 expected: cardinality,
188 found: flattened.len(),
189 });
190 }
191 let order_map = OrdinalMap::try_new(flattened)?;
192 Ok(Self {
193 cardinality,
194 blocks,
195 order_map,
196 })
197 }
198
199 pub fn contiguous(block_lengths: Vec<usize>) -> Result<Self, BlockPartitionError> {
201 let mut cardinality = 0usize;
202 let mut blocks = Vec::with_capacity(block_lengths.len());
203 for (block, length) in block_lengths.into_iter().enumerate() {
204 if length == 0 {
205 return Err(BlockPartitionError::EmptyBlock { block });
206 }
207 let end = cardinality
208 .checked_add(length)
209 .ok_or(BlockPartitionError::CardinalityOverflow)?;
210 blocks.push((cardinality..end).collect());
211 cardinality = end;
212 }
213 Self::try_new(cardinality, blocks)
214 }
215
216 pub fn cardinality(&self) -> usize {
218 self.cardinality
219 }
220
221 pub fn blocks(&self) -> &[Vec<usize>] {
223 &self.blocks
224 }
225
226 pub fn order_map(&self) -> &OrdinalMap {
228 &self.order_map
229 }
230}