def calcLogSumChoiceProbs(Vals, sigma):
    '\n    Returns the final optimal value and choice probabilities given the choice\n    specific value functions `Vals`. Probabilities are degenerate if sigma == 0.0.\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    P : [numpy.array]\n        A numpy.array that holds the discrete choice probabilities\n    '
    if (sigma == 0.0):
        Pflat = np.argmax(Vals, axis=0)
        V = np.zeros(Vals[0].shape)
        Probs = np.zeros(Vals.shape)
        for i in range(Vals.shape[0]):
            optimalIndices = (Pflat == i)
            V[optimalIndices] = Vals[i][optimalIndices]
            Probs[i][optimalIndices] = 1
        return (V, Probs)
    maxV = np.max(Vals, axis=0)
    sumexp = np.sum(np.exp(((Vals - maxV) / sigma)), axis=0)
    LogSumV = np.log(sumexp)
    LogSumV = (maxV + (sigma * LogSumV))
    Probs = np.exp(((Vals - LogSumV) / sigma))
    return (LogSumV, Probs)
Returns the final optimal value and choice probabilities given the choice
specific value functions `Vals`. Probabilities are degenerate if sigma == 0.0.
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.
P : [numpy.array]
    A numpy.array that holds the discrete choice probabilities
def calcLogSumChoiceProbs(Vals, sigma):
    '\n    Returns the final optimal value and choice probabilities given the choice\n    specific value functions `Vals`. Probabilities are degenerate if sigma == 0.0.\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    P : [numpy.array]\n        A numpy.array that holds the discrete choice probabilities\n    '
    if (sigma == 0.0):
        Pflat = np.argmax(Vals, axis=0)
        V = np.zeros(Vals[0].shape)
        Probs = np.zeros(Vals.shape)
        for i in range(Vals.shape[0]):
            optimalIndices = (Pflat == i)
            V[optimalIndices] = Vals[i][optimalIndices]
            Probs[i][optimalIndices] = 1
        return (V, Probs)
    maxV = np.max(Vals, axis=0)
    sumexp = np.sum(np.exp(((Vals - maxV) / sigma)), axis=0)
    LogSumV = np.log(sumexp)
    LogSumV = (maxV + (sigma * LogSumV))
    Probs = np.exp(((Vals - LogSumV) / sigma))
    return (LogSumV, Probs)