From 46694ea38488179491defb9fa4720e69da9f25ea Mon Sep 17 00:00:00 2001 From: mmatera Date: Tue, 3 Dec 2024 07:59:27 -0300 Subject: [PATCH 1/4] removing the numerical comparison test. Adding an explanation at the beginning of the file --- test/test_mathics_precedence.py | 329 ++++---------------------------- 1 file changed, 36 insertions(+), 293 deletions(-) diff --git a/test/test_mathics_precedence.py b/test/test_mathics_precedence.py index 975bfa5..10978e7 100644 --- a/test/test_mathics_precedence.py +++ b/test/test_mathics_precedence.py @@ -1,5 +1,40 @@ """ Test precedences +================ + +Precedence values reported in the Mathics Scanner tables do not always match +with the values reported by `Precedence[...]` in WMA. As it was +pointed out by Robert L. Jacobson in +[https://www.robertjacobson.dev/posts/2018-09-03-generalizing-pemdas-what-is-an-operator/] +and [https://www.robertjacobson.dev/posts/2018-09-04-defining-the-wolfram-language-part-2-operator-properties/] + +The behavior of the parser and the formatter of WMA do not always is consistent with the values +reported by `Precedence[...]`. Jacobson mentions that in the most of the cases, the behaviour is more +consistent with the values reported by `WolframLanguageData`, which are given following a different +numeric convention. + +Some examples of these inconsistencies are: +* In WMA, `Precedence` reports the same value (215) for all the boolean operators +(`Not`, `And`, `Nand`, `Xor`, `Or`, `Nor`) but behaves as +``` +Precedence[Not]>Precedence[And]==Precedence[Nand]>Precedence[Xor]>Precedence[Or]==Precedence[Nor] +``` + +In other cases, precedence values of some operators are reported to be the default value (670) +while its behaviour is different (Ej: `GreaterSlantEqual` and `LessSlantEqual` behaves as +their precedence were the same that the one for `LessEqual` and `GreaterEqual`). + +In any case, the relevant information is the order relation that `Precedence` induce over the +operator and their associated symbols, and this is the information that we want to curate in +the MathicsScanner tables. + +This module test that the *order* induced by the precedence values assigned to each operator/symbol +to be consistent with the one of a list built from WMA. This list was build by sorting the elements +according to their WMA `Precedence` values, and then modified in a way the ordering be consistent +with the way in which expressions involving these symbols / operators are parsed and formatter +by `OutputForm`. This consistency was tested in WMA using the functions defined in +the `testprecedence.m` module. + """ try: @@ -11,265 +46,6 @@ import pytest -WMA_PRECEDENCES = { - "CompoundExpression": 10.0, - "Put": 30.0, - "PutAppend": 30.0, - "Set": 40.0, - "SetDelayed": 40.0, - "UpSet": 40.0, - "UpSetDelayed": 40.0, - "Because": 50.0, - "Therefore": 50.0, - "Postfix": 70.0, - "Colon": 80.0, - "Function": 90.0, - "AddTo": 100.0, - "DivideBy": 100.0, - "SubtractFrom": 100.0, - "TimesBy": 100.0, - "ReplaceAll": 110.0, - "ReplaceRepeated": 110.0, - "RuleDelayed": 120.0, - "Rule": 120.0, - "Condition": 130.0, - "StringExpression": 135.0, - "Optional": 140.0, - "Alternatives": 160.0, - "Repeated": 170.0, - "RepeatedNull": 170.0, - "SuchThat": 180.0, - "DoubleLeftTee": 190.0, - "DoubleRightTee": 190.0, - "DownTee": 190.0, - "LeftTee": 190.0, - "Perpendicular": 190.0, - "RightTee": 190.0, - "UpTee": 190.0, - "Implies": 200.0, - "Equivalent": 205.0, - "And": 215.0, - "Nand": 215.0, - "Nor": 215.0, - "Or": 215.0, - "Xor": 215.0, - "Not": 230.0, - "RoundImplies": 240.0, - "NotReverseElement": 250.0, - "NotSquareSubsetEqual": 250.0, - "NotSquareSupersetEqual": 250.0, - "NotSubset": 250.0, - "NotSubsetEqual": 250.0, - "NotSuperset": 250.0, - "NotSupersetEqual": 250.0, - "ReverseElement": 250.0, - "SquareSubset": 250.0, - "SquareSubsetEqual": 250.0, - "SquareSuperset": 250.0, - "SquareSupersetEqual": 250.0, - "Subset": 250.0, - "SubsetEqual": 250.0, - "Superset": 250.0, - "SupersetEqual": 250.0, - "DoubleLeftArrow": 270.0, - "DoubleLeftRightArrow": 270.0, - "DoubleRightArrow": 270.0, - "DownLeftRightVector": 270.0, - "DownLeftTeeVector": 270.0, - "DownLeftVector": 270.0, - "DownLeftVectorBar": 270.0, - "DownRightTeeVector": 270.0, - "DownRightVector": 270.0, - "DownRightVectorBar": 270.0, - "LeftArrow": 270.0, - "LeftArrowBar": 270.0, - "LeftArrowRightArrow": 270.0, - "LeftRightArrow": 270.0, - "LeftRightVector": 270.0, - "LeftTeeArrow": 270.0, - "LeftTeeVector": 270.0, - "LeftVector": 270.0, - "LeftVectorBar": 270.0, - "LowerLeftArrow": 270.0, - "LowerRightArrow": 270.0, - "RightArrow": 270.0, - "RightArrowBar": 270.0, - "RightArrowLeftArrow": 270.0, - "RightTeeArrow": 270.0, - "RightTeeVector": 270.0, - "RightVector": 270.0, - "RightVectorBar": 270.0, - "ShortLeftArrow": 270.0, - "ShortRightArrow": 270.0, - "UpperLeftArrow": 270.0, - "UpperRightArrow": 270.0, - "DoubleVerticalBar": 280.0, - "NotDoubleVerticalBar": 280.0, - "VerticalBar": 280.0, - "Equal": 290.0, - "Greater": 290.0, - "GreaterEqual": 290.0, - "Less": 290.0, - "LessEqual": 290.0, - "SameQ": 290.0, - "Unequal": 290.0, - "UnsameQ": 290.0, - "Congruent": 290.0, - "CupCap": 290.0, - "DotEqual": 290.0, - "EqualTilde": 290.0, - "Equilibrium": 290.0, - "GreaterEqualLess": 290.0, - "GreaterFullEqual": 290.0, - "GreaterGreater": 290.0, - "GreaterLess": 290.0, - "GreaterTilde": 290.0, - "HumpDownHump": 290.0, - "HumpEqual": 290.0, - "LeftTriangle": 290.0, - "LeftTriangleBar": 290.0, - "LeftTriangleEqual": 290.0, - "LessEqualGreater": 290.0, - "LessFullEqual": 290.0, - "LessGreater": 290.0, - "LessLess": 290.0, - "LessTilde": 290.0, - "NestedGreaterGreater": 290.0, - "NestedLessLess": 290.0, - "NotCongruent": 290.0, - "NotCupCap": 290.0, - "NotGreater": 290.0, - "NotGreaterEqual": 290.0, - "NotGreaterFullEqual": 290.0, - "NotGreaterLess": 290.0, - "NotGreaterTilde": 290.0, - "NotLeftTriangle": 290.0, - "NotLeftTriangleEqual": 290.0, - "NotLess": 290.0, - "NotLessEqual": 290.0, - "NotLessFullEqual": 290.0, - "NotLessGreater": 290.0, - "NotLessTilde": 290.0, - "NotPrecedes": 290.0, - "NotPrecedesSlantEqual": 290.0, - "NotPrecedesTilde": 290.0, - "NotRightTriangle": 290.0, - "NotRightTriangleEqual": 290.0, - "NotSucceeds": 290.0, - "NotSucceedsSlantEqual": 290.0, - "NotSucceedsTilde": 290.0, - "NotTilde": 290.0, - "NotTildeEqual": 290.0, - "NotTildeFullEqual": 290.0, - "NotTildeTilde": 290.0, - "Precedes": 290.0, - "PrecedesEqual": 290.0, - "PrecedesSlantEqual": 290.0, - "PrecedesTilde": 290.0, - "Proportion": 290.0, - "Proportional": 290.0, - "ReverseEquilibrium": 290.0, - "RightTriangle": 290.0, - "RightTriangleBar": 290.0, - "RightTriangleEqual": 290.0, - "Succeeds": 290.0, - "SucceedsEqual": 290.0, - "SucceedsSlantEqual": 290.0, - "SucceedsTilde": 290.0, - "Tilde": 290.0, - "TildeEqual": 290.0, - "TildeFullEqual": 290.0, - "TildeTilde": 290.0, - "DirectedEdge": 295.0, - "UndirectedEdge": 295.0, - "SquareUnion": 300.0, - "UnionPlus": 300.0, - "Span": 305.0, - "SquareIntersection": 305.0, - "MinusPlus": 310.0, - "PlusMinus": 310.0, - "Plus": 310.0, - "Subtract": 310.0, - "CircleMinus": 330.0, - "CirclePlus": 330.0, - "Cup": 340.0, - "Cap": 350.0, - "Coproduct": 360.0, - "VerticalTilde": 370.0, - "Star": 390.0, - "Times": 400.0, - "CenterDot": 410.0, - "CircleTimes": 420.0, - "Vee": 430.0, - "Wedge": 440.0, - "Diamond": 450.0, - "Backslash": 460.0, - "Divide": 470.0, - "Minus": 480.0, - "Dot": 490.0, - "CircleDot": 520.0, - "SmallCircle": 530.0, - "Square": 540.0, - "CapitalDifferentialD": 550.0, - "Del": 550.0, - "DifferentialD": 550.0, - "DoubleDownArrow": 580.0, - "DoubleLongLeftArrow": 580.0, - "DoubleLongLeftRightArrow": 580.0, - "DoubleLongRightArrow": 580.0, - "DoubleUpArrow": 580.0, - "DoubleUpDownArrow": 580.0, - "DownArrow": 580.0, - "DownArrowBar": 580.0, - "DownArrowUpArrow": 580.0, - "DownTeeArrow": 580.0, - "LeftDownTeeVector": 580.0, - "LeftDownVector": 580.0, - "LeftDownVectorBar": 580.0, - "LeftUpDownVector": 580.0, - "LeftUpTeeVector": 580.0, - "LeftUpVector": 580.0, - "LeftUpVectorBar": 580.0, - "LongLeftArrow": 580.0, - "LongLeftRightArrow": 580.0, - "LongRightArrow": 580.0, - "ReverseUpEquilibrium": 580.0, - "RightDownTeeVector": 580.0, - "RightDownVector": 580.0, - "RightDownVectorBar": 580.0, - "RightUpDownVector": 580.0, - "RightUpTeeVector": 580.0, - "RightUpVector": 580.0, - "RightUpVectorBar": 580.0, - "ShortDownArrow": 580.0, - "ShortUpArrow": 580.0, - "UpArrow": 580.0, - "UpArrowBar": 580.0, - "UpArrowDownArrow": 580.0, - "UpDownArrow": 580.0, - "UpEquilibrium": 580.0, - "UpTeeArrow": 580.0, - "Power": 590.0, - "StringJoin": 600.0, - "Factorial": 610.0, - "Factorial2": 610.0, - "Apply": 620.0, - "Map": 620.0, - "Prefix": 640.0, - "Decrement": 660.0, - "Increment": 660.0, - "PreDecrement": 660.0, - "PreIncrement": 660.0, - "Unset": 670.0, - "Information": 670.0, - "GreaterSlantEqual": 670.0, - "LessSlantEqual": 670.0, - "Derivative": 670.0, - "MapApply": 670.0, - "PatternTest": 680.0, - "Get": 720.0, - "MessageName": 750.0, -} SORTED_SYMBOLS_BY_PRECEDENCE = [ "CompoundExpression", @@ -546,41 +322,8 @@ ] -@pytest.mark.skipif(MATHICS_NOT_INSTALLED, reason="Requires Mathics-core installed") -@pytest.mark.parametrize( - ( - "symbol", - "prec", - ), - list(WMA_PRECEDENCES.items()), -) -@pytest.mark.xfail -def test_precedence_values(symbol, prec): - """ - - TrueRelPrecedence[op1_, op2_] := - Module[{formatted = - ToString[ - HoldForm[ope2[ope1[a, b], c]] /. {ope1 -> op1, ope2 -> op2}, - InputForm]}, - Not[Or[StringPart[formatted, 1] == "(", - StringPart[formatted, -1] == ")"]]] - - Transpose[{a, ALLOPS}] // TableForm""" - - mathics_prec = session.evaluate(f"Precedence[{symbol}]").value - print("Check", f"Precedence[{symbol}]=={prec}") - check_evaluation( - f"Precedence[{symbol}]=={prec}", - "True", - to_string_expr=True, - to_string_expected=True, - hold_expected=True, - failure_message=f"Precendece of {symbol} in mathics {mathics_prec} != WMA value {prec}", - expected_messages=None, - ) - +# TODO: rewrite this test by reading the table directly. @pytest.mark.skipif(MATHICS_NOT_INSTALLED, reason="Requires Mathics-core installed") def test_precedence_order(): """ From 26359bade4b1fb9e4aaf7b4186834af49106fe9b Mon Sep 17 00:00:00 2001 From: mmatera Date: Tue, 3 Dec 2024 08:12:09 -0300 Subject: [PATCH 2/4] fixing the name of the constant. Improving docstrings --- test/test_mathics_precedence.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/test/test_mathics_precedence.py b/test/test_mathics_precedence.py index 10978e7..79ec113 100644 --- a/test/test_mathics_precedence.py +++ b/test/test_mathics_precedence.py @@ -21,7 +21,7 @@ ``` In other cases, precedence values of some operators are reported to be the default value (670) -while its behaviour is different (Ej: `GreaterSlantEqual` and `LessSlantEqual` behaves as +while its behavior is different (Ej: `GreaterSlantEqual` and `LessSlantEqual` behaves as their precedence were the same that the one for `LessEqual` and `GreaterEqual`). In any case, the relevant information is the order relation that `Precedence` induce over the @@ -35,6 +35,10 @@ by `OutputForm`. This consistency was tested in WMA using the functions defined in the `testprecedence.m` module. +Notice also that the tests of this module does not tries to check the behavior +of the parser or the formatters in Mathics-core, but just that the information +that MathicsScanner reports to be consistent with the behavior of WMA. + """ try: @@ -47,7 +51,7 @@ import pytest -SORTED_SYMBOLS_BY_PRECEDENCE = [ +SYMBOLS_SORTED_BY_PRECEDENCE = [ "CompoundExpression", "Put", "PutAppend", @@ -328,20 +332,22 @@ def test_precedence_order(): """ Test the precedence order. - This is a slighly flexible test, which does not - requires the numerical coincidence of the Precedence values - with WMA, but just to preserve the order. + + This test checks that the precedence values of the symbols associted + to WL operators follows the order required to make the + that the parser and the OutputForm formatter produce + outputs consistent with the WMA behavior. """ precedence_values = [ session.evaluate(f"Precedence[{symbol}]").value - for symbol in SORTED_SYMBOLS_BY_PRECEDENCE + for symbol in SYMBOLS_SORTED_BY_PRECEDENCE ] fails = [] for i in range(len(precedence_values) - 1): if precedence_values[i] > precedence_values[i + 1]: fails.append( - f"Precedence[{SORTED_SYMBOLS_BY_PRECEDENCE[i]}]={precedence_values[i]}>" - f"{precedence_values[i+1]}=Precedence[{SORTED_SYMBOLS_BY_PRECEDENCE[i+1]}]" + f"Precedence[{SYMBOLS_SORTED_BY_PRECEDENCE[i]}]={precedence_values[i]}>" + f"{precedence_values[i+1]}=Precedence[{SYMBOLS_SORTED_BY_PRECEDENCE[i+1]}]" ) for fail in fails: print(fail) From 2d4cad3db080df1df91e99d465acfc6a604fdaa1 Mon Sep 17 00:00:00 2001 From: mmatera Date: Tue, 3 Dec 2024 08:17:14 -0300 Subject: [PATCH 3/4] black --- test/test_mathics_precedence.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test_mathics_precedence.py b/test/test_mathics_precedence.py index 79ec113..0b70f92 100644 --- a/test/test_mathics_precedence.py +++ b/test/test_mathics_precedence.py @@ -326,7 +326,6 @@ ] - # TODO: rewrite this test by reading the table directly. @pytest.mark.skipif(MATHICS_NOT_INSTALLED, reason="Requires Mathics-core installed") def test_precedence_order(): From 6dc971fab11564a8d4bcc1eea9dd3572f2418215 Mon Sep 17 00:00:00 2001 From: mmatera Date: Tue, 3 Dec 2024 08:23:55 -0300 Subject: [PATCH 4/4] codespell --- test/test_mathics_precedence.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_mathics_precedence.py b/test/test_mathics_precedence.py index 0b70f92..05e35b5 100644 --- a/test/test_mathics_precedence.py +++ b/test/test_mathics_precedence.py @@ -1,6 +1,6 @@ """ -Test precedences -================ +Test operator precedences +========================= Precedence values reported in the Mathics Scanner tables do not always match with the values reported by `Precedence[...]` in WMA. As it was @@ -332,7 +332,7 @@ def test_precedence_order(): """ Test the precedence order. - This test checks that the precedence values of the symbols associted + This test checks that the precedence values of the symbols associated to WL operators follows the order required to make the that the parser and the OutputForm formatter produce outputs consistent with the WMA behavior.