docs: def _cloglog_transform_deriv_v(systematic_utilities,
                                 alt_IDs,
                                 rows_to_alts,
                                 shape_params,
                                 output_array=None,
                                 *args, **kwargs):
      """
      Parameters
      ----------
      systematic_utilities : 1D ndarray.
          All elements should be ints, floats, or longs. Should contain the
          systematic utilities of each observation per available alternative.
          Note that this vector is formed by the dot product of the design matrix
          with the vector of utility coefficients.
      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_alts : 2D scipy sparse matrix.
          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. All
          elements should be zeros or ones.
      shape_params : None or 1D ndarray.
          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.
      output_array : 2D scipy sparse array.
          The array should be square and it should have
          `systematic_utilities.shape[0]` rows. It's data is to be replaced with
          the correct derivatives of the transformation vector with respect to
          the vector of systematic utilities. This argument is NOT optional.
  
      Returns
      -------
      output_array : 2D scipy sparse array.
          The shape of the returned array is `(systematic_utilities.shape[0],
          systematic_utilities.shape[0])`. The returned array specifies the
          derivative of the transformed utilities with respect to the systematic
          utilities. All elements are ints, floats, or longs.
      """
      exp_neg_v = np.exp(-1 * systematic_utilities)
      exp_v = np.exp(systematic_utilities)
      denom_part_1 = 1 - np.exp(-1 * exp_v)
  
      ##########
      # Guard against numeric overflow and underflow
      ##########
      exp_neg_v[np.isposinf(exp_neg_v)] = max_comp_value
      exp_neg_v[np.where(exp_neg_v == 0)] = min_comp_value
      # Note that we don't care about the limiting cases of exp_v.
      # This term can go to positive infinity or zero. If it goes to positive
      # infinity, then this is okay because denom_part_1 will just go to 1.
      # If exp_v goes to zero, then denom_part_1 will go to zero. We will simply
      # cater to that last outcome since we can't divide by zero. The next line
      # is retained to show what should NOT be done. We will use L'Hopital's rule
      # after calculating derivs, as should be done.
      # denom_part_1[np.where(denom_part_1 == 0)] = min_comp_value
  
      ##########
      # Calculate the required derivatives and guard against underflow
      ##########
      derivs = 1.0 / (denom_part_1 * exp_neg_v)
      # Note that the limiting value of the expression above, as the systematic
      # utility goes to negative infinity (i.e. as denom_part_1 goes to zero),
      # is one. This can be checked using L'Hopital's rule. We will define
      # infinity as being so negative that `denom_part_1 == 0`
      derivs[np.where(denom_part_1 == 0)] = 1
      derivs[np.isposinf(derivs)] = max_comp_value
  
      # Assign the calculated derivatives to the output array
      output_array.data = derivs
  
      # Return the matrix of dh_dv. Note the off-diagonal entries are zero
      # because each transformation only depends on its value of v and no others
      return output_array