1

In the latest MATLAB release, I am using the feature of local functions in the script to simplify and shorten the code.

Right now I have a simple script that does mathematical calculations, up to millions of iterations in a for loop. From the loop, I extracted the mathematical part as it is used in multiple independent loops. However, I have the problem with speed and constant variables that need to be in the function. If I write the code without the local function, it is fast, but in the case of using the function, it is 10x slower.

I think it is due to the repetitive read-in of variables in the function. If the read-in happens from a file, it takes forever. The best I have achieved is by using evalin function to call in variables from the base workspace. It works, but as I mentioned, it is 10x slower than without a separate local function.

How to overcome this?

The structure looks like this:

load('Data.mat'); r=1; %Reads variables L,n

for Lx = L1:Ld:L2
    for x = x1:d:x2
        Yx(r) = myF(x); r=r+1
    end
end

%A few more different loops...

function y = myF(x)
    L = evalin('base','L');
    n = evalin('base','n');
    ...
    a = (x-L)^2; b = sin(a)-n/2; ... y=b*a/L;
end
Klaidonis
  • 559
  • 2
  • 6
  • 22

1 Answers1

2

You will want to explicitly pass the variables as additional input arguments to myF so that you don't have to load them every time. This way you don't have to worry about calling evalin or loading them from the file every iteration through the loop.

load('Data.mat'); r=1; %Reads variables L,n

for Lx = L1:Ld:L2
    for x = x1:d:x2
        Yx(r) = myF(x, L, n); r=r+1
    end
end

function y = myF(x, L, n)
    a = (x-L)^2; b = sin(a)-n/2;
    y=b*a/L;
end

If for some reason you can't modify myF, just turn the entire thing into a function and make myF a subfunction and it will therefore automatically have access to any variable within the parent function. In this case you'll also want to assign the output of load to a variable to prevent strange behavior and not have issues with adding a variable to a static workspace

function myfunction()
    data = load('Data.mat');

    L = data.L;
    n = data.n;

    for Lx = L1:Ld:L2
        for x = x1:d:x2
            Yx(r) = myF(x);             
            r=r+1
        end
    end

    function y = myF(x)
        a = (x-L)^2; b = sin(a)-n/2;
        y=b*a/L;
    end
end

A third alternative is to take a hard look at myF and consider whether you can vectorize the contents so that you don't actually have to continuously call it millions of times.

You could vectorize it by doing something like

[Lx, x] = ndgrid(L1:Ld:L2, x1:d:x2);
a = (x - L).^2;
b = sin(a) - (n / 2);
Yx = (b .* a) ./ L;
Community
  • 1
  • 1
Suever
  • 64,497
  • 14
  • 82
  • 101
  • The first approach works great, forgot about that :D But the second approach looks even better because it is quite lame to parse the same constant variables over and over again to the function. However, with the second approach, I cannot simply load all the variables from the file, I have to specify all of them: `Error using load` `Attempt to add "L" to a static workspace.` – Klaidonis Jan 25 '17 at 12:27
  • Vectorization is a nice approach too but I cannot implement it in my code, as I need a bit more than just calculations, like finding the right and forecasting a value from the data and some `if` conditions. – Klaidonis Jan 25 '17 at 12:33
  • @Klaidonis Right, you really should specify an [output parameter to `load` to prevent strange behavior](http://stackoverflow.com/questions/36288909/what-happens-if-a-function-is-also-a-variable-in-matlab/36289118#36289118) – Suever Jan 25 '17 at 16:41
  • Currently I am using the same first method. I think it still should be possible to improve performance. I tried to place the `load` in `myF` function with `if isempty(L)` to load it just on the first execution and by defining those constant variables as `persistent`. However, the speed dropped more than by 50%. Is it simply contributed to checking that `if` millions of times? And still, the first approach currently is the fastest. With the second approach, I do not like that all variables are shared, if you define a new one you can easily overlook that such a variable already exists. – Klaidonis Jan 27 '17 at 09:34