Skip to content

Commit

Permalink
refact(jssp): store all run output in single directory instead of sin…
Browse files Browse the repository at this point in the history
…gle file (#429)

## Description

Multiple output files are now produced. Description can be found in ECDK
docs.
  • Loading branch information
kkafar authored Oct 9, 2023
1 parent da6d8ed commit 069bed1
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 39 deletions.
4 changes: 2 additions & 2 deletions examples/jssp/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ pub struct Args {
pub input_file: PathBuf,

/// Output file name
#[arg(short = 'o', long = "output-file")]
pub output_file: PathBuf,
#[arg(short = 'o', long = "output-dir")]
pub output_dir: PathBuf,
}

fn validate_args(args: &Args) -> Result<(), String> {
Expand Down
54 changes: 29 additions & 25 deletions examples/jssp/logging.rs
Original file line number Diff line number Diff line change
@@ -1,48 +1,52 @@
use std::path::Path;
use std::{path::{Path, PathBuf}, collections::HashMap};

use log4rs::{
append::{console::ConsoleAppender, file::FileAppender},
config::{Appender, Logger},
encode::pattern::PatternEncoder,
};

pub fn init_logging(log_file: Option<&Path>) -> Result<log4rs::Handle, log::SetLoggerError> {
pub fn init_logging(log_files: &HashMap<String, PathBuf>) -> Result<log4rs::Handle, log::SetLoggerError> {
let log_pattern = String::from("[{l}] {m}{n}");
let csv_log_pattern = String::from("{m}{n}");

let stdout_appender = ConsoleAppender::builder()
.encoder(Box::new(PatternEncoder::new(&log_pattern)))
.build();

let config =
log4rs::Config::builder().appender(Appender::builder().build("main", Box::new(stdout_appender)));

let config = if let Some(log_file) = log_file {
let csv_appender = FileAppender::builder()
.encoder(Box::new(PatternEncoder::new(&csv_log_pattern)))
.append(false)
.build(log_file)
.unwrap();
config
.appender(Appender::builder().build("csv_appender", Box::new(csv_appender)))
.logger(
Logger::builder()
.appender("csv_appender")
.additive(false)
.build("csv", log::LevelFilter::Info),
)
} else {
config
};

let config = config
let mut cfg_builder = log4rs::Config::builder();

// Register console appender
cfg_builder = cfg_builder.appender(Appender::builder().build("main", Box::new(stdout_appender)));

// Register appenders & loggers for given events
if !log_files.is_empty() {
let csv_encoder = Box::new(PatternEncoder::new(&csv_log_pattern));
for (event_name, log_file) in log_files.iter() {
let csv_appender = FileAppender::builder()
.encoder(csv_encoder.clone())
.append(false)
.build(log_file)
.unwrap();

cfg_builder = cfg_builder
.appender(Appender::builder().build(event_name, Box::new(csv_appender)))
.logger(
Logger::builder()
.appender(event_name)
.additive(false)
.build(event_name, log::LevelFilter::Info)
);
}
}

let config = cfg_builder
.build(
log4rs::config::Root::builder()
.appender("main")
.build(log::LevelFilter::Trace),
)
.unwrap();
// .appender(FileAppender::builder().encoder(Box::new(PatternEncoder::new(&csv_log_pattern))).build("log.txt"))

log4rs::init_config(config)
}
6 changes: 4 additions & 2 deletions examples/jssp/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,10 @@ fn run_with_ecrs(instance: JsspInstance, _args: Args) {

fn run() {
let args = cli::parse_args();

if let Err(err) = logging::init_logging(Some(args.output_file.as_path())) {

util::assert_dir_exists(args.output_dir.as_ref());
let event_map = util::create_event_map(args.output_dir.as_ref());
if let Err(err) = logging::init_logging(&event_map) {
panic!("Logger initialization failed with error: {err}");
}

Expand Down
21 changes: 12 additions & 9 deletions examples/jssp/problem/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@ impl Probe<JsspIndividual> for JsspProbe {

#[inline]
fn on_start(&mut self, _metadata: &ecrs::ga::GAMetadata) {
// This is a marker record for ECDataKit. Since it looks like
// polars.DataFrame.read_csv deduces number of columns from the first encoutered
// record it leads to crashes when longer records are encountered deeper in the file.
info!(target: "csv", "event,,,,,,,");
// Writing csv header to each file
info!(target: "diversity", "event_name,generation,total_duration,population_size,diversity");
info!(target: "popgentime", "event_name,time");
info!(target: "newbest", "event_name,generation,total_duration,fitness");
info!(target: "bestingen", "event_name,generation,total_duration,fitness");
info!(target: "iterinfo", "event_name,eval_time,sel_time,cross_time,mut_time,repl_time,iter_time");
}

fn on_initial_population_created(
Expand All @@ -47,12 +49,13 @@ impl Probe<JsspIndividual> for JsspProbe {
// TODO: As this metric is useless right now I'm disabling it temporarily
// let diversity = JsspProbe::estimate_pop_diversity(population);
let diversity = 0.0;
info!(target: "csv", "diversity,0,0,{},{diversity}\npopgentime,{}", population.len(), metadata.pop_gen_dur.unwrap().as_millis());
info!(target: "diversity", "diversity,0,0,{},{diversity}", population.len());
info!(target: "popgentime", "popgentime,{}", metadata.pop_gen_dur.unwrap().as_millis());
}

fn on_new_best(&mut self, metadata: &ecrs::ga::GAMetadata, individual: &JsspIndividual) {
info!(
target: "csv",
target: "newbest",
"newbest,{},{},{}",
metadata.generation,
metadata.total_dur.unwrap().as_millis(),
Expand All @@ -65,7 +68,7 @@ impl Probe<JsspIndividual> for JsspProbe {
// let diversity = JsspProbe::estimate_pop_diversity(generation);
let diversity = 0.0;
info!(
target: "csv",
target: "diversity",
"diversity,{},{},{},{diversity}",
metadata.generation,
metadata.total_dur.unwrap().as_millis(),
Expand All @@ -75,7 +78,7 @@ impl Probe<JsspIndividual> for JsspProbe {

fn on_best_fit_in_generation(&mut self, metadata: &ecrs::ga::GAMetadata, individual: &JsspIndividual) {
info!(
target: "csv",
target: "bestingen",
"bestingen,{},{},{}",
metadata.generation,
metadata.total_dur.unwrap().as_millis(),
Expand All @@ -89,7 +92,7 @@ impl Probe<JsspIndividual> for JsspProbe {

#[inline]
fn on_iteration_end(&mut self, metadata: &ecrs::ga::GAMetadata) {
info!(target: "csv", "iterinfo,{},{},{},{},{},{},{}",
info!(target: "iterinfo", "iterinfo,{},{},{},{},{},{},{}",
metadata.generation,
metadata.pop_eval_dur.unwrap().as_millis(),
metadata.selection_dur.unwrap().as_millis(),
Expand Down
24 changes: 23 additions & 1 deletion examples/jssp/util.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![allow(dead_code)]

use std::{collections::HashSet, fmt::Display};
use std::{collections::{HashSet, HashMap, hash_map}, fmt::Display, path::{PathBuf, Path}};

pub fn print_hash_set<T: Display>(set: &HashSet<T>) {
for elem in set {
Expand All @@ -15,3 +15,25 @@ pub fn print_slice<T: Display>(slc: &[T]) {
}
println!();
}

#[inline]
pub fn create_event_map(base_dir: &Path) -> HashMap<String, PathBuf> {
HashMap::from([
("diversity".to_owned(), base_dir.join("event_diversity.csv")),
("newbest".to_owned(), base_dir.join("event_newbest.csv")),
("bestingen".to_owned(), base_dir.join("event_bestingen.csv")),
("popgentime".to_owned(), base_dir.join("event_popgentime.csv")),
("iterinfo".to_owned(), base_dir.join("event_iterinfo.csv"))
])
}

pub fn assert_dir_exists(dir: &Path) {
if dir.is_dir() {
return;
}

match std::fs::create_dir_all(dir) {
Ok(()) => return,
Err(err) => panic!("Failed to create outuput directory with error {err}"),
};
}

0 comments on commit 069bed1

Please sign in to comment.