How to make dynamic variable names (A1, A2, ..., An) with "for" loop? Using "eval" "num2str"?
Mostrar comentarios más antiguos
Hello community,
my knowledge of Matlab is limited, I admit it. So, I am sorry if I am going to make mistakes.
I have to create a series of variable using a "for" loop.
I make this:
for i=1:3
eval(['A' num2str(i) '= i'])
end
and it works well, it makes 3 variables A1, A2, A3.
But I need to use this variables to make other variables B1, B2, B3 where Bi=Ai*i. So I should have B1=A1*1=1, B2=A2*2=2*2=4, B3=A3*3=3*3=9
I tried something like this:
for i=1:3
eval(['A' num2str(i) '= i'])
eval(['B' num2str(i) '= 'A' num2str(i) '*i])
end
but it gives me error and it doesn't work. Of course I simplified things, the real code is a bt more complicated but I need to know the basics of how this could work.
Thank you
11 comentarios
Muna
el 22 de En. de 2014
for i=1:3
genvarname('A', num2str(i));
eval(['A' num2str(i) '= i'])
genvarname('B', num2str(i));
eval(['B' num2str(i) '= A' num2str(i) '*i'])
end
Stephen23
el 30 de Nov. de 2017
Duijnhouwer
el 19 de Abr. de 2020
% struct fields can be named dynamically
for i=1:3
s.(['a' num2str(i)]) = i;
end
Stephen23
el 19 de Abr. de 2020
"struct fields can be named dynamically"
This is true. However indexing is simpler and much more efficient:
S(k) = k % numeric array
S{k} = k % cell array
S(k).a = k % structure array
Tin Nilaraung
el 5 de Jul. de 2020
for i=1:10 eval(['result',num2str(i),'=runpf(''case33_test', num2str(i) '.mat'')']); eval(['S',num2str(i),'=sqrt(branch(33,14)^2 + branch(33,15)^2(result',num2str(i),'))']); end
In this program, unbalanced or unexpected parenthesis or bracket error has occurred in second eval. Why?? Please explain me
Walter Roberson
el 5 de Jul. de 2020
Your difficulty in debugging this should be a major hint that you should not be using eval.
Meanwhile, build up the character vector and assign it to a variable, and then eval the variable. This will permit you to examine the character vector you are creating to see why it is wrong.
"...unbalanced or unexpected parenthesis or bracket error has occurred in second eval. Why??"
Looking at the character vector shows at least one obvious syntax error (which looks like an implicit multiplication, but without any code comments, this is just a guess), which is quite possibly the cause of that error. There might be more syntax errors.
"Please explain me"
If this code had been written better** using basic indexing then the location of any syntax errors would get highlighted by the MATLAB Editor, and the code would be much easier to debug. So whoever wrote that code chose an approach which forces the user into writing slow, complex, buggy code which is hard to debug. Now you are finding that (otherwise very simple) code is buggy and hard to debug, which will come as no surprise to any readers of this forum (or for that matter to anyone who reads the MATLAB documentation).
** better in the sense simpler, neater, faster, more efficient, less buggy, easier to debug, e.g. by using basic indexing.
Luck Haviland
el 19 de En. de 2022
Hello index fans,
I have a question about your indexing suggestion. While I agree that it is more efficient to use indexes over dynamic naming I am confused as to how this indexing can be used to save files using matlab.
For example, say you have many pictures that you need to extract from a .seq file and you are using matlab for the multi-core processing speed improvement it provides. With dynamic naming you can call them pic1.png, pic2.png, pic3.png, pic4.png, etc and have them automatically saved in the directory of your choosing. Using indexing, how can you call them pic1, pic2, pic3, and pic4 in order to automatically increment and save each photo?
(Is this off topic? I am new here)
Thank you,
Luck
Walter Roberson
el 19 de En. de 2022
filename = sprintf('pic%d.png', PICTURE_INDEX);
imwrite(IMAGE_ARRAY, filename);
PICTURE_INDEX = PICTURE_INDEX + 1;
"With dynamic naming you can call them pic1.png, pic2.png, pic3.png, pic4.png, etc and have them automatically saved in the directory of your choosing."
No, you are mixing up filenames with the names of variables in the MATLAB workspace. Two totally different things.
Mixing up unrelated topics will not make it easy to understand or use MATLAB. Or any programming language, for that matter.
Also note that MATLAB variable names cannot have the dot character in them, so your example variable names are invalid and would not work, even though you incorrectly state that "you can call them pic1.png, pic2.png, pic3.png, pic4.png". This should also give you a hint as to one reason why your approach of dynamically naming variables based on a filenames is a really bad idea (hint: consider all of the Unicode characters that are valid in filenames. Are they also valid in variable names? hint: no).
"Using indexing, how can you call them pic1, pic2, pic3, and pic4 in order to automatically increment and save each photo?"
Very easily: the two main approaches are:
- read a list of existing files and alter the names (e.g. append a suffix, change the extension).
- generate the filenames (e.g. using SPRINTF).
Both of these methods generally use indexing, as shown in the MATLAB documentation here:
and also on thousands and thousands and thousands of threads on this forum (none of which require dynamic variable names, even if their filenames increment numbers just as you show), because, surprisingly, importing and exporting file data is a very common topic that people want to achieve. Using indexing. Because that is how MATLAB works.
I think of dynamic file names as somewhat different from dynamic variable names, as the file names are usually themselves data (passed into a function that reads the file contents then returns a variable whose name is not necessarily tied to the file name, or performs some other operation on the file.)
t = fullfile(tempdir, 'writeASeriesOfFiles');
if ~isfolder(t)
mkdir(t);
end
dir(t) % Nothing in this directory yet
for k = 1:5
fn = fullfile(t, "file" + k + ".txt");
% Now use fn as data in several function calls
fclose(fopen(fn, 'wt')); % Open and immediately close the file
doesItExist = isfile(fn);
if doesItExist
fprintf("File %s does exist!\n", fn)
else
fprintf("File %s does NOT exist!\n", fn)
end
end
dir(t)
Respuesta aceptada
Más respuestas (5)
Italo, I am glad you're trying out things on matlab.
Matlab is very good with matrixes. What you're doing in these can be done much easily. For example:
A = 1:3;
B = A.*A; %
You can find many tutorials online on how to use MAtlab. For example: http://www.mathworks.com/academia/student_center/tutorials/launchpad.html
2 comentarios
Amit
el 22 de En. de 2014
In you code:
for i=1:3
eval(['A' num2str(i) '= i'])
eval(['B' num2str(i) '= A' num2str(i) '*i']) % Issue was Here. Notice the positions of '
end
Bruno Pop-Stefanov
el 22 de En. de 2014
Gabor
el 20 de Sept. de 2021
T=table;
Date=datetime(2014,12,31);
eval(['Dynamic_var_name_' datestr(Date,'mm_dd_yyyy') '=T;']);
This is how you name dynamically a variable or a table or a cell or anything regardless if it is recommended or not.
1 comentario
Whether it is recommended or not is irrelevant.
The fact is that it forces beginners into writing slow, complex, inefficient code, as this thread already demonsrates:
Jerry Olup
el 28 de Abr. de 2018
Editada: Jerry Olup
el 28 de Abr. de 2018
I did find dynamically named variables useful for a specific need. I have several files in a directory. Each file has a few columns that are read into a structure. It's convenient to read and simultaneously name the variables per a filename. For instance I read to a temp var then use the ill-advised exec capability to assign this to a variable specific to the file I read in. Looping, I read all files in the dir efficiently. 'files' is a cell array of file names discovered in that directory....
tmp = table(dataArray{1:end-1}, 'VariableNames', {'max_mag','max_noise','max_cnt'});
eval([files{i} '=tmp'])
I do see where this is not good for general variable naming, but I believe there's a niche usage in this case. Opinions? Best, Jerry
3 comentarios
" It's convenient to read and simultaneously name the variables per a filename."
A structure would be simpler, as well as be more efficient and easier to debug:
S.(files{i}) = table(...);
Or simply store the tables themselves in a cell array, and keep the corresponding files data in another cell array: this would be trivial to achieve using indexing, and also has the significant advantage that then the files data are not restricted to valid field/variable names.
Or just use one table, and add a files column to distinguish between the different cases.
"I do see where this is not good for general variable naming"
How do you then access those dynamically defined variables? Your "niche case" does not see to be any different to any of the other cases that have been described on this forum: can you explain why writing slow, complex code is better than using a simple structure, like I showed? Or better than using very simple (and very efficient) indexing?
"but I believe there's a niche usage in this case"
So far you have not actually described anywhere in your answer why it is necessary to dynamically create/access variable names: other methods would also store your data more efficiently than what you have shown, and you have not given any reason why none of those methods would work.
I cannot emphasize it enough how important Stephen's suggestions are. Creating the variables dynamically impedes the JIT acceleration massively, such that the complete function can runs ways slower, not just the line containing these variables. The JIT must be able to handle the case, that one of the "files{i}" is called "plot". Afterwards plot is not a command anymore, but a table object. To catch such problems, all function calls must be checked manually if they have been overwritten dynamically.
Using dynamic field names instead by S.(files{i})=table(...) is safe and efficient. In addition reading the code allows to identify these variables directly: If I find "S.function" in the source code, I know where it is coming from, while for a simple "function" I cannot be sure, if this is a typo or a dynamically created variable. The editor cannot distinguish this also and will assume an illegal definition of a function. Such strange effect can never happen with dynamic field names.
Summary: No, there is no niche for dynamically created variables. eval is a shot in your knee. Sometimes it does not hurt immediately, but the later it starts to bite you, the harder it will be to clean up the code.
This has been discussed exhaustively in the links, Stephen has posted in his answer above. Believe him and the bunch of corresponding threads.
Jerry Olup
el 12 de Ag. de 2018
Editada: Stephen23
el 12 de Ag. de 2018
Hi Stephen, I'll give the idea of provide parallel constructs where the file-specific variable references are in one cell while data is collected in structure. I've shifted in the last month or so to use python for preprocessing - so this problem has largely gone away and been replaces with xlsread, csvread etc.
>>files data are not restricted to valid field/variable names
My file names are conventionally, ascii with underscores and timestamps yyyymmdd_hhmmss type, so I do see where this is problem. They are pretty specific so I thought I was giving a concrete counter example in contrast to @Italo and @Muna, who started this thread naming generic matrices.
>>you have not given any reason why none of those methods would work.
You're absolutely correct. I latched onto that solution as it was elegant for what I needed.
Thanks for the interaction, best, Jerry
César Silva Proaño
el 12 de Ag. de 2018
Hi, look I was doing something similar in order to create a function with the Krammer Method, for solving any size of matrix-equation problem. Look I created a function in order to do this, therefore, I needed to do it automatically, creating variables dinamically. Look at this fucntion.
function [ X ] = funcionMetodoKrammer( A )
%UNTITLED Summary of this function goes here
% Detailed explanation goes here
% ex: A = [-3 2 1 10;5 -8 3 15;-8 -9 10 20];
sizeA = size(A);
sizeFilasA = sizeA(1,1);
sizeColumnasA = sizeA(1,2);
matrizASinResultado = A(1:sizeFilasA,1:sizeFilasA);
matrizResultados = A(:,sizeColumnasA);
if (sizeFilasA == sizeColumnasA - 1)
for (i = 1:sizeColumnasA)
genvarname('matrizColumna', num2str(i));
eval(['matrizColumna' num2str(i) '=A(:,i)']);
end
for (i = 1:sizeFilasA)
genvarname('matrizTemporalColumna', num2str(i));
eval(['matrizTemporalColumna' num2str(i) '=matrizASinResultado(:,i)']);
end
matrizIncognita1 = [matrizResultados,matrizASinResultado(:,2:sizeFilasA)];
for (i = 2:sizeFilasA)
genvarname('matrizIncognita', num2str(i));
eval(['matrizIncognita' num2str(i) '=[matrizASinResultado(:,1:i-
1),matrizResultados,matrizASinResultado(:,i+1:sizeFilasA)]']);
end
else
msgbox('La matriz ingresada para el método Krammer es incorrecta');
end
for (i = 1:sizeFilasA)
genvarname('X', num2str(i));
genvarname('matrizIncognita', num2str(i));
eval(['X' num2str(i) '= det(matrizIncognita' num2str(i) ')/det(matrizASinResultado)']);
end
X = zeros(1,sizeFilasA);
for (i = 1:sizeFilasA)
genvarname('X', num2str(i));
eval(['X' '(1,' num2str(i) ')=X' num2str(i)]);
end
end
%{
Asuminedo que existen variables B1, B2 y B3 se pueden acceder a las
variables de la siguiente manera
B1 = 10; B2 = 11; B3 = 12;
for (i = 1:3)
genvarname('Prueba', num2str(i));
genvarname('B', num2str(i));
eval(['Prueba' num2str(i) '=' 'B' num2str(i) '+10']);
end
%}
I strongly disagree with the idea that you shouldn't use this because, if it exists I mean why not? It is not prohibited, and additionally it is very helpful in some cases.
Regards,
Sebastián
5 comentarios
Walter Roberson
el 12 de Ag. de 2018
I see nothing in your code that could not be replaced with a cell array or perhaps multidimensional array.
"if it exists I mean why not?"
Experience has shown that it often leads to bugs that are difficult to find. It is also slower, as MATLAB cannot use Just In Time compiling effectively. You will find that in newer releases, using this kind of code can fail for no obvious reason, as MATLAB is going stricter and stricter at prohibiting or ignoring dynamic variable creation.
Already if you have something like
eval('sum = ones(3,5);');
sum(2)
then the sum(2) will be a reference to the function sum, not the variable that was poofed into existence.
@César Silva Proaño: thank you for showing us your function. It is a good example of what we warn against: eval causing pointlessly slow, pointlessly complex, obfuscated, inefficient code. One bad design decision that ruins what should be a simple function.
"I strongly disagree with the idea that you shouldn't use this because, if it exists I mean why not? It is not prohibited, and additionally it is very helpful in some cases."
You can "strongly disagree" all you want, but in this case it "helped" you to write pointlessly slow, pointlessly complex, pointlessly obfuscated code. Which is exactly "why not" !
"Look I created a function in order to do this, therefore, I needed to do it automatically, creating variables dinamically."
There is absolutely nothing in your algorithm that you "needed to" use dynamically named variables for. I proved this with my own simpler version of your function (see betterKrammer below), which uses basic indexing to give a much faster, much simpler, less buggy, and easier-to-debug function. Actually you used exactly the same indexing, you just obfuscated it behind lots of dynamically named variables.
OBFUSCATION: using eval made it easy to hide pointless "features". For example:
eval(['X' '(1,' num2str(i) ') = ...
Why do you need eval to simply use basic indexing? Answer: you don't. If you had read the eval documentation you would know that in that case it is recommended to put the eval only on the RHS of the assignment.
None of the genvarname calls do anything useful (just waste time), because their outputs are not assigned to any variable and so are immediately discarded:
genvarname('X', num2str(i)); <- discarded output.
genvarname('matrizTemporalColumna', num2str(i)); <- discarded output.
... etc
So they just slow down your code and produce nothing.
What do you use the ['matrizColumna'...] and ['matrizTemporalColumna'...] variables for? Answer: also nothing. So why do you bother to generate them? If you had written better code (without eval) then the MATLAB editor would simply warn you that all these variables are unused. But by choosing to use eval you turned off all of these warnings, and so have lots of pointless calculations in your code: literally pointless because they are not used for anything. That is the "help" that eval gave you: it turned off those useful warnings!
Your function also inefficiently and pointlessly duplicates parts of the input array into their own variables: obviously all of that data duplication escaped your attention, but really it is not necessary to copy the same data into lots of (dynamically named) variables, when you can access it very efficiently using indexing, and without any data duplication whatsoever.
SLOW and COMPLEX: I rewrote your function without any dynamically named variables, by using basic MATLAB indexing. This is what I came up with:
function X = betterKrammer(A)
% ex: A = [-3 2 1 10;5 -8 3 15;-8 -9 10 20];
S = size(A);
assert(numel(S)==2&&diff(S)==1,'La matriz ingresada para el método Krammer es incorrecta')
X = nan(1,S(1)); % preallocate output.
for k = 1:S(1)
X(k) = det(A(:,[1:k-1,S(2),k+1:S(1)])) ./ det(A(:,1:S(1)));
end
end
Notice that your function has sixty lines, whereas my function has just nine lines (including the same comments and better input checking). Of course it returns exactly the same answer, it just does so much more efficiently. After I stopped your function from printing to the command window I did some timing tests using tic and toc, here are the results (1e4 iterations):
Elapsed time is 109.192323 seconds. % your slow function using EVAL.
Elapsed time is 0.842797 seconds. % my fast function sans EVAL.
And we can compare the outputs:
>> funcionMetodoKrammer([-3 2 1 10;5 -8 3 15;-8 -9 10 20]) % your slow function
ans =
6.9898 8.0612 14.847
>> betterKrammer([-3 2 1 10;5 -8 3 15;-8 -9 10 20]) % my fast function
ans =
6.9898 8.0612 14.847
So by using basic indexing and avoiding eval I wrote a simpler function that is over one hundred times faster than yours. This is what happens when beginners use eval: they force themselves into writing inefficient, complex, obfuscated code. Which, no matter how much you "strongly disagree" with it, is the reality that we warn against.
So there you have it: your code is a very good example of exactly what we are warning about: pointless eval usage forcing beginners into writing really slow, complex code. Thank you for the example!
César Silva Proaño
el 12 de Ag. de 2018
Thanks for the feedback. But I can see that in every post, in which this question about the generation of dinamic variables with eval and genvarname is lauched, you just attack this method and you do not present an formal solution. Thanks for the critics, yes in fact, that code is not the final one. This is the one:
function [X] = funcionMetodoKrammer(A)
%{
Esta función resuelve un sistema se ecuaciones lineales con el método
de
Krammer, se debe ingresar una matriz de tamaño n x n+1, es decir la
parte
n x n contiene los valores de x1, x2, etc, y la columna n+1 tiene los
valores resultado de cada ecuación.
%}
% ex: A = [-3 2 1 10;5 -8 3 15;-8 -9 10 20];
sizeA = size(A);
sizeFilasA = sizeA(1,1);
sizeColumnasA = sizeA(1,2);
matrizASinResultado = A(1:sizeFilasA,1:sizeFilasA);
matrizResultados = A(:,sizeColumnasA);
if (sizeFilasA == sizeColumnasA - 1)
% Aquí se forman las matrices para cada respuesta:
matrizIncognita1 =
[matrizResultados,matrizASinResultado(:,2:sizeFilasA)];
for (i = 2:sizeFilasA)
genvarname('matrizIncognita', num2str(i));
eval(['matrizIncognita' num2str(i) '=[matrizASinResultado(:,1:i-1),matrizResultados,matrizASinResultado(:,i+1:sizeFilasA)]']);
end
% Se determinan las respuestas
for (i = 1:sizeFilasA)
genvarname('X', num2str(i));
genvarname('matrizIncognita', num2str(i));
eval(['X' num2str(i) '= det(matrizIncognita' num2str(i) ')/det(matrizASinResultado)']);
end
% Ahora se determina el vector con las respuestas:
X = zeros(1,sizeFilasA);
for (i = 1:sizeFilasA)
genvarname('X', num2str(i));
eval(['X' '(1,' num2str(i) ')=X' num2str(i)]);
end
% En caso de que la matriz ingresada sea incorrecta:
else
msgbox('La matriz ingresada para el método Krammer es incorrecta');
end
end
It seems that you have a personal issue with this form of approaching the dinamic generation of variables. Perhaps you are an excellent Matlab user, so why don't you give us an enlightening solution for this problem, instead of criticizing?
The question should be, how do you generate dinamic variables?
But please make us all a favor and present a code, not just words or links, because as my previous code, that is useless for people who want to learn matlab in a good manner. And yes, I am a beginner in this program, that is why perhaps I can commit mistakes, but I beg my pardon, everyone can make mistakes, specially me and others who are not so smart as you ;) Regards,
Walter Roberson
el 13 de Ag. de 2018
César Silva Proaño:
Imagine that you were building a bird house by using a beer bottle to hammer in nails. You get something made and present it to us as a model for how to make bird houses.
Imagine that we notice that you used the wrong size of nails for the materials, that you used the wrong kind of nails for the materials, that using a beer bottle as a hammer is dangerous, and that our considered experience is that it is a lot better to build bird houses with screws instead of with nails.
In those circumstances, should we advise you to use screws and a screwdriver instead of nails, or should we refrain from saying anything, seeing as you created a birdhouse that looks good enough to you? Should we just shrug our shoulders about the dangers of bottles shattering in hands when used as hammers, figuring that people will eventually figure it out for themselves?
"you just attack this method and you do not present an formal solution"
This is simply untrue. On the contrary, from what I've seen Stephen always provides a concrete solution when possible. Here's an example from 5 minutes ago ( link ) which is nothing out of the ordinary.
"But please make us all a favor and present a code, not just words or links..."
This is the mindset I see in a lot of younger students today - avoid instructions like the plague and feel entitled to a solution. Remember that no one is getting paid to read about your dynamic variables, so you should appreciate any replies including links and words (whatever that means).
I too have a potential reason to want to do what the original OP posted. My example is that I want to numerically solve a system of nonlinear functions, in which the number of functions and variables depend on the input. I don't think any of the suggested alternatives solve this case. Am I wrong?
14 comentarios
Walter Roberson
el 4 de Mayo de 2022
Editada: Walter Roberson
el 4 de Mayo de 2022
fsolve() expects to be called with a single function, and it expects the function to accept a vector of input values. The function is permitted to return non-scalar.
The function in turn could be something like
fun = @(x) cellfun( @(F) F(x), CellOfFunctions )
where CellOfFunctions is a cell array of function handles, each of which expects a vector as input.
If you had reason, you could instead use
CallWith = @(f, parameter_cell) f(parameter_cell{:})
fun = @(x) cellfun( @(F) CallWith(F, num2cell(F)), CellOfFunctions )
where CellOfFunctions is a cell array of function handles, each of which expects as many inputs as length(x) . This would help for the situation where the functions to be called expects each model parameter to be passed as individual variables.
João
el 4 de Mayo de 2022
@Walter thank you very much for this answer. I'm not well versed with the suggested solution and I will check it soon to see if i understand it fully and can work with it. My problem can be written as Given n variables I know n equations of the kind a1*x1 = b2*x2 + c for xi and i between 1 and n-2 and two additional equations function of all xi. I will have always a n equation n variables problem. If it is simple could you suggest a way to get something like this working using your solution? Thanks
Walter Roberson
el 4 de Mayo de 2022
That setup sounds like a system of linear equations, which could be solved with the \ operator. The "A" matrix looks like it would mostly be the sum of two diagonal matrices, something like
diag(a) + diag(b,1)
(with some adjustment for the fact that the diagonals are different lengths)
João
el 4 de Mayo de 2022
I forgot to say one of the two equations depends on the square of some of the variables hence nonlinearity. I need to sleep now and I appreciate your time and information. Thanks
@João: it sounds like you are mixing up the common/mathematical meaning of "variable" with the specific meaning that it has in MATLAB (which is something more like "an array that is available in the workspace"). You can certainly represent many mathematical "variables" or "parameters" (or whatever you want to call them) in one array. Not only can you do this, but doing so is rather the entire point of MATLAB: you need to start thinking in terms of arrays.
" Am I wrong?"
Whatever solver you use, it will be much simpler if you use arrays rather than lots of numbered variables.
Stephen23
el 5 de Mayo de 2022
" I'm coming from python and the way fsolve works there is less flexible than in MATLAB"
AFAIK, Python itself does not have an FSOLVE operator. The SCIPY function FSOLVE is documented as requiring "A function that takes at least one (possibly vector) argument, and returns a value of the same length", much the same as MATLAB.
João
el 5 de Mayo de 2022
@Stephen I tried several alternatives in python and even search for help and I got no answer.
Take this example:
def equations(vars):
x, y = vars
eq1 = x+y**2-4
eq2 = exp(x) + x*y - 3
return [eq1, eq2]
from scipy.optimize import fsolve, broyden1, root
from math import exp
sol = fsolve(equations, [1.0, 1.0])
The function equations does not accept a list to define eq1 and eq2 as Matlab accepts.
Stephen23
el 5 de Mayo de 2022
"I need to define the number of variables x1 to xn"
I don't see why that would be a problem with Python any more than it would be a challenge with MATLAB: in both cases you could use a loop over any number of values (the word "variable" is misleading here) or use vectorized code (e.g. via numpy/scipy) with e.g. indexing to select the required variables for each function, which is probably the better solution.
As far as I can tell, your idea that you need numbered variable names is a red-herring for numpy/scipy just as much as for MATLAB.
But because you are very vague about your actual functions, I can only guess.
João
el 5 de Mayo de 2022
Dear @Stephen Just not to ask more of your time I'll go straight to the point: I'm a python user, but the case I'm trying to model involves solving a system of mix linear and nonlinear equations that change as the program progresses. To detail, the equations consist in equations of motion of objects during their impact. Over time some objects which were at rest become affected by the pressure wave, so no longer in equilibrium, so the equations of motion will change over time as the net force also changes. The knowns are which objects are in motion or at rest. I have more 2 variables than equations of motion, but I can use the law of conservation of momentum and the law of conservation of total energy (plus some assumptions) to get a n equations and n variables system. The equations of motion are linear (depend on displacement and velocity), as the aw of conservation of momentum. The law of conservation of total energy is nonlinear since it depends on the square of the velocity. I am using very small time increments so that the velocity and displacement can be assumed constant and modelled not as functions of time but as time independent variables at each increment. I want to use a loop to define the equations for each set of objects at rest and in motion, and skip having to write them one by one. Also the number of objects is an initial input from the user. So inside each loop, I will define a set of linear an nonlinear equations, in which the number of equations and the name of variables depend on the range of the loop. So for a 2 objects system and a specific time increment I might have (in Python):
def equations(vars):
g = 9.8
c = 7.
d = 0
k = 1000
m = 100
dt = 0.1
x, y, z, j = vars # variables
eq1 = (m*g - k*(y-x)) * dt - m * (j - c) # where m, k, g and c are known values
eq2 = (k*(y-x) + m*g - k*x) * dt - m * (z - d) # where m, k, g and d are known values
eq3 = m * (c + d) - m * (z + j)
eq4 = m*g*y - 1/2*k*(y-x)**2 + m*g*x - 1/2*k*x**2 - 1/2*m*(j**2 - c**2) - 1/2*m*(z**2 - d**2)
return [eq1, eq2, eq3, eq4]
from scipy.optimize import fsolve
sol = fsolve(equations, [0.0, 0.0, 0.0, 0.0])
The issue is that for another time increment I might have slightly different equations, and also I want to make the number of objects a user defined variable. So having to define functions for all increments and all possibilities is not feasible.
"So having to define functions for all increments and all possibilities is not feasible."
Sure.
"I want to use a loop to define the equations for each set of objects at rest and in motion, and skip having to write them one by one"
So presumably there is some kind of pattern to these things: those equations must be abe to be defined systematically depending on the number of objects/whatever (otherwise your task is moot), and that is really what you need to utilize if you want a general solution to this (regardless of Python or MATLAB).
Please show one (or all) of the equations for three objects, to give me an idea of how they change.
"Over time some objects which were at rest become affected by the pressure wave, so no longer in equilibrium, so the equations of motion will change over time as the net force also changes"
That sounds like something that could be handled using indexing. Or at worst some loops and IFs.
The more you explain, the more your approach that "the name of variables depend on the range of the loop" seems ... unhelpful in either language. Numpy and MATLAB both work with arrays, so should you.
João
el 6 de Mayo de 2022
@Stephen23 Yes, equations must be abe to be defined systematically depending on the number of objects. And yes, for each time increment I know which equations to use and which x, y, z, ... to define.
For two objects I would have something like:
x, y, z, j = vars # variables
eq1 = (m*g - k*(y - x)) * dt - m * (j - c) # where m, k, g and c are known values
eq2 = (k*(y - x) + m*g - k*x * dt - m * (z - d) # where m, k, g and d are known values
eq3 = m * (c + d) - m * (z + j)
eq4 = m*g*y - 1/2*k*(y-x)**2 + m*g*x - 1/2*k*(x-l)**2 + m*g*l - 1/2*k*(l)**2
- 1/2*m*(j**2 - c**2) - 1/2*m*(z**2 - d**2)
For three objects I would have something like:
x, y, z, j, l, f = vars # variables
eq1 = (m*g - k*(y - x)) * dt - m * (j - c) # where m, k, g and c are known values
eq2 = (k*(y - x) + m*g - k*(x - l) * dt - m * (z - d) # where m, k, g and d are known values
eq3 = (k*(x - l) + m*g - k*l) * dt - m * (f - e) # where m, k, g and e are known values
eq4 = m * (c + d + e) - m * (z + j + f)
eq5 = m*g*y - 1/2*k*(y-x)**2 + m*g*x - 1/2*k*(x-l)**2 + m*g*l - 1/2*k*(l)**2
- 1/2*m*(j**2 - c**2) - 1/2*m*(z**2 - d**2) - 1/2*m*(f**2 - e**2)
eq6 = j - c # assuming that the velocities of object 1 and object 2 are the same during impact, i.e. when object 1 hits objects 2 they have the same velocity
So this made me realise I have to keep making assumptions as the number of objects grows.
So I need to solve the equations explicitly by Runge-Kutta or Central Difference methods...
I need to restructure my code. Thank you for the constructive input!
Categorías
Más información sobre Loops and Conditional Statements en Centro de ayuda y File Exchange.
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!