def ddm_single_period(D1: float, S1: float, r: float) -> float:
    """
    Single-period dividend discount model.
    
    This function calculates the present value of a stock that will pay
    one dividend and then be sold after one period.
    
    Args:
        D1: Dividend to be paid at the end of period 1
        S1: Expected stock price at the end of period 1
        r: Required rate of return (as decimal, e.g., 0.1 for 10%)
        
    Returns:
        Present value of the stock
        
    Example:
        >>> ddm_single_period(2.0, 50.0, 0.1)
        47.272...
    """
    return (D1 + S1) / (1.0 + r)

def ddm_multi_period(dividends: list[float], ST: float, r: float) -> float:
    """
    Multi-period dividend discount model with terminal value.
    
    This function calculates the present value of a stock that pays
    dividends over multiple periods and has a terminal value.
    
    Args:
        dividends: List of dividends to be paid (D1, D2, ..., DT)
        ST: Terminal stock price at the end of period T
        r: Required rate of return (as decimal, e.g., 0.1 for 10%)
        
    Returns:
        Present value of the stock
        
    Example:
        >>> ddm_multi_period([2.0, 2.2, 2.4], 55.0, 0.1)
        46.033...
    """
    T = len(dividends)
    pv = sum(Dt / (1.0 + r)**(t+1) for t, Dt in enumerate(dividends))
    pv += ST / (1.0 + r)**T
    return pv

def ddm_infinite(dividends: list[float], r: float) -> float:
    """
    Infinite-period dividend discount model (perpetuity).
    
    This function calculates the present value of a stock that pays
    an infinite stream of specified dividends.
    
    Args:
        dividends: List of dividends to be paid (can represent a pattern)
        r: Required rate of return (as decimal, e.g., 0.1 for 10%)
        
    Returns:
        Present value of the infinite dividend stream
        
    Example:
        >>> ddm_infinite([2.0, 2.0, 2.0], 0.1)  # First 3 of infinite 2.0 dividends
        4.982...
    """
    return sum(Dt / (1.0 + r)**(t+1) for t, Dt in enumerate(dividends))

def cost_of_equity(D1: float, S1: float, S0: float) -> float:
    """
    Calculate cost of equity using dividend growth model.
    
    This function calculates the required rate of return for equity
    based on expected dividends and price appreciation.
    
    Args:
        D1: Expected dividend at the end of period 1
        S1: Expected stock price at the end of period 1
        S0: Current stock price (must be non-zero)
        
    Returns:
        Cost of equity as a decimal (e.g., 0.12 for 12%)
        
    Raises:
        ValueError: If S0 is zero
        
    Example:
        >>> cost_of_equity(2.0, 55.0, 50.0)
        0.14
    """
    if S0 == 0:
        raise ValueError("Current price must be nonzero")
    return (D1 + S1) / S0 - 1.0

def ddm_gordon_growth(D1: float, r: float, g: float) -> float:
    """
    Gordon growth model for dividend discount valuation.
    
    This model assumes dividends grow at a constant rate forever.
    The formula is: P0 = D1 / (r - g)
    
    Args:
        D1: Expected dividend in the next period
        r: Required rate of return (as decimal, e.g., 0.12 for 12%)
        g: Constant growth rate of dividends (as decimal, e.g., 0.05 for 5%)
        
    Returns:
        Present value of the stock under constant growth
        
    Raises:
        ValueError: If growth rate is greater than or equal to discount rate
        
    Example:
        >>> ddm_gordon_growth(2.0, 0.12, 0.05)
        28.571...
    """
    if g >= r:
        raise ValueError("Growth rate must be less than discount rate for convergence")
    return D1 / (r - g)