problem_generator/problem/
configuration.rs

1/*!
2Module for reading the configuration ranges (and iterating over it)
3*/
4
5use structopt::StructOpt;
6use rand_chacha::ChaChaRng;
7use rand::SeedableRng;
8
9use std::{error::Error, path::Path};
10
11use super::{clique_tree::InputParameters, codomain_subclasses::CodomainFunction};
12
13///Struct to contain the configuration parameters, to conveniently iterate over
14#[derive(Debug, Clone)]
15pub struct ConfigurationParameters {
16    pub m_begin: u32,
17    pub m_end: u32,
18    pub k_begin: u32,
19    pub k_end: u32,
20    pub o_begin: u32,
21    pub o_end: u32,
22    pub b_begin: u32,
23    pub b_end: u32,
24    pub codomain_function: CodomainFunction,
25}
26
27impl ConfigurationParameters {
28    pub fn new(
29        m_begin: u32,
30        m_end: u32,
31        k_begin: u32,
32        k_end: u32,
33        o_begin: u32,
34        o_end: u32,
35        b_begin: u32,
36        b_end: u32,
37        codomain_function: CodomainFunction,
38    ) -> ConfigurationParameters {
39        ConfigurationParameters {
40            m_begin,
41            m_end,
42            k_begin,
43            k_end,
44            o_begin,
45            o_end,
46            b_begin,
47            b_end,
48            codomain_function,
49        }
50    }
51
52    ///Read configuration parameters from a file
53    pub fn from_file(input_file_path: &Path) -> Result<ConfigurationParameters, Box<dyn Error>> {
54        let contents = std::fs::read_to_string(&input_file_path)?;
55        let mut content_iterator = contents.lines();
56
57        let mut split_line = content_iterator.next().unwrap().split(' ');
58        let m_or_n = split_line.next().unwrap();
59        // .skip(1);
60        let m_or_n_begin: u32 = split_line.next().unwrap().parse()?;
61        let m_or_n_end: u32 = split_line.next().unwrap().parse()?;
62
63        let mut split_line = content_iterator.next().unwrap().split(' ').skip(1);
64        let k_begin: u32 = split_line.next().unwrap().parse()?;
65        let k_end: u32 = split_line.next().unwrap().parse()?;
66
67        let mut split_line = content_iterator.next().unwrap().split(' ').skip(1);
68        let o_begin: u32 = split_line.next().unwrap().parse()?;
69        let o_end: i32 = split_line.next().unwrap().trim().parse()?;
70        let o_end: u32 = o_end as u32;
71
72        let mut split_line = content_iterator.next().unwrap().split(' ').skip(1);
73        let b_begin: u32 = split_line.next().unwrap().parse()?;
74        let b_end: u32 = split_line.next().unwrap().parse()?;
75
76        let (m_begin, m_end) = if m_or_n == "M" {
77            (m_or_n_begin, m_or_n_end)
78        } else if m_or_n == "N" {
79            if k_end - k_begin > 1 || o_end - o_begin > 1 {
80                return Err("Can not use problem size in configuration when k and o are not one fixed value".into());
81            }
82            (
83                get_m_for_min_problem_size(m_or_n_begin, k_begin, o_begin),
84                get_m_for_max_problem_size(m_or_n_end, k_begin, o_begin),
85            )
86        } else {
87            return Err("First letter in configuration not recognized; not M or N".into());
88        };
89
90        let codomain_functions_split_line: Vec<&str> =
91            content_iterator.next().unwrap().split(',').collect();
92
93        assert_eq!(codomain_functions_split_line.len(), 1);
94
95        let codomain_function_string = String::from(codomain_functions_split_line[0]);
96        let mut iter_list = vec![" "];
97        iter_list.extend(codomain_function_string.split(' '));
98        let codomain_function = CodomainFunction::from_iter(iter_list);
99
100        Ok(ConfigurationParameters::new(
101            m_begin,
102            m_end,
103            k_begin,
104            k_end,
105            o_begin,
106            o_end,
107            b_begin,
108            b_end,
109            codomain_function,
110        ))
111    }
112}
113
114///Get iterator from configuration parameters struct, for convenient iteration
115impl IntoIterator for ConfigurationParameters {
116    type Item = InputParameters;
117    type IntoIter = ConfigurationParametersIterator;
118
119    fn into_iter(self) -> Self::IntoIter {
120        ConfigurationParametersIterator::from_configuration_parameters(&self)
121    }
122}
123
124///Iterator to iterate over all possible experiment parameters
125pub struct ConfigurationParametersIterator {
126    pub m_begin: u32,
127    pub m_end: u32,
128    pub k_begin: u32,
129    pub k_end: u32,
130    pub o_begin: u32,
131    pub o_end: u32,
132    pub b_begin: u32,
133    pub b_end: u32,
134    pub codomain_function: CodomainFunction,
135
136    pub current_parameters: InputParameters,
137}
138
139impl ConfigurationParametersIterator {
140    pub fn new(
141        m_begin: u32,
142        m_end: u32,
143        k_begin: u32,
144        k_end: u32,
145        o_begin: u32,
146        o_end: u32,
147        b_begin: u32,
148        b_end: u32,
149        codomain_function: CodomainFunction,
150    ) -> ConfigurationParametersIterator {
151        ConfigurationParametersIterator {
152            m_begin,
153            m_end,
154            k_begin,
155            k_end,
156            o_begin,
157            o_end,
158            b_begin,
159            b_end,
160            codomain_function,
161            current_parameters: InputParameters::new_from_primitives(0, 0, 0, 0),
162        }
163    }
164
165    pub fn from_configuration_parameters(
166        configuration_parameters: &ConfigurationParameters,
167    ) -> ConfigurationParametersIterator {
168        ConfigurationParametersIterator::new(
169            configuration_parameters.m_begin,
170            configuration_parameters.m_end,
171            configuration_parameters.k_begin,
172            configuration_parameters.k_end,
173            configuration_parameters.o_begin,
174            configuration_parameters.o_end,
175            configuration_parameters.b_begin,
176            configuration_parameters.b_end,
177            configuration_parameters.codomain_function.clone(),
178        )
179    }
180}
181
182///Implement the Iterator trait for ConfigurationParameters; iterate over all possible configuration parameters
183impl Iterator for ConfigurationParametersIterator {
184    type Item = InputParameters;
185
186    fn next(&mut self) -> Option<Self::Item> {
187        if self.current_parameters.m == 0 {
188            self.current_parameters = InputParameters::new_from_primitives(
189                self.m_begin,
190                self.k_begin,
191                self.o_begin,
192                self.b_begin,
193            );
194        } else if self.current_parameters.b < self.b_end - 1 {
195            self.current_parameters.b += 1;
196        } else if self.current_parameters.o < self.o_end - 1 {
197            self.current_parameters.o += 1;
198            self.current_parameters.b = self.b_begin;
199        } else if self.current_parameters.k < self.k_end - 1 {
200            self.current_parameters.k += 1;
201            self.current_parameters.o = self.o_begin;
202            self.current_parameters.b = self.b_begin;
203        } else if self.current_parameters.m < self.m_end - 1 {
204            self.current_parameters.m += 1;
205            self.current_parameters.k = self.k_begin;
206            self.current_parameters.o = self.o_begin;
207            self.current_parameters.b = self.b_begin;
208        } else {
209            return None;
210        }
211        Some(self.current_parameters.clone())
212    }
213}
214
215//min problem size (incl. )
216fn get_m_for_min_problem_size(min_problem_size: u32, k: u32, o: u32) -> u32 {
217    let a = (min_problem_size as i32 + (k - o) as i32 - k as i32) as f32 / (k - o) as f32;
218    (a.ceil() as i32).max(1) as u32
219}
220
221//max problem size (excl. )
222fn get_m_for_max_problem_size(max_problem_size: u32, k: u32, o: u32) -> u32 {
223    let a = (max_problem_size + (k - o) - k) as f32 / (k - o) as f32;
224    (a.ceil() as u32).max(2)
225}
226
227pub fn get_rng(seed: Option<u64>) -> ChaChaRng {
228    match seed {
229        Some(seed) => ChaChaRng::seed_from_u64(seed),
230        None => ChaChaRng::from_entropy(),
231    }
232}