0
$\begingroup$

The question is simple. I'm trying to improve the (time) performance of a "Do" loop that looks like the following MWE

xlist = Range[0., 1., 0.1];
ylist = Range[0., 2., 0.2];

f[x_, y_, z_] := x + 3*y - z

results = {};

Do[
input = Tuples[{xlist, ylist, {step}}];
evalf = f @@ Transpose[input];
AppendTo[results, {step, Mean@evalf}]
, {step, Range[-1., 1., 0.1]}]

What is the most efficient way to speed up a thing like this?

$\endgroup$
5
  • 1
    $\begingroup$ Not in a position where I can answer rn, but it strikes me that you could simply use Table instead of a Do and AppendTo here. Also an iterator of the form {step, -1, 1, 0.1} might be better, instead of computing the whole Range; not sure. $\endgroup$
    – thorimur
    Mar 17, 2021 at 5:07
  • $\begingroup$ Also, I don’t think you need to compute Tuples each time, since the step is constant in a given, well, step! Maybe simply compute xylist = Transpose @ Tuples[{xlist, ylist}] outside the loop, then instead of Do use results = Table[{step, Mean[f[#1, #2, step]& @@ xylist]}, {step, -1, 1, 0.1}]. Does that work as expected? (Sorry, not at a computer rn...) $\endgroup$
    – thorimur
    Mar 17, 2021 at 5:15
  • 1
    $\begingroup$ Of course, given that your function is linear, we could simply compute Mean[#1 + 3*#2 & @@ Transpose[Tuples[{xlist, ylist}], or analytically simply $\bar{x} + 3\bar{y} = 0.5 + 3$, and then results = Table[{step, 3.5 - step}, {step, -1, 1, 0.1}], I think, but assuming you want to use an arbitrary function in general... :P $\endgroup$
    – thorimur
    Mar 17, 2021 at 5:25
  • $\begingroup$ With[{ran = Range[-1., 1., 0.1]}, Transpose[{ran, Mean[xlist] + 3 Mean[ylist] - ran}] ] $\endgroup$ Mar 17, 2021 at 6:32
  • $\begingroup$ I should have mentioned maybe that the function I'm working with is not linear... $\endgroup$
    – Pablo G
    Mar 17, 2021 at 18:33

1 Answer 1

3
$\begingroup$

In MMA you seldom use loops. And when you nevertheless use a loop to create a list, do not use AppendTo, this will reallocate the list every time you add an element. Instead use Sow and Reap. Here is a solution without loops:

xlist = Range[0., 1., 0.1];
ylist = Range[0., 2., 0.2];

Clear[f, f1]
f[x_, y_, z_] := x + 3*y - z
f1[z_] = {z, Mean[f[xlist, ylist, z]]}

results = f1 /@ Range[-1., 1., 0.1]
$\endgroup$
2
  • $\begingroup$ The key point of using Tuples in my original code was to create a grid on which you could evaluate the function. Then I want to obtain the fraction of points on this grid where the function is greater OR smaller than certain limits. For this I used Mean[UnitStep[f[args]-valmax]] + Mean[UnitStep[valmin- f[args]]]. If I'm right, with your code the function only gets evaluated at the pairs of values in the lists with the same position, and that's not what I want. Is there a workaround for Tuples or the UnitStep usage in this case? $\endgroup$
    – Pablo G
    Mar 17, 2021 at 18:30
  • $\begingroup$ I have difficulties understanding what you want. I think you should open an new question and explain exactly what you want. with a small test example. $\endgroup$ Mar 17, 2021 at 19:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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