candding 0.1.0

Pure candle embeddings for Rust with no ONNX: dense, sparse, multi-vector and rerank models today, image models on the roadmap
Documentation
use super::*;
use crate::registry::Support;
use crate::registry::WeightsFormat;
use crate::registry::sparse::SparseComputation;

#[test]
fn the_builder_produces_a_working_embedder() {
  let model = Bm25TextEmbedding::builder().build();
  let rows = model.embed(&["The quick brown fox jumps over the lazy dog."]);
  assert_eq!(rows.len(), 1);
  assert_eq!(rows[0].len(), 6, "six surviving stems, as in the reference");
}

#[test]
fn the_descriptor_reports_no_encoder_no_weights_and_no_device_or_dtype_status() {
  let model = Bm25TextEmbedding::builder().build();
  let descriptor = model.descriptor();
  assert_eq!(descriptor.id, "Qdrant/bm25");
  assert_eq!(descriptor.family, None);
  assert_eq!(descriptor.weights, WeightsFormat::NoWeights);
  assert_eq!(descriptor.computation, SparseComputation::Computed);
  assert_eq!(descriptor.backends.cpu, Support::NotApplicable);
  assert_eq!(descriptor.backends.metal, Support::NotApplicable);
  assert_eq!(descriptor.backends.cuda, Support::NotApplicable);
  for row in [
    descriptor.dtype_backends.f32,
    descriptor.dtype_backends.f16,
    descriptor.dtype_backends.bf16,
  ] {
    assert_eq!(row, crate::registry::BackendSupport::not_applicable());
  }
}

/// A repeated word tells the uniform query side from the term-frequency passage side; `embed` is the passage side.
#[test]
fn passage_and_query_embed_diverge_on_a_repeated_word() {
  let model = Bm25TextEmbedding::builder().build();
  let passage = &model.passage_embed(&["dog dog dog cat"])[0];
  let query = &model.query_embed(&["dog dog dog cat"])[0];
  assert_eq!(&model.embed(&["dog dog dog cat"])[0], passage);
  assert_eq!(passage.len(), 2);
  assert_eq!(query.len(), 2);
  assert_ne!(passage.values, query.values);
  assert!(
    query.values.iter().all(|&v| v == 1.0),
    "every query weight is exactly 1.0"
  );
}

#[test]
fn empty_inputs_produce_empty_rows_without_a_device_of_any_kind() {
  let model = Bm25TextEmbedding::builder().build();
  let none: [&str; 0] = [];
  assert!(model.embed(&none).is_empty());
  let one_empty = model.embed(&[""]);
  assert_eq!(one_empty.len(), 1);
  assert!(one_empty[0].is_empty());
}