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

12 vues (au cours des 30 derniers jours)
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.

Réponse acceptée

Guillaume
Guillaume le 19 Fév 2015
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 commentaires
Guillaume
Guillaume le 19 Fév 2015
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.
Alex Antipin
Alex Antipin le 24 Fév 2015
Thanks a lot. I believe that version with container is more suitable for my functions.

Connectez-vous pour commenter.

Plus de réponses (1)

Alessandro Masullo
Alessandro Masullo le 19 Fév 2015
If you want to clear the persistent variable you need to do it explicitly:
clear example

Produits

Community Treasure Hunt

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

Start Hunting!

Translated by