Multiplying “Scalar-Looking” Terms in Matrix Equations by Unit Matrix
Kristjan Kannike, 2005

ClearAttributes[Plus,Listable];

1+2

1+{1,2}

{1,2}+{3,4}

eq0={{a,b},{c,d}}+e+a b+a^b+g ({{a,b},{c,d}}+e) (* A sample expression *)

transf0=x_+y_:>x IDM+y/;FreeQ[x,List]&&(!FreeQ[y,List])&&FreeQ[x,IDM]; (* A foolproof transformation to insert identity matrices *)

eq0//.transf0 (* Note that we must use ReplaceRepeated everywhere *)

eq1=c1+c2+c3+c4+c5+c6+c7+c8+c9+c10+{{a,b},{c,d}}

times0=Map[(Timing[eq1//.transf0])[[1]]&,Range[10]]/.Second->1

Mean[times0]

transf1=(x_/;FreeQ[x,List]&&FreeQ[x,IDM])+(y_/;!FreeQ[y,List])->x IDM+y; (* The foolproof transformation with the constraint divided to separate parts *)

eq0//.transf1

times1=Map[(Timing[eq1//.transf1])[[1]]&,Range[10]]/.Second->1

Mean[times1]

transf[0]=(x_/;FreeQ[x,List]&&FreeQ[x,IDM])+{X__}->x IDM+{X}; (* The plainest transformation: sum of a scalar and a matrix *)

times2=Map[(Timing[eq1//.transf[0]])[[1]]&,Range[10]]/.Second->1

Mean[times2]

eq1//.transf[0]

(* eq[i] are test cases *)

eq[0]= a+{{a,b},{c,d}};

eq[0]//.transf[0]

eq[1]=2 a+3 {{a,b},{c,d}};

eq[1]//.transf[0]

eq[2]=a+b ({{a,b},{c,d}}+c);

eq[2]//.transf[0]

transf[1]=(x_/;FreeQ[x,List]&&FreeQ[x,IDM])+c_ ({Y__}+y_)->x IDM+c ({Y}+y); (* The factor c is essential here: otherwise the brackets were superfluous *)

eq[2]//.transf[1]

transf[2]=(x_/;FreeQ[x,List]&&FreeQ[x,IDM])+c_. ({Y__}+y_.)->x IDM+c ({Y}+y);

(* NB! *)

1+0

{1}+0

{1}+1

eq[2]//.transf[2]

eq[3]=a+b+c ({{a,b},{c,d}}+c+d);

eq[3]//.transf[2]

eq[4]=a+3 b ({{a,b},{c,d}}+{{a1,b1},{c1,d1}});

eq[4]//.transf[2]

eq[5]=a+{{a,b},{c,d}}.({{a1,b1},{c1,d1}}+e);

transf[3]=(x_/;FreeQ[x,List]&&FreeQ[x,IDM])+c_.*Dot[Y_,Z_]->x IDM+c Dot[Y,Z]; (* All kinds of sums of a scalar and a matrix multiplication, e.g. matches even a+A.B.C too, thanks to the associativity of Dot *)

eq[5]//.transf[3]

a IDM+{{a,b},{c,d}}.(e+{{a1,b1},{c1,d1}})

eq[6]=a+g {{a,b},{c,d}}.({{a1,b1},{c1,d1}}+e);

eq[6]//.transf[3]

eq[7]=a+g {{a,b},{c,d}}.({{a1,b1},{c1,d1}}+k {{a2,b2},{c2,d2}});

eq[7]//.transf[3]

eq[8]=a+({{a1,b1},{c1,d1}}+e).{{a,b},{c,d}};

eq[8]//.transf[3]

eq[9]=a+k {{a,b},{c,d}}.({{a1,b1},{c2,d2}}+c1).({{a2,b2},{c2,d2}}+c2);

eq[9]//.transf[3]

(* Transform all the test cases with the combined rules: *)
Scan[Print,(eq[#]//.transf[2]//.transf[3])&/@Range[9]]