Determining a matrix to be positive definite - matlab

I want to check whether a matrix is positive definite or not. I have searched on the internet on how to check it using matlab. I am interested in using the chol way for checking (not check the eigenvalues one). Below are the codes:
[~, r] = chol(A);
r == 0 && rank(A) == size(A,1)
I know that if A is not positive definite, then r is positive. However, what is the point of checking rank(A)==size(A,1)? It seems that it still works if I just use the following codes:
[~, r] = chol(A);
r == 0 % check if r>0
I wonder if A is positive semi-definite matrix, r==0. However, if I use A=[1,0;0,0] as an example, using the above codes for checking, r = 2 > 0. This makes me feel uncomfortable on checking the rank.
I found this code here.

Why not use the 1-output variant of chol? This throws an error when A is not positive definite.
You can use that fact like this:
function itis = isPositiveDefinite(A)
% Input checks
errId = #(str) [mfilename ':' str];
assert(isnumeric(A) && ~isempty(A),...
errId('invalid_argument'),...
'Input argument must be a non-empty numeric matrix.');
% Initialize
itis = true;
% Trivial cases
if ~isequal(A.', A) || any(~isfinite(A(:))) || any(~isreal(A(:)))
itis = false;
% Less trivial cases -- use chol()
else
try
[~] = chol(double(A));
catch ME
if strcmp(ME.identifier, 'MATLAB:posdef')
itis = false;
else
baseME = MException(errId('chol_failure'), [...
'Failed to determine whether matrix is ',...
'positive definite.']);
throw(addCause(baseME, ME));
end
end
end
end

Related

Bisection doesn't return a value

The function below, bisection, is supposed to find a root given three inputs: a function f, and an interval defined using the two parameters a and b. The intention is that the value of a and b are changed within the function to approach a common point, as long as their signs are different.
When I call my function like this:
bisection( #(x)x-1 ,-2,3)
no output is returned. What am I doing wrong?
function X = bisection(f,a,b)
if ge((f(a)*f(b)),0)
disp('Wrong')
return;
end
X = (a+b)/2;
while abs(X)>0.01
if f(X)*f(a)>0
X=a;
else
X=b;
end
end
Enter the Infinite!
Well done! You've written your first (and not last, believe me) infinite loop. The problem is threefold. Firstly your stop condition was abs(X) and should have been abs(f(X)) - you don't care for X to be zero, you want f(X) to be zeros. Secondly you don't update your your X correctly so your break condition is never hit (unless you are lucky to give this function symmetrical a,b bounds around the zero of the function). You could see this easily by adding a line like disp(f(X)); pause(0.5); somewhere in the while-loop.
In general try to avoid infinite loops with some explicit stop condition. In my code below I've put in the interaction limit past which the algorithm will just stop (it would be more elegant to catch that condition and warn the user of hitting the iteration limit...).
function x0 = bisection(f,a,b)
assert(f(a)*f(b)<0,'Invalid f(x) range. f(a)*f(b) >= 0');
tol = 0.00001; % Tolerance
iter_limit = 10000; % Limit of number of iterations
iter = 0;
x0 = (a+b)/2; % Midpoint
while abs(f(x0)) > tol && iter < iter_limit
if f(x0)*f(a) > 0
a = x0; % Zero to the right of the midpoint
else
b = x0; % Zero to the left
end
x0 = (a+b)/2; % Recalculate midpoint
iter = iter + 1;
end
end
This should work no problem with
f = #(x)x-1;
bisection(f,-2,3);
I get something like 0.999992370... which is within specified tolerance from the actual answer (1).

Find zero crossing of sampled function [duplicate]

I have written a function in MATLAB to count the number of zero crossings given a vector of signal data. If I find a zero crossing, I also check whether the absolute difference between the two vector indices involved is greater than a threshold value - this is to try to reduce the influence of signal noise.
zc = [];
thresh = 2;
for i = 1:length(v)-1
if ( (v(i)>0 && v(i+1)<0) || (v(i)<0 && v(i+1)>0) ) && abs(v(i)-v(i+1)) >= thresh
zc = [zc; i+1];
end
end
zcCount = length(zc);
I used the vector from the zero crossings function here to test it: http://hips.seas.harvard.edu/content/count-zero-crossings-matlab
A = [-0.49840598306643,
1.04975509964655,
-1.67055867973620,
-2.01437026154355,
0.98661592496732,
-0.06048256273708,
1.19294080740269,
2.68558025885591,
0.85373360483580,
1.00554850567375];
It seems to work fine but is there a more efficient way of achieving the same result? E.g. on the above webpage, they simply use the following line to calculate zero crossings:
z=find(diff(v>0)~=0)+1;
Is there a way to incorporate the threshold check into something similarly efficient?
How about
zeroCrossIndex=diff(v>0)~=0
threshholdIndex = diff(v) >= thresh;
zcCount = sum(zeroCrossIndex & threshholdIndex)

MATLAB: Cannot properly evaluate function using input vector

I am trying to pass a vector into a function, and evaluate the vector over a piecewise function. When I run the code below, I am only returned a single number rather than a vector. Any ideas?
Thanks!
t[-5:1:50]
velocity(t)
function [v] = velocity( t )
%This function takes vector 't' and evaluates a velocity over a given
%piecewise function
if t>=0 & t<=8
v=10*t^2-5*t;
elseif t>=8 & t<=16
v=624-5*t;
elseif t>=16 & t<=26
v= 36*t+12*(t-16)^2;
elseif t>26
v=2136*exp(-0.1*(t-26));
else t<0
end
When you elevate a vector to the square, you are performing a scalar product with itself.
Replace t^2 with t.^2 for element-wise operators.
Do the same for (t-16).^2.
All the other operators should fall automatically into the element wise case but you can add points before them to be sure.
And, furthermore, the conditions as you have wrote them apply to a t as a scalar value. You can get the researched effect by doing the following:
Instead of
if cond1:
v = something
elif cond2:
v = something_else
Do
indices1 = (cond1) % where cond1 is t < 10 for example
indices2 = (cond2) % and cond2 is t >= 10
v[indices1] = something
v[indices2] = something_else
I hope you get the gist.

Warning: Possibly spurious solutions. [solvelib::checkSolutions]

I am trying to solve four algebraic equations in a for loop. It is giving a warning 'Possibly spurious solutions'. Could you please help me to figure out how to remove it. Code is attached herewith.
a=[1.78E-05 3.39E-04 0.0104 -0.05791 -16.36];
for i=1:R/l0
syms x y l r
[sol_l,sol_r,sol_x,sol_y] = solve(l == (sqrt((x-x0)^2+(y-y0)^2)), r == abs((x+x0)/2),...
poly2sym(a) == y, l*r*t == l0*r0*t0,x,y,l,r, 'Real', true);
for j=1:length(sol_x)
if (sol_x(j)<0)&&(sol_x(j)>x0)
if (sol_y(j)<0)&&(sol_y(j)<y0)
x_req(1,i) = sol_x(j);
y_req(1,i) = sol_y(j);
end
end
end
x0 = x_req(1,i);
y0 = y_req(1,i);
r0 = R-l0*(2*i-1)/2;
end
If you change your first equation to this, the warning no longer crops up:
l^2 == (x-x0)^2+(y-y0)^2
I'm not sure that you actually have spurious values though. The it's possible that the square root gave solvelib::checkSolutions trouble.
You may have thought that you had spurious values when you checked because you weren't outputting the variables correctly. You specify that solve solve for x, y, l, r (in that order), but then you name the output variables as sol_l, sol_r, sol_x, sol_y (different order). You must use the same order as `solve cannot guess bases on the names of your variables.
Your code:
R=30;
x0=-R;
y0=0;
l0=R/100;
t0=1.2;
t=0.7071;
r0=R-l0/2;
a=[1.78E-05 3.39E-04 0.0104 -0.05791 -16.36];
[sol_x,sol_y,sol_l,sol_r] = solve(l^2 == (x-x0)^2+(y-y0)^2, ...
r == abs((x+x0)/2), ...
poly2sym(a) == y, ...
l*r*t == l0*r0*t0, ...
x,y,l,r, 'Real', true)
% Check
sol_l2.^2 - (sol_x2-x0).^2+(sol_y2-y0).^2
sol_r - abs((sol_x+x0)/2)
[subs(poly2sym(a),x,sol_x(1));subs(poly2sym(a),x,sol_x(2));...
subs(poly2sym(a),x,sol_x(3));subs(poly2sym(a),x,sol_x(4))]-sol_y;
sol_l2.*sol_r2*t - l0*r0*t0
The check returns small values close zero.

Replace values in matrix with other values

I have a matrix with integers and I need to replace all appearances of 2 with -5. What is the most efficient way to do it? I made it the way below, but I am sure there is more elegant way.
a=[1,2,3;1,3,5;2,2,2]
ind_plain = find(a == 2)
[row_indx col_indx] = ind2sub(size(a), ind_plain)
for el_id=1:length(row_indx)
a(row_indx(el_id),col_indx(el_id)) = -5;
end
Instead of loop I I seek for something like: a(row_indx,col_indx) = -5, which does not work.
find is not needed in this case.
Use logical indexing instead:
a(a == 2) = -5
In case of searching whether a matrix is equal to inf you should use
a(isinf(a)) = -5
The general case is:
Mat(boolMask) = val
where Mat is your matrix, boolMask is another matrix of logical values, and val is the assignment value
Try this:
a(a==2) = -5;
The somewhat longer version would be
ind_plain = find(a == 2);
a(ind_plain) = -5;
In other words, you can index a matrix directly using linear indexes, no need to convert them using ind2sub -- very useful! But as demonstrated above, you can get even shorter if you index the matrix using a boolean matrix.
By the way, you should put semicolons after your statements if (as is usually the case) you're not interested in getting the result of the statement dumped out to the console.
The Martin B's method is good if you are changing values in vector. However, to use it in matrix you need to get linear indices.
The easiest solution I found is to use changem function. Very easy to use:
mapout = changem(Z,newcode,oldcode)
In your case: newA = changem(a, 5, -2)
More info: http://www.mathworks.com/help/map/ref/changem.html
Here's a trivial, unoptimised, probably slow implementation of changem from the Mapping Toolbox.
function mapout = changem(Z, newcode, oldcode)
% Idential to the Mapping Toolbox's changem
% Note the weird order: newcode, oldcode. I left it unchanged from Matlab.
if numel(newcode) ~= numel(oldcode)
error('newcode and oldcode must be equal length');
end
mapout = Z;
for ii = 1:numel(oldcode)
mapout(Z == oldcode(ii)) = newcode(ii);
end
end