gsm_helpers Module

Overview

The gsm_helpers module contains helper code for the dynamic programming (DP) algorithm to solve the guaranteed-service model (GSM) for multi-echelon inventory systems with tree structures by Graves and Willems (2000, 2003), which is implemented in the gsm_tree module.

Note

The terms “node” and “stage” are used interchangeably in the documentation.

Note

The notation and references (equations, sections, examples, etc.) used below refer to Snyder and Shen, Fundamentals of Supply Chain Theory (FoSCT), 2nd edition (2019).

See Also

For an overview of multi-echelon inventory optimization in Stockpyl, see the tutorial page for multi-echelon inventory optimization.

References

S. C. Graves and S. P. Willems. Optimizing strategic safety stock placement in supply chains. Manufacturing and Service Operations Management, 2(1):68-83, 2000.

S. C. Graves and S. P. Willems. Erratum: Optimizing strategic safety stock placement in supply chains. Manufacturing and Service Operations Management, 5(2):176-177, 2003.

API Reference

solution_cost_from_cst(tree, cst)[source]

Calculate expected cost per period of given solution as specified by committed service times (CSTs).

Parameters
  • tree (SupplyChainNetwork) – The multi-echelon tree network. Network need not have been relabeled.

  • cst (dict) – Dict of CSTs for each node, using the same node labeling as tree. [\(S\)]

Returns

cost – Expected cost of the solution. [\(g(S)\)]

Return type

float

Example (Example 6.5):

>>> from stockpyl.instances import load_instance
>>> tree = preprocess_tree(load_instance("example_6_5"))
>>> solution_cost_from_cst(tree, {1: 0, 2: 0, 3: 0, 4: 1})
8.277916867529369
solution_cost_from_base_stock_levels(tree, local_bsl)[source]

Calculate expected cost per period of given solution as specified by base-stock levels. Cost is based on safety stock, which is calculated as base-stock level minus demand mean.

Parameters
  • tree (SupplyChainNetwork) – The multi-echelon tree network. Graph need not have been relabeled.

  • local_bsl (dict) – Dict of local base-stock levels for each node, using the same node labeling as tree. [\(y\)]

Returns

cost – Expected cost of the solution. [\(g(S)\)]

Return type

float

Example (Example 6.5):

>>> from stockpyl.instances import load_instance
>>> tree = preprocess_tree(load_instance("example_6_5"))
>>> solution_cost_from_base_stock_levels(tree, {1: 2.45, 2: 1.00, 3: 1.41, 4: 0.00})
8.27
inbound_cst(tree, node_index, cst)[source]

Determine the inbound CST (\(SI\)) for one or more stages, given all of the outbound CSTs. The inbound CST is calculated as the maximum of the outbound CST for all predecessors, and the external inbound CST (if any).

Parameters
  • tree (SupplyChainNetwork) – The multi-echelon tree network. Network need not have been relabeled.

  • node_index (node or iterable container) – A single node index or a container of node indices (dict, list, set, etc.).

  • cst (dict) – Dict of CSTs for each node, using the same node labeling as tree. [\(S\)]

Returns

SI – Inbound CST of node node_index (if node_index is a single node); or a dictionary of inbound CST values keyed by node (if node_index is an iterable container) [\(SI\)].

Return type

int or dict

Example (Problem 6.9):

>>> from stockpyl.instances import load_instance
>>> tree = preprocess_tree(load_instance("problem_6_9"))
>>> inbound_cst(tree, 3, {1: 3, 2: 3, 3: 31, 4: 3, 5: 10, 6: 2})
10
net_lead_time(tree, node_index, cst)[source]

Determine the net lead time (NLT) for one or more stages, given the outbound CSTs.

Parameters
  • tree (SupplyChainNetwork) – The multi-echelon tree network. Network need not have been relabeled.

  • node_index (node or iterable container) – A single node index or a container of node indices (dict, list, set, etc.).

  • cst (dict) – Dict of CSTs for each node, using the same node labeling as tree. [\(S\)]

Returns

nlt – NLT of node node_index (if node_index is a single node); or a dictionary of NLT values keyed by node (if node_index is an iterable container).

Return type

int or dict

Example (Problem 6.9):

>>> from stockpyl.instances import load_instance
>>> tree = preprocess_tree(load_instance("problem_6_9"))
>>> net_lead_time(tree, tree.node_indices, {1: 3, 2: 3, 3: 31, 4: 3, 5: 10, 6: 2})
{1: 35, 2: 35, 3: 0, 4: 0, 5: 0, 6: 0}
cst_to_base_stock_levels(tree, node_index, cst)[source]

Determine base-stock levels for one or more stages, for given committed service times (CST).

Parameters
  • tree (SupplyChainNetwork) – The multi-echelon tree network. Graph need not have been relabeled.

  • node_index (node or iterable container) – A single node index or a container of node indices (dict, list, set, etc.).

  • cst (dict) – Dict of CSTs for each node, using the same node labeling as tree. [\(S\)]

Returns

base_stock_level – Base-stock level of node node_index (if node_index is a single node); or a dictionary of base-stock levels keyed by node (if node_index is an iterable container). [\(y\)]

Return type

float or dict

Example (Problem 6.9):

>>> from stockpyl.instances import load_instance
>>> tree = preprocess_tree(load_instance("example_6_5"))
>>> cst_to_base_stock_levels(tree, tree.node_indices, {1: 0, 2: 0, 3: 0, 4: 1})
{1: 2.4494897427831783, 3: 1.4142135623730951, 2: 1.0, 4: 0.0}
safety_stock_levels(tree, node_index, cst)[source]

Determine safety stock levels for one or more nodes, for given committed service times (CST).

Parameters
  • tree (SupplyChainNetwork) – The multi-echelon tree network. Graph need not have been relabeled.

  • node_index (node or iterable container) – A single node index or a container of node indices (dict, list, set, etc.).

  • cst (dict) – Dict of CSTs for each node, using the same node labeling as tree. [\(S\)]

Returns

safety_stock_level – Safety stock of node node_index (if node_index is a single node); or a dictionary of safety stock values keyed by node (if node_index is an iterable container).

Return type

float or dict

Example (Problem 6.9):

>>> from stockpyl.instances import load_instance
>>> tree = preprocess_tree(load_instance("example_6_5"))
>>> safety_stock_levels(tree, tree.node_indices, {1: 0, 2: 0, 3: 0, 4: 1})
{1: 2.4494897427831783, 3: 1.4142135623730951, 2: 1.0, 4: 0.0}