What is the alternative function for evalin?

19 views (last 30 days)
Ammy
Ammy on 14 Aug 2021
Answered: Jan on 17 Aug 2021
I want to improve the performance of my function.
  • Avoid functions such as eval, evalc, evalin, and feval(fname). Use the function handle input to feval whenever possible. Indirectly evaluating a MATLAB expression from text is computationally expensive.
I 'm using the following to read data from workspace to function file.
A= evalin('base','dataset');
Is there any alternative way for reading variables from workspace to Matlab function that is efficient.
  2 Comments
Walter Roberson
Walter Roberson on 16 Aug 2021
And see my newest test just posted here that shows passing parameters through multiple levels is faster.

Sign in to comment.

Accepted Answer

Walter Roberson
Walter Roberson on 14 Aug 2021
Shared variables are 2 to 5 times faster than evalin('base')
test_base()
ans = 5.7348e-06
ans = 2.7770e-06
function test_base
A = rand(1e7,1);
assignin('base', 'A', A);
timeit(@() via_evalin(), 0)
timeit(@() via_shared(), 0)
function B = via_evalin()
B = evalin('base', 'A');
end
function B = via_shared()
B = A;
end
end
  7 Comments
Walter Roberson
Walter Roberson on 16 Aug 2021
It is a fair question to ask what the best performance is if you have multiple levels of calls.
The following code goes through 5 calling levels before doing the "work" (fetching the value and assigning to output). Exact timings depend upon the run, but it seems consistent that creating 5 levels of shared variables is the slowest of these three, and that passing as a parameter is the fastest.
In the earlier tests, sharing through one level of nested function was nearly indistinguishable from passing as parameters; this test tells us that there is a performance penalty to having to find the shared variable through multiple levels.
format long g
test_base();
t = 3×1
0.005531 0.00831 0.002545
function test_base
N = 500;
A = rand(1e7,1);
assignin('base', 'A', A);
t = zeros(3,1);
tic; for K = 1:N; via_evalin1(); end; t(1) = toc;
tic; for K = 1:N; via_shared1(); end; t(2) = toc;
tic; for K = 1:N; via_passed1(A); end; t(3) = toc;
t
cats = categorical({'evalin', 'shared variable', 'passed parameter'});
bar(cats, t);
function B = via_evalin1()
B = via_evalin2();
end
function B = via_evalin2()
B = via_evalin3();
end
function B = via_evalin3();
B = via_evalin4();
end
function B = via_evalin4();
B = via_evalin5();
end
function B = via_evalin5();
B = evalin('base', 'A');
end
function B = via_shared1()
B = via_shared2();
function B = via_shared2()
B = via_shared3();
function B = via_shared3();
B = via_shared4();
function B = via_shared4();
B = via_shared5();
function B = via_shared5();
B = A;
end
end
end
end
end
function B = via_passed1(A)
B = via_passed2(A);
end
function B = via_passed2(A)
B = via_passed3(A);
end
function B = via_passed3(A);
B = via_passed4(A);
end
function B = via_passed4(A);
B = via_passed5(A);
end
function B = via_passed5(A);
B = A;
end
end

Sign in to comment.

More Answers (2)

Jan
Jan on 17 Aug 2021
You asked clearly for the runtime of the code. Distributing a variable by evalin() is a drawback, as explained by others already. It is faster to design a program such, that all used variables are provided by input and output arguments. This is the reason, why e.g. almost all functions of Matlab's toolboxed use this method. (Exceptions: disp and save, which are driven by using the names of the variables instead of their values.)
Stephen Cobeldick hit an important point in his comment: evalin() makes the code hard to debug and to maintain. If your code is useful, you will use it in other applications. Over the time such codes will grow. In my case some tiny scripts with 20 lines of code, which fixed some inputs taken from Excel files, grow to 227'000 lines of Matlab code since 1999. Now imagine that some of the functions use variables stored in the base workspace called "A1", and the GUI of this propgram is open, while some users run scripts in the command window, which use "A1" as name of a variable by accident. This will cause unexpected outputs and it nearly impossible to debug this.
Storing variables in the base workspace and accessing them by evalin is a source of serious troubles. The debugging may need an hour, or in my case some weeks, because I would have to visit the lab, which uses my software and they will not be able to reproduce the problem until the other user runs its script again. Even if the runtime with evalin() would be some microseconds faster than with other methods, an instable code design can slow down the time to get the results dramatically.
Remember: We write code to solve problems. The time, until the problem is solved, is ths sum:
t_solved = t_designing + d_programming + t_documenting + ...
t_debugging + t_optimizing + t_runtime
Trying to improve the processing speed, while the code is still fragile dur to evalin's is called "premature optimizing" and a common reason for instable and in consequence not usable code.
Your question shows, that it is time to enter the next level of programming by learing, how to design code efficiently. Software engineering is important and more or less unknown for too many scientists. I've seen a lot of programs developped for e.g. a PhD, which are an undocumented pile of scripts which must be called in a specific order to obtain some results. As soon as the PhD is finished and the author lost the post-it on which the needed order was written, this software is useless and worth to be deleted soon.
My answer:
Do not try to improve the runtime, but spend your time to refactor the complete code, such that all variables are provided either by inputs and outputs, of by sharing the variables using inlined functions. Take into account, that good code will be reused in other projects, and this is only possible, if the functions have a well designed and documented interface. evalin() is a secure indicator for messy code, so find a way to avoid it.

Matt J
Matt J on 14 Aug 2021
You could pass 'dataset' as an input argument to your function.
  4 Comments
Jan
Jan on 17 Aug 2021
@Walter Roberson: "When I used timeit() instead of tic/toc then the variation between runs was much greater than the difference between the timings."
This is interesting.There is a reason for the variation and for the different timings. I assume, that you did not test this with a high CPU load from other applications. According to my experiences with the undocumented JIT acceleration, both methods use a direct addressing of the variables and do not need to search in the lookup table (this is needed e.g. for eval()'ed variables). Then I'd expect more constant timings.
I'm going to run your test cases on a machine without speed-stepping of the CPU. Maybe Matlab is such efficient, that the CPU falls asleep during the processing.

Sign in to comment.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!