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}