You've already forked pgvecto.rs
mirror of
https://github.com/tensorchord/pgvecto.rs.git
synced 2025-08-01 06:46:52 +03:00
merge 'main' into 'feat/binary-vector'
Signed-off-by: Mingzhuo Yin <yinmingzhuo@gmail.com>
This commit is contained in:
@ -4,37 +4,33 @@ version.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[dependencies]
|
||||
bincode.workspace = true
|
||||
bitvec.workspace = true
|
||||
bytemuck.workspace = true
|
||||
byteorder.workspace = true
|
||||
half.workspace = true
|
||||
libc.workspace = true
|
||||
log.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
validator.workspace = true
|
||||
rustix.workspace = true
|
||||
thiserror.workspace = true
|
||||
byteorder.workspace = true
|
||||
bincode.workspace = true
|
||||
half.workspace = true
|
||||
memmap2.workspace = true
|
||||
num-traits.workspace = true
|
||||
rand.workspace = true
|
||||
bytemuck.workspace = true
|
||||
bitvec.workspace = true
|
||||
rustix.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
thiserror.workspace = true
|
||||
uuid.workspace = true
|
||||
validator.workspace = true
|
||||
base = { path = "../base" }
|
||||
c = { path = "../c" }
|
||||
detect = { path = "../detect" }
|
||||
crc32fast = "1.3.2"
|
||||
crossbeam = "0.8.2"
|
||||
dashmap = "5.4.0"
|
||||
crc32fast = "1.4.0"
|
||||
crossbeam = "0.8.4"
|
||||
dashmap = "5.5.3"
|
||||
parking_lot = "0.12.1"
|
||||
memoffset = "0.9.0"
|
||||
arrayvec = { version = "0.7.3", features = ["serde"] }
|
||||
memmap2 = "0.9.0"
|
||||
rayon = "1.6.1"
|
||||
uuid = { version = "1.6.1", features = ["v4", "serde"] }
|
||||
rayon = "1.8.1"
|
||||
arc-swap = "1.6.0"
|
||||
multiversion = "0.7.3"
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
ulock-sys = "0.1.0"
|
||||
|
||||
[lints]
|
||||
clippy.derivable_impls = "allow"
|
||||
clippy.len_without_is_empty = "allow"
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::prelude::*;
|
||||
use crate::utils::vec2::Vec2;
|
||||
use base::scalar::FloatCast;
|
||||
use rand::rngs::StdRng;
|
||||
use rand::{Rng, SeedableRng};
|
||||
use std::ops::{Index, IndexMut};
|
||||
|
@ -5,6 +5,7 @@ use crate::index::IndexOptions;
|
||||
use crate::prelude::*;
|
||||
use crate::utils::dir_ops::sync_dir;
|
||||
use crate::utils::mmap_array::MmapArray;
|
||||
use base::scalar::FloatCast;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
@ -1,456 +0,0 @@
|
||||
#![allow(unused)]
|
||||
|
||||
use crate::algorithms::raw::Raw;
|
||||
use crate::prelude::*;
|
||||
use crossbeam::atomic::AtomicCell;
|
||||
use parking_lot::RwLock;
|
||||
use parking_lot::RwLockReadGuard;
|
||||
use parking_lot::RwLockWriteGuard;
|
||||
use rand::distributions::Uniform;
|
||||
use rand::prelude::SliceRandom;
|
||||
use rand::Rng;
|
||||
use rayon::prelude::*;
|
||||
use std::cmp::Reverse;
|
||||
use std::collections::{BTreeMap, BinaryHeap, HashSet};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct VertexWithDistance {
|
||||
pub id: u32,
|
||||
pub distance: Scalar,
|
||||
}
|
||||
|
||||
impl VertexWithDistance {
|
||||
pub fn new(id: u32, distance: Scalar) -> Self {
|
||||
Self { id, distance }
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for VertexWithDistance {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.distance.eq(&other.distance)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for VertexWithDistance {}
|
||||
|
||||
impl PartialOrd for VertexWithDistance {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.distance.cmp(&other.distance))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for VertexWithDistance {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.distance.cmp(&other.distance)
|
||||
}
|
||||
}
|
||||
|
||||
/// DiskANN search state.
|
||||
pub struct SearchState {
|
||||
pub visited: HashSet<u32>,
|
||||
candidates: BTreeMap<Scalar, u32>,
|
||||
heap: BinaryHeap<Reverse<VertexWithDistance>>,
|
||||
heap_visited: HashSet<u32>,
|
||||
l: usize,
|
||||
/// Number of results to return.
|
||||
//TODO: used during search.
|
||||
k: usize,
|
||||
}
|
||||
|
||||
impl SearchState {
|
||||
/// Creates a new search state.
|
||||
pub(crate) fn new(k: usize, l: usize) -> Self {
|
||||
Self {
|
||||
visited: HashSet::new(),
|
||||
candidates: BTreeMap::new(),
|
||||
heap: BinaryHeap::new(),
|
||||
heap_visited: HashSet::new(),
|
||||
k,
|
||||
l,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the next unvisited vertex.
|
||||
fn pop(&mut self) -> Option<u32> {
|
||||
while let Some(vertex) = self.heap.pop() {
|
||||
if !self.candidates.contains_key(&vertex.0.distance) {
|
||||
// The vertex has been removed from the candidate lists,
|
||||
// from [`push()`].
|
||||
continue;
|
||||
}
|
||||
|
||||
self.visited.insert(vertex.0.id);
|
||||
return Some(vertex.0.id);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Push a new (unvisited) vertex into the search state.
|
||||
fn push(&mut self, vertex_id: u32, distance: Scalar) {
|
||||
assert!(!self.visited.contains(&vertex_id));
|
||||
self.heap_visited.insert(vertex_id);
|
||||
self.heap
|
||||
.push(Reverse(VertexWithDistance::new(vertex_id, distance)));
|
||||
self.candidates.insert(distance, vertex_id);
|
||||
if self.candidates.len() > self.l {
|
||||
self.candidates.pop_last();
|
||||
}
|
||||
}
|
||||
|
||||
/// Mark a vertex as visited.
|
||||
fn visit(&mut self, vertex_id: u32) {
|
||||
self.visited.insert(vertex_id);
|
||||
}
|
||||
|
||||
// Returns true if the vertex has been visited.
|
||||
fn is_visited(&self, vertex_id: u32) -> bool {
|
||||
self.visited.contains(&vertex_id) || self.heap_visited.contains(&vertex_id)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VamanaImpl {
|
||||
raw: Arc<Raw>,
|
||||
|
||||
/// neighbors[vertex_id*r..(vertex_id+1)*r] records r neighbors for each vertex
|
||||
neighbors: Vec<AtomicCell<u32>>,
|
||||
|
||||
/// neighbor_size[vertex_id] records the actual number of neighbors for each vertex
|
||||
/// the RwLock is for protecting both the data for size and original data
|
||||
neighbor_size: Vec<RwLock<u32>>,
|
||||
|
||||
/// the entry for the entire graph, the closet vector to centroid
|
||||
medoid: u32,
|
||||
|
||||
dims: u16,
|
||||
r: u32,
|
||||
alpha: f32,
|
||||
l: usize,
|
||||
|
||||
d: Distance,
|
||||
}
|
||||
|
||||
unsafe impl Send for VamanaImpl {}
|
||||
unsafe impl Sync for VamanaImpl {}
|
||||
|
||||
impl VamanaImpl {
|
||||
pub fn new(
|
||||
raw: Arc<Raw>,
|
||||
n: u32,
|
||||
dims: u16,
|
||||
r: u32,
|
||||
alpha: f32,
|
||||
l: usize,
|
||||
d: Distance,
|
||||
) -> Self {
|
||||
let neighbors = {
|
||||
let mut result = Vec::new();
|
||||
result.resize_with(r as usize * n as usize, || AtomicCell::new(0));
|
||||
result
|
||||
};
|
||||
let neighbor_size = unsafe {
|
||||
let mut result = Vec::new();
|
||||
result.resize_with(n as usize, || RwLock::new(0));
|
||||
result
|
||||
};
|
||||
let medoid = 0;
|
||||
|
||||
let mut new_vamana = Self {
|
||||
raw,
|
||||
neighbors,
|
||||
neighbor_size,
|
||||
medoid,
|
||||
dims,
|
||||
r,
|
||||
alpha,
|
||||
l,
|
||||
d,
|
||||
};
|
||||
|
||||
// 1. init graph with r random neighbors for each node
|
||||
let rng = rand::thread_rng();
|
||||
new_vamana._init_graph(n, rng.clone());
|
||||
|
||||
// 2. find medoid
|
||||
new_vamana.medoid = new_vamana._find_medoid(n);
|
||||
|
||||
// 3. iterate pass
|
||||
new_vamana._one_pass(n, 1.0, r, l, rng.clone());
|
||||
|
||||
new_vamana._one_pass(n, alpha, r, l, rng.clone());
|
||||
|
||||
new_vamana
|
||||
}
|
||||
|
||||
pub fn search<F>(&self, target: Box<[Scalar]>, k: usize, f: F) -> Vec<(Scalar, Payload)>
|
||||
where
|
||||
F: FnMut(Payload) -> bool,
|
||||
{
|
||||
// TODO: filter
|
||||
let state = self._greedy_search_with_filter(0, &target, k, k * 2, f);
|
||||
|
||||
let mut results = BinaryHeap::<(Scalar, u32)>::new();
|
||||
for (distance, row) in state.candidates {
|
||||
if results.len() == k {
|
||||
break;
|
||||
}
|
||||
|
||||
results.push((distance, row));
|
||||
}
|
||||
let mut res_vec: Vec<(Scalar, Payload)> = results
|
||||
.iter()
|
||||
.map(|x| (x.0, self.raw.payload(x.1)))
|
||||
.collect();
|
||||
res_vec.sort();
|
||||
res_vec
|
||||
}
|
||||
|
||||
fn _greedy_search_with_filter<F>(
|
||||
&self,
|
||||
start: u32,
|
||||
query: &[Scalar],
|
||||
k: usize,
|
||||
search_size: usize,
|
||||
mut f: F,
|
||||
) -> SearchState
|
||||
where
|
||||
F: FnMut(Payload) -> bool,
|
||||
{
|
||||
let mut state = SearchState::new(k, search_size);
|
||||
|
||||
let dist = self.d.distance(query, self.raw.vector(start));
|
||||
state.push(start, dist);
|
||||
while let Some(id) = state.pop() {
|
||||
// only pop id in the search list but not visited
|
||||
state.visit(id);
|
||||
{
|
||||
let guard = self.neighbor_size[id as usize].read();
|
||||
let neighbor_ids = self._get_neighbors(id, &guard);
|
||||
for neighbor_id in neighbor_ids {
|
||||
let neighbor_id = neighbor_id.load();
|
||||
if state.is_visited(neighbor_id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if f(self.raw.payload(neighbor_id)) {
|
||||
let dist = self.d.distance(query, self.raw.vector(neighbor_id));
|
||||
state.push(neighbor_id, dist); // push and retain closet l nodes
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state
|
||||
}
|
||||
|
||||
fn _init_graph(&self, n: u32, mut rng: impl Rng) {
|
||||
let distribution = Uniform::new(0, n);
|
||||
for i in 0..n {
|
||||
let mut neighbor_ids: HashSet<u32> = HashSet::new();
|
||||
if self.r < n {
|
||||
while neighbor_ids.len() < self.r as usize {
|
||||
let neighbor_id = rng.sample(distribution);
|
||||
if neighbor_id != i {
|
||||
neighbor_ids.insert(neighbor_id);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
neighbor_ids = (0..n).collect();
|
||||
}
|
||||
|
||||
{
|
||||
let mut guard = self.neighbor_size[i as usize].write();
|
||||
self._set_neighbors(i, &neighbor_ids, &mut guard);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn _set_neighbors(
|
||||
&self,
|
||||
vertex_index: u32,
|
||||
neighbor_ids: &HashSet<u32>,
|
||||
guard: &mut RwLockWriteGuard<u32>,
|
||||
) {
|
||||
assert!(neighbor_ids.len() <= self.r as usize);
|
||||
for (i, item) in neighbor_ids.iter().enumerate() {
|
||||
self.neighbors[vertex_index as usize * self.r as usize + i].store(*item);
|
||||
}
|
||||
**guard = neighbor_ids.len() as u32;
|
||||
}
|
||||
|
||||
fn _get_neighbors(
|
||||
&self,
|
||||
vertex_index: u32,
|
||||
guard: &RwLockReadGuard<u32>,
|
||||
) -> &[AtomicCell<u32>] {
|
||||
//TODO: store neighbor length
|
||||
let size = **guard;
|
||||
&self.neighbors[(vertex_index as usize * self.r as usize)
|
||||
..(vertex_index as usize * self.r as usize + size as usize)]
|
||||
}
|
||||
|
||||
fn _get_neighbors_with_write_guard(
|
||||
&self,
|
||||
vertex_index: u32,
|
||||
guard: &RwLockWriteGuard<u32>,
|
||||
) -> &[AtomicCell<u32>] {
|
||||
let size = **guard;
|
||||
&self.neighbors[(vertex_index as usize * self.r as usize)
|
||||
..(vertex_index as usize * self.r as usize + size as usize)]
|
||||
}
|
||||
|
||||
fn _find_medoid(&self, n: u32) -> u32 {
|
||||
let centroid = self._compute_centroid(n);
|
||||
let centroid_arr: &[Scalar] = ¢roid;
|
||||
|
||||
let mut medoid_index = 0;
|
||||
let mut min_dis = Scalar::INFINITY;
|
||||
for i in 0..n {
|
||||
let dis = self.d.distance(centroid_arr, self.raw.vector(i));
|
||||
if dis < min_dis {
|
||||
min_dis = dis;
|
||||
medoid_index = i;
|
||||
}
|
||||
}
|
||||
medoid_index
|
||||
}
|
||||
|
||||
fn _compute_centroid(&self, n: u32) -> Vec<Scalar> {
|
||||
let dim = self.dims as usize;
|
||||
let mut sum = vec![0_f64; dim]; // change to f32 to avoid overflow
|
||||
for i in 0..n {
|
||||
let vec = self.raw.vector(i);
|
||||
for j in 0..dim {
|
||||
sum[j] += f32::from(vec[j]) as f64;
|
||||
}
|
||||
}
|
||||
|
||||
let collection: Vec<Scalar> = sum
|
||||
.iter()
|
||||
.map(|v| Scalar::from((*v / n as f64) as f32))
|
||||
.collect();
|
||||
collection
|
||||
}
|
||||
|
||||
// r and l leave here for multiple pass extension
|
||||
fn _one_pass(&self, n: u32, alpha: f32, r: u32, l: usize, mut rng: impl Rng) {
|
||||
let mut ids = (0..n).collect::<Vec<_>>();
|
||||
ids.shuffle(&mut rng);
|
||||
|
||||
ids.into_par_iter()
|
||||
.for_each(|id| self.search_and_prune_for_one_vertex(id, alpha, r, l));
|
||||
}
|
||||
|
||||
fn search_and_prune_for_one_vertex(&self, id: u32, alpha: f32, r: u32, l: usize) {
|
||||
let query = self.raw.vector(id);
|
||||
let mut state = self._greedy_search(self.medoid, query, 1, l);
|
||||
state.visited.remove(&id); // in case visited has id itself
|
||||
let mut new_neighbor_ids: HashSet<u32> = HashSet::new();
|
||||
{
|
||||
let mut guard = self.neighbor_size[id as usize].write();
|
||||
let neighbor_ids = self._get_neighbors_with_write_guard(id, &guard);
|
||||
state.visited.extend(neighbor_ids.iter().map(|x| x.load()));
|
||||
let neighbor_ids = self._robust_prune(id, state.visited, alpha, r);
|
||||
let neighbor_ids: HashSet<u32> = neighbor_ids.into_iter().collect();
|
||||
self._set_neighbors(id, &neighbor_ids, &mut guard);
|
||||
new_neighbor_ids = neighbor_ids;
|
||||
}
|
||||
|
||||
for &neighbor_id in new_neighbor_ids.iter() {
|
||||
{
|
||||
let mut guard = self.neighbor_size[neighbor_id as usize].write();
|
||||
let old_neighbors = self._get_neighbors_with_write_guard(neighbor_id, &guard);
|
||||
let mut old_neighbors: HashSet<u32> =
|
||||
old_neighbors.iter().map(|x| x.load()).collect();
|
||||
old_neighbors.insert(id);
|
||||
if old_neighbors.len() > r as usize {
|
||||
// need robust prune
|
||||
let new_neighbors = self._robust_prune(neighbor_id, old_neighbors, alpha, r);
|
||||
let new_neighbors: HashSet<u32> = new_neighbors.into_iter().collect();
|
||||
self._set_neighbors(neighbor_id, &new_neighbors, &mut guard);
|
||||
} else {
|
||||
self._set_neighbors(neighbor_id, &old_neighbors, &mut guard);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn _greedy_search(
|
||||
&self,
|
||||
start: u32,
|
||||
query: &[Scalar],
|
||||
k: usize,
|
||||
search_size: usize,
|
||||
) -> SearchState {
|
||||
let mut state = SearchState::new(k, search_size);
|
||||
|
||||
let dist = self.d.distance(query, self.raw.vector(start));
|
||||
state.push(start, dist);
|
||||
while let Some(id) = state.pop() {
|
||||
// only pop id in the search list but not visited
|
||||
state.visit(id);
|
||||
{
|
||||
let guard = self.neighbor_size[id as usize].read();
|
||||
let neighbor_ids = self._get_neighbors(id, &guard);
|
||||
for neighbor_id in neighbor_ids {
|
||||
let neighbor_id = neighbor_id.load();
|
||||
if state.is_visited(neighbor_id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let dist = self.d.distance(query, self.raw.vector(neighbor_id));
|
||||
state.push(neighbor_id, dist); // push and retain closet l nodes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state
|
||||
}
|
||||
|
||||
fn _robust_prune(&self, id: u32, mut visited: HashSet<u32>, alpha: f32, r: u32) -> Vec<u32> {
|
||||
let mut heap: BinaryHeap<VertexWithDistance> = visited
|
||||
.iter()
|
||||
.map(|v| {
|
||||
let dist = self.d.distance(self.raw.vector(id), self.raw.vector(*v));
|
||||
VertexWithDistance {
|
||||
id: *v,
|
||||
distance: dist,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut new_neighbor_ids: Vec<u32> = vec![];
|
||||
while !visited.is_empty() {
|
||||
if let Some(mut p) = heap.pop() {
|
||||
while !visited.contains(&p.id) {
|
||||
match heap.pop() {
|
||||
Some(value) => {
|
||||
p = value;
|
||||
}
|
||||
None => {
|
||||
return new_neighbor_ids;
|
||||
}
|
||||
}
|
||||
}
|
||||
new_neighbor_ids.push(p.id);
|
||||
if new_neighbor_ids.len() >= r as usize {
|
||||
break;
|
||||
}
|
||||
let mut to_remove: HashSet<u32> = HashSet::new();
|
||||
for pv in visited.iter() {
|
||||
let dist_prime = self.d.distance(self.raw.vector(p.id), self.raw.vector(*pv));
|
||||
let dist_query = self.d.distance(self.raw.vector(id), self.raw.vector(*pv));
|
||||
if Scalar::from(alpha) * dist_prime <= dist_query {
|
||||
to_remove.insert(*pv);
|
||||
}
|
||||
}
|
||||
for pv in to_remove.iter() {
|
||||
visited.remove(pv);
|
||||
}
|
||||
} else {
|
||||
return new_neighbor_ids;
|
||||
}
|
||||
}
|
||||
new_neighbor_ids
|
||||
}
|
||||
}
|
@ -92,13 +92,10 @@ pub struct SegmentStat {
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum IndexStat {
|
||||
Normal {
|
||||
indexing: bool,
|
||||
segments: Vec<SegmentStat>,
|
||||
options: IndexOptions,
|
||||
},
|
||||
Upgrade,
|
||||
pub struct IndexStat {
|
||||
pub indexing: bool,
|
||||
pub segments: Vec<SegmentStat>,
|
||||
pub options: IndexOptions,
|
||||
}
|
||||
|
||||
pub struct Index<S: G> {
|
||||
@ -113,10 +110,10 @@ pub struct Index<S: G> {
|
||||
}
|
||||
|
||||
impl<S: G> Index<S> {
|
||||
pub fn create(path: PathBuf, options: IndexOptions) -> Result<Arc<Self>, ServiceError> {
|
||||
pub fn create(path: PathBuf, options: IndexOptions) -> Result<Arc<Self>, CreateError> {
|
||||
if let Err(err) = options.validate() {
|
||||
return Err(ServiceError::BadOption {
|
||||
validation: err.to_string(),
|
||||
return Err(CreateError::InvalidIndexOptions {
|
||||
reason: err.to_string(),
|
||||
});
|
||||
}
|
||||
std::fs::create_dir(&path).unwrap();
|
||||
@ -277,7 +274,7 @@ impl<S: G> Index<S> {
|
||||
}
|
||||
pub fn stat(&self) -> IndexStat {
|
||||
let view = self.view();
|
||||
IndexStat::Normal {
|
||||
IndexStat {
|
||||
indexing: self.instant_index.load() < self.instant_write.load(),
|
||||
options: self.options().clone(),
|
||||
segments: {
|
||||
@ -326,9 +323,14 @@ impl<S: G> IndexView<S> {
|
||||
vector: S::VectorRef<'_>,
|
||||
opts: &'a SearchOptions,
|
||||
filter: F,
|
||||
) -> Result<impl Iterator<Item = Pointer> + 'a, ServiceError> {
|
||||
) -> Result<impl Iterator<Item = Pointer> + 'a, BasicError> {
|
||||
if self.options.vector.dims != vector.dims() {
|
||||
return Err(ServiceError::Unmatched);
|
||||
return Err(BasicError::InvalidVector);
|
||||
}
|
||||
if let Err(err) = opts.validate() {
|
||||
return Err(BasicError::InvalidSearchOptions {
|
||||
reason: err.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
struct Comparer(std::collections::BinaryHeap<Reverse<Element>>);
|
||||
@ -399,9 +401,14 @@ impl<S: G> IndexView<S> {
|
||||
vector: S::VectorRef<'a>,
|
||||
opts: &'a SearchOptions,
|
||||
filter: F,
|
||||
) -> Result<impl Iterator<Item = Pointer> + 'a, ServiceError> {
|
||||
) -> Result<impl Iterator<Item = Pointer> + 'a, VbaseError> {
|
||||
if self.options.vector.dims != vector.dims() {
|
||||
return Err(ServiceError::Unmatched);
|
||||
return Err(VbaseError::InvalidVector);
|
||||
}
|
||||
if let Err(err) = opts.validate() {
|
||||
return Err(VbaseError::InvalidSearchOptions {
|
||||
reason: err.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
struct Filtering<'a, F: 'a> {
|
||||
@ -463,7 +470,7 @@ impl<S: G> IndexView<S> {
|
||||
}
|
||||
}))
|
||||
}
|
||||
pub fn list(&self) -> impl Iterator<Item = Pointer> + '_ {
|
||||
pub fn list(&self) -> Result<impl Iterator<Item = Pointer> + '_, ListError> {
|
||||
let sealed = self
|
||||
.sealed
|
||||
.values()
|
||||
@ -477,18 +484,19 @@ impl<S: G> IndexView<S> {
|
||||
.iter()
|
||||
.map(|(_, x)| x)
|
||||
.flat_map(|x| (0..x.len()).map(|i| x.payload(i)));
|
||||
sealed
|
||||
let iter = sealed
|
||||
.chain(growing)
|
||||
.chain(write)
|
||||
.filter_map(|p| self.delete.check(p))
|
||||
.filter_map(|p| self.delete.check(p));
|
||||
Ok(iter)
|
||||
}
|
||||
pub fn insert(
|
||||
&self,
|
||||
vector: S::VectorOwned,
|
||||
pointer: Pointer,
|
||||
) -> Result<Result<(), OutdatedError>, ServiceError> {
|
||||
) -> Result<Result<(), OutdatedError>, InsertError> {
|
||||
if self.options.vector.dims != vector.dims() {
|
||||
return Err(ServiceError::Unmatched);
|
||||
return Err(InsertError::InvalidVector);
|
||||
}
|
||||
|
||||
let payload = (pointer.as_u48() << 16) | self.delete.version(pointer) as Payload;
|
||||
@ -502,14 +510,16 @@ impl<S: G> IndexView<S> {
|
||||
Ok(Err(OutdatedError))
|
||||
}
|
||||
}
|
||||
pub fn delete(&self, p: Pointer) {
|
||||
pub fn delete(&self, p: Pointer) -> Result<(), DeleteError> {
|
||||
self.delete.delete(p);
|
||||
Ok(())
|
||||
}
|
||||
pub fn flush(&self) {
|
||||
pub fn flush(&self) -> Result<(), FlushError> {
|
||||
self.delete.flush();
|
||||
if let Some((_, write)) = &self.write {
|
||||
write.flush();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,9 +14,9 @@ pub struct OptimizingOptions {
|
||||
#[serde(default = "OptimizingOptions::default_sealing_size")]
|
||||
#[validate(range(min = 1, max = 4_000_000_000))]
|
||||
pub sealing_size: u32,
|
||||
#[serde(default = "OptimizingOptions::default_deleted_threshold", skip)]
|
||||
#[serde(default = "OptimizingOptions::default_delete_threshold")]
|
||||
#[validate(range(min = 0.01, max = 1.00))]
|
||||
pub deleted_threshold: f64,
|
||||
pub delete_threshold: f64,
|
||||
#[serde(default = "OptimizingOptions::default_optimizing_threads")]
|
||||
#[validate(range(min = 1, max = 65535))]
|
||||
pub optimizing_threads: usize,
|
||||
@ -29,7 +29,7 @@ impl OptimizingOptions {
|
||||
fn default_sealing_size() -> u32 {
|
||||
1
|
||||
}
|
||||
fn default_deleted_threshold() -> f64 {
|
||||
fn default_delete_threshold() -> f64 {
|
||||
0.2
|
||||
}
|
||||
fn default_optimizing_threads() -> usize {
|
||||
@ -45,7 +45,7 @@ impl Default for OptimizingOptions {
|
||||
Self {
|
||||
sealing_secs: Self::default_sealing_secs(),
|
||||
sealing_size: Self::default_sealing_size(),
|
||||
deleted_threshold: Self::default_deleted_threshold(),
|
||||
delete_threshold: Self::default_delete_threshold(),
|
||||
optimizing_threads: Self::default_optimizing_threads(),
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,22 @@ use crate::prelude::*;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub trait InstanceViewOperations {
|
||||
fn basic<'a, F: Fn(Pointer) -> bool + Clone + 'a>(
|
||||
&'a self,
|
||||
vector: &'a DynamicVector,
|
||||
opts: &'a SearchOptions,
|
||||
filter: F,
|
||||
) -> Result<Box<dyn Iterator<Item = Pointer> + 'a>, BasicError>;
|
||||
fn vbase<'a, F: FnMut(Pointer) -> bool + Clone + 'a>(
|
||||
&'a self,
|
||||
vector: &'a DynamicVector,
|
||||
opts: &'a SearchOptions,
|
||||
filter: F,
|
||||
) -> Result<Box<dyn Iterator<Item = Pointer> + 'a>, VbaseError>;
|
||||
fn list(&self) -> Result<Box<dyn Iterator<Item = Pointer> + '_>, ListError>;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Instance {
|
||||
F32Cos(Arc<Index<F32Cos>>),
|
||||
@ -28,7 +44,7 @@ pub enum Instance {
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
pub fn create(path: PathBuf, options: IndexOptions) -> Result<Self, ServiceError> {
|
||||
pub fn create(path: PathBuf, options: IndexOptions) -> Result<Self, CreateError> {
|
||||
match (options.vector.d, options.vector.k) {
|
||||
(Distance::Cos, Kind::F32) => {
|
||||
let index = Index::create(path.clone(), options)?;
|
||||
@ -148,21 +164,21 @@ impl Instance {
|
||||
Instance::Upgrade => None,
|
||||
}
|
||||
}
|
||||
pub fn stat(&self) -> IndexStat {
|
||||
pub fn stat(&self) -> Option<IndexStat> {
|
||||
match self {
|
||||
Instance::F32Cos(x) => x.stat(),
|
||||
Instance::F32Dot(x) => x.stat(),
|
||||
Instance::F32L2(x) => x.stat(),
|
||||
Instance::F16Cos(x) => x.stat(),
|
||||
Instance::F16Dot(x) => x.stat(),
|
||||
Instance::F16L2(x) => x.stat(),
|
||||
Instance::SparseF32L2(x) => x.stat(),
|
||||
Instance::SparseF32Cos(x) => x.stat(),
|
||||
Instance::SparseF32Dot(x) => x.stat(),
|
||||
Instance::BinaryCos(x) => x.stat(),
|
||||
Instance::BinaryDot(x) => x.stat(),
|
||||
Instance::BinaryL2(x) => x.stat(),
|
||||
Instance::Upgrade => IndexStat::Upgrade,
|
||||
Instance::F32Cos(x) => Some(x.stat()),
|
||||
Instance::F32Dot(x) => Some(x.stat()),
|
||||
Instance::F32L2(x) => Some(x.stat()),
|
||||
Instance::F16Cos(x) => Some(x.stat()),
|
||||
Instance::F16Dot(x) => Some(x.stat()),
|
||||
Instance::F16L2(x) => Some(x.stat()),
|
||||
Instance::SparseF32L2(x) => Some(x.stat()),
|
||||
Instance::SparseF32Cos(x) => Some(x.stat()),
|
||||
Instance::SparseF32Dot(x) => Some(x.stat()),
|
||||
Instance::BinaryCos(x) => Some(x.stat()),
|
||||
Instance::BinaryDot(x) => Some(x.stat()),
|
||||
Instance::BinaryL2(x) => Some(x.stat()),
|
||||
Instance::Upgrade => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -182,13 +198,13 @@ pub enum InstanceView {
|
||||
BinaryL2(Arc<IndexView<BinaryL2>>),
|
||||
}
|
||||
|
||||
impl InstanceView {
|
||||
pub fn basic<'a, F: Fn(Pointer) -> bool + Clone + 'a>(
|
||||
impl InstanceViewOperations for InstanceView {
|
||||
fn basic<'a, F: Fn(Pointer) -> bool + Clone + 'a>(
|
||||
&'a self,
|
||||
vector: &'a DynamicVector,
|
||||
opts: &'a SearchOptions,
|
||||
filter: F,
|
||||
) -> Result<impl Iterator<Item = Pointer> + 'a, ServiceError> {
|
||||
) -> Result<Box<dyn Iterator<Item = Pointer> + 'a>, BasicError> {
|
||||
match (self, vector) {
|
||||
(InstanceView::F32Cos(x), DynamicVector::F32(vector)) => {
|
||||
Ok(Box::new(x.basic(vector, opts, filter)?) as Box<dyn Iterator<Item = Pointer>>)
|
||||
@ -226,15 +242,15 @@ impl InstanceView {
|
||||
(InstanceView::BinaryL2(x), DynamicVector::Binary(vector)) => {
|
||||
Ok(Box::new(x.basic(vector.into(), opts, filter)?))
|
||||
}
|
||||
_ => Err(ServiceError::Unmatched),
|
||||
_ => Err(BasicError::InvalidVector),
|
||||
}
|
||||
}
|
||||
pub fn vbase<'a, F: FnMut(Pointer) -> bool + Clone + 'a>(
|
||||
fn vbase<'a, F: FnMut(Pointer) -> bool + Clone + 'a>(
|
||||
&'a self,
|
||||
vector: &'a DynamicVector,
|
||||
opts: &'a SearchOptions,
|
||||
filter: F,
|
||||
) -> Result<impl Iterator<Item = Pointer> + '_, ServiceError> {
|
||||
) -> Result<Box<dyn Iterator<Item = Pointer> + 'a>, VbaseError> {
|
||||
match (self, vector) {
|
||||
(InstanceView::F32Cos(x), DynamicVector::F32(vector)) => {
|
||||
Ok(Box::new(x.vbase(vector, opts, filter)?) as Box<dyn Iterator<Item = Pointer>>)
|
||||
@ -272,30 +288,33 @@ impl InstanceView {
|
||||
(InstanceView::BinaryL2(x), DynamicVector::Binary(vector)) => {
|
||||
Ok(Box::new(x.vbase(vector.into(), opts, filter)?))
|
||||
}
|
||||
_ => Err(ServiceError::Unmatched),
|
||||
_ => Err(VbaseError::InvalidVector),
|
||||
}
|
||||
}
|
||||
pub fn list(&self) -> impl Iterator<Item = Pointer> + '_ {
|
||||
fn list(&self) -> Result<Box<dyn Iterator<Item = Pointer> + '_>, ListError> {
|
||||
match self {
|
||||
InstanceView::F32Cos(x) => Box::new(x.list()) as Box<dyn Iterator<Item = Pointer>>,
|
||||
InstanceView::F32Dot(x) => Box::new(x.list()),
|
||||
InstanceView::F32L2(x) => Box::new(x.list()),
|
||||
InstanceView::F16Cos(x) => Box::new(x.list()),
|
||||
InstanceView::F16Dot(x) => Box::new(x.list()),
|
||||
InstanceView::F16L2(x) => Box::new(x.list()),
|
||||
InstanceView::SparseF32Cos(x) => Box::new(x.list()),
|
||||
InstanceView::SparseF32Dot(x) => Box::new(x.list()),
|
||||
InstanceView::SparseF32L2(x) => Box::new(x.list()),
|
||||
InstanceView::BinaryCos(x) => Box::new(x.list()),
|
||||
InstanceView::BinaryDot(x) => Box::new(x.list()),
|
||||
InstanceView::BinaryL2(x) => Box::new(x.list()),
|
||||
InstanceView::F32Cos(x) => Ok(Box::new(x.list()?) as Box<dyn Iterator<Item = Pointer>>),
|
||||
InstanceView::F32Dot(x) => Ok(Box::new(x.list()?)),
|
||||
InstanceView::F32L2(x) => Ok(Box::new(x.list()?)),
|
||||
InstanceView::F16Cos(x) => Ok(Box::new(x.list()?)),
|
||||
InstanceView::F16Dot(x) => Ok(Box::new(x.list()?)),
|
||||
InstanceView::F16L2(x) => Ok(Box::new(x.list()?)),
|
||||
InstanceView::SparseF32Cos(x) => Ok(Box::new(x.list()?)),
|
||||
InstanceView::SparseF32Dot(x) => Ok(Box::new(x.list()?)),
|
||||
InstanceView::SparseF32L2(x) => Ok(Box::new(x.list()?)),
|
||||
InstanceView::BinaryCos(x) => Ok(Box::new(x.list()?)),
|
||||
InstanceView::BinaryDot(x) => Ok(Box::new(x.list()?)),
|
||||
InstanceView::BinaryL2(x) => Ok(Box::new(x.list()?)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InstanceView {
|
||||
pub fn insert(
|
||||
&self,
|
||||
vector: DynamicVector,
|
||||
pointer: Pointer,
|
||||
) -> Result<Result<(), OutdatedError>, ServiceError> {
|
||||
) -> Result<Result<(), OutdatedError>, InsertError> {
|
||||
match (self, vector) {
|
||||
(InstanceView::F32Cos(x), DynamicVector::F32(vector)) => x.insert(vector, pointer),
|
||||
(InstanceView::F32Dot(x), DynamicVector::F32(vector)) => x.insert(vector, pointer),
|
||||
@ -319,10 +338,10 @@ impl InstanceView {
|
||||
x.insert(vector, pointer)
|
||||
}
|
||||
(InstanceView::BinaryL2(x), DynamicVector::Binary(vector)) => x.insert(vector, pointer),
|
||||
_ => Err(ServiceError::Unmatched),
|
||||
_ => Err(InsertError::InvalidVector),
|
||||
}
|
||||
}
|
||||
pub fn delete(&self, pointer: Pointer) {
|
||||
pub fn delete(&self, pointer: Pointer) -> Result<(), DeleteError> {
|
||||
match self {
|
||||
InstanceView::F32Cos(x) => x.delete(pointer),
|
||||
InstanceView::F32Dot(x) => x.delete(pointer),
|
||||
@ -338,7 +357,7 @@ impl InstanceView {
|
||||
InstanceView::BinaryL2(x) => x.delete(pointer),
|
||||
}
|
||||
}
|
||||
pub fn flush(&self) {
|
||||
pub fn flush(&self) -> Result<(), FlushError> {
|
||||
match self {
|
||||
InstanceView::F32Cos(x) => x.flush(),
|
||||
InstanceView::F32Dot(x) => x.flush(),
|
||||
|
@ -1,6 +1,5 @@
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(avx512_target_feature)]
|
||||
#![feature(pointer_is_aligned)]
|
||||
|
||||
pub mod algorithms;
|
||||
pub mod index;
|
||||
|
@ -1,37 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
#[must_use]
|
||||
#[derive(Debug, Clone, Error, Serialize, Deserialize)]
|
||||
#[rustfmt::skip]
|
||||
pub enum ServiceError {
|
||||
#[error("\
|
||||
The given index option is invalid.
|
||||
INFORMATION: reason = {validation:?}\
|
||||
")]
|
||||
BadOption { validation: String },
|
||||
#[error("\
|
||||
The index is not existing in the background worker.
|
||||
ADVICE: Drop or rebuild the index.\
|
||||
")]
|
||||
UnknownIndex,
|
||||
#[error("\
|
||||
The index is already existing in the background worker.\
|
||||
")]
|
||||
KnownIndex,
|
||||
#[error("\
|
||||
The given vector is invalid for input.
|
||||
ADVICE: Check if dimensions and scalar type of the vector is matched with the index.\
|
||||
")]
|
||||
Unmatched,
|
||||
#[error("\
|
||||
The extension is upgraded so all index files are outdated.
|
||||
ADVICE: Delete all index files. Please read `https://docs.pgvecto.rs/admin/upgrading.html`.\
|
||||
")]
|
||||
Upgrade,
|
||||
#[error("\
|
||||
The extension is upgraded so this index is outdated.
|
||||
ADVICE: Rebuild the index. Please read `https://docs.pgvecto.rs/admin/upgrading.html`.\
|
||||
")]
|
||||
Upgrade2,
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
use crate::prelude::*;
|
||||
use base::scalar::FloatCast;
|
||||
|
||||
pub fn cosine(lhs: &[F16], rhs: &[F16]) -> F32 {
|
||||
#[inline(always)]
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::prelude::*;
|
||||
use base::scalar::FloatCast;
|
||||
use std::borrow::Cow;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum F16Cos {}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::prelude::*;
|
||||
use base::scalar::FloatCast;
|
||||
use std::borrow::Cow;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum F16Dot {}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::prelude::*;
|
||||
use base::scalar::FloatCast;
|
||||
use std::borrow::Cow;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum F16L2 {}
|
||||
|
@ -1,6 +1,5 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::prelude::*;
|
||||
use std::borrow::Cow;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum F32L2 {}
|
||||
|
@ -15,6 +15,9 @@ mod sparse_f32_cos;
|
||||
mod sparse_f32_dot;
|
||||
mod sparse_f32_l2;
|
||||
|
||||
pub use binary_cos::BinaryCos;
|
||||
pub use binary_dot::BinaryDot;
|
||||
pub use binary_l2::BinaryL2;
|
||||
pub use f16_cos::F16Cos;
|
||||
pub use f16_dot::F16Dot;
|
||||
pub use f16_l2::F16L2;
|
||||
@ -24,9 +27,6 @@ pub use f32_l2::F32L2;
|
||||
pub use sparse_f32_cos::SparseF32Cos;
|
||||
pub use sparse_f32_dot::SparseF32Dot;
|
||||
pub use sparse_f32_l2::SparseF32L2;
|
||||
pub use binary_cos::BinaryCos;
|
||||
pub use binary_dot::BinaryDot;
|
||||
pub use binary_l2::BinaryL2;
|
||||
|
||||
use crate::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -50,7 +50,7 @@ pub trait G: Copy + Debug + 'static {
|
||||
+ Zero
|
||||
+ num_traits::NumOps
|
||||
+ num_traits::NumAssignOps
|
||||
+ FloatCast;
|
||||
+ base::scalar::FloatCast;
|
||||
type Storage: for<'a> Storage<VectorRef<'a> = Self::VectorRef<'a>>;
|
||||
type L2: for<'a> G<Scalar = Self::Scalar, VectorRef<'a> = &'a [Self::Scalar]>;
|
||||
type VectorOwned: Vector + Clone + Serialize + for<'a> Deserialize<'a>;
|
||||
@ -126,33 +126,6 @@ pub trait G: Copy + Debug + 'static {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait FloatCast: Sized {
|
||||
fn from_f32(x: f32) -> Self;
|
||||
fn to_f32(self) -> f32;
|
||||
fn from_f(x: F32) -> Self {
|
||||
Self::from_f32(x.0)
|
||||
}
|
||||
fn to_f(self) -> F32 {
|
||||
F32(Self::to_f32(self))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Vector {
|
||||
fn dims(&self) -> u16;
|
||||
}
|
||||
|
||||
impl<T> Vector for Vec<T> {
|
||||
fn dims(&self) -> u16 {
|
||||
self.len().try_into().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Vector for &'a [T] {
|
||||
fn dims(&self) -> u16 {
|
||||
self.len().try_into().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum DynamicVector {
|
||||
F32(Vec<F32>),
|
||||
|
@ -47,6 +47,6 @@ impl G for SparseF32Cos {
|
||||
}
|
||||
|
||||
fn elkan_k_means_distance2(lhs: &SparseF32, rhs: &[Self::Scalar]) -> F32 {
|
||||
super::sparse_f32::dot_2( SparseF32Ref::from(lhs), rhs).acos()
|
||||
super::sparse_f32::dot_2(SparseF32Ref::from(lhs), rhs).acos()
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,13 @@
|
||||
mod error;
|
||||
mod global;
|
||||
mod scalar;
|
||||
mod search;
|
||||
mod storage;
|
||||
mod sys;
|
||||
|
||||
pub use self::error::ServiceError;
|
||||
pub use self::global::*;
|
||||
pub use self::scalar::{BinaryVec, BinaryVecRef, SparseF32, SparseF32Ref, F16, F32};
|
||||
pub use self::search::{Element, Filter, Payload};
|
||||
pub use self::storage::{DenseMmap, SparseMmap, Storage, BinaryMmap};
|
||||
pub use self::sys::{Handle, Pointer};
|
||||
pub use self::storage::{BinaryMmap, DenseMmap, SparseMmap, Storage};
|
||||
|
||||
pub use base::error::*;
|
||||
pub use base::scalar::{F16, F32};
|
||||
pub use base::search::{Element, Filter, Payload};
|
||||
pub use base::sys::{Handle, Pointer};
|
||||
pub use base::vector::{BinaryVec, BinaryVecRef, SparseF32, SparseF32Ref, Vector};
|
||||
|
||||
pub use num_traits::{Float, Zero};
|
||||
|
@ -1,61 +0,0 @@
|
||||
use crate::prelude::*;
|
||||
use bitvec::{slice::BitSlice, vec::BitVec};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct BinaryVec {
|
||||
pub values: BitVec,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct BinaryVecRef<'a> {
|
||||
// NOTE: In order to store bitslice to &[usize], we need to ensure there are no prefix bits.
|
||||
pub values: &'a BitSlice,
|
||||
}
|
||||
|
||||
impl<'a> From<BinaryVecRef<'a>> for BinaryVec {
|
||||
fn from(value: BinaryVecRef<'a>) -> Self {
|
||||
Self {
|
||||
values: value.values.to_bitvec(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a BinaryVec> for BinaryVecRef<'a> {
|
||||
fn from(value: &'a BinaryVec) -> Self {
|
||||
Self {
|
||||
values: &value.values,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Vector for BinaryVec {
|
||||
fn dims(&self) -> u16 {
|
||||
self.values.len().try_into().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Vector for BinaryVecRef<'a> {
|
||||
fn dims(&self) -> u16 {
|
||||
self.values.len().try_into().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<BinaryVecRef<'a>> for Vec<F32> {
|
||||
fn from(value: BinaryVecRef<'a>) -> Self {
|
||||
value.values.iter().map(|x| F32(*x as u32 as f32)).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> BinaryVecRef<'a> {
|
||||
pub fn as_bytes(self) -> &'a [usize] {
|
||||
// ensure that the slice doesn't contain prefix bits
|
||||
assert!(self.values.as_bitptr().pointer().is_aligned());
|
||||
unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
self.values.as_bitptr().pointer(),
|
||||
self.values.len().div_ceil(std::mem::size_of::<usize>() * 8),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,653 +0,0 @@
|
||||
use crate::prelude::global::FloatCast;
|
||||
use half::f16;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::num::ParseFloatError;
|
||||
use std::ops::*;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Clone, Copy, Default, Serialize, Deserialize)]
|
||||
#[repr(transparent)]
|
||||
#[serde(transparent)]
|
||||
pub struct F16(pub f16);
|
||||
|
||||
impl Debug for F16 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
Debug::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for F16 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for F16 {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0.total_cmp(&other.0) == Ordering::Equal
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for F16 {}
|
||||
|
||||
impl PartialOrd for F16 {
|
||||
#[inline(always)]
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(Ord::cmp(self, other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for F16 {
|
||||
#[inline(always)]
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.0.total_cmp(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl bytemuck::Zeroable for F16 {}
|
||||
|
||||
unsafe impl bytemuck::Pod for F16 {}
|
||||
|
||||
impl num_traits::Zero for F16 {
|
||||
fn zero() -> Self {
|
||||
Self(f16::zero())
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> bool {
|
||||
self.0.is_zero()
|
||||
}
|
||||
}
|
||||
|
||||
impl num_traits::One for F16 {
|
||||
fn one() -> Self {
|
||||
Self(f16::one())
|
||||
}
|
||||
}
|
||||
|
||||
impl num_traits::FromPrimitive for F16 {
|
||||
fn from_i64(n: i64) -> Option<Self> {
|
||||
f16::from_i64(n).map(Self)
|
||||
}
|
||||
|
||||
fn from_u64(n: u64) -> Option<Self> {
|
||||
f16::from_u64(n).map(Self)
|
||||
}
|
||||
|
||||
fn from_isize(n: isize) -> Option<Self> {
|
||||
f16::from_isize(n).map(Self)
|
||||
}
|
||||
|
||||
fn from_i8(n: i8) -> Option<Self> {
|
||||
f16::from_i8(n).map(Self)
|
||||
}
|
||||
|
||||
fn from_i16(n: i16) -> Option<Self> {
|
||||
f16::from_i16(n).map(Self)
|
||||
}
|
||||
|
||||
fn from_i32(n: i32) -> Option<Self> {
|
||||
f16::from_i32(n).map(Self)
|
||||
}
|
||||
|
||||
fn from_i128(n: i128) -> Option<Self> {
|
||||
f16::from_i128(n).map(Self)
|
||||
}
|
||||
|
||||
fn from_usize(n: usize) -> Option<Self> {
|
||||
f16::from_usize(n).map(Self)
|
||||
}
|
||||
|
||||
fn from_u8(n: u8) -> Option<Self> {
|
||||
f16::from_u8(n).map(Self)
|
||||
}
|
||||
|
||||
fn from_u16(n: u16) -> Option<Self> {
|
||||
f16::from_u16(n).map(Self)
|
||||
}
|
||||
|
||||
fn from_u32(n: u32) -> Option<Self> {
|
||||
f16::from_u32(n).map(Self)
|
||||
}
|
||||
|
||||
fn from_u128(n: u128) -> Option<Self> {
|
||||
f16::from_u128(n).map(Self)
|
||||
}
|
||||
|
||||
fn from_f32(n: f32) -> Option<Self> {
|
||||
Some(Self(f16::from_f32(n)))
|
||||
}
|
||||
|
||||
fn from_f64(n: f64) -> Option<Self> {
|
||||
Some(Self(f16::from_f64(n)))
|
||||
}
|
||||
}
|
||||
|
||||
impl num_traits::ToPrimitive for F16 {
|
||||
fn to_i64(&self) -> Option<i64> {
|
||||
self.0.to_i64()
|
||||
}
|
||||
|
||||
fn to_u64(&self) -> Option<u64> {
|
||||
self.0.to_u64()
|
||||
}
|
||||
|
||||
fn to_isize(&self) -> Option<isize> {
|
||||
self.0.to_isize()
|
||||
}
|
||||
|
||||
fn to_i8(&self) -> Option<i8> {
|
||||
self.0.to_i8()
|
||||
}
|
||||
|
||||
fn to_i16(&self) -> Option<i16> {
|
||||
self.0.to_i16()
|
||||
}
|
||||
|
||||
fn to_i32(&self) -> Option<i32> {
|
||||
self.0.to_i32()
|
||||
}
|
||||
|
||||
fn to_i128(&self) -> Option<i128> {
|
||||
self.0.to_i128()
|
||||
}
|
||||
|
||||
fn to_usize(&self) -> Option<usize> {
|
||||
self.0.to_usize()
|
||||
}
|
||||
|
||||
fn to_u8(&self) -> Option<u8> {
|
||||
self.0.to_u8()
|
||||
}
|
||||
|
||||
fn to_u16(&self) -> Option<u16> {
|
||||
self.0.to_u16()
|
||||
}
|
||||
|
||||
fn to_u32(&self) -> Option<u32> {
|
||||
self.0.to_u32()
|
||||
}
|
||||
|
||||
fn to_u128(&self) -> Option<u128> {
|
||||
self.0.to_u128()
|
||||
}
|
||||
|
||||
fn to_f32(&self) -> Option<f32> {
|
||||
Some(self.0.to_f32())
|
||||
}
|
||||
|
||||
fn to_f64(&self) -> Option<f64> {
|
||||
Some(self.0.to_f64())
|
||||
}
|
||||
}
|
||||
|
||||
impl num_traits::NumCast for F16 {
|
||||
fn from<T: num_traits::ToPrimitive>(n: T) -> Option<Self> {
|
||||
num_traits::NumCast::from(n).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl num_traits::Num for F16 {
|
||||
type FromStrRadixErr = <f16 as num_traits::Num>::FromStrRadixErr;
|
||||
|
||||
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
|
||||
f16::from_str_radix(str, radix).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl num_traits::Float for F16 {
|
||||
fn nan() -> Self {
|
||||
Self(f16::nan())
|
||||
}
|
||||
|
||||
fn infinity() -> Self {
|
||||
Self(f16::infinity())
|
||||
}
|
||||
|
||||
fn neg_infinity() -> Self {
|
||||
Self(f16::neg_infinity())
|
||||
}
|
||||
|
||||
fn neg_zero() -> Self {
|
||||
Self(f16::neg_zero())
|
||||
}
|
||||
|
||||
fn min_value() -> Self {
|
||||
Self(f16::min_value())
|
||||
}
|
||||
|
||||
fn min_positive_value() -> Self {
|
||||
Self(f16::min_positive_value())
|
||||
}
|
||||
|
||||
fn max_value() -> Self {
|
||||
Self(f16::max_value())
|
||||
}
|
||||
|
||||
fn is_nan(self) -> bool {
|
||||
self.0.is_nan()
|
||||
}
|
||||
|
||||
fn is_infinite(self) -> bool {
|
||||
self.0.is_infinite()
|
||||
}
|
||||
|
||||
fn is_finite(self) -> bool {
|
||||
self.0.is_finite()
|
||||
}
|
||||
|
||||
fn is_normal(self) -> bool {
|
||||
self.0.is_normal()
|
||||
}
|
||||
|
||||
fn classify(self) -> std::num::FpCategory {
|
||||
self.0.classify()
|
||||
}
|
||||
|
||||
fn floor(self) -> Self {
|
||||
Self(self.0.floor())
|
||||
}
|
||||
|
||||
fn ceil(self) -> Self {
|
||||
Self(self.0.ceil())
|
||||
}
|
||||
|
||||
fn round(self) -> Self {
|
||||
Self(self.0.round())
|
||||
}
|
||||
|
||||
fn trunc(self) -> Self {
|
||||
Self(self.0.trunc())
|
||||
}
|
||||
|
||||
fn fract(self) -> Self {
|
||||
Self(self.0.fract())
|
||||
}
|
||||
|
||||
fn abs(self) -> Self {
|
||||
Self(self.0.abs())
|
||||
}
|
||||
|
||||
fn signum(self) -> Self {
|
||||
Self(self.0.signum())
|
||||
}
|
||||
|
||||
fn is_sign_positive(self) -> bool {
|
||||
self.0.is_sign_positive()
|
||||
}
|
||||
|
||||
fn is_sign_negative(self) -> bool {
|
||||
self.0.is_sign_negative()
|
||||
}
|
||||
|
||||
fn mul_add(self, a: Self, b: Self) -> Self {
|
||||
Self(self.0.mul_add(a.0, b.0))
|
||||
}
|
||||
|
||||
fn recip(self) -> Self {
|
||||
Self(self.0.recip())
|
||||
}
|
||||
|
||||
fn powi(self, n: i32) -> Self {
|
||||
Self(self.0.powi(n))
|
||||
}
|
||||
|
||||
fn powf(self, n: Self) -> Self {
|
||||
Self(self.0.powf(n.0))
|
||||
}
|
||||
|
||||
fn sqrt(self) -> Self {
|
||||
Self(self.0.sqrt())
|
||||
}
|
||||
|
||||
fn exp(self) -> Self {
|
||||
Self(self.0.exp())
|
||||
}
|
||||
|
||||
fn exp2(self) -> Self {
|
||||
Self(self.0.exp2())
|
||||
}
|
||||
|
||||
fn ln(self) -> Self {
|
||||
Self(self.0.ln())
|
||||
}
|
||||
|
||||
fn log(self, base: Self) -> Self {
|
||||
Self(self.0.log(base.0))
|
||||
}
|
||||
|
||||
fn log2(self) -> Self {
|
||||
Self(self.0.log2())
|
||||
}
|
||||
|
||||
fn log10(self) -> Self {
|
||||
Self(self.0.log10())
|
||||
}
|
||||
|
||||
fn max(self, other: Self) -> Self {
|
||||
Self(self.0.max(other.0))
|
||||
}
|
||||
|
||||
fn min(self, other: Self) -> Self {
|
||||
Self(self.0.min(other.0))
|
||||
}
|
||||
|
||||
fn abs_sub(self, _: Self) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn cbrt(self) -> Self {
|
||||
Self(self.0.cbrt())
|
||||
}
|
||||
|
||||
fn hypot(self, other: Self) -> Self {
|
||||
Self(self.0.hypot(other.0))
|
||||
}
|
||||
|
||||
fn sin(self) -> Self {
|
||||
Self(self.0.sin())
|
||||
}
|
||||
|
||||
fn cos(self) -> Self {
|
||||
Self(self.0.cos())
|
||||
}
|
||||
|
||||
fn tan(self) -> Self {
|
||||
Self(self.0.tan())
|
||||
}
|
||||
|
||||
fn asin(self) -> Self {
|
||||
Self(self.0.asin())
|
||||
}
|
||||
|
||||
fn acos(self) -> Self {
|
||||
Self(self.0.acos())
|
||||
}
|
||||
|
||||
fn atan(self) -> Self {
|
||||
Self(self.0.atan())
|
||||
}
|
||||
|
||||
fn atan2(self, other: Self) -> Self {
|
||||
Self(self.0.atan2(other.0))
|
||||
}
|
||||
|
||||
fn sin_cos(self) -> (Self, Self) {
|
||||
let (_x, _y) = self.0.sin_cos();
|
||||
(Self(_x), Self(_y))
|
||||
}
|
||||
|
||||
fn exp_m1(self) -> Self {
|
||||
Self(self.0.exp_m1())
|
||||
}
|
||||
|
||||
fn ln_1p(self) -> Self {
|
||||
Self(self.0.ln_1p())
|
||||
}
|
||||
|
||||
fn sinh(self) -> Self {
|
||||
Self(self.0.sinh())
|
||||
}
|
||||
|
||||
fn cosh(self) -> Self {
|
||||
Self(self.0.cosh())
|
||||
}
|
||||
|
||||
fn tanh(self) -> Self {
|
||||
Self(self.0.tanh())
|
||||
}
|
||||
|
||||
fn asinh(self) -> Self {
|
||||
Self(self.0.asinh())
|
||||
}
|
||||
|
||||
fn acosh(self) -> Self {
|
||||
Self(self.0.acosh())
|
||||
}
|
||||
|
||||
fn atanh(self) -> Self {
|
||||
Self(self.0.atanh())
|
||||
}
|
||||
|
||||
fn integer_decode(self) -> (u64, i16, i8) {
|
||||
self.0.integer_decode()
|
||||
}
|
||||
|
||||
fn epsilon() -> Self {
|
||||
Self(f16::EPSILON)
|
||||
}
|
||||
|
||||
fn is_subnormal(self) -> bool {
|
||||
self.0.classify() == std::num::FpCategory::Subnormal
|
||||
}
|
||||
|
||||
fn to_degrees(self) -> Self {
|
||||
Self(self.0.to_degrees())
|
||||
}
|
||||
|
||||
fn to_radians(self) -> Self {
|
||||
Self(self.0.to_radians())
|
||||
}
|
||||
|
||||
fn copysign(self, sign: Self) -> Self {
|
||||
Self(self.0.copysign(sign.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<F16> for F16 {
|
||||
type Output = F16;
|
||||
|
||||
#[inline(always)]
|
||||
fn add(self, rhs: F16) -> F16 {
|
||||
unsafe { self::intrinsics::fadd_fast(self.0, rhs.0).into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<F16> for F16 {
|
||||
#[inline(always)]
|
||||
fn add_assign(&mut self, rhs: F16) {
|
||||
unsafe { self.0 = self::intrinsics::fadd_fast(self.0, rhs.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<F16> for F16 {
|
||||
type Output = F16;
|
||||
|
||||
#[inline(always)]
|
||||
fn sub(self, rhs: F16) -> F16 {
|
||||
unsafe { self::intrinsics::fsub_fast(self.0, rhs.0).into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign<F16> for F16 {
|
||||
#[inline(always)]
|
||||
fn sub_assign(&mut self, rhs: F16) {
|
||||
unsafe { self.0 = self::intrinsics::fsub_fast(self.0, rhs.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<F16> for F16 {
|
||||
type Output = F16;
|
||||
|
||||
#[inline(always)]
|
||||
fn mul(self, rhs: F16) -> F16 {
|
||||
unsafe { self::intrinsics::fmul_fast(self.0, rhs.0).into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl MulAssign<F16> for F16 {
|
||||
#[inline(always)]
|
||||
fn mul_assign(&mut self, rhs: F16) {
|
||||
unsafe { self.0 = self::intrinsics::fmul_fast(self.0, rhs.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<F16> for F16 {
|
||||
type Output = F16;
|
||||
|
||||
#[inline(always)]
|
||||
fn div(self, rhs: F16) -> F16 {
|
||||
unsafe { self::intrinsics::fdiv_fast(self.0, rhs.0).into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl DivAssign<F16> for F16 {
|
||||
#[inline(always)]
|
||||
fn div_assign(&mut self, rhs: F16) {
|
||||
unsafe { self.0 = self::intrinsics::fdiv_fast(self.0, rhs.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Rem<F16> for F16 {
|
||||
type Output = F16;
|
||||
|
||||
#[inline(always)]
|
||||
fn rem(self, rhs: F16) -> F16 {
|
||||
unsafe { self::intrinsics::frem_fast(self.0, rhs.0).into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl RemAssign<F16> for F16 {
|
||||
#[inline(always)]
|
||||
fn rem_assign(&mut self, rhs: F16) {
|
||||
unsafe { self.0 = self::intrinsics::frem_fast(self.0, rhs.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Neg for F16 {
|
||||
type Output = Self;
|
||||
|
||||
fn neg(self) -> Self::Output {
|
||||
Self(self.0.neg())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for F16 {
|
||||
type Err = ParseFloatError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
f16::from_str(s).map(|x| x.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl FloatCast for F16 {
|
||||
fn from_f32(x: f32) -> Self {
|
||||
Self(f16::from_f32(x))
|
||||
}
|
||||
|
||||
fn to_f32(self) -> f32 {
|
||||
f16::to_f32(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f16> for F16 {
|
||||
fn from(value: f16) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<F16> for f16 {
|
||||
fn from(F16(float): F16) -> Self {
|
||||
float
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<f16> for F16 {
|
||||
type Output = F16;
|
||||
|
||||
#[inline(always)]
|
||||
fn add(self, rhs: f16) -> F16 {
|
||||
unsafe { self::intrinsics::fadd_fast(self.0, rhs).into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<f16> for F16 {
|
||||
fn add_assign(&mut self, rhs: f16) {
|
||||
unsafe { self.0 = self::intrinsics::fadd_fast(self.0, rhs) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<f16> for F16 {
|
||||
type Output = F16;
|
||||
|
||||
#[inline(always)]
|
||||
fn sub(self, rhs: f16) -> F16 {
|
||||
unsafe { self::intrinsics::fsub_fast(self.0, rhs).into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign<f16> for F16 {
|
||||
#[inline(always)]
|
||||
fn sub_assign(&mut self, rhs: f16) {
|
||||
unsafe { self.0 = self::intrinsics::fsub_fast(self.0, rhs) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<f16> for F16 {
|
||||
type Output = F16;
|
||||
|
||||
#[inline(always)]
|
||||
fn mul(self, rhs: f16) -> F16 {
|
||||
unsafe { self::intrinsics::fmul_fast(self.0, rhs).into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl MulAssign<f16> for F16 {
|
||||
#[inline(always)]
|
||||
fn mul_assign(&mut self, rhs: f16) {
|
||||
unsafe { self.0 = self::intrinsics::fmul_fast(self.0, rhs) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<f16> for F16 {
|
||||
type Output = F16;
|
||||
|
||||
#[inline(always)]
|
||||
fn div(self, rhs: f16) -> F16 {
|
||||
unsafe { self::intrinsics::fdiv_fast(self.0, rhs).into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl DivAssign<f16> for F16 {
|
||||
#[inline(always)]
|
||||
fn div_assign(&mut self, rhs: f16) {
|
||||
unsafe { self.0 = self::intrinsics::fdiv_fast(self.0, rhs) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Rem<f16> for F16 {
|
||||
type Output = F16;
|
||||
|
||||
#[inline(always)]
|
||||
fn rem(self, rhs: f16) -> F16 {
|
||||
unsafe { self::intrinsics::frem_fast(self.0, rhs).into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl RemAssign<f16> for F16 {
|
||||
#[inline(always)]
|
||||
fn rem_assign(&mut self, rhs: f16) {
|
||||
unsafe { self.0 = self::intrinsics::frem_fast(self.0, rhs) }
|
||||
}
|
||||
}
|
||||
|
||||
mod intrinsics {
|
||||
use half::f16;
|
||||
|
||||
pub unsafe fn fadd_fast(lhs: f16, rhs: f16) -> f16 {
|
||||
lhs + rhs
|
||||
}
|
||||
pub unsafe fn fsub_fast(lhs: f16, rhs: f16) -> f16 {
|
||||
lhs - rhs
|
||||
}
|
||||
pub unsafe fn fmul_fast(lhs: f16, rhs: f16) -> f16 {
|
||||
lhs * rhs
|
||||
}
|
||||
pub unsafe fn fdiv_fast(lhs: f16, rhs: f16) -> f16 {
|
||||
lhs / rhs
|
||||
}
|
||||
pub unsafe fn frem_fast(lhs: f16, rhs: f16) -> f16 {
|
||||
lhs % rhs
|
||||
}
|
||||
}
|
@ -1,632 +0,0 @@
|
||||
use crate::prelude::global::FloatCast;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::num::ParseFloatError;
|
||||
use std::ops::*;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Clone, Copy, Default, Serialize, Deserialize)]
|
||||
#[repr(transparent)]
|
||||
#[serde(transparent)]
|
||||
pub struct F32(pub f32);
|
||||
|
||||
impl Debug for F32 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
Debug::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for F32 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for F32 {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0.total_cmp(&other.0) == Ordering::Equal
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for F32 {}
|
||||
|
||||
impl PartialOrd for F32 {
|
||||
#[inline(always)]
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(Ord::cmp(self, other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for F32 {
|
||||
#[inline(always)]
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.0.total_cmp(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl bytemuck::Zeroable for F32 {}
|
||||
|
||||
unsafe impl bytemuck::Pod for F32 {}
|
||||
|
||||
impl num_traits::Zero for F32 {
|
||||
fn zero() -> Self {
|
||||
Self(f32::zero())
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> bool {
|
||||
self.0.is_zero()
|
||||
}
|
||||
}
|
||||
|
||||
impl num_traits::One for F32 {
|
||||
fn one() -> Self {
|
||||
Self(f32::one())
|
||||
}
|
||||
}
|
||||
|
||||
impl num_traits::FromPrimitive for F32 {
|
||||
fn from_i64(n: i64) -> Option<Self> {
|
||||
f32::from_i64(n).map(Self)
|
||||
}
|
||||
|
||||
fn from_u64(n: u64) -> Option<Self> {
|
||||
f32::from_u64(n).map(Self)
|
||||
}
|
||||
|
||||
fn from_isize(n: isize) -> Option<Self> {
|
||||
f32::from_isize(n).map(Self)
|
||||
}
|
||||
|
||||
fn from_i8(n: i8) -> Option<Self> {
|
||||
f32::from_i8(n).map(Self)
|
||||
}
|
||||
|
||||
fn from_i16(n: i16) -> Option<Self> {
|
||||
f32::from_i16(n).map(Self)
|
||||
}
|
||||
|
||||
fn from_i32(n: i32) -> Option<Self> {
|
||||
f32::from_i32(n).map(Self)
|
||||
}
|
||||
|
||||
fn from_i128(n: i128) -> Option<Self> {
|
||||
f32::from_i128(n).map(Self)
|
||||
}
|
||||
|
||||
fn from_usize(n: usize) -> Option<Self> {
|
||||
f32::from_usize(n).map(Self)
|
||||
}
|
||||
|
||||
fn from_u8(n: u8) -> Option<Self> {
|
||||
f32::from_u8(n).map(Self)
|
||||
}
|
||||
|
||||
fn from_u16(n: u16) -> Option<Self> {
|
||||
f32::from_u16(n).map(Self)
|
||||
}
|
||||
|
||||
fn from_u32(n: u32) -> Option<Self> {
|
||||
f32::from_u32(n).map(Self)
|
||||
}
|
||||
|
||||
fn from_u128(n: u128) -> Option<Self> {
|
||||
f32::from_u128(n).map(Self)
|
||||
}
|
||||
|
||||
fn from_f32(n: f32) -> Option<Self> {
|
||||
f32::from_f32(n).map(Self)
|
||||
}
|
||||
|
||||
fn from_f64(n: f64) -> Option<Self> {
|
||||
f32::from_f64(n).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl num_traits::ToPrimitive for F32 {
|
||||
fn to_i64(&self) -> Option<i64> {
|
||||
self.0.to_i64()
|
||||
}
|
||||
|
||||
fn to_u64(&self) -> Option<u64> {
|
||||
self.0.to_u64()
|
||||
}
|
||||
|
||||
fn to_isize(&self) -> Option<isize> {
|
||||
self.0.to_isize()
|
||||
}
|
||||
|
||||
fn to_i8(&self) -> Option<i8> {
|
||||
self.0.to_i8()
|
||||
}
|
||||
|
||||
fn to_i16(&self) -> Option<i16> {
|
||||
self.0.to_i16()
|
||||
}
|
||||
|
||||
fn to_i32(&self) -> Option<i32> {
|
||||
self.0.to_i32()
|
||||
}
|
||||
|
||||
fn to_i128(&self) -> Option<i128> {
|
||||
self.0.to_i128()
|
||||
}
|
||||
|
||||
fn to_usize(&self) -> Option<usize> {
|
||||
self.0.to_usize()
|
||||
}
|
||||
|
||||
fn to_u8(&self) -> Option<u8> {
|
||||
self.0.to_u8()
|
||||
}
|
||||
|
||||
fn to_u16(&self) -> Option<u16> {
|
||||
self.0.to_u16()
|
||||
}
|
||||
|
||||
fn to_u32(&self) -> Option<u32> {
|
||||
self.0.to_u32()
|
||||
}
|
||||
|
||||
fn to_u128(&self) -> Option<u128> {
|
||||
self.0.to_u128()
|
||||
}
|
||||
|
||||
fn to_f32(&self) -> Option<f32> {
|
||||
self.0.to_f32()
|
||||
}
|
||||
|
||||
fn to_f64(&self) -> Option<f64> {
|
||||
self.0.to_f64()
|
||||
}
|
||||
}
|
||||
|
||||
impl num_traits::NumCast for F32 {
|
||||
fn from<T: num_traits::ToPrimitive>(n: T) -> Option<Self> {
|
||||
num_traits::NumCast::from(n).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl num_traits::Num for F32 {
|
||||
type FromStrRadixErr = <f32 as num_traits::Num>::FromStrRadixErr;
|
||||
|
||||
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
|
||||
f32::from_str_radix(str, radix).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl num_traits::Float for F32 {
|
||||
fn nan() -> Self {
|
||||
Self(f32::nan())
|
||||
}
|
||||
|
||||
fn infinity() -> Self {
|
||||
Self(f32::infinity())
|
||||
}
|
||||
|
||||
fn neg_infinity() -> Self {
|
||||
Self(f32::neg_infinity())
|
||||
}
|
||||
|
||||
fn neg_zero() -> Self {
|
||||
Self(f32::neg_zero())
|
||||
}
|
||||
|
||||
fn min_value() -> Self {
|
||||
Self(f32::min_value())
|
||||
}
|
||||
|
||||
fn min_positive_value() -> Self {
|
||||
Self(f32::min_positive_value())
|
||||
}
|
||||
|
||||
fn max_value() -> Self {
|
||||
Self(f32::max_value())
|
||||
}
|
||||
|
||||
fn is_nan(self) -> bool {
|
||||
self.0.is_nan()
|
||||
}
|
||||
|
||||
fn is_infinite(self) -> bool {
|
||||
self.0.is_infinite()
|
||||
}
|
||||
|
||||
fn is_finite(self) -> bool {
|
||||
self.0.is_finite()
|
||||
}
|
||||
|
||||
fn is_normal(self) -> bool {
|
||||
self.0.is_normal()
|
||||
}
|
||||
|
||||
fn classify(self) -> std::num::FpCategory {
|
||||
self.0.classify()
|
||||
}
|
||||
|
||||
fn floor(self) -> Self {
|
||||
Self(self.0.floor())
|
||||
}
|
||||
|
||||
fn ceil(self) -> Self {
|
||||
Self(self.0.ceil())
|
||||
}
|
||||
|
||||
fn round(self) -> Self {
|
||||
Self(self.0.round())
|
||||
}
|
||||
|
||||
fn trunc(self) -> Self {
|
||||
Self(self.0.trunc())
|
||||
}
|
||||
|
||||
fn fract(self) -> Self {
|
||||
Self(self.0.fract())
|
||||
}
|
||||
|
||||
fn abs(self) -> Self {
|
||||
Self(self.0.abs())
|
||||
}
|
||||
|
||||
fn signum(self) -> Self {
|
||||
Self(self.0.signum())
|
||||
}
|
||||
|
||||
fn is_sign_positive(self) -> bool {
|
||||
self.0.is_sign_positive()
|
||||
}
|
||||
|
||||
fn is_sign_negative(self) -> bool {
|
||||
self.0.is_sign_negative()
|
||||
}
|
||||
|
||||
fn mul_add(self, a: Self, b: Self) -> Self {
|
||||
Self(self.0.mul_add(a.0, b.0))
|
||||
}
|
||||
|
||||
fn recip(self) -> Self {
|
||||
Self(self.0.recip())
|
||||
}
|
||||
|
||||
fn powi(self, n: i32) -> Self {
|
||||
Self(self.0.powi(n))
|
||||
}
|
||||
|
||||
fn powf(self, n: Self) -> Self {
|
||||
Self(self.0.powf(n.0))
|
||||
}
|
||||
|
||||
fn sqrt(self) -> Self {
|
||||
Self(self.0.sqrt())
|
||||
}
|
||||
|
||||
fn exp(self) -> Self {
|
||||
Self(self.0.exp())
|
||||
}
|
||||
|
||||
fn exp2(self) -> Self {
|
||||
Self(self.0.exp2())
|
||||
}
|
||||
|
||||
fn ln(self) -> Self {
|
||||
Self(self.0.ln())
|
||||
}
|
||||
|
||||
fn log(self, base: Self) -> Self {
|
||||
Self(self.0.log(base.0))
|
||||
}
|
||||
|
||||
fn log2(self) -> Self {
|
||||
Self(self.0.log2())
|
||||
}
|
||||
|
||||
fn log10(self) -> Self {
|
||||
Self(self.0.log10())
|
||||
}
|
||||
|
||||
fn max(self, other: Self) -> Self {
|
||||
Self(self.0.max(other.0))
|
||||
}
|
||||
|
||||
fn min(self, other: Self) -> Self {
|
||||
Self(self.0.min(other.0))
|
||||
}
|
||||
|
||||
fn abs_sub(self, _: Self) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn cbrt(self) -> Self {
|
||||
Self(self.0.cbrt())
|
||||
}
|
||||
|
||||
fn hypot(self, other: Self) -> Self {
|
||||
Self(self.0.hypot(other.0))
|
||||
}
|
||||
|
||||
fn sin(self) -> Self {
|
||||
Self(self.0.sin())
|
||||
}
|
||||
|
||||
fn cos(self) -> Self {
|
||||
Self(self.0.cos())
|
||||
}
|
||||
|
||||
fn tan(self) -> Self {
|
||||
Self(self.0.tan())
|
||||
}
|
||||
|
||||
fn asin(self) -> Self {
|
||||
Self(self.0.asin())
|
||||
}
|
||||
|
||||
fn acos(self) -> Self {
|
||||
Self(self.0.acos())
|
||||
}
|
||||
|
||||
fn atan(self) -> Self {
|
||||
Self(self.0.atan())
|
||||
}
|
||||
|
||||
fn atan2(self, other: Self) -> Self {
|
||||
Self(self.0.atan2(other.0))
|
||||
}
|
||||
|
||||
fn sin_cos(self) -> (Self, Self) {
|
||||
let (_x, _y) = self.0.sin_cos();
|
||||
(Self(_x), Self(_y))
|
||||
}
|
||||
|
||||
fn exp_m1(self) -> Self {
|
||||
Self(self.0.exp_m1())
|
||||
}
|
||||
|
||||
fn ln_1p(self) -> Self {
|
||||
Self(self.0.ln_1p())
|
||||
}
|
||||
|
||||
fn sinh(self) -> Self {
|
||||
Self(self.0.sinh())
|
||||
}
|
||||
|
||||
fn cosh(self) -> Self {
|
||||
Self(self.0.cosh())
|
||||
}
|
||||
|
||||
fn tanh(self) -> Self {
|
||||
Self(self.0.tanh())
|
||||
}
|
||||
|
||||
fn asinh(self) -> Self {
|
||||
Self(self.0.asinh())
|
||||
}
|
||||
|
||||
fn acosh(self) -> Self {
|
||||
Self(self.0.acosh())
|
||||
}
|
||||
|
||||
fn atanh(self) -> Self {
|
||||
Self(self.0.atanh())
|
||||
}
|
||||
|
||||
fn integer_decode(self) -> (u64, i16, i8) {
|
||||
self.0.integer_decode()
|
||||
}
|
||||
|
||||
fn epsilon() -> Self {
|
||||
Self(f32::EPSILON)
|
||||
}
|
||||
|
||||
fn is_subnormal(self) -> bool {
|
||||
self.0.classify() == std::num::FpCategory::Subnormal
|
||||
}
|
||||
|
||||
fn to_degrees(self) -> Self {
|
||||
Self(self.0.to_degrees())
|
||||
}
|
||||
|
||||
fn to_radians(self) -> Self {
|
||||
Self(self.0.to_radians())
|
||||
}
|
||||
|
||||
fn copysign(self, sign: Self) -> Self {
|
||||
Self(self.0.copysign(sign.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<F32> for F32 {
|
||||
type Output = F32;
|
||||
|
||||
#[inline(always)]
|
||||
fn add(self, rhs: F32) -> F32 {
|
||||
unsafe { std::intrinsics::fadd_fast(self.0, rhs.0).into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<F32> for F32 {
|
||||
#[inline(always)]
|
||||
fn add_assign(&mut self, rhs: F32) {
|
||||
unsafe { self.0 = std::intrinsics::fadd_fast(self.0, rhs.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<F32> for F32 {
|
||||
type Output = F32;
|
||||
|
||||
#[inline(always)]
|
||||
fn sub(self, rhs: F32) -> F32 {
|
||||
unsafe { std::intrinsics::fsub_fast(self.0, rhs.0).into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign<F32> for F32 {
|
||||
#[inline(always)]
|
||||
fn sub_assign(&mut self, rhs: F32) {
|
||||
unsafe { self.0 = std::intrinsics::fsub_fast(self.0, rhs.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<F32> for F32 {
|
||||
type Output = F32;
|
||||
|
||||
#[inline(always)]
|
||||
fn mul(self, rhs: F32) -> F32 {
|
||||
unsafe { std::intrinsics::fmul_fast(self.0, rhs.0).into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl MulAssign<F32> for F32 {
|
||||
#[inline(always)]
|
||||
fn mul_assign(&mut self, rhs: F32) {
|
||||
unsafe { self.0 = std::intrinsics::fmul_fast(self.0, rhs.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<F32> for F32 {
|
||||
type Output = F32;
|
||||
|
||||
#[inline(always)]
|
||||
fn div(self, rhs: F32) -> F32 {
|
||||
unsafe { std::intrinsics::fdiv_fast(self.0, rhs.0).into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl DivAssign<F32> for F32 {
|
||||
#[inline(always)]
|
||||
fn div_assign(&mut self, rhs: F32) {
|
||||
unsafe { self.0 = std::intrinsics::fdiv_fast(self.0, rhs.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Rem<F32> for F32 {
|
||||
type Output = F32;
|
||||
|
||||
#[inline(always)]
|
||||
fn rem(self, rhs: F32) -> F32 {
|
||||
unsafe { std::intrinsics::frem_fast(self.0, rhs.0).into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl RemAssign<F32> for F32 {
|
||||
#[inline(always)]
|
||||
fn rem_assign(&mut self, rhs: F32) {
|
||||
unsafe { self.0 = std::intrinsics::frem_fast(self.0, rhs.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Neg for F32 {
|
||||
type Output = Self;
|
||||
|
||||
fn neg(self) -> Self::Output {
|
||||
Self(self.0.neg())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for F32 {
|
||||
type Err = ParseFloatError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
f32::from_str(s).map(|x| x.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl FloatCast for F32 {
|
||||
fn from_f32(x: f32) -> Self {
|
||||
Self(x)
|
||||
}
|
||||
|
||||
fn to_f32(self) -> f32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f32> for F32 {
|
||||
fn from(value: f32) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<F32> for f32 {
|
||||
fn from(F32(float): F32) -> Self {
|
||||
float
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<f32> for F32 {
|
||||
type Output = F32;
|
||||
|
||||
#[inline(always)]
|
||||
fn add(self, rhs: f32) -> F32 {
|
||||
unsafe { std::intrinsics::fadd_fast(self.0, rhs).into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<f32> for F32 {
|
||||
fn add_assign(&mut self, rhs: f32) {
|
||||
unsafe { self.0 = std::intrinsics::fadd_fast(self.0, rhs) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<f32> for F32 {
|
||||
type Output = F32;
|
||||
|
||||
#[inline(always)]
|
||||
fn sub(self, rhs: f32) -> F32 {
|
||||
unsafe { std::intrinsics::fsub_fast(self.0, rhs).into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign<f32> for F32 {
|
||||
#[inline(always)]
|
||||
fn sub_assign(&mut self, rhs: f32) {
|
||||
unsafe { self.0 = std::intrinsics::fsub_fast(self.0, rhs) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<f32> for F32 {
|
||||
type Output = F32;
|
||||
|
||||
#[inline(always)]
|
||||
fn mul(self, rhs: f32) -> F32 {
|
||||
unsafe { std::intrinsics::fmul_fast(self.0, rhs).into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl MulAssign<f32> for F32 {
|
||||
#[inline(always)]
|
||||
fn mul_assign(&mut self, rhs: f32) {
|
||||
unsafe { self.0 = std::intrinsics::fmul_fast(self.0, rhs) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<f32> for F32 {
|
||||
type Output = F32;
|
||||
|
||||
#[inline(always)]
|
||||
fn div(self, rhs: f32) -> F32 {
|
||||
unsafe { std::intrinsics::fdiv_fast(self.0, rhs).into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl DivAssign<f32> for F32 {
|
||||
#[inline(always)]
|
||||
fn div_assign(&mut self, rhs: f32) {
|
||||
unsafe { self.0 = std::intrinsics::fdiv_fast(self.0, rhs) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Rem<f32> for F32 {
|
||||
type Output = F32;
|
||||
|
||||
#[inline(always)]
|
||||
fn rem(self, rhs: f32) -> F32 {
|
||||
unsafe { std::intrinsics::frem_fast(self.0, rhs).into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl RemAssign<f32> for F32 {
|
||||
#[inline(always)]
|
||||
fn rem_assign(&mut self, rhs: f32) {
|
||||
unsafe { self.0 = std::intrinsics::frem_fast(self.0, rhs) }
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
mod binary;
|
||||
mod f16;
|
||||
mod f32;
|
||||
mod sparse_f32;
|
||||
|
||||
pub use binary::{BinaryVec, BinaryVecRef};
|
||||
pub use f16::F16;
|
||||
pub use f32::F32;
|
||||
pub use sparse_f32::{SparseF32, SparseF32Ref};
|
@ -1,62 +0,0 @@
|
||||
use crate::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SparseF32 {
|
||||
pub dims: u16,
|
||||
pub indexes: Vec<u16>,
|
||||
pub values: Vec<F32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct SparseF32Ref<'a> {
|
||||
pub dims: u16,
|
||||
pub indexes: &'a [u16],
|
||||
pub values: &'a [F32],
|
||||
}
|
||||
|
||||
impl<'a> From<SparseF32Ref<'a>> for SparseF32 {
|
||||
fn from(value: SparseF32Ref<'a>) -> Self {
|
||||
Self {
|
||||
dims: value.dims,
|
||||
indexes: value.indexes.to_vec(),
|
||||
values: value.values.to_vec(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a SparseF32> for SparseF32Ref<'a> {
|
||||
fn from(value: &'a SparseF32) -> Self {
|
||||
Self {
|
||||
dims: value.dims,
|
||||
indexes: &value.indexes,
|
||||
values: &value.values,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Vector for SparseF32 {
|
||||
fn dims(&self) -> u16 {
|
||||
self.dims
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Vector for SparseF32Ref<'a> {
|
||||
fn dims(&self) -> u16 {
|
||||
self.dims
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SparseF32Ref<'a> {
|
||||
pub fn to_dense(&self) -> Vec<F32> {
|
||||
let mut dense = vec![F32::zero(); self.dims as usize];
|
||||
for (&index, &value) in self.indexes.iter().zip(self.values.iter()) {
|
||||
dense[index as usize] = value;
|
||||
}
|
||||
dense
|
||||
}
|
||||
|
||||
pub fn length(&self) -> u16 {
|
||||
self.indexes.len().try_into().unwrap()
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
use crate::prelude::F32;
|
||||
|
||||
pub type Payload = u64;
|
||||
|
||||
pub trait Filter: Clone {
|
||||
fn check(&mut self, payload: Payload) -> bool;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Element {
|
||||
pub distance: F32,
|
||||
pub payload: Payload,
|
||||
}
|
@ -53,7 +53,9 @@ impl Storage for BinaryMmap {
|
||||
ram: RawRam<S>,
|
||||
) -> Self {
|
||||
let n = ram.len();
|
||||
let vectors_iter = (0..n).flat_map(|i| ram.vector(i).as_bytes().iter()).copied();
|
||||
let vectors_iter = (0..n)
|
||||
.flat_map(|i| ram.vector(i).as_bytes().iter())
|
||||
.copied();
|
||||
let payload_iter = (0..n).map(|i| ram.payload(i));
|
||||
let vectors = MmapArray::create(&path.join("vectors"), vectors_iter);
|
||||
let payload = MmapArray::create(&path.join("payload"), payload_iter);
|
||||
|
@ -1,10 +1,10 @@
|
||||
mod binary;
|
||||
mod dense;
|
||||
mod sparse;
|
||||
mod binary;
|
||||
|
||||
pub use binary::BinaryMmap;
|
||||
pub use dense::DenseMmap;
|
||||
pub use sparse::SparseMmap;
|
||||
pub use binary::BinaryMmap;
|
||||
|
||||
use crate::algorithms::raw::RawRam;
|
||||
use crate::index::IndexOptions;
|
||||
|
@ -1,44 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{fmt::Display, num::ParseIntError, str::FromStr};
|
||||
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct Handle {
|
||||
pub newtype: u32,
|
||||
}
|
||||
|
||||
impl Handle {
|
||||
pub fn as_u32(self) -> u32 {
|
||||
self.newtype
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Handle {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.as_u32())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Handle {
|
||||
type Err = ParseIntError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(Handle {
|
||||
newtype: u32::from_str(s)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Pointer {
|
||||
pub newtype: u64,
|
||||
}
|
||||
|
||||
impl Pointer {
|
||||
pub fn from_u48(value: u64) -> Self {
|
||||
assert!(value < (1u64 << 48));
|
||||
Self { newtype: value }
|
||||
}
|
||||
pub fn as_u48(self) -> u64 {
|
||||
self.newtype
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
pub mod metadata;
|
||||
|
||||
use crate::index::IndexOptions;
|
||||
use crate::instance::Instance;
|
||||
use crate::index::{IndexOptions, IndexStat};
|
||||
use crate::instance::{Instance, InstanceView, InstanceViewOperations};
|
||||
use crate::prelude::*;
|
||||
use crate::utils::clean::clean;
|
||||
use crate::utils::dir_ops::sync_dir;
|
||||
@ -13,6 +13,25 @@ use std::collections::{HashMap, HashSet};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub trait WorkerOperations {
|
||||
type InstanceView: InstanceViewOperations;
|
||||
|
||||
fn create(&self, handle: Handle, options: IndexOptions) -> Result<(), CreateError>;
|
||||
fn drop(&self, handle: Handle) -> Result<(), DropError>;
|
||||
fn flush(&self, handle: Handle) -> Result<(), FlushError>;
|
||||
fn insert(
|
||||
&self,
|
||||
handle: Handle,
|
||||
vector: DynamicVector,
|
||||
pointer: Pointer,
|
||||
) -> Result<(), InsertError>;
|
||||
fn delete(&self, handle: Handle, pointer: Pointer) -> Result<(), DeleteError>;
|
||||
fn basic_view(&self, handle: Handle) -> Result<Self::InstanceView, BasicError>;
|
||||
fn vbase_view(&self, handle: Handle) -> Result<Self::InstanceView, VbaseError>;
|
||||
fn list_view(&self, handle: Handle) -> Result<Self::InstanceView, ListError>;
|
||||
fn stat(&self, handle: Handle) -> Result<IndexStat, StatError>;
|
||||
}
|
||||
|
||||
pub struct Worker {
|
||||
path: PathBuf,
|
||||
protect: Mutex<WorkerProtect>,
|
||||
@ -65,11 +84,12 @@ impl Worker {
|
||||
pub fn view(&self) -> Arc<WorkerView> {
|
||||
self.view.load_full()
|
||||
}
|
||||
pub fn instance_create(
|
||||
&self,
|
||||
handle: Handle,
|
||||
options: IndexOptions,
|
||||
) -> Result<(), ServiceError> {
|
||||
}
|
||||
|
||||
impl WorkerOperations for Worker {
|
||||
type InstanceView = InstanceView;
|
||||
|
||||
fn create(&self, handle: Handle, options: IndexOptions) -> Result<(), CreateError> {
|
||||
use std::collections::hash_map::Entry;
|
||||
let mut protect = self.protect.lock();
|
||||
match protect.indexes.entry(handle) {
|
||||
@ -80,15 +100,70 @@ impl Worker {
|
||||
protect.maintain(&self.view);
|
||||
Ok(())
|
||||
}
|
||||
Entry::Occupied(_) => Err(ServiceError::KnownIndex),
|
||||
Entry::Occupied(_) => Err(CreateError::Exist),
|
||||
}
|
||||
}
|
||||
pub fn instance_destroy(&self, handle: Handle) {
|
||||
fn drop(&self, handle: Handle) -> Result<(), DropError> {
|
||||
let mut protect = self.protect.lock();
|
||||
if protect.indexes.remove(&handle).is_some() {
|
||||
protect.maintain(&self.view);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(DropError::NotExist)
|
||||
}
|
||||
}
|
||||
fn flush(&self, handle: Handle) -> Result<(), FlushError> {
|
||||
let view = self.view();
|
||||
let instance = view.get(handle).ok_or(FlushError::NotExist)?;
|
||||
let view = instance.view().ok_or(FlushError::Upgrade)?;
|
||||
view.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
fn insert(
|
||||
&self,
|
||||
handle: Handle,
|
||||
vector: DynamicVector,
|
||||
pointer: Pointer,
|
||||
) -> Result<(), InsertError> {
|
||||
let view = self.view();
|
||||
let instance = view.get(handle).ok_or(InsertError::NotExist)?;
|
||||
loop {
|
||||
let view = instance.view().ok_or(InsertError::Upgrade)?;
|
||||
match view.insert(vector.clone(), pointer)? {
|
||||
Ok(()) => break,
|
||||
Err(_) => instance.refresh(),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn delete(&self, handle: Handle, pointer: Pointer) -> Result<(), DeleteError> {
|
||||
let view = self.view();
|
||||
let instance = view.get(handle).ok_or(DeleteError::NotExist)?;
|
||||
let view = instance.view().ok_or(DeleteError::Upgrade)?;
|
||||
view.delete(pointer)?;
|
||||
Ok(())
|
||||
}
|
||||
fn basic_view(&self, handle: Handle) -> Result<InstanceView, BasicError> {
|
||||
let view = self.view();
|
||||
let instance = view.get(handle).ok_or(BasicError::NotExist)?;
|
||||
instance.view().ok_or(BasicError::Upgrade)
|
||||
}
|
||||
fn vbase_view(&self, handle: Handle) -> Result<InstanceView, VbaseError> {
|
||||
let view = self.view();
|
||||
let instance = view.get(handle).ok_or(VbaseError::NotExist)?;
|
||||
instance.view().ok_or(VbaseError::Upgrade)
|
||||
}
|
||||
fn list_view(&self, handle: Handle) -> Result<InstanceView, ListError> {
|
||||
let view = self.view();
|
||||
let instance = view.get(handle).ok_or(ListError::NotExist)?;
|
||||
instance.view().ok_or(ListError::Upgrade)
|
||||
}
|
||||
fn stat(&self, handle: Handle) -> Result<IndexStat, StatError> {
|
||||
let view = self.view();
|
||||
let instance = view.get(handle).ok_or(StatError::NotExist)?;
|
||||
let stat = instance.stat().ok_or(StatError::Upgrade)?;
|
||||
Ok(stat)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WorkerView {
|
||||
|
Reference in New Issue
Block a user