Skip to content

Commit

Permalink
Refactor dimensions to avoid using string as a key
Browse files Browse the repository at this point in the history
  • Loading branch information
reinterpretcat committed Jun 14, 2024
1 parent 5afa552 commit 7282132
Show file tree
Hide file tree
Showing 61 changed files with 434 additions and 468 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ are already published. So, I stick to it for now.
* tweak infeasible search heuristic
* refactor route intervals and multi trip enablers
* refactor feature objective
* refactor dimensions approach


## [v1.23.0]- 2023-12-22
Expand Down
5 changes: 2 additions & 3 deletions vrp-cli/src/extensions/analyze/clusters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ mod clusters_test;
use std::io::{BufReader, BufWriter, Read};
use std::sync::Arc;
use vrp_core::construction::clustering::dbscan::create_job_clusters;
use vrp_core::models::common::IdDimension;
use vrp_core::models::problem::get_job_locations;
use vrp_core::models::problem::{get_job_locations, JobIdDimension};
use vrp_core::models::Problem;
use vrp_core::prelude::GenericError;
use vrp_core::utils::Environment;
Expand Down Expand Up @@ -35,7 +34,7 @@ pub fn get_clusters<F: Read>(
.flat_map(|(cluster_idx, jobs)| {
jobs.iter()
.filter_map(move |job| {
job.dimens().get_id().cloned().map(|job_id| {
job.dimens().get_job_id().cloned().map(|job_id| {
get_job_locations(job)
.flatten()
.filter_map(move |l_idx| coord_index.get_by_idx(l_idx))
Expand Down
9 changes: 4 additions & 5 deletions vrp-core/src/construction/clustering/vicinity/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
mod vicinity_test;

use crate::construction::heuristics::*;
use crate::models::common::Dimensions;
use crate::models::common::*;
use crate::models::common::{Dimensions, ValueDimension};
use crate::models::problem::{Actor, Job};
use crate::models::Problem;
use hashbrown::HashSet;
Expand All @@ -19,8 +19,6 @@ mod estimations;
use self::estimations::*;
use crate::models::solution::Commute;

const CLUSTER_DIMENSION_KEY: &str = "cls";

/// A trait to get or set cluster info.
pub trait ClusterDimension {
/// Sets cluster.
Expand All @@ -29,14 +27,15 @@ pub trait ClusterDimension {
fn get_cluster(&self) -> Option<&Vec<ClusterInfo>>;
}

struct ClusterDimensionKey;
impl ClusterDimension for Dimensions {
fn set_cluster(&mut self, jobs: Vec<ClusterInfo>) -> &mut Self {
self.set_value(CLUSTER_DIMENSION_KEY, jobs);
self.set_value::<ClusterDimensionKey, _>(jobs);
self
}

fn get_cluster(&self) -> Option<&Vec<ClusterInfo>> {
self.get_value(CLUSTER_DIMENSION_KEY)
self.get_value::<ClusterDimensionKey, _>()
}
}

Expand Down
6 changes: 3 additions & 3 deletions vrp-core/src/construction/heuristics/insertions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
mod insertions_test;

use crate::construction::heuristics::*;
use crate::models::common::{Cost, IdDimension};
use crate::models::problem::{Actor, Job};
use crate::models::common::Cost;
use crate::models::problem::{Actor, Job, JobIdDimension};
use crate::models::solution::Activity;
use crate::models::ViolationCode;
use rosomaxa::prelude::*;
Expand Down Expand Up @@ -52,7 +52,7 @@ impl Debug for InsertionSuccess {
.map(|(a, idx)| {
(
a.retrieve_job()
.and_then(|job| job.dimens().get_id().cloned())
.and_then(|job| job.dimens().get_job_id().cloned())
.unwrap_or("undef".to_string()),
*idx,
)
Expand Down
26 changes: 26 additions & 0 deletions vrp-core/src/models/common/dimens.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use hashbrown::HashMap;
use rustc_hash::FxHasher;
use std::any::{Any, TypeId};
use std::hash::BuildHasherDefault;
use std::sync::Arc;

/// Multiple named dimensions which can contain anything:
/// * unit of measure, e.g. volume, mass, size, etc.
/// * set of skills
/// * tag.
#[derive(Clone, Debug, Default)]
pub struct Dimensions {
index: HashMap<TypeId, Arc<dyn Any + Send + Sync>, BuildHasherDefault<FxHasher>>,
}

impl Dimensions {
/// Gets a value using type provided.
pub fn get_value<K: 'static, V: 'static>(&self) -> Option<&V> {
self.index.get(&TypeId::of::<K>()).and_then(|any| any.downcast_ref::<V>())
}

/// Sets the value using type provided.
pub fn set_value<K: 'static, V: 'static + Sync + Send>(&mut self, value: V) {
self.index.insert(TypeId::of::<K>(), Arc::new(value));
}
}
49 changes: 1 addition & 48 deletions vrp-core/src/models/common/domain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,9 @@
mod domain_test;

use crate::models::common::{Duration, Timestamp};
use hashbrown::HashMap;
use rosomaxa::prelude::compare_floats;
use rustc_hash::FxHasher;
use std::any::Any;
use std::cmp::Ordering;
use std::hash::{BuildHasherDefault, Hash, Hasher};
use std::sync::Arc;
use std::hash::{Hash, Hasher};

/// Specifies location type.
pub type Location = usize;
Expand Down Expand Up @@ -217,49 +213,6 @@ impl PartialEq<Schedule> for Schedule {

impl Eq for Schedule {}

/// Multiple named dimensions which can contain anything:
/// * unit of measure, e.g. volume, mass, size, etc.
/// * set of skills
/// * tag.
pub type Dimensions = HashMap<String, Arc<dyn Any + Send + Sync>, BuildHasherDefault<FxHasher>>;

/// A trait to return arbitrary typed value by its key.
pub trait ValueDimension {
/// Gets value from dimension with given key.
fn get_value<T: 'static>(&self, key: &str) -> Option<&T>;
/// Sets value in dimension with given key and value.
fn set_value<T: 'static + Sync + Send>(&mut self, key: &str, value: T);
}

impl ValueDimension for Dimensions {
fn get_value<T: 'static>(&self, key: &str) -> Option<&T> {
self.get(key).and_then(|any| any.downcast_ref::<T>())
}

fn set_value<T: 'static + Sync + Send>(&mut self, key: &str, value: T) {
self.insert(key.to_owned(), Arc::new(value));
}
}

/// A trait to get or set id.
pub trait IdDimension {
/// Sets value as id.
fn set_id(&mut self, id: &str) -> &mut Self;
/// Gets id value if present.
fn get_id(&self) -> Option<&String>;
}

impl IdDimension for Dimensions {
fn set_id(&mut self, id: &str) -> &mut Self {
self.set_value("id", id.to_string());
self
}

fn get_id(&self) -> Option<&String> {
self.get_value("id")
}
}

impl Hash for TimeInterval {
fn hash<H: Hasher>(&self, state: &mut H) {
let earliest = self.earliest.unwrap_or(0.).to_bits() as i64;
Expand Down
14 changes: 7 additions & 7 deletions vrp-core/src/models/common/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@
#[path = "../../../tests/unit/models/common/load_test.rs"]
mod load_test;

use crate::models::common::{Dimensions, ValueDimension};
use crate::models::common::Dimensions;
use rosomaxa::prelude::UnwrapValue;
use std::cmp::Ordering;
use std::fmt::{Debug, Display, Formatter};
use std::iter::Sum;
use std::ops::{Add, ControlFlow, Mul, Sub};

const CAPACITY_DIMENSION_KEY: &str = "capacity";
const DEMAND_DIMENSION_KEY: &str = "demand";
const LOAD_DIMENSION_SIZE: usize = 8;

/// Represents a load type used to represent customer's demand or vehicle's load.
Expand Down Expand Up @@ -114,25 +112,27 @@ impl<T: LoadOps> Add for Demand<T> {
}
}

struct CapacityDimenKey;
impl<T: LoadOps> CapacityDimension<T> for Dimensions {
fn set_capacity(&mut self, demand: T) -> &mut Self {
self.set_value(CAPACITY_DIMENSION_KEY, demand);
self.set_value::<CapacityDimenKey, _>(demand);
self
}

fn get_capacity(&self) -> Option<&T> {
self.get_value(CAPACITY_DIMENSION_KEY)
self.get_value::<CapacityDimenKey, _>()
}
}

struct DemandDimenKey;
impl<T: LoadOps> DemandDimension<T> for Dimensions {
fn set_demand(&mut self, demand: Demand<T>) -> &mut Self {
self.set_value(DEMAND_DIMENSION_KEY, demand);
self.set_value::<DemandDimenKey, _>(demand);
self
}

fn get_demand(&self) -> Option<&Demand<T>> {
self.get_value(DEMAND_DIMENSION_KEY)
self.get_value::<DemandDimenKey, _>()
}
}

Expand Down
3 changes: 3 additions & 0 deletions vrp-core/src/models/common/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
//! Common models.

mod dimens;
pub use self::dimens::*;

mod domain;
pub use self::domain::*;

Expand Down
8 changes: 4 additions & 4 deletions vrp-core/src/models/examples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ fn create_example_fleet() -> Arc<Fleet> {
details: vec![],
})];
let mut vehicle_dimens = Dimensions::default();
vehicle_dimens.set_id("v1");
vehicle_dimens.set_vehicle_id("v1");
let vehicles = vec![Arc::new(Vehicle {
profile: Profile::default(),
costs: Costs { fixed: 0., per_distance: 1., per_driving_time: 0., per_waiting_time: 0., per_service_time: 0. },
Expand Down Expand Up @@ -80,15 +80,15 @@ struct ExampleCapacityAspects {

impl CapacityAspects<SingleDimLoad> for ExampleCapacityAspects {
fn get_capacity<'a>(&self, vehicle: &'a Vehicle) -> Option<&'a SingleDimLoad> {
vehicle.dimens.get_value("capacity")
vehicle.dimens.get_capacity()
}

fn get_demand<'a>(&self, single: &'a Single) -> Option<&'a Demand<SingleDimLoad>> {
single.dimens.get_value("demand")
single.dimens.get_demand()
}

fn set_demand(&self, single: &mut Single, demand: Demand<SingleDimLoad>) {
single.dimens.set_value("demand", demand);
single.dimens.set_demand(demand);
}

fn get_state_keys(&self) -> &CapacityKeys {
Expand Down
27 changes: 15 additions & 12 deletions vrp-core/src/models/extras.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
use crate::construction::enablers::ScheduleKeys;
use crate::construction::features::CapacityKeys;
use crate::construction::heuristics::StateKeyRegistry;
use crate::models::common::{Dimensions, ValueDimension};
use crate::solver::HeuristicKeys;
use hashbrown::HashMap;
use rosomaxa::prelude::GenericError;
use rustc_hash::FxHasher;
use std::any::Any;
use std::hash::BuildHasherDefault;
use std::sync::Arc;

/// Specifies a type used to store any values regarding problem configuration.
pub struct Extras {
index: Dimensions,
index: HashMap<String, Arc<dyn Any + Send + Sync>, BuildHasherDefault<FxHasher>>,
}

impl Extras {
/// Gets value for the key if it is stored and has `T` type.
pub fn get_value<T: 'static>(&self, key: &str) -> Option<&T> {
self.index.get(key).and_then(|any| any.downcast_ref::<T>())
}

/// Sets value using the given key.
pub fn set_value<T: 'static + Sync + Send>(&mut self, key: &str, value: T) {
self.index.insert(key.to_string(), Arc::new(value));
}

/// Returns a shared reference for the value under the given key.
pub fn get_value_raw<T: 'static + Send + Sync>(&self, key: &str) -> Option<Arc<T>> {
self.index.get(key).cloned().and_then(|any| any.downcast::<T>().ok())
Expand Down Expand Up @@ -118,13 +131,3 @@ impl CoreStateKeys for Extras {
self.get_value("heuristic_keys")
}
}

impl ValueDimension for Extras {
fn get_value<T: 'static>(&self, key: &str) -> Option<&T> {
self.index.get_value(key)
}

fn set_value<T: 'static + Sync + Send>(&mut self, key: &str, value: T) {
self.index.set_value(key, value)
}
}
23 changes: 22 additions & 1 deletion vrp-core/src/models/problem/fleet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ pub struct Actor {
impl Debug for Actor {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct(short_type_name::<Self>())
.field("vehicle", &self.vehicle.dimens.get_id().map(|id| id.as_str()).unwrap_or("undef"))
.field("vehicle", &self.vehicle.dimens.get_vehicle_id().map(|id| id.as_str()).unwrap_or("undef"))
.finish_non_exhaustive()
}
}
Expand Down Expand Up @@ -203,3 +203,24 @@ impl Hash for Actor {
address.hash(state);
}
}

/// A trait to get or set vehicle id.
pub trait VehicleIdDimension {
/// Sets value as vehicle id.
fn set_vehicle_id(&mut self, value: &str) -> &mut Self;

/// Gets vehicle id value if present.
fn get_vehicle_id(&self) -> Option<&String>;
}

struct VehicleIdDimensionKey;
impl VehicleIdDimension for Dimensions {
fn set_vehicle_id(&mut self, id: &str) -> &mut Self {
self.set_value::<VehicleIdDimensionKey, _>(id.to_string());
self
}

fn get_vehicle_id(&self) -> Option<&String> {
self.get_value::<VehicleIdDimensionKey, _>()
}
}
Loading

0 comments on commit 7282132

Please sign in to comment.