6
$\begingroup$

While checking out the different pattern replacement methods in this question, I have a query regarding the basic difference between the following two replacements:

 expr = a x^3 + b x y - c x^7 y^2;
 expr /. {x^m_Integer :> x^Mod[m, 2]}
 expr /. {x^m_?Integer :> x^Mod[m, 2]}

The first replacement works as expected, but the second replacement does not do anything. What is happening in the second one. Also, another code to effect the desired replacement is

expr /. {x^_?EvenQ -> 1, x^_?OddQ -> x}

which contains "?" after an underscore.

Any help to solve this confusion will be appreciated.

$\endgroup$
6
  • 3
    $\begingroup$ you can use expr /. {x^m_?IntegerQ :> x^Mod[m, 2]} $\endgroup$
    – kglr
    May 12 '19 at 10:01
  • $\begingroup$ see tutorial/PuttingConstraintsOnPatterns $\endgroup$
    – kglr
    May 12 '19 at 10:11
  • $\begingroup$ @kglr Thanks for the solution and the link. Could you kindly illustrate the difference between _Integer and _?IntegerQ ? Another one is "_Integer?" mentioned in the following link discussing partly my doubts. mathematica.stackexchange.com/questions/9356/… $\endgroup$ May 12 '19 at 10:25
  • 2
    $\begingroup$ If you use the _?func pattern then func can be any function at all. Any function you can think of. _head is a shorthand for the pattern head[___]. A pattern that doesn't involve arbitrary black box functions can be optimized in ways that it couldn't if it had to evaluate arbitrary functions on each possible match. Don't use _?func unless you have to. $\endgroup$
    – C. E.
    May 12 '19 at 10:51
  • $\begingroup$ m_?Integer is incorrect. Did you mean IntegerQ? $\endgroup$
    – Szabolcs
    May 12 '19 at 11:05
14
$\begingroup$

See PatternTest.

x_?test matches if test[x] is True. It is equivalent to x_ /; test[x] (see Condition).

x_symbol matches if Head[x] is symbol.

m_?Integer makes no sense because Integer is not a function that returns True or False. m_?IntegerQ is valid and works. See Integer and IntegerQ.

_Integer and _?IntegerQ are very similar, but there are some important differences:

_Integer is faster than _?IntegerQ:

list = Developer`FromPackedArray@RandomInteger[1000, 1000000];

fun1[_Integer] := "x";
fun2[_?IntegerQ] := "x";

fun1 /@ list; // Timing
(* {0.23702, Null} *)

fun2 /@ list; // Timing
(* {0.376331, Null} *)

But _Integer also matches expressions which are not really integers, such as Integer["abc"].

The same applies to other, similarly named functions as well.

_?GraphQ and _Graph are not the same. _?AssociationQ and _Association are not the same. This is because there are expressions with the head Association that are not atomic associations.

expr = Association[123]
(* Association[123] *)

MatchQ[expr, _Association]
(* True *)

MatchQ[expr, _?AssociationQ]
(* False *)

In these cases, one usually needs the pattern _?AssociationQ. Then the expression will work with functions like Lookup, KeyTake, etc.

There is even use for _Association?AssociationQ. This pattern is faster to reject non-associations than _?AssociationQ, but it is otherwise functionally equivalent.

$\endgroup$
5
  • $\begingroup$ Are _?EvenQ and _Even equivalent? The code expr /. {x^_Even -> 1, x^_Odd -> x} does not work. $\endgroup$ May 12 '19 at 14:12
  • 4
    $\begingroup$ @MarkRobinson I don't follow your thinking ... as I said, _Even matches expressions with the head Even. That symbol has no built-in meaning. Why would you even try to use it? Why do you think it has any connection to EvenQ? If something was not clear in my explanation, please ask. $\endgroup$
    – Szabolcs
    May 12 '19 at 14:30
  • $\begingroup$ It might be worth noting that _Integer and _?IntegerQ are not fully equivalent - e.g. for Integer["a"], only the former matches. While this is admittedly a rather contrived example, I encountered this issue a few times with Symbol[…] (I was using _Symbol to get all symbols in the expression, which failed due to the above) $\endgroup$
    – Lukas Lang
    May 12 '19 at 17:21
  • $\begingroup$ @LukasLang Thanks! You're right, it's the same situation as with Association. $\endgroup$
    – Szabolcs
    May 12 '19 at 17:26
  • $\begingroup$ @Szabolcs Thanks for the clearly explained and to the point answer and illustrating the equivalence with condition. I now understand it to a good extent. $\endgroup$ May 13 '19 at 4:21

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