problem_generator/problem/
codomain.rs1use indicatif::ProgressIterator;
6use rand_chacha::ChaChaRng;
7use structopt::StructOpt;
8use itertools::Itertools;
9
10use super::io::get_output_folder_path_from_configuration_file;
11
12use super::clique_tree::InputParameters;
13use super::codomain_subclasses::*;
14use super::configuration::{ConfigurationParameters, get_rng};
15
16use std::fmt::Write as fmtWrite;
17use std::fs::File;
18use std::io::{BufWriter, Write};
19use std::path::Path;
20use std::path::PathBuf;
21use std::{
22 error::Error,
23 fs::{self, remove_dir_all},
24 str::Lines,
25};
26
27#[derive(StructOpt, Debug)]
28#[structopt(
29 name = "Codomain Generator",
30 about = "Generate the codomain of a TD Mk Landscape using a file or cli arguments"
31)]
32pub struct CodomainOpt {
33 #[structopt(subcommand)]
34 pub codomain_command: CodomainCommand,
35 #[structopt(short = "s", long = "seed")]
36 pub seed: Option<u64>,
37}
38
39#[derive(StructOpt, Debug)]
40pub enum CodomainCommand {
41 #[structopt(name = "folder")]
43 Folder {
44 #[structopt(parse(from_os_str))]
46 folder_paths: Vec<PathBuf>,
47 },
48 #[structopt(name = "file")]
50 File {
51 #[structopt(parse(from_os_str))]
53 file_path: PathBuf,
54 },
55 #[structopt(name = "instance")]
57 Instance {
58 m: u32,
60 k: u32,
62 o: u32,
64 b: u32,
66 #[structopt(name = "f", parse(from_os_str))]
68 output_file_path: PathBuf,
69 #[structopt(subcommand)]
71 codomain_function: CodomainFunction,
72 },
73}
74
75pub fn run_opt(codomain_opt: CodomainOpt) -> Result<(), Box<dyn Error>> {
77 let mut rng = get_rng(codomain_opt.seed);
78 match codomain_opt.codomain_command {
79 CodomainCommand::Folder { folder_paths} => {
80 for folder_path in folder_paths {
81 handle_folder(folder_path, &mut rng)?;
82 }
83 Ok(())
84 }
85 CodomainCommand::File { file_path } => {
86 handle_input_configuration_file(file_path, &mut rng)
87 },
88 CodomainCommand::Instance {
89 m,
90 k,
91 o,
92 b,
93 output_file_path,
94 codomain_function
95 } => {
96 let input_parameters = InputParameters::new_from_primitives(m, k, o, b);
97 generate_and_write(&input_parameters, &codomain_function, &output_file_path, &mut rng)?;
98 Ok(())
99 }
100 }
101}
102
103fn handle_folder(folder_path: PathBuf, rng: &mut ChaChaRng) -> Result<(), Box<dyn Error>> {
105 folder_path
107 .read_dir()?
108 .map(|file| file.unwrap())
109 .filter(|file| {
110 file.file_type().unwrap().is_dir() && file.file_name() != "codomain_generation"
111 })
112 .map(|file| remove_dir_all(file.path()))
113 .collect::<Result<Vec<()>, std::io::Error>>()?;
114
115 let mut codomain_generation_folder_path = folder_path;
117 codomain_generation_folder_path.push("codomain_generation");
118 let file_entries: Vec<PathBuf> = codomain_generation_folder_path
119 .read_dir()?
120 .map(|file| file.unwrap())
121 .filter(|file| !file.file_type().unwrap().is_dir())
122 .map(|file| file.path())
123 .sorted()
124 .collect();
125
126 file_entries.into_iter().progress().for_each(|path| {
128 handle_input_configuration_file(path, rng).unwrap();
129 });
130
131 Ok(())
132}
133
134fn handle_input_configuration_file(
137 input_configuration_file_path: PathBuf,
138 rng: &mut ChaChaRng
139) -> Result<(), Box<dyn Error>> {
140 let experiment_parameters = ConfigurationParameters::from_file(&input_configuration_file_path)?;
141 let codomain_function = experiment_parameters.codomain_function.clone();
142 let directory_path_buf = get_output_folder_path_from_configuration_file(
143 &input_configuration_file_path,
144 "codomain_files",
145 )?;
146
147 for input_parameters in experiment_parameters {
149 for num in 0..25 {
151 let mut output_file_path = directory_path_buf.clone();
152 let output_file_name = format!(
153 "{}_{}_{}_{}_{}_{}.txt",
154 codomain_function.to_io_string(),
155 input_parameters.m,
156 input_parameters.k,
157 input_parameters.o,
158 input_parameters.b,
159 num
160 );
161
162 output_file_path.push(output_file_name);
163 generate_and_write(&input_parameters, &codomain_function, &output_file_path, rng)?;
166 }
167 }
168
169 Ok(())
170}
171
172fn generate_and_write(
174 input_parameters: &InputParameters,
175 codomain_function: &CodomainFunction,
176 output_file_path: &Path,
177 rng: &mut ChaChaRng
178) -> Result<(), Box<dyn Error>> {
179 write_codomain(
180 input_parameters,
181 codomain_function,
182 output_file_path,
183 &generate_codomain(input_parameters, codomain_function, rng),
184 )?;
185 Ok(())
186}
187
188pub fn generate_write_return(
190 input_parameters: &InputParameters,
191 codomain_function: &CodomainFunction,
192 output_file_path: &Path,
193 rng: &mut ChaChaRng
194) -> Result<Vec<Vec<f64>>, Box<dyn Error>> {
195 let codomain = generate_codomain(input_parameters, codomain_function, rng);
196 write_codomain(
197 input_parameters,
198 codomain_function,
199 output_file_path,
200 &codomain,
201 )?;
202 Ok(codomain)
203}
204
205pub fn generate_codomain(
207 input_parameters: &InputParameters,
208 codomain_function: &CodomainFunction,
209 rng: &mut ChaChaRng
210) -> Vec<Vec<f64>> {
211 match codomain_function {
212 CodomainFunction::Random => generate_random(input_parameters, rng),
213 CodomainFunction::Trap => generate_trap(input_parameters, 2.5),
214 CodomainFunction::DeceptiveTrap => generate_trap_general(input_parameters, rng), CodomainFunction::NKq { q } => generate_nk_q(input_parameters, *q, rng),
216 CodomainFunction::NKp { p } => generate_nk_p(input_parameters, *p, rng),
217 CodomainFunction::RandomDeceptiveTrap { p_deceptive } => {
218 generate_random_trap(input_parameters, *p_deceptive, rng)
219 }
220 CodomainFunction::Unknown => panic!("We can't generate codomain for unknown codomain"),
221 }
222}
223
224fn write_codomain(
226 input_parameters: &InputParameters,
227 codomain_function: &CodomainFunction,
228 file_path: &Path,
229 codomain: &[Vec<f64>],
230) -> Result<(), Box<dyn Error>> {
231 let file = File::create(file_path)?;
232 let mut buf_writer = BufWriter::new(file);
233 let mut write_buffer = String::new();
234
235 writeln!(write_buffer, "{}", codomain_function)?;
237 buf_writer.write_all(write_buffer.as_bytes())?;
238 write_buffer.clear();
239
240 writeln!(
242 write_buffer,
243 "{} {} {} {}",
244 input_parameters.m, input_parameters.k, input_parameters.o, input_parameters.b
245 )?;
246 buf_writer.write_all(write_buffer.as_bytes())?;
247 write_buffer.clear();
248
249 for clique in codomain {
251 for value in clique {
252 writeln!(write_buffer, "{}", value)?;
253 buf_writer.write_all(write_buffer.as_bytes())?;
254 write_buffer.clear();
255 }
256 }
257
258 buf_writer.flush()?;
260
261 Ok(())
262}
263
264pub fn get_codomain_from_iterator(
267 content_iterator: &mut Lines,
268 skip_number_lines: u32,
269 input_parameters: &InputParameters,
270) -> Result<Vec<Vec<f64>>, Box<dyn Error>> {
271 let mut content_iterator = content_iterator.skip(skip_number_lines as usize);
272 let mut codomain = Vec::with_capacity(input_parameters.m as usize);
273 for _i in 0..(input_parameters.m as usize) {
274 let mut clique_codomain = Vec::with_capacity((1 << input_parameters.k) as usize);
275 for _j in 0..(1 << input_parameters.k) {
276 let fitness: f64 = content_iterator
277 .next()
278 .ok_or("Codomain file does not contain enough entries")?
279 .parse()?;
280 clique_codomain.push(fitness);
281 }
282 codomain.push(clique_codomain);
283 }
284
285 Ok(codomain)
286}
287
288pub fn read_codomain(
290 input_parameters: &InputParameters,
291 codomain_file: &Path,
292 skip_number_lines: u32,
293) -> Result<Vec<Vec<f64>>, Box<dyn Error>> {
294 let contents = fs::read_to_string(codomain_file)?;
295 let mut content_iterator = contents.lines();
297 get_codomain_from_iterator(&mut content_iterator, skip_number_lines, input_parameters)
298}