diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md index 02dedd57f..30e4a8cca 100644 --- a/BREAKING-CHANGES.md +++ b/BREAKING-CHANGES.md @@ -38,6 +38,8 @@ read first. | | `MathS.Vector()` and `new Entity[0].ToVector()` | `IndexOutOfRangeException` — outside the documented hierarchy | `InvalidMatrixOperationException` | | | `"x3 - 1".ToEntity().Factorize()`, and every polynomial no rewrite rule has a rule for | `x ^ 3 - 1` — handed back whole | `(x - 1) * (x ^ 2 + x + 1)` | | | `"x^2/(x^4 + 1)".Integrate("x")`, and every quotient whose denominator is a biquadratic irreducible over `Q` | `integral(x ^ 2 / (x ^ 4 + 1), x)` — left unevaluated | the antiderivative, over the real quadratic factors | +| | `"sqrt(x)/(1 + x^2)".Integrate("x")`, and every integrand a fractional power of the variable makes rational | `integral(sqrt(x) / (1 + x ^ 2), x)` — left unevaluated | the antiderivative | +| | `"sqrt(tan(x))".Integrate("x")`, and every integrand that is a function of `tan(x)` alone and rational in it | `integral(sqrt(tan(x)), x)` — left unevaluated | the antiderivative | | | `Entity.DomainConditionIn(Domain)` | did not exist | the domain of definition for a **stated** reading, through the whole tree | | | `MathS.Polynomials.Factor("(y * x3 + 1) * (x4 - y3)", "x")`, and bivariate polynomials whose leading coefficient in the main variable is a polynomial | `null` — a refusal | `(x ^ 4 - y ^ 3) * (x ^ 3 * y + 1)` | | | `MathS.Polynomials.Factor("x7 - y7", "x")`, and bivariate polynomials whose substituted image over-factors | `null` — a refusal | `(x - y) * (x ^ 6 + x ^ 5 * y + … + y ^ 6)` | @@ -2401,7 +2403,72 @@ because every guard here is rational arithmetic on coefficients already read. `sqrt(tan(x))`, the one remaining entry on #233's list, is **not** answered by this. It reduces under `u = sqrt(tan x)` to `2 * integral(u^2/(u^4 + 1), u)`, which is now integrable — but the -substitution that gets there is a separate capability and is not built here. +substitution that gets there is a separate capability and is not built here. *It is built in the +entry below, and `sqrt(tan(x))` is now answered.* + +[#233](https://github.com/asc-community/AngouriMath/issues/233). + +### A fractional power, and the tangent, are substitutions + +Two substitutions, in one entry because neither reaches `sqrt(tan(x))` without the other and +without the entry above. That integral is the last of the five +[#233](https://github.com/asc-community/AngouriMath/issues/233) lists, and the one it calls "very +painful, requires different solvers" — which it is. Three capabilities in a row: + +``` +int sqrt(tan(x)) dx + --- u = tan(x), dx = du/(1 + u^2) -------> int sqrt(u)/(1 + u^2) du + --- t = sqrt(u), a fractional power -------> int 2t^2/(1 + t^4) dt + --- 1 + t^4 factored over the reals -------> logarithms and arctangents +``` + +Take any one away and it comes back unevaluated. + +``` +"sqrt(tan(x))".Integrate("x") + +was integral(sqrt(tan(x)), x) +is a sum of two logarithms and two arctangents in sqrt(tan(x)) — the shape the + entry above produces, with sqrt(tan(x)) where it had x +``` + +**The fractional power.** A power substitution rewrites the other powers of the variable into +powers of itself: for `u = x^r` the identity is `x^n = u^(n/r)`, applied wherever `n/r` is a whole +number. A whole `r` reaches only the powers it divides, which is what this did before. An `r` of +`1/2` reaches every one of them — including the bare `x`, which a whole `r` never can — so +`int sqrt(x)/(1 + x^2)` becomes `int 2u^2/(1 + u^4) du`. `1/(1 + sqrt(x))`, +`1/(sqrt(x) * (1 + x))`, `1/(sqrt(x) * (1 + x^2))` and `1/(sqrt(x) + x)` come with it. + +The rewrite is made in two passes, powers first and a leftover bare `x` second, because the tree +is rewritten from the leaves up: in one pass the `x` inside `sqrt(x)` is reached before the +`sqrt(x)` node is, and `u = sqrt(x)` turns it into `sqrt(u^2)` rather than `u` — an integrand free +of `x` and no more integrable than it started. + +**The tangent.** An integrand that is a function of `tan(x)` and of nothing else becomes a +rational function under `u = tan(x)`, with `dx` as `du/(1 + u^2)`. The test is the rewrite itself: +replace every `tan(x)` and see whether an `x` survives. `tan(x) + x` keeps one and is declined, +which is right — it is answered, but by linearity over the sum. + +This is a step of its own rather than a candidate for the general substitution, and the reason is +worth recording. The general one divides the integrand by `du/dx` and asks what is left, which +works while the substitution survives the division. Here it does not: `sqrt(tan(x))` over the +derivative of `sqrt(tan(x))` is `2 tan(x) cos(x)^2`, which is `sin(2x)` and is simplified to it — +a correct answer to a question that has stopped being about the tangent. + +**What is still declined**, each by what the rewrite hands on rather than by the rewrite: +`cotan` is its own node rather than a reciprocal of the tangent, so `sqrt(cotan(x))` never starts; +`tan(x)^2` and `tan(x)^3` become improper fractions, and dividing an improper fraction out is not +something the rational integrator does; `1/(1 + tan(x)^2)` becomes `1/(1 + u^2)^2`, a repeated +irreducible quadratic. On the other side, `sqrt(x)/(1 + x^4)` becomes `2u^2/(1 + u^8)`, whose +denominator is neither factorable over the rationals nor a biquadratic. + +**The rule for the tangent itself still wins**, being reached first: `int tan(x)` is +`-ln(cos(x)) + C` and not the longer thing this would produce. + +**The corpus gate now reads 40 solved of 40.** Its one unsolved problem was `int:hard`, and +`int:hard` is `sqrt(tan(x))` — chosen for that list as the standing example of an integral out of +reach. The gate reached the same verdict independently, by differentiating the answer back rather +than by comparing it with anything. [#233](https://github.com/asc-community/AngouriMath/issues/233). diff --git a/Sources/.editorconfig b/Sources/.editorconfig index 5cf7aca58..0158e73df 100644 --- a/Sources/.editorconfig +++ b/Sources/.editorconfig @@ -158,3 +158,6 @@ file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed [Tests/UnitTests/Common/ExponentialOfALogarithmTest.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/Calculus/TangentSubstitutionIntegralTest.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 diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs index 594b32a4a..51a95a875 100644 --- a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs +++ b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs @@ -205,6 +205,56 @@ arg is Entity.Powf(var y, var pow) ? // log(b, y^p) = ln(y^p) / ln(b) = ln(p) / _ => null }; + /// + /// An integrand that is a function of tan(x) and of nothing else, integrated by + /// the substitution u = tan(x), under which dx is du/(1 + u^2). + /// + /// + /// + /// The substitution that turns every rational function of the tangent into a rational + /// function, and int sqrt(tan(x)) — the last of the five integrals + /// #233 lists — into + /// int sqrt(u)/(1 + u^2) du. + /// + /// + /// Why this is not a candidate in . That one + /// divides the integrand by du/dx and asks whether any x is left, which + /// works when the substitution survives the division. Here it does not: + /// sqrt(tan(x)) over the derivative of sqrt(tan(x)) is + /// 2 tan(x) cos(x)^2, which is sin(2x) and is simplified to it — a correct + /// answer to a question that has stopped being about the tangent. Rewriting the integrand + /// asks a different question and does not lose the shape. + /// + /// + /// The test is the rewrite itself: replace every tan(x) and see whether an + /// x survives. tan(x) + x keeps one and is declined, which is right — it is + /// not a function of the tangent alone. cotan is not covered, since it is + /// its own node rather than a reciprocal of this one, so sqrt(cotan(x)) is still + /// declined. + /// + /// + /// No condition is owed by the substitution, but the answer inherits the + /// tangent's: u = tan(x) is undefined exactly where the integrand is, since the + /// integrand is a function of it, and 1 + u^2 is never zero for real u. + /// + /// + internal static Entity? SolveByTangentSubstitution(Entity expr, Entity.Variable x, bool integrateByParts) + { + var tangent = MathS.Tan(x); + if (!expr.ContainsNode(tangent)) + return null; + + var uSub = Variable.CreateUnique(expr, "u_tan"); + var inU = expr.Substitute(tangent, uSub); + if (inU.ContainsNode(x)) + return null; + + var integrand = (inU / (1 + MathS.Sqr(uSub))).InnerSimplified; + return Integration.ComputeIndefiniteIntegral(integrand, uSub, integrateByParts) is { } result + ? result.Substitute(uSub, tangent) + : null; + } + /// /// Attempts to solve an integral using u-substitution. /// Looks for patterns where f(g(x)) * g'(x) can be integrated as F(g(x)). @@ -276,31 +326,69 @@ arg is Entity.Powf(var y, var pow) ? // log(b, y^p) = ln(y^p) / ln(b) = ln(p) / /// /// /// So a power substitution rewrites the other powers of the variable into powers of - /// itself, which it can do exactly when its exponent divides theirs. Nothing is assumed - /// by it: the caller still checks that no x survives, so a rewrite that does not - /// clear the variable leaves the candidate rejected as before — which is what happens to - /// x^2 / (x^4 + 1), where a bare x remains and the integral genuinely needs - /// a factorisation this does not have. + /// itself. For u = x^r the identity is x^n = u^(n/r), and the rewrite is + /// made wherever n/r is a whole number — which for a whole r means + /// r divides n, and is the only case this covered at first. + /// + /// + /// A fractional r is the case that reaches the other way, and it is what + /// int sqrt(x)/(1 + x^2) needs. There u = sqrt(x), so r is + /// 1/2 and n/r is 2n — a whole number for every n, including + /// the bare x that a whole r can never rewrite. The integrand becomes + /// 2u^2/(1 + u^4), which is answered. + /// + /// + /// Nothing is assumed by it: the caller still checks that no x survives, so a + /// rewrite that does not clear the variable leaves the candidate rejected as before. /// /// private static Entity InTermsOf(Entity expr, Entity u, Entity.Variable uSub, Entity.Variable x) { - if (u is not Powf(var powerBase, Number.Integer exponent) - || powerBase != x - || !exponent.EInteger.CanFitInInt32()) + if (u is not Powf(var powerBase, Number.Rational exponent) || powerBase != x) return expr.Substitute(u, uSub); - var k = exponent.EInteger.ToInt32Checked(); - if (k < 2) + var r = exponent.ERational; + if (r.IsZero) return expr.Substitute(u, uSub); - return expr.Replace(node => - node is Powf(var otherBase, Number.Integer otherExponent) + // The written powers of x first, and only then a bare x that is left over. Both in + // one pass does not work, because Replace rewrites from the leaves up: the x inside + // sqrt(x) is reached before the sqrt(x) node is, so with u = sqrt(x) it becomes + // sqrt(u^2) rather than u, and the integrand ends up free of x and no more + // integrable than it started. + // + // The exponent is read as a rational rather than a whole number because the + // candidate is itself one of these nodes: with u = sqrt(x) the integrand still holds + // a sqrt(x), and leaving it alone leaves an x that rejects the candidate. Anything + // else -- x inside a function, or a base that is not x -- is left for the caller's + // check on whether x survives. + var written = expr.Replace(node => + node is Powf(var otherBase, Number.Rational otherExponent) && otherBase == x - && otherExponent.EInteger.CanFitInInt32() - && otherExponent.EInteger.ToInt32Checked() is var n - && n >= k - && n % k == 0 - ? (n == k ? uSub : MathS.Pow(uSub, n / k)) + && Rewritten(otherExponent.ERational) is { } power + ? power : node); + return written.Replace(node => + node == x && Rewritten(PeterO.Numbers.ERational.One) is { } bare ? bare : node); + + // u^(n/r), where that is a whole power, and null where it is not. Done on the four + // integers rather than by dividing the rationals and asking whether the result is + // whole: an ERational quotient is not reduced, so 4/2 answers that question with a + // denominator of two and every whole r would be refused. + // + // The ceiling is against a tiny r turning a modest power of x into an enormous one, + // rather than against anything mathematical. + Entity? Rewritten(PeterO.Numbers.ERational n) + { + var scaled = n.Numerator.Multiply(r.Denominator); + var by = n.Denominator.Multiply(r.Numerator); + if (by.IsZero || !scaled.Remainder(by).IsZero) + return null; + var whole = scaled.Divide(by); + if (whole.IsZero || whole.Abs().CompareTo(PeterO.Numbers.EInteger.FromInt32(64)) > 0) + return null; + return whole.Equals(PeterO.Numbers.EInteger.One) + ? uSub + : MathS.Pow(uSub, Number.Integer.Create(whole)); + } } /// diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs b/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs index db4fbb1f7..5aaef26c5 100644 --- a/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs +++ b/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs @@ -122,6 +122,11 @@ private static Entity Normalized(Entity expr) => if ((answer = IndefiniteIntegralSolver.SolveAsPolynomialTerm(expr, x, integrateByParts)) is { }) return answer; if ((answer = IndefiniteIntegralSolver.SolveLogarithmic(expr, x, integrateByParts)) is { }) return answer; if ((answer = IndefiniteIntegralSolver.SolveBySubstitution(expr, x, integrateByParts)) is { }) return answer; + // After the general substitution rather than inside it, because the general one + // divides by du/dx and asks what is left, and that question loses the shape here: + // sqrt(tan(x)) over the derivative of sqrt(tan(x)) simplifies to sin(2x), in which + // the substitution is no longer visible. This one rewrites rather than divides. + if ((answer = IndefiniteIntegralSolver.SolveByTangentSubstitution(expr, x, integrateByParts)) is { }) return answer; if ((answer = IndefiniteIntegralSolver.SolveByPartialFractions(expr, x, integrateByParts)) is { }) return answer; // Linearity comes before integration by parts, because it decomposes the problem // into strictly simpler ones where by parts searches. It cannot cost an answer: diff --git a/Sources/Tests/UnitTests/Calculus/PowerSubstitutionIntegralTest.cs b/Sources/Tests/UnitTests/Calculus/PowerSubstitutionIntegralTest.cs index 965c7e8a0..0f2ed99a6 100644 --- a/Sources/Tests/UnitTests/Calculus/PowerSubstitutionIntegralTest.cs +++ b/Sources/Tests/UnitTests/Calculus/PowerSubstitutionIntegralTest.cs @@ -71,6 +71,41 @@ private static void DifferentiatesBack(string integrand) + "so this asserts almost nothing"); } + /// + /// A fractional power of the variable as the substitution, which is the same + /// rewrite read the other way: u = x^r means x^n = u^(n/r), and where a + /// whole r can only rewrite the powers it divides, an r of 1/2 + /// rewrites every one of them — the bare x included, which a whole r never + /// can. + /// + /// + /// int sqrt(x)/(1 + x^2) becomes int 2u^2/(1 + u^4) du under + /// u = sqrt(x), which is answered — so this reaches what it does partly because + /// the denominator now factors over the reals. + /// #233 + /// + [Theory] + [InlineData("sqrt(x)/(1 + x^2)")] + [InlineData("1/(1 + sqrt(x))")] + [InlineData("1/(sqrt(x) * (1 + x))")] + [InlineData("1/(sqrt(x) * (1 + x^2))")] + [InlineData("1/(sqrt(x) + x)")] + public void AFractionalPowerIsAlsoASubstitution(string integrand) + => DifferentiatesBack(integrand); + + /// + /// Where a fractional substitution reaches and the rest of the chain does not, recorded + /// so the boundary is visible. sqrt(x)/(1 + x^4) becomes 2u^2/(1 + u^8), + /// whose denominator is neither factorable over the rationals nor a biquadratic; and + /// sqrt(x)/(x + 1) becomes 2u^2/(1 + u^2), which is improper, and dividing + /// an improper fraction out is not something the rational integrator does. + /// + [Theory] + [InlineData("sqrt(x)/(1 + x^4)")] + [InlineData("sqrt(x)/(x + 1)")] + public void WhereTheChainStops(string integrand) + => Assert.Contains("integral(", integrand.ToEntity().Integrate("x").Stringize()); + /// /// The shape the issue is about: an odd power over an even one, where the substitution is /// the root of the denominator's power. diff --git a/Sources/Tests/UnitTests/Calculus/TangentSubstitutionIntegralTest.cs b/Sources/Tests/UnitTests/Calculus/TangentSubstitutionIntegralTest.cs new file mode 100644 index 000000000..ef177d239 --- /dev/null +++ b/Sources/Tests/UnitTests/Calculus/TangentSubstitutionIntegralTest.cs @@ -0,0 +1,129 @@ +// +// 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 +{ + /// + /// Integrands that are a function of tan(x) and of nothing else, which the + /// substitution u = tan(x) turns into a rational function — dx being + /// du/(1 + u^2). + /// #233 + /// + /// + /// + /// int sqrt(tan(x)) is the last of the five integrals that issue lists, and the one it + /// calls "very painful, requires different solvers", which it is: the substitution here makes + /// it int sqrt(u)/(1 + u^2) du, a fractional power substitution makes that + /// int 2t^2/(1 + t^4) dt, and answering that needs the denominator factored + /// over the reals. Three capabilities in a row, and it comes out unevaluated if any of them + /// is missing. + /// + /// + /// Checked by differentiating the answer back and comparing at points, never by comparing + /// printed forms — the answers here are sums of logarithms and arctangents of radicals in + /// tan(x), and their shape says nothing about whether they differentiate back. + /// + /// + [Trait("Area", "Calculus")] + public sealed class TangentSubstitutionIntegralTest + { + /// + /// Sample points inside a single branch of the tangent, well away from the pole at + /// pi/2. sqrt(tan(x)) is real only where the tangent is non-negative, so + /// they stay on (0, pi/2) rather than straddling zero. + /// + private static readonly double[] Points = { 0.2, 0.45, 0.8, 1.1, 1.35 }; + + private static void DifferentiatesBack(string integrand) + { + var integral = integrand.ToEntity().Integrate("x"); + Assert.DoesNotContain("integral(", integral.Stringize()); + + var derivative = integral.Substitute("C", 0).Differentiate("x"); + var original = integrand.ToEntity(); + var compared = 0; + foreach (var at in Points) + { + var got = derivative.Substitute("x", at).EvalNumerical(); + var want = original.Substitute("x", at).EvalNumerical(); + if (got.IsNaN || want.IsNaN) + continue; + compared++; + var difference = Math.Abs((double)(got - want).RealPart); + var scale = Math.Max(1.0, Math.Abs((double)want.RealPart)); + Assert.True(difference / scale < 1e-9, + $"d/dx of the antiderivative of {integrand} is {got} at x = {at}, " + + $"where the integrand is {want}"); + } + Assert.True(compared >= 4, + $"only {compared} of {Points.Length} points were comparable for {integrand}, " + + "so this asserts almost nothing"); + } + + /// The integral the issue names, and the reason this substitution exists. + [Theory] + [InlineData("sqrt(tan(x))")] + public void TheIntegralTheIssueNames(string integrand) => DifferentiatesBack(integrand); + + /// + /// A function of the tangent alone, whatever it is made of. Each of these is answered + /// through the rewrite rather than by a rule of its own. + /// + [Theory] + [InlineData("1/sqrt(tan(x))")] + [InlineData("tan(x)/(1 + tan(x)^2)")] + public void AFunctionOfTheTangentAlone(string integrand) => DifferentiatesBack(integrand); + + /// + /// What the neighbours still answer, and must go on answering the same way: the tangent + /// itself has a rule, which is reached before this and gives the shorter form. + /// + [Theory] + [InlineData("tan(x)", "-ln(cos(x)) + C")] + [InlineData("tan(2 * x)", "-ln(cos(2 * x)) / 2 + C")] + public void TheRuleForTheTangentItselfStillWins(string integrand, string expected) + => Assert.Equal(expected.ToEntity(), integrand.ToEntity().Integrate("x")); + + /// + /// An integrand that mentions x outside the tangent is not a function of the + /// tangent alone, and the rewrite leaves that x behind rather than pretending + /// otherwise. tan(x) + x is answered, but by linearity over the sum, not by this. + /// + [Theory] + [InlineData("tan(x) + x", "-ln(cos(x)) + x ^ 2 / 2 + C")] + public void AnXOutsideTheTangentIsNotRewritten(string integrand, string expected) + => Assert.Equal(expected.ToEntity(), integrand.ToEntity().Integrate("x")); + + /// + /// What is still declined, recorded so the boundary is visible rather than inferred from + /// an absence. Each is declined by what the rewrite hands on, not by the rewrite itself: + /// + /// + /// + /// sqrt(cotan(x)) — cotan is its own node rather than a reciprocal of + /// the tangent, so the rewrite finds nothing to replace and this never starts. + /// tan(x)^2 and tan(x)^3 become u^2/(1 + u^2) and + /// u^3/(1 + u^2), which are improper — a polynomial plus a proper fraction + /// — and dividing that out is not something the rational integrator does. + /// 1/(1 + tan(x)^2) becomes 1/(1 + u^2)^2, a repeated irreducible + /// quadratic, which the partial fraction step declines because there is no rule for a + /// numerator over one. + /// + /// + [Theory] + [InlineData("sqrt(cotan(x))")] + [InlineData("tan(x) ^ 2")] + [InlineData("tan(x) ^ 3")] + [InlineData("1/(1 + tan(x)^2)")] + public void WhatIsStillDeclined(string integrand) + => Assert.Contains("integral(", integrand.ToEntity().Integrate("x").Stringize()); + } +} diff --git a/Sources/Tests/UnitTests/Corpus/Corpus.cs b/Sources/Tests/UnitTests/Corpus/Corpus.cs index ad71d8718..2beacf7a6 100644 --- a/Sources/Tests/UnitTests/Corpus/Corpus.cs +++ b/Sources/Tests/UnitTests/Corpus/Corpus.cs @@ -138,7 +138,11 @@ public static class Corpus new("int:by-parts-cyclic", Op.Integrate, "sin(x) * e ^ x"), new("int:arctan-form", Op.Integrate, "1 / (1 + x ^ 2)"), new("int:partial-fractions", Op.Integrate, "1 / (x ^ 4 + 3 * x ^ 2 + 2)"), - new("int:hard", Op.Integrate, "sqrt(tan(x))", Verdict.Unsolved), + // Solved since the tangent substitution: u = tan(x) makes it sqrt(u)/(1 + u^2), a + // fractional power substitution makes that 2t^2/(1 + t^4), and the biquadratic + // denominator factors over the reals. It was the corpus's standing example of an + // integral that is out of reach. https://github.com/asc-community/AngouriMath/issues/233 + new("int:hard", Op.Integrate, "sqrt(tan(x))"), // --- Limits: compared against the stated value --- new("lim:0/0", Op.Limit, "sin(x) / x", Approach: "0", Expected: "1"), diff --git a/Sources/Tests/UnitTests/Corpus/corpus-baseline.tsv b/Sources/Tests/UnitTests/Corpus/corpus-baseline.tsv index 3603a8cfa..b2667d374 100644 --- a/Sources/Tests/UnitTests/Corpus/corpus-baseline.tsv +++ b/Sources/Tests/UnitTests/Corpus/corpus-baseline.tsv @@ -3,12 +3,12 @@ # in Corpus.cs, re-run the suite with AM_UPDATE_CORPUS_BASELINE=1, and commit both. # Its git history is the per-commit history of the corpus -- item 36 of # https://github.com/asc-community/AngouriMath/issues/746. -# totals Solved=39 Unsolved=1 Wrong=0 Error=0 Timeout=0 Total=40 +# totals Solved=40 Unsolved=0 Wrong=0 Error=0 Timeout=0 Total=40 name op verdict int:arctan-form Integrate Solved int:by-parts-cyclic Integrate Solved int:exponential Integrate Solved -int:hard Integrate Unsolved +int:hard Integrate Solved int:partial-fractions Integrate Solved int:power Integrate Solved int:reciprocal Integrate Solved