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}