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
Original file line number Diff line number Diff line change
Expand Up @@ -23250,6 +23250,12 @@ bool MayBeARootOfASquare(Entity node, Entity.Variable x)
&& (Mulf.LinearChildren(rest).Where(part => part.ContainsNode(x)).ToList() is not [Sumf or Minusf]
|| Sumf.LinearChildren(rest).All(term => PowerOfX(term, x) is (_, Number.Integer { EInteger: var degree }) && degree.CompareTo(1) <= 0 && degree.Sign >= 0)))
continue;
// The rest of the integrand a constant times the sum's derivative is the plain
// substitution's, u = the sum, which answers it as a power of u, where the sum
// with x taken out is a search: `(x - 3 sqrt(x))^(2/3) (2 sqrt(x) - 3)/sqrt(x)`
// was answered in a fifth of a second before this rule and not in twenty after.
if (IsAConstantTimesTheDerivativeOf(side == above ? expr / factor : expr * factor, sum, x))
continue;
// Two such would want two factors.
if (found is { })
return null;
Expand Down Expand Up @@ -31557,6 +31563,44 @@ node is Powf(var radicand, Number.Rational { IsNegative: true } negative) && neg
return null;
}

/// <summary>
/// Whether <paramref name="rest"/> is a nonzero constant times the derivative of
/// <paramref name="sum"/>: their quotient one number at three positive points, every other
/// symbol pinned, agreeing to nine digits relative to its size. Positive points, since a
/// fractional power of x is real there; a point where either side cannot be evaluated
/// answers no.
/// </summary>
private static bool IsAConstantTimesTheDerivativeOf(Entity rest, Entity sum, Entity.Variable x)
{
var derivative = sum.Differentiate(x);
var pinned = new Dictionary<Variable, Entity>();
var values = new[] { 1.37, 0.61, 2.23, 1.91, 0.83, 1.13 };
var index = 0;
foreach (var symbol in rest.Vars.Concat(sum.Vars).Distinct())
if (symbol != x)
pinned[symbol] = values[index++ % values.Length];
Number.Complex? At(Entity function, double point)
{
var value = function.Substitute(x, point);
foreach (var pair in pinned)
value = value.Substitute(pair.Key, pair.Value);
return value.Evaled is Number.Complex { IsNaN: false } number && number.IsFinite && !number.IsZero ? number : null;
}
Number.Complex? first = null;
foreach (var point in new[] { 0.37, 1.71, 2.93 })
{
if (At(rest, point) is not { } above || At(derivative, point) is not { } below)
return false;
var ratio = (Number.Complex)(above / below);
var size = ((Number.Real)ratio.Abs()).EDecimal.ToDouble();
if (!(size > 1e-12 && size < 1e12)
|| first is { } earlier && ((Number.Real)(ratio - earlier).Abs()).EDecimal.ToDouble() > 1e-9 * size)
return false;
first ??= ratio;
}
return true;
}

/// <summary>
/// <paramref name="above"/>/<paramref name="below"/>, two polynomials in <paramref name="x"/>,
/// as a constant, or <see langword="null"/> where one is not a constant multiple of the
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//
// 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 fractional power of a sum beside a constant times the sum's derivative is the plain
/// substitution's, <c>u</c> = the sum, and the power of x is not taken out of it first:
/// <c>(x - 3 sqrt(x))^(2/3) (2 sqrt(x) - 3)/sqrt(x)</c> is <c>2 u^(2/3) du</c>. 2.5.0 answered it
/// in a fifth of a second; with the power of x taken out it was not answered in twenty. Rubi's 1.3.2.
/// <a href="https://github.com/asc-community/AngouriMath/issues/718">#718</a>
/// </summary>
[Trait("Area", "Calculus")]
public sealed class ASumBesideItsDerivativeKeepsItsPowerOfXIntegralTest
{
[Theory]
[InlineData("(x - 3*sqrt(x))^(2/3)*(-3 + 2*sqrt(x))/sqrt(x)")]
[InlineData("(2*x + 3*b*x^2)*(x^2 + b*x^3)^(1/2)")]
public void BySubstitutingTheSum(string integrand)
{
var integral = integrand.ToEntity().Integrate("x");
var text = integral.Stringize();
Assert.DoesNotContain("integral(", text);
Assert.True(text.Length < 5000, $"{text.Length} characters of answer for {integrand}");
Entity Pinned(Entity e) => e.Substitute("b", 0.7);
var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x");
var original = Pinned(integrand.ToEntity());
var compared = 0;
foreach (var at in new[] { 0.3, 0.8, 1.3, 2.9, 11.3, 15.1 })
{
var want = original.Substitute("x", at).EvalNumerical();
var got = derivative.Substitute("x", at).EvalNumerical();
if (want.IsNaN)
continue;
compared++;
Assert.True(Math.Abs((double)(got - want).RealPart) + Math.Abs((double)(got - want).ImaginaryPart)
< 1e-9 * Math.Max(1, Math.Abs((double)want.RealPart) + Math.Abs((double)want.ImaginaryPart)),
$"d/dx of the antiderivative of {integrand} is {got} at x = {at}, where the integrand is {want}");
}
Assert.True(compared >= 5, $"only {compared} points could be compared for {integrand}");
}
}
}
Loading