Skip to content

Commit

Permalink
changes to the JSON solution format + extra docs
Browse files Browse the repository at this point in the history
  • Loading branch information
JeroenGar committed Feb 19, 2024
1 parent 0ae2f40 commit 5c61cd3
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 23 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ These problems typically contain two challenges:
This allows for the separation of concerns and the development of optimization algorithms that can focus on the combinatorial challenge, while `jagua-rs` handles the geometric challenge.
Thereby, lowering the barrier to entry for researchers and practitioners to develop and test new optimization algorithms and enable independent improvements in the geometric challenge.

## Contents of the repository
## Contents

### Jagua-rs
The **[`jagua-rs`](jaguars)** crate contains everything necessary to solve 2D irregular cutting and packing problems without the combinatorial decision-making (i.e. which items to place where). It provides all necessary entities and components to create a dynamic model of a 2D irregular C&P instance and provide a collision detection engine to check the feasibility of a placement.
Expand Down
26 changes: 24 additions & 2 deletions jaguars/src/io/json_instance.rs
Original file line number Diff line number Diff line change
@@ -1,66 +1,88 @@
use serde::{Deserialize, Serialize};

/// The JSON representation of a problem instance
#[derive(Serialize, Deserialize, Clone)]
pub struct JsonInstance {
#[serde(rename = "Name")]
/// The name of the instance
pub name: String,
/// Set of items to be produced
#[serde(rename = "Items")]
pub items: Vec<JsonItem>,
/// Set of bins where the items are to be placed (for Bin Packing problems)
#[serde(rename = "Objects")]
#[serde(skip_serializing_if = "Option::is_none")]
pub bins: Option<Vec<JsonBin>>,
/// A strip where the items are to be placed (for Strip Packing problems)
#[serde(rename = "Strip")]
#[serde(skip_serializing_if = "Option::is_none")]
pub strip: Option<JsonStrip>,
}

/// The JSON representation of a bin
#[derive(Serialize, Deserialize, Clone)]
#[serde(rename_all = "PascalCase")]
pub struct JsonBin {
/// The cost of using this bin
pub cost: u64,
/// Number of this bin available
pub stock: u64,
/// Polygon shape of the bin
pub shape: JsonPoly,
/// A list of zones with different quality levels
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub zones: Vec<JsonQualityZone>,
}

/// The JSON representation of a strip
#[derive(Serialize, Deserialize, Clone)]
#[serde(rename_all = "PascalCase")]
pub struct JsonStrip {
pub height: f64,
}

/// The JSON representation of an item
#[derive(Serialize, Deserialize, Clone)]
#[serde(rename_all = "PascalCase")]
pub struct JsonItem {
/// Number of times this item should be produced
pub demand: u64,
/// List of allowed orientations angles (in degrees).
/// If Some(), only the specified angles are allowed
/// If None, continuous rotation is allowed
/// Some(_) if only the specified angles are allowed; None if continuous rotation is allowed
#[serde(skip_serializing_if = "Option::is_none")]
pub allowed_orientations: Option<Vec<f64>>,
/// Polygon shape of the item
pub shape: JsonPoly,
/// A list of zones with different quality requirements
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub zones: Vec<JsonQualityZone>,
/// The value of the item (for knapsack problems)
pub value: Option<u64>,
/// The quality required for the entire item
pub base_quality: Option<usize>,
}

/// A polygon represented as an outer boundary and a list of holes
#[derive(Serialize, Deserialize, Clone)]
#[serde(rename_all = "PascalCase")]
pub struct JsonPoly {
/// The outer boundary of the polygon
pub outer: JsonSimplePoly,
/// A list of holes in the polygon (if any)
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub inner: Vec<JsonSimplePoly>,
}

/// A simple polygon represented as a list of points (x, y)
#[derive(Serialize, Deserialize, Clone)]
pub struct JsonSimplePoly(pub Vec<(f64, f64)>);

/// A zone with a specific quality level
#[derive(Serialize, Deserialize, Clone)]
#[serde(rename_all = "PascalCase")]
pub struct JsonQualityZone {
/// The quality level of this zone
pub quality: usize,
/// The polygon shape of this zone
pub shape: JsonPoly,
}
36 changes: 30 additions & 6 deletions jaguars/src/io/json_solution.rs
Original file line number Diff line number Diff line change
@@ -1,49 +1,73 @@
use serde::{Deserialize, Serialize};

/// Representation of a solution
#[derive(Serialize, Deserialize, Clone)]
#[serde(rename_all = "PascalCase")]
pub struct JsonSolution {
/// Sum of the area of the produced items divided by the sum of the area of the containers
pub usage: f64,
/// The time it took to generate the solution in seconds
pub run_time_sec: u64,
/// Layouts which compose the solution
pub layouts: Vec<JsonLayout>,
}

/// Representation how a set of items are placed in a certain container
#[derive(Serialize, Deserialize, Clone)]
#[serde(rename_all = "PascalCase")]
pub struct JsonLayout {
pub object_type: JsonObjectType,
/// The container that was used
pub container: JsonContainer,
/// The items placed in the container and where they were placed
pub placed_items: Vec<JsonPlacedItem>,
/// Some statistics about the layout
pub statistics: JsonLayoutStats,
}

/// Represents an item placed in a container
#[derive(Serialize, Deserialize, Clone)]
#[serde(rename_all = "PascalCase")]
pub struct JsonPlacedItem {
pub item_index: usize,
/// The index of the item in the instance
pub index: usize,
/// The transformation applied to the item to place it in the container
pub transformation: JsonTransformation,
}

/// Represents a proper rigid transformation defined as a rotation followed by translation
#[derive(Serialize, Deserialize, Clone)]
#[serde(rename_all = "PascalCase")]
pub struct JsonTransformation {
/// The rotation angle in radians
pub rotation: f64,
/// The translation vector (x, y)
pub translation: (f64, f64),
}

/// Some statistics about the layout
#[derive(Serialize, Deserialize, Clone)]
#[serde(rename_all = "PascalCase")]
pub struct JsonLayoutStats {
//
pub usage: f64,
/// The percentage of the container that is packed with items
pub usage: f64
}

/// Type of container that was used
#[derive(Serialize, Deserialize, Clone)]
#[serde(rename_all = "PascalCase")]
pub enum JsonObjectType {
Object { id: usize },
#[serde(tag = "Type", content = "Params")]
pub enum JsonContainer {
Bin {
/// The index of the object in the instance
#[serde(rename = "Index")]
index: usize
},
Strip {
/// The length of the strip (variable)
#[serde(rename = "Length")]
width: f64,
/// The height of the strip (fixed)
#[serde(rename = "Height")]
height: f64,
},
}
28 changes: 14 additions & 14 deletions jaguars/src/io/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::geometry::primitives::point::Point;
use crate::geometry::primitives::simple_polygon::SimplePolygon;
use crate::geometry::transformation::Transformation;
use crate::io::json_instance::{JsonInstance, JsonPoly, JsonSimplePoly};
use crate::io::json_solution::{JsonLayout, JsonLayoutStats, JsonObjectType, JsonPlacedItem, JsonSolution, JsonTransformation};
use crate::io::json_solution::{JsonLayout, JsonLayoutStats, JsonContainer, JsonPlacedItem, JsonSolution, JsonTransformation};
use crate::util::config::CDEConfig;
use crate::util::polygon_simplification;
use crate::util::polygon_simplification::{PolySimplConfig, PolySimplMode};
Expand Down Expand Up @@ -177,19 +177,19 @@ fn build_solution_from_json(json_layouts: &[JsonLayout], instance: Arc<Instance>
Instance::BP(bp_i) => Problem::BP(BPProblem::new(bp_i.clone())),
Instance::SP(sp_i) => {
assert_eq!(json_layouts.len(), 1);
match json_layouts[0].object_type {
JsonObjectType::Object { .. } => panic!("Strip packing solution should not contain layouts with references to an Object"),
JsonObjectType::Strip { width, height: _ } => {
match json_layouts[0].container {
JsonContainer::Bin { .. } => panic!("Strip packing solution should not contain layouts with references to an Object"),
JsonContainer::Strip { width, height: _ } => {
Problem::SP(SPProblem::new(sp_i.clone(), width, cde_config))
}
}
}
};

for json_layout in json_layouts {
let bin = match (instance.as_ref(), &json_layout.object_type) {
(Instance::BP(bpi), JsonObjectType::Object { id }) => Some(&bpi.bins[*id].0),
(Instance::SP(_spi), JsonObjectType::Strip { .. }) => None,
let bin = match (instance.as_ref(), &json_layout.container) {
(Instance::BP(bpi), JsonContainer::Bin { index }) => Some(&bpi.bins[*index].0),
(Instance::SP(_spi), JsonContainer::Strip { .. }) => None,
_ => panic!("Layout object type does not match packing type")
};
//Create the layout by inserting the first item
Expand All @@ -201,7 +201,7 @@ fn build_solution_from_json(json_layouts: &[JsonLayout], instance: Arc<Instance>
let bin_centering = bin.map_or(DTransformation::empty(), |b| DTransformation::from(&b.centering_transform)).translation();

let json_first_item = json_layout.placed_items.get(0).unwrap();
let first_item = instance.item(json_first_item.item_index);
let first_item = instance.item(json_first_item.index);

//all items have a centering transformation applied during parsing.
//However, the transformation described in the JSON solution is relative to the item's original position, not the one after the centering transformation
Expand Down Expand Up @@ -229,7 +229,7 @@ fn build_solution_from_json(json_layouts: &[JsonLayout], instance: Arc<Instance>

//Insert the rest of the items
for json_item in json_layout.placed_items.iter().skip(1) {
let item = instance.item(json_item.item_index);
let item = instance.item(json_item.index);
let item_centering_correction = item.centering_transform.clone().inverse().decompose().translation();
let transf = Transformation::empty()
.translate(item_centering_correction)
Expand All @@ -256,9 +256,9 @@ fn build_solution_from_json(json_layouts: &[JsonLayout], instance: Arc<Instance>
pub fn compose_json_solution(solution: &Solution, instance: &Instance, epoch: Instant) -> JsonSolution {
let layouts = solution.layout_snapshots.iter()
.map(|sl| {
let object_type = match &instance {
Instance::BP(_bpi)=> JsonObjectType::Object { id: sl.bin.id },
Instance::SP(spi) => JsonObjectType::Strip { width: sl.bin.bbox().width(), height: spi.strip_height },
let container = match &instance {
Instance::BP(_bpi)=> JsonContainer::Bin { index: sl.bin.id },
Instance::SP(spi) => JsonContainer::Strip { width: sl.bin.bbox().width(), height: spi.strip_height },
};
//JSON solution should have their bins back in their original position, so we need to correct for the centering transformation
let bin_centering_correction = match &instance {
Expand Down Expand Up @@ -291,15 +291,15 @@ pub fn compose_json_solution(solution: &Solution, instance: &Instance, epoch: In
translation: decomp_transf.translation(),
};
JsonPlacedItem {
item_index,
index: item_index,
transformation: json_transform,
}
}).collect::<Vec<JsonPlacedItem>>();
let statistics = JsonLayoutStats {
usage: sl.usage,
};
JsonLayout {
object_type,
container,
placed_items,
statistics,
}
Expand Down

0 comments on commit 5c61cd3

Please sign in to comment.