Skip to content

Commit

Permalink
improved documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
JeroenGar committed Feb 9, 2024
1 parent 2c7b7a4 commit c9965c6
Show file tree
Hide file tree
Showing 17 changed files with 113 additions and 103 deletions.
3 changes: 3 additions & 0 deletions jaguars/src/entities/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::entities::item::Item;
use crate::geometry::geo_traits::Shape;
use crate::util::assertions;

/// Static representation of a problem instance.
#[derive(Debug)]
pub struct Instance {
items: Vec<(Item, usize)>,
Expand Down Expand Up @@ -51,6 +52,8 @@ impl Instance {
}
}


//TODO: clean this up
#[derive(Debug, Clone)]
pub enum PackingType {
BinPacking(Vec<(Bin, usize)>),
Expand Down
3 changes: 3 additions & 0 deletions jaguars/src/entities/placed_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ use crate::geometry::d_transformation::DTransformation;
use crate::geometry::geo_traits::Transformable;
use crate::geometry::primitives::simple_polygon::SimplePolygon;

/// Represents an `Item` that has been placed in a `Layout`
#[derive(Clone, Debug)]
pub struct PlacedItem {
/// Unique identifier for the placed item
pi_uid: PlacedItemUID,
qz_haz_filter: Option<QZHazardFilter>,
/// The shape of the `Item` after it has been transformed and placed in a `Layout`
shape: Arc<SimplePolygon>,
}

Expand Down
2 changes: 1 addition & 1 deletion jaguars/src/entities/placing_option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::geometry::d_transformation::DTransformation;
use crate::geometry::transformation::Transformation;

#[derive(Clone, Debug)]
/// Represents a (valid) configuration of placing an item in a layout
/// Contains information about how an `Item` with a `Transformation` applied can be placed in a `Layout`
pub struct PlacingOption {
pub layout_index: LayoutIndex,
pub item_id: usize,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::entities::problems::problem::private::ProblemPrivate;
use crate::entities::solution::Solution;
use crate::util::assertions;

/// Bin Packing Problem
#[derive(Clone)]
pub struct BPProblem {
instance: Arc<Instance>,
Expand Down Expand Up @@ -114,7 +115,7 @@ impl BPProblem {
}

impl Problem for BPProblem {
fn insert_item(&mut self, i_opt: &PlacingOption) {
fn place_item(&mut self, i_opt: &PlacingOption) {
let item_id = i_opt.item_id;
let layout = match &i_opt.layout_index {
LayoutIndex::Existing(i) => {
Expand Down Expand Up @@ -158,10 +159,10 @@ impl Problem for BPProblem {
let bin_qtys = self.bin_qtys().to_vec();
let layout_snapshots = match old_solution {
Some(old_solution) => {
assert_eq!(old_solution.id(), self.unchanged_layouts_solution_id.unwrap());
assert_eq!(old_solution.id, self.unchanged_layouts_solution_id.unwrap());
self.layouts.iter_mut().map(|l| {
match self.unchanged_layouts.contains(&l.id()) {
true => old_solution.layout_snapshots().iter().find(|sl| sl.id() == l.id()).unwrap().clone(),
true => old_solution.layout_snapshots.iter().find(|sl| sl.id() == l.id()).unwrap().clone(),
false => l.create_layout_snapshot()
}
}).collect()
Expand All @@ -176,21 +177,21 @@ impl Problem for BPProblem {
let solution = Solution::new(id, layout_snapshots, self.usage(), included_item_qtys, target_item_qtys, bin_qtys);

debug_assert!(assertions::problem_matches_solution(self, &solution));
self.reset_unchanged_layouts(solution.id());
self.reset_unchanged_layouts(solution.id);

solution
}

fn restore_to_solution(&mut self, solution: &Solution) {
match self.unchanged_layouts_solution_id == Some(solution.id()) {
match self.unchanged_layouts_solution_id == Some(solution.id) {
true => {
//A partial restore is possible.
//TODO: hashset here is probably slower than just using a (sorted) vector
let mut layout_ids_in_problem = HashSet::new();
let mut layout_ids_not_in_solution = vec![];
for layout in self.layouts.iter_mut() {
//For all layouts in the problem, check which ones occur in the solution
match solution.layout_snapshots().iter().position(|sl| sl.id() == layout.id()) {
match solution.layout_snapshots.iter().position(|sl| sl.id() == layout.id()) {
Some(i) => {
//layout is present in the solution
match self.unchanged_layouts.contains(&layout.id()) {
Expand All @@ -199,7 +200,7 @@ impl Problem for BPProblem {
}
false => {
//layout was changed, needs to be restored
layout.restore(&solution.layout_snapshots()[i], &self.instance);
layout.restore(&solution.layout_snapshots[i], &self.instance);
}
}
layout_ids_in_problem.insert(layout.id());
Expand All @@ -213,7 +214,7 @@ impl Problem for BPProblem {
layout_ids_not_in_solution.iter().for_each(|id| { self.layouts.retain(|l| l.id() != *id); });

//Some layouts are present in the solution, but not in the problem
for sl in solution.layout_snapshots().iter() {
for sl in solution.layout_snapshots.iter() {
if !layout_ids_in_problem.contains(&sl.id()) {
//It is possible they are in the uncommitted_removed_layouts
match self.uncommitted_removed_layouts.iter().position(|l| l.id() == sl.id()) {
Expand All @@ -235,20 +236,20 @@ impl Problem for BPProblem {
false => {
//The id of the solution does not match unchanged_layouts_solution_id, a partial restore is not possible
self.layouts.clear();
for sl in solution.layout_snapshots().iter() {
for sl in solution.layout_snapshots.iter() {
let layout = Layout::new_from_stored(sl.id(), sl, &self.instance());
self.layouts.push(layout);
}
}
}

self.missing_item_qtys.iter_mut().enumerate().for_each(|(i, qty)| {
*qty = (self.instance.item_qty(i) - solution.placed_item_qtys()[i]) as isize
*qty = (self.instance.item_qty(i) - solution.placed_item_qtys[i]) as isize
});
self.bin_qtys.clone_from_slice(solution.bin_qtys());
self.bin_qtys.clone_from_slice(&solution.bin_qtys);
self.uncommitted_removed_layouts.clear();

self.reset_unchanged_layouts(solution.id());
self.reset_unchanged_layouts(solution.id);

debug_assert!(assertions::problem_matches_solution(self, solution));
}
Expand Down
4 changes: 2 additions & 2 deletions jaguars/src/entities/problems/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
pub mod problem;
pub mod bp_problem;
pub mod sp_problem;
pub mod bin_packing;
pub mod strip_packing;
39 changes: 29 additions & 10 deletions jaguars/src/entities/problems/problem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,45 @@ use crate::entities::placing_option::PlacingOption;
use crate::entities::instance::Instance;
use crate::entities::layout::Layout;
use crate::entities::placed_item::PlacedItemUID;
use crate::entities::problems::bp_problem::BPProblem;
use crate::entities::problems::bin_packing::BPProblem;
use crate::entities::problems::problem::private::ProblemPrivate;
use crate::entities::problems::sp_problem::SPProblem;
use crate::entities::problems::strip_packing::SPProblem;
use crate::entities::solution::Solution;

#[enum_dispatch]
/// Enum which contains all the different types implementing the Problem trait.
/// Uses the enum_dispatch crate to have performant polymorphism for different problem types, see
/// <https://docs.rs/enum_dispatch/latest/enum_dispatch/> for more information on enum_dispatch
#[derive(Clone)]
pub enum ProblemEnum {
BPProblem, //Bin Packing Problem
SPProblem, //Strip Packing Problem
#[enum_dispatch]
pub enum ProblemType {
/// Bin Packing Problem
BP(BPProblem),
/// Strip Packing Problem
SP(SPProblem),
}

#[enum_dispatch(ProblemEnum)]
/// Trait for public shared functionality of all problem types.
/// A `Problem` represents a problem instance in a modifiable state.
/// It can insert or remove items, create a snapshot from the current state called a `Solution`,
/// and restore its state to a previous `Solution`.
#[enum_dispatch(ProblemType)]
pub trait Problem: ProblemPrivate {
fn insert_item(&mut self, i_opt: &PlacingOption);

/// Places an item into the problem instance according to the given `PlacingOption`.
fn place_item(&mut self, i_opt: &PlacingOption);

/// Removes an item with a specific `PlacedItemUID` from a specific `Layout`
fn remove_item(&mut self, layout_index: LayoutIndex, pi_uid: &PlacedItemUID);

/// Saves the current state into a `Solution`.
fn create_solution(&mut self, old_solution: &Option<Solution>) -> Solution;

/// Restores the state of the problem to a previous `Solution`.
fn restore_to_solution(&mut self, solution: &Solution);

fn instance(&self) -> &Arc<Instance>;

/// Returns the layouts of the problem instance, with at least one item placed in them.
fn layouts(&self) -> &[Layout];

fn layouts_mut(&mut self) -> &mut [Layout];
Expand Down Expand Up @@ -91,9 +106,10 @@ pub trait Problem: ProblemPrivate {

pub(super) mod private {
use enum_dispatch::enum_dispatch;
use crate::entities::problems::problem::ProblemEnum;
use crate::entities::problems::problem::ProblemType;

#[enum_dispatch(ProblemEnum)]
/// Trait for shared functionality of all problem types, but not exposed to the public.
#[enum_dispatch(ProblemType)]
pub trait ProblemPrivate : Clone {
fn next_solution_id(&mut self) -> usize;

Expand All @@ -111,7 +127,10 @@ pub(super) mod private {


#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
/// Unique identifier for a layout in a problem instance.
pub enum LayoutIndex {
/// Existing layout (at least one item) and its index in the `Problem`'s `layouts` vector.
Existing(usize),
/// Empty layout (no items) and its index in the `Problem`'s `empty_layouts` vector.
Empty(usize),
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use crate::geometry::geo_traits::{Shape, Transformable};
use crate::util::assertions;
use crate::util::config::CDEConfig;

/// Strip Packing Problem
#[derive(Clone)]
pub struct SPProblem {
instance: Arc<Instance>,
Expand Down Expand Up @@ -70,7 +71,7 @@ impl SPProblem {
transf,
d_transf: p_uid.d_transf.clone(),
};
self.insert_item(&insert_opt);
self.place_item(&insert_opt);
}
}
}
Expand Down Expand Up @@ -103,7 +104,7 @@ impl SPProblem {
}

impl Problem for SPProblem {
fn insert_item(&mut self, i_opt: &PlacingOption) {
fn place_item(&mut self, i_opt: &PlacingOption) {
assert_eq!(i_opt.layout_index, LayoutIndex::Existing(0), "strip packing problems only have a single layout");
let item_id = i_opt.item_id;
let item = self.instance.item(item_id);
Expand Down Expand Up @@ -133,10 +134,10 @@ impl Problem for SPProblem {
}

fn restore_to_solution(&mut self, solution: &Solution) {
debug_assert!(solution.layout_snapshots().len() == 1);
self.layout.restore(&solution.layout_snapshots()[0], &self.instance);
debug_assert!(solution.layout_snapshots.len() == 1);
self.layout.restore(&solution.layout_snapshots[0], &self.instance);
self.missing_item_qtys.iter_mut().enumerate().for_each(|(i, qty)| {
*qty = (self.instance.item_qty(i) - solution.placed_item_qtys()[i]) as isize
*qty = (self.instance.item_qty(i) - solution.placed_item_qtys[i]) as isize
});

debug_assert!(assertions::problem_matches_solution(self, solution));
Expand Down
53 changes: 17 additions & 36 deletions jaguars/src/entities/solution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,24 @@ use crate::entities::instance::{Instance, PackingType};
use crate::entities::layout::LayoutSnapshot;
use crate::geometry::geo_traits::Shape;

//TODO: clean this up properly
/// Represents a snapshot of a `Problem` at a specific moment.
/// Solutions can be used to restore the state of a `Problem` to a previous state.
#[derive(Debug, Clone)]
pub struct Solution {
id: usize,
layout_snapshots: Vec<LayoutSnapshot>,
usage: f64,
placed_item_qtys: Vec<usize>,
target_item_qtys: Vec<usize>,
bin_qtys: Vec<usize>,
time_stamp: Instant,
/// Unique identifier for the solution
pub id: usize,
/// Snapshots of all `Layout`s in the `Problem` at the moment the solution was created
pub layout_snapshots: Vec<LayoutSnapshot>,
/// Average usage of bins in the solution
pub usage: f64,
/// Quantity of placed items for each `Item` in the solution
pub placed_item_qtys: Vec<usize>,
/// Target quantity of each `Item` in the solution
pub target_item_qtys: Vec<usize>,
/// Quantity of bins used for each type of bin
pub bin_qtys: Vec<usize>,
/// Instant the solution was created
pub time_stamp: Instant,
}

impl Solution {
Expand All @@ -31,10 +39,6 @@ impl Solution {
}
}

pub fn layout_snapshots(&self) -> &Vec<LayoutSnapshot> {
&self.layout_snapshots
}

pub fn is_complete(&self, instance: &Instance) -> bool {
self.placed_item_qtys.iter().enumerate().all(|(i, &qty)| qty >= instance.item_qty(i))
}
Expand All @@ -49,33 +53,14 @@ impl Solution {
completeness
}

pub fn id(&self) -> usize {
self.id
}

pub fn placed_item_qtys(&self) -> &Vec<usize> {
&self.placed_item_qtys
}

pub fn missing_item_qtys(&self, instance: &Instance) -> Vec<isize> {
debug_assert!(instance.items().len() == self.placed_item_qtys.len());
self.placed_item_qtys.iter().enumerate()
.map(|(i, &qty)| instance.item_qty(i) as isize - qty as isize)
.collect_vec()
}

pub fn bin_qtys(&self) -> &Vec<usize> {
&self.bin_qtys
}

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

pub fn target_item_qtys(&self) -> &Vec<usize> {
&self.target_item_qtys
}

//TODO: clean this up properly
pub fn is_best_possible(&self, instance: &Instance) -> bool {
match instance.packing_type() {
PackingType::StripPacking { .. } => false,
Expand All @@ -92,10 +77,6 @@ impl Solution {
}
}

pub fn time_stamp(&self) -> Instant {
self.time_stamp
}

pub fn n_items_placed(&self) -> usize {
self.placed_item_qtys.iter().sum()
}
Expand Down
2 changes: 2 additions & 0 deletions jaguars/src/geometry/d_transformation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ use crate::geometry::transformation::Transformation;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
/// A proper rigid transformation, decomposed into a rotation followed by a translation.
pub struct DTransformation {
/// The rotation in radians
pub rotation: NotNan<f64>,
/// The translation in the x and y-axis
pub translation: (NotNan<f64>, NotNan<f64>),
}

Expand Down
Loading

0 comments on commit c9965c6

Please sign in to comment.