permu_rs/
inversion.rs

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