I have a script that calls a function, which is written in separate file and contains sub-functions that are inner to main function only. In one of my sub-functions, I have persistent variable that I would like to clear every time I run the main script. How can I do so? In addition, I have breakpoints through my code, and I would prefer to keep them while I clear the persistent variable - how that can be done?
MainScript.m script:
clear variables;
for iterNum=1:5
dataOut = MyMainFunction(iterNum);
end
disp(dataOut);
MyMainFunction code:
function dataOut = MyMainFunction(iterNum)
if (iterNum==1)
clear MySubFunction;
end
dataOut = MySubFunction();
end
function dataOut = MySubFunction()
persistent idx;
if isempty(idx)
idx=1;
end
dataOut=idx;
idx=idx+1;
end
I would like to clear "idx" persistent variable every time that I run MainScript.m, but of course to keep that variable as long as the script is running.
Thanks, John
The easiest way I see is to call clear followed the function name:
clear MySubFunction
instead of
clear variables;
This should clear all the persistent variables in that particular function. This will probably have the side effect of removing the stored JIT'd copy of it, causing it to be reparsed the next time it is invoked.
You can use munlock if you previously mlock'ed your function.
OR
You can define a special set of parameters in your function that are designed to solely clear the persistent variable, and you call the function with this syntax at the beginning of your main file.
Unfortunately, the other answer is partially incorrect - it is NOT possible to clear persistent variables in a sub-function using clear MySubFunction.
To quote an answer by a MathWorks staff member,
Only top level or main functions (with the same name as the file) may be cleared. To clear any local or nested function the main function must be cleared and that can't be done while the main function (or any other function in the file) is running.
and
Only whole m files can be cleared from memory. The entire file is managed as a unit so sub functions can't be cleared without clearing the main function.
As such, your options are to
separate the sub-function into its own m-file, or
clear the entire MyMainFunction from within MainScript.m, or
follow Ratbert's second suggestion, i.e. instead of using clear, give MySubFunction an additional argument that tells it to reset the persistent variables by itself
Related
I have a MATLAB program that I want to run in parallel so that it runs faster. However, when I do that parallel workers seem not to be able to access global variables created beforehand. Here is what my code looks like:
createData % a .m file that creates a global variable (Var)
parfor i:j
processData() % a function that is dependent on some global variables
end
However, I get an error message undefined function or variable Var. I've already included a call for global variables global Var inside the function processData() but this is not working either. Is there any way of making global variables visible within the parallel loop?
This is not the same question as here as I declared global variables outside of the parfor loop and want to access them within the loop with out the need to modify or update the its value across workers of the parallel loop.
The simplest advice is: don't use global for the myriad reasons already described/linked here. Ideally, you would restructure your code like so:
Var = createData(); % returns 'Var' rather than creating a global 'Var'
parfor idx = ...
% simply use 'Var' inside the parfor loop.
out(idx) = processData(Var, ...);
end
Note that parfor is smart enough to send Var to each worker exactly once for the above loop. However, it isn't smart enough not to send it across multiple times if you have multiple parfor loops. In that case, I would suggest using parallel.pool.Constant. How you use that depends on the cost of creating Var compared to its size. If it is small, but expensive to create - that implies you're best off creating it only once at the client and sending it to the workers, like this:
cVar = parallel.pool.Constant(Var);
If it is large, but relatively quick to construct, you could consider getting the workers each to construct their own copy independently, like this:
cVar = parallel.pool.Constant(#createData); % invokes 'createData' on each worker
Citing the author of the parallel toolbox:
GLOBAL data is hard to use inside PARFOR because each worker is a separate MATLAB process, and global variables are not synchronised from the client (or any other process) to the workers.
Emphasis mine. So the only way to get a global variable on a worker (which is a bad idea for reasons mentioned in the linked post) is to write a function which sets up the global variables, run that on each worker, then run your own, global-dependent function.
Citing another comment of mine to illustrate why this is a bad idea:
One of the pitfalls in terms of good practise is that you can suddenly overwrite a variable which is used inside a function in other functions. Therefore it can be difficult to keep track of changes and going back and forth between functions might cause unexpected behaviour because of that. This happens especially often if you call your global variables things like h, a etc (this of course makes for bad reading also when the variable is not global)
And finally an article outlining most of the reasons using global variables is generally a bad idea.
Bottom line: what you want is not possible, and generally thought to be bad practise.
I have a GUI callback that includes a for loop but compared to running the same code in a script, the data/variable being retrieved within the loop after the loop ends is not being recognized and instead MATLAB says that the variable is undefined. The script runs fine with the same inputs. I am well aware that scripts and functions have different workspaces, but does this mean that the recent data in a function after ending a loop is forgotten?
The callback belongs to a push button while the data I am handling in that callback is symbolic.
I would like to know what is causing this problem
There is difference between functions and scripts.
functions have their local variables. These variables are defined within the scope of that function only. Inside of a function is isolated from the caller scope. The only way to exchange data is input and output parameters of the function.
When the flow of program reaches to a function, all variables are stored in stack, and the execution of function starts without any variables except the input parameter. On the exit from function, all local variable defined in the function are deleted, and the stored variable on the stack will be returned back to the scope.
To circumvent this mechanism, you can use
global variables
assignin and evalin functions
But this is not considered as a procedural programming.
I have to work with a lot of data and run the same MATLAB program more than once, and every time the program is run it will store the data in the same preset variables. The problem is, every time the program is run the values are overwritten and replaced, most likely because all the variables are type double and are not a matrix. I know how to make a variable that can store multiple values in a program, but only when the program is run once.
This is the code I am able to provide:
volED = reconstructVolume(maskAlignedED1,maskAlignedED2,maskAlignedED3,res)
volMean = (volED1+volED2+volES3)/3
strokeVol = volED-volES
EF = strokeVol/volED*100
The program I am running depends on a ton more MATLAB files that I cannot provide at this moment, however I believe the double variables strokeVol and EF are created at this instant. How do I create a variable that will store multiple values and keep adding the values every time the program is run?
The reason your variables are "overwritten" with each run is that every function (or standalone program) has its own workspace where the local variables are located, and these local variables cease to exist when the function (or standalone program) returns/terminates. In order to preserve the value of a variable, you have to return it from your function. Since MATLAB passes its variables by value (rather than reference), you have to explicitly provide a vector (or more generally, an array) as input and output from your function if you want to have a cumulative set of data in your calling workspace. But it all depends on whether you have a function or a deployed program.
Assuming your program is a function
If your function is now declared as something like
function strokefraction(inputvars)
you can change its definition to
function [EFvec]=strokefraction(inputvars,EFvec)
%... code here ...
%volES initialized somewhere
volED = reconstructVolume(maskAlignedED1,maskAlignedED2,maskAlignedED3,res);
volMean = (volED1+volED2+volES3)/3;
strokeVol = volED-volES;
EF = strokeVol/volED*100;
EFvec = [EFvec; EF]; %add EF to output (column) vector
Note that it's legal to have the same name for an input and an output variable. Now, when you call your function (from MATLAB or from another function) each time, you add the vector to its call, like this:
EFvec=[]; %initialize with empty vector
for k=1:ndata %simulate several calls
inputvar=inputvarvector(k); %meaning that the input changes
EFvec=strokefraction(inputvar,EFvec);
end
and you will see that the size of EFvec grows from call to call, saving the output from each run. If you want to save several variables or arrays, do the same (for arrays, you can always introduce an input/output array with one more dimension for this purpose, but you probably have to use explicit indexing instead of just shoving the next EF value to the bottom of your vector).
Note that if your input/output array eventually grows large, then it will cost you a lot of time to keep allocating the necessary memory by small chunks. You could then choose to allocate the EFvec (or equivalent) array instead of initializing it to [], and introduce a counter variable telling you where to overwrite the next data points.
Disclaimer: what I said about the workspace of functions is only true for local variables. You could also define a global EFvec in your function and on your workspace, and then you don't have to pass it in and out of the function. As I haven't yet seen a problem which actually needed the use of global variables, I would avoid this option. Then you also have persistent variables, which are basically globals with their scope limited to their own workspace (run help global and help persistent in MATLAB if you'd like to know more, these help pages are surprisingly informative compared to usual help entries).
Assuming your program is a standalone (deployed) program
While I don't have any experience with standalone MATLAB programs, it seems to me that it would be hard to do what you want for that. A MathWorks Support answer suggests that you can pass variables to standalone programs, but only as you would pass to a shell script. By this I mean that you have to pass filenames or explicit numbers (but this makes sense, as there is no MATLAB workspace in the first place). This implies that in order to keep a cumulative set of output from your program you would probably have to store those in a file. This might not be so painful: opening a file to append the next set of data is straightforward (I don't know about issues such as efficiency, and anyway this all depends on how much data and how many runs of your function we're talking about).
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Declaring a global variable in MATLAB
Currently my matlab code is in one big script file with no internal functions. I would like to have functions declared within my script, to make my code more readable and reuse code etc. This in itself is not difficult in matlab, e.g.
Example 1:
function main()
myfunc('goat');
end
function myfunc(x)
fprintf(x);
end
My problem is that I have a biig datafile, which I want to load only once, such that I can re-run my code during development without spending time on re-loading the data. This is not a problem in my current framework with one big script with no internal functions. One solution is to have two matlab script files. One for loading data and then calling the functions in another script.
However in the above example 1 a true global variable declaration will not work, and I am forced load the biig file every time I run the script. What I would like to do can be shown in two examples:
Example 2:
% Global variable
if ~exist('data',var)
data = load biigdatafile.mat; %FAILS, outside function.
end
function main()
myfunc('goat');
end
function myfunc(x)
fprintf(x);
end
Example 3:
function main()
% Global variable
if ~exist('data',var)
global data; % Is not really global after whole script is completed.
data = load biigdatafile.mat;
end
myfunc('goat');
end
function myfunc(x)
fprintf(x);
end
So my question is how to declare a true global variable as in example 2, where I load my data once to stay in workspace, while calling my functions inside one script?
Use input arguments, that's what they're made for
You could just use arguments to the main function, load the dataset once into the base workspace and call your function with that dataset as an argument. If any subfunctions also use the dataset, pass it along
function main(data)
if nargin<1
disp('hey, you forgot to supply the dataset!');
end
% do your stuff
showData(data);
end
and then in the base workspace:
Data = load('biigdatafile.mat');
main(Data);
Use persistent variables
persistent X Y Z defines X, Y, and Z as variables that are local to the function in which they are declared; yet their values are retained in memory between calls to the function. Persistent variables are similar to global variables because the MATLAB software creates permanent storage for both. They differ from global variables in that persistent variables are known only to the function in which they are declared.
So you could easily use:
function main()
persistent data;
if isempty(data)
disp('loading dataset');
data=load('biigdatafile.mat');
end
% do your stuff
showData(data);
end
First time you call this function on a cleared base workspace or cleared function*, the dataset will be loaded. Every next time (when the function hasn't been edited), the dataset will already/still be in memory.
I usually do this when I'm just using one dataset; it's tedious to always load the dataset and when testing a function, it's also easier to just press F5.
* when is a function cleared you might ask?
Whenever you clear or modify a function that is in memory, MATLAB also clears all persistent variables declared by that function. To keep a function in memory until MATLAB quits, use mlock.
Global variables have to be declared everywhere they are used. Just add the global data to whereever you need it, and it will work.
It is not a duplicate of declaring global variables in matlab. A global var is only accesible to all functions, but when the script is complete, the global variables are gone and I need to read them into memory again.
What I need is to move the local variable into the base workspace and then access it again during other function calls. I actually solved it myself, just now with this code
function main()
try
Data = evalin('base','Data'); % Move back from base workspace
fprintf('Already loaded...\n');
catch
fprintf('Loading data...');
data = load biigdatafile.mat;
assignin('base', 'Data', Data); % Move to base workspace
fprintf('Ok\n');
end
showDocID(Data{1});
end
function showData(Data)
fprintf(['Data: "' Data '"\n']);
end
I've toto.m + model.mdl
from a function toto.m , I open model which load variable in workspace
after closing model I want to clear variables loaded in workspace
is there a way to do that without using clear all?
function toto
model = 'model1';
open_system(model1);
close_system(model1);
end
when I run the function the workspace isn't cleared , how could I clear variable only used by model without using clear all ?
You can use clear followed by a list of variables, for example clear a b c. However, I don't know whether there is a method that clears all the variables declared in a given script, though you can always use functions so all the variables in the scope of the function will be cleared when it ends.
If you want to clear all variables except those that existed already before running the script, you can temporarily store these already existing variable names and run clear afterwards using:
already_existing_vars = who;
% your actual script ...
% ...
% clear variables created in this script
vars_to_clear = setdiff(who,already_existing_vars);
clear(vars_to_clear{:},'vars_to_clear')