Skip to main content

expression manipulation - Pattern matching a pattern with patterns


Confusing title, I know. But the question is, if we have two patterns which have the same general structure but different names used in the patterns and different names:


 a = HoldPattern[f[x_, y_, g_, h_]] :> g[x] + h[y];
b = HoldPattern[g[y_, z_, m_, l_]] :> m[y] + l[z];

And I would like to be able to define a pattern for these two pattens, letting {f,x,y,g,h} take arbitrary values. How would I go about this?


To clearify. If I had a=4;b=5. I could define a common pattern through: _Integer and get MatchQ[a,_Integer](*=>True*) and MatchQ[b,_Integer](*=>True*).


But for my above two patterns, I cannot simply base my pattenr on a and substitute out {f,x,y,g,h} with _ eg:


badpattern = HoldPattern[f_[Pattern[x_,_], Pattern[y_,_],
Pattern[g_,_], Pattern[h_,_]]] :> h_[x_] + h_[y_];


I should not that what I want as a result is a working pattern not just a method that accomplishes this. Why? Well because the I would have to reimpliment MatchQ, Cases, Position and so forth for everything that expects a pattern as it's input to still work. The code below accomplishes this, however in an ad-hoc fasion.


This is wrong since the result does not distinguish between structural Blanks, and pattern blanks.


My initial code
Just to get a pattern to match to itself I need to get rid of HoldPattern which I do as:


MatchQ[a, a /. HoldPattern -> hp_ /; hp === HoldPattern]
(* True *)

Of cause I could just use Verbatim however then I won't be able to do the next part. Where I extend the same type of pattern of switching out pattern components such as HoldPattern.


To check b against a pattern based on a, I switch out a collection of heads inject new patterns and condition the pattern on the switched out heads:



myPatternPatternA=(a/.{HoldPattern->hp_,Pattern->p_,Blank->b_,RuleDelayed->rd_}
/.{f->f_,x-> x_,y-> y_,g-> g_,h-> h_ }
)/;And[hp===HoldPattern,p===Pattern,b===Blank,rd===RuleDelayed];

MatchQ[b,myPatternPatternA]
(* True *)

Note that I'm just using a as a template of the new pattern I construct, in the new pattern {f,x,y,g,h} can all take arbitrary values since I'm injecting a new pattern for them after removing {HoldPattern,Pattern,Blank,RuleDelayed}.


It seems however that I'll occasionally have problems with other symbols, which means I need to extend the list for instance to include Set and SetDelayed, however only when they actually appear in the expression, since otherwise the check fails. As such it feels like a rather cumbersome method. So I'm wondering if others have dealt with such cases and how they have carried this out.


Update



I should add that I'm relying on the matching to return values aswell, eg:


myPatternPattern = (a/.{HoldPattern->hp_,Pattern->p_,Blank->b_,RuleDelayed->rd_}
/.{f->f_,x-> x_,y-> y_,g-> g_,h-> h_ }
)/;And[hp===HoldPattern,p===Pattern,b===Blank,rd===RuleDelayed]:>f;

Cases[{a,b},myPatternPattern]
(*{f,g}*)

Mr. Wizard inquired as to what exactly I mean by the two definitions having the same structure. So I'll clarify. If we have two different expressions: f[3,4] and g[2,5] and I wanted to describe their structure, then I could write name_[_Integer,_Integer] as one possible common structure. When I have two patterns this approach breaks down for obvious reasons, Consider; _[varA_] and _[varB_]. I would like to define a "pattern^2" that matches both of these patterns and assigns varA or varB to a name, so I just follow the same recipe as before and substitute varA in the first with name_ and get: `_[_name_]. This obviously fails. So what I have above is a way to define a pattern for patterns such that I can match elements inside them. Confusing, I know.



Answer




From a short discussion in Chat I think this question is going in a different direction. It may be a duplicate of How to match a pattern with a pattern? but perhaps more complicated than the examples there.


To illustrate how a pattern can be fully broken down:


a = HoldPattern[g[x_, y_, _, {1, 2}, q : {g_, h_}]] :> g[x] + h[y];

meta =
Replace[
HoldPattern @@ {a},
{Pattern -> Verbatim[Pattern], Blank -> Verbatim[Blank], HoldPattern -> Verbatim[HoldPattern]},
{2, -1},
Heads -> True

];

MatchQ[a, meta]


True



HoldPattern @@ {a} and {2, -1} is used to keep an outer HoldPattern around the entire thing to prevent any unintentional evaluations.


Every part of meta can be tagged with patterns and used as normal.





Since it doesn't make sense to me to assert that f and g literals are similar I shall ignore that for now. Consider this:


fill[pat_] := Range@Length@# /. # -> Extract[pat, 2, Hold] & @ 
Cases[pat[[1]], Quiet[Verbatim[Pattern][name_, _] :> name_], -1];

similar[a_, b_] := And[
SameQ @@ ({a, b}[[All, 1]] //. Verbatim[Pattern][_, x_] :> x),
SameQ @@ fill /@ {a, b}
]

Now:



a = HoldPattern[f[x_, y_, g_, h_]] :> g[x] + h[y];
b = HoldPattern[f[y_, z_, m_, l_]] :> m[y] + l[z];

similar[a, b]


True



Comments

Popular posts from this blog

plotting - Plot 4D data with color as 4th dimension

I have a list of 4D data (x position, y position, amplitude, wavelength). I want to plot x, y, and amplitude on a 3D plot and have the color of the points correspond to the wavelength. I have seen many examples using functions to define color but my wavelength cannot be expressed by an analytic function. Is there a simple way to do this? Answer Here a another possible way to visualize 4D data: data = Flatten[Table[{x, y, x^2 + y^2, Sin[x - y]}, {x, -Pi, Pi,Pi/10}, {y,-Pi,Pi, Pi/10}], 1]; You can use the function Point along with VertexColors . Now the points are places using the first three elements and the color is determined by the fourth. In this case I used Hue, but you can use whatever you prefer. Graphics3D[ Point[data[[All, 1 ;; 3]], VertexColors -> Hue /@ data[[All, 4]]], Axes -> True, BoxRatios -> {1, 1, 1/GoldenRatio}]

plotting - Filling between two spheres in SphericalPlot3D

Manipulate[ SphericalPlot3D[{1, 2 - n}, {θ, 0, Pi}, {ϕ, 0, 1.5 Pi}, Mesh -> None, PlotPoints -> 15, PlotRange -> {-2.2, 2.2}], {n, 0, 1}] I cant' seem to be able to make a filling between two spheres. I've already tried the obvious Filling -> {1 -> {2}} but Mathematica doesn't seem to like that option. Is there any easy way around this or ... Answer There is no built-in filling in SphericalPlot3D . One option is to use ParametricPlot3D to draw the surfaces between the two shells: Manipulate[ Show[SphericalPlot3D[{1, 2 - n}, {θ, 0, Pi}, {ϕ, 0, 1.5 Pi}, PlotPoints -> 15, PlotRange -> {-2.2, 2.2}], ParametricPlot3D[{ r {Sin[t] Cos[1.5 Pi], Sin[t] Sin[1.5 Pi], Cos[t]}, r {Sin[t] Cos[0 Pi], Sin[t] Sin[0 Pi], Cos[t]}}, {r, 1, 2 - n}, {t, 0, Pi}, PlotStyle -> Yellow, Mesh -> {2, 15}]], {n, 0, 1}]

plotting - Mathematica: 3D plot based on combined 2D graphs

I have several sigmoidal fits to 3 different datasets, with mean fit predictions plus the 95% confidence limits (not symmetrical around the mean) and the actual data. I would now like to show these different 2D plots projected in 3D as in but then using proper perspective. In the link here they give some solutions to combine the plots using isometric perspective, but I would like to use proper 3 point perspective. Any thoughts? Also any way to show the mean points per time point for each series plus or minus the standard error on the mean would be cool too, either using points+vertical bars, or using spheres plus tubes. Below are some test data and the fit function I am using. Note that I am working on a logit(proportion) scale and that the final vertical scale is Log10(percentage). (* some test data *) data = Table[Null, {i, 4}]; data[[1]] = {{1, -5.8}, {2, -5.4}, {3, -0.8}, {4, -0.2}, {5, 4.6}, {1, -6.4}, {2, -5.6}, {3, -0.7}, {4, 0.04}, {5, 1.0}, {1, -6.8}, {2, -4.7}, {3, -1....