From 9f90281705b5b75aa658f1b7b2a93c07359085bd Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Sun, 9 Aug 2026 00:01:51 +0000 Subject: [PATCH 1/2] Add floor and ceil (#809) Both were refused by name since #733. They exist now, as nodes rather than as sugar, with every convention measured against SymPy 1.14 rather than chosen -- AGENTS.md asks for exactly that when a convention has to be settled. What the measurement decided, and in three places it is not what the issue assumed: - Rounding is toward the infinities, not toward zero: floor(-3/2) is -2 and ceil(-3/2) is -1. - A complex argument is taken componentwise, so floor(3/2 + 5/2i) is 1 + 2i. SymPy and Mathematica agree, and it is the only reading under which floor of a real keeps its meaning when the imaginary part is zero. - The derivative is 0 provided the argument is not an integer. The issue guessed "zero almost everywhere"; SymPy declines to answer at all. Stating the condition says more than either, and it is what Signumf and Absf already do -- this library has Providedf and SymPy does not. ceiling( is accepted because that is SymPy's spelling, so an expression copied from there parses; Stringize prints the short ceil(, which is what the round trip pins. Inverting them is many-to-one: floor(f(x)) = v is solvable only for integer v and then f(x) is anywhere in [v, v + 1). So the inverse is a parameter over that interval, the same device Signumf and Absf use, and floor(x) - 3 = 0 now answers { 3 + t_1 provided t_1 in RR and t_1 >= 0 and t_1 < 1 } where #733 recorded it answering { 3 / floor }. The grammar was regenerated with JDK 25 and the committed ANTLR 4.13.1 jar. The unmodified grammar was regenerated first and reproduced the checked-in parser byte for byte, so the diff here is the new rules and not a toolchain difference. Seven tests in MissingFunctionNamesRefusedTest asserted these names were refused. That is the answer getting better rather than a test that was pinning a fudge: the refusal cases move to names still missing, and the equation from the original report is now asserted to be answered instead of refused. Tests: 5872 passing, 0 failed, 14 skipped; F# 130. Co-Authored-By: Claude Opus 5 (1M context) --- BREAKING-CHANGES.md | 28 ++++ Sources/.editorconfig | 5 + Sources/AngouriMath/Convenience/MathS.cs | 57 ++++++++ Sources/AngouriMath/Core/Antlr/AngouriMath.g | 8 +- .../Core/Antlr/AngouriMathParser.cs | 6 +- Sources/AngouriMath/Core/Domains.Classes.cs | 15 ++ .../Entity.Continuous.Definition.cs | 4 + .../Entity.Continuous.Floors.Classes.cs | 56 ++++++++ .../Functions/Continuous/Differentiation.cs | 19 +++ .../EquationSolver/InvertNode.Classes.cs | 36 +++++ ...aluation.Continuous.Arithmetics.Classes.cs | 45 ++++++ .../Output/Latex/Latex.Arithmetics.Classes.cs | 14 ++ .../ToString/ToString.Arithmetics.Classes.cs | 16 +++ .../ToSympy/ToSympy.Arithmetics.Classes.cs | 13 ++ Sources/AngouriMath/Functions/Substitute.cs | 14 ++ .../Functions/TreeAnalyzer/Sort.Classes.cs | 12 ++ .../UnitTests/Convenience/FloorCeilTest.cs | 136 ++++++++++++++++++ .../MissingFunctionNamesRefusedTest.cs | 45 ++++-- 18 files changed, 515 insertions(+), 14 deletions(-) create mode 100644 Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Floors.Classes.cs create mode 100644 Sources/Tests/UnitTests/Convenience/FloorCeilTest.cs diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md index 4b216b673..bc986a28c 100644 --- a/BREAKING-CHANGES.md +++ b/BREAKING-CHANGES.md @@ -49,6 +49,7 @@ read first. | loud | `Compile` over a missing variable | `KeyNotFoundException` | `UncompilableNodeException` | | loud | `Expand` of a quotient of factorials | `AngouriBugException` | the expanded polynomial | | loud | parsing a `provided` in a parenthesised comma list | `NullReferenceException` | `UnhandledParseException` | +| loud | `floor(x)`, `ceil(x)`, `ceiling(x)` | `UnrecognizedFunctionParseException` | the functions | | loud | the target frameworks | `net7.0;netstandard2.0` | `netstandard2.0;net8.0;net10.0` | | **silent** | `abs(x) = c` for a negative `c` | a set of non-solutions | the empty set | @@ -1290,6 +1291,33 @@ throw. `Simplify` was never affected — it answered `1 + x` throughout. Issue [#817](https://github.com/asc-community/AngouriMath/issues/817). +### `floor` and `ceil` exist, so they no longer raise + +```csharp +"floor(x)".ToEntity(); +// was UnrecognizedFunctionParseException: floor is not a function this library has +// is floor(x) + +"floor(x) - 3 = 0".ToEntity().Solve("x"); +// was UnrecognizedFunctionParseException +// is { 3 + t_1 provided t_1 in RR and t_1 >= 0 and t_1 < 1 } +``` + +`ceiling(` is accepted as well, since that is SymPy's spelling; `Stringize` prints the short +`ceil(`. Both round toward the infinities rather than toward zero — `floor(-3/2)` is `-2` — and both +are taken componentwise on a complex argument, which is what SymPy and Mathematica do. Every value +in the test file was measured against SymPy 1.14 rather than reasoned about. + +**If you were catching `UnrecognizedFunctionParseException` around these names, that is now dead +code.** Nothing else moves: `round`, `trunc`, `min`, `max`, `gcd` and `lcm` are still refused by +name, and `floor` on its own — without a bracket — is still an ordinary variable. + +The derivative is `0 provided not x in ZZ`: flat between the integers, undefined at each of them. +SymPy leaves that derivative unevaluated; this library states the condition instead, which is the +stance `Signumf` and `Absf` already take. + +Issue [#809](https://github.com/asc-community/AngouriMath/issues/809). + ### A parse failure no longer escapes as a `NullReferenceException` ```csharp diff --git a/Sources/.editorconfig b/Sources/.editorconfig index 876c81824..849f1b983 100644 --- a/Sources/.editorconfig +++ b/Sources/.editorconfig @@ -29,3 +29,8 @@ file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed [Tests/UnitTests/Core/Transformations/*.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 + +# A new file in a directory whose other files predate it, so the section is on the file +# rather than the folder. +[AngouriMath/Core/Entity/Continuous/Entity.Continuous.Floors.Classes.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/Convenience/MathS.cs b/Sources/AngouriMath/Convenience/MathS.cs index 2a6d73ed2..490f578f1 100644 --- a/Sources/AngouriMath/Convenience/MathS.cs +++ b/Sources/AngouriMath/Convenience/MathS.cs @@ -973,6 +973,63 @@ public static Integer GreatestCommonDivisor(Integer a, Integer b) [MethodImpl(MethodImplOptions.AggressiveInlining), NativeExport] public static Entity Abs(Entity a) => new Absf(a); + /// + /// The greatest integer not above . + /// + /// The argument to take the floor of. + /// The floor of the argument. + /// + /// Toward negative infinity, not toward zero: floor(-3/2) is -2. On a + /// complex argument it is taken componentwise, which is what SymPy and Mathematica + /// both do. + /// + /// + /// + /// using System; + /// using static AngouriMath.MathS; + /// + /// Console.WriteLine(Floor("3/2").Simplify()); + /// Console.WriteLine(Floor("-3/2").Simplify()); + /// Console.WriteLine(Floor("x")); + /// + /// Prints + /// + /// 1 + /// -2 + /// floor(x) + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Entity Floor(Entity a) => new Floorf(a); + + /// + /// The least integer not below . + /// + /// The argument to take the ceiling of. + /// The ceiling of the argument. + /// + /// Toward positive infinity, not away from zero: ceil(-3/2) is -1. + /// Componentwise on a complex argument, as is. + /// + /// + /// + /// using System; + /// using static AngouriMath.MathS; + /// + /// Console.WriteLine(Ceil("3/2").Simplify()); + /// Console.WriteLine(Ceil("-3/2").Simplify()); + /// Console.WriteLine(Ceil("x")); + /// + /// Prints + /// + /// 2 + /// -1 + /// ceil(x) + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Entity Ceil(Entity a) => new Ceilf(a); + /// Boolean negation /// Wikipedia /// Argument node of which Negation function will be taken diff --git a/Sources/AngouriMath/Core/Antlr/AngouriMath.g b/Sources/AngouriMath/Core/Antlr/AngouriMath.g index 4e9d1034d..14f86da08 100644 --- a/Sources/AngouriMath/Core/Antlr/AngouriMath.g +++ b/Sources/AngouriMath/Core/Antlr/AngouriMath.g @@ -407,15 +407,17 @@ atom returns[Entity value] | 'sign(' args = function_arguments ')' { Assert("sign", 1, $args.list.Count); $value = MathS.Signum($args.list[0]); } | 'abs(' args = function_arguments ')' { Assert("abs", 1, $args.list.Count); $value = MathS.Abs($args.list[0]); } | 'phi(' args = function_arguments ')' { Assert("phi", 1, $args.list.Count); $value = MathS.NumberTheory.Phi($args.list[0]); } + | 'floor(' args = function_arguments ')' { Assert("floor", 1, $args.list.Count); $value = MathS.Floor($args.list[0]); } + | 'ceil(' args = function_arguments ')' { Assert("ceil", 1, $args.list.Count); $value = MathS.Ceil($args.list[0]); } + /* SymPy's spelling, accepted so that an expression copied from there parses. Stringize + prints the short form, which is what the round-trip test pins. */ + | 'ceiling(' args = function_arguments ')' { Assert("ceiling", 1, $args.list.Count); $value = MathS.Ceil($args.list[0]); } /* Names the library does not have. Each is a function every other CAS spells this way, so a caller reaches for it, and without these rules each is silently read as a product -- see NotImplementedFunction above. Refusing is not the feature; it is the difference between a missing function and a wrong answer. */ - | 'floor(' args = function_arguments ')' { $value = NotImplementedFunction("floor", "rounding functions"); } - | 'ceil(' args = function_arguments ')' { $value = NotImplementedFunction("ceil", "rounding functions"); } - | 'ceiling(' args = function_arguments ')' { $value = NotImplementedFunction("ceiling", "rounding functions"); } | 'round(' args = function_arguments ')' { $value = NotImplementedFunction("round", "rounding functions"); } | 'trunc(' args = function_arguments ')' { $value = NotImplementedFunction("trunc", "rounding functions"); } | 'min(' args = function_arguments ')' { $value = NotImplementedFunction("min", "minimum or maximum function"); } diff --git a/Sources/AngouriMath/Core/Antlr/AngouriMathParser.cs b/Sources/AngouriMath/Core/Antlr/AngouriMathParser.cs index 6fb5f8e8c..23ea8b798 100644 --- a/Sources/AngouriMath/Core/Antlr/AngouriMathParser.cs +++ b/Sources/AngouriMath/Core/Antlr/AngouriMathParser.cs @@ -3064,7 +3064,7 @@ public AtomContext atom() { _localctx.args = function_arguments(); State = 806; Match(T__40); - _localctx.value = NotImplementedFunction("floor", "rounding functions"); + Assert("floor", 1, _localctx.args.list.Count); _localctx.value = MathS.Floor(_localctx.args.list[0]); } break; case 103: @@ -3076,7 +3076,7 @@ public AtomContext atom() { _localctx.args = function_arguments(); State = 811; Match(T__40); - _localctx.value = NotImplementedFunction("ceil", "rounding functions"); + Assert("ceil", 1, _localctx.args.list.Count); _localctx.value = MathS.Ceil(_localctx.args.list[0]); } break; case 104: @@ -3088,7 +3088,7 @@ public AtomContext atom() { _localctx.args = function_arguments(); State = 816; Match(T__40); - _localctx.value = NotImplementedFunction("ceiling", "rounding functions"); + Assert("ceiling", 1, _localctx.args.list.Count); _localctx.value = MathS.Ceil(_localctx.args.list[0]); } break; case 105: diff --git a/Sources/AngouriMath/Core/Domains.Classes.cs b/Sources/AngouriMath/Core/Domains.Classes.cs index f3cd6f220..982f4bbf7 100644 --- a/Sources/AngouriMath/Core/Domains.Classes.cs +++ b/Sources/AngouriMath/Core/Domains.Classes.cs @@ -200,6 +200,21 @@ partial record Absf public override Domain Codomain { get; protected init; } = Domain.Real; } + partial record Floorf + { + // Complex rather than Integer: taken componentwise, floor of a complex number + // is a Gaussian integer, and there is no domain for those. The codomain of the + // real case is stated by the value, not by this. + /// + public override Domain Codomain { get; protected init; } = Domain.Complex; + } + + partial record Ceilf + { + /// + public override Domain Codomain { get; protected init; } = Domain.Complex; + } + partial record Boolean { /// diff --git a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Definition.cs b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Definition.cs index 55f1cfe88..3e58b7d80 100644 --- a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Definition.cs +++ b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Definition.cs @@ -127,5 +127,9 @@ public abstract partial record CalculusOperator(Entity Expression, Entity Var) : public Entity Signum() => new Signumf(this); /// public Entity Abs() => new Absf(this); + /// + public Entity Floor() => new Floorf(this); + /// + public Entity Ceil() => new Ceilf(this); } } diff --git a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Floors.Classes.cs b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Floors.Classes.cs new file mode 100644 index 000000000..05f94f543 --- /dev/null +++ b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Floors.Classes.cs @@ -0,0 +1,56 @@ +// +// 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; + +namespace AngouriMath +{ + partial record Entity + { +#pragma warning disable CS1591 // only while records' parameters cannot be documented + /// + /// A node of floor: the greatest integer not above the argument. + /// + /// + /// On a complex argument it is taken componentwise, so that + /// floor(3/2 + 5/2i) is 1 + 2i. That is what SymPy and Mathematica + /// both do, and it is the only reading under which floor of a real number + /// keeps its meaning when the imaginary part happens to be zero. + /// + public sealed partial record Floorf(Entity Argument) : Function, IUnaryNode + { + public Entity NodeChild => Argument; + + private Floorf New(Entity arg) => + ReferenceEquals(Argument, arg) ? this : new(arg); + /// + public override Entity Replace(Func func) => func(New(Argument.Replace(func))); + /// + protected override Entity[] InitDirectChildren() => new[] { Argument }; + } + + /// + /// A node of ceil: the least integer not below the argument. + /// + /// + /// Componentwise on a complex argument, for the same reason as + /// . + /// + public sealed partial record Ceilf(Entity Argument) : Function, IUnaryNode + { + public Entity NodeChild => Argument; + + private Ceilf New(Entity arg) => + ReferenceEquals(Argument, arg) ? this : new(arg); + /// + public override Entity Replace(Func func) => func(New(Argument.Replace(func))); + /// + protected override Entity[] InitDirectChildren() => new[] { Argument }; + } +#pragma warning restore CS1591 // only while records' parameters cannot be documented + } +} diff --git a/Sources/AngouriMath/Functions/Continuous/Differentiation.cs b/Sources/AngouriMath/Functions/Continuous/Differentiation.cs index bef6ba8df..f8a465ec5 100644 --- a/Sources/AngouriMath/Functions/Continuous/Differentiation.cs +++ b/Sources/AngouriMath/Functions/Continuous/Differentiation.cs @@ -341,6 +341,25 @@ protected override Entity InnerDifferentiate(Variable variable) => MathS.Signum(Argument).Provided(!Argument.EqualTo(Integer.Zero)) * Argument.InnerDifferentiate(variable); } + partial record Floorf + { + // Flat between consecutive integers and discontinuous at each of them, so the + // derivative is 0 wherever it exists and nowhere at an integer argument. Saying + // that with a condition is the stance Signumf and Absf take above; SymPy + // instead leaves the derivative unevaluated, which says less, and this library + // has Providedf to say more with. + /// + protected override Entity InnerDifferentiate(Variable variable) + => Integer.Zero.Provided(!Argument.In(MathS.Sets.Z)); + } + + partial record Ceilf + { + /// + protected override Entity InnerDifferentiate(Variable variable) + => Integer.Zero.Provided(!Argument.In(MathS.Sets.Z)); + } + partial record Providedf { /// diff --git a/Sources/AngouriMath/Functions/Continuous/Solvers/EquationSolver/InvertNode.Classes.cs b/Sources/AngouriMath/Functions/Continuous/Solvers/EquationSolver/InvertNode.Classes.cs index bee882dda..044692da2 100644 --- a/Sources/AngouriMath/Functions/Continuous/Solvers/EquationSolver/InvertNode.Classes.cs +++ b/Sources/AngouriMath/Functions/Continuous/Solvers/EquationSolver/InvertNode.Classes.cs @@ -273,6 +273,42 @@ private protected override IEnumerable InvertNode(Entity value, Entity x } } + partial record Floorf + { + // floor(f(x)) = value + // solvable only where value is an integer, and then f(x) is anywhere in the + // half-open interval [value, value + 1) -- so the preimage is a parameter t in + // [0, 1) rather than a point, which is the same device Signumf and Absf use for + // their own many-to-one inverses. + private protected override IEnumerable InvertNode(Entity value, Entity x) + { + var t = Variable.CreateUnique(value + Argument, "t"); + return Argument.Invert(value + t, x) + .Select(c => c.Provided( + value.In(MathS.Sets.Z) + & t.In(MathS.Sets.R) + & new GreaterOrEqualf(t, 0) + & new Lessf(t, 1))); + } + } + + partial record Ceilf + { + // ceil(f(x)) = value + // likewise integer-valued, with f(x) in (value - 1, value] -- so the parameter + // is subtracted rather than added. + private protected override IEnumerable InvertNode(Entity value, Entity x) + { + var t = Variable.CreateUnique(value + Argument, "t"); + return Argument.Invert(value - t, x) + .Select(c => c.Provided( + value.In(MathS.Sets.Z) + & t.In(MathS.Sets.R) + & new GreaterOrEqualf(t, 0) + & new Lessf(t, 1))); + } + } + partial record Boolean { private protected override IEnumerable InvertNode(Entity value, Entity x) diff --git a/Sources/AngouriMath/Functions/Evaluation/Evaluation.Continuous/Evaluation.Continuous.Arithmetics.Classes.cs b/Sources/AngouriMath/Functions/Evaluation/Evaluation.Continuous/Evaluation.Continuous.Arithmetics.Classes.cs index 4e8d8c827..1cdfb8308 100644 --- a/Sources/AngouriMath/Functions/Evaluation/Evaluation.Continuous/Evaluation.Continuous.Arithmetics.Classes.cs +++ b/Sources/AngouriMath/Functions/Evaluation/Evaluation.Continuous/Evaluation.Continuous.Arithmetics.Classes.cs @@ -266,6 +266,51 @@ protected override Entity InnerSimplify(bool isExact) (@this, a) => ((Signumf)@this).New(a), isExact); } + public partial record Floorf + { + // Defined everywhere in the complex plane, taken componentwise. + private protected override Entity IntrinsicCondition => Boolean.True; + + /// + protected override Entity InnerSimplify(bool isExact) + => ExpandOnOneArgument(Argument, + a => a switch + { + // An integer is already its own floor, and it stays exact. + Integer n => n, + Rational n => Integer.Create(n.EDecimal.Floor().ToEInteger()), + Real n when !isExact => Integer.Create(n.EDecimal.Floor().ToEInteger()), + Complex n when !isExact => Complex.Create( + n.RealPart.EDecimal.Floor(), n.ImaginaryPart.EDecimal.Floor()), + // Idempotent: the floor of an integer is that integer, and floor + // always produces one. + Floorf or Ceilf => a, + _ => null + }, + (@this, a) => ((Floorf)@this).New(a), isExact); + } + + public partial record Ceilf + { + // Defined everywhere in the complex plane, taken componentwise. + private protected override Entity IntrinsicCondition => Boolean.True; + + /// + protected override Entity InnerSimplify(bool isExact) + => ExpandOnOneArgument(Argument, + a => a switch + { + Integer n => n, + Rational n => Integer.Create(n.EDecimal.Ceiling().ToEInteger()), + Real n when !isExact => Integer.Create(n.EDecimal.Ceiling().ToEInteger()), + Complex n when !isExact => Complex.Create( + n.RealPart.EDecimal.Ceiling(), n.ImaginaryPart.EDecimal.Ceiling()), + Floorf or Ceilf => a, + _ => null + }, + (@this, a) => ((Ceilf)@this).New(a), isExact); + } + public partial record Absf { // Absolute value is defined everywhere in the complex plane diff --git a/Sources/AngouriMath/Functions/Output/Latex/Latex.Arithmetics.Classes.cs b/Sources/AngouriMath/Functions/Output/Latex/Latex.Arithmetics.Classes.cs index 47f354f20..1a3348501 100644 --- a/Sources/AngouriMath/Functions/Output/Latex/Latex.Arithmetics.Classes.cs +++ b/Sources/AngouriMath/Functions/Output/Latex/Latex.Arithmetics.Classes.cs @@ -158,6 +158,20 @@ public override string Latexise() => $@"\left|{Argument.Latexise()}\right|"; } + partial record Floorf + { + /// + public override string Latexise() + => $@"\left\lfloor{{{Argument.Latexise()}}}\right\rfloor"; + } + + partial record Ceilf + { + /// + public override string Latexise() + => $@"\left\lceil{{{Argument.Latexise()}}}\right\rceil"; + } + partial record Phif { /// diff --git a/Sources/AngouriMath/Functions/Output/ToString/ToString.Arithmetics.Classes.cs b/Sources/AngouriMath/Functions/Output/ToString/ToString.Arithmetics.Classes.cs index d9211893b..2c29467f5 100644 --- a/Sources/AngouriMath/Functions/Output/ToString/ToString.Arithmetics.Classes.cs +++ b/Sources/AngouriMath/Functions/Output/ToString/ToString.Arithmetics.Classes.cs @@ -109,6 +109,22 @@ public partial record Absf public override string ToString() => Stringize(); } + public partial record Floorf + { + /// + public override string Stringize() => $"floor({Argument.Stringize()})"; + /// + public override string ToString() => Stringize(); + } + + public partial record Ceilf + { + /// + public override string Stringize() => $"ceil({Argument.Stringize()})"; + /// + public override string ToString() => Stringize(); + } + public partial record Factorialf { /// diff --git a/Sources/AngouriMath/Functions/Output/ToSympy/ToSympy.Arithmetics.Classes.cs b/Sources/AngouriMath/Functions/Output/ToSympy/ToSympy.Arithmetics.Classes.cs index 7079c1544..1bbc32fec 100644 --- a/Sources/AngouriMath/Functions/Output/ToSympy/ToSympy.Arithmetics.Classes.cs +++ b/Sources/AngouriMath/Functions/Output/ToSympy/ToSympy.Arithmetics.Classes.cs @@ -64,6 +64,19 @@ internal override string ToSymPy() => $@"sympy.Abs({Argument.ToSymPy()})"; } + public partial record Floorf + { + internal override string ToSymPy() + => $@"sympy.floor({Argument.ToSymPy()})"; + } + + public partial record Ceilf + { + // SymPy spells it in full; `ceil` is not a name it has. + internal override string ToSymPy() + => $@"sympy.ceiling({Argument.ToSymPy()})"; + } + public partial record Phif { internal override string ToSymPy() => $"sympy.totient({Argument.ToSymPy()})"; diff --git a/Sources/AngouriMath/Functions/Substitute.cs b/Sources/AngouriMath/Functions/Substitute.cs index 7d9ed6c48..1627407a3 100644 --- a/Sources/AngouriMath/Functions/Substitute.cs +++ b/Sources/AngouriMath/Functions/Substitute.cs @@ -172,6 +172,20 @@ public override Entity Substitute(Entity x, Entity value) => this == x ? value : New(Argument.Substitute(x, value)); } + partial record Floorf + { + /// + public override Entity Substitute(Entity x, Entity value) + => this == x ? value : New(Argument.Substitute(x, value)); + } + + partial record Ceilf + { + /// + public override Entity Substitute(Entity x, Entity value) + => this == x ? value : New(Argument.Substitute(x, value)); + } + partial record Boolean { /// diff --git a/Sources/AngouriMath/Functions/TreeAnalyzer/Sort.Classes.cs b/Sources/AngouriMath/Functions/TreeAnalyzer/Sort.Classes.cs index 9e682a28c..d6eddeae8 100644 --- a/Sources/AngouriMath/Functions/TreeAnalyzer/Sort.Classes.cs +++ b/Sources/AngouriMath/Functions/TreeAnalyzer/Sort.Classes.cs @@ -203,6 +203,18 @@ private protected override string SortHashName(SortLevel level) => Choice(level, "sgnabs_", "abs_", "abs_"); } + public partial record Floorf + { + private protected override string SortHashName(SortLevel level) + => Choice(level, "floorceil_", "floor_", "floor_"); + } + + public partial record Ceilf + { + private protected override string SortHashName(SortLevel level) + => Choice(level, "floorceil_", "ceil_", "ceil_"); + } + partial record Boolean { private protected override string SortHashName(SortLevel level) diff --git a/Sources/Tests/UnitTests/Convenience/FloorCeilTest.cs b/Sources/Tests/UnitTests/Convenience/FloorCeilTest.cs new file mode 100644 index 000000000..c2c5ccf94 --- /dev/null +++ b/Sources/Tests/UnitTests/Convenience/FloorCeilTest.cs @@ -0,0 +1,136 @@ +// +// 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.Linq; +using AngouriMath; +using AngouriMath.Extensions; +using Xunit; + +namespace AngouriMath.Tests.Convenience +{ + /// + /// floor and ceil#809. + /// + /// + /// The expected values are SymPy 1.14's, measured rather than reasoned about, as + /// AGENTS.md asks when a convention has to be chosen. The ones that matter are the + /// negative arguments — rounding toward the infinities rather than toward zero — and the + /// complex case, which both SymPy and Mathematica take componentwise. + /// + [Trait("Area", "Convenience")] + public sealed class FloorCeilTest + { + [Theory] + [InlineData("floor(3/2)", 1)] + [InlineData("floor(-3/2)", -2)] + [InlineData("floor(-1/2)", -1)] + [InlineData("floor(5/2)", 2)] + [InlineData("floor(-5/2)", -3)] + [InlineData("floor(2)", 2)] + [InlineData("floor(-2)", -2)] + [InlineData("ceil(3/2)", 2)] + [InlineData("ceil(-3/2)", -1)] + [InlineData("ceil(-1/2)", 0)] + [InlineData("ceil(5/2)", 3)] + [InlineData("ceil(-5/2)", -2)] + [InlineData("ceil(2)", 2)] + [InlineData("ceil(-2)", -2)] + public void TheValueIsWhatSymPyGives(string input, int expected) + => Assert.Equal(Entity.Number.Integer.Create(expected), input.ToEntity().Simplify()); + + // Componentwise, so that floor of a real keeps its meaning when the imaginary part + // happens to be zero. + [Theory] + [InlineData("floor(3/2 + 5/2 * i)", "1 + 2i")] + [InlineData("ceil(3/2 + 5/2 * i)", "2 + 3i")] + [InlineData("floor(-3/2 - 5/2 * i)", "-2 - 3i")] + [InlineData("ceil(-3/2 - 5/2 * i)", "-1 - 2i")] + public void AComplexArgumentIsTakenComponentwise(string input, string expected) + => Assert.Equal(expected.ToEntity().EvalNumerical(), input.ToEntity().EvalNumerical()); + + // Both produce an integer, and both leave one alone. + [Theory] + [InlineData("floor(floor(x))", "floor(x)")] + [InlineData("ceil(ceil(x))", "ceil(x)")] + [InlineData("floor(ceil(x))", "ceil(x)")] + [InlineData("ceil(floor(x))", "floor(x)")] + public void ApplyingItTwiceChangesNothing(string input, string expected) + => Assert.Equal(expected.ToEntity(), input.ToEntity().Simplify()); + + [Theory] + [InlineData("floor(x)")] + [InlineData("ceil(x)")] + [InlineData("floor(x + y)")] + [InlineData("ceil(sin(x))")] + public void ASymbolicArgumentIsLeftAlone(string input) + => Assert.Equal(input.ToEntity(), input.ToEntity().Simplify()); + + // Flat between the integers and discontinuous at each of them, so the derivative is + // zero where it exists and the condition says where that is. SymPy declines to + // answer at all here; this library can say more, because it has Providedf. + [Theory] + [InlineData("floor(x)")] + [InlineData("ceil(x)")] + public void TheDerivativeIsZeroAwayFromTheIntegers(string input) + { + var derivative = input.ToEntity().Differentiate("x"); + var provided = Assert.IsType(derivative); + Assert.Equal(Entity.Number.Integer.Create(0), provided.Expression); + } + + [Theory] + [InlineData("floor(x)", @"\left\lfloor{x}\right\rfloor")] + [InlineData("ceil(x)", @"\left\lceil{x}\right\rceil")] + public void TheLatexIsTheUsualBrackets(string input, string expected) + => Assert.Equal(expected, input.ToEntity().Latexise()); + + // Stringize prints the short spelling, and SymPy's `ceiling` is accepted on the way + // in so that an expression copied from there parses. + [Theory] + [InlineData("floor(x)", "floor(x)")] + [InlineData("ceil(x)", "ceil(x)")] + [InlineData("ceiling(x)", "ceil(x)")] + public void ItPrintsTheShortSpellingAndParsesBoth(string input, string expected) + => Assert.Equal(expected, input.ToEntity().Stringize()); + + [Theory] + [InlineData("floor(x)")] + [InlineData("ceil(x)")] + [InlineData("floor(x) + ceil(y)")] + public void ThePrintedFormParsesBackToTheSameExpression(string input) + => Assert.Equal(input.ToEntity(), input.ToEntity().Stringize().ToEntity()); + + [Theory] + [InlineData("floor(x)", "7/2", 3)] + [InlineData("ceil(x)", "7/2", 4)] + [InlineData("floor(x)", "-7/2", -4)] + [InlineData("ceil(x)", "-7/2", -3)] + public void SubstitutingReachesTheValue(string input, string at, int expected) + => Assert.Equal(Entity.Number.Integer.Create(expected), + input.ToEntity().Substitute("x", at.ToEntity()).Simplify()); + + /// + /// floor(x) = 3 holds on the whole of [3, 4), so the inverse is a + /// parameter over that interval rather than a point. What it must not do is invent a + /// single root. + /// + [Fact] + public void SolvingGivesTheWholeIntervalAndNotAPoint() + { + var solutions = "floor(x) - 3 = 0".ToEntity().Solve("x"); + Assert.NotNull(solutions); + var conditions = solutions!.Nodes.OfType().ToList(); + Assert.NotEmpty(conditions); + + // Every point of [3, 4) is a solution, and 4 is not. + foreach (var point in new[] { "3", "3.5", "39/10" }) + Assert.Equal(Entity.Number.Integer.Create(3), + $"floor({point})".ToEntity().Simplify()); + Assert.Equal(Entity.Number.Integer.Create(4), "floor(4)".ToEntity().Simplify()); + } + } +} diff --git a/Sources/Tests/UnitTests/Convenience/MissingFunctionNamesRefusedTest.cs b/Sources/Tests/UnitTests/Convenience/MissingFunctionNamesRefusedTest.cs index bbde307fd..584c6d65a 100644 --- a/Sources/Tests/UnitTests/Convenience/MissingFunctionNamesRefusedTest.cs +++ b/Sources/Tests/UnitTests/Convenience/MissingFunctionNamesRefusedTest.cs @@ -26,10 +26,9 @@ namespace AngouriMath.Tests.Convenience [Trait("Area", "Convenience")] public sealed class MissingFunctionNamesRefusedTest { + // floor, ceil and ceiling were on this list until they were implemented: + // https://github.com/asc-community/AngouriMath/issues/809 [Theory] - [InlineData("floor(x)")] - [InlineData("ceil(x)")] - [InlineData("ceiling(x)")] [InlineData("round(x)")] [InlineData("trunc(x)")] [InlineData("erf(x)")] @@ -46,7 +45,7 @@ public void ANameTheLibraryDoesNotHaveIsRefused(string written) => /// cannot otherwise tell what happened to their expression. /// [Theory] - [InlineData("floor(x)", "floor")] + [InlineData("round(x)", "round")] [InlineData("gcd(x, y)", "gcd")] [InlineData("conjugate(x)", "conjugate")] public void TheRefusalNamesTheFunction(string written, string name) => @@ -63,11 +62,22 @@ public void TheRefusalNamesTheFunction(string written, string name) => [InlineData("min(x)")] [InlineData("min(x, y)")] [InlineData("min(x, y, z)")] - [InlineData("floor(x)")] - [InlineData("floor(x, y)")] + [InlineData("round(x)")] + [InlineData("round(x, y)")] public void TheArgumentCountDoesNotDecideWhetherItIsReported(string written) => Assert.Throws(() => written.ToEntity()); + /// + /// A name the library does have, called with the wrong number of arguments, is + /// a different complaint and says so -- the count is the problem, not the name. + /// + [Theory] + [InlineData("floor(x, y)", "floor")] + [InlineData("ceil(x, y)", "ceil")] + public void AnImplementedNameWithTheWrongArgumentCountSaysThat(string written, string name) + => Assert.Contains(name, + Assert.Throws(() => written.ToEntity()).Message); + /// /// What the defect actually cost, and the reason this is worth a parse error rather /// than being left as a feature request: the solver answered confidently and wrongly. @@ -76,8 +86,24 @@ public void TheArgumentCountDoesNotDecideWhetherItIsReported(string written) => public void TheEquationThatUsedToBeAnsweredWithNonsenseNowSaysWhyItCannotBe() { var thrown = Assert.Throws( - () => "floor(x) - 3 = 0".ToEntity().Solve("x")); - Assert.Contains("floor", thrown.Message); + () => "round(x) - 3 = 0".ToEntity().Solve("x")); + Assert.Contains("round", thrown.Message); + } + + /// + /// And the original expression from #733 is now answered rather than refused, since + /// floor exists. floor(x) = 3 holds on the whole of [3, 4), so the + /// answer is that interval carried as a parameter and not a single point -- what it + /// must never be again is { 3 / floor }. + /// https://github.com/asc-community/AngouriMath/issues/809 + /// + [Fact] + public void TheEquationFromTheOriginalReportIsAnsweredNow() + { + var solutions = "floor(x) - 3 = 0".ToEntity().Solve("x"); + Assert.NotNull(solutions); + Assert.DoesNotContain(solutions!.Nodes, node => node is Entity.Variable { Name: "floor" }); + Assert.Contains(solutions.Nodes, node => node is Entity.Providedf); } /// @@ -114,6 +140,9 @@ public void EverythingElseParsesAsItDid(string written, string expected) => [InlineData("sin(x)")] [InlineData("arsinh(x)")] [InlineData("phi(x)")] + [InlineData("floor(x)")] + [InlineData("ceil(x)")] + [InlineData("ceiling(x)")] public void TheNamesTheLibraryHasStillParse(string written) => Assert.NotNull(written.ToEntity()); From 851c5e979ba8f1443955387dcb4ff260ea3ceb95 Mon Sep 17 00:00:00 2001 From: Rafael Vuijk Date: Sun, 9 Aug 2026 00:34:21 +0000 Subject: [PATCH 2/2] Add round, min, max and gcd, closing #809 The four that were left after floor and ceil. Every convention was measured against SymPy 1.14 rather than chosen, and two of them are not what the issue assumed. round is half to even -- round(1/2) is 0, round(5/2) is 2 -- matching Python, SymPy, Mathematica and IEEE 754, and .NET's Math.Round default. It is deliberately not floor(x + 1/2), which is the obvious translation and disagrees at every tie: that sends 1/2 to 1 and 5/2 to 3. A test pins that the two differ, so nobody simplifies the node into it. That also decided the SymPy export. SymPy has no symbolic round -- RoundFunction is an abstract base that raises, and .round() is a method on a concrete number -- so ToSymPy builds the tie correction out of floor, frac and Mod rather than emitting the wrong one-liner. Checked against Rational.round() on ties, non-ties and negatives. min and max are nodes, not sugar over (a + b -+ abs(a - b)) / 2. The closed form is what they simplify to where it helps; it is not what they should print as, and the round-trip contract would make that permanent. SymPy keeps Min as a node for the same reason. They compare only where the arguments are ordered, so an unordered pair is left alone rather than guessed at, and their derivative stays unevaluated because stating it needs a case split on which argument is smaller. gcd is not integers only, which is what the issue said and what I repeated. SymPy's gcd is the polynomial gcd with the integer case inside it, so gcd(1/2, 1/3) is 1/6 and gcd(x^2-1, x-1) is x-1. Integers and rationals are computed here; the polynomial case is left as the node rather than half-done, and this library already has PolynomialGcd for whoever wires it in. min, max and gcd take any number of arguments and fold, which needed one new helper -- AssertAtLeast -- since every existing arity check is for a fixed count. The grammar was regenerated with JDK 25 and the committed ANTLR 4.13.1 jar, after confirming on the previous change that the unmodified grammar reproduces the checked-in parser byte for byte. Twelve tests in MissingFunctionNamesRefusedTest asserted these names were refused, and they are not any more. That is the answer getting better: the refusal cases move to trunc, lcm, erf and conjugate, which are what is still missing. Tests: 5928 passing, 0 failed, 14 skipped; F# 130. Co-Authored-By: Claude Opus 5 (1M context) --- BREAKING-CHANGES.md | 24 +++ Sources/.editorconfig | 2 +- Sources/AngouriMath/Convenience/MathS.cs | 66 +++++++ Sources/AngouriMath/Core/Antlr/AngouriMath.g | 10 +- .../AngouriMath/Core/Antlr/AngouriMath.interp | 2 +- .../AngouriMath/Core/Antlr/AngouriMath.tokens | 8 +- .../Core/Antlr/AngouriMathLexer.cs | 24 +-- .../Core/Antlr/AngouriMathLexer.interp | 4 +- .../Core/Antlr/AngouriMathLexer.tokens | 8 +- .../Core/Antlr/AngouriMathParser.cs | 12 +- Sources/AngouriMath/Core/Domains.Classes.cs | 25 +++ .../Entity.Continuous.Definition.cs | 8 + .../Entity.Continuous.Rounding.Classes.cs | 104 +++++++++++ .../Core/Exceptions/ParseException.cs | 10 ++ .../Functions/Continuous/Differentiation.cs | 9 + .../EquationSolver/InvertNode.Classes.cs | 43 +++++ ...aluation.Continuous.Arithmetics.Classes.cs | 80 +++++++++ .../Functions/InternalAMExtensions.cs | 11 ++ .../Output/Latex/Latex.Arithmetics.Classes.cs | 29 +++ .../ToString/ToString.Arithmetics.Classes.cs | 32 ++++ .../ToSympy/ToSympy.Arithmetics.Classes.cs | 42 +++++ Sources/AngouriMath/Functions/Substitute.cs | 28 +++ .../Functions/TreeAnalyzer/Sort.Classes.cs | 24 +++ .../MissingFunctionNamesRefusedTest.cs | 30 ++-- .../Convenience/RoundMinMaxGcdTest.cs | 168 ++++++++++++++++++ 25 files changed, 754 insertions(+), 49 deletions(-) create mode 100644 Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Rounding.Classes.cs create mode 100644 Sources/Tests/UnitTests/Convenience/RoundMinMaxGcdTest.cs diff --git a/BREAKING-CHANGES.md b/BREAKING-CHANGES.md index bc986a28c..c71dfc246 100644 --- a/BREAKING-CHANGES.md +++ b/BREAKING-CHANGES.md @@ -50,6 +50,7 @@ read first. | loud | `Expand` of a quotient of factorials | `AngouriBugException` | the expanded polynomial | | loud | parsing a `provided` in a parenthesised comma list | `NullReferenceException` | `UnhandledParseException` | | loud | `floor(x)`, `ceil(x)`, `ceiling(x)` | `UnrecognizedFunctionParseException` | the functions | +| loud | `round(x)`, `min(a, b)`, `max(a, b)`, `gcd(a, b)` | `UnrecognizedFunctionParseException` | the functions | | loud | the target frameworks | `net7.0;netstandard2.0` | `netstandard2.0;net8.0;net10.0` | | **silent** | `abs(x) = c` for a negative `c` | a set of non-solutions | the empty set | @@ -1291,6 +1292,29 @@ throw. `Simplify` was never affected — it answered `1 + x` throughout. Issue [#817](https://github.com/asc-community/AngouriMath/issues/817). +### `round`, `min`, `max` and `gcd` exist, so they no longer raise + +```csharp +"round(5/2)".ToEntity().Simplify(); // was UnrecognizedFunctionParseException, is 2 +"min(3, 5)".ToEntity().Simplify(); // was UnrecognizedFunctionParseException, is 3 +"gcd(1/2, 1/3)".ToEntity().Simplify();// was UnrecognizedFunctionParseException, is 1/6 +``` + +**`round` is half to even**, which is what Python, SymPy, Mathematica and IEEE 754 all mean by +rounding, and what .NET's `Math.Round` does by default: `round(1/2)` is `0`, `round(5/2)` is `2`. +It is deliberately **not** `floor(x + 1/2)`, which disagrees at every tie, and there is a test +pinning that they differ. + +`min`, `max` and `gcd` take any number of arguments and fold, so `min(3, 5, 1)` is `1`. `min` and +`max` compare only where the arguments are ordered — an unordered pair is left as the node rather +than guessed at, as SymPy's `Min` does. `gcd` covers integers and rationals, `gcd(1/2, 1/3)` being +`1/6` exactly as SymPy gives; the polynomial case is left unevaluated for now even though this +library computes polynomial gcds elsewhere. + +`trunc`, `lcm`, `erf` and `conjugate` are still refused by name. + +Issue [#809](https://github.com/asc-community/AngouriMath/issues/809). + ### `floor` and `ceil` exist, so they no longer raise ```csharp diff --git a/Sources/.editorconfig b/Sources/.editorconfig index 849f1b983..5ba88dd3d 100644 --- a/Sources/.editorconfig +++ b/Sources/.editorconfig @@ -32,5 +32,5 @@ file_header_template=\nCopyright (c) 2019-2026 Angouri.\nAngouriMath is licensed # A new file in a directory whose other files predate it, so the section is on the file # rather than the folder. -[AngouriMath/Core/Entity/Continuous/Entity.Continuous.Floors.Classes.cs] +[AngouriMath/Core/Entity/Continuous/Entity.Continuous.{Floors,Rounding}.Classes.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/Convenience/MathS.cs b/Sources/AngouriMath/Convenience/MathS.cs index 490f578f1..46093165a 100644 --- a/Sources/AngouriMath/Convenience/MathS.cs +++ b/Sources/AngouriMath/Convenience/MathS.cs @@ -1030,6 +1030,72 @@ public static Integer GreatestCommonDivisor(Integer a, Integer b) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Entity Ceil(Entity a) => new Ceilf(a); + /// + /// The nearest integer to , a tie going to the even one. + /// + /// The argument to round. + /// The rounded argument. + /// + /// Half to even, as Python, SymPy, Mathematica and IEEE 754 all round: round(1/2) + /// is 0 and round(3/2) is 2. It is therefore not + /// floor(x + 1/2), which differs at every tie. + /// + /// + /// + /// using System; + /// using static AngouriMath.MathS; + /// + /// Console.WriteLine(Round("1/2").Simplify()); + /// Console.WriteLine(Round("3/2").Simplify()); + /// Console.WriteLine(Round("5/2").Simplify()); + /// + /// Prints + /// + /// 0 + /// 2 + /// 2 + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Entity Round(Entity a) => new Roundf(a); + + /// + /// The lesser of and . + /// + /// The first argument. + /// The second argument. + /// Whichever is smaller, or the unevaluated node where they cannot be compared. + /// + /// Only ordered arguments compare, so a complex one is left alone rather than + /// guessed at. For more than two, nest: Min(Min(a, b), c). + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Entity Min(Entity a, Entity b) => new Minf(a, b); + + /// + /// The greater of and . + /// + /// The first argument. + /// The second argument. + /// Whichever is larger, or the unevaluated node where they cannot be compared. + /// See . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Entity Max(Entity a, Entity b) => new Maxf(a, b); + + /// + /// The greatest common divisor of and . + /// + /// The first argument. + /// The second argument. + /// The gcd where it can be computed, the unevaluated node otherwise. + /// + /// Integers and rationals are computed — gcd(1/2, 1/3) is 1/6, as + /// SymPy gives. The polynomial case is left unevaluated for now, though this library + /// does compute polynomial gcds elsewhere. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Entity Gcd(Entity a, Entity b) => new Gcdf(a, b); + /// Boolean negation /// Wikipedia /// Argument node of which Negation function will be taken diff --git a/Sources/AngouriMath/Core/Antlr/AngouriMath.g b/Sources/AngouriMath/Core/Antlr/AngouriMath.g index 14f86da08..d2f2a2de5 100644 --- a/Sources/AngouriMath/Core/Antlr/AngouriMath.g +++ b/Sources/AngouriMath/Core/Antlr/AngouriMath.g @@ -412,17 +412,19 @@ atom returns[Entity value] /* SymPy's spelling, accepted so that an expression copied from there parses. Stringize prints the short form, which is what the round-trip test pins. */ | 'ceiling(' args = function_arguments ')' { Assert("ceiling", 1, $args.list.Count); $value = MathS.Ceil($args.list[0]); } + | '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)); } + | '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 a caller reaches for it, and without these rules each is silently read as a product -- see NotImplementedFunction above. Refusing is not the feature; it is the difference between a missing function and a wrong answer. */ - | 'round(' args = function_arguments ')' { $value = NotImplementedFunction("round", "rounding functions"); } | 'trunc(' args = function_arguments ')' { $value = NotImplementedFunction("trunc", "rounding functions"); } - | 'min(' args = function_arguments ')' { $value = NotImplementedFunction("min", "minimum or maximum function"); } - | 'max(' args = function_arguments ')' { $value = NotImplementedFunction("max", "minimum or maximum function"); } - | 'gcd(' args = function_arguments ')' { $value = NotImplementedFunction("gcd", "greatest common divisor as a symbolic function"); } | 'lcm(' args = function_arguments ')' { $value = NotImplementedFunction("lcm", "least common multiple as a symbolic function"); } | 'erf(' args = function_arguments ')' { $value = NotImplementedFunction("erf", "error function"); } | 'conjugate(' args = function_arguments ')' { $value = NotImplementedFunction("conjugate", "complex conjugate as a symbolic function"); } diff --git a/Sources/AngouriMath/Core/Antlr/AngouriMath.interp b/Sources/AngouriMath/Core/Antlr/AngouriMath.interp index d20d2a5b0..847ccacd2 100644 --- a/Sources/AngouriMath/Core/Antlr/AngouriMath.interp +++ b/Sources/AngouriMath/Core/Antlr/AngouriMath.interp @@ -132,10 +132,10 @@ null 'ceil(' 'ceiling(' 'round(' -'trunc(' 'min(' 'max(' 'gcd(' +'trunc(' 'lcm(' 'erf(' 'conjugate(' diff --git a/Sources/AngouriMath/Core/Antlr/AngouriMath.tokens b/Sources/AngouriMath/Core/Antlr/AngouriMath.tokens index ea9c4c471..3ef57341c 100644 --- a/Sources/AngouriMath/Core/Antlr/AngouriMath.tokens +++ b/Sources/AngouriMath/Core/Antlr/AngouriMath.tokens @@ -280,10 +280,10 @@ WS=150 'ceil('=130 'ceiling('=131 'round('=132 -'trunc('=133 -'min('=134 -'max('=135 -'gcd('=136 +'min('=133 +'max('=134 +'gcd('=135 +'trunc('=136 'lcm('=137 'erf('=138 'conjugate('=139 diff --git a/Sources/AngouriMath/Core/Antlr/AngouriMathLexer.cs b/Sources/AngouriMath/Core/Antlr/AngouriMathLexer.cs index aa563fd70..e237563c9 100644 --- a/Sources/AngouriMath/Core/Antlr/AngouriMathLexer.cs +++ b/Sources/AngouriMath/Core/Antlr/AngouriMathLexer.cs @@ -125,7 +125,7 @@ public AngouriMathLexer(ICharStream input, TextWriter output, TextWriter errorOu "'arcsch('", "'arccosech('", "'acsch('", "'factorial('", "'gamma('", "'derivative('", "'integral('", "'limit('", "'limitleft('", "'limitright('", "'signum('", "'sgn('", "'sign('", "'abs('", "'phi('", "'floor('", "'ceil('", "'ceiling('", - "'round('", "'trunc('", "'min('", "'max('", "'gcd('", "'lcm('", "'erf('", + "'round('", "'min('", "'max('", "'gcd('", "'trunc('", "'lcm('", "'erf('", "'conjugate('", "'domain('", "'piecewise('", "'apply('", "'lambda('" }; private static readonly string[] _SymbolicNames = { @@ -252,8 +252,8 @@ static AngouriMathLexer() { 1,126,1,127,1,127,1,127,1,127,1,127,1,128,1,128,1,128,1,128,1,128,1,128, 1,128,1,129,1,129,1,129,1,129,1,129,1,129,1,130,1,130,1,130,1,130,1,130, 1,130,1,130,1,130,1,130,1,131,1,131,1,131,1,131,1,131,1,131,1,131,1,132, - 1,132,1,132,1,132,1,132,1,132,1,132,1,133,1,133,1,133,1,133,1,133,1,134, - 1,134,1,134,1,134,1,134,1,135,1,135,1,135,1,135,1,135,1,136,1,136,1,136, + 1,132,1,132,1,132,1,132,1,133,1,133,1,133,1,133,1,133,1,134,1,134,1,134, + 1,134,1,134,1,135,1,135,1,135,1,135,1,135,1,135,1,135,1,136,1,136,1,136, 1,136,1,136,1,137,1,137,1,137,1,137,1,137,1,138,1,138,1,138,1,138,1,138, 1,138,1,138,1,138,1,138,1,138,1,138,1,139,1,139,1,139,1,139,1,139,1,139, 1,139,1,139,1,140,1,140,1,140,1,140,1,140,1,140,1,140,1,140,1,140,1,140, @@ -347,8 +347,8 @@ static AngouriMathLexer() { 963,1,0,0,0,237,970,1,0,0,0,239,982,1,0,0,0,241,992,1,0,0,0,243,999,1, 0,0,0,245,1010,1,0,0,0,247,1022,1,0,0,0,249,1030,1,0,0,0,251,1035,1,0, 0,0,253,1041,1,0,0,0,255,1046,1,0,0,0,257,1051,1,0,0,0,259,1058,1,0,0, - 0,261,1064,1,0,0,0,263,1073,1,0,0,0,265,1080,1,0,0,0,267,1087,1,0,0,0, - 269,1092,1,0,0,0,271,1097,1,0,0,0,273,1102,1,0,0,0,275,1107,1,0,0,0,277, + 0,261,1064,1,0,0,0,263,1073,1,0,0,0,265,1080,1,0,0,0,267,1085,1,0,0,0, + 269,1090,1,0,0,0,271,1095,1,0,0,0,273,1102,1,0,0,0,275,1107,1,0,0,0,277, 1112,1,0,0,0,279,1123,1,0,0,0,281,1131,1,0,0,0,283,1142,1,0,0,0,285,1149, 1,0,0,0,287,1161,1,0,0,0,289,1167,1,0,0,0,291,1209,1,0,0,0,293,1221,1, 0,0,0,295,1241,1,0,0,0,297,1244,1,0,0,0,299,1280,1,0,0,0,301,1285,1,0, @@ -542,13 +542,13 @@ static AngouriMathLexer() { 5,105,0,0,1067,1068,5,108,0,0,1068,1069,5,105,0,0,1069,1070,5,110,0,0, 1070,1071,5,103,0,0,1071,1072,5,40,0,0,1072,262,1,0,0,0,1073,1074,5,114, 0,0,1074,1075,5,111,0,0,1075,1076,5,117,0,0,1076,1077,5,110,0,0,1077,1078, - 5,100,0,0,1078,1079,5,40,0,0,1079,264,1,0,0,0,1080,1081,5,116,0,0,1081, - 1082,5,114,0,0,1082,1083,5,117,0,0,1083,1084,5,110,0,0,1084,1085,5,99, - 0,0,1085,1086,5,40,0,0,1086,266,1,0,0,0,1087,1088,5,109,0,0,1088,1089, - 5,105,0,0,1089,1090,5,110,0,0,1090,1091,5,40,0,0,1091,268,1,0,0,0,1092, - 1093,5,109,0,0,1093,1094,5,97,0,0,1094,1095,5,120,0,0,1095,1096,5,40,0, - 0,1096,270,1,0,0,0,1097,1098,5,103,0,0,1098,1099,5,99,0,0,1099,1100,5, - 100,0,0,1100,1101,5,40,0,0,1101,272,1,0,0,0,1102,1103,5,108,0,0,1103,1104, + 5,100,0,0,1078,1079,5,40,0,0,1079,264,1,0,0,0,1080,1081,5,109,0,0,1081, + 1082,5,105,0,0,1082,1083,5,110,0,0,1083,1084,5,40,0,0,1084,266,1,0,0,0, + 1085,1086,5,109,0,0,1086,1087,5,97,0,0,1087,1088,5,120,0,0,1088,1089,5, + 40,0,0,1089,268,1,0,0,0,1090,1091,5,103,0,0,1091,1092,5,99,0,0,1092,1093, + 5,100,0,0,1093,1094,5,40,0,0,1094,270,1,0,0,0,1095,1096,5,116,0,0,1096, + 1097,5,114,0,0,1097,1098,5,117,0,0,1098,1099,5,110,0,0,1099,1100,5,99, + 0,0,1100,1101,5,40,0,0,1101,272,1,0,0,0,1102,1103,5,108,0,0,1103,1104, 5,99,0,0,1104,1105,5,109,0,0,1105,1106,5,40,0,0,1106,274,1,0,0,0,1107, 1108,5,101,0,0,1108,1109,5,114,0,0,1109,1110,5,102,0,0,1110,1111,5,40, 0,0,1111,276,1,0,0,0,1112,1113,5,99,0,0,1113,1114,5,111,0,0,1114,1115, diff --git a/Sources/AngouriMath/Core/Antlr/AngouriMathLexer.interp b/Sources/AngouriMath/Core/Antlr/AngouriMathLexer.interp index 4d94cb3dc..5e12aa599 100644 --- a/Sources/AngouriMath/Core/Antlr/AngouriMathLexer.interp +++ b/Sources/AngouriMath/Core/Antlr/AngouriMathLexer.interp @@ -132,10 +132,10 @@ null 'ceil(' 'ceiling(' 'round(' -'trunc(' 'min(' 'max(' 'gcd(' +'trunc(' 'lcm(' 'erf(' 'conjugate(' @@ -465,4 +465,4 @@ mode names: DEFAULT_MODE atn: -[4, 0, 150, 1291, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 2, 88, 7, 88, 2, 89, 7, 89, 2, 90, 7, 90, 2, 91, 7, 91, 2, 92, 7, 92, 2, 93, 7, 93, 2, 94, 7, 94, 2, 95, 7, 95, 2, 96, 7, 96, 2, 97, 7, 97, 2, 98, 7, 98, 2, 99, 7, 99, 2, 100, 7, 100, 2, 101, 7, 101, 2, 102, 7, 102, 2, 103, 7, 103, 2, 104, 7, 104, 2, 105, 7, 105, 2, 106, 7, 106, 2, 107, 7, 107, 2, 108, 7, 108, 2, 109, 7, 109, 2, 110, 7, 110, 2, 111, 7, 111, 2, 112, 7, 112, 2, 113, 7, 113, 2, 114, 7, 114, 2, 115, 7, 115, 2, 116, 7, 116, 2, 117, 7, 117, 2, 118, 7, 118, 2, 119, 7, 119, 2, 120, 7, 120, 2, 121, 7, 121, 2, 122, 7, 122, 2, 123, 7, 123, 2, 124, 7, 124, 2, 125, 7, 125, 2, 126, 7, 126, 2, 127, 7, 127, 2, 128, 7, 128, 2, 129, 7, 129, 2, 130, 7, 130, 2, 131, 7, 131, 2, 132, 7, 132, 2, 133, 7, 133, 2, 134, 7, 134, 2, 135, 7, 135, 2, 136, 7, 136, 2, 137, 7, 137, 2, 138, 7, 138, 2, 139, 7, 139, 2, 140, 7, 140, 2, 141, 7, 141, 2, 142, 7, 142, 2, 143, 7, 143, 2, 144, 7, 144, 2, 145, 7, 145, 2, 146, 7, 146, 2, 147, 7, 147, 2, 148, 7, 148, 2, 149, 7, 149, 2, 150, 7, 150, 1, 0, 1, 0, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 17, 1, 17, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 29, 1, 29, 1, 30, 1, 30, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 32, 1, 33, 1, 33, 1, 33, 1, 33, 1, 34, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 39, 1, 39, 1, 40, 1, 40, 1, 41, 1, 41, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 50, 1, 50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 69, 1, 69, 1, 69, 1, 69, 1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 77, 1, 77, 1, 77, 1, 77, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 79, 1, 79, 1, 79, 1, 79, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 81, 1, 81, 1, 81, 1, 81, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 88, 1, 88, 1, 88, 1, 88, 1, 88, 1, 88, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 90, 1, 90, 1, 90, 1, 90, 1, 90, 1, 90, 1, 90, 1, 90, 1, 91, 1, 91, 1, 91, 1, 91, 1, 91, 1, 91, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 99, 1, 99, 1, 99, 1, 99, 1, 99, 1, 99, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 101, 1, 101, 1, 101, 1, 101, 1, 101, 1, 101, 1, 101, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 103, 1, 103, 1, 103, 1, 103, 1, 103, 1, 103, 1, 103, 1, 103, 1, 103, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 105, 1, 105, 1, 105, 1, 105, 1, 105, 1, 105, 1, 105, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 107, 1, 107, 1, 107, 1, 107, 1, 107, 1, 107, 1, 107, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 109, 1, 109, 1, 109, 1, 109, 1, 109, 1, 109, 1, 109, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 111, 1, 111, 1, 111, 1, 111, 1, 111, 1, 111, 1, 111, 1, 111, 1, 111, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 126, 1, 126, 1, 126, 1, 126, 1, 126, 1, 127, 1, 127, 1, 127, 1, 127, 1, 127, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 1, 129, 1, 129, 1, 129, 1, 129, 1, 129, 1, 129, 1, 130, 1, 130, 1, 130, 1, 130, 1, 130, 1, 130, 1, 130, 1, 130, 1, 130, 1, 131, 1, 131, 1, 131, 1, 131, 1, 131, 1, 131, 1, 131, 1, 132, 1, 132, 1, 132, 1, 132, 1, 132, 1, 132, 1, 132, 1, 133, 1, 133, 1, 133, 1, 133, 1, 133, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 135, 1, 135, 1, 135, 1, 135, 1, 135, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 137, 1, 137, 1, 137, 1, 137, 1, 137, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 139, 1, 139, 1, 139, 1, 139, 1, 139, 1, 139, 1, 139, 1, 139, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 141, 1, 141, 1, 141, 1, 141, 1, 141, 1, 141, 1, 141, 1, 142, 1, 142, 1, 142, 1, 142, 1, 142, 1, 142, 1, 142, 1, 142, 1, 143, 3, 143, 1159, 8, 143, 1, 143, 4, 143, 1162, 8, 143, 11, 143, 12, 143, 1163, 1, 143, 1, 143, 1, 144, 1, 144, 3, 144, 1170, 8, 144, 1, 144, 4, 144, 1173, 8, 144, 11, 144, 12, 144, 1174, 1, 145, 4, 145, 1178, 8, 145, 11, 145, 12, 145, 1179, 1, 145, 1, 145, 5, 145, 1184, 8, 145, 10, 145, 12, 145, 1187, 9, 145, 1, 145, 3, 145, 1190, 8, 145, 1, 145, 3, 145, 1193, 8, 145, 1, 145, 3, 145, 1196, 8, 145, 1, 145, 4, 145, 1199, 8, 145, 11, 145, 12, 145, 1200, 1, 145, 3, 145, 1204, 8, 145, 1, 145, 3, 145, 1207, 8, 145, 1, 145, 3, 145, 1210, 8, 145, 1, 146, 1, 146, 1, 146, 1, 146, 1, 146, 1, 146, 1, 146, 1, 146, 1, 146, 1, 146, 3, 146, 1222, 8, 146, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 3, 147, 1242, 8, 147, 1, 148, 4, 148, 1245, 8, 148, 11, 148, 12, 148, 1246, 1, 148, 1, 148, 4, 148, 1251, 8, 148, 11, 148, 12, 148, 1252, 3, 148, 1255, 8, 148, 1, 149, 1, 149, 1, 149, 1, 149, 5, 149, 1261, 8, 149, 10, 149, 12, 149, 1264, 9, 149, 1, 149, 3, 149, 1267, 8, 149, 1, 149, 1, 149, 1, 149, 1, 149, 1, 149, 5, 149, 1274, 8, 149, 10, 149, 12, 149, 1277, 9, 149, 1, 149, 1, 149, 3, 149, 1281, 8, 149, 1, 149, 1, 149, 1, 150, 4, 150, 1286, 8, 150, 11, 150, 12, 150, 1287, 1, 150, 1, 150, 1, 1275, 0, 151, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23, 12, 25, 13, 27, 14, 29, 15, 31, 16, 33, 17, 35, 18, 37, 19, 39, 20, 41, 21, 43, 22, 45, 23, 47, 24, 49, 25, 51, 26, 53, 27, 55, 28, 57, 29, 59, 30, 61, 31, 63, 32, 65, 33, 67, 34, 69, 35, 71, 36, 73, 37, 75, 38, 77, 39, 79, 40, 81, 41, 83, 42, 85, 43, 87, 44, 89, 45, 91, 46, 93, 47, 95, 48, 97, 49, 99, 50, 101, 51, 103, 52, 105, 53, 107, 54, 109, 55, 111, 56, 113, 57, 115, 58, 117, 59, 119, 60, 121, 61, 123, 62, 125, 63, 127, 64, 129, 65, 131, 66, 133, 67, 135, 68, 137, 69, 139, 70, 141, 71, 143, 72, 145, 73, 147, 74, 149, 75, 151, 76, 153, 77, 155, 78, 157, 79, 159, 80, 161, 81, 163, 82, 165, 83, 167, 84, 169, 85, 171, 86, 173, 87, 175, 88, 177, 89, 179, 90, 181, 91, 183, 92, 185, 93, 187, 94, 189, 95, 191, 96, 193, 97, 195, 98, 197, 99, 199, 100, 201, 101, 203, 102, 205, 103, 207, 104, 209, 105, 211, 106, 213, 107, 215, 108, 217, 109, 219, 110, 221, 111, 223, 112, 225, 113, 227, 114, 229, 115, 231, 116, 233, 117, 235, 118, 237, 119, 239, 120, 241, 121, 243, 122, 245, 123, 247, 124, 249, 125, 251, 126, 253, 127, 255, 128, 257, 129, 259, 130, 261, 131, 263, 132, 265, 133, 267, 134, 269, 135, 271, 136, 273, 137, 275, 138, 277, 139, 279, 140, 281, 141, 283, 142, 285, 143, 287, 144, 289, 0, 291, 145, 293, 146, 295, 147, 297, 148, 299, 149, 301, 150, 1, 0, 6, 2, 0, 69, 69, 101, 101, 2, 0, 43, 43, 45, 45, 4, 0, 65, 90, 97, 122, 880, 1279, 7936, 8191, 5, 0, 48, 57, 65, 90, 97, 122, 880, 1279, 7936, 8191, 2, 0, 10, 10, 13, 13, 2, 0, 9, 9, 32, 32, 1318, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, 41, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 49, 1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1, 0, 0, 0, 0, 55, 1, 0, 0, 0, 0, 57, 1, 0, 0, 0, 0, 59, 1, 0, 0, 0, 0, 61, 1, 0, 0, 0, 0, 63, 1, 0, 0, 0, 0, 65, 1, 0, 0, 0, 0, 67, 1, 0, 0, 0, 0, 69, 1, 0, 0, 0, 0, 71, 1, 0, 0, 0, 0, 73, 1, 0, 0, 0, 0, 75, 1, 0, 0, 0, 0, 77, 1, 0, 0, 0, 0, 79, 1, 0, 0, 0, 0, 81, 1, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 85, 1, 0, 0, 0, 0, 87, 1, 0, 0, 0, 0, 89, 1, 0, 0, 0, 0, 91, 1, 0, 0, 0, 0, 93, 1, 0, 0, 0, 0, 95, 1, 0, 0, 0, 0, 97, 1, 0, 0, 0, 0, 99, 1, 0, 0, 0, 0, 101, 1, 0, 0, 0, 0, 103, 1, 0, 0, 0, 0, 105, 1, 0, 0, 0, 0, 107, 1, 0, 0, 0, 0, 109, 1, 0, 0, 0, 0, 111, 1, 0, 0, 0, 0, 113, 1, 0, 0, 0, 0, 115, 1, 0, 0, 0, 0, 117, 1, 0, 0, 0, 0, 119, 1, 0, 0, 0, 0, 121, 1, 0, 0, 0, 0, 123, 1, 0, 0, 0, 0, 125, 1, 0, 0, 0, 0, 127, 1, 0, 0, 0, 0, 129, 1, 0, 0, 0, 0, 131, 1, 0, 0, 0, 0, 133, 1, 0, 0, 0, 0, 135, 1, 0, 0, 0, 0, 137, 1, 0, 0, 0, 0, 139, 1, 0, 0, 0, 0, 141, 1, 0, 0, 0, 0, 143, 1, 0, 0, 0, 0, 145, 1, 0, 0, 0, 0, 147, 1, 0, 0, 0, 0, 149, 1, 0, 0, 0, 0, 151, 1, 0, 0, 0, 0, 153, 1, 0, 0, 0, 0, 155, 1, 0, 0, 0, 0, 157, 1, 0, 0, 0, 0, 159, 1, 0, 0, 0, 0, 161, 1, 0, 0, 0, 0, 163, 1, 0, 0, 0, 0, 165, 1, 0, 0, 0, 0, 167, 1, 0, 0, 0, 0, 169, 1, 0, 0, 0, 0, 171, 1, 0, 0, 0, 0, 173, 1, 0, 0, 0, 0, 175, 1, 0, 0, 0, 0, 177, 1, 0, 0, 0, 0, 179, 1, 0, 0, 0, 0, 181, 1, 0, 0, 0, 0, 183, 1, 0, 0, 0, 0, 185, 1, 0, 0, 0, 0, 187, 1, 0, 0, 0, 0, 189, 1, 0, 0, 0, 0, 191, 1, 0, 0, 0, 0, 193, 1, 0, 0, 0, 0, 195, 1, 0, 0, 0, 0, 197, 1, 0, 0, 0, 0, 199, 1, 0, 0, 0, 0, 201, 1, 0, 0, 0, 0, 203, 1, 0, 0, 0, 0, 205, 1, 0, 0, 0, 0, 207, 1, 0, 0, 0, 0, 209, 1, 0, 0, 0, 0, 211, 1, 0, 0, 0, 0, 213, 1, 0, 0, 0, 0, 215, 1, 0, 0, 0, 0, 217, 1, 0, 0, 0, 0, 219, 1, 0, 0, 0, 0, 221, 1, 0, 0, 0, 0, 223, 1, 0, 0, 0, 0, 225, 1, 0, 0, 0, 0, 227, 1, 0, 0, 0, 0, 229, 1, 0, 0, 0, 0, 231, 1, 0, 0, 0, 0, 233, 1, 0, 0, 0, 0, 235, 1, 0, 0, 0, 0, 237, 1, 0, 0, 0, 0, 239, 1, 0, 0, 0, 0, 241, 1, 0, 0, 0, 0, 243, 1, 0, 0, 0, 0, 245, 1, 0, 0, 0, 0, 247, 1, 0, 0, 0, 0, 249, 1, 0, 0, 0, 0, 251, 1, 0, 0, 0, 0, 253, 1, 0, 0, 0, 0, 255, 1, 0, 0, 0, 0, 257, 1, 0, 0, 0, 0, 259, 1, 0, 0, 0, 0, 261, 1, 0, 0, 0, 0, 263, 1, 0, 0, 0, 0, 265, 1, 0, 0, 0, 0, 267, 1, 0, 0, 0, 0, 269, 1, 0, 0, 0, 0, 271, 1, 0, 0, 0, 0, 273, 1, 0, 0, 0, 0, 275, 1, 0, 0, 0, 0, 277, 1, 0, 0, 0, 0, 279, 1, 0, 0, 0, 0, 281, 1, 0, 0, 0, 0, 283, 1, 0, 0, 0, 0, 285, 1, 0, 0, 0, 0, 287, 1, 0, 0, 0, 0, 291, 1, 0, 0, 0, 0, 293, 1, 0, 0, 0, 0, 295, 1, 0, 0, 0, 0, 297, 1, 0, 0, 0, 0, 299, 1, 0, 0, 0, 0, 301, 1, 0, 0, 0, 1, 303, 1, 0, 0, 0, 3, 305, 1, 0, 0, 0, 5, 307, 1, 0, 0, 0, 7, 309, 1, 0, 0, 0, 9, 311, 1, 0, 0, 0, 11, 313, 1, 0, 0, 0, 13, 315, 1, 0, 0, 0, 15, 319, 1, 0, 0, 0, 17, 329, 1, 0, 0, 0, 19, 332, 1, 0, 0, 0, 21, 338, 1, 0, 0, 0, 23, 341, 1, 0, 0, 0, 25, 353, 1, 0, 0, 0, 27, 355, 1, 0, 0, 0, 29, 358, 1, 0, 0, 0, 31, 361, 1, 0, 0, 0, 33, 364, 1, 0, 0, 0, 35, 366, 1, 0, 0, 0, 37, 368, 1, 0, 0, 0, 39, 370, 1, 0, 0, 0, 41, 373, 1, 0, 0, 0, 43, 377, 1, 0, 0, 0, 45, 381, 1, 0, 0, 0, 47, 383, 1, 0, 0, 0, 49, 387, 1, 0, 0, 0, 51, 390, 1, 0, 0, 0, 53, 392, 1, 0, 0, 0, 55, 400, 1, 0, 0, 0, 57, 403, 1, 0, 0, 0, 59, 412, 1, 0, 0, 0, 61, 414, 1, 0, 0, 0, 63, 416, 1, 0, 0, 0, 65, 418, 1, 0, 0, 0, 67, 422, 1, 0, 0, 0, 69, 426, 1, 0, 0, 0, 71, 429, 1, 0, 0, 0, 73, 432, 1, 0, 0, 0, 75, 434, 1, 0, 0, 0, 77, 437, 1, 0, 0, 0, 79, 439, 1, 0, 0, 0, 81, 441, 1, 0, 0, 0, 83, 443, 1, 0, 0, 0, 85, 445, 1, 0, 0, 0, 87, 447, 1, 0, 0, 0, 89, 452, 1, 0, 0, 0, 91, 459, 1, 0, 0, 0, 93, 465, 1, 0, 0, 0, 95, 470, 1, 0, 0, 0, 97, 476, 1, 0, 0, 0, 99, 482, 1, 0, 0, 0, 101, 487, 1, 0, 0, 0, 103, 491, 1, 0, 0, 0, 105, 496, 1, 0, 0, 0, 107, 501, 1, 0, 0, 0, 109, 506, 1, 0, 0, 0, 111, 511, 1, 0, 0, 0, 113, 518, 1, 0, 0, 0, 115, 523, 1, 0, 0, 0, 117, 528, 1, 0, 0, 0, 119, 535, 1, 0, 0, 0, 121, 540, 1, 0, 0, 0, 123, 548, 1, 0, 0, 0, 125, 556, 1, 0, 0, 0, 127, 564, 1, 0, 0, 0, 129, 574, 1, 0, 0, 0, 131, 582, 1, 0, 0, 0, 133, 592, 1, 0, 0, 0, 135, 600, 1, 0, 0, 0, 137, 606, 1, 0, 0, 0, 139, 612, 1, 0, 0, 0, 141, 618, 1, 0, 0, 0, 143, 624, 1, 0, 0, 0, 145, 632, 1, 0, 0, 0, 147, 638, 1, 0, 0, 0, 149, 646, 1, 0, 0, 0, 151, 652, 1, 0, 0, 0, 153, 660, 1, 0, 0, 0, 155, 666, 1, 0, 0, 0, 157, 670, 1, 0, 0, 0, 159, 676, 1, 0, 0, 0, 161, 680, 1, 0, 0, 0, 163, 686, 1, 0, 0, 0, 165, 690, 1, 0, 0, 0, 167, 698, 1, 0, 0, 0, 169, 704, 1, 0, 0, 0, 171, 709, 1, 0, 0, 0, 173, 715, 1, 0, 0, 0, 175, 720, 1, 0, 0, 0, 177, 728, 1, 0, 0, 0, 179, 734, 1, 0, 0, 0, 181, 741, 1, 0, 0, 0, 183, 749, 1, 0, 0, 0, 185, 755, 1, 0, 0, 0, 187, 764, 1, 0, 0, 0, 189, 771, 1, 0, 0, 0, 191, 779, 1, 0, 0, 0, 193, 785, 1, 0, 0, 0, 195, 794, 1, 0, 0, 0, 197, 801, 1, 0, 0, 0, 199, 809, 1, 0, 0, 0, 201, 815, 1, 0, 0, 0, 203, 824, 1, 0, 0, 0, 205, 831, 1, 0, 0, 0, 207, 839, 1, 0, 0, 0, 209, 848, 1, 0, 0, 0, 211, 858, 1, 0, 0, 0, 213, 865, 1, 0, 0, 0, 215, 876, 1, 0, 0, 0, 217, 883, 1, 0, 0, 0, 219, 891, 1, 0, 0, 0, 221, 898, 1, 0, 0, 0, 223, 907, 1, 0, 0, 0, 225, 916, 1, 0, 0, 0, 227, 926, 1, 0, 0, 0, 229, 934, 1, 0, 0, 0, 231, 945, 1, 0, 0, 0, 233, 952, 1, 0, 0, 0, 235, 963, 1, 0, 0, 0, 237, 970, 1, 0, 0, 0, 239, 982, 1, 0, 0, 0, 241, 992, 1, 0, 0, 0, 243, 999, 1, 0, 0, 0, 245, 1010, 1, 0, 0, 0, 247, 1022, 1, 0, 0, 0, 249, 1030, 1, 0, 0, 0, 251, 1035, 1, 0, 0, 0, 253, 1041, 1, 0, 0, 0, 255, 1046, 1, 0, 0, 0, 257, 1051, 1, 0, 0, 0, 259, 1058, 1, 0, 0, 0, 261, 1064, 1, 0, 0, 0, 263, 1073, 1, 0, 0, 0, 265, 1080, 1, 0, 0, 0, 267, 1087, 1, 0, 0, 0, 269, 1092, 1, 0, 0, 0, 271, 1097, 1, 0, 0, 0, 273, 1102, 1, 0, 0, 0, 275, 1107, 1, 0, 0, 0, 277, 1112, 1, 0, 0, 0, 279, 1123, 1, 0, 0, 0, 281, 1131, 1, 0, 0, 0, 283, 1142, 1, 0, 0, 0, 285, 1149, 1, 0, 0, 0, 287, 1161, 1, 0, 0, 0, 289, 1167, 1, 0, 0, 0, 291, 1209, 1, 0, 0, 0, 293, 1221, 1, 0, 0, 0, 295, 1241, 1, 0, 0, 0, 297, 1244, 1, 0, 0, 0, 299, 1280, 1, 0, 0, 0, 301, 1285, 1, 0, 0, 0, 303, 304, 5, 33, 0, 0, 304, 2, 1, 0, 0, 0, 305, 306, 5, 94, 0, 0, 306, 4, 1, 0, 0, 0, 307, 308, 5, 45, 0, 0, 308, 6, 1, 0, 0, 0, 309, 310, 5, 43, 0, 0, 310, 8, 1, 0, 0, 0, 311, 312, 5, 42, 0, 0, 312, 10, 1, 0, 0, 0, 313, 314, 5, 47, 0, 0, 314, 12, 1, 0, 0, 0, 315, 316, 5, 109, 0, 0, 316, 317, 5, 111, 0, 0, 317, 318, 5, 100, 0, 0, 318, 14, 1, 0, 0, 0, 319, 320, 5, 105, 0, 0, 320, 321, 5, 110, 0, 0, 321, 322, 5, 116, 0, 0, 322, 323, 5, 101, 0, 0, 323, 324, 5, 114, 0, 0, 324, 325, 5, 115, 0, 0, 325, 326, 5, 101, 0, 0, 326, 327, 5, 99, 0, 0, 327, 328, 5, 116, 0, 0, 328, 16, 1, 0, 0, 0, 329, 330, 5, 47, 0, 0, 330, 331, 5, 92, 0, 0, 331, 18, 1, 0, 0, 0, 332, 333, 5, 117, 0, 0, 333, 334, 5, 110, 0, 0, 334, 335, 5, 105, 0, 0, 335, 336, 5, 116, 0, 0, 336, 337, 5, 101, 0, 0, 337, 20, 1, 0, 0, 0, 338, 339, 5, 92, 0, 0, 339, 340, 5, 47, 0, 0, 340, 22, 1, 0, 0, 0, 341, 342, 5, 115, 0, 0, 342, 343, 5, 101, 0, 0, 343, 344, 5, 116, 0, 0, 344, 345, 5, 115, 0, 0, 345, 346, 5, 117, 0, 0, 346, 347, 5, 98, 0, 0, 347, 348, 5, 116, 0, 0, 348, 349, 5, 114, 0, 0, 349, 350, 5, 97, 0, 0, 350, 351, 5, 99, 0, 0, 351, 352, 5, 116, 0, 0, 352, 24, 1, 0, 0, 0, 353, 354, 5, 92, 0, 0, 354, 26, 1, 0, 0, 0, 355, 356, 5, 105, 0, 0, 356, 357, 5, 110, 0, 0, 357, 28, 1, 0, 0, 0, 358, 359, 5, 62, 0, 0, 359, 360, 5, 61, 0, 0, 360, 30, 1, 0, 0, 0, 361, 362, 5, 60, 0, 0, 362, 363, 5, 61, 0, 0, 363, 32, 1, 0, 0, 0, 364, 365, 5, 62, 0, 0, 365, 34, 1, 0, 0, 0, 366, 367, 5, 60, 0, 0, 367, 36, 1, 0, 0, 0, 368, 369, 5, 61, 0, 0, 369, 38, 1, 0, 0, 0, 370, 371, 5, 60, 0, 0, 371, 372, 5, 62, 0, 0, 372, 40, 1, 0, 0, 0, 373, 374, 5, 110, 0, 0, 374, 375, 5, 111, 0, 0, 375, 376, 5, 116, 0, 0, 376, 42, 1, 0, 0, 0, 377, 378, 5, 97, 0, 0, 378, 379, 5, 110, 0, 0, 379, 380, 5, 100, 0, 0, 380, 44, 1, 0, 0, 0, 381, 382, 5, 38, 0, 0, 382, 46, 1, 0, 0, 0, 383, 384, 5, 120, 0, 0, 384, 385, 5, 111, 0, 0, 385, 386, 5, 114, 0, 0, 386, 48, 1, 0, 0, 0, 387, 388, 5, 111, 0, 0, 388, 389, 5, 114, 0, 0, 389, 50, 1, 0, 0, 0, 390, 391, 5, 124, 0, 0, 391, 52, 1, 0, 0, 0, 392, 393, 5, 105, 0, 0, 393, 394, 5, 109, 0, 0, 394, 395, 5, 112, 0, 0, 395, 396, 5, 108, 0, 0, 396, 397, 5, 105, 0, 0, 397, 398, 5, 101, 0, 0, 398, 399, 5, 115, 0, 0, 399, 54, 1, 0, 0, 0, 400, 401, 5, 45, 0, 0, 401, 402, 5, 62, 0, 0, 402, 56, 1, 0, 0, 0, 403, 404, 5, 112, 0, 0, 404, 405, 5, 114, 0, 0, 405, 406, 5, 111, 0, 0, 406, 407, 5, 118, 0, 0, 407, 408, 5, 105, 0, 0, 408, 409, 5, 100, 0, 0, 409, 410, 5, 101, 0, 0, 410, 411, 5, 100, 0, 0, 411, 58, 1, 0, 0, 0, 412, 413, 5, 44, 0, 0, 413, 60, 1, 0, 0, 0, 414, 415, 5, 59, 0, 0, 415, 62, 1, 0, 0, 0, 416, 417, 5, 58, 0, 0, 417, 64, 1, 0, 0, 0, 418, 419, 5, 43, 0, 0, 419, 420, 5, 111, 0, 0, 420, 421, 5, 111, 0, 0, 421, 66, 1, 0, 0, 0, 422, 423, 5, 45, 0, 0, 423, 424, 5, 111, 0, 0, 424, 425, 5, 111, 0, 0, 425, 68, 1, 0, 0, 0, 426, 427, 5, 40, 0, 0, 427, 428, 5, 124, 0, 0, 428, 70, 1, 0, 0, 0, 429, 430, 5, 124, 0, 0, 430, 431, 5, 41, 0, 0, 431, 72, 1, 0, 0, 0, 432, 433, 5, 91, 0, 0, 433, 74, 1, 0, 0, 0, 434, 435, 5, 93, 0, 0, 435, 436, 5, 84, 0, 0, 436, 76, 1, 0, 0, 0, 437, 438, 5, 93, 0, 0, 438, 78, 1, 0, 0, 0, 439, 440, 5, 40, 0, 0, 440, 80, 1, 0, 0, 0, 441, 442, 5, 41, 0, 0, 442, 82, 1, 0, 0, 0, 443, 444, 5, 123, 0, 0, 444, 84, 1, 0, 0, 0, 445, 446, 5, 125, 0, 0, 446, 86, 1, 0, 0, 0, 447, 448, 5, 108, 0, 0, 448, 449, 5, 111, 0, 0, 449, 450, 5, 103, 0, 0, 450, 451, 5, 40, 0, 0, 451, 88, 1, 0, 0, 0, 452, 453, 5, 108, 0, 0, 453, 454, 5, 111, 0, 0, 454, 455, 5, 103, 0, 0, 455, 456, 5, 49, 0, 0, 456, 457, 5, 48, 0, 0, 457, 458, 5, 40, 0, 0, 458, 90, 1, 0, 0, 0, 459, 460, 5, 108, 0, 0, 460, 461, 5, 111, 0, 0, 461, 462, 5, 103, 0, 0, 462, 463, 5, 50, 0, 0, 463, 464, 5, 40, 0, 0, 464, 92, 1, 0, 0, 0, 465, 466, 5, 112, 0, 0, 466, 467, 5, 111, 0, 0, 467, 468, 5, 119, 0, 0, 468, 469, 5, 40, 0, 0, 469, 94, 1, 0, 0, 0, 470, 471, 5, 115, 0, 0, 471, 472, 5, 113, 0, 0, 472, 473, 5, 114, 0, 0, 473, 474, 5, 116, 0, 0, 474, 475, 5, 40, 0, 0, 475, 96, 1, 0, 0, 0, 476, 477, 5, 99, 0, 0, 477, 478, 5, 98, 0, 0, 478, 479, 5, 114, 0, 0, 479, 480, 5, 116, 0, 0, 480, 481, 5, 40, 0, 0, 481, 98, 1, 0, 0, 0, 482, 483, 5, 115, 0, 0, 483, 484, 5, 113, 0, 0, 484, 485, 5, 114, 0, 0, 485, 486, 5, 40, 0, 0, 486, 100, 1, 0, 0, 0, 487, 488, 5, 108, 0, 0, 488, 489, 5, 110, 0, 0, 489, 490, 5, 40, 0, 0, 490, 102, 1, 0, 0, 0, 491, 492, 5, 101, 0, 0, 492, 493, 5, 120, 0, 0, 493, 494, 5, 112, 0, 0, 494, 495, 5, 40, 0, 0, 495, 104, 1, 0, 0, 0, 496, 497, 5, 115, 0, 0, 497, 498, 5, 105, 0, 0, 498, 499, 5, 110, 0, 0, 499, 500, 5, 40, 0, 0, 500, 106, 1, 0, 0, 0, 501, 502, 5, 99, 0, 0, 502, 503, 5, 111, 0, 0, 503, 504, 5, 115, 0, 0, 504, 505, 5, 40, 0, 0, 505, 108, 1, 0, 0, 0, 506, 507, 5, 116, 0, 0, 507, 508, 5, 97, 0, 0, 508, 509, 5, 110, 0, 0, 509, 510, 5, 40, 0, 0, 510, 110, 1, 0, 0, 0, 511, 512, 5, 99, 0, 0, 512, 513, 5, 111, 0, 0, 513, 514, 5, 116, 0, 0, 514, 515, 5, 97, 0, 0, 515, 516, 5, 110, 0, 0, 516, 517, 5, 40, 0, 0, 517, 112, 1, 0, 0, 0, 518, 519, 5, 99, 0, 0, 519, 520, 5, 111, 0, 0, 520, 521, 5, 116, 0, 0, 521, 522, 5, 40, 0, 0, 522, 114, 1, 0, 0, 0, 523, 524, 5, 115, 0, 0, 524, 525, 5, 101, 0, 0, 525, 526, 5, 99, 0, 0, 526, 527, 5, 40, 0, 0, 527, 116, 1, 0, 0, 0, 528, 529, 5, 99, 0, 0, 529, 530, 5, 111, 0, 0, 530, 531, 5, 115, 0, 0, 531, 532, 5, 101, 0, 0, 532, 533, 5, 99, 0, 0, 533, 534, 5, 40, 0, 0, 534, 118, 1, 0, 0, 0, 535, 536, 5, 99, 0, 0, 536, 537, 5, 115, 0, 0, 537, 538, 5, 99, 0, 0, 538, 539, 5, 40, 0, 0, 539, 120, 1, 0, 0, 0, 540, 541, 5, 97, 0, 0, 541, 542, 5, 114, 0, 0, 542, 543, 5, 99, 0, 0, 543, 544, 5, 115, 0, 0, 544, 545, 5, 105, 0, 0, 545, 546, 5, 110, 0, 0, 546, 547, 5, 40, 0, 0, 547, 122, 1, 0, 0, 0, 548, 549, 5, 97, 0, 0, 549, 550, 5, 114, 0, 0, 550, 551, 5, 99, 0, 0, 551, 552, 5, 99, 0, 0, 552, 553, 5, 111, 0, 0, 553, 554, 5, 115, 0, 0, 554, 555, 5, 40, 0, 0, 555, 124, 1, 0, 0, 0, 556, 557, 5, 97, 0, 0, 557, 558, 5, 114, 0, 0, 558, 559, 5, 99, 0, 0, 559, 560, 5, 116, 0, 0, 560, 561, 5, 97, 0, 0, 561, 562, 5, 110, 0, 0, 562, 563, 5, 40, 0, 0, 563, 126, 1, 0, 0, 0, 564, 565, 5, 97, 0, 0, 565, 566, 5, 114, 0, 0, 566, 567, 5, 99, 0, 0, 567, 568, 5, 99, 0, 0, 568, 569, 5, 111, 0, 0, 569, 570, 5, 116, 0, 0, 570, 571, 5, 97, 0, 0, 571, 572, 5, 110, 0, 0, 572, 573, 5, 40, 0, 0, 573, 128, 1, 0, 0, 0, 574, 575, 5, 97, 0, 0, 575, 576, 5, 114, 0, 0, 576, 577, 5, 99, 0, 0, 577, 578, 5, 115, 0, 0, 578, 579, 5, 101, 0, 0, 579, 580, 5, 99, 0, 0, 580, 581, 5, 40, 0, 0, 581, 130, 1, 0, 0, 0, 582, 583, 5, 97, 0, 0, 583, 584, 5, 114, 0, 0, 584, 585, 5, 99, 0, 0, 585, 586, 5, 99, 0, 0, 586, 587, 5, 111, 0, 0, 587, 588, 5, 115, 0, 0, 588, 589, 5, 101, 0, 0, 589, 590, 5, 99, 0, 0, 590, 591, 5, 40, 0, 0, 591, 132, 1, 0, 0, 0, 592, 593, 5, 97, 0, 0, 593, 594, 5, 114, 0, 0, 594, 595, 5, 99, 0, 0, 595, 596, 5, 99, 0, 0, 596, 597, 5, 115, 0, 0, 597, 598, 5, 99, 0, 0, 598, 599, 5, 40, 0, 0, 599, 134, 1, 0, 0, 0, 600, 601, 5, 97, 0, 0, 601, 602, 5, 99, 0, 0, 602, 603, 5, 115, 0, 0, 603, 604, 5, 99, 0, 0, 604, 605, 5, 40, 0, 0, 605, 136, 1, 0, 0, 0, 606, 607, 5, 97, 0, 0, 607, 608, 5, 115, 0, 0, 608, 609, 5, 105, 0, 0, 609, 610, 5, 110, 0, 0, 610, 611, 5, 40, 0, 0, 611, 138, 1, 0, 0, 0, 612, 613, 5, 97, 0, 0, 613, 614, 5, 99, 0, 0, 614, 615, 5, 111, 0, 0, 615, 616, 5, 115, 0, 0, 616, 617, 5, 40, 0, 0, 617, 140, 1, 0, 0, 0, 618, 619, 5, 97, 0, 0, 619, 620, 5, 116, 0, 0, 620, 621, 5, 97, 0, 0, 621, 622, 5, 110, 0, 0, 622, 623, 5, 40, 0, 0, 623, 142, 1, 0, 0, 0, 624, 625, 5, 97, 0, 0, 625, 626, 5, 99, 0, 0, 626, 627, 5, 111, 0, 0, 627, 628, 5, 116, 0, 0, 628, 629, 5, 97, 0, 0, 629, 630, 5, 110, 0, 0, 630, 631, 5, 40, 0, 0, 631, 144, 1, 0, 0, 0, 632, 633, 5, 97, 0, 0, 633, 634, 5, 115, 0, 0, 634, 635, 5, 101, 0, 0, 635, 636, 5, 99, 0, 0, 636, 637, 5, 40, 0, 0, 637, 146, 1, 0, 0, 0, 638, 639, 5, 97, 0, 0, 639, 640, 5, 99, 0, 0, 640, 641, 5, 111, 0, 0, 641, 642, 5, 115, 0, 0, 642, 643, 5, 101, 0, 0, 643, 644, 5, 99, 0, 0, 644, 645, 5, 40, 0, 0, 645, 148, 1, 0, 0, 0, 646, 647, 5, 97, 0, 0, 647, 648, 5, 99, 0, 0, 648, 649, 5, 111, 0, 0, 649, 650, 5, 116, 0, 0, 650, 651, 5, 40, 0, 0, 651, 150, 1, 0, 0, 0, 652, 653, 5, 97, 0, 0, 653, 654, 5, 114, 0, 0, 654, 655, 5, 99, 0, 0, 655, 656, 5, 99, 0, 0, 656, 657, 5, 111, 0, 0, 657, 658, 5, 116, 0, 0, 658, 659, 5, 40, 0, 0, 659, 152, 1, 0, 0, 0, 660, 661, 5, 115, 0, 0, 661, 662, 5, 105, 0, 0, 662, 663, 5, 110, 0, 0, 663, 664, 5, 104, 0, 0, 664, 665, 5, 40, 0, 0, 665, 154, 1, 0, 0, 0, 666, 667, 5, 115, 0, 0, 667, 668, 5, 104, 0, 0, 668, 669, 5, 40, 0, 0, 669, 156, 1, 0, 0, 0, 670, 671, 5, 99, 0, 0, 671, 672, 5, 111, 0, 0, 672, 673, 5, 115, 0, 0, 673, 674, 5, 104, 0, 0, 674, 675, 5, 40, 0, 0, 675, 158, 1, 0, 0, 0, 676, 677, 5, 99, 0, 0, 677, 678, 5, 104, 0, 0, 678, 679, 5, 40, 0, 0, 679, 160, 1, 0, 0, 0, 680, 681, 5, 116, 0, 0, 681, 682, 5, 97, 0, 0, 682, 683, 5, 110, 0, 0, 683, 684, 5, 104, 0, 0, 684, 685, 5, 40, 0, 0, 685, 162, 1, 0, 0, 0, 686, 687, 5, 116, 0, 0, 687, 688, 5, 104, 0, 0, 688, 689, 5, 40, 0, 0, 689, 164, 1, 0, 0, 0, 690, 691, 5, 99, 0, 0, 691, 692, 5, 111, 0, 0, 692, 693, 5, 116, 0, 0, 693, 694, 5, 97, 0, 0, 694, 695, 5, 110, 0, 0, 695, 696, 5, 104, 0, 0, 696, 697, 5, 40, 0, 0, 697, 166, 1, 0, 0, 0, 698, 699, 5, 99, 0, 0, 699, 700, 5, 111, 0, 0, 700, 701, 5, 116, 0, 0, 701, 702, 5, 104, 0, 0, 702, 703, 5, 40, 0, 0, 703, 168, 1, 0, 0, 0, 704, 705, 5, 99, 0, 0, 705, 706, 5, 116, 0, 0, 706, 707, 5, 104, 0, 0, 707, 708, 5, 40, 0, 0, 708, 170, 1, 0, 0, 0, 709, 710, 5, 115, 0, 0, 710, 711, 5, 101, 0, 0, 711, 712, 5, 99, 0, 0, 712, 713, 5, 104, 0, 0, 713, 714, 5, 40, 0, 0, 714, 172, 1, 0, 0, 0, 715, 716, 5, 115, 0, 0, 716, 717, 5, 99, 0, 0, 717, 718, 5, 104, 0, 0, 718, 719, 5, 40, 0, 0, 719, 174, 1, 0, 0, 0, 720, 721, 5, 99, 0, 0, 721, 722, 5, 111, 0, 0, 722, 723, 5, 115, 0, 0, 723, 724, 5, 101, 0, 0, 724, 725, 5, 99, 0, 0, 725, 726, 5, 104, 0, 0, 726, 727, 5, 40, 0, 0, 727, 176, 1, 0, 0, 0, 728, 729, 5, 99, 0, 0, 729, 730, 5, 115, 0, 0, 730, 731, 5, 99, 0, 0, 731, 732, 5, 104, 0, 0, 732, 733, 5, 40, 0, 0, 733, 178, 1, 0, 0, 0, 734, 735, 5, 97, 0, 0, 735, 736, 5, 115, 0, 0, 736, 737, 5, 105, 0, 0, 737, 738, 5, 110, 0, 0, 738, 739, 5, 104, 0, 0, 739, 740, 5, 40, 0, 0, 740, 180, 1, 0, 0, 0, 741, 742, 5, 97, 0, 0, 742, 743, 5, 114, 0, 0, 743, 744, 5, 115, 0, 0, 744, 745, 5, 105, 0, 0, 745, 746, 5, 110, 0, 0, 746, 747, 5, 104, 0, 0, 747, 748, 5, 40, 0, 0, 748, 182, 1, 0, 0, 0, 749, 750, 5, 97, 0, 0, 750, 751, 5, 114, 0, 0, 751, 752, 5, 115, 0, 0, 752, 753, 5, 104, 0, 0, 753, 754, 5, 40, 0, 0, 754, 184, 1, 0, 0, 0, 755, 756, 5, 97, 0, 0, 756, 757, 5, 114, 0, 0, 757, 758, 5, 99, 0, 0, 758, 759, 5, 115, 0, 0, 759, 760, 5, 105, 0, 0, 760, 761, 5, 110, 0, 0, 761, 762, 5, 104, 0, 0, 762, 763, 5, 40, 0, 0, 763, 186, 1, 0, 0, 0, 764, 765, 5, 97, 0, 0, 765, 766, 5, 99, 0, 0, 766, 767, 5, 111, 0, 0, 767, 768, 5, 115, 0, 0, 768, 769, 5, 104, 0, 0, 769, 770, 5, 40, 0, 0, 770, 188, 1, 0, 0, 0, 771, 772, 5, 97, 0, 0, 772, 773, 5, 114, 0, 0, 773, 774, 5, 99, 0, 0, 774, 775, 5, 111, 0, 0, 775, 776, 5, 115, 0, 0, 776, 777, 5, 104, 0, 0, 777, 778, 5, 40, 0, 0, 778, 190, 1, 0, 0, 0, 779, 780, 5, 97, 0, 0, 780, 781, 5, 114, 0, 0, 781, 782, 5, 99, 0, 0, 782, 783, 5, 104, 0, 0, 783, 784, 5, 40, 0, 0, 784, 192, 1, 0, 0, 0, 785, 786, 5, 97, 0, 0, 786, 787, 5, 114, 0, 0, 787, 788, 5, 99, 0, 0, 788, 789, 5, 99, 0, 0, 789, 790, 5, 111, 0, 0, 790, 791, 5, 115, 0, 0, 791, 792, 5, 104, 0, 0, 792, 793, 5, 40, 0, 0, 793, 194, 1, 0, 0, 0, 794, 795, 5, 97, 0, 0, 795, 796, 5, 116, 0, 0, 796, 797, 5, 97, 0, 0, 797, 798, 5, 110, 0, 0, 798, 799, 5, 104, 0, 0, 799, 800, 5, 40, 0, 0, 800, 196, 1, 0, 0, 0, 801, 802, 5, 97, 0, 0, 802, 803, 5, 114, 0, 0, 803, 804, 5, 116, 0, 0, 804, 805, 5, 97, 0, 0, 805, 806, 5, 110, 0, 0, 806, 807, 5, 104, 0, 0, 807, 808, 5, 40, 0, 0, 808, 198, 1, 0, 0, 0, 809, 810, 5, 97, 0, 0, 810, 811, 5, 114, 0, 0, 811, 812, 5, 116, 0, 0, 812, 813, 5, 104, 0, 0, 813, 814, 5, 40, 0, 0, 814, 200, 1, 0, 0, 0, 815, 816, 5, 97, 0, 0, 816, 817, 5, 114, 0, 0, 817, 818, 5, 99, 0, 0, 818, 819, 5, 116, 0, 0, 819, 820, 5, 97, 0, 0, 820, 821, 5, 110, 0, 0, 821, 822, 5, 104, 0, 0, 822, 823, 5, 40, 0, 0, 823, 202, 1, 0, 0, 0, 824, 825, 5, 97, 0, 0, 825, 826, 5, 99, 0, 0, 826, 827, 5, 111, 0, 0, 827, 828, 5, 116, 0, 0, 828, 829, 5, 104, 0, 0, 829, 830, 5, 40, 0, 0, 830, 204, 1, 0, 0, 0, 831, 832, 5, 97, 0, 0, 832, 833, 5, 114, 0, 0, 833, 834, 5, 99, 0, 0, 834, 835, 5, 111, 0, 0, 835, 836, 5, 116, 0, 0, 836, 837, 5, 104, 0, 0, 837, 838, 5, 40, 0, 0, 838, 206, 1, 0, 0, 0, 839, 840, 5, 97, 0, 0, 840, 841, 5, 99, 0, 0, 841, 842, 5, 111, 0, 0, 842, 843, 5, 116, 0, 0, 843, 844, 5, 97, 0, 0, 844, 845, 5, 110, 0, 0, 845, 846, 5, 104, 0, 0, 846, 847, 5, 40, 0, 0, 847, 208, 1, 0, 0, 0, 848, 849, 5, 97, 0, 0, 849, 850, 5, 114, 0, 0, 850, 851, 5, 99, 0, 0, 851, 852, 5, 111, 0, 0, 852, 853, 5, 116, 0, 0, 853, 854, 5, 97, 0, 0, 854, 855, 5, 110, 0, 0, 855, 856, 5, 104, 0, 0, 856, 857, 5, 40, 0, 0, 857, 210, 1, 0, 0, 0, 858, 859, 5, 97, 0, 0, 859, 860, 5, 114, 0, 0, 860, 861, 5, 99, 0, 0, 861, 862, 5, 116, 0, 0, 862, 863, 5, 104, 0, 0, 863, 864, 5, 40, 0, 0, 864, 212, 1, 0, 0, 0, 865, 866, 5, 97, 0, 0, 866, 867, 5, 114, 0, 0, 867, 868, 5, 99, 0, 0, 868, 869, 5, 99, 0, 0, 869, 870, 5, 111, 0, 0, 870, 871, 5, 116, 0, 0, 871, 872, 5, 97, 0, 0, 872, 873, 5, 110, 0, 0, 873, 874, 5, 104, 0, 0, 874, 875, 5, 40, 0, 0, 875, 214, 1, 0, 0, 0, 876, 877, 5, 97, 0, 0, 877, 878, 5, 115, 0, 0, 878, 879, 5, 101, 0, 0, 879, 880, 5, 99, 0, 0, 880, 881, 5, 104, 0, 0, 881, 882, 5, 40, 0, 0, 882, 216, 1, 0, 0, 0, 883, 884, 5, 97, 0, 0, 884, 885, 5, 114, 0, 0, 885, 886, 5, 115, 0, 0, 886, 887, 5, 101, 0, 0, 887, 888, 5, 99, 0, 0, 888, 889, 5, 104, 0, 0, 889, 890, 5, 40, 0, 0, 890, 218, 1, 0, 0, 0, 891, 892, 5, 97, 0, 0, 892, 893, 5, 114, 0, 0, 893, 894, 5, 115, 0, 0, 894, 895, 5, 99, 0, 0, 895, 896, 5, 104, 0, 0, 896, 897, 5, 40, 0, 0, 897, 220, 1, 0, 0, 0, 898, 899, 5, 97, 0, 0, 899, 900, 5, 114, 0, 0, 900, 901, 5, 99, 0, 0, 901, 902, 5, 115, 0, 0, 902, 903, 5, 101, 0, 0, 903, 904, 5, 99, 0, 0, 904, 905, 5, 104, 0, 0, 905, 906, 5, 40, 0, 0, 906, 222, 1, 0, 0, 0, 907, 908, 5, 97, 0, 0, 908, 909, 5, 99, 0, 0, 909, 910, 5, 111, 0, 0, 910, 911, 5, 115, 0, 0, 911, 912, 5, 101, 0, 0, 912, 913, 5, 99, 0, 0, 913, 914, 5, 104, 0, 0, 914, 915, 5, 40, 0, 0, 915, 224, 1, 0, 0, 0, 916, 917, 5, 97, 0, 0, 917, 918, 5, 114, 0, 0, 918, 919, 5, 99, 0, 0, 919, 920, 5, 111, 0, 0, 920, 921, 5, 115, 0, 0, 921, 922, 5, 101, 0, 0, 922, 923, 5, 99, 0, 0, 923, 924, 5, 104, 0, 0, 924, 925, 5, 40, 0, 0, 925, 226, 1, 0, 0, 0, 926, 927, 5, 97, 0, 0, 927, 928, 5, 114, 0, 0, 928, 929, 5, 99, 0, 0, 929, 930, 5, 115, 0, 0, 930, 931, 5, 99, 0, 0, 931, 932, 5, 104, 0, 0, 932, 933, 5, 40, 0, 0, 933, 228, 1, 0, 0, 0, 934, 935, 5, 97, 0, 0, 935, 936, 5, 114, 0, 0, 936, 937, 5, 99, 0, 0, 937, 938, 5, 99, 0, 0, 938, 939, 5, 111, 0, 0, 939, 940, 5, 115, 0, 0, 940, 941, 5, 101, 0, 0, 941, 942, 5, 99, 0, 0, 942, 943, 5, 104, 0, 0, 943, 944, 5, 40, 0, 0, 944, 230, 1, 0, 0, 0, 945, 946, 5, 97, 0, 0, 946, 947, 5, 99, 0, 0, 947, 948, 5, 115, 0, 0, 948, 949, 5, 99, 0, 0, 949, 950, 5, 104, 0, 0, 950, 951, 5, 40, 0, 0, 951, 232, 1, 0, 0, 0, 952, 953, 5, 102, 0, 0, 953, 954, 5, 97, 0, 0, 954, 955, 5, 99, 0, 0, 955, 956, 5, 116, 0, 0, 956, 957, 5, 111, 0, 0, 957, 958, 5, 114, 0, 0, 958, 959, 5, 105, 0, 0, 959, 960, 5, 97, 0, 0, 960, 961, 5, 108, 0, 0, 961, 962, 5, 40, 0, 0, 962, 234, 1, 0, 0, 0, 963, 964, 5, 103, 0, 0, 964, 965, 5, 97, 0, 0, 965, 966, 5, 109, 0, 0, 966, 967, 5, 109, 0, 0, 967, 968, 5, 97, 0, 0, 968, 969, 5, 40, 0, 0, 969, 236, 1, 0, 0, 0, 970, 971, 5, 100, 0, 0, 971, 972, 5, 101, 0, 0, 972, 973, 5, 114, 0, 0, 973, 974, 5, 105, 0, 0, 974, 975, 5, 118, 0, 0, 975, 976, 5, 97, 0, 0, 976, 977, 5, 116, 0, 0, 977, 978, 5, 105, 0, 0, 978, 979, 5, 118, 0, 0, 979, 980, 5, 101, 0, 0, 980, 981, 5, 40, 0, 0, 981, 238, 1, 0, 0, 0, 982, 983, 5, 105, 0, 0, 983, 984, 5, 110, 0, 0, 984, 985, 5, 116, 0, 0, 985, 986, 5, 101, 0, 0, 986, 987, 5, 103, 0, 0, 987, 988, 5, 114, 0, 0, 988, 989, 5, 97, 0, 0, 989, 990, 5, 108, 0, 0, 990, 991, 5, 40, 0, 0, 991, 240, 1, 0, 0, 0, 992, 993, 5, 108, 0, 0, 993, 994, 5, 105, 0, 0, 994, 995, 5, 109, 0, 0, 995, 996, 5, 105, 0, 0, 996, 997, 5, 116, 0, 0, 997, 998, 5, 40, 0, 0, 998, 242, 1, 0, 0, 0, 999, 1000, 5, 108, 0, 0, 1000, 1001, 5, 105, 0, 0, 1001, 1002, 5, 109, 0, 0, 1002, 1003, 5, 105, 0, 0, 1003, 1004, 5, 116, 0, 0, 1004, 1005, 5, 108, 0, 0, 1005, 1006, 5, 101, 0, 0, 1006, 1007, 5, 102, 0, 0, 1007, 1008, 5, 116, 0, 0, 1008, 1009, 5, 40, 0, 0, 1009, 244, 1, 0, 0, 0, 1010, 1011, 5, 108, 0, 0, 1011, 1012, 5, 105, 0, 0, 1012, 1013, 5, 109, 0, 0, 1013, 1014, 5, 105, 0, 0, 1014, 1015, 5, 116, 0, 0, 1015, 1016, 5, 114, 0, 0, 1016, 1017, 5, 105, 0, 0, 1017, 1018, 5, 103, 0, 0, 1018, 1019, 5, 104, 0, 0, 1019, 1020, 5, 116, 0, 0, 1020, 1021, 5, 40, 0, 0, 1021, 246, 1, 0, 0, 0, 1022, 1023, 5, 115, 0, 0, 1023, 1024, 5, 105, 0, 0, 1024, 1025, 5, 103, 0, 0, 1025, 1026, 5, 110, 0, 0, 1026, 1027, 5, 117, 0, 0, 1027, 1028, 5, 109, 0, 0, 1028, 1029, 5, 40, 0, 0, 1029, 248, 1, 0, 0, 0, 1030, 1031, 5, 115, 0, 0, 1031, 1032, 5, 103, 0, 0, 1032, 1033, 5, 110, 0, 0, 1033, 1034, 5, 40, 0, 0, 1034, 250, 1, 0, 0, 0, 1035, 1036, 5, 115, 0, 0, 1036, 1037, 5, 105, 0, 0, 1037, 1038, 5, 103, 0, 0, 1038, 1039, 5, 110, 0, 0, 1039, 1040, 5, 40, 0, 0, 1040, 252, 1, 0, 0, 0, 1041, 1042, 5, 97, 0, 0, 1042, 1043, 5, 98, 0, 0, 1043, 1044, 5, 115, 0, 0, 1044, 1045, 5, 40, 0, 0, 1045, 254, 1, 0, 0, 0, 1046, 1047, 5, 112, 0, 0, 1047, 1048, 5, 104, 0, 0, 1048, 1049, 5, 105, 0, 0, 1049, 1050, 5, 40, 0, 0, 1050, 256, 1, 0, 0, 0, 1051, 1052, 5, 102, 0, 0, 1052, 1053, 5, 108, 0, 0, 1053, 1054, 5, 111, 0, 0, 1054, 1055, 5, 111, 0, 0, 1055, 1056, 5, 114, 0, 0, 1056, 1057, 5, 40, 0, 0, 1057, 258, 1, 0, 0, 0, 1058, 1059, 5, 99, 0, 0, 1059, 1060, 5, 101, 0, 0, 1060, 1061, 5, 105, 0, 0, 1061, 1062, 5, 108, 0, 0, 1062, 1063, 5, 40, 0, 0, 1063, 260, 1, 0, 0, 0, 1064, 1065, 5, 99, 0, 0, 1065, 1066, 5, 101, 0, 0, 1066, 1067, 5, 105, 0, 0, 1067, 1068, 5, 108, 0, 0, 1068, 1069, 5, 105, 0, 0, 1069, 1070, 5, 110, 0, 0, 1070, 1071, 5, 103, 0, 0, 1071, 1072, 5, 40, 0, 0, 1072, 262, 1, 0, 0, 0, 1073, 1074, 5, 114, 0, 0, 1074, 1075, 5, 111, 0, 0, 1075, 1076, 5, 117, 0, 0, 1076, 1077, 5, 110, 0, 0, 1077, 1078, 5, 100, 0, 0, 1078, 1079, 5, 40, 0, 0, 1079, 264, 1, 0, 0, 0, 1080, 1081, 5, 116, 0, 0, 1081, 1082, 5, 114, 0, 0, 1082, 1083, 5, 117, 0, 0, 1083, 1084, 5, 110, 0, 0, 1084, 1085, 5, 99, 0, 0, 1085, 1086, 5, 40, 0, 0, 1086, 266, 1, 0, 0, 0, 1087, 1088, 5, 109, 0, 0, 1088, 1089, 5, 105, 0, 0, 1089, 1090, 5, 110, 0, 0, 1090, 1091, 5, 40, 0, 0, 1091, 268, 1, 0, 0, 0, 1092, 1093, 5, 109, 0, 0, 1093, 1094, 5, 97, 0, 0, 1094, 1095, 5, 120, 0, 0, 1095, 1096, 5, 40, 0, 0, 1096, 270, 1, 0, 0, 0, 1097, 1098, 5, 103, 0, 0, 1098, 1099, 5, 99, 0, 0, 1099, 1100, 5, 100, 0, 0, 1100, 1101, 5, 40, 0, 0, 1101, 272, 1, 0, 0, 0, 1102, 1103, 5, 108, 0, 0, 1103, 1104, 5, 99, 0, 0, 1104, 1105, 5, 109, 0, 0, 1105, 1106, 5, 40, 0, 0, 1106, 274, 1, 0, 0, 0, 1107, 1108, 5, 101, 0, 0, 1108, 1109, 5, 114, 0, 0, 1109, 1110, 5, 102, 0, 0, 1110, 1111, 5, 40, 0, 0, 1111, 276, 1, 0, 0, 0, 1112, 1113, 5, 99, 0, 0, 1113, 1114, 5, 111, 0, 0, 1114, 1115, 5, 110, 0, 0, 1115, 1116, 5, 106, 0, 0, 1116, 1117, 5, 117, 0, 0, 1117, 1118, 5, 103, 0, 0, 1118, 1119, 5, 97, 0, 0, 1119, 1120, 5, 116, 0, 0, 1120, 1121, 5, 101, 0, 0, 1121, 1122, 5, 40, 0, 0, 1122, 278, 1, 0, 0, 0, 1123, 1124, 5, 100, 0, 0, 1124, 1125, 5, 111, 0, 0, 1125, 1126, 5, 109, 0, 0, 1126, 1127, 5, 97, 0, 0, 1127, 1128, 5, 105, 0, 0, 1128, 1129, 5, 110, 0, 0, 1129, 1130, 5, 40, 0, 0, 1130, 280, 1, 0, 0, 0, 1131, 1132, 5, 112, 0, 0, 1132, 1133, 5, 105, 0, 0, 1133, 1134, 5, 101, 0, 0, 1134, 1135, 5, 99, 0, 0, 1135, 1136, 5, 101, 0, 0, 1136, 1137, 5, 119, 0, 0, 1137, 1138, 5, 105, 0, 0, 1138, 1139, 5, 115, 0, 0, 1139, 1140, 5, 101, 0, 0, 1140, 1141, 5, 40, 0, 0, 1141, 282, 1, 0, 0, 0, 1142, 1143, 5, 97, 0, 0, 1143, 1144, 5, 112, 0, 0, 1144, 1145, 5, 112, 0, 0, 1145, 1146, 5, 108, 0, 0, 1146, 1147, 5, 121, 0, 0, 1147, 1148, 5, 40, 0, 0, 1148, 284, 1, 0, 0, 0, 1149, 1150, 5, 108, 0, 0, 1150, 1151, 5, 97, 0, 0, 1151, 1152, 5, 109, 0, 0, 1152, 1153, 5, 98, 0, 0, 1153, 1154, 5, 100, 0, 0, 1154, 1155, 5, 97, 0, 0, 1155, 1156, 5, 40, 0, 0, 1156, 286, 1, 0, 0, 0, 1157, 1159, 5, 13, 0, 0, 1158, 1157, 1, 0, 0, 0, 1158, 1159, 1, 0, 0, 0, 1159, 1160, 1, 0, 0, 0, 1160, 1162, 5, 10, 0, 0, 1161, 1158, 1, 0, 0, 0, 1162, 1163, 1, 0, 0, 0, 1163, 1161, 1, 0, 0, 0, 1163, 1164, 1, 0, 0, 0, 1164, 1165, 1, 0, 0, 0, 1165, 1166, 6, 143, 0, 0, 1166, 288, 1, 0, 0, 0, 1167, 1169, 7, 0, 0, 0, 1168, 1170, 7, 1, 0, 0, 1169, 1168, 1, 0, 0, 0, 1169, 1170, 1, 0, 0, 0, 1170, 1172, 1, 0, 0, 0, 1171, 1173, 2, 48, 57, 0, 1172, 1171, 1, 0, 0, 0, 1173, 1174, 1, 0, 0, 0, 1174, 1172, 1, 0, 0, 0, 1174, 1175, 1, 0, 0, 0, 1175, 290, 1, 0, 0, 0, 1176, 1178, 2, 48, 57, 0, 1177, 1176, 1, 0, 0, 0, 1178, 1179, 1, 0, 0, 0, 1179, 1177, 1, 0, 0, 0, 1179, 1180, 1, 0, 0, 0, 1180, 1181, 1, 0, 0, 0, 1181, 1185, 5, 46, 0, 0, 1182, 1184, 2, 48, 57, 0, 1183, 1182, 1, 0, 0, 0, 1184, 1187, 1, 0, 0, 0, 1185, 1183, 1, 0, 0, 0, 1185, 1186, 1, 0, 0, 0, 1186, 1189, 1, 0, 0, 0, 1187, 1185, 1, 0, 0, 0, 1188, 1190, 3, 289, 144, 0, 1189, 1188, 1, 0, 0, 0, 1189, 1190, 1, 0, 0, 0, 1190, 1192, 1, 0, 0, 0, 1191, 1193, 5, 105, 0, 0, 1192, 1191, 1, 0, 0, 0, 1192, 1193, 1, 0, 0, 0, 1193, 1210, 1, 0, 0, 0, 1194, 1196, 5, 46, 0, 0, 1195, 1194, 1, 0, 0, 0, 1195, 1196, 1, 0, 0, 0, 1196, 1198, 1, 0, 0, 0, 1197, 1199, 2, 48, 57, 0, 1198, 1197, 1, 0, 0, 0, 1199, 1200, 1, 0, 0, 0, 1200, 1198, 1, 0, 0, 0, 1200, 1201, 1, 0, 0, 0, 1201, 1203, 1, 0, 0, 0, 1202, 1204, 3, 289, 144, 0, 1203, 1202, 1, 0, 0, 0, 1203, 1204, 1, 0, 0, 0, 1204, 1206, 1, 0, 0, 0, 1205, 1207, 5, 105, 0, 0, 1206, 1205, 1, 0, 0, 0, 1206, 1207, 1, 0, 0, 0, 1207, 1210, 1, 0, 0, 0, 1208, 1210, 5, 105, 0, 0, 1209, 1177, 1, 0, 0, 0, 1209, 1195, 1, 0, 0, 0, 1209, 1208, 1, 0, 0, 0, 1210, 292, 1, 0, 0, 0, 1211, 1212, 5, 67, 0, 0, 1212, 1222, 5, 67, 0, 0, 1213, 1214, 5, 82, 0, 0, 1214, 1222, 5, 82, 0, 0, 1215, 1216, 5, 81, 0, 0, 1216, 1222, 5, 81, 0, 0, 1217, 1218, 5, 90, 0, 0, 1218, 1222, 5, 90, 0, 0, 1219, 1220, 5, 66, 0, 0, 1220, 1222, 5, 66, 0, 0, 1221, 1211, 1, 0, 0, 0, 1221, 1213, 1, 0, 0, 0, 1221, 1215, 1, 0, 0, 0, 1221, 1217, 1, 0, 0, 0, 1221, 1219, 1, 0, 0, 0, 1222, 294, 1, 0, 0, 0, 1223, 1224, 5, 116, 0, 0, 1224, 1225, 5, 114, 0, 0, 1225, 1226, 5, 117, 0, 0, 1226, 1242, 5, 101, 0, 0, 1227, 1228, 5, 84, 0, 0, 1228, 1229, 5, 114, 0, 0, 1229, 1230, 5, 117, 0, 0, 1230, 1242, 5, 101, 0, 0, 1231, 1232, 5, 102, 0, 0, 1232, 1233, 5, 97, 0, 0, 1233, 1234, 5, 108, 0, 0, 1234, 1235, 5, 115, 0, 0, 1235, 1242, 5, 101, 0, 0, 1236, 1237, 5, 70, 0, 0, 1237, 1238, 5, 97, 0, 0, 1238, 1239, 5, 108, 0, 0, 1239, 1240, 5, 115, 0, 0, 1240, 1242, 5, 101, 0, 0, 1241, 1223, 1, 0, 0, 0, 1241, 1227, 1, 0, 0, 0, 1241, 1231, 1, 0, 0, 0, 1241, 1236, 1, 0, 0, 0, 1242, 296, 1, 0, 0, 0, 1243, 1245, 7, 2, 0, 0, 1244, 1243, 1, 0, 0, 0, 1245, 1246, 1, 0, 0, 0, 1246, 1244, 1, 0, 0, 0, 1246, 1247, 1, 0, 0, 0, 1247, 1254, 1, 0, 0, 0, 1248, 1250, 5, 95, 0, 0, 1249, 1251, 7, 3, 0, 0, 1250, 1249, 1, 0, 0, 0, 1251, 1252, 1, 0, 0, 0, 1252, 1250, 1, 0, 0, 0, 1252, 1253, 1, 0, 0, 0, 1253, 1255, 1, 0, 0, 0, 1254, 1248, 1, 0, 0, 0, 1254, 1255, 1, 0, 0, 0, 1255, 298, 1, 0, 0, 0, 1256, 1257, 5, 47, 0, 0, 1257, 1258, 5, 47, 0, 0, 1258, 1262, 1, 0, 0, 0, 1259, 1261, 8, 4, 0, 0, 1260, 1259, 1, 0, 0, 0, 1261, 1264, 1, 0, 0, 0, 1262, 1260, 1, 0, 0, 0, 1262, 1263, 1, 0, 0, 0, 1263, 1266, 1, 0, 0, 0, 1264, 1262, 1, 0, 0, 0, 1265, 1267, 5, 13, 0, 0, 1266, 1265, 1, 0, 0, 0, 1266, 1267, 1, 0, 0, 0, 1267, 1268, 1, 0, 0, 0, 1268, 1281, 5, 10, 0, 0, 1269, 1270, 5, 47, 0, 0, 1270, 1271, 5, 42, 0, 0, 1271, 1275, 1, 0, 0, 0, 1272, 1274, 9, 0, 0, 0, 1273, 1272, 1, 0, 0, 0, 1274, 1277, 1, 0, 0, 0, 1275, 1276, 1, 0, 0, 0, 1275, 1273, 1, 0, 0, 0, 1276, 1278, 1, 0, 0, 0, 1277, 1275, 1, 0, 0, 0, 1278, 1279, 5, 42, 0, 0, 1279, 1281, 5, 47, 0, 0, 1280, 1256, 1, 0, 0, 0, 1280, 1269, 1, 0, 0, 0, 1281, 1282, 1, 0, 0, 0, 1282, 1283, 6, 149, 0, 0, 1283, 300, 1, 0, 0, 0, 1284, 1286, 7, 5, 0, 0, 1285, 1284, 1, 0, 0, 0, 1286, 1287, 1, 0, 0, 0, 1287, 1285, 1, 0, 0, 0, 1287, 1288, 1, 0, 0, 0, 1288, 1289, 1, 0, 0, 0, 1289, 1290, 6, 150, 0, 0, 1290, 302, 1, 0, 0, 0, 24, 0, 1158, 1163, 1169, 1174, 1179, 1185, 1189, 1192, 1195, 1200, 1203, 1206, 1209, 1221, 1241, 1246, 1252, 1254, 1262, 1266, 1275, 1280, 1287, 1, 6, 0, 0] \ No newline at end of file +[4, 0, 150, 1291, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 2, 88, 7, 88, 2, 89, 7, 89, 2, 90, 7, 90, 2, 91, 7, 91, 2, 92, 7, 92, 2, 93, 7, 93, 2, 94, 7, 94, 2, 95, 7, 95, 2, 96, 7, 96, 2, 97, 7, 97, 2, 98, 7, 98, 2, 99, 7, 99, 2, 100, 7, 100, 2, 101, 7, 101, 2, 102, 7, 102, 2, 103, 7, 103, 2, 104, 7, 104, 2, 105, 7, 105, 2, 106, 7, 106, 2, 107, 7, 107, 2, 108, 7, 108, 2, 109, 7, 109, 2, 110, 7, 110, 2, 111, 7, 111, 2, 112, 7, 112, 2, 113, 7, 113, 2, 114, 7, 114, 2, 115, 7, 115, 2, 116, 7, 116, 2, 117, 7, 117, 2, 118, 7, 118, 2, 119, 7, 119, 2, 120, 7, 120, 2, 121, 7, 121, 2, 122, 7, 122, 2, 123, 7, 123, 2, 124, 7, 124, 2, 125, 7, 125, 2, 126, 7, 126, 2, 127, 7, 127, 2, 128, 7, 128, 2, 129, 7, 129, 2, 130, 7, 130, 2, 131, 7, 131, 2, 132, 7, 132, 2, 133, 7, 133, 2, 134, 7, 134, 2, 135, 7, 135, 2, 136, 7, 136, 2, 137, 7, 137, 2, 138, 7, 138, 2, 139, 7, 139, 2, 140, 7, 140, 2, 141, 7, 141, 2, 142, 7, 142, 2, 143, 7, 143, 2, 144, 7, 144, 2, 145, 7, 145, 2, 146, 7, 146, 2, 147, 7, 147, 2, 148, 7, 148, 2, 149, 7, 149, 2, 150, 7, 150, 1, 0, 1, 0, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 17, 1, 17, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 29, 1, 29, 1, 30, 1, 30, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 32, 1, 33, 1, 33, 1, 33, 1, 33, 1, 34, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 39, 1, 39, 1, 40, 1, 40, 1, 41, 1, 41, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 50, 1, 50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 69, 1, 69, 1, 69, 1, 69, 1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 77, 1, 77, 1, 77, 1, 77, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 79, 1, 79, 1, 79, 1, 79, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 81, 1, 81, 1, 81, 1, 81, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 88, 1, 88, 1, 88, 1, 88, 1, 88, 1, 88, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 90, 1, 90, 1, 90, 1, 90, 1, 90, 1, 90, 1, 90, 1, 90, 1, 91, 1, 91, 1, 91, 1, 91, 1, 91, 1, 91, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 99, 1, 99, 1, 99, 1, 99, 1, 99, 1, 99, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 101, 1, 101, 1, 101, 1, 101, 1, 101, 1, 101, 1, 101, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 103, 1, 103, 1, 103, 1, 103, 1, 103, 1, 103, 1, 103, 1, 103, 1, 103, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 105, 1, 105, 1, 105, 1, 105, 1, 105, 1, 105, 1, 105, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 107, 1, 107, 1, 107, 1, 107, 1, 107, 1, 107, 1, 107, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 109, 1, 109, 1, 109, 1, 109, 1, 109, 1, 109, 1, 109, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 111, 1, 111, 1, 111, 1, 111, 1, 111, 1, 111, 1, 111, 1, 111, 1, 111, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 126, 1, 126, 1, 126, 1, 126, 1, 126, 1, 127, 1, 127, 1, 127, 1, 127, 1, 127, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 1, 129, 1, 129, 1, 129, 1, 129, 1, 129, 1, 129, 1, 130, 1, 130, 1, 130, 1, 130, 1, 130, 1, 130, 1, 130, 1, 130, 1, 130, 1, 131, 1, 131, 1, 131, 1, 131, 1, 131, 1, 131, 1, 131, 1, 132, 1, 132, 1, 132, 1, 132, 1, 132, 1, 133, 1, 133, 1, 133, 1, 133, 1, 133, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 135, 1, 135, 1, 135, 1, 135, 1, 135, 1, 135, 1, 135, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 137, 1, 137, 1, 137, 1, 137, 1, 137, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 139, 1, 139, 1, 139, 1, 139, 1, 139, 1, 139, 1, 139, 1, 139, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 141, 1, 141, 1, 141, 1, 141, 1, 141, 1, 141, 1, 141, 1, 142, 1, 142, 1, 142, 1, 142, 1, 142, 1, 142, 1, 142, 1, 142, 1, 143, 3, 143, 1159, 8, 143, 1, 143, 4, 143, 1162, 8, 143, 11, 143, 12, 143, 1163, 1, 143, 1, 143, 1, 144, 1, 144, 3, 144, 1170, 8, 144, 1, 144, 4, 144, 1173, 8, 144, 11, 144, 12, 144, 1174, 1, 145, 4, 145, 1178, 8, 145, 11, 145, 12, 145, 1179, 1, 145, 1, 145, 5, 145, 1184, 8, 145, 10, 145, 12, 145, 1187, 9, 145, 1, 145, 3, 145, 1190, 8, 145, 1, 145, 3, 145, 1193, 8, 145, 1, 145, 3, 145, 1196, 8, 145, 1, 145, 4, 145, 1199, 8, 145, 11, 145, 12, 145, 1200, 1, 145, 3, 145, 1204, 8, 145, 1, 145, 3, 145, 1207, 8, 145, 1, 145, 3, 145, 1210, 8, 145, 1, 146, 1, 146, 1, 146, 1, 146, 1, 146, 1, 146, 1, 146, 1, 146, 1, 146, 1, 146, 3, 146, 1222, 8, 146, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 3, 147, 1242, 8, 147, 1, 148, 4, 148, 1245, 8, 148, 11, 148, 12, 148, 1246, 1, 148, 1, 148, 4, 148, 1251, 8, 148, 11, 148, 12, 148, 1252, 3, 148, 1255, 8, 148, 1, 149, 1, 149, 1, 149, 1, 149, 5, 149, 1261, 8, 149, 10, 149, 12, 149, 1264, 9, 149, 1, 149, 3, 149, 1267, 8, 149, 1, 149, 1, 149, 1, 149, 1, 149, 1, 149, 5, 149, 1274, 8, 149, 10, 149, 12, 149, 1277, 9, 149, 1, 149, 1, 149, 3, 149, 1281, 8, 149, 1, 149, 1, 149, 1, 150, 4, 150, 1286, 8, 150, 11, 150, 12, 150, 1287, 1, 150, 1, 150, 1, 1275, 0, 151, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23, 12, 25, 13, 27, 14, 29, 15, 31, 16, 33, 17, 35, 18, 37, 19, 39, 20, 41, 21, 43, 22, 45, 23, 47, 24, 49, 25, 51, 26, 53, 27, 55, 28, 57, 29, 59, 30, 61, 31, 63, 32, 65, 33, 67, 34, 69, 35, 71, 36, 73, 37, 75, 38, 77, 39, 79, 40, 81, 41, 83, 42, 85, 43, 87, 44, 89, 45, 91, 46, 93, 47, 95, 48, 97, 49, 99, 50, 101, 51, 103, 52, 105, 53, 107, 54, 109, 55, 111, 56, 113, 57, 115, 58, 117, 59, 119, 60, 121, 61, 123, 62, 125, 63, 127, 64, 129, 65, 131, 66, 133, 67, 135, 68, 137, 69, 139, 70, 141, 71, 143, 72, 145, 73, 147, 74, 149, 75, 151, 76, 153, 77, 155, 78, 157, 79, 159, 80, 161, 81, 163, 82, 165, 83, 167, 84, 169, 85, 171, 86, 173, 87, 175, 88, 177, 89, 179, 90, 181, 91, 183, 92, 185, 93, 187, 94, 189, 95, 191, 96, 193, 97, 195, 98, 197, 99, 199, 100, 201, 101, 203, 102, 205, 103, 207, 104, 209, 105, 211, 106, 213, 107, 215, 108, 217, 109, 219, 110, 221, 111, 223, 112, 225, 113, 227, 114, 229, 115, 231, 116, 233, 117, 235, 118, 237, 119, 239, 120, 241, 121, 243, 122, 245, 123, 247, 124, 249, 125, 251, 126, 253, 127, 255, 128, 257, 129, 259, 130, 261, 131, 263, 132, 265, 133, 267, 134, 269, 135, 271, 136, 273, 137, 275, 138, 277, 139, 279, 140, 281, 141, 283, 142, 285, 143, 287, 144, 289, 0, 291, 145, 293, 146, 295, 147, 297, 148, 299, 149, 301, 150, 1, 0, 6, 2, 0, 69, 69, 101, 101, 2, 0, 43, 43, 45, 45, 4, 0, 65, 90, 97, 122, 880, 1279, 7936, 8191, 5, 0, 48, 57, 65, 90, 97, 122, 880, 1279, 7936, 8191, 2, 0, 10, 10, 13, 13, 2, 0, 9, 9, 32, 32, 1318, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, 41, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 49, 1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1, 0, 0, 0, 0, 55, 1, 0, 0, 0, 0, 57, 1, 0, 0, 0, 0, 59, 1, 0, 0, 0, 0, 61, 1, 0, 0, 0, 0, 63, 1, 0, 0, 0, 0, 65, 1, 0, 0, 0, 0, 67, 1, 0, 0, 0, 0, 69, 1, 0, 0, 0, 0, 71, 1, 0, 0, 0, 0, 73, 1, 0, 0, 0, 0, 75, 1, 0, 0, 0, 0, 77, 1, 0, 0, 0, 0, 79, 1, 0, 0, 0, 0, 81, 1, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 85, 1, 0, 0, 0, 0, 87, 1, 0, 0, 0, 0, 89, 1, 0, 0, 0, 0, 91, 1, 0, 0, 0, 0, 93, 1, 0, 0, 0, 0, 95, 1, 0, 0, 0, 0, 97, 1, 0, 0, 0, 0, 99, 1, 0, 0, 0, 0, 101, 1, 0, 0, 0, 0, 103, 1, 0, 0, 0, 0, 105, 1, 0, 0, 0, 0, 107, 1, 0, 0, 0, 0, 109, 1, 0, 0, 0, 0, 111, 1, 0, 0, 0, 0, 113, 1, 0, 0, 0, 0, 115, 1, 0, 0, 0, 0, 117, 1, 0, 0, 0, 0, 119, 1, 0, 0, 0, 0, 121, 1, 0, 0, 0, 0, 123, 1, 0, 0, 0, 0, 125, 1, 0, 0, 0, 0, 127, 1, 0, 0, 0, 0, 129, 1, 0, 0, 0, 0, 131, 1, 0, 0, 0, 0, 133, 1, 0, 0, 0, 0, 135, 1, 0, 0, 0, 0, 137, 1, 0, 0, 0, 0, 139, 1, 0, 0, 0, 0, 141, 1, 0, 0, 0, 0, 143, 1, 0, 0, 0, 0, 145, 1, 0, 0, 0, 0, 147, 1, 0, 0, 0, 0, 149, 1, 0, 0, 0, 0, 151, 1, 0, 0, 0, 0, 153, 1, 0, 0, 0, 0, 155, 1, 0, 0, 0, 0, 157, 1, 0, 0, 0, 0, 159, 1, 0, 0, 0, 0, 161, 1, 0, 0, 0, 0, 163, 1, 0, 0, 0, 0, 165, 1, 0, 0, 0, 0, 167, 1, 0, 0, 0, 0, 169, 1, 0, 0, 0, 0, 171, 1, 0, 0, 0, 0, 173, 1, 0, 0, 0, 0, 175, 1, 0, 0, 0, 0, 177, 1, 0, 0, 0, 0, 179, 1, 0, 0, 0, 0, 181, 1, 0, 0, 0, 0, 183, 1, 0, 0, 0, 0, 185, 1, 0, 0, 0, 0, 187, 1, 0, 0, 0, 0, 189, 1, 0, 0, 0, 0, 191, 1, 0, 0, 0, 0, 193, 1, 0, 0, 0, 0, 195, 1, 0, 0, 0, 0, 197, 1, 0, 0, 0, 0, 199, 1, 0, 0, 0, 0, 201, 1, 0, 0, 0, 0, 203, 1, 0, 0, 0, 0, 205, 1, 0, 0, 0, 0, 207, 1, 0, 0, 0, 0, 209, 1, 0, 0, 0, 0, 211, 1, 0, 0, 0, 0, 213, 1, 0, 0, 0, 0, 215, 1, 0, 0, 0, 0, 217, 1, 0, 0, 0, 0, 219, 1, 0, 0, 0, 0, 221, 1, 0, 0, 0, 0, 223, 1, 0, 0, 0, 0, 225, 1, 0, 0, 0, 0, 227, 1, 0, 0, 0, 0, 229, 1, 0, 0, 0, 0, 231, 1, 0, 0, 0, 0, 233, 1, 0, 0, 0, 0, 235, 1, 0, 0, 0, 0, 237, 1, 0, 0, 0, 0, 239, 1, 0, 0, 0, 0, 241, 1, 0, 0, 0, 0, 243, 1, 0, 0, 0, 0, 245, 1, 0, 0, 0, 0, 247, 1, 0, 0, 0, 0, 249, 1, 0, 0, 0, 0, 251, 1, 0, 0, 0, 0, 253, 1, 0, 0, 0, 0, 255, 1, 0, 0, 0, 0, 257, 1, 0, 0, 0, 0, 259, 1, 0, 0, 0, 0, 261, 1, 0, 0, 0, 0, 263, 1, 0, 0, 0, 0, 265, 1, 0, 0, 0, 0, 267, 1, 0, 0, 0, 0, 269, 1, 0, 0, 0, 0, 271, 1, 0, 0, 0, 0, 273, 1, 0, 0, 0, 0, 275, 1, 0, 0, 0, 0, 277, 1, 0, 0, 0, 0, 279, 1, 0, 0, 0, 0, 281, 1, 0, 0, 0, 0, 283, 1, 0, 0, 0, 0, 285, 1, 0, 0, 0, 0, 287, 1, 0, 0, 0, 0, 291, 1, 0, 0, 0, 0, 293, 1, 0, 0, 0, 0, 295, 1, 0, 0, 0, 0, 297, 1, 0, 0, 0, 0, 299, 1, 0, 0, 0, 0, 301, 1, 0, 0, 0, 1, 303, 1, 0, 0, 0, 3, 305, 1, 0, 0, 0, 5, 307, 1, 0, 0, 0, 7, 309, 1, 0, 0, 0, 9, 311, 1, 0, 0, 0, 11, 313, 1, 0, 0, 0, 13, 315, 1, 0, 0, 0, 15, 319, 1, 0, 0, 0, 17, 329, 1, 0, 0, 0, 19, 332, 1, 0, 0, 0, 21, 338, 1, 0, 0, 0, 23, 341, 1, 0, 0, 0, 25, 353, 1, 0, 0, 0, 27, 355, 1, 0, 0, 0, 29, 358, 1, 0, 0, 0, 31, 361, 1, 0, 0, 0, 33, 364, 1, 0, 0, 0, 35, 366, 1, 0, 0, 0, 37, 368, 1, 0, 0, 0, 39, 370, 1, 0, 0, 0, 41, 373, 1, 0, 0, 0, 43, 377, 1, 0, 0, 0, 45, 381, 1, 0, 0, 0, 47, 383, 1, 0, 0, 0, 49, 387, 1, 0, 0, 0, 51, 390, 1, 0, 0, 0, 53, 392, 1, 0, 0, 0, 55, 400, 1, 0, 0, 0, 57, 403, 1, 0, 0, 0, 59, 412, 1, 0, 0, 0, 61, 414, 1, 0, 0, 0, 63, 416, 1, 0, 0, 0, 65, 418, 1, 0, 0, 0, 67, 422, 1, 0, 0, 0, 69, 426, 1, 0, 0, 0, 71, 429, 1, 0, 0, 0, 73, 432, 1, 0, 0, 0, 75, 434, 1, 0, 0, 0, 77, 437, 1, 0, 0, 0, 79, 439, 1, 0, 0, 0, 81, 441, 1, 0, 0, 0, 83, 443, 1, 0, 0, 0, 85, 445, 1, 0, 0, 0, 87, 447, 1, 0, 0, 0, 89, 452, 1, 0, 0, 0, 91, 459, 1, 0, 0, 0, 93, 465, 1, 0, 0, 0, 95, 470, 1, 0, 0, 0, 97, 476, 1, 0, 0, 0, 99, 482, 1, 0, 0, 0, 101, 487, 1, 0, 0, 0, 103, 491, 1, 0, 0, 0, 105, 496, 1, 0, 0, 0, 107, 501, 1, 0, 0, 0, 109, 506, 1, 0, 0, 0, 111, 511, 1, 0, 0, 0, 113, 518, 1, 0, 0, 0, 115, 523, 1, 0, 0, 0, 117, 528, 1, 0, 0, 0, 119, 535, 1, 0, 0, 0, 121, 540, 1, 0, 0, 0, 123, 548, 1, 0, 0, 0, 125, 556, 1, 0, 0, 0, 127, 564, 1, 0, 0, 0, 129, 574, 1, 0, 0, 0, 131, 582, 1, 0, 0, 0, 133, 592, 1, 0, 0, 0, 135, 600, 1, 0, 0, 0, 137, 606, 1, 0, 0, 0, 139, 612, 1, 0, 0, 0, 141, 618, 1, 0, 0, 0, 143, 624, 1, 0, 0, 0, 145, 632, 1, 0, 0, 0, 147, 638, 1, 0, 0, 0, 149, 646, 1, 0, 0, 0, 151, 652, 1, 0, 0, 0, 153, 660, 1, 0, 0, 0, 155, 666, 1, 0, 0, 0, 157, 670, 1, 0, 0, 0, 159, 676, 1, 0, 0, 0, 161, 680, 1, 0, 0, 0, 163, 686, 1, 0, 0, 0, 165, 690, 1, 0, 0, 0, 167, 698, 1, 0, 0, 0, 169, 704, 1, 0, 0, 0, 171, 709, 1, 0, 0, 0, 173, 715, 1, 0, 0, 0, 175, 720, 1, 0, 0, 0, 177, 728, 1, 0, 0, 0, 179, 734, 1, 0, 0, 0, 181, 741, 1, 0, 0, 0, 183, 749, 1, 0, 0, 0, 185, 755, 1, 0, 0, 0, 187, 764, 1, 0, 0, 0, 189, 771, 1, 0, 0, 0, 191, 779, 1, 0, 0, 0, 193, 785, 1, 0, 0, 0, 195, 794, 1, 0, 0, 0, 197, 801, 1, 0, 0, 0, 199, 809, 1, 0, 0, 0, 201, 815, 1, 0, 0, 0, 203, 824, 1, 0, 0, 0, 205, 831, 1, 0, 0, 0, 207, 839, 1, 0, 0, 0, 209, 848, 1, 0, 0, 0, 211, 858, 1, 0, 0, 0, 213, 865, 1, 0, 0, 0, 215, 876, 1, 0, 0, 0, 217, 883, 1, 0, 0, 0, 219, 891, 1, 0, 0, 0, 221, 898, 1, 0, 0, 0, 223, 907, 1, 0, 0, 0, 225, 916, 1, 0, 0, 0, 227, 926, 1, 0, 0, 0, 229, 934, 1, 0, 0, 0, 231, 945, 1, 0, 0, 0, 233, 952, 1, 0, 0, 0, 235, 963, 1, 0, 0, 0, 237, 970, 1, 0, 0, 0, 239, 982, 1, 0, 0, 0, 241, 992, 1, 0, 0, 0, 243, 999, 1, 0, 0, 0, 245, 1010, 1, 0, 0, 0, 247, 1022, 1, 0, 0, 0, 249, 1030, 1, 0, 0, 0, 251, 1035, 1, 0, 0, 0, 253, 1041, 1, 0, 0, 0, 255, 1046, 1, 0, 0, 0, 257, 1051, 1, 0, 0, 0, 259, 1058, 1, 0, 0, 0, 261, 1064, 1, 0, 0, 0, 263, 1073, 1, 0, 0, 0, 265, 1080, 1, 0, 0, 0, 267, 1085, 1, 0, 0, 0, 269, 1090, 1, 0, 0, 0, 271, 1095, 1, 0, 0, 0, 273, 1102, 1, 0, 0, 0, 275, 1107, 1, 0, 0, 0, 277, 1112, 1, 0, 0, 0, 279, 1123, 1, 0, 0, 0, 281, 1131, 1, 0, 0, 0, 283, 1142, 1, 0, 0, 0, 285, 1149, 1, 0, 0, 0, 287, 1161, 1, 0, 0, 0, 289, 1167, 1, 0, 0, 0, 291, 1209, 1, 0, 0, 0, 293, 1221, 1, 0, 0, 0, 295, 1241, 1, 0, 0, 0, 297, 1244, 1, 0, 0, 0, 299, 1280, 1, 0, 0, 0, 301, 1285, 1, 0, 0, 0, 303, 304, 5, 33, 0, 0, 304, 2, 1, 0, 0, 0, 305, 306, 5, 94, 0, 0, 306, 4, 1, 0, 0, 0, 307, 308, 5, 45, 0, 0, 308, 6, 1, 0, 0, 0, 309, 310, 5, 43, 0, 0, 310, 8, 1, 0, 0, 0, 311, 312, 5, 42, 0, 0, 312, 10, 1, 0, 0, 0, 313, 314, 5, 47, 0, 0, 314, 12, 1, 0, 0, 0, 315, 316, 5, 109, 0, 0, 316, 317, 5, 111, 0, 0, 317, 318, 5, 100, 0, 0, 318, 14, 1, 0, 0, 0, 319, 320, 5, 105, 0, 0, 320, 321, 5, 110, 0, 0, 321, 322, 5, 116, 0, 0, 322, 323, 5, 101, 0, 0, 323, 324, 5, 114, 0, 0, 324, 325, 5, 115, 0, 0, 325, 326, 5, 101, 0, 0, 326, 327, 5, 99, 0, 0, 327, 328, 5, 116, 0, 0, 328, 16, 1, 0, 0, 0, 329, 330, 5, 47, 0, 0, 330, 331, 5, 92, 0, 0, 331, 18, 1, 0, 0, 0, 332, 333, 5, 117, 0, 0, 333, 334, 5, 110, 0, 0, 334, 335, 5, 105, 0, 0, 335, 336, 5, 116, 0, 0, 336, 337, 5, 101, 0, 0, 337, 20, 1, 0, 0, 0, 338, 339, 5, 92, 0, 0, 339, 340, 5, 47, 0, 0, 340, 22, 1, 0, 0, 0, 341, 342, 5, 115, 0, 0, 342, 343, 5, 101, 0, 0, 343, 344, 5, 116, 0, 0, 344, 345, 5, 115, 0, 0, 345, 346, 5, 117, 0, 0, 346, 347, 5, 98, 0, 0, 347, 348, 5, 116, 0, 0, 348, 349, 5, 114, 0, 0, 349, 350, 5, 97, 0, 0, 350, 351, 5, 99, 0, 0, 351, 352, 5, 116, 0, 0, 352, 24, 1, 0, 0, 0, 353, 354, 5, 92, 0, 0, 354, 26, 1, 0, 0, 0, 355, 356, 5, 105, 0, 0, 356, 357, 5, 110, 0, 0, 357, 28, 1, 0, 0, 0, 358, 359, 5, 62, 0, 0, 359, 360, 5, 61, 0, 0, 360, 30, 1, 0, 0, 0, 361, 362, 5, 60, 0, 0, 362, 363, 5, 61, 0, 0, 363, 32, 1, 0, 0, 0, 364, 365, 5, 62, 0, 0, 365, 34, 1, 0, 0, 0, 366, 367, 5, 60, 0, 0, 367, 36, 1, 0, 0, 0, 368, 369, 5, 61, 0, 0, 369, 38, 1, 0, 0, 0, 370, 371, 5, 60, 0, 0, 371, 372, 5, 62, 0, 0, 372, 40, 1, 0, 0, 0, 373, 374, 5, 110, 0, 0, 374, 375, 5, 111, 0, 0, 375, 376, 5, 116, 0, 0, 376, 42, 1, 0, 0, 0, 377, 378, 5, 97, 0, 0, 378, 379, 5, 110, 0, 0, 379, 380, 5, 100, 0, 0, 380, 44, 1, 0, 0, 0, 381, 382, 5, 38, 0, 0, 382, 46, 1, 0, 0, 0, 383, 384, 5, 120, 0, 0, 384, 385, 5, 111, 0, 0, 385, 386, 5, 114, 0, 0, 386, 48, 1, 0, 0, 0, 387, 388, 5, 111, 0, 0, 388, 389, 5, 114, 0, 0, 389, 50, 1, 0, 0, 0, 390, 391, 5, 124, 0, 0, 391, 52, 1, 0, 0, 0, 392, 393, 5, 105, 0, 0, 393, 394, 5, 109, 0, 0, 394, 395, 5, 112, 0, 0, 395, 396, 5, 108, 0, 0, 396, 397, 5, 105, 0, 0, 397, 398, 5, 101, 0, 0, 398, 399, 5, 115, 0, 0, 399, 54, 1, 0, 0, 0, 400, 401, 5, 45, 0, 0, 401, 402, 5, 62, 0, 0, 402, 56, 1, 0, 0, 0, 403, 404, 5, 112, 0, 0, 404, 405, 5, 114, 0, 0, 405, 406, 5, 111, 0, 0, 406, 407, 5, 118, 0, 0, 407, 408, 5, 105, 0, 0, 408, 409, 5, 100, 0, 0, 409, 410, 5, 101, 0, 0, 410, 411, 5, 100, 0, 0, 411, 58, 1, 0, 0, 0, 412, 413, 5, 44, 0, 0, 413, 60, 1, 0, 0, 0, 414, 415, 5, 59, 0, 0, 415, 62, 1, 0, 0, 0, 416, 417, 5, 58, 0, 0, 417, 64, 1, 0, 0, 0, 418, 419, 5, 43, 0, 0, 419, 420, 5, 111, 0, 0, 420, 421, 5, 111, 0, 0, 421, 66, 1, 0, 0, 0, 422, 423, 5, 45, 0, 0, 423, 424, 5, 111, 0, 0, 424, 425, 5, 111, 0, 0, 425, 68, 1, 0, 0, 0, 426, 427, 5, 40, 0, 0, 427, 428, 5, 124, 0, 0, 428, 70, 1, 0, 0, 0, 429, 430, 5, 124, 0, 0, 430, 431, 5, 41, 0, 0, 431, 72, 1, 0, 0, 0, 432, 433, 5, 91, 0, 0, 433, 74, 1, 0, 0, 0, 434, 435, 5, 93, 0, 0, 435, 436, 5, 84, 0, 0, 436, 76, 1, 0, 0, 0, 437, 438, 5, 93, 0, 0, 438, 78, 1, 0, 0, 0, 439, 440, 5, 40, 0, 0, 440, 80, 1, 0, 0, 0, 441, 442, 5, 41, 0, 0, 442, 82, 1, 0, 0, 0, 443, 444, 5, 123, 0, 0, 444, 84, 1, 0, 0, 0, 445, 446, 5, 125, 0, 0, 446, 86, 1, 0, 0, 0, 447, 448, 5, 108, 0, 0, 448, 449, 5, 111, 0, 0, 449, 450, 5, 103, 0, 0, 450, 451, 5, 40, 0, 0, 451, 88, 1, 0, 0, 0, 452, 453, 5, 108, 0, 0, 453, 454, 5, 111, 0, 0, 454, 455, 5, 103, 0, 0, 455, 456, 5, 49, 0, 0, 456, 457, 5, 48, 0, 0, 457, 458, 5, 40, 0, 0, 458, 90, 1, 0, 0, 0, 459, 460, 5, 108, 0, 0, 460, 461, 5, 111, 0, 0, 461, 462, 5, 103, 0, 0, 462, 463, 5, 50, 0, 0, 463, 464, 5, 40, 0, 0, 464, 92, 1, 0, 0, 0, 465, 466, 5, 112, 0, 0, 466, 467, 5, 111, 0, 0, 467, 468, 5, 119, 0, 0, 468, 469, 5, 40, 0, 0, 469, 94, 1, 0, 0, 0, 470, 471, 5, 115, 0, 0, 471, 472, 5, 113, 0, 0, 472, 473, 5, 114, 0, 0, 473, 474, 5, 116, 0, 0, 474, 475, 5, 40, 0, 0, 475, 96, 1, 0, 0, 0, 476, 477, 5, 99, 0, 0, 477, 478, 5, 98, 0, 0, 478, 479, 5, 114, 0, 0, 479, 480, 5, 116, 0, 0, 480, 481, 5, 40, 0, 0, 481, 98, 1, 0, 0, 0, 482, 483, 5, 115, 0, 0, 483, 484, 5, 113, 0, 0, 484, 485, 5, 114, 0, 0, 485, 486, 5, 40, 0, 0, 486, 100, 1, 0, 0, 0, 487, 488, 5, 108, 0, 0, 488, 489, 5, 110, 0, 0, 489, 490, 5, 40, 0, 0, 490, 102, 1, 0, 0, 0, 491, 492, 5, 101, 0, 0, 492, 493, 5, 120, 0, 0, 493, 494, 5, 112, 0, 0, 494, 495, 5, 40, 0, 0, 495, 104, 1, 0, 0, 0, 496, 497, 5, 115, 0, 0, 497, 498, 5, 105, 0, 0, 498, 499, 5, 110, 0, 0, 499, 500, 5, 40, 0, 0, 500, 106, 1, 0, 0, 0, 501, 502, 5, 99, 0, 0, 502, 503, 5, 111, 0, 0, 503, 504, 5, 115, 0, 0, 504, 505, 5, 40, 0, 0, 505, 108, 1, 0, 0, 0, 506, 507, 5, 116, 0, 0, 507, 508, 5, 97, 0, 0, 508, 509, 5, 110, 0, 0, 509, 510, 5, 40, 0, 0, 510, 110, 1, 0, 0, 0, 511, 512, 5, 99, 0, 0, 512, 513, 5, 111, 0, 0, 513, 514, 5, 116, 0, 0, 514, 515, 5, 97, 0, 0, 515, 516, 5, 110, 0, 0, 516, 517, 5, 40, 0, 0, 517, 112, 1, 0, 0, 0, 518, 519, 5, 99, 0, 0, 519, 520, 5, 111, 0, 0, 520, 521, 5, 116, 0, 0, 521, 522, 5, 40, 0, 0, 522, 114, 1, 0, 0, 0, 523, 524, 5, 115, 0, 0, 524, 525, 5, 101, 0, 0, 525, 526, 5, 99, 0, 0, 526, 527, 5, 40, 0, 0, 527, 116, 1, 0, 0, 0, 528, 529, 5, 99, 0, 0, 529, 530, 5, 111, 0, 0, 530, 531, 5, 115, 0, 0, 531, 532, 5, 101, 0, 0, 532, 533, 5, 99, 0, 0, 533, 534, 5, 40, 0, 0, 534, 118, 1, 0, 0, 0, 535, 536, 5, 99, 0, 0, 536, 537, 5, 115, 0, 0, 537, 538, 5, 99, 0, 0, 538, 539, 5, 40, 0, 0, 539, 120, 1, 0, 0, 0, 540, 541, 5, 97, 0, 0, 541, 542, 5, 114, 0, 0, 542, 543, 5, 99, 0, 0, 543, 544, 5, 115, 0, 0, 544, 545, 5, 105, 0, 0, 545, 546, 5, 110, 0, 0, 546, 547, 5, 40, 0, 0, 547, 122, 1, 0, 0, 0, 548, 549, 5, 97, 0, 0, 549, 550, 5, 114, 0, 0, 550, 551, 5, 99, 0, 0, 551, 552, 5, 99, 0, 0, 552, 553, 5, 111, 0, 0, 553, 554, 5, 115, 0, 0, 554, 555, 5, 40, 0, 0, 555, 124, 1, 0, 0, 0, 556, 557, 5, 97, 0, 0, 557, 558, 5, 114, 0, 0, 558, 559, 5, 99, 0, 0, 559, 560, 5, 116, 0, 0, 560, 561, 5, 97, 0, 0, 561, 562, 5, 110, 0, 0, 562, 563, 5, 40, 0, 0, 563, 126, 1, 0, 0, 0, 564, 565, 5, 97, 0, 0, 565, 566, 5, 114, 0, 0, 566, 567, 5, 99, 0, 0, 567, 568, 5, 99, 0, 0, 568, 569, 5, 111, 0, 0, 569, 570, 5, 116, 0, 0, 570, 571, 5, 97, 0, 0, 571, 572, 5, 110, 0, 0, 572, 573, 5, 40, 0, 0, 573, 128, 1, 0, 0, 0, 574, 575, 5, 97, 0, 0, 575, 576, 5, 114, 0, 0, 576, 577, 5, 99, 0, 0, 577, 578, 5, 115, 0, 0, 578, 579, 5, 101, 0, 0, 579, 580, 5, 99, 0, 0, 580, 581, 5, 40, 0, 0, 581, 130, 1, 0, 0, 0, 582, 583, 5, 97, 0, 0, 583, 584, 5, 114, 0, 0, 584, 585, 5, 99, 0, 0, 585, 586, 5, 99, 0, 0, 586, 587, 5, 111, 0, 0, 587, 588, 5, 115, 0, 0, 588, 589, 5, 101, 0, 0, 589, 590, 5, 99, 0, 0, 590, 591, 5, 40, 0, 0, 591, 132, 1, 0, 0, 0, 592, 593, 5, 97, 0, 0, 593, 594, 5, 114, 0, 0, 594, 595, 5, 99, 0, 0, 595, 596, 5, 99, 0, 0, 596, 597, 5, 115, 0, 0, 597, 598, 5, 99, 0, 0, 598, 599, 5, 40, 0, 0, 599, 134, 1, 0, 0, 0, 600, 601, 5, 97, 0, 0, 601, 602, 5, 99, 0, 0, 602, 603, 5, 115, 0, 0, 603, 604, 5, 99, 0, 0, 604, 605, 5, 40, 0, 0, 605, 136, 1, 0, 0, 0, 606, 607, 5, 97, 0, 0, 607, 608, 5, 115, 0, 0, 608, 609, 5, 105, 0, 0, 609, 610, 5, 110, 0, 0, 610, 611, 5, 40, 0, 0, 611, 138, 1, 0, 0, 0, 612, 613, 5, 97, 0, 0, 613, 614, 5, 99, 0, 0, 614, 615, 5, 111, 0, 0, 615, 616, 5, 115, 0, 0, 616, 617, 5, 40, 0, 0, 617, 140, 1, 0, 0, 0, 618, 619, 5, 97, 0, 0, 619, 620, 5, 116, 0, 0, 620, 621, 5, 97, 0, 0, 621, 622, 5, 110, 0, 0, 622, 623, 5, 40, 0, 0, 623, 142, 1, 0, 0, 0, 624, 625, 5, 97, 0, 0, 625, 626, 5, 99, 0, 0, 626, 627, 5, 111, 0, 0, 627, 628, 5, 116, 0, 0, 628, 629, 5, 97, 0, 0, 629, 630, 5, 110, 0, 0, 630, 631, 5, 40, 0, 0, 631, 144, 1, 0, 0, 0, 632, 633, 5, 97, 0, 0, 633, 634, 5, 115, 0, 0, 634, 635, 5, 101, 0, 0, 635, 636, 5, 99, 0, 0, 636, 637, 5, 40, 0, 0, 637, 146, 1, 0, 0, 0, 638, 639, 5, 97, 0, 0, 639, 640, 5, 99, 0, 0, 640, 641, 5, 111, 0, 0, 641, 642, 5, 115, 0, 0, 642, 643, 5, 101, 0, 0, 643, 644, 5, 99, 0, 0, 644, 645, 5, 40, 0, 0, 645, 148, 1, 0, 0, 0, 646, 647, 5, 97, 0, 0, 647, 648, 5, 99, 0, 0, 648, 649, 5, 111, 0, 0, 649, 650, 5, 116, 0, 0, 650, 651, 5, 40, 0, 0, 651, 150, 1, 0, 0, 0, 652, 653, 5, 97, 0, 0, 653, 654, 5, 114, 0, 0, 654, 655, 5, 99, 0, 0, 655, 656, 5, 99, 0, 0, 656, 657, 5, 111, 0, 0, 657, 658, 5, 116, 0, 0, 658, 659, 5, 40, 0, 0, 659, 152, 1, 0, 0, 0, 660, 661, 5, 115, 0, 0, 661, 662, 5, 105, 0, 0, 662, 663, 5, 110, 0, 0, 663, 664, 5, 104, 0, 0, 664, 665, 5, 40, 0, 0, 665, 154, 1, 0, 0, 0, 666, 667, 5, 115, 0, 0, 667, 668, 5, 104, 0, 0, 668, 669, 5, 40, 0, 0, 669, 156, 1, 0, 0, 0, 670, 671, 5, 99, 0, 0, 671, 672, 5, 111, 0, 0, 672, 673, 5, 115, 0, 0, 673, 674, 5, 104, 0, 0, 674, 675, 5, 40, 0, 0, 675, 158, 1, 0, 0, 0, 676, 677, 5, 99, 0, 0, 677, 678, 5, 104, 0, 0, 678, 679, 5, 40, 0, 0, 679, 160, 1, 0, 0, 0, 680, 681, 5, 116, 0, 0, 681, 682, 5, 97, 0, 0, 682, 683, 5, 110, 0, 0, 683, 684, 5, 104, 0, 0, 684, 685, 5, 40, 0, 0, 685, 162, 1, 0, 0, 0, 686, 687, 5, 116, 0, 0, 687, 688, 5, 104, 0, 0, 688, 689, 5, 40, 0, 0, 689, 164, 1, 0, 0, 0, 690, 691, 5, 99, 0, 0, 691, 692, 5, 111, 0, 0, 692, 693, 5, 116, 0, 0, 693, 694, 5, 97, 0, 0, 694, 695, 5, 110, 0, 0, 695, 696, 5, 104, 0, 0, 696, 697, 5, 40, 0, 0, 697, 166, 1, 0, 0, 0, 698, 699, 5, 99, 0, 0, 699, 700, 5, 111, 0, 0, 700, 701, 5, 116, 0, 0, 701, 702, 5, 104, 0, 0, 702, 703, 5, 40, 0, 0, 703, 168, 1, 0, 0, 0, 704, 705, 5, 99, 0, 0, 705, 706, 5, 116, 0, 0, 706, 707, 5, 104, 0, 0, 707, 708, 5, 40, 0, 0, 708, 170, 1, 0, 0, 0, 709, 710, 5, 115, 0, 0, 710, 711, 5, 101, 0, 0, 711, 712, 5, 99, 0, 0, 712, 713, 5, 104, 0, 0, 713, 714, 5, 40, 0, 0, 714, 172, 1, 0, 0, 0, 715, 716, 5, 115, 0, 0, 716, 717, 5, 99, 0, 0, 717, 718, 5, 104, 0, 0, 718, 719, 5, 40, 0, 0, 719, 174, 1, 0, 0, 0, 720, 721, 5, 99, 0, 0, 721, 722, 5, 111, 0, 0, 722, 723, 5, 115, 0, 0, 723, 724, 5, 101, 0, 0, 724, 725, 5, 99, 0, 0, 725, 726, 5, 104, 0, 0, 726, 727, 5, 40, 0, 0, 727, 176, 1, 0, 0, 0, 728, 729, 5, 99, 0, 0, 729, 730, 5, 115, 0, 0, 730, 731, 5, 99, 0, 0, 731, 732, 5, 104, 0, 0, 732, 733, 5, 40, 0, 0, 733, 178, 1, 0, 0, 0, 734, 735, 5, 97, 0, 0, 735, 736, 5, 115, 0, 0, 736, 737, 5, 105, 0, 0, 737, 738, 5, 110, 0, 0, 738, 739, 5, 104, 0, 0, 739, 740, 5, 40, 0, 0, 740, 180, 1, 0, 0, 0, 741, 742, 5, 97, 0, 0, 742, 743, 5, 114, 0, 0, 743, 744, 5, 115, 0, 0, 744, 745, 5, 105, 0, 0, 745, 746, 5, 110, 0, 0, 746, 747, 5, 104, 0, 0, 747, 748, 5, 40, 0, 0, 748, 182, 1, 0, 0, 0, 749, 750, 5, 97, 0, 0, 750, 751, 5, 114, 0, 0, 751, 752, 5, 115, 0, 0, 752, 753, 5, 104, 0, 0, 753, 754, 5, 40, 0, 0, 754, 184, 1, 0, 0, 0, 755, 756, 5, 97, 0, 0, 756, 757, 5, 114, 0, 0, 757, 758, 5, 99, 0, 0, 758, 759, 5, 115, 0, 0, 759, 760, 5, 105, 0, 0, 760, 761, 5, 110, 0, 0, 761, 762, 5, 104, 0, 0, 762, 763, 5, 40, 0, 0, 763, 186, 1, 0, 0, 0, 764, 765, 5, 97, 0, 0, 765, 766, 5, 99, 0, 0, 766, 767, 5, 111, 0, 0, 767, 768, 5, 115, 0, 0, 768, 769, 5, 104, 0, 0, 769, 770, 5, 40, 0, 0, 770, 188, 1, 0, 0, 0, 771, 772, 5, 97, 0, 0, 772, 773, 5, 114, 0, 0, 773, 774, 5, 99, 0, 0, 774, 775, 5, 111, 0, 0, 775, 776, 5, 115, 0, 0, 776, 777, 5, 104, 0, 0, 777, 778, 5, 40, 0, 0, 778, 190, 1, 0, 0, 0, 779, 780, 5, 97, 0, 0, 780, 781, 5, 114, 0, 0, 781, 782, 5, 99, 0, 0, 782, 783, 5, 104, 0, 0, 783, 784, 5, 40, 0, 0, 784, 192, 1, 0, 0, 0, 785, 786, 5, 97, 0, 0, 786, 787, 5, 114, 0, 0, 787, 788, 5, 99, 0, 0, 788, 789, 5, 99, 0, 0, 789, 790, 5, 111, 0, 0, 790, 791, 5, 115, 0, 0, 791, 792, 5, 104, 0, 0, 792, 793, 5, 40, 0, 0, 793, 194, 1, 0, 0, 0, 794, 795, 5, 97, 0, 0, 795, 796, 5, 116, 0, 0, 796, 797, 5, 97, 0, 0, 797, 798, 5, 110, 0, 0, 798, 799, 5, 104, 0, 0, 799, 800, 5, 40, 0, 0, 800, 196, 1, 0, 0, 0, 801, 802, 5, 97, 0, 0, 802, 803, 5, 114, 0, 0, 803, 804, 5, 116, 0, 0, 804, 805, 5, 97, 0, 0, 805, 806, 5, 110, 0, 0, 806, 807, 5, 104, 0, 0, 807, 808, 5, 40, 0, 0, 808, 198, 1, 0, 0, 0, 809, 810, 5, 97, 0, 0, 810, 811, 5, 114, 0, 0, 811, 812, 5, 116, 0, 0, 812, 813, 5, 104, 0, 0, 813, 814, 5, 40, 0, 0, 814, 200, 1, 0, 0, 0, 815, 816, 5, 97, 0, 0, 816, 817, 5, 114, 0, 0, 817, 818, 5, 99, 0, 0, 818, 819, 5, 116, 0, 0, 819, 820, 5, 97, 0, 0, 820, 821, 5, 110, 0, 0, 821, 822, 5, 104, 0, 0, 822, 823, 5, 40, 0, 0, 823, 202, 1, 0, 0, 0, 824, 825, 5, 97, 0, 0, 825, 826, 5, 99, 0, 0, 826, 827, 5, 111, 0, 0, 827, 828, 5, 116, 0, 0, 828, 829, 5, 104, 0, 0, 829, 830, 5, 40, 0, 0, 830, 204, 1, 0, 0, 0, 831, 832, 5, 97, 0, 0, 832, 833, 5, 114, 0, 0, 833, 834, 5, 99, 0, 0, 834, 835, 5, 111, 0, 0, 835, 836, 5, 116, 0, 0, 836, 837, 5, 104, 0, 0, 837, 838, 5, 40, 0, 0, 838, 206, 1, 0, 0, 0, 839, 840, 5, 97, 0, 0, 840, 841, 5, 99, 0, 0, 841, 842, 5, 111, 0, 0, 842, 843, 5, 116, 0, 0, 843, 844, 5, 97, 0, 0, 844, 845, 5, 110, 0, 0, 845, 846, 5, 104, 0, 0, 846, 847, 5, 40, 0, 0, 847, 208, 1, 0, 0, 0, 848, 849, 5, 97, 0, 0, 849, 850, 5, 114, 0, 0, 850, 851, 5, 99, 0, 0, 851, 852, 5, 111, 0, 0, 852, 853, 5, 116, 0, 0, 853, 854, 5, 97, 0, 0, 854, 855, 5, 110, 0, 0, 855, 856, 5, 104, 0, 0, 856, 857, 5, 40, 0, 0, 857, 210, 1, 0, 0, 0, 858, 859, 5, 97, 0, 0, 859, 860, 5, 114, 0, 0, 860, 861, 5, 99, 0, 0, 861, 862, 5, 116, 0, 0, 862, 863, 5, 104, 0, 0, 863, 864, 5, 40, 0, 0, 864, 212, 1, 0, 0, 0, 865, 866, 5, 97, 0, 0, 866, 867, 5, 114, 0, 0, 867, 868, 5, 99, 0, 0, 868, 869, 5, 99, 0, 0, 869, 870, 5, 111, 0, 0, 870, 871, 5, 116, 0, 0, 871, 872, 5, 97, 0, 0, 872, 873, 5, 110, 0, 0, 873, 874, 5, 104, 0, 0, 874, 875, 5, 40, 0, 0, 875, 214, 1, 0, 0, 0, 876, 877, 5, 97, 0, 0, 877, 878, 5, 115, 0, 0, 878, 879, 5, 101, 0, 0, 879, 880, 5, 99, 0, 0, 880, 881, 5, 104, 0, 0, 881, 882, 5, 40, 0, 0, 882, 216, 1, 0, 0, 0, 883, 884, 5, 97, 0, 0, 884, 885, 5, 114, 0, 0, 885, 886, 5, 115, 0, 0, 886, 887, 5, 101, 0, 0, 887, 888, 5, 99, 0, 0, 888, 889, 5, 104, 0, 0, 889, 890, 5, 40, 0, 0, 890, 218, 1, 0, 0, 0, 891, 892, 5, 97, 0, 0, 892, 893, 5, 114, 0, 0, 893, 894, 5, 115, 0, 0, 894, 895, 5, 99, 0, 0, 895, 896, 5, 104, 0, 0, 896, 897, 5, 40, 0, 0, 897, 220, 1, 0, 0, 0, 898, 899, 5, 97, 0, 0, 899, 900, 5, 114, 0, 0, 900, 901, 5, 99, 0, 0, 901, 902, 5, 115, 0, 0, 902, 903, 5, 101, 0, 0, 903, 904, 5, 99, 0, 0, 904, 905, 5, 104, 0, 0, 905, 906, 5, 40, 0, 0, 906, 222, 1, 0, 0, 0, 907, 908, 5, 97, 0, 0, 908, 909, 5, 99, 0, 0, 909, 910, 5, 111, 0, 0, 910, 911, 5, 115, 0, 0, 911, 912, 5, 101, 0, 0, 912, 913, 5, 99, 0, 0, 913, 914, 5, 104, 0, 0, 914, 915, 5, 40, 0, 0, 915, 224, 1, 0, 0, 0, 916, 917, 5, 97, 0, 0, 917, 918, 5, 114, 0, 0, 918, 919, 5, 99, 0, 0, 919, 920, 5, 111, 0, 0, 920, 921, 5, 115, 0, 0, 921, 922, 5, 101, 0, 0, 922, 923, 5, 99, 0, 0, 923, 924, 5, 104, 0, 0, 924, 925, 5, 40, 0, 0, 925, 226, 1, 0, 0, 0, 926, 927, 5, 97, 0, 0, 927, 928, 5, 114, 0, 0, 928, 929, 5, 99, 0, 0, 929, 930, 5, 115, 0, 0, 930, 931, 5, 99, 0, 0, 931, 932, 5, 104, 0, 0, 932, 933, 5, 40, 0, 0, 933, 228, 1, 0, 0, 0, 934, 935, 5, 97, 0, 0, 935, 936, 5, 114, 0, 0, 936, 937, 5, 99, 0, 0, 937, 938, 5, 99, 0, 0, 938, 939, 5, 111, 0, 0, 939, 940, 5, 115, 0, 0, 940, 941, 5, 101, 0, 0, 941, 942, 5, 99, 0, 0, 942, 943, 5, 104, 0, 0, 943, 944, 5, 40, 0, 0, 944, 230, 1, 0, 0, 0, 945, 946, 5, 97, 0, 0, 946, 947, 5, 99, 0, 0, 947, 948, 5, 115, 0, 0, 948, 949, 5, 99, 0, 0, 949, 950, 5, 104, 0, 0, 950, 951, 5, 40, 0, 0, 951, 232, 1, 0, 0, 0, 952, 953, 5, 102, 0, 0, 953, 954, 5, 97, 0, 0, 954, 955, 5, 99, 0, 0, 955, 956, 5, 116, 0, 0, 956, 957, 5, 111, 0, 0, 957, 958, 5, 114, 0, 0, 958, 959, 5, 105, 0, 0, 959, 960, 5, 97, 0, 0, 960, 961, 5, 108, 0, 0, 961, 962, 5, 40, 0, 0, 962, 234, 1, 0, 0, 0, 963, 964, 5, 103, 0, 0, 964, 965, 5, 97, 0, 0, 965, 966, 5, 109, 0, 0, 966, 967, 5, 109, 0, 0, 967, 968, 5, 97, 0, 0, 968, 969, 5, 40, 0, 0, 969, 236, 1, 0, 0, 0, 970, 971, 5, 100, 0, 0, 971, 972, 5, 101, 0, 0, 972, 973, 5, 114, 0, 0, 973, 974, 5, 105, 0, 0, 974, 975, 5, 118, 0, 0, 975, 976, 5, 97, 0, 0, 976, 977, 5, 116, 0, 0, 977, 978, 5, 105, 0, 0, 978, 979, 5, 118, 0, 0, 979, 980, 5, 101, 0, 0, 980, 981, 5, 40, 0, 0, 981, 238, 1, 0, 0, 0, 982, 983, 5, 105, 0, 0, 983, 984, 5, 110, 0, 0, 984, 985, 5, 116, 0, 0, 985, 986, 5, 101, 0, 0, 986, 987, 5, 103, 0, 0, 987, 988, 5, 114, 0, 0, 988, 989, 5, 97, 0, 0, 989, 990, 5, 108, 0, 0, 990, 991, 5, 40, 0, 0, 991, 240, 1, 0, 0, 0, 992, 993, 5, 108, 0, 0, 993, 994, 5, 105, 0, 0, 994, 995, 5, 109, 0, 0, 995, 996, 5, 105, 0, 0, 996, 997, 5, 116, 0, 0, 997, 998, 5, 40, 0, 0, 998, 242, 1, 0, 0, 0, 999, 1000, 5, 108, 0, 0, 1000, 1001, 5, 105, 0, 0, 1001, 1002, 5, 109, 0, 0, 1002, 1003, 5, 105, 0, 0, 1003, 1004, 5, 116, 0, 0, 1004, 1005, 5, 108, 0, 0, 1005, 1006, 5, 101, 0, 0, 1006, 1007, 5, 102, 0, 0, 1007, 1008, 5, 116, 0, 0, 1008, 1009, 5, 40, 0, 0, 1009, 244, 1, 0, 0, 0, 1010, 1011, 5, 108, 0, 0, 1011, 1012, 5, 105, 0, 0, 1012, 1013, 5, 109, 0, 0, 1013, 1014, 5, 105, 0, 0, 1014, 1015, 5, 116, 0, 0, 1015, 1016, 5, 114, 0, 0, 1016, 1017, 5, 105, 0, 0, 1017, 1018, 5, 103, 0, 0, 1018, 1019, 5, 104, 0, 0, 1019, 1020, 5, 116, 0, 0, 1020, 1021, 5, 40, 0, 0, 1021, 246, 1, 0, 0, 0, 1022, 1023, 5, 115, 0, 0, 1023, 1024, 5, 105, 0, 0, 1024, 1025, 5, 103, 0, 0, 1025, 1026, 5, 110, 0, 0, 1026, 1027, 5, 117, 0, 0, 1027, 1028, 5, 109, 0, 0, 1028, 1029, 5, 40, 0, 0, 1029, 248, 1, 0, 0, 0, 1030, 1031, 5, 115, 0, 0, 1031, 1032, 5, 103, 0, 0, 1032, 1033, 5, 110, 0, 0, 1033, 1034, 5, 40, 0, 0, 1034, 250, 1, 0, 0, 0, 1035, 1036, 5, 115, 0, 0, 1036, 1037, 5, 105, 0, 0, 1037, 1038, 5, 103, 0, 0, 1038, 1039, 5, 110, 0, 0, 1039, 1040, 5, 40, 0, 0, 1040, 252, 1, 0, 0, 0, 1041, 1042, 5, 97, 0, 0, 1042, 1043, 5, 98, 0, 0, 1043, 1044, 5, 115, 0, 0, 1044, 1045, 5, 40, 0, 0, 1045, 254, 1, 0, 0, 0, 1046, 1047, 5, 112, 0, 0, 1047, 1048, 5, 104, 0, 0, 1048, 1049, 5, 105, 0, 0, 1049, 1050, 5, 40, 0, 0, 1050, 256, 1, 0, 0, 0, 1051, 1052, 5, 102, 0, 0, 1052, 1053, 5, 108, 0, 0, 1053, 1054, 5, 111, 0, 0, 1054, 1055, 5, 111, 0, 0, 1055, 1056, 5, 114, 0, 0, 1056, 1057, 5, 40, 0, 0, 1057, 258, 1, 0, 0, 0, 1058, 1059, 5, 99, 0, 0, 1059, 1060, 5, 101, 0, 0, 1060, 1061, 5, 105, 0, 0, 1061, 1062, 5, 108, 0, 0, 1062, 1063, 5, 40, 0, 0, 1063, 260, 1, 0, 0, 0, 1064, 1065, 5, 99, 0, 0, 1065, 1066, 5, 101, 0, 0, 1066, 1067, 5, 105, 0, 0, 1067, 1068, 5, 108, 0, 0, 1068, 1069, 5, 105, 0, 0, 1069, 1070, 5, 110, 0, 0, 1070, 1071, 5, 103, 0, 0, 1071, 1072, 5, 40, 0, 0, 1072, 262, 1, 0, 0, 0, 1073, 1074, 5, 114, 0, 0, 1074, 1075, 5, 111, 0, 0, 1075, 1076, 5, 117, 0, 0, 1076, 1077, 5, 110, 0, 0, 1077, 1078, 5, 100, 0, 0, 1078, 1079, 5, 40, 0, 0, 1079, 264, 1, 0, 0, 0, 1080, 1081, 5, 109, 0, 0, 1081, 1082, 5, 105, 0, 0, 1082, 1083, 5, 110, 0, 0, 1083, 1084, 5, 40, 0, 0, 1084, 266, 1, 0, 0, 0, 1085, 1086, 5, 109, 0, 0, 1086, 1087, 5, 97, 0, 0, 1087, 1088, 5, 120, 0, 0, 1088, 1089, 5, 40, 0, 0, 1089, 268, 1, 0, 0, 0, 1090, 1091, 5, 103, 0, 0, 1091, 1092, 5, 99, 0, 0, 1092, 1093, 5, 100, 0, 0, 1093, 1094, 5, 40, 0, 0, 1094, 270, 1, 0, 0, 0, 1095, 1096, 5, 116, 0, 0, 1096, 1097, 5, 114, 0, 0, 1097, 1098, 5, 117, 0, 0, 1098, 1099, 5, 110, 0, 0, 1099, 1100, 5, 99, 0, 0, 1100, 1101, 5, 40, 0, 0, 1101, 272, 1, 0, 0, 0, 1102, 1103, 5, 108, 0, 0, 1103, 1104, 5, 99, 0, 0, 1104, 1105, 5, 109, 0, 0, 1105, 1106, 5, 40, 0, 0, 1106, 274, 1, 0, 0, 0, 1107, 1108, 5, 101, 0, 0, 1108, 1109, 5, 114, 0, 0, 1109, 1110, 5, 102, 0, 0, 1110, 1111, 5, 40, 0, 0, 1111, 276, 1, 0, 0, 0, 1112, 1113, 5, 99, 0, 0, 1113, 1114, 5, 111, 0, 0, 1114, 1115, 5, 110, 0, 0, 1115, 1116, 5, 106, 0, 0, 1116, 1117, 5, 117, 0, 0, 1117, 1118, 5, 103, 0, 0, 1118, 1119, 5, 97, 0, 0, 1119, 1120, 5, 116, 0, 0, 1120, 1121, 5, 101, 0, 0, 1121, 1122, 5, 40, 0, 0, 1122, 278, 1, 0, 0, 0, 1123, 1124, 5, 100, 0, 0, 1124, 1125, 5, 111, 0, 0, 1125, 1126, 5, 109, 0, 0, 1126, 1127, 5, 97, 0, 0, 1127, 1128, 5, 105, 0, 0, 1128, 1129, 5, 110, 0, 0, 1129, 1130, 5, 40, 0, 0, 1130, 280, 1, 0, 0, 0, 1131, 1132, 5, 112, 0, 0, 1132, 1133, 5, 105, 0, 0, 1133, 1134, 5, 101, 0, 0, 1134, 1135, 5, 99, 0, 0, 1135, 1136, 5, 101, 0, 0, 1136, 1137, 5, 119, 0, 0, 1137, 1138, 5, 105, 0, 0, 1138, 1139, 5, 115, 0, 0, 1139, 1140, 5, 101, 0, 0, 1140, 1141, 5, 40, 0, 0, 1141, 282, 1, 0, 0, 0, 1142, 1143, 5, 97, 0, 0, 1143, 1144, 5, 112, 0, 0, 1144, 1145, 5, 112, 0, 0, 1145, 1146, 5, 108, 0, 0, 1146, 1147, 5, 121, 0, 0, 1147, 1148, 5, 40, 0, 0, 1148, 284, 1, 0, 0, 0, 1149, 1150, 5, 108, 0, 0, 1150, 1151, 5, 97, 0, 0, 1151, 1152, 5, 109, 0, 0, 1152, 1153, 5, 98, 0, 0, 1153, 1154, 5, 100, 0, 0, 1154, 1155, 5, 97, 0, 0, 1155, 1156, 5, 40, 0, 0, 1156, 286, 1, 0, 0, 0, 1157, 1159, 5, 13, 0, 0, 1158, 1157, 1, 0, 0, 0, 1158, 1159, 1, 0, 0, 0, 1159, 1160, 1, 0, 0, 0, 1160, 1162, 5, 10, 0, 0, 1161, 1158, 1, 0, 0, 0, 1162, 1163, 1, 0, 0, 0, 1163, 1161, 1, 0, 0, 0, 1163, 1164, 1, 0, 0, 0, 1164, 1165, 1, 0, 0, 0, 1165, 1166, 6, 143, 0, 0, 1166, 288, 1, 0, 0, 0, 1167, 1169, 7, 0, 0, 0, 1168, 1170, 7, 1, 0, 0, 1169, 1168, 1, 0, 0, 0, 1169, 1170, 1, 0, 0, 0, 1170, 1172, 1, 0, 0, 0, 1171, 1173, 2, 48, 57, 0, 1172, 1171, 1, 0, 0, 0, 1173, 1174, 1, 0, 0, 0, 1174, 1172, 1, 0, 0, 0, 1174, 1175, 1, 0, 0, 0, 1175, 290, 1, 0, 0, 0, 1176, 1178, 2, 48, 57, 0, 1177, 1176, 1, 0, 0, 0, 1178, 1179, 1, 0, 0, 0, 1179, 1177, 1, 0, 0, 0, 1179, 1180, 1, 0, 0, 0, 1180, 1181, 1, 0, 0, 0, 1181, 1185, 5, 46, 0, 0, 1182, 1184, 2, 48, 57, 0, 1183, 1182, 1, 0, 0, 0, 1184, 1187, 1, 0, 0, 0, 1185, 1183, 1, 0, 0, 0, 1185, 1186, 1, 0, 0, 0, 1186, 1189, 1, 0, 0, 0, 1187, 1185, 1, 0, 0, 0, 1188, 1190, 3, 289, 144, 0, 1189, 1188, 1, 0, 0, 0, 1189, 1190, 1, 0, 0, 0, 1190, 1192, 1, 0, 0, 0, 1191, 1193, 5, 105, 0, 0, 1192, 1191, 1, 0, 0, 0, 1192, 1193, 1, 0, 0, 0, 1193, 1210, 1, 0, 0, 0, 1194, 1196, 5, 46, 0, 0, 1195, 1194, 1, 0, 0, 0, 1195, 1196, 1, 0, 0, 0, 1196, 1198, 1, 0, 0, 0, 1197, 1199, 2, 48, 57, 0, 1198, 1197, 1, 0, 0, 0, 1199, 1200, 1, 0, 0, 0, 1200, 1198, 1, 0, 0, 0, 1200, 1201, 1, 0, 0, 0, 1201, 1203, 1, 0, 0, 0, 1202, 1204, 3, 289, 144, 0, 1203, 1202, 1, 0, 0, 0, 1203, 1204, 1, 0, 0, 0, 1204, 1206, 1, 0, 0, 0, 1205, 1207, 5, 105, 0, 0, 1206, 1205, 1, 0, 0, 0, 1206, 1207, 1, 0, 0, 0, 1207, 1210, 1, 0, 0, 0, 1208, 1210, 5, 105, 0, 0, 1209, 1177, 1, 0, 0, 0, 1209, 1195, 1, 0, 0, 0, 1209, 1208, 1, 0, 0, 0, 1210, 292, 1, 0, 0, 0, 1211, 1212, 5, 67, 0, 0, 1212, 1222, 5, 67, 0, 0, 1213, 1214, 5, 82, 0, 0, 1214, 1222, 5, 82, 0, 0, 1215, 1216, 5, 81, 0, 0, 1216, 1222, 5, 81, 0, 0, 1217, 1218, 5, 90, 0, 0, 1218, 1222, 5, 90, 0, 0, 1219, 1220, 5, 66, 0, 0, 1220, 1222, 5, 66, 0, 0, 1221, 1211, 1, 0, 0, 0, 1221, 1213, 1, 0, 0, 0, 1221, 1215, 1, 0, 0, 0, 1221, 1217, 1, 0, 0, 0, 1221, 1219, 1, 0, 0, 0, 1222, 294, 1, 0, 0, 0, 1223, 1224, 5, 116, 0, 0, 1224, 1225, 5, 114, 0, 0, 1225, 1226, 5, 117, 0, 0, 1226, 1242, 5, 101, 0, 0, 1227, 1228, 5, 84, 0, 0, 1228, 1229, 5, 114, 0, 0, 1229, 1230, 5, 117, 0, 0, 1230, 1242, 5, 101, 0, 0, 1231, 1232, 5, 102, 0, 0, 1232, 1233, 5, 97, 0, 0, 1233, 1234, 5, 108, 0, 0, 1234, 1235, 5, 115, 0, 0, 1235, 1242, 5, 101, 0, 0, 1236, 1237, 5, 70, 0, 0, 1237, 1238, 5, 97, 0, 0, 1238, 1239, 5, 108, 0, 0, 1239, 1240, 5, 115, 0, 0, 1240, 1242, 5, 101, 0, 0, 1241, 1223, 1, 0, 0, 0, 1241, 1227, 1, 0, 0, 0, 1241, 1231, 1, 0, 0, 0, 1241, 1236, 1, 0, 0, 0, 1242, 296, 1, 0, 0, 0, 1243, 1245, 7, 2, 0, 0, 1244, 1243, 1, 0, 0, 0, 1245, 1246, 1, 0, 0, 0, 1246, 1244, 1, 0, 0, 0, 1246, 1247, 1, 0, 0, 0, 1247, 1254, 1, 0, 0, 0, 1248, 1250, 5, 95, 0, 0, 1249, 1251, 7, 3, 0, 0, 1250, 1249, 1, 0, 0, 0, 1251, 1252, 1, 0, 0, 0, 1252, 1250, 1, 0, 0, 0, 1252, 1253, 1, 0, 0, 0, 1253, 1255, 1, 0, 0, 0, 1254, 1248, 1, 0, 0, 0, 1254, 1255, 1, 0, 0, 0, 1255, 298, 1, 0, 0, 0, 1256, 1257, 5, 47, 0, 0, 1257, 1258, 5, 47, 0, 0, 1258, 1262, 1, 0, 0, 0, 1259, 1261, 8, 4, 0, 0, 1260, 1259, 1, 0, 0, 0, 1261, 1264, 1, 0, 0, 0, 1262, 1260, 1, 0, 0, 0, 1262, 1263, 1, 0, 0, 0, 1263, 1266, 1, 0, 0, 0, 1264, 1262, 1, 0, 0, 0, 1265, 1267, 5, 13, 0, 0, 1266, 1265, 1, 0, 0, 0, 1266, 1267, 1, 0, 0, 0, 1267, 1268, 1, 0, 0, 0, 1268, 1281, 5, 10, 0, 0, 1269, 1270, 5, 47, 0, 0, 1270, 1271, 5, 42, 0, 0, 1271, 1275, 1, 0, 0, 0, 1272, 1274, 9, 0, 0, 0, 1273, 1272, 1, 0, 0, 0, 1274, 1277, 1, 0, 0, 0, 1275, 1276, 1, 0, 0, 0, 1275, 1273, 1, 0, 0, 0, 1276, 1278, 1, 0, 0, 0, 1277, 1275, 1, 0, 0, 0, 1278, 1279, 5, 42, 0, 0, 1279, 1281, 5, 47, 0, 0, 1280, 1256, 1, 0, 0, 0, 1280, 1269, 1, 0, 0, 0, 1281, 1282, 1, 0, 0, 0, 1282, 1283, 6, 149, 0, 0, 1283, 300, 1, 0, 0, 0, 1284, 1286, 7, 5, 0, 0, 1285, 1284, 1, 0, 0, 0, 1286, 1287, 1, 0, 0, 0, 1287, 1285, 1, 0, 0, 0, 1287, 1288, 1, 0, 0, 0, 1288, 1289, 1, 0, 0, 0, 1289, 1290, 6, 150, 0, 0, 1290, 302, 1, 0, 0, 0, 24, 0, 1158, 1163, 1169, 1174, 1179, 1185, 1189, 1192, 1195, 1200, 1203, 1206, 1209, 1221, 1241, 1246, 1252, 1254, 1262, 1266, 1275, 1280, 1287, 1, 6, 0, 0] \ No newline at end of file diff --git a/Sources/AngouriMath/Core/Antlr/AngouriMathLexer.tokens b/Sources/AngouriMath/Core/Antlr/AngouriMathLexer.tokens index ea9c4c471..3ef57341c 100644 --- a/Sources/AngouriMath/Core/Antlr/AngouriMathLexer.tokens +++ b/Sources/AngouriMath/Core/Antlr/AngouriMathLexer.tokens @@ -280,10 +280,10 @@ WS=150 'ceil('=130 'ceiling('=131 'round('=132 -'trunc('=133 -'min('=134 -'max('=135 -'gcd('=136 +'min('=133 +'max('=134 +'gcd('=135 +'trunc('=136 'lcm('=137 'erf('=138 'conjugate('=139 diff --git a/Sources/AngouriMath/Core/Antlr/AngouriMathParser.cs b/Sources/AngouriMath/Core/Antlr/AngouriMathParser.cs index 23ea8b798..c971fba09 100644 --- a/Sources/AngouriMath/Core/Antlr/AngouriMathParser.cs +++ b/Sources/AngouriMath/Core/Antlr/AngouriMathParser.cs @@ -107,7 +107,7 @@ public const int "'arcsch('", "'arccosech('", "'acsch('", "'factorial('", "'gamma('", "'derivative('", "'integral('", "'limit('", "'limitleft('", "'limitright('", "'signum('", "'sgn('", "'sign('", "'abs('", "'phi('", "'floor('", "'ceil('", "'ceiling('", - "'round('", "'trunc('", "'min('", "'max('", "'gcd('", "'lcm('", "'erf('", + "'round('", "'min('", "'max('", "'gcd('", "'trunc('", "'lcm('", "'erf('", "'conjugate('", "'domain('", "'piecewise('", "'apply('", "'lambda('" }; private static readonly string[] _SymbolicNames = { @@ -3100,7 +3100,7 @@ public AtomContext atom() { _localctx.args = function_arguments(); State = 821; Match(T__40); - _localctx.value = NotImplementedFunction("round", "rounding functions"); + Assert("round", 1, _localctx.args.list.Count); _localctx.value = MathS.Round(_localctx.args.list[0]); } break; case 106: @@ -3112,7 +3112,7 @@ public AtomContext atom() { _localctx.args = function_arguments(); State = 826; Match(T__40); - _localctx.value = NotImplementedFunction("trunc", "rounding functions"); + AssertAtLeast("min", 1, _localctx.args.list.Count); _localctx.value = _localctx.args.list.Aggregate((a, b) => MathS.Min(a, b)); } break; case 107: @@ -3124,7 +3124,7 @@ public AtomContext atom() { _localctx.args = function_arguments(); State = 831; Match(T__40); - _localctx.value = NotImplementedFunction("min", "minimum or maximum function"); + AssertAtLeast("max", 1, _localctx.args.list.Count); _localctx.value = _localctx.args.list.Aggregate((a, b) => MathS.Max(a, b)); } break; case 108: @@ -3136,7 +3136,7 @@ public AtomContext atom() { _localctx.args = function_arguments(); State = 836; Match(T__40); - _localctx.value = NotImplementedFunction("max", "minimum or maximum function"); + AssertAtLeast("gcd", 1, _localctx.args.list.Count); _localctx.value = _localctx.args.list.Aggregate((a, b) => MathS.Gcd(a, b)); } break; case 109: @@ -3148,7 +3148,7 @@ public AtomContext atom() { _localctx.args = function_arguments(); State = 841; Match(T__40); - _localctx.value = NotImplementedFunction("gcd", "greatest common divisor as a symbolic function"); + _localctx.value = NotImplementedFunction("trunc", "rounding functions"); } break; case 110: diff --git a/Sources/AngouriMath/Core/Domains.Classes.cs b/Sources/AngouriMath/Core/Domains.Classes.cs index 982f4bbf7..c607db54f 100644 --- a/Sources/AngouriMath/Core/Domains.Classes.cs +++ b/Sources/AngouriMath/Core/Domains.Classes.cs @@ -215,6 +215,31 @@ partial record Ceilf public override Domain Codomain { get; protected init; } = Domain.Complex; } + partial record Roundf + { + /// + public override Domain Codomain { get; protected init; } = Domain.Complex; + } + + partial record Minf + { + // Only ordered arguments compare, so the value is real wherever there is one. + /// + public override Domain Codomain { get; protected init; } = Domain.Real; + } + + partial record Maxf + { + /// + public override Domain Codomain { get; protected init; } = Domain.Real; + } + + partial record Gcdf + { + /// + public override Domain Codomain { get; protected init; } = Domain.Complex; + } + partial record Boolean { /// diff --git a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Definition.cs b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Definition.cs index 3e58b7d80..29f579e42 100644 --- a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Definition.cs +++ b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Definition.cs @@ -131,5 +131,13 @@ public abstract partial record CalculusOperator(Entity Expression, Entity Var) : public Entity Floor() => new Floorf(this); /// public Entity Ceil() => new Ceilf(this); + /// + public Entity Round() => new Roundf(this); + /// + public Entity Min(Entity another) => new Minf(this, another); + /// + public Entity Max(Entity another) => new Maxf(this, another); + /// + public Entity Gcd(Entity another) => new Gcdf(this, another); } } diff --git a/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Rounding.Classes.cs b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Rounding.Classes.cs new file mode 100644 index 000000000..147dcb921 --- /dev/null +++ b/Sources/AngouriMath/Core/Entity/Continuous/Entity.Continuous.Rounding.Classes.cs @@ -0,0 +1,104 @@ +// +// 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; + +namespace AngouriMath +{ + partial record Entity + { +#pragma warning disable CS1591 // only while records' parameters cannot be documented + /// + /// A node of round: the nearest integer, with a tie going to the even one. + /// + /// + /// Half to even, which is what Python, SymPy, Mathematica and IEEE 754 all do — and + /// what .NET's Math.Round does by default, though not what most people expect + /// of it. So round(1/2) is 0 and round(3/2) is 2, and it + /// is not floor(x + 1/2), which differs at every tie. + /// + public sealed partial record Roundf(Entity Argument) : Function, IUnaryNode + { + public Entity NodeChild => Argument; + + private Roundf New(Entity arg) => + ReferenceEquals(Argument, arg) ? this : new(arg); + /// + public override Entity Replace(Func func) => func(New(Argument.Replace(func))); + /// + protected override Entity[] InitDirectChildren() => new[] { Argument }; + } + + /// + /// A node of min: the lesser of its two arguments. + /// + /// + /// A node rather than sugar over (a + b - abs(a - b)) / 2. The closed form is + /// what this simplifies to where that helps; it is not what it should print + /// as, and the round-trip contract would make that permanent. SymPy keeps + /// Min as a node for the same reason. + /// Only ordered arguments compare, so a complex one is left alone rather than + /// guessed at. + /// + public sealed partial record Minf(Entity Left, Entity Right) : Function, IBinaryNode + { + public Entity NodeFirstChild => Left; + + public Entity NodeSecondChild => Right; + + private Minf New(Entity left, Entity right) => + ReferenceEquals(Left, left) && ReferenceEquals(Right, right) ? this : new(left, right); + /// + public override Entity Replace(Func func) => func(New(Left.Replace(func), Right.Replace(func))); + /// + protected override Entity[] InitDirectChildren() => new[] { Left, Right }; + } + + /// + /// A node of max: the greater of its two arguments. + /// + /// See for why this is a node. + public sealed partial record Maxf(Entity Left, Entity Right) : Function, IBinaryNode + { + public Entity NodeFirstChild => Left; + + public Entity NodeSecondChild => Right; + + private Maxf New(Entity left, Entity right) => + ReferenceEquals(Left, left) && ReferenceEquals(Right, right) ? this : new(left, right); + /// + public override Entity Replace(Func func) => func(New(Left.Replace(func), Right.Replace(func))); + /// + protected override Entity[] InitDirectChildren() => new[] { Left, Right }; + } + + /// + /// A node of gcd: the greatest common divisor of its two arguments. + /// + /// + /// Not integers only. SymPy's gcd is the polynomial gcd with the integer case + /// as a special case, and this library already computes one — see + /// , which the + /// PolynomialGcdCancellation rule set uses. What cannot be settled is left as + /// this node rather than guessed at. + /// + public sealed partial record Gcdf(Entity Left, Entity Right) : Function, IBinaryNode + { + public Entity NodeFirstChild => Left; + + public Entity NodeSecondChild => Right; + + private Gcdf New(Entity left, Entity right) => + ReferenceEquals(Left, left) && ReferenceEquals(Right, right) ? this : new(left, right); + /// + public override Entity Replace(Func func) => func(New(Left.Replace(func), Right.Replace(func))); + /// + protected override Entity[] InitDirectChildren() => new[] { Left, Right }; + } +#pragma warning restore CS1591 // only while records' parameters cannot be documented + } +} diff --git a/Sources/AngouriMath/Core/Exceptions/ParseException.cs b/Sources/AngouriMath/Core/Exceptions/ParseException.cs index e995b181a..5ee3b71a2 100644 --- a/Sources/AngouriMath/Core/Exceptions/ParseException.cs +++ b/Sources/AngouriMath/Core/Exceptions/ParseException.cs @@ -81,5 +81,15 @@ internal static bool Assert(string function, (int, int) expected, int actual) throw new FunctionArgumentCountException( $"{function} should have exactly {CountArguments(expected.Item1, false)} or {CountArguments(expected.Item2, false)} but {CountArguments(actual, true)} provided"); } + /// + /// For the functions that take any number of arguments and fold over them — + /// min, max and gcd, which have no fixed arity anywhere else + /// either. + /// + internal static void AssertAtLeast(string function, int least, int actual) + { + if (actual < least) throw new FunctionArgumentCountException( + $"{function} should have at least {CountArguments(least, false)} but {CountArguments(actual, true)} provided"); + } } } diff --git a/Sources/AngouriMath/Functions/Continuous/Differentiation.cs b/Sources/AngouriMath/Functions/Continuous/Differentiation.cs index f8a465ec5..4c0673c0a 100644 --- a/Sources/AngouriMath/Functions/Continuous/Differentiation.cs +++ b/Sources/AngouriMath/Functions/Continuous/Differentiation.cs @@ -360,6 +360,15 @@ protected override Entity InnerDifferentiate(Variable variable) => Integer.Zero.Provided(!Argument.In(MathS.Sets.Z)); } + partial record Roundf + { + // Flat between the half-integers and discontinuous at each of them -- round + // jumps where the argument is exactly a half, not where it is an integer. + /// + protected override Entity InnerDifferentiate(Variable variable) + => Integer.Zero.Provided(!(Argument - Rational.Create(1, 2)).In(MathS.Sets.Z)); + } + partial record Providedf { /// diff --git a/Sources/AngouriMath/Functions/Continuous/Solvers/EquationSolver/InvertNode.Classes.cs b/Sources/AngouriMath/Functions/Continuous/Solvers/EquationSolver/InvertNode.Classes.cs index 044692da2..c23be9bd1 100644 --- a/Sources/AngouriMath/Functions/Continuous/Solvers/EquationSolver/InvertNode.Classes.cs +++ b/Sources/AngouriMath/Functions/Continuous/Solvers/EquationSolver/InvertNode.Classes.cs @@ -309,6 +309,49 @@ private protected override IEnumerable InvertNode(Entity value, Entity x } } + partial record Roundf + { + // round(f(x)) = value, solvable only for integer value, and then f(x) lies in + // [value - 1/2, value + 1/2] -- closed at whichever end keeps the tie going to + // the even integer, which depends on the parity of value. Rather than encode + // that, the parameter covers the open interval and the two endpoints are left + // out: every point named is a solution, which is the direction that matters. + private protected override IEnumerable InvertNode(Entity value, Entity x) + { + var t = Variable.CreateUnique(value + Argument, "t"); + return Argument.Invert(value + t, x) + .Select(c => c.Provided( + value.In(MathS.Sets.Z) + & t.In(MathS.Sets.R) + & new Greaterf(t, Rational.Create(-1, 2)) + & new Lessf(t, Rational.Create(1, 2)))); + } + } + + partial record Minf + { + // min(a, b) = value says one of them is value and the other is no smaller, which + // is a disjunction over which one it was rather than an inversion of a function + // of x. Nothing here can express that, and inventing a branch would answer + // confidently and wrongly, so this declines the way Factorialf and Phif do. + private protected override IEnumerable InvertNode(Entity value, Entity x) + => Enumerable.Empty(); + } + + partial record Maxf + { + private protected override IEnumerable InvertNode(Entity value, Entity x) + => Enumerable.Empty(); + } + + partial record Gcdf + { + // The preimage of a gcd is every pair whose greatest common divisor is the + // value, which is not a function of x that can be undone. + private protected override IEnumerable InvertNode(Entity value, Entity x) + => Enumerable.Empty(); + } + partial record Boolean { private protected override IEnumerable InvertNode(Entity value, Entity x) diff --git a/Sources/AngouriMath/Functions/Evaluation/Evaluation.Continuous/Evaluation.Continuous.Arithmetics.Classes.cs b/Sources/AngouriMath/Functions/Evaluation/Evaluation.Continuous/Evaluation.Continuous.Arithmetics.Classes.cs index 1cdfb8308..2bff72213 100644 --- a/Sources/AngouriMath/Functions/Evaluation/Evaluation.Continuous/Evaluation.Continuous.Arithmetics.Classes.cs +++ b/Sources/AngouriMath/Functions/Evaluation/Evaluation.Continuous/Evaluation.Continuous.Arithmetics.Classes.cs @@ -311,6 +311,86 @@ protected override Entity InnerSimplify(bool isExact) (@this, a) => ((Ceilf)@this).New(a), isExact); } + public partial record Roundf + { + private protected override Entity IntrinsicCondition => Boolean.True; + + /// + protected override Entity InnerSimplify(bool isExact) + => ExpandOnOneArgument(Argument, + a => a switch + { + Integer n => n, + Rational n => Integer.Create(n.EDecimal.RoundHalfEven().ToEInteger()), + Real n when !isExact => Integer.Create(n.EDecimal.RoundHalfEven().ToEInteger()), + Complex n when !isExact => Complex.Create( + n.RealPart.EDecimal.RoundHalfEven(), n.ImaginaryPart.EDecimal.RoundHalfEven()), + // Anything that already produced an integer is left alone. + Floorf or Ceilf or Roundf => a, + _ => null + }, + (@this, a) => ((Roundf)@this).New(a), isExact); + } + + public partial record Minf + { + private protected override Entity IntrinsicCondition => Boolean.True; + + /// + protected override Entity InnerSimplify(bool isExact) + => ExpandOnTwoArguments(Left, Right, + (a, b) => (a, b) switch + { + // Only ordered arguments compare. A complex one is left alone rather + // than guessed at, which is what SymPy's Min does too. + (Real l, Real r) => l.EDecimal.CompareTo(r.EDecimal) <= 0 ? l : r, + var (l, r) when l == r => l, + _ => null + }, + (@this, a, b) => ((Minf)@this).New(a, b), isExact); + } + + public partial record Maxf + { + private protected override Entity IntrinsicCondition => Boolean.True; + + /// + protected override Entity InnerSimplify(bool isExact) + => ExpandOnTwoArguments(Left, Right, + (a, b) => (a, b) switch + { + (Real l, Real r) => l.EDecimal.CompareTo(r.EDecimal) >= 0 ? l : r, + var (l, r) when l == r => l, + _ => null + }, + (@this, a, b) => ((Maxf)@this).New(a, b), isExact); + } + + public partial record Gcdf + { + private protected override Entity IntrinsicCondition => Boolean.True; + + /// + protected override Entity InnerSimplify(bool isExact) + => ExpandOnTwoArguments(Left, Right, + (a, b) => (a, b) switch + { + // gcd is non-negative by convention, and gcd(0, n) is |n|. + (Integer l, Integer r) => Integer.Create(l.EInteger.Gcd(r.EInteger)), + // gcd(a/b, c/d) = gcd(a, c) / lcm(b, d) -- which is what SymPy gives, + // so gcd(1/2, 1/3) is 1/6 rather than an error. + (Rational l, Rational r) => Rational.Create( + l.Numerator.EInteger.Gcd(r.Numerator.EInteger), + l.Denominator.EInteger / l.Denominator.EInteger.Gcd(r.Denominator.EInteger) * r.Denominator.EInteger), + var (l, r) when l == r => l, + // The polynomial case is left to the node: PolynomialGcd already + // computes one for the cancellation rule, and wiring it in here is + // its own change rather than something to guess at. + _ => null + }, + (@this, a, b) => ((Gcdf)@this).New(a, b), isExact); + } + public partial record Absf { // Absolute value is defined everywhere in the complex plane diff --git a/Sources/AngouriMath/Functions/InternalAMExtensions.cs b/Sources/AngouriMath/Functions/InternalAMExtensions.cs index b16866c89..85cdbe606 100644 --- a/Sources/AngouriMath/Functions/InternalAMExtensions.cs +++ b/Sources/AngouriMath/Functions/InternalAMExtensions.cs @@ -610,6 +610,17 @@ public static (EInteger Integral, EDecimal Fractional) SplitDecimal(this EDecima public static EDecimal Ceiling(this EDecimal x) => x.RoundToExponent(0, ERounding.Ceiling); /// If there is a fractional part, returns the previous largest integer public static EDecimal Floor(this EDecimal x) => x.RoundToExponent(0, ERounding.Floor); + /// + /// Rounds to the nearest integer, a tie going to the even one — what + /// means by rounding. + /// + /// + /// Distinct from just above, which is half up + /// and is what the numeric helpers around it want. The two disagree at every tie: + /// half up sends 5/2 to 3, half to even sends it to 2. Python, SymPy, Mathematica + /// and IEEE 754 all mean the latter by "round". + /// + public static EDecimal RoundHalfEven(this EDecimal x) => x.RoundToExponent(0, ERounding.HalfEven); // Based on https://github.com/eobermuhlner/big-math/blob/ba75e9a80f040224cfeef3c2ac06390179712443/ch.obermuhlner.math.big/src/main/java/ch/obermuhlner/math/big/BigDecimalMath.java diff --git a/Sources/AngouriMath/Functions/Output/Latex/Latex.Arithmetics.Classes.cs b/Sources/AngouriMath/Functions/Output/Latex/Latex.Arithmetics.Classes.cs index 1a3348501..883e57cf7 100644 --- a/Sources/AngouriMath/Functions/Output/Latex/Latex.Arithmetics.Classes.cs +++ b/Sources/AngouriMath/Functions/Output/Latex/Latex.Arithmetics.Classes.cs @@ -172,6 +172,35 @@ public override string Latexise() => $@"\left\lceil{{{Argument.Latexise()}}}\right\rceil"; } + partial record Roundf + { + // The nearest-integer brackets: a floor on the left, a ceiling on the right. + /// + public override string Latexise() + => $@"\left\lfloor{{{Argument.Latexise()}}}\right\rceil"; + } + + partial record Minf + { + /// + public override string Latexise() + => $@"\min\left({Left.Latexise()}, {Right.Latexise()}\right)"; + } + + partial record Maxf + { + /// + public override string Latexise() + => $@"\max\left({Left.Latexise()}, {Right.Latexise()}\right)"; + } + + partial record Gcdf + { + /// + public override string Latexise() + => $@"\gcd\left({Left.Latexise()}, {Right.Latexise()}\right)"; + } + partial record Phif { /// diff --git a/Sources/AngouriMath/Functions/Output/ToString/ToString.Arithmetics.Classes.cs b/Sources/AngouriMath/Functions/Output/ToString/ToString.Arithmetics.Classes.cs index 2c29467f5..be2782930 100644 --- a/Sources/AngouriMath/Functions/Output/ToString/ToString.Arithmetics.Classes.cs +++ b/Sources/AngouriMath/Functions/Output/ToString/ToString.Arithmetics.Classes.cs @@ -125,6 +125,38 @@ public partial record Ceilf public override string ToString() => Stringize(); } + public partial record Roundf + { + /// + public override string Stringize() => $"round({Argument.Stringize()})"; + /// + public override string ToString() => Stringize(); + } + + public partial record Minf + { + /// + public override string Stringize() => $"min({Left.Stringize()}, {Right.Stringize()})"; + /// + public override string ToString() => Stringize(); + } + + public partial record Maxf + { + /// + public override string Stringize() => $"max({Left.Stringize()}, {Right.Stringize()})"; + /// + public override string ToString() => Stringize(); + } + + public partial record Gcdf + { + /// + public override string Stringize() => $"gcd({Left.Stringize()}, {Right.Stringize()})"; + /// + public override string ToString() => Stringize(); + } + public partial record Factorialf { /// diff --git a/Sources/AngouriMath/Functions/Output/ToSympy/ToSympy.Arithmetics.Classes.cs b/Sources/AngouriMath/Functions/Output/ToSympy/ToSympy.Arithmetics.Classes.cs index 1bbc32fec..3ca5bb89d 100644 --- a/Sources/AngouriMath/Functions/Output/ToSympy/ToSympy.Arithmetics.Classes.cs +++ b/Sources/AngouriMath/Functions/Output/ToSympy/ToSympy.Arithmetics.Classes.cs @@ -77,6 +77,48 @@ internal override string ToSymPy() => $@"sympy.ceiling({Argument.ToSymPy()})"; } + public partial record Roundf + { + /// + /// SymPy has no symbolic round -- `RoundFunction` is an abstract base and + /// raises, and `.round()` is a method on a concrete number rather than a + /// function of an expression. So this is built out of what SymPy does have. + /// + /// It is deliberately not `sympy.floor(x + 1/2)`, which is the obvious + /// translation and is wrong at every tie: that sends 1/2 to 1 and 5/2 to 3, + /// where rounding half to even gives 0 and 2. The correction below is exactly + /// the tie case -- when the fractional part is a half and the candidate is odd, + /// step down to the even neighbour -- and was checked against SymPy's own + /// `Rational.round()` on ties, non-ties and negatives. + /// + internal override string ToSymPy() + { + var arg = Argument.ToSymPy(); + var candidate = $"sympy.floor({arg} + sympy.Rational(1, 2))"; + return $"sympy.Piecewise(({candidate} - 1, " + + $"sympy.Eq(sympy.frac({arg}), sympy.Rational(1, 2)) & sympy.Eq(sympy.Mod({candidate}, 2), 1)), " + + $"({candidate}, True))"; + } + } + + public partial record Minf + { + internal override string ToSymPy() + => $@"sympy.Min({Left.ToSymPy()}, {Right.ToSymPy()})"; + } + + public partial record Maxf + { + internal override string ToSymPy() + => $@"sympy.Max({Left.ToSymPy()}, {Right.ToSymPy()})"; + } + + public partial record Gcdf + { + internal override string ToSymPy() + => $@"sympy.gcd({Left.ToSymPy()}, {Right.ToSymPy()})"; + } + public partial record Phif { internal override string ToSymPy() => $"sympy.totient({Argument.ToSymPy()})"; diff --git a/Sources/AngouriMath/Functions/Substitute.cs b/Sources/AngouriMath/Functions/Substitute.cs index 1627407a3..2b9ffc24a 100644 --- a/Sources/AngouriMath/Functions/Substitute.cs +++ b/Sources/AngouriMath/Functions/Substitute.cs @@ -186,6 +186,34 @@ public override Entity Substitute(Entity x, Entity value) => this == x ? value : New(Argument.Substitute(x, value)); } + partial record Roundf + { + /// + public override Entity Substitute(Entity x, Entity value) + => this == x ? value : New(Argument.Substitute(x, value)); + } + + partial record Minf + { + /// + public override Entity Substitute(Entity x, Entity value) + => this == x ? value : New(Left.Substitute(x, value), Right.Substitute(x, value)); + } + + partial record Maxf + { + /// + public override Entity Substitute(Entity x, Entity value) + => this == x ? value : New(Left.Substitute(x, value), Right.Substitute(x, value)); + } + + partial record Gcdf + { + /// + public override Entity Substitute(Entity x, Entity value) + => this == x ? value : New(Left.Substitute(x, value), Right.Substitute(x, value)); + } + partial record Boolean { /// diff --git a/Sources/AngouriMath/Functions/TreeAnalyzer/Sort.Classes.cs b/Sources/AngouriMath/Functions/TreeAnalyzer/Sort.Classes.cs index d6eddeae8..a08c285ee 100644 --- a/Sources/AngouriMath/Functions/TreeAnalyzer/Sort.Classes.cs +++ b/Sources/AngouriMath/Functions/TreeAnalyzer/Sort.Classes.cs @@ -215,6 +215,30 @@ private protected override string SortHashName(SortLevel level) => Choice(level, "floorceil_", "ceil_", "ceil_"); } + public partial record Roundf + { + private protected override string SortHashName(SortLevel level) + => Choice(level, "floorceil_", "round_", "round_"); + } + + public partial record Minf + { + private protected override string SortHashName(SortLevel level) + => Choice(level, "minmax_", "min_", "min_"); + } + + public partial record Maxf + { + private protected override string SortHashName(SortLevel level) + => Choice(level, "minmax_", "max_", "max_"); + } + + public partial record Gcdf + { + private protected override string SortHashName(SortLevel level) + => Choice(level, "gcd_", "gcd_", "gcd_"); + } + partial record Boolean { private protected override string SortHashName(SortLevel level) diff --git a/Sources/Tests/UnitTests/Convenience/MissingFunctionNamesRefusedTest.cs b/Sources/Tests/UnitTests/Convenience/MissingFunctionNamesRefusedTest.cs index 584c6d65a..8bce0370c 100644 --- a/Sources/Tests/UnitTests/Convenience/MissingFunctionNamesRefusedTest.cs +++ b/Sources/Tests/UnitTests/Convenience/MissingFunctionNamesRefusedTest.cs @@ -26,16 +26,12 @@ namespace AngouriMath.Tests.Convenience [Trait("Area", "Convenience")] public sealed class MissingFunctionNamesRefusedTest { - // floor, ceil and ceiling were on this list until they were implemented: - // https://github.com/asc-community/AngouriMath/issues/809 + // floor, ceil, ceiling, round, min, max and gcd were all on this list until they + // were implemented: https://github.com/asc-community/AngouriMath/issues/809 [Theory] - [InlineData("round(x)")] [InlineData("trunc(x)")] [InlineData("erf(x)")] [InlineData("conjugate(x)")] - [InlineData("min(x, y)")] - [InlineData("max(x, y)")] - [InlineData("gcd(x, y)")] [InlineData("lcm(x, y)")] public void ANameTheLibraryDoesNotHaveIsRefused(string written) => Assert.Throws(() => written.ToEntity()); @@ -45,8 +41,8 @@ public void ANameTheLibraryDoesNotHaveIsRefused(string written) => /// cannot otherwise tell what happened to their expression. /// [Theory] - [InlineData("round(x)", "round")] - [InlineData("gcd(x, y)", "gcd")] + [InlineData("trunc(x)", "trunc")] + [InlineData("lcm(x, y)", "lcm")] [InlineData("conjugate(x)", "conjugate")] public void TheRefusalNamesTheFunction(string written, string name) => Assert.Contains(name, @@ -59,11 +55,11 @@ public void TheRefusalNamesTheFunction(string written, string name) => /// absence was invisible or cryptic according to how the caller happened to write it. /// [Theory] - [InlineData("min(x)")] - [InlineData("min(x, y)")] - [InlineData("min(x, y, z)")] - [InlineData("round(x)")] - [InlineData("round(x, y)")] + [InlineData("lcm(x)")] + [InlineData("lcm(x, y)")] + [InlineData("lcm(x, y, z)")] + [InlineData("trunc(x)")] + [InlineData("trunc(x, y)")] public void TheArgumentCountDoesNotDecideWhetherItIsReported(string written) => Assert.Throws(() => written.ToEntity()); @@ -86,8 +82,8 @@ public void AnImplementedNameWithTheWrongArgumentCountSaysThat(string written, s public void TheEquationThatUsedToBeAnsweredWithNonsenseNowSaysWhyItCannotBe() { var thrown = Assert.Throws( - () => "round(x) - 3 = 0".ToEntity().Solve("x")); - Assert.Contains("round", thrown.Message); + () => "trunc(x) - 3 = 0".ToEntity().Solve("x")); + Assert.Contains("trunc", thrown.Message); } /// @@ -143,6 +139,10 @@ public void EverythingElseParsesAsItDid(string written, string expected) => [InlineData("floor(x)")] [InlineData("ceil(x)")] [InlineData("ceiling(x)")] + [InlineData("round(x)")] + [InlineData("min(x, y)")] + [InlineData("max(x, y)")] + [InlineData("gcd(x, y)")] public void TheNamesTheLibraryHasStillParse(string written) => Assert.NotNull(written.ToEntity()); diff --git a/Sources/Tests/UnitTests/Convenience/RoundMinMaxGcdTest.cs b/Sources/Tests/UnitTests/Convenience/RoundMinMaxGcdTest.cs new file mode 100644 index 000000000..94a68e09c --- /dev/null +++ b/Sources/Tests/UnitTests/Convenience/RoundMinMaxGcdTest.cs @@ -0,0 +1,168 @@ +// +// 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 AngouriMath; +using AngouriMath.Core.Exceptions; +using AngouriMath.Extensions; +using Xunit; + +namespace AngouriMath.Tests.Convenience +{ + /// + /// round, min, max and gcd — + /// #809. + /// + /// + /// Expected values are SymPy 1.14's, measured rather than reasoned about. + /// + [Trait("Area", "Convenience")] + public sealed class RoundMinMaxGcdTest + { + /// + /// Half to even — Python, SymPy, Mathematica and IEEE 754 all agree, and it is what + /// .NET's Math.Round does by default. The ties are the whole point: 1/2 goes + /// down to 0 and 5/2 goes down to 2, because the even neighbour wins. + /// + [Theory] + [InlineData("round(1/2)", 0)] + [InlineData("round(3/2)", 2)] + [InlineData("round(5/2)", 2)] + [InlineData("round(7/2)", 4)] + [InlineData("round(-1/2)", 0)] + [InlineData("round(-3/2)", -2)] + [InlineData("round(-5/2)", -2)] + [InlineData("round(13/10)", 1)] + [InlineData("round(17/10)", 2)] + [InlineData("round(2)", 2)] + [InlineData("round(-2)", -2)] + public void RoundGoesToTheEvenNeighbourOnATie(string input, int expected) + => Assert.Equal(Entity.Number.Integer.Create(expected), input.ToEntity().Simplify()); + + /// + /// The obvious translation of rounding is floor(x + 1/2), and it is wrong at + /// every tie. Pinned so that nobody simplifies the node into it. + /// + [Theory] + [InlineData("1/2")] + [InlineData("5/2")] + [InlineData("-3/2")] + public void RoundIsNotFloorOfTheArgumentPlusAHalf(string at) + { + var rounded = $"round({at})".ToEntity().Simplify(); + var floored = $"floor({at} + 1/2)".ToEntity().Simplify(); + Assert.NotEqual(floored, rounded); + } + + [Theory] + [InlineData("min(3, 5)", 3)] + [InlineData("max(3, 5)", 5)] + [InlineData("min(-2, -7)", -7)] + [InlineData("max(-2, -7)", -2)] + [InlineData("min(3, 5, 1)", 1)] + [InlineData("max(3, 5, 1)", 5)] + [InlineData("min(4)", 4)] + public void MinAndMaxCompareWhereTheArgumentsAreOrdered(string input, int expected) + => Assert.Equal(Entity.Number.Integer.Create(expected), input.ToEntity().Simplify()); + + [Theory] + [InlineData("min(x, x)", "x")] + [InlineData("max(x, x)", "x")] + public void MinAndMaxOfOneThingWithItselfIsThatThing(string input, string expected) + => Assert.Equal(expected.ToEntity(), input.ToEntity().Simplify()); + + // Only ordered arguments compare, so an unordered pair is left alone rather than + // guessed at -- which is what SymPy's Min does too. + [Theory] + [InlineData("min(x, y)")] + [InlineData("max(x, y)")] + public void AnUncomparablePairIsLeftAlone(string input) + => Assert.Equal(input.ToEntity(), input.ToEntity().Simplify()); + + [Theory] + [InlineData("gcd(12, 18)", "6")] + [InlineData("gcd(-12, 18)", "6")] + [InlineData("gcd(0, 5)", "5")] + [InlineData("gcd(12, 18, 8)", "2")] + // Rationals, not integers only: gcd(a/b, c/d) is gcd(a, c) / lcm(b, d). + [InlineData("gcd(1/2, 1/3)", "1/6")] + public void GcdIsWhatSymPyGives(string input, string expected) + => Assert.Equal(expected.ToEntity().Simplify(), input.ToEntity().Simplify()); + + [Fact] + public void AGcdItCannotSettleIsLeftAsANode() + => Assert.IsType("gcd(x, y)".ToEntity().Simplify()); + + [Theory] + [InlineData("round(x)", "round(x)")] + [InlineData("min(x, y)", "min(x, y)")] + [InlineData("max(x, y)", "max(x, y)")] + [InlineData("gcd(x, y)", "gcd(x, y)")] + public void ThePrintedFormIsTheUsualSpelling(string input, string expected) + => Assert.Equal(expected, input.ToEntity().Stringize()); + + [Theory] + [InlineData("round(x)")] + [InlineData("min(x, y)")] + [InlineData("max(x, y)")] + [InlineData("gcd(x, y)")] + [InlineData("min(x, y) + max(a, b) + gcd(p, q) + round(z)")] + public void ThePrintedFormParsesBackToTheSameExpression(string input) + => Assert.Equal(input.ToEntity(), input.ToEntity().Stringize().ToEntity()); + + [Theory] + [InlineData("round(x)", @"\left\lfloor{x}\right\rceil")] + [InlineData("min(x, y)", @"\min\left(x, y\right)")] + [InlineData("max(x, y)", @"\max\left(x, y\right)")] + [InlineData("gcd(x, y)", @"\gcd\left(x, y\right)")] + public void TheLatexIsTheUsualNotation(string input, string expected) + => Assert.Equal(expected, input.ToEntity().Latexise()); + + /// + /// Round is flat between the half-integers and jumps at each of them, which is + /// a different condition from floor's. + /// + [Fact] + public void TheDerivativeOfRoundIsZeroAwayFromTheHalfIntegers() + { + var provided = Assert.IsType("round(x)".ToEntity().Differentiate("x")); + Assert.Equal(Entity.Number.Integer.Create(0), provided.Expression); + } + + /// + /// Min and max have no derivative this library can state without a case split on + /// which argument is smaller, so they decline rather than guess. + /// + [Theory] + [InlineData("min(x, y)")] + [InlineData("max(x, y)")] + public void MinAndMaxDeclineToDifferentiate(string input) + => Assert.Contains(input.ToEntity().Differentiate("x").Nodes, + node => node is Entity.Derivativef); + + [Theory] + [InlineData("min()")] + [InlineData("max()")] + [InlineData("gcd()")] + public void TheVariadicOnesStillNeedAnArgument(string input) + => Assert.Throws(() => input.ToEntity()); + + [Theory] + [InlineData("round(x, y)")] + public void RoundTakesExactlyOneArgument(string input) + => Assert.Throws(() => input.ToEntity()); + + [Theory] + [InlineData("round(x)", "7/2", 4)] + [InlineData("round(x)", "5/2", 2)] + [InlineData("min(x, 3)", "1", 1)] + [InlineData("max(x, 3)", "1", 3)] + [InlineData("gcd(x, 18)", "12", 6)] + public void SubstitutingReachesTheValue(string input, string at, int expected) + => Assert.Equal(Entity.Number.Integer.Create(expected), + input.ToEntity().Substitute("x", at.ToEntity()).Simplify()); + } +}