mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-26 04:35:41 +03:00
LibTest: Add more numeric generators
Rename unsigned_int generator to number_u32. Add generators: - number_u64 - number_f64 - percentage
This commit is contained in:
parent
dd53f64d2f
commit
d52ffcd830
Notes:
sideshowbarker
2024-07-17 06:40:21 +09:00
Author: https://github.com/Janiczek Commit: https://github.com/SerenityOS/serenity/commit/d52ffcd830 Pull-request: https://github.com/SerenityOS/serenity/pull/22506 Reviewed-by: https://github.com/ADKaster ✅ Reviewed-by: https://github.com/LucasChollet Reviewed-by: https://github.com/ronak69
@ -5,6 +5,8 @@
|
||||
*/
|
||||
|
||||
#include <AK/Random.h>
|
||||
#include <AK/UFixedBigInt.h>
|
||||
#include <AK/UFixedBigIntDivision.h>
|
||||
|
||||
namespace AK {
|
||||
|
||||
@ -28,4 +30,16 @@ u32 get_random_uniform(u32 max_bounds)
|
||||
return random_value % max_bounds;
|
||||
}
|
||||
|
||||
u64 get_random_uniform_64(u64 max_bounds)
|
||||
{
|
||||
// Uses the same algorithm as `get_random_uniform`,
|
||||
// by replacing u64 with u128 and u32 with u64.
|
||||
const u64 max_usable = UINT64_MAX - static_cast<u64>((static_cast<u128>(UINT64_MAX) + 1) % max_bounds);
|
||||
auto random_value = get_random<u64>();
|
||||
for (int i = 0; i < 20 && random_value > max_usable; ++i) {
|
||||
random_value = get_random<u64>();
|
||||
}
|
||||
return random_value % max_bounds;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -60,6 +60,7 @@ inline T get_random()
|
||||
}
|
||||
|
||||
u32 get_random_uniform(u32 max_bounds);
|
||||
u64 get_random_uniform_64(u64 max_bounds);
|
||||
|
||||
template<typename Collection>
|
||||
inline void shuffle(Collection& collection)
|
||||
|
@ -28,13 +28,13 @@ TEST_CASE(all_but_one_false)
|
||||
|
||||
RANDOMIZED_TEST_CASE(trivial_all_true)
|
||||
{
|
||||
GEN(vec, Gen::vector(0, 10, []() { return Gen::unsigned_int(); }));
|
||||
GEN(vec, Gen::vector(0, 10, []() { return Gen::number_u64(); }));
|
||||
EXPECT(all_of(vec.begin(), vec.end(), [](auto) { return true; }));
|
||||
}
|
||||
|
||||
RANDOMIZED_TEST_CASE(trivial_all_false)
|
||||
{
|
||||
GEN(vec, Gen::vector(1, 10, []() { return Gen::unsigned_int(); }));
|
||||
GEN(vec, Gen::vector(1, 10, []() { return Gen::number_u64(); }));
|
||||
EXPECT(!all_of(vec.begin(), vec.end(), [](auto) { return false; }));
|
||||
}
|
||||
|
||||
|
@ -28,13 +28,13 @@ TEST_CASE(all_false)
|
||||
|
||||
RANDOMIZED_TEST_CASE(trivial_all_true)
|
||||
{
|
||||
GEN(vec, Gen::vector(1, 10, []() { return Gen::unsigned_int(); }));
|
||||
GEN(vec, Gen::vector(1, 10, []() { return Gen::number_u64(); }));
|
||||
EXPECT(any_of(vec.begin(), vec.end(), [](auto) { return true; }));
|
||||
}
|
||||
|
||||
RANDOMIZED_TEST_CASE(trivial_all_false)
|
||||
{
|
||||
GEN(vec, Gen::vector(0, 10, []() { return Gen::unsigned_int(); }));
|
||||
GEN(vec, Gen::vector(0, 10, []() { return Gen::number_u64(); }));
|
||||
EXPECT(!any_of(vec.begin(), vec.end(), [](auto) { return false; }));
|
||||
}
|
||||
|
||||
|
@ -70,35 +70,35 @@ TEST_CASE(large_populate_reverse)
|
||||
|
||||
RANDOMIZED_TEST_CASE(pop_min_is_min)
|
||||
{
|
||||
GEN(vec, Gen::vector(1, 10, []() { return Gen::unsigned_int(); }));
|
||||
GEN(vec, Gen::vector(1, 10, []() { return Gen::number_u64(); }));
|
||||
|
||||
auto sorted { vec };
|
||||
AK::quick_sort(sorted);
|
||||
|
||||
BinaryHeap<u32, u32, 10> heap;
|
||||
BinaryHeap<u64, u64, 10> heap;
|
||||
|
||||
// insert in a non-sorted order
|
||||
for (u32 n : vec) {
|
||||
for (u64 n : vec) {
|
||||
heap.insert(n, n);
|
||||
}
|
||||
|
||||
// check in a sorted order
|
||||
for (u32 sorted_n : sorted) {
|
||||
for (u64 sorted_n : sorted) {
|
||||
EXPECT_EQ(heap.pop_min(), sorted_n);
|
||||
}
|
||||
}
|
||||
|
||||
RANDOMIZED_TEST_CASE(peek_min_same_as_pop_min)
|
||||
{
|
||||
GEN(vec, Gen::vector(1, 10, []() { return Gen::unsigned_int(); }));
|
||||
BinaryHeap<u32, u32, 10> heap;
|
||||
for (u32 n : vec) {
|
||||
GEN(vec, Gen::vector(1, 10, []() { return Gen::number_u64(); }));
|
||||
BinaryHeap<u64, u64, 10> heap;
|
||||
for (u64 n : vec) {
|
||||
heap.insert(n, n);
|
||||
}
|
||||
|
||||
while (!heap.is_empty()) {
|
||||
u32 peeked = heap.peek_min();
|
||||
u32 popped = heap.pop_min();
|
||||
u64 peeked = heap.peek_min();
|
||||
u64 popped = heap.pop_min();
|
||||
EXPECT_EQ(peeked, popped);
|
||||
}
|
||||
}
|
||||
|
@ -122,10 +122,10 @@ TEST_CASE(unsigned_to_signed_regression)
|
||||
|
||||
RANDOMIZED_TEST_CASE(finds_number_that_is_present)
|
||||
{
|
||||
GEN(vec, Gen::vector(1, 16, []() { return Gen::unsigned_int(); }));
|
||||
GEN(i, Gen::unsigned_int(0, vec.size() - 1));
|
||||
GEN(vec, Gen::vector(1, 16, []() { return Gen::number_u64(); }));
|
||||
GEN(i, Gen::number_u64(0, vec.size() - 1));
|
||||
AK::quick_sort(vec);
|
||||
u32 n = vec[i];
|
||||
u64 n = vec[i];
|
||||
auto ptr = binary_search(vec, n);
|
||||
EXPECT_NE(ptr, nullptr);
|
||||
EXPECT_EQ(*ptr, n);
|
||||
@ -133,10 +133,10 @@ RANDOMIZED_TEST_CASE(finds_number_that_is_present)
|
||||
|
||||
RANDOMIZED_TEST_CASE(doesnt_find_number_that_is_not_present)
|
||||
{
|
||||
GEN(vec, Gen::vector(1, 16, []() { return Gen::unsigned_int(); }));
|
||||
GEN(vec, Gen::vector(1, 16, []() { return Gen::number_u64(); }));
|
||||
AK::quick_sort(vec);
|
||||
|
||||
u32 not_present = 0;
|
||||
u64 not_present = 0;
|
||||
while (!vec.find(not_present).is_end()) {
|
||||
++not_present;
|
||||
}
|
||||
|
@ -201,7 +201,7 @@ TEST_CASE(bit_reads_beyond_stream_limits)
|
||||
|
||||
RANDOMIZED_TEST_CASE(roundtrip_u8_little_endian)
|
||||
{
|
||||
GEN(n, Gen::unsigned_int(NumericLimits<u8>::max()));
|
||||
GEN(n, Gen::number_u64(NumericLimits<u8>::max()));
|
||||
|
||||
auto memory_stream = make<AllocatingMemoryStream>();
|
||||
LittleEndianOutputBitStream sut_write { MaybeOwned<Stream>(*memory_stream) };
|
||||
@ -216,7 +216,7 @@ RANDOMIZED_TEST_CASE(roundtrip_u8_little_endian)
|
||||
|
||||
RANDOMIZED_TEST_CASE(roundtrip_u16_little_endian)
|
||||
{
|
||||
GEN(n, Gen::unsigned_int(NumericLimits<u16>::max()));
|
||||
GEN(n, Gen::number_u64(NumericLimits<u16>::max()));
|
||||
|
||||
auto memory_stream = make<AllocatingMemoryStream>();
|
||||
LittleEndianOutputBitStream sut_write { MaybeOwned<Stream>(*memory_stream) };
|
||||
@ -231,7 +231,7 @@ RANDOMIZED_TEST_CASE(roundtrip_u16_little_endian)
|
||||
|
||||
RANDOMIZED_TEST_CASE(roundtrip_u32_little_endian)
|
||||
{
|
||||
GEN(n, Gen::unsigned_int(NumericLimits<u32>::max()));
|
||||
GEN(n, Gen::number_u64(NumericLimits<u32>::max()));
|
||||
|
||||
auto memory_stream = make<AllocatingMemoryStream>();
|
||||
LittleEndianOutputBitStream sut_write { MaybeOwned<Stream>(*memory_stream) };
|
||||
@ -246,7 +246,7 @@ RANDOMIZED_TEST_CASE(roundtrip_u32_little_endian)
|
||||
|
||||
RANDOMIZED_TEST_CASE(roundtrip_u8_big_endian)
|
||||
{
|
||||
GEN(n, Gen::unsigned_int(NumericLimits<u8>::max()));
|
||||
GEN(n, Gen::number_u64(NumericLimits<u8>::max()));
|
||||
|
||||
auto memory_stream = make<AllocatingMemoryStream>();
|
||||
BigEndianOutputBitStream sut_write { MaybeOwned<Stream>(*memory_stream) };
|
||||
@ -260,7 +260,7 @@ RANDOMIZED_TEST_CASE(roundtrip_u8_big_endian)
|
||||
|
||||
RANDOMIZED_TEST_CASE(roundtrip_u16_big_endian)
|
||||
{
|
||||
GEN(n, Gen::unsigned_int(NumericLimits<u16>::max()));
|
||||
GEN(n, Gen::number_u64(NumericLimits<u16>::max()));
|
||||
|
||||
auto memory_stream = make<AllocatingMemoryStream>();
|
||||
BigEndianOutputBitStream sut_write { MaybeOwned<Stream>(*memory_stream) };
|
||||
@ -274,7 +274,7 @@ RANDOMIZED_TEST_CASE(roundtrip_u16_big_endian)
|
||||
|
||||
RANDOMIZED_TEST_CASE(roundtrip_u32_big_endian)
|
||||
{
|
||||
GEN(n, Gen::unsigned_int(NumericLimits<u32>::max()));
|
||||
GEN(n, Gen::number_u64(NumericLimits<u32>::max()));
|
||||
|
||||
auto memory_stream = make<AllocatingMemoryStream>();
|
||||
BigEndianOutputBitStream sut_write { MaybeOwned<Stream>(*memory_stream) };
|
||||
|
@ -283,8 +283,8 @@ RANDOMIZED_TEST_CASE(set_get)
|
||||
{
|
||||
GEN(init, Gen::boolean());
|
||||
GEN(new_value, Gen::boolean());
|
||||
GEN(size, Gen::unsigned_int(1, 64));
|
||||
GEN(i, Gen::unsigned_int(size - 1));
|
||||
GEN(size, Gen::number_u64(1, 64));
|
||||
GEN(i, Gen::number_u64(size - 1));
|
||||
|
||||
auto bitmap = MUST(Bitmap::create(size, init));
|
||||
bitmap.set(i, new_value);
|
||||
@ -295,11 +295,11 @@ RANDOMIZED_TEST_CASE(set_get)
|
||||
RANDOMIZED_TEST_CASE(set_range)
|
||||
{
|
||||
GEN(init, Gen::boolean());
|
||||
GEN(size, Gen::unsigned_int(1, 64));
|
||||
GEN(size, Gen::number_u64(1, 64));
|
||||
GEN(new_value, Gen::boolean());
|
||||
|
||||
GEN(start, Gen::unsigned_int(size - 1));
|
||||
GEN(len, Gen::unsigned_int(size - start - 1));
|
||||
GEN(start, Gen::number_u64(size - 1));
|
||||
GEN(len, Gen::number_u64(size - start - 1));
|
||||
|
||||
auto bitmap = MUST(Bitmap::create(size, init));
|
||||
bitmap.set_range(start, len, new_value);
|
||||
@ -313,7 +313,7 @@ RANDOMIZED_TEST_CASE(set_range)
|
||||
RANDOMIZED_TEST_CASE(fill)
|
||||
{
|
||||
GEN(init, Gen::boolean());
|
||||
GEN(size, Gen::unsigned_int(1, 64));
|
||||
GEN(size, Gen::number_u64(1, 64));
|
||||
GEN(new_value, Gen::boolean());
|
||||
|
||||
auto bitmap = MUST(Bitmap::create(size, init));
|
||||
@ -334,11 +334,11 @@ TEST_CASE(find_one_anywhere_edge_case)
|
||||
RANDOMIZED_TEST_CASE(find_one_anywhere)
|
||||
{
|
||||
GEN(init, Gen::boolean());
|
||||
GEN(size, Gen::unsigned_int(1, 64));
|
||||
GEN(hint, Gen::unsigned_int(size - 1));
|
||||
GEN(size, Gen::number_u64(1, 64));
|
||||
GEN(hint, Gen::number_u64(size - 1));
|
||||
|
||||
GEN(new_value, Gen::boolean());
|
||||
GEN(i, Gen::unsigned_int(size - 1));
|
||||
GEN(i, Gen::number_u64(size - 1));
|
||||
|
||||
auto bitmap = MUST(Bitmap::create(size, init));
|
||||
bitmap.set(i, new_value);
|
||||
@ -363,10 +363,10 @@ TEST_CASE(find_first_edge_case)
|
||||
RANDOMIZED_TEST_CASE(find_first)
|
||||
{
|
||||
GEN(init, Gen::boolean());
|
||||
GEN(size, Gen::unsigned_int(1, 64));
|
||||
GEN(size, Gen::number_u64(1, 64));
|
||||
|
||||
GEN(new_value, Gen::boolean());
|
||||
GEN(i, Gen::unsigned_int(size - 1));
|
||||
GEN(i, Gen::number_u64(size - 1));
|
||||
|
||||
auto bitmap = MUST(Bitmap::create(size, init));
|
||||
bitmap.set(i, new_value);
|
||||
|
@ -72,13 +72,13 @@ RANDOMIZED_TEST_CASE(count_leading_zeroes)
|
||||
{
|
||||
// count_leading_zeroes(0b000...0001000...000)
|
||||
// == count_leading_zeroes(0b000...0001___...___) (where _ is 0 or 1)
|
||||
GEN(e, Gen::unsigned_int(0, 63));
|
||||
GEN(e, Gen::number_u64(0, 63));
|
||||
auto power_of_two = 1ULL << e;
|
||||
|
||||
// We add random one-bits below the leftmost (and only) one-bit.
|
||||
// This shouldn't change the output of count_leading_zeroes because
|
||||
// the function should only care about the most significant one.
|
||||
GEN(below, Gen::unsigned_int(0, power_of_two - 1));
|
||||
GEN(below, Gen::number_u64(0, power_of_two - 1));
|
||||
auto n = power_of_two + below;
|
||||
|
||||
EXPECT_EQ(count_leading_zeroes(n), count_leading_zeroes(power_of_two));
|
||||
@ -89,7 +89,7 @@ RANDOMIZED_TEST_CASE(count_required_bits)
|
||||
// count_required_bits(n) == log2(n) + 1
|
||||
|
||||
// log2(0) is -infinity, we don't care about that
|
||||
GEN(n, Gen::unsigned_int(1, NumericLimits<u32>::max()));
|
||||
GEN(n, Gen::number_u32(1, NumericLimits<u32>::max()));
|
||||
|
||||
size_t expected = AK::log2(static_cast<double>(n)) + 1;
|
||||
|
||||
@ -99,6 +99,6 @@ RANDOMIZED_TEST_CASE(count_required_bits)
|
||||
RANDOMIZED_TEST_CASE(bit_scan_forward_count_trailing_zeroes)
|
||||
{
|
||||
// Behaviour for 0 differs, so we skip it.
|
||||
GEN(n, Gen::unsigned_int(1, 1 << 31));
|
||||
GEN(n, Gen::number_u32(1, 1 << 31));
|
||||
EXPECT_EQ(bit_scan_forward(n), count_trailing_zeroes(n) + 1);
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ void randomized_compare_bool_output_over(u32 range, auto& old_function, auto& ne
|
||||
for (u32 n = 0; n < 100; ++n) {
|
||||
bool result1 = false;
|
||||
bool result2 = false;
|
||||
GEN(i, Gen::unsigned_int(range - 1));
|
||||
GEN(i, Gen::number_u64(range - 1));
|
||||
EXPECT_EQ(result1 = (old_function(i) > 0), result2 = (new_function(i) > 0));
|
||||
if (result1 != result2)
|
||||
FAIL(String::formatted("New result {} does not match old result {} for input {}.", result1, result2, i));
|
||||
@ -55,7 +55,7 @@ void randomized_compare_value_output_over(u32 range, auto& old_function, auto& n
|
||||
for (u32 n = 0; n < 100; ++n) {
|
||||
i64 result1 = false;
|
||||
i64 result2 = false;
|
||||
GEN(i, Gen::unsigned_int(range - 1));
|
||||
GEN(i, Gen::number_u64(range - 1));
|
||||
EXPECT_EQ(result1 = old_function(i), result2 = new_function(i));
|
||||
if (result1 != result2)
|
||||
FAIL(String::formatted("New result {} does not match old result {} for input {}.", result1, result2, i));
|
||||
|
@ -7,46 +7,47 @@
|
||||
#include <AK/StdLibExtras.h>
|
||||
#include <LibTest/Randomized/Generator.h>
|
||||
#include <LibTest/TestCase.h>
|
||||
#include <math.h>
|
||||
|
||||
using namespace Test::Randomized;
|
||||
|
||||
RANDOMIZED_TEST_CASE(unsigned_int_max_bounds)
|
||||
RANDOMIZED_TEST_CASE(number_u64_max_bounds)
|
||||
{
|
||||
GEN(n, Gen::unsigned_int(10));
|
||||
GEN(n, Gen::number_u64(10));
|
||||
EXPECT(n <= 10);
|
||||
}
|
||||
|
||||
RANDOMIZED_TEST_CASE(unsigned_int_min_max_bounds)
|
||||
RANDOMIZED_TEST_CASE(number_u64_min_max_bounds)
|
||||
{
|
||||
GEN(n, Gen::unsigned_int(3, 6));
|
||||
GEN(n, Gen::number_u64(3, 6));
|
||||
EXPECT(n >= 3 && n <= 6);
|
||||
}
|
||||
|
||||
RANDOMIZED_TEST_CASE(assume)
|
||||
{
|
||||
GEN(n, Gen::unsigned_int(10));
|
||||
GEN(n, Gen::number_u64(10));
|
||||
ASSUME(n % 2 == 0); // This will try to generate until it finds an even number
|
||||
EXPECT(n % 2 == 0); // This will then succeed
|
||||
// It will give up if the value doesn't pass the ASSUME(...) predicate 15 times in a row.
|
||||
}
|
||||
|
||||
// TODO find a way to test that a test "unsigned_int(3) can't reach 0" fails
|
||||
// TODO find a way to test that a test "unsigned_int(3) can't reach 3" fails
|
||||
// TODO find a way to test that a test "unsigned_int(3,6) can't reach 3" fails
|
||||
// TODO find a way to test that a test "unsigned_int(3,6) can't reach 6" fails
|
||||
// TODO find a way to test that a test "unsigned_int(10) can reach n>10" fails
|
||||
// TODO find a way to test that a test "number_u64(3) can't reach 0" fails
|
||||
// TODO find a way to test that a test "number_u64(3) can't reach 3" fails
|
||||
// TODO find a way to test that a test "number_u64(3,6) can't reach 3" fails
|
||||
// TODO find a way to test that a test "number_u64(3,6) can't reach 6" fails
|
||||
// TODO find a way to test that a test "number_u64(10) can reach n>10" fails
|
||||
|
||||
RANDOMIZED_TEST_CASE(map_like)
|
||||
{
|
||||
GEN(n1, Gen::unsigned_int(10));
|
||||
GEN(n1, Gen::number_u64(10));
|
||||
GEN(n2, n1 * 2);
|
||||
EXPECT(n2 % 2 == 0);
|
||||
}
|
||||
|
||||
RANDOMIZED_TEST_CASE(bind_like)
|
||||
{
|
||||
GEN(n1, Gen::unsigned_int(1, 9));
|
||||
GEN(n2, Gen::unsigned_int(n1 * 10, n1 * 100));
|
||||
GEN(n1, Gen::number_u64(1, 9));
|
||||
GEN(n2, Gen::number_u64(n1 * 10, n1 * 100));
|
||||
EXPECT(n2 >= 10 && n2 <= 900);
|
||||
}
|
||||
|
||||
@ -68,7 +69,7 @@ RANDOMIZED_TEST_CASE(bind_like)
|
||||
template<typename FN>
|
||||
Vector<InvokeResult<FN>> vector_suboptimal(FN item_gen)
|
||||
{
|
||||
u32 length = Gen::unsigned_int(5);
|
||||
u32 length = Gen::number_u64(5);
|
||||
Vector<InvokeResult<FN>> acc;
|
||||
for (u32 i = 0; i < length; ++i) {
|
||||
acc.append(item_gen());
|
||||
@ -79,7 +80,7 @@ Vector<InvokeResult<FN>> vector_suboptimal(FN item_gen)
|
||||
RANDOMIZED_TEST_CASE(bind_vector_suboptimal)
|
||||
{
|
||||
u32 max_item = 5;
|
||||
GEN(vec, vector_suboptimal([&]() { return Gen::unsigned_int(max_item); }));
|
||||
GEN(vec, vector_suboptimal([&]() { return Gen::number_u64(max_item); }));
|
||||
u32 sum = 0;
|
||||
for (u32 n : vec) {
|
||||
sum += n;
|
||||
@ -90,21 +91,21 @@ RANDOMIZED_TEST_CASE(bind_vector_suboptimal)
|
||||
RANDOMIZED_TEST_CASE(vector)
|
||||
{
|
||||
u32 max_item = 5;
|
||||
GEN(vec, Gen::vector([&]() { return Gen::unsigned_int(max_item); }));
|
||||
GEN(vec, Gen::vector([&]() { return Gen::number_u64(max_item); }));
|
||||
EXPECT(vec.size() <= 32);
|
||||
}
|
||||
|
||||
RANDOMIZED_TEST_CASE(vector_length)
|
||||
{
|
||||
u32 max_item = 5;
|
||||
GEN(vec, Gen::vector(3, [&]() { return Gen::unsigned_int(max_item); }));
|
||||
GEN(vec, Gen::vector(3, [&]() { return Gen::number_u64(max_item); }));
|
||||
EXPECT(vec.size() == 3);
|
||||
}
|
||||
|
||||
RANDOMIZED_TEST_CASE(vector_min_max)
|
||||
{
|
||||
u32 max_item = 5;
|
||||
GEN(vec, Gen::vector(1, 4, [&]() { return Gen::unsigned_int(max_item); }));
|
||||
GEN(vec, Gen::vector(1, 4, [&]() { return Gen::number_u64(max_item); }));
|
||||
EXPECT(vec.size() >= 1 && vec.size() <= 4);
|
||||
}
|
||||
|
||||
@ -160,9 +161,57 @@ RANDOMIZED_TEST_CASE(boolean_false)
|
||||
EXPECT(b == false);
|
||||
}
|
||||
|
||||
RANDOMIZED_TEST_CASE(one_of_int)
|
||||
{
|
||||
GEN(x, Gen::one_of(1, 2));
|
||||
EXPECT(x == 1 || x == 2);
|
||||
}
|
||||
|
||||
RANDOMIZED_TEST_CASE(frequency_int)
|
||||
{
|
||||
GEN(x, Gen::frequency(Gen::Choice { 5, 'x' }, Gen::Choice { 1, 'o' }));
|
||||
ASSUME(x == 'x');
|
||||
EXPECT(x == 'x');
|
||||
}
|
||||
|
||||
RANDOMIZED_TEST_CASE(percentage)
|
||||
{
|
||||
GEN(x, Gen::percentage());
|
||||
EXPECT(x >= 0 && x <= 1);
|
||||
}
|
||||
|
||||
RANDOMIZED_TEST_CASE(number_f64_max_bounds)
|
||||
{
|
||||
GEN(x, Gen::number_f64(10));
|
||||
EXPECT(x <= 10);
|
||||
}
|
||||
|
||||
RANDOMIZED_TEST_CASE(number_f64_min_max_bounds)
|
||||
{
|
||||
GEN(x, Gen::number_f64(-10, 10));
|
||||
EXPECT(x >= -10 && x <= 10);
|
||||
}
|
||||
|
||||
RANDOMIZED_TEST_CASE(number_f64_never_nan)
|
||||
{
|
||||
GEN(x, Gen::number_f64());
|
||||
EXPECT(!isnan(x));
|
||||
}
|
||||
|
||||
RANDOMIZED_TEST_CASE(number_f64_never_infinite)
|
||||
{
|
||||
GEN(x, Gen::number_f64());
|
||||
EXPECT(!isinf(x));
|
||||
}
|
||||
|
||||
RANDOMIZED_TEST_CASE(number_u32_max_bounds)
|
||||
{
|
||||
GEN(n, Gen::number_u32(10));
|
||||
EXPECT(n <= 10);
|
||||
}
|
||||
|
||||
RANDOMIZED_TEST_CASE(number_u32_min_max_bounds)
|
||||
{
|
||||
GEN(n, Gen::number_u32(3, 6));
|
||||
EXPECT(n >= 3 && n <= 6);
|
||||
}
|
||||
|
@ -15,22 +15,24 @@
|
||||
#include <AK/StringView.h>
|
||||
#include <AK/Tuple.h>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
namespace Test {
|
||||
namespace Randomized {
|
||||
|
||||
// Returns a random double value in range 0..1.
|
||||
inline double get_random_probability()
|
||||
// This is not a generator. It is meant to be used inside RandomnessSource::draw_value().
|
||||
// Based on: https://dotat.at/@/2023-06-23-random-double.html
|
||||
inline f64 get_random_probability()
|
||||
{
|
||||
static constexpr u32 max_u32 = NumericLimits<u32>::max();
|
||||
u32 random_u32 = AK::get_random_uniform(max_u32);
|
||||
return static_cast<double>(random_u32) / static_cast<double>(max_u32);
|
||||
return static_cast<f64>(AK::get_random<u64>() >> 11) * 0x1.0p-53;
|
||||
}
|
||||
|
||||
// Generators take random bits from the RandomnessSource and return a value
|
||||
// back.
|
||||
//
|
||||
// Example:
|
||||
// - Gen::u32(5,10) --> 9, 7, 5, 10, 8, ...
|
||||
// - Gen::number_u64(5,10) --> 9, 7, 5, 10, 8, ...
|
||||
namespace Gen {
|
||||
|
||||
// An unsigned integer generator.
|
||||
@ -38,41 +40,41 @@ namespace Gen {
|
||||
// The minimum value will always be 0.
|
||||
// The maximum value is given by user in the argument.
|
||||
//
|
||||
// Gen::unsigned_int(10) -> value 5, RandomRun [5]
|
||||
// -> value 8, RandomRun [8]
|
||||
// etc.
|
||||
// Gen::number_u64(10) -> value 5, RandomRun [5]
|
||||
// -> value 8, RandomRun [8]
|
||||
// etc.
|
||||
//
|
||||
// Shrinks towards 0.
|
||||
inline u32 unsigned_int(u32 max)
|
||||
inline u64 number_u64(u64 max)
|
||||
{
|
||||
if (max == 0)
|
||||
return 0;
|
||||
|
||||
u32 random = Test::randomness_source().draw_value(max, [&]() {
|
||||
// `clamp` to guard against integer overflow and calling get_random_uniform(0).
|
||||
u32 exclusive_bound = AK::clamp(max + 1, max, NumericLimits<u32>::max());
|
||||
return AK::get_random_uniform(exclusive_bound);
|
||||
u64 random = Test::randomness_source().draw_value(max, [&]() {
|
||||
// `clamp` to guard against integer overflow
|
||||
u64 exclusive_bound = AK::clamp(max + 1, max, NumericLimits<u64>::max());
|
||||
return AK::get_random_uniform_64(exclusive_bound);
|
||||
});
|
||||
return random;
|
||||
}
|
||||
|
||||
// An unsigned integer generator in a particular range.
|
||||
//
|
||||
// Gen::unsigned_int(3,10) -> value 3, RandomRun [0]
|
||||
// -> value 8, RandomRun [5]
|
||||
// -> value 10, RandomRun [7]
|
||||
// etc.
|
||||
// Gen::number_u64(3,10) -> value 3, RandomRun [0]
|
||||
// -> value 8, RandomRun [5]
|
||||
// -> value 10, RandomRun [7]
|
||||
// etc.
|
||||
//
|
||||
// In case `min == max`, the RandomRun footprint will be smaller: no randomness
|
||||
// is needed.
|
||||
//
|
||||
// Gen::unsigned_int(3,3) -> value 3, RandomRun [] (always)
|
||||
// Gen::number_u64(3,3) -> value 3, RandomRun [] (always)
|
||||
//
|
||||
// Shrinks towards the minimum.
|
||||
inline u32 unsigned_int(u32 min, u32 max)
|
||||
inline u64 number_u64(u64 min, u64 max)
|
||||
{
|
||||
VERIFY(max >= min);
|
||||
return unsigned_int(max - min) + min;
|
||||
return number_u64(max - min) + min;
|
||||
}
|
||||
|
||||
// Randomly (uniformly) selects a value out of the given arguments.
|
||||
@ -89,7 +91,7 @@ CommonType<Ts...> one_of(Ts... choices)
|
||||
Vector<CommonType<Ts...>> choices_vec { choices... };
|
||||
|
||||
constexpr size_t count = sizeof...(choices);
|
||||
size_t i = unsigned_int(count - 1);
|
||||
size_t i = number_u64(count - 1);
|
||||
return choices_vec[i];
|
||||
}
|
||||
|
||||
@ -118,16 +120,16 @@ CommonType<Ts...> frequency(Choice<Ts>... choices)
|
||||
{
|
||||
Vector<Choice<CommonType<Ts...>>> choices_vec { choices... };
|
||||
|
||||
u32 sum = 0;
|
||||
u64 sum = 0;
|
||||
for (auto const& choice : choices_vec) {
|
||||
VERIFY(choice.weight > 0);
|
||||
sum += static_cast<u32>(choice.weight);
|
||||
sum += static_cast<u64>(choice.weight);
|
||||
}
|
||||
|
||||
u32 target = unsigned_int(sum);
|
||||
u64 target = number_u64(sum);
|
||||
size_t i = 0;
|
||||
for (auto const& choice : choices_vec) {
|
||||
u32 weight = static_cast<u32>(choice.weight);
|
||||
u64 weight = static_cast<u64>(choice.weight);
|
||||
if (weight >= target) {
|
||||
return choice.value;
|
||||
}
|
||||
@ -137,46 +139,47 @@ CommonType<Ts...> frequency(Choice<Ts>... choices)
|
||||
return choices_vec[i - 1].value;
|
||||
}
|
||||
|
||||
// An unsigned integer generator in the full u32 range.
|
||||
// An unsigned integer generator in the full u64 range.
|
||||
//
|
||||
// 8/17 (47%) of the time it will bias towards 8bit numbers,
|
||||
// 4/17 (23%) towards 4bit numbers,
|
||||
// 2/17 (12%) towards 16bit numbers,
|
||||
// 1/17 (6%) towards 32bit numbers,
|
||||
// 2/17 (12%) towards edge cases like 0 and NumericLimits::max() of various unsigned int types.
|
||||
// Prefers 8bit numbers, then 4bit, 16bit, 32bit and 64bit ones.
|
||||
// Around 11% of the time it tries edge cases like 0 and various NumericLimits::max().
|
||||
//
|
||||
// Gen::unsigned_int() -> value 3, RandomRun [0,3]
|
||||
// -> value 8, RandomRun [1,8]
|
||||
// -> value 100, RandomRun [2,100]
|
||||
// -> value 5, RandomRun [3,5]
|
||||
// -> value 255, RandomRun [4,1]
|
||||
// -> value 65535, RandomRun [4,2]
|
||||
// etc.
|
||||
// Gen::number_u64() -> value 3, RandomRun [0,3]
|
||||
// -> value 8, RandomRun [1,8]
|
||||
// -> value 100, RandomRun [2,100]
|
||||
// -> value 5, RandomRun [3,5]
|
||||
// -> value 255, RandomRun [4,1]
|
||||
// -> value 65535, RandomRun [4,2]
|
||||
// etc.
|
||||
//
|
||||
// Shrinks towards 0.
|
||||
inline u32 unsigned_int()
|
||||
inline u64 number_u64()
|
||||
{
|
||||
u32 bits = frequency(
|
||||
u64 bits = frequency(
|
||||
// weight, bits
|
||||
Choice { 4, 4 },
|
||||
Choice { 8, 8 },
|
||||
Choice { 2, 16 },
|
||||
Choice { 1, 32 },
|
||||
Choice { 1, 64 },
|
||||
Choice { 2, 0 });
|
||||
|
||||
// The special cases go last as they can be the most extreme (large) values.
|
||||
|
||||
if (bits == 0) {
|
||||
// Special cases, eg. max integers for u8, u16, u32.
|
||||
// Special cases, eg. max integers for u8, u16, u32, u64.
|
||||
return one_of(
|
||||
0U,
|
||||
NumericLimits<u8>::max(),
|
||||
NumericLimits<u16>::max(),
|
||||
NumericLimits<u32>::max());
|
||||
NumericLimits<u32>::max(),
|
||||
NumericLimits<u64>::max());
|
||||
}
|
||||
|
||||
u32 max = ((u64)1 << bits) - 1;
|
||||
return unsigned_int(max);
|
||||
u64 max = bits == 64
|
||||
? NumericLimits<u64>::max()
|
||||
: ((u64)1 << bits) - 1;
|
||||
return number_u64(max);
|
||||
}
|
||||
|
||||
// A generator returning `true` with the given `probability` (0..1).
|
||||
@ -190,15 +193,15 @@ inline u32 unsigned_int()
|
||||
// -> value true, RandomRun [1]
|
||||
//
|
||||
// Shrinks towards false.
|
||||
inline bool weighted_boolean(double probability)
|
||||
inline bool weighted_boolean(f64 probability)
|
||||
{
|
||||
if (probability <= 0)
|
||||
return false;
|
||||
if (probability >= 1)
|
||||
return true;
|
||||
|
||||
u32 random_int = Test::randomness_source().draw_value(1, [&]() {
|
||||
double drawn_probability = get_random_probability();
|
||||
u64 random_int = Test::randomness_source().draw_value(1, [&]() {
|
||||
f64 drawn_probability = get_random_probability();
|
||||
return drawn_probability <= probability ? 1 : 0;
|
||||
});
|
||||
bool random_bool = random_int == 1;
|
||||
@ -219,7 +222,7 @@ inline bool boolean()
|
||||
|
||||
// A vector generator of a random length between the given limits.
|
||||
//
|
||||
// Gen::vector(2,3,[]() { return Gen::unsigned_int(5); })
|
||||
// Gen::vector(2,3,[]() { return Gen::number_u64(5); })
|
||||
// -> value [1,5], RandomRun [1,1,1,5,0]
|
||||
// -> value [1,5,0], RandomRun [1,1,1,5,1,0,0]
|
||||
// etc.
|
||||
@ -227,7 +230,7 @@ inline bool boolean()
|
||||
// In case `min == max`, the RandomRun footprint will be smaller, as there will
|
||||
// be no randomness involved in figuring out the length:
|
||||
//
|
||||
// Gen::vector(3,3,[]() { return Gen::unsigned_int(5); })
|
||||
// Gen::vector(3,3,[]() { return Gen::number_u64(5); })
|
||||
// -> value [1,3], RandomRun [1,3]
|
||||
// -> value [5,2], RandomRun [5,2]
|
||||
// etc.
|
||||
@ -266,7 +269,7 @@ inline Vector<InvokeResult<Fn>> vector(size_t min, size_t max, Fn item_gen)
|
||||
++size;
|
||||
}
|
||||
|
||||
double average = static_cast<double>(min + max) / 2.0;
|
||||
f64 average = static_cast<f64>(min + max) / 2.0;
|
||||
VERIFY(average > 0);
|
||||
|
||||
// A geometric distribution: https://en.wikipedia.org/wiki/Geometric_distribution#Moments_and_cumulants
|
||||
@ -279,7 +282,7 @@ inline Vector<InvokeResult<Fn>> vector(size_t min, size_t max, Fn item_gen)
|
||||
// That gives us `1 - 1/p`. Then, E(X) also contains the final success, so we
|
||||
// need to say `1 + average` instead of `average`, as it will mean "our X
|
||||
// items + the final failure that stops the process".
|
||||
double probability = 1.0 - 1.0 / (1.0 + average);
|
||||
f64 probability = 1.0 - 1.0 / (1.0 + average);
|
||||
|
||||
while (size < max) {
|
||||
if (weighted_boolean(probability)) {
|
||||
@ -295,7 +298,7 @@ inline Vector<InvokeResult<Fn>> vector(size_t min, size_t max, Fn item_gen)
|
||||
|
||||
// A vector generator of a given length.
|
||||
//
|
||||
// Gen::vector_of_length(3,[]() { return Gen::unsigned_int(5); })
|
||||
// Gen::vector_of_length(3,[]() { return Gen::number_u64(5); })
|
||||
// -> value [1,5,0], RandomRun [1,1,1,5,1,0,0]
|
||||
// -> value [2,9,3], RandomRun [1,2,1,9,1,3,0]
|
||||
// etc.
|
||||
@ -312,7 +315,7 @@ inline Vector<InvokeResult<Fn>> vector(size_t length, Fn item_gen)
|
||||
// If you need a different length, use vector(max,item_gen) or
|
||||
// vector(min,max,item_gen).
|
||||
//
|
||||
// Gen::vector([]() { return Gen::unsigned_int(5); })
|
||||
// Gen::vector([]() { return Gen::number_u64(5); })
|
||||
// -> value [], RandomRun [0]
|
||||
// -> value [1], RandomRun [1,1,0]
|
||||
// -> value [1,5], RandomRun [1,1,1,5,0]
|
||||
@ -327,6 +330,118 @@ inline Vector<InvokeResult<Fn>> vector(Fn item_gen)
|
||||
return vector(0, 32, item_gen);
|
||||
}
|
||||
|
||||
// A double generator in the [0,1) range.
|
||||
//
|
||||
// RandomRun footprint: a single number.
|
||||
//
|
||||
// Shrinks towards 0.
|
||||
//
|
||||
// Based on: https://dotat.at/@/2023-06-23-random-double.html
|
||||
inline f64 percentage()
|
||||
{
|
||||
return static_cast<f64>(number_u64() >> 11) * 0x1.0p-53;
|
||||
}
|
||||
|
||||
// An internal double generator. This one won't make any attempt to shrink nicely.
|
||||
// Test writers should use number_f64(f64 min, f64 max) instead.
|
||||
inline f64 number_f64_scaled(f64 min, f64 max)
|
||||
{
|
||||
VERIFY(max >= min);
|
||||
|
||||
if (min == max)
|
||||
return min;
|
||||
|
||||
f64 p = percentage();
|
||||
return min * (1.0 - p) + max * p;
|
||||
}
|
||||
|
||||
inline f64 number_f64(f64 min, f64 max)
|
||||
{
|
||||
// FIXME: after we figure out how to use frequency() with lambdas,
|
||||
// do edge cases and nicely shrinking float generators here
|
||||
|
||||
return number_f64_scaled(min, max);
|
||||
}
|
||||
|
||||
inline f64 number_f64()
|
||||
{
|
||||
// FIXME: this could be much nicer to the user, at the expense of code complexity
|
||||
// We could follow Hypothesis' lead and remap integers 0..MAXINT to _simple_
|
||||
// floats rather than small floats. Meaning, we would like to prefer integers
|
||||
// over floats with decimal digits, positive numbers over negative numbers etc.
|
||||
// As a result, users would get failures with floats like 0, 1, or 0.5 instead of
|
||||
// ones like 1.175494e-38.
|
||||
// Check the doc comment in Hypothesis: https://github.com/HypothesisWorks/hypothesis/blob/master/hypothesis-python/src/hypothesis/internal/conjecture/floats.py
|
||||
|
||||
return number_f64(NumericLimits<f64>::lowest(), NumericLimits<f64>::max());
|
||||
}
|
||||
|
||||
// A double generator.
|
||||
//
|
||||
// The minimum value will always be NumericLimits<f64>::lowest().
|
||||
// The maximum value is given by user in the argument.
|
||||
//
|
||||
// Prefers positive numbers, then negative numbers, then edge cases.
|
||||
//
|
||||
// Shrinks towards 0.
|
||||
inline f64 number_f64(f64 max)
|
||||
{
|
||||
// FIXME: after we figure out how to use frequency() with lambdas,
|
||||
// do edge cases and nicely shrinking float generators here
|
||||
|
||||
return number_f64_scaled(NumericLimits<f64>::lowest(), max);
|
||||
}
|
||||
|
||||
// TODO
|
||||
inline u32 number_u32(u32 max)
|
||||
{
|
||||
if (max == 0)
|
||||
return 0;
|
||||
|
||||
u32 random = Test::randomness_source().draw_value(max, [&]() {
|
||||
// `clamp` to guard against integer overflow
|
||||
u32 exclusive_bound = AK::clamp(max + 1, max, NumericLimits<u32>::max());
|
||||
return AK::get_random_uniform(exclusive_bound);
|
||||
});
|
||||
return random;
|
||||
}
|
||||
|
||||
// TODO
|
||||
inline u32 number_u32(u32 min, u32 max)
|
||||
{
|
||||
VERIFY(max >= min);
|
||||
return number_u32(max - min) + min;
|
||||
}
|
||||
|
||||
// TODO
|
||||
inline u32 number_u32()
|
||||
{
|
||||
u32 bits = frequency(
|
||||
// weight, bits
|
||||
Choice { 4, 4 },
|
||||
Choice { 8, 8 },
|
||||
Choice { 2, 16 },
|
||||
Choice { 1, 32 },
|
||||
Choice { 1, 64 },
|
||||
Choice { 2, 0 });
|
||||
|
||||
// The special cases go last as they can be the most extreme (large) values.
|
||||
|
||||
if (bits == 0) {
|
||||
// Special cases, eg. max integers for u8, u16, u32.
|
||||
return one_of(
|
||||
0U,
|
||||
NumericLimits<u8>::max(),
|
||||
NumericLimits<u16>::max(),
|
||||
NumericLimits<u32>::max());
|
||||
}
|
||||
|
||||
u32 max = bits == 32
|
||||
? NumericLimits<u32>::max()
|
||||
: ((u32)1 << bits) - 1;
|
||||
return number_u32(max);
|
||||
}
|
||||
|
||||
} // namespace Gen
|
||||
} // namespace Randomized
|
||||
} // namespace Test
|
||||
|
@ -29,24 +29,24 @@ public:
|
||||
RandomRun() = default;
|
||||
RandomRun(RandomRun const& rhs) = default;
|
||||
RandomRun& operator=(RandomRun const& rhs) = default;
|
||||
explicit RandomRun(Vector<u32> const& data)
|
||||
explicit RandomRun(Vector<u64> const& data)
|
||||
: m_data(move(data))
|
||||
{
|
||||
}
|
||||
bool is_empty() const { return m_data.is_empty(); }
|
||||
bool contains_chunk(Chunk const& c) const { return c.index + c.size <= m_data.size(); }
|
||||
void append(u32 n) { m_data.append(n); }
|
||||
void append(u64 n) { m_data.append(n); }
|
||||
size_t size() const { return m_data.size(); }
|
||||
Optional<u32> next()
|
||||
Optional<u64> next()
|
||||
{
|
||||
if (m_current_index < m_data.size()) {
|
||||
return m_data[m_current_index++];
|
||||
}
|
||||
return Optional<u32> {};
|
||||
return Optional<u64> {};
|
||||
}
|
||||
u32& operator[](size_t index) { return m_data[index]; }
|
||||
u32 const& operator[](size_t index) const { return m_data[index]; }
|
||||
Vector<u32> data() const { return m_data; }
|
||||
u64& operator[](size_t index) { return m_data[index]; }
|
||||
u64 const& operator[](size_t index) const { return m_data[index]; }
|
||||
Vector<u64> data() const { return m_data; }
|
||||
|
||||
// Shortlex sorting
|
||||
//
|
||||
@ -85,7 +85,7 @@ public:
|
||||
|
||||
RandomRun with_sorted(Chunk c) const
|
||||
{
|
||||
Vector<u32> new_data = m_data;
|
||||
Vector<u64> new_data = m_data;
|
||||
AK::dual_pivot_quick_sort(
|
||||
new_data,
|
||||
c.index,
|
||||
@ -95,13 +95,13 @@ public:
|
||||
}
|
||||
RandomRun with_deleted(Chunk c) const
|
||||
{
|
||||
Vector<u32> new_data(m_data);
|
||||
Vector<u64> new_data(m_data);
|
||||
new_data.remove(c.index, c.size);
|
||||
return RandomRun(move(new_data));
|
||||
}
|
||||
|
||||
private:
|
||||
Vector<u32> m_data;
|
||||
Vector<u64> m_data;
|
||||
size_t m_current_index = 0;
|
||||
};
|
||||
|
||||
|
@ -26,11 +26,11 @@ public:
|
||||
static RandomnessSource live() { return RandomnessSource(RandomRun(), true); }
|
||||
static RandomnessSource recorded(RandomRun const& run) { return RandomnessSource(run, false); }
|
||||
RandomRun& run() { return m_run; }
|
||||
u32 draw_value(u32 max, Function<u32()> random_generator)
|
||||
u64 draw_value(u64 max, Function<u64()> random_generator)
|
||||
{
|
||||
// Live: use the random generator and remember the value.
|
||||
if (m_is_live) {
|
||||
u32 value = random_generator();
|
||||
u64 value = random_generator();
|
||||
m_run.append(value);
|
||||
return value;
|
||||
}
|
||||
|
@ -77,15 +77,15 @@ ShrinkResult keep_if_better(RandomRun const& new_run, RandomRun const& current_b
|
||||
}
|
||||
|
||||
template<typename Fn, typename UpdateRunFn>
|
||||
ShrinkResult binary_shrink(u32 orig_low, u32 orig_high, UpdateRunFn update_run, RandomRun const& orig_run, Fn const& test_function)
|
||||
ShrinkResult binary_shrink(u64 orig_low, u64 orig_high, UpdateRunFn update_run, RandomRun const& orig_run, Fn const& test_function)
|
||||
{
|
||||
if (orig_low == orig_high) {
|
||||
return no_improvement(orig_run);
|
||||
}
|
||||
|
||||
RandomRun current_best = orig_run;
|
||||
u32 low = orig_low;
|
||||
u32 high = orig_high;
|
||||
u64 low = orig_low;
|
||||
u64 high = orig_high;
|
||||
|
||||
// Let's try with the best case (low = most shrunk) first
|
||||
RandomRun run_with_low = update_run(low, current_best);
|
||||
@ -111,7 +111,7 @@ ShrinkResult binary_shrink(u32 orig_low, u32 orig_high, UpdateRunFn update_run,
|
||||
// pass/reject/overrun.
|
||||
ShrinkResult result = after_low;
|
||||
while (low + 1 < high) {
|
||||
u32 mid = low + (high - low) / 2;
|
||||
u64 mid = low + (high - low) / 2;
|
||||
RandomRun run_with_mid = update_run(mid, current_best);
|
||||
ShrinkResult after_mid = keep_if_better(run_with_mid, current_best, test_function);
|
||||
switch (after_mid.was_improvement) {
|
||||
@ -194,7 +194,7 @@ ShrinkResult shrink_delete(DeleteChunkAndMaybeDecPrevious command, RandomRun con
|
||||
template<typename Fn>
|
||||
ShrinkResult shrink_minimize(MinimizeChoice command, RandomRun const& run, Fn const& test_function)
|
||||
{
|
||||
u32 value = run[command.index];
|
||||
u64 value = run[command.index];
|
||||
|
||||
// We can't minimize 0! Already the best possible case.
|
||||
if (value == 0) {
|
||||
@ -204,7 +204,7 @@ ShrinkResult shrink_minimize(MinimizeChoice command, RandomRun const& run, Fn co
|
||||
return binary_shrink(
|
||||
0,
|
||||
value,
|
||||
[&](u32 new_value, RandomRun const& run) {
|
||||
[&](u64 new_value, RandomRun const& run) {
|
||||
RandomRun copied_run = run;
|
||||
copied_run[command.index] = new_value;
|
||||
return copied_run;
|
||||
@ -236,12 +236,12 @@ ShrinkResult shrink_redistribute(RedistributeChoicesAndMaybeInc command, RandomR
|
||||
|
||||
ShrinkResult after_swap = keep_if_better(run_after_swap, current_best, test_function);
|
||||
current_best = after_swap.run;
|
||||
u32 constant_sum = current_best[command.right_index] + current_best[command.left_index];
|
||||
u64 constant_sum = current_best[command.right_index] + current_best[command.left_index];
|
||||
|
||||
ShrinkResult after_redistribute = binary_shrink(
|
||||
0,
|
||||
current_best[command.left_index],
|
||||
[&](u32 new_value, RandomRun const& run) {
|
||||
[&](u64 new_value, RandomRun const& run) {
|
||||
RandomRun copied_run = run;
|
||||
copied_run[command.left_index] = new_value;
|
||||
copied_run[command.right_index] = constant_sum - new_value;
|
||||
@ -275,7 +275,7 @@ ShrinkResult shrink_redistribute(RedistributeChoicesAndMaybeInc command, RandomR
|
||||
ShrinkResult after_inc_redistribute = binary_shrink(
|
||||
0,
|
||||
current_best[command.left_index],
|
||||
[&](u32 new_value, RandomRun const& run) {
|
||||
[&](u64 new_value, RandomRun const& run) {
|
||||
RandomRun copied_run = run;
|
||||
copied_run[command.left_index] = new_value;
|
||||
copied_run[command.right_index] = constant_sum - new_value;
|
||||
|
Loading…
Reference in New Issue
Block a user