4
$\begingroup$

Below is a function intended to test if an expression is a polynomial in which all the coefficients and exponents are integers:

intPolyQ[Optional[_Integer] + 
Plus[Optional[_Integer] x_Symbol^Optional[_Integer] ...], x_] := True;
intPolyQ[___] := False;

It gives unexpected results in some cases. For example,

intPolyQ[#, x] & /@ {x, 2 x, 2 x + 1, 2 x^2 + 3 x, 2 x^2 + 3 x + 1}

gives

{True, True, True, False, True}

which is wrong in the 4th case.

Why does this happen? How do I fix it?

$\endgroup$
4
$\begingroup$

Don't quite understand why, but one needs both patterns (Jens' and ywdr1987's) to get True for all the expressions in the example. This can be done using Alternatives or adding an additional definition to cover the pattern in Jens's answer:

ClearAll[intPolyQa];
intPolyQa[HoldPattern[Optional[_Integer] + Plus[Optional[_Integer]
  x_Symbol^Optional[_Integer] ...]],  x_] := True; 
intPolyQa[Optional[_Integer] + Plus[Optional[_Integer] 
  x_Symbol^Optional[_Integer] ...],  x_] := True;
intPolyQa[___] := False;
intPolyQa[#, x] & /@ {x, 2 x, 2 x + 1, 2 x^2 + 3 x, 2 x^2 + 3 x + 1}
(* {True, True, True, True, True}  *)

or

 ClearAll[intPolyQb];
 intPolyQb[Alternatives[HoldPattern[Optional[_Integer] + 
  Plus[Optional[_Integer] x_Symbol^Optional[_Integer] ...]], 
  Optional[_Integer] + Plus[Optional[_Integer]
      x_Symbol^Optional[_Integer] ...]], x_] :=  True;
 intPolyQb[___] := False;
 intPolyQb[#, x] & /@ {x, 2 x, 2 x + 1, 2 x^2 + 3 x, 2 x^2 + 3 x + 1}
 (* {True, True, True, True, True} *)
$\endgroup$
  • $\begingroup$ You're right (+1). $\endgroup$ – Jens Dec 10 '12 at 15:23
10
$\begingroup$

The problem isn't with Optional but with the fact that Plus will evaluate pattern sequences as in _ + _ to get unpleasant results like 2 _. In your pattern, you can prevent this by simply wrapping everything in HoldPattern:

intPolyQ[HoldPattern[
    Optional[_Integer] + 
     Plus[Optional[_Integer] x_Symbol^Optional[_Integer] ...]], x_] :=
   True;
intPolyQ[___] := False;

With this, the function seems to work fine if you also retain your old definitions as @kguler observed:

intPolyQ[#, x] & /@ {x, 2 x, 2 x + 1, 2 x^2 + 3 x, 2 x^2 + 3 x + 1}

(* ==> {True, True, True, True, True} *)

Of course there is also an easier way to test for integer polynomials - let's call the polynomial poly, then you could just do

And @@ IntegerQ /@ CoefficientList[poly]
$\endgroup$
  • 1
    $\begingroup$ With your definition of intPolyQ, it turns out that intPolyQ[#, x] & /@ {x, 2 x, 2 x + 1, 2 x^2 + 3 x, 2 x^2 + 3 x + 1} returns {False, False, False, True, False} in my computer! What's wrong!? @Jens $\endgroup$ – ywdr1987 Dec 10 '12 at 11:24
  • $\begingroup$ MatchQ[list, {__Integer}] is much faster than And @@ IntegerQ /@ list to check for a list of Integers. @ywdr1987 CoefficientList[#, x] ~MatchQ~ {__Integer} & /@ {x, 2 x, 2 x + 1, 2 x^2 + 3 x, 2 x^2 + 3 x + 1} returns {True, True, True, True, True} here. $\endgroup$ – Mr.Wizard Dec 10 '12 at 13:45
  • $\begingroup$ Oh yes, you need both patterns as @kguler observed. I got True everywhere because I must have not exectuted the Clear so I did have both your and my definitions. $\endgroup$ – Jens Dec 10 '12 at 15:21

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.