2
$\begingroup$

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.

$\endgroup$
  • 2
    $\begingroup$ Use the level specs to include level 0 : Cases[expr, (any0_. Exp[any1_. c + any2_.]), {0, Infinity}]? $\endgroup$ – kglr Jul 19 '17 at 22:07
  • $\begingroup$ @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 $\endgroup$ – Nasser Jul 19 '17 at 22:10
  • $\begingroup$ Cases[expr, (any0_. Exp[any1_. c + any2_.]), {0}] gives a single hit. $\endgroup$ – kglr Jul 19 '17 at 22:13
  • $\begingroup$ @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. $\endgroup$ – Nasser Jul 19 '17 at 22:15
  • $\begingroup$ 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). $\endgroup$ – kglr Jul 19 '17 at 22:33
5
$\begingroup$

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)}}

$\endgroup$
  • $\begingroup$ 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. $\endgroup$ – Nasser Jul 21 '17 at 5:21
  • $\begingroup$ 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 + _.]]? $\endgroup$ – Carl Woll Jul 21 '17 at 5:28
  • $\begingroup$ Thanks, getPatterns[expr, x_. Exp[_. c + _.] /; FreeQ[x, E]] seems to work! Will test more now. Pattern matching is too hard. $\endgroup$ – Nasser Jul 21 '17 at 5:31
2
$\begingroup$

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)}

$\endgroup$
1
$\begingroup$

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.

$\endgroup$
  • $\begingroup$ Thanks, but please see comment above. This returns 2 hits for 4 Exp[c + y] when I only expect one !Mathematica graphics $\endgroup$ – Nasser Jul 19 '17 at 22:13
  • $\begingroup$ 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. $\endgroup$ – Nasser Jul 19 '17 at 22:31
  • $\begingroup$ +1 thanks for information about level. But I am hoping for general method that works for all cases. Will keep trying :) $\endgroup$ – Nasser Jul 19 '17 at 22:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.