Why doesn't Mathematica simplify $ie^{-\frac{i\pi}{2}(1+a+b)}$?

Consider this

I * Exp[-I Pi / 2 * (1+a)] // Simplify


Mathematica understands that it is possible to cancel $$i$$ with $$e^{-i\pi/2}$$ and gives the result $$e^{ia\pi/2}$$ as expected. But if we try instead

I * Exp[-I Pi / 2 * (1+a+b)] // Simplify


Mathematica for some reason doesn't understand that it is still possible to simplify $$i$$ with $$e^{-i\pi/2}$$ and it just gives back the same thing, i.e., $$ie^{-\frac{i\pi}{2}(1+a+b)}$$, which is very weird to me.

What is behind this weird behavior of Simplify and FullSimplify? Why in the first case Mathematica recognizes the simplification and in the second it doesn't?

Instead of just posting workarounds, I will explain why they work. Simplify is a discrete, global minimization solver that minimizes a ComplexityFunction. The default ComplexityFunction is SimplifySimplifyCount:

(* input *)
I*Exp[-I  Pi/2*(1 + a + b)] // SimplifySimplifyCount

(* 18 *)

(* a potential intermediate step *)
I*Exp[-I  Pi/2*(1 + a + b)] // ExpandAll // SimplifySimplifyCount

(* 33 *)

(* desired output *)
Exp[-I  Pi/2*(a + b)] // SimplifySimplifyCount

(* 13 *)


Simplify searches for the minimum trying steps from a defined set of TransformationFunctions. If a short sequence of steps raises the complexity too much, the sequence is rejected and Simplify goes back to least complex expression found. At some point it gives up and returns the best answer found. The exact algorithm is unknown to me, so I cannot comment on the heuristics and thresholds it uses for determining when to continue and when to stop. It is known that it may work on subexpressions as well as the whole expression.

Workaround by adjustment of ComplexityFunction:

Simplify[I*Exp[-I  Pi/2*(1 + a + b)],
ComplexityFunction -> (LeafCount[#] + 3 Count[#, I, Infinity] &)]

(* E^(-(1/2) I (a + b) \[Pi]) *)


The coefficient 3 of Count was the minimally successful choice, which I determined by trial and error. I first picked something greater than 20, due to the results of SimplifyCount above.

@Domen's solution, implemented as an additional TransformationFunction:

Simplify[I*Exp[-I  Pi/2*(1 + a + b)],
TransformationFunctions -> {Automatic, Simplify@*ExpandAll}]

(* E^(-(1/2) I (a + b) \[Pi]) *)


Inspecting the process:

Simplify[I*Exp[-I  Pi/2*(1 + a + b)],
ComplexityFunction -> SimplifySimplifyCount@*Echo]


Echo will print all the steps tested by the ComplexityFunction. Use wisely: the number of steps a computer can make in a few milliseconds might overwhelm the Frond End. In this case it is only a few dozen. Also, in my implementation of @Domen's idea, Simplify calls Simplify: Beware infinite loops. In this case, the inner Simplify does not inherit the TransformationFunctions of the outer Simplify. So the inner one does not call Simplify again.

Here is a safer use of ComplexExpand (@AsukaMinato's idea):

Simplify[I*Exp[-I  Pi/2*(1 + a + b)],
TransformationFunctions -> {Automatic,
FullSimplify@ComplexExpand[#, {a, b}] &}]

(* E^(-(1/2) I (a + b) \[Pi]) *)


ComplexExpand (resp. PowerExpand) assumes variables are real (resp. positive). For ComplexExpand, the second argument specifies which variables are to be treated as complex. Using assumptions, when they are true, usually helps; when they are not true, the danger is that invalid transformations might be used. In cases where assumptions are unspecified, the ExpandAll solution makes a valid transformation. The drawback to ExpandAll is the risk of a combinatorial explosion of terms in a more complicated input.

• Thanks much for the explanation! Commented Feb 4 at 20:35
I * Exp[-I Pi / 2 * (1 + a + b)] // ComplexExpand // FullSimplify


E^(-(1/2) I (a+b) [Pi])

I guess there is a limit to what Simplify can do.

Here is another alternative

expr = I*Exp[-I  Pi/2*(1 + a + b)];
Simplify@TrigToExp@Simplify@ExpToTrig@expr


Another method with using ExpandAll prior to Simplify.

I*Exp[-I Pi/2*(1 + a + b)] // ExpandAll // Simplify
(* E^(-(1/2) I (a + b) π) *)
`