<commit_before>/**
 * @file hoeffding_split_impl.hpp
 * @author <NAME>
 *
 * Implementation of the HoeffdingSplit class.
 */
#ifndef __MLPACK_METHODS_HOEFFDING_TREES_HOEFFDING_SPLIT_IMPL_HPP
#define __MLPACK_METHODS_HOEFFDING_TREES_HOEFFDING_SPLIT_IMPL_HPP

namespace mlpack {
namespace tree {

template<typename FitnessFunction,
         typename NumericSplitType,
         typename CategoricalSplitType>
HoeffdingSplit<
    FitnessFunction,
    NumericSplitType,
    CategoricalSplitType
>::HoeffdingSplit(const size_t dimensionality,
                  const size_t numClasses,
                  const data::DatasetInfo& datasetInfo,
                  const double successProbability) :
    numSamples(0),
    numClasses(numClasses),
    datasetInfo(datasetInfo),
    successProbability(successProbability),
    splitDimension(size_t(-1)),
    categoricalSplit(0)
{
  for (size_t i = 0; i < dimensionality; ++i)
  {
    if (datasetInfo.Type(i) == data::Datatype::categorical)
      categoricalSplits.push_back(
          CategoricalSplitType(datasetInfo.NumMappings(i), numClasses));
    // else, numeric splits (not yet!)
  }
}

template<typename FitnessFunction,
         typename NumericSplitType,
         typename CategoricalSplitType>
template<typename VecType>
void HoeffdingSplit<
    FitnessFunction,
    NumericSplitType,
    CategoricalSplitType
>::Train(const VecType& point, const size_t label)
{
  if (splitDimension == size_t(-1))
  {
    ++numSamples;
    size_t numericIndex = 0;
    size_t categoricalIndex = 0;
    for (size_t i = 0; i < point.n_rows; ++i)
    {
      if (datasetInfo.Type(i) == data::Datatype::categorical)
        categoricalSplits[categoricalIndex++].Train(point[i], label);
      else if (datasetInfo.Type(i) == data::Datatype::numeric)
        numericSplits[numericIndex++].Train(point[i], label);
    }
  }
  else
  {
    // Already split.
    // But we should probably pass it down anyway.
  }
}

template<typename FitnessFunction,
         typename NumericSplitType,
         typename CategoricalSplitType>
size_t HoeffdingSplit<
    FitnessFunction,
    NumericSplitType,
    CategoricalSplitType
>::SplitCheck()
{
  // Do nothing if we've already split.
  if (splitDimension != size_t(-1))
    return 0;

  // Check the fitness of each dimension.  Then we'll use a Hoeffding bound
  // somehow.

  // Calculate epsilon, the value we need things to be greater than.
  const double rSquared = std::pow(FitnessFunction::Range(numClasses), 2.0);
  const double epsilon = std::sqrt(rSquared *
      std::log(1.0 / successProbability) / (2 * numSamples));

  arma::vec gains(categoricalSplits.size() + numericSplits.size());
  for (size_t i = 0; i < categoricalSplits.size(); ++i)
    gains[i] = categoricalSplits[i].EvaluateFitnessFunction();

  // Now find the largest and second-largest.
  double largest = -DBL_MAX;
  size_t largestIndex = 0;
  double secondLargest = -DBL_MAX;
  for (size_t i = 0; i < gains.n_elem; ++i)
  {
    if (gains[i] > largest)
    {
      secondLargest = largest;
      largest = gains[i];
      largestIndex = i;
    }
    else if (gains[i] > secondLargest)
    {
      secondLargest = gains[i];
    }
  }

  // Are these far enough apart to split?
  if (largest - secondLargest > epsilon)
  {
    // Split!
    splitDimension = largestIndex;
    if (datasetInfo.Type(largestIndex) == data::Datatype::categorical)
    {
      // I don't know if this should be here.
      std::cout << "split: largest index " << largestIndex << ".\n";
      majorityClass = categoricalSplits[largestIndex].MajorityClass();
      return datasetInfo.NumMappings(largestIndex);
    }
    else
    {
      majorityClass = 0;
      return 0; // I have no idea what to do yet.
    }
  }
  else
  {
    return 0; // Don't split.
  }
}

template<
    typename FitnessFunction,
    typename NumericSplitType,
    typename CategoricalSplitType
>
template<typename VecType>
size_t HoeffdingSplit<
    FitnessFunction,
    NumericSplitType,
    CategoricalSplitType
>::CalculateDirection(const VecType& point) const
{
  // Don't call this before the node is split...
  if (datasetInfo.Type(splitDimension) == data::Datatype::numeric)
    return numericSplit.CalculateDirection(point[splitDimension]);<commit_msg>Remove debugging output.<commit_after>/**
 * @file hoeffding_split_impl.hpp
 * @author <NAME>
 *
 * Implementation of the HoeffdingSplit class.
 */
#ifndef __MLPACK_METHODS_HOEFFDING_TREES_HOEFFDING_SPLIT_IMPL_HPP
#define __MLPACK_METHODS_HOEFFDING_TREES_HOEFFDING_SPLIT_IMPL_HPP

namespace mlpack {
namespace tree {

template<typename FitnessFunction,
         typename NumericSplitType,
         typename CategoricalSplitType>
HoeffdingSplit<
    FitnessFunction,
    NumericSplitType,
    CategoricalSplitType
>::HoeffdingSplit(const size_t dimensionality,
                  const size_t numClasses,
                  const data::DatasetInfo& datasetInfo,
                  const double successProbability) :
    numSamples(0),
    numClasses(numClasses),
    datasetInfo(datasetInfo),
    successProbability(successProbability),
    splitDimension(size_t(-1)),
    categoricalSplit(0)
{
  for (size_t i = 0; i < dimensionality; ++i)
  {
    if (datasetInfo.Type(i) == data::Datatype::categorical)
      categoricalSplits.push_back(
          CategoricalSplitType(datasetInfo.NumMappings(i), numClasses));
    // else, numeric splits (not yet!)
  }
}

template<typename FitnessFunction,
         typename NumericSplitType,
         typename CategoricalSplitType>
template<typename VecType>
void HoeffdingSplit<
    FitnessFunction,
    NumericSplitType,
    CategoricalSplitType
>::Train(const VecType& point, const size_t label)
{
  if (splitDimension == size_t(-1))
  {
    ++numSamples;
    size_t numericIndex = 0;
    size_t categoricalIndex = 0;
    for (size_t i = 0; i < point.n_rows; ++i)
    {
      if (datasetInfo.Type(i) == data::Datatype::categorical)
        categoricalSplits[categoricalIndex++].Train(point[i], label);
      else if (datasetInfo.Type(i) == data::Datatype::numeric)
        numericSplits[numericIndex++].Train(point[i], label);
    }
  }
  else
  {
    // Already split.
    // But we should probably pass it down anyway.
  }
}

template<typename FitnessFunction,
         typename NumericSplitType,
         typename CategoricalSplitType>
size_t HoeffdingSplit<
    FitnessFunction,
    NumericSplitType,
    CategoricalSplitType
>::SplitCheck()
{
  // Do nothing if we've already split.
  if (splitDimension != size_t(-1))
    return 0;

  // Check the fitness of each dimension.  Then we'll use a Hoeffding bound
  // somehow.

  // Calculate epsilon, the value we need things to be greater than.
  const double rSquared = std::pow(FitnessFunction::Range(numClasses), 2.0);
  const double epsilon = std::sqrt(rSquared *
      std::log(1.0 / successProbability) / (2 * numSamples));

  arma::vec gains(categoricalSplits.size() + numericSplits.size());
  for (size_t i = 0; i < categoricalSplits.size(); ++i)
    gains[i] = categoricalSplits[i].EvaluateFitnessFunction();

  // Now find the largest and second-largest.
  double largest = -DBL_MAX;
  size_t largestIndex = 0;
  double secondLargest = -DBL_MAX;
  for (size_t i = 0; i < gains.n_elem; ++i)
  {
    if (gains[i] > largest)
    {
      secondLargest = largest;
      largest = gains[i];
      largestIndex = i;
    }
    else if (gains[i] > secondLargest)
    {
      secondLargest = gains[i];
    }
  }

  // Are these far enough apart to split?
  if (largest - secondLargest > epsilon)
  {
    // Split!
    splitDimension = largestIndex;
    if (datasetInfo.Type(largestIndex) == data::Datatype::categorical)
    {
      // I don't know if this should be here.
      majorityClass = categoricalSplits[largestIndex].MajorityClass();
      return datasetInfo.NumMappings(largestIndex);
    }
    else
    {
      majorityClass = 0;
      return 0; // I have no idea what to do yet.
    }
  }
  else
  {
    return 0; // Don't split.
  }
}

template<
    typename FitnessFunction,
    typename NumericSplitType,
    typename CategoricalSplitType
>
template<typename VecType>
size_t HoeffdingSplit<
    FitnessFunction,
    NumericSplitType,
    CategoricalSplitType
>::CalculateDirection(const VecType& point) const
{
  // Don't call this before the node is split...
  if (datasetInfo.Type(splitDimension) == data::Datatype::numeric)
    return numericSplit.CalculateDirection(point[splitDimension]);
{'fraction_non_alphanumeric': 0.10607852412488174, 'fraction_numerical': 0.004966887417218543, 'mean_word_length': 3.3324795081967213, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3313322', 'n_tokens_mistral': 2830, 'n_tokens_neox': 2692, 'n_words': 625}