1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
//! This module contains the Brick structure.
//! The Brick structure represents the set of all strings that can be built
//! through concatenation of a given sequence of strings with upper and lower boundaries.
//!
//! For instance, let \[{"mo", "de"}\]^{1,2} be a Brick. The following set of strings is
//! constructed through the aforementioned Brick:
//! - {mo, de, momo, dede, mode, demo}
use std::collections::BTreeSet;
use crate::prelude::*;
use itertools::Itertools;
/// A single Brick with the set of strings, a minimum and maximum bound.
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct Brick {
sequence: BTreeSet<String>,
min: u32,
max: u32,
}
impl Default for Brick {
fn default() -> Self {
Self::new()
}
}
impl Brick {
/// Creates a new instance of the Brick struct.
pub fn new() -> Self {
Brick {
sequence: BTreeSet::new(),
min: 0,
max: 0,
}
}
/// Set the sequence of the Brick.
pub fn set_sequence(&mut self, sequence: BTreeSet<String>) {
self.sequence = sequence;
}
/// Set the minimum bound for the element occurrences in the Brick.
pub fn set_min(&mut self, min: u32) {
self.min = min;
}
/// Set the maximum bound for the element occurrences in the Brick.
pub fn set_max(&mut self, max: u32) {
self.max = max;
}
/// Returns a reference to the string sequence in the brick.
pub fn get_sequence(&self) -> &BTreeSet<String> {
&self.sequence
}
/// Returns the minimum occurrence of the sequences contained in the brick.
pub fn get_min(&self) -> u32 {
self.min
}
/// Returns the maximum occurrence of the sequences contained in the brick.
pub fn get_max(&self) -> u32 {
self.max
}
/// Checks whether a brick represents an empty string (Rule 1)
pub fn is_empty_string(&self) -> bool {
if self.sequence.is_empty() && self.min == 0 && self.max == 0 {
return true;
}
false
}
/// **merge** bricks with the same indices max = 1, min = 1, in a new single brick
/// with the new string set being the concatenation of the former two. e.g. B0 = \[{a,cd}\]^{1,1}
/// and B1 = \[{b,ef}\]^{1,1} become B_new = \[{ab, aef, cdb, cdef}\]^{1,1}.
pub fn merge_bricks_with_bound_one(&self, other: Brick) -> Self {
let product = self
.sequence
.iter()
.cartesian_product(other.sequence.iter())
.collect_vec();
let sequence: BTreeSet<String> = product
.iter()
.map(|&(str1, str2)| str1.clone() + str2)
.collect();
Brick {
sequence,
min: 1,
max: 1,
}
}
/// **transform** a brick in which the number of applications is constant (min = max) into one in which
/// min = max = 1. e.g. B = \[{a,b}\]^{2,2} => B_new = \[{aa, ab, ba, bb}\]^{1,1}.
pub fn transform_brick_with_min_max_equal(&self, length: usize) -> Self {
let permutations: BTreeSet<String> =
Self::generate_permutations_of_fixed_length(length, &self.sequence, Vec::new(), 1)
.into_iter()
.collect();
Brick {
sequence: permutations,
min: 1,
max: 1,
}
}
/// **merge** two bricks in which the set of strings is the same. e.g. B1 = \[S\]^{m1, M1}
/// and B2 = \[S\]^{m2, M2} => B_new = \[S\]^{m1+m2, M1+M2}
pub fn merge_bricks_with_equal_content(&self, other: Brick) -> Self {
Brick {
sequence: self.sequence.clone(),
min: self.min + other.min,
max: self.max + other.max,
}
}
/// **break** a single brick with min >= 1 and max != min into two simpler bricks where B = \[S\]^{min,max} =>
/// B1 = \[S^min\]^{1,1}, B2 = \[S\]^{0, max-min}.
/// e.g. B = \[{a}\]^{2,5} => B1 = \[{aa}\]^{1,1}, B2 = \[{a}\]^{0,3}
pub fn break_single_brick_into_simpler_bricks(&self) -> (Self, Self) {
let brick_1 = self.transform_brick_with_min_max_equal(self.min as usize);
let brick_2 = Brick {
sequence: self.sequence.clone(),
min: 0,
max: self.max - self.min,
};
(brick_1, brick_2)
}
/// Recursive function to generate sequence permutations of fixed length.
/// For instance, \[{a,b}\] with length = 2 becomes \[{aa, ab, ba, bb}\]
/// Note that the length can also be greater or smaller than
/// the number of elements in the sequence.
pub fn generate_permutations_of_fixed_length(
max_length: usize,
sequence: &BTreeSet<String>,
generated: Vec<String>,
current_length: usize,
) -> Vec<String> {
let mut new_gen: Vec<String> = Vec::new();
for s in sequence.iter() {
if generated.is_empty() {
new_gen.push(s.to_string());
} else {
for g in generated.iter() {
new_gen.push(g.clone() + s);
}
}
}
if current_length < max_length {
return Self::generate_permutations_of_fixed_length(
max_length,
sequence,
new_gen,
current_length + 1,
);
}
new_gen
}
}