MATLAB thinks function is a matrix
10 visualizzazioni (ultimi 30 giorni)
Mostra commenti meno recenti
I am trying to make the following code (using the Newton-Raphson method) dynamically adjust to any number of variables.
clearvars
tic
xx = [1;1]
syms x1 x2
f1 = @(x1,x2)x1^2*x2 - x1*x2^2 + 6;
f2 = @(x1,x2)x2^2 + 4*x1^2 - 3*x1*x2 - 7;
J = {sym(zeros(length(xx)))};
J{1,1} = str2func(['@(x1,x2)', char(diff(f1,x1))]);
J{1,2} = str2func(['@(x1,x2)', char(diff(f1,x2))]);
J{2,1} = str2func(['@(x1,x2)', char(diff(f2,x1))]);
J{2,2} = str2func(['@(x1,x2)', char(diff(f2,x2))]);
F{1,1} = matlabFunction(-sym(f1));
F{2,1} = matlabFunction(-sym(f2));
for i = 1:200
syms x1 x2
%jacobian matrix
x1 = xx(1);
x2 = xx(2);
% dx = subs(J)\subs(F);
% dx = vpa(subs(J))\vpa(subs(F));
dx = double(subs(J))\double(subs(F));
xx(1) = xx(1) + dx(1);
xx(2) = xx(2) + dx(2);
clear x1 x2
if abs(dx) < 0.0001
break
end
end
formatspec = 'x(1) = %#.3g x(2) = %#.3g';
fprintf(formatspec,xx(1),xx(2))
toc % 0.981564
I do know well that the method I am using is stupid and weird and slow and shouldn't really be used etc., but I just need it to work. I am open to suggestions through. Just please don't be rude.
What I came up with on my own is the following:
clearvars
tic
xx = [1;1]
% syms x1 x2
for i = 1:length(xx)
syms(strcat('x',string(i)))
end
% sym('x',[1,length(xx)])
f = {sym(zeros(size(xx)))}
f(1,1) = {@(x1,x2)x1^2*x2-x1*x2^2 + 6}
f(2,1) = {@(x1,x2)x2^2+4*x1^2-3*x1*x2-7}
J = {sym(zeros(length(xx)))};
% J{1,1} = str2func(['@(x1,x2)', char(diff(f1,x1))]);
% J{1,2} = str2func(['@(x1,x2)', char(diff(f1,x2))]);
% J{2,1} = str2func(['@(x1,x2)', char(diff(f2,x1))]);
% J{2,2} = str2func(['@(x1,x2)', char(diff(f2,x2))]);
% F{1,1} = matlabFunction(-sym(f(1)));
% F{2,1} = matlabFunction(-sym(f(2)));
for i = 1:length(xx)
for j = 1:length(xx)
J{i,j} = str2func(['@(x1,x2)', char(diff(f(i),eval(strcat('x',string(j)))))])
end
F{i,1} = matlabFunction(-sym(f(i)));
F{i,1} = matlabFunction(-sym(f(i)));
end
for i = 1:200
syms x1 x2
%jacobian matrix
% x1 = xx(1);
% x2 = xx(2);
for j = 1:length(xx)
% subs(eval(strcat('x',string(j))),xx(j))
syms(strcat('x',string(j))) = xx(j); % HERE, getting "Unable to use a value of type string as an index."
end
dx = subs(J)\subs(F);
% dx = vpa(subs(J))\vpa(subs(F));
% dx = double(subs(J))\double(subs(F));
for j = 1:length(xx)
% xx(1) = xx(1) + dx(1);
% xx(2) = xx(2) + dx(2);
xx(j) = xx(j) + dx(j);
end
clear x1 x2
if abs(dx) < 0.0001
break
end
end
formatspec = 'x(1) = %#.3g x(2) = %#.3g';
fprintf(formatspec,xx(1),xx(2))
toc % 0.981564
Any help is appreciated, thank you.
Edit: Distilled it down to this: Is there a way to get rid of "syms x1 x2" and replace it with "X = transpose(sym('x',[1;nx]));" inside the loop, and pass however many xx(i) into function handles i.e. f(x1,x2) if there are 2 variables or f(x1,x2,x3,x4) if there are 4 variables?
There are only 2 sections left to replace.
clearvars
tic
% Needs to be edited
xx = [1;1;1;1];
% End edit
nx = length(xx);
X = transpose(sym('x',[1;nx]));
F = cell(nx,1);
% Needs to be edited
F{1} = matlabFunction(5*X(1)*X(3) - 2*X(1)*X(2) +4*X(3)^2 - X(2)*X(4)-9.75);
F{2} = matlabFunction(6*X(1) + 3*X(2) + X(3) - X(4)-5.5);
F{3} = matlabFunction(2*X(1)^(2) + X(2)*X(3)-5*X(3)+X(1)*X(4)+3.50);
F{4} = matlabFunction(-3*X(1)*X(4) -2*X(2)^2+6*X(3)*X(4)+X(3)*X(4)-16.00);
% End edit
J = {sym(zeros(nx))};
for i = 1:length(xx)
for j = 1:length(xx)
J{i,j} = matlabFunction(diff(F{i},X(j)));
end
end
for i = 1:nx
F{i} = matlabFunction(-sym(F{i}));
end
for i = 1:200
% X = transpose(sym('x',[1;nx]));
% Currently needs to be edited
syms x1 x2 x3 x4
x1 = xx(1);
x2 = xx(2);
x3 = xx(3);
x4 = xx(4);
% End edit
JJ = subs(J);
FF = subs(F);
dx = JJ\FF;
xx = xx + dx;
if abs(dx) < 0.0000001
break
end
% Currently needs to be edited
clear x1 x2
% End edit
end
formatSpec = 'Ans =';
for i = 1:nx
formatSpec = append(formatSpec,' %#.8g');
end
fprintf(formatSpec,xx);
toc
2 Commenti
AndresVar
il 5 Mar 2022
hi matlab has a function called jacobian that will make the jacobian matrix for you.
Walter Roberson
il 6 Mar 2022
X = transpose(sym('x',[1;nx]));
can be replaced with
X = sym('x', [nx, 1]);
and pass however many xx(i) into function handles
See the matlabFunction option named 'vars', and in particular notice the {} syntax.
matlabFunction(expression, 'vars', {X(1:5)})
for example would create a function which expected 5 rows of data, and would use the first row for x1, the second row for x2, the third row for x3, and so on.
I say "rows" here because you assign X as a column vector instead of the more typical row vector. When you use a single index into a vector, the result is always the same shape as the orientation of the vector, no matter what the orientation is of the index, so row index 1:5 into the column vector X gives you a column vector of values that then gets wrapped with {} . When the 'vars' option sees a column vector then the first row of input is allocated to the first variable, the second row to the second variable, and so on. With the more typical row vector of symbols, the first column of input would be allocated to the first symbol, the second column of input would be allocated to the second symbol, and so on.
Risposte (1)
Walter Roberson
il 5 Mar 2022
syms(strcat('x',string(j))) = xx(j); % HERE, getting "Unable to use a value of type string as an index."
That does not dynamically create the name of a variable to assign to.
That evaluates strcat('x',string(j)) and takes the value as an index to assign to in an array named syms
In MATLAB it is not possbile to compute the name of a [complete] variable to assign to.
But you do not need to anyhow. You could build up a list of names, and a list of values, and use subs()
2 Commenti
Vedere anche
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!