permu_rs/rim.rs
1use std::convert::{TryFrom, TryInto};
2use std::fmt::{Debug, Display};
3use std::fmt;
4
5use rand::Rng;
6
7use crate::errors::Error;
8use crate::permutation::{Permutation, PermuPopulation};
9use crate::{Distribution, Population};
10
11/// Contains a repeated insertion model (RIM) vector and methods to generate and trasnform them.
12#[derive(Debug)]
13#[derive(Clone)]
14#[derive(PartialEq)]
15pub struct Rim<T> {
16 pub inner : Vec<T>,
17}
18
19impl<T> Rim<T> where
20 T : Copy +
21 From<u8> +
22 TryFrom<usize> +
23 TryInto<usize> +
24 Eq +
25 rand::distributions::range::SampleRange +
26 std::cmp::PartialOrd +
27 std::ops::Sub +
28 Display +
29 Debug
30{
31 /// Creates a Inversion object from the vector.
32 ///
33 /// # Example
34 /// ```
35 /// use permu_rs::rim::Rim;
36 /// let rim_vec = vec![0,0,1,1];
37 /// let rim = Rim::<u8>::from_vec(rim_vec);
38 /// ```
39 pub fn from_vec(inner : Vec<T>) -> Rim<T> {
40 Rim { inner }
41 }
42
43 /// Creates a `Rim`vector of the length given.
44 pub fn zeros(length: usize) -> Rim<T> {
45 Rim { inner: vec![T::from(0u8); length] }
46 }
47
48 /// Returns the length of the inner `Rim` vector.
49 pub fn len(&self) -> usize {
50 self.inner.len()
51 }
52
53 /// Transforms a given insertion vector (RIM) into it's permutation representation.
54 ///
55 /// # Errors
56 /// Returns a `LengthError` if the length of the output permutation is not the length of the
57 /// given rim vector + 1.
58 ///
59 /// # Example
60 /// ```
61 /// use permu_rs::{ permutation::Permutation, rim::Rim };
62 /// let rim = Rim::<u8>::from_vec(vec![0,2,2]);
63 /// let mut output = Permutation::<u8>::identity(4);
64 ///
65 /// Rim::<u8>::to_permu(&rim, &mut output).unwrap();
66 ///
67 /// println!("insertion vector: {:?}", rim.inner);
68 /// println!("permutation: {:?}", output.permu);
69 ///
70 /// let target = Permutation::from_vec(vec![1,0,3,2]).unwrap();
71 /// assert_eq!(target, output);
72 /// ```
73 pub fn to_permu(iv: &Rim<T>, out: &mut Permutation<T>) -> Result<(), Error> {
74 let permu_length = out.len();
75 // Check lengths are compatible
76 if permu_length != iv.len() + 1 {
77 return Err(Error::LengthError);
78 }
79
80 // Clear all the values from the output permutation
81 out.permu.clear();
82 let inner = &mut out.permu;
83
84 // Start by pushing 0 to the output permutation
85 inner.push(T::from(0u8));
86
87 (1..permu_length)
88 .for_each(|e| {
89 // Get the index to insert the element
90 let index = match iv.inner[e-1].try_into() {
91 Ok(v) => {
92 if v > inner.len() {
93 inner.len()
94 } else {
95 v
96 }
97 },
98 Err(_) => panic!("Fatal conversion error"),
99 };
100 // Obtain the element to insert (from identity)
101 let element = match T::try_from(e) {
102 Ok(v) => v,
103 Err(_) => panic!("Fatal conversion error"),
104 };
105
106 inner.insert(index, element);
107 });
108 Ok(())
109 }
110
111 /// Transforms a given permutation vector into it's insertion vector (Rim) representation.
112 ///
113 /// # Errors
114 /// Returns a `LengthError` if the length of the given permutation is not the length of the
115 /// output rim vector + 1.
116 ///
117 /// # Example
118 /// ```
119 /// use permu_rs::{ permutation::Permutation, rim::Rim };
120 /// let permu = Permutation::<u8>::from_vec(vec![1,0,3,2]).unwrap();
121 /// let mut rim = Rim::<u8>::zeros(3);
122 ///
123 /// Rim::<u8>::from_permu(&permu, &mut rim).unwrap();
124 ///
125 /// println!("permutation: {:?}", permu.permu);
126 /// println!("insertion vector: {:?}", rim.inner);
127 ///
128 /// let target = Rim::<u8>::from_vec(vec![0,2,2]);
129 /// assert_eq!(target, rim);
130 /// ```
131 pub fn from_permu(permu: &Permutation<T>, out: &mut Rim<T>) -> Result<(), Error> {
132 let length = permu.len();
133 // Check lengths
134 if length != out.len() + 1 {
135 return Err(Error::LengthError);
136 }
137
138 let mut permu = permu.permu.clone(); // NOTE: Not efficient
139 // let mut inner: Vec<T> = vec![T::from(0u8); length];
140 out.inner = out.inner.iter_mut()
141 .map(|_| T::from(0u8))
142 .collect();
143
144 (1..length).rev()
145 .for_each(|element| {
146
147 let elem_t = match T::try_from(element) {
148 Ok(v) => v,
149 Err(_) => unimplemented!(),
150 };
151
152 let index = permu.iter().position(|&e| e == elem_t);
153
154 let (index_t, index) = match index {
155 Some(i) => match T::try_from(i) {
156 Ok(v) => (v, i),
157 Err(_) => unreachable!(),
158 },
159 None => unreachable!(),
160 };
161
162 //println!("Position of {} is {}", element, index_t);
163 out.inner[element-1] = index_t;
164
165 permu.remove(index);
166
167 });
168
169 Ok(())
170 }
171}
172
173/// Population of `Rim` vectors.
174#[derive(PartialEq)]
175#[derive(Debug)]
176#[derive(Clone)]
177pub struct RimPopulation<T> {
178 pub population : Vec<Rim<T>>,
179 pub size : usize,
180}
181
182impl<T> RimPopulation<T> where
183 T : Copy +
184 From<u8> +
185 TryFrom<usize> +
186 TryInto<usize> +
187 Eq +
188 rand::distributions::range::SampleRange +
189 std::cmp::PartialOrd +
190 std::ops::Sub +
191 Display +
192 Debug,
193{
194 /// Creates an `InversionPopulation` based on a given matrix.
195 ///
196 /// # Errors
197 /// Returns a `LengthError` if the length of all vectors is not equal.
198 ///
199 /// # Example
200 /// ```
201 /// use permu_rs::rim::RimPopulation;
202 /// let pop_matrix: Vec<Vec<u16>> = vec![vec![0,2,0,0], vec![1,2,0,0], vec![0,0,0,0]];
203 /// let pop = RimPopulation::from_vec(&pop_matrix).unwrap();
204 ///
205 /// println!("{}", pop);
206 ///
207 /// // Now, the second vector contais one item less
208 /// let pop_matrix: Vec<Vec<u16>> = vec![vec![0,2,0,0], vec![1,0,0], vec![0,0,0,0]];
209 /// let pop = RimPopulation::from_vec(&pop_matrix); // This should return a LengthError
210 /// assert!(pop.is_err());
211 /// ```
212 pub fn from_vec(vec: &Vec<Vec<T>>) -> Result<RimPopulation<T>, Error> {
213 let mut pop : Vec<Rim<T>> = Vec::with_capacity(vec.len());
214 let len = vec[0].len();
215
216 for v in vec {
217 if v.len() == len {
218 pop.push(Rim::from_vec(v.clone()));
219 } else {
220 return Err(Error::LengthError);
221 }
222 }
223 Ok(RimPopulation {population: pop, size: vec.len()})
224 }
225
226 /// Creates a `RimPopulation` of zero valued `Rim` vectors of the size and length given.
227 ///
228 /// # Example
229 /// ```
230 /// use permu_rs::rim::RimPopulation;
231 ///
232 /// let (size, length) = (7, 5);
233 /// let pop = RimPopulation::<u8>::zeros(size, length);
234 /// println!("{}", pop);
235 /// ```
236 pub fn zeros(size: usize, length: usize) -> RimPopulation<T> {
237 let mut population: Vec<Rim<T>> = Vec::with_capacity(size);
238 let zeros = vec![T::from(0u8);length];
239
240 (0..size).for_each(|_| population.push(Rim::from_vec(zeros.clone())));
241
242 RimPopulation { population, size }
243 }
244
245 /// Takes a `PermuPopulation` as an output and fills this population with the `Permutation`
246 /// representation of each `Rim`vector in the `RimPopulation`. `RimPopulation` to its
247 /// `Permutation` representation. Positions of vectors are respected.
248 ///
249 /// # Errors
250 /// Returns a `LengthError` if the size of both population isn't equal or the length
251 /// of the `Permutation`s isn't the length of the `Rim` vectors + 1.
252 ///
253 /// # Example
254 /// ```
255 /// use permu_rs::{
256 /// permutation::{ Permutation, PermuPopulation },
257 /// rim::RimPopulation };
258 ///
259 /// let (size, length) = (10, 5);
260 /// let rim_zeros = RimPopulation::<u16>::zeros(size, length-1);
261 /// let mut permus = PermuPopulation::<u16>::random(size, length);
262 /// // The output should look like this
263 /// let target = PermuPopulation::<u16>::from_vec(vec![
264 /// Permutation::<u16>::from_vec(vec![4,3,2,1,0]).unwrap();size]);
265 ///
266 /// // Convert the rim population to its permutation representation
267 /// rim_zeros.to_permus(&mut permus).unwrap();
268 /// assert_eq!(target, permus);
269 /// ```
270 pub fn to_permus(&self, permu_pop: &mut PermuPopulation<T>) -> Result<(), Error> {
271
272 // Check if for every Rim vector there's a Permutation in permu_pop
273 if permu_pop.size != self.size {
274 return Err(Error::LengthError);
275 }
276
277 // Check Permutation and Rim vector lengths are compatible
278 if permu_pop.population[0].len() != self.population[0].len()+1 {
279 return Err(Error::LengthError);
280 }
281
282 // Convert each Rim vector of the population to permutation
283 (0..self.size).for_each(|i| {
284 match Rim::to_permu(&self.population[i], &mut permu_pop.population[i]) {
285 Ok(_) => (),
286 Err(e) => panic!("Fatal error converting InversionPopulation to PermuPopulation: {}", e),
287 }
288 });
289 Ok(())
290 }
291
292
293 /// Fills a `RimPopulation` with the rim vector representation of each
294 /// permutation vector inside a given `PermuPopulation`. Note that the sizes
295 /// of both populations must match and the length of permutations must be
296 /// equal to the length of the rim vectors + 1.
297 ///
298 /// # Errors
299 /// Returns a `LengthError` if the size of both population isn't equal or the length
300 /// of the `Permutation`s isn't the length of the `Rim` vectors + 1.
301 ///
302 /// # Example
303 /// ```
304 /// use permu_rs::{
305 /// permutation::PermuPopulation,
306 /// rim::RimPopulation,
307 /// };
308 /// // Create a target population of random permutations
309 /// let mut permus = PermuPopulation::<u8>::random(10, 5);
310 /// let target = permus.clone();
311 /// // Init rim population
312 /// let mut rims = RimPopulation::<u8>::zeros(10, 4);
313 ///
314 /// // Convert the permutations into rim vectors and then recover the
315 /// // original permutations from the rim vectors.
316 /// RimPopulation::from_permus(&permus, &mut rims).unwrap();
317 /// RimPopulation::to_permus(&rims, &mut permus).unwrap();
318 ///
319 /// assert_eq!(target, permus);
320 /// ```
321 pub fn from_permus(permu_pop: &PermuPopulation<T>,
322 rim_pop: &mut RimPopulation<T>) -> Result<(), Error>{
323 // Check sizes
324 if permu_pop.size != rim_pop.size {
325 return Err(Error::LengthError);
326 }
327 // Check lengths, permu.len() must be rim.len()+1
328 if permu_pop.population[0].len() != rim_pop.population[0].len()+1 {
329 return Err(Error::LengthError);
330 }
331
332 permu_pop.population.iter()
333 .enumerate()
334 .for_each(|(i, permu)| Rim::from_permu(permu, &mut rim_pop.population[i]).unwrap());
335
336 Ok(())
337 }
338}
339
340impl<T> Population<T> for RimPopulation<T> where
341 T : Copy +
342 From<u8> +
343 TryFrom<usize> +
344 TryInto<usize> +
345 // PartialEq<T> +
346 Eq +
347 rand::distributions::range::SampleRange +
348 std::cmp::PartialOrd +
349 std::ops::Sub +
350 Display +
351 Debug,
352{
353
354 /// Implementation of `learn` method for `RimPopulation`.
355 ///
356 /// # Example
357 /// ```
358 /// use permu_rs::{Distribution, Population, rim::RimPopulation};
359 ///
360 /// // Init a population of custom rim vectors
361 /// let pop: Vec<Vec<u8>> = vec![vec![2,1,0], vec![1,0,0], vec![0,0,0]];
362 /// let pop = RimPopulation::from_vec(&pop).unwrap();
363 ///
364 /// // Cratethe target distribution for the created rim population
365 /// let target = vec![vec![1,1,1,0],vec![2,1,0,0],vec![3,0,0,0]];
366 /// let target = Distribution::RimDistribution(target, false);
367 ///
368 /// let distr = pop.learn();
369 /// assert_eq!(target, distr);
370 /// ```
371 fn learn(&self) -> Distribution {
372 let m = self.population[0].len(); // Number of positions
373 let n = m+1; // Number of possible values
374
375 let mut distr: Vec<Vec<usize>> = vec![vec![0; n]; m]; // Init distribution matrix
376
377 for i in 0..self.population.len() { // For each vector in population
378 for j in 0..m { // For position item in the vector
379 let value: usize = match self.population[i].inner[j].try_into() {
380 Ok(val) => val,
381 Err(_) => panic!("Fatal error converting generic type usize"),
382 };
383 distr[j][value] += 1;
384 }
385 }
386 Distribution::RimDistribution(distr, false)
387 }
388
389 /// Implementation of `sample` method for `RimPopulation`.
390 ///
391 /// # Example
392 /// ```
393 /// use permu_rs::{Distribution, Population, rim::RimPopulation};
394 ///
395 /// // Init a population of custom rim vectors
396 /// let pop: Vec<Vec<u8>> = vec![vec![2,1,0], vec![1,0,0], vec![0,0,0]];
397 /// let pop = RimPopulation::from_vec(&pop).unwrap();
398 ///
399 /// // Init a population to store the samples
400 /// let mut samples = RimPopulation::<u8>::zeros(7, 3);
401 ///
402 /// let mut distr = pop.learn();
403 /// println!("Distribution:\n{}", distr);
404 ///
405 /// samples.sample(&mut distr).unwrap();
406 /// println!("Distribution after sampling:\n{}", distr);
407 ///
408 /// println!("Original population:\n{}", pop);
409 /// println!("Sampled population:\n{}", samples);
410 /// ```
411 fn sample(&mut self, distr: &mut Distribution) -> Result<(), Error> {
412 // Check if the given Distribution type is correct
413 let (distr, soften) = match distr {
414 Distribution::RimDistribution(d, s) => (d, s),
415 _ => return Err(Error::IncorrectDistrType),
416 };
417
418 // Check distribution and population's vector's sizes are correct
419 // length = the number of positions in the rim vectors
420 let length = match distr.len() == self.population[0].len() {
421 true => distr.len(),
422 false => return Err(Error::LengthError),
423 };
424
425 // Check if the distribution is soften
426 if !*soften {
427 // If not, soften the distribution by adding one to every element of the matrix.
428 (0..length).for_each(|i| {
429 (0..length+1).for_each(|j| distr[i][j] += 1);
430 });
431 // Mark the distribution as soften
432 *soften = true;
433 }
434
435 // This is where the actual sampling happens
436 (0..self.size).for_each(|out_i| { // For each individual in the population (out_i=index)
437
438 // Iterate the distribution randomly
439 Permutation::<usize>::random(length).permu.iter()
440 .for_each(|pos_i| { // For each row in the distribution (random)
441 let max_sum : usize = distr[*pos_i].iter().sum();
442 let rand: f64 = rand::thread_rng().gen_range(0.0, max_sum as f64);
443
444 let mut sum = distr[*pos_i][0]; // Sum is initialized with the first value of distr[pos_i]
445 let mut i = 0;
446 while (sum as f64) < rand {
447 i += 1;
448 sum += distr[*pos_i][i];
449 }
450
451 // Add sampled value to the individual that is being sampled
452 self.population[out_i].inner[*pos_i] = match T::try_from(i) {
453 Ok(v) => v,
454 Err(_) => unreachable!(),
455 };
456 });
457 });
458 Ok(())
459 }
460
461 fn to_permus(&self, permus: &mut PermuPopulation<T>) -> Result<(), Error> {
462 RimPopulation::to_permus(&self, permus)?;
463 Ok(())
464 }
465
466 fn from_permus(&mut self, permus: &PermuPopulation<T>) -> Result<(), Error> {
467 RimPopulation::from_permus(permus, self)?;
468 Ok(())
469 }
470}
471
472impl<T> fmt::Display for RimPopulation<T> where
473 T : Debug
474{
475 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
476
477 // For empty distibutions
478 if self.size == 0 {
479 return write!(f, "[]\nRimPopulation. Shape: 0,0\n");
480 }
481
482 let mut formatted = String::from("[");
483 self.population.iter()
484 .take(self.size -1) // Do not take the last item
485 .for_each(|rim| {
486 formatted.push_str(format!("{:?},\n", rim.inner).as_str());
487 });
488
489 // Now, take the last item
490 formatted.push_str(format!("{:?}]",
491 self.population[self.size-1].inner).as_str());
492
493 write!(f, "{}\nInversionPopulation. Shape: {},{}\n",
494 formatted, self.size, self.population[0].inner.len())
495 }
496}