From 54a2c3ab56124867f0da112116ea54ac01e8f9e2 Mon Sep 17 00:00:00 2001 From: mmatera Date: Sat, 30 Nov 2024 10:12:31 -0300 Subject: [PATCH 1/7] fix precedence for Directed and Undirected Edge --- mathics_scanner/data/operators.yml | 4 ++-- test/test_mathics_precedence.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mathics_scanner/data/operators.yml b/mathics_scanner/data/operators.yml index 7d8a844..54fd943 100644 --- a/mathics_scanner/data/operators.yml +++ b/mathics_scanner/data/operators.yml @@ -1137,7 +1137,7 @@ DifferentialD: # comments: DirectedEdge: - precedence: 128 + precedence: 295 WolframLanguageData: WolframLanguageData-corrected: 49 UnicodeCharacters.tr: 395 @@ -7057,7 +7057,7 @@ UnderscriptBox: # comments: UndirectedEdge: - precedence: 120 # FIXME: is probably 295. Check and adjust after code and mathics-core are merge + precedence: 295 WolframLanguageData: WolframLanguageData-corrected: 49 UnicodeCharacters.tr: 395 diff --git a/test/test_mathics_precedence.py b/test/test_mathics_precedence.py index fd038c9..88b737a 100644 --- a/test/test_mathics_precedence.py +++ b/test/test_mathics_precedence.py @@ -456,8 +456,8 @@ "TildeFullEqual", "TildeTilde", # In Mathics, the precedence of these operators is quite low. - # "DirectedEdge", # Mathics 128 , WMA 295 - # "UndirectedEdge", # Mathics 120, WMA 295 + "DirectedEdge", # Mathics 128 , WMA 295 + "UndirectedEdge", # Mathics 120, WMA 295 "SquareUnion", "UnionPlus", "Span", From da9bd6da72e4e29315339a09ca3042735d64a0a7 Mon Sep 17 00:00:00 2001 From: mmatera Date: Sat, 30 Nov 2024 10:35:29 -0300 Subject: [PATCH 2/7] black and remove comment --- test/test_mathics_precedence.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/test_mathics_precedence.py b/test/test_mathics_precedence.py index 88b737a..975bfa5 100644 --- a/test/test_mathics_precedence.py +++ b/test/test_mathics_precedence.py @@ -455,9 +455,8 @@ "TildeEqual", "TildeFullEqual", "TildeTilde", - # In Mathics, the precedence of these operators is quite low. - "DirectedEdge", # Mathics 128 , WMA 295 - "UndirectedEdge", # Mathics 120, WMA 295 + "DirectedEdge", + "UndirectedEdge", "SquareUnion", "UnionPlus", "Span", From 306a79843f3acf137e3ef5261dc3da4dbac289fd Mon Sep 17 00:00:00 2001 From: Juan Mauricio Matera Date: Tue, 3 Dec 2024 08:29:33 -0300 Subject: [PATCH 3/7] Improving docstrings (#105) * removing the numerical comparison test. Adding an explanation at the beginning of the file * fixing the name of the constant. Improving docstrings * black * codespell --- test/test_mathics_precedence.py | 352 +++++--------------------------- 1 file changed, 50 insertions(+), 302 deletions(-) diff --git a/test/test_mathics_precedence.py b/test/test_mathics_precedence.py index 975bfa5..05e35b5 100644 --- a/test/test_mathics_precedence.py +++ b/test/test_mathics_precedence.py @@ -1,5 +1,44 @@ """ -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 +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 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 +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. + +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: @@ -11,267 +50,8 @@ 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 = [ +SYMBOLS_SORTED_BY_PRECEDENCE = [ "CompoundExpression", "Put", "PutAppend", @@ -546,59 +326,27 @@ ] -@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(): """ 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 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. """ 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 242eb0a07c74a4e6a48fab91df62b781a27e7c56 Mon Sep 17 00:00:00 2001 From: mmatera Date: Tue, 3 Dec 2024 08:52:28 -0300 Subject: [PATCH 4/7] adding rockys tests --- test/test_mathics_precedence.py | 41 +++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/test/test_mathics_precedence.py b/test/test_mathics_precedence.py index 975bfa5..cc0ac46 100644 --- a/test/test_mathics_precedence.py +++ b/test/test_mathics_precedence.py @@ -603,3 +603,44 @@ def test_precedence_order(): for fail in fails: print(fail) assert len(fails) == 0 + + +# Just because @rocky's ask: + + +@pytest.mark.skipif(MATHICS_NOT_INSTALLED, reason="Requires Mathics-core installed") +@pytest.mark.parametrize( + ("expr", "expected"), + [ + ( + "a\[TildeTilde]b\[DirectedEdge]c//FullForm", + "TildeTilde[a, DirectedEdge[b, c]]", + ), + ( + "a\[DirectedEdge]b\[TildeTilde]c//FullForm", + "TildeTilde[DirectedEdge[a, b], c]", + ), + ( + "a\[UndirectedEdge]b\[DirectedEdge]c//FullForm", + "UndirectedEdge[a, DirectedEdge[b, c]]", + ), + ( + "a\[UndirectedEdge]b\[TildeTilde]c//FullForm", + "UndirectedEdge[DirectedEdge[a, b], c]", + ), + ( + "a\[SquareUnion]b\[UndirectedEdge]c//FullForm", + "UndirectedEdge[a, SquareUnion[b, c]]", + ), + ( + "a\[UndirectedEdge]b\[SquareUnion]c//FullForm", + "UndirectedEdge[SquareUnion[a, b], c]", + ), + ('OutputForm[Infix[{DirectedEdge[a, b],c},"#", 294,None]]', "a → b#c"), + ('OutputForm[Infix[{DirectedEdge[a, b],c},"#", 295,None]]', "(a → b)#c"), + ('OutputForm[Infix[{UndirectedEdge[a, b],c},"#", 294,None]]', "a → b#c"), + ('OutputForm[Infix[{UndirectedEdge[a, b],c},"#", 295,None]]', "(a → b)#c"), + ], +) +def test_parsing_and_formatting(expr, expected): + check_evaluation(str_expr, str_expected) From f94286829e2b04a63b3933731c85dfb322a719c9 Mon Sep 17 00:00:00 2001 From: mmatera Date: Tue, 3 Dec 2024 10:02:42 -0300 Subject: [PATCH 5/7] adding operational tests --- test/test_mathics_precedence.py | 471 +++++++++++--------------------- 1 file changed, 153 insertions(+), 318 deletions(-) diff --git a/test/test_mathics_precedence.py b/test/test_mathics_precedence.py index cc0ac46..e6ba051 100644 --- a/test/test_mathics_precedence.py +++ b/test/test_mathics_precedence.py @@ -1,5 +1,44 @@ """ -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 +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 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 +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. + +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: @@ -11,267 +50,8 @@ 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 = [ +SYMBOLS_SORTED_BY_PRECEDENCE = [ "CompoundExpression", "Put", "PutAppend", @@ -546,101 +326,156 @@ ] -@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(): """ 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 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. """ 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) assert len(fails) == 0 -# Just because @rocky's ask: +# Here are "operational" tests. In my opinion, these tests belongs to mathics-core. +# Some of them fails, not because the data in the tables are wrong, +# but because our parser gives a different result when two operators has the same precedence: @pytest.mark.skipif(MATHICS_NOT_INSTALLED, reason="Requires Mathics-core installed") @pytest.mark.parametrize( - ("expr", "expected"), + ("str_expr", "str_expected"), [ + # DirectedEdge has smaller precedence than TildeTilde: ( - "a\[TildeTilde]b\[DirectedEdge]c//FullForm", + r"a\[TildeTilde]b\[DirectedEdge]c//FullForm", "TildeTilde[a, DirectedEdge[b, c]]", ), ( - "a\[DirectedEdge]b\[TildeTilde]c//FullForm", + r"a\[DirectedEdge]b\[TildeTilde]c//FullForm", "TildeTilde[DirectedEdge[a, b], c]", ), + # Directed and Undirected has the same precedence: + ( + r"a\[UndirectedEdge]b\[DirectedEdge]c//FullForm", + "DirectedEdge[UndirectedEdge[a, b], c]", + # In WMA, this is parsed as: + # "UndirectedEdge[a, DirectedEdge[b, c]]", + ), + ( + r"a\[DirectedEdge]b\[UndirectedEdge]c//FullForm", + "UndirectedEdge[DirectedEdge[a, b], c]" + # In WMA, this is parsed as: + #'DirectedEdge[UndirectedEdge[a, b], c]' + ), + # LongLeftArrow and LongRightArrow has also the same precedence, but: ( - "a\[UndirectedEdge]b\[DirectedEdge]c//FullForm", - "UndirectedEdge[a, DirectedEdge[b, c]]", + r"a\[LongLeftArrow]b\[LongRightArrow]c//FullForm", + # In this case, both behaviors matches + "LongRightArrow[LongLeftArrow[a, b], c]", ), ( - "a\[UndirectedEdge]b\[TildeTilde]c//FullForm", - "UndirectedEdge[DirectedEdge[a, b], c]", + r"a\[LongRightArrow]b\[LongLeftArrow]c//FullForm", + # In this case, both behaviors matches + "LongLeftArrow[LongRightArrow[a, b], c]", ), + # UndirectedEdge has larger precedence than SquareUnion ( "a\[SquareUnion]b\[UndirectedEdge]c//FullForm", - "UndirectedEdge[a, SquareUnion[b, c]]", + "UndirectedEdge[SquareUnion[a, b], c]", ), ( "a\[UndirectedEdge]b\[SquareUnion]c//FullForm", - "UndirectedEdge[SquareUnion[a, b], c]", + "UndirectedEdge[a, SquareUnion[b, c]]", ), - ('OutputForm[Infix[{DirectedEdge[a, b],c},"#", 294,None]]', "a → b#c"), - ('OutputForm[Infix[{DirectedEdge[a, b],c},"#", 295,None]]', "(a → b)#c"), - ('OutputForm[Infix[{UndirectedEdge[a, b],c},"#", 294,None]]', "a → b#c"), - ('OutputForm[Infix[{UndirectedEdge[a, b],c},"#", 295,None]]', "(a → b)#c"), ], ) -def test_parsing_and_formatting(expr, expected): - check_evaluation(str_expr, str_expected) +# @pytest.mark.xfail +def test_parsing(str_expr, str_expected): + check_evaluation(str_expr, str_expected, hold_expected=True) + + +# The same happens with formatting. +# Test cases are taken from the result in WMA, except by the character used for +# representing the operator, and the spaces between operands (WMA does not print them). + + +@pytest.mark.skipif(MATHICS_NOT_INSTALLED, reason="Requires Mathics-core installed") +@pytest.mark.parametrize( + ("str_expr", "str_expected"), + [ + # LongLeftArrow a + ('OutputForm[Infix[{LongLeftArrow[a, b],c},"#", 579,None]]', "a \u27f5 b # c"), + ( + 'OutputForm[Infix[{LongLeftArrow[a, b],c},"#", 580,None]]', + "(a \u27f5 b) # c", + ), + ( + 'OutputForm[Infix[{LongLeftArrow[a, b],c},"#", 581,None]]', + "(a \u27f5 b) # c", + ), + ('OutputForm[Infix[{a, LongLeftArrow[b, c]},"#", 579,None]]', "a # b \u27f5 c"), + ( + 'OutputForm[Infix[{a, LongLeftArrow[b, c]},"#", 580,None]]', + "a # (b \u27f5 c)", + ), + ( + 'OutputForm[Infix[{a, LongLeftArrow[b, c]},"#", 581,None]]', + "a # (b \u27f5 c)", + ), + # DirectedEdge + ('OutputForm[Infix[{DirectedEdge[a, b],c},"#", 294,None]]', "a \u2192 b # c"), + ('OutputForm[Infix[{DirectedEdge[a, b],c},"#", 295,None]]', "(a \u2192 b) # c"), + ('OutputForm[Infix[{DirectedEdge[a, b],c},"#", 296,None]]', "(a \u2192 b) # c"), + ('OutputForm[Infix[{a, DirectedEdge[b, c]},"#", 294,None]]', "a # b \u2192 c"), + ( + 'OutputForm[Infix[{a, DirectedEdge[b, c]},"#", 295,None]]', + "a # (b \u2192 c)", + ), + ( + 'OutputForm[Infix[{a, DirectedEdge[b, c]},"#", 296,None]]', + "a # (b \u2192 c)", + ), + # UndirectedEdge + ('OutputForm[Infix[{UndirectedEdge[a, b],c},"#", 294,None]]', "a \u2194 b # c"), + ( + 'OutputForm[Infix[{UndirectedEdge[a, b],c},"#", 295,None]]', + "(a \u2194 b) # c", + ), + ( + 'OutputForm[Infix[{UndirectedEdge[a, b],c},"#", 296,None]]', + "(a \u2194 b) # c", + ), + ( + 'OutputForm[Infix[{a, UndirectedEdge[b, c]},"#", 294,None]]', + "a # b \u2194 c", + ), + ( + 'OutputForm[Infix[{a, UndirectedEdge[b, c]},"#", 295,None]]', + "a # b \u2194 c", + ), + ( + 'OutputForm[Infix[{a, UndirectedEdge[b, c]},"#", 296,None]]', + "a # (b \u2194 c)", + ), + ], +) +@pytest.mark.xfail +def test_formatting(str_expr, str_expected): + check_evaluation(str_expr, str_expected, hold_expected=True) From faec1fdc4ffbd3ba156e35f6ab74d09f04e49613 Mon Sep 17 00:00:00 2001 From: mmatera Date: Tue, 3 Dec 2024 10:04:19 -0300 Subject: [PATCH 6/7] merge --- test/test_mathics_precedence.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/test_mathics_precedence.py b/test/test_mathics_precedence.py index e6ba051..1c8baa2 100644 --- a/test/test_mathics_precedence.py +++ b/test/test_mathics_precedence.py @@ -26,18 +26,18 @@ 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. +the MathicsScanner tables. -This module test that the *order* induced by the precedence values assigned to each operator/symbol +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 +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. 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. +that MathicsScanner reports to be consistent with the behavior of WMA. """ @@ -353,6 +353,7 @@ def test_precedence_order(): assert len(fails) == 0 + # Here are "operational" tests. In my opinion, these tests belongs to mathics-core. # Some of them fails, not because the data in the tables are wrong, # but because our parser gives a different result when two operators has the same precedence: From f19e4cb1c78f3f7a514a5641b588b75296510511 Mon Sep 17 00:00:00 2001 From: mmatera Date: Tue, 3 Dec 2024 10:13:37 -0300 Subject: [PATCH 7/7] black --- test/test_mathics_precedence.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/test_mathics_precedence.py b/test/test_mathics_precedence.py index 1c8baa2..daa18da 100644 --- a/test/test_mathics_precedence.py +++ b/test/test_mathics_precedence.py @@ -353,7 +353,6 @@ def test_precedence_order(): assert len(fails) == 0 - # Here are "operational" tests. In my opinion, these tests belongs to mathics-core. # Some of them fails, not because the data in the tables are wrong, # but because our parser gives a different result when two operators has the same precedence: @@ -381,7 +380,7 @@ def test_precedence_order(): ), ( r"a\[DirectedEdge]b\[UndirectedEdge]c//FullForm", - "UndirectedEdge[DirectedEdge[a, b], c]" + "UndirectedEdge[DirectedEdge[a, b], c]", # In WMA, this is parsed as: #'DirectedEdge[UndirectedEdge[a, b], c]' ),