Skip to main content

pattern matching - Successful match in Replace but not in Cases?


I have a little example that exhibits a successful pattern match in ReplaceAll that Cases misses and I wonder if the assembled sages would be so kind as to offer me an explanation?


This is chopped from an original Prolog emulator by Renan Cabrera circa 2000.


ClearAll[k,s,l,m,j,f,w,g,a,b]

Consider an unordered sequence of statements s stored in a knowledge base k, each being a predicate l about some terms m, f, j, and w:


k=s[l[m,f],
l[m,w],
l[j,w],

l[j,m]
];

We wish to search this knowledge base for any predicates such that l[m,X_] and l[j,X_], where X_ matches the same term in both predicates. Our first cut is something like


k /. s[l[m,X_],l[j,X_]] -> a[X]
(* Out[42]:= s[l[m,f],l[m,w],l[j,w],l[j,m]] *)

but this doesn't work until we make s flat and orderless (associative and commutative):


SetAttributes[s,{Flat,Orderless}]


and now


k /. s[l[m,X_],l[j,X_]] -> a[X]
(* Out[43]:= s[a[w],l[j,m],l[m,f]] *)

This is, of course, just the same as ReplaceAll[k, s[l[m,X_],l[j,X_]] -> a[X]]. (notice the canonical reordering in the output), and now I can extract my answer with something like


Cases[k /. s[ l[m, X_], l[j, X_] ]->a[X],a[Y_]->Y]
(* Out[44]:= {w} *)

The surprise and the question is why doesn't this work?


Cases[k, s[ l[m, X_], l[j, X_] ] -> a[X]]

(* Out[45]:= {} *)

or even this


MatchQ[k, s[ l[m, X_], l[j, X_] ]]
(* Out[46]:= False *)

It's as though ReplaceAll, Cases, and MatchQ are using different pattern matchers.


Will be grateful for advice, clues, discussion, etc.



Answer



MatchQ looks to see if the whole expression matches the pattern, so you need to add a blank to allow for the other elements of s:



MatchQ[k, s[l[m, X_], l[j, X_], ___]]

Cases takes a list and checks each element in turn, so I think the pattern matcher only gets to see each l[a,b] in isolation. The best I could come up with is:


Cases[Subsets[k, {2}], s[l[m, X_], l[j, X_]] -> a[X]]

Further investigation


Here are a couple of questions about Cases I have tried to answer experimentally. I don't know if this helps anyone else much, but it was useful for me to go through it and I think I now understand how Cases behaves, even if the why is a mystery.


Q1. Does Cases take into account Orderless ?


In[1]:= SetAttributes[a,{Orderless}]
In[2]:= Cases[a[x,y],a[y,_]->0,{0}]

Out[2]= {0}

A1. Yes, it does. The pattern matcher understands that a[x,y] === a[y,x] which matches the pattern.


Q2. Does Cases take into account Flat ?


In[3]:= SetAttributes[a,{Flat}]
In[4]:= Cases[a[x,y,z],a[onebit_,anotherbit_]:>{onebit+anotherbit},{0}]
Out[4]= {{a[x]+a[y,z]}}

A2. Yes, it does. The pattern matcher understands that a[x,y,z] === a[a[x],a[y,z]] which matches the pattern.


Q3. Given that Cases can use the above transformation, will it get a "hit" on the pattern a[x] ?



In[5]:= Cases[a[x,y,z],a[x]->b,{0,Infinity}]
Out[5]= {}

A3. No, even though the transformed expression a[a[x],a[y,z]] clearly contains a match for a[x] at level 1, this doesn't count. Cases appears to require the entire expression at level n to match the pattern. The logic appears to be:



  • Level 0: expression a[x,y,x] does not match a[x]

  • Level 0: transformed expression a[a[x],a[y,z]] does not match a[x]

  • Level 1: expression x does not match a[x]

  • Level 1: expression y does not match a[x]



etc...


This is in contrast to ReplaceAll, which does pick up the a[x] in the transformed expression:


In[6]:= a[x,y,z]/.a[x]->b
Out[6]= a[b,y,z]

So it seems like ReplaceAll applies Flat and Orderless transformations outermost, and then for each transformed expression it digs down into the subexpressions looking for a match. Whereas Cases digs down into the subexpressions of the untransformed original expression outermost, and for each subexpression it tries the various Flat and Orderless transformations looking for a match.


I realise this is probably a complete misrepresentation of how the pattern matcher actually works, but as a hand-waving mental picture it seems to explain the different behaviour of Cases and ReplaceAll


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...