Absolute maximum of symbolic expression in matlab - matlab

Is there any direct function for finding maximum of absolute of a symbolic function? for example
syms x1 x2
assume(-10<x1<10)
assume(-12<x2<8)
max(abs(x1+x2))
returns
Input arguments must be convertible to floating-point numbers.
as error.

The ability to use the functions MAX and MIN for objects of class sym is not available in MATLAB.
To work around this issue, you could do one of the following, depending on the definition of the symbolic variables:
For symbolic comparisons there is no general workaround as there is no clear definition of what the result should look like. An example shows quite clearly the lack of a definition of a "good" result.
% This code will not work
syms x1 x2 x3 x4 x5
X = [x1,x2,x3,x4,x5];
max(X)
min(X)
% also unclear:
x1 > x2
x4 < x3
If the ranges of the symbolic variables being compared are clearly separated, the function FEVAL can be used as follows:
syms x positive;
syms y positive;
feval(symengine,'max',x,-y)
Similarly, a comparison can be made between a symbolic variable and a double using the function FEVAL:
syms x positive
feval(symengine,'max',x,-1)
This will return "x" as x would be always greater 0 and therefore greater -1.
If you have an array of symbolic numbers like
X = sym([1,2,3,4]);
then the array can be cast to type DOUBLE before using the function MAX/MIN on it. E.g.
max(double(X))

Related

Plot log(n over k)

I've never used Matlab before and I really don't know how to fix the code. I need to plot log(1000 over k) with k going from 1 to 1000.
y = #(x) log(nchoosek(1000,x));
fplot(y,[1 1000]);
Error:
Warning: Function behaves unexpectedly on array inputs. To improve performance, properly
vectorize your function to return an output with the same size and shape as the input
arguments.
In matlab.graphics.function.FunctionLine>getFunction
In matlab.graphics.function.FunctionLine/updateFunction
In matlab.graphics.function.FunctionLine/set.Function_I
In matlab.graphics.function.FunctionLine/set.Function
In matlab.graphics.function.FunctionLine
In fplot>singleFplot (line 241)
In fplot>#(f)singleFplot(cax,{f},limits,extraOpts,args) (line 196)
In fplot>vectorizeFplot (line 196)
In fplot (line 166)
In P1 (line 5)
There are several problems with the code:
nchoosek does not vectorize on the second input, that is, it does not accept an array as input. fplot works faster for vectorized functions. Otherwise it can be used, but it issues a warning.
The result of nchoosek is close to overflowing for such large values of the first input. For example, nchoosek(1000,500) gives 2.702882409454366e+299, and issues a warning.
nchoosek expects integer inputs. fplot uses in general non-integer values within the specified limits, and so nchoosek issues an error.
You can solve these three issues exploiting the relationship between the factorial and the gamma function and the fact that Matlab has gammaln, which directly computes the logarithm of the gamma function:
n = 1000;
y = #(x) gammaln(n+1)-gammaln(x+1)-gammaln(n-x+1);
fplot(y,[1 1000]);
Note that you get a plot with y values for all x in the specified range, but actually the binomial coefficient is only defined for non-negative integers.
OK, since you've gotten spoilers for your homework exercise anyway now, I'll post an answer that I think is easier to understand.
The multiplicative formula for the binomial coefficient says that
n over k = producti=1 to k( (n+1-i)/i )
(sorry, no way to write proper formulas on SO, see the Wikipedia link if that was not clear).
To compute the logarithm of a product, we can compute the sum of the logarithms:
log(product(xi)) = sum(log(xi))
Thus, we can compute the values of (n+1-i)/i for all i, take the logarithm, and then sum up the first k values to get the result for a given k.
This code accomplishes that using cumsum, the cumulative sum. Its output at array element k is the sum over all input array elements from 1 to k.
n = 1000;
i = 1:1000;
f = (n+1-i)./i;
f = cumsum(log(f));
plot(i,f)
Note also ./, the element-wise division. / performs a matrix division in MATLAB, and is not what you need here.
syms function type reproduces exactly what you want
syms x
y = log(nchoosek(1000,x));
fplot(y,[1 1000]);
This solution uses arrayfun to deal with the fact that nchoosek(n,k) requires k to be a scalar. This approach requires no toolboxes.
Also, this uses plot instead of fplot since this clever answer already addresses how to do with fplot.
% MATLAB R2017a
n = 1000;
fh=#(k) log(nchoosek(n,k));
K = 1:1000;
V = arrayfun(fh,K); % calls fh on each element of K and return all results in vector V
plot(K,V)
Note that for some values of k greater than or equal to 500, you will receive the warning
Warning: Result may not be exact. Coefficient is greater than 9.007199e+15 and is only accurate to 15 digits
because nchoosek(1000,500) = 2.7029e+299. As pointed out by #Luis Mendo, this is due to realmax = 1.7977e+308 which is the largest real floating-point supported. See here for more info.

Symbolic differentiation

Well, I know, for a normal case, if I define
syms x,y
K = f(x,y)
as an explicit expression on x and y, we can do diff(K, x) or diff(K, y) to obtain what we want.
But right now, if I have another function
J = g(K)
And I want to do
diff(J, K)
then error occurs as:
'The second argument must be a variable or a non negative integer specifying the number of differentiations.'
So, in a nutshell, how to solve this kind of 'chained expression differentiation'? (Sorry for this ambiguous description.)
According to the diff function in Matlab,
The first argument should be the function you want to differentiate
and the remaining arguments must be either the symbolic variables or a
non-negative number which represents the number of differentiation.
So, the error.
The second argument must be a variable or a non negative integer specifying the number of differentiations.
In the code diff(J, K) is saying that K is a symbolic variable to the Matlab but in actual case, K is an expression in the terms of x and y. So, this is the reason why Matlab is throwing that error.
So if you want to differentiate a chained function with variables x, y then you need to mention each symbolic variables explicitly within the diff() function whenever you want to differentiate that expression. The code to do so is below.
% define the symbolic functions
% as f(x,y) and g(K)
syms f(x,y) g(K)
% create the functions
K = f(x,y)
J = g(K)
% differentiate the functions with
% respect to x and y respectively.
% ------------------------
% differentiate w.r.t x
diff_K_x = diff(K, x)
% differentiate w.r.t y
diff_K_y = diff(K, y)
% -----------------------
% differentiate the function J with respect to x and y both
diff_K_xy = diff(J,x,y)

Symbolic multiplication of functions

I get an error when trying to multiply a symbolic function and a symbolic integral:
eta02=vpa(-i*omega2/((i*alpha2*lambda_0)^(2/3)),prec); %whatever
eta_inf2=vpa(vpa(((i*alpha2*lambda_0)^(1/3))*YMAX,prec)+eta02,prec); %whatever
%%
syms lu
syms x
myairyf(lu)= airy(lu);
mybairyf(lu)=airy(2,lu);
Gi2(x)=-(mybairyf*int(myairyf,lu,[eta_inf2,(x)])-myairyf*int(mybairyf,lu,[eta02,(x)]));
Error using sym/subsindex (line 769)
Invalid indexing or function definition. When defining a function, ensure that the arguments are symbolic variables and the body of the
function is a SYM expression. When indexing, the input must be numeric, logical, or ':'.
How can this be done? Additionally, how could I plot Gi2(x), given that it's symbolic?
By using the symfun function.
Gi2 = sumfun(-(mybairyf*int(myairyf,lu,[eta_inf2,(x)])-myairyf*int(mybairyf,lu,[eta02,(x)])), x);
Now Gi2(val) will evaluate the function for the value ´val´
Plotting then can be done by evaluating this function for the values you want to plot for, storing them in a vector, and plot the x and y values.
xvals = linspace(0,10,100);
yvals = Gi2(xvals);
figure
plot(xvals,vals)

Differentiating symbolically then obtaining a numerical value

syms x
syms y
f = 2*x^2 + y
z = diff(f,x)
x = 3
SolvedDiffEq = z
Obviously z = 4x. But how do I solve to get the numerical answer of 12? I've played with vpa, double, subs and cannot figure it out.
This is a simple example. My actual code has very complex equations with many variables. Furthermore, I am trying to iteratively solve these equations so it is not practical to manually substitute each variable.
You are looking for symbolic substitution command, which is subs. In your example, subs(z) returns 12.

Numerically integrate a function f(x) over x using MATLAB where f(x) has another argument y which is a vector

I would like to numerically integrate a vector which represents a function f(x) over the range of x specified by bounds x0 and x1 in Matlab. I would like to check that the output of the integration is correct and that it converges.
There are the quad and quadl functions that serve well in identifying the required error tolerance, but they need the input argument to be a function and not the resulting vector of the function. There is also the trapz function where we can enter the two vectors x and f(x), but then it computes the integral of f(x) with respect to x depending on the spacing used by vector x. However, there is no given way using trapz to adjust the tolerance as in quad and quadl and make sure the answer is converging.
The main problem why I can't use quad and quadl functions is that f(x) is the following equation:
f(x) = sum(exp(-1/2 *(x-y))), the summation is over y, where y is a vector of length n and x is an element that is given each time to the function f(x). Therefore, all elements in vector y are subtracted from element x and then the summation over y is calculated to give us the value f(x). This is done for m values of x, where m is not equal to n.
When I use quadl as explained in the Matlab manual, where f(x) is defined in a separate function .m file and then in the main calling file, I use Q = quadl(#f,x0,x1,tolerance,X,Y); here X is a vector of length m and Y is a vector of length L. Matlab gives an error: "??? Error using ==> minus
Matrix dimensions must agree." at the line where I define the function f(x) in the .m function file. f(x) = sum(exp(-1/2 *(x-y)))
I assume the problem is that Matlab treats x and y as vectors that should be of the same length when they are subtracted from each other, whereas what's needed is to subtract the vector Y each time from a single element from the vector X.
Would you please recommend a way to solve this problem and successfully numerically integrate f(x) versus x with a method to control the tolerance?
From the documentationon quad it says:
The function y = fun(x) should accept a vector argument x and return a vector result y, the integrand evaluated at each element of x.
So every time we call the function, we need to evaluate the integrand at each given x.
Also, to parameterize the function call with the constant vector Y, I recommend an anonymous function call. There's a reasonable demo here. Here's how I implemented your problem in Matlab:
function Q = test_num_int(x0,x1,Y)
Q = quad(#(x) myFun(x,Y),x0,x1);
end
function fx = myFun(x,Y)
fy = zeros(size(Y));
fx = zeros(size(x));
for jj=1:length(fx)
for ii=1:length(Y)
fy(ii) = exp(-1/2 *(x(jj)-Y(ii)));
end
fx(jj) = sum(fy);
end
end
Then I called the function and got the following output:
Y = 0:0.1:1;
x0 = 0;
x1 = 1;
Q = test_num_int(x0,x1,Y)
Q =
11.2544
The inputs for the lower and upper bound and the constant array are obviously just dummy values, but the integral converges very quickly, almost immediately. Hope this helps!
I believe the following would also work:
y = randn(10,1);
func = #(x) sum(exp(-1/2 *(x-y)));
integral(func,0,1,'ArrayValued',true)