| name | inventory-optimizer |
| description | Inventory optimization skill for safety stock, reorder point, and order quantity calculations. |
| allowed-tools | Bash(*) Read Write Edit Glob Grep WebFetch |
| metadata | {"author":"babysitter-sdk","version":"1.0.0","category":"supply-chain","backlog-id":"SK-IE-025"} |
| graph | {"domains":["domain:industrial-engineering"],"skillAreas":["skill-area:statistical-analysis","skill-area:organizational-design","skill-area:data-analysis"],"roles":["role:operations-analyst","role:research-engineer"]} |
inventory-optimizer
You are inventory-optimizer - a specialized skill for optimizing inventory policies including safety stock, reorder points, and order quantities.
Overview
This skill enables AI-powered inventory optimization including:
- ABC/XYZ classification
- Economic Order Quantity (EOQ) calculation
- Safety stock calculation by service level
- Reorder point determination
- Periodic review (R,S) policy optimization
- Continuous review (r,Q) policy optimization
- Multi-echelon inventory optimization
- Inventory investment analysis
Capabilities
1. ABC/XYZ Classification
import numpy as np
import pandas as pd
def abc_analysis(items: pd.DataFrame, value_column: str, quantity_column: str):
"""
ABC classification based on annual value (Pareto analysis)
A: Top 80% of value (typically 20% of items)
B: Next 15% of value (typically 30% of items)
C: Remaining 5% of value (typically 50% of items)
"""
items = items.copy()
items['annual_value'] = items[value_column] * items[quantity_column]
items = items.sort_values('annual_value', ascending=False)
total_value = items['annual_value'].sum()
items['cum_value'] = items['annual_value'].cumsum()
items['cum_pct'] = items['cum_value'] / total_value * 100
def assign_class(pct):
if pct <= 80:
return 'A'
elif pct <= 95:
return 'B'
else:
return 'C'
items['ABC_class'] = items['cum_pct'].apply(assign_class)
return items
def xyz_analysis(items: pd.DataFrame, demand_history_columns: list):
items = items.copy()
demand_data = items[demand_history_columns]
items[] = demand_data.mean(axis=)
items[] = demand_data.std(axis=)
items[] = items[] / items[]
():
cv < :
cv < :
:
items[] = items[].apply(assign_xyz)
items
():
matrix = items.groupby([, ]).size().unstack(fill_value=)
recommendations = {
: ,
: ,
: ,
: ,
: ,
: ,
: ,
: ,
:
}
{
: matrix,
: recommendations
}
2. Economic Order Quantity (EOQ)
def economic_order_quantity(annual_demand: float, ordering_cost: float,
holding_cost_per_unit: float):
"""
Classic EOQ calculation
EOQ = sqrt(2 * D * S / H)
D: Annual demand
S: Ordering cost per order
H: Holding cost per unit per year
"""
eoq = np.sqrt((2 * annual_demand * ordering_cost) / holding_cost_per_unit)
orders_per_year = annual_demand / eoq
annual_ordering_cost = orders_per_year * ordering_cost
average_inventory = eoq / 2
annual_holding_cost = average_inventory * holding_cost_per_unit
total_cost = annual_ordering_cost + annual_holding_cost
return {
"EOQ": round(eoq, 0),
"orders_per_year": round(orders_per_year, 1),
"order_interval_days": round(365 / orders_per_year, 1),
"annual_ordering_cost": round(annual_ordering_cost, 2),
"annual_holding_cost": round(annual_holding_cost, 2),
"total_relevant_cost": round(total_cost, 2),
"average_inventory": round(average_inventory, 0)
}
def eoq_with_quantity_discounts(annual_demand: float, ordering_cost: float,
holding_rate: float, price_breaks: list):
"""
EOQ with quantity discounts
price_breaks: [(min_qty, unit_price), ...]
"""
results = []
min_qty, unit_price (price_breaks, key= x: x[], reverse=):
holding_cost = unit_price * holding_rate
eoq = np.sqrt(( * annual_demand * ordering_cost) / holding_cost)
eoq < min_qty:
order_qty = min_qty
:
order_qty = eoq
orders_per_year = annual_demand / order_qty
annual_ordering = orders_per_year * ordering_cost
annual_holding = (order_qty / ) * holding_cost
annual_purchase = annual_demand * unit_price
total_cost = annual_ordering + annual_holding + annual_purchase
results.append({
: min_qty,
: unit_price,
: (eoq, ),
: (order_qty, ),
: (total_cost, )
})
optimal = (results, key= x: x[])
{
: results,
: optimal
}
3. Safety Stock Calculation
from scipy import stats
def safety_stock_service_level(demand_std: float, lead_time_mean: float,
lead_time_std: float = 0, service_level: float = 0.95):
"""
Calculate safety stock for desired service level
Accounts for variability in both demand and lead time
"""
z = stats.norm.ppf(service_level)
if lead_time_std > 0:
combined_std = np.sqrt(lead_time_mean * demand_std**2)
safety_stock = z * combined_std
else:
safety_stock = z * demand_std * np.sqrt(lead_time_mean)
return {
"safety_stock": round(safety_stock, 0),
"service_level": service_level,
"z_score": round(z, 2),
"demand_std": demand_std,
"lead_time": lead_time_mean
}
def safety_stock_fill_rate(demand_mean: float, demand_std: float,
order_quantity: float, target_fill_rate: float = 0.98):
"""
Calculate safety stock for target fill rate
Fill rate: proportion of demand satisfied from stock
"""
target_shortage = ( - target_fill_rate) * order_quantity
ss (, (demand_std * ), ):
z = ss / demand_std
loss = demand_std * (stats.norm.pdf(z) - z * ( - stats.norm.cdf(z)))
loss <= target_shortage:
{
: ss,
: target_fill_rate,
: - loss / order_quantity
}
{: (demand_std * ), : }
4. Reorder Point Determination
def calculate_reorder_point(average_demand_per_period: float,
lead_time_periods: float,
safety_stock: float):
"""
Calculate reorder point (r)
r = d * L + SS
d: Average demand per period
L: Lead time in periods
SS: Safety stock
"""
lead_time_demand = average_demand_per_period * lead_time_periods
reorder_point = lead_time_demand + safety_stock
return {
"reorder_point": round(reorder_point, 0),
"lead_time_demand": round(lead_time_demand, 0),
"safety_stock": round(safety_stock, 0),
"interpretation": f"Order when inventory reaches {round(reorder_point, 0)} units"
}
5. Continuous Review (r, Q) Policy
def optimize_rQ_policy(annual_demand: float, demand_std_per_period: float,
lead_time_periods: float, ordering_cost: float,
holding_cost_per_unit: float, service_level: float = 0.95):
"""
Optimize continuous review policy
r: Reorder point
Q: Order quantity (EOQ)
"""
eoq_result = economic_order_quantity(annual_demand, ordering_cost, holding_cost_per_unit)
Q = eoq_result['EOQ']
ss_result = safety_stock_service_level(
demand_std=demand_std_per_period,
lead_time_mean=lead_time_periods,
service_level=service_level
)
SS = ss_result['safety_stock']
periods_per_year = 12
avg_demand_per_period = annual_demand / periods_per_year
r = avg_demand_per_period * lead_time_periods + SS
return {
"policy": "(r, Q)",
"reorder_point": round(r, 0),
"order_quantity": round(Q, 0),
"safety_stock": round(SS, 0),
"service_level": service_level,
"average_inventory": round(Q/2 + SS, 0),
"annual_cost": eoq_result['total_relevant_cost']
}
6. Periodic Review (R, S) Policy
def optimize_RS_policy(annual_demand: float, demand_std_per_period: float,
review_period_periods: float, lead_time_periods: float,
holding_cost_per_unit: float, service_level: float = 0.95):
"""
Optimize periodic review policy
R: Review period
S: Order-up-to level
"""
z = stats.norm.ppf(service_level)
protection_period = review_period_periods + lead_time_periods
periods_per_year = 12
avg_demand_per_period = annual_demand / periods_per_year
avg_demand_protection = avg_demand_per_period * protection_period
std_protection = demand_std_per_period * np.sqrt(protection_period)
SS = z * std_protection
S = avg_demand_protection + SS
avg_order_qty = avg_demand_per_period * review_period_periods
avg_inventory = avg_order_qty / 2 + SS
return {
"policy": "(R, S)",
"review_period": review_period_periods,
"order_up_to_level": round(S, 0),
"safety_stock": round(SS, 0),
"service_level": service_level,
"average_inventory": round(avg_inventory, 0),
"annual_holding_cost": round(avg_inventory * holding_cost_per_unit, 2)
}
Process Integration
This skill integrates with the following processes:
inventory-optimization-analysis.js
demand-forecasting-model-development.js
warehouse-layout-slotting-optimization.js
Output Format
{
"item": "SKU-12345",
"abc_class": "A",
"xyz_class": "X",
"policy": "(r, Q)",
"reorder_point": 450,
"order_quantity": 200,
"safety_stock": 85,
"service_level": 0.95,
"average_inventory": 185,
"annual_cost": 5420.50,
"recommendations": [
"Consider vendor-managed inventory given high volume"
]
}
Best Practices
- Classify items first - Use ABC/XYZ to prioritize
- Match policy to class - More sophisticated for A items
- Review parameters regularly - Demand patterns change
- Consider total cost - Not just inventory cost
- Validate assumptions - Lead time, demand distributions
- Monitor service levels - Actual vs target
Constraints
- Requires accurate demand and cost data
- Assumes known distributions
- Lead time variability often underestimated
- Review periodically as conditions change