My code wont run, keep getting error "Not enough input arguments"

The following is my code for secant method optimization search. I have my objective function in one file called f.m and the algorithm in another named secant.m. Whenever I run my code I keep getting an error: Not enough input arguments. I am using MATLAB 2019b
Additionlly, could someone please let me know if the logic of my code is correct? after many iterations I should reach a value z which minimizes my function and I would like to take all the "z"s that were calculated each iteration and calculate an error and then plot those error values per iteration as my y axis and iteration on the x axis to get my graph. If someone if familiar with the secant method could you please let me know if this is correct? Thanks alot.
code in f.m file:
function g = f(x)
g = 2*((x-3)^2)+exp(0.5*x^2);
code in secant.m file:
f_prime = diff(f);
a = 0;
b = 3;
epsilon = 0.0001;
x1 = a;
x2 = b;
k = 0;
iteration = 100;
f1 = f_prime(x1);
f2 = f_prime(x2);
z = x1 - (f1/((f1-f2)*(x1-x2)));
f3 = f_prime(z);
while (abs(f3) > epsilon) && (k<iteration)
k = k+1;
if (f1>f2)
x2 = z;
z = x1 - (f1/((f1-f2)*(x1-x2)));
f3 = f_prime(z);
error = abs(f(z)-f(3));
else
x1 = z;
z = x1 - (f1/((f1-f2)*(x1-x2)));
f3 = f_prime{z};
error = abs(f(z)-f(3));
end
end
plot (iteration, error, 'rx')

Risposte (1)

f_prime = diff(f);
That line starts by looking to see if there is a variable named f that is in scope. If there is no such variable, then it looks to see if there is a function named f that is in scope. MATLAB sees the f.m file so Yes there is a function named f in scope. Having located the function named f, that syntax would attempt to invoke f without any arguments, just as if the code had written
f_prime = diff(f());
So the code in f.m starts running, with variable x (from the function definition line for function f) internally marked as missing. Then the second line of f is reached,
g = 2*((x-3)^2)+exp(0.5*x^2);
and the reference to x is seen. x is searched for as a variable in scope, and is located in the function header -- but since no parameters were passed, x is marked as missing. And MATLAB then complains that you invoked a function (namely f) with insufficient arguments.
Now... you need information beyond just the above.
What you need to know at this point is that MATLAB has two diff functions. (Well, more than two.)
The main diff function is designed to take numeric differences -- for a vector x and no optional arguments, it would output [x(2)-x(1), x(3)-x(2), x(4)-x(3), x(5)-x(4)] and so on to x(end)-x(end-1) . That kind of subtraction of adjacent elements is used for almost all data types. It is the "difference" operator, not the "differentiation" operator.
The second important diff function only applies to symbolic expressions and symbolic functions created by the Symbolic Toolbox, and in the context of symbolic expressions and symbolic functions, it is the differentiation operator.
But... your function f is a regular function, not a symbolic function. So you cannot invoke the differentiation operator on it -- not directly .
If you have access to the Symbolic Toolbox, what you could do would be to change
f_prime = diff(f);
into
syms x
f_prime = matlabFunction(diff(f(x)))
Creating x as symbolic, and passing it to x specifically results in function f being invoked with symbolic variable x as a parameter. The particular function you defined happens to be fine receiving a symbolic parameter, and would do a calculation that would return a symbolic expression. The symbolic expression would then get passed to the symbolic differentiation operator, returning a symbolic expression as a result. Then matlabFunction() would convert the symbolic expression into an anonymous function that can receive (and return) numeric values.

14 Commenti

If you do not have access to the Symbolic Toolbox, then you will need to calculate the derivative of your f "by hand" and write that into a function... perhaps in a file named f_prime.m
Brace indexing is not supported for variables of this type.
Error in secant (line 28)
f3 = f_prime{z};
this is the error I get. So if I used the sybmolic toolbox to calculate my derivative and then I wanted to calculate the derivative at a specific point (like the above, I am trying to see the value of my f_prime at point z, in fact at every iteration I have a different value of z and so the f_prime value at that z is different and I am trying to calculate the error through that "error = abs(f(z)-f3)" where f3 should be the optimal point where abs(f_prime(z) < epsilon) and my f(z) is the value of function f at every value z from every iteration, so if it took 100 iterations before the while loop condition was satisfied then we would have 100 different values of z). Am I expressing that correctly through my code or not?
Thanks for the help by the way, I really appreciate it
In your "if" branch you use
f3 = f_prime(z);
In your "else" branch you use
f3 = f_prime{z};
Is there a reason for the difference?
@Walter Roberson I'd say that the reason is @Nizar Sharkas is unsure when to use braces, when to use parentheses, and when to use brackets. Perhaps the FAQ will explain part of that:
my bad, it should be closed braces. the below is the code, I ran it now but I didnt get what I am looking for so I am not sure if what I wrote above is expressed correctly. instead of getting a graph of my error vs iteration I am getting a single point (which cant be since the secant method is very slow in reaching to an optimal point).
syms x
f_prime = matlabFunction(diff(f(x)));
a = 0;
b = 3;
epsilon = 0.0001;
x1 = a;
x2 = b;
k = 0;
iteration = 100;
f1 = f_prime(x1);
f2 = f_prime(x2);
z = x1 - (f1/((f1-f2)*(x1-x2)));
f3 = f_prime(z);
while (abs(f3) > epsilon) && (k<iteration)
k = k+1;
if (f1>f2)
x2 = z;
z = x1 - (f1/((f1-f2)*(x1-x2)));
f3 = f_prime(z);
error = abs(f(z)-f(3));
else
x1 = z;
z = x1 - (f1/((f1-f2)*(x1-x2)));
f3 = f_prime(z);
error = abs(f(z)-f3);
end
end
plot (iteration, error, 'rx')
so if it took 100 iterations before the while loop condition was satisfied then we would have 100 different values of z).
You are not keeping track of the 100 different z values or 100 different f values, only of the current value. The current value is all you need for computation, but tracking the other values might be interesting for plotting or analysis.
so my code is not tracking those, how can I track them? I am actually trying to compute them to actually plot my error. Walter, would it be possible to have a zoom call? Thanks sir!
syms x
f_prime = matlabFunction(diff(f(x)));
a = 0;
b = 3;
epsilon = 0.0001;
x1 = a;
x2 = b;
k = 0;
iteration = 100;
f1 = f_prime(x1);
f2 = f_prime(x2);
z(1) = x1 - (f1/((f1-f2)*(x1-x2)));
f3 = f_prime(z);
error = [];
while (abs(f3) > epsilon) && (k<iteration)
k = k+1;
if (f1>f2)
x2 = z(end);
z(end+1) = x1 - (f1/((f1-f2)*(x1-x2)));
f3 = f_prime(z(end));
error(end+1) = abs(f(z(end))-f(3));
else
x1 = z(end);
z(end+1) = x1 - (f1/((f1-f2)*(x1-x2)));
f3 = f_prime(z(end));
error(end+1) = abs(f(z(end))-f3);
end
end
plot(error, 'rx')
However... error here records the error "after" the iteration. Suppose that abs(f3)>epsilon was false right at the beginning so that the body of the while loop never executed, then what should be in error ?
With this code, z is always one element longer than error, because z(1) exists before the loop and each loop execution adds another value to z. But with your code, error does not exist until you have done a computation -- so when you just created z(3) then you would have just created error(2)
You could initialize error = inf instead of error = [] and then the lengths would match and error should in theory decrease as you go.
How do you want the graphs to appear in the case that the loop body does not execute?
well I understand your comment, however thats why I have the error like that, becuase epsilon is so small that you wont have an error until z is computed. As for the graph, I am only interested in the error vs iterations for the values of z calcualted and the optimal point so if hypothetically there are no iterationsn because the algorithm converged on the optimal point in one iteration (k = 0) then tychincally there is no error (error is 0) so there wont be a graph anyways. However, the optimal point I am getting through my code is wrong (optimal should be 1.59 and the one I get is 2.3 so there has to be an error in the logic of the code). If you happen to know the secant method and could let me know what part of the algorithm logic isnt correct I would really appreciate it.
You were subtracting f(3) instead of f3
I renamed f3 to fpz (that is, fprime at z)
I suspect your error calculation is wrong
syms x
f(x) = 2*((x-3)^2)+exp(0.5*x^2);
f_prime = matlabFunction(diff(f(x)))
f_prime = function_handle with value:
@(x)x.*4.0+x.*exp(x.^2./2.0)-1.2e+1
a = 0;
b = 3;
epsilon = 0.0001;
x1 = a;
x2 = b;
k = 0;
iteration = 100;
f1 = f_prime(x1);
f2 = f_prime(x2);
z(1) = x1 - (f1/((f1-f2)*(x1-x2)));
fpz(1) = f_prime(z);
error = [];
while (abs(fpz(end)) > epsilon) && (k<iteration)
k = k+1;
if (f1>f2)
x2 = z(end);
z(end+1) = x1 - (f1/((f1-f2)*(x1-x2)));
fpz(end+1) = f_prime(z(end));
error(end+1) = abs(f(z(end))-fpz(end));
else
x1 = z(end);
z(end+1) = x1 - (f1/((f1-f2)*(x1-x2)));
fpz(end+1) = f_prime(z(end));
error(end+1) = abs(f(z(end))-fpz(end));
end
end
plot(error, 'rx')
title('error vs iteration')
plot(1:length(z), f(z), 'g+', 1:length(fpz), fpz, 'bx')
title("f(z), f' vs iteration")
legend({'f(z)', "f'"})
[minfpz, idx] = min(abs(fpz))
minfpz = 0.0973
idx = 83
double(f(z(idx)))
ans = 7.5162
Your current error function is looking for the place where f(z) == f'(z) . But that isn't necessarily where f(z) == 0 . f'(z) == 0 holds at critical points, not at zeros .
An example of a function where f(z) == f'(z) everywhere is f(z) = exp(z)
that was an error which I have corrected, because my error is the absolute value of f(zi) - f(xopt) where zi is the values of z after each iteration and xopt is the value of z that finally breaks my while loop (optimum point). I tried running the below but its telling me that the following:
Unable to perform assignment because the left and right sides have a different number of elements.
Error in secant2 (line 14)
fpz(1) = f_prime(z)
syms x
f(x) = 2*((x-3)^2)+exp(0.5*x^2);
f_prime = matlabFunction(diff(f(x)));
a = 0;
b = 3;
epsilon = 0.0001;
x1 = a;
x2 = b;
k = 0;
iteration = 100;
f1 = f_prime(x1);
f2 = f_prime(x2);
z(1) = x1 - (f1/((f1-f2)/(x1-x2)));
fpz(1) = f_prime(z);
error = [];
while (abs(fpz(end)) > epsilon) && (k<iteration)
k = k+1;
if (f1>f2)
x2 = z(end);
z(end+1) = x1 - (f1/((f1-f2)/(x1-x2)));
fpz(end+1) = f_prime(z(end));
error(end+1) = abs(f(z(end))-fpz(end));
sprintf('x_min=%f', z(end))
else
x1 = z(end);
z(end+1) = x1 - (f1/((f1-f2)/(x1-x2)));
fpz(end+1) = f_prime(z(end));
error(end+1) = abs(f(z(end))-fpz(end));
sprintf('x_min=%f', z(end))
end
end
plot(error, 'rx')
title('error vs iteration')
That error is not occuring when I execute your code unchanged.
syms x
f(x) = 2*((x-3)^2)+exp(0.5*x^2);
f_prime = matlabFunction(diff(f(x)));
a = 0;
b = 3;
epsilon = 0.0001;
x1 = a;
x2 = b;
k = 0;
iteration = 100;
f1 = f_prime(x1);
f2 = f_prime(x2);
z(1) = x1 - (f1/((f1-f2)/(x1-x2)));
fpz(1) = f_prime(z);
error = [];
while (abs(fpz(end)) > epsilon) && (k<iteration)
k = k+1;
if (f1>f2)
x2 = z(end);
z(end+1) = x1 - (f1/((f1-f2)/(x1-x2)));
fpz(end+1) = f_prime(z(end));
error(end+1) = abs(f(z(end))-fpz(end));
sprintf('x_min=%f', z(end))
else
x1 = z(end);
z(end+1) = x1 - (f1/((f1-f2)/(x1-x2)));
fpz(end+1) = f_prime(z(end));
error(end+1) = abs(f(z(end))-fpz(end));
sprintf('x_min=%f', z(end))
end
end
ans = 'x_min=0.249842'
ans = 'x_min=0.366849'
ans = 'x_min=0.478878'
ans = 'x_min=0.586140'
ans = 'x_min=0.688839'
ans = 'x_min=0.787168'
ans = 'x_min=0.881314'
ans = 'x_min=0.971454'
ans = 'x_min=1.057760'
ans = 'x_min=1.140393'
ans = 'x_min=1.219511'
ans = 'x_min=1.295263'
ans = 'x_min=1.367791'
ans = 'x_min=1.437234'
ans = 'x_min=1.503723'
ans = 'x_min=1.567383'
ans = 'x_min=1.628334'
ans = 'x_min=1.686692'
ans = 'x_min=1.742567'
ans = 'x_min=1.796065'
ans = 'x_min=1.847287'
ans = 'x_min=1.896330'
ans = 'x_min=1.943286'
ans = 'x_min=1.988244'
ans = 'x_min=2.031290'
ans = 'x_min=2.072504'
ans = 'x_min=2.111965'
ans = 'x_min=2.149747'
ans = 'x_min=2.185921'
ans = 'x_min=2.220557'
ans = 'x_min=2.253718'
ans = 'x_min=2.285469'
ans = 'x_min=2.315869'
ans = 'x_min=2.344976'
ans = 'x_min=2.372844'
ans = 'x_min=2.399527'
ans = 'x_min=2.425074'
ans = 'x_min=2.449535'
ans = 'x_min=2.472954'
ans = 'x_min=2.495378'
ans = 'x_min=2.516847'
ans = 'x_min=2.537403'
ans = 'x_min=2.557085'
ans = 'x_min=2.575929'
ans = 'x_min=2.593971'
ans = 'x_min=2.611246'
ans = 'x_min=2.627785'
ans = 'x_min=2.643621'
ans = 'x_min=2.658784'
ans = 'x_min=2.673301'
ans = 'x_min=2.687200'
ans = 'x_min=2.700509'
ans = 'x_min=2.713251'
ans = 'x_min=2.725450'
ans = 'x_min=2.737131'
ans = 'x_min=2.748315'
ans = 'x_min=2.759023'
ans = 'x_min=2.769276'
ans = 'x_min=2.779092'
ans = 'x_min=2.788491'
ans = 'x_min=2.797489'
ans = 'x_min=2.806105'
ans = 'x_min=2.814355'
ans = 'x_min=2.822253'
ans = 'x_min=2.829815'
ans = 'x_min=2.837056'
ans = 'x_min=2.843988'
ans = 'x_min=2.850626'
ans = 'x_min=2.856981'
ans = 'x_min=2.863066'
ans = 'x_min=2.868892'
ans = 'x_min=2.874470'
ans = 'x_min=2.879811'
ans = 'x_min=2.884924'
ans = 'x_min=2.889820'
ans = 'x_min=2.894508'
ans = 'x_min=2.898996'
ans = 'x_min=2.903293'
ans = 'x_min=2.907408'
ans = 'x_min=2.911347'
ans = 'x_min=2.915119'
ans = 'x_min=2.918730'
ans = 'x_min=2.922188'
ans = 'x_min=2.925498'
ans = 'x_min=2.928668'
ans = 'x_min=2.931703'
ans = 'x_min=2.934609'
ans = 'x_min=2.937391'
ans = 'x_min=2.940054'
ans = 'x_min=2.942605'
ans = 'x_min=2.945047'
ans = 'x_min=2.947385'
ans = 'x_min=2.949623'
ans = 'x_min=2.951767'
ans = 'x_min=2.953819'
ans = 'x_min=2.955784'
ans = 'x_min=2.957665'
ans = 'x_min=2.959466'
ans = 'x_min=2.961190'
ans = 'x_min=2.962842'
plot(error, 'rx')
title('error vs iteration')
my error is the absolute value of f(zi) - f(xopt) where zi is the values of z after each iteration and xopt is the value of z that finally breaks my while loop (optimum point).
In that case, do not calculate error inside the loop: keep track of all of the z values (which you are already doing), and after the loop,
fz = f(z);
error = fz - fz(end);
This of course only being valid if you converged within the allocated iterations: if you do not converge then fz(end) could be just about anything, and calculating the error relative to it would not be useful.

Accedi per commentare.

Prodotti

Release

R2019b

Richiesto:

il 9 Ott 2021

Modificato:

il 13 Ott 2021

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by