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
17 changes: 17 additions & 0 deletions BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,23 @@ arctangent of something real, and an arcsine and an arccosine inside (-1, 1). Wh
| `"sqrt(x^2)^(-3/2)".ToEntity().Limit("x", 0)` | `NaN` | `+oo` |
| `"sin(arcsin(x)) * (tan(-1) + 2/x)".ToEntity().Limit("x", 0)` | `NaN` | `2` |

### A limit over a vanishing even power is not claimed not to exist

**Silent: `1/((x^2)^tanh(1))` at 0 is `+oo`, where it was `NaN`, the claim that the limit does not exist.** A base
was read as never negative only for an absolute value, or a real power, product or quotient of never-negative parts,
so `x^2` was not. A vanishing power of it to a constant that is not a number, or to an exponent tending to a negative
number, was left unevaluated from each side, and the two-sided limit was `NaN`. An even power of a base real for
real `x` is now never negative. `1/(((i*x)^2)^tanh(1))`, whose base is `-x^2`, is still not answered.

| Input | Was (2.6.0) | Now |
|---|---|---|
| `"1/((x^2)^tanh(1))".ToEntity().Limit("x", 0)` | `NaN` | `+oo` |
| `"1/((x^2)^tanh(1))".ToEntity().Limit("x", 0, ApproachFrom.Right)` | `limitright(1 / (x ^ 2) ^ ((e ^ (2 * 1) - 1) / (e ^ (2 * 1) + 1)), x, 0)` | `+oo` |
| `"(sinh(x)^2)^(sin(x) - 1)".ToEntity().Limit("x", 0)` | `NaN` | `+oo` |
| `"(sinh(x)^2)^(sin(x) - 1)".ToEntity().Limit("x", 0, ApproachFrom.Right)` | `limitright((((e ^ x - e ^ (-x)) / 2) ^ 2) ^ (sin(x) - 1), x, 0)` | `+oo` |
| `"sqrt(x^2)^tan(pi - 1)".ToEntity().Limit("x", 0)` | `NaN` | `+oo` |
| `"sqrt(x^2)^tan(pi - 1)".ToEntity().Limit("x", 0, ApproachFrom.Right)` | `limitright((sqrt(x ^ 2)) ^ tan(pi - 1), x, 0)` | `+oo` |

### An equation in two different square roots is solved exactly

**Silent: an equation `m_1 sqrt(A) + m_2 sqrt(B) + P = 0` in x alone, with two different square roots, is answered in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ partial record Powf
// was left unevaluated from each side for it. Where the base vanishes, it does from
// above.
if (baseLimit?.Evaled is Real { IsZero: true } && exponentLimit?.Evaled is Real { IsNegative: true, IsFinite: true }
&& IsNeverNegative(Base))
&& IsNeverNegative(Base, x))
return Real.PositiveInfinity;
var substituted =
(baseLimit, exponentLimit)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ bool RealThere(Entity node)
// reads off the form, an even power of something real, and a real power that is itself
// real -- sqrt(x^2), whose base vanishes at 0 and is not positive there.
bool NotNegativeThere(Entity node)
=> IsNeverNegative(node)
=> IsNeverNegative(node, x)
|| node is Powf(var @base, Integer { EInteger.IsEven: true }) && RealThere(@base)
|| node is Powf(_, not Integer) && RealThere(node);
bool StrictlyInsideTheUnitInterval(Entity node)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1102,7 +1102,7 @@ internal static bool IsDeterminate(Entity combined, Variable x)
// https://github.com/asc-community/AngouriMath/issues/2274
if (EvalAssumingContinuous(dividend.Limit(x, dest, side)) is not Real { IsZero: false, IsNaN: false } dividendLimit)
return null;
if ((IsNeverNegative(divisor) ? 1 : SignFromVanishingOrder(divisor, x, dest, side)) is not { } divisorSign)
if ((IsNeverNegative(divisor, x) ? 1 : SignFromVanishingOrder(divisor, x, dest, side)) is not { } divisorSign)
return null;
return dividendLimit.IsNegative == divisorSign > 0
? Real.NegativeInfinity
Expand All @@ -1121,12 +1121,16 @@ internal static bool IsDeterminate(Entity combined, Variable x)
/// from each side and NaN from both, where it is +oo. Where such an expression vanishes
/// it does so from above, whatever its argument does.
/// </remarks>
internal static bool IsNeverNegative(Entity expr) => expr switch
internal static bool IsNeverNegative(Entity expr, Variable x) => expr switch
{
Absf => true,
Powf(var @base, var exponent) => IsNeverNegative(@base) && exponent.Evaled is Real { IsNaN: false },
Mulf(var multiplier, var multiplicand) => IsNeverNegative(multiplier) && IsNeverNegative(multiplicand),
Divf(var dividend, var divisor) => IsNeverNegative(dividend) && IsNeverNegative(divisor),
// An even power of something real: x^2, and sinh(x)^2, whose powers to a negative
// exponent were NaN at 0 from both sides for want of it. The base has to be real for
// real x, since sqrt(x)^2 is x.
Powf(var @base, Integer { EInteger.IsEven: true }) when TreeAnalyzer.IsRealValued(@base, x) => true,
Powf(var @base, var exponent) => IsNeverNegative(@base, x) && exponent.Evaled is Real { IsNaN: false },
Mulf(var multiplier, var multiplicand) => IsNeverNegative(multiplier, x) && IsNeverNegative(multiplicand, x),
Divf(var dividend, var divisor) => IsNeverNegative(dividend, x) && IsNeverNegative(divisor, x),
_ when expr.Evaled is Real { IsNegative: false, IsNaN: false } => !expr.FreeVariables.Any(),
_ => false
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// 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 AngouriMath.Core;
using Xunit;

namespace AngouriMath.Tests.Calculus
{
/// <summary>
/// <c>1/((x^2)^tanh(1))</c> at 0 was NaN -- the claim that the limit does not exist -- where it is +oo from both sides.
/// A base was read as never negative only for an absolute value, or a power, product or quotient of never-negative
/// parts, so <c>x^2</c> was not, and a vanishing power of it to a constant that is not a number, or to an exponent
/// tending to a negative number, as <c>(sinh(x)^2)^(sin(x) - 1)</c>, was left unevaluated from each side. An even
/// power of a base real for real <c>x</c> is never negative now. The same on 2.6.0. Found by limitcheck at
/// <c>DEPTH=3</c>, <c>SEED=36</c>, and <c>sqrt(x^2)^tan(pi - 1)</c> at
/// <c>SEED=29</c>; no issue was filed.
/// </summary>
[Trait("Area", "Calculus")]
public sealed class AnEvenPowerVanishesFromAboveTest
{
[Theory]
[InlineData("1/((x^2)^tanh(1))", "0", "+oo")]
[InlineData("-1/((x^2)^tanh(1))", "0", "-oo")]
[InlineData("(sinh(x)^2)^(sin(x) - 1)", "0", "+oo")]
[InlineData("((x - 1)^2)^(-pi/4)", "1", "+oo")]
[InlineData("(sin(x)^4)^(-tanh(1))", "0", "+oo")]
[InlineData("sqrt(x^2)^tan(pi - 1)", "0", "+oo")]
public void IsTheLimitFromEachSideAndBoth(string input, string destination, string expected)
{
foreach (var side in new[] { ApproachFrom.Left, ApproachFrom.Right, ApproachFrom.BothSides })
Assert.Equal(MathS.FromString(expected), MathS.FromString(input).Limit("x", destination, side));
}

// (i x)^2 is -x^2, negative on both sides, so a power of it to an exponent that is not whole is not real there,
// and is not claimed to diverge to +oo.
[Fact]
public void AnEvenPowerOfSomethingNotRealIsNotClaimed()
=> Assert.NotEqual(MathS.FromString("+oo"),
MathS.FromString("1/(((i*x)^2)^tanh(1))").Limit("x", 0, ApproachFrom.Right));
}
}
Loading