Using A For Loop To Create Symbolic Variables - matlab

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.

Related

make iterative variable a cell array in matlab

In matlab, is it possible to make the iterative variable a cell array? is there a workaround? This is the code I ideally want, but throws errors:
dim={};
a=magic(5);
for dim{1}=1:5
for dim{2}=1:5
a(dim{:})=1; %aimed to be equivalent to a(dim{1},dim{2})=1;
end
end
for dim{1}=1:5
↑
Error: Invalid expression. When calling a function or indexing a variable, use
parentheses. Otherwise, check for mismatched delimiters.
I tested that you cannot have A(1), or A{1} or A.x as index variable. https://www.mathworks.com/help/matlab/ref/for.html doesn't explicitly prohibit that, but it doesn't allow it either.
After very slight changes on your code, this should achieve what you seem to want:
dim={};
a = magic(5);
for dim1=1:5
dim{1} = dim1;
for dim2=1:5
dim{2} = dim2;
a(dim{:})=1; %aimed to be equivalent to a(dim{1},dim{2})=1;
end
end
However, I believe the following is a slightly better solution keeping the spirit of "use a cell array to index in your array":
CV = combvec(1:5,1:5); % get all combinations from (1,1) to (5,5). 2x25 double array. This function is a part of deep learning toolbox. Alternatives are available.
CM = num2cell(CV); % 2x25 cell array. Each element is a single number.
for dim = CM
% dim is a 2x1 cell array, eg {2,3}.
a(dim{:}) = 1; % as above.
end
However, none of these are likely a good solution to the underlying problem.

Printing multiple disp functions with one for loop

So, I have a series of display functions, ranging from x1 to x7. These all contain both strings and variables like:
x1 = ['The result of the scalar multiplication of V and U: ',num2str(scalar_uv)];
x2 = similar to above but with for example a value on the cross multiplication of the two scalars.
Instead of printing out each one through:
disp(x1);
disp(x2);
disp(x3);
I thought it would be possible to print them all out through a for loop or perhaps a nested for loop but I just can't figure out how to do it. I preferably don't want straight up solutions (I won't say no to them) but rather some hints or tips of possible.
A simple example solution would be to make a cell array and loop through it, or use celldisp() to display it. But if you want to print nicely, i.e. formatted specifically, to the command window you can use the fprintf function and format in line breaks. For example:
for displayValue = {x1, x2, x3, x4}
fprintf('%s\n', displayValue{1});
end
If you want more formatting options, such as precision, or fieldwidth, the formatspec code (%s in the example) has many configurations. You can see them on the fprintf helpdoc. The \n just tells the fprintf function to create a newline when it prints.
Instead of creating seven different variables (x1...x7), just create a cell array to hold all your strings:
x{1} = ['The result of the scalar multiplication of V and U: ',num2str(scalar_uv)];
x{2} = ['Some other statement with a value at the end: ',num2str(somevar)];
Now you can write a loop:
for iX = 1:length(x)
disp(x{iX})
end
Or use cellfun to display them without a for loop:
cellfun(#disp,x)
If you really want to keep them named x1...x7, then you can use an eval statement to get your variable names:
for iX = 1:7
disp(eval(['x' num2str(iX)]));
end

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.

Double for loop, how to set non-continuous index?

If I want to construct a double for loop, but for index k I don't want it to be continuous index but like [1,2,4,7]. I tried to do the following, and it did not work.
for i=1:100
for k=1:2:4:7;
b(i)=i*k;
end
end
Anyone could help me deal with that?
When you want to construct an array, you don't want to necessarily use the colon (:) operator unless you want to create a range of values (like you do when you want i to be all values between 1 and 100), instead you want to use square brackets ([]) with comma separators to explicitly create an array of discrete values.
k = [1,2,4,7];
Now that you do this you can specify your loop like you had it with this small substitution for the values of k
kvalues = [1,2,4,7];
for i = 1:100
for k = 1:numel(kvalues)
b(i) = i * kvalues(k);
end
end
Notice that I have defined kvalues once outside of the loop so that it is not created every iteration through the outer loop (thanks to #dfri for pointing this oversight out)
The way that you have your loop written, you're actually over-writing the value of b(i) every time through the inner loop. I'm not sure if that's what you intended to do. If it is, then you can reduce your loop to the following:
b = k(end) * (1:100);
Otherwise, if you meant to have it be b(i,k) = i * k, you could rewrite this with bsxfun.
b = bsxfun(#mtimes, [1,2,4,7], (1:100).');
The syntax k=1:2:4:7 will not work as you intend. Usually we make use of the "two colon" syntax to describe a non-default (1) step size from the given start to end values, k = start:stepSize:end. Using an additional colon here even yields a Matlab warning ("third colon probably not intended?").
One possible workaround is to let your "non-continuous" indices reside in a vector and extract members of this vector in the inner for loop as follows
nonContIndex = [1; 2; 4; 7];
numIndices = numel(nonContIndex);
b = zeros(100,numIndices);
for i=1:100
for k=1:numIndices
b(i,k)=i*nonContIndex(k);
end
end
As noted by comments and the other answer: if b is simply a vector, your original loop will overwrite the b(i):th entry for each run of the inner loop. The above assumes that you in fact want a 2D matrix as a result.

Assigning dynamic values to variables in base workspace in 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.