docs: def calc_nested_log_likelihood(nest_coefs,
                                 index_coefs,
                                 design,
                                 rows_to_obs,
                                 rows_to_nests,
                                 choice_vector,
                                 ridge=None,
                                 weights=None,
                                 *args,
                                 **kwargs):
      """
      Parameters
      ----------
      nest_coefs : 1D or 2D ndarray.
          All elements should by ints, floats, or longs. If 1D, should have 1
          element for each nesting coefficient being estimated. If 2D, should
          have 1 column for each set of nesting coefficients being used to
          predict the probabilities of each alternative being chosen. There
          should be one row per nesting coefficient. Elements denote the inverse
          of the scale coefficients for each of the lower level nests.
      index_coefs : 1D or 2D ndarray.
          All elements should by ints, floats, or longs. If 1D, should have 1
          element for each utility coefficient being estimated
          (i.e. num_features). If 2D, should have 1 column for each set of
          coefficients being used to predict the probabilities of choosing each
          alternative. There should be one row per index coefficient.
      design : 2D ndarray.
          There should be one row per observation per available alternative.
          There should be one column per utility coefficient being estimated. All
          elements should be ints, floats, or longs.
      rows_to_obs : 2D scipy sparse array.
          There should be one row per observation per available alternative and
          one column per observation. This matrix maps the rows of the design
          matrix to the unique observations (on the columns).
      rows_to_nests : 2D scipy sparse array.
          There should be one row per observation per available alternative and
          one column per nest. This matrix maps the rows of the design matrix to
          the unique nests (on the columns).
      choice_vector : 1D ndarray.
          All elements should be either ones or zeros. There should be one row
          per observation per available alternative for the given observation.
          Elements denote the alternative which is chosen by the given
          observation with a 1 and a zero otherwise.
      ridge : int, float, long, or None, optional.
          Determines whether or not ridge regression is performed. If an int,
          float or long is passed, then that scalar determines the ridge penalty
          for the optimization. Default = None.
      weights : 1D ndarray or None, optional.
          Allows for the calculation of weighted log-likelihoods. The weights can
          represent various things. In stratified samples, the weights may be
          the proportion of the observations in a given strata for a sample in
          relation to the proportion of observations in that strata in the
          population. In latent class models, the weights may be the probability
          of being a particular class.
  
      Returns
      -------
      log_likelihood : float.
          The log likelihood of the nested logit model. Includes ridge penalty if
          a penalized regression is being performed.
      """
      # Calculate the probability of each individual choosing each available
      # alternative for that individual.
      long_probs = calc_nested_probs(nest_coefs,
                                     index_coefs,
                                     design,
                                     rows_to_obs,
                                     rows_to_nests,
                                     return_type='long_probs')
  
      # Calculate the weights for the sample
      if weights is None:
          weights = 1
  
      # Calculate the log likelihood
      log_likelihood = choice_vector.dot(weights * np.log(long_probs))
  
      if ridge is None:
          return log_likelihood
      else:
          # Note that the 1.0 is used since the 'null' nest coefficient is equal
          # to 1.0.
          params = np.concatenate(((nest_coefs - 1.0), index_coefs), axis=0)
  
          return log_likelihood - ridge * np.square(params).sum()