@@ -14320,26 +14320,35 @@ static Entity Reduced(Entity constant)
1432014320 /// <summary>
1432114321 /// A polynomial times an odd half power of a linear over a whole power of a quadratic with
1432214322 /// a root at zero, <c>P(x) (d + e x)^(j/2)/(b x + c x^2)^m</c> with <c>j</c> odd and
14323- /// positive and <c>m >= 3</c>, under <c>t = sqrt(d + e x)</c> with the quadratic written
14324- /// as its two linears, <c>x (b + c x)</c>.
14325- /// </summary>
14326- /// <remarks>
14327- /// <para>
14328- /// With <c>x = (t^2 - d)/e</c>, <c>b + c x = (c t^2 + r)/e</c> for <c>r = b e - c d</c>, and
14329- /// <c>dx = 2 t dt/e</c>, the integrand is
14330- /// <c>2 e^(2m - 1) P((t^2 - d)/e) t^(j + 1)/((t^2 - d)^m (c t^2 + r)^m)</c>, and exactly so:
14331- /// <c>t^j</c> is <c>(d + e x)^(j/2)</c> for the principal root and every complex <c>x</c>.
14332- /// The two factors below the bar have the resultant <c>b e</c>, and a compound coefficient
14333- /// is named by a symbol of its own and written back into the answer, as in
14334- /// <see cref="SolveCubeRootsOfTwoLinearsBesideAWholePowerOfAThird"/>.
14335- /// </para>
14336- /// <para>
14337- /// Rubi's <c>(A + B x) (d + e x)^(j/2)/(b x + c x^2)^3</c> ran past the budget: the rational
14338- /// function in <c>t</c> is answered in a second, and the substitution that reaches it is
14339- /// late in the chain and multiplies the quadratic out. Only the root above the bar and a
14340- /// third power or higher, with a symbol to name: the root below the bar, the second power,
14341- /// and numbers for coefficients are answered as they are, and left to that. Declined where
14342- /// <c>d</c> or <c>r</c> is zero as a value, the linear then sharing a root with the quadratic.
14323+ /// positive and <c>m >= 2</c>, under <c>t = sqrt(d + e x)</c> with the quadratic written
14324+ /// as its two linears, <c>x (b + c x)</c>, and split over them.
14325+ /// </summary>
14326+ /// <remarks>
14327+ /// <para>
14328+ /// With <c>s = t^2</c>, <c>x = (s - d)/e</c>, <c>b + c x = c (s + rho)/e</c> for
14329+ /// <c>rho = r/c</c> and <c>r = b e - c d</c>, and <c>dx = 2 t dt/e</c>, the integrand is
14330+ /// <c>2 e^(2m - 1)/c^m N(s)/((s - d)^m (s + rho)^m)</c> with
14331+ /// <c>N(s) = s^((j + 1)/2) P((s - d)/e)</c>, and exactly so: <c>t^j</c> is
14332+ /// <c>(d + e x)^(j/2)</c> for the principal root and every complex <c>x</c>. That is its
14333+ /// quotient by the monic denominator, a polynomial in <c>s</c>, and its partial fractions
14334+ /// over <c>s - d</c> and <c>s + rho</c>, whose coefficients are those of the Taylor series
14335+ /// of <c>N</c> over the other power at each root. The roots are <c>b e/c</c> apart, which
14336+ /// is not zero. Each linear's fractions are asked as one question in <c>t</c>. Each of
14337+ /// <c>d</c>, <c>b e/c</c>, <c>e</c> and the coefficients of <c>P</c> that is compound is
14338+ /// named by a symbol of its own and written back into the answer, as in
14339+ /// <see cref="SolveCubeRootsOfTwoLinearsBesideAWholePowerOfAThird"/>, and <c>rho</c> is
14340+ /// written in them, so that a power of <c>x</c> in <c>P</c> cancels.
14341+ /// </para>
14342+ /// <para>
14343+ /// Rubi's <c>(A + B x) (d + e x)^(j/2)/(b x + c x^2)^3</c> ran past the budget: the
14344+ /// substitution that reaches it is late in the chain and multiplies the quadratic out.
14345+ /// Asked as one rational function in <c>t</c>, the second power came back in up to 940,000
14346+ /// characters and 11 GB, <c>(d + e x)^(7/2)/(b x + c x^2)^2</c> among them, and the third
14347+ /// in 10,000 to 66,000; split, each is under 7,000 characters, in megabytes. The first
14348+ /// power and numbers for coefficients are answered compactly as they are, and left to
14349+ /// that, and so is the root below the bar, which puts a power of <c>s</c> below it too.
14350+ /// Declined where <c>d</c> or <c>r</c> is zero as a value, the linear then sharing a root
14351+ /// with the quadratic.
1434314352 /// https://github.com/asc-community/AngouriMath/issues/233
1434414353 /// </para>
1434514354 /// </remarks>
@@ -14370,7 +14379,7 @@ static Entity Reduced(Entity constant)
1437014379 }
1437114380 if (root is not var (linear, half) || quadratic is not var (q, n) || half.Sign <= 0
1437214381 || half.Multiply(ERational.FromInt32(2)) is not { } twice || !twice.IsInteger() || !twice.ToEInteger().CanFitInInt32()
14373- || n < 3 || n > MaximumQuadraticPowerUnderARoot)
14382+ || n < 2 || n > MaximumQuadraticPowerUnderARoot)
1437414383 return null;
1437514384 var j = twice.ToEInteger().ToInt32Checked();
1437614385 if (j > MaximumHalfPowerOfTheLinear
@@ -14385,40 +14394,136 @@ static Entity Reduced(Entity constant)
1438514394 || VanishesIdentically(e) || VanishesIdentically(d) || VanishesIdentically(r))
1438614395 return null;
1438714396
14397+ // P((t^2 - d)/e) e^degree as a polynomial in s = t^2, whose coefficient of s^l is the sum
14398+ // over i of p_i e^(degree - i) binomial(i, l) (-d)^(i - l), and with the quadratic's
14399+ // coefficients and r there is something to name, or the rules after this answer it.
14400+ var coefficients = new Entity[degree + 1];
14401+ for (var l = 0; l <= degree; l++)
14402+ {
14403+ Entity coefficient = Number.Integer.Zero;
14404+ foreach (var (i, p) in read.Select(pair => (pair.Key.ToInt32Checked(), pair.Value)).Where(pair => pair.Item1 >= l))
14405+ coefficient += p * MathS.Pow(e, degree - i) * Binomial(i, l) * MathS.Pow(-d, i - l);
14406+ coefficients[l] = VanishesIdentically(coefficient) ? Number.Integer.Zero : Reduced(coefficient);
14407+ }
14408+ if (coefficients.Concat(new[] { Reduced(-d), Reduced(c), Reduced(r) }).All(value => value is Number || IsAName(value)))
14409+ return null;
14410+
14411+ // The integrand is 2 e^(2n - 1 - degree)/c^n times N(s)/((s - d)^n (s + rho)^n) in
14412+ // s = t^2, with N = s^h P((s - d)/e) e^degree and rho = r/c: its polynomial part, and
14413+ // its partial fractions over s - d and s + rho, whose coefficients are those of the
14414+ // Taylor series at each root of N over the other power. The atoms are named and rho is
14415+ // written in them, so that a power of x in P cancels there.
14416+ var h = (j + 1) / 2;
1438814417 var t = Variable.CreateUnique(expr, "t_root");
1438914418 var named = new List<(Variable Name, Entity Value)>();
1439014419 Entity Named(Entity value)
1439114420 {
14392- if (value is Number or Variable || value is Mulf(Number, Variable) || value is Powf(Variable, Number ))
14421+ if (value is Number || IsAName( value))
1439314422 return value;
1439414423 var name = Variable.CreateUnique(expr + t + named.Aggregate((Entity)Number.Integer.Zero, (sum, pair) => sum + pair.Name), "k_named");
1439514424 named.Add((name, value));
1439614425 return name;
1439714426 }
14398- // P((t^2 - d)/e) e^degree as a polynomial in t^2: the coefficient of t^(2l) is the sum
14399- // over i of p_i e^(degree - i) binomial(i, l) (-d)^(i - l).
14400- Entity above = Number.Integer.Zero;
14427+ var atD = Named(Reduced(d));
14428+ var delta = Named(Reduced(b * e / c));
14429+ var rho = delta - atD;
14430+ var slope = Named(Reduced(e));
14431+ var ofP = read.Select(pair => (Power: pair.Key.ToInt32Checked(), Coefficient: Named(Reduced(pair.Value)))).ToList();
14432+ var numerator = new Entity[h + degree + 1];
14433+ for (var l = 0; l < h; l++)
14434+ numerator[l] = Number.Integer.Zero;
1440114435 for (var l = 0; l <= degree; l++)
1440214436 {
1440314437 Entity coefficient = Number.Integer.Zero;
14404- foreach (var (i, p) in read.Select(pair => (pair.Key.ToInt32Checked(), pair.Value)).Where(pair => pair.Item1 >= l))
14405- coefficient += p * MathS.Pow(e, degree - i) * Binomial(i, l) * MathS.Pow(-d, i - l);
14406- // t^0 is written as nothing: InnerSimplified makes it 1 provided t is not 0.
14407- if (!VanishesIdentically(coefficient))
14408- above += l == 0 ? Named(Reduced(coefficient)) : Named(Reduced(coefficient)) * MathS.Pow(t, 2 * l);
14438+ foreach (var (i, p) in ofP.Where(pair => pair.Power >= l))
14439+ coefficient += p * PowerOf(slope, degree - i) * Binomial(i, l) * PowerOf(-atD, i - l);
14440+ numerator[h + l] = Reduced(coefficient);
1440914441 }
14442+ // The shift a question in t is asked over, named apart from what it is in the atoms.
14443+ var shift = Named(Reduced(r / c));
1441014444 var square = MathS.Sqr(t);
14411- var below = MathS.Pow(square + Named(Reduced(-d)), n) * MathS.Pow(Named(Reduced(c)) * square + Named(Reduced(r)), n);
14412- // With nothing to name the coefficients are numbers, and the rules after this answer them.
14413- if (named.Count == 0)
14414- return null;
14415- var inT = (MathS.Pow(t, j + 1) * above / below).InnerSimplified;
14416- if (Integration.ComputeAsAQuestionOfItsOwn(inT, t, integrateByParts) is not { } answer
14417- || answer.Nodes.Any(node => node == MathS.NaN))
14418- return null;
14445+
14446+ // The quotient by the monic (s - d)^n (s + rho)^n, integrated term by term.
14447+ Entity inT = Number.Integer.Zero;
14448+ if (numerator.Length > 2 * n)
14449+ {
14450+ var monic = new Entity[2 * n + 1];
14451+ for (var k = 0; k <= 2 * n; k++)
14452+ monic[k] = Number.Integer.Zero;
14453+ for (var first = 0; first <= n; first++)
14454+ for (var second = 0; second <= n; second++)
14455+ monic[first + second] += Binomial(n, first) * PowerOf(-atD, n - first) * Binomial(n, second) * PowerOf(rho, n - second);
14456+ var remainder = numerator.ToArray();
14457+ for (var top = numerator.Length - 1; top >= 2 * n; top--)
14458+ {
14459+ var quotient = Reduced(remainder[top]);
14460+ if (quotient == Number.Integer.Zero)
14461+ continue;
14462+ for (var k = 0; k < 2 * n; k++)
14463+ remainder[top - 2 * n + k] -= quotient * monic[k];
14464+ var power = 2 * (top - 2 * n) + 1;
14465+ inT += quotient * MathS.Pow(t, power) / power;
14466+ }
14467+ }
14468+
14469+ // Each power of s - d and of s + rho over a coefficient named apart, and each sum
14470+ // asked as one question: the answer over one quadratic is one piecewise in the sign
14471+ // of its constant.
14472+ var parts = new List<(Variable Name, Entity Value)>();
14473+ foreach (var (at, gap, linearInS) in new[] { (atD, delta, square - atD), (-rho, -delta, square + shift) })
14474+ {
14475+ Entity? fractions = null;
14476+ foreach (var (power, value) in TaylorCoefficients(at, gap).Select((value, m) => (n - m, value)))
14477+ {
14478+ if (VanishesIdentically(value))
14479+ continue;
14480+ var name = Variable.CreateUnique(expr + t + named.Concat(parts).Aggregate((Entity)Number.Integer.Zero, (sum, pair) => sum + pair.Name), "k_part");
14481+ parts.Add((name, value));
14482+ var term = name / (power == 1 ? linearInS : MathS.Pow(linearInS, power));
14483+ fractions = fractions is null ? term : fractions + term;
14484+ }
14485+ if (fractions is null)
14486+ continue;
14487+ if (Integration.ComputeAsAQuestionOfItsOwn(fractions, t, integrateByParts) is not { } part
14488+ || part.Nodes.Any(node => node == MathS.NaN))
14489+ return null;
14490+ inT += part;
14491+ }
14492+ var answer = inT;
14493+ foreach (var (name, value) in parts)
14494+ answer = answer.Substitute(name, value);
1441914495 foreach (var (name, value) in named)
1442014496 answer = answer.Substitute(name, value);
14421- return Reduced(2 * constant * MathS.Pow(e, 2 * n - 1 - degree)) * answer.Substitute(t, MathS.Sqrt(linear));
14497+ return Reduced(2 * constant * MathS.Pow(e, 2 * n - 1 - degree) / MathS.Pow(c, n)) * answer.Substitute(t, MathS.Sqrt(linear));
14498+
14499+ // The coefficients of u^0 to u^(n - 1) in N(at + u)/(u + gap)^n, in lowest terms.
14500+ Entity[] TaylorCoefficients(Entity at, Entity gap)
14501+ {
14502+ var shifted = new Entity[n];
14503+ for (var q = 0; q < n; q++)
14504+ {
14505+ Entity sum = Number.Integer.Zero;
14506+ for (var l = q; l < numerator.Length; l++)
14507+ if (numerator[l] != Number.Integer.Zero)
14508+ sum += numerator[l] * Binomial(l, q) * PowerOf(at, l - q);
14509+ shifted[q] = sum;
14510+ }
14511+ var series = new Entity[n];
14512+ for (var m = 0; m < n; m++)
14513+ {
14514+ Entity sum = Number.Integer.Zero;
14515+ for (var q = 0; q <= m; q++)
14516+ sum += shifted[q] * Binomial(n + m - q - 1, m - q) * Number.Integer.Create((m - q) % 2 == 0 ? 1 : -1) / MathS.Pow(gap, n + m - q);
14517+ series[m] = Reduced(sum);
14518+ }
14519+ return series;
14520+ }
14521+
14522+ static bool IsAName(Entity value)
14523+ => value is Variable || value is Mulf(Number, Variable) || value is Powf(Variable, Number);
14524+
14525+ static Entity PowerOf(Entity @base, int power)
14526+ => power == 0 ? Number.Integer.One : power == 1 ? @base : MathS.Pow(@base, power);
1442214527
1442314528 static Entity Reduced(Entity constant)
1442414529 => constant.Vars.Any() ? Functions.PartialFractions.InLowestTermsOverTheSymbols(constant) : constant.InnerSimplified;
0 commit comments