mod clean_words;
mod gather;
use std::collections::HashMap;
use candle_core::Tensor;
use super::index;
use super::term_frequency;
use super::vocab::Vocab;
use crate::error::Result;
use crate::models::sparse::punctuation::is_bare_punctuation;
use crate::models::sparse::stemmer::stem;
use crate::models::sparse::stopwords::Stopwords;
use crate::models::sparse::words;
use crate::sparse::SparseEmbedding;
const SPECIAL_TOKENS: [&str; 5] = ["[CLS]", "[SEP]", "[PAD]", "[UNK]", "[MASK]"];
fn is_special_token(text: &str) -> bool {
SPECIAL_TOKENS.contains(&text)
}
struct UnrecognizedGroup {
representative: String,
word_count: u32,
}
fn unrecognized_pairs(
groups: &HashMap<String, UnrecognizedGroup>,
doc_len: u32,
uniform_weight: bool,
) -> Vec<(u32, f32)> {
groups
.values()
.map(|group| {
let tf = if uniform_weight {
1.0
} else {
term_frequency::saturation(group.word_count, doc_len)
};
(index::hashed_index(&group.representative), tf)
})
.collect()
}
pub(super) fn pool_row(
hidden_row: &[Vec<f32>],
ids_row: &[u32],
token_text: &[String],
vocab: &Vocab,
stopwords: &Stopwords,
matrix: &Tensor,
uniform_weight: bool,
) -> Result<SparseEmbedding> {
let hidden_size = matrix.dims()[1];
let texts: Vec<String> = ids_row
.iter()
.map(|&id| token_text.get(id as usize).cloned().unwrap_or_default())
.collect();
let mut recognized: HashMap<u32, gather::RecognizedGroup> = HashMap::new();
let mut unrecognized: HashMap<String, UnrecognizedGroup> = HashMap::new();
let mut doc_len: u32 = 0;
for word in words::reconstruct(&texts) {
if is_special_token(&word.text)
|| stopwords.contains(&word.text)
|| is_bare_punctuation(&word.text)
{
continue;
}
match vocab.resolve(&word.text) {
Some(word_id) => {
doc_len += 1;
let group = recognized
.entry(word_id)
.or_insert_with(|| gather::RecognizedGroup::new(hidden_size));
for position in word.tokens {
group.add_token(&hidden_row[position]);
}
group.word_count += 1;
}
None => {
for subword in clean_words::resplit(&word.text, stopwords) {
doc_len += 1;
let stem = stem(&subword);
unrecognized
.entry(stem)
.or_insert_with(move || UnrecognizedGroup {
representative: subword,
word_count: 0,
})
.word_count += 1;
}
}
}
}
let mut pairs = gather::pairs(&recognized, matrix, doc_len, uniform_weight)?;
pairs.extend(unrecognized_pairs(&unrecognized, doc_len, uniform_weight));
Ok(SparseEmbedding::from_pairs(pairs))
}