Add support for the Halton sequence

Bug: b/358039777
Change-Id: Id191d584e22cf82384a5d16ed355f41c0bb32b7b
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/358981
Reviewed-by: Erik Språng <sprang@webrtc.org>
Commit-Queue: Fanny Linderborg <linderborg@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#42764}
This commit is contained in:
Fanny Linderborg 2024-08-09 13:49:29 +02:00 committed by WebRTC LUCI CQ
parent 06163404a5
commit c2a82417e9
5 changed files with 222 additions and 0 deletions

View File

@ -959,6 +959,7 @@ if (rtc_include_tests) {
"config:encoder_config",
"config:streams_config",
"config:video_config_tests",
"corruption_detection:corruption_detection_tests",
"//third_party/abseil-cpp/absl/algorithm:container",
"//third_party/abseil-cpp/absl/functional:any_invocable",
"//third_party/abseil-cpp/absl/memory",

View File

@ -0,0 +1,34 @@
# Copyright 2024 The WebRTC project authors. All rights reserved.
#
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file in the root of the source
# tree. An additional intellectual property rights grant can be found
# in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
import("../../webrtc.gni")
rtc_library("halton_sequence") {
sources = [
"halton_sequence.cc",
"halton_sequence.h",
]
deps = [ "../../rtc_base:checks" ]
}
if (rtc_include_tests) {
rtc_library("halton_sequence_unittest") {
testonly = true
sources = [ "halton_sequence_unittest.cc" ]
deps = [
":halton_sequence",
"../../test/:test_support",
]
}
rtc_library("corruption_detection_tests") {
testonly = true
sources = []
deps = [ ":halton_sequence_unittest" ]
}
}

View File

@ -0,0 +1,66 @@
/*
* Copyright 2024 The WebRTC project authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "video/corruption_detection/halton_sequence.h"
#include <algorithm>
#include <vector>
#include "rtc_base/checks.h"
namespace webrtc {
namespace {
static constexpr int kMaxDimensions = 5;
const int kBases[kMaxDimensions] = {2, 3, 5, 7, 11};
double GetVanDerCorputSequenceElement(int sequence_idx, int base) {
if (sequence_idx < 0 || base < 2) {
sequence_idx = 0;
base = 2;
}
double element = 0.0;
double positional_value = 1.0;
int left = sequence_idx;
while (left > 0) {
positional_value /= base;
element += positional_value * (left % base);
left /= base;
}
return element;
}
} // namespace
HaltonSequence::HaltonSequence(int num_dimensions)
: num_dimensions_(num_dimensions), current_idx_(0) {
RTC_CHECK_GE(num_dimensions_, 1)
<< "num_dimensions must be >= 1. Will be set to 1.";
RTC_CHECK_LE(num_dimensions_, kMaxDimensions)
<< "num_dimensions must be <= " << kMaxDimensions << ". Will be set to "
<< kMaxDimensions << ".";
num_dimensions_ = std::clamp(num_dimensions_, 1, kMaxDimensions);
}
std::vector<double> HaltonSequence::GetNext() {
std::vector<double> point = {};
point.reserve(num_dimensions_);
for (int i = 0; i < num_dimensions_; ++i) {
point.push_back(GetVanDerCorputSequenceElement(current_idx_, kBases[i]));
}
++current_idx_;
return point;
}
void HaltonSequence::Reset() {
HaltonSequence::current_idx_ = 0;
}
} // namespace webrtc

View File

@ -0,0 +1,48 @@
/*
* Copyright 2024 The WebRTC project authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef VIDEO_CORRUPTION_DETECTION_HALTON_SEQUENCE_H_
#define VIDEO_CORRUPTION_DETECTION_HALTON_SEQUENCE_H_
#include <vector>
namespace webrtc {
// Generates the Halton sequence: a low discrepancy sequence of doubles in the
// half-open interval [0,1). See https://en.wikipedia.org/wiki/Halton_sequence
// for information on how the sequence is constructed.
class HaltonSequence {
public:
// Creates a sequence in `num_dimensions` number of dimensions. Possible
// values are [1, 5].
explicit HaltonSequence(int num_dimensions);
// Creates a default sequence in a single dimension.
HaltonSequence() = default;
HaltonSequence(const HaltonSequence&) = default;
HaltonSequence(HaltonSequence&&) = default;
HaltonSequence& operator=(const HaltonSequence&) = default;
HaltonSequence& operator=(HaltonSequence&&) = default;
~HaltonSequence() = default;
// Gets the next point in the sequence where each value is in the half-open
// interval [0,1).
std::vector<double> GetNext();
int GetCurrentIndex() const { return current_idx_; }
void SetCurrentIndex(int idx) { current_idx_ = idx; }
void Reset();
private:
int num_dimensions_ = 1;
int current_idx_ = 0;
};
} // namespace webrtc
#endif // VIDEO_CORRUPTION_DETECTION_HALTON_SEQUENCE_H_

View File

@ -0,0 +1,73 @@
/*
* Copyright 2024 The WebRTC project authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "video/corruption_detection/halton_sequence.h"
#include "test/gmock.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
using ::testing::DoubleEq;
using ::testing::ElementsAre;
TEST(HaltonSequenceTest, ShouldGenerateBase2SequenceByDefault) {
HaltonSequence halton_sequence;
EXPECT_THAT(halton_sequence.GetNext(), ElementsAre(DoubleEq(0.0)));
EXPECT_THAT(halton_sequence.GetNext(), ElementsAre(DoubleEq(1.0 / 2)));
EXPECT_THAT(halton_sequence.GetNext(), ElementsAre(DoubleEq(1.0 / 4)));
EXPECT_THAT(halton_sequence.GetNext(), ElementsAre(DoubleEq(3.0 / 4)));
EXPECT_THAT(halton_sequence.GetNext(), ElementsAre(DoubleEq(1.0 / 8)));
EXPECT_THAT(halton_sequence.GetNext(), ElementsAre(DoubleEq(5.0 / 8)));
EXPECT_THAT(halton_sequence.GetNext(), ElementsAre(DoubleEq(3.0 / 8)));
}
TEST(HaltonSequenceTest,
ShouldGenerateBase2Base3SequencesWhenCreatedAs2Dimensional) {
HaltonSequence halton_sequence(2);
EXPECT_THAT(halton_sequence.GetNext(),
ElementsAre(DoubleEq(0.0), DoubleEq(0.0)));
EXPECT_THAT(halton_sequence.GetNext(),
ElementsAre(DoubleEq(1.0 / 2), DoubleEq(1.0 / 3)));
EXPECT_THAT(halton_sequence.GetNext(),
ElementsAre(DoubleEq(1.0 / 4), DoubleEq(2.0 / 3)));
EXPECT_THAT(halton_sequence.GetNext(),
ElementsAre(DoubleEq(3.0 / 4), DoubleEq(1.0 / 9)));
EXPECT_THAT(halton_sequence.GetNext(),
ElementsAre(DoubleEq(1.0 / 8), DoubleEq(4.0 / 9)));
EXPECT_THAT(halton_sequence.GetNext(),
ElementsAre(DoubleEq(5.0 / 8), DoubleEq(7.0 / 9)));
EXPECT_THAT(halton_sequence.GetNext(),
ElementsAre(DoubleEq(3.0 / 8), DoubleEq(2.0 / 9)));
}
TEST(HaltonSequenceTest, ShouldRestartSequenceWhenResetIsCalled) {
HaltonSequence halton_sequence;
EXPECT_THAT(halton_sequence.GetCurrentIndex(), 0);
EXPECT_THAT(halton_sequence.GetNext(), ElementsAre(DoubleEq(0.0)));
EXPECT_THAT(halton_sequence.GetCurrentIndex(), 1);
EXPECT_THAT(halton_sequence.GetNext(), ElementsAre(DoubleEq(1.0 / 2)));
EXPECT_THAT(halton_sequence.GetCurrentIndex(), 2);
halton_sequence.Reset();
EXPECT_THAT(halton_sequence.GetCurrentIndex(), 0);
EXPECT_THAT(halton_sequence.GetNext(), ElementsAre(DoubleEq(0.0)));
}
TEST(HaltonSequenceTest, ShouldSetCurrentIndexWhenSetCurrentIndexIsCalled) {
HaltonSequence halton_sequence;
EXPECT_THAT(halton_sequence.GetCurrentIndex(), 0);
halton_sequence.SetCurrentIndex(3);
EXPECT_THAT(halton_sequence.GetCurrentIndex(), 3);
EXPECT_THAT(halton_sequence.GetNext(), ElementsAre(DoubleEq(3.0 / 4)));
}
} // namespace
} // namespace webrtc