Does it possible to use a function with persistent variables several times?

I want to process several independent data arrays using a function which includes persistent variables in the following manner:
function cnt = example()
persistent cnt_p;
if isempty cnt_p
cnt_p = 0;
end
cnt=cnt_p;
cnt_p=cnt_p+1;
end
A = [1 2 3];
B = [4 5 6];
cnt1 = example(A(1));
cnt2 = example(B(1));
cnt1 = example(A(2));
cnt2 = example(B(2));
.....
Function saves variable cnt_p so result of this code will be: cnt1 = 3; cnt2 = 4;
But I want to see: cnt1 = 2; cnt2 = 2;
P.S. Of course I can simply create several copies of this function but it does not convenient.

 Accepted Answer

Problem 1 is you're passing some arguments to example, yet your function doesn't take any argument. One would presume you'd want to do something with these arguments inside your function.
In any case, you need to think a bit more about what it is you want to do. I understand that you want your example function to keep track of the count independently if you call it with A as an argument or B as an argument.
The problem is that you don't actually call your example with A as an argument, or B as an argument, but with A(1) or B(1) or A(x) or X(y). Therefore, when the function call actually takes place, there is no more notion of A, B, X, it's just a number. You could of course keep track of different counts for different input numbers in your example function, but I don't think that's what you want?
If you wanted to keep a different count for different input numbers:
function count = countbynumber(number)
persistent m;
if isempty(m)
m = containers.Map('KeyType', 'double', 'ValueType', 'double');
end
if m.isKey(number)
count = m(number);
m(number) = m(number)+1;
else
count = 0;
m(number) = 1;
end
%do something with number ?
end
If you want to keep a different count for different name of input variable, you would have to call the function with:
c1 = countbyinputname(A);
c2 = countbyinputname(B);
c1 = countbyinputname(A);
c2 = countbyinputname(B);
That is you can't index the inputs. In which case the function itself is:
function count = countbynumber(v)
persistent m;
if isempty(m)
m = containers.Map('KeyType', 'char', 'ValueType', 'double');
end
varname = inputname(1);
if m.isKey(varname)
count = m(varname);
m(varname) = m(varname)+1;
else
count = 0;
m(varname) = 1;
end
%do something with v?
end
I'm not sure what would happen if you were to call the function with temporaries such as A(1).
But ultimately, the best solution may be to use a handle class for which you use different instances for different variables:
classdef counter < handle
properties (SetAccess = private)
count = 0;
end
methods
function count = increment(this, x)
count = this.count;
this.count = this.count+1;
%do something with x?
end
end
end
You'd use it like this:
counterA = counter;
counterB = counter;
c1 = counterA(A(1));
c2 = counterB(B(1));
c1 = counterA(A(2));
c2 = counterB(B(2));

3 Comments

Thank you for the answer, but counters is not my goal. It was only example (as seems not good). Lets take another one: a function which filters signal and track filter states between calls. Also we have to independent data streams portioned by frames, i.e. only one part of data stream available at the moment. If I call my_filter function (that saves states in persistents) for the first frame of the first stream, than I must to clear it before using with the first frame of the second stream. But states of the first filter would lost in this case. And when I call my_filter with second frame of the first stream it does not possible to restore states after first call.
The quetion is: Does it possible to save and then restore states of function with persistent variables? May be programmatically create a copy using nested functions (I' not familiar with it).
Is it possible to save and then restore states of function with persistent variables? No, there's no such mechanism available.
But any of the options I've shown in my example would do what you want.
Using a map container:
function result = my_filter(streamid, frame)
%streamid: a unique ID per stream, an integer here. You could use strings if you prefer
%frame: frame data
persistent mapid
if isempty(mapid)
mapid = containers.Map('KeyType', 'int32', 'ValueType', 'any');
end
if mapid.isKey(streamid)
%restore previous state:
state = mapid(streamid);
else
%create new state:
state = ????
end
%filter processing
%... done processing
%save state:
mapid(streamid) = currentstate;
end
And call the function with different ID for each stream:
r = my_filter(1, frame1(1)); %1st frame of 1st stream
r = my_filter(2, frame2(1)); %1st frame of 2nd stream
r = my_filter(1, frame1(2)); %2nd frame of 1st stream
r = my_filter(2, frame2(2)); etc.
Using classes:
classdef my_filter < handle
properties (SetAccess = private)
state;
end
methods
function this = my_filter(initialstate)
%constructor, possibly optional
this.state = initialstate;
end
function result = processframe(this, frame)
currentstate = this.state;
%process frame with currentstate
%...
this.state = currentstate;
end
end
end
And usage:
filterstream1 = myfilter(init1)
filterstream2 = myfilter(init2)
r = filterstream1(frame1(1)); %1st frame of 1st stream
r = filterstream2(frame2(1)); %1st frame of 2nd stream
%etc.
Finally, the last option is to for your filter to return its state, and accept a state as input. Then, it's down to the caller to read and write the state:
function [result, state] = myfilter(state, frame);
if isempty(state)
state = newstate;
end
%process frame using state
end
Usage:
[r, statestream1] = myfilter([], frame1(1));
[r, statestream2] = myfilter([], frame2(1));
[r, statestream1] = myfilter(statestream1, frame1(2));
[r, statestream2] = myfilter(statestream2, frame2(2));
Personally, I'd use classes for this.
Thanks a lot. I believe that version with container is more suitable for my functions.

Sign in to comment.

More Answers (1)

If you want to clear the persistent variable you need to do it explicitly:
clear example

Categories

Products

Community Treasure Hunt

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

Start Hunting!