Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,21 @@ is the canonical one: square-free, and without what the answer's own denominator
| `"(a - 1)/(1 - b) - (1 - a)/(b - 1)".Simplify()` | `0 provided not (b - 1) * (1 - b) = 0` | `0 provided not b - 1 = 0` |
| `"(x*y*a*b*c)/(c*b*a*x*x)".Simplify()` | `y / x provided not a * b * c * x = 0` | `y / x provided not a * b * c = 0` |

### A sine or cosine with no real radical form stays as written

**Silent: `sin(pi/7)`, `cos(2pi/9)` and the other values whose only radical form goes through the complex numbers
simplify to themselves, where they were nested radicals with cube roots of complex numbers.** That is casus
irreducibilis: no real radical form exists, and the radical was many times longer than the input. The table's
entries for the sevenths, ninths and eighteenths are passed over, and their half angles with them. A value with a
real radical form still takes it ([#2143](https://github.com/asc-community/AngouriMath/issues/2143)).

| Input | Was (2.6.0) | Now |
|---|---|---|
| `"sin(pi/7)".ToEntity().Simplify()` | `sqrt((1 - 1/6 * (-1 + ((7 + 21 * sqrt(-3)) / 2) ^ (1/3) + ((7 - 21 * sqrt(-3)) / 2) ^ (1/3))) / 2)` | `sin(pi / 7)` |
| `"cos(2 pi/9)".ToEntity().Simplify()` | `(((sqrt(-3) - 1) / 2) ^ (1/3) + (-(sqrt(-3) + 1) / 2) ^ (1/3)) / 2` | `cos(2/9 * pi)` |
| `"sin(pi/18)".ToEntity().Simplify()` | `sqrt((1 - 1/4 * ((4 + 4 * sqrt(-3)) ^ (1/3) + (4 - 4 * sqrt(-3)) ^ (1/3))) / 2)` | `sin(pi / 18)` |
| `"sin(pi/5)".ToEntity().Simplify()` | `1/4 * sqrt(10 - 2 * sqrt(5))` | `1/4 * sqrt(10 - 2 * sqrt(5))` |

### A step function at a jump takes the side its argument arrives from

**Silent: a limit of `floor`, `ceil` or `sgn` whose argument arrives on a jump is answered, where it was left
Expand Down
3 changes: 3 additions & 0 deletions Sources/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,9 @@ file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed
[Tests/UnitTests/Convenience/ArctangentPolesTest.cs]
file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed under MIT.\nDetails: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.\nWebsite: https://am.angouri.org.\n

[Tests/UnitTests/PatternsTest/CasusIrreducibilisTest.cs]
file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed under MIT.\nDetails: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.\nWebsite: https://am.angouri.org.\n

[Tests/UnitTests/Algebra/SolveTest/ModulusEquationTest.cs]
file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed under MIT.\nDetails: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.\nWebsite: https://am.angouri.org.\n

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ private static bool TryPulling(TrigTable table, Complex arg,

for (var j = begin; j <= end; j++)
{
if (Number.IsZero(table[j].arg - dArg))
if (Number.IsZero(table[j].arg - dArg) && !IsWrittenThroughTheComplexNumbers(table[j].res))
{
res = table[j].res;
return true;
Expand All @@ -62,6 +62,20 @@ private static bool TryPulling(TrigTable table, Complex arg,
return false;
}

/// <summary>
/// Whether a value is written through numbers that are not real: <c>i</c>, or a square root
/// of a negative number. Every angle here is real, so such a value is a real number whose
/// radical form needs the complex numbers, casus irreducibilis, and the function of its angle
/// is the shorter answer: <c>cos(2pi/7)</c> is
/// <c>(-1 + cbrt((7 + 21 sqrt(-3))/2) + cbrt((7 - 21 sqrt(-3))/2))/6</c>, and no real
/// radical form exists. <c>sin(pi/7)</c> simplified to the half-angle of it, many times
/// longer than the input. Such an entry is passed over rather than removed, so the closed form
/// stays on record. https://github.com/asc-community/AngouriMath/issues/2143
/// </summary>
private static bool IsWrittenThroughTheComplexNumbers(Entity value)
=> value.Nodes.Any(node => node is Complex and not Real
|| node is Powf(Real { IsNegative: true }, Rational { ERational.Denominator.IsEven: true }));

/// <summary>
/// Every angle in the tables below is written <c>2pi/n</c>, so they name nothing at
/// all between <c>2pi/5</c> and <c>2pi/3</c> -- the whole lower half of the circle
Expand Down
6 changes: 4 additions & 2 deletions Sources/Tests/UnitTests/Common/TrigonometricTableTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,10 @@ public void EveryExactValueAgreesWithTheCallItReplaces()
// the 1158 calls swept: 581 of them resolved before the half turn was applied
// and 690 after, and the 581 were already sound -- what was missing was missing,
// not wrong. Raise this if the table gains entries; it is here to catch losing
// them silently.
Assert.True(resolved >= 690, $"only {resolved} of the swept angles resolved at all");
// them silently. 642 since the entries written through the complex numbers, the
// sevenths, ninths and eighteenths and the half angles of them, are passed over and
// their calls left as written: https://github.com/asc-community/AngouriMath/issues/2143
Assert.True(resolved >= 642, $"only {resolved} of the swept angles resolved at all");
}

/// <summary>
Expand Down
54 changes: 54 additions & 0 deletions Sources/Tests/UnitTests/PatternsTest/CasusIrreducibilisTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//
// Copyright (c) 2019-2026 Angouri.
// AngouriMath is licensed under MIT.
// Details: https://github.com/asc-community/AngouriMath/blob/master/LICENSE.md.
// Website: https://am.angouri.org.
//

using System.Linq;
using AngouriMath;
using AngouriMath.Extensions;
using Xunit;
using static AngouriMath.Entity.Number;

namespace AngouriMath.Tests.PatternsTest
{
/// <summary>
/// A sine or cosine whose only radical form goes through the complex numbers, casus irreducibilis, stays as the
/// function of its angle. <c>sin(pi/7)</c> simplified to <c>sqrt((1 - 1/6 * (-1 + ((7 + 21 * sqrt(-3)) / 2) ^ (1/3) +
/// ((7 - 21 * sqrt(-3)) / 2) ^ (1/3))) / 2)</c>, many times longer than the input, and no real radical form exists.
/// <a href="https://github.com/asc-community/AngouriMath/issues/2143">#2143</a>
/// </summary>
[Trait("Area", "PatternsTest")]
public sealed class CasusIrreducibilisTest
{
[Theory]
[InlineData("sin(pi/7)")]
[InlineData("cos(pi/7)")]
[InlineData("cos(2 pi/7)")]
[InlineData("sin(4 pi/7)")]
[InlineData("sin(pi/9)")]
[InlineData("cos(2 pi/9)")]
[InlineData("sin(pi/18)")]
public void ItStaysAsWritten(string value)
{
var simplified = value.ToEntity().Simplify();
Assert.DoesNotContain(simplified.Nodes, node => node is Complex and not Real || node is Entity.Powf(_, Rational { ERational.Denominator.IsEven: false }));
Assert.True(simplified.Nodes.Count() <= value.ToEntity().Nodes.Count() + 2, simplified.Stringize());
var difference = (simplified - value.ToEntity()).EvalNumerical();
Assert.True(difference.Abs() < 1e-30, $"{simplified} differs from {value} by {difference}");
}

/// <summary>A value with a real radical form still takes it.</summary>
[Theory]
[InlineData("sin(pi/5)", "1/4 * sqrt(10 - 2 * sqrt(5))")]
[InlineData("sin(pi/3)", "sqrt(3) / 2")]
[InlineData("cos(2 pi/5)", "(sqrt(5) - 1) / 4")]
public void ARealRadicalIsStillTaken(string value, string expected)
=> Assert.Equal(expected, value.ToEntity().Simplify().Stringize());

[Fact]
public void TheIdentitiesStillHold()
=> Assert.Equal(Integer.One, "sin(pi/7)^2 + cos(pi/7)^2".ToEntity().Simplify());
}
}
Loading