# A better simplification function

I am creating this question and posting an answer to it as a help for those who have problems with Mathematica simplification oddities that appear in other questions on the site.

First of all, there were simplification problems like this one:

Simplify[x + y, x + y == a]
(* ==> x + y *)

Simplify[x + y, x + y == z]
(* ==> z *)


We can see that the culprit is the well known variables names problem in Mathematica simplification. One of the answers points out a simplification function developed by Adam Strzebonski that is based on a series of FullSimplify calls with permutations of the symbols names, in hope of achieving the desired result:

VOISimplify[vars_, expr_, assum_: True] := Module[{perm, ee, best},
perm = Permutations[vars];
ee = (FullSimplify @@ ({expr, assum} /. Thread[vars -> #])) & /@ perm;
best = Sort[Transpose[{LeafCount /@ ee, ee, perm}]][[1]];
]


It works:

VOISimplify[{a, x, y}, x + y, x + y == a]
(* ==> a *)


Now, testing FullSimplify and VOISimplify on another simplification problem in this question, we don't have success (the z variable is not canceled):

FullSimplify[(E^(-I x) y z + (1 + E^(I y)) (x + y) z)/z, z != 0]
(* ==> (E^(-I x) y z + (1 + E^(I y)) (x + y) z)/z *)

VOISimplify[{x, y, z}, (E^(-I x) y z + (1 + E^(I y)) (x + y) z)/z, z != 0]
(* ==> (E^(-I x) y z + (1 + E^(I y)) (x + y) z)/z *)


One of the answers to this question was to simply change the variable name from y to a:

FullSimplify[(E^(-I x) y z + (1 + E^(I y)) (x + y) z)/z /. y -> a,  z != 0]
(* ==> a E^(-I x) + (1 + E^(I a)) (a + x) *)


We can see that even VOISimplify has a problem. How to deal with this case?

• I wish there were an alternative expression simplification suite for Mathematica much like RUBI is for integration. Is anyone aware of this ever being seriously attempted? – Mr.Wizard May 19 '15 at 6:11

It is proposed an improvement based on VOISimplify:

ExpressionUnknownSymbols[expression_]:=Union@Cases[expression,Except[__Symbol?(Context@#==="System"&),_Symbol],{1,Infinity},Heads->True]
SetAttributes[ExpressionUnknownSymbols,Listable];

Options[SuperFullSimplify]={Assumptions->False,ComplexityFunction->Automatic,ExcludedForms->{},TimeConstraint->Infinity,TransformationFunctions->Automatic,Trig->True};
SuperFullSimplify[expression_,options:OptionsPattern[]]:=SuperFullSimplify[expression,True,options]
SuperFullSimplify[expression_,assumptions_,OptionsPattern[]]:=Module[{unknownSymbols,unknownSymbolsPermutations,a,simplificationVersions,bestSimplification},Quiet[
unknownSymbols=Union[ExpressionUnknownSymbols[expression],ExpressionUnknownSymbols[assumptions]];
unknownSymbolsPermutations=Permutations[Table[Unique[a],{i,Length[unknownSymbols]}]];
With[{parallelKernelAssumptions=$Assumptions},ParallelEvaluate[$Assumptions=parallelKernelAssumptions]];
bestSimplification=Sort[Transpose[{ParallelMap[If[OptionValue[ComplexityFunction]===Automatic,SimplifySimplifyCount,OptionValue[ComplexityFunction]],simplificationVersions],simplificationVersions,unknownSymbolsPermutations}]][[1]];
,{ParallelMap::subpar,ParallelEvaluate::subnopar}]]
SetAttributes[SuperFullSimplify,Listable];


Now, applying it to our last problem in the question, which was

SuperFullSimplify[(E^(-I x) y z + (1 + E^(I y)) (x + y) z)/z, z != 0]
(* ==> E^(-I x) y+(1+E^(I y)) (x+y) *)


, we get the desired result.

There are some modifications in comparison to VOISimplify:

• Instead of permutations of the variables names, permutations of Unique[a] names are performed (this is what actually solves the above problem);

• Automatic variables detection from the expression to be simplified (in VOISimplify they need to be specified);

• Added the possibility of setting any of the options that appear in FullSimplify: Assumptions, ComplexityFunction, ExcludedForms, TimeConstraint, TransformationFunctions and Trig;

• It is Listable as is FullSimplify;

• It executes the FullSimplify calls of each variables names permutation in parallel, so it is much faster;

The Quiet messages were included because Mathematica does not allow ParallelMap and ParallelEvaluate inside for example a ParallelTable, as they are parallelizations inside parallelizations.

Please feel free to point any problems with the code and to post other answers as alternative/optimized simplification functions.

• I saw VOISimplify when it was posted in MathGroup years ago. Ever since, I have wanted WRI to make FullSimplify do this when the LeafCount and number of variables is not too large. – Ted Ersek May 18 '15 at 23:08
• Or add in form of a third and more expensive simplification funcion. – Giovanni F. May 19 '15 at 20:25
• It would be good if SuperFullSimplify had a MaxTime option. Once the maximum time has passed it should return the best answer it found so far. Also, it seems no ComplexityFuntion is full proof. There will always be cases where the expression deemed least complex isn't the one you like best. It would be good if we could get the 3,4,5 etc expressions have the lowest complexity based on the specified ComplexityFuntion. – Ted Ersek May 21 '15 at 20:58
• Hi Ted, the goal for me was to clone as max as possible the behavior of FullSimplify without its current problems described in the question, but feel free to use the code to add new options. – Giovanni F. May 21 '15 at 21:16