Define multiple variables efficiently - matlab

Is there a way to define multiple variables efficiently in matlab? Everything I've found isn't quite what I'm looking for. Here's the situation:
parstrs = {'a','b','c'};
parvals = [1 2 3];
I want an efficient command which would in effect do the following;
parstrs = parvals;
where the result is that the number 1 is stored in the variable a, 2 is stored in b, and 3 is stored in c, etc.
I'm open to doing this with cells or structs.
Any suggestions?
More clarification: As I mention below, I would like to write code that doesn't care how long the list of variable names is for use in curve fitting. The best way I've discovered is to use a structure, like the following:
parstrs = {'a','b','c'};
parvals = num2cell([1 2 3]);
partmp = {parstrs{:};parvals{:}};
pars = struct(partmp{:});
The problem with this is that the pars structure can't be edited in the same way. That is,
pars = setfield(pars,partmp{:});
will throw the following error:
Error using setfield (line 48)
Inputs must be either cell arrays or strings.

You're looking for eval, but that would probably still require a loop (yes you could generate a lengthy command, but do you really want that?):
Loop (please do not use this!):
for ii=1:numel(parvals)
eval([parstrs(ii) '=parvals(' ii ')']);
end
eval is most of the time totally not needed and discouraged; changing to cells is much easier to manage and use. You already have the variables in a vector, what's the problem with just using indexing to inspect them?
You should explain your application a bit more, so we can understand what you're really after, why you really want to use this kind of variable assignment.
For exporting variables outside from a gui to the base matlab environment, you can switch to evalin, and use it as follows:
function main_gui()
% do your thing, generate some values
parvals = [1 2 3];
% now is the time to export
give_me_my_vars({'a','b','c'});
% note that the following function is nested:
function give_me_my_vars(parstrs)
for ii=1:numel(parvals)
evalin('base',[parstrs(ii) '=' parvals(ii)]);
end
end
end
This is only possible for simple scalars, which fit in a string. I think you actually want to look for something to switch variables from one workspace to another (gui to base), but I don't know if that'd be possible.

You could use
parstrs = {'a','b','c'};
parvals = {'1' '2' '3'};
cellfun(#(x,y)evalin('caller', [x '=' y]), parstrs, parvals)
Alternatively, you could do something like
parstrs = {'a','b','c'};
parvals = {1 2 3};
parstrs = cellfun(#(x)[x ','], parstrs, 'UniformOutput', false);
eval(['[' parstrs{:} '] = deal(parvals{:});'])
However, as MATLAB's code analyzer will already complain about, this is a bit smelly. Usually, mass-defining variables using eval and friends is a sign you should think about a different approach.
For example, why do you even want to be able to address the values by separate variable name? Why is parvals(1), parvals(2) etc. not good enough?

You can create a structure with field names from parstrs with values taken from parvals like so:
parstrs = {'a', 'b', 'c'};
parvals = [1 2 3];
nValues = length(parvals);
for iValue = 1:nValues
s.(parstrs{iValue}) = parvals(iValue);
end
The structure, s, then looks like this:
s =
a: 1
b: 2
c: 3
So instead of a = 1, you'd have s.a = 1, but I think it's otherwise what you were after.

You could do something like:
[a, b] = function_returning_values();
You can also use eval.

Most of the chances that you can store the values in a single array:
x = [1 2 3];
Then, instead of writing a , write x(1) , instead of b write x(2), etc...

How about something like [a,b,c] = deal(1,2,3)? Or am I oversimplifying?

Related

save columns of matrix in vector variables in Matlab

In Matlab (R2021b) I am using some given function, which reads time-dependent values of several variables and returns them in a combined matrix together with a time vector. In the data matrix each column represents one vector of time-dependent values for one variable.
[data,time] = function_reading_data_of_several_values('filename');
For readability of the following code where the variables are further processed, I would like to store these columns in separate vector variables. I am doing it like that:
MomentX = data(1,:);
MomentY = data(2,:);
MomentZ = data(3,:);
ForceX = data(4,:);
ForceY = data(5,:);
ForceZ = data(6,:);
That is working. But is there some simpler (or shorter) way of assigning the column of the matrix to individual vectors? I am asking because in real program I have more than the 6 columns as in the example. Code is getting quite long. I was thinking of something similar to the line below, but that does not work:
[MomentX,MomentY,MomentZ,ForceX,ForceY,ForceZ] = data; %does not work
Do you have any idea? Thanks for help!
Update:
Thanks to the hint here in the group to use tables, a solution could be like this:
...
[data,time] = function_reading_data_of_several_values('filename');
% data in matrix. Each column representing a stime dependent variable
varNames = {'MomentX', 'MomentX',...}; % Names of columns
T=array2table(data','VariableNames',varNames); % Transform to Table
Stress = T.MomentX/W + T.ForceY/A %accesing table columns
...
This seems to work fine and readable to me.
Solution 1: In industrial solutions like dSpace, it is very common to do it in struct arrays:
mydata.X(1).time = [0.01 0.02 0.03 0.04];
mydata.Y(1).name = 'MomentX';
mydata.Y(1).data = [1 2 3 4];
mydata.Y(2).name = 'MomentY';
mydata.Y(2).data = [2 3 4 5];
Solution 2: It is also very common to create tables
See: https://de.mathworks.com/help/matlab/ref/table.html
As already commented, it is probably better to use a table instead of separate variables may not be a good idea. But if you want to, it can be done this way:
A = magic(6): % example 6-column matrix
A_cell = num2cell(A, 1); % separate columns in cells
[MomentX, MomentY, MomentZ, ForceX, ForceY, ForceZ] = A_cell{:};
This is almost the same as your
[MomentX,MomentY,MomentZ,ForceX,ForceY,ForceZ] = data; %does not work
except that the right-hand side needs to be a comma-separated list, which in this case is obtained from a cell array.

Is certain matlab-routine used in matlab script?

I am running a big m-file that I didn't write myself and that depends on certain subfunctions. I want to know if anywhere in all nested functions a particular function (in my case the function eig.m (to calculate eigenvalues) ) is used.
Is there a quick way to do this?
kind regards,
Koen
You can use the semi-documented function getcallinfo (see Yair Altman's blog for more information about it):
getcallinfo
Returns called functions and their first and last lines
This function is unsupported and might change or be removed without
notice in a future version.
General use of getcallinfo
Let's create an example script which contains subfunctions (this works in Matlab R2016b or newer) and save it as 'filename.m'. The procedure also works if there are nested functions, or if the main file is a function instead of a script.
x = input('');
y = find(x);
z = f(norm(x));
disp(z)
function u = f(v)
u = -log2(v) + log2(pi);
end
Then:
>> g = getcallinfo('filename.m');
gives you a nested struct array with interesting information, including function calls. The first entry, g(1), refers to the main file. There may be further entries for subfunctions or nested functions. In this case, g(2) refers to subfunction f.
>> g(1).calls.fcnCalls
ans =
struct with fields:
names: {'input' 'find' 'norm' 'disp' 'log2' 'log2' 'pi'}
lines: [1 2 3 4 6 6 6]
>> g(1).calls.innerCalls
ans =
struct with fields:
names: {'f'}
lines: 3
>> g(2).calls.fcnCalls
ans =
struct with fields:
names: {'log2' 'log2' 'pi'}
lines: [6 6 6]
>> g(2).calls.innerCalls
ans =
struct with fields:
names: {1×0 cell}
lines: [1×0 double]
Other fields of g give further details, such as name
>> g(1).name
ans =
filename
>> g(2).name
ans =
f
or type
>> g(1).type
ans =
Script with no properties.
>> g(2).type
ans =
subfunction
How to determine if a given function is used anywhere in the file
Obtain g as explained above, and then look for the desired function name in all calls.fcnCalls.names fields of g:
g = getcallinfo('filename.m');
sought_function = 'log2'; % or 'eig' in your case
t = arrayfun(#(x) x.calls.fcnCalls.names, g, 'UniformOutput', false);
% collect all names of called functions. Gives a cell array of cell arrays
% of strings (character vectors)
t = [t{:}]; % de-nest: concatenate into cell array of strings
result = any(strcmp(t, sought_function)); % compare with sought function name
One option to check by hand would be to use the profiler.
I'm using a 2014 Matlab, i cannot run the previous example. However, as far as i saw on the previous answer by Luis Mendo, it shows similar information but in a webpage style.
Basically, I would also suggest you use the profiler, which will list all called functions.
But to give you an alternative, if you are looking for just a single function (please see the disclaimer), you can utilize that functions in the current folder have precedence. Thus, say that you want to check if you use a function called jacobianest, then you create a new function in your folder called jacobianest.m with e.g.
function jacobianest(args)
error('jacobianest is being used')
end
then if the program terminates with that error, you are using jacobianest.
Disclaimer 1: This works only for the non-build-in functions. In the sense that if you type edit *name of function* and only comments come up, you cannot use this strategy. If the code itself shows up, you can.

Matlab vector Printing

How do i print a vector in matlab with also something before the values. For example i have a vector with the following values A' = [1 2 3]. I want to print it out in such a way that the output will be
w0 = 1
w1 = 2
w2 = 3
How do i do this?
Can i do this using a loop?
I am using the following code and i am not getting the right output
for qux = 1:3
fprintf('w%i=%.4lf\n',qux-1,answ);
end
Output:
w0=w1=w2
Your format string is not formed properly. Specifically '%.4lf' should be '%.4f'. Additionally, the third input to fprintf should be A(qux) to access the value in A.
for qux = 1:3
fprintf('w%i=%.4f\n', qux-1, A(qux));
end
I would, however, recommend using '%g' to use a format that optimizes the display of each number. Additionally, you could remove the for loop and do something like
A = [1, 2, 3];
fprintf('w%i = %g\n', [0:numel(A)-1; A])
If I have understand the question correctly, I think that you could do that with the following code:
for i = 1:3
disp(['w' num2str(A(i)-1) '=' num2str(A(i))]);
end
Using disp and num2str you could get the following output:
w0=1
w1=2
w2=3

Matlab: Automatically create cell array with name with meaning

I would like to name variable (type double) in the following way:
k0 = D(1,1);
k1 = D(2,2);
k2 = D(3,3);
k3 = D(4,4);
k4 = D(5,5);
k5 = D(6,6);
k6 = D(7,7);
k7 = D(8,8);
...
up to k99 automatically using for loop. So I see that I should use array or cell instead of double variable using eval as it is slow. But if I should use array or cell instead of double variable, I have to start at k{1} or k(1), which loses the meaning as I want exactly that k0 refers to D(1,1), i.e. the number in my variable is 1 less. How do I create meaningful cell name like k{0}?
Also, say I have an array A. There are also some times i need meaningful variable name, such as
c111 = A(1)*A(1)*A(1)
c222 = A(2)*A(2)*A(2)
c333 = A(3)*A(3)*A(3)
How can I create c{111} efficiently using for loop?
Use structures:
D = rand(21);
c = 1;
for k = -10:10
if k<0
s.(['k_' num2str(abs(k))]) = D(c,c);
else
s.(['k' num2str(k)]) = D(c,c);
end
c = c+1;
end
This will give you a structure like:
s =
k_10: 0.51785
k_9: 0.90121
k_8: 0.40746
k_7: 0.092989
.
.
k_1: 0.75522
k0: 0.55257
k1: 0.28708
.
.
k9: 0.94182
k10: 0.2124
and don't use eval...
Answer to 1st Question:-
D=randn(100); % A matrix of random elements of size 8x8
for m=0:99
assignin('base', ['k' num2str(m)], D(m+1,m+1))
end
Answer to 2nd Question:-
A=randn(1,3); % An array of 3 random elements
for n=1:3
assignin('base', ['c' num2str(111*n)], A(n)^3)
end
Comments:-
You've stated that you need variables like k0,k1,k2,... and c111,c222,c333 but you're asking how to create k{0}, k{1},k{2},... and c{111},c{222},c{333}. As far as your need is concerned, I have given answer to it. Regarding the latter, k{0} is never possible and c{111},c{222},c{333},... don't make good sense without using any of the first 0:100 values and then 112:221 values and so on. Although you can do it using:
A=rand(1,3); % An array of 3 random elements
c{333} = 0 ; % Pre-allocation
for p=1:3 % Since you want to use a 'for loop'
c{111*p} = A(p)^3;
end
And regarding the requirement that you made in the comment in these words "I also have some variable using negative index", you can never have variables in the negative index. If you mean you want to create variables with names like k-1, k-2,... etc, it is not possible. An alternate way is to use k_1, k_2,... etc but then as you said in the question "k0 refers to D(1,1), i.e. the number in my variable is 1 less". It means k_1 will refer to D(0,0) and so on which is again an invalid thing for MATLAB.
Recommendation:-
You really need to modify your code.

Create a total data with different subdata in MATLAB

I have several data named ET1_A_C1_l1, ET1_A_C2_l1, ET1_A_C3_l1, ..., ET1_A_C63_l1 in Workspace. Besides that,I also have another sets of data named ET1_H_C1_l1, ET1_H_C2_l1, ..., ET1_A_C63_l1
Now I need to combine 2 set of data into one named Total_data.mat; For example,
Total_data=[ET1_A_C1_l1 ET1_A_C2_l1 ET1_A_C3_l1 ..... ET1_A_63_l1;ET1_H_C1_l1 ET1_H_C2_l1 ....ET1_H_C63_l1]
and need to take a huge of time to type the code one by one. Is there any idea using the loop to do this??
Thanks.
Rather than jumping on my wagon straight away, I'll start with the solution (which has been set up with an example):
%# State the size of each matrix
T = 6; N = 2;
%# State the number of matrices in category A and H (63 in your case - but 2 in my example)
K = 2;
%# Set up some example matrices
ET1_A_C1_l1 = rand(T, N); ET1_A_C2_l1 = 1 + rand(T, N);
ET1_H_C1_l1 = 2 + rand(T, N); ET1_H_C2_l1 = 3 + rand(T, N);
%# Preallocate a matrix to hold the output
M = NaN(2 * T, K * N);
%# Loop over the variables and add them to the matrix using the evil eval
for k = 1:K
M(1:T, (k*N)-1:k*N) = eval(['ET1_A_C', num2str(k), '_l1']);
M(T+1:2*T, (k*N)-1:k*N) = eval(['ET1_H_C', num2str(k), '_l1']);
end
%# Save to a mat file
save('Total_Data.mat', 'M');
Now, wagon time: If you've been given the data in the form that you have it now, and there was nothing you could do about it, and you realize what a terrible situation it is to be in, then you can stop reading now.
But, if you were responsible for creating all those E_blah variables in the first place, then you need to take a look at the answer of #jerad and start thinking about different ways of storing data. A cell array or a structure is one way to go about it. Or start with one big matrix in the first place. But remember the following two general rules:
1) If you have more than 20 variables in your workspace, then you're probably doing it wrong.
2) If you find yourself frequently using the evil function eval then you're almost definitely doing it wrong.
Having this kind of problem suggests to me that you're not yet comfortable with the other data structures available in matlab... like cell arrays and structures. You could easily solve this problem by storing your data in a less arrays and then indexing them properly when needed.
Read about structures (this tutorial is excellent) in the matlab documentation and then try to use one to store all of your data. I think that will solve this problem and many others you didn't know you had.
You should be using something like the following.
ET = struct;
ET.A.C(1) = ET1_A_C1;
ET.A.C(2) = ET1_A_C2;
...
ET.A.C(N) = ET1_A_CN;
ET.H.C(1) = ET1_H_C1;
ET.H.C(2) = ET1_H_C2;
...
ET.H.C(N) = ET1_H_CN;
Now every thing is one variable which you can save without typing anything extra.
filename=Total_data.mat;
for i=1:63
J(i,1)=ET1_A_C{i};
J(i,2)=ET1_H_C{i};
end
save(filename,'J(1:63,1)','J(1:63,2)');