Class: SwarmMemory::Search::TextSimilarity

Inherits:
Object
  • Object
show all
Defined in:
lib/swarm_memory/search/text_similarity.rb

Overview

Text similarity calculations using multiple algorithms

Provides both Jaccard (word overlap) and cosine similarity metrics.

Class Method Summary collapse

Class Method Details

.cosine(vec1, vec2) ⇒ Float

Calculate cosine similarity between two embedding vectors

Cosine similarity measures the angle between vectors. Score ranges from -1.0 to 1.0 (0.0-1.0 for normalized embeddings).

Examples:

vec1 = [0.1, 0.2, 0.3]
vec2 = [0.2, 0.3, 0.4]
TextSimilarity.cosine(vec1, vec2)
# => 0.99 (very similar)

Parameters:

  • vec1 (Array<Float>)

    First embedding vector

  • vec2 (Array<Float>)

    Second embedding vector

Returns:

  • (Float)

    Similarity score -1.0 to 1.0

Raises:

  • (ArgumentError)


51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/swarm_memory/search/text_similarity.rb', line 51

def cosine(vec1, vec2)
  raise ArgumentError, "Vectors must have same length" if vec1.size != vec2.size
  return 0.0 if vec1.empty?

  dot_product = vec1.zip(vec2).sum { |a, b| a * b }
  magnitude1 = Math.sqrt(vec1.sum { |x| x * x })
  magnitude2 = Math.sqrt(vec2.sum { |x| x * x })

  return 0.0 if magnitude1.zero? || magnitude2.zero?

  dot_product / (magnitude1 * magnitude2)
end

.jaccard(text1, text2) ⇒ Float

Calculate Jaccard similarity between two texts

Jaccard similarity measures the overlap of word sets. Score ranges from 0.0 (no overlap) to 1.0 (identical).

Examples:

TextSimilarity.jaccard("ruby classes", "ruby modules")
# => 0.33 (1 shared word out of 3 total unique words)

Parameters:

  • text1 (String)

    First text

  • text2 (String)

    Second text

Returns:

  • (Float)

    Similarity score 0.0-1.0



22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/swarm_memory/search/text_similarity.rb', line 22

def jaccard(text1, text2)
  words1 = tokenize(text1)
  words2 = tokenize(text2)

  return 0.0 if words1.empty? && words2.empty?
  return 0.0 if words1.empty? || words2.empty?

  intersection = (words1 & words2).size
  union = (words1 | words2).size

  return 0.0 if union.zero?

  intersection.to_f / union
end