Skip to main content

A Python package for inventory optimization

Project description

Stockpyl

PyPI Documentation Status Coverage GitHub GitHub issues Twitter Follow

Stockpyl is a Python package for inventory optimization. It implements classical single-node inventory models like the economic order quantity (EOQ), newsvendor, and Wagner-Whitin problems. It also contains algorithms for multi-echelon inventory optimization (MEIO) under both stochastic-service model (SSM) and guaranteed-service model (GSM) assumptions.

Most of the models and algorithms implemented in Stockpyl are discussed in the textbook Fundamentals of Supply Chain Theory (FoSCT) by Snyder and Shen, Wiley, 2019, 2nd ed. Most of them are much older; see FoSCT for references to original sources.

For lots of details, read the docs.

Some Examples

Solve the EOQ problem with :math:K=8, :math:h=0.225, and :math:\lambda=1300 (Example 3.1 in FoSCT):

    >>> from stockpyl.eoq import economic_order_quantity
    >>> Q, cost = economic_order_quantity(fixed_cost=8, holding_cost=0.225, demand_rate=1300)
    >>> Q
    304.0467800264368
    >>> cost
    68.41052550594829

Or the newsvendor problem with :math:h=0.18, :math:p=0.70, and :math:D\sim N(50, 8^2) (Example 4.3 in FoSCT):

    >>> from stockpyl.newsvendor import newsvendor_normal
    >>> S, cost = newsvendor_normal(holding_cost=0.18, stockout_cost=0.70, demand_mean=50, demand_sd=8)
    >>> S
    56.60395592743389
    >>> cost
    1.9976051931766445

Note that most functions in Stockpyl use longer, more descriptive parameter names (holding_cost, fixed_cost, etc.) rather than the shorter notation assigned to them in textbooks and articles (h, K).

Stockpyl can solve the Wagner-Whitin model using dynamic programming:

    >>> from stockpyl.wagner_whitin import wagner_whitin
    >>> T = 4
    >>> h = 2
    >>> K = 500
    >>> d = [90, 120, 80, 70]
    >>> Q, cost, theta, s = wagner_whitin(T, h, K, d)
    >>> Q # Optimal order quantities
    [0, 210, 0, 150, 0]
    >>> cost # Optimal cost
    1380.0
    >>> theta # Cost-to-go function
    array([   0., 1380.,  940.,  640.,  500.,    0.])
    >>> s # Optimal next period to order in
    [0, 3, 5, 5, 5]

And finite-horizon stochastic inventory problems:

    >>> from stockpyl.finite_horizon import finite_horizon_dp
    >>> T = 5
    >>> h = 1
    >>> p = 20
    >>> h_terminal = 1
    >>> p_terminal = 20
    >>> c = 2
    >>> K = 50
    >>> mu = 100
    >>> sigma = 20
    >>> s, S, cost, _, _, _ = finite_horizon_dp(T, h, p, h_terminal, p_terminal, c, K, mu, sigma)
    >>> s # Reorder points
    [0, 110, 110, 110, 110, 111]
    >>> S # Order-up-to levels
    [0, 133.0, 133.0, 133.0, 133.0, 126.0]

Stockpyl includes an implementation of the Clark and Scarf (1960) algorithm for stochastic serial systems (more precisely, Chen-Zheng's (1994) reworking of it):

    >>> from stockpyl.supply_chain_network import serial_system
    >>> from stockpyl.ssm_serial import optimize_base_stock_levels
    >>> # Build network.
    >>> network = serial_system(
    ...     num_nodes=3,
    ...     node_order_in_system=[3, 2, 1],
    ...     echelon_holding_cost=[4, 3, 1],
    ...     local_holding_cost=[4, 7, 8],
    ...     shipment_lead_time=[1, 1, 2],
    ...     stockout_cost=40,
    ...     demand_type='N',
    ...     mean=10,
    ...     standard_deviation=2
    ... )
    >>> # Optimize echelon base-stock levels.
    >>> S_star, C_star = optimize_base_stock_levels(network=network)
    >>> print(f"Optimal echelon base-stock levels = {S_star}")
    Optimal echelon base-stock levels = {3: 44.1689463285519, 2: 34.93248526934437, 1: 25.69602421013684}
    >>> print(f"Optimal expected cost per period = {C_star}")
    Optimal expected cost per period = 227.15328525645054

Stockpyl has extensive features for simulating multi-echelon inventory systems. Below, we simulate the same serial system, obtaining an average cost per period that is similar to what the theoretical model predicted above.

    >>> from stockpyl.supply_chain_network import echelon_to_local_base_stock_levels
    >>> from stockpyl.sim import simulation
    >>> from stockpyl.policy import Policy
    >>> # Convert to local base-stock levels and set nodes' inventory policies.
    >>> S_star_local = echelon_to_local_base_stock_levels(network, S_star)
    >>> for n in network.nodes:
    ...     n.inventory_policy = Policy(type='BS', base_stock_level=S_star_local[n.index], node=n)
    >>> # Simulate the system.
    >>> T = 1000
    >>> total_cost = simulation(network=network, num_periods=T, rand_seed=42)
    >>> print(f"Average total cost per period = {total_cost/T}")
    Average total cost per period = 226.16794575837224

Stockpyl also implements Graves and Willems' (2000) dynamic programming algorithm for optimizing committed service times (CSTs) in acyclical guaranteed-service model (GSM) systems:

    >>> from stockpyl.gsm_tree import optimize_committed_service_times
    >>> from stockpyl.instances import load_instance
    >>> # Load a named instance, Example 6.5 from FoSCT.
    >>> tree = load_instance("example_6_5")
    >>> # Optimize committed service times.
    >>> opt_cst, opt_cost = optimize_committed_service_times(tree)
    >>> print(f"Optimal CSTs = {opt_cst}")
    Optimal CSTs = {1: 0, 3: 0, 2: 0, 4: 1}
    >>> print(f"Optimal expected cost per period = {opt_cost}")
    Optimal expected cost per period = 8.277916867529369

Resources

Feedback

If you have feedback or encounter problems, please report them on the Stockpyl GitHub Issues Page. (If you are not comfortable using GitHub for this purpose, feel free to e-mail me. My contact info is on my webpage.)

License

Stockpyl is open-source and released under the GPLv3 License.

Citation

If you'd like to cite the Stockpyl package, you can use the following BibTeX entry:

@misc{stockpyl,
    title={Stockpyl},
    author={Snyder, Lawrence V.},
    year={2022},
    url={https://github.com/LarrySnyder/stockpyl}
}

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

stockpyl-0.0.6.tar.gz (131.6 kB view details)

Uploaded Source

Built Distribution

stockpyl-0.0.6-py3-none-any.whl (136.5 kB view details)

Uploaded Python 3

File details

Details for the file stockpyl-0.0.6.tar.gz.

File metadata

  • Download URL: stockpyl-0.0.6.tar.gz
  • Upload date:
  • Size: 131.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.8.13

File hashes

Hashes for stockpyl-0.0.6.tar.gz
Algorithm Hash digest
SHA256 8bd8b6525a77883940e2ce31d99af62fd3b58e55953c7017a41191dffc613f61
MD5 45d7988963544e70a3d2ac47092d024f
BLAKE2b-256 e85518adbde69f4e9440ac712e52cb81e5cdb78dd50e7a0ab9170eda26f3a5bf

See more details on using hashes here.

File details

Details for the file stockpyl-0.0.6-py3-none-any.whl.

File metadata

  • Download URL: stockpyl-0.0.6-py3-none-any.whl
  • Upload date:
  • Size: 136.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.8.13

File hashes

Hashes for stockpyl-0.0.6-py3-none-any.whl
Algorithm Hash digest
SHA256 753a4b3dce04f80fb6a651692e0955aa98c8d149d73ca6d666127007d146ab2a
MD5 90f66794903d1babe87bb00d7521642d
BLAKE2b-256 74337e6ded393e2a0fc749ce35f4c8c227d6b4a9cff5da495aaa42be8864a9b7

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