Reference

Optimization

SupplyChainOptimization.minimize_cost!Function
minimize_cost!(supply_chain::SupplyChain, optimizer=HiGHS.Optimizer)

Optimizes the supply chain for cost. The service level should be set to one to force the optimizer to serve all customers.

mip_rel_gap, mip_heuristic_effort, presolve and parallel map directly to the same-named HiGHS options (see HiGHS's documentation) and are left at HiGHS's own defaults when not given. Raising mip_heuristic_effort (0-1, HiGHS default 0.05) trades B&B time for more time spent in HiGHS's primal heuristics - useful on instances where the default effort doesn't find good incumbents quickly.

source
SupplyChainOptimization.maximize_profits!Function
maximize_profits!(supply_chain::SupplyChain, optimizer=HiGHS.Optimizer)

Optimizes the supply chain for profits. The service level should be set to zero to let the optimizer decide which customers to serve.

mip_rel_gap, mip_heuristic_effort, presolve and parallel map directly to the same-named HiGHS options (see HiGHS's documentation) and are left at HiGHS's own defaults when not given. Raising mip_heuristic_effort (0-1, HiGHS default 0.05) trades B&B time for more time spent in HiGHS's primal heuristics - useful on instances where the default effort doesn't find good incumbents quickly.

source
SupplyChainOptimization.warm_start_from_relaxation!Function
warm_start_from_relaxation!(supply_chain, objective, optimizer=HiGHS.Optimizer; bigM, single_source, evergreen, use_direct_model, relaxation_time_fraction=0.3)

Solves the LP relaxation and a fast polishing sub-MIP (see _relaxed_solution_hints) to produce a complete, guaranteed-feasible solution. Sets these values as warm start initial values on supply_chain.optimization_model. Returns true if a warm start was applied, false otherwise.

source
SupplyChainOptimization.solve_relax_and_fix!Function
solve_relax_and_fix!(supply_chain, objective, optimizer=HiGHS.Optimizer; bigM, single_source, evergreen, use_direct_model, window_size=3, time_limit_per_window=nothing)

Rolling-horizon relax-and-fix matheuristic over the facility opened decisions: relaxes opened[s, t] to continuous for every period, then slides a window_size-period window of real binaries across the horizon, solving and permanently fixing each window's rounded decisions before moving on. opening/closing/used/serviced_by are left exactly as JuMP created them throughout - opening/closing get pinned automatically by the real model's own constraints once the opened values on either side of them are fixed, and used/serviced_by don't need relaxing since their combinatorics are local to a single (lane, period)/(customer, period) pair.

Once every period is fixed, the resulting solve's entire solution (every variable, not just opened) is captured and handed back to the real, fully-binary model as a start value - not a permanent fix - so the caller's subsequent full-MIP solve (the one minimize_cost!/maximize_profits! runs right after this) can still improve on it within its own time budget.

time_limit_per_window bounds each window's sub-solve; when nothing (the default) it's computed by splitting the model's current time limit evenly across the windows plus one extra share reserved for that final full-MIP polish solve. Before returning, the model's time limit is set to whatever's left of the original budget after the window phase (not restored to the full original), so total wall time - window phase plus the caller's subsequent real solve - stays within the caller's original time_limit instead of using it twice.

Returns true if at least one window solved to a usable solution, false otherwise (e.g. the very first window was infeasible) - the real model is left untouched in that case, so the caller's normal solve proceeds without a warm start.

source

Querying Results

SupplyChainOptimization.get_financialsFunction
get_financials(supply_chain; max_time=supply_chain.horizon)

Gets the financial results of operating the supply chain.

(Moved here from Visualization.jl: unlike everything else in that file, this doesn't touch PlotlyJS/Plots at all, so it stays available without the ext/SupplyChainOptimizationPlotlyJSExt package extension - see that file and Visualization.jl for why the split exists.)

source
SupplyChainOptimization.get_productionFunction
get_production(supply_chain::SupplyChain, plant::Plant, product::Product, period=1)

Gets the amount of a given product produced at a given plant during a given period.

source
SupplyChainOptimization.get_receiptsFunction
get_receipts(supply_chain::SupplyChain, storage::Storage, product::Product, period=1)

Gets the amount of a given product received at a given storage location at a given period.

source
SupplyChainOptimization.get_shipmentsFunction
get_shipments(supply_chain::SupplyChain, storage::Storage, product::Product, period=1)

Gets the amount of a given product sent from a given storage location at a given period.

source
get_shipments(supply_chain::SupplyChain, plant::Plant, product::Product, period=1)

Gets the amount of a given product sent from a given plant at a given period.

source
get_shipments(supply_chain::SupplyChain, supplier::Supplier, product::Product, period=1)

Gets the amount of a given product shipped from a given supplier at a given period.

source
get_shipments(supply_chain::SupplyChain, lane::Lane, product::Product, period=1)

Gets the amount of a given product sent on a lane at a given period.

source
get_shipments(supply_chain::SupplyChain, lane::Lane, destination, product::Product, period=1)

Gets the amount of a given product sent on a lane at a given period.

source
get_shipments(supply_chain::SupplyChain, customer::Customer, product::Product, period=1)

Gets the amount of a given product received by a given customer at a given period.

source
SupplyChainOptimization.is_openedFunction
is_opened(supply_chain::SupplyChain, storage::Storage, period=1)

Gets whether a given storage location is opened during a given period.

source
is_opened(supply_chain::SupplyChain, plant::Plant, period=1)

Gets whether a given plant is opened during a given period.

source

Safety Stock Placement (GSM)

SupplyChainOptimization.compute_safety_stock_gsmFunction
compute_safety_stock_gsm(supply_chain::SupplyChain, product::Product; service_level::Real=0.95, maximum_customer_wait::Real=0)

Computes optimal safety-stock placement for product across supply_chain using the Graves & Willems (2000) Guaranteed Service Model (GSM): for each node, finds an incoming/outgoing service-time pair that minimizes total safety-stock holding cost, subject to a common target service_level (converted to a z-score) and guaranteed-service consistency across the network (a node cannot promise faster service than what its own incoming service time and lead time allow).

maximum_customer_wait is the number of periods a customer is willing to wait, measured at the storage(s) serving them directly (0 means that storage must have inventory ready to ship the moment an order arrives). It does not separately account for the transit time of the final lane from that storage to the customer, which is a fixed delay layered on top and doesn't affect which safety-stock placement is cost-optimal.

This is a tree-structured (single-sourced) implementation, matching the scope of the original Graves & Willems (2000) algorithm: every storage/supplier may have at most one upstream lane for product, and plants/production (bill-of-material) are not yet supported, since both introduce the merge points that the general-acyclic-network extension (Humair & Willems, 2011) is needed for. Both raise a clear ArgumentError rather than silently producing a wrong answer.

source
SupplyChainOptimization.GSMResultType

The result of a Guaranteed Service Model (GSM) safety-stock placement run: for each node, the guaranteed incoming/outgoing service times and the resulting safety stock.

source
SupplyChainOptimization.get_net_replenishment_timeFunction
get_net_replenishment_time(result::GSMResult, node::Node)

Gets the net replenishment time (incoming service time + lead time - outgoing service time) - the number of periods node must cover demand from its own safety stock.

source

Visualization

SupplyChainOptimization.plot_networkFunction
plot_network(supply_chain, period=1; geography="usa", showlegend=true)

Plots the nodes of the supply chain on a map.

The geography must be one of: "world" | "usa" | "europe" | "asia" | "africa" | "north america" | "south america".

Requires PlotlyJS and Plots to be loaded (see this file's top-of-file note).

source
SupplyChainOptimization.plot_flowsFunction
plot_flows(supply_chain, period=1; geography="usa", showlegend=true)

Plots the flows of products in the supply chain.

Requires PlotlyJS and Plots to be loaded (see this file's top-of-file note).

source
SupplyChainOptimization.plot_financialsFunction
plot_financials(supply_chain; max_time=supply_chain.horizon)

Plots the financial results of operating the supply chain.

Requires PlotlyJS and Plots to be loaded (see this file's top-of-file note).

source
SupplyChainOptimization.plot_inventoryFunction
plot_inventory(supply_chain, storage, product)

Plots the amount of inventory of a product on-hand at a storage location at the beginning of each period.

Requires PlotlyJS and Plots to be loaded (see this file's top-of-file note).

source
SupplyChainOptimization.animate_flowsFunction
animate_flows; geography="usa", showlegend=true, excluded_origins=[])

Creates an animation of the product flows through time.

Requires PlotlyJS and Plots to be loaded (see this file's top-of-file note).

source