Skip to content

Commit 004e3a4

Browse files
Simplify the intersection #415 actually asks for, and fix two wrong tests (#677)
Following up on the review of #666, where three of the tests I added were pinning something other than what the issue was about. #415. The screenshot in the issue is (-1; 1) /\ ((-(sqrt(33) + 3) / 6; (sqrt(33) - 3) / 6) \/ (1; +oo)) and it came back exactly as written. Two things were missing, and both are here: - An intersection did not distribute over a union, so nothing could be done with the right-hand side however simple each piece was. - IntersectIntervalAndInterval gave up unless every endpoint was a bare Real node. (sqrt(33) - 3) / 6 is a division, so it never was one. Endpoints are compared by what they evaluate to now, while the bounds of the answer are taken from the original expressions, so the result stays exact rather than becoming a hundred decimal places. It gives (-1; (sqrt(33) - 3) / 6). #424 was tested with `provided`, which is a Providedf. The issue is about the Piecewise node, which is a different one, so the test was not testing the issue. Rewritten with piecewise(), including a three-branch case to check the branches are taken in order. It passes -- the feature does work, my test simply did not exercise it. #263 asserted only that the limit came back. The limit is what the expression was written for, so its value is asserted: 167403915. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
1 parent 6642e56 commit 004e3a4

3 files changed

Lines changed: 55 additions & 24 deletions

File tree

‎Sources/AngouriMath/Core/Entity/Omni/Sets/SetOperators.Intersection.cs‎

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,21 @@ internal static Set IntersectIntervalAndInterval(Interval A, Interval B)
3030
{
3131
if (A.Left == B.Left && A.Right == B.Right)
3232
return new Interval(A.Left, A.LeftClosed && B.LeftClosed, A.Right, A.RightClosed && B.RightClosed);
33-
if (A.Left is not Real aLeft ||
34-
A.Right is not Real aRight ||
35-
B.Left is not Real bLeft ||
36-
B.Right is not Real bRight)
33+
// Compared by what the endpoints are worth, not by whether they are written as
34+
// bare numbers. (sqrt(33) - 3) / 6 is a Divf and never a Real, so an interval
35+
// written with one was given up on -- which is
36+
// https://github.com/asc-community/AngouriMath/issues/415. The bounds of the result
37+
// are taken from the original expressions, so the answer keeps them exact
38+
// rather than turning them into a hundred decimal places.
39+
if (A.Left.Evaled is not Real aLeft ||
40+
A.Right.Evaled is not Real aRight ||
41+
B.Left.Evaled is not Real bLeft ||
42+
B.Right.Evaled is not Real bRight)
3743
return A.Intersect(B);
3844
if (aLeft == bRight)
39-
return A.LeftClosed && B.RightClosed ? new FiniteSet(aLeft) : Empty;
45+
return A.LeftClosed && B.RightClosed ? new FiniteSet(A.Left) : Empty;
4046
if (bLeft == aRight)
41-
return A.RightClosed && B.LeftClosed ? new FiniteSet(bLeft) : Empty;
47+
return A.RightClosed && B.LeftClosed ? new FiniteSet(B.Left) : Empty;
4248
if (aLeft >= aRight)
4349
return B;
4450
if (bLeft >= bRight)
@@ -49,12 +55,12 @@ B.Left is not Real bLeft ||
4955
return Empty;
5056
var (left, leftClosed) =
5157
aLeft == bLeft ?
52-
(aLeft, A.LeftClosed && B.LeftClosed) :
53-
(bLeft < aLeft ? (aLeft, A.LeftClosed) : (bLeft, B.LeftClosed));
58+
(A.Left, A.LeftClosed && B.LeftClosed) :
59+
(bLeft < aLeft ? (A.Left, A.LeftClosed) : (B.Left, B.LeftClosed));
5460
var (right, rightClosed) =
5561
aRight == bRight ?
56-
(aRight, A.RightClosed && B.RightClosed) :
57-
(bRight > aRight ? (aRight, A.RightClosed) : (bRight, B.RightClosed));
62+
(A.Right, A.RightClosed && B.RightClosed) :
63+
(bRight > aRight ? (A.Right, A.RightClosed) : (B.Right, B.RightClosed));
5864
return new Interval(left, leftClosed, right, rightClosed);
5965
}
6066

‎Sources/AngouriMath/Functions/Simplification/Patterns/Patterns.Sets.cs‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ internal static partial class Patterns
1818
internal static Entity SetOperatorRules(Entity x) => x switch
1919
{
2020
Intersectionf(var any1, var any1a) when any1 == any1a => any1,
21+
22+
// A /\ (B \/ C) = (A /\ B) \/ (A /\ C). Without this, an intersection whose
23+
// other side is a union is left as written however simple each piece is, which
24+
// is half of https://github.com/asc-community/AngouriMath/issues/415.
25+
Intersectionf(Set setA, Unionf(Set setB, Set setC)) =>
26+
setA.Intersect(setB).Unite(setA.Intersect(setC)),
27+
Intersectionf(Unionf(Set setB, Set setC), Set setA) =>
28+
setB.Intersect(setA).Unite(setC.Intersect(setA)),
2129
Unionf(var any1, var any1a) when any1 == any1a => any1,
2230
SetMinusf(var any1, var any1a) when any1 == any1a => Empty,
2331
ConditionalSet(var var1, Inf(var var1a, var set)) when var1 == var1a => set,

‎Sources/Tests/UnitTests/Common/AlreadyFixedIssuesTest.cs‎

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,15 @@ private static T Terminates<T>(System.Func<T> work, string what)
4444
[Fact]
4545
public void Issue263_InnerSimplifyTerminates() =>
4646
Terminates(() => Issue263Quotient.ToEntity().InnerSimplified,
47-
"InnerSimplify of the #263 quotient");
47+
"InnerSimplify of the quotient from https://github.com/asc-community/AngouriMath/issues/263");
4848

49+
// The limit is what the quotient was written for, so its value is asserted rather
50+
// than only that it comes back. Reported on the issue, this is 15*14/2 * 3^13.
4951
[Fact]
50-
public void Issue263_LimitTerminates() =>
51-
Terminates(() => Issue263Quotient.ToEntity().Limit("x", 3, ApproachFrom.Left),
52-
"the #263 limit");
52+
public void Issue263_LimitIsComputed() =>
53+
Assert.Equal(Entity.Number.Integer.Create(167403915),
54+
Terminates(() => Issue263Quotient.ToEntity().Limit("x", 3, ApproachFrom.Left).Simplify(),
55+
"the limit from https://github.com/asc-community/AngouriMath/issues/263"));
5356

5457
// https://github.com/asc-community/AngouriMath/issues/347
5558
// Taking a limit of a boolean expression overflowed the stack. It is still not
@@ -66,23 +69,37 @@ public void Issue362_CoefficientsAreCollected() =>
6669
Assert.Equal("(-2) * d * t", "(-1/2d-3/2d)t".ToEntity().Simplify().Stringize());
6770

6871
// https://github.com/asc-community/AngouriMath/issues/424
69-
// Piecewise was to become compileable.
72+
// Piecewise was to become compileable. These are piecewise() nodes: the earlier
73+
// version of this test used `provided`, which is a Providedf and a different node
74+
// altogether, so it was not testing the issue at all.
7075
[Theory]
71-
[InlineData("5 provided x = 3", 3.0, 5.0)]
72-
[InlineData("x provided true", 7.0, 7.0)]
73-
[InlineData("2 * x provided x > 0", 4.0, 8.0)]
76+
[InlineData("piecewise(2 * x provided x > 0, -x provided true)", 3.0, 6.0)]
77+
[InlineData("piecewise(2 * x provided x > 0, -x provided true)", -4.0, 4.0)]
78+
[InlineData("piecewise(1 provided x > 10, 2 provided x > 5, 3 provided true)", 12.0, 1.0)]
79+
[InlineData("piecewise(1 provided x > 10, 2 provided x > 5, 3 provided true)", 7.0, 2.0)]
80+
[InlineData("piecewise(1 provided x > 10, 2 provided x > 5, 3 provided true)", 1.0, 3.0)]
7481
public void Issue424_PiecewiseCompiles(string expression, double argument, double expected) =>
7582
Assert.Equal(expected, expression.ToEntity().Compile<double, double>("x")(argument), 9);
7683

7784
// https://github.com/asc-community/AngouriMath/issues/415
78-
// Intersections and unions of intervals were to be simplified.
85+
// The example in the issue's screenshot, which is what it asks for. It needed two
86+
// things: an intersection has to distribute over a union, and endpoints have to be
87+
// compared by what they are worth rather than by whether they are written as bare
88+
// numbers -- (sqrt(33) - 3) / 6 is a division and never a Real.
7989
[Fact]
80-
public void Issue415_IntervalsIntersect() =>
81-
Assert.Equal(@"[3; 5]".ToEntity(), @"[1; 5] /\ [3; 8]".ToEntity().Simplify());
90+
public void Issue415_TheScreenshottedExample() =>
91+
Assert.Equal(@"(-1; (sqrt(33) - 3) / 6)".ToEntity().Simplify(),
92+
@"(-1; 1) /\ (((-(sqrt(33) + 3) / 6; (sqrt(33) - 3) / 6) \/ (1; +oo)))"
93+
.ToEntity().Simplify());
8294

83-
[Fact]
84-
public void Issue415_IntervalsUnite() =>
85-
Assert.Equal(@"[1; 8]".ToEntity(), @"[1; 5] \/ [3; 8]".ToEntity().Simplify());
95+
[Theory]
96+
[InlineData(@"[1; 5] /\ [3; 8]", "[3; 5]")]
97+
[InlineData(@"[1; 5] \/ [3; 8]", "[1; 8]")]
98+
[InlineData(@"(-1; 1) /\ ((0; 3) \/ (5; 7))", "(0; 1)")]
99+
[InlineData(@"(-1; 1) /\ (-2; sqrt(2) / 4)", "(-1; sqrt(2) / 4)")]
100+
[InlineData(@"(-1; 1) /\ (1; +oo)", "{ }")]
101+
public void Issue415_IntervalsSimplify(string input, string expected) =>
102+
Assert.Equal(expected.ToEntity().Simplify(), input.ToEntity().Simplify());
86103

87104
// https://github.com/asc-community/AngouriMath/issues/550
88105
// The reporter's small system did not solve. The 25x26 one from the same report

0 commit comments

Comments
 (0)