The HoldTemporary Package
By Ted Ersek 
ted.ersek@navy.mil

Version History

Version 1.0  (Feb 2001)

Version 1.0 was posted on MathSource in February 2001.

Version 1.1  (Nov 2003)

In Version 1.1 the function PowerTogether was greatly improved to expand the cases where it can combine the product of powers under one power.  Also in this version  InputForm and FullForm don't release HoldTemporary by default.

Version 1.2  (Dec 2003)

Version 1.2 was enhanced to check for a conflict due to use of $Pre, $Post, or $PrePrint.  If a conflict is likely  a message is posted when loading the package.

Version 1.3  (Jan 2004)

In Version 1.3  PowerTogether was further improved to make it perform simplifications such as 

PowerTogether[(2^(2 + 3 z)) (3^z) + (3^z) (8^(1 + z))]    ⟶   12*(24^z)   

PowerTogether[
            a^(b c) + (a^b)^
                c,  (a ≥ 0) && (b ∈ 
                  Reals)]   ⟶   2 (a^(b c)) 

PowerTogether[
            a^(b c) + (a^b)^c,  (c ∈ 
                Integers)]   ⟶   2 (a^(b c))

PowerTogether[((((a^b)))^c) + 
              (a^(b c)),  -1 < b < 
              1]    ⟶    2 (a^(b c))

PowerTogether[(1/(Sqrt[a])) - (Sqrt[(1/a)]), 
          a < 0]    ⟶    (2/(Sqrt[a]))

Installation and Loading Instructions

To determine where to put the (HoldTemporary.m) file evaluate the next cell.  If this directory doesn't already have a directory called Enhancements add one now.  The (HoldTemporary.m) file should then be copied to this Enhancements directory.

ToFileName[{$TopDirectory, "AddOns", "ExtraPackages"}]

Once the (HoldTemporary.m) file is copied to the right directory the package can be loaded by evaluating the Needs statement in the next cell.

Needs["Enhancements`HoldTemporary`"]

Caution:
The HoldTemporary package usually doesn't work if a value is assigned to either  $Pre,  $Post, or  $PrePrint.

HoldTemporary

The HoldTemporary usage message is shown below.

?HoldTemporary

In the next cell HoldTemporary is used in the definition of  M[n].

M[n_Integer?Positive] := HoldTemporary[(2^n) - 1]

numb = M[67]

We can use the result above in FactorInteger and the Hold is automatically released.  Also you can edit the above Output cell and end up with an new Input such as (2^67) - 1000.  When you evaluate the new Input cell you get the same result as if you typed it from scratch.  HoldTemporary creates the illusion that the held expression wasn't held at all.

FactorInteger[numb]

By default any Symbol except one in the following list will release a hold due to HoldTemporary. 
    {Set, SetDelayed, UpSet, UpSetDelayed, Head, Apply, Replace, ReplaceAll, ReplaceRepeated, 
    ReplaceList, MakeBoxes, Return,Catch, Check, CheckAbort, TimeConstrained, MemoryConstrained, 
    AbortProtect, FullForm, InputForm, TraditionalForm}

Any function will release HoldTemporary by default.  In the next cell we see that (f1) releases HoldTemporary.

ClearAll[f1];
f1[numb]

In the next cell we make  ReleaseHoldTemporaryQ[f1] evaluate to False, and now (f1) doesn't release HoldTemporary.  
However, a caution is in order.  ClearAll[f1] doesn't clear the setting ReleaseHoldTemporary[f1]=False,  but Remove[f1] will erase any assignment to ReleaseHoldTemporary[f1].

ReleaseHoldTemporaryQ[f1] = False;
f1[numb]

Apply is one of the few System functions that will not automatically release HoldTemporary and this allows one to change the head HoldTemporary to Hold as in the next cell.

t1 = HoldTemporary[3 (5 + 8/4)];
Apply[Hold, t1]

By default Head doesn't release HoldTemporary as we see below.  This is useful in programming since we can then use 
If[Head[expr]===HoldTemporary, Do This, Do That].

Head[t1]

By default InputForm, FullForm, and TraditionalForm don't release HoldTemporary and this is demonstrated below.

InputForm[t1]

FullForm[t1]

TraditionalForm[t1]

PowerTogether

The are many applications for HoldTemporary and the PowerTogether function is one of them.  The next cell displays the PowerTogether usage message. Writing the code for PowerTogether was difficult, but there are also less complicated applications of HoldTemporary.

?PowerTogether

Examples using  PowerTogether[expr]

To demonstrate the need for PowerTogether consider the next cell where Mathematica refuses to return an expression with a format that looks good.

(Sqrt[((5 - 3)/((7 - 4) x))]) + (((π x))^2)

HoldTemporary was needed to define PowerTogether.  In the next cell the previous result is transformed into the more attractive form.  Since the hold is only temporary we can send the result directly to Plot!

f2 = PowerTogether[%]

Plot[f2, {x, 0.005, 2}];

We can even load the  (Graphics`Graphics`)  package and use the held result in LogPlot!

Needs["Graphics`Graphics`"];
LogPlot[f2, {x, 0.005, 2}];

The next cell gives another example where PowerTogether is helpful.

expr = 
      3 (Sqrt[ 2/z]) + 5 (Sqrt[ z/2]) + 4 (Sqrt[ 2  z])
PowerTogether[expr]

The next cell gives an example where I think Mathematica doesn't do a good job of simplifying an expression.

Clear[y, z];
expr = FullSimplify[(10 + 2)*(((20 + 4))^z)*(90^y) + z]

In the next cell PowerTogether makes the previous result much simpler.

PowerTogether[expr]

Below I give some more examples using  PowerTogether[expr].

PowerTogether[
      6 + (2^(2 + 3 z)) (3^z) + (3^z) (8^(1 + z))]

PowerTogether[
      1 - 7 (2^(2 + z)) (5^(-1 + 2 z)) (11^(-2 + z)) (13^(1 - 2 z)) (3^(4 z))]

PowerTogether[1 - (1/5) (2^(2 + z)) (3^(1 - z))]

expr = 
        (2^z) + 7 (2^(2 - 3 f[y] + g[z])) (3^(f[y] + 2 g[z])) (5^(-1 + 2 g[z])) (11^(-2 + g[z])) (13^(1 - 2 g[z])) + 
          (z^2);
PowerTogether[expr]

PowerTogether[((((x^(1/3))))^y) + (x^(y/3))]

Examples using  PowerTogether[expr, assum]

PowerTogether refuses to simplify the next cell since  (Sqrt[x]) (Sqrt[y]) (Sqrt[z]) ≠ (Sqrt[x y z])  and  (w^n) 
          (x^n) (y^n) (z^n)  ≠ (((w x y z))^n) for certain values of  (w, x, y, z, n).

PowerTogether[(Sqrt[x]) (Sqrt[y]) (Sqrt[z]) + (w^n) (x^n) (y^n) 
          (z^n)]

However, PowerTogether simplifies the previous example when given the right assumptions as a second argument.  Notice (z) can go under the square root even though it could be any complex number!

PowerTogether[(Sqrt[x]) (Sqrt[y]) (Sqrt[z]) + (w^n) (x^n) (y^n) 
          (z^n),   x > 0 && y > 0 && n ∈ Integers]

Below I give more examples using PowerTogether with assumptions.  Look carefully at these examples and you should see that PowerTogether is very powerful.  Later I explain how you can verify that PowerTogether only makes simplifications that are true.

PowerTogether[(Sqrt[2 - x]) (Sqrt[3 - x]) + ((Sqrt[2 + x])/(Sqrt[1 - x])), 
      x > 4]

PowerTogether[(Sqrt[2]) (Sqrt[u]) (Sqrt[z]) (Sqrt[(1/(1 + x))]), 
      x > 4]

PowerTogether[(Sqrt[2]) (Sqrt[2 + x]) (Sqrt[(1/u)]), x > 4]

PowerTogether[(((Sqrt[2]) (Sqrt[u]))/(Sqrt[x + 2])) + (((Sqrt[2]) (Sqrt[2 + x]))/(Sqrt[u])), x > 1]

PowerTogether[3 (u^z) (w^z) (x^z) (((1 + x))^(-z)) (y^z), 
      x > 1 && y > 0]

PowerTogether[3 (u^z) (w^z) (x^z) (((1 + x))^(-z)) (y^z), 
      z ∈ Integers]

expr = 
      PowerTogether[(((-1 + x))^z) (((-1 + y))^(-z)), 
        x < 0 && y ∈ Reals]

PowerTogether[
      a^(b*c) + (a^b)^
          c, (a > 0) && (b ∈ Reals)]

PowerTogether[((((a^b)))^c) + (a^(b c)), 
      c ∈ Integers]

PowerTogether[((((a^b)))^c) + (a^(b c)), -1 < b < 1]

PowerTogether[(1/(Sqrt[a])) - (Sqrt[(1/a)]), a < 0]

How to Verify PowerTogether results

The next cell shows a result we might like to verify.

PowerTogether[(((-1 + x))^z) (((-1 + y))^(-z)), 
      x < 0 && y ∈ Reals]

We can use FullSimplify to show that the above input and output expressions are equal under the given assumptions.  Unfortunately in some cases when you tell PowerTogether a variable is an element of Reals you need to consider two inequalities in FullSimplify as I do below.  If the expressions are equal for (y≥0) and for (y≤0) then they are clearly equal for any (y∈Reals).

FullSimplify[(((-1 + 
                  x))^z) (((-1 + y))^(-z)) == (((((-1 + x)/(-1 + y))))^z), x < 0 && y ≥ 0]
FullSimplify[(((-1 + 
                  x))^z) (((-1 + y))^(-z)) == (((((-1 + x)/(-1 + y))))^z), x < 0 && y < 0]

Transformations made by PowerTogether

You could without much trouble review the PowerTogether code and ensure all the steps it performs can be justified with what I present below.

List of identities used by PowerTogether

Most of the transformations made by PowerTogether can be justified by the fact that Mathematica tells us each of the following identities are True.  I should point out that PowerTogether makes the transformation \(TraditionalForm\`\((\(\@x\) \@y :> \(-\@\(x\ y\)\))\)\) when (x ≤ 0  &&  y ≤ 0) rather than (x < 0 && y < 0) as in the last identity below.  It's easy to see that the this last identity is True in the more general case where  (x ≤ 0 && y ≤ 0) even though FullSimplify doesn't tell us it's True in that case.

FullSimplify[(a^(b c)) == ((((a^b)))^c), 
      a ≥ 0 && (b ∈ Reals)]
FullSimplify[(a^(b c)) == ((((a^b)))^c), 
      c ∈ Integers]
FullSimplify[
      (a^(b c)) == ((((a^b)))^c), -1 < b < 1]
FullSimplify[(a^c) (b^c) == (((a b))^c), 
      a ≥ 0]
FullSimplify[(a^c) (b^c) == (((a b))^c), 
      c ∈ Integers]
FullSimplify[(a^c) (b^(-c)) == (((a/b))^c), 
      b ≥ 0]
FullSimplify[(a^c) (b^(-c)) == (((a/b))^c), 
      a ≤ 0 && b ≤ 0]
FullSimplify[(a^c) (b^(-c)) == (((a/b))^c), 
      c ∈ Integers]
FullSimplify[((((1/x)))^a) == (x^(-a)), 
      x ≥ 0]
FullSimplify[((((1/x)))^a) == (x^(-a)), 
      a ∈ Integers]
FullSimplify[(Sqrt[(1/x)]) == ((-1)/(Sqrt[x])), x < 0]
FullSimplify[((Sqrt[x])/(Sqrt[y])) == -(Sqrt[(x/y)]), 
      x ≥ 0 && y < 0]
FullSimplify[(Sqrt[x]) (Sqrt[y]) == -(Sqrt[x*y]), 
      x < 0 && y < 0]

A chain of transformations used by PowerTogether

To explain how PowerTogether simplifies the following I have to demonstrate several lines of code.

PowerTogether[(3^z) ((2^(2 + 3 z)) + (8^(1 + z)))]

To demonstrate the necessary steps evaluate the next cell to make the Mathematica kernel start over.

Quit[]

The next cell defines functions (func) and (NumTest) which are used by PowerTogether.

func[e : (_?NumbTest^_Plus)] := 
        Times @@ (Thread[e, Plus] /. Power -> pwr);
func[n_?NumbTest^s_] := pwr[n, s];
func[e_] := e;
NumbTest[a_] := 
      Complement[{Head[a]}, {Integer, Rational}] === {}

The next few cells demonstrate the function (func).  Notice Mathematica will not allow you to return 4*(2^(3  z)) as an expression so (func) has to use the temporary head (pwr).

func[(2^(2 + 3 z))]

func[(2^(5  z))]

Next I demonstrate that func[e] returns e when e isn't (a Rational number or an Integer raised to a power).

{func[3], func[x], func[(x^(2 + 3  z))]}

In the next line the example I am demonstrated is assigned to (result).

result = (3^z) ((2^(2 + 3 z)) + (8^(1 + z)));

PowerTogether makes the transformation in the next cell.  Here we map (func) to each subexpression of (result) in the previous cell.

result = Map[func, result, -1] /. Power -> pwr

PowerTogether also makes the transformation in the next cell.  This step is justified by the fact that  
FullSimplify[ n^(s*m) == (n^m)^s ,  
        NonNegative[n]  &&  (m ∈ Reals)]    returns True.

result = 
      result //. (pwr[n_?NonNegative, 
                s_*m_] /; (Im[m] === 
                    0) && (m =!= -1)) :> 
          pwr[n^m, s]

In later steps PowerTogether changes the expression above into  12*pwr[24, z].  The the result is wrapped un HoldTemporary, and pwr is changed to Power.

How to avoid use of (Tan, Cot, Sec, Csc)

Every now and then a question comes up in the MathGroup on how one can ensure  Sin[x]/Cos[x]  is displayed instead of  Tan[x]  and likewise for Cot[x], Sec[x], Csc[x].  Below HoldTemporary is used to define a function MyForm that does this very well.

The HoldTemporary package is set up so that by default ReplaceAll (expr/.rules) doesn't release HoldTemporary, and this is required for the implementation below to work.  Also in the implementation of MyForm we use  HoldTemporary@@result  rather than  HoldTemporary[result]  because we have to let (result) evaluate to the expression it was given in the previous line.

Needs["Enhancements`HoldTemporary`"];

MyForm[expr_] := 
      Module[{sine, cosine, result}, 
result = 
          expr //. 
{Tan[x_] :> 
                sine[x]/cosine[x], 
              Cot[x_] :> 
                cosine[x]/sine[x], 
Sec[x_] :> 
                1/cosine[x], 
              Csc[x_] :> 
                1/sine[x]}; 
(HoldTemporary @@ {result}) /. {sine -> Sin, 
            cosine -> Cos}
]

Next we see that Tan[x] is changed to  Sin[x]/Cos[x]  and Sec[x]^2 is changed to  (1/Cos)[x]^2 , and the cosines are combined.

sample = MyForm[Tan[x] Sec[x]^2]

HoldTemporary creates the illusion that the expression isn't held, so we can use the result above without using ReleaseHold in the next cell.

Plot[sample, {x, 0, π/4}];