Skip to content

Commit 477f117

Browse files
committed
fix(graph): include target vertex in ReadOnlyGraph::hasPath result
Align ReadOnlyGraph::hasPath behavior with SizeBoundedGraph by adding the target vertex to the returned path. Add dedicated unit tests to verify exact path structure and connectivity in both graph implementations.
1 parent b8dba51 commit 477f117

3 files changed

Lines changed: 44 additions & 1 deletion

File tree

‎cpp/deglib/include/deglib/graph/readonly_graph.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ class ReadOnlyGraph : public deglib::graph::InternalGraph {
288288
// found our target vertex, create a path back to the entry vertex
289289
if(neighbor_index == to_vertex) {
290290
auto path = std::vector<deglib::graph::ObjectDistance>();
291+
path.emplace_back(to_vertex, 0.f);
291292
path.emplace_back(next_vertex.getIdentifier(), next_vertex.getDistance());
292293

293294
auto last_vertex = trackback.find(next_vertex.getIdentifier());

‎cpp/test/src/unit/graph/test_readonly_graph.cpp‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,10 @@ TEST(ReadOnlyGraph, HasPath) {
295295
deglib::graph::ReadOnlyGraph graph(mutable_graph.size(), 4, space, mutable_graph);
296296

297297
auto path = graph.hasPath({0}, 1, 0.0f, 5);
298-
EXPECT_GT(path.size(), 0u);
298+
ASSERT_EQ(path.size(), 2u);
299+
EXPECT_EQ(path[0].getIdentifier(), 1u);
300+
EXPECT_EQ(path[0].getDistance(), 0.0f);
301+
EXPECT_EQ(path[1].getIdentifier(), 0u);
299302
}
300303

301304
TEST(ReadOnlyGraph, HasPathNoConnection) {

‎cpp/test/src/unit/graph/test_sizebounded_graph.cpp‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ static std::vector<float> make_vec_4d(float x, float y, float z, float w) {
2525
return {x, y, z, w};
2626
}
2727

28+
static std::vector<float> make_float_vec(size_t dim, float default_val = 0.0f) {
29+
return std::vector<float>(dim, default_val);
30+
}
31+
2832
static std::unique_ptr<std::byte[]> make_float_bytes(const std::vector<float>& v) {
2933
auto bytes = std::make_unique<std::byte[]>(v.size() * sizeof(float));
3034
std::memcpy(bytes.get(), v.data(), v.size() * sizeof(float));
@@ -583,6 +587,41 @@ TEST(SizeBoundedGraph, ExploreWithMaxDistanceCount) {
583587
EXPECT_GT(results.size(), 0u);
584588
EXPECT_LE(results.size(), 5u);
585589
}
590+
591+
TEST(SizeBoundedGraph, HasPathBasic) {
592+
deglib::distances::FloatSpace space(4, deglib::distances::Metric::FP32_L2);
593+
deglib::graph::SizeBoundedGraph graph(5, 4, space);
594+
595+
for (int i = 0; i < 5; ++i) {
596+
auto v = make_float_vec(4);
597+
v[0] = static_cast<float>(i);
598+
graph.addVertex(i, make_float_bytes(v).get());
599+
}
600+
601+
uint32_t sorted_neighbors[] = {0, 1, 2, 3};
602+
float weights[] = {0.0f, 1.0f, 4.0f, 9.0f};
603+
graph.changeEdges(0, sorted_neighbors, weights);
604+
605+
auto path = graph.hasPath({0}, 1, 0.0f, 5);
606+
ASSERT_EQ(path.size(), 2u);
607+
EXPECT_EQ(path[0].getIdentifier(), 1u);
608+
EXPECT_EQ(path[0].getDistance(), 0.0f);
609+
EXPECT_EQ(path[1].getIdentifier(), 0u);
610+
}
611+
612+
TEST(SizeBoundedGraph, HasPathNoConnection) {
613+
deglib::distances::FloatSpace space(4, deglib::distances::Metric::FP32_L2);
614+
deglib::graph::SizeBoundedGraph graph(5, 4, space);
615+
616+
for (int i = 0; i < 5; ++i) {
617+
auto v = make_float_vec(4);
618+
v[0] = static_cast<float>(i);
619+
graph.addVertex(i, make_float_bytes(v).get());
620+
}
621+
622+
auto path = graph.hasPath({0}, 4, 0.0f, 5);
623+
EXPECT_EQ(path.size(), static_cast<size_t>(0));
624+
}
586625
// ---------------------------------------------------------------------------
587626
// 10. Internal vs External ID Verification
588627
// ---------------------------------------------------------------------------

0 commit comments

Comments
 (0)