Skip to content

Commit

Permalink
feat(jssp): print solution order, hash & more metadata at solution end (
Browse files Browse the repository at this point in the history
#431)

<!-- If applicable - remember to add the PR to the EA Rust project (ONLY
IF THERE IS NO LINKED ISSUE) -->

## Description

<!-- Please describe the motivation & changes introduced by this PR -->

## Linked issues

<!-- Please use "Resolves #<issue_no> syntax in case this PR should be
linked to an issue -->

## Important implementation details

<!-- if any, optional section -->
  • Loading branch information
kkafar authored Oct 9, 2023
1 parent ff0a0cf commit cd9a3e9
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 7 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ num-traits = { version = "0.2.15", optional = true }
log4rs = "1.2.0"
criterion = "0.5.1"
clap = { version = "4.2.7", features = ["derive"] }
md5 = "0.7.0"


[[bench]]
Expand Down
34 changes: 31 additions & 3 deletions examples/jssp/logging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,20 @@ use log4rs::{
encode::pattern::PatternEncoder,
};

pub fn init_logging(log_files: &HashMap<String, PathBuf>) -> Result<log4rs::Handle, log::SetLoggerError> {

#[derive(serde::Serialize, Clone, Debug)]
pub struct OutputData {
pub solution_string: String,
pub hash: String,
pub fitness: usize,
pub generation_count: usize,
pub total_time: u128,
}

pub fn init_logging(event_log_files: &HashMap<String, PathBuf>, metadata_log_file: &PathBuf) -> Result<log4rs::Handle, log::SetLoggerError> {
let log_pattern = String::from("[{l}] {m}{n}");
let csv_log_pattern = String::from("{m}{n}");
let csv_encoder = Box::new(PatternEncoder::new(&csv_log_pattern));

let stdout_appender = ConsoleAppender::builder()
.encoder(Box::new(PatternEncoder::new(&log_pattern)))
Expand All @@ -22,10 +33,11 @@ pub fn init_logging(log_files: &HashMap<String, PathBuf>) -> Result<log4rs::Hand
// 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() {
if !event_log_files.is_empty() {
let csv_encoder = Box::new(PatternEncoder::new(&csv_log_pattern));
for (event_name, log_file) in log_files.iter() {
for (event_name, log_file) in event_log_files.iter() {
let csv_appender = FileAppender::builder()
.encoder(csv_encoder.clone())
.append(false)
Expand All @@ -43,6 +55,22 @@ pub fn init_logging(log_files: &HashMap<String, PathBuf>) -> Result<log4rs::Hand
}
}

let result_appender = FileAppender::builder()
.encoder(csv_encoder)
.append(false)
.build(metadata_log_file)
.unwrap();

cfg_builder = cfg_builder
.appender(Appender::builder().build("metadata_appender", Box::new(result_appender)))
.logger(
Logger::builder()
.appender("metadata_appender")
.additive(false)
.build("metadata", log::LevelFilter::Info),
);


let config = cfg_builder
.build(
log4rs::config::Root::builder()
Expand Down
2 changes: 1 addition & 1 deletion examples/jssp/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ fn run() {

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) {
if let Err(err) = logging::init_logging(&event_map, &args.output_dir.join("run_metadata.json")) {
panic!("Logger initialization failed with error: {err}");
}

Expand Down
45 changes: 42 additions & 3 deletions examples/jssp/problem/probe.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
use std::cmp::Ordering;

use ecrs::ga::{individual::IndividualTrait, Probe};
use itertools::Itertools;
use log::info;
use md5;

use crate::logging::OutputData;

use super::individual::JsspIndividual;

Expand Down Expand Up @@ -107,9 +112,43 @@ impl Probe<JsspIndividual> for JsspProbe {
#[inline]
fn on_end(
&mut self,
_metadata: &ecrs::ga::GAMetadata,
metadata: &ecrs::ga::GAMetadata,
_population: &[JsspIndividual],
_best_individual: &JsspIndividual,
) { /* defaults to noop */
best_individual: &JsspIndividual,
) {
let mut ops = best_individual.operations.clone();
ops.sort_unstable_by(|a, b| {
if a.finish_time == b.finish_time {
if a.duration == 0 && b.duration != 0 {
return Ordering::Greater;
} else if a.duration != 0 && b.duration == 0 {
return Ordering::Less;
} else if a.machine < b.machine {
return Ordering::Less;
} else {
return Ordering::Greater;
}
} else if a.finish_time < b.finish_time {
return Ordering::Less;
} else {
return Ordering::Greater;
}
});
let n = ops.len();
let solution_string = ops.into_iter()
.filter(|op| op.id != 0 && op.id != n + 1)
.map(|op| op.id.to_string())
.join("_");

let hash = md5::compute(solution_string.clone());
let outdata = OutputData {
solution_string,
hash: format!("{:x}", hash),
fitness: best_individual.fitness,
generation_count: metadata.generation,
total_time: metadata.total_dur.unwrap().as_millis(),
};
let serialized_object = serde_json::to_string(&outdata).unwrap();
info!(target: "metadata", "{serialized_object}");
}
}

0 comments on commit cd9a3e9

Please sign in to comment.