<commit_before># @!visibility private
module GamesDice::ProbabilityValidations

  # TODO: Copy class methods over on include
  def included
    super
  end

  private

  def check_probs_array probs_array
    raise TypeError unless probs_array.is_a?( Array )
    probs_array.map!{ |n| Float(n) }
    total = probs_array.inject(0.0) do |t,x|
      if x < 0.0 || x > 1.0
        raise ArgumentError, "Found probability value #{x} which is not in range 0.0..1.0"
      end
      t+x
    end
    if (total-1.0).abs > 1e-6
      raise ArgumentError, "Total probabilities too far from 1.0 for a valid distribution"
    end
    probs_array
  end

  def check_keep_mode kmode
    raise "Keep mode #{kmode.inspect} not recognised" unless [:keep_best,:keep_worst].member?( kmode )
  end
end

# @!visibility private
# This module is a set of related private methods from GamesDice::Probabilities, extracted
# to a single place to keep complexity manageable.
module GamesDice::ProbabilityCalcAddDistributions
  private

  def mult_combos m_a, pd_a, m_b, pd_b
    all_minmax_combinations.map do |pda_meth, pdb_meth|
      m_a * pd_a.send(pda_meth) + m_b * pd_b.send(pdb_meth)
    end
  end

  def all_minmax_combinations
    [ [ :min, :min ], [ :min, :max ], [ :max, :min ], [ :max, :max ] ]
  end

  def add_distributions_internal combined_min, combined_max, m_a, pd_a, m_b, pd_b
    new_probs = Array.new( 1 + combined_max - combined_min, 0.0 )
    probs_a, offset_a = pd_a.to_ao
    probs_b, offset_b = pd_b.to_ao

    probs_a.each_with_index do |pa,i|
      probs_b.each_with_index do |pb,j|
        k = m_a * (i + offset_a) + m_b * (j + offset_b) - combined_min
        pc = pa * pb
        new_probs[ k ] += pc
      end
    end
    GamesDice::Probabilities.new( new_probs, combined_min )
  end
end


# @!visibility private
# This module is a set of related private methods from GamesDice::Probabilities, extracted
# to a single place to keep complexity manageable.
module GamesDice::ProbabilityCalcSums

  private

  def repeat_sum_internal( n )
    pd_power = self
    pd_result = nil

    use_power = 1
    loop do
      if ( use_power & n ) > 0
        if pd_result
          pd_result = GamesDice::Probabilities.add_distributions( pd_result, pd_power )
        else
          pd_result = pd_power
        end
      end
      use_power = use_power << 1
      break if use_power > n
      pd_power = GamesDice::Probabilities.add_distributions( pd_power, pd_power )
    end
    pd_result
  end

  def repeat_n_sum_k_internal( n, k, kmode )
    if k >= n
      return repeat_sum_internal( n )<commit_msg>Improved decsriptive comments on 'private' probability modules<commit_after># @!visibility private
module GamesDice::ProbabilityValidations

  # TODO: Copy class methods over on include
  def included
    super
  end

  private

  def check_probs_array probs_array
    raise TypeError unless probs_array.is_a?( Array )
    probs_array.map!{ |n| Float(n) }
    total = probs_array.inject(0.0) do |t,x|
      if x < 0.0 || x > 1.0
        raise ArgumentError, "Found probability value #{x} which is not in range 0.0..1.0"
      end
      t+x
    end
    if (total-1.0).abs > 1e-6
      raise ArgumentError, "Total probabilities too far from 1.0 for a valid distribution"
    end
    probs_array
  end

  def check_keep_mode kmode
    raise "Keep mode #{kmode.inspect} not recognised" unless [:keep_best,:keep_worst].member?( kmode )
  end
end

# @!visibility private
# This module is a set of related private methods for GamesDice::Probabilities that
# calculate how two distributions can be combined.
module GamesDice::ProbabilityCalcAddDistributions
  private

  def mult_combos m_a, pd_a, m_b, pd_b
    all_minmax_combinations.map do |pda_meth, pdb_meth|
      m_a * pd_a.send(pda_meth) + m_b * pd_b.send(pdb_meth)
    end
  end

  def all_minmax_combinations
    [ [ :min, :min ], [ :min, :max ], [ :max, :min ], [ :max, :max ] ]
  end

  def add_distributions_internal combined_min, combined_max, m_a, pd_a, m_b, pd_b
    new_probs = Array.new( 1 + combined_max - combined_min, 0.0 )
    probs_a, offset_a = pd_a.to_ao
    probs_b, offset_b = pd_b.to_ao

    probs_a.each_with_index do |pa,i|
      probs_b.each_with_index do |pb,j|
        k = m_a * (i + offset_a) + m_b * (j + offset_b) - combined_min
        pc = pa * pb
        new_probs[ k ] += pc
      end
    end
    GamesDice::Probabilities.new( new_probs, combined_min )
  end
end


# @!visibility private
# This module is a set of related private methods for GamesDice::Probabilities that
# calculate how a distribution can be combined with itself.
module GamesDice::ProbabilityCalcSums

  private

  def repeat_sum_internal( n )
    pd_power = self
    pd_result = nil

    use_power = 1
    loop do
      if ( use_power & n ) > 0
        if pd_result
          pd_result = GamesDice::Probabilities.add_distributions( pd_result, pd_power )
        else
          pd_result = pd_power
        end
      end
      use_power = use_power << 1
      break if use_power > n
      pd_power = GamesDice::Probabilities.add_distributions( pd_power, pd_power )
    end
    pd_result
  end

  def repeat_n_sum_k_internal( n, k, kmode )
    if k >= n
      return repeat_sum_internal( n )
{'fraction_non_alphanumeric': 0.08476517754868271, 'fraction_numerical': 0.008400152730049638, 'mean_word_length': 2.9302325581395348, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 13, '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': '5500732', 'n_tokens_mistral': 1898, 'n_tokens_neox': 1820, 'n_words': 524}