Skip to content

Commit

Permalink
Implement basic Solution::new(model)
Browse files Browse the repository at this point in the history
  • Loading branch information
cnpryer committed Jan 19, 2025
1 parent 0694b39 commit 63900ad
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 23 deletions.
75 changes: 69 additions & 6 deletions crates/solver-vrp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,80 @@ struct Solver {
}

impl Solver {
fn new() -> Self {
Self {
model: Model::new(),
}
fn new(model: Model) -> Self {
Self { model }
}

fn solve(&self) -> Solution {
todo!()
fn solve(&self, options: Options) -> Solution {
let initial_solution = Solution::new(&self.model);

for _ in 0..options.iterations {
unimplemented!()
}

initial_solution
}

fn model(&self) -> &Model {
&self.model
}
}

struct Options {
iterations: u64,
}

impl Default for Options {
fn default() -> Self {
Self { iterations: 10 }
}
}

#[test]
fn test_solver() {
use schema::{
InitialStop, Input, Location as InputLocation, Stop as InputStop, Vehicle as InputVehicle,
};
use std::collections::HashMap;

let model = Model::from(Input {
stops: vec![
InputStop {
id: String::from("pickup"),
precedes: Some(vec![String::from("delivery")]),
quantity: HashMap::from([(String::from("count"), -1.)]),
start_time_windows: [0; 2],
location: InputLocation { lat: 0., lon: 0. },
},
InputStop {
id: String::from("delivery"),
precedes: None,
quantity: HashMap::from([(String::from("count"), 1.)]),
start_time_windows: [0; 2],
location: InputLocation { lat: 0., lon: 0. },
},
],
vehicles: vec![InputVehicle {
id: String::from("vehicle"),
capacity: HashMap::from([(String::from("count"), 1.)]),
speed: 0.,
initial_stops: Some(vec![
InitialStop {
id: String::from("pickup"),
},
InitialStop {
id: String::from("pickup"),
},
]),
}],
distance_matrix: vec![vec![0., 1.], vec![1., 0.]],
options: None,
});

let solution = Solver::new(model).solve(Options {
iterations: 0,
..Default::default()
});

assert_eq!(solution.value(), 0.)
}
48 changes: 34 additions & 14 deletions crates/solver-vrp/src/model.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::collections::{HashMap, HashSet};
use std::{
collections::{HashMap, HashSet},
vec::IntoIter,
};

use crate::{Id, Index, schema::Input};

Expand All @@ -21,7 +24,7 @@ impl Model {
&self.stops
}

fn vehicles(&self) -> &Vehicles {
pub fn vehicles(&self) -> &Vehicles {
&self.vehicles
}
}
Expand Down Expand Up @@ -60,11 +63,15 @@ impl From<Input> for Model {
};

// Currently only one pickup and one delivery stop is supported.
if stop.precedes.len() > 1 {
if stop
.precedes
.as_ref()
.is_some_and(|precedes| precedes.len() > 1)
{
panic!("stop {} has too many precedes", stop.id);
}

if let Some(id) = stop.precedes.first() {
if let Some(id) = stop.precedes.as_ref().and_then(|precedes| precedes.first()) {
let next_index = *stop_map.get(id.as_str()).expect("stop precedes not found");
if plan_unit_set.contains(&next_index) {
panic!("stop {} is already part of a plan unit", id);
Expand All @@ -87,14 +94,18 @@ impl From<Input> for Model {
index,
stops: vehicle
.initial_stops
.iter()
.map(|stop| {
let stop_index = *stop_map
.get(stop.id.as_str())
.expect("initial stop not found in stops");
stops_vec[stop_index].clone()
.as_ref()
.map(|it| {
it.iter()
.map(|stop| {
let stop_index = *stop_map
.get(stop.id.as_str())
.expect("initial stop not found in stops");
stops_vec[stop_index].clone()
})
.collect()
})
.collect(),
.unwrap_or(Vec::new()),
})
.collect(),
);
Expand Down Expand Up @@ -187,9 +198,14 @@ impl Vehicles {
fn new() -> Self {
Self(Vec::new())
}

// TODO
pub fn iter(&self) -> impl Iterator<Item = &Vehicle> {
self.0.iter()
}
}

struct Vehicle {
pub struct Vehicle {
id: Id,
index: Index,
stops: Vec<Stop>,
Expand All @@ -200,17 +216,21 @@ impl Vehicle {
&self.id
}

fn index(&self) -> Index {
pub fn index(&self) -> Index {
self.index
}

fn stops(&self) -> &Vec<Stop> {
pub fn stops(&self) -> &Vec<Stop> {
&self.stops
}

fn push_stop(&mut self, stop: Stop) {
self.stops.push(stop);
}

pub fn is_empty(&self) -> bool {
self.stops.is_empty()
}
}

struct VehicleType {
Expand Down
4 changes: 2 additions & 2 deletions crates/solver-vrp/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub struct Input {

pub struct Stop {
pub id: Id,
pub precedes: Vec<Id>,
pub precedes: Option<Vec<Id>>,
pub quantity: HashMap<String, f64>,
pub start_time_windows: [u64; 2],
pub location: Location,
Expand All @@ -26,7 +26,7 @@ pub struct Vehicle {
pub id: Id,
pub capacity: HashMap<String, f64>,
pub speed: f64,
pub initial_stops: Vec<InitialStop>,
pub initial_stops: Option<Vec<InitialStop>>,
}

pub struct InitialStop {
Expand Down
58 changes: 57 additions & 1 deletion crates/solver-vrp/src/solution.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,53 @@
use std::collections::HashMap;

use crate::{Index, model};
use crate::{
Index,
model::{self, Model},
};
use model::{PlanUnit as ModelPlanUnit, Stop as ModelStop};

pub struct Solution {
value: f64,
vehicles: Vehicles,
planned_plan_units: PlanUnitsCollection,
unplanned_plan_units: PlanUnitsCollection,
}

impl Solution {
pub fn new(model: &Model) -> Self {
let mut planned_plan_units = PlanUnitsCollection::new();
let mut unplanned_plan_units = PlanUnitsCollection::new();

let mut solution = Self {
value: 0.,
vehicles: Vehicles(
model
.vehicles()
.iter()
.filter(|vehicle| !vehicle.is_empty())
.map(|vehicle| {
for stop in vehicle.stops() {
// TODO: Naive solution for now.
todo!("pull planned and unplanned plan units from model")
}

Vehicle {
index: vehicle.index(),
}
})
.collect(),
),
planned_plan_units,
unplanned_plan_units,
};

solution
}

pub fn value(&self) -> f64 {
self.value
}

fn vehicles(&self) -> &Vehicles {
&self.vehicles
}
Expand Down Expand Up @@ -42,6 +80,13 @@ impl Solution {

struct Vehicles(Vec<Vehicle>);

impl Vehicles {
// TODO
pub fn iter(&self) -> impl Iterator<Item = &Vehicle> {
self.0.iter()
}
}

struct Vehicle {
index: Index,
}
Expand All @@ -54,6 +99,13 @@ struct PlanUnitsCollection {
type ModelIndex = Index;

impl PlanUnitsCollection {
fn new() -> Self {
Self {
indices: HashMap::new(),
plan_units: PlanUnits::new(),
}
}

fn plan_unit_index(&self, model_plan_unit: &ModelPlanUnit) -> Option<&Index> {
self.indices.get(model_plan_unit.index())
}
Expand All @@ -68,6 +120,10 @@ impl PlanUnitsCollection {
struct PlanUnits(Vec<PlanUnit>);

impl PlanUnits {
fn new() -> Self {
Self(Vec::new())
}

fn get(&self, index: Index) -> Option<&PlanUnit> {
self.0.get(index)
}
Expand Down

0 comments on commit 63900ad

Please sign in to comment.