Skip to content

Commit

Permalink
streamlined how instance variants are handled (strip & bin packing)
Browse files Browse the repository at this point in the history
  • Loading branch information
JeroenGar committed Feb 10, 2024
1 parent 892aeda commit 133a236
Show file tree
Hide file tree
Showing 14 changed files with 203 additions and 177 deletions.
96 changes: 59 additions & 37 deletions jaguars/src/entities/instance.rs
Original file line number Diff line number Diff line change
@@ -1,63 +1,85 @@
use enum_dispatch::enum_dispatch;
use crate::entities::bin::Bin;
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 {
#[derive(Debug, Clone)]
#[enum_dispatch]
pub enum Instance {
SP(SPInstance),
BP(BPInstance),
}

#[enum_dispatch(Instance)]
pub trait InstanceVariant {
fn items(&self) -> &[(Item, usize)];
fn item_qty(&self, id: usize) -> usize{
self.items()[id].1
}
fn item(&self, id: usize) -> &Item {
&self.items()[id].0
}
fn total_item_qty(&self) -> usize{
self.items().iter().map(|(_, qty)| qty).sum()
}

fn item_area(&self) -> f64;
}


#[derive(Debug, Clone)]
pub struct BPInstance {
/// Items to be packed in the instance, along with their requested quantities
items: Vec<(Item, usize)>,
pub items: Vec<(Item, usize)>,
/// Total area of all items in the instance
item_area: f64,
packing_type: PackingType,
pub item_area: f64,

pub bins: Vec<(Bin, usize)>,
}

impl Instance {
pub fn new(items: Vec<(Item, usize)>, packing_type: PackingType) -> Instance {
assert!(assertions::instance_item_bin_ids_correct(&items, &packing_type));
#[derive(Debug, Clone)]
pub struct SPInstance {
pub items: Vec<(Item, usize)>,
pub item_area: f64,
pub strip_height: f64,
}

let item_area = items.iter().map(|(item, qty)| item.shape().area() * *qty as f64).sum();
impl BPInstance {
pub fn new(items: Vec<(Item, usize)>, bins: Vec<(Bin, usize)>) -> Self {
assert!(assertions::instance_item_bin_ids_correct(&items, &bins));

Instance { items, item_area, packing_type }
}
let item_area = items.iter().map(|(item, qty)| item.shape().area() * *qty as f64).sum();

pub fn bin(&self, id: usize) -> &Bin {
match &self.packing_type {
PackingType::BinPacking(bins) => &bins[id].0,
PackingType::StripPacking { .. } => panic!("Instance is not a bin packing instance"),
}
Self { items, item_area, bins }
}
}

pub fn items(&self) -> &Vec<(Item, usize)> {
&self.items
}
impl SPInstance {
pub fn new(items: Vec<(Item, usize)>, strip_height: f64) -> Self {
let item_area = items.iter().map(|(item, qty)| item.shape().area() * *qty as f64).sum();

pub fn item_qty(&self, id: usize) -> usize {
self.items[id].1
Self { items, item_area, strip_height }
}
}

pub fn item(&self, id: usize) -> &Item {
&self.items[id].0
impl InstanceVariant for BPInstance {
fn items(&self) -> &[(Item, usize)] {
&self.items
}

pub fn total_item_qty(&self) -> usize {
self.items.iter().map(|(_, qty)| qty).sum()
fn item_area(&self) -> f64 {
self.item_area
}
}

pub fn packing_type(&self) -> &PackingType {
&self.packing_type
impl InstanceVariant for SPInstance {
fn items(&self) -> &[(Item, usize)] {
&self.items
}

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


//TODO: clean this up
#[derive(Debug, Clone)]
pub enum PackingType {
BinPacking(Vec<(Bin, usize)>),
StripPacking { height: f64 },
}
}
6 changes: 3 additions & 3 deletions jaguars/src/entities/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ impl Layout {
}
}

pub fn new_from_stored(id: usize, layout_snapshot: &LayoutSnapshot, instance: &Instance) -> Self {
pub fn new_from_stored(id: usize, layout_snapshot: &LayoutSnapshot) -> Self {
let mut layout = Layout::new(id, layout_snapshot.bin.clone());
layout.restore(&layout_snapshot, instance);
layout.restore(&layout_snapshot);
layout
}

Expand All @@ -45,7 +45,7 @@ impl Layout {
}
}

pub fn restore(&mut self, layout_snapshot: &LayoutSnapshot, _instance: &Instance) {
pub fn restore(&mut self, layout_snapshot: &LayoutSnapshot) {
assert_eq!(self.bin.id(), layout_snapshot.bin.id());

self.placed_items = layout_snapshot.placed_items.clone();
Expand Down
80 changes: 41 additions & 39 deletions jaguars/src/entities/problems/bin_packing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ use std::sync::Arc;

use itertools::Itertools;

use crate::entities::placing_option::PlacingOption;
use crate::entities::instance::{Instance, PackingType};
use crate::entities::instance::{BPInstance, Instance};
use crate::entities::instance::InstanceVariant;
use crate::entities::layout::Layout;
use crate::entities::placed_item::PlacedItemUID;
use crate::entities::placing_option::PlacingOption;
use crate::entities::problems::problem::{LayoutIndex, ProblemVariant};
use crate::entities::problems::problem::private::ProblemVariantPrivate;
use crate::entities::solution::Solution;
Expand All @@ -15,7 +16,7 @@ use crate::util::assertions;
/// Bin Packing Problem
#[derive(Clone)]
pub struct BPProblem {
instance: Arc<Instance>,
instance: BPInstance,
layouts: Vec<Layout>,
empty_layouts: Vec<Layout>,
missing_item_qtys: Vec<isize>,
Expand All @@ -28,34 +29,29 @@ pub struct BPProblem {
}

impl BPProblem {
pub fn new(instance: Arc<Instance>) -> Self {
match instance.packing_type() {
PackingType::StripPacking { .. } => panic!("cannot create BinPackingProblem from strip packing instance"),
PackingType::BinPacking(bins) => {
let missing_item_qtys = instance.items().iter().map(|(_, qty)| *qty as isize).collect_vec();
let bin_qtys = bins.iter().map(|(_, qty)| *qty).collect_vec();
let layouts = vec![];
let empty_layouts = bins.iter().enumerate().map(|(i, (bin, _))| {
Layout::new(i, bin.clone())
}).collect_vec();
let layout_id_counter = empty_layouts.len();
let unchanged_layouts = vec![];
let unchanged_layouts_solution_id = None;
let uncommitted_removed_layouts = vec![];

Self {
instance,
layouts,
empty_layouts,
missing_item_qtys,
bin_qtys,
layout_id_counter,
solution_id_counter: 0,
unchanged_layouts,
unchanged_layouts_solution_id,
uncommitted_removed_layouts,
}
}
pub fn new(instance: BPInstance) -> Self {
let missing_item_qtys = instance.items.iter().map(|(_, qty)| *qty as isize).collect_vec();
let bin_qtys = instance.bins.iter().map(|(_, qty)| *qty).collect_vec();
let layouts = vec![];
let empty_layouts = instance.bins.iter().enumerate().map(|(i, (bin, _))| {
Layout::new(i, bin.clone())
}).collect_vec();
let layout_id_counter = empty_layouts.len();
let unchanged_layouts = vec![];
let unchanged_layouts_solution_id = None;
let uncommitted_removed_layouts = vec![];

Self {
instance,
layouts,
empty_layouts,
missing_item_qtys,
bin_qtys,
layout_id_counter,
solution_id_counter: 0,
unchanged_layouts,
unchanged_layouts_solution_id,
uncommitted_removed_layouts,
}
}

Expand Down Expand Up @@ -112,6 +108,10 @@ impl BPProblem {
self.unchanged_layouts.remove(index);
}
}

fn instance(&self) -> &BPInstance {
&self.instance
}
}

impl ProblemVariant for BPProblem {
Expand Down Expand Up @@ -200,7 +200,7 @@ impl ProblemVariant for BPProblem {
}
false => {
//layout was changed, needs to be restored
layout.restore(&solution.layout_snapshots[i], &self.instance);
layout.restore(&solution.layout_snapshots[i]);
}
}
layout_ids_in_problem.insert(layout.id());
Expand All @@ -221,12 +221,12 @@ impl ProblemVariant for BPProblem {
Some(i) => {
//original layout is still present, restore it and add it to the problem
let mut layout = self.uncommitted_removed_layouts.swap_remove(i);
layout.restore(sl, &self.instance());
layout.restore(sl);
self.layouts.push(layout);
}
None => {
//If not, the layout will have to be rebuilt from scratch
let layout = Layout::new_from_stored(sl.id(), sl, &self.instance());
let layout = Layout::new_from_stored(sl.id(), sl);
self.layouts.push(layout);
}
}
Expand All @@ -237,7 +237,7 @@ impl ProblemVariant for BPProblem {
//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() {
let layout = Layout::new_from_stored(sl.id(), sl, &self.instance());
let layout = Layout::new_from_stored(sl.id(), sl);
self.layouts.push(layout);
}
}
Expand All @@ -254,10 +254,6 @@ impl ProblemVariant for BPProblem {
debug_assert!(assertions::problem_matches_solution(self, solution));
}

fn instance(&self) -> &Arc<Instance> {
&self.instance
}

fn layouts(&self) -> &[Layout] {
&self.layouts
}
Expand All @@ -274,6 +270,12 @@ impl ProblemVariant for BPProblem {
&self.missing_item_qtys
}

fn included_item_qtys(&self) -> Vec<usize> {
(0..self.missing_item_qtys().len())
.map(|i| (self.instance.item_qty(i) as isize - self.missing_item_qtys()[i]) as usize)
.collect_vec()
}

fn bin_qtys(&self) -> &[usize] {
&self.bin_qtys
}
Expand Down
9 changes: 2 additions & 7 deletions jaguars/src/entities/problems/problem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use itertools::Itertools;

use crate::entities::placing_option::PlacingOption;
use crate::entities::instance::Instance;
use crate::entities::instance::InstanceVariant;
use crate::entities::layout::Layout;
use crate::entities::placed_item::PlacedItemUID;
use crate::entities::problems::bin_packing::BPProblem;
Expand Down Expand Up @@ -45,8 +46,6 @@ pub trait ProblemVariant: ProblemVariantPrivate {
/// 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];

Expand Down Expand Up @@ -74,11 +73,7 @@ pub trait ProblemVariant: ProblemVariantPrivate {
self.layouts().iter().map(|l| l.bin().value()).sum()
}

fn included_item_qtys(&self) -> Vec<usize> {
(0..self.missing_item_qtys().len())
.map(|i| (self.instance().item_qty(i) as isize - self.missing_item_qtys()[i]) as usize)
.collect_vec()
}
fn included_item_qtys(&self) -> Vec<usize>;

fn empty_layout_has_stock(&self, index: usize) -> bool {
let bin_id = self.empty_layouts()[index].bin().id();
Expand Down
Loading

0 comments on commit 133a236

Please sign in to comment.