Module: StrideAlign

Defined in:
lib/stride_align.rb,
lib/stride_align/core.rb,
lib/stride_align/batch.rb,
lib/stride_align/backend.rb,
lib/stride_align/version.rb,
lib/stride_align/keyboard.rb,
lib/stride_align/matrices.rb,
lib/stride_align/algorithms.rb,
lib/stride_align/alignment_path.rb

Defined Under Namespace

Modules: BackendKind, BmpmRuleType, DoubleMetaphoneVariant, Keyboard, MetaphoneVariant, Scorer Classes: AlignmentPath, AlignmentResult, BackendRecord, LevenshteinScorer, ScorerEntry, Scores, SubstitutionMatrix

Constant Summary collapse

NATIVE_MODULES =
{
  "generic" => "Generic",
  "sse41" => "Sse41",
  "avx2" => "Avx2",
  "avx512bwvl" => "Avx512bwvl",
  "neon" => "Neon",
  "sve" => "Sve",
  "sve2" => "Sve2",
  "lsx" => "Lsx",
  "lasx" => "Lasx",
  "vsx" => "Vsx",
  "rvv" => "Rvv"
}.freeze
VERSION =
"0.6.0"
MATRIX_NAMES =
(
  [30, 35, 40, 45, 50, 55, 60, 62, 65, 70, 75, 80, 85, 90, 100]
    .map { |level| "blosum#{level}" } +
  (10..500).step(10).map { |level| "pam#{level}" } +
  %w[nuc44 dna_match ascii_text]
).freeze

Class Method Summary collapse

Class Method Details

.__available_backend_namesObject



60
61
62
# File 'lib/stride_align.rb', line 60

def __available_backend_names
  @available_backend_names
end

.__data_directory(kind) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/stride_align.rb', line 64

def __data_directory(kind)
  installed = File.expand_path("../data/#{kind}", __dir__)
  return installed if File.directory?(installed)

  repository_relative = case kind
                        when "keyboard_data"
                          "../../../src/stride_align/matrices/keyboard_data"
                        else
                          "../../../src/stride_align/#{kind}"
                        end
  File.expand_path(repository_relative, __dir__)
end

.__native_backendObject



52
53
54
# File 'lib/stride_align.rb', line 52

def __native_backend
  @native_backend
end

.__primary_backendObject



56
57
58
# File 'lib/stride_align.rb', line 56

def __primary_backend
  @primary_backend
end

.ascii_matrix(match: 1, mismatch: -1,, name: "ASCII", gap_score: -1,, gap_open: nil, gap_extend: nil) ⇒ Object



181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/stride_align/matrices.rb', line 181

def ascii_matrix(match: 1, mismatch: -1, name: "ASCII", gap_score: -1,
                 gap_open: nil, gap_extend: nil)
  symbols = (0..127).map(&:chr)
  values = Array.new(128) { Array.new(128, mismatch) }
  128.times { |index| values[index][index] = match }
  128.times do |index|
    values[127][index] = mismatch
    values[index][127] = mismatch
  end
  SubstitutionMatrix.new(
    name: name, alphabet: symbols.join, matrix: values,
    gap_score: gap_score, wildcard: symbols[127],
    gap_open: gap_open, gap_extend: gap_extend
  )
end

.available_backendsObject



33
34
35
36
37
# File 'lib/stride_align/backend.rb', line 33

def available_backends
  stride_available_backends.map do |name|
    BackendRecord.new(kind: name, name: name, compiled: true, available: true)
  end
end

.backend_is_available(kind) ⇒ Object



39
40
41
# File 'lib/stride_align/backend.rb', line 39

def backend_is_available(kind)
  __available_backend_names.include?(kind.to_s)
end

.beider_morse(input, rule_type: BmpmRuleType::APPROX, concat: true, max_phonemes: 20) ⇒ Object



194
195
196
197
198
199
200
# File 'lib/stride_align/algorithms.rb', line 194

def beider_morse(input, rule_type: BmpmRuleType::APPROX,
                 concat: true, max_phonemes: 20)
  register_bmpm_resources
  unary(input) do |value|
    __primary_backend.beider_morse(value, rule_type, concat, max_phonemes)
  end
end

.caverphone(input) ⇒ Object



172
173
174
# File 'lib/stride_align/algorithms.rb', line 172

def caverphone(input)
  unary(input) { |value| __primary_backend.caverphone(value) }
end

.cdist(queries, targets, scorer: nil, matrix: nil, match_score: 2, mismatch_score: -1,, gap_score: -1,, gap_open_score: nil, gap_extend_score: nil, width: nil, tqdm: nil, cpu_count: 0, prefix_weight: 0.1, prefix_threshold: 0.7, prefix_cap: 4) ⇒ Object



392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
# File 'lib/stride_align/batch.rb', line 392

def cdist(queries, targets, scorer: nil, matrix: nil,
          match_score: 2, mismatch_score: -1, gap_score: -1,
          gap_open_score: nil, gap_extend_score: nil, width: nil,
          tqdm: nil, cpu_count: 0, prefix_weight: 0.1,
          prefix_threshold: 0.7, prefix_cap: 4)
  _ = cpu_count
  queries = target_array(queries)
  targets = target_array(targets)
  if scorer.nil?
    raise ArgumentError, "cdist requires either scorer or matrix" if matrix.nil?
    scorer = Scorer::SMITH_WATERMAN
  end
  entry = resolve_scorer(scorer)
  if matrix && ![Scorer::SMITH_WATERMAN, Scorer::NEEDLEMAN_WUNSCH].include?(entry.id)
    raise ArgumentError,
          "matrix cdist requires a Smith-Waterman or Needleman-Wunsch scorer"
  end

  progress = nil
  if tqdm
    raise ArgumentError, "tqdm must respond to call" unless tqdm.respond_to?(:call)
    progress = tqdm.call(queries.length)
    unless progress.respond_to?(:update) && progress.respond_to?(:close)
      raise ArgumentError, "tqdm progress object must provide update and close"
    end
  end

  begin
    queries.map do |query|
      options = {}
      if (12..15).cover?(entry.id)
        options.merge!(
          match_score: match_score, mismatch_score: mismatch_score,
          gap_score: gap_score, gap_open_score: gap_open_score,
          gap_extend_score: gap_extend_score, width: width
        )
        options[:matrix] = matrix if matrix
      elsif entry.id == Scorer::JARO_WINKLER
        options.merge!(
          prefix_weight: prefix_weight,
          prefix_threshold: prefix_threshold,
          prefix_cap: prefix_cap
        )
      end
      row = if options.empty?
              public_send(entry.batch_method, query, targets)
            else
              public_send(entry.batch_method, query, targets, **options)
            end
      progress.update(1) if progress
      row
    end
  ensure
    progress.close if progress
  end
end

.cdist_above_threshold(queries, targets, scorer: nil, threshold:, matrix: nil, **kwargs) ⇒ Object



449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
# File 'lib/stride_align/batch.rb', line 449

def cdist_above_threshold(queries, targets, scorer: nil, threshold:,
                          matrix: nil, **kwargs)
  if scorer.nil? && matrix.nil?
    raise ArgumentError, "cdist_above_threshold requires either scorer or matrix"
  end
  resolved = scorer.nil? ? Scorer::SMITH_WATERMAN : scorer
  entry = resolve_scorer(resolved)
  if matrix.nil? && !entry.normalized
    raise ArgumentError,
          "cdist_above_threshold requires a normalized or similarity scorer"
  end
  finite_number(threshold, "threshold")
  if matrix.nil? && !threshold.between?(0, 1)
    raise ArgumentError, "threshold must be between 0 and 1"
  end
  clean_queries = target_array(queries)
  clean_targets = target_array(targets)
  scores = cdist(
    clean_queries, clean_targets, scorer: resolved, matrix: matrix, **kwargs
  )
  output = []
  scores.each_with_index do |row, query_index|
    row.each_with_index do |score, target_index|
      next if score.nil? || score < threshold
      output << {
        score: score, query: clean_queries[query_index],
        target: clean_targets[target_index], query_index: query_index,
        target_index: target_index
      }
    end
  end
  output
end

.cdist_top_k(queries, targets, scorer: nil, k:, matrix: nil, reject_duplicates: false, **kwargs) ⇒ Object



483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
# File 'lib/stride_align/batch.rb', line 483

def cdist_top_k(queries, targets, scorer: nil, k:, matrix: nil,
                reject_duplicates: false, **kwargs)
  if scorer.nil? && matrix.nil?
    raise ArgumentError, "cdist_top_k requires either scorer or matrix"
  end
  resolved = scorer.nil? ? Scorer::SMITH_WATERMAN : scorer
  entry = resolve_scorer(resolved)
  if matrix.nil? && !entry.normalized
    raise ArgumentError, "cdist_top_k requires a normalized or similarity scorer"
  end
  if matrix && reject_duplicates
    raise ArgumentError, "reject_duplicates is not supported with matrix"
  end
  k = non_negative_integer(k, "k")
  clean_queries = target_array(queries)
  clean_targets = target_array(targets)
  scores = cdist(
    clean_queries, clean_targets, scorer: resolved, matrix: matrix, **kwargs
  )
  values = []
  scores.each_with_index do |row, query_index|
    row.each_with_index do |score, target_index|
      next if score.nil?
      next if reject_duplicates && clean_queries[query_index] == clean_targets[target_index]
      values << {
        score: score, query: clean_queries[query_index],
        target: clean_targets[target_index], query_index: query_index,
        target_index: target_index
      }
    end
  end
  values.sort_by { |item| [-item[:score], item[:query_index], item[:target_index]] }
        .first(k)
end

.cdist_top_k_per_query(queries, targets, scorer:, k: 5, pruning: false, cpu_count: 0, prefix_weight: 0.1, prefix_threshold: 0.7, prefix_cap: 4) ⇒ Object



518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
# File 'lib/stride_align/batch.rb', line 518

def cdist_top_k_per_query(queries, targets, scorer:, k: 5,
                          pruning: false, cpu_count: 0,
                          prefix_weight: 0.1,
                          prefix_threshold: 0.7, prefix_cap: 4)
  _ = [pruning, cpu_count]
  clean_queries = target_array(queries)
  clean_targets = target_array(targets)
  entry = resolve_scorer(scorer)
  unless entry.normalized
    raise ArgumentError,
          "cdist_top_k_per_query requires a normalized or similarity scorer"
  end
  options = entry.id == Scorer::JARO_WINKLER ? {
    prefix_weight: prefix_weight,
    prefix_threshold: prefix_threshold,
    prefix_cap: prefix_cap
  } : {}
  clean_queries.each_with_object({}) do |query, output|
    if entry.id == Scorer::HAMMING_NORMALIZED
      valid = clean_targets.each_index.select do |index|
        !query.nil? && !clean_targets[index].nil? &&
          clean_targets[index].each_char.count == query.each_char.count
      end
      subset = valid.map { |index| clean_targets[index] }
      ranked = ranked(
        subset, hamming_normalized_scores(query, subset), k, true
      )
      ranked.each { |item| item[:index] = valid[item[:index]] }
      output[query] = ranked
    else
      output[query] = top_k(query, clean_targets, scorer, k: k, **options)
    end
  end
end

.cologne_phonetic(input) ⇒ Object



176
177
178
# File 'lib/stride_align/algorithms.rb', line 176

def cologne_phonetic(input)
  unary(input) { |value| __primary_backend.cologne_phonetic(value) }
end

.cosine(query, target, n: 2) ⇒ Object



42
43
44
# File 'lib/stride_align/algorithms.rb', line 42

def cosine(query, target, n: 2)
  pairwise(query, target) { |left, right| __primary_backend.cosine(left, right, n) }
end

.cosine_similarities(query, targets, n: 2) ⇒ Object



58
59
60
# File 'lib/stride_align/algorithms.rb', line 58

def cosine_similarities(query, targets, n: 2)
  one_to_many(query, targets) { |left, right| cosine(left, right, n: n) }
end

.daitch_mokotoff(input, branching: true, folding: true) ⇒ Object



180
181
182
183
184
# File 'lib/stride_align/algorithms.rb', line 180

def daitch_mokotoff(input, branching: true, folding: true)
  unary(input) do |value|
    __primary_backend.daitch_mokotoff(value, branching, folding)
  end
end

.damerau_levenshtein_best(query, targets) ⇒ Object



340
341
342
# File 'lib/stride_align/batch.rb', line 340

def damerau_levenshtein_best(query, targets)
  best(query, targets, Scorer::DAMERAU_LEVENSHTEIN)
end

.damerau_levenshtein_normalized_best(query, targets) ⇒ Object



344
345
346
# File 'lib/stride_align/batch.rb', line 344

def damerau_levenshtein_normalized_best(query, targets)
  best(query, targets, Scorer::DAMERAU_LEVENSHTEIN_NORMALIZED)
end

.damerau_levenshtein_normalized_score(query, target) ⇒ Object



82
83
84
# File 'lib/stride_align/batch.rb', line 82

def damerau_levenshtein_normalized_score(query, target)
  stride_osa_similarity(query, target)
end

.damerau_levenshtein_normalized_scores(query, targets) ⇒ Object



205
206
207
208
209
# File 'lib/stride_align/batch.rb', line 205

def damerau_levenshtein_normalized_scores(query, targets)
  one_to_many(query, targets) do |left, right|
    damerau_levenshtein_normalized_score(left, right)
  end
end

.damerau_levenshtein_normalized_top_k(query, targets, k: 5) ⇒ Object



292
293
294
# File 'lib/stride_align/batch.rb', line 292

def damerau_levenshtein_normalized_top_k(query, targets, k: 5)
  top_k(query, targets, Scorer::DAMERAU_LEVENSHTEIN_NORMALIZED, k: k)
end

.damerau_levenshtein_score(query, target) ⇒ Object



78
79
80
# File 'lib/stride_align/batch.rb', line 78

def damerau_levenshtein_score(query, target)
  stride_osa(query, target)
end

.damerau_levenshtein_scores(query, targets) ⇒ Object



201
202
203
# File 'lib/stride_align/batch.rb', line 201

def damerau_levenshtein_scores(query, targets)
  one_to_many(query, targets) { |left, right| damerau_levenshtein_score(left, right) }
end

.damerau_levenshtein_top_k(query, targets, k: 5) ⇒ Object



288
289
290
# File 'lib/stride_align/batch.rb', line 288

def damerau_levenshtein_top_k(query, targets, k: 5)
  top_k(query, targets, Scorer::DAMERAU_LEVENSHTEIN, k: k)
end

.detect_best_backendObject



43
44
45
# File 'lib/stride_align/backend.rb', line 43

def detect_best_backend
  stride_backend
end

.dice(query, target, n: 2) ⇒ Object



38
39
40
# File 'lib/stride_align/algorithms.rb', line 38

def dice(query, target, n: 2)
  pairwise(query, target) { |left, right| __primary_backend.dice(left, right, n) }
end

.dice_similarities(query, targets, n: 2) ⇒ Object



54
55
56
# File 'lib/stride_align/algorithms.rb', line 54

def dice_similarities(query, targets, n: 2)
  one_to_many(query, targets) { |left, right| dice(left, right, n: n) }
end

.double_metaphone(input, max_length: 64, variant: DoubleMetaphoneVariant::COMMONS) ⇒ Object



186
187
188
189
190
191
192
# File 'lib/stride_align/algorithms.rb', line 186

def double_metaphone(input, max_length: 64,
                     variant: DoubleMetaphoneVariant::COMMONS)
  unary(input) do |value|
    result = __primary_backend.double_metaphone(value, max_length, variant)
    result.nil? ? nil : { primary: result[0], alternate: result[1] }
  end
end

.dtw(query, target, window: nil, distance: nil, score_cutoff: nil) ⇒ Object



202
203
204
205
206
207
208
# File 'lib/stride_align/algorithms.rb', line 202

def dtw(query, target, window: nil, distance: nil, score_cutoff: nil)
  unless query.is_a?(Array) && target.is_a?(Array)
    raise ArgumentError, "query and target must be numeric Arrays"
  end
  distance ||= query.all? { |value| value.is_a?(Integer) } ? "l1" : "l2_squared"
  __primary_backend.dtw(query, target, window, distance.to_s, score_cutoff)
end

.dtw_distances(query, targets, window: nil, distance: nil, score_cutoff: nil) ⇒ Object

Raises:

  • (ArgumentError)


210
211
212
213
214
215
216
217
218
219
# File 'lib/stride_align/algorithms.rb', line 210

def dtw_distances(query, targets, window: nil, distance: nil,
                  score_cutoff: nil)
  raise ArgumentError, "targets must be an Array of numeric Arrays" unless targets.is_a?(Array)
  targets.map do |target|
    dtw(
      query, target, window: window, distance: distance,
      score_cutoff: score_cutoff
    )
  end
end

.extract(query, targets, scorer, k: 5, **kwargs) ⇒ Object



384
385
386
# File 'lib/stride_align/batch.rb', line 384

def extract(query, targets, scorer, k: 5, **kwargs)
  top_k(query, targets, scorer, k: k, **kwargs)
end

.extract_best(query, targets, scorer, **kwargs) ⇒ Object



388
389
390
# File 'lib/stride_align/batch.rb', line 388

def extract_best(query, targets, scorer, **kwargs)
  best(query, targets, scorer, **kwargs)
end

.hamming_best(query, targets) ⇒ Object



364
365
366
# File 'lib/stride_align/batch.rb', line 364

def hamming_best(query, targets)
  best(query, targets, Scorer::HAMMING)
end

.hamming_normalized_best(query, targets) ⇒ Object



368
369
370
# File 'lib/stride_align/batch.rb', line 368

def hamming_normalized_best(query, targets)
  best(query, targets, Scorer::HAMMING_NORMALIZED)
end

.hamming_normalized_score(query, target) ⇒ Object



122
123
124
# File 'lib/stride_align/batch.rb', line 122

def hamming_normalized_score(query, target)
  stride_hamming_similarity(query, target)
end

.hamming_normalized_scores(query, targets) ⇒ Object



239
240
241
# File 'lib/stride_align/batch.rb', line 239

def hamming_normalized_scores(query, targets)
  one_to_many(query, targets) { |left, right| hamming_normalized_score(left, right) }
end

.hamming_normalized_top_k(query, targets, k: 5) ⇒ Object



316
317
318
# File 'lib/stride_align/batch.rb', line 316

def hamming_normalized_top_k(query, targets, k: 5)
  top_k(query, targets, Scorer::HAMMING_NORMALIZED, k: k)
end

.hamming_score(query, target) ⇒ Object



118
119
120
# File 'lib/stride_align/batch.rb', line 118

def hamming_score(query, target)
  stride_hamming(query, target)
end

.hamming_scores(query, targets) ⇒ Object



235
236
237
# File 'lib/stride_align/batch.rb', line 235

def hamming_scores(query, targets)
  one_to_many(query, targets) { |left, right| hamming_score(left, right) }
end

.hamming_top_k(query, targets, k: 5) ⇒ Object



312
313
314
# File 'lib/stride_align/batch.rb', line 312

def hamming_top_k(query, targets, k: 5)
  top_k(query, targets, Scorer::HAMMING, k: k)
end

.identity_matrix(alphabet, match: 1, mismatch: 0, wildcard: "*", name: "IDENTITY", gap_score: -1,, gap_open: nil, gap_extend: nil) ⇒ Object

Raises:

  • (ArgumentError)


160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/stride_align/matrices.rb', line 160

def identity_matrix(alphabet, match: 1, mismatch: 0, wildcard: "*",
                    name: "IDENTITY", gap_score: -1,
                    gap_open: nil, gap_extend: nil)
  raise ArgumentError, "alphabet must be a String" unless alphabet.is_a?(String)

  symbols = alphabet.each_char.to_a
  symbols << wildcard unless symbols.include?(wildcard)
  values = Array.new(symbols.length) { Array.new(symbols.length, mismatch) }
  symbols.length.times { |index| values[index][index] = match }
  wildcard_index = symbols.index(wildcard)
  symbols.length.times do |index|
    values[wildcard_index][index] = mismatch
    values[index][wildcard_index] = mismatch
  end
  SubstitutionMatrix.new(
    name: name, alphabet: symbols.join, matrix: values,
    gap_score: gap_score, wildcard: wildcard,
    gap_open: gap_open, gap_extend: gap_extend
  )
end

.indel_best(query, targets) ⇒ Object



356
357
358
# File 'lib/stride_align/batch.rb', line 356

def indel_best(query, targets)
  best(query, targets, Scorer::INDEL)
end

.indel_normalized_best(query, targets) ⇒ Object



360
361
362
# File 'lib/stride_align/batch.rb', line 360

def indel_normalized_best(query, targets)
  best(query, targets, Scorer::INDEL_NORMALIZED)
end

.indel_normalized_score(query, target, score_cutoff: nil) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/stride_align/batch.rb', line 102

def indel_normalized_score(query, target, score_cutoff: nil)
  unless score_cutoff.nil? ||
         (score_cutoff.is_a?(Numeric) && score_cutoff.finite? &&
          score_cutoff.between?(0, 1))
    raise ArgumentError, "score_cutoff must be between 0 and 1"
  end
  pairwise(query, target) do |left, right|
    value = __native_backend.indel_similarity(left, right)
    if value.nil? || score_cutoff.nil?
      value
    else
      value < score_cutoff ? 0.0 : value
    end
  end
end

.indel_normalized_scores(query, targets, score_cutoff: nil) ⇒ Object



229
230
231
232
233
# File 'lib/stride_align/batch.rb', line 229

def indel_normalized_scores(query, targets, score_cutoff: nil)
  one_to_many(query, targets) do |left, right|
    indel_normalized_score(left, right, score_cutoff: score_cutoff)
  end
end

.indel_normalized_top_k(query, targets, k: 5) ⇒ Object



308
309
310
# File 'lib/stride_align/batch.rb', line 308

def indel_normalized_top_k(query, targets, k: 5)
  top_k(query, targets, Scorer::INDEL_NORMALIZED, k: k)
end

.indel_score(query, target, score_cutoff: nil) ⇒ Object



94
95
96
97
98
99
100
# File 'lib/stride_align/batch.rb', line 94

def indel_score(query, target, score_cutoff: nil)
  cutoff = score_cutoff.nil? ? nil : non_negative_integer(score_cutoff, "score_cutoff")
  pairwise(query, target) do |left, right|
    value = __native_backend.indel(left, right)
    value.nil? || cutoff.nil? ? value : [value, cutoff + 1].min
  end
end

.indel_scores(query, targets, score_cutoff: nil) ⇒ Object



223
224
225
226
227
# File 'lib/stride_align/batch.rb', line 223

def indel_scores(query, targets, score_cutoff: nil)
  one_to_many(query, targets) do |left, right|
    indel_score(left, right, score_cutoff: score_cutoff)
  end
end

.indel_top_k(query, targets, k: 5) ⇒ Object



304
305
306
# File 'lib/stride_align/batch.rb', line 304

def indel_top_k(query, targets, k: 5)
  top_k(query, targets, Scorer::INDEL, k: k)
end

.jaccard(query, target, n: 2) ⇒ Object



34
35
36
# File 'lib/stride_align/algorithms.rb', line 34

def jaccard(query, target, n: 2)
  pairwise(query, target) { |left, right| __primary_backend.jaccard(left, right, n) }
end

.jaccard_similarities(query, targets, n: 2) ⇒ Object



50
51
52
# File 'lib/stride_align/algorithms.rb', line 50

def jaccard_similarities(query, targets, n: 2)
  one_to_many(query, targets) { |left, right| jaccard(left, right, n: n) }
end

.jaro_best(query, targets) ⇒ Object



372
373
374
# File 'lib/stride_align/batch.rb', line 372

def jaro_best(query, targets)
  best(query, targets, Scorer::JARO)
end

.jaro_similarities(query, targets) ⇒ Object



243
244
245
# File 'lib/stride_align/batch.rb', line 243

def jaro_similarities(query, targets)
  one_to_many(query, targets) { |left, right| jaro_similarity(left, right) }
end

.jaro_similarity(query, target) ⇒ Object



126
127
128
# File 'lib/stride_align/batch.rb', line 126

def jaro_similarity(query, target)
  stride_jaro(query, target)
end

.jaro_top_k(query, targets, k: 5) ⇒ Object



320
321
322
# File 'lib/stride_align/batch.rb', line 320

def jaro_top_k(query, targets, k: 5)
  top_k(query, targets, Scorer::JARO, k: k)
end

.jaro_winkler_best(query, targets, **kwargs) ⇒ Object



376
377
378
# File 'lib/stride_align/batch.rb', line 376

def jaro_winkler_best(query, targets, **kwargs)
  best(query, targets, Scorer::JARO_WINKLER, **kwargs)
end

.jaro_winkler_similarities(query, targets, **kwargs) ⇒ Object



247
248
249
250
251
# File 'lib/stride_align/batch.rb', line 247

def jaro_winkler_similarities(query, targets, **kwargs)
  one_to_many(query, targets) do |left, right|
    jaro_winkler_similarity(left, right, **kwargs)
  end
end

.jaro_winkler_similarity(query, target, prefix_weight: 0.1, prefix_threshold: 0.7, prefix_cap: 4) ⇒ Object



130
131
132
133
134
135
136
# File 'lib/stride_align/batch.rb', line 130

def jaro_winkler_similarity(query, target, prefix_weight: 0.1,
                            prefix_threshold: 0.7, prefix_cap: 4)
  stride_jaro_winkler(
    query, target, prefix_weight: prefix_weight,
    prefix_threshold: prefix_threshold, prefix_cap: prefix_cap
  )
end

.jaro_winkler_top_k(query, targets, k: 5, **kwargs) ⇒ Object



324
325
326
# File 'lib/stride_align/batch.rb', line 324

def jaro_winkler_top_k(query, targets, k: 5, **kwargs)
  top_k(query, targets, Scorer::JARO_WINKLER, k: k, **kwargs)
end

.keyboardObject



25
26
27
# File 'lib/stride_align/keyboard.rb', line 25

def keyboard
  Keyboard
end

.keyboard_availableObject



95
96
97
98
99
100
101
# File 'lib/stride_align/keyboard.rb', line 95

def keyboard_available
  directory = __data_directory("keyboard_data")
  return [] unless File.directory?(directory)
  Dir[File.join(directory, "*.npy")].map do |path|
    File.basename(path, ".npy")
  end.sort
end

.keyboard_from_confusion_counts(counts, alphabet: Keyboard::ASCII_ALPHABET, name: "KEYBOARD", scale: 2, match_margin: 4, floor: nil, wildcard: alphabet.each_char.to_a.last, gap_score: -1,, gap_open: nil, gap_extend: nil) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/stride_align/keyboard.rb', line 44

def keyboard_from_confusion_counts(counts,
                                   alphabet: Keyboard::ASCII_ALPHABET,
                                   name: "KEYBOARD", scale: 2,
                                   match_margin: 4, floor: nil,
                                   wildcard: alphabet.each_char.to_a.last,
                                   gap_score: -1, gap_open: nil,
                                   gap_extend: nil)
  grid_counts = keyboard_counts_grid(counts, alphabet)
  size = grid_counts.length
  total = grid_counts.sum { |row| row.sum }
  grid = if total.zero?
           Array.new(size) do |row|
             Array.new(size) { |column| row == column ? 1 : -1 }
           end
         else
           row_totals = grid_counts.map(&:sum)
           column_totals = grid_counts.transpose.map(&:sum)
           scores = Array.new(size) { Array.new(size) }
           finite_scores = []
           size.times do |row|
             size.times do |column|
               denominator = row_totals[row] * column_totals[column]
               value = if grid_counts[row][column].zero? || denominator.zero?
                         -Float::INFINITY
                       else
                         scale * Math.log2(grid_counts[row][column] * total / denominator.to_f)
                       end
               scores[row][column] = value
               finite_scores << value if value.finite?
             end
           end
           resolved_floor = floor.nil? ? (finite_scores.min&.floor || -1) : floor
           scores.map! do |row|
             row.map do |value|
               value = resolved_floor unless value.finite?
               [[value.round, -128].max, 127].min
             end
           end
           size.times { |index| scores[index][index] = -128 }
           best_substitution = scores.flatten.max
           diagonal = [[best_substitution, 0].max + match_margin, 127].min
           size.times { |index| scores[index][index] = diagonal }
           scores
         end
  SubstitutionMatrix.new(
    name: name, alphabet: alphabet, matrix: grid,
    gap_score: gap_score, wildcard: wildcard,
    gap_open: gap_open, gap_extend: gap_extend
  )
end

.keyboard_from_npy(path, name: File.basename(path, File.extname(path)), alphabet: Keyboard::ASCII_ALPHABET, wildcard: Keyboard::ASCII_WILDCARD, transpose: false, gap_score: -1,, gap_open: nil, gap_extend: nil) ⇒ Object

Raises:

  • (ArgumentError)


29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/stride_align/keyboard.rb', line 29

def keyboard_from_npy(path, name: File.basename(path, File.extname(path)),
                      alphabet: Keyboard::ASCII_ALPHABET,
                      wildcard: Keyboard::ASCII_WILDCARD,
                      transpose: false, gap_score: -1,
                      gap_open: nil, gap_extend: nil)
  raise ArgumentError, "path must be one filename" unless path.is_a?(String)
  grid = keyboard_grid_for_alphabet(read_npy(path), alphabet)
  grid = grid.transpose if transpose
  SubstitutionMatrix.new(
    name: name, alphabet: alphabet, matrix: grid,
    gap_score: gap_score, wildcard: wildcard,
    gap_open: gap_open, gap_extend: gap_extend
  )
end

.lcs_length(query, target) ⇒ Object



20
21
22
# File 'lib/stride_align/algorithms.rb', line 20

def lcs_length(query, target)
  pairwise(query, target) { |left, right| __primary_backend.lcs_length(left, right) }
end

.lcs_substring(query, target) ⇒ Object



30
31
32
# File 'lib/stride_align/algorithms.rb', line 30

def lcs_substring(query, target)
  pairwise(query, target) { |left, right| __primary_backend.lcs_substring(left, right) }
end

.lcs_substring_length(query, target) ⇒ Object



24
25
26
27
28
# File 'lib/stride_align/algorithms.rb', line 24

def lcs_substring_length(query, target)
  pairwise(query, target) do |left, right|
    __primary_backend.lcs_substring_length(left, right)
  end
end

.levenshtein_best(query, targets) ⇒ Object



332
333
334
# File 'lib/stride_align/batch.rb', line 332

def levenshtein_best(query, targets)
  best(query, targets, Scorer::LEVENSHTEIN)
end

.levenshtein_normalized_best(query, targets) ⇒ Object



336
337
338
# File 'lib/stride_align/batch.rb', line 336

def levenshtein_normalized_best(query, targets)
  best(query, targets, Scorer::LEVENSHTEIN_NORMALIZED)
end

.levenshtein_normalized_score(query, target, score_cutoff: nil) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/stride_align/batch.rb', line 64

def levenshtein_normalized_score(query, target, score_cutoff: nil)
  cutoff = score_cutoff.nil? ? nil : non_negative_integer(score_cutoff, "score_cutoff")
  pairwise(query, target) do |left, right|
    if left.nil? || right.nil?
      nil
    else
      distance = __native_backend.levenshtein(left, right)
      distance = [distance, cutoff + 1].min unless cutoff.nil?
      longest = [left.each_char.count, right.each_char.count].max
      longest.zero? ? 1.0 : [0.0, 1.0 - distance.to_f / longest].max
    end
  end
end

.levenshtein_normalized_scores(query, targets, score_cutoff: nil) ⇒ Object



195
196
197
198
199
# File 'lib/stride_align/batch.rb', line 195

def levenshtein_normalized_scores(query, targets, score_cutoff: nil)
  one_to_many(query, targets) do |left, right|
    levenshtein_normalized_score(left, right, score_cutoff: score_cutoff)
  end
end

.levenshtein_normalized_top_k(query, targets, k: 5) ⇒ Object



284
285
286
# File 'lib/stride_align/batch.rb', line 284

def levenshtein_normalized_top_k(query, targets, k: 5)
  top_k(query, targets, Scorer::LEVENSHTEIN_NORMALIZED, k: k)
end

.levenshtein_score(query, target, score_cutoff: nil) ⇒ Object



56
57
58
59
60
61
62
# File 'lib/stride_align/batch.rb', line 56

def levenshtein_score(query, target, score_cutoff: nil)
  cutoff = score_cutoff.nil? ? nil : non_negative_integer(score_cutoff, "score_cutoff")
  pairwise(query, target) do |left, right|
    value = __native_backend.levenshtein(left, right)
    value.nil? || cutoff.nil? ? value : [value, cutoff + 1].min
  end
end

.levenshtein_scores(query, targets, score_cutoff: nil) ⇒ Object



189
190
191
192
193
# File 'lib/stride_align/batch.rb', line 189

def levenshtein_scores(query, targets, score_cutoff: nil)
  one_to_many(query, targets) do |left, right|
    levenshtein_score(left, right, score_cutoff: score_cutoff)
  end
end

.levenshtein_top_k(query, targets, k: 5) ⇒ Object



280
281
282
# File 'lib/stride_align/batch.rb', line 280

def levenshtein_top_k(query, targets, k: 5)
  top_k(query, targets, Scorer::LEVENSHTEIN, k: k)
end

.match_rating_codex(input) ⇒ Object



162
163
164
# File 'lib/stride_align/algorithms.rb', line 162

def match_rating_codex(input)
  unary(input) { |value| __primary_backend.match_rating_codex(value) }
end

.match_rating_compare(query, target) ⇒ Object



166
167
168
169
170
# File 'lib/stride_align/algorithms.rb', line 166

def match_rating_compare(query, target)
  pairwise(query, target) do |left, right|
    __primary_backend.match_rating_compare(left, right)
  end
end

.metaphone(input, variant: MetaphoneVariant::PHILIPS) ⇒ Object



146
147
148
# File 'lib/stride_align/algorithms.rb', line 146

def metaphone(input, variant: MetaphoneVariant::PHILIPS)
  unary(input) { |value| __primary_backend.metaphone(value, variant) }
end

.metaphone_equal(query, target, variant: MetaphoneVariant::PHILIPS) ⇒ Object



150
151
152
# File 'lib/stride_align/algorithms.rb', line 150

def metaphone_equal(query, target, variant: MetaphoneVariant::PHILIPS)
  phonetic_equal(query, target, :metaphone, variant)
end

.monge_elkan(query, target, inner: :jaro, processor: nil, symmetric: false) ⇒ Object

Raises:

  • (ArgumentError)


120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/stride_align/algorithms.rb', line 120

def monge_elkan(query, target, inner: :jaro, processor: nil,
                symmetric: false)
  query = scalar_query(query)
  target = scalar_query(target)
  raise ArgumentError, "query and target cannot be nil" if query.nil? || target.nil?
  query = apply_processor(query, processor)
  target = apply_processor(target, processor)
  scorer = resolve_inner_scorer(inner)
  left = query.split
  right = target.split
  return 1.0 if left.empty? && right.empty?
  return 0.0 if left.empty? || right.empty?

  forward = monge_direction(left, right, scorer)
  return forward unless symmetric
  (forward + monge_direction(right, left, scorer)) / 2.0
end

.needleman_wunsch_cigar(*args, **kwargs) ⇒ Object Also known as: needleman_wunsch_trace_cigar, needleman_wunsch_trade_cigar



133
134
135
# File 'lib/stride_align/alignment_path.rb', line 133

def needleman_wunsch_cigar(*args, **kwargs)
  needleman_wunsch_path_info(*args, **kwargs).cigar
end

.needleman_wunsch_normalized_score(query, target, **kwargs) ⇒ Object



180
181
182
183
184
# File 'lib/stride_align/batch.rb', line 180

def needleman_wunsch_normalized_score(query, target, **kwargs)
  match_score = kwargs.fetch(:match_score, 2)
  raw = needleman_wunsch_score(query, target, **kwargs)
  normalize_alignment_result(raw, query, target, false, match_score)
end

.needleman_wunsch_normalized_scores(query, targets, **kwargs) ⇒ Object



274
275
276
277
278
# File 'lib/stride_align/batch.rb', line 274

def needleman_wunsch_normalized_scores(query, targets, **kwargs)
  one_to_many(query, targets) do |left, right|
    needleman_wunsch_normalized_score(left, right, **kwargs)
  end
end

.needleman_wunsch_path(query, target, match_score: 2, mismatch_score: -1,, gap_score: -1,, gap_open_score: nil, gap_extend_score: nil, width: nil, matrix: nil) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
# File 'lib/stride_align/alignment_path.rb', line 111

def needleman_wunsch_path(query, target, match_score: 2,
                          mismatch_score: -1, gap_score: -1,
                          gap_open_score: nil, gap_extend_score: nil,
                          width: nil, matrix: nil)
  alignment_path(
    query, target, false,
    match_score: match_score, mismatch_score: mismatch_score,
    gap_score: gap_score, gap_open_score: gap_open_score,
    gap_extend_score: gap_extend_score, width: width, matrix: matrix
  )
end

.needleman_wunsch_path_info(*args, **kwargs) ⇒ Object



123
124
125
# File 'lib/stride_align/alignment_path.rb', line 123

def needleman_wunsch_path_info(*args, **kwargs)
  needleman_wunsch_path(*args, **kwargs).to_path
end

.needleman_wunsch_score(query, target, match_score: 2, mismatch_score: -1,, gap_score: -1,, gap_open_score: nil, gap_extend_score: nil, width: nil, matrix: nil) ⇒ Object



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/stride_align/batch.rb', line 156

def needleman_wunsch_score(query, target, match_score: 2,
                           mismatch_score: -1, gap_score: -1,
                           gap_open_score: nil, gap_extend_score: nil,
                           width: nil, matrix: nil)
  if matrix
    matrix_kwargs_clean(match_score, mismatch_score, width)
    return matrix_pairwise(
      query, target, matrix, false, gap_score: gap_score,
      gap_open_score: gap_open_score, gap_extend_score: gap_extend_score
    )
  end
  validate_width(width)
  alignment_score(
    query, target, false, match_score, mismatch_score, gap_score,
    gap_open_score, gap_extend_score
  )
end

.needleman_wunsch_scores(query, targets, **kwargs) ⇒ Object



268
269
270
271
272
# File 'lib/stride_align/batch.rb', line 268

def needleman_wunsch_scores(query, targets, **kwargs)
  one_to_many(query, targets) do |left, right|
    needleman_wunsch_score(left, right, **kwargs)
  end
end

.nysiis(input) ⇒ Object



154
155
156
# File 'lib/stride_align/algorithms.rb', line 154

def nysiis(input)
  unary(input) { |value| __primary_backend.nysiis(value) }
end

.nysiis_equal(query, target) ⇒ Object



158
159
160
# File 'lib/stride_align/algorithms.rb', line 158

def nysiis_equal(query, target)
  phonetic_equal(query, target, :nysiis, MetaphoneVariant::PHILIPS)
end

.overlap(query, target, n: 2) ⇒ Object



46
47
48
# File 'lib/stride_align/algorithms.rb', line 46

def overlap(query, target, n: 2)
  pairwise(query, target) { |left, right| __primary_backend.overlap(left, right, n) }
end

.overlap_similarities(query, targets, n: 2) ⇒ Object



62
63
64
# File 'lib/stride_align/algorithms.rb', line 62

def overlap_similarities(query, targets, n: 2)
  one_to_many(query, targets) { |left, right| overlap(left, right, n: n) }
end

.partial_ratio(query, target, processor: nil) ⇒ Object



78
79
80
81
82
# File 'lib/stride_align/algorithms.rb', line 78

def partial_ratio(query, target, processor: nil)
  processed_pairwise(query, target, processor) do |left, right|
    __primary_backend.partial_ratio(left, right)
  end
end

.partial_token_set_ratio(query, target, processor: nil) ⇒ Object



102
103
104
105
106
# File 'lib/stride_align/algorithms.rb', line 102

def partial_token_set_ratio(query, target, processor: nil)
  processed_pairwise(query, target, processor) do |left, right|
    __primary_backend.partial_token_set_ratio(left, right)
  end
end

.partial_token_sort_ratio(query, target, processor: nil) ⇒ Object



96
97
98
99
100
# File 'lib/stride_align/algorithms.rb', line 96

def partial_token_sort_ratio(query, target, processor: nil)
  processed_pairwise(query, target, processor) do |left, right|
    __primary_backend.partial_token_sort_ratio(left, right)
  end
end

.ratcliff_obershelp_similarities(query, targets) ⇒ Object



72
73
74
75
76
# File 'lib/stride_align/algorithms.rb', line 72

def ratcliff_obershelp_similarities(query, targets)
  one_to_many(query, targets) do |left, right|
    ratcliff_obershelp_similarity(left, right)
  end
end

.ratcliff_obershelp_similarity(query, target) ⇒ Object



66
67
68
69
70
# File 'lib/stride_align/algorithms.rb', line 66

def ratcliff_obershelp_similarity(query, target)
  pairwise(query, target) do |left, right|
    __primary_backend.ratcliff_obershelp(left, right)
  end
end

.smith_waterman_best(query, targets, **kwargs) ⇒ Object



380
381
382
# File 'lib/stride_align/batch.rb', line 380

def smith_waterman_best(query, targets, **kwargs)
  best(query, targets, Scorer::SMITH_WATERMAN, **kwargs)
end

.smith_waterman_cigar(*args, **kwargs) ⇒ Object Also known as: smith_waterman_trace_cigar, smith_waterman_trade_cigar



127
128
129
# File 'lib/stride_align/alignment_path.rb', line 127

def smith_waterman_cigar(*args, **kwargs)
  smith_waterman_path_info(*args, **kwargs).cigar
end

.smith_waterman_normalized_score(query, target, **kwargs) ⇒ Object Also known as: smith_waterman_farrar_normalized_score



174
175
176
177
178
# File 'lib/stride_align/batch.rb', line 174

def smith_waterman_normalized_score(query, target, **kwargs)
  match_score = kwargs.fetch(:match_score, 2)
  raw = smith_waterman_score(query, target, **kwargs)
  normalize_alignment_result(raw, query, target, true, match_score)
end

.smith_waterman_normalized_scores(query, targets, **kwargs) ⇒ Object Also known as: smith_waterman_farrar_normalized_scores



259
260
261
262
263
# File 'lib/stride_align/batch.rb', line 259

def smith_waterman_normalized_scores(query, targets, **kwargs)
  one_to_many(query, targets) do |left, right|
    smith_waterman_normalized_score(left, right, **kwargs)
  end
end

.smith_waterman_path(query, target, match_score: 2, mismatch_score: -1,, gap_score: -1,, gap_open_score: nil, gap_extend_score: nil, width: nil, matrix: nil) ⇒ Object



95
96
97
98
99
100
101
102
103
104
105
# File 'lib/stride_align/alignment_path.rb', line 95

def smith_waterman_path(query, target, match_score: 2,
                        mismatch_score: -1, gap_score: -1,
                        gap_open_score: nil, gap_extend_score: nil,
                        width: nil, matrix: nil)
  alignment_path(
    query, target, true,
    match_score: match_score, mismatch_score: mismatch_score,
    gap_score: gap_score, gap_open_score: gap_open_score,
    gap_extend_score: gap_extend_score, width: width, matrix: matrix
  )
end

.smith_waterman_path_info(*args, **kwargs) ⇒ Object



107
108
109
# File 'lib/stride_align/alignment_path.rb', line 107

def smith_waterman_path_info(*args, **kwargs)
  smith_waterman_path(*args, **kwargs).to_path
end

.smith_waterman_score(query, target, match_score: 2, mismatch_score: -1,, gap_score: -1,, gap_open_score: nil, gap_extend_score: nil, width: nil, matrix: nil) ⇒ Object Also known as: smith_waterman_farrar_score



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/stride_align/batch.rb', line 138

def smith_waterman_score(query, target, match_score: 2,
                         mismatch_score: -1, gap_score: -1,
                         gap_open_score: nil, gap_extend_score: nil,
                         width: nil, matrix: nil)
  if matrix
    matrix_kwargs_clean(match_score, mismatch_score, width)
    return matrix_pairwise(
      query, target, matrix, true, gap_score: gap_score,
      gap_open_score: gap_open_score, gap_extend_score: gap_extend_score
    )
  end
  validate_width(width)
  alignment_score(
    query, target, true, match_score, mismatch_score, gap_score,
    gap_open_score, gap_extend_score
  )
end

.smith_waterman_scores(query, targets, **kwargs) ⇒ Object Also known as: smith_waterman_farrar_scores



253
254
255
256
257
# File 'lib/stride_align/batch.rb', line 253

def smith_waterman_scores(query, targets, **kwargs)
  one_to_many(query, targets) do |left, right|
    smith_waterman_score(left, right, **kwargs)
  end
end

.smith_waterman_top_k(query, targets, k: 5, **kwargs) ⇒ Object



328
329
330
# File 'lib/stride_align/batch.rb', line 328

def smith_waterman_top_k(query, targets, k: 5, **kwargs)
  top_k(query, targets, Scorer::SMITH_WATERMAN, k: k, **kwargs)
end

.soundex(input) ⇒ Object



138
139
140
# File 'lib/stride_align/algorithms.rb', line 138

def soundex(input)
  unary(input) { |value| __primary_backend.soundex(value) }
end

.soundex_equal(query, target) ⇒ Object



142
143
144
# File 'lib/stride_align/algorithms.rb', line 142

def soundex_equal(query, target)
  phonetic_equal(query, target, :soundex, MetaphoneVariant::PHILIPS)
end

.stride_available_backendsObject



29
30
31
# File 'lib/stride_align/backend.rb', line 29

def stride_available_backends
  __available_backend_names.dup
end

.stride_backendObject



25
26
27
# File 'lib/stride_align/backend.rb', line 25

def stride_backend
  @backend_name
end

.stride_hamming(query, target) ⇒ Object



115
116
117
# File 'lib/stride_align/core.rb', line 115

def stride_hamming(query, target)
  pairwise(query, target) { |left, right| __native_backend.hamming(left, right) }
end

.stride_hamming_similarity(query, target) ⇒ Object



119
120
121
122
123
# File 'lib/stride_align/core.rb', line 119

def stride_hamming_similarity(query, target)
  pairwise(query, target) do |left, right|
    __native_backend.hamming_similarity(left, right)
  end
end

.stride_indel(query, target) ⇒ Object



105
106
107
# File 'lib/stride_align/core.rb', line 105

def stride_indel(query, target)
  pairwise(query, target) { |left, right| __native_backend.indel(left, right) }
end

.stride_indel_similarity(query, target) ⇒ Object



109
110
111
112
113
# File 'lib/stride_align/core.rb', line 109

def stride_indel_similarity(query, target)
  pairwise(query, target) do |left, right|
    __native_backend.indel_similarity(left, right)
  end
end

.stride_jaro(query, target) ⇒ Object



125
126
127
# File 'lib/stride_align/core.rb', line 125

def stride_jaro(query, target)
  pairwise(query, target) { |left, right| __native_backend.jaro(left, right) }
end

.stride_jaro_winkler(query, target, prefix_weight: 0.1, prefix_threshold: 0.7, prefix_cap: 4) ⇒ Object



129
130
131
132
133
134
135
136
# File 'lib/stride_align/core.rb', line 129

def stride_jaro_winkler(query, target, prefix_weight: 0.1,
                        prefix_threshold: 0.7, prefix_cap: 4)
  pairwise(query, target) do |left, right|
    __native_backend.jaro_winkler(
      left, right, prefix_weight, prefix_threshold, prefix_cap
    )
  end
end

.stride_levenshtein(query, target) ⇒ Object



75
76
77
# File 'lib/stride_align/core.rb', line 75

def stride_levenshtein(query, target)
  pairwise(query, target) { |left, right| __native_backend.levenshtein(left, right) }
end

.stride_levenshtein_similarity(query, target) ⇒ Object



79
80
81
82
83
# File 'lib/stride_align/core.rb', line 79

def stride_levenshtein_similarity(query, target)
  pairwise(query, target) do |left, right|
    __native_backend.levenshtein_similarity(left, right)
  end
end

.stride_needleman_wunsch(query, target, match_score: 2, mismatch_score: -1,, gap_score: -1)) ⇒ Object



147
148
149
150
151
152
153
154
# File 'lib/stride_align/core.rb', line 147

def stride_needleman_wunsch(query, target, match_score: 2,
                            mismatch_score: -1, gap_score: -1)
  pairwise(query, target) do |left, right|
    __native_backend.needleman_wunsch(
      left, right, match_score, mismatch_score, gap_score
    )
  end
end

.stride_needleman_wunsch_affine(query, target, match_score: 2, mismatch_score: -1,, gap_open_score: -2,, gap_extend_score: -1)) ⇒ Object



168
169
170
171
172
173
174
175
176
177
178
# File 'lib/stride_align/core.rb', line 168

def stride_needleman_wunsch_affine(query, target, match_score: 2,
                                   mismatch_score: -1,
                                   gap_open_score: -2,
                                   gap_extend_score: -1)
  pairwise(query, target) do |left, right|
    __native_backend.needleman_wunsch_affine(
      left, right, match_score, mismatch_score,
      gap_open_score, gap_extend_score
    )
  end
end

.stride_osa(query, target) ⇒ Object



85
86
87
# File 'lib/stride_align/core.rb', line 85

def stride_osa(query, target)
  pairwise(query, target) { |left, right| __native_backend.osa(left, right) }
end

.stride_osa_similarity(query, target) ⇒ Object



89
90
91
# File 'lib/stride_align/core.rb', line 89

def stride_osa_similarity(query, target)
  pairwise(query, target) { |left, right| __native_backend.osa_similarity(left, right) }
end

.stride_smith_waterman(query, target, match_score: 2, mismatch_score: -1,, gap_score: -1)) ⇒ Object



138
139
140
141
142
143
144
145
# File 'lib/stride_align/core.rb', line 138

def stride_smith_waterman(query, target, match_score: 2,
                          mismatch_score: -1, gap_score: -1)
  pairwise(query, target) do |left, right|
    __native_backend.smith_waterman(
      left, right, match_score, mismatch_score, gap_score
    )
  end
end

.stride_smith_waterman_affine(query, target, match_score: 2, mismatch_score: -1,, gap_open_score: -2,, gap_extend_score: -1)) ⇒ Object



156
157
158
159
160
161
162
163
164
165
166
# File 'lib/stride_align/core.rb', line 156

def stride_smith_waterman_affine(query, target, match_score: 2,
                                 mismatch_score: -1,
                                 gap_open_score: -2,
                                 gap_extend_score: -1)
  pairwise(query, target) do |left, right|
    __native_backend.smith_waterman_affine(
      left, right, match_score, mismatch_score,
      gap_open_score, gap_extend_score
    )
  end
end

.stride_true_damerau_levenshtein(query, target) ⇒ Object



93
94
95
96
97
# File 'lib/stride_align/core.rb', line 93

def stride_true_damerau_levenshtein(query, target)
  pairwise(query, target) do |left, right|
    __native_backend.true_damerau_levenshtein(left, right)
  end
end

.stride_true_damerau_levenshtein_similarity(query, target) ⇒ Object



99
100
101
102
103
# File 'lib/stride_align/core.rb', line 99

def stride_true_damerau_levenshtein_similarity(query, target)
  pairwise(query, target) do |left, right|
    __native_backend.true_damerau_levenshtein_similarity(left, right)
  end
end

.substitution_matrix_encode(substitution_matrix, sequence) ⇒ Object



85
86
87
88
89
90
91
92
93
94
# File 'lib/stride_align/matrices.rb', line 85

def substitution_matrix_encode(substitution_matrix, sequence)
  validate_substitution_matrix(substitution_matrix)
  if sequence.is_a?(Array)
    sequence.map { |value| value.nil? ? nil : substitution_matrix.encode_one(value) }
  elsif sequence.nil?
    nil
  else
    substitution_matrix.encode_one(sequence)
  end
end

.substitution_matrix_from_ncbi_text(text, name: "<unnamed>", gap_score: -4,, wildcard: "X", gap_open: nil, gap_extend: nil) ⇒ Object

Raises:

  • (ArgumentError)


132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/stride_align/matrices.rb', line 132

def substitution_matrix_from_ncbi_text(text, name: "<unnamed>",
                                       gap_score: -4, wildcard: "X",
                                       gap_open: nil, gap_extend: nil)
  raise ArgumentError, "text must be one String" unless text.is_a?(String)

  lines = text.lines.map(&:strip).reject { |line| line.empty? || line.start_with?("#") }
  raise ArgumentError, "NCBI matrix text has no header or data rows" if lines.length < 2

  header = lines.shift.split
  rows = lines.map(&:split)
  labels = rows.map(&:first)
  raise ArgumentError, "NCBI matrix row labels do not match column header" unless labels == header

  values = rows.map do |row|
    raise ArgumentError, "NCBI matrix row has the wrong number of values" unless row.length == header.length + 1
    row.drop(1).map do |token|
      Integer(token, 10)
    rescue ArgumentError
      raise ArgumentError, "non-integer score in NCBI matrix row"
    end
  end
  SubstitutionMatrix.new(
    name: name, alphabet: header.join, matrix: values,
    gap_score: gap_score, wildcard: wildcard,
    gap_open: gap_open, gap_extend: gap_extend
  )
end

.substitution_matrix_score(substitution_matrix, query, target) ⇒ Object



96
97
98
99
100
101
102
# File 'lib/stride_align/matrices.rb', line 96

def substitution_matrix_score(substitution_matrix, query, target)
  validate_substitution_matrix(substitution_matrix)
  smith_waterman_score(
    query, target, matrix: substitution_matrix,
    gap_score: substitution_matrix.gap_score
  )
end

.substitution_matrix_score_step_limit(substitution_matrix, gap_score: nil, gap_open: nil, gap_extend: nil) ⇒ Object



104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/stride_align/matrices.rb', line 104

def substitution_matrix_score_step_limit(substitution_matrix,
                                          gap_score: nil,
                                          gap_open: nil,
                                          gap_extend: nil)
  validate_substitution_matrix(substitution_matrix)
  if gap_score.nil? && gap_open.nil? && gap_extend.nil?
    gap_score = substitution_matrix.gap_score
    gap_open = substitution_matrix.gap_open
    gap_extend = substitution_matrix.gap_extend
  end
  [substitution_matrix.max_abs, gap_score, gap_open, gap_extend]
    .compact.map(&:abs).max
end

.substitution_matrix_transpose(substitution_matrix, name: "#{substitution_matrix.name}.T") ⇒ Object



118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/stride_align/matrices.rb', line 118

def substitution_matrix_transpose(substitution_matrix,
                                  name: "#{substitution_matrix.name}.T")
  validate_substitution_matrix(substitution_matrix)
  SubstitutionMatrix.new(
    name: name,
    alphabet: substitution_matrix.alphabet,
    matrix: substitution_matrix.matrix.transpose,
    gap_score: substitution_matrix.gap_score,
    wildcard: substitution_matrix.wildcard,
    gap_open: substitution_matrix.gap_open,
    gap_extend: substitution_matrix.gap_extend
  )
end

.SubstitutionMatrix(name:, alphabet:, matrix:, gap_score: -4,, wildcard: "X", gap_open: nil, gap_extend: nil) ⇒ Object



76
77
78
79
80
81
82
83
# File 'lib/stride_align/matrices.rb', line 76

def SubstitutionMatrix(name:, alphabet:, matrix:, gap_score: -4,
                       wildcard: "X", gap_open: nil, gap_extend: nil)
  SubstitutionMatrix.new(
    name: name, alphabet: alphabet, matrix: matrix,
    gap_score: gap_score, wildcard: wildcard,
    gap_open: gap_open, gap_extend: gap_extend
  )
end

.token_set_ratio(query, target, processor: nil) ⇒ Object



90
91
92
93
94
# File 'lib/stride_align/algorithms.rb', line 90

def token_set_ratio(query, target, processor: nil)
  processed_pairwise(query, target, processor) do |left, right|
    __primary_backend.token_set_ratio(left, right)
  end
end

.token_sort_ratio(query, target, processor: nil) ⇒ Object



84
85
86
87
88
# File 'lib/stride_align/algorithms.rb', line 84

def token_sort_ratio(query, target, processor: nil)
  processed_pairwise(query, target, processor) do |left, right|
    __primary_backend.token_sort_ratio(left, right)
  end
end

.true_damerau_levenshtein_best(query, targets) ⇒ Object



348
349
350
# File 'lib/stride_align/batch.rb', line 348

def true_damerau_levenshtein_best(query, targets)
  best(query, targets, Scorer::TRUE_DAMERAU_LEVENSHTEIN)
end

.true_damerau_levenshtein_normalized_best(query, targets) ⇒ Object



352
353
354
# File 'lib/stride_align/batch.rb', line 352

def true_damerau_levenshtein_normalized_best(query, targets)
  best(query, targets, Scorer::TRUE_DAMERAU_LEVENSHTEIN_NORMALIZED)
end

.true_damerau_levenshtein_normalized_score(query, target) ⇒ Object



90
91
92
# File 'lib/stride_align/batch.rb', line 90

def true_damerau_levenshtein_normalized_score(query, target)
  stride_true_damerau_levenshtein_similarity(query, target)
end

.true_damerau_levenshtein_normalized_scores(query, targets) ⇒ Object



217
218
219
220
221
# File 'lib/stride_align/batch.rb', line 217

def true_damerau_levenshtein_normalized_scores(query, targets)
  one_to_many(query, targets) do |left, right|
    true_damerau_levenshtein_normalized_score(left, right)
  end
end

.true_damerau_levenshtein_normalized_top_k(query, targets, k: 5) ⇒ Object



300
301
302
# File 'lib/stride_align/batch.rb', line 300

def true_damerau_levenshtein_normalized_top_k(query, targets, k: 5)
  top_k(query, targets, Scorer::TRUE_DAMERAU_LEVENSHTEIN_NORMALIZED, k: k)
end

.true_damerau_levenshtein_score(query, target) ⇒ Object



86
87
88
# File 'lib/stride_align/batch.rb', line 86

def true_damerau_levenshtein_score(query, target)
  stride_true_damerau_levenshtein(query, target)
end

.true_damerau_levenshtein_scores(query, targets) ⇒ Object



211
212
213
214
215
# File 'lib/stride_align/batch.rb', line 211

def true_damerau_levenshtein_scores(query, targets)
  one_to_many(query, targets) do |left, right|
    true_damerau_levenshtein_score(left, right)
  end
end

.true_damerau_levenshtein_top_k(query, targets, k: 5) ⇒ Object



296
297
298
# File 'lib/stride_align/batch.rb', line 296

def true_damerau_levenshtein_top_k(query, targets, k: 5)
  top_k(query, targets, Scorer::TRUE_DAMERAU_LEVENSHTEIN, k: k)
end

.WRatio(query, target, processor: nil) ⇒ Object



108
109
110
111
112
113
114
115
116
117
118
# File 'lib/stride_align/algorithms.rb', line 108

def WRatio(query, target, processor: nil)
  processed_pairwise(query, target, processor) do |left, right|
    if left.nil? || right.nil?
      nil
    elsif left.empty? && right.empty?
      1.0
    else
      __primary_backend.wratio(left, right)
    end
  end
end