4

MATLAB stores variables along with anonymous functions. Here is an example of how this works from the documentation.

Variables in the Expression:

Function handles can store not only an expression, but also variables that the expression requires for evaluation.

For example, create a function handle to an anonymous function that requires coefficients a, b, and c.

a = 1.3;
b = .2;
c = 30;
parabola = @(x) a*x.^2 + b*x + c;

Because a, b, and c are available at the time you create parabola, the function handle includes those values. The values persist within the function handle even if you clear the variables:

clear a b c
x = 1;
y = parabola(x)
y =
   31.5000

Supposedly, the values of a b and c are stored with the function even when it's saved and reloaded from a mat file. In practice, I've found that these values do not persist, especially if the code that originally created the function is edited.

Is there a way to define the function handle in terms of the numeric values of the variables? I would like something of the form

>> a = 1.3;
>> b = .2;
>> c = 30;
>> parabola = @(x) a*x.^2 + b*x + c

parabola = @(x) a*x.^2+b*x+c

>> parabola2 = forceEval(parabola)

parabola2 = @(x) 1.3*x.^2+.2x+30

EDIT: Perhaps my problem is with the file association, but when I edit the file that I originally defined the anonymous function in, I get an error that looks like:

Unable to find function @(ydata)nr/(na*dt)*normpdf(ydata,mu(j),s(j))./normpdf(ydata,mu_a(j),s_a(j)) within C:...\mfilename.m. (where I've changed the name of my mfile to mfilename)

My usual solution to this kind of stuff has been to use func2str() to remove the file dependency, but this also strips out the workspace information including the parameter values. So I would like to force all the parameters to take on their numerical values in the function definition.

Marc
  • 5,315
  • 5
  • 30
  • 36
  • What is `forceEval`? – horchler Nov 07 '14 at 19:51
  • @horchler - this is the function I'd like to write that makes the implicit values of a,b,c explicit in the anonymous function definition. Alternately, I'd like some way of defining the anonymous function so that instead of storing the values of a,b,c implicitly, they are stored explicitly as 1.3 0.2 30. – Marc Nov 07 '14 at 19:53
  • 1
    What versoin of matlab are you using? The behavior you desire seems to be what is already implemented for release 2014b. – Mad Physicist Nov 07 '14 at 19:57
  • @madphysicist 2012a - I will check 2014b – Marc Nov 07 '14 at 22:35

3 Answers3

8

The values are stored in the function. As I've demonstrated in different answers before, you can check this with the functions command:

>> a = 1.3; b = .2; c = 30;
>> parabola = @(x) a*x.^2 + b*x + c;
>> x = 1;
>> y = parabola(x)
y =
         31.5
>> clear a b c
>> y = parabola(x)
y =
         31.5
>> fi = functions(parabola)
fi = 
     function: '@(x)a*x.^2+b*x+c'
         type: 'anonymous'
         file: ''
    workspace: {[1x1 struct]}
>> fi.workspace{1}
ans = 
    a: 1.3
    b: 0.2
    c: 30

Even when you save the handle to disk:

>> save parabolaFun.mat parabola
>> clear parabola a b c
>> load parabolaFun.mat parabola
>> y = parabola(x)
y =
         31.5
>> fi = functions(parabola)
fi = 
     function: '@(x)a*x.^2+b*x+c'
         type: 'anonymous'
         file: ''
    workspace: {[1x1 struct]}
>> fi.workspace{1}
ans = 
    a: 1.3
    b: 0.2
    c: 30

And you can simplify the creation of a parabola handle like this:

function p = makeParabola(a,b,c)

p = @(x) a*x.^2 + b*x + c;

end

There are certain caveats:

You can save and load function handles in a MAT-file using the MATLAB® save and load functions. If you load a function handle that you saved in an earlier MATLAB session, the following conditions could cause unexpected behavior:

  • Any of the files that define the function have been moved, and thus no longer exist on the path stored in the handle.
  • You load the function handle into an environment different from that in which it was saved. For example, the source for the function either does not exist or is located in a different folder than on the system on which the handle was saved.

In both of these cases, the function handle is now invalid because it is no longer associated with any existing function code. Although the handle is invalid, MATLAB still performs the load successfully and without displaying a warning. Attempting to invoke the handle, however, results in an error.

Hence, if you create the handle from a file-backed function (not a script, that's OK), and then modify or delete the file, the handle will become invalid.

chappjc
  • 30,359
  • 6
  • 75
  • 132
  • I run into problems when fi.file is not empty (i.e. the function is defined in an m-file) and the mfile is later edited. So I want to put the function in a form that can be written out using "str2func" and preserve the values --- i.e. I would like (in your example) str2func(makeParabola(1,2,3)) to give '@(x) x.^2 +2*x + 3' not '@(x) a*x.^2 + b*x + c' – Marc Nov 07 '14 at 22:33
  • I didn't know about `functions`. Cool! +1 – rayryeng Nov 07 '14 at 22:36
  • 1
    @Marc: use the last pattern suggested by chappjc (factory pattern, where you use a function to creates anonymous functions). That way you don't have to worry about editing the original one.. – Amro Nov 07 '14 at 22:36
  • @Marc Yes, if you create the handle in a file-backed function and then delete or modify that file, the handle becomes invalid. I just made a note of some caveats with function handles. If you want them to be bullet-proof they must be defined in the base workspace. – chappjc Nov 07 '14 at 23:06
3

Anonymous functions capture the values of all variables involved in the expression. If you want to see the environment workspace captured, use functions as @chappjc showed in his answer.

Now you gotta be careful about the type of variables used in the anonymous function (think value-type vs. handle-type).

All native types (numerics, logicals, structs, cells, etc..) are captured by-value not by-reference. Example:

x = magic(4);
f = @() x;    % captures matrix x

x(1) = 1      % modify x
xx = f()      % change not reflected here

Compare that to using handle-class types (e.g containers.Map):

x = containers.Map('KeyType','char', 'ValueType','double');
f = @() x;        % captures handle-class object x

x('1') = 1;       % modify map
keys(x)           % changed
keys(f())         % also changed!

f() == x          % compare handle equality, evaluates to true
Community
  • 1
  • 1
Amro
  • 123,847
  • 25
  • 243
  • 454
1
a = 1.3, b = 0.2, c = 30;
parabola = eval(['@(x) ', num2str(a), '*x^2 + ', num2str(b), '*x + ', num2str(c)]);
Akshay Rao
  • 352
  • 1
  • 7
  • Sorry, I'm not asking how to change the values of parameters in anonymous functions on the fly. I'm asking how to store the explicit numeric values of parameters in the definition of the function. – Marc Nov 07 '14 at 19:50
  • I'm afraid I don't understand the question then. Sorry. – Akshay Rao Nov 07 '14 at 20:04
  • this will definitely work, but it's super clunky and something I was hoping to avoid (but upvote for working) – Marc Nov 07 '14 at 22:21
  • Oh, this was after an edit I made that wasn't clunky. Believe me, I'll not use eval() even if I had a gun to my head. :) – Akshay Rao Nov 08 '14 at 02:18