Does A Function's Workspace Duplicate A Variable Input? - matlab

I have defined in the base Workspace a variable
a = ones(10);
And I would like to create function that inputs a vector vec1 and gives back vec2:
function vec2 = myfun(vec1)
Operations with vec1
end
Lets make
b = myfun(a);
In the Workspace of myfun we will have a variable called vec1 which has the same values as a but it is not in the base Workspace.
When being in Debugging Mode and using
dbup;
I can see two different variables a and vec1 in base and myfun Workspaces respectively.
Is myfun duplicating the variable a in two different Workspaces (and therefore using more memory)?
If this is not the case, how does it work? Is it a pointer assigning two different names to the same information?
Thank you in advance.

MATLAB uses a system commonly called "copy-on-write" to avoid making a copy of the input argument inside the function workspace until or unless you modify the input argument. If you do not modify the input argument, MATLAB will avoid making a copy. For instance, in this code:
function y = functionOfLargeMatrix(x)
y = x(1);
MATLAB will not make a copy of the input in the workspace of functionOfLargeMatrix, as x is not being changed in that function. If on the other hand, you called this function:
function y = functionOfLargeMatrix2(x)
x(2) = 2;
y = x(1);
then x is being modified inside the workspace of functionOfLargeMatrix2, and so a copy must be made.

Related

Inequality indexing using optimization variables in MATLAB

Let the variables A and B be n x 1 doubles and c be a scalar. My goal is to sum the values in A corresponding to indices for which the optimization variable x is greater than B. I have written this up below:
x = optimvar('x',n); % Creates optimization variable
objfun = sum(x); % Creates objective function
constraint = sum(A(x>=B))>=c; % Constraint based on logical indexing
The third line in the code above returns an error message because optimization variables are not compatible with inequality indexing. Specifically, x>=B cannot be input as indexes into A. Is there a way around this? Or am I thinking about this the wrong way?
Thank you!
You need to use function handles for both, the objective function as well as the constraint-function:
objfun = #(var) sum(var);
constraint = #(var) sum(A(var>=B)) >= c;
In fact, for the objective function objfun, you may also use objfun = #sum. This is a function handle. You can think of it as a pointer or reference to a certain function. Function, which work with one input can be used directly (with #). The optimizer calls the function and uses the optimization variable as input.
Now, if you have multiple inputs, you need to create a function, where you define all inputs but one. For this, you create an anonymous function handle, where you tell the handle what variables are placed where: #(var) sum(A(var>=B)) >= c. The variable var is the changing input and the other variables A, B, and c are taken from the workspace at the point of definition (i.e. the function handle is unaffected if you change the variables later or even delete them).

Can a Matlab Function create a global variable?

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.

Efficient Way to Generate Vector of Points Used in Recursive Scheme

I am implementing the adaptive Simpsons method in Matlab recursively. I wish to store all of the points where function evaluations take place to generate a histogram after integrating. I currently have:
function [S, points] = adsimp(f, a, b, fv, tol, level, points)
...
d = (a+b)*0.25;
e = (a+b)*0.75;
points = [points, d, e];
...
Thus, for every function call, I am increasing the length of points by two. My understanding of Matlab's function input/output scheme is poor. I'd like to know:
1) When the input and output share a variable name, does this use a single variable, or is a local copy made and then returned?
2) If it is a copy, is there a way to pass points by reference and preallocate sufficient memory?
To answer your first question, see here. Most MATLAB variables are passed by value (matrices, etc.) unless it is a handle object (function handle, axis handle etc.) A local copy of an input variable is made only if that variable is altered in the function. ie.
function y = doTheFunc1(x)
x(2) = 17;
y = x;
a copy must be made. As opposed to:
function y = doTheFunc2(x)
y = x(1);
where no copy need be made inside the function. In other words, MATLAB is a "copy on write" language. I am almost certain this is true regardless what your output variable output name is (ie. this holds even if your output and input are both named x).
To answer your second question, look at the first answer here. Consider using a nested function or a handle object.

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.

To link a value in an .M-file to a .MAT-file

I'm writing a program in MATLAB to solve integrals, and I have my function in a .M-file. Now I wonder how I can write a program in the .MAT-file that lets the user set a value that exists in the both files. The .M-file looks like this:
function fh = f(y)
fh = 62.5.*(b-y).*(40-20.*exp(-(0.01.*y).*(0.01.*y)));
and as you can see, the function depends on two variables, y and b. I want the user to set b. I tried putting b = input('Type in the value of b: ') in the .M-file but for some reason the user would then have to put in the same value four times.
Can I ask for the value of b in the .MAT-file?
Firstly, m-files store code (i.e. functions), while MAT-files store data (i.e. variables). You can save workspace variables to a MAT-file using the function SAVE and load them into a workspace from a file using the function LOAD. If you have a user choose a value for b, then save it to a MAT-file ('b_value.mat', for example), you can simply load the value from the MAT-file inside your m-file function like so:
function fh = f(y)
load('b_value.mat','b');
fh = 62.5.*(b-y).*(40-20.*exp(-(0.01.*y).*(0.01.*y)));
However, this is not a very good way to handle the larger problem I think you are having. It requires that you hardcode the name of the MAT-file in your function f, plus it will give you an error if the file doesn't exist or if b isn't present in the file.
Let's address what I think the larger underlying problem is, and how to better approach a solution...
You mention that you are solving integrals, and that probably means you are performing numerical integration using one or more of the various built-in integration functions, such as QUAD. As you've noticed, using these functions requires you to supply a function for the integrand which accepts a single vector argument and returns a single vector argument.
In your case, you have other additional parameters you want to pass to the function, which is complicated by the fact that the integration functions only accept integrand functions with a single input argument. There is actually a link in the documentation for QUAD (and the other integration functions) that shows you a couple of ways you can parameterize the integrand function without adding extra input arguments by using either nested functions or anonymous functions.
As an example, I'll show you how you can do this by writing f as an anonymous function instead of an m-file function. First you would have the user choose the parameter b, then you would construct your anonymous function as follows:
b = input('Type in the value of b: ');
f = #(y) 62.5.*(b-y).*(40-20.*exp(-(0.01.*y).^2));
Note that the value of b used by the anonymous function will be fixed at what it was at the time that the function was created. If b is later changed, you would need to re-make your anonymous function so that it uses the new value.
And here's an example of how to use f in a call to QUAD:
q = quad(f,lowerLimit,upperLimit);
In your m file declare b as a global
function fh = f(y)
global b
fh = 62.5.(b-y).(40-20.*exp(-(0.01.y).(0.01.*y)));
This allows the variable to be accessed from another file without having to create another function to set the value of b. You could also add b to the arguments of your fh function.