Using fzero to solve eqn in MatLab - matlab

I hope this is the right area. I'm trying to get this code to work in MatLab.
function y=test(x)
y=-x+(B/(B-1))*(r-a)*p+(B/(B-1))*(r-a)*(b((1-(b/x)^(B-1))/r- a)+p* ((b/x)^B))/(1-(b/x)^B);
end
I then jump to the command value and type this:
B=3.0515;
b=1.18632*10^5;
a=.017;
r=.054;
p=5931617;
I then try to find the zeros of the first equation by typing this and I get errors:
solution=fzero(#test,5000000)
I'm getting the following error:
Error: File: test.m Line: 5 Column: 1 This statement is not
inside any function. (It follows the END that terminates the
definition of the function "test".)
New error
Error using fzero (line 289)
FZERO cannot continue because user supplied function_handle ==> #(x)
(test(x,B,b,a,r,p))
failed with the error below.
Subscript indices must either be real positive integers or logicals.

I would guess that this is a problem of scoping, you are defining variables (B, b, etc...) in the command line but trying to use them inside your test function where they are out of scope. You should alter your test function to take these in as parameters and then use an anonymous function so that your call to test in fsolve still only takes a single parameter:
function y=test(x, B, b, r, a, p)
y=-x+(B/(B-1))*(r-a)*p+(B/(B-1))*(r-a)*(b((1-(b/x)^(B-1))/r- a)+p* ((b/x)^B))/(1-(b/x)^B);
end
and
B=3.0515;
b=1.18632*10^5;
a=.017;
r=.054;
p=5931617;
solution=fzero(#(x)(test(x,B,b,a,r,p)),5000000)
As an aside, unless you really do mean matrix multiplication, I would suggest that you replace all your *s and /s in test with the element-wise operators .* and ./. If you are dealing with scalars, it doesn't matter now, but it makes a big difference if you later want to scale your project and need a vectorized solution.
Regarding the errors you have added to your question:
You can't put code after the end in your function file. (With the exception of local functions). Your objective function should be an .m-file containing the code for one single function.
This is because in your test function you have ...b((1-(b/x)^(B-1))... which in MATLAB means you are trying to index the variable b in which case the value of (1-(b/x)^(B-1) has to be a positive integer. I'm guess you are missing a *

Your
function y=test(x)
y=-x+(B/(B-1))*(r-a)*p+(B/(B-1))*(r-a)*(b((1-(b/x)^(B-1))/r- a)+p* ((b/x)^B))/(1-(b/x)^B);
end
cannot access variables in your workspace. You need to pass the values in somehow. You could do something like:
function y=test(x,B,b,a,r,p)
y=-x+(B/(B-1))*(r-a)*p+(B/(B-1))*(r-a)*(b((1-(b/x)^(B-1))/r- a)+p* ((b/x)^B))/(1-(b/x)^B);
end
and then you can create an implicit wrapper function:
B=3.0515;
b=1.18632*10^5;
a=.017;
r=.054;
p=5931617;
solution = fzero(#(x) test(x,B,b,a,r,p),5000000)
I haven't tested whether fzero returns sensible results, but this code shouldn't give an error.

Related

Write recursive sub-functions and non-recursive sub-functions in Matlab

I'm newbie to Matlab
I have an assignment :
Legendre polynomial Pn(x), n=0,1,2,. . . The recursive formula of is
Write recursive sub-functions and non-recursive sub-functions separately to find the value of the Legendre polynomial function
This is my code :
function P =Legendre(n,x)
syms x;
n = input('n=');
if n==0
P=1;
elseif n==1
P=x;
elseif n>=2
P=((2*n-1)/n)*x*Legendre(n-1)-((n-1)/n)*Legendre(n-2);
end
end
But I get an error message:
Unrecognized function or variable 'Legendre'.
Error in ti4 (line 9)
P=((2*n-1)/n)*x*Legendre(n-1)-((n-1)/n)*Legendre(n-2);
Sorry for the stupid question. Can anyone help me? Thank u so much
A few things are probably going on here.
File name needs to match function name (for the primary function)
In your case, the filename needs to be Legendre.m.
Symbolic toolbox OR do you want an answer
for most uses of this function, I would leave two full inputs, just as you have them. Bur I would remove the first two lines completely.
As it is, the first two lines will break your inputs. The value for n is reset by the input function. I'm actually not sure what happens when you declare an existing variable x, to a sym.
Input consistency
You are setting up a function with two inputs, named n and x. But when you maek your recursive calls you only pass in one variable. The easiest thing to do here is simply keep passing n in as the first input.
(Right now, you are trying to pass in x in the recursive calls, but it will be interpreted as n.)

Error regarding inlineeval in MATLAB

As part of a group project we have a system of 2 non linear differential equations and we have to draw the S=S(t) , I=I(t) graphic using the midpoint method.
And I'm getting the following error when trying to insert the matrix with the corresponding differential equations:
"Error in inline expression ==> matrix([[-(IS)/1000], [(IS)/1000 - (3*I)/10]])
Undefined function 'matrix' for input arguments of type 'double'.
Error in inline/subsref (line 23)
INLINE_OUT_ = inlineeval(INLINE_INPUTS_, INLINE_OBJ_.inputExpr, INLINE_OBJ_.expr);"
The code I have done is the following:
syms I S
u=[S;I];
F=[-0.001*S*I;0.001*S*I-0.3*I];
F1=inline(char(F),'I','S');
h=100; %Valores aleatórios
T=100000;
ni=(T/h);
u0=[799;1];
f=zeros(1,2);
k=zeros(1,2);
i=1;
while i<=ni
f(1)=F1(u0(1));
f(2)=F1(u0(2));
dx=h*f;
k(1)=F1((u0(1)+h*(1/2)),(u0(2)+h*(1/2)));
k(2)=F1((u0(1)+h*(1/2)),(u0(2)+h*(1/2)));
u1=u0+h*k;
disp('i:'),disp(i)
disp('u= '),disp(u1)
u0=u1;
i=i+1;
end
I'm new to this so the algorithm it's very likely to be wrong but if someone could help me with that error I'd apreciate it. Thank you!
The problem that specifically creates the error is that you are putting two symbolic functions into a matrix and then calling char (which outputs matrix([[-(IS)/1000], [(IS)/1000 - (3*I)/10]]) rather than converting nicely to string).
The secondary problem is that you are trying to pass two functions simultaneously to inline. inline creates a single function from a string (and using anonymous functions instead of inline is preferred anyway). You cannot put multiple functions in it.
You don't need sym here. In fact, avoid it (more trouble than it's worth) if you don't need to manipulate the equations at all. A common method is to create a cell array:
F{1} = #(I,S) -0.001*S*I;
F{2} = #(I,S) 0.001*S*I-0.3*I;
You can then pass in I and S as so:
F{1}(500,500)
Note that both your functions include both I and S, so they are always necessary. Reconsider what you were expecting when passing only one variable like this: f(1)=F1(u0(1));, because that will also give an error.

How to call a custom function with exponentiation for every element of a matrix in GNU Octave?

Trying to find a way to call the exponentiation function ( ^ ) used in a custom function for every item in a matrix in GNU Octave.
I am quite a beginner, and I suppose that this is very simple, but I can't get it to work.
The code looks like this:
function result = the_function(the_val)
result = (the_val - 5) ^ 2
endfunction
I have tried to call it like this:
>> A = [1,2,3];
>> the_function(A);
>> arrayfun(#the_function, A);
>> A .#the_function 2;
None of these have worked (the last one I believe is simply not correct syntax), throwing the error:
error: for A^b, A must be a square matrix
This, I guess, means it is trying to square the matrix, not the elements inside of it.
How should I do this?
Thanks very much!
It is correct to call the function as the_function(A), but you have to make sure the function can handle a vector input. As you say, (the_val - 5)^2 tries to square the matrix (and it thus gives an error if the_val is not square). To compute an element-wise power you use .^ instead of ^.
So: in the definition of your function, you need to change
result = (the_val-5)^2;
to
result = (the_val-5).^2;
As an additional note, since your code as it stands does work with scalar inputs, you could also use the arrayfun approach. The correct syntax would be (remove the #):
arrayfun(the_function, A)
However, using arrayfun is usually slower than defining your function such that it works directly with vector inputs (or "vectorizing" it). So, whenever possible, vectorize your function. That's what my .^suggestion above does.

MATLAB symbolic variables couldn't be used in nested function

I have a MATLAB function to solve a Inertia Tensor , and I have a nested function in my program . All the variables in it are symbolics but it told me
“Error using assignin: Attempt to add ”x“ to a static workspace”
and I don't understand why this happens . Here is my test.m code:
function test
syms x y z
f=x
f1=f+1
f2=f1^2
function r=test2
r=f2^3;
end
f3=test2
end
After searching this web-forum I have found some answers . But at the same time I just don't understand it
Andrew Janke explianed it like this : While syms A may look like a static variable declaration, it isn't. It's just a regular function call. It's using Matlab's "command" invocation style to look like syntax, but it's really equivalent to syms('a', 'b', 'c').
on this page : Matlab: "Error using assignin: Attempt to add "c" to a static workspace"
what does static variable mean ?
I also search the HELP doc and it said :In functions and scripts, do not use syms to create symbolic variables with the same names as MATLAB® functions. For these names MATLAB does not create symbolic variables, but keeps the names assigned to the functions.
I only know syms x to create a symbolic variable in the workspace but why does the documentation say MATLAB does not create ?
'Static' means fixed, 'workspace' is what Matlab calls the places where all of its variables are stored. For non-nested functions the workspace starts off as empty when Matlab is at the beginning of the function; as Matlab continues through function's lines of code it continuously add more variables to the workspace.
For functions with a nested function, Matlab first parses the function to see what variable will be created (it specifically looks for x = type lines), then it creates all of these variables (with value as 'unassigned'), and then only does it start to run through the code; but while running through the code, it can never create a new variable.
This is why the code
function TestNestedFunction
syms x;
function Nested()
end
end
generates an error, there is no x = to tell it to pre-create the unassigned variable x at the start of the code. It fails at syms x;, as that line tries to create a new variable x, which fails as it may not.
This is also why the following code runs
function TestNestedFunction
syms x;
x = x;
function Nested()
end
end
it sees the x = and then pre-creates x. (This is why your example of adding [x, y, z] = deal([]); also works).
You can test this with a break point at the beginning of simple non-nested function and a simple nested function. Just run it step by step.
This code works:
function test
x=sym('x')
y=sym('y')
z=sym('z')
f=x
f1=f+1
f2=f1^2
function r=test2
r=f2^3;
end
f3=test2
end
I think the pages you found are quite clear.
You need to declare the variables one by one and use:
x = sym('x')
Otherwise syms will try to assign the values into a workspace where this is not allowed.

In Matlab, how to solve an equation originating in a function?

How do I easiest solve an equation=0 with a function as a parameter?
My function with one input variable is called potd(angle), with one output variable, potNRGderiv. I tried:
syms x
solve(potd(x))
This gave me error: Undefined function 'sind' for input arguments of type 'sym'.
Have you got any ideas? Thanks in advance.
solve is the wrong avenue here, unless your function can be rewritten as a simple equation. solve uses muPAD functions which is why you can do solve(sin(x)) but not solve(sind(x)). You can, of course, just do the conversion yourself.
If your function is more complicated or you'd rather not rewrite it, look into fsolve:
x = fsolve(#myfun,x0)
Where x0 is your initial guess - i.e. myfun(x0) is close to 0 - and myfun is a function which takes x and returns a single output. Depending on what your function does, you may have to adjust the options using optimoptions (tolerance, step size, etc) to get a good result.