Skip to main content

Big and Little surprises when unrolling tests of pattern-matching and attributes


Related question concerning interpretation of the substitutions:


Subtle order-of-evaluation issues when pattern-matching with attributes


Questions researched before posting this one:



Orderless pattern matching


Combinations of multiple matching patterns


About OneIdentity


What has changed in pattern matching functions with the Orderless attribute?


Transformation rule for arbitrary number of argument expressions


Pattern does not match with Orderless head


All work done with Mathematica 11.3.0.0 on Ubuntu 18.04 (bionic)


In an attempt to understand pattern-matching better, I tried some exhaustive testing of a certain substitution rule under all seven combinations of attributes, leaving out the null case of no attributes:


In[1]:= allAtts =
Flatten[Table[

Union[Sort /@
Permutations[{Flat, Orderless, OneIdentity}, {i}]], {i, 3}], 1]
Out[1]= {{Flat}, {OneIdentity}, {Orderless}, {Flat, OneIdentity}, {Flat,
Orderless}, {OneIdentity, Orderless}, {Flat, OneIdentity,
Orderless}}

The substitution rule attempts to match the pattern eqv[x_, y_] against the input eqv[p, q, r] to see what gets bound to x and y for each combination of attributes.


In the first test, I define the substitution before setting the attributes. After some manual prettification:


In[2]:= Table[Module[{e = (eqv[p, q, r] /. {eqv[x_, y_] :> {x, y}})},
ClearAll[eqv];

SetAttributes[eqv, j];
{j, First@e, Rest@e}],
{j, allAtts}]
Out[2]= {{{Flat}, p, eqv[q, r]},
{{OneIdentity}, eqv[p], {eqv[q, r]}},
{{Orderless}, p, eqv[q, r]},
{{Flat, OneIdentity}, p, eqv[q, r]},
{{Flat, Orderless}, p, {eqv[q, r]}},
{{OneIdentity, Orderless}, q, {eqv[p, r]}},
{{Flat, OneIdentity, Orderless}, p, eqv[q, r]}}


The results are reasonable, plausible, interpretable. I won't go into interpreting the results in this post other than to note that the results are subtly different when attributes are set before the substitution rule is parsed. The subject of this post is that unrolling the tests produce very different, not subtly different, results. Because I unroll below under both conditions --- substitution parsed before attributes set and attributes set before substitution parsed --- here are the results of the latter, subtly different:


In[3]:= Table[Module[{e},
ClearAll[eqv];
SetAttributes[eqv, j];
e = (eqv[p, q, r] /. {eqv[x_, y_] :> {x, y}});
{j, First@e, Rest@e}],
{j, allAtts}]
Out[3]= {{{Flat}, eqv[p], {eqv[q, r]}}, (* difft *)
{{OneIdentity}, p, eqv[q, r]}, (* difft *)

{{Orderless}, p, eqv[q, r]},
{{Flat, OneIdentity}, p, {eqv[q, r]}}, (* difft *)
{{Flat, Orderless}, q, {eqv[p, r]}}, (* difft *)
{{OneIdentity, Orderless}, p, eqv[q, r]}, (* difft *)
{{Flat, OneIdentity, Orderless}, p, {eqv[q, r]}}}

In a separate post, I have questions about interpreting the results. I Continue here with the main question about unrolling.


I now attempt to unroll these tests, one test for each combination of attributes rather than one table with all combinations. I get many surprises that reveal I don't really understand what's going on. I highlight these surprises below and would be grateful for explanation and clarification.


First, here is my attempt at unrolling the tests:


In[3]:= test32substBeforeAttrs[attrs_] := Module[{eval},

eval[] := eqv[p, q, r] /. {eqv[x_, y_] :> {x, y}};
ClearAll[eqv]; SetAttributes[eqv, attrs]; eval[]]

I try to prevent any early evaluation of the substitution by packaging it in a delayed rule named eval, but I do want the substitution denoted and parsed before attributes are set, which (I thought), were the same conditions as in the rolled-up test.


Surprise number one, the Flat results look similar to the test where attributes are set before the substitution rule is parsed, just without a list enclosing the second binding for y:


In[5]:= test32substBeforeAttrs[{Flat}]
Out[5]= {eqv[p], eqv[q, r]}

Surprise number two, we get no matches for OneIdentity alone and for Orderless alone:


In[6]:= test32substBeforeAttrs[{OneIdentity}]

Out[6]= eqv[p, q, r]
In[7]:= test32substBeforeAttrs[{Orderless}]
Out[7]= eqv[p, q, r]

No surprises for {Flat, OneIdentity}:


In[8]:= test32substBeforeAttrs[{Flat, OneIdentity}]
Out[8]= {p, eqv[q, r]}

but surprise number three for {Flat, Orderless}: p and q are reversed, just like the rolled-up case for {OneIdentity, Orderless}, except, again, no list enclosing the second binding, the binding for y:


In[9]:= test32substBeforeAttrs[{Flat, Orderless}]

Out[9]= {q, eqv[p, r]}

Surprise number four: no match for unrolled {OneIdentity, Orderless}:


In[10]:= test32substBeforeAttrs[{OneIdentity, Orderless}]
Out[10]= eqv[p, q, r]

No surprise for the case of all attributes.


In[11]:= test32substBeforeAttrs[{Flat, OneIdentity, Orderless}]
Out[11]= {p, eqv[q, r]}


Now, my attempt at an unrolled setting of attributes before denoting and parsing the substitution rule. Again, I attempt to prevent early evaluation by packaging my main substitution rule in an outer, delayed substitution rule named eval:


In[12]:= test32AttrsBeforeSubst[attrs_] := Module[{eval},
ClearAll[eqv]; SetAttributes[eqv, attrs];
eval[] := eqv[p, q, r] /. {eqv[x_, y_] :> {x, y}};
eval[]]

In[13]:= test32AttrsBeforeSubst[{Flat}]
Out[13]= {eqv[p], eqv[q, r]}
In[14]:= test32AttrsBeforeSubst[{OneIdentity}]
Out[14]= eqv[p, q, r]

In[15]:= test32AttrsBeforeSubst[{Orderless}]
Out[15]= eqv[p, q, r]
In[16]:= test32AttrsBeforeSubst[{Flat, OneIdentity}]
Out[16]= {p, eqv[q, r]}
In[17]:= test32AttrsBeforeSubst[{Flat, Orderless}]
Out[17]= {q, eqv[p, r]}
In[18]:= test32AttrsBeforeSubst[{OneIdentity, Orderless}]
Out[18]= eqv[p, q, r]
In[19]:= test32AttrsBeforeSubst[{Flat, OneIdentity, Orderless}]
Out[19]= {p, eqv[q, r]}


The big surprise here is that the results are exactly the same as the unrolled test with substitution parsed before attributes set.


To summarize, in addition to the four little surprises when unrolling the tests, there is a big surprise that the relative order of denoting the rule matters when the tests are rolled up and not when the tests are unrolled.


I've managed to confuse myself mightily, here, and would be grateful for insights from those who understand both the big picture and the micro details better than I do. I apologize for the length and complexity of this question, but I made it as short and as simple as I know how to. The gist of this question is that I don't know nearly as much as I thought I did about pattern-matching and attributes. Perhaps after I learn more from you-all, a much simpler form of the essential question --- hiding in here somewhere I hope --- will emerge.




Comments

Popular posts from this blog

plotting - How to draw lines between specified dots on ListPlot?

I would like to create a plot where I have unconnected dots and some connected. So far, I have figured out how to draw the dots. My code is the following: ListPlot[{{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4,13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full] I have thought using ListLinePlot command, but I don't know how to specify to the command to draw only selected lines between the dots. Do have any suggestions/hints on how to do that? Thank you. Answer One possibility would be to use Epilog with Line : ListPlot[ {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4, 13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full, Epilog -> { Line[ ...

equation solving - Invert and fit implicitly defined curve

I need to fit an implicitly defined curve. I thought I could get some data out of Solve , and then using FindFit . Therefore, I would like to find the relation the parametric curve defined by $F(x,y)=0$: Solve[-(1/2) + 1/2 (0.41202 BesselK[0, 0.1 Sqrt[x^2 + y^2]] + (0.101483 x BesselK[1, 0.1 Sqrt[x^2 + y^2]])/Sqrt[x^2 + y^2]) == 0, y] But I can't get an output: Solve was unable to solve the system with inexact coefficients or the system obtained by direct rationalization of inexact numbers present in the system. Since many of the methods used by Solve require exact input, providing Solve with an exact version of the system may help. >> Edit: In particular, I would like to fit the data coming from the curve with the expression of another curve, and not with a function $f(x)$. In particular, since this clearly looks like a cardioid , I would like it to fit to something like it. What other strategies could I try?

dynamic - How can I make a clickable ArrayPlot that returns input?

I would like to create a dynamic ArrayPlot so that the rectangles, when clicked, provide the input. Can I use ArrayPlot for this? Or is there something else I should have to use? Answer ArrayPlot is much more than just a simple array like Grid : it represents a ranged 2D dataset, and its visualization can be finetuned by options like DataReversed and DataRange . These features make it quite complicated to reproduce the same layout and order with Grid . Here I offer AnnotatedArrayPlot which comes in handy when your dataset is more than just a flat 2D array. The dynamic interface allows highlighting individual cells and possibly interacting with them. AnnotatedArrayPlot works the same way as ArrayPlot and accepts the same options plus Enabled , HighlightCoordinates , HighlightStyle and HighlightElementFunction . data = {{Missing["HasSomeMoreData"], GrayLevel[ 1], {RGBColor[0, 1, 1], RGBColor[0, 0, 1], GrayLevel[1]}, RGBColor[0, 1, 0]}, {GrayLevel[0], GrayLevel...