docs: def _scobit_transform_deriv_shape(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 have shape `(systematic_utilities.shape[0],
          shape_params.shape[0])`. It's data is to be replaced with the correct
          derivatives of the transformation vector with respect to the vector of
          shape parameters. This argument is NOT optional.
  
      Returns
      -------
      output_array : 2D scipy sparse array.
          The shape of the returned array is `(systematic_utilities.shape[0],
          shape_params.shape[0])`. The returned array specifies the derivative of
          the transformed utilities with respect to the shape parameters. All
          elements are ints, floats, or longs.
      """
      # Note the np.exp is needed because the raw curvature params are the log
      # of the 'natural' curvature params. This is to ensure the natural shape
      # params are always positive.
      curve_shapes = np.exp(shape_params)
      curve_shapes[np.isposinf(curve_shapes)] = max_comp_value
      long_curve_shapes = rows_to_alts.dot(curve_shapes)
  
      # Generate the needed terms for the derivative of the transformation with
      # respect to the systematic utility and guard against underflow or overflow
      exp_neg_v = np.exp(-1 * systematic_utilities)
  
      powered_term = np.power(1 + exp_neg_v, long_curve_shapes)
  
      # Note the "* long_curve_shapes" accounts for the fact that the derivative
      # of the natural shape params (i.e. exp(shape_param)) with respect to the
      # shape param is simply exp(shape_param) = natural shape param. The
      # multipication comes from the chain rule.
      curve_derivs = (-1 * np.log1p(exp_neg_v) *
                      powered_term / (powered_term - 1)) * long_curve_shapes
      # Note that all of the following overflow and underflow guards are based
      # on L'Hopital's rule.
      # Guard against underflow from v --> inf. Note we end up with '-1' after
      # accounting for the jacobian.
      too_big_idx = np.where((powered_term - 1) == 0)
      curve_derivs[too_big_idx] = -1
      # Guard against overflow from v --> -inf.
      too_small_idx = np.isposinf(exp_neg_v)
      curve_derivs[too_small_idx] = max_comp_value
      # Guard against overflow from moderate v but shape --> inf.
      shape_too_big_idx = np.where((np.abs(systematic_utilities) <= 10) &
                                   np.isposinf(powered_term))
      curve_derivs[shape_too_big_idx] =\
          (-1 * np.log1p(exp_neg_v))[shape_too_big_idx]
  
      # Assign the calculated derivatives to the output array
      output_array.data = curve_derivs
  
      return output_array