# How can I check whether a long rational expression contains a minus?

I have some monster expressions, but for simplicity, consider

m = -(-3 + a+3 b-5 c)/(-d -5);


How can I check if "undisplayable" expressions contain minuses? For m, I can use the eye to see it does, but what can I do for expressions that are too long to display?

This is in fact discussed in the question: In a long sum ... In a long sum, how can we find how many terms are preceded by the plus (or minus) sign

Count[m, _?InternalSyntacticNegativeQ]
Count[m, _?Negative*Optional[__]]


yield both wrongly 0 in this case. Maybe the answers in that question do not apply to rational expressions? My favorite answer was first, for simplicity, that of @ydd

Length[Cases[m, -_, Infinity]]


It catches 2 of the five minuses (probably because three minuses simplified). It's nice that the AI caught that, but I didn't ask for that, so I'm a bit puzzled. Unfortunately @Michael E2 found a counterexample

Length[Cases[3b-5c, -_ , Infinity]]


where this fails. I also found an example where the solution of @Roland F (the second for simplicity) does weird things

m = -(-3 + a + 3 b - 5 c)/(-2 - d - 5);
countMSp[m_] :=
Cases[HoldForm[m], #, \[Infinity]] & /@ {(x_?Negative + ___ :>
x), (_?Negative*___)}
countMSp[m]


({{-7}, {-a, -3 b, -d}})

• Length[Cases[m, -_ , Infinity]] > 0?
– ydd
Commented Aug 4 at 18:39
• @ydd That does not work if there is for example k[3]-2 in the expression. Commented Aug 4 at 19:15
• This question is similar to: In a long sum, how can we find how many terms are preceded by the plus (or minus) sign. If you believe it’s different, please edit the question, make it clear how it’s different and/or how the answers on that question are not helpful for your problem. Commented Aug 4 at 19:31
• If you only have one rational expression, test separately Denominator and Numerator for the presence of minuses. Commented Aug 4 at 20:20
• @florin, this whole discussion and your question is now getting messy. You are changing what you want, you keep adding some new test cases etc. Please take some time and decide what you actually want. Prepare a couple of test cases (expression) and write what the expected result should be. Also, try to understand how pattern matching works in Mathematica, and keep in mind that minuses in Mathematica expressions may occur at unexpected places by looking at the FullForm. Commented Aug 5 at 13:08

May as well join the melee...

Problem. Determine whether any of the coefficients of the polynomials in the numerator and denominator of a reduced rational function in which the denominator has a positive leading coefficient in the standard Mathematica order are negative.

This has the virtue of being a clear, well-defined problem. A rational function is the quotient of two polynomials. In reduced form they are unique up to a constant multiple; but the condition on the denominator makes their signs determinate. Together[] (it seems) puts a rational function into this standard form, which rules out all negative coefficients, such as (-a-b)/(-c-d), as a standard form.

While I am still not certain the exact statement of the OP's problem, I hope this clear statement makes it easy to determine whether this yields the desired solution.

A second point, I will use algebraic operations as opposed to syntactical operations. The problem as stated is algebraic, and I have found that algebraic operations are usually more robust and usually not too much slower. Here is a step-by-step code in functional form:

Block[
{m = -(-3 + a + 3 b - 5 c)/(-d - 5)}, (* input *)
m // Together // (* put polynomials in standard form *)
NumeratorDenominator // (* get polys *)
Map@CoefficientArrays // (* get coefficients of polys *)
ReplaceAll[sa_SparseArray :> sa["NonzeroValues"]] // (* get nonzero coeffs *)
Flatten // (* preconditioner for AllTrue *)
AllTrue[#, NonNegative] & (* has 0 if constant term is zero *)
]

(*  False  *)

• Thanks! Is the Block useful here? I was hoping to use this as a function which may be applied to lists in the style isPosOnly/@, yielding answer False, True, True, ...,and I'm having trouble "deblocking this" Commented Aug 5 at 17:42
• @florin Block[] keeps m from being set in my system, so I don't have to remember to clear it later. Further, in developing functions, I often use with Block[] in this way to set test values for the arguments. Sometimes the arguments change, and Block[] sandboxes the test calculations for me. Then, when everything works fine, I can replace the Block[{}, line with isPosOnlyQ[m_] := and delete the last ]. Then my function is done. Function development was my mindset here, in fact. I had to hurry away and posted, not really paying attention to the Block[] I left behind. Commented Aug 5 at 20:27
• The function obtained from the Block above yielded answers consistent with those in the literature, while the other methods proposed (which dealt with the harder problem of counting minuses) didn't. I'm going to stretch my luck and ask a new question to produce also a correct counting function. For the motivation, finding the domain where a family of polynomials is positive for positive arguments is important, for stability of matrices (Routh -Hurwitz), etc. The Hurwicz determinants may get quickly horrendous. But sometimes they contain no minuses, sometimes just 1, and this helps Commented Aug 6 at 7:40
• @florin If you replace AllTrue[#, NonNegative] & by Count[#, _?Negative] &, does it give the correct count of minus signs? Commented Aug 6 at 11:45
• the answer obtained was consistent with the logic answer (and it took only 12 minutes, double that for the logic one ). If you are interested in either stability problems, or in mathematical epidemiology or chemical reaction networks models, I would love to send you my paper which combines these, since your script will play an important role in a package I'm developping dedicated to these three topics Commented Aug 7 at 13:30

You first asked for something that checked if an expression contains minuses. Later you seem disappointed that all of the minuses weren't accounted for. Also, you don't seem satisfied with the semantic negative approach and instead want literal minuses in the input, but that would require interrupting evaluation. So, with all of that, I'd do the following, but I'm honestly not sure if this is what you're asking for.

SetAttributes[{CountMinusSigns, ContainsMinusSignQ}, HoldAll];
CountMinusSigns[expr_] := StringCount[ToString[InputForm[Hold[expr]]], "-"];
ContainsMinusSignQ[expr_] := StringContainsQ[ToString[InputForm[Hold[expr]]], "-"]


Demonstration:

CountMinusSigns[-(-3 + a + 3  b - 5  c)/(-d - 5)]
(* 5 *)

ContainsMinusSignQ[-(-3 + a + 3  b - 5  c)/(-d - 5)]
(* True *)


Caveat: This assumes that you're going to input expressions that are mathematical in the sense that the only "-" are those indicating subtraction or negation.

• Thanks! This works! My first motivation was the practical problem of expressions which cannot be displayed (but can be manipulated, say under numeric values). As far as simplifying them, I guess some quick commands like Factor might reduce the number of minuses without taking 10 minutes, so we may assume a Factor has been applied already. My second motivation was that it seemed the answers provided in the "sum question" gave puzzling answers . Now that the question has been answered three times beautifully, I must spend some time digesting the solutions and choosing the one I understan Commented Aug 5 at 8:05
• m = -(-3 + a + 3 b - 5 c)/(-2 - d - 5); CountMinusSigns[expr_] := StringCount[ToString[InputForm[Hold[expr]]], "-"]; CountMinusSigns[m] yields wrongly 0 Commented Aug 5 at 12:10
• @florin, this answer requires you to enter your expression directly in the function, namely CountMinusSigns[-(-3 + a + 3 b - 5 c)/(-2 - d - 5)], because it has the attribute HoldAll. Commented Aug 5 at 13:04

The following alternative, using FullForm, also does the job:

SetAttributes[{CountMinusSigns, ContainsMinusSignQ}, HoldAll]
CountMinusSigns[expr_] :=
Length@Cases[FullForm[Hold[expr]] /. Power[x_, -1] :> Power[x, 1],
s_Integer?Negative :> -Unitize[s], \[Infinity]]

ContainsMinusSignQ[expr_] := CountMinusSigns@expr != 0


Demonstrations:

CountMinusSigns[-(-3 + a + 3 b - 5 c)/(-d - 5)]

(*5*)

ContainsMinusSignQ[-(-3 + a + 3 b - 5 c)/(-d - 5)]

(*True*)

CountMinusSigns[-(3 + a - 3 b + 5 c)/(d - 5)]

(*3*)

ContainsMinusSignQ[-(3 + a - 3 b + 5 c)/(d - 5)]

(*True*)

CountMinusSigns[3 + a + 3 b + 5 c/(d + 5)]

(*0*)

ContainsMinusSignQ[3 + a + 3 b + 5 c/(d + 5)]

(*False*)

CountMinusSigns[a/c/b] (*Thanks to @Domen!*)

(*0*)

ContainsMinusSignQ[a/c/b]

(*False*)

• It should be warned that this solution has a similar problems regarding the fractions as mentioned in the comments, namely ContainsMinusSignQ[a/c/b] gives True. Commented Aug 5 at 9:22
• You're right, @Domen! See the update, please. Commented Aug 5 at 15:48
 Cases[HoldForm[
m = -(-3 + a + 3 b - 5 c)/(-d - 5)], #, \[Infinity]] & /@
{(x_?  Negative + ___ :> x), (_?Negative*___)}

{{-3, -5}, {-5 c, -a + 5 c, -d}}

• I understand the -5, but not the -3 Commented Aug 5 at 10:12
• There is a negative x= -3 in a sum, that is projected out by :>x. It seems to me the simpleste way to find isolated negative numbers. All my ideas about Alternative patterns did not work. There are subtle rules in Rules with Patterns on the left , evaluated or not. One problem is to exclude numerical negative exponents in simple powers and fractions. Commented Aug 5 at 10:58

I have a list of monsters, and I need to count the minuses in them without displaying them. I produced the last answer using hints from the discussants, and it seems to work better than some of the previous answers (to my badly explained question --sorry )

lm = {-(-3 + a + 3 b - 5 c)/(-2 - d - 5),
3 b - 5 c, k[3] - 2};
CountMinusSigns[expr_] :=
StringCount[ToString[InputForm[Hold[expr]]], "-"];
countM[m_] := Length[Cases[m, -_ , Infinity]];
countMS[m_] :=
Module[{tog, num, den, mn, md}, tog = Together[m];
num = Numerator[tog] ;
mn = Count[num, _?InternalSyntacticNegativeQ];
den = Denominator[tog] ;
md = Count[den, _?InternalSyntacticNegativeQ];
mn + md];
CountMinusSigns /@ lm (*{4, 1,  1}*)
countM /@ lm  (*{2, 0,  0}*)
countMS /@ lm  (*{2, 1,  1}*)

• @Domen The correct countMS from my answer takes 30 s on my real list of monsters lm, and the countM which produces wrong answers occasionally ends quickly with plausible answers. Worse, using in my Count MS the other answer from the sum question, i.e. Count[m, _?InternalSyntacticNegativeQ], yields different answers!!! So, everything rests on having quick reliable solutions to the sum problem. But do we? Commented Aug 5 at 14:44
• I don't know what to say ... We still don't know what you consider as the "correct" answer, we don't have access to your monster expressions ... Commented Aug 5 at 14:53
• the correct answer should be clear when you see the expressions, because all the variables are assumed positive, and I hope a bit of preprocessing like Together, Numerator, etc, will remove hopefully things like -(-2). Unfortunately, Simplify is not allowed by time... I probably need to find a smaller example, where I might understand why the solutions from the sums question yield different answers Commented Aug 5 at 15:19