<commit_before>require_relative '../support'
require_relative '../data_models'
module Bioinform
  class PWM < PM
    def score_mean
      each_position.inject(0){ |mean, position| mean + position.each_index.inject(0){|sum, letter| sum + position[letter] * probability[letter]} }
    end
    def score_variance
      each_position.inject(0) do |variance, position|
        variance  + position.each_index.inject(0) { |sum,letter| sum + position[letter]**2 * probability[letter] } -
                    position.each_index.inject(0) { |sum,letter| sum + position[letter]    * probability[letter] }**2
      end
    end

    def threshold_gauss_estimation(pvalue)
      sigma = Math.sqrt(score_variance)
      n_ = Math.inverf(1 - 2 * pvalue) * Math.sqrt(2)
      score_mean + n_ * sigma
    end

    def score(word)
      raise ArgumentError, 'word in PWM#score(word) should have the same length as matrix'  unless word.length == length
      #raise ArgumentError, 'word in PWM#score(word) should have only ACGT-letters'  unless word.each_char.all?{|letter| %w{A C G T}.include? letter}
      (0...length).map do |pos|
        letter = word[pos]
        if IndexByLetter[letter]
          matrix[pos][IndexByLetter[letter]]
        elsif letter == 'N'
          matrix[pos].zip(probability).map{|el, p| el * p}.inject(0.0, &:+)
        else
          raise ArgumentError, "word in PWM#score(#{word}) should have only ACGT or N letters"
        end
      end.inject(0.0, &:+)
    end

    def to_pwm
      self
    end

    def best_score
      @matrix.inject(0.0){|sum, col| sum + col.max}
    end
    def worst_score
      @matrix.inject(0.0){|sum, col| sum + col.min}
    end

    # best score of suffix s[i..l]
    def best_suffix(i)
      @matrix[i...length].map(&:max).inject(0.0, &:+)
    end

    def worst_suffix(i)
      @matrix[i...length].map(&:min).inject(0.0, &:+)
    end
  end
end<commit_msg>score calculation can be faster for integer matrices, so it's preferrabble to convert score to real value at the very end of calculation<commit_after>require_relative '../support'
require_relative '../data_models'
module Bioinform
  class PWM < PM
    def score_mean
      each_position.inject(0){ |mean, position| mean + position.each_index.inject(0){|sum, letter| sum + position[letter] * probability[letter]} }
    end
    def score_variance
      each_position.inject(0) do |variance, position|
        variance  + position.each_index.inject(0) { |sum,letter| sum + position[letter]**2 * probability[letter] } -
                    position.each_index.inject(0) { |sum,letter| sum + position[letter]    * probability[letter] }**2
      end
    end

    def threshold_gauss_estimation(pvalue)
      sigma = Math.sqrt(score_variance)
      n_ = Math.inverf(1 - 2 * pvalue) * Math.sqrt(2)
      score_mean + n_ * sigma
    end

    def score(word)
      raise ArgumentError, 'word in PWM#score(word) should have the same length as matrix'  unless word.length == length
      #raise ArgumentError, 'word in PWM#score(word) should have only ACGT-letters'  unless word.each_char.all?{|letter| %w{A C G T}.include? letter}
      (0...length).map do |pos|
        letter = word[pos]
        if IndexByLetter[letter]
          matrix[pos][IndexByLetter[letter]]
        elsif letter == 'N'
          matrix[pos].zip(probability).map{|el, p| el * p}.inject(0, &:+)
        else
          raise ArgumentError, "word in PWM#score(#{word}) should have only ACGT or N letters"
        end
      end.inject(0, &:+).to_f
    end

    def to_pwm
      self
    end

    def best_score
      @matrix.inject(0.0){|sum, col| sum + col.max}
    end
    def worst_score
      @matrix.inject(0.0){|sum, col| sum + col.min}
    end

    # best score of suffix s[i..l]
    def best_suffix(i)
      @matrix[i...length].map(&:max).inject(0.0, &:+)
    end

    def worst_suffix(i)
      @matrix[i...length].map(&:min).inject(0.0, &:+)
    end
  end
end
{'fraction_non_alphanumeric': 0.1324351804778851, 'fraction_numerical': 0.011184544992374174, 'mean_word_length': 2.7333965844402277, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, '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': '646610', 'n_tokens_mistral': 1331, 'n_tokens_neox': 1289, 'n_words': 324}