Performance of `eval` compared to `str2func` to evalulate a function from a string - matlab

eval and str2func are both able to evaluate a function represented by a string, f.e. f='a^x+exp(b)+sin(c*x)+d':
Using eval:
y = eval(f)
or (suggested by rahnema1)
fHandle = eval(['#(x, a, b, c, d) ' f]);
y = fHandle(x, a, b, c, d);
Using str2func:
fHandle = str2func(['#(x, a, b, c, d) ' f]);
y = fHandle(x, a, b, c, d);
Which of both methods has the best performance?
Remarks
Note that this benchmark is inspired on this question.
Note that I'm aware that using eval and str2func is often bad practice[1][2] (as mentioned in the comments).

Short answer: use str2func.
Benchmark
The benchmark will evaluate the function for N different values of x.
f='a^x+exp(b)+sin(c*x)+d';
Ns = linspace(1, 1000, 20);
timeEval = zeros(size(Ns));
timeEvalHandle = zeros(size(Ns));
timeStr2func = zeros(size(Ns));
for i=1:length(Ns)
N = Ns(i);
timeEval(i) = timeit(#() useEval(f, N));
timeEvalHandle(i) = timeit(#() useEvalHandle(f, N));
timeStr2func(i) = timeit(#() useStr2func(f, N));
end
figure
plot(Ns, timeEval, 'DisplayName', 'time eval');
hold on
plot(Ns, timeEvalHandle, 'DisplayName', 'time eval');
hold on
plot(Ns, timeStr2func, 'DisplayName', 'time str2func');
legend show
xlabel('N');
figure
plot(Ns, timeEval./timeStr2func, 'DisplayName', 'time_{eval}/time_{str2func}');
hold on
plot(Ns, timeEvalHandle./timeStr2func, 'DisplayName', 'time_{eval handle}/time_{str2func}');
legend show
xlabel('N');
figure
plot(Ns, timeEvalHandle./timeStr2func);
ylabel('time_{eval handle}/time_{str2func}')
xlabel('N');
function y = useEval(f, N)
a = 1; b = 2; c = 3; d = 4;
for x=1:N
y = eval(f);
end
end
function y = useEvalHandle(f, N)
a = 1; b = 2; c = 3; d = 4;
fHandle = eval(['#(x, a, b, c, d) ' f]);
for x=1:N
y = fHandle(x, a, b, c, d);
end
end
function y = useStr2func(f, N)
a = 1; b = 2; c = 3; d = 4;
fHandle = str2func(['#(x, a, b, c, d) ' f]);
for x=1:N
y = fHandle(x, a, b, c, d);
end
end
str2func vs eval (without function handle): The results show that even for evaluating the function once, it is around 50% faster to use str2func than eval (without function handle). For a large number of evaluations, str2func may be around 100x faster (depending on the function you are evaluating).
str2func vs eval (with function handle): eval is around 100% slower than str2func for a single evaluation, but becomes are almost equally fast for a large number of evaluations (eval is ~5% slower).
eval with and without function handle: Note that for a single evaluation creating a function handle with eval is ~50% slower than evaluating it directly.
Conclusion: str2func is always faster than eval.

In the following benchmark a collection of function handles is created and performance of eval is compare to that of str2func to evaluate strings. The functions are combination of variables with +- signs.
n = 16;
op=char((dec2bin(0:2^n-1)-48)*2+43);
vars= 'a':'z';
v = vars(1:n+1);
s(1:2^n,1:2:2*n+1)=repmat(v,2^n,1);
s(:,2:2:end)=op;
h=repmat(['#(' sprintf('%c,',v(1:end-1)) v(end) ')'],2^n,1);
farray=[h,s];
tic
for k = 1:2^n
f = eval(farray(k,:));
end
toc
tic
for k = 1:2^n
f = str2func(farray(k,:));
end
toc
Result in Octave:
There is no difference between two methods.

Related

Store values within recursion to use later MATLAB

I'm trying to write a recursive multigrid algorithm in MATLAB.
I need to store the values of v and TC at each of the levels I'm going through to use when I'm no longer in the recursion by just calling them, in a similar way v{L} would have worked for example if I did a for loop.
Any help is much appreciated. Thank you.
function x = vcycle1d(n, x, b, T, w, levels)
x = damped_jacobiM(w, x, T, b, 10^-7, 3);
res = b - T*x;
k = log2(n+1);
N = 2^(k-1)-1;
RE = zeros(N,n);
for i = 1:N
RE(i,2*i-1:2*i+1) = [1 2 1];
end
RE = RE/4;
II = 2*RE';
TC = RE * T * II;
v = zeros(N, 1);
for i = 1:N
v(i) = (res(2*i-1) + 2*res(2*i) + res(2*i+1))/4;
end
if levels ~= 1
err= vcycle1d(N, zeros(length(v), 1), v, TC, w, levels-1);
else
err = TC\v;
end
There are two ways to do this.
Option 1: Use a persistent variable. This allows you to store details in a variable that retains values between calls.
The pros of this are that you can use it to "remember" all sorts of things from previous calls.
The cons of this are that you'll need to manage that memory in some sensible way.
Option 2: Use additional, optional, inputs.
function x = vcycle1d(n, x, b, T, w, levels, varargin)
if nargin == 7
priordetails = varargin{1};
end
currentdetails = ... ;
....
err= vcycle1d(N, zeros(length(v), 1), v, TC, w, levels-1, currentdetails);

Plotting an implicit function in Matlab

I have a function of 4 variables, let us say $f(x,t,w,n)$, the function $g(x,n)$ is defined as
g(x,n)=\int_a^b\int_c^d f(x,t,w,n) dt dw
where $a$, $b$, $c$, $d$ are given constants and the integral cannot be explicitly computed in a closed form. Then, $h(x,n)$ is given by
h(x,n)=\ln\frac{g(x,n)}{g(-x,n)}
I want to ploy $y=h(x,n)$ as a function of $x$ for different values of $n$ on the same plot. How can I do this. If it helps, $f(x,t,w,n)$ is of the following form
f(x,t,w,n)=\exp{-\frac{x^2+tw+wx}{n}}+\exp{-\frac{t^2+tx^2-2tx}{2n}}
I think this probably does what you want. I specify f, g, and h as anonymous functions and use the quad2d to estimate the value of the double integral.
%% Input bounds
a = 0;
b = 1;
c = 0;
d = 2;
%% Specify functions
% vectorize function as a prerequisite to using in quad2d
f = #(x,t,w,n) exp( -(x.^2 + t.*w + w.*x)./n) + exp(-(t.^2 + t.*x.^2 - 2.*t.*x)./(2.*n));
% keeps x,n fixed in function call to f(...), varies a < t < b; c < w < d
g = #(x,n) quad2d(#(t,w) f(x, t, w, n), a, b, c, d);
% wrap functions into h
h = #(x,n) log(g(x,n)/g(-x,n));
%%
figure();
hold on % keep lines
x_range = linspace(-1,1);
for n = 1:5
plotMe = zeros(1, length(x_range));
for iter = 1:length(x_range)
plotMe(iter) = h(x_range(iter), n);
end
lineHandle(n) = plot(x_range, plotMe);
end
legend(lineHandle, {
['N: ', num2str(1)],...
['N: ', num2str(2)],...
['N: ', num2str(3)],...
['N: ', num2str(4)],...
['N: ', num2str(5)]...
}...
)

How to create a matrix from a row vector and a column vector without using a loop in MATLAB?

I have two vectors, say A of size nx1, and B of size 1xm. I want to create a result matrix C (nxm) from a non-linear formula so that
C(i,j) = A(i)/(A(i)+B(j)).
I know I can do this with a loop such as:
for i=1:n,
C(i,1:m)=A(i)./(A(i)+B(1:m));
end
but is it possible in some way to do this without using a loop?
EDIT: Thanks for your answers! As a small addition, before I saw them a friend suggested the following solution:
C = A*ones(1,m)./(ones(n,1)*B+A*ones(1,m))
If you are on MATLAB R2016a or earlier you'll want to use bsxfun to accomplish this
result = bsxfun(#rdivide, A, bsxfun(#plus, A, B));
If you are on R2016b or newer, then there is implicit expansion which allows you to remove bsxfun and just apply the element-operators directly
result = A ./ (A + B);
Benchmark
Here is a real benchmark using timeit to compare the execution speed of using bsxfun, repmat, implicit broadcasting and a for loop. As you can see from the results, the bsxfun and implicit broadcasting methods yield the fastest execution time.
function comparision()
sz = round(linspace(10, 5000, 30));
times1 = nan(size(sz));
times2 = nan(size(sz));
times3 = nan(size(sz));
times4 = nan(size(sz));
for k = 1:numel(sz)
A = rand(sz(k), 1);
B = rand(1, sz(k));
times1(k) = timeit(#()option1(A,B));
A = rand(sz(k), 1);
B = rand(1, sz(k));
times2(k) = timeit(#()option2(A,B));
A = rand(sz(k), 1);
B = rand(1, sz(k));
times3(k) = timeit(#()option3(A,B));
A = rand(sz(k), 1);
B = rand(1, sz(k));
times4(k) = timeit(#()option4(A,B));
end
figure
p(1) = plot(sz, times1 * 1000, 'DisplayName', 'bsxfun');
hold on
p(2) = plot(sz, times2 * 1000, 'DisplayName', 'repmat');
p(3) = plot(sz, times3 * 1000, 'DisplayName', 'implicit');
p(4) = plot(sz, times4 * 1000, 'DisplayName', 'for loop');
ylabel('Execution time (ms)')
xlabel('Elements in A')
legend(p)
end
function C = option1(A,B)
C = bsxfun(#rdivide, A, bsxfun(#plus, A, B));
end
function C = option2(A,B)
m = numel(B);
n = numel(A);
C = repmat(A,1,m) ./ (repmat(A,1,m) + repmat(B,n,1));
end
function C = option3(A, B)
C = A ./ (A + B);
end
function C = option4(A, B)
m = numel(B);
n = numel(A);
C = zeros(n, m);
for i=1:n,
C(i,1:m)=A(i)./(A(i)+B(1:m));
end
end
See this answer for more information comparing implicit expansion and bsxfun.
Implicit expansion is the way to go if you have 2016b or newer, as mentioned by Suever. Another approach without that is to do element-wise operations after making A and B the same size as C, using repmat...
A1 = repmat(A,1,m);
B1 = repmat(B,n,1);
C = A1 ./ (A1 + B1);
Or in 1 line...
C = repmat(A,1,m) ./ (repmat(A,1,m) + repmat(B,n,1));
As a benchmark, I ran your loop method, the above repmat method, and Suever's bsxfun method for m = 1000, n = 100, averaging over 1,000 runs each:
Using for loop 0.00290520 sec
Using repmat 0.00014693 sec
Using bsxfun 0.00016402 sec
So for large matrices, repmat and bsxfun are comparable with repmat edging it. For small matrices though, just looping can be quicker than both, especially with a small n as that's your loop variable!
It's worth testing the given methods for your specific use case, as the timing results seem fairly variable depending on the inputs.

parallelizing for-loop containing if-statement

I have to traverse a 2D-array and perform some operations on them, depending on the results of an if-statement. I have made a small example of the loop here:
N=128;
A = rand(N,N);
B = rand(N,N);
sqr = #(x) x.^2;
for xi=1:N
for yi=1:N
a = A(xi,yi);
b = B(xi,yi);
if( abs(a-b)<1 )
result=2.0;
else
result = sqr(a-b);
end
res_matrix(xi,yi) = result;
end
end
I want to parallelize this for-loop. I have read the MathWorks-page on parfor, and the way I would parallelize it is just by making the outer-loop into a parfor.
Is this the best speed-up I can get, or should I structure my loop differently?
Here is a more detailed version of my loop:
for xi= 1:N
for yi= 1:N
a = A(:,xi,yi); %a is a vector
b = B(:,xi,yi); %b is a vector
D = a-b;
if( max(D./a)<1e-3 )
test_var=2.0;
else
F_min = F(a, b, 0); %F is some function, such as a Newton-Raphson solver etc...
F_max = F(a, b, 1); %F is some function, such as a Newton-Raphson solver etc...
if( F_min*F_max>0.0 )
test_var=2.0;
else
test_var = F(a, b, 2);
end
end
var(1, xi,yi) = test_var;
end
end
I think you can reduce the code (replace the two for-loops and the if statement) into something like this:
C = abs(A-B);
D = ones(N);
R = sqrt(C);
idxC = bsxfun(#gt,C,D);
R(idxC) = 2.0;
first you calculate the condition abs(A,B) and then apply the comparison to all the elements of the matrix.
If you want a speed-up you may be interested in the vectorized form:
[s1, s2, s3] = size(A); % Size of A and B
C=A-B; % Difference between A and B
%// Upper threshold condition
idx_under_threshold = squeeze(max(C,[],1)<threshold);
%// Functions to compute operations involving function F
fmin = #(idx1, idx2) F(A(:,idx1,idx2),B(:,idx1,idx2),0);
fmax = #(idx1, idx2) F(A(:,idx1,idx2),B(:,idx1,idx2),1);
fvalue = #(idx1, idx2) F(A(:,idx1,idx2),B(:,idx1,idx2),2);
%// Combined indices of A and B
idA = repmat((1:s2)',1,s3); %'
idB = repmat(1:s3, s2, 1);
%// Computation of fmin, fmax and fvalue over all the elements
Fmin = cell2mat(arrayfun(fmin, idA, idB, 'UniformOutput', false));
Fmax = cell2mat(arrayfun(fmax, idA, idB, 'UniformOutput', false));
Fvalue = cell2mat(arrayfun(fvalue, idA, idB, 'UniformOutput', false));
%// Second condition: ( abs(a-b)<1 )
idx_2 = idx_under_threshold | (Fmin.*Fmax < 5);
%// Inizalization of the result to 'result = sqr(a-b)'
Var = Fvalue;
%// Handling cases where 'result = 2.0'
Var(idx_2) = 2;
You can place that piece of code instead of the for loop

How to show all the midpoints on my bisection code?

I have a code for finding the bisection (and it finally works!), but I need to include 3 more things:
output- Root History a vector containing the sequence of midpoints obtained by the algorithm
output- the absolute value of the function
f(x) at r, i.e., fRoot = f(r) input- max iterations
function [R, E] = myBisection(f, a, b, tol)
m = (a + b)/2;
R = m;
E = abs(f(m));
while E(end) > tol
if sign(f(a)) == sign(f(m))
a = m;
else
b = m;
end
m = (a + b)/2;
R = [R, m];
E = [E, abs(f(m))];
end
how do I do this? thanks!!
I have corrected indents an you can see that you've left out end from the end of the function. (it is optional but best not to leave those things out so you know you did not mean to write couple lines to the end but you forgot it.)
R and E should be returned now, if you call myBisection apropriately, that is
[R, E] = myBisection(f, a, b, tol);
If you just call
myBisection(f, a, b, tol)
it will only return R.
To add a limit on the number of iterations, you change while's condition like so:
iter=0;
while (E(end) > tol) && (iter<max_iter)
iter = iter+1;
% ...
end
or it is better to do it in a for loop, with an if plus break:
for iter=1:max_iter
if(E(end) <= tol), break, end;
% ...
end