docs: def calc_log_likelihood(beta,
                          design,
                          alt_IDs,
                          rows_to_obs,
                          rows_to_alts,
                          choice_vector,
                          utility_transform,
                          intercept_params=None,
                          shape_params=None,
                          ridge=None,
                          weights=None):
      """
      Parameters
      ----------
      beta : 1D ndarray.
          All elements should by ints, floats, or longs. Should have 1 element
          for each utility coefficient being estimated (i.e. num_features).
      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.
      alt_IDs : 1D ndarray.
          All elements should be ints. There should be one row per obervation per
          available alternative for the given observation. Elements denote the
          alternative corresponding to the given row of the design matrix.
      rows_to_obs : 2D ndarray.
          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_alts : 2D ndarray.
          There should be one row per observation per available alternative and
          one column per possible alternative. This matrix maps the rows of the
          design matrix to the possible alternatives for this dataset.
      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.
      utility_transform:  callable.
          Should accept a 1D array of systematic utility values, a 1D array of
          alternative IDs, and miscellaneous args and kwargs. Should return a 1D
          array whose elements contain the appropriately transformed systematic
          utility values, based on the current model being evaluated.
      intercept_params:   1D ndarray, or None, optional.
          If an array, each element should be an int, float, or long. For
          identifiability, there should be J- 1 elements where J is the total
          number of observed alternatives for this dataset. Default == None.
      shape_params : 1D ndarray, or None, optional.
          If an array, each element should be an int, float, or long. There
          should be one value per shape parameter of the model being used.
          Default == None.
      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 multinomial choice model.
      """
      # Calculate the probability of each individual choosing each available
      # alternative for that individual.
      long_probs = calc_probabilities(beta,
                                      design,
                                      alt_IDs,
                                      rows_to_obs,
                                      rows_to_alts,
                                      utility_transform,
                                      intercept_params=intercept_params,
                                      shape_params=shape_params,
                                      return_long_probs=True)
  
      # 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:
          param_list = [x for x in [shape_params, intercept_params, beta]
                        if x is not None]
          if len(param_list) > 1:
              params = np.concatenate(param_list, axis=0)
          else:
              params = param_list[0]
          return log_likelihood - ridge * np.square(params).sum()