Loren on the Art of MATLAB

March 29th, 2006

Understanding Persistence

Questions about using persistent variables arise from time to time in the MATLAB newsgroup. Today I'd like to show you a little about what you might think you can do, but can't with persistent variables. I am also curious to hear from you about your use persistent variables, how often, and in what contexts. I personally now use nested functions exclusively (I think?) instead. Here are some links: blog article [1], blog article [2], the documentation.

Contents

First Sample Function

Here is the first of two sample functions that appear to be fairly similar. However, there are profound differences in the these functions, and only the first one will run in MATLAB.

type fcnPersist1
function q = fcnPersist1(u)
% fcnPersistent creates and uses a persistent variable.
persistent y;
if isempty(y)
    y = u;
else
    y = y+1;
end
q = y;


What you see is:

  • first the declaration that the variable y is persistent, followed by
  • some code to either initialize the persistent variable or to update its value, and
  • finally compute the desired output.

When I run mlint on this file, I find no messages. And when I run the code, I get no warning messages.

fcnPersist1(0)
fcnPersist1(3)
ans =

     4


ans =

     5

Second Sample Function

Here's the second sample function. In this function, you can see that I try to assign the persistent variable y to also be the output of the function. This is not allowed, and mlint does warn about us about this.

type fcnPersist2
function y = fcnPersist2(u)
% fcnPersist2 tries to create and use a persistent variable.
persistent y;
if isempty(y)
    y = u;
else
    y = y+1;
end

Here's on line of the mlint output:

  • 'y' appears to be incompatibly used or redefined.

This redefinition of y, as both an output variable and as a persistent variable, is prohibited in MATLAB and the result, as in the first example, must be assigned to another output variable.

6 Responses to “Understanding Persistence”

  1. Gary Roth replied on :

    Shouldn’t fcnPersist1(0) evaluate to 0 and fcnPersist1(3) evaluate to 2?

  2. Loren replied on :

    Depends how many times I ran it before. If I’d start from scratch, then fcnPersist1(0) returns 0. If I clear functions again right away and then run fcnPersist1(3), I get 3. If I don’t clear functions, after the call with 0 input, I get 3 as my output.

  3. Jiro Doke replied on :

    I think there are other uses to persistent variables that can’t be achieved by nested functions. I use it to load a large variable into the function space, so that subsequent calls will run faster. For example, in my FEX contribution, LOOK4 (http://www.mathworks.com/matlabcentral/fileexchange/loadFile.do?objectId=9963&objectType=file), I load a large mat file (which may take a few seconds) into persistent variable. Next time I run it, it returns the results instantly. What’s a few seconds? I guess it’s not that big of a deal, but I like the speed improvement.

  4. Markus replied on :

    In my project, sometimes a function on a lower level needs some common parameter to work. Instead of handing over this parameter each time from function to function, I run this function once in the project initialization and save the parameter in a persistent variable. It looks like this:

    function obj = whatever(obj, varargin)

    persistent param1 param2

    if length(varargin) > 1
    param1 = obj.param1;
    param2 = obj.param2;
    return
    end

    The function is called with an extra argument in the initialization.

  5. Loren replied on :

    For grins, here’s an example M-file using a nested function that loads in a data set for use over and over again.

    function fh = loadBig
    % Contrived example to show how one might load a variable once and use it
    % without using a PERSISTENT variable.
    
    X = [];
    caption = [];
    map = [];
    load clown
    lmap = length(map);
    h = image(X); colormap(map);
    fh = @changePix;
        function changePix(i,j)
           X(i,j) = round(rand(length(i),length(j))*lmap);  % replace pix with random integers
           set(h,'CData',X);
        end
    end
    

    An advantage of this method over persistent is that I can have 2 function handles to this, with different data (don’t hardwire in the filename, for example) and work on them simultaneously. With the persistent solution, I can have only one instance.

  6. Jiro Doke replied on :

    Thanks Loren! I’ve been working mostly with R13, so I didn’t know nested functions could be used in this way. So I guess when the function handle is created, the variables present during declaration remains in the function workspace. This is pretty useful.

Leave a Reply

Wrap code fragments inside <pre> tags, like this:

<pre class="code">
a = magic(3);
sum(a)
</pre>

If you have a "<" character in your code, either follow it with a space or replace it with "&lt;" (including the semicolon).


Loren Shure works on design of the MATLAB language at The MathWorks. She writes here about once a week on MATLAB programming and related topics.

  • Jun: I totally can not believe it, Loren. You are really helpful. Thank you so much, MATLAB master!
  • Loren: Wow folks- Always lots of interest when there’s a quickie to try out! I will only make 2 general...
  • Loren: Jun- ismember is your friend here: >> [aa,ind] = ismember(Array2,Arra y1) aa = 1 1 1 1 1 1 1 ind = 1 2 1 4 4 3...
  • Dan: I like the first way better than the second way. Combining the arrays into one and running any is nice, although...
  • James Myatt: How about I = (a == 0 | b == 0); a(I) = []; b(I) = [];
  • Tunc: Hello Loren, love your blog because of such inspiring and challenging comments to such ’small’...
  • Pekka Kumpulainen: Here is my tradeoff. I usually want to keep the original variables as they are most probably...
  • Iain: Followup: Of course, to allow NaNs (counting them as non-zero): mask = (a~=0) & (b~=0); The mask says “a...
  • Matt Fig: I would usually go with something like this: y = a&b; x = a(y); y = b(y); But I was surprised to find...
  • kk: c=all([a;b]) a(c) a(b)

These postings are the author's and don't necessarily represent the opinions of The MathWorks.