diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md
index 58bd36482..3e5c5aa24 100644
--- a/BREAKING-CHANGES.md
+++ b/BREAKING-CHANGES.md
@@ -1004,6 +1004,21 @@ roots, `1 - x^2`, is taken as its two ([#718](https://github.com/asc-community/A
| `"1/((1 - x^2)*(a + b*x^3))".ToEntity().Integrate("x")` | `integral(...)` | 1,600 characters |
| `"1/(x*(1 - x^2)*(a + b*x^3))".ToEntity().Integrate("x")` | `integral(...)` | 1,637 characters |
+### A hyperbolic quotient over a quadratic in its sine or cosine is asked as the sine's, before the tangent
+
+**Answers where there were none, and one longer spelling.** Rubi's 6.7.1 `sinh(x)^2/(a + b sinh(x) + c sinh(x)^2)`
+and `sinh(x)^3/(a + b sinh(x) + c sinh(x)^2)` ran past the budget. The tangent of the half argument made each a
+quartic with symbols in it, and its partial fractions did not return. Under Osborn's rule each is a rational
+function of a sine over a symbolic quadratic in it, and the sine's rule for that shape is now asked first, before
+the tangent. A quotient master answered some other way can come back spelled through the sine instead
+([#233](https://github.com/asc-community/AngouriMath/issues/233)).
+
+| Input | Was (2.5.0) | Now |
+|---|---|---|
+| `"sinh(x)^2/(a+b*sinh(x)+c*sinh(x)^2)".ToEntity().Integrate("x")` | no answer in twenty seconds | 681 characters |
+| `"sinh(x)^3/(a+b*sinh(x)+c*sinh(x)^2)".ToEntity().Integrate("x")` | no answer in twenty seconds | 810 characters |
+| `"cosh(x)^2/(a+b*cosh(x)+c*cosh(x)^2)".ToEntity().Integrate("x")` | no answer in twenty seconds; 791 characters on the unreleased master | 813 characters |
+
### A hyperbolic integrand is asked as a trigonometric one
**Answers where there were none.** The parser writes the hyperbolic functions as exponentials, so the trigonometric
diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
index 4f63bd3f5..4edce37ab 100644
--- a/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
+++ b/Sources/AngouriMath/Functions/Continuous/Integration/IndefiniteIntegralSolver.cs
@@ -1429,7 +1429,8 @@ static bool APowerOfAQuotientOfLinearsVanishingAtPlusOrMinusOne(Entity inU, Vari
/// the bar of degree above two: the second pass answers it in e^L, and the question in
/// s took seconds to decline, five gigabytes for 1/(1 + sinh(x)^3) against 0.2.
///
- internal static Entity? SolveAHyperbolicIntegrandAsATrigonometricOne(Entity expr, Entity.Variable x, bool integrateByParts, bool rationalToo)
+ internal static Entity? SolveAHyperbolicIntegrandAsATrigonometricOne(Entity expr, Entity.Variable x, bool integrateByParts, bool rationalToo,
+ bool overAQuadraticInTheSine = false)
{
// Only the question asked: a question in s is not cheap to decline, and below the top every
// sub-question a route gives up on would ask it.
@@ -1497,7 +1498,11 @@ static bool APowerOfAQuotientOfLinearsVanishingAtPlusOrMinusOne(Entity inU, Vari
&& AFactorAboveAQuadraticInS(inS, s))
return null;
var question = MathS.i / slopeOfL * inS;
- if (Integration.ComputeAsAQuestionOfItsOwn(question, s, integrateByParts) is not { } inTermsOfS
+ // Or the one rule for a rational function of a sine or a cosine over a symbolic quadratic in
+ // it, asked ahead of the exponential substitution and cheap to decline.
+ if ((overAQuadraticInTheSine
+ ? SolveARationalFunctionOfASineOverASymbolicQuadratic(inS, s, integrateByParts) is { } overTheQuadratic ? MathS.i / slopeOfL * overTheQuadratic : null
+ : Integration.ComputeAsAQuestionOfItsOwn(question, s, integrateByParts)) is not { } inTermsOfS
|| inTermsOfS.Nodes.Any(node => node is Integralf || node == MathS.NaN))
return null;
var linear = interceptOfL.Evaled is Number.Complex { IsZero: true } ? slopeOfL * x : interceptOfL + slopeOfL * x;
diff --git a/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs b/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs
index 1544c7c7b..1e7d235de 100644
--- a/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs
+++ b/Sources/AngouriMath/Functions/Continuous/Integration/Integration.Definition.cs
@@ -1229,6 +1229,11 @@ internal static bool ASumOverRootsWouldAnswer
// `cosh(x)^7/(a + b cosh(x)^2)` and `sech(x)^3/(a + b sinh(x))^2` are a second here
// and past the budget there.
if ((answer = IndefiniteIntegralSolver.SolveByBiochesOddHyperbolicSubstitution(expr, x, integrateByParts)) is { }) return answer;
+ // A rational function of e^L that Osborn's rule makes one of a sine or a cosine over a symbolic
+ // quadratic in it, asked as that before the tangent: under it Rubi's
+ // `sinh(x)^2/(a + b sinh(x) + c sinh(x)^2)` is a quartic with symbols, and its partial
+ // fractions ran past the budget, where the sine's rule answers the question in s at once.
+ if ((answer = IndefiniteIntegralSolver.SolveAHyperbolicIntegrandAsATrigonometricOne(expr, x, integrateByParts, rationalToo: true, overAQuadraticInTheSine: true)) is { }) return answer;
if ((answer = IndefiniteIntegralSolver.SolveARationalFunctionOfTheHyperbolicTangent(expr, x, integrateByParts)) is { }) return answer;
// A rational function of a sine or a cosine over a quadratic in it with a symbol
// among the coefficients, split over the quadratic's two roots: under the
diff --git a/Sources/Tests/UnitTests/Calculus/AHyperbolicQuotientOverAQuadraticInItAsTheSinesIntegralTest.cs b/Sources/Tests/UnitTests/Calculus/AHyperbolicQuotientOverAQuadraticInItAsTheSinesIntegralTest.cs
new file mode 100644
index 000000000..f49570725
--- /dev/null
+++ b/Sources/Tests/UnitTests/Calculus/AHyperbolicQuotientOverAQuadraticInItAsTheSinesIntegralTest.cs
@@ -0,0 +1,53 @@
+//
+// 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 System.Threading;
+using System.Threading.Tasks;
+using AngouriMath.Extensions;
+using Xunit;
+
+namespace AngouriMath.Tests.Calculus
+{
+ ///
+ /// A rational function of a hyperbolic sine or cosine over a symbolic quadratic in it, asked under
+ /// Osborn's rule as one of a sine over a quadratic before the tangent of the half argument: under that
+ /// tangent Rubi's 6.7.1 sinh(x)^2/(a + b sinh(x) + c sinh(x)^2) is a quartic with symbols in it,
+ /// and its partial fractions ran past the budget.
+ /// #233
+ ///
+ [Trait("Area", "Calculus")]
+ public sealed class AHyperbolicQuotientOverAQuadraticInItAsTheSinesIntegralTest
+ {
+ [Theory]
+ [InlineData("sinh(x)^2/(a + b*sinh(x) + c*sinh(x)^2)")]
+ [InlineData("sinh(x)^3/(a + b*sinh(x) + c*sinh(x)^2)")]
+ [InlineData("cosh(x)^2/(a + b*cosh(x) + c*cosh(x)^2)")]
+ public void IsAnswered(string integrand)
+ {
+ Entity? answer = null;
+ // A thread of its own, so that the guard is not spent waiting behind other tests' work.
+ var task = Task.Factory.StartNew(() => answer = integrand.ToEntity().Integrate("x"),
+ CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
+ Assert.True(task.Wait(LimitTermination.Guard), $"{integrand} did not finish within {LimitTermination.Guard}");
+ var integral = answer!;
+ Assert.DoesNotContain("integral(", integral.Stringize());
+ Entity Pinned(Entity e) => e.Substitute("a", 1.3).Substitute("b", 0.7).Substitute("c", 0.4);
+ var derivative = Pinned(integral.Substitute("C", 0)).Differentiate("x");
+ var original = Pinned(integrand.ToEntity());
+ foreach (var at in new[] { -1.7, -0.6, 0.4, 1.3, 2.2 })
+ {
+ var want = original.Substitute("x", at).EvalNumerical();
+ var got = derivative.Substitute("x", at).EvalNumerical();
+ Assert.False(got.IsNaN, $"d/dx of the antiderivative of {integrand} has no value at x = {at}, where the integrand is {want}");
+ 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}");
+ }
+ }
+ }
+}