Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal for overtime cost handling #163

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ members = [
]

[workspace.package]
version = "1.24.0"
version = "1.24.1"
authors = ["Ilya Builuk <[email protected]>"]
license = "Apache-2.0"
keywords = ["vrp", "optimization"]
Expand All @@ -26,7 +26,7 @@ edition = "2021"
[workspace.dependencies]
# internal dependencies
rosomaxa = { path = "rosomaxa", version = "0.8.0" }
vrp-core = { path = "vrp-core", version = "1.24.0" }
vrp-core = { path = "vrp-core", version = "1.24.1" }
vrp-scientific = { path = "vrp-scientific", version = "1.24.0" }
vrp-pragmatic = { path = "vrp-pragmatic", version = "1.24.0" }
vrp-cli = { path = "vrp-cli", version = "1.24.0" }
Expand Down
2 changes: 1 addition & 1 deletion vrp-cli/src/extensions/import/csv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ mod actual {
type_id: vehicle.id.clone(),
vehicle_ids: (1..=vehicle.amount).map(|seq| format!("{}_{}", vehicle.profile, seq)).collect(),
profile: VehicleProfile { matrix: vehicle.profile, scale: None },
costs: VehicleCosts { fixed: Some(25.), distance: 0.0002, time: 0.005 },
costs: VehicleCosts { fixed: Some(25.), distance: 0.0002, time: 0.005, overtime: Some(OvertimeCosts { threshold: f64::MAX, time: 0. }) },
shifts: vec![VehicleShift {
start: ShiftStart {
earliest: vehicle.tw_start,
Expand Down
2 changes: 1 addition & 1 deletion vrp-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ mod cli {

pub fn get_app() -> Command {
Command::new("Vehicle Routing Problem Solver")
.version("1.24.0")
.version("1.24.1")
.author("Ilya Builuk <[email protected]>")
.about("A command line interface to Vehicle Routing Problem solver")
.subcommand(get_analyze_app())
Expand Down
1 change: 1 addition & 0 deletions vrp-core/src/construction/heuristics/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ impl InsertionContext {
// .
// TODO calculate actual cost
+ costs.per_driving_time.max(costs.per_service_time).max(costs.per_waiting_time) * duration
+ calculate_overtime_cost(duration, costs)
};

self.solution.routes.iter().try_fold(Cost::default(), |acc, route_ctx| {
Expand Down
2 changes: 2 additions & 0 deletions vrp-core/src/models/problem/builders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ impl Default for VehicleBuilder {
per_driving_time: 0.0,
per_waiting_time: 0.0,
per_service_time: 0.0,
overtime_threshold: 0.0,
overtime_cost: 0.0,
},
dimens: Default::default(),
details: vec![],
Expand Down
6 changes: 6 additions & 0 deletions vrp-core/src/models/problem/fleet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ pub struct Costs {
pub per_waiting_time: f64,
/// Cost per service time unit.
pub per_service_time: f64,
/// the threshold in time unit of overtime.
pub overtime_threshold: f64,
///cost per overtime unit.
pub overtime_cost: f64,
}

/// Represents driver detail (reserved for future use).
Expand Down Expand Up @@ -54,6 +58,8 @@ impl Driver {
per_driving_time: 0.,
per_waiting_time: 0.,
per_service_time: 0.,
overtime_threshold: 0.,
overtime_cost: 0.,
},
dimens: Default::default(),
details: vec![],
Expand Down
11 changes: 11 additions & 0 deletions vrp-core/src/models/problem/jobs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,15 @@ fn get_cost_between_jobs(
routing_cost
}

pub fn calculate_overtime_cost(work_time: f64, costs: &Costs) -> f64 {
if work_time > costs.overtime_threshold {
let overtime = work_time - costs.overtime_threshold;
overtime * costs.overtime_cost
} else {
0.0
}
}

fn get_avg_profile_costs(fleet: &Fleet) -> HashMap<usize, Costs> {
let get_avg_by = |costs: &Vec<Costs>, map_cost_fn: fn(&Costs) -> f64| -> f64 {
costs.iter().map(map_cost_fn).sum::<f64>() / (costs.len() as f64)
Expand All @@ -428,6 +437,8 @@ fn get_avg_profile_costs(fleet: &Fleet) -> HashMap<usize, Costs> {
per_driving_time: get_avg_by(costs, |c| c.per_driving_time),
per_waiting_time: get_avg_by(costs, |c| c.per_waiting_time),
per_service_time: get_avg_by(costs, |c| c.per_service_time),
overtime_cost: get_avg_by(costs, |c| c.overtime_cost),
overtime_threshold: get_avg_by(costs, |c| c.overtime_threshold),
},
)
})
Expand Down
11 changes: 11 additions & 0 deletions vrp-pragmatic/src/format/problem/fleet_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,21 @@ pub(super) fn read_fleet(api_problem: &ApiProblem, props: &ProblemProperties, co
let mut vehicles: Vec<Arc<Vehicle>> = Default::default();

api_problem.fleet.vehicles.iter().for_each(|vehicle| {
let overtime = vehicle.costs.overtime.as_ref().unwrap_or_else(|| {
&OvertimeCosts {
threshold: f64::MAX,
time: 0.0,
}
});

let costs = Costs {
fixed: vehicle.costs.fixed.unwrap_or(0.),
per_distance: vehicle.costs.distance,
per_driving_time: vehicle.costs.time,
per_waiting_time: vehicle.costs.time,
per_service_time: vehicle.costs.time,
overtime_threshold: overtime.threshold,
overtime_cost: overtime.time,
};

let index = *profile_indices.get(&vehicle.profile.matrix).unwrap();
Expand Down Expand Up @@ -175,6 +184,8 @@ pub(super) fn read_fleet(api_problem: &ApiProblem, props: &ProblemProperties, co
per_driving_time: 0.0,
per_waiting_time: 0.0,
per_service_time: 0.0,
overtime_threshold: f64::MAX,
overtime_cost: 0.0,
},
dimens: Default::default(),
details: vec![],
Expand Down
16 changes: 16 additions & 0 deletions vrp-pragmatic/src/format/problem/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,22 @@ pub struct VehicleCosts {

/// Cost per time unit.
pub time: f64,

/// Fixed is cost of vehicle usage per tour.
#[serde(skip_serializing_if = "Option::is_none")]
pub overtime: Option<OvertimeCosts>,

}

/// Specifies vehicle costs.
#[derive(Clone, Deserialize, Debug, Serialize)]
pub struct OvertimeCosts {
/// The threshold above which overtime cost is calculated
pub threshold: f64,

/// Overtime cost per time unit.
pub time: f64,

}

/// Specifies vehicle shift start.
Expand Down
4 changes: 4 additions & 0 deletions vrp-scientific/src/common/text_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ pub(crate) fn create_fleet_with_distance_costs(
per_driving_time: 0.0,
per_waiting_time: 0.0,
per_service_time: 0.0,
overtime_threshold: 0.0,
overtime_cost: 0.0,
},
dimens: Default::default(),
details: Default::default(),
Expand All @@ -73,6 +75,8 @@ pub(crate) fn create_fleet_with_distance_costs(
per_driving_time: 0.0,
per_waiting_time: 0.0,
per_service_time: 0.0,
overtime_threshold: 0.0,
overtime_cost: 0.0,
},
dimens,
details: vec![VehicleDetail {
Expand Down