# Given a symbolic expression how to find if starts with a minus or not?

I am using a Mathematica function which returns some error term in symbolic form. I needed a way to determine if this term starts with a minus sign or not. There will be only one term. This is to avoid having to worry about Mathematica auto arranging terms like x-h to become -h+x and hence it is not fair to ask for more than one term solution.

Here are some examples of the expressions, all in input form

negativeTruetests = {(-(71/12))*h^2*Derivative[f],
(-1)*h^2*Derivative[f],
(-(359/3))*h^2*Derivative[f], -2*h, -x*h^-2, -1/h*x }

negativeFalseTests = { h^2*Derivative[f] , h^2*Derivative[f],
33*h^2*Derivative[f], h^-2, 1/h}


I need a pattern to check if the expression starts with minus sign or not. • Does only the sign of the highest-order term of h count for your decision? Aug 22, 2013 at 14:53
• Only ONE term, and hence, the term, if it has a minus sign, it will have to be the first thing (looking at it, not in tree form). So, only ONE term. Hence -h-f will not show up. Only (- h) * derivative(something) or h*derivative or number*h*derivative etc.... Aug 22, 2013 at 14:58

I will use your test lists alone as reference. If they are incomplete you will need to update the question.

When looking for a pattern for a group of expressions it is helpful to look at their TreeForm:

TreeForm /@ {negativeTruetests (*sic*), negativeFalseTests} // Column  You see that your True expressions always have the head Times with one negative leaf, be it -1, -2 or a Rational that is negative. Your False expressions either have head Times or Power but in the case of Times they do not have a negative leaf. Therefore for these expressions you may use:

p = _. _?Negative;

MatchQ[#, p] & /@ negativeTruetests
MatchQ[#, p] & /@ negativeFalseTests


{True, True, True, True, True, True}

{False, False, False, False, False}

Because of the Optional and OneIdentity(1) this pattern will also handle a negative singlet:

MatchQ[#, p] & /@ {-Pi, 7/22}


{True, False}

## Format-level pattern matching

Since it was revealed that this question relates to formatting it may be more appropriate to perform the test in that domain.

I will use a recursive pattern as I did for How to match expressions with a repeating pattern after converting to boxes with ToBoxes:

test = MatchQ[#, RowBox[{"-" | _?#0, __}]] & @ ToBoxes @ # &;

test /@ negativeTruetests
test /@ negativeFalseTests


{True, True, True, True, True, True}

{False, False, False, False, False}

Another approach is to convert to a StandardForm string and use StringMatchQ, which is essentially the same as the test above because StandardForm uses encoded Boxes:

test2 = StringMatchQ[ToString[#, StandardForm], ("\!" | "\(") ... ~~ "-" ~~ __] &;

test2 /@ negativeTruetests
test2 /@ negativeFalseTests


{True, True, True, True, True, True}

{False, False, False, False, False}

You can do it the way a human does it: Look for the "-" in the string.

#==1&/@StringCount[ToString/@InputForm/@negativeTruetests,Alternatives["-",Repeated["("]~~"-"]]

{True,True,True}

#==1&/@StringCount[ToString/@InputForm/@negativeFalseTests,Alternatives["-",Repeated["("]~~"-"]]

{False,False,False}


There are probably many creative ways to break this one horribly, but for the test cases it works:

(# /. Thread[Variables[#] -> 1]) < 0 & /@ negativeTruetests


(* {True, True, True, True, True, True} *)

(# /. Thread[Variables[#] -> 1]) < 0 & /@ negativeFalseTests


(* {False, False, False, False, False} *)

• For additional historical information, look here. Aug 22, 2013 at 14:23
• You have a bug: expr = h^2*Derivative[f]- 2 h then (expr /. Thread[Variables[expr] -> 1]) < 0 it gives true. But it should be False ! I knew this was not as easy as it looked :) will add this to the tests Aug 22, 2013 at 14:39
• @Nasser Well, it was only designed for products... let´s see Aug 22, 2013 at 14:46
• I think it is ok. Adding terms is not fair. Since Mathematica will rearrange terms on its own. So x-h might end up as -h+x. So let just leave it at one term for now. I did not mean for this to become too hard. Aug 22, 2013 at 14:52

All of your examples are of the form Times[...], which case you can do this (on the original examples):

MemberQ[#, _?Negative] & /@ Flatten[{negativeFalseTests, negativeTruetests}]
(* {False, False, False, True, True, True} *)


or this

expr /. {Times[c_?NumericQ, ___] :> c < 0, _Times :> False}


but not this

MemberQ[#, _?Negative] & /@ {h^-2}
(* {True} *)


Edit

Here's a modification of the second method that works on powers, now with the updated examples:

# /. {Times[c_?NumericQ, ___] :> c < 0, _ :> False} & /@
Flatten[{negativeFalseTests, negativeTruetests}]
(* {False, False, False, False, False, True, True, True, True, True, True} *)

• Yes, the last case, h^-2 should NOT be negative. THere is only ONE term, all symbolic, but can start with a minus sign or not. Hence $h^{-2}$ should not be valid for saying it starts with minus sign. For example, MemberQ[#, _?Negative] & /@ {1/h} return TRUE, which is not right. Aug 22, 2013 at 15:17
• @Nasser I know that. I was asking whether that use-case is to be handled or not. I take it might arise and you would like a solution that includes it. Aug 22, 2013 at 15:19
• Sure. I know you knew that and were just checking on requirements. Will add it to the question to be more clear. thanks. Aug 22, 2013 at 15:21

This function

 checkMinus[expr_] :=
Select[expr /. Head[expr] -> List, # < 0 &] // Length


applied to your terms returns 1, if there is a minus in the expression with the structure you indicated, and 0 in the opposite case.

checkMinus[-((h^12 m')/24)]

(* 1  *)

checkMinus[(h^4 m')/12]

(* 0 *)


How about looking at the displayed boxes? Specifically, look for the first RowBox containing a string as its first element (as opposed to another box), and check to see if that string is a minus sign:

SetAttributes[isMinus, {HoldFirst}];
isMinus[expr_] := Cases[MakeBoxes[expr], RowBox[{s_String, ___}] :> s, {0, -1}, 1] == {"-"}

isMinus /@ negativeTruetests
(* {True, True, True} *)

isMinus /@ negativeFalseTests
(* {False, False, False} *)


isMinus doesn't evaluate its argument, so for example:

isMinus[h^2*Derivative[f] - 2 h]
(* False *)


The first term has no minus sign so the result is false. However, if Mathematica is allowed to evalute the argument it will rearrange the expression to put -2h at the beginning, so:

isMinus[Evaluate[h^2*Derivative[f] - 2 h]]
(* True *)


You can make use of the undocumented, internal function InternalSyntacticNegativeQ for this purpose (see this answer):

InternalSyntacticNegativeQ /@ negativeTruetests


{True, True, True, True, True, True}

InternalSyntacticNegativeQ /@ negativeFalseTests


{False, False, False, False, False}

  dummy = (1.0/1.0);
Negative[Extract[dummy*(#), 1]] & /@ negativeTruetests
(* {True, True, True} *)

Negative[Extract[dummy*(#), 1]] & /@ negativeFalseTests
{False, False, False}

• THat does not work? Negative[Extract[ h^2*Derivative[f], 1]] gives Negative[h^2] It has to work even if there is no number at the start of the expression. I'll add that as an example also. Aug 22, 2013 at 14:31
• Multiplying by that dummy seems to work.I know its ugly but it works right:). Aug 22, 2013 at 14:40
• Nope. Expression returned does not have a dummy. Have to use the expressions as shown. Can't modify them. These are returned from a function. Aug 22, 2013 at 14:44
• Why cant you do like Negative[Extract[dummy*(Last@FDFormula[]), 1]] Aug 22, 2013 at 14:50
• I tried you solution like this: Negative[Extract[dummy*negativeFalseTests, 1]]` and I get this: !Mathematica graphics Aug 22, 2013 at 15:04