Table from a function with while loop [MATLAB] - matlab

I've written a code that gives me a zero in an interval of functions. This code uses the combination method of Newton's and Bisection methods.
Here's my code,
function p = newtonbisection(f, df, a, b, tol)
p = a;
while abs(f(p)) >= tol
if a <= p && b<= p
p = p - f(p)/df(p);
else
p = (a+b)/2;
end
if f(p)*f(b)<0
a = p;
else
b = p;
end
end
end
I've tested this code and works fine. However, if I want to create a table in .txt file with outputs {method that is used for each iter (Newton or bisection), a, b, p, f(p)} from each iteration, what should I need to add?
I could get desired data that I need in the command window (with the code below), but I'm having trouble with making an actual table with Matlab.
function p = newtonbisection(f, df, a, b, tol)
p = a;
iter = 0;
while abs(f(p)) >= tol
if a <= p && b<= p
p = p - f(p)/df(p);
iter = iter+1;
fprintf("newton\n")
else
p = (a+b)/2;
iter = iter+1;
fprintf("bisection\n")
end
if f(p)*f(b)<0
a = p;
else
b = p;
end
iter
a
b
p
disp(f(p))
end
end
Can I get some help?

There are multiple ways to do this. A simple approach would be:
preallocate your table (for performance purposes, cf. doc Preallocation)
add the corresponding values for each iteration to the table
delete remaining rows and store the table to a txt file
Example:
function p = newtonbisection(f, df, a, b, tol)
p = a;
iter = 0;
noRowsPreAll = 1000000;
sz = [noRowsPreAll 6];
varTypes = {'int32','categorical','double','double','double','double'};
varNames = {'step', 'method', 'a', 'b', 'p','f(p)'};
T = table('Size',sz,'VariableTypes',varTypes,'VariableNames', varNames);
while abs(f(p)) >= tol
iter = iter+1;
if iter > noRowsPreAll
disp('Warning: preallocate a bigger table!')
end
T.step(iter) = iter;
if a <= p && b<= p
p = p - f(p)/df(p);
T.method(iter) = 'newton';
else
p = (a+b)/2;
T.method(iter) = 'bisection';
end
if f(p)*f(b)<0
a = p;
else
b = p;
end
T.a(iter) = a;
T.b(iter) = b;
T.p(iter) = p;
T.("f(p)")(iter) = f(p);
end
T(iter+1:end,:) = [];
writetable(T, 'output.txt')
end

Related

My approximate entropy script for MATLAB isn't working

This is my Approximate entropy Calculator in MATLAB. https://en.wikipedia.org/wiki/Approximate_entropy
I'm not sure why it isn't working. It's returning a negative value.Can anyone help me with this? R1 being the data.
FindSize = size(R1);
N = FindSize(1);
% N = input ('insert number of data values');
%if you want to put your own N in, take away the % from the line above
and
%insert the % before the N = FindSize(1)
%m = input ('insert m: integer representing length of data, embedding
dimension ');
m = 2;
%r = input ('insert r: positive real number for filtering, threshold
');
r = 0.2*std(R1);
for x1= R1(1:N-m+1,1)
D1 = pdist2(x1,x1);
C11 = (D1 <= r)/(N-m+1);
c1 = C11(1);
end
for i1 = 1:N-m+1
s1 = sum(log(c1));
end
phi1 = (s1/(N-m+1));
for x2= R1(1:N-m+2,1)
D2 = pdist2(x2,x2);
C21 = (D2 <= r)/(N-m+2);
c2 = C21(1);
end
for i2 = 1:N-m+2
s2 = sum(log(c2));
end
phi2 = (s2/(N-m+2));
Ap = phi1 - phi2;
Apen = Ap(1)
Following the documentation provided by the Wikipedia article, I developed this small function that calculates the approximate entropy:
function res = approximate_entropy(U,m,r)
N = numel(U);
res = zeros(1,2);
for i = [1 2]
off = m + i - 1;
off_N = N - off;
off_N1 = off_N + 1;
x = zeros(off_N1,off);
for j = 1:off
x(:,j) = U(j:off_N+j);
end
C = zeros(off_N1,1);
for j = 1:off_N1
dist = abs(x - repmat(x(j,:),off_N1,1));
C(j) = sum(~any((dist > r),2)) / off_N1;
end
res(i) = sum(log(C)) / off_N1;
end
res = res(1) - res(2);
end
I first tried to replicate the computation shown the article, and the result I obtain matches the result shown in the example:
U = repmat([85 80 89],1,17);
approximate_entropy(U,2,3)
ans =
-1.09965411068114e-05
Then I created another example that shows a case in which approximate entropy produces a meaningful result (the entropy of the first sample is always less than the entropy of the second one):
% starting variables...
s1 = repmat([10 20],1,10);
s1_m = mean(s1);
s1_s = std(s1);
s2_m = 0;
s2_s = 0;
% datasample will not always return a perfect M and S match
% so let's repeat this until equality is achieved...
while ((s1_m ~= s2_m) && (s1_s ~= s2_s))
s2 = datasample([10 20],20,'Replace',true,'Weights',[0.5 0.5]);
s2_m = mean(s2);
s2_s = std(s2);
end
m = 2;
r = 3;
ae1 = approximate_entropy(s1,m,r)
ae2 = approximate_entropy(s2,m,r)
ae1 =
0.00138568170752751
ae2 =
0.680090884817465
Finally, I tried with your sample data:
fid = fopen('O1.txt','r');
U = cell2mat(textscan(fid,'%f'));
fclose(fid);
m = 2;
r = 0.2 * std(U);
approximate_entropy(U,m,r)
ans =
1.08567461184858

how to find newton iteration for each of initial points

function p = newton_hw(p0,tol,Nmax)
%NEWTON'S METHOD: Enter f(x), f'(x), x0, tol, Nmax
f = #(x) x*cos(x)-((sin(x))^2);
fp= #(x) -x*sin(x)+ cos(x)-2*sin(x)*cos(x);
p = p0 - (f(p0)/fp(p0));
y1=f(p);
fprintf('y1=%f',y1)
i = 1;
while (abs(p - p0) >= tol)
p0 = p;
p = p0 - f(p0)/fp(p0);
i = i + 1;
if (i >= Nmax)
fprintf('Fail after %d iterations\n',Nmax);
break
end
y=f(p);
fprintf('a=%f,y=%f,\n',p,y);
end
end
This is my question:
How to iterate for each of p0 = 0,.1,.2,...,49,5.
Iterating using user's step can be done this way:
for i = 0:0.1:5
Also any indexing can be done the same way: x = [0:2:50].
If your function works correctly (I suppose so), we can go this way:
k = 1;
for i = 0:0.1:5
res(k) = newton_hw(i,0.001,1000);
k = k+1;
end
But also we can do it at one line - style:
res = arrayfun( #(x) newton_hw(x, 0.001, 1000), I)

How to skip an error inside a loop and let the loop continue

The following is my full code: (Most of it isn't useful for what I'm asking, but I just put in the entire code for context, the part of the code that is causing me trouble is towards the end)
clc
clear
P = xlsread('b3.xlsx', 'P');
d = xlsread('b3.xlsx', 'd');
CM = xlsread('b3.xlsx', 'Cov');
Original_PD = P; %Store original PD
LM_rows = size(P,1)+1; %Expected LM rows
LM_columns = size(P,2); %Expected LM columns
LM_FINAL = zeros(LM_rows,LM_columns); %Dimensions of LM_FINAL
% Start of the outside loop
for k = 1:size(P,2)
P = Original_PD(:,k);
interval = cell(size(P,1)+2,1);
for i = 1:size(P,1)
interval{i,1} = NaN(size(P,1),2);
interval{i,1}(:,1) = -Inf;
interval{i,1}(:,2) = d;
interval{i,1}(i,1) = d(i,1);
interval{i,1}(i,2) = Inf;
end
interval{i+1,1} = [-Inf*ones(size(P,1),1) d];
interval{i+2,1} = [d Inf*ones(size(P,1),1)];
c = NaN(size(interval,1),1);
for i = 1:size(c,1)
c(i,1) = mvncdf(interval{i,1}(:,1),interval{i,1}(:,2),0,CM);
end
c0 = c(size(P,1)+1,1);
f = c(size(P,1)+2,1);
c = c(1:size(P,1),:);
b0 = exp(1);
b = exp(1)*P;
syms x;
eqn = f*x;
for i = 1:size(P,1)
eqn = eqn*(c0/c(i,1)*x + (b(i,1)-b0)/c(i,1));
end
eqn = c0*x^(size(P,1)+1) + eqn - b0*x^size(P,1);
x0 = solve(eqn);
for i = 1:size(x0)
id(i,1) = isreal(x0(i,1));
end
x0 = x0(id,:);
x0 = x0(x0 > 0,:);
clear x;
for i = 1:size(P,1)
x(i,:) = (b(i,1) - b0)./(c(i,1)*x0) + c0/c(i,1);
end
x = [x0'; x];
x = double(x);
x = x(:,sum(x <= 0,1) == 0)
lamda = -log(x);
LM_FINAL(:,k) = lamda;
end
% end of the outside loop
The important part of the above loop is towards the end:
x = x(:,sum(x <= 0,1) == 0)
This condition is sometimes not satisfied and hence the variable x is empty, which means LM_FINAL(:,k) = lamda is also empty. When this happens, I get the error:
x =
Empty matrix: 43-by-0
Improper assignment with rectangular empty matrix.
Error in Solution (line 75)
LM_FINAL(:,k) = lamda;
How can I skip this error so that the column for LM_FINAL remains as empty, but the loop continues (so that the rest of LM_FINAL's columns are filled) rather than terminating?
You can use try and catch phrase to explicitly handle errors inside loop (or elsewhere in your code).

QR Decomposition Algorithm Using Givens Rotations

I am coding a QR decomposition algorithm in MATLAB, just to make sure I have the mechanics correct. Here is the code for the main function:
function [Q,R] = QRgivens(A)
n = length(A(:,1));
Q = eye(n);
R = A;
for j = 1:(n-1)
for i = n:(-1):(j+1)
G = eye(n);
[c,s] = GivensRotation( A(i-1,j),A(i,j) );
G(i-1,(i-1):i) = [c s];
G(i,(i-1):i) = [-s c];
Q = Q*G';
R = G*R;
end
end
end
The sub function GivensRotation is given below:
function [c,s] = GivensRotation(a,b)
if b == 0
c = 1;
s = 0;
else
if abs(b) > abs(a)
r = -a / b;
s = 1 / sqrt(1 + r^2);
c = s*r;
else
r = -b / a;
c = 1 / sqrt(1 + r^2);
s = c*r;
end
end
end
I've done research and I'm pretty sure this is one of the most straightforward ways to implement this decomposition, in MATLAB especially. But when I test it on a matrix A, the R produced is not right triangular as it should be. The Q is orthogonal, and Q*R = A, so the algorithm is doing some things right, but it is not producing exactly the correct factorization. Perhaps I've just been staring at the problem too long, but any insight as to what I've overlooked would be appreciated.
this seems to have more bugs,
what I see:
You should rather use [c,s] = GivensRotation( R(i-1,j),R(i,j) ); (note, R instead of A)
The original multiplications Q = Q*G'; R = G*R are correct.
r = a/b and r = b/a (without minus, not sure if it's important)
G([i-1, i],[i-1, i]) = [c -s; s c];
Here is an example code, seems to work.
First file,
% qrgivens.m
function [Q,R] = qrgivens(A)
[m,n] = size(A);
Q = eye(m);
R = A;
for j = 1:n
for i = m:-1:(j+1)
G = eye(m);
[c,s] = givensrotation( R(i-1,j),R(i,j) );
G([i-1, i],[i-1, i]) = [c -s; s c];
R = G'*R;
Q = Q*G;
end
end
end
and the second
% givensrotation.m
function [c,s] = givensrotation(a,b)
if b == 0
c = 1;
s = 0;
else
if abs(b) > abs(a)
r = a / b;
s = 1 / sqrt(1 + r^2);
c = s*r;
else
r = b / a;
c = 1 / sqrt(1 + r^2);
s = c*r;
end
end
end

Shorter code in matlab to minimize data and getting corresponding indices

EDIT How to simplify the following code:
if(x(a) > x(b))
s = b;
e = a;
else
s = a;
e = b;
end
I can get it shorter like:
s = a;
e = b;
if(x(a) > x(b))
s = b;
e = a;
end
Thanks!
EDIT
h = [a b];
[~, idx] = min([x(a) x(b)]);
s = h(idx)
e = h(3-idx)
Are you sure your code does what you wanted it to do?
Maybe you want to try
s = min([x(a),x(b)]);
e = max([x(a),x(b)]);
EDIT: OK there you go,
r = [find(x==max(x), find(x==minx)];
you have what you need in r but if you need them as s and e then:
s = r(1);
e = r(2);