When you call a function in MATLAB, MATLAB first evaluates all the inputs, and then passes these (possibly) computed values as the inputs. Recently Ljubomir Josifovski asked if there was a way to delay evaluation of function inputs and only evaluate them on demand. Here's what I came up with.
Instead of calling the function with expressions as input values, create those expressions as anonymous functions with no inputs.
Let's create an array and an expression to evaluate.
a = rand(2000); tic, f = @() a'*a, toc
f = @()a'*a Elapsed time is 0.003365 seconds.
You can see that setting up the anonymous function f doesn't take a lot of time.
We aren't passing arguments here, but comparing the direct computation time for a'*a with evaluating the same quantity via the anonymous function.
tic, b = a'*a; toc tic, c = f(); toc
Elapsed time is 0.508455 seconds. Elapsed time is 0.482722 seconds.
Setting up the function handle takes little time, but the evaluation is similar to the time for the expression itself.
This is what timeit, Steve Eddins' utility for benchmark timing, uses just this approach. timeit helps wash out first time evaluation costs and other timing artifacts that can show up in benchmarking. So let's try using that now for the anonymous function evaluation.
ans = 0.456538375738468
Now, if you want your function to evaluate either expression 1 or expression 2 based on something criterion, you can do so by passing in the two expressions as anonymous functions and using some logic like this.
if criterion == true y = expr1(); else y = expr2(); end
If you want to streamline your computations, do you have a strategy for delaying evaluation of expressions until necessary? How do you do this? Let me know here.
Get the MATLAB code
Published with MATLAB® 7.11
Comments are closed.
8 CommentsOldest to Newest
The use of anonymous functions to delay the evaluation is a nice idea, but it has one weakness: it repeats the evaluation of the input on every mention. E.g:
function myFunction(x, f) if x > 0 a = f(); % Line 1 % ... intervening code... b = f(); % Line 2 else % don't invoke f() at all end end
Ideally, we want the following behavior:
* if x ~= 0, then f() should not be evaluated at all.
* if x == 0, then f() should be evaluated only once, at Line 1, and Line 2 should reuse the results of the evaluation. However, the anonymous function results in two evaluations.
An alternative may be a simple handle class that does the evaluation when needed & caches the result, e.g.
classdef lazyEval < handle properties(Access=private) fcnHandle cachedData end methods function obj = lazyEval(fcn) obj.fcnHandle = fcn; end function val = getdata(obj) if isempty(obj.cachedData) obj.cachedData = obj.fcnHandle(); end val = obj.cachedData; end end end
The class can be improved by using a subsref to get the data instead of a explicit method call.
Minor correction: The middle of the post should be:
Ideally, we want the following behavior:
* if x <= 0, then f() should not be evaluated at all
* if x > 0, then f() should be evaluated only once […]
Interesting topic again. The solution you provided suits best if you are welling to pass three inputs (two expressions and a condition) instead of one (the one computed). This is against the very essence of MATLAB which places it above other programming softwares. I would take one of the expressions from your recent blog
as an example. Here MATLAB has given you the luxury of writing everthing as one command. This will no longer be the case if we adopt the approach asked by Ljubomir Josifovski. So we should be writing functions in such a way that every input is really used and any redundancy be implemented as conditional statements inside the function rather than passing as inputs.
I am not advocating the use of delayed evaluation in all cases. In fact, I think it’s somewhat less common than computing things as you go. However, there are simply some situations in which it is one approach to solving a particular set of problems, and not even the only approach. So choose the way(s) you prefer.
You said “The use of anonymous functions to delay the evaluation is a nice idea, but it has one weakness: it repeats the evaluation of the input on every mention.”
That’s true in your code but doesn’t have to be. Why not compute f() once in your function and store results in a variable to reuse, e.g., the value a you computed?
Storing the result in a local variable allows reuse only within the local function scope. If the lazily-evaluated parameter needs to be passed to other functions or shared in some way (e.g., between different callbacks), it would be cleaner to have the caching be encapsulated within the parameter.
Of course, the above use case is quite specialized :)
It does depend what problem one is trying to solve. I was trying to solve the original one posed by Ljubomir. Storing the values in between was not a requirement of his problem as I recall.
We should be aware that the result of the delayed computation may not be what we want. This is true when
(1) The expression involved depends on environment. For example, when the expression need to fetch a value stored in a global variable.
(2) The expression, when computed, causes an error. In a delayed computation we may never see the error.