def number_of_partitions(max_range, max_sum):
    '''
    Returns an array arr of the same shape as max_range, where
    arr[j] = number of admissible partitions for 
             j summands bounded by max_range[j:] and with sum <= max_sum
    '''
    M = max_sum + 1
    N = len(max_range) 
    arr = np.zeros(shape=(M,N), dtype = int)    
    arr[:,-1] = np.where(np.arange(M) <= min(max_range[-1], max_sum), 1, 0)
    for i in range(N-2,-1,-1):
        for j in range(max_range[i]+1):
            arr[j:,i] += arr[:M-j,i+1] 
    return arr.sum(axis = 0)
Returns an array arr of the same shape as max_range, where
    arr[j] = number of admissible partitions for 
             j summands bounded by max_range[j:] and with sum <= max_sum