Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .cargo/config

This file was deleted.

69 changes: 69 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: ci
on:
push:
branches:
- main
pull_request:

jobs:
lints:
name: lints
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4

- name: Install beta toolchain
uses: dtolnay/rust-toolchain@beta
with:
components: rustfmt, clippy

- name: Set up cache
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true

- name: Run cargo fmt
run: cargo fmt --all -- --check

- name: Run cargo clippy
run: cargo clippy --all-targets --tests -- -D warnings

no_std:
name: no_std
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4

- name: Install beta toolchain for ARM
uses: dtolnay/rust-toolchain@beta
with:
targets: armv7a-none-eabi

- name: Set up cache
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true

- name: Build binary for armv7a-none-eabi
run: cargo rustc --target=armv7a-none-eabi --manifest-path=ensure_no_std/Cargo.toml

tests:
name: tests
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4

- name: Install beta toolchain
uses: dtolnay/rust-toolchain@beta

- name: Set up cache
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true

- name: Run cargo test
#run: cargo test --all-features --no-fail-fast --locked --workspace -- --nocapture
run: cargo test --all-features --no-fail-fast --workspace -- --nocapture
55 changes: 0 additions & 55 deletions .github/workflows/lints.yml

This file was deleted.

26 changes: 0 additions & 26 deletions .github/workflows/no-std.yml

This file was deleted.

28 changes: 0 additions & 28 deletions .github/workflows/tests.yml

This file was deleted.

20 changes: 13 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
[package]
name = "space"
version = "0.18.1-alpha.0"
authors = ["Geordon Worley <vadixidav@gmail.com>", "Yuhan Liin <yuhanliin+github@protonmail.com>"]
edition = "2018"
version = "0.19.0"
authors = [
"Geordon Worley <vadixidav@gmail.com>",
"Yuhan Liin <yuhanliin+github@protonmail.com>",
]
edition = "2024"
description = "A library providing abstractions for spatial datastructures and search"
documentation = "https://docs.rs/space/"
repository = "https://github.com/rust-cv/space"
Expand All @@ -17,13 +20,16 @@ default = ["alloc"]
alloc = []

[dependencies]
num-traits = { version = "0.2.14", default-features = false }
num-traits = { version = "0.2.19", default-features = false }
doc-comment = "0.3.3"
pgat = "0.3.0"

[dev-dependencies]
criterion = "0.3.4"
rand_core = "0.6.2"
rand_pcg = "0.3.0"
criterion = "0.7.0"
rand_core = "0.9.3"
rand_pcg = "0.9.0"
ndarray = "0.16.1"
decorum = "0.4.0"

[[bench]]
name = "knn"
Expand Down
50 changes: 30 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,56 +30,66 @@ See the [bitarray](https://crates.io/crates/bitarray) crate for an implementatio
of `MetricPoint` using hamming distance (with optional, though unstable, 512-bit
SIMD support, and always-on 64-bit popcnt instruction support).

## Usage
## Usage Examples

```rust
use space::Metric;

struct Hamming;

impl Metric<u8> for Hamming {
type Unit = u8;

fn distance(&self, &a: &u8, &b: &u8) -> Self::Unit {
(a ^ b).count_ones() as u8
}
}
```
This example shows how to use the LinearSearch and LinearContainer that come built-in by default. You would use third party containers similarly and can abstract over them using the traits like SpatialContainer and Knn.

```rust
use space::{Knn, KnnFromBatch, LinearKnn, Metric};
use pgat::ReferenceProxy;
use space::{Knn, LinearContainer, LinearSearch, Metric, SpatialContainer};

#[derive(Default)]
#[derive(Copy, Clone, Default)]
struct Hamming;

impl Metric<u8> for Hamming {
impl Metric<ReferenceProxy<u8>> for Hamming {
type Unit = u8;

fn distance(&self, &a: &u8, &b: &u8) -> Self::Unit {
(a ^ b).count_ones() as u8
}
}

let data = vec![
// Use type aliases like below to get default proxy types (ReferenceView) on the container.
type Container = LinearContainer<Hamming, u8, u8>;
type Search<'a> = LinearSearch<'a, Hamming, u8, u8>;

let data = [
(0b1010_1010, 12),
(0b1111_1111, 13),
(0b0000_0000, 14),
(0b1111_0000, 16),
(0b0000_1111, 10),
];

let search: LinearKnn<Hamming, _> = KnnFromBatch::from_batch(data.iter());
let search = Search::new(Hamming, &data);

assert_eq!(
&search.knn(&0b0101_0000, 3),
search.knn(&0b0101_0000, 3).as_slice(),
&[
(2, &data[2].0, &data[2].1),
(2, &data[3].0, &data[3].1),
(6, &data[0].0, &data[0].1)
]
);

let mut search = Container::from_metric_and_iterator(Hamming, data);

assert_eq!(
search.knn(&0b0101_0000, 3).as_slice(),
&[
(2, &data[2].0, &data[2].1),
(2, &data[3].0, &data[3].1),
(6, &data[0].0, &data[0].1)
]
);

search.insert(0b0101_0001, 8);

assert_eq!(search.nn(&0b0101_0000), Some((1, &0b0101_0001, &8)));
```

For an example on how to create a container, a great reference may be found in tests/ndarray.rs in the repository. For brevity it is omitted here, but it shows how to create a specialized structure that uses an Array2 as the storage mechanism for Array1 points.

## Benchmarks

To run the benchmarks, use the following command:
Expand Down
8 changes: 4 additions & 4 deletions benches/knn.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
use criterion::{criterion_group, criterion_main, Criterion};
use criterion::{Criterion, criterion_group, criterion_main};
use rand_core::{RngCore, SeedableRng};
use rand_pcg::Pcg64;
use space::{Bits512, Knn, MetricPoint};

fn criterion_benchmark(c: &mut Criterion) {
let mut rng = Pcg64::from_seed([1; 32]);
let mut gen = || {
let mut generator = || {
let mut feature = Bits512([0; 64]);
rng.fill_bytes(&mut *feature);
feature
};
let search = gen();
let data = (0..16384).map(|_| gen()).collect::<Vec<_>>();
let search = generator();
let data = (0..16384).map(|_| generator()).collect::<Vec<_>>();
c.bench_function("space: 4-nn in 16384", |b| {
b.iter(|| space::LinearKnn(data.iter()).knn(&search, 4).len())
})
Expand Down
Loading