Skip to content

Supply Chain Transport

Minimize inventory holding and transport costs with TL/LTL mode selection.

Goals
OptimizePlan
Reasoning types
Prescriptive
Experience level
Intermediate
Browse files

What this template is for

In freight logistics, choosing between truckload (TL) and less-than-truckload (LTL) shipping modes involves a cost trade-off. TL shipments have a fixed cost per truck but offer lower per-unit rates for large volumes. LTL shipments have a piecewise cost structure that is cheaper for small volumes but expensive at scale. On top of mode selection, freight sitting in a vendor warehouse incurs inventory holding costs. The optimal strategy balances when to ship, how much to ship, and which mode to use.

This template formulates a mixed-integer program that jointly optimizes inventory holding, transport mode selection (TL vs LTL), and shipment timing for multiple freight groups. Each freight group has its own inventory window, transport window, and arrival deadline. The solver determines the cost-minimizing plan that ships all freight on time while respecting TL capacity limits and LTL piecewise cost breakpoints.

The model demonstrates several advanced techniques: multi-period inventory flow conservation, binary mode selection with big-M coupling, piecewise linear cost modeling for LTL segments, and arrival-day linking through transit times.

Who this is for

  • Supply chain planners optimizing freight consolidation and mode selection.
  • Logistics analysts comparing TL vs LTL cost trade-offs.
  • Operations researchers building multi-period transport models.
  • Developers learning mixed-integer programming with RelationalAI.
  • Assumed knowledge: comfortable reading Python; the transport and optimization terms are explained as they come up. No prior RelationalAI experience is required to run it.

What you’ll build

  • A cost-minimizing transport plan — per-freight-group inventory levels, shipment quantities, mode choice, and arrival days — produced by the prescriptive reasoner as a mixed-integer program.
  • A binary mode-selection decision (truckload vs less-than-truckload) coupled to shipment volume through big-M constraints, expressed as prescriptive decision variables and constraints.
  • A piecewise-linear cost model for less-than-truckload freight, with per-segment breakpoint variables the solver activates as volume grows.
  • Arrival days derived from departure day and transit time, linked into the solve so on-time-arrival deadlines are enforced as constraints.

What’s included

  • supply_chain_transport.py — main script with ontology, formulation, and solver call
  • runbook.md — a paste-testable walkthrough that reproduces the template step by step with the RAI skills; as important a reference as the script itself
  • data/freight_groups.csv — 2 freight groups with inventory/transport/arrival windows
  • pyproject.toml — Python package configuration

Prerequisites

Access

  • A Snowflake account that has the RAI Native App installed.
  • A Snowflake user with permissions to access the RAI Native App.

Tools

  • Python >= 3.10
  • RelationalAI Python SDK (relationalai == 1.0.14)

Quickstart

  1. Download ZIP:

    Terminal window
    curl -O https://docs.relational.ai/templates/zips/v1/supply_chain_transport.zip
    unzip supply_chain_transport.zip
    cd supply_chain_transport
  2. Create venv:

    Terminal window
    python -m venv .venv
    source .venv/bin/activate
    python -m pip install --upgrade pip
  3. Install:

    Terminal window
    python -m pip install .
  4. Configure:

    Terminal window
    rai init
  5. Run:

    Terminal window
    python supply_chain_transport.py
  6. Expected output:

    Status: OPTIMAL
    Total cost: $1444.00
    === Transport Quantities ===
    type freight_group day quantity
    ltl fg1 2 4000.0
    ltl fg2 2 5000.0

    Both freight groups ship less-than-truckload on day 2 (zero truckload trucks); see runbook.md for the full inventory and arrival-day tables.

Template structure

.
├── README.md
├── pyproject.toml
├── supply_chain_transport.py
└── data/
└── freight_groups.csv

Start here: run python supply_chain_transport.py for the full formulation and solve end to end, or follow runbook.md to reproduce it step by step with the RAI skills.

Sample data

The bundled data is synthetic and illustrative — a minimal two-group example designed to teach the formulation on a Snowflake-connected RAI account, not to match a specific shipper’s freight book. The transport modes and cost segments are defined inline in the script, not loaded from CSV.

  • freight_groups.csv (2 rows) — one row per freight group, giving its inventory window (inv_start_t to inv_end_t), transport window (tra_start_t to tra_end_t), arrival window (arr_start_t to arr_end_t), and starting inventory weight (inv_start).

Model overview

The formulation is built on three concepts: the freight groups loaded from CSV, and the transport types and LTL cost segments defined inline in the script.

  • Key entities: FreightGroup — a batch of freight with its own inventory, transport, and arrival time windows (the optimization solves for its per-day inventory, shipment quantities, and arrival day); TransportType — a shipping mode (truckload or less-than-truckload), with its transit time; LTLSegment — a breakpoint in the piecewise-linear less-than-truckload cost curve.
  • Primary identifiers: name on FreightGroup and TransportType; integer seg on LTLSegment.
  • Important invariants: window start days are less than or equal to window end days; inv_start weights are non-negative; transport-mode indicators and segment activation variables are binary; each freight group ships all inventory out by the end of its inventory window.

For the full concept and property definitions, see supply_chain_transport.py; runbook.md builds them step by step with the RAI skills.

How it works

CSV freight groups + inline modes/segments → decision variables → inventory + mode + arrival constraints → cost objective → solve

1. Define freight groups with time windows. Each freight group loads from CSV with its inventory, transport (departure), and arrival deadline windows plus a starting inventory weight.

2. Define transport types and LTL cost segments. The two shipping modes — truckload (TL, 2-day transit) and less-than-truckload (LTL, 3-day transit) — are defined inline, along with the LTL cost-curve breakpoints. TL carries a flat per-truck fixed cost; LTL is priced as a piecewise-linear curve the solver walks up as volume grows.

3. Formulate decision variables. The solve determines per-day inventory levels, per-mode shipment quantities, binary mode indicators, computed arrival days, and the piecewise LTL segment variables — indexed over each group’s own time windows.

4. Add constraints. Multi-period inventory flow conservation ties each day’s inventory to the next day’s plus what ships out; big-M coupling links the binary mode indicator to shipment volume; segment-activation logic enforces the LTL piecewise cost; and arrival days derived from departure day plus transit time must land within each group’s arrival window.

5. Minimize total cost. The objective combines inventory holding cost, TL fixed cost, and piecewise LTL variable cost, and the MIP is solved end to end.

For the implementation, see supply_chain_transport.py; to reproduce it step by step with the RAI skills, follow runbook.md.

Customize this template

Focus on the first changes most users will make.

Use your own data

  • Replace data/freight_groups.csv with your own; keep the column names listed in Sample data above.
  • Ensure each group’s windows are internally consistent (start day less than or equal to end day) and that the arrival window is reachable given transit times.

Tune parameters

  • Cost parameters — change inv_cost, tl_tra_cost, or the LTL segment costs and limits in the script.
  • Transit times — adjust the inline transit_time values on the tl and ltl transport types.

Extend the model

  • Add more freight groups by extending freight_groups.csv with additional rows and time windows.
  • Add more LTL segments by defining additional LTLSegment instances for finer cost granularity.
  • Extend to multiple origins/destinations by adding location concepts and routing constraints.
  • Add capacity constraints on warehouses or transport links.

Scale up / productionize

  • Replace the CSV load with model.data(snowflake_table) for a Snowflake-backed freight book.
  • The formulation scales to many freight groups within the prescriptive engine’s solve budget; pin the SDK version for reproducible runs.

Troubleshooting

Solver returns INFEASIBLE
  • Verify that each freight group’s transport window overlaps with the departure days (1-4).
  • Check that arrival windows are reachable given transit times (TL=2, LTL=3 days).
  • Ensure inv_start values are positive and time windows are consistent (start <= end).
Import error for relationalai
  • Confirm your virtual environment is active: which python should point to .venv.
  • Reinstall dependencies: python -m pip install ..
Authentication or configuration errors
  • Run rai init to create or update your RelationalAI/Snowflake configuration.
  • If you have multiple profiles, set export RAI_PROFILE=<your_profile>.
Unexpected cost values
  • The LTL cost is piecewise: the first 6000 lbs cost 0.12/lb.
  • TL has a flat $2000 per truck with a 24,000 lb capacity.
  • Inventory holding is 0.1% of weight per day. Double-check that your freight weights match expectations.

Learn more

Core concepts

Reasoner reference

Support

  • File issues at the RelationalAI templates repository.