71
$\begingroup$

I use Mathematica mainly as an aid in symbolic attacks on problems, usually intermediate or harder and often number theoretic. While Reduce, Simplify, et al. are remarkably powerful, they of course cannot solve most real problems. If they could, most of mathematics would be solved and we wouldn't need mathematicians any more. We could just Reduce[Exists[{x,y,z,n},x^n+y^n==z^n&&n>2]] and out would pop a proof or disproof of Fermat's Last Theorem (yes, I realize that Mathematica actually has recently been given this as an axiom and would hence may reduce to False here, but in general it of course cannot).

So, instead, I like to use Mathematica as superior replacement for the old-fashioned pen-and-paper method I've used all my life. Ideally, I'd supply the specifications and transformations, but Mathematica would take care of all the error-prone tedium of substitutions and obvious simplifications. The savings on writing pads alone would pay for a Mathematica license.

Any general advice on working in this mode (how, ideally, to specify the problem; advanced tips on when to use Reduce, Simplify, FullSimplify, Solve, and Refine, etc.) welcome.

But I also have some specific recurring situations in which Mathematica just refuses to do obvious simplifications. Whenever that happens, I have to copy the Output by hand, perform the simplifications manually, and continue work from there. That is not ideal as it introduces the possibility of error and can be labor-intensive if the simplifications are complex or need to be done repeatedly after every change of a previous transformation.

Common cases of failure and frustration for me are sub-expression are as follows (where p, q, r, ... stand for complicated expression of the symbolic variables x, y, ... with specified domains (Integers, usually) and n, m, ... stand for integral constants):

  • Power[p^(n m) q,1/n]. Of course you want to pull the p out of the Power, to transform the subexpression to p^m Power[q,1/n], if p is demonstrably non-negative or n odd, or Abs[p^m] Power[q,1/n], if it is not. But no matter how I try to coax Mathematica to do this, &&ing p>0 or giving that as an assumption to Simplify or Refine, Mathematica just won't do it.
  • (p^n q)/(p^m r). You want to cancel out p as far as possible, either completely if p is demonstrably positive or with a ConditionalExpression or PieceWise otherwise. I can't make Mathematica do it.
  • p==q+Power[r,1/n] && Elem[x,Integers] && Elem[y,Integers]. A good Reduce would be to introduce a dummy variable z and rewrite as p==q+z && z^n==r && Elem[x,Integers] && Elem[y,Integers] && Elem[z,Integers]. Again, I can't make Mathematica do it automatically.

Is there some function beyond Reduce, Simplify, FullSimplify, Refine, or Solve that would do these kinds of reductions automatically?

Would it be worthwhile and effective to write some custom TransformationFunctions that perform these reductions automatically for the cases I frequently see?

Any other advice?

EDIT 1: CLARIFICATION: I understand that most of these simplifications will happen if p, q, ... are just Mathematica symbols or very simple expressions. What I should have made clear is that I used them as meta-syntactic variables. Then when you enter something even moderately complicated for p or q (like a polynomial in x and y with integer coefficients), they unfortunately often don't.

EDIT 2: SUMMARY CONCLUSION: First, let me thank the helpful commenters, in particular MarcoB who pointed me in the direction of ComplexityFunction (of which I had previously been ignorant) and provided interesting links.

In general, MarcoB is of course absolutely right. What the simplest version of an equation is not at all obvious. Minimizing LeafCount is a good heuristic, but it is incomplete and fallible.

Incomplete because, for example, $(x+y)(x-y)$ or $(x^2-y^2)$ are equivalent and have the same leaf count, but I will sometimes prefer the one and sometimes the other. Or: $(a_0 + a_1 x + a_2 x^2)$ or $a_2 (x-x_0) (x-x_1)$? Again, similar leaf count, but different preferences. Also fallible because one sometimes prefers slightly higher leaf counts.

For most sums, I--and I think most people--prefer the terms to be listed from largest to smallest and with leading term apparently positive, pulling out a minus sign if necessary. So the StandardForm of listing polynomials from lowest to highest power--while perfectly sensible from a coding point of view--is sufficiently jarring to the trained eye that, for a while, I had set OutputForm to TraditionalForm until the warnings every time I copied and pasted out of it scared me away from that option. And, of course, that the polynomial is in some small variable, like in a perturbation equation or power series expansion, I do want the polynomial listed from lowest to highest power.

Obviously, always producing the version preferred by the user is beyond the power of computers until we have human-level (or at least near-mathematician-level) A.I.

That said, I dream of a version of Mathematica (11? Are you listening Mathematica devs?) in which the OutputForm can be interactively manipulated by the user. One would be able to pick up a sub-expression with the mouse and jiggle it to quickly vary it between the most commonly useful forms or drag it to other parts of the expression while maintaining mathematical correctness. That should be doable and would be very neat.

$\endgroup$
  • 1
    $\begingroup$ As an example of an expression with an obvious simplification that Mathematica just won't do, consider this, which I just ran across: FullSimplify[((d^2 + g)^2 (256 d^8 g^4 - 1024 d^6 g^5 - 1024 d^2 g^7 + 256 g^8 + d^4 (1536 g^6 + 65536 g^5 r^2 + t^4)))/ d^6 == (32 g^2 (d^8 + g^4 - 2 d^4 g (g - 64 r^2)) t^2)/d^4, Assumptions -> {d > 0}]. A mess, but the obvious first step is to multiply out the d's and Mathematica won't. $\endgroup$ – CarlEdman Aug 31 '15 at 15:15
  • 4
    $\begingroup$ Carl, what would be the preferred outcome from that expression in your opinion? As I touched upon in my answer below, simplification in Mathematica is sometimes frustrating because the user's and the system's concepts of "simpler" may not coincide. $\endgroup$ – MarcoB Aug 31 '15 at 15:58
  • 1
    $\begingroup$ Fair enough. I am not sure what the simplest version of this expression is, but it seems inarguable that multiplying both sides by d^6 or d^4 would lead to a simpler expression--by any standard--than returning it unchanged as FullSimplify does. $\endgroup$ – CarlEdman Aug 31 '15 at 16:41
  • 2
    $\begingroup$ Last week I discovered something that is a primitive form of your "dream". There is a palette called "Algebraic Manipulations" that allows you to apply these transformation functions to parts of an InputForm. I found this to be very helpful in some cases. $\endgroup$ – QuantumDot Sep 1 '15 at 22:29
  • 1
    $\begingroup$ The "Evaluate in place" feature is also sometimes handy when doing algebraic gymnastics. You can highlight certain sections of your long expression, press Ctrl+Shift+Enter, and whatever you've highlighted is replaced by its evaluated version. $\endgroup$ – J. M. is away Sep 2 '15 at 4:46
50
$\begingroup$

In the first case PowerExpand comes to the rescue:

PowerExpand@Power[p^(n m) q, 1/n]

(* Out: p^m q^(1/n) *)

Note however that "the transformations made by PowerExpand are correct only if $c$ is an integer or $a$ and $b$ are positive real numbers".


Generally speaking, your assumptions can be listed in Reduce, Simplify, or FullSimplify using the Assumptions option, or alternatively using by wrapping those functions within Assuming.

If you know that certain assumptions about one or more parameters will hold throughout your calculation, however, it can be very handy to declare them globally using the $Assumptions variable, to whose documentation I refer you. This will make them "sticky".

This variable is empty at kernel start. If you set it to e.g.

$Assumptions = {Element[n, Integers], n > 0}

whenever you use any function that has an Assumptions option (e.g. Simplify, FullSimplify, Reduce) then the contents of $Assumptions will be automatically added to any further local assumptions you might want to make and will carry throughout your computation.


Even more generally, simplification in Mathematica is sometimes frustrating because the user's and the system's concepts of "simpler" may not coincide. The Simplify family of functions use an automatic ComplexityFunction to gauge how "complicated" an expression is; the system strives to generate an expression that minimizes this complexity function. Left to its own devices, the system primarily attempts to minimize the LeafCount of the resulting expression (see the "Details" section of the docs). Code that approximates the behavior of the standard ComplexityFunction is available in its docs, under "Properties and Relations".

One can write one's own ComplexityFunction to hand-hold the system and arrive at specific results. A good example is provided by the expression in the OP's comment to the question:

expr = ((d^2 + g)^2 (256 d^8 g^4 - 1024 d^6 g^5 - 1024 d^2 g^7 + 
       256 g^8 + d^4 (1536 g^6 + 65536 g^5 r^2 + t^4)))/ d^6 == 
       (32 g^2 (d^8 + g^4 - 2 d^4 g (g - 64 r^2)) t^2)/d^4

original expression

Assuming that $d>0$, Carl would like the expression to be simplified by multiplication by a $d^4$ or $d^6$ factor. Although they do modify the expression somewhat, neither Simplify[expr, Assumptions -> d > 0 nor the equivalent FullSimplify will do that.

FullSimplify[expr, Assumptions -> d > 0]

FullSimplify result with standard complexity function

However, we can write a custom complexity function that penalizes the presence of denominators, as measured by the count of Power terms with negative exponents.

FullSimplify[expr,
  ComplexityFunction -> (Count[#, Power[_, _?Negative], Infinity] &),
  Assumptions -> d > 0
]

Custom complexity, no denominator, but nasty

This removes the denominators, but the resulting expression is quite messy (the LeafCount is a staggering 162!). We can still achieve the desired rewriting while retaining some tidiness in the result by using a more nuanced complexity function that highly disfavors the presence of denominators (see the $1000$ weighing factor in front of Count) and also penalizes the presence of a high number of terms:

FullSimplify[expr,
  ComplexityFunction -> (1000 Count[#, Power[_, _?Negative], Infinity] + LeafCount[#] &),
  Assumptions -> d > 0
]

Final version with double complexityfunction

The leaf count of the last expression is a much more agreeable 72, and the denominators have been removed as desired.


A simpler approach may be to augment the list of manipulating functions that Simplify&co. will try out on your input expression. This can be achieved using a custom TransformationFunctions option. For instance, one could add PowerExpand from above to the standard list of manipulator functions:

Simplify[Power[p^(n m) q, 1/n]]
Simplify[Power[p^(n m) q, 1/n], TransformationFunctions -> {Automatic, PowerExpand}]

(*Out:
(p^(m n) q)^(1/n)
p^m q^(1/n)
*)

This may be dangerous though, because PowerExpand carries implicit assumptions (see above) that may not always be appropriate!


Here are a few links for bed-time reading on the subject :-)

$\endgroup$
  • $\begingroup$ Thank you. That is very helpful and I will follow your leads. But I am still not sure why the standard LeafCount ComplexityFunction didn't at least multiply by d^4 or d^6 before returning the expression. That must have a lower leaf count than what it returned and be inside the search space. A bug? $\endgroup$ – CarlEdman Aug 31 '15 at 17:43
20
$\begingroup$

I can't help you with functions beyond Reduce, Simplify, ... but I can offer you a tip to help with reducing errors from manual translation.

In order to validate that your manual transformation is correct, one can subtract the original expression from the manual transformation and then use Simplify on that expression.

Sometimes it will return zero using symbols, but if that doesn't work you can put in numbers from the domain where you are working.

For example, the problem where you want (p^(m n) q)^(1/n) to simplify to p^m (q)^(1/n) you can execute:

FullSimplify[(p^(m n) q)^(1/n) - p^m  (q)^(1/n) /.
  {p -> 2.3, m -> 1.5, n -> 3.}]

which returns 0.

I have successfully used this to reduce my mistakes in manual translation.

$\endgroup$
  • 1
    $\begingroup$ Even better: you can put in random numbers from the specified domain and check that the difference is always 0 $\endgroup$ – magma Apr 8 '16 at 12:01
20
$\begingroup$

I use Mathematica in much the same way as you, although in the context of multi-stage physics derivations. Since no one has mentioned it, I'll describe an obvious approach to successive rewrites of an expression.

I label each step a calculation with an indexed symbol that I can refer to later. This is preferable to In's and Out's whose numbers can change if you go back and redo something.

w[1] = ((d^2 + g)^2 (256 d^8 g^4 - 1024 d^6 g^5 - 1024 d^2 g^7 + 
       256 g^8 + d^4 (1536 g^6 + 65536 g^5 r^2 + t^4)))/ d^6 == 
       (32 g^2 (d^8 + g^4 - 2 d^4 g (g - 64 r^2)) t^2)/d^4

Visual inspection of the result suggests the cancellation of the denominators -- so just do it.

w[2] = (#d^6)& /@ w[1]

and carry on.

If you see a simplification you would make in a pen and paper calculation, you can almost always duplicate it in Mathematica by application of function or pattern matching rule. Also, this step by step process allows you much more control over the appearance of an intermediate results. A bonus is that if you find that a series of calculations is to be repeated for other initial conditions, you can simply gather w[1], ..., w[n] into an encapsulating function and perform the various rewrites automatically.

$\endgroup$
  • $\begingroup$ +1 this sounds like a nice paradigm, could you post a minimal example of what you mean w.r.t. the 'encapsulating function'? $\endgroup$ – dionys Sep 2 '15 at 9:26
  • $\begingroup$ When I do this I finish up with a Simplify[w[1]==w[n]] and hope I get a True. Adding assumptions made along the way checks these as well. $\endgroup$ – Hugh Sep 2 '15 at 12:10
18
$\begingroup$

One thing is to make sure you have all the assumptions stated properly. For instance, the first two cases can be handled by passing all the assumptions to FullSimplify

FullSimplify[Power[p^(n m) q, 1/n], 
 Assumptions -> {q > 0, p > 0, n ∈ Integers, m ∈ Integers}]

p^m q^(1/n)

and

FullSimplify[(p^n q)/(p^m r), 
 Assumptions -> {q > 0, p > 0, n ∈ Integers, m ∈ Integers}]

(regular Simplify also works). One thing I always find frustrating is that Assumptions are not "sticky." If you assume n is an integer in one Simplify than it does not mean that n is an integer in another Simplify. So one trick is to gather all the assumptions at the beginning

assum = {q > 0, p > 0, n ∈ Integers, m ∈ Integers};

Now the simplify commands are easier to write and I'm less likely to forget one, thus the first command above becomes

FullSimplify[Power[p^(n m) q, 1/n], Assumptions -> assum]
$\endgroup$
  • $\begingroup$ Thank you. That is indeed true and works if p and q are just variables or simple combinations, but it stops working at some point as p and q become more complicated expressions, even if they are fully of the form given here. I'll clarify the question and post an example the next time I see the problem. $\endgroup$ – CarlEdman Aug 31 '15 at 14:51
  • 1
    $\begingroup$ Just thought I'd point out that if you are annoyed with setting a lot of assumptions you can also set global assumptions using $Assumptions={...} $\endgroup$ – JeffDror Sep 1 '15 at 1:51
17
$\begingroup$

I often find that Simplify, etc work better when applied to parts of an expression. As I mentioned in this post, using something like

Collect[expression, {selectedvariables}, Simplify[#, options -> values]& ]

can work well in this respect. More generally, if you wish to simplify a particular Part, try

expression[[index]] = Simplify[expression[[index]], options -> values]

As mentioned in other answers, effective options include Assumptions, ComplexityFunction, and TransformationFunctions. Determining the index of a particular term can be difficult in a complicated expression, of course. For short expressions FullForm may be practical. Position sometimes is effective for long expressions. It would be nice, if Mathematica provided the index, when a portion of an expression was highlighted.

$\endgroup$

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.