Skip to content

Commit 729ccdb

Browse files
authored
šŸŒ #46 Improve the bounds scaling algorithm by discretely picking interesting bounds as the size increases (#76)
1 parent b3fc346 commit 729ccdb

File tree

138 files changed

+32136
-17162
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

138 files changed

+32136
-17162
lines changed

ā€Ž.gitattributes

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Set the default behavior, in case people don't have core.autocrlf set.
2+
* text=auto
3+
4+
# Explicitly declare text files you want to always be normalized and converted
5+
# to native line endings on checkout.
6+
*.cs text
7+
*.cshtml text
8+
*.js text
9+
*.css text
10+
*.json text
11+
*.config text
12+
*.md text
13+
*.snap text
14+
15+
# Declare files that will always have CRLF line endings on checkout.
16+
*.sln text eol=crlf
17+
*.csproj text eol=crlf
18+
*.xproj text eol=crlf
19+
*.ps1 text eol=crlf
20+
*.sql text eol=crlf
21+
*.sh text eol=lf
22+
swagger-spec.yaml text eol=lf
23+
24+
# Denote all files that are truly binary and should not be modified.
25+
*.png binary
26+
*.jpg binary
27+
*.svg binary
28+
29+
*.pdf filter=lfs diff=lfs merge=lfs -text
30+
*.zip filter=lfs diff=lfs merge=lfs -text
31+
*.dll filter=lfs diff=lfs merge=lfs -text
32+
*.exe filter=lfs diff=lfs merge=lfs -text
33+
*.dacpac filter=lfs diff=lfs merge=lfs -text
34+
*.lgp filter=lfs diff=lfs merge=lfs -text
35+
*.swf filter=lfs diff=lfs merge=lfs -text
36+
*.rar filter=lfs diff=lfs merge=lfs -text
37+
*.chm filter=lfs diff=lfs merge=lfs -text
38+
*.flv filter=lfs diff=lfs merge=lfs -text
39+
*.pkg filter=lfs diff=lfs merge=lfs -text
40+
*.dmg filter=lfs diff=lfs merge=lfs -text
41+
*.db filter=lfs diff=lfs merge=lfs -text
42+
*.ap_ filter=lfs diff=lfs merge=lfs -text
43+
*.apk filter=lfs diff=lfs merge=lfs -text

ā€Žsrc/GalaxyCheck.Tests/Sizing/BoundsScalingFunc/AboutScaledExponentially.cs

-67
This file was deleted.

ā€Žsrc/GalaxyCheck.Tests/Sizing/BoundsScalingFunc/AboutScaledLinearly.cs

-77
This file was deleted.

ā€Žsrc/GalaxyCheck.Tests/Sizing/BoundsScalingFunc/AboutUnscaled.cs

-27
This file was deleted.

ā€Žsrc/GalaxyCheck/Gens/Int32Gen.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ private static StatefulGenFunc<int> CreateUnbiasedStatefulGen(int min, int max)
159159

160160
private static StatefulGenFunc<int> CreateBiasedStatefulGen(int min, int max, int origin)
161161
{
162-
var getBounds = BoundsScalingFactoryFuncs.ScaledExponentially(min, max, origin);
162+
var getBounds = BoundsScalingFactoryFuncs.ScaledExponentiallyWithDiscreteIntervals(min, max, origin);
163163
int? extremeMinimum = min == origin ? null : min;
164164
int? extremeMaximum = max == origin ? null : max;
165165

Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
ļ»æusing System;
2+
using System.Collections.Generic;
3+
using System.Collections.Immutable;
4+
using System.Linq;
25

36
namespace GalaxyCheck.Internal.Sizing
47
{
@@ -8,61 +11,111 @@ namespace GalaxyCheck.Internal.Sizing
811

912
public static class BoundsScalingFactoryFuncs
1013
{
11-
public static BoundsScalingFactoryFunc Unscaled => (min, max, origin) => (size) =>
14+
public static BoundsScalingFactoryFunc ScaledExponentiallyWithDiscreteIntervals => (min, max, origin) =>
1215
{
13-
return (min, max);
14-
};
16+
static Dictionary<Size, int> GetBoundsBySize(int from, int to)
17+
{
18+
var discreteBounds = GetIntervals(from, to).Select(interval => IntervalToBound(from, to, interval));
19+
return InterpolateBoundOverSizes(discreteBounds.ToImmutableList());
20+
}
1521

16-
public static BoundsScalingFactoryFunc ScaledLinearly => (min, max, origin) => (size) =>
17-
{
18-
if (size.Value == Size.MinValue.Value) return (origin, origin);
19-
if (size.Value == Size.MaxValue.Value) return (min, max);
22+
var leftIntervals = GetBoundsBySize(origin, min);
23+
var rightIntervals = GetBoundsBySize(origin, max);
2024

21-
return (ScaleLinear(min, origin, size), ScaleLinear(origin, max, size));
25+
return (size) => (leftIntervals[size], rightIntervals[size]);
2226
};
2327

24-
public static BoundsScalingFactoryFunc ScaledExponentially => (min, max, origin) => (size) =>
28+
private static Func<int, int> Interpolate(int x1, int y1, int x2, int y2) => (x) =>
2529
{
26-
if (size.Value == Size.MinValue.Value) return (origin, origin);
27-
if (size.Value == Size.MaxValue.Value) return (min, max);
28-
29-
return (ScaleExponential(min, origin, size), ScaleExponential(origin, max, size));
30+
return (int)(y1 + (x - x1) * ((double)(y2 - y1) / (x2 - x1)));
3031
};
3132

32-
private static int ScaleLinear(int from, int to, Size size)
33+
private static int IntervalToBound(int from, int to, uint interval)
3334
{
34-
var width = CalculateWidthSafe(from, to);
35-
var multiplier = (double)size.Value / Size.MaxValue.Value;
36-
var scaledWidth = (int)Math.Round(width * multiplier);
37-
38-
return from < 0
39-
? to > from ? to - scaledWidth : to + scaledWidth
40-
: to > from ? from + scaledWidth : from - scaledWidth;
35+
if (to > from)
36+
{
37+
return (int)(from + interval);
38+
}
39+
else
40+
{
41+
return (int)(from - interval);
42+
}
4143
}
4244

43-
private static int ScaleExponential(int from, int to, Size size)
45+
private static uint CalculateWidthSafe(int from, int to)
4446
{
45-
var width = CalculateWidthSafe(from, to);
46-
var exponent = ((double)size.Value / Size.MaxValue.Value) - 1;
47-
var multiplier = Math.Pow(Size.MaxValue.Value, exponent);
48-
var scaledWidth = (int)Math.Round(width * multiplier);
47+
var fromSign = Math.Sign(from);
48+
var toSign = Math.Sign(to);
49+
50+
if (fromSign >= 0 && toSign >= 0)
51+
{
52+
return SafeNegate(to - from);
53+
}
54+
else if (toSign <= 0 && fromSign <= 0)
55+
{
56+
return SafeNegate(to - from);
57+
}
58+
else
59+
{
60+
var fromToZero = SafeNegate(from);
61+
var toToZero = SafeNegate(to);
62+
return fromToZero + toToZero;
63+
}
64+
}
4965

50-
return from < 0
51-
? to > from ? to - scaledWidth : to + scaledWidth
52-
: to > from ? from + scaledWidth : from - scaledWidth;
66+
private static uint SafeNegate(int x)
67+
{
68+
return x == int.MinValue ? (uint)(int.MaxValue) + 1 : (uint)Math.Abs(x);
5369
}
5470

55-
private static int CalculateWidthSafe(int from, int to)
71+
private static IEnumerable<uint> GetIntervals(int from, int to)
5672
{
57-
var unsignedWidth = to - from;
73+
const int MinimumIntervalCount = 6;
5874

59-
if (unsignedWidth == int.MinValue)
75+
var width = CalculateWidthSafe(from, to);
76+
var subMaxIntervals = WidthIntervals.Where(w => w < width).ToList();
77+
78+
foreach (var interval in subMaxIntervals)
6079
{
61-
// int.MinValue is -2147483648, which when negated, exceeds int.MaxValue (2147483647).
62-
return int.MaxValue;
80+
yield return interval;
6381
}
6482

65-
return Math.Abs(unsignedWidth);
83+
yield return width;
84+
85+
for (var i = subMaxIntervals.Count + 1; i < MinimumIntervalCount; i++)
86+
{
87+
yield return width;
88+
}
89+
}
90+
91+
private static readonly ImmutableList<uint> WidthIntervals = BaseWidthIntervals
92+
.Concat(ExponentialWidthIntervals)
93+
.Concat(AlmostMaxIntervals)
94+
.Concat(new[] { uint.MaxValue })
95+
.ToImmutableList();
96+
97+
private static IEnumerable<uint> BaseWidthIntervals => new uint[] { 0, 1, 5 };
98+
99+
private static IEnumerable<uint> ExponentialWidthIntervals => new[] { 1, 2, 4, 8 }.Select(exponent => (uint)Math.Pow(10, exponent));
100+
101+
// These make the range from int.MinValue => int.MaxValue more interesting. The bound won't jump from < 0 to int.MaxValue.
102+
private static IEnumerable<uint> AlmostMaxIntervals => ImmutableList.Create(
103+
uint.MaxValue / 2,
104+
(uint.MaxValue / 4) * 3,
105+
(uint.MaxValue / 8) * 7);
106+
107+
private static Dictionary<Size, int> InterpolateBoundOverSizes(ImmutableList<int> bounds)
108+
{
109+
var interpolate = Interpolate(0, 0, 100, bounds.Count - 1);
110+
111+
return Enumerable.Range(0, 101).ToDictionary(
112+
size => new Size(size),
113+
size =>
114+
{
115+
var interpolatedIndex = interpolate(size);
116+
var boundIndex = size == 0 ? 0 : Math.Min(interpolatedIndex + 1, bounds.Count - 1);
117+
return bounds[boundIndex];
118+
});
66119
}
67120
}
68121
}

ā€Žtests/GalaxyCheck.Tests.V2/GalaxyCheck.Tests.V2.csproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
<PackageReference Include="FluentAssertions" Version="5.10.3" />
1313
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
1414
<PackageReference Include="Moq" Version="4.16.1" />
15-
<PackageReference Include="NebulaCheck" Version="0.0.0-638618715" />
16-
<PackageReference Include="NebulaCheck.Xunit" Version="0.0.0-638618715" />
15+
<PackageReference Include="NebulaCheck" Version="0.0.0-642201967" />
16+
<PackageReference Include="NebulaCheck.Xunit" Version="0.0.0-642201967" />
1717
<PackageReference Include="Snapshooter.Xunit" Version="0.5.8" />
1818
<PackageReference Include="xunit" Version="2.4.1" />
1919
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">

0 commit comments

Comments
Ā (0)