How to create serially numbered variables in workspace? [duplicate] - matlab

This question already has answers here:
Dynamic variables matlab
(2 answers)
Closed 8 years ago.
I was wondering how I can use a for loop to create multiple matrix when given a certain number.
Such as If 3 was given I would need three matricies called: C1, C2 and C3.
k = 3
for i = 1:K
C... = [ ]
end
Not sure how to implement this.

The first thing coming in mind is the eval function mentioned by Dennis Jaheruddin, and yes, it is bad practice. So does the documentation say:
Why Avoid the eval Function?
Although the eval function is very powerful and flexible, it not
always the best solution to a programming problem. Code that calls
eval is often less efficient and more difficult to read and debug than
code that uses other functions or language constructs. For example:
MATLAB® compiles code the first time you run it to enhance performance for future runs. However, because code in an eval
statement can change at run time, it is not compiled.
Code within an eval statement can unexpectedly create or assign to a variable already in the current workspace, overwriting existing
data.
Concatenating strings within an eval statement is often difficult to read. Other language constructs can simplify the syntax in your
code.
The "safer" alternative is the function assignin:
The following will do exactly what you want:
letter = 'C';
numbers = 1:3;
arrayfun(#(x) assignin('base',[letter num2str(x)],[]),numbers)
I know cases where you need to create variables likes this, but in most cases it is better and more convenient to use cell arrays or structs.

The trick is to use a cell array:
k=3
C=cell(k,1)
for t=1:k
C{t}= rand(t)
end
If each matrix is of equal size, you would probably just want a three dimensional matrix rather than a cell array.
You now have one cell array,but can access the matrices like this:
C{2} %Access the second matrix.

The use of eval is almost inevitable in this case:
k = 3;
for i = 1:k
eval(sprintf('C%d = [];', i));
end;
Mind you that generating variable names for data storage rather than indexing them (numerically -- see the solution of Dennis Jaheruddin based on cell arrays -- or creating a dynamic struct with named fields that store the data) is almost always a bad idea. Unless you do so to cope up with some weird scripts that you don't want to / cannot modify that need some variables already created in the global workspace.

Related

Get variable content from his name Matlab [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I want to get the content of a variable from its name as a string:
%suppose that I have structures variables in the workspace:
struct_1=struct('field1' ,"str",'field2',0:5)
struct_2=struct('field1' ,"str",'field2',0:10)
struct_3=struct('field1' ,"str",'field2',0:20)
%and I have an other variable like:
a=5
var2='hello'
%and I want to concatenate all these structures in the same structure
%So i wan to get their name.
%I don't know if there is an other way to get just the structure variables
structures=who(str*)
array=[]
for i=1:length(structures)
array=[array; structures(i). field2]; % here I get an error because the content of structures are string representing the variable name
end
%create the new struct
str='newstr_value'
struct_4=struct('field1',str, 'field2',array)
How to fix this error and is there any way to do this better ?
While I would still highly recommend going back to the point of origin of these dynamically named structures (shame 🔔🔔🔔 on the toolbox creator if this is actually the output...) and fixing this problem there, there is an approach that does not require the use of eval.
Similar to my approach for a tangentially related question, you can save the desired structures to a temporary *.mat file and take advantage of load's optional structure output to consolidate the data structures for access in a more robust programmatic matter.
For example:
struct_1=struct('field1' ,"str",'field2',0:5);
struct_2=struct('field1' ,"str",'field2',0:10);
struct_3=struct('field1' ,"str",'field2',0:20);
save('tmp.mat', '-regexp', '^struct_');
clear
oldworkspace = load('tmp.mat');
varnames = fieldnames(oldworkspace);
nvars = numel(varnames);
% Get original structure fields
% The subsequent steps assume that all input structs have the same fields
fields = fieldnames(oldworkspace.(varnames{1}));
nfields = numel(fields);
% Initialize output struct
for ii = 1:nfields
newstruct.(fields{ii}) = [];
end
newstruct(nvars) = newstruct;
for ii = 1:nvars
for jj = 1:nfields
newstruct(ii).(fields{jj}) = oldworkspace.(varnames{ii}).(fields{jj});
end
end
Gives us:
Yay.
Not sure if your situation absolutely requires dynamic calls of variables by their string names. eval can solve your problem. However, eval is slow. At times, it is unreliable. You can easily have conflicting code as you build various components of your project. And in my experience, there have always been alternatives to eval. In your case, Adriaan outlined an example in his comment.
Since you are only trying to interface with a third-party toolbox, if the number of variables you read is reasonable, you can do the followings with eval.
array=struct;
for i=1:length(structures)
eval(['array(',num2str(i),').field2=',structures{i},';'])
end
If you know all the structs are named struct_#, you can also do
array=struct;
num=3; % the number of outputs from your toolbox
for i=1:num
eval(['array(',num2str(i),').field2=struct_',num2str(i),'.field2;'])
end
Note that your field2 values are all arrays. You can't just create an array and expect each "cell" to carry another array value. Arrays, or rather matrices, in Matlab are a special data type. They only take numerical values. (Matrices are highly optimized in Matlab in various ways. That is why we use Matlab.)
Also note that when you set equality of fields of structs, the equality is by reference. There is no deep copy of the data. Modifying one will modify another. (Just beware of this but don't necessarily rely on it. Deciding when to deep copy things is one of the things we let Matlab handle.)
As well, be careful with the result from who. You need to be absolutely clear with what is in the local scope. Above is assuming your result from calling structures=who(str*) is correct for your application.

Clean methodology for running a function for a large set of input parameters (in Matlab)

I have a differential equation that's a function of around 30 constants. The differential equation is a system of (N^2+1) equations (where N is typically 4). Solving this system produces N^2+1 functions.
Often I want to see how the solution of the differential equation functionally depends on constants. For example, I might want to plot the maximum value of one of the output functions and see how that maximum changes for each solution of the differential equation as I linearly increase one of the input constants.
Is there a particularly clean method of doing this?
Right now I turn my differential-equation-solving script into a large function that returns an array of output functions. (Some of the inputs are vectors & matrices). For example:
for i = 1:N
[OutputArray1(i, :), OutputArray2(i, :), OutputArray3(i, :), OutputArray4(i, :), OutputArray5(i, :)] = DE_Simulation(Parameter1Array(i));
end
Here I loop through the function. The function solves a differential equation, and then returns the set of solution functions for that input parameter, and then each is appended as a row to a matrix.
There are a few issues I have with my method:
If I want to see the solution to the differential equation for a different parameter, I have to redefine the function so that it is an input of one of the thirty other parameters. For the sake of code readability, I cannot see myself explicitly writing all of the input parameters as individual inputs. (Although I've read that structures might be helpful here, but I'm not sure how that would be implemented.)
I typically get lost in parameter space and often have to update the same parameter across multiple scripts. I have a script that runs the differential-equation-solving function, and I have a second script that plots the set of simulated data. (And I will save the local variables to a file so that I can load them explicitly for plotting, but I often get lost figuring out which file is associated with what set of parameters). The remaining parameters that are not in the input of the function are inside the function itself. I've tried making the parameters global, but doing so drastically slows down the speed of my code. Additionally, some of the inputs are arrays I would like to plot and see before running the solver. (Some of the inputs are time-dependent boundary conditions, and I often want to see what they look like first.)
I'm trying to figure out a good method for me to keep track of everything. I'm trying to come up with a smart method of saving generated figures with a file tag that displays all the parameters associated with that figure. I can save such a file as a notepad file with a generic tagging-number that's listed in the title of the figure, but I feel like this is an awkward system. It's particularly awkward because it's not easy to see what's different about a long list of 30+ parameters.
Overall, I feel as though what I'm doing is fairly simple, yet I feel as though I don't have a good coding methodology and consequently end up wasting a lot of time saving almost-identical functions and scripts to solve fairly simple tasks.
It seems like what you really want here is something that deals with N-D arrays instead of splitting up the outputs.
If all of the OutputArray_ variables have the same number of rows, then the line
for i = 1:N
[OutputArray1(i, :), OutputArray2(i, :), OutputArray3(i, :), OutputArray4(i, :), OutputArray5(i, :)] = DE_Simulation(Parameter1Array(i));
end
seems to suggest that what you really want your function to return is an M x K array (where in this case, K = 5), and you want to pack that output into an M x K x N array. That is, it seems like you'd want to refactor your DE_Simulation to give you something like
for i = 1:N
OutputArray(:,:,i) = DE_Simulation(Parameter1Array(i));
end
If they aren't the same size, then a struct or a table is probably the best way to go, as you could assign to one element of the struct array per loop iteration or one row of the table per loop iteration (the table approach would assume that the size of the variables doesn't change from iteration to iteration).
If, for some reason, you really need to have these as separate outputs (and perhaps later as separate inputs), then what you probably want is a cell array. In that case you'd be able to deal with the variable number of inputs doing something like
for i = 1:N
[OutputArray{i, 1:K}] = DE_Simulation(Parameter1Array(i));
end
I hesitate to even write that, though, because this almost certainly seems like the wrong data structure for what you're trying to do.

Replace values in an array in matlab without changing the original array

My question is that given an array A, how can you give another array identical to A except changing all negatives to 0 (without changing values in A)?
My way to do this is:
B = A;
B(B<0)=0
Is there any one-line command to do this and also not requiring to create another copy of A?
While this particular problem does happen to have a one-liner solution, e.g. as pointed out by Luis and Ian's suggestions, in general if you want a copy of a matrix with some operation performed on it, then the way to do it is exactly how you did it. Matlab doesn't allow chained operations or compound expressions, so you generally have no choice but to assign to a temporary variable in this manner.
However, if it makes you feel better, B=A is efficient as it will not result in any new allocated memory, unless / until B or A change later on. In other words, before the B(B<0)=0 step, B is simply a reference to A and takes no extra memory. This is just how matlab works under the hood to ensure no memory is wasted on simple aliases.
PS. There is nothing efficient about one-liners per se; in fact, you should avoid them if they lead to obscure code. It's better to have things defined over multiple lines if it makes the logic and intent of the algorithm clearer.
e.g, this is also a valid one-liner that solves your problem:
B = subsasgn(A, substruct('()',{A<0}), 0)
This is in fact the literal answer to your question (i.e. this is pretty much code that matlab will call under the hood for your commands). But is this clearer, more elegant code just because it's a one-liner? No, right?
Try
B = A.*(A>=0)
Explanation:
A>=0 - create matrix where each element is 1 if >= 0, 0 otherwise
A.*(A>=0) - multiply element-wise
B = A.*(A>=0) - Assign the above to B.

How to use a M-.file in a parfor loop in Matlab?

my code inside a parfor loop is getting longer and longer and I would like to split it up. Having parts of the code saved in different script files seems logical and very attractive and since it doesn't change anything except where the code is saved it seems like it should work. But it doesn't.
I get the usual "Transparency violation error".
The problem seems typical but I did not find this question asked or answered anywhere.
Below is a small working example.
(Yes, this could be made as a function. But in case of many more Input and Output variables this becomes really ugly imo and probably also slower due to communicating the arguments)
C = NaN(10,1); %Result vector
parfor loop = 1:10
a = 1;
b = 2;
MFile_Test %Run the m-file which contains only one line:
% c = a + b;
C(loop)=c;
end
the MFile_Test is a script just containing the line one line c = a + b.
I am beginning to understand why parallel computing has an issue here but not how to solve it. Since this would be possible without any problem if I just had the line c = a + b inside the parfor file I cannot belief there is no simple way to solve this (e.g. in the worst case something like tell matlab to load the text from another file and run it as code here and now).
If there are alternative ways to structure my code without using the script files (and, if possible, without using only functions ;)) I would appreciate such comments as well, of course.
Many thanks,
Daniel
parfor has various constraints that make using scripts inside the loop generally a bad option. The main constraint is that the text of the parfor loop must be analysable to see what new variables might be created - this is referred to as "transparency" in the doc. Try using a function instead.
So, for other people or for possible hints to improve, here is how I did it with a function and loading the input variables.
a = 1;
b = 2;
save('Input.mat');
pseudo_input = NaN;%for the function
D= NaN(10,1);%result vector
parfor loop = 1:10
D(loop) = Parfor_Fun_Test(pseudo_input);
end
And the function looks like this:
function d = Parfor_Fun_Test(InputArgs)
load('Input.mat');
d = a + b ;
end
I would have preferred to also save the output, i.e. 'd', within the function and then load it in the parfor loop, but that causes an error, probably because the same file is accessed for loading and saving at the same time by different parallel workers. So this will have to do it. (This can apparently be circumvented by saving under a different name each time, but that would probably really slow down the code.)
By the way, it seems that using cells or structures is slightly faster, but then I have to write the code inside the function as this, I assume:
d = Input.a + Input.b ;
which is more ugly and more work. So I use the save and load method as above for now.

MATLAB nesting multiple input functions

Given a multiple-input MATLAB function
out=f(in1, in2)
I would like to write a second function g which generates the inputs for f, e.g.
[in1, in2]=g(in)
so that I can call something like:
out=f(g(in))
I have tried writing g as a single output function that stores in1 and in2 in a cell array so that I can feed the output of g to f using the colon operator:
in_c=g(in);
out=f(in_c{:})
but I was looking for a one-line solution, which seems not possible to achieve this way as I read in this Stack Overflow question
Is there any other way to do this?
As discussed recently, this is not possible in Matlab.
However, if you do not want to re-write your function g(x,y) to return a cell array, you can still do everything in two lines:
[in4f{1}, in4f{2}] = g(in);
out = f(in4f{:});
As an aside: Unless you're really hurting for memory, it doesn't make a lot of sense to try and force one-line statements everywhere by avoiding temporary variables. Sure, you can make your code look like CrazyPerl, but in the long run, you'll be glad for the added readability.