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 @@ -2760,6 +2760,21 @@ whatever `a` is ([#718](https://github.com/asc-community/AngouriMath/issues/718)
| `"sqrt(a + i*a*sinh(g + f*x))/x".ToEntity().Integrate("x")` | `integral(...)` | `Shi` and `Chi` of half of `f x` |
| `"1/sqrt(a + i*a*sinh(g + f*x))".ToEntity().Integrate("x")` | `integral(...)` | arctangents and logarithms of `e^((g + f x)/2)` |

### A quadratic with an even root of a symbol among its coefficients is integrated where the root is imaginary

**Answers where there were none.** `1/(b (c + d x)^2 + sqrt(-a))` was answered by arms on the sign
of its discriminant `4 sqrt(-a) b d^2`, which is imaginary for every `a > 0` and has no sign there,
so the answer had a value for no positive `a`. The arm off the real line that a quadratic with `i`
among its coefficients takes, the arctangent, which uses nothing about its root but
`sqrt(q)^2 = q`, is taken where an even root of a symbol is among them too. An odd root is real
here and a root seen only squared leaves the discriminant real, so neither takes it. Rubi's 1.3.1
([#233](https://github.com/asc-community/AngouriMath/issues/233)).

| Input | Was (2.5.0) | Now |
|---|---|---|
| `"1/(b*(c + d*x)^2 + sqrt(-a))".ToEntity().Integrate("x")` | 920 characters, with no value at a real `x` for `a = 1.07` or `a = -1.3`; 570, with none for `a > 0`, on the unreleased master | 608 characters, the arctangent `provided not D in RR or D > 0` |
| `"1/(x^2 + sqrt(a))".ToEntity().Integrate("x")` | 297 characters, with no value at a real `x` for `a = 1.07` or `a = -1.3`; 261, with none for `a < 0`, on the unreleased master | 286 characters |

### The arm for a quadratic off the real line excludes the arms on the sign of its discriminant

**Shorter answers.** An antiderivative over a quadratic with `i` among its coefficients has an arm
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -819,8 +819,8 @@ private static Entity IntegrateOverRootOfQuadratic(
/// <summary>
/// The arm that a piecewise on a sign owes a quadratic off the real line, answered by
/// <paramref name="form"/> wherever one of <paramref name="coefficients"/> is not real;
/// <see langword="null"/> where none of them holds the imaginary unit, and the sign arms
/// are left to decide.
/// <see langword="null"/> where none of them holds the imaginary unit or an even root of a
/// symbol, and the sign arms are left to decide.
/// </summary>
/// <remarks>
/// The sign arms choose between forms by which is real where the integrand is, and off
Expand All @@ -834,18 +834,43 @@ private static Entity IntegrateOverRootOfQuadratic(
/// came back as minus its integrand below -2. The arctangent and the logarithm use nothing about their root but
/// <c>sqrt(q)^2 = q</c>, and are antiderivatives off the real line as well.
/// https://github.com/asc-community/AngouriMath/issues/1598
/// <para>
/// An even root of a symbol leaves the real line as the imaginary unit does, on half of the
/// symbol's values: <c>1/(b (c + d x)^2 + sqrt(-a))</c> has the discriminant
/// <c>4 sqrt(-a) b d^2</c>, imaginary for every <c>a &gt; 0</c>, and was answered with
/// nothing there, an antiderivative of a function with one. Rubi's 1.3.1. An odd root is
/// real here, <c>(-8)^(1/3) = -2</c>, and is left to the sign arms, and so is a root seen
/// only squared: the discriminant of <c>a b - b^2 x^2 - x sqrt(b^2 - 4 a b^3)</c> holds
/// <c>sqrt(b^2 - 4 a b^3)^2</c>, and is real.
/// https://github.com/asc-community/AngouriMath/issues/233
/// </para>
/// </remarks>
private static Entity.Providedf? ArmOffTheRealLine(Entity form, params Entity[] coefficients)
{
Entity? offTheRealLine = null;
foreach (var coefficient in coefficients)
if (coefficient.InnerSimplified.Nodes.Any(node => node is Entity.Number.Complex number && !number.ImaginaryPart.EDecimal.IsZero))
{
var simplified = coefficient.InnerSimplified;
if (simplified.Nodes.Any(node => node is Entity.Number.Complex number && !number.ImaginaryPart.EDecimal.IsZero)
|| AnEvenRootOfASymbolNotSquared(simplified))
offTheRealLine = offTheRealLine is null
? !coefficient.In(AngouriMath.Core.Domain.Real)
: offTheRealLine | !coefficient.In(AngouriMath.Core.Domain.Real);
}
return offTheRealLine is null ? null : new Entity.Providedf(form, offTheRealLine);
}

// An even root of something with a symbol in it, anywhere but as the base of an even power.
private static bool AnEvenRootOfASymbolNotSquared(Entity expr) => expr switch
{
Entity.Powf(var root, Entity.Number.Integer { EInteger.IsEven: true }) when IsAnEvenRootOfASymbol(root) => false,
_ when IsAnEvenRootOfASymbol(expr) => true,
_ => expr.DirectChildren.Any(AnEvenRootOfASymbolNotSquared),
};

private static bool IsAnEvenRootOfASymbol(Entity expr)
=> expr is Entity.Powf(var radicand, Entity.Number.Rational { ERational.Denominator.IsEven: true }) && radicand.Vars.Any();

/// <summary>
/// ∫ (px + q)/(ax^2 + bx + c) dx, by writing the numerator as a multiple of the
/// denominator's derivative plus a constant:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//
// 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;
using AngouriMath.Extensions;
using Xunit;

namespace AngouriMath.Tests.Calculus
{
/// <summary>
/// A quadratic with an even root of a symbol among its coefficients is off the real line on
/// half of that symbol's values, as one with <c>i</c> in it is, and takes the arm there:
/// <c>1/(b (c + d x)^2 + sqrt(-a))</c> has the discriminant <c>4 sqrt(-a) b d^2</c>, which has no
/// sign for <c>a &gt; 0</c>, and the answer had no value for any positive <c>a</c>. Rubi's 1.3.1.
/// <a href="https://github.com/asc-community/AngouriMath/issues/233">#233</a>
/// </summary>
[Trait("Area", "Calculus")]
public sealed class AnEvenRootOfASymbolInAQuadraticIntegralTest
{
[Theory]
[InlineData("1/(b*(c + d*x)^2 + sqrt(-a))", "1.3")]
[InlineData("1/(b*(c + d*x)^2 + sqrt(-a))", "-1.3")]
[InlineData("1/(x^2 + sqrt(a))", "1.3")]
[InlineData("1/(x^2 + sqrt(a))", "-1.3")]
[InlineData("x/(x^2 + x + sqrt(a))", "-1.3")]
public void DifferentiatesBackOnEitherSideOfTheRoot(string integrand, string a)
{
var integral = integrand.ToEntity().Integrate("x");
Assert.DoesNotContain("integral(", integral.Stringize());
Entity Pinned(Entity e) => e.Substitute("a", a.ToEntity()).Substitute("b", 0.7).Substitute("c", 0.4).Substitute("d", 0.3);
var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x");
var original = Pinned(integrand.ToEntity());
var compared = 0;
foreach (var at in new[] { -1.7, -0.6, 0.3, 0.8, 1.3, 2.9 })
{
var want = original.Substitute("x", at).EvalNumerical();
if (want.IsNaN)
continue;
var got = derivative.Substitute("x", at).EvalNumerical();
compared++;
var size = Math.Max(1, Math.Abs((double)want.RealPart) + Math.Abs((double)want.ImaginaryPart));
Assert.True(Math.Abs((double)(got - want).RealPart) + Math.Abs((double)(got - want).ImaginaryPart) < 1e-9 * size,
$"d/dx of the antiderivative of {integrand} at a = {a} is {got} at x = {at}, where the integrand is {want}");
}
Assert.True(compared >= 5, $"only {compared} points could be compared for {integrand} at a = {a}");
}

// An odd root is real here, (-8)^(1/3) = -2, and leaves the arms on the sign as they were.
[Fact]
public void AnOddRootTakesNoArmOffTheRealLine()
=> Assert.DoesNotContain("in RR", "1/(x^2 + a^(1/3))".ToEntity().Integrate("x").Stringize());
}
}
Loading