def calcLogSum(Vals, sigma):
    '\n    Returns the optimal value given the choice specific value functions Vals.\n    Parameters\n    ----------\n    Vals : [numpy.array]\n        A numpy.array that holds choice specific values at common grid points.\n    sigma : float\n        A number that controls the variance of the taste shocks\n    Returns\n    -------\n    V : [numpy.array]\n        A numpy.array that holds the integrated value function.\n    '
    if (sigma == 0.0):
        V = np.amax(Vals, axis=0)
        return V
    maxV = np.max(Vals, axis=0)
    sumexp = np.sum(np.exp(((Vals - maxV) / sigma)), axis=0)
    LogSumV = np.log(sumexp)
    LogSumV = (maxV + (sigma * LogSumV))
    return LogSumV
Returns the optimal value given the choice specific value functions Vals.
Parameters
----------
Vals : [numpy.array]
    A numpy.array that holds choice specific values at common grid points.
sigma : float
    A number that controls the variance of the taste shocks
Returns
-------
V : [numpy.array]
    A numpy.array that holds the integrated value function.
def calcLogSum(Vals, sigma):
    '\n    Returns the optimal value given the choice specific value functions Vals.\n    Parameters\n    ----------\n    Vals : [numpy.array]\n        A numpy.array that holds choice specific values at common grid points.\n    sigma : float\n        A number that controls the variance of the taste shocks\n    Returns\n    -------\n    V : [numpy.array]\n        A numpy.array that holds the integrated value function.\n    '
    if (sigma == 0.0):
        V = np.amax(Vals, axis=0)
        return V
    maxV = np.max(Vals, axis=0)
    sumexp = np.sum(np.exp(((Vals - maxV) / sigma)), axis=0)
    LogSumV = np.log(sumexp)
    LogSumV = (maxV + (sigma * LogSumV))
    return LogSumV