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
33 changes: 33 additions & 0 deletions BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ read first.
| | `RewriteRules.Power.Rules.Count` | `35` | `31` |
| | `RewriteRules.Common.Rules.Count` | `100` | `62` |
| | `RewriteRules.All.Sum(set => set.Rules.Count)` | `407` | `313` |
| **Loud** | `"max(x, y in S)".ToEntity()`, and `argmax`/`argmin` of any arguments | `max(x, y in S)` — the two-value max of `x` and the membership statement; `argmax(f, t in S)` was a parse error | `max(f(t), t in S)` reads as the largest value over the set: `max(sin(t)^3 cos(t), t in [0; pi/2])` is `3 sqrt(3) / 16`, and `argmax` and `argmin` are the points where it is taken |
| **Silent** | `RewriteRules.ExpandFactorialDivisions.Rules[0].Growth` | `Collects` — guessed from string length | `Unknown`; whether it collects depends on the offsets |
| **Silent** | `RewriteStep.Soundness` on a rewrite whose rule declares a tier — `RewriteRules.SetOperator` on `A /\ A`, and every rewrite of the nineteen sets described from their data form | `SoundUnderAssumptions` — its rule set's tier, which is the minimum over every rule in the set | `Sound` — the rule's own |
| **Silent** | `DerivationStep.Soundness` | its rule set's tier | the weakest tier any rewrite that actually fired inside the step holds at |
Expand Down Expand Up @@ -248,6 +249,38 @@ suspect was measured and ruled out.

[#717](https://github.com/asc-community/AngouriMath/issues/717).

### The extremum of an expression over a set, as a binder

An expression had no way to name its largest value over a set. `max` and `min` took two values and
returned the larger or smaller, and `max(f(t), t in S)` parsed as the two-value `max` of `f(t)` and
the membership statement `t in S` — a category error that stayed unevaluated. `argmax` and `argmin`
were not functions at all. Four binders now read the second argument as `variable in set` and bind
the variable over the expression and the set: `Maximumf`, `Minimumf`, `Argmaxf`, `Argminf`, spelt
`max(f, t in S)`, `min`, `argmax`, `argmin`, printed `\max_{t \in S} f` and
`\operatorname{argmax}_{t \in S} f` in LaTeX. The two-value `max(a, b)` is untouched, and a second
argument that is not `variable in set` — `max(x, y)`, or `max(x, 1 in S)` — stays the two-value form.

The value is answered over a finite set of numbers, by evaluating at each and comparing, and over a
closed interval with numeric ends for an expression whose extrema are all stationary — sums,
products, whole non-negative powers, sines, cosines, exponentials with a positive base — by
comparing the closed endpoints with the derivative's zeros inside, a periodic family of them
enumerated where it lands in the interval. The best candidate is checked against the expression
sampled along the interval, and the question is left as written where a sample beats it, since the
solver's list of zeros is not guaranteed complete. An open endpoint is not a candidate, so
`max(x, x in [0; 1))` has no maximum and stays as written; a symbolic set or end, a pole, a kink,
and a set with a symbol in it are all left as written. `argmax` and `argmin` return the set of
points. Question I.6 of [#1212](https://github.com/asc-community/AngouriMath/issues/1212). Both
columns measured on a build, `27ed5b53` against this change.

| | Was | Is |
|---|---|---|
| `"max(sin(t)^3 * cos(t), t in [0; pi/2])".ToEntity().Simplify()` | `max(sin(t)^3 * cos(t), t in [0; pi/2])` — a two-value `max` with a membership statement, unevaluated | `3/16 * sqrt(3)` |
| `"argmax(sin(t)^3 * cos(t), t in [0; pi/2])".ToEntity()` | a parse error — `argmax` was not a function | `{ pi/3 }` once simplified |
| `"max(x^3 - 3x, x in [-2; 2])".ToEntity().Simplify()`, and `min` | a two-value `max`/`min` with a membership statement | `2`, `-2` |
| `"max(x^2, x in { 1, -3, 2 })".ToEntity().Simplify()`, `argmax` of the same | `max(x^2, x in { 1, -3, 2 })` | `9`, `{ -3 }` |
| `"max(1, 2)".ToEntity().Evaled`, `max(x, y)` | `2`, `max(x, y)` | the same — the two-value form is untouched |
| `"max(x, x in [0; 1))".ToEntity().Simplify()` | a two-value `max` with a membership statement | left as written — the value at an open end is not attained |

### A polynomial summand is summed in closed form

A summation wrote itself out term by term where the bounds were concrete and there were fewer
Expand Down
6 changes: 6 additions & 0 deletions Sources/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,12 @@ file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed
[AngouriMath/Functions/Continuous/Integration/BreakpointIntegration.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/ExtremumOverSet.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/ExtremumTest.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/BreakpointIntegrationTest.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
27 changes: 27 additions & 0 deletions Sources/AngouriMath/Convenience/MathS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7013,6 +7013,33 @@ public static Entity Limit(Entity expr, Entity var, Entity dest, ApproachFrom ap
public static Entity Sum(Entity expr, Entity var, Entity from, Entity to)
=> new Summationf(expr, var, from, to);

/// <summary>
/// The largest value <paramref name="expr"/> takes as <paramref name="var"/> ranges over
/// <paramref name="over"/>, written <c>max(expr, var in over)</c>. Answered over a finite
/// set of numbers, and over a closed interval with numeric ends for an expression whose
/// extrema are all stationary; left as written otherwise, and where the value is not
/// attained. https://github.com/asc-community/AngouriMath/issues/1212
/// </summary>
/// <example>
/// <code>
/// Console.WriteLine(MathS.Maximum("sin(t)^3 * cos(t)", "t", "[0; pi/2]").Simplify());
/// </code>
/// Prints
/// <code>
/// 3/16 * sqrt(3)
/// </code>
/// </example>
public static Entity Maximum(Entity expr, Entity var, Entity over) => new Maximumf(expr, var, over);

/// <summary>The smallest value; see <see cref="Maximum"/>.</summary>
public static Entity Minimum(Entity expr, Entity var, Entity over) => new Minimumf(expr, var, over);

/// <summary>The set of points where <see cref="Maximum"/> is taken, written <c>argmax(expr, var in over)</c>.</summary>
public static Entity Argmax(Entity expr, Entity var, Entity over) => new Argmaxf(expr, var, over);

/// <summary>The set of points where <see cref="Minimum"/> is taken, written <c>argmin(expr, var in over)</c>.</summary>
public static Entity Argmin(Entity expr, Entity var, Entity over) => new Argminf(expr, var, over);

/// <summary>
/// A product of <paramref name="expr"/> as <paramref name="var"/> runs from
/// <paramref name="from"/> to <paramref name="to"/> inclusive. Mirrors
Expand Down
6 changes: 4 additions & 2 deletions Sources/AngouriMath/Core/Antlr/AngouriMath.g
Original file line number Diff line number Diff line change
Expand Up @@ -460,8 +460,10 @@ atom returns[Entity value]
| 'round(' args = function_arguments ')' { Assert("round", 1, $args.list.Count); $value = MathS.Round($args.list[0]); }
/* min and max take any number of arguments, as they do everywhere else, and fold left
into the binary node. One argument is that argument. */
| 'min(' args = function_arguments ')' { AssertAtLeast("min", 1, $args.list.Count); $value = $args.list.Aggregate((a, b) => MathS.Min(a, b)); }
| 'max(' args = function_arguments ')' { AssertAtLeast("max", 1, $args.list.Count); $value = $args.list.Aggregate((a, b) => MathS.Max(a, b)); }
| 'min(' args = function_arguments ')' { AssertAtLeast("min", 1, $args.list.Count); $value = $args.list.Count == 2 && $args.list[1] is Entity.Set.Inf { Element: Variable } minRange ? MathS.Minimum($args.list[0], minRange.Element, minRange.SupSet) : $args.list.Aggregate((a, b) => MathS.Min(a, b)); }
| 'max(' args = function_arguments ')' { AssertAtLeast("max", 1, $args.list.Count); $value = $args.list.Count == 2 && $args.list[1] is Entity.Set.Inf { Element: Variable } maxRange ? MathS.Maximum($args.list[0], maxRange.Element, maxRange.SupSet) : $args.list.Aggregate((a, b) => MathS.Max(a, b)); }
| 'argmax(' args = function_arguments ')' { Assert("argmax", 2, $args.list.Count); $value = $args.list[1] is Entity.Set.Inf { Element: Variable } argmaxRange ? MathS.Argmax($args.list[0], argmaxRange.Element, argmaxRange.SupSet) : throw new InvalidArgumentParseException("argmax expects its second argument to say which variable ranges over which set, as in argmax(f(t), t in S)"); }
| 'argmin(' args = function_arguments ')' { Assert("argmin", 2, $args.list.Count); $value = $args.list[1] is Entity.Set.Inf { Element: Variable } argminRange ? MathS.Argmin($args.list[0], argminRange.Element, argminRange.SupSet) : throw new InvalidArgumentParseException("argmin expects its second argument to say which variable ranges over which set, as in argmin(f(t), t in S)"); }
| 'gcd(' args = function_arguments ')' { AssertAtLeast("gcd", 1, $args.list.Count); $value = $args.list.Aggregate((a, b) => MathS.Gcd(a, b)); }

/* Names the library does not have. Each is a function every other CAS spells this way, so
Expand Down
6 changes: 5 additions & 1 deletion Sources/AngouriMath/Core/Antlr/AngouriMath.interp

Large diffs are not rendered by default.

40 changes: 22 additions & 18 deletions Sources/AngouriMath/Core/Antlr/AngouriMath.tokens
Original file line number Diff line number Diff line change
Expand Up @@ -145,14 +145,16 @@ T__143=144
T__144=145
T__145=146
T__146=147
NEWLINE=148
NUMBER=149
SPECIALSET=150
BOOLEAN=151
NAN=152
VARIABLE=153
COMMENT=154
WS=155
T__147=148
T__148=149
NEWLINE=150
NUMBER=151
SPECIALSET=152
BOOLEAN=153
NAN=154
VARIABLE=155
COMMENT=156
WS=157
'!'=1
'^'=2
'-'=3
Expand Down Expand Up @@ -291,13 +293,15 @@ WS=155
'round('=136
'min('=137
'max('=138
'gcd('=139
'trunc('=140
'lcm('=141
'erf('=142
'conjugate('=143
'domain('=144
'piecewise('=145
'apply('=146
'lambda('=147
'NaN'=152
'argmax('=139
'argmin('=140
'gcd('=141
'trunc('=142
'lcm('=143
'erf('=144
'conjugate('=145
'domain('=146
'piecewise('=147
'apply('=148
'lambda('=149
'NaN'=154
Loading
Loading