From 710c53b4b4f0e3db553e239f771dc87d542aac41 Mon Sep 17 00:00:00 2001 From: emeric Date: Fri, 5 Jun 2026 13:53:30 +0200 Subject: [PATCH] Try not to suggest same audio tracks, added some unit tests --- .../NearDuplicateEmbeddingConstraint.hpp | 2 +- .../recommendation/test/CMakeLists.txt | 1 + .../recommendation/test/ConstraintsTest.cpp | 74 +++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/libs/services/recommendation/impl/audio-similarity/NearDuplicateEmbeddingConstraint.hpp b/src/libs/services/recommendation/impl/audio-similarity/NearDuplicateEmbeddingConstraint.hpp index 4f1e6a56..8cf49725 100644 --- a/src/libs/services/recommendation/impl/audio-similarity/NearDuplicateEmbeddingConstraint.hpp +++ b/src/libs/services/recommendation/impl/audio-similarity/NearDuplicateEmbeddingConstraint.hpp @@ -25,8 +25,8 @@ #include "math/NormalizedCosineDistance.hpp" #include "math/Vector.hpp" -#include "track-selection-constraints/ITrackCandidateHardConstraint.hpp" #include "Types.hpp" +#include "track-selection-constraints/ITrackCandidateHardConstraint.hpp" namespace lms::recommendation { diff --git a/src/libs/services/recommendation/test/CMakeLists.txt b/src/libs/services/recommendation/test/CMakeLists.txt index 1c748704..34812aed 100644 --- a/src/libs/services/recommendation/test/CMakeLists.txt +++ b/src/libs/services/recommendation/test/CMakeLists.txt @@ -4,6 +4,7 @@ add_executable(test-recommendation target_link_libraries(test-recommendation PRIVATE lmsrecommendation + lmsmath GTest::GTest GTest::gtest_main ) diff --git a/src/libs/services/recommendation/test/ConstraintsTest.cpp b/src/libs/services/recommendation/test/ConstraintsTest.cpp index ebc4e25e..5fe8dd29 100644 --- a/src/libs/services/recommendation/test/ConstraintsTest.cpp +++ b/src/libs/services/recommendation/test/ConstraintsTest.cpp @@ -22,7 +22,9 @@ #include "database/objects/ArtistId.hpp" #include "database/objects/ReleaseId.hpp" #include "database/objects/TrackId.hpp" +#include "math/Vector.hpp" +#include "audio-similarity/NearDuplicateEmbeddingConstraint.hpp" #include "track-selection-constraints/DuplicateTrackConstraint.hpp" #include "track-selection-constraints/SameArtistConstraint.hpp" #include "track-selection-constraints/SameReleaseConstraint.hpp" @@ -238,3 +240,75 @@ TEST(TrackCandidateEvaluator, hardConstraintPassesEvenWithSoftConstraints) EXPECT_FALSE(evaluator.rejects(ctx)); EXPECT_FLOAT_EQ(evaluator.score(ctx), 1.F); } + +namespace +{ + using TestVec = math::Vector<2, float>; + const TestVec v_x{ 1.F, 0.F }; + const TestVec v_y{ 0.F, 1.F }; + + using TestConstraint = NearDuplicateEmbeddingConstraint<2>; + using TestVectorMap = TestConstraint::TrackVectorMap; +} // namespace + +TEST(NearDuplicateEmbeddingConstraint, acceptsWhenCandidateNotInMap) +{ + const TestVectorMap trackVectors{ { T1, &v_x } }; + const TestConstraint constraint{ trackVectors, 0.1F }; + const std::vector selected{ T1 }; + const TrackCandidateContext ctx{ .candidateTrackId = T2, .selectedTracks = selected }; + EXPECT_FALSE(constraint.rejects(ctx)); +} + +TEST(NearDuplicateEmbeddingConstraint, acceptsWhenSelectionEmpty) +{ + const TestVectorMap trackVectors{ { T1, &v_x } }; + const TestConstraint constraint{ trackVectors, 0.1F }; + const TrackCandidateContext ctx{ .candidateTrackId = T1, .selectedTracks = {} }; + EXPECT_FALSE(constraint.rejects(ctx)); +} + +TEST(NearDuplicateEmbeddingConstraint, acceptsWhenSelectedTrackNotInMap) +{ + const TestVectorMap trackVectors{ { T1, &v_x } }; + const TestConstraint constraint{ trackVectors, 0.1F }; + const std::vector selected{ T2 }; + const TrackCandidateContext ctx{ .candidateTrackId = T1, .selectedTracks = selected }; + EXPECT_FALSE(constraint.rejects(ctx)); +} + +TEST(NearDuplicateEmbeddingConstraint, rejectsWhenDistanceBelowThreshold) +{ + const TestVectorMap trackVectors{ { T1, &v_x }, { T2, &v_x } }; + const TestConstraint constraint{ trackVectors, 0.1F }; + const std::vector selected{ T2 }; + const TrackCandidateContext ctx{ .candidateTrackId = T1, .selectedTracks = selected }; + EXPECT_TRUE(constraint.rejects(ctx)); +} + +TEST(NearDuplicateEmbeddingConstraint, acceptsWhenDistanceAboveThreshold) +{ + const TestVectorMap trackVectors{ { T1, &v_x }, { T2, &v_y } }; + const TestConstraint constraint{ trackVectors, 0.1F }; + const std::vector selected{ T2 }; + const TrackCandidateContext ctx{ .candidateTrackId = T1, .selectedTracks = selected }; + EXPECT_FALSE(constraint.rejects(ctx)); +} + +TEST(NearDuplicateEmbeddingConstraint, rejectsWhenOneOfManySelectedIsNearDuplicate) +{ + const TestVectorMap trackVectors{ { T1, &v_x }, { T3, &v_y }, { T4, &v_x } }; + const TestConstraint constraint{ trackVectors, 0.1F }; + const std::vector selected{ T3, T4 }; + const TrackCandidateContext ctx{ .candidateTrackId = T1, .selectedTracks = selected }; + EXPECT_TRUE(constraint.rejects(ctx)); +} + +TEST(NearDuplicateEmbeddingConstraint, acceptsWhenAllSelectedAreFarEnough) +{ + const TestVectorMap trackVectors{ { T1, &v_x }, { T2, &v_y }, { T3, &v_y } }; + const TestConstraint constraint{ trackVectors, 0.1F }; + const std::vector selected{ T2, T3 }; + const TrackCandidateContext ctx{ .candidateTrackId = T1, .selectedTracks = selected }; + EXPECT_FALSE(constraint.rejects(ctx)); +}