Pretty print - #1162
Conversation
* Improving handling for Infix, Prefix and Postfix format
Briefly looking at the code, I have a gut feeling that something is amiss. It doesn't fully follow the kind of tree parsing pattern that I often have seen in code. And instead, the code keeps stuff like An approach that can build on and contribute back to SymPy feels like a better approach overall, but this is more of a gut feeling that digging into the code deeply right now with more concrete suggestions. Let's defer merging this until we have boxing under better control. |
|
@rocky, I put a PR in Sympy related to this sympy/sympy#27257 |
I am very glad to see some sort of collaboration (as opposed to reinvention) here. Thanks for engaging with SymPy. Let's wait on this to see where things go. |
ff2f585 to
002f183
Compare
There was a problem hiding this comment.
⚠️ Performance Alert ⚠️
Possible performance regression was detected for benchmark 'Mathics3 Core Benchmarks'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.50.
| Benchmark suite | Current: 90cf764 | Previous: 11107cf | Ratio |
|---|---|---|---|
test/timings/test_patterns.py::test_orderless_plus_match_benchmark[n=11] |
434.35271281151756 iter/sec (stddev: 0.00022144598453726307) |
655.9624096804085 iter/sec (stddev: 0.00015810020296261142) |
1.51 |
test/timings/test_patterns.py::test_orderless_exhaustive_failure_benchmark[n=4] |
114.95294056605488 iter/sec (stddev: 0.00019718394612353718) |
181.22826733279368 iter/sec (stddev: 0.0001616213814867379) |
1.58 |
test/timings/test_patterns.py::test_orderless_exhaustive_failure_benchmark[n=5] |
16.49105688336866 iter/sec (stddev: 0.002548120461168035) |
26.07389735356884 iter/sec (stddev: 0.0014981448856669808) |
1.58 |
test/timings/test_patterns.py::test_orderless_exhaustive_failure_benchmark[n=6] |
2.009063345496612 iter/sec (stddev: 0.0007365444892242935) |
3.248505988002981 iter/sec (stddev: 0.0018704372126017697) |
1.62 |
test/timings/test_patterns.py::test_blank_sequence_backtracking_benchmark[MatchQ[bigList, {a___, 3000, b___}]-SystemTrue]` |
0.6704533134771515 iter/sec (stddev: 0.009384368005040146) |
1.0186038696427617 iter/sec (stddev: 0.008724957153457408) |
1.52 |
test/timings/test_patterns.py::test_blank_sequence_backtracking_benchmark[MatchQ[bigList, {a___, 3001, b___}]-SystemFalse]` |
304.71032803850466 iter/sec (stddev: 0.000024038523929241808) |
468.351290351065 iter/sec (stddev: 0.0001732508127826809) |
1.54 |
test/timings/test_patterns.py::test_get_match_candidates_benchmark[n=10] |
4840.1122388022695 iter/sec (stddev: 0.000009149153798856202) |
7644.386015362796 iter/sec (stddev: 0.00000589139036201033) |
1.58 |
test/timings/test_patterns.py::test_get_match_candidates_benchmark[n=100] |
512.3374918187573 iter/sec (stddev: 0.00003728734139466469) |
785.9403487585644 iter/sec (stddev: 0.000012527751978590962) |
1.53 |
test/timings/test_patterns.py::test_get_match_candidates_benchmark[n=1000] |
50.881604133700314 iter/sec (stddev: 0.00019704314389202258) |
79.18347198457376 iter/sec (stddev: 0.00013507608507845872) |
1.56 |
test/timings/test_patterns.py::test_get_match_candidates_benchmark[n=5000] |
10.33860924655988 iter/sec (stddev: 0.0019397741571019439) |
15.572208767590576 iter/sec (stddev: 0.0009039125485853565) |
1.51 |
test/timings/test_patterns.py::test_get_match_candidates_count_benchmark[n=10] |
4871.208366170652 iter/sec (stddev: 0.00000893435656554904) |
7399.00043134964 iter/sec (stddev: 0.000016605594559593932) |
1.52 |
test/timings/test_patterns.py::test_get_match_candidates_count_benchmark[n=100] |
521.3848985123985 iter/sec (stddev: 0.00004062416866103663) |
783.0177452265693 iter/sec (stddev: 0.00001651809868056019) |
1.50 |
test/timings/test_patterns.py::test_get_match_candidates_count_benchmark[n=1000] |
51.029987012576335 iter/sec (stddev: 0.00033107862848192655) |
78.53635216307391 iter/sec (stddev: 0.00007747215001173897) |
1.54 |
test/timings/test_patterns.py::test_get_match_candidates_count_benchmark[n=5000] |
10.268729342221524 iter/sec (stddev: 0.001743346486800647) |
15.851448797502806 iter/sec (stddev: 0.00023081424027309718) |
1.54 |
test/timings/test_patterns.py::test_orderless_repeated_names_scaling_benchmark[match-n=6] |
57.27288459101047 iter/sec (stddev: 0.052829514048921916) |
1615.5529932884122 iter/sec (stddev: 0.00040016768863210684) |
28.21 |
test/timings/test_patterns.py::test_orderless_repeated_names_scaling_benchmark[fail-n=4] |
1101.0332315894289 iter/sec (stddev: 0.00011387646617462781) |
1730.8680233807067 iter/sec (stddev: 0.000014109838657042502) |
1.57 |
test/timings/test_patterns.py::test_orderless_repeated_names_scaling_benchmark[fail-n=6] |
766.8776935092071 iter/sec (stddev: 0.00039340122714096834) |
1536.5661250463622 iter/sec (stddev: 0.00001857806356873446) |
2.00 |
test/timings/test_patterns.py::test_orderless_repeated_names_scaling_benchmark[fail-n=8] |
855.1391683410718 iter/sec (stddev: 0.00013283350346074343) |
1303.6470307997545 iter/sec (stddev: 0.0001068584128537411) |
1.52 |
test/timings/test_patterns.py::test_orderless_repeated_names_scaling_benchmark[fail-n=10] |
750.0384957286614 iter/sec (stddev: 0.0001400139217057392) |
1172.3407764761887 iter/sec (stddev: 0.00010819719463373896) |
1.56 |
test/timings/test_patterns.py::test_orderless_repeated_names_scaling_benchmark[fail-n=12] |
697.8922259114946 iter/sec (stddev: 0.00010709230434587356) |
1056.6642546590003 iter/sec (stddev: 0.0001363997596266633) |
1.51 |
test/timings/test_patterns.py::test_blank_sequence_position_scaling_benchmark[literal-first-n=300] |
1030.5981499157544 iter/sec (stddev: 0.000013277216999397663) |
1556.2543137123205 iter/sec (stddev: 0.000016140743232458547) |
1.51 |
test/timings/test_patterns.py::test_blank_sequence_position_scaling_benchmark[literal-first-n=1000] |
522.326425186307 iter/sec (stddev: 0.000021947639228805754) |
805.6797846653858 iter/sec (stddev: 0.000030387126789931407) |
1.54 |
test/timings/test_patterns.py::test_blank_sequence_position_scaling_benchmark[literal-first-n=2000] |
310.95867502830424 iter/sec (stddev: 0.000042668428683861946) |
480.11823199515936 iter/sec (stddev: 0.00002396762316410957) |
1.54 |
test/timings/test_patterns.py::test_blank_sequence_position_scaling_benchmark[literal-middle-n=100] |
373.2911663659443 iter/sec (stddev: 0.00002007018566392978) |
599.1934496642235 iter/sec (stddev: 0.00003329315150473894) |
1.61 |
test/timings/test_patterns.py::test_blank_sequence_position_scaling_benchmark[literal-middle-n=300] |
67.22178144895754 iter/sec (stddev: 0.00012307815341901565) |
113.31064317912264 iter/sec (stddev: 0.00007063256806277752) |
1.69 |
test/timings/test_patterns.py::test_blank_sequence_position_scaling_benchmark[literal-middle-n=1000] |
7.5229727684098995 iter/sec (stddev: 0.0006323454341728561) |
12.173808092548846 iter/sec (stddev: 0.00037301159839629716) |
1.62 |
test/timings/test_patterns.py::test_blank_sequence_position_scaling_benchmark[literal-middle-n=2000] |
2.0847672870897087 iter/sec (stddev: 0.003059402222316694) |
3.137322234063359 iter/sec (stddev: 0.002356055380067824) |
1.50 |
test/timings/test_patterns.py::test_blank_sequence_position_scaling_benchmark[literal-last-n=100] |
262.6952607298852 iter/sec (stddev: 0.0000655382649982556) |
417.7978369013429 iter/sec (stddev: 0.000036304085821634565) |
1.59 |
test/timings/test_patterns.py::test_blank_sequence_position_scaling_benchmark[literal-last-n=300] |
47.49645858100445 iter/sec (stddev: 0.0002173858393236407) |
78.1919646981202 iter/sec (stddev: 0.00005245127442438013) |
1.65 |
test/timings/test_patterns.py::test_blank_sequence_position_scaling_benchmark[literal-last-n=1000] |
5.621736062907763 iter/sec (stddev: 0.0008979337441516396) |
8.584320523612341 iter/sec (stddev: 0.0016037790488133848) |
1.53 |
test/timings/test_patterns.py::test_blank_sequence_position_scaling_benchmark[literal-absent-n=300] |
1256.7204698396897 iter/sec (stddev: 0.00001666940692797309) |
1905.4544013269442 iter/sec (stddev: 0.000014838427721074915) |
1.52 |
test/timings/test_patterns.py::test_blank_sequence_position_scaling_benchmark[literal-absent-n=1000] |
684.8329096823023 iter/sec (stddev: 0.000038263707741485334) |
1075.2120506287617 iter/sec (stddev: 0.000016446512819736496) |
1.57 |
test/timings/test_patterns.py::test_blank_sequence_position_scaling_benchmark[literal-absent-n=2000] |
428.22242729143136 iter/sec (stddev: 0.000018368602447607362) |
660.9040678561984 iter/sec (stddev: 0.000018755371151916586) |
1.54 |
test/timings/test_patterns.py::test_multiple_blank_sequences_benchmark[match-n=30] |
859.9114033030986 iter/sec (stddev: 0.000024883840911586914) |
1320.334551652687 iter/sec (stddev: 0.00002297207280147043) |
1.54 |
test/timings/test_patterns.py::test_multiple_blank_sequences_benchmark[match-n=60] |
523.889299664117 iter/sec (stddev: 0.000016924891407931474) |
830.3645034494309 iter/sec (stddev: 0.00001799547015017952) |
1.58 |
test/timings/test_patterns.py::test_multiple_blank_sequences_benchmark[match-n=100] |
302.1913648544599 iter/sec (stddev: 0.000024177791872838412) |
482.6182852785447 iter/sec (stddev: 0.00009652555124457837) |
1.60 |
test/timings/test_patterns.py::test_multiple_blank_sequences_benchmark[match-n=150] |
170.9483939960532 iter/sec (stddev: 0.00012304789067537868) |
286.56340583568476 iter/sec (stddev: 0.000018330704785767418) |
1.68 |
test/timings/test_patterns.py::test_multiple_blank_sequences_benchmark[fail-n=30] |
1508.2150968151868 iter/sec (stddev: 0.00004034819631581197) |
2279.032942510329 iter/sec (stddev: 0.00002058310221697063) |
1.51 |
test/timings/test_patterns.py::test_multiple_blank_sequences_benchmark[fail-n=100] |
1384.3455436791728 iter/sec (stddev: 0.000017893319923863104) |
2098.562337891957 iter/sec (stddev: 0.000012195621502051837) |
1.52 |
test/timings/test_uniform_tables.py::test_evaluate_benchmark[Plus@@uniformTable-2.075674547634748] |
135.1944398203771 iter/sec (stddev: 0.00009045592861755487) |
205.9796107581378 iter/sec (stddev: 0.00009345957581376688) |
1.52 |
test/timings/test_uniform_tables.py::test_evaluate_benchmark[MatchQ[uniformTable,{__Real}]-SystemTrue]` |
657.6627160338596 iter/sec (stddev: 0.0001195450298578684) |
988.9830257873544 iter/sec (stddev: 0.000118320287910051) |
1.50 |
test/timings/test_uniform_tables.py::test_evaluate_benchmark[Length[F@@uniformTable]-0] |
316.8836847206561 iter/sec (stddev: 0.000019505555665841485) |
495.57811752004164 iter/sec (stddev: 0.00003106871342288367) |
1.56 |
test/timings/test_uniform_tables.py::test_evaluate_benchmark[Plus@@nonuniformTable-2.075674547634748] |
134.80046383813365 iter/sec (stddev: 0.00004518833388496668) |
207.5541857302082 iter/sec (stddev: 0.000037145532188691984) |
1.54 |
This comment was automatically generated by workflow using github-action-benchmark.
This is a (partial) reimplementation of #1155, based on
sympy.printing.pretty.stringpict.prettyFormobjects. #1155 was written following the same idea of that class, but in a way that supports "standard" string operations instead of "prettyPrint". With this I mean for example, thattext1_TextBlock + text2_TextBlockreturns the concatenation of both text blocks.In
prettyFormobjects,text1_TextBlock + text2_TextBlockproduces a block with a sign+or-depending on the second argument represents a positive or a negative quantity. I find it weird, but it seems it works for Sympy.Issues with the current implementation of (Sympy)
PrettyFormsympy.printing.pretty.stringpict.prettyFormalso has other problems, like bugs in the implementation ofprettyForm.root, and a weird interface to concatenate text blocks. Also, some features I would like to have for these objects are still not implemented, like handling text aligning.All of this can be improved by asking Sympy's guys to consider implementing some fixes, something that I have eventually planned to do.
Why not building over the higher level
PrettyPrinter?Regarding using
PrettyPrinterinstead of this lower-level class is motivated in thatPrettyPrinteris designed to work with Sympy objects. The equivalent of the "head" of a Mathics expression in Sympy is the class of the object. So, to support Mathics objects by subclassingPrettyPrinteressentially would mean to define methods_print_Expressionor_print_Atom, and do what I have already done inmathics.format.prettyprint: define a dispatch table to associate heads and Mathics types to formatter functions.Another possibility would be to implement a special converter from Mathics expressions to Sympy, which would require duplicating the conversion function. Also, it would necessarily be a less flexible approach, and the representation of certain WL objects would be less precise or even more hacky.