0

I want to perform the computation shown in the code given below in a much faster way.

I have three loops for e, i and j. The matrices B1e, B2e, ...., B6e are functions of xi and eta. There are two ReplaceAll expressions which will replace the new value of xi and eta in the B1e, B2e, ...., B6e matrices, which are calculated repeatedly for the each i and j in the loops. But it is too slow.

Is there a way to make it faster? Maybe parallel computation? I'm open to advice.

\[Alpha] = MatrixForm[Table[i^2, {i, 5}]];

D1 = Table[i*j, {i, 3}, {j, 3}];

B1 = Table[\[Xi]^(i + e)*\[Eta]^(j + e), {i, 3}, {j, 3}, {e, 360}];
Ke1 = ConstantArray[0, {3, 3, 360}];

For[e = 1, e < 361, e++,
  For[i = 1, i < 6, i++,
    For[j = 1, j < 6, j++,
      Ke1[[All, All, e]] = 
        ReplaceAll[
         ReplaceAll[(Transpose[
             B1[[All, All, e]]].D1.B1[[All, All, 
              e]]), \[Xi] -> \[Alpha][[1, i]]], \[Eta] -> \[Alpha][[1,
             j]]];
      ];
    ];
  ];

@Henrik Schumacher the problem is that my ξ and η are functions of i,j and e but they are defined in matrices such as Alpha, U and V in which their dimensions are already known. Here Compile[{{i, _Integer}, {j, _Integer}, {e, _Integer}},if I dont mention the limits of i, j and e while compiling the function f, there will be a problem. Lets say na[[1,e]] matrix is defined for e=6 and for higher values of e>6 can not be found in na[[1,6]],na[[1,7]],..., and compilation can give an error. How could we fix it ? Below, you could see the code which is revised according to your solution strategy.

 Block[{i, j, e}, 
  f = {i, j, e} \[Function] 
    Evaluate[
     With[{ξ = ((U[[1, na[[1, e]] + 1]] - 
              U[[1, na[[1, e]]]])*\[Alpha][[NGaussxitilda[[1, 2]], 
             i]] + (U[[1, na[[1, e]] + 1]] + 
             U[[1, na[[1, e]]]]))*0.5, η = ((V[[1, 
               nb[[1, e]] + 1]] - V[[1, nb[[1, e]]]])*\[Alpha][[
             NGaussetatilda[[1, 2]], j]] + (V[[1, nb[[1, e]] + 1]] + 
             V[[1, nb[[1, e]]]]))*0.5}, (Transpose[
           B1e [[All, All, e]]].D1hat.B1e[[All, All, e]] + 
         Transpose[B1e[[All, All, e]]].D2hat.B2e[[All, All, e]] + 
         Transpose[B2e[[All, All, e]]].D3hat.B1e[[All, All, e]] + 
         Transpose[B2e[[All, All, e]]].D4hat.B2e[[All, All, e]] + 
         Transpose[B3e[[All, All, e]]].D5hat.B3e[[All, All, e]] + 
         Transpose[B3e[[All, All, e]]].D6hat.B4e[[All, All, e]] + 
         Transpose[B4e[[All, All, e]]].D7hat.B3e[[All, All, e]] + 
         Transpose[B4e[[All, All, e]]].D8hat.B4e[[All, All, e]] + 
         Transpose[B5e[[All, All, e]]].D9hat.B5e[[All, All, e]] + 
         Transpose[B6e[[All, All, e]]].D10hat.B6e[[All, All, e]])*
       detJe[[1, e]]
      ]]];


cf = With[{code = f[i, j, e]}, 
   Compile[{{i, _Integer}, {j, _Integer}, {e, _Integer}}, code, 
    CompilationTarget -> "C", RuntimeAttributes -> {Listable}, 
    Parallelization -> True, RuntimeOptions -> "Speed"]];


For[e = 1, e < nel + 1, e++,

  For[i = 1, i < NGaussxitilda[[1, 2]] + 1, i++,

    For[j = 1, j < NGaussetatilda[[1, 2]] + 1, j++,

      For[m = 1, m < nen*ndf + 1, m++,
        For[n = 1, n < nen*ndf + 1, n++,
          Kel[[m, n, e]] = Kel[[m, n, e]] + f[i, j, e];
          ];
        ];

      ];

    ];

  ];
J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
user45055
  • 193
  • 7
  • 1
    Don't use For-loops. They are very slow. Replace item by item operations with functional list manipulation operation or array manipulation operation. – m_goldberg Mar 19 '18 at 06:50
  • Could you give me an example from the given code ? How could I rearrange, just for one loop, m_goldberg ? – user45055 Mar 19 '18 at 06:53
  • 1
    @user45055: Very difficult to give an example from your code because we cannot evaluate your code. Try giving us a smaller example with all parameters defined. – Lotus Mar 19 '18 at 07:19
  • No. Your code is incomplete. It will not run as posted. There is no way I could rewrite it to work with functional constructs without having definitions for all the quantities referenced. – m_goldberg Mar 19 '18 at 07:19
  • 2
    @user45055, how would you write the matrix operations with pen and paper? If there is a compact way to express it on paper, it should be possible to do it almost directly like that in Mathematica. – Kiro Mar 19 '18 at 07:57
  • If you can't write a description of what you are actually trying to do, or you can't supply complete code that can be evaluated by other people, then your question cannot be answered. – J. M.'s missing motivation Mar 19 '18 at 09:37
  • About MatrixForm[]: don't use it except for displaying matrices. See this. – J. M.'s missing motivation Mar 19 '18 at 10:42
  • @m_goldberg I have rearranged the code and now it is complete and works. Could you show me how to use list manipulation tools instead of using loops which take so much time to solve. – user45055 Mar 19 '18 at 10:43
  • @J.M. could you help me how to decrease the time for loops ? Lets say if e=2000, then it will be a great challenge to solve. – user45055 Mar 19 '18 at 10:46
  • I would say that you should avoid writing loops if you can. In this case, you don't need to do Ke1 = ConstantArray[0, {3, 3, 360}]; before assigning to entries if you directly construct a list of matrices with Table[]. Also, the innermost part of your loop is wasted effort, since you keep on replacing entries even though the only result at the end is the one corresponding to ξ == η == 25. – J. M.'s missing motivation Mar 19 '18 at 10:51
  • In short: your long code is more compactly done as With[{ξ = 25, η = 25}, Ke1 = Table[With[{bm = Table[ξ^(i + e) η^(j + e), {i, 3}, {j, 3}]}, Transpose[bm].D1.bm], {e, 360}]]. – J. M.'s missing motivation Mar 19 '18 at 10:55
  • @J.M. Thank you for your response but I want ξ=1,η=1 for (i=1,j=1) and for (i=1,j=2) ξ=1,η=4, then for (i=1,j=3) ξ=1,η=9, ....., for (i=2,j=1) ξ=4,η=1.... for each loop value of i,j they need to take different values for ξ and η. – user45055 Mar 19 '18 at 11:02
  • Ah, but that's not what the code you wrote was doing. (Check it yourself.) If that's what you actually want, then: Ke1 = Table[With[{bm = Table[(i^2)^(i + e) (j^2)^(j + e), {i, 3}, {j, 3}]}, Transpose[bm].D1.bm], {e, 360}] – J. M.'s missing motivation Mar 19 '18 at 11:07
  • @user45055 Have you noticed that your code overwrites Ke1[[All, All, e]] 36 times with different values? That does not make sense. – Henrik Schumacher Mar 19 '18 at 11:13
  • @HenrikSchumacher you are right but under this code I will put a line such as For[m = 1, m < nenndf + 1, m++, For[n = 1, n < nenndf + 1, n++, Kel[[m, n, e]] = Kel[[m, n, e]] + Ke1[[m, n,e]]; ]; ]; – user45055 Mar 19 '18 at 11:22
  • @J.M. the last code you have given does not give the same answer of the code I have written above. – user45055 Mar 19 '18 at 11:24
  • It doesn't, because as I said, your code is not doing what you thought it was doing. Compare the two snippets I gave with the result of your slow loop, and perhaps using a lower value of e. – J. M.'s missing motivation Mar 19 '18 at 11:53
  • Maybe you should explain what you're trying to do with these matrices; there might actually be a much better way to proceed than forcing yourself to write loops. – J. M.'s missing motivation Mar 19 '18 at 13:12
  • @J.M. the problem nearly solved. But Compile[{{i, _Integer}, {j, _Integer}, {e, _Integer}}, here, how can I define i is an integer and could be from 1 to 10. – user45055 Mar 19 '18 at 13:22

1 Answers1

3

A major issue with your code is that you do symbolic calculations over and over again within a threefold nested loop. Symbolic computations are slows. In the and you want to have a numerical array, so you get tid of symbolic computations as early as possible. Compute the entries of the resulting array once outside any loops and create a function depending on the loop indices. This could, e.g., like this:

Block[{i, j, e},

  f = {i, j, e} \[Function] 
    Evaluate[With[{ξ = i^2, η = j^2},

      (ξ η)^(2 e) Dot[Range[3],ξ^Range[3]]^2 TensorProduct[η^Range[3],η^Range[3]]]

     ]];

So, f[i,j,e] returns what the monstrosity

Ke1[[All, All, e]] = 
        ReplaceAll[
         ReplaceAll[(Transpose[
             B1[[All, All, e]]].D1.B1[[All, All, 
              e]]), ξ -> α[[1, i]]], η -> α[[1,
             j]]]

is supposed to compute. This can even be sped up by compiling the function cf:

cf = With[{code = f[i, j, e]},
   Compile[{{i, _Integer}, {j, _Integer}, {e, _Integer}},
    code,
    CompilationTarget -> "C",
    RuntimeAttributes -> {Listable},
    Parallelization -> True,
    RuntimeOptions -> "Speed"
    ]
   ];

The full array can be obtained, e.g., with

Table[cf[i,j,e],{i,1,3},{j,1,3},{e,1,360}]

I'll stop here since it is not exactly clear to me, what you are going to do with it. Be sure to get rid of the For loops: They are slow and do not scope their rinnung indices, so it is easy to write buggy code with it. Use Do or Table instead.

Addendum

Better not compile the code or at least not with RuntimeOptions -> "Speed". I have the very bad habit to use this option which deactivates---amongst other things---checks for overflow. And integer overflow is precisely what is happening here: The numbers that occur in the result are simply too large to be stored in machine integer type.

Henrik Schumacher
  • 106,770
  • 7
  • 179
  • 309
  • your solution strategy is great. – user45055 Mar 19 '18 at 12:06
  • Thank you very much @Henrik Schumacher – user45055 Mar 19 '18 at 12:17
  • Last thing I want to ask is in the compilation function cf could I give the boundaries of {i, _Integer}, {j, _Integer}, {e, _Integer}. Lets say I want to limit the element numbers e to 100, could I write {e,1,100} ? – user45055 Mar 19 '18 at 12:36
  • Something like Outer[cf,Range[3],Range[3],Range[360]] should compute all needed values at once. Of course, you are free to replace 360 with 100. – Henrik Schumacher Mar 19 '18 at 12:52
  • the problem is that my ξ and η are functions of i,j and e but they are defined in matrices such as Alpha, U and V in which their dimensions are already known. Here Compile[{{i, _Integer}, {j, _Integer}, {e, _Integer}},if I dont mention the limits of i, j and e while compiling the function f, there will be a problem. Lets say na[[1,e]] matrix is defined for e=6 and for higher values of e>6 can not be found in na[[1,6]],na[[1,7]],., and compilation can give an error. How could we fix it ? Below, you could see the code which is revised – user45055 Mar 19 '18 at 13:16
  • Block[{i, j, e}, f = {i, j, e} [Function] Evaluate[ With[{ξ = ((U[[1, na[[1, e]] + 1]] - U[[1, na[[1, e]]]])[Alpha][[NGaussxitilda[[1, 2]], i]] + (U[[1, na[[1, e]] + 1]] + U[[1, na[[1, e]]]]))0.5, η = ((V[[1, nb[[1, e]] + 1]] - V[[1, nb[[1, e]]]])[Alpha][[ NGaussetatilda[[1, 2]], j]] + (V[[1, nb[[1, e]] + 1]] + V[[1, nb[[1, e]]]]))0.5}, (Transpose[ B1e [[All, All, e]]].D1hat.B1e[[All, All, e]]) detJe[[1, e]] ]]]; – user45055 Mar 19 '18 at 13:19
  • Note that the matrix \[Alpha] does not appear here anymore since its values can easily computed. I answered your original question as good as a could. Please open a new post for further questions. And please give complete but minimal information about the problem. Honestly, this way of hooking new questions into old post and this "yes, but... there is something that you didn't know..." is driving me nuts. – Henrik Schumacher Mar 19 '18 at 13:24
  • And get rid of the For loops. Don't expect advice on coding if you don't even try to take given advice seriously... – Henrik Schumacher Mar 19 '18 at 13:28
  • Im sorry for that, I try to take given advice seriously, I know you have excluded alfa matrix in your code and I have explained my problem in another post and stopped here not to hook more questions into this post. – user45055 Mar 19 '18 at 13:38