Skip to content

Commit

Permalink
closes #11
Browse files Browse the repository at this point in the history
  • Loading branch information
azizkayumov committed Aug 29, 2024
1 parent c4cfae9 commit 07bbad4
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 23 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
[![crates.io](https://img.shields.io/crates/v/rindex)](https://crates.io/crates/rindex)

# rindex
Rindex: dynamic spatial index for efficiently maintaining *k* nearest neighbors graph.
Rindex: dynamic spatial index for efficiently maintaining *k* nearest neighbors graph of multi-dimensional clustered datasets.

## Features
Rindex supports spatial indexing operations while also maintaining k nearest neighbor information for dynamic data:
Expand Down
103 changes: 81 additions & 22 deletions lib/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,93 @@
[![crates.io](https://img.shields.io/crates/v/rindex)](https://crates.io/crates/rindex)

# rindex
Rindex: dynamic spatial index for efficiently maintaining *k* nearest neighbors graph.
Rindex: dynamic spatial index for efficiently maintaining *k* nearest neighbors graph of multi-dimensional clustered datasets.

## Usage

The following example shows how to maintain *k* nearest neighbors using Rindex:
```rust
use rindex::Rindex;

fn main() {
let fanout = 10;
let k = 3; // maintain 3 nearest neighbors for each point
let mut rindex = Rindex::new(fanout, k).expect("Failed to create Rindex");

// Insert some points
let a = rindex.insert([1.0, 1.0]);
let b = rindex.insert([2.0, 2.0]);
let c = rindex.insert([3.0, 3.0]);
let d = rindex.insert([20.0, 20.0]);

// Check k nearest neighbors of point a
let (neighbors, distances) = rindex.neighbors_of(a);
assert_eq!(neighbors, vec![a, b, c]);

// Remove point b
rindex.delete(b);

// Check k nearest neighbors of point a again
let (neighbors, distances) = rindex.neighbors_of(a);
assert_eq!(neighbors, vec![a, c, d]); // b is not in the result
}
```
let fanout = 10;
let k = 3;
let mut rindex = Rindex::new(fanout, k).expect("Failed to create Rindex");
// Insert some points
let a = rindex.insert([1.0, 1.0]);
let b = rindex.insert([2.0, 2.0]);
let c = rindex.insert([3.0, 3.0]);
let d = rindex.insert([20.0, 20.0]);
// Check k nearest neighbors of point a
let (neighbors, distances) = rindex.neighbors_of(a);
assert_eq!(neighbors, vec![a, b, c]);
// Remove point b
rindex.delete(b);
// Check k nearest neighbors of point a again
let (neighbors, distances) = rindex.neighbors_of(a);
assert_eq!(neighbors, vec![a, c, d]); // b is not in the result
Both insertion and deletion operations dynamically updates the *k* nearest neighbors for all remaining points efficiently (see the references below).

<details>
<summary>Update operations</summary>

The insertion algorithm returns an id of the newly-inserted point, store it for later usage, e.g. to delete the point:

```rust
use rindex::Rindex;

fn main() {
let mut rindex = Rindex::default();
let a = rindex.insert([1.0, 1.0]);
assert_eq!(rindex.num_points(), 1);
rindex.delete(a);
assert_eq!(rindex.num_points(), 0);
}
```
Both insertion and deletion operations dynamically updates the *k* nearest neighbors for all remaining points (efficiently).
</details>

<details>
<summary>Nearest neighbor queries</summary>

The traditional query operations are supported in addition to the reverse nearest neighbors query:

```rust
use rindex::Rindex;

fn main() {
let fanout = 10;
let k = 3;
let mut rindex = Rindex::new(fanout, k).expect("Failed to create Rindex");
let a = rindex.insert([1.0, 1.0]);
let b = rindex.insert([2.0, 2.0]);
let c = rindex.insert([3.0, 3.0]);
let d = rindex.insert([20.0, 20.0]);

let query_point = [0.0, 0.0];

// Range queries: find all points within query_radius distance
let query_radius = 10.0;
let (neighbors, distances) = rindex.query(&query_point, query_radius);
assert_eq!(neighbors, vec![a, b, c]);

// Nearest neighbors: find 3 nearest neighbors of the query point
let (neighbors, distances) = rindex.query_neighbors(&query_point, 3);
assert_eq!(neighbors, vec![a, b, c]);

// Reverse nearest neighbors: find such points that sees the query point
// as one of their 3 nearest neighbors
let (neighbors, distances) = rindex.query_reverse(&[0.0, 0.0]);
assert_eq!(neighbors, vec![a]);
}
```

</details>

## References
Rindex combines the algorithms presented in the following papers:
Expand Down
64 changes: 64 additions & 0 deletions lib/tests/usage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use rindex::Rindex;

#[allow(unused_variables)]
#[test]
fn test_main_usage() {
let fanout = 10;
let k = 3; // maintain 3 nearest neighbors for each point
let mut rindex = Rindex::new(fanout, k).expect("Failed to create Rindex");

// Insert some points
let a = rindex.insert([1.0, 1.0]);
let b = rindex.insert([2.0, 2.0]);
let c = rindex.insert([3.0, 3.0]);
let d = rindex.insert([20.0, 20.0]);

// Check k nearest neighbors of point a
let (neighbors, distances) = rindex.neighbors_of(a);
assert_eq!(neighbors, vec![a, b, c]);

// Remove point b
rindex.delete(b);

// Check k nearest neighbors of point a again
let (neighbors, distances) = rindex.neighbors_of(a);
assert_eq!(neighbors, vec![a, c, d]); // b is not in the result
}

#[allow(unused_variables)]
#[test]
fn test_update_operations() {
let mut rindex = Rindex::default();
let a = rindex.insert([1.0, 1.0]);
assert_eq!(rindex.num_points(), 1);
rindex.delete(a);
assert_eq!(rindex.num_points(), 0);
}

#[allow(unused_variables)]
#[test]
fn test_query_operations() {
let fanout = 10;
let k = 3;
let mut rindex = Rindex::new(fanout, k).expect("Failed to create Rindex");
let a = rindex.insert([1.0, 1.0]);
let b = rindex.insert([2.0, 2.0]);
let c = rindex.insert([3.0, 3.0]);
let d = rindex.insert([20.0, 20.0]);

let query_point = [0.0, 0.0];

// Range queries: find all points within query_radius distance
let query_radius = 10.0;
let (neighbors, distances) = rindex.query(&query_point, query_radius);
assert_eq!(neighbors, vec![a, b, c]);

// Nearest neighbors: find 3 nearest neighbors of the query point
let (neighbors, distances) = rindex.query_neighbors(&query_point, 3);
assert_eq!(neighbors, vec![a, b, c]);

// Reverse nearest neighbors: find such points that sees the query point
// as one of their 3 nearest neighbors
let (neighbors, distances) = rindex.query_reverse(&[0.0, 0.0]);
assert_eq!(neighbors, vec![a]);
}

0 comments on commit 07bbad4

Please sign in to comment.