Skip to main content
9 of 9
added 25 characters in body

Outline

  • Usage example

  • Code (included cases where the expression has powers of terms)

  • Explanation

  • Comparing with Simplify on random expressions (major addition since last edit)

  • Previous version of code


One could consider a home cooked simplify.

The purpose of the code below is to eliminate any guidance from the user. That is, there is no hard coding or any way to incorporate insight from the user.

The main idea is to find the terms that occur the most in multiplications and use Collect with those variables.


Usage example

Using simplify defined below:

expr // simplify

(G3 + G4 + G5 + G7 + G8) P2 + (G1 + G3 + G4 + G5 + G7 + G8) P5 + (G1 + G2 + G4 + G5 + G6 + G8) (P3 + P6)

In LaTeX :

$$(\text{P3}+\text{P6}) (\text{G1}+\text{G2}+\text{G4}+\text{G5}+\text{G6}+\text{G8})+\text{P5} (\text{G1}+\text{G3}+\text{G4}+\text{G5}+\text{G7}+\text{G8})+\text{P2} (\text{G3}+\text{G4}+\text{G5}+\text{G7}+\text{G8})$$

(expr // simplify) == desired

(*True*)


Code:

(code unpacked and mostly explained below)

Note: The code checks that the expression is a sum containing powers or multiplications and aborts otherwise.

Note: this version of the code uses ReplaceRepeated and so it might end up in an infinite loop for some expressions.

I changed the code to use Bob Hanlon's replacement rule as my idea looks silly now. The beginning of the code that did not involve finding multiple occurrences of a factor is the same. The previous version of the code is given at the end of this answer

Clear[simplify];

simplify[expression_]:=

Module[{check,var,tocollect,
simplified},

(******************************)

(* Begin check (End check below) *)

(* 
check that the expression is a 
sum of products or powers
 *)
 
check= Head[expression]===Plus && 
(List@@expression//AllTrue[#,MatchQ[_Power | _Times]]&);

If[check===False,
    Print["simplify is not adapted to this structure"];
    Abort[]
];

(* End check *)

(**********************************)

var=(expression//Variables);

tocollect={Count[expression,#*_],#}&/@var
            //MaximalBy[First]
            //Map[Last];
            
simplified=Collect[expression, tocollect, Simplify]
//. a_*b_+c_*b_:> (a+c)*b
]

Explanation

  • Step 1

Find the variables:

var = (expr // Variables);
  • Step 2

Find which variables occur the most in the multiplications:

{Count[expr, #*_], #} & /@ var // Sort

{{2, G2}, {2, G3}, {2, G6}, {2, G7}, {3, G1}, {4, G4}, {4, G5}, {4, G8}, {5, P2}, {6, P3}, {6, P5}, {6, P6}}

(included transposition to reduce displayed height )

$$\left( \begin{array}{cccccccccccc} 2 & 2 & 2 & 2 & 3 & 4 & 4 & 4 & 5 & 6 & 6 & 6 \\ \text{G2} & \text{G3} & \text{G6} & \text{G7} & \text{G1} & \text{G4} & \text{G5} & \text{G8} & \text{P2} & \text{P3} & \text{P5} & \text{P6} \\ \end{array} \right)$$

  • Step 3

Collect the variables that occur the most in multiplications:

simplified = Collect[expr, {P6, P5, P3}, Simplify]

(G3 + G4 + G5 + G7 + G8) P2 + (G1 + G2 + G4 + G5 + G6 + G8) P3 + (G1 + G3 + G4 + G5 + G7 + G8) P5 + (G1 + G2 + G4 + G5 + G6 + G8) P6

$$ \text{P3} (\text{G1}+\text{G2}+\text{G4}+\text{G5}+\text{G6}+\text{G8})+\text{P6} (\text{G1}+\text{G2}+\text{G4}+\text{G5}+\text{G6}+\text{G8})+\text{P5} (\text{G1}+\text{G3}+\text{G4}+\text{G5}+\text{G7}+\text{G8})+\text{P2} (\text{G3}+\text{G4}+\text{G5}+\text{G7}+\text{G8}) $$

  • Step 4:

factor common factors with //. a_*b_+c_*b_:> (a+c)*b (using Bob Hanlon's method instead of mines in the previous code )


Comparing with Simplify on random expressions

List of variables:

vars = Array[m, 30];

Test expression:

expression = RandomChoice[vars, 20] . RandomChoice[vars, 20];

Comparison between Simplify and simplify on this example:

simplified1 = expression // Simplify;
simplified2 = expression // simplify ;
simplified1 // LeafCount
simplified2 // LeafCount

Simplify : 94

simplify : 82

Check:

simplified1 == simplified2 // Simplify

(* True *)

Statistics :

expressiontable = 
  Table[RandomChoice[vars, 20] . RandomChoice[vars, 20], 20];

simps1 = simplify /@ expressiontable ;
simps2 = Simplify /@ expressiontable;
simps1 == simps2 // Simplify

(* True *)

LeafCount /@ simps1 // Mean // N
LeafCount /@ simps2 // Mean // N

Average complexity using simplify: 76.3

Average complexity using Simplify: 94.


Previous version of the code

Clear[simplify];

simplify[expression_]:=
Module[{check,var,to⎵collect,
simplified,duplicated,x,renaming⎵rule,
renaming⎵rule⎵inversed,new⎵variables},

check= Head[expression]===Plus && 
(List@@expression//AllTrue[#,MatchQ[_Times]]&);

If[check===False,
    Print["simplify is not adapted to this structure"];
    Abort[]
];

var=(expression//Variables);

to⎵collect={Count[expression,#*_],#}&/@var
            //MaximalBy[First]
            //Map[Last];
            
simplified=Collect[expression, to⎵collect, Simplify];

(* Find subexpressions that occur
 multiple times *)
 
duplicated=simplified
//Level[#,{2}]&
//Gather
//Select[Length@#>1&]
//Map[DeleteDuplicates]
//Flatten;


Collect[simplified, 
        duplicated,
        Simplify]

]

The major change difference with the newer version is that it explicitly collects sub expressions that occur more than once.

Explanation:

One could maybe use

Experimental`OptimizeExpression

(see for example Common subexpression from two expressions )

to find common sub expressions in the expression above but instead I consider a more simple approach for this kind of structure:

simplified // Level[#, {2}] & // Tally

{{G3 + G4 + G5 + G7 + G8, 1}, {P2, 1}, {G1 + G2 + G4 + G5 + G6 + G8, 2}, {P3, 1}, {G1 + G3 + G4 + G5 + G7 + G8, 1}, {P5, 1}, {P6, 1}}

$$\left( \begin{array}{cc} \text{G3}+\text{G4}+\text{G5}+\text{G7}+\text{G8} & 1 \\ \text{P2} & 1 \\ \text{G1}+\text{G2}+\text{G4}+\text{G5}+\text{G6}+\text{G8} & 2 \\ \text{P3} & 1 \\ \text{G1}+\text{G3}+\text{G4}+\text{G5}+\text{G7}+\text{G8} & 1 \\ \text{P5} & 1 \\ \text{P6} & 1 \\ \end{array} \right)$$

G1 + G2 + G4 + G5 + G6 + G8 appears twice we can collect that term:

Collect[simplified , G1 + G2 + G4 + G5 + G6 + G8]

$$(\text{P3}+\text{P6}) (\text{G1}+\text{G2}+\text{G4}+\text{G5}+\text{G6}+\text{G8})+\text{P5} (\text{G1}+\text{G3}+\text{G4}+\text{G5}+\text{G7}+\text{G8})+\text{P2} (\text{G3}+\text{G4}+\text{G5}+\text{G7}+\text{G8})$$