1 /*
2 * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "modules/audio_processing/agc2/rnn_vad/symmetric_matrix_buffer.h"
12
13 #include "modules/audio_processing/agc2/rnn_vad/ring_buffer.h"
14 #include "test/gtest.h"
15
16 namespace webrtc {
17 namespace rnn_vad {
18 namespace {
19
20 template <typename T, int S>
CheckSymmetry(const SymmetricMatrixBuffer<T,S> * sym_matrix_buf)21 void CheckSymmetry(const SymmetricMatrixBuffer<T, S>* sym_matrix_buf) {
22 for (int row = 0; row < S - 1; ++row)
23 for (int col = row + 1; col < S; ++col)
24 EXPECT_EQ(sym_matrix_buf->GetValue(row, col),
25 sym_matrix_buf->GetValue(col, row));
26 }
27
28 using PairType = std::pair<int, int>;
29
30 // Checks that the symmetric matrix buffer contains any pair with a value equal
31 // to the given one.
32 template <int S>
CheckPairsWithValueExist(const SymmetricMatrixBuffer<PairType,S> * sym_matrix_buf,const int value)33 bool CheckPairsWithValueExist(
34 const SymmetricMatrixBuffer<PairType, S>* sym_matrix_buf,
35 const int value) {
36 for (int row = 0; row < S - 1; ++row) {
37 for (int col = row + 1; col < S; ++col) {
38 auto p = sym_matrix_buf->GetValue(row, col);
39 if (p.first == value || p.second == value)
40 return true;
41 }
42 }
43 return false;
44 }
45
46 // Test that shows how to combine RingBuffer and SymmetricMatrixBuffer to
47 // efficiently compute pair-wise scores. This test verifies that the evolution
48 // of a SymmetricMatrixBuffer instance follows that of RingBuffer.
TEST(RnnVadTest,SymmetricMatrixBufferUseCase)49 TEST(RnnVadTest, SymmetricMatrixBufferUseCase) {
50 // Instance a ring buffer which will be fed with a series of integer values.
51 constexpr int kRingBufSize = 10;
52 RingBuffer<int, 1, kRingBufSize> ring_buf;
53 // Instance a symmetric matrix buffer for the ring buffer above. It stores
54 // pairs of integers with which this test can easily check that the evolution
55 // of RingBuffer and SymmetricMatrixBuffer match.
56 SymmetricMatrixBuffer<PairType, kRingBufSize> sym_matrix_buf;
57 for (int t = 1; t <= 100; ++t) { // Evolution steps.
58 SCOPED_TRACE(t);
59 const int t_removed = ring_buf.GetArrayView(kRingBufSize - 1)[0];
60 ring_buf.Push({&t, 1});
61 // The head of the ring buffer is `t`.
62 ASSERT_EQ(t, ring_buf.GetArrayView(0)[0]);
63 // Create the comparisons between `t` and the older elements in the ring
64 // buffer.
65 std::array<PairType, kRingBufSize - 1> new_comparions;
66 for (int i = 0; i < kRingBufSize - 1; ++i) {
67 // Start comparing `t` to the second newest element in the ring buffer.
68 const int delay = i + 1;
69 const auto t_prev = ring_buf.GetArrayView(delay)[0];
70 ASSERT_EQ(std::max(0, t - delay), t_prev);
71 // Compare the last element `t` with `t_prev`.
72 new_comparions[i].first = t_prev;
73 new_comparions[i].second = t;
74 }
75 // Push the new comparisons in the symmetric matrix buffer.
76 sym_matrix_buf.Push({new_comparions.data(), new_comparions.size()});
77 // Tests.
78 CheckSymmetry(&sym_matrix_buf);
79 // Check that the pairs resulting from the content in the ring buffer are
80 // in the right position.
81 for (int delay1 = 0; delay1 < kRingBufSize - 1; ++delay1) {
82 for (int delay2 = delay1 + 1; delay2 < kRingBufSize; ++delay2) {
83 const auto t1 = ring_buf.GetArrayView(delay1)[0];
84 const auto t2 = ring_buf.GetArrayView(delay2)[0];
85 ASSERT_LE(t2, t1);
86 const auto p = sym_matrix_buf.GetValue(delay1, delay2);
87 EXPECT_EQ(p.first, t2);
88 EXPECT_EQ(p.second, t1);
89 }
90 }
91 // Check that every older element in the ring buffer still has a
92 // corresponding pair in the symmetric matrix buffer.
93 for (int delay = 1; delay < kRingBufSize; ++delay) {
94 const auto t_prev = ring_buf.GetArrayView(delay)[0];
95 EXPECT_TRUE(CheckPairsWithValueExist(&sym_matrix_buf, t_prev));
96 }
97 // Check that the element removed from the ring buffer has no corresponding
98 // pairs in the symmetric matrix buffer.
99 if (t > kRingBufSize - 1) {
100 EXPECT_FALSE(CheckPairsWithValueExist(&sym_matrix_buf, t_removed));
101 }
102 }
103 }
104
105 } // namespace
106 } // namespace rnn_vad
107 } // namespace webrtc
108