Assigning dynamic values to variables in base workspace in MATLAB - matlab

load( lapFileSource, 'UntitledMeta_Data' );%My MetaData
universal={'TestType';'TestApparatus';'TestSystem Location';
'Configuration';'Wire condition';'Wire Type';'Circuit';};
u=11;
for o=drange(1:u)
if strcmp('',MetaData{o})
universal{o}='Null';
else
universal{o}=MetaData{o};
end
assignin('base','universal{o}',MetaData{o})
end
I am getting error to assignin the variable in workplace.

You need to read the documentation for the functions you use. From the documentation for assignin:
% The var input must be the array name only; it cannot contain array indices.
And, even more explicitly:
% assignin does not assign to specific elements of an array.
% The following statement generates an error:
X = 1:8;
assignin('base', 'X(3:5)', -1);
You can either shift your assignin call outside of the for loop and pass your full array to the base workspace, or you can follow the advice of the documentation and utilize evalin.
For example:
function trialcode
n = 5;
myarray = cell(1, 5);
for ii = 1:n;
if mod(ii,2)
myarray{ii} = 'odd';
else
myarray{ii} = 'even';
end
mycmd = sprintf('evalinarray{%u} = ''%s'';', ii, myarray{ii});
evalin('base', mycmd);
end
assignin('base','assigninarray', myarray)
end
The resulting arrays, evalinarray and assigninarray, are equivalent. Of the two, I would recommend using assignin as it is a lot more robust and explicit than the evalin approach.

Related

Variable classification error while storing structure within parfor

I have a function which runs a parfor loop. Within the loop, I call another function which generates a structure as a result. I need to store all the structures.
function myFunction(arguments)
% do some preliminary calcultions
parfor i = 1:num_sim % number of simulations
name = sprintf('result_%i',i)
% do some calculations and generate a structure as a result called "struct_result"
total_results.(name) = struct_result
end
end
This gives me an error message:
The variable total_results in a parfor cannot be classified.
How can I store the structure "struct_result" from all the simulations? It is a nested structure.
The problem here is that you are assigning to part of total_results during the loop, but not in a "sliced" manner. It's probably simpler to collect up the names and values separately, and then use cell2struct after the parfor loop, like this:
N = 10;
names = cell(1, N);
results = cell(1, N);
parfor i = 1:10
name = sprintf('result_%i',i)
names{i} = name;
results{i} = struct('a', rand(i), 'b', rand(i));
end
total_results = cell2struct(results, names, 2);
EDIT another way of slicing the outputs (as suggested in the comments) is to use
parfor i = 1:10
total_results(i).result = struct('a', rand(i), 'b', rand(i));
end
In this case, this works because the first-level indexing expression is a "sliced" expression.

Is it possible to change an anonymous function keeping the workspace?

What I would like to be able to do is programmatically change an anonymous function for example by changing all the plus signs to multiplication signs in the function. This example can in many cases this can be done as follows:
function f2 = changefunction(f1)
fs = func2str(f1);
fs(fs=='+') = '*';
f2 = str2func(fs);
end
But consider the example
f = #(x) x+5;
a = 5;
g = #(x) x+a;
Both f and g will be anonymous functions that adds 5 to whatever you plug into it; however only f will be changed correctly by the changefunction function, whereas g will be changed into a function that will err on any input.
So my question is is it possible to extract the workspace from the function handle and retain it in the new function handle created? I need to do it programmatically and preferably without using the built-in function functions!
One naive implementation is to replace str2func with eval so you are not running into str2func's roadblock of not allowing access to local variables. We can use functions to obtain the workspace information for the input function handle.
For example:
a = 5;
f = #(x) x+a;
finfo = functions(f)
Yields:
finfo =
struct with fields:
function: '#(x)x+a'
type: 'anonymous'
file: 'X:\testcode-matlab\testcode.m'
workspace: {[1×1 struct]}
within_file_path: 'testcode'
Where workspace is a cell array containing a structure (come on MathWorks...) containing all of the variables in your function handle's namespace:
>> wspace = finfo.workspace{1}
wspace =
struct with fields:
a: 5
Using this functionality, the naive solution is to loop through the variables in this workspace, assign them in the namespace of changefunction, then use eval to generate the new function handle.
For example:
function f2 = changefunction_new(f1)
tmp = functions(f1);
workspacevars = tmp.workspace{1};
varnames = fieldnames(workspacevars);
for ii = 1:length(varnames)
evalstr = sprintf('%s = %d;', varnames{ii}, workspacevars.(varnames{ii}));
eval(evalstr);
end
fs = func2str(f1);
fs(fs=='+') = '*';
f2 = eval(fs);
end
Here I'm assuming that the variables are going to be strictly numeric. You can add logic to check the class of the data to be generated if this is not always the case.
With this we have:
a = 5;
g = #(x) x+a;
test1 = changefunction(g);
test2 = changefunction_new(g);
>> g(1)
ans =
6
>> test1(1)
Undefined function or variable 'a'.
Error in testcode>#(x)x*a
>> test2(1)
ans =
5
All that being said, the best solution really is to just explicitly define your function handles. It may be a pain but it's much easier to understand and debug.
A few caveats:
Because eval arbitrarily executes all code passed to it, it can be a very dangerous function that must be used with care.
The documentation for functions warns against using it programmatically, so take care to check behavior as MATLAB versions change:
Use the functions function for querying and debugging purposes only.
Note: Do not use functions programmatically because its behavior could change in subsequent MATLAB® releases.
One possible way to do this is to save the function handle to a .mat file (using the -v7.3 flag so that it creates an easily-modifiable HDF5 file), modify the struct within the file that contains the workspace data for the anonymous function (using the HDF5 tools built into MATLAB), and then load the anonymous function again from the file.
Here is a little function which does exactly that (and it works for relatively simple variable types)
function result = modifyfunc(f, varname, value)
% modifyfunc - Modify the workspace of an anonymous function
%
% INPUTS:
% f: Function Handle, Anonymous function to modify
% varname: String, Name of the variable to modify
% value: Data to replace the specified variable
% If the value is a struct, recursively modify the function handle
if isstruct(value)
fields = fieldnames(value);
result = f;
% Modify each field separately
for k = 1:numel(fields)
% Append the fieldname to the variable name and modify
name = [varname, '.', fields{k}];
result = modifyfunc(result, name, value.(fields{k}));
end
return;
end
% Write the anonymous function to an HDF5 file
fname = tempname;
save(fname, 'f', '-mat', '-v7.3');
% Replace any "." in the variable name with "/" to construct the HDF5 path
varname = strrep(varname, '.' , '/');
% Now modify the data in the file
h5write(fname, ['/#refs#/e/' varname], value);
% Load the modified function handle from the file
result = load(fname, '-mat');
result = result.f;
% Remove the temporary file
delete(fname);
end
And you can use it like:
a = 1;
b = struct('field', 2);
f = #(x)disp(a + b.field + x);
f(10)
% 13
f2 = modifyfunc(f, 'a', 2);
f2(10)
% 14
f3 = modifyfunc(f2, 'b.field', 3);
f3(10)
% 15
b.field = 4;
f4 = modifyfunc(f3, 'b', b);
f4(10)
% 16
Some caveats include:
The replacement data must be the same size as the original data
This relies upon the format of the .mat file which for anonymous functions is completely undocumented so it could fail in future releases.
This currently doesn't work for variables in the function workspace that are cell arrays.

How does function work regarding to the memory usage?

When you are using function in MATLAB you have just the output of the function in the work space and all the other variables that maybe created or used in the body of that function are not shown. I am wondering how does function work? Does it clear all other variables from memory and just save the output?
function acts like a small, isolated programming environment. At the front end you insert your input (e.g. variables, strings, name-value pairs etc). After the function has finished, only the output is available, discarding all temporarily created variables.
function [SUM] = MySum(A)
for ii = 1:length(A)-1
SUM(ii) = A(ii)+A(ii+1);
kk(ii) = ii;
end
end
>> A=1:10
>> MySum(A)
This code just adds two consecutive values for the input array A. Note that the iteration number, stored in kk, is not output and is thus discarded after the function has completed. In MATLAB kk(ii) = ii; will be underlined orange, since it 'might be unused'.
Say you want to also retain kk, just add it to the function outputs:
function [SUM,kk] = MySum(A)
and keep the rest the same.
If you have large variables that you only use up to a certain point and wish them not clogging up your memory whilst the function is running, use clear for that:
function [SUM] = MySum(A)
for ii = 1:length(A)-1
SUM(ii) = A(ii)+A(ii+1);
kk(ii) = ii;
end
clear kk
end

Using A For Loop To Create Symbolic Variables

I am trying to create a large number of symbolic variables using a for loop, so that I do not have to type each individual variable. Here is my attempt:
for i 1:19
yi = sym('yi');
end
However, I am getting this error: Unexpected MATLAB expression.
I don't have access to the Symbolic Math Toolbox but see if this helps:
for i=1:19
eval(sprintf('y%d = sym(''y%d'')', i,i))
end
Although, I highly recommend against doing it this way.
You can use syms and a cell array to generate a comma-separated list to do this:
varname = 'y';
idx = 19;
y = arrayfun(#(x)char(x),sym(varname,[1 idx]),'UniformOutput',false);
syms(y{:})
which creates nineteen distinct symbolic variables. No need for the explicit use of eval. If you want arbitrary numbering this is more flexible and probably faster:
varname = 'y';
idx = [1:3 9:12 17:19];
y = arrayfun(#(x)sprintf([varname '%d'],x),idx,'UniformOutput',false);
syms(y{:})
There are other ways to create the cell array of strings, e.g., using only sprintf and textscan, but that is left as an exercise to the reader.
Here's another (simpler, but less elegant) option that uses the symfun creation capability of syms:
varname = 'y';
idx = 1:19;
y = sprintf([varname '%d,'],idx);
syms(['tmp(' y(1:end-1) ')']);
The symbolic function tmp can safely be cleared afterwards without bothering the other symbolic variables.

Using varargin inputs as structure name and string

Is there a way to use varargin inputs in several different forms. I would like the varargin inputs to become the name of a structure, but I also want it be passed into a fprintf which doesn't accept cell or structure arrays. If I have a function like:
function[] = myfunc(varargin)
for k = varargin
for m = 'ABC'
for n = 1:10
varname = sprintf('%c%d',m,n);
filename = sprintf('Images\\%s',varname);
fprintf('Take measurement %s for %s\n',k,varname);
image = imread(fullfile(filename));
pause
cursor_info = evalin('base','cursor_info');
p1 = cursor_info(2).Position
p2 = cursor_info(1).Position
[d,s] = measure(p1,p2) %measure is a separate function in my directory
k.(varname) = [d,s]
end
end
save('Distances,'k','-append')
end
My function is used to analyze several pictures, hence the ABC and 1:10 for loops. If I call the function with inputs of 'M1', 'M2', 'M3', I would like the function to create structures M1, M2, and M3 with A1,B1,C1 - A10,B10,C10 as the field names. [d,s] will be the data saved in each field which is found with the imagesc GUI and function measure.
The problem is that in the loop iterations I want the varargin inputs to be inputed into fprintf and I also want the varargin inputs to become the structure name. I can edit the code so that fprintf accepts the inputs using the function char. But is it possible to have an input in a function become the name of structure to fill with data? And if so, the solution still has to allow the iterator k to be passed into fprintf.
You can have a single structure that holds all k-s, then you can save it with '-struct' option to "strip" it into its fields:
function[] = myfunc(varargin)
for k = varargin
for m = 'ABC'
for n = 1:10
% your stuff here... I am too lazy to copy it...
[d,s] = measure(p1,p2) %measure is a separate function in my directory
meta.(k{1}).(varname) = [d,s] ; % note the {1} for k, loop over cell elements
end
end
save('Distances','meta','-struct','-append'); % not 100% sure -append wirks with -struct, you'll have to verify that...
end