inline void LogSoftmax(const SoftmaxParams& params,
                       const RuntimeShape& input_shape, const float* input_data,
                       const RuntimeShape& output_shape, float* output_data) {
  ruy::profiler::ScopeLabel label("LogSoftmax");
  const int trailing_dim = input_shape.DimensionsCount() - 1;
  const int outer_size =
      MatchingFlatSizeSkipDim(input_shape, trailing_dim, output_shape);
  const int depth =
      MatchingDim(input_shape, trailing_dim, output_shape, trailing_dim);

  for (int i = 0; i < outer_size; ++i) {
    VectorMap<const float> block_input(input_data + i * depth, depth, 1);
    VectorMap<float> block_output(output_data + i * depth, depth, 1);
    // Find max element value which we'll use to ensure numerical stability
    // taking advantage of the following equality:
    // log(exp(x[i])/sum(exp(x[i]))) == log(exp(x[i]+C)/sum(exp(x[i]+C)))
    const float max = block_input.maxCoeff();
    const float log_sum = std::log((block_input.array() - max).exp().sum());
    block_output = block_input.array() - max - log_sum;
  }
}
inline void LogSoftmax(const SoftmaxParams& params,
                       const RuntimeShape& input_shape, const float* input_data,
                       const RuntimeShape& output_shape, float* output_data) {
  ruy::profiler::ScopeLabel label("LogSoftmax");
  const int trailing_dim = input_shape.DimensionsCount() - 1;
  const int outer_size =
      MatchingFlatSizeSkipDim(input_shape, trailing_dim, output_shape);
  const int depth =
      MatchingDim(input_shape, trailing_dim, output_shape, trailing_dim);

  for (int i = 0; i < outer_size; ++i) {
    VectorMap<const float> block_input(input_data + i * depth, depth, 1);
    VectorMap<float> block_output(output_data + i * depth, depth, 1);
     
     
     
    const float max = block_input.maxCoeff();
    const float log_sum = std::log((block_input.array() - max).exp().sum());
    block_output = block_input.array() - max - log_sum;
  }
}