Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ impl storage::bin::GetAdjacencyList for SimpleNeighborProviderAsync {
/// Key differences between the formats:
/// 1. Disk format requires a valid vector ID as start point, while async index uses a
/// virtual ID (max_points + 1) that exceeds the valid dataset range
/// 2. In-memory index appends the virtual start point at the end of adjacency lists
/// 2. In-memory adjacency lists may contain the virtual start point ID
Comment thread
partychen marked this conversation as resolved.
Outdated
/// 3. Disk format expects additional_points = 0, while async index uses additional_points = 1
///
/// This adaptor handles these differences by:
Expand All @@ -327,15 +327,26 @@ impl storage::bin::GetAdjacencyList for DiskAdaptor<'_> {
let mut list = AdjacencyList::new();
self.provider.get_neighbors_sync(i, &mut list)?;

// Need to change to a `Vec` because remapping the start point can cause duplicates,
// and changing the logic to not have duplicates changes the exact nature of the
// graph and breaks integration tests for the disk index builder.
let mut list: Vec<_> = list.into();
for i in list.iter_mut() {
if *i == self.inmem_start_point {
*i = self.actual_start_point;
let node_id = u32::try_from(i).ok();
Comment thread
partychen marked this conversation as resolved.
Outdated
let mut seen_actual_start_point = false;
list.retain_mut(|neighbor| {
if *neighbor == self.inmem_start_point {
*neighbor = self.actual_start_point;
}
}

if Some(*neighbor) == node_id {
return false;
}

if *neighbor != self.actual_start_point {
return true;
}

let first = !seen_actual_start_point;
seen_actual_start_point = true;
first
});

Ok(list)
}
Expand All @@ -361,7 +372,7 @@ impl storage::bin::GetAdjacencyList for DiskAdaptor<'_> {

#[cfg(test)]
mod tests {
use crate::storage::VirtualStorageProvider;
use crate::storage::{VirtualStorageProvider, bin::GetAdjacencyList};

use super::*;

Expand Down Expand Up @@ -391,6 +402,22 @@ mod tests {
assert_eq!(new_adj_list, result);
}

#[test]
fn disk_adaptor_removes_duplicates_and_self_loops_after_remapping() {
let provider = SimpleNeighborProviderAsync::new(4, 1, 4, 1.0);
provider.set_neighbors_sync(0, &[4, 2, 1]).unwrap();
provider.set_neighbors_sync(1, &[4, 3]).unwrap();

let adaptor = DiskAdaptor {
provider: &provider,
inmem_start_point: 4,
actual_start_point: 1,
};

assert_eq!(adaptor.get_adjacency_list(0).unwrap(), vec![1, 2]);
assert_eq!(adaptor.get_adjacency_list(1).unwrap(), vec![3]);
}

#[tokio::test]
async fn test_save_load() {
let max_degree = 5;
Expand Down
Git LFS file not shown
Loading