Klaidonis
Klaidonis

Reputation: 639

MATLAB: Slow Read-in of constant variables in Script Function

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

Upvotes: 1

Views: 142

Answers (1)

Suever
Suever

Reputation: 65460

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;

Upvotes: 2

Related Questions