use crate::convert::Bag;
use crate::feature_from::FeatureFrom;
use crate::HashedAs;
use fxhash::hash32;
use std::cmp;
use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque};
use std::hash::{BuildHasher, Hash};
use std::ops::AddAssign;
use std::sync::Arc;
#[cfg(feature = "heapless")]
use heapless::binary_heap::{self, Kind};
pub trait Ftzr<InputData> {
type TokenGroup;
fn push_tokens<Push: FnMut(Self::TokenGroup)>(&self, input: InputData, push: &mut Push);
fn push_tokens_from<Push, T>(&self, input: InputData, push: &mut Push)
where
Push: FnMut(T),
T: FeatureFrom<Self::TokenGroup>,
{
let mut _push = |t| push(FeatureFrom::from(t));
self.push_tokens(input, &mut _push)
}
fn featurize<Feature, A>(&self, input: InputData) -> A
where
Feature: FeatureFrom<Self::TokenGroup>,
A: Accumulates<Feature>,
{
let mut state: A::State = Default::default();
{
let mut push = |t: Self::TokenGroup| A::accum_token(&mut state, FeatureFrom::from(t));
self.push_tokens(input, &mut push);
}
A::finish(state)
}
fn featurize_x2<A1, T1, A2, T2>(&self, input: InputData) -> (A1, A2)
where
Self::TokenGroup: Clone,
A1: Accumulates<T1>,
A2: Accumulates<T2>,
T1: FeatureFrom<Self::TokenGroup>,
T2: FeatureFrom<Self::TokenGroup>,
{
let mut state1: A1::State = Default::default();
let mut state2: A2::State = Default::default();
{
let mut push = |t: Self::TokenGroup| {
A1::accum_token(&mut state1, FeatureFrom::from(t.clone()));
A2::accum_token(&mut state2, FeatureFrom::from(t));
};
self.push_tokens(input, &mut push);
}
(A1::finish(state1), A2::finish(state2))
}
#[allow(missing_docs)]
#[allow(clippy::wrong_self_convention)]
fn as_fn<X: FeatureFrom<Self::TokenGroup>>(
self,
) -> Arc<dyn Fn(InputData) -> Vec<X> + Send + Sync>
where
Self: Sized + Send + Sync + 'static,
{
Arc::new(move |o| self.featurize(o))
}
}
pub trait IterFtzr<InputData> {
type TokenGroup;
type Iter: Iterator<Item = Self::TokenGroup>;
fn iterate_features(&self, input: InputData) -> Self::Iter;
}
pub trait LinearFixed {
fn chunk_size(&self) -> usize;
}
pub trait Accumulates<Token> {
type State: Default;
fn accum_token(state: &mut Self::State, token: Token);
fn finish(state: Self::State) -> Self;
}
#[cfg(feature = "heapless")]
impl<Token: Ord, K: Kind, const N: usize> Accumulates<Token>
for binary_heap::BinaryHeap<Token, K, N>
{
type State = Self;
fn accum_token(state: &mut Self::State, token: Token) {
let _ = state.push(token);
}
fn finish(state: Self::State) -> Self {
state
}
}
#[derive(Debug)]
pub struct MinHashState<const N: usize> {
seeds: [u32; N],
mins: [u32; N],
}
impl<const N: usize> Default for MinHashState<N> {
fn default() -> Self {
let mut k = [0; N];
for (i, slot) in k.iter_mut().enumerate() {
*slot = hash32(&i);
}
MinHashState {
seeds: k,
mins: [u32::MAX; N],
}
}
}
impl<Token: Hash, const N_HASHES: usize> Accumulates<Token> for [HashedAs<u32>; N_HASHES] {
type State = MinHashState<N_HASHES>;
fn accum_token(state: &mut Self::State, token: Token) {
for i in 0..N_HASHES {
state.mins[i] = cmp::min(state.mins[i], hash32(&(state.seeds[i], &token)));
}
}
fn finish(state: Self::State) -> Self {
let mut k = [HashedAs(0); N_HASHES];
for (slot, &m) in k.iter_mut().zip(state.mins.iter()) {
*slot = HashedAs(m);
}
k
}
}
impl<Token, A, B> Accumulates<Token> for (A, B)
where
Token: Clone,
A: Accumulates<Token>,
B: Accumulates<Token>,
{
type State = (A::State, B::State);
fn accum_token(state: &mut Self::State, token: Token) {
A::accum_token(&mut state.0, token.clone());
B::accum_token(&mut state.1, token);
}
fn finish(state: Self::State) -> Self {
(A::finish(state.0), B::finish(state.1))
}
}
impl<Token> Accumulates<Token> for Vec<Token> {
type State = Self;
fn accum_token(state: &mut Self, token: Token) {
state.push(token);
}
fn finish(state: Self) -> Self {
state
}
}
impl<Token> Accumulates<Token> for VecDeque<Token> {
type State = Self;
fn accum_token(state: &mut Self, token: Token) {
state.push_back(token);
}
fn finish(state: Self) -> Self {
state
}
}
impl<Token> Accumulates<Token> for LinkedList<Token> {
type State = Self;
fn accum_token(state: &mut Self, token: Token) {
state.push_back(token);
}
fn finish(state: Self) -> Self {
state
}
}
impl<Token: Ord> Accumulates<Token> for BinaryHeap<Token> {
type State = Self;
fn accum_token(state: &mut Self, token: Token) {
state.push(token);
}
fn finish(state: Self) -> Self {
state
}
}
impl<Token: Ord> Accumulates<Token> for BTreeSet<Token> {
type State = Self;
fn accum_token(state: &mut Self, token: Token) {
state.insert(token);
}
fn finish(state: Self) -> Self {
state
}
}
impl<Token: Eq + Hash, S: Default + BuildHasher> Accumulates<Token> for HashSet<Token, S> {
type State = Self;
fn accum_token(state: &mut Self, token: Token) {
state.insert(token);
}
fn finish(state: Self) -> Self {
state
}
}
impl<Token, N, S> Accumulates<Token> for Bag<HashMap<Token, N, S>>
where
Token: Eq + Hash,
N: Default + AddAssign + From<u8>,
S: Default + BuildHasher,
{
type State = Self;
fn accum_token(state: &mut Self, token: Token) {
*state.0.entry(token).or_default() += From::from(1);
}
fn finish(state: Self) -> Self {
state
}
}
impl<Token: Ord, N: Default + AddAssign + From<u8>> Accumulates<Token> for Bag<BTreeMap<Token, N>> {
type State = Self;
fn accum_token(state: &mut Self, token: Token) {
*state.0.entry(token).or_default() += From::from(1);
}
fn finish(state: Self) -> Self {
state
}
}
impl<Token, K, V, S> Accumulates<Token> for HashMap<K, V, S>
where
S: Default + BuildHasher,
Token: Clone + Eq + Hash,
K: Eq + Hash + FeatureFrom<Token>,
V: FeatureFrom<Token>,
{
type State = Self;
fn accum_token(state: &mut Self, token: Token) {
state.insert(
FeatureFrom::from(token.clone()),
FeatureFrom::from(token.clone()),
);
}
fn finish(state: Self) -> Self {
state
}
}
impl<Token, K, V> Accumulates<Token> for BTreeMap<K, V>
where
Token: Clone,
K: Ord + FeatureFrom<Token>,
V: FeatureFrom<Token>,
{
type State = Self;
fn accum_token(state: &mut Self, token: Token) {
state.insert(
FeatureFrom::from(token.clone()),
FeatureFrom::from(token.clone()),
);
}
fn finish(state: Self) -> Self {
state
}
}
impl Accumulates<&[&str]> for String {
type State = Self;
#[inline]
fn accum_token(state: &mut Self::State, tokens: &[&str]) {
let len = tokens.len();
for (x, t) in tokens.iter().enumerate() {
state.push_str(t);
if x != len - 1 {
state.push(' ');
}
}
}
#[inline]
fn finish(state: Self::State) -> Self {
state
}
}
impl<'a> Accumulates<&'a [char]> for String {
type State = Self;
#[inline]
fn accum_token(state: &mut Self::State, tokens: &'a [char]) {
state.extend(tokens.iter())
}
#[inline]
fn finish(state: Self::State) -> Self {
state
}
}
impl<'a> Accumulates<&'a [u8]> for String {
type State = Self;
#[inline]
fn accum_token(state: &mut Self::State, tokens: &'a [u8]) {
state.extend(tokens.iter().map(|token| {
let chr: char = From::from(*token);
chr
}))
}
#[inline]
fn finish(state: Self::State) -> Self {
state
}
}
impl<'a> Accumulates<&'a str> for String {
type State = Self;
#[inline]
fn accum_token(state: &mut Self::State, tokens: &'a str) {
state.push_str(tokens);
}
#[inline]
fn finish(state: Self::State) -> Self {
state
}
}