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
17 changes: 17 additions & 0 deletions BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,23 @@ as `a - b = 0`, as a statement's own solve reads it: `"x + 1 = 3".Solve("x")` wa
| `MathS.Equations("x + y = 3", "x - y = 1").Solve("x", "y")` | `null` | `[[2, 1]]` |
| `MathS.Equations("x + y = 3", "x - y = 1").ToString()` | `x + y = 3 = 0` and `x - y = 1 = 0` | `x + y - 3 = 0` and `x - y - 1 = 0` |

### A definite integral of a floor or a ceiling of something in x is the sum over its pieces

**Silent: values where the integral was left as written.** A floor or a ceiling was split only where its argument was
`x` itself, and `integral(floor(x^2), x, 0, 2)` stayed as written. Between two bounds that are numbers it is now the
sum of the integrals of the pieces `MathS.ExperimentalFeatures.PiecewiseOver` writes the integrand in, each with the
step a constant there: the points where the argument is a whole number, from the solver, with a proof that there are
no others. Where that proof does not go through, or a bound is symbolic, the integral is left as written, as before
([#1807](https://github.com/asc-community/AngouriMath/issues/1807)).

| Input | Was (2.6.0) | Now |
|---|---|---|
| `integral(floor(x^2), x, 0, 2)` | `integral(floor(x ^ 2), x, 0, 2)` | `5 - sqrt(2) - sqrt(3)` |
| `integral(floor(2*x), x, 0, 3)` | `integral(floor(2 * x), x, 0, 3)` | `15/2` |
| `integral(floor(sin(pi*x*(4-x)/2)), x, 0, 4)` | as written | `(-2) * sqrt(2)` |
| `integral(floor(1/x), x, 1/4, 1)` | as written | `13/12` |
| `integral(floor(1/x), x, -1, 1)` | as written | as written: a pole inside the range |

### The polygamma functions, and the derivative of the factorial

**Silent: a new reading, and an answer where there was none.**
Expand Down
3 changes: 3 additions & 0 deletions Sources/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed
[AngouriMath/Functions/TreeAnalyzer/PerfectPower.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

[AngouriMath/Functions/Continuous/StepPieces.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/Common/LogarithmOfAPerfectPowerTest.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

Expand Down
26 changes: 26 additions & 0 deletions Sources/AngouriMath/Convenience/Experimental/MathS.Experimental.cs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,32 @@ public static Entity ExpandCosineOfSum(IReadOnlyList<(Entity SinX, Entity CosX)>
/// </returns>
public static Entity? SymbolicFormOfCosine(Entity angle)
=> TrigonometricAngleExpansion.SymbolicFormOfCosine(angle)?.InnerSimplified;

/// <summary>
/// <paramref name="expr"/> over <c>[<paramref name="from"/>, <paramref name="to"/>]</c> as the piecewise it is
/// there, with each floor and ceiling of <paramref name="x"/> replaced by its value on each piece: the pieces
/// partition the range, their ends are exact, and an end belongs to the piece whose value it has, which the
/// closedness of each piece's interval says. <c>floor(x^2)</c> over <c>[0, 2]</c> is <c>0</c> for
/// <c>x in [0; 1)</c>, <c>1</c> for <c>x in [1; sqrt(2))</c>, <c>2</c> for <c>x in [sqrt(2); sqrt(3))</c>,
/// <c>3</c> for <c>x in [sqrt(3); 2)</c>, and <c>4</c> for <c>x = 2</c>.
/// </summary>
/// <remarks>
/// The ends are the points where a floor's or ceiling's argument is a whole number, from the solver; that
/// there are no others is proved, by intervals that hold every value the argument takes between two ends.
/// Where that cannot be proved -- a root the solver does not give, an argument with a pole in the range, a
/// floor inside another, or any other jump in <paramref name="x"/> -- the answer is <see langword="null"/>,
/// and never a partition with a piece missing.
/// https://github.com/asc-community/AngouriMath/issues/1807
/// </remarks>
/// <param name="expr">The expression, with floors and ceilings of <paramref name="x"/> in it</param>
/// <param name="x">The variable</param>
/// <param name="from">The start of the range, a finite real number</param>
/// <param name="to">The end of the range, a finite real number above <paramref name="from"/></param>
/// <returns>
/// The piecewise, or <see langword="null"/> where its pieces cannot be proved to be all of them
/// </returns>
public static Entity.Piecewise? PiecewiseOver(Entity expr, Entity.Variable x, Entity from, Entity to)
=> Functions.Algebra.StepPieces.Of(expr, x, from, to);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ namespace AngouriMath.Functions.Algebra
/// (<a href="https://github.com/asc-community/AngouriMath/issues/1174">#1174</a>).
/// </para>
/// <para>
/// <b>Where something in the variable is a whole number</b> -- a floor or a ceiling of
/// <c>x^2</c>, of <c>sin(pi x/2)</c> -- the breaks are those points, which
/// <see cref="StepPieces"/> finds and proves to be all of them over a range with numeric
/// bounds; each piece is then integrated with its step a constant.
/// </para>
/// <para>
/// Offered only where every piece then resolves; an integral rewritten as an unevaluated sum
/// of unevaluated integrals is not an answer. Question I.2 of
/// <a href="https://github.com/asc-community/AngouriMath/issues/1212">#1212</a>, and the
Expand All @@ -65,16 +71,16 @@ internal static class BreakpointIntegration
{
/// <summary>
/// Whether the integrand can jump in <paramref name="x"/>: a piecewise whose conditions
/// mention it, or a floor or ceiling of it.
/// mention it, or a floor or ceiling of something in it.
/// </summary>
internal static bool HasABreak(Entity expr, Variable x)
=> expr.Nodes.Any(node => IsABreak(node, x));

private static bool IsABreak(Entity node, Variable x)
=> node switch
{
Floorf(var argument) => argument == x,
Ceilf(var argument) => argument == x,
Floorf(var argument) => argument.ContainsNode(x),
Ceilf(var argument) => argument.ContainsNode(x),
Piecewise piecewise => piecewise.Cases.Any(c => c.Predicate.ContainsNode(x)),
// A condition on the variable is a one-case piecewise whose other case is undefined.
Providedf provided => provided.Predicate.ContainsNode(x),
Expand All @@ -85,11 +91,45 @@ private static bool IsABreak(Entity node, Variable x)
{
if (expr.Nodes.Any(node => node is Piecewise or Providedf && IsABreak(node, x)))
return OverCaseBoundaries(expr, x, from, to);
if (expr.Nodes.Any(node => node is Floorf(var f) && f != x && f.ContainsNode(x) || node is Ceilf(var c) && c != x && c.ContainsNode(x)))
return OverStepPieces(expr, x, from, to);
if (HasAStep(expr, x))
return OverUnitIntervals(expr, x, from, to);
return null;
}

// ---- a floor or a ceiling of something in the variable: the pieces StepPieces proves -------

/// <summary>
/// The integral as the sum of the integrals of the pieces <see cref="StepPieces"/> writes the integrand in over
/// the range, each with its steps replaced by their values there, so with no jump in it: <c>floor(x^2)</c> from 0
/// to 2 is <c>(sqrt(2) - 1) + 2 (sqrt(3) - sqrt(2)) + 3 (2 - sqrt(3))</c>, which is <c>5 - sqrt(2) - sqrt(3)</c>.
/// A piece that is a point adds nothing. Where the pieces are not proved complete, or a piece does not integrate,
/// the integral is left as written. https://github.com/asc-community/AngouriMath/issues/1807
/// </summary>
private static Entity? OverStepPieces(Entity expr, Variable x, Entity from, Entity to)
{
if (from.Evaled is not Real lower || !lower.IsFinite || to.Evaled is not Real upper || !upper.IsFinite)
return null;
if (lower == upper)
return Integer.Zero;
if (upper < lower)
return OverStepPieces(expr, x, to, from) is { } reversed ? (-reversed).InnerSimplified : null;
if (StepPieces.Of(expr, x, from, to) is not { } pieces)
return null;
Entity total = Integer.Zero;
foreach (var @case in pieces.Cases)
{
if (@case.Predicate is not Set.Inf(_, Set.Interval interval))
continue;
var piece = @case.Expression.Integrate(x, interval.Left, interval.Right);
if (piece.Nodes.Any(node => node is Integralf))
return null;
total += piece;
}
return total.InnerSimplified;
}

// ---- finitely many breakpoints: a piecewise --------------------------------------------

private static Entity? OverCaseBoundaries(Entity expr, Variable x, Entity from, Entity to)
Expand Down
Loading
Loading