Skip to main content

A fast trailer load optimization service provided by YAT, LLC

Project description

YTL - YAT Trailer Loading Package

Simple package for turning list of freight pieces into a trailer plan and associated metrics helpful for LTL (Less than Truckload) and Partial planning and pricing. The package includes an out-of-the-box trailer load optimization allowing for flexible trailer dimension options, allows or disallows stacking/rotating of pieces, and handling of overweight shipments/pieces. A detailed load plan is returned, as wells as several measurements like linear feet, actual volume, cubed volume, and effective trailer volume occupancy of the load plan.

The aim of the optimization is to load the provided shipments/pieces into a trailer of the specified dimensions with minimal linear foot occupancy of the trailer. The default configuration makes it easy to plug and play to use in your own Python development or in an internally hosted API (see accompanying yat-trailer-loading-api for a simple Python Flask implementation).

Beyond the standard out-of-the-box style implementation, the package is readily available for development of additional optimization algorithms. The optimization in this package is simulation-based, leveraging Python Classes that model Trailers, Shipments, and Pieces as well as the placement and movement of Pieces and Shipments within a Trailer. For more information on adding your own optimization, see additional details in the Simulation Model Description section below.

Install

pip install ytl

Usage

Setup

Import trailer optimization service (this version is intended to support an API)

from ytl import optimize_trailer_load_plan_wrapper

Specify shipment piece list (dimensions assumed to be in inches, weight in pounds). Packing type must be PALLET or BOX (pallets are not allowed to be stacked on boxes, even if the pieces involved allow stacking).

shipment_list = [
    {
        "length": 40,
        "width": 42,
        "height": 35,
        "weight": 225,
        "packing": "PALLET",
        "stack_limit": 2,
        "num_pieces": 5
    },
    {
        "length": 44,
        "width": 40,
        "height": 30,
        "weight": 200,
        "packing": "BOX",
        "stack_limit": 3,
        "num_pieces": 8
    }
]

Trailer Load Optimization with Pre-Defined Trailer Type

Define request data and call optimization function. This example sets the equipment type to a typical 53' dry-van trailer and allow shipment pieces to be rotated.

request_data = {
    'equipment_code' : 'DV_53',
    'shipment_list' : shipment_list,
    'allow_rotations' : True
}
status_code,response_data = optimize_trailer_load_plan_wrapper(request_data=request_data)

The status_code is intended to be the status associated to an API call and the response_data is the response body. You can interogate the response data for a large amount detail about the resulting optimization. Below are a few examples showing the linear feet occupied in the trailer and a detailed list of the load plan.

print('status: {}'.format(status_code))
print('linear feet: {:.1f} ({:.0f}% of Trailer)'.format(response_data.get('linear_feet'),100*response_data.get('linear_feet_portion_of_trailer')))

print('Load Plan')
print('-'*100)
print('-'*100)
print('{:34}{:19}{:21}{:11}{:20}{}'.format('Desc','Location','Size','Weight','Orientation','Packing'))
print('-'*100)
for k,v in response_data['load_order'].items():
    print(
        '{name:30}  {x:3.0f} x {y:3.0f} x {z:3.0f}   {l:3.0f}" x {w:3.0f}" x {h:3.0f}"  {weight:5,.0f} Lbs    {rotated:15}     {packing:12}'.format(
            name=v.get('name'),
            x=v.get('position')[0],
            y=v.get('position')[1],
            z=v.get('position')[2],
            l=v.get('piece_length'),
            w=v.get('piece_width'),
            h=v.get('piece_height'),
            weight=v.get('piece_weight'),
            rotated='Rotated' if v.get('piece_is_rotated') else 'Not Rotated',
            packing=v.get('piece_packing')
        )
    )

The options for predefined equipment types are available in ytl.STANDARD_TRAILER_DIMS. The code values are to be used in the optimization function. The inner length, inner width, inner hieght, and max weight attributes are availalbe there for additional information. The inner_height field for open top trailers is set to be the estimated maximum freight height for typical bridge clearances.

from ytl import STANDARD_TRAILER_DIMS
import json
print(json.dumps(STANDARD_TRAILER_DIMS,indent=2))

Trailer Load Optimization with Specified Trailer Dimensions

trailer_dims = {
    "inner_width": 98.5,
    "inner_length": 630,
    "inner_height": 108,
    "max_weight": 42500
}
request_data = {
    'trailer_dims' : trailer_dims,
    'shipment_list' : shipment_list,
    'allow_rotations' : False
}
status_code,response_data = optimize_trailer_load_plan_wrapper(request_data=request_data)

Trailer Load Optimization with Altered Optimization Parameters

You can alter the optimization as well by specifying router keys for the piece and shipment arrangement algorithms.

request_data = {
    'equipment_code' : 'DV_53',
    'shipment_list' : shipment_list,
    'allow_rotations' : True,
    'piece_arrangement_algorithm' : 'NAIVE',
    'shipment_optimization_ls' : [
        {
            'algorithm' : 'GREEDY_LOAD',
            'max_iter' : 5,
            'timeout' : 2.5,
        }
    ]
}
status_code,response_data = optimize_trailer_load_plan_wrapper(request_data=request_data)

The piece arrangement algorith is a single use optimization that arranges (potentially stacking) pieces into shipments. The shipment arrangement algorithm is iterative optimization that attempts to find the best way (*best meaning minimal linear feet occupied) of loading those shipments into the trailer. Since the shipment arrangement is an iterated optimization, you can provide a list of algorithm parameters to use. See ytl.optimizer_functions.PIECE_ARRANGEMENT_ROUTER for piece_arrangement_algorithm options and ytl.optimizer_functions.SHIPMENT_ARRANGEMENT_ROUTER for algorithm options in the shipment_optimization_ls parameter. Also see ytl.defaults.DEFAULT_PIECE_ARRANGEMENT_ALGORITHM and ytl.defaults.DEFAULT_SHIPMENT_ARRANGEMENT_ALGORITHM for default values.

import ytl
import json

# Piece arrangement algorithm options
print(json.dumps([b for a,b in ytl.optimizer_functions.PIECE_ARRANGEMENT_ROUTER.values()],indent=2))
# Piece arrangement algorithm default
print(ytl.defaults.DEFAULT_PIECE_ARRANGEMENT_ALGORITHM)

# Shipment arrangement algorithm options
print(json.dumps([b for a,b in ytl.optimizer_functions.SHIPMENT_ARRANGEMENT_ROUTER.values()],indent=2))
# Shipment arrangement algorithm default
print(json.dumps(ytl.defaults.DEFAULT_SHIPMENT_ARRANGEMENT_ALGORITHM,indent=2))

Simulation Model Description

Given the complexity of the trailer loading optimization problem, we are well-advised to seek approximate optimization approach rather than exact optimization that may be very costly and time-consuming. This package includes an object-oriented framework for simulation-based optimizers, which can be used as the underpinning for approaches like simulated annealing/MCMC style methods, genetic algorithms, and other heuristic/stochastic/dynamical systems optimization schemes.

The simulation framework is composed of 3 types of objects: Trailers, Shipments, and Pieces.

  • Piece (ytl.logistics_objects.Piece): Pieces are indivisible objects intended to be loaded into a trailer. They are assumed to be rectangular prisms with length, width, and height dimensions, as well as weight, stackable, and rotation-allowed attributes. Only rotations in the x-y plane are allowed (pieces may be turned but not allowed to be tipped on their side or set upside down).

  • Shipment (ytl.logistics_objects.Shipment): Shipments are made up of Piece objects and store information about the relative location of Pieces arranged within its boundaries. Shipments have calculated length, width, height, and weight attributes based on the contained pieces and their relative placement within the Shipment.

  • Trailer (ytl.logistics_objects.Trailer): Trailer objects are made up of Shipment objects and store information about where the relative location of Shipments arraged within its boundaries. Trailers have inner length, inner width, inner height, and maximum weight parameters that dictate how Shipment objects can be arranged inside of them. Shipment objects are not allowed to be stacked inside of a trailer - any stacking of shipping units must be treated as stackinng of Piece objects to make up a Shipment.

These definitions set up a natural two-stage optimization framework. Based on user inputs, create a collection of Piece objects and a Trailer of the appropriate dimensions. The first stage of the optimization is to arrange the Piece objects into Shipments, and the second is to arrange the Shipment objects in the Trailer object. These two stages are implemented in ytl/optimizer_functions/__init__.py:

  • Piece Arrangement Optimation Router (ytl.optimizer_functions.optimize_pieces_arrangement): This function takes as input parameters a list of Piece objects and algorithm specification, and it returns a list of Shipment objects containing all provided pieces. This optimization is built to be run to generate a list of Shipment objects from provided Piece objects (not built to be run iteratively).

  • Shipment Arrangement Optimation Router (ytl.optimizer_functions.optimize_shipment_arrangement): This function takes as parameters a Trailer object (assumed to have Shipment objects already defined) and algorithm max_iter/timeout parameters to control optimization runtime. It returns None, but makes updates to the Trailer object in place that model rearrangement of shipments within the trailer. These optimizers are intended to be run iteratively on a Trailer object in the process of a simulation-based optimization. Loss function measurements are made based on the state of the Trailer object, which in our case we simply use the linear foot trailer occupancy as the loss function.

The optimization is implemented in ytl.services.trailer_load.optimize_trailer_load_plan, which manages the creation of Piece/Trailer objects from user inputs and both stages (Piece and Shipment arrangement) of the optimization. The options used for each stage of the optimization can be specified in the user request, otherwise the defaults set in ytl.defaults are used.

Further development can be done by adding additional optimizers to ytl.optimizer_functions.optimize_pieces_arrangement and/or ytl.optimizer_functions.optimize_shipment_arrangement, altering the goal of the optimization by using another loss function instead of linear feet, or altering the valid Piece arrangement methodology inside the Piece/Shipment objects.

For examples of how to generate and work with Piece, Shipment, and Trailer objects, start with demo/demo_trailer_load.py and ytl.services.trailer_load.optimize_trailer_load_plan.

Reference

Portions of this package make use of an optimization presented by Dube and Kanavalty in the conference papaer cited below. There is a Python implementation of this algorithm available on PyPi, which is a derivative work of a Go implementation available on GitHub (The article by Dube and Kanavalty is also available in this GitHub repository). The py3dbp Python implementation, with minor variations to suite our purposes, is in the ytl.py3dbp module of this package and leveraged in portions of the trailer load optimization services.

E. Dube and L. Kanavalty, "Optimizing Three-Dimensional Bin Packing Through Simulation", Proceedings of the Sixth IASTED International Confernece Modelling, Simulation, and Optimization pp. 1-7, September 11-13, 2006, Gaborone, Botswana.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ytl-1.0.1.tar.gz (30.8 kB view details)

Uploaded Source

Built Distribution

ytl-1.0.1-py3-none-any.whl (34.9 kB view details)

Uploaded Python 3

File details

Details for the file ytl-1.0.1.tar.gz.

File metadata

  • Download URL: ytl-1.0.1.tar.gz
  • Upload date:
  • Size: 30.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.1

File hashes

Hashes for ytl-1.0.1.tar.gz
Algorithm Hash digest
SHA256 293299703e6a2f77de78b71ea1305f4fd12a6458dc3e9ecf02573a8443e8d51e
MD5 1812db57f7235f4b210b249be8ed2ff3
BLAKE2b-256 3ed86e358aa93b6b2e7e471064a03e344dbd42cd9093212fc2ce9d8f875efd7f

See more details on using hashes here.

File details

Details for the file ytl-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: ytl-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 34.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.1

File hashes

Hashes for ytl-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 fcaa828dafe84469010e9fc991b3205fd18c97d0a3a175af3a523f938551f35c
MD5 ee572cd41dddd4779322b2492fc11ec1
BLAKE2b-256 2b4df1405191e2c2e91575870759adae7c2ea6cc28d68cd509c178083ada6497

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page