1
$\begingroup$

I have two almost identical pieces of code: one with MatrixPower responsible for matrix multiplication and another with Do loop. Why the latter performs much faster? It looks counterintuitive...

refl1[λ_, d1_, d2_, n1_, n2_, Np_] := 
Module[{MN, M2}, MN = {{0.5, 0.5}, {0.5, -0.5}} + 0.0 I;
M2 = {{Cos[
   2 Pi*n1*d1/λ], -((I Sin[2 Pi*n1*d1/λ])/
     n1)}, {-I n1*Sin[2 Pi*n1*d1/λ], 
  Cos[2 Pi*n1*d1/λ]}}.{{Cos[
   2 Pi*n2*d2/λ], -((I Sin[2 Pi*n2*d2/λ])/
     n2)}, {-I n2*Sin[2 Pi*n2*d2/λ], 
  Cos[2 Pi*n2*d2/λ]}};
MN = MN.MatrixPower[M2, Np];
MN = MN.{{1.0, 1.0}, {1.0, -1.0}};
Abs[MN[[2]][[1]]/MN[[1]][[1]]]^2]
Timing[Do[refl1[100, 2, 3, 5, 6, 100], {100}]]

refl2[λ_, d1_, d2_, n1_, n2_, Np_] := 
Module[{MN, M2}, MN = {{0.5, 0.5}, {0.5, -0.5}} + 0.0 I;
M2 = {{Cos[
   2 Pi*n1*d1/λ], -((I Sin[2 Pi*n1*d1/λ])/
     n1)}, {-I n1*Sin[2 Pi*n1*d1/λ], 
  Cos[2 Pi*n1*d1/λ]}}.{{Cos[
   2 Pi*n2*d2/λ], -((I Sin[2 Pi*n2*d2/λ])/
     n2)}, {-I n2*Sin[2 Pi*n2*d2/λ], 
  Cos[2 Pi*n2*d2/λ]}};
  Do[MN = MN.M2, {i, 1, Np}];
  MN = MN.{{1.0, 1.0}, {1.0, -1.0}};
  Abs[MN[[2]][[1]]/MN[[1]][[1]]]^2]
  Timing[Do[refl2[100, 2, 3, 5, 6, 100], {100}]]
$\endgroup$
9
$\begingroup$

The reason for that is that MN is numerical, since you have 0.5 in it. So in the Do loop, every step is done just numerically. In refl1 the MatrixPower is analytically performed and converted to numerical just as last step. If you change the MatrixPower input also to a numerical input the execution times is much faster with the MatrixPower function.

refl3[λ_, d1_, d2_, n1_, n2_, Np_] := 
 Module[{MN, M2}, MN = {{0.5, 0.5}, {0.5, -0.5}} + 0.0 I;
  M2 = N[{{Cos[
        2 Pi*n1*d1/λ], -((I Sin[2 Pi*n1*d1/λ])/
          n1)}, {-I n1*Sin[2 Pi*n1*d1/λ], 
       Cos[2 Pi*n1*d1/λ]}}.{{Cos[
        2 Pi*n2*d2/λ], -((I Sin[2 Pi*n2*d2/λ])/
          n2)}, {-I n2*Sin[2 Pi*n2*d2/λ], 
       Cos[2 Pi*n2*d2/λ]}}];
  MN = MN.MatrixPower[M2, Np];
  MN = MN.{{1.0, 1.0}, {1.0, -1.0}};
  Abs[MN[[2]][[1]]/MN[[1]][[1]]]^2]


Timing[Do[refl2[100, 2, 3, 5, 6, 100000], {100}]]

{6.30906, Null}

Timing[Do[refl3[100, 2, 3, 5, 6, 100000], {100}]]

{0.017559, Null}

$\endgroup$
3
$\begingroup$

It is because you are using exact numbers. Use floating number instead. Like

Timing[Do[refl1[100., 2., 3., 5., 6., 100.], {100}]]
Timing[Do[refl2[100., 2., 3., 5., 6., 100.], {100}]]

{0.012001, Null}

{0.016001, Null}

which is the counter example of your counter intuition :)

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.