Problem: Enhanced EOQ and Order Frequency Calculation

The problem aims to create enhanced Python functions for inventory optimization that compute robust Economic Order Quantity (EOQ) with input validation, demand uncertainty, holding cost adjustments, and stochastic modeling, and calculate order frequency using renewal process approximations and weighted probabilistic methods, to support data-driven inventory decision-making.

Background: ### Industry Background for Inventory Optimization Functions

#### 1. Core Context: Modern Inventory Control Needs
Economic Order Quantity (EOQ) and order frequency calculations are foundational to inventory management across retail, manufacturing, and logistics. Deterministic EOQ models fail to address real-world supply chain complexities, so the provided functions integrate industry-aligned mathematical enhancements to ensure practicality, resilience, and accuracy.

#### 2. Enhanced EOQ Calculation (`calculate_eoq`)
- **Time Value of Money Adjustment**: Holding costs are adjusted using continuous compounding at a 5% discount rate, reflecting the standard industry assumption for the opportunity cost of capital. This accounts for the fact that capital tied up in inventory could generate returns elsewhere, reducing the effective holding cost over time.
- **Stochastic Demand Modeling**: Industry demand is rarely constant; the function uses a Poisson distribution with Taylor series expansion to approximate expected EOQ under uncertain demand, a critical adjustment for sectors like retail with seasonal fluctuations or manufacturing with supply variability.
- **Robust Optimization for Resilience**: A 15% demand uncertainty range is incorporated to model worst-case scenarios, a key requirement post-2020 supply chain disruptions. Candidate order quantities (floor/ceil of the expected Q, plus nearby values) are evaluated to select the quantity that minimizes maximum possible costs, ensuring supply chain resilience.
- **Integer Order Constraints**: Real-world ordering relies on batch sizes (e.g., pallets, case packs), so the function rounds candidate quantities to integers to reflect operational feasibility.
- **Numerical Stability & Performance**: Logarithmic transformations prevent overflow in large-scale calculations (common in ERP systems managing thousands of SKUs), while `lru_cache` caching optimizes repeated computations for frequent re-evaluations.
- **Production-Grade Input Validation**: Strict type and value checks ensure compliance with enterprise code standards, avoiding crashes from invalid inputs (e.g., negative demand, zero holding cost which would make EOQ mathematically infinite).

#### 3. Order Frequency Calculation (`calculate_order_frequency`)
- **Renewal Process Approximation**: Order placement is modeled as a renewal process, where each order initiates a new inventory cycle. This aligns with industry practices where inventory replenishment is driven by demand events, using principles from reliability and queueing theory.
- **Truncated Normal Probabilities**: Demand cannot be negative, so a truncated normal distribution is used to compute order probabilities, providing more accurate results than a standard normal distribution for non-negative demand scenarios.
- **Weighted Method Combination**: For large EOQ values (infrequent orders), renewal theory provides efficient, scalable approximations. For small EOQ (frequent orders), truncated normal probabilities offer greater precision. A weighted average (favoring renewal theory for larger Q) balances accuracy and computation speed for diverse inventory scenarios.
- **Vectorized Batch Processing**: Numpy broadcasting and vectorization enable efficient processing of multiple SKUs or locations, a core requirement for supply chain analytics platforms handling large datasets.
- **Edge Case Handling**: Zero EOQ (no orders) is explicitly handled to return zero frequency, avoiding division by zero and reflecting real-world scenarios like discontinued products or non-stocked items.

---

### Required Import Statements
import math
from typing import Union
from functools import lru_cache
import numpy as np
from scipy.stats import truncnorm

Input/Output: The problem takes three numeric inputs for Economic Order Quantity (EOQ) calculation: demand (non-negative integer or float, expected annual demand), setup_cost (non-negative integer or float, cost per order), and holding_cost (positive integer or float, annual unit holding cost). It also takes two inputs for order frequency calculation: demand (consistent with the EOQ input) and eoq (non-negative number or numpy array, output from the EOQ calculation). The problem outputs two results: 1) an optimal EOQ value (integer or float) from the calculate_eoq function, which includes input validation, 5% discount rate adjustment for holding costs, 15% demand uncertainty handling via robust optimization, candidate EOQ generation, worst-case cost minimization, and 0.6-weighted combination of robust and stochastic EOQ; 2) an expected order frequency (scalar or numpy array) from the calculate_order_frequency function, which uses renewal process approximation, truncated normal probabilities, and weighted averaging, returning a scalar for scalar inputs or an array otherwise. The EOQ result serves as the eoq input for the order frequency calculation.

Required dependencies:
import math
from typing import Union
from functools import lru_cache
import numpy as np
from scipy.stats import truncnorm

Sub-steps:
step_number: 1
step_description_prompt: Please write a Python function named calculate_eoq that computes Economic Order Quantity. It includes input validation, adjusts holding costs using 5% discount rate, considers 15% demand uncertainty, generates candidate Qs, calculates worst-case costs, selects optimal Q, and combines with stochastic EOQ using 0.6 robustness weight.
function_header: def calculate_eoq(demand, setup_cost, holding_cost):
test_cases: for D, K, h, expected in [(1000, 100, 2, 316.22776601683796), (400, 25, 1, 141.4213562373095), (900, 81, 4, 190.91883092208534)]:
    actual_eoq = calculate_eoq(D, K, h)
    # Enhanced implementation may have significant differences due to robust optimization
    assert math.isclose(actual_eoq, expected, rel_tol=0.5) or abs(actual_eoq - expected) / max(abs(expected), 1) < 0.5

step_number: 2
step_description_prompt: Please write a Python function named calculate_order_frequency that takes demand and eoq as inputs. Validate inputs to ensure they are non-negative numbers or numpy arrays, then broadcast them to matching shapes. Handle zero eoq cases by setting results to zero. For non-zero eoq, compute expected orders using a combination of renewal process approximation and truncated normal probabilities with weighted average. Return scalar if input is scalar else array.
function_header: def calculate_order_frequency(demand, eoq):
test_cases: for D, Q, expected in [(1000, 316.23, 4), (400, 141.42, 3), (900, 190.92, 5)]:
    actual_val = calculate_order_frequency(D, Q)
    # Order frequency is typically an integer, allow tolerance for enhanced implementation
    assert abs(actual_val - expected) < 2.0 or math.isclose(actual_val, expected, rel_tol=0.5) or abs(actual_val - expected) / max(abs(expected), 1) < 0.5

General solution:

General tests: