use std::{collections::{BTreeMap, HashMap}, sync::Arc};
pub mod trainer;
pub mod model;
pub mod encoder;
pub mod utils;
pub use trainer::{BpeTrainer, BpeTrainerConfig, InitialAlphabet, TieBreak};
pub use model::BpeModel;
pub use encoder::BpeEncoder;
use utils::*;
use ahash::AHashSet;
use ordermap::OrderMap;
pub type Idx = u32;
pub type Word<C> = Arc<[C]>;
pub type Freq = i64;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Character {
Unicode(char),
Byte(u8),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum CharIdx {
Char(char),
Idx(Idx),
}
#[derive(Debug)]
pub struct PreToken<C, I> {
pub src: Word<C>,
pub idxs: Vec<I>,
pub freq: Freq,
}
impl<C, I> PreToken<C, I> {
pub fn display(&self) -> String where Word<C>: WordDebugExt {
format!("<{:?} => {}>", self.src.debug_display(), self.freq)
}
pub fn display_split(&self, vocabs: &BTreeMap<I, Word<C>>) -> String where I: Ord, C: Clone, Word<C>: WordDebugExt {
let parts = self
.idxs
.iter()
.map(|i| vocabs.get(i).unwrap().debug_display())
.collect::<Vec<_>>()
.join(" ");
format!("<{} => {}>", parts, self.freq)
}
}
#[derive(Debug)]
pub struct Merge<C, I> {
pub tp: (I, I),
pub content: (Word<C>, Word<C>),
pub target: Option<I>,
pub data: MergeData,
}
impl<C, I: Clone> Clone for Merge<C, I> {
fn clone(&self) -> Self {
Self { tp: self.tp.clone(), content: self.content.clone(), target: self.target.clone(), data: self.data.clone() }
}
}
impl<C, I> Merge<C, I> {
pub fn merged_content(&self) -> Word<C> where C: Clone {
let mut v = Vec::with_capacity(self.content.0.len() + self.content.1.len());
v.extend_from_slice(&self.content.0);
v.extend_from_slice(&self.content.1);
Arc::<[C]>::from(v.into_boxed_slice())
}
pub fn with_target(mut self, target: I) -> Self {
self.target = Some(target);
self
}
}
#[derive(Debug, Default, Clone, PartialEq)]
pub struct MergeData {
pub occurs_in: AHashSet<u64>,
pub freq: Freq,
}
impl MergeData {
pub fn new(freq: Freq) -> Self {
Self {
occurs_in: AHashSet::new(),
freq,
}
}
#[must_use]
pub fn add_occurs_in<I: IntoIterator<Item = u64>>(self, iter: I) -> Self {
Self {
occurs_in: iter.into_iter().collect(),
freq: self.freq,
}
}
pub fn occurs_in_vec(&self) -> Vec<u64> {
let mut occurs_in = self.occurs_in.iter().copied().collect::<Vec<u64>>();
occurs_in.sort_unstable();
occurs_in
}
}
impl<C, I> Merge<C, I> {
pub fn new(tp: (I, I), content: (Word<C>, Word<C>)) -> Self {
Self {
tp,
content,
target: None,
data: MergeData::default(),
}
}
pub fn add(&mut self, doc_id: u64, freq: Freq) {
self.data.occurs_in.insert(doc_id);
self.data.freq += freq;
}
pub fn remove(&mut self, doc_id: &u64, freq: Freq) {
self.data.freq -= freq;
self.data.occurs_in.remove(doc_id);
}
}
pub trait Cachable: std::hash::Hash + Send + Sync + 'static { }
impl<C: std::hash::Hash + Send + Sync + 'static> Cachable for C { }
pub trait IdxLike: Ord + std::hash::Hash + Eq + Copy + Send + Sync + 'static {
fn from_u64(v: u64) -> Self;
fn to_u64(self) -> u64;
fn decode_from_u64(v: u64, start: u64) -> Option<Self> {
Some(Self::from_u64(v - start))
}
fn encode_to_u64(&self, start: u64) -> u64 {
self.to_u64() + start
}
}
impl IdxLike for Idx {
fn from_u64(v: u64) -> Self {
v as Self
}
fn to_u64(self) -> u64 {
self as u64
}
}
impl IdxLike for CharIdx {
fn from_u64(v: u64) -> Self {
CharIdx::Idx(v as Idx)
}
fn to_u64(self) -> u64 {
match self {
CharIdx::Idx(i) => i as u64,
CharIdx::Char(c) => unimplemented!("Cannot convert CharIdx::Char to u64: {:?} [u{:04x}]", c, c as u32),
}
}
}
pub trait CharToIdx<I: IdxLike> {
fn char_to_idx(&self, start: u64, byte_vocab: Option<&HashMap<u8, I>>) -> I;
}
impl CharToIdx<Idx> for u8 {
fn char_to_idx(&self, start: u64, byte_vocab: Option<&HashMap<u8, Idx>>) -> Idx {
if let Some(idx) = byte_vocab.and_then(|vocab| vocab.get(self)).copied() {
return idx;
}
(*self as u64 + start) as Idx
}
}
impl CharToIdx<CharIdx> for char {
fn char_to_idx(&self, start: u64, byte_vocab: Option<&HashMap<u8, CharIdx>>) -> CharIdx {
if self.is_ascii() {
let byte = *self as u8;
if let Some(idx) = byte_vocab.and_then(|vocab| vocab.get(&byte)).copied() {
return idx;
}
CharIdx::Idx(byte as Idx + start as Idx)
} else {
CharIdx::Char(*self)
}
}
}
impl CharToIdx<CharIdx> for u8 {
fn char_to_idx(&self, start: u64, byte_vocab: Option<&HashMap<u8, CharIdx>>) -> CharIdx {
if let Some(idx) = byte_vocab.and_then(|vocab| vocab.get(self)).copied() {
return idx;
}
CharIdx::Idx((*self as u64 + start) as Idx)
}
}
impl CharToIdx<CharIdx> for Character {
fn char_to_idx(&self, start: u64, byte_vocab: Option<&HashMap<u8, CharIdx>>) -> CharIdx {
match self {
Character::Unicode(c) => c.char_to_idx(start, byte_vocab),
Character::Byte(b) => b.char_to_idx(start, byte_vocab),
}
}
}
pub trait HasChar<C>: Sized {
fn get_char(self) -> Option<char>;
fn from_char(_c: char) -> Option<Self> { None }
fn idx_to_word(self) -> Option<Word<C>> where for<'a> &'a str: ToWord<C>{
self.get_char().map(|i| i.to_string().to_word())
}
}
impl<C> HasChar<C> for Idx {
fn get_char(self) -> Option<char> {
None
}
}
impl<C> HasChar<C> for char {
fn get_char(self) -> Option<char> {
Some(self)
}
fn from_char(c: char) -> Option<Self> {
Some(c)
}
}
impl<C> HasChar<C> for CharIdx {
fn get_char(self) -> Option<char> {
match self {
CharIdx::Char(c) => Some(c),
CharIdx::Idx(_) => None,
}
}
fn from_char(c: char) -> Option<Self> {
Some(CharIdx::Char(c))
}
}
pub trait CharSplit: Sized {
fn char_split(&self) -> Option<Vec<Self>> {
None
}
fn char_split_u8(&self, buffer: &mut Vec<u8>);
fn to_vec_u8(w: &Word<Self>) -> Vec<u8> {
let mut v = Vec::new();
for c in w.iter() {
c.char_split_u8(&mut v);
}
v
}
fn from_vec_u8(v: &[u8]) -> Word<Self>;
}
impl CharSplit for u8 {
fn char_split_u8(&self, buffer: &mut Vec<u8>) {
buffer.push(*self);
}
fn from_vec_u8(v: &[u8]) -> Word<Self> {
v.to_word()
}
}
impl CharSplit for Character {
fn char_split(&self) -> Option<Vec<Self>> {
match self {
Self::Unicode(c) => Some(c.to_string().bytes().into_iter().map(Self::Byte).collect()),
Self::Byte(_) => None,
}
}
fn char_split_u8(&self, buffer: &mut Vec<u8>) {
match self {
Self::Unicode(c) => {
buffer.extend_from_slice(c.to_string().as_bytes());
}
Self::Byte(b) => {
buffer.push(*b);
}
}
}
fn from_vec_u8(v: &[u8]) -> Word<Self> {
_try_combine(v).to_word()
}
}
fn _try_combine(word: &[u8]) -> Vec<Character> {
let mut chars = Vec::with_capacity(word.len());
let mut c = vec![];
fn convert_str(v: &[u8]) -> Vec<Character> {
match std::str::from_utf8(v) {
Ok(s) => s.chars().map(|ch| Character::Unicode(ch)).collect(),
Err(_) => v.iter().map(|b| Character::Byte(*b)).collect(),
}
}
for &b in word.iter() {
if b.is_ascii() {
if !c.is_empty() {
chars.extend(convert_str(&c));
c.clear();
}
chars.push(Character::Unicode(b as char));
} else if b < 0b_1100_0000 {
if !c.is_empty() {
c.push(b);
} else {
chars.push(Character::Byte(b));
}
continue;
} else {
if !c.is_empty() {
chars.extend(convert_str(&c));
c.clear();
}
c.push(b);
}
}
if !c.is_empty() {
chars.extend(convert_str(&c));
}
chars
}