Matlab: Plotting the conditions output of symbolic solve - matlab

I have a loop where I symbolically solve for intervals. Each iteration of the loop gives exactly one interval, for example:
v=[x+1,-x+4];
v = v > 0;
sol=solve(v,x,'ReturnConditions',true);
cond = sol.conditions;
ezplot(cond)
Would I be able to plot the 1x1 symbolic array " cond = -1 < x & x < 4 " at a y value of my choosing? When I use ezplot it always plots at y=1.

Maybe by multiplying the cond by the y value you wish to use. In that case the title must be changed to match the original condition, cond by casting it as a string. In the example below I plotted the condition/region at a height of y = 2. To implement this in the for-loop I'd probably make a y a vector a retrieve one value/cell upon each iteration.
syms x
v = [x+1,-x+4];
v = v > 0;
sol = solve(v,x,'ReturnConditions',true);
cond = sol.conditions;
y = 2;
ezplot(y*cond);
ylim([0 y*1.2]);
title(string(cond));

Related

How to use matlab to quickly judge whether a function is convex?

For example, FX = x ^ 2 + sin (x)
Just for curiosity, I don't want to use the CVX toolbox to do this.
You can check this within some interval [a,b] by checking if the second derivative is nonnegative. For this you have to define a vector of x-values, find the numerical second derivative and check whether it is not too negative:
a = 0;
b = 1;
margin = 1e-5;
point_count = 100;
f=#(x) x.^2 + sin(x);
x = linspace(a, b, point_count)
is_convex = all(diff(x, 2) > -margin);
Since this is a numerical test, you need to adjust the parameter to the properties of the function, that is if the function does wild things on a small scale we might not be able to pick it up. E.g. with the parameters above the test will falsely report the function f=#(x)sin(99.5*2*pi*x-3) as convex.
clear
syms x real
syms f(x) d(x) d1(x)
f = x^2 + sin(x)
d = diff(f,x,2)==0
d1 = diff(f,x,2)
expSolution = solve(d, x)
if size(expSolution,1) == 0
if eval(subs(d1,x,0))>0
disp("condition 1- the graph is concave upward");
else
disp("condition 2 - the graph is concave download");
end
else
disp("condition 3 -- not certain")
end

Create a variable number of terms in an anonymous function that outputs a vector

I'd like to create an anonymous function that does something like this:
n = 5;
x = linspace(-4,4,1000);
f = #(x,a,b,n) a(1)*exp(b(1)^2*x.^2) + a(2)*exp(b(2)^2*x.^2) + ... a(n)*exp(b(n)^2*x.^2);
I can do this as such, without passing explicit parameter n:
f1 = #(x,a,b) a(1)*exp(-b(1)^2*x.^2);
for j = 2:n
f1 = #(x,a,b) f1(x,a,b) + a(j)*exp(b(j)^2*x.^2);
end
but it seems, well, kind of hacky. Does someone have a better solution for this? I'd like to know how someone else would treat this.
Your hacky solution is definitely not the best, as recursive function calls in MATLAB are not very efficient, and you can quickly run into the maximum recursion depth (500 by default).
You can introduce a new dimension along which you can sum up your arrays a and b. Assuming that x, a and b are row vectors:
f = #(x,a,b,n) a(1:n)*exp((b(1:n).^2).'*x.^2)
This will use the first dimension as summing dimension: (b(1:n).^2).' is a column vector, which produces a matrix when multiplied by x (this is a dyadic product, to be precise). The resulting n * length(x) matrix can be multiplied by a(1:n), since the latter is a matrix of size [1,n]. This vector-matrix product will also perform the summation for us.
Mini-proof:
n = 5;
x = linspace(-4,4,1000);
a = rand(1,10);
b = rand(1,10);
y = 0;
for k=1:n
y = y + a(k)*exp(b(k)^2*x.^2);
end
y2 = a(1:n)*exp((b(1:n).^2).'*x.^2); %'
all(abs(y-y2))<1e-10
The last command returns 1, so the two are essentially identical.

Algorithm to find a value that gives the minimum output for two or equations

Suppose I have two equations with only one variable (free parameter) x and that k1 and k2 are constants. I would like to solve for:
f(x) + k1 = 0
&
g(x) + k2 = 0
...
h(x) + kn = 0
Of course there is no value of x that satisfies all of these equations. I basically would like the value of x that minimizes the output of each of these equations.
'solve' in matlab looks for an exact answer and returns an error, here's an example to demonstrate:
syms x
solution = solve(0.5*(x-k1)/sqrt(2) == 0, 0.5*(x-k2)/sqrt(2) == 0);
You can try using Unconstrained Optimization method such as fminsearch, for example:
h=#(x) x^2;
g=#(x) x^3;
k1=2;
k2=4;
inital_guess=3;
f = #(x) sum(abs([h(x)+k1; g(x)+k2]));
[x,fval] = fminsearch(f,inital_guess)
Note that I represent both eq in matrix form, and the minimization is by looking at the sum of their absolute values.
For the values I entered the value of x that minmize these eq is given by the output x = -1.5874

Meshgrid and double for-loops does not result in the same matrix, why?

I am trying to evaluate all values the expression f = 2y-exp(z) can take for different values of z and y. Were y and z are two vectors of length M. I am wondering why the two approaches for generating the expression f yields different results.
Using meshgrid:
[Y,Z] = meshgrid(y,z);
argument = 2*Y-exp(Z);
and with double for-loops
argument_new = zeros(M,M);
for i = 1:length(y)
for j = 1:length(z)
argument_new(i,j) = 2*y(i)-exp(z(j));
end
end
Any hints will be highly appreciated!
That's because of the way meshgrid creates 'inverted' directions. I don't find the right words, but here is an example illustrating with your code.You see that if you uncomment option 2 and use argument_new(j,i) instead of argument_new(i,j) both matrices are equal (as obtained with isequal).
clear
clc
M = 20;
y = 1:M;
z = 1:M;
[Y,Z] = meshgrid(y,z);
argument = 2*Y-exp(Z);
argument_new = zeros(M,M);
for i = 1:length(y)
for j = 1:length(z)
%// 1)
argument_new(i,j) = 2*y(i)-exp(z(j));
%// 2)
%// argument_new(j,i) = 2*y(i)-exp(z(j));
end
end
isequal(argument,argument_new) %// Gives 0 for option 1 and 1 for option 2.
Blame that on meshgrid:
MESHGRID is like NDGRID except that the order of the first two input
and output arguments are switched (i.e., [X,Y,Z] = MESHGRID(x,y,z)
produces the same result as [Y,X,Z] = NDGRID(y,x,z)).
Solution: use ndgrid, which doesn't do that switching, and is thus more "natural":
[Y,Z] = ndgrid(y,z);
argument = 2*Y-exp(Z);
Or in your code, after meshgrid, add a transpose operation: argument = argument.';)
They are the same, you should just transpose either one (' in Matlab), or you can replace i by j and vice versa in the for loops

Nested anonymous functions including arrayfun

I'm trying to do something like the following code:
k = linspace(a,b);
x = c:0.01:d;
% k and x are of different sizes
f = #(s) arrayfun(#(t) normcdf(s, b0+b1*t, sigma), x);
y = arrayfun(f, k);
I get the following error
Error using arrayfun Non-scalar in Uniform output, at index 1,
output 1. Set 'UniformOutput' to false.
I'm trying to avoid using a for loop for each element in k.
Also, for each result matching an element in k, I need to do another small calculation
Example with a loop:
for i=1:m % m is the number of elements in k
f = #(t) normcdf(k(i), b0+b1*x, sigma);
y = arrayfun(f, x);
res(i) = trapz(x,y);
end
any idea how can I get the same result as the for loop with the first method?
and why am I getting the error?
I would suggest the following:
k = linspace(a,b);
x = c:0.01:d;
[X,K] = meshgrid(x,k)
y = arrayfun(#(p,t) normcdf(p, b0+b1*t, sigma), K(:), X(:))
res = cumtrapz(x,y)
Untested though as you gave no example data and desired results. Maybe you need to swap the order of x and k as well as X and K to get the desired result. (or use ndgrid instead of meshgrid, has the same effect)