2

I am back learning pattern matching in Mathematica, which I am not good at.

An input is a mathematica expression, and I need to simply get a list of all the sub-expressions inside this expression of the pattern (any0_. Exp[any1_. c + any2_.]) anywhere in the expression.

c above is the literal symbol. All others are patterns.

For example, the above pattern will match $e^{c +x}$ or $4 e^{5 c+ x}$ and so on. So I tried it and it works, except when the input expression contains a single Exp[...]

case 1, works

ClearAll[x,y,c]
expr=x y +4 Exp[c + y]+5 Sin[x]+Exp[c + x]
Cases[expr,(any0_. Exp[any1_. c + any2_.])]

Mathematica graphics

case 2, works

expr=x y +4 Exp[c + y]+5 Sin[x]
Cases[expr,(any0_. Exp[any1_. c + any2_.])]

Mathematica graphics

case 3, do not work

expr=4 Exp[c + y]
Cases[expr,(any0_. Exp[any1_. c + any2_.])]

Mathematica graphics

the 4 was dropped out in the above. And when there is a single Exp it does not work at all

case 4, do not work

expr=Exp[c + y]
Cases[expr,(any0_. Exp[any1_. c + any2_.])]

Mathematica graphics

I can handle these last two special cases by forcing the input to be a list

expr=Exp[c + y]
Cases[{expr},(any0_. Exp[any1_. c + any2_.])]

Mathematica graphics

But if I do the above, then the first two cases now fail. So I changed the test to be as follows

If[Head[expr] === Plus,
 Cases[expr, (any0_. Exp[any1_. c + any2_.])]
 ,
 Cases[{expr}, (any0_. Exp[any1_. c + any2_.])]
 ]

And now the above works for all of 4 cases. (But I am not sure if it will fail for some cases I have not thought about as I only check for Plus head)

My question is, is the above a correct way to do all of this, or is there a better and canonical way to handle this in Mathematica?

Update: Thanks to all the answers. But I also need it to work for division. As in this new case

case 5

 expr = Exp[c + x]/(3 + Exp[3*c + x]);

So in the above, it should find Exp[c + x] and Exp[3*c + x] separately. The whole idea, is that I want to rewrite any subexpression Exp[any1_*c + any2_] as c*Exp[any2]

I did say in the original question above anywhere in the expression but I did not put the above case in there and I was just now testing the answers given and noticed this problem.

Nasser
  • 143,286
  • 11
  • 154
  • 359
  • 2
    Use the level specs to include level 0 : Cases[expr, (any0_. Exp[any1_. c + any2_.]), {0, Infinity}]? – kglr Jul 19 '17 at 22:07
  • @kglr But your method will now return 2 hits for this: 4 Exp[c + y], it returned {E^(c+y),4 E^(c+y)} and I only wanted 4 E^(c+y) ? screen shot Mathematica graphics – Nasser Jul 19 '17 at 22:10
  • Cases[expr, (any0_. Exp[any1_. c + any2_.]), {0}] gives a single hit. – kglr Jul 19 '17 at 22:13
  • @kglr Sure, now it gives single hit on this case, but for case 1 it now returns empty list ! expr = x y + 4 Exp[c + y] + 5 Sin[x]; Cases[expr, (any0_. Exp[any1_. c + any2_.]), {0}] gives empty list. Mathematica graphics This is not as easy as it looks :) I need a method that works for all cases. – Nasser Jul 19 '17 at 22:15
  • Nasser, it does give an empty list as it should. For "a method that works for all cases", you need to decide and specify the levels you you are looking for a match: 4 Exp[c + y] will have two matches for levelspec {0,1}and one for levelspec 0. With your If[...] approach you are just adding one more level to input expr (hence default levelspec 1 kicks in). In general the pattern in the second argument, in addition to being inside an expression with any Head, can be at arbitrary depth (consider y + foo[bar[4 Exp[c=y]] for example). – kglr Jul 19 '17 at 22:33
  • @kglr But I do not know what the expression will look like. That is why I asked. I need a way to find all occurrences of (any0_. Exp[any1_. c + any2_.]) anywhere in the expression. This will be inside a black box function that user calls with an expression. You say I need to specify the level. But how? I do not know what the expression will be like. Are you saying in Mathematica it is not possible to write such a general pattern matching? – Nasser Jul 19 '17 at 22:43
  • Nasser, "to find all occurrences of " a pattern, anywhere in an expr, using Cases, afaik you need {0, Infinity} as the third argument of Cases. But this returns 2 hits for 4 Exp[c + y] and you only want 4 E^(c+y) although E^(c+y) is a perfectly legitimate occurrence of your pattern inside 4 Exp[c + y]. If you have a criterion in mind (that is totally different from what levelspecs can express) that determines why only 4 Exp[c + y] and not Exp[c + y] matches (any0_. Exp[any1_. c + any2_.]) in expr =4 Exp[c + y] , ... – kglr Jul 19 '17 at 22:58

3 Answers3

5

Instead of Cases, you can use ReplaceAll. ReplaceAll will not search inside of a part of the expression that it already replaced, unlike Cases which searches at every level specified. So:

getPatterns[expr_, pat_] := Last @ Reap[
    expr /. a:pat :> Sow[a],
    _,
    Sequence@@#2&
]

For your examples:

expr1=x y+4 Exp[c+y]+5 Sin[x]+Exp[c+x];
expr2=x y+4 Exp[c+y]+5 Sin[x];
expr3=4 Exp[c+y];
expr4=Exp[c+y];

getPatterns[#, _. Exp[_. c+_.]]& /@ {expr1, expr2, expr3, expr4}

{{E^(c + x), 4 E^(c + y)}, {4 E^(c + y)}, {4 E^(c + y)}, {E^(c + y)}}

Carl Woll
  • 130,679
  • 6
  • 243
  • 355
  • Thanks for the answer. I just found the above does not work for division? Here is an example: expr = Exp[c + x]/(3 + Exp[3*c + x]) getPatterns[expr, (_. Exp[_. c + _.])] and this does not find Exp[c + x] and Exp[3*c + x], but it returns the whole expression back. Is it hard to make your function find these patterns also in there is a division? I did not put this example in my question, but I said anywhere in the expression. :) and I was now just testing this answer. I should add this case now. Thanks. – Nasser Jul 21 '17 at 05:21
  • The whole expression does match the pattern, it is 1/(3 + Exp[3 c+x]) times Exp[c+x]. Perhaps something like getPatterns[expr, x_. Exp[_. c + _.] /; FreeQ[x, E]] or getPatterns[expr, _Integer Exp[_. c + _.]]? – Carl Woll Jul 21 '17 at 05:28
  • Thanks, getPatterns[expr, x_. Exp[_. c + _.] /; FreeQ[x, E]] seems to work! Will test more now. Pattern matching is too hard. – Nasser Jul 21 '17 at 05:31
2

Your problem seems to be basically a level specification problem. We can see what's going on by looking a much simpler case.

Cases[Exp[c + y], Exp[c + _]]

{}

Cases will accept expressions with any head, but it normally only looks at the elements at level 1 of the expression. Therefore, in this example, it only sees the argument c + y, which does not match the pattern, so it returns an empty list.

There are two work-arrounds.

The obvious one

Cases[{Exp[c + y]}, Exp[c + _]]

(now Exp[c + y] is at level 1) and the less obvious one

Cases[Exp[c + y], Exp[c + _], {0}]

(now Cases looks at level 0). They both return

{E^(c + y)}

m_goldberg
  • 107,779
  • 16
  • 103
  • 257
1

Update: Maybe something like this

ClearAll[caseS]
caseS = Module[{i = 0, res = {}}, While[i < Depth[#] &&
  (res = Cases[{#}, (any0_. Exp[any1_. c + any2_.]), i++])  === {}]; res] &;

expr1 = x y+ 4 Exp[c + y]+ 5 Sin[x] + Exp[c + x];
expr2 = x y+ 4 Exp[c + y]+ 5 Sin[x];
expr3 = 4 Exp[c + y];
expr4 = Exp[c + y];

caseS /@ {expr1, expr2, expr3, expr4}

{{E^(c + x), 4 E^(c + y)}, {4 E^(c + y)}, {4 E^(c + y)}, {E^(c + y)}}

caseS /@ {foo[expr1], {expr2}, {{{bar @@ {{expr3}}}}}, {{{expr4}}}}

{{E^(c + x), 4 E^(c + y)}, {4 E^(c + y)}, {4 E^(c + y)}, {E^(c + y)}}

Original answer:

expr = 4 Exp[c + y]
Cases[expr, (any0_.  Exp[any1_. c + any2_.]), {0, Infinity}]

{E^(c + y), 4 E^(c + y)}

Or get the matches in level 0 only:

Cases[expr, (any0_.  Exp[any1_. c + any2_.]), {0}]

{4 E^(c + y)}

expr = Exp[c + y]
Cases[expr, (any0_. Exp[any1_. c + any2_.]), {0, Infinity}]]

{E^(c + y)}

From Cases >> Details and options:

  • The default value for levelspec in Cases is {1}.

And 4 Exp[c + y] has two elements Level 1

Level[4 Exp[c + y], 1]

{4, E^(c + y)}

Only the second matches the pattern and is returned by Cases with default levelspec.

Similarly,

Level[Exp[c + y], 1]

{E, c + y}

none of which matches the pattern specified.

You need to include level 0 to force pattern matching to include the whole expression.

kglr
  • 394,356
  • 18
  • 477
  • 896
  • Thanks, but please see comment above. This returns 2 hits for 4 Exp[c + y] when I only expect one Mathematica graphics – Nasser Jul 19 '17 at 22:13
  • Using {0} does not work on case 1 Mathematica graphics and using {0, Infinity} gives two hits for 4 Exp[c + y] Mathematica graphics I am looking for one method that will work for all cases. But thanks for the input. – Nasser Jul 19 '17 at 22:31
  • +1 thanks for information about level. But I am hoping for general method that works for all cases. Will keep trying :) – Nasser Jul 19 '17 at 22:57