Skip to content

Commit

Permalink
Add benches for goal evaluation of CVRPTW
Browse files Browse the repository at this point in the history
  • Loading branch information
reinterpretcat committed Aug 28, 2024
1 parent ef7dbee commit 442bc59
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 1 deletion.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ rayon = "1.10.0"
rustc-hash = "2.0.0"
paste = "1.0.15"

# dev dependencies
criterion = "0.5.1"

[profile.release]
lto = "fat" # enables "fat" LTO, for faster release builds
codegen-units = 1 # makes sure that all code is compiled together, for LTO
Expand Down
11 changes: 11 additions & 0 deletions examples/data/scientific/solomon/C101.100.partial.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Route 1 : 81 78 76 80
Route 2 : 57 55 54 53 56 58 60 59
Route 3 : 98 96 95 94 92 93 97 100 99
Route 4 : 32 33 31 35 37 38 39 36 34
Route 5 : 13 17 18 19 15 16 14 12
Route 6 : 90 87 86 83 89 91
Route 7 : 43 42 41 40 48 51 50 52 49 47
Route 8 : 67 65 63 62 74 72 61 64 68 66 69
Route 9 : 5 3 7 8 10 11 9 6 4 2 1 75
Route 10 : 20 24 30 28 26 23 22 21
Cost 1000
2 changes: 1 addition & 1 deletion examples/json-pragmatic/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ edition.workspace = true
vrp-pragmatic.workspace = true

[dev-dependencies]
criterion = "0.5.1"
criterion.workspace = true

[[bench]]
name = "general_benchmark"
Expand Down
7 changes: 7 additions & 0 deletions vrp-scientific/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,10 @@ edition.workspace = true
[dependencies]
vrp-core.workspace = true
paste.workspace = true

[dev-dependencies]
criterion.workspace = true

[[bench]]
name = "solomon_goal"
harness = false
127 changes: 127 additions & 0 deletions vrp-scientific/benches/solomon_goal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
//! This benchmark evaluates the goal pipeline for the Solomon problem variant (CVRPTW).
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use std::fs::File;
use std::io::BufReader;
use std::sync::Arc;
use vrp_core::construction::heuristics::ActivityContext;
use vrp_core::models::common::{Schedule, Timestamp};
use vrp_core::models::problem::{JobIdDimension, Single};
use vrp_core::models::solution::{Activity, Place};
use vrp_core::prelude::*;
use vrp_scientific::common::read_init_solution;
use vrp_scientific::solomon::SolomonProblem;

pub fn get_bench_resource(resource_path: &str) -> std::io::Result<File> {
let mut path = std::env::current_dir()?;
path.push("benches");
path.push(resource_path);

File::open(path)
}

/// Returns a partial insertion context: some jobs are excluded from the used initial solution.
fn get_partial_insertion_context() -> InsertionContext {
let environment = Arc::new(Environment::default());
let problem = Arc::new(
BufReader::new(get_bench_resource("../../examples/data/scientific/solomon/C101.100.txt").unwrap())
.read_solomon(false)
.unwrap(),
);
assert_eq!(problem.jobs.size(), 100);

let solution = read_init_solution(
BufReader::new(get_bench_resource("../../examples/data/scientific/solomon/C101.100.partial.txt").unwrap()),
problem.clone(),
environment.random.clone(),
)
.expect("cannot read initial solution");

assert!(!solution.routes.is_empty());
assert!(!solution.unassigned.is_empty());

InsertionContext::new_from_solution(problem, (solution, None), environment)
}

fn get_insertion_entities(solution_ctx: &SolutionContext) -> (&RouteContext, &Arc<Single>) {
// get route for insertion
let route_ctx = solution_ctx
.routes
.iter()
.find(|route_ctx| {
route_ctx
.route()
.tour
.get(1)
.and_then(|a| a.retrieve_job())
.and_then(|job| job.dimens().get_job_id().cloned())
.map_or(false, |job_id| job_id == "67")
})
.expect("cannot find expected route in the solution");
assert_eq!(route_ctx.route().tour.job_count(), 11, "unexpected job count in the route");

// get job for insertion
let job = solution_ctx
.unassigned
.iter()
.find(|(job, _)| job.dimens().get_job_id().map_or(false, |id| id == "45"))
.and_then(|(job, _)| job.as_single())
.expect("cannot find single job in the unassigned jobs");

(route_ctx, job)
}

fn bench_evaluate_route(c: &mut Criterion) {
c.bench_function("CVRPTW: run Goal::evaluate for route on C101.100", |b| {
let insertion_ctx = get_partial_insertion_context();
let solution_ctx = &insertion_ctx.solution;
let (route_ctx, job) = get_insertion_entities(solution_ctx);

b.iter(|| {
insertion_ctx.problem.goal.evaluate(&MoveContext::Route {
solution_ctx,
route_ctx,
job: &Job::Single(job.clone()),
});
black_box(())
})
});
}

fn bench_evaluate_activity(c: &mut Criterion) {
c.bench_function("CVRPTW: run Goal::evaluate for activity on C101.100", |b| {
let insertion_ctx = get_partial_insertion_context();
let solution_ctx = &insertion_ctx.solution;
let (route_ctx, job) = get_insertion_entities(solution_ctx);

// get activities for insertion context
let prev = route_ctx.route().tour.get(7).unwrap();
let target = Activity {
place: Place {
idx: 7,
location: job.places[0].location.unwrap(),
duration: job.places[0].duration.clone(),
time: job.places[0].times[0].to_time_window(Timestamp::default()),
},
schedule: Schedule { arrival: 0.0, departure: 0.0 },
job: Some(job.clone()),
commute: None,
};
let next = route_ctx.route().tour.get(8);

b.iter(|| {
insertion_ctx.problem.goal.evaluate(&MoveContext::Activity {
route_ctx,
activity_ctx: &ActivityContext { index: 0, prev, target: &target, next },
});
})
});
}

criterion_group! {
name = benches;
config = Criterion::default().sample_size(64);
targets = bench_evaluate_route,
bench_evaluate_activity,
}
criterion_main!(benches);

0 comments on commit 442bc59

Please sign in to comment.