4

Let's say we want a pattern, that matches, when expression contains some terms but it can optionaly contain some other terms. For example:

Cases[
{-x^2 + Log@x + Sin@x, 3.14 x^2 + Log@x, x^2, x^2 + Tan@x},

(((?NumericQ)x^2|x^2) + Log@x + Sin@x)| (((?NumericQ)x^2|x^2) + Log@x)| (((?NumericQ)x^2|x^2) + Sin@x)| (((?NumericQ)x^2|x^2)) ]

Out:

{-x^2 + Log[x] + Sin[x], 3.14 x^2 + Log[x], x^2}

In this example expression has to contain $a x^2$, but it can also contain $\sin(x)$ and $\ln(x)$. In my real example, I have $6$ optional terms, meaning, I would have to write $2^6=64$ versions.

Instead I would like to do something like this, where NothingP woluld be equivalent of Nothing for patterns:

Cases[
{-x^2 + Log@x + Sin@x, 3.14 x^2 + Log@x, x^2, x^2 + Tan@x},
(((_?NumericQ)x^2|x^2) + (Log@x|NothingP) + (Sin@x|NothingP))
]

So is there such a command/ another way to do it? I can't find it in a documentation.

Also a side question: is there a short form of ((_?NumericQ)x^2|x^2) ?

GalZoidberg
  • 511
  • 2
  • 9
  • 1
    For the short form of ((_?NumericQ)x^2|x^2) there is _.x^2. Basically _.*expression means that the expression is multiplied by something or 1. Also _.+expression means expression plus something or 0. You can check OneIdentity and Default for more details. – userrandrand Sep 16 '22 at 12:48
  • 1
    Correcting my deleted comment: I am not sure how general or abstract you would like the solution to be but in the case you gave you could use the pattern Alternatives[_.*x^2 + __?(MemberQ[{Log[x], Sin[x]}, #] &), x^2] (Notice the double blank) – userrandrand Sep 16 '22 at 13:12
  • Thanks, that is exactly what I Needed. Alternatives[.x^2 + __?(MemberQ[{Log[x], Sin[x]}, #] &), x^2] works. But how to use the _.+ expression? _.x^2 +. Log[x]_.+Sin[x] doesn't work. – GalZoidberg Sep 16 '22 at 13:19
  • Hi sorry I am not sure what the "." in your expressions meant. For example ". Log". Maybe it is due to the processing of Stack Exchange comments. It might help if you surround your command with (not ' the used when using packages in Mathematica with Needs) – userrandrand Sep 16 '22 at 13:28
  • Ok, I can't edit the comment, but I meant to ask, how to use _.+expression, that you mentioned. How to use it in this example. – GalZoidberg Sep 16 '22 at 13:45
  • 1
    Like for example Cases[{r, s, n + r} , _. + r]. – userrandrand Sep 16 '22 at 14:00
  • I had never used this before but using the answer I found here it seems that you can avoid the Alternatives in my previous comment by using the pattern (in the pattern that follows b is just a name that can be replaced with another symbol) _.*x^2 + b : (__?(MemberQ[{Log[x], Sin[x]}, #] &)) : 0 – userrandrand Sep 16 '22 at 14:02
  • 1
    Thank you for accepting my answer but it could be better to wait a day or two until someone finds an answer to your original question, meaning to find a pattern object that acts like Nothing – userrandrand Sep 16 '22 at 14:16
  • After reading kirma's answer I saw that I should have included the NumericQ restriction on the coefficient of x^2 as _.x^2 matches with anything that multiplies x^2. Kirma's answer gives a solution to that. Another possibility is to use (g : _?NumericQ : 0)x^2 where "g" can be exchanged with another name. – userrandrand Sep 16 '22 at 19:26

2 Answers2

5

You could use Repeated[..., {0,1}] to match elements which may appear zero or one times, but there's even better option in this case, that is, Optional.

Cases[{-x^2 + Log@x + Sin@x, 3.14 x^2 + Log@x, x^2, x^2 + Tan@x},
 (a_. x^2 /; NumericQ[a]) + Optional[sin : Sin[x], 0] + 
  Optional[log : Log[x], 0]]

(* {-x^2 + Log[x] + Sin[x], 3.14 x^2 + Log[x], x^2} *)

This way you don't need to special-case the form for x^2. I'm not entirely certain I find the explicit description of interaction of Optional, Default and OneIdentity for Plus (which is of course 0) in the documentation, but nonetheless, this works.

This syntax, with unnecessary pattern name is a bit odd, in my opinion. It can be also written as:

Cases[{-x^2 + Log@x + Sin@x, 3.14 x^2 + Log@x, x^2, x^2 + Tan@x},
 (a_. x^2 /; NumericQ[a]) + (sin : Sin[x] : 0) + (log : Log[x] : 0)]

Technically, what you refer as NothingP is PatternSequence[]. The problem with this form is that it doesn't have a default value, and thus doesn't interact very gracefully with Plus in this case.

kirma
  • 19,056
  • 1
  • 51
  • 93
3

The comment section got a bit long and as it would be tedious for someone else to read through the comments I moved my last comment, that only solves this specific situation, to an answer.

I had never used this kind of pattern matching before but using the answer I found here, it seems that, for the specific problem at hand, instead of using a pattern that has the properties of Nothing you can use the code below (in the pattern that follows b is just a name that can be replaced with another symbol)

 _.*x^2 + b : (__?(MemberQ[{Log[x], Sin[x]}, #] &)) : 0

Example:

    Cases[{-x^2 + Log@x + Sin@x, 3.14 x^2 + Log@x, x^2, 
  x^2 + Tan@x}, _.*x^2 + 
  b : (__?(MemberQ[{Log[x], Sin[x]}, #] &)) : 0]

Output: (* {-x^2 + Log[x] + Sin[x], 3.14 x^2 + Log[x], x^2} *)

userrandrand
  • 5,847
  • 6
  • 33
  • I noticed after @kirma's answer that I should have included a NumericQ restriction. Using the syntax above one could replace _.x^2 with (g : _?NumericQ : 0)x^2 where g can be exchanged with another name. – userrandrand Sep 16 '22 at 19:28