8
$\begingroup$

Context

I would like to simplify expression involving, say, (x-1) or (x^2-1) when I know that |x|<1 so that the global sign appears more clearly.

I apologise in advance if it turns out to be trivial.

Attempt

I have tried e.g.

Simplify[(-2*x^2*(-1 + x^2))/135,Assumptions->x<1&&x>0]

Mathematica graphics

but I would like to have instead

Mathematica graphics

I guess I want to put a penalty on having a negative sign in front at the rendering stage?

The motivation for this is to be able to typeset the result into a publication.

Update

While the answers this question have received address successfully my original question, I think it would be of wide interest to scientists in general who typeset equations extracted from mathematica to be able to improve simplification when assumptions on the sign of certain variables are made.

For example,

  (Sqrt[1 - x] - 3*(-1 + x)*ArcTan[3*Sqrt[1 -x]])/(4*Pi) 

Can be simplified if $0<x<1$.

I realise it is probably not a trivial task to produce such simplification generically, but no one would typeset this equation as

$$\frac{\sqrt{1-x}-3 (x-1) \tan ^{-1}\left(3 \sqrt{1-x}\right)}{4 \pi }$$

$\endgroup$
4
  • $\begingroup$ But your answer is the same as what you requested, just rendered slightly differently (the canonical order in Mathematica, with increasing powers of $x$. What's the true problem? $\endgroup$ Nov 27, 2018 at 2:02
  • $\begingroup$ As you rightly notice, its only a rendering issue. Basically when I publish the result, the second form is preferable to the first one, since the reader will understand more easily that the quantity is positive since he knows that |x|<1. In other words, can I wrap a rendering option to formulas so it respect my convention, not mathematica's? $\endgroup$
    – chris
    Nov 27, 2018 at 2:04
  • $\begingroup$ What's the desired outcome of Simplify[(2*x^2*(-1 + x^2))/135,Assumptions->x<1&&x>0]? @kglr's gives no minus sign, mine gives a minus sign. $\endgroup$
    – Michael E2
    Nov 27, 2018 at 4:19
  • 1
    $\begingroup$ @MichaelE2 your expression is preferred. The drawback of your function is that it is less easily encapsulated as it involves both ComplexityFunction and TransformationFunctions. I wish I could grant both of you the solved badge! $\endgroup$
    – chris
    Nov 27, 2018 at 4:21

4 Answers 4

9
$\begingroup$

You can use ComplexityFunction option to "penalize" the number of terms with a negative sign:

cf = (LeafCount[#] + 100 Count[#, _?Internal`SyntacticNegativeQ, ∞] &); 

Simplify[(-2*x^2*(-1 + x^2))/135, ComplexityFunction -> cf]

2/135 x^2 (1 - x^2)

As chris noted in comments, this gives an unsatisfactory result for the following example:

Simplify[(Sqrt[1 - x] - 3*(-1 + x)*ArcTan[3*Sqrt[1 - x]])/(4*Pi), 
 ComplexityFunction -> cf]

(Sqrt[1 - x] + (3 - 3 x) ArcTan[3 Sqrt[1 - x]])/(4 π)

since it expands - 3*(-1 + x) to (3-3x).

A simple modification of cf to cf2 normalizing the second term by the LeafCount of input expression:

cf2 = LeafCount[#] + 100 Count[#, _?Internal`SyntacticNegativeQ, ∞]/ LeafCount[#] &; 

gives the desired result for both examples:

Simplify[(-2*x^2*(-1 + x^2))/135, ComplexityFunction -> cf2]

2/135 x^2 (1 - x^2)

Simplify[(Sqrt[1 - x] - 3*(-1 + x)*ArcTan[3*Sqrt[1 - x]])/(4*Pi), 
 ComplexityFunction -> cf2]

(Sqrt[1 - x] + 3 (1 - x) ArcTan[3 Sqrt[1 - x]])/(4 π)

Needless to say, I am sure there will be examples where both will fail to give the desired result.

$\endgroup$
5
  • 1
    $\begingroup$ Thanks! Do you think this question is worth keeping on the site or is it too trivial? $\endgroup$
    – chris
    Nov 27, 2018 at 2:13
  • 2
    $\begingroup$ @chris, it is not trivial at all. $\endgroup$
    – kglr
    Nov 27, 2018 at 2:21
  • $\begingroup$ The result on (Sqrt[1 - x] - 3*(-1 + x)*ArcTan[3*Sqrt[1 - x]])/(4*Pi) is a bit disappointing since it expands the 3. Any suggestion? $\endgroup$
    – chris
    Jun 5, 2019 at 12:32
  • $\begingroup$ @chris, ComplexityFunction -> (LeafCount[#] + 100 Count[#, _?Internal`SyntacticNegativeQ, \[Infinity]]/ LeafCount[#] &) gives the desired result for your example. I am sure there will be cases the trick will fail. $\endgroup$
    – kglr
    Jun 5, 2019 at 23:42
  • $\begingroup$ Fair enough! Thanks for your help. $\endgroup$
    – chris
    Jun 6, 2019 at 6:43
2
$\begingroup$

Second Answer

Sticking with the problem of having a product's syntactic sign agree with the sign of its real value under $Assumptions, assuming it's real-valued (and not the problem of just supressing an initial minus sign regardless of the sign of the expression)...

The idea of syntacticallyCorrectSignForm is to convert any negative factors to positive factors and and keep track of the sign changes:

syntacticallyCorrectSignForm[e_Times] := Module[{sign = 1, res},
  res = If[
      TrueQ@Simplify[# < 0],
      sign = -sign
      ; If[Internal`SyntacticNegativeQ[#], Defer[#], #] &@Simplify[-#],
      #] & /@ e;
  sign*res]

OP's example (from comment below):

Assuming[x < 1 && x > 0 && b > 0,
 syntacticallyCorrectSignForm[b (-2*x^2*(-1 + x^2))/135]
 ]

Mathematica graphics

Powers of negative expressions are difficult, since (-y)^3 automatically evaluates to -(y^3). The use of Defer in syntacticallyCorrectSignForm allows the output expression to be copied as input.

Assuming[x < 1 && x > 0 && b > 0 && y < 0,
 syntacticallyCorrectSignForm[b (-2*x^2*y^3*(-1 + x^2))/135]
 ]

Mathematica graphics


Original Answer

Here's what I came up with, understanding the question to say that we want a negative sign when the expression is negative:

cf[e_Times] := 
  Boole[Internal`SyntacticNegativeQ[e] =!= 
    TrueQ@Simplify[
      Reduce[$Assumptions \[Implies] e < 0], $Assumptions]];
cf[e_Plus] := cf /@ e;
cf[e_] := 0;
xf = # /. e_Plus /; Simplify[
        Reduce[$Assumptions \[Implies] e < 0],
    $Assumptions
        ] :> -\[FormalX][-e] /. \[FormalX] -> Expand &;

OP's example:

Assuming[x < 1 && x > 0,
 Simplify[(-2*x^2*(-1 + x^2))/135, 
  ComplexityFunction ->
   (Simplify`SimplifyCount[#] + 10 cf[#] - 5 Boole[Head[#] === Times] &), 
  TransformationFunctions -> {Automatic, xf}
  ]
 ];
(*  2/135 x^2 (1 - x^2)  : This expression is positive under the assumptions *)

The negative of the OP's example:

Assuming[x < 1 && x > 0,
 Simplify[(2*x^2*(-1 + x^2))/135,
  ComplexityFunction ->
   (Simplify`SimplifyCount[#] + 10 cf[#] - 5 Boole[Head[#] === Times] &), 
  TransformationFunctions -> {Automatic, xf}
  ]
 ]
(*  -(2/135) x^2 (1 - x^2)  : This expression is negative under the assumptions *)

Another example from a comment:

Assuming[x < 1 && x > 0 && b > 0,
 Simplify[b (2*x^2*(-1 + x^2))/135, 
  ComplexityFunction ->
   (Simplify`SimplifyCount[#] + 10 cf[#] - 5 Boole[Head[#] === Times] &), 
  TransformationFunctions -> {Automatic, xf}
  ]
 ]
(*  -(2/135) b x^2 (1 - x^2)  *)

Note that there's nothing that can be done about expressions like -(1-x^2), which evaluates automatically to x^2 - 1, AFAICT.

$\endgroup$
3
  • $\begingroup$ Thanks. I does not seem to be able to cope with b (2*x^2*(-1 + x^2))/135 even if I specify that b >0. ? $\endgroup$
    – chris
    Nov 27, 2018 at 4:30
  • $\begingroup$ @chris This may not be worth investigating further, but I tweaked it to work with your example. $\endgroup$
    – Michael E2
    Nov 27, 2018 at 4:50
  • $\begingroup$ Whaow! The second answer is exactly what is needed I think. For people like me this should be super useful. Thanks a lot! $\endgroup$
    – chris
    Nov 27, 2018 at 23:56
1
$\begingroup$

Try this:

expr = (-2*x^2*(-1 + x^2))/135;
exprA = -Last[expr]
exprB = -expr[[1 ;; 2]]

(*  1 - x^2

(2 x^2)/135   *)

Now:

exprA*exprB

(*  2/135 x^2 (1 - x^2)  *)

as you wished.

One can also make sure that Mma will never change this if you make a slight change in the code. It is as follows

MapAt[HoldForm, exprA*exprB, {3}]

enter image description here

There exists a special function for such things in the package "Presentations" of David Park that can be used.

As much as I understood from the explanations, you need it for the purposes of demonstration or publishing. You did not, however, specify, what kind of document (or demonstration) are you creating. For example, it is not clear, why do not you simply type this function in a cell of the "Display Formula" type? Probably you have your reasons. Depending on this, however, one may use other more simple and efficient ways.

Have fun!

$\endgroup$
1
  • $\begingroup$ Thank you for your work. I meant to say I will export the formula into a paper via TexForm. I typically do this by hand but it is nice to be able to teach mathematica to write things the way I want. $\endgroup$
    – chris
    Nov 27, 2018 at 15:09
1
$\begingroup$

One way to do this to check each subexpression with the head Plus under given assumptions, and replace it with its negative version depending on the sign. One then does the simplification again but leaves these terms untouched using ExcludedForms option of Simplify.

For example, OP's case:

simplify[(-2*x^2*(-1+x^2))/135]
(* 2/135 x^2 (1-x^2) *)

in contrast to

Simplify[(-2*x^2*(-1+x^2))/135]
(* -(2/135) x^2 (-1+x^2) *)

The code is as follows:

ClearAll[assumptions];
assumptions = {1 > x > 0};

ClearAll[simplify];
simplify = Function[
       Module[{m, transform},
       transform = Function[# /. a_Plus /; Simplify[a < 0, Assumptions -> assumptions] :> m Plus[-a]];
       Simplify[transform[#], ExcludedForms -> a_Plus /; Simplify[a > 0, Assumptions -> assumptions], 
       TransformationFunctions -> {Automatic, transform}
       ] /. m -> -1
       ]];

As there are many pattern matching going on, this function is best to be used at the very end. However, it is quite generic.

Another example:

assumptions={1>x>0,y<5};
Sin[(x-1)(6-y)]//simplify
(* -Sin[(1-x) (6-y)] *)
$\endgroup$
1
  • $\begingroup$ Thanks for your function ! $\endgroup$
    – chris
    Dec 1, 2018 at 5:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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