Can a Matlab Function create a global variable? - matlab

I'm using Octave (or Matlab... I have both available), and trying to make a function that will setup my important variables used throughout the rest of my investigation.
However by default, variables declared in a function have a limited scope of that function only.
Is there a way to do this?
function defineBasicTerms()
global G = 9.807;
global F = [exp(1) 0; 0 1/exp(1)];
endfunction
such that after this function is called, variables G and F exist in the set of globally named variables?

Global variables require to be declared in each scope in which they are used. For example, if you have a function M-file defineBasicTerms.m containing:
function defineBasicTerms
global G = 9.807;
end
then in the base workspace you can write:
defineBasicTerms
G % produces error: variable doesn't exist
global G
G % gives 9.807
Next, in a function that will use the constant G:
function out = computeSomethingImportant(m)
global G
out = G * m;
end
That is, every time we want to use G we need to do global G to be access the global variable G.
Note that this is a very dangerous situation. Two things can go wrong:
Some function assigns to the global variable G, changing its value for the rest of the current session. It is really hard to know that this has happened, but computeSomethingImportant will return the wrong values from this point on, until we again call defineBasicTerms.
We call computeSomethingImportant before calling defineBasicTerms during the session.
The established method in MATLAB (and by extension in Octave) to define a constant is through a function. Functions can be written to always return the same value (MATLAB has no other way to declare a variable to be constant), and functions are automatically available in all workspaces and all contexts (as long as the function is on the path of course).
In your example, we'd write an M-file function G.m containing:
function value = G
value = 9.807;
end
Now, in the base workspace:
G % gives 9.807
The function that uses the constant G now looks simply like this:
function out = computeSomethingImportant(m)
out = G * m;
end
Note that constants such as pi are defined in this way in MATLAB and Octave.
You would have to write one function M-file for each of the constants you want to declare. There is an alternative method that involves a class with static values, so that all constants can be defined in a single file. The syntax then however becomes different, one would need to use constants.G, or something like that, to access the content value.

Related

using global variable in other functions in matlab [duplicate]

Is there a way to declare global variables in MATLAB?
Please don't respond with:
global x y z;
Because I can also read the help files.
I've declared a global variable, x, and then done something like this:
function[x] = test()
global x;
test1();
end
Where the function test1() is defined as:
function test1()
x = 5;
end
When I run test(), my output is x = []. Is there a way I can make it output the x=5, or whatever I define x to be in a separate function? In C, this would be an external variable, and I thought making it a global variable should accomplish just that.
You need to declare x as a global variable in every scope (i.e. function/workspace) that you want it to be shared across. So, you need to write test1 as:
function test1()
global x;
x = 5;
end
Referring to your comment towards gnovice using a global variable can be an approach to solve your issue, but it's not a commonly used.
First of all make sure that your .m files are functions and not scripts. Scripts share a common workspace, making it easy to unwillingly overwrite your variables. In contrast, functions have their own scope.
Use xUnit in order to generate repeatable unit test for your functions. By testing each function involved in your program you will track down the error source. Having your unit test in place, further code modifications, can be easily verified.
A possible way to get around the global mess is to assign the variable as appdata. You can use the functions setappdata and getappdata to assign and retrieve appdata from a MATLAB window. As long as a MATLAB session is active there exists a window denoted by 0.
>> setappdata(0,'x',10) % 0 indicates the root MATLAB window
Now the variable x is not visible to any script or function but can be accessed wherever needed by using getappdata.
function test
globalX = getappdata(0,'x');
disp(globalX);
end
x =
10
The good news is that you can assign any valid MATLAB object to appdata, just be cautious with the names, using unique names for appdata fields like ModelOptimizerOptions instead of a generic x,y would help. This works on compiled executables and code deployed on the MATLAB production server as well.

Variables in Matlab declared inside a nested condition are then accessed outside of the scope

This doesn't make sense in any other language I've seen:
for...
if (...)
if (...)
ids = [1,2,3;4,5,6]
end
end
end
K = ids(:,3)
I can't find any reference in the Matlab docs, but that to me in C, Ruby, Javascript, PHP, Java, Python, heck even Ada95, should not work. It's not in the input parameters of the function, it's not declared anywhere else.
This approach is used twice in this code attached to a paper though. Can anyone shed light? Is there just global scope in Matlab?
The variable first declared and defined inside a loop is not global, but you can declare a variable just about anywhere. I don't believe there is scope more local than a function. In general, scope is very broad in MATLAB. I'd agree that the scope of a non-global variable is limited to the function in which it's defined, but there are a couple of unusual ways in which variables can get passed around in MATLAB.
One oddity that seems to defy usual scope rules is function handles. Unlike many other languages where a function handle is little more than a pointer to the function in memory, MATLAB stores a workspace for a function handle. For example:
>> a = pi;
>> aFun = #(r) a*r.^2;
>> a = 1
>> aFun(1/sqrt(2))
ans =
1.5708
The handle swallows up the initial value of a:
>> finfo = functions(aFun)
finfo =
function: '#(r)a*r.^2'
type: 'anonymous'
file: ''
workspace: {[1x1 struct]}
>> finfo.workspace{1}
ans =
a: 3.1416
Function handles to nested functions are also another way to make a variable accessible outside of their original scope, including the nested function itself, which can even be made accessed outside of that file! Again it does it by storing the value at the time the handle is created. Consider the function:
function [y,hf] = nestTest(x)
a = 2; b = 1;
y = nestFun(x);
hf = #nestFun;
function y = nestFun(x)
y = a*x + b;
end
end
It calls the nested function, but also returns a handle to it. It would seem to not be defining a and b, but it works:
>> [y,hf] = nestTest(2)
y =
5
hf =
#nestTest/nestFun
And so does the handle:
>> hf(2)
ans =
5
Again because it stores an internal workspace with the values that it inherited when it was defined:
>> finfo = functions(hf)
finfo =
function: 'nestTest/nestFun'
type: 'nested'
file: 'C:\Users\Jon.bobs-tavern\Documents\MATLAB\nestTest.m'
workspace: {[1x1 struct]}
>> finfo.workspace{1}
ans =
y: 5
hf: #nestTest/nestFun
x: 2
a: 2
b: 1
See Preserving Data from the Workspace for more info. Also, the MATLAB editor has highlighting to help indicate scope.
Another thing to keep in mind, which should be familiar to users of other programming languages, is the stack (or the workspace in which the variable exists). You can use assignin to directly assign a variable to the caller or "base" workspace.
I believe (though if someone wishes to contradict me I'll be interested to learn) that MATLAB variable scope is limited to the function it's defined in, not the block. So a variable defined within an if-else block within a function is accessible outside that block, but only within the same function. Basically, each function has its own workspace, and variables defined within that function all go into that workspace. It gets a bit more complicated when we start using nested functions and such, and for that I refer you to the very helpful Art of MATLAB Blog.
For your second question, MATLAB does has global scope - functions defined as
global var
are defined within the global workspace, and can be accessed anywhere* in MATLAB. If you define a variable as global within one function, you can access the variable in another function by repeating the global var statement. Read here for more information.
*Note that global variables don't work well with parallelised code (for instance, within a par-for loop.

make matlab variable in workspace as global

In the workspace I make a matrix .
Now I can access the variable in script. Like doing Variable(2) will return 4.
But inside a function like
function y= getvariable(x)
y=Variable(x)
end
I get error
y=getvariable(2)
??? Undefined function or method 'Variable' for input
arguments of type 'double'.
Error in ==> getvariable at 3
y=Variable(x)
So how to make the Variable matrix global so that I can access it through any function?
Although you could use globals
>> global Variable = rand(50,12);
...
function y = getvariable(x)
% Always needed
global Variable;
% Here ya go
y = Variable;
end
the MUCH better alternative is to use
function x = getvariable(x)
% no body needed
end
which you call as
>> y = getvariable(Variable);
(Of course, for this contrived example, this would just be equal to
>> y = Variable;
)
Although there are some legitimate use cases for global variables, in general they tend to spaghettify your code and make it far more bug-prone and much harder to debug. Have a read on the subject.
As #rody suggested, pass the matrix and the x inside the function
I am just giving an example to make things clear.
Like you want to access the 10th element of Variable matrix, so make the function as
function y= getvariable(matrixname,no)
y=matrixname(no)
end
If you want to access 3rd element of Variable, so you type
y=getvariable(Variable,3)
you will get 3rd element
call global Variable before you define it in your workspace
call global Variable before you use it in your function
However I suggest you think of other ways to pass variables to your function, as globals might cause difficulties during debugging.

Matlab function handle workspace shenanigans

In short: is there an elegant way to restrict the scope of anonymous functions, or is Matlab broken in this example?
I have a function that creates a function handle to be used in a pipe network solver. It takes as input a Network state which includes information about the pipes and their connections (or edges and vertices if you must), constructs a large string which will return a large matrix when in function form and "evals" that string to create the handle.
function [Jv,...] = getPipeEquations(Network)
... %// some stuff happens here
Jv_str = ['[listConnected(~endNodes,:)',...
' .* areaPipes(~endNodes,:);\n',...
anotherLongString,']'];
Jv_str = sprintf(Jv_str); %// This makes debugging the string easier
eval(['Jv = #(v,f,rho)', Jv_str, ';']);
This function works as intended, but whenever I need to save later data structures that contain this function handle, it requires a ridiculous amount of memory (150MB) - coincidentally about as much as the entire Matlab workspace at the time of this function's creation (~150MB). The variables that this function handle requires from the getPipeEquations workspace are not particularly large, but what's even crazier is that when I examine the function handle:
>> f = functions(Network.jacobianFun)
f =
function: [1x8323 char]
type: 'anonymous'
file: '...\pkg\+adv\+pipe\getPipeEquations.m'
workspace: {2x1 cell}
...the workspace field contains everything that getPipeEquations had (which, incidentally is not the entire Matlab workspace).
If I instead move the eval statement to a sub-function in an attempt to force the scope, the handle will save much more compactly (~1MB):
function Jv = getJacobianHandle(Jv_str,listConnected,areaPipes,endNodes,D,L,g,dz)
eval(['Jv = #(v,f,rho)', Jv_str, ';']);
Is this expected behavior? Is there a more elegant way to restrict the scope of this anonymous function?
As an addendum, when I run the simulation that includes this function several times, clearing workspaces becomes painfully slow, which may or may not be related to Matlab's handling of the function and its workspace.
I can reproduce: anonymous functions for me are capturing copies of all variables in the enclosing workspace, not just those referenced in the expression of the anonymous function.
Here's a minimal repro.
function fcn = so_many_variables()
a = 1;
b = 2;
c = 3;
fcn = #(x) a+x;
a = 42;
And indeed, it captures a copy of the whole enclosing workspace.
>> f = so_many_variables;
>> f_info = functions(f);
>> f_info.workspace{1}
ans =
a: 1
>> f_info.workspace{2}
ans =
fcn: #(x)a+x
a: 1
b: 2
c: 3
This was a surprise to me at first. But it makes sense when you think about it: because of the presence of feval and eval, Matlab can't actually know at construction time what variables the anonymous function is actually going to end up referencing. So it has to capture everything in scope just in case they get referenced dynamically, like in this contrived example. This uses the value of foo but Matlab won't know that until you invoke the returned function handle.
function fcn = so_many_variables()
a = 1;
b = 2;
foo = 42;
fcn = #(x) x + eval(['f' 'oo']);
The workaround you're doing - isolating the function construction in a separate function with a minimal workspace - sounds like the right fix.
Here's a generalized way to get that restricted workspace to build your anonymous function in.
function eval_with_vars_out = eval_with_vars(eval_with_vars_expr, varargin)
% Assign variables to the local workspace so they can be captured
ewvo__reserved_names = {'varargin','eval_with_vars_out','eval_with_vars_expr','ewvo__reserved_names','ewvo_i'};
for ewvo_i = 2:nargin
if ismember(inputname(ewvo_i), ewvo__reserved_names)
error('variable name collision: %s', inputname(ewvo_i));
end
eval([ inputname(ewvo_i) ' = varargin{ewvo_i-1};']);
end
clear ewvo_i ewvo__reserved_names varargin;
% And eval the expression in that context
eval_with_vars_out = eval(eval_with_vars_expr);
The long variable names here hurt readability, but reduce the likelihood of collision with the caller's variables.
You just call eval_with_vars() instead of eval(), and pass in all the input variables as additional arguments. Then you don't have to type up a static function definition for each of your anonymous function builders. This'll work as long as you know up front what variables are actually going to be referenced, which is the same limitation as the approach with getJacobianHandle.
Jv = eval_with_vars_out(['#(v,f,rho) ' Jv_str],listConnected,areaPipes,endNodes,D,L,g,dz);
Anonymous functions capture everything within their scope and store them in the function workspace. See MATLAB documentation for anonymous functions
In particular:
"Variables specified in the body of the expression. MATLAB captures these variables and holds them constant throughout the lifetime of the function handle.
The latter variables must have a value assigned to them at the time you construct an anonymous function that uses them. Upon construction, MATLAB captures the current value for each variable specified in the body of that function. The function will continue to associate this value with the variable even if the value should change in the workspace or go out of scope."
An alternative workaround to your problem, is to use the fact that the matlab save function can be used to save only the specific variables you need. I have had issues with the save function saving way too much data (very different context from yours), but some judicial naming conventions, and use of wildcards in the variables list made all my problems go away.

Declaring a global variable in MATLAB

Is there a way to declare global variables in MATLAB?
Please don't respond with:
global x y z;
Because I can also read the help files.
I've declared a global variable, x, and then done something like this:
function[x] = test()
global x;
test1();
end
Where the function test1() is defined as:
function test1()
x = 5;
end
When I run test(), my output is x = []. Is there a way I can make it output the x=5, or whatever I define x to be in a separate function? In C, this would be an external variable, and I thought making it a global variable should accomplish just that.
You need to declare x as a global variable in every scope (i.e. function/workspace) that you want it to be shared across. So, you need to write test1 as:
function test1()
global x;
x = 5;
end
Referring to your comment towards gnovice using a global variable can be an approach to solve your issue, but it's not a commonly used.
First of all make sure that your .m files are functions and not scripts. Scripts share a common workspace, making it easy to unwillingly overwrite your variables. In contrast, functions have their own scope.
Use xUnit in order to generate repeatable unit test for your functions. By testing each function involved in your program you will track down the error source. Having your unit test in place, further code modifications, can be easily verified.
A possible way to get around the global mess is to assign the variable as appdata. You can use the functions setappdata and getappdata to assign and retrieve appdata from a MATLAB window. As long as a MATLAB session is active there exists a window denoted by 0.
>> setappdata(0,'x',10) % 0 indicates the root MATLAB window
Now the variable x is not visible to any script or function but can be accessed wherever needed by using getappdata.
function test
globalX = getappdata(0,'x');
disp(globalX);
end
x =
10
The good news is that you can assign any valid MATLAB object to appdata, just be cautious with the names, using unique names for appdata fields like ModelOptimizerOptions instead of a generic x,y would help. This works on compiled executables and code deployed on the MATLAB production server as well.