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$
  • $\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$ – David G. Stork Nov 27 '18 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 '18 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 '18 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 '18 at 4:21
10
$\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$
  • 1
    $\begingroup$ Thanks! Do you think this question is worth keeping on the site or is it too trivial? $\endgroup$ – chris Nov 27 '18 at 2:13
  • 2
    $\begingroup$ @chris, it is not trivial at all. $\endgroup$ – kglr Nov 27 '18 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 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 at 23:42
  • $\begingroup$ Fair enough! Thanks for your help. $\endgroup$ – chris Jun 6 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$
  • $\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 '18 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 '18 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 '18 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$
  • $\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 '18 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$
  • $\begingroup$ Thanks for your function ! $\endgroup$ – chris Dec 1 '18 at 5:12

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.