Warning: Matrix is singular, close to singular or badly scaled. Results may be inaccurate. RCOND = NaN - matlab

The following code uses rk4 to simulate the dynamics defined via fe function. However, I encountered the warning Warning: Matrix is singular, close to singular or badly scaled. Results may be inaccurate. RCOND = NaN. .
I felt that the function defined in fe, sometimes the Numerator equals zero, thus creates singularity. But I don't know how to avoid it.
Should I change the function formula (I prefer not to), or should I revise the code, or change the solver?
Thank you in advance for any suggestion.
clear;
global G
tic
n=40;
A = ones(n) - eye(n);
G = graph(A);
num_samples =1;
p.G = A
dim_G = size(p.G);
p.K = 1;
p.N = dim_G(1);
nIters = 2000;
tBegin = 0;
tEnd = 100;
% initial condition
Init = -pi + 2*pi.*rand(p.N,num_samples);
dim_thetaInit = size(Init);
Init = Init(:,1);
[t,sol] = rk4(#fe,tBegin,tEnd,Init,nIters,p);
function td = fe(t,theta,p)
[theta_i,theta_j] = meshgrid(theta);
adj_matrix = p.G;
a = 4;
b = 1;
td= sum(adj_matrix'.*( ( b*cos(theta_i-theta_j) * (2*a^2*cos(theta_i-theta_j)*sin(theta_i-theta_j)-2*b^2*cos(theta_i-theta_j)*sin(theta_i-theta_j)) ) / ( 2*(b^2*(cos(theta_i-theta_j))^2+a^2*(sin(theta_i-theta_j))^2)^(3/2) ) + (b*sin(theta_i-theta_j))/( sqrt( b^2*cos(theta_i-theta_j)^2 + a^2*sin(theta_i-theta_j)^2 ) ) ),1)';
end
function [T,Y] = rk4(f,a,b,ya,m,p)
%---------------------------------------------------------------------------
% RK4 Runge-Kutta solution for y' = f(t,y) with y(a) = ya .
% Sample call
% [T,Y] = rk4('f',a,b,ya,m)
% Inputs
% f name of the function
% a left endpoint of [a,b]
% b right endpoint of [a,b]
% ya initial value
% m number of steps
% p Kuramoto function arguments
% Return
% T solution: vector of abscissas
% Y solution: vector of ordinates
%
% NUMERICAL METHODS: MATLAB Programs, (c) John H . Mathews 1995
% To accompany the text:
% NUMERICAL METHODS for Mathematics, Science and Engineering, 2nd Ed, 1992
% Prentice Hall, Englewood Cliffs, New Jersey, 07632, U . S . A .
% Prentice Hall, Inc .; USA, Canada, Mexico ISBN 0-13-624990-6
% Prentice Hall, International Editions: ISBN 0-13-625047-5
% This free software is compliments of the author .
% E-mail address: in % "mathews#fullerton.edu"
%
% Algorithm 9.4 (Runge-Kutta Method of Order 4) .
% Section 9.5, Runge-Kutta Methods, Page 460
%---------------------------------------------------------------------------
h = (b - a)/m;
T = zeros(1,m+1);
size(ya,1)
Y = zeros(size(ya,1),m+1);
T(1) = a;
Y(:,1) = ya;
for j=1:m
tj = T(j);
yj = Y(:,j);
k1 = h*feval(f,tj,yj,p);
k2 = h*feval(f,tj+h/2,yj+k1/2,p);
k3 = h*feval(f,tj+h/2,yj+k2/2,p);
k4 = h*feval(f,tj+h,yj+k3,p);
Y(:,j+1) = yj + (k1 + 2*k2 + 2*k3 + k4)/6;
T(j+1) = a + h*j;
end
end

Related

Fast approach in matlab to estimate linear regression with AR terms

I am trying to estimate regression and AR parameters for (loads of) linear regressions with AR error terms. (You could also think of this as a MA process with exogenous variables):
, where
, with lags of length p
I am following the official matlab recommendations and use regArima to set up a number of regressions and extract regression and AR parameters (see reproducible example below).
The problem: regArima is slow! For 5 regressions, matlab needs 14.24sec. And I intend to run a large number of different regression models. Is there any quicker method around?
y = rand(100,1);
r2 = rand(100,1);
r3 = rand(100,1);
r4 = rand(100,1);
r5 = rand(100,1);
exo = [r2 r3 r4 r5];
tic
for p = 0:4
Mdl = regARIMA(3,0,0);
[EstMdl, ~, LogL] = estimate(Mdl,y,'X',exo,'Display','off');
end
toc
Unlike the regArima function which uses Maximum Likelihood, the Cochrane-Orcutt prodecure relies on an iteration of OLS regression. There are a few more particularities when this approach is valid (refer to the link posted). But for the aim of this question, the appraoch is valid, and fast!
I modified James Le Sage's code which covers only AR lags of order 1, to cover lags of order p.
function result = olsc(y,x,arterms)
% PURPOSE: computes Cochrane-Orcutt ols Regression for AR1 errors
%---------------------------------------------------
% USAGE: results = olsc(y,x)
% where: y = dependent variable vector (nobs x 1)
% x = independent variables matrix (nobs x nvar)
%---------------------------------------------------
% RETURNS: a structure
% results.meth = 'olsc'
% results.beta = bhat estimates
% results.rho = rho estimate
% results.tstat = t-stats
% results.trho = t-statistic for rho estimate
% results.yhat = yhat
% results.resid = residuals
% results.sige = e'*e/(n-k)
% results.rsqr = rsquared
% results.rbar = rbar-squared
% results.iter = niter x 3 matrix of [rho converg iteration#]
% results.nobs = nobs
% results.nvar = nvars
% results.y = y data vector
% --------------------------------------------------
% SEE ALSO: prt_reg(results), plt_reg(results)
%---------------------------------------------------
% written by:
% James P. LeSage, Dept of Economics
% University of Toledo
% 2801 W. Bancroft St,
% Toledo, OH 43606
% jpl#jpl.econ.utoledo.edu
% do error checking on inputs
if (nargin ~= 3); error('Wrong # of arguments to olsc'); end;
[nobs nvar] = size(x);
[nobs2 junk] = size(y);
if (nobs ~= nobs2); error('x and y must have same # obs in olsc'); end;
% ----- setup parameters
ITERMAX = 100;
converg = 1.0;
rho = zeros(arterms,1);
iter = 1;
% xtmp = lag(x,1);
% ytmp = lag(y,1);
% truncate 1st observation to feed the lag
% xlag = x(1:nobs-1,:);
% ylag = y(1:nobs-1,1);
yt = y(1+arterms:nobs,1);
xt = x(1+arterms:nobs,:);
xlag = zeros(nobs-arterms,arterms);
for tt = 1 : arterms
xlag(:,nvar*(tt-1)+1:nvar*(tt-1)+nvar) = x(arterms-tt+1:nobs-tt,:);
end
ylag = zeros(nobs-arterms,arterms);
for tt = 1 : arterms
ylag(:,tt) = y(arterms-tt+1:nobs-tt,:);
end
% setup storage for iteration results
iterout = zeros(ITERMAX,3);
while (converg > 0.0001) & (iter < ITERMAX),
% step 1, using intial rho = 0, do OLS to get bhat
ystar = yt - ylag*rho;
xstar = zeros(nobs-arterms,nvar);
for ii = 1 : nvar
tmp = zeros(1,arterms);
for tt = 1:arterms
tmp(1,tt)=ii+nvar*(tt-1);
end
xstar(:,ii) = xt(:,ii) - xlag(:,tmp)*rho;
end
beta = (xstar'*xstar)\xstar' * ystar;
e = y - x*beta;
% truncate 1st observation to account for the lag
et = e(1+arterms:nobs,1);
elagt = zeros(nobs-arterms,arterms);
for tt = 1 : arterms
elagt(:,tt) = e(arterms-tt+1:nobs-tt,:);
end
% step 2, update estimate of rho using residuals
% from step 1
res_rho = (elagt'*elagt)\elagt' * et;
rho_last = rho;
rho = res_rho;
converg = sum(abs(rho - rho_last));
% iterout(iter,1) = rho;
iterout(iter,2) = converg;
iterout(iter,3) = iter;
iter = iter + 1;
end; % end of while loop
if iter == ITERMAX
% error('ols_corc did not converge in 100 iterations');
print('ols_corc did not converge in 100 iterations');
end;
result.iter= iterout(1:iter-1,:);
% after convergence produce a final set of estimates using rho-value
ystar = yt - ylag*rho;
xstar = zeros(nobs-arterms,nvar);
for ii = 1 : nvar
tmp = zeros(1,arterms);
for tt = 1:arterms
tmp(1,tt)=ii+nvar*(tt-1);
end
xstar(:,ii) = xt(:,ii) - xlag(:,tmp)*rho;
end
result.beta = (xstar'*xstar)\xstar' * ystar;
e = y - x*result.beta;
et = e(1+arterms:nobs,1);
elagt = zeros(nobs-arterms,arterms);
for tt = 1 : arterms
elagt(:,tt) = e(arterms-tt+1:nobs-tt,:);
end
u = et - elagt*rho;
result.vare = std(u)^2;
result.meth = 'olsc';
result.rho = rho;
result.iter = iterout(1:iter-1,:);
% % compute t-statistic for rho
% varrho = (1-rho*rho)/(nobs-2);
% result.trho = rho/sqrt(varrho);
(I did not adapt in the last 2 lines the t-test for rho vectors of length p, but this should be straight forward to do..)

Finding Percent Error of a Fourier Series

Find the error as a function of n, where the error is defined as the difference between two the voltage from the Fourier series (vF (t)) and the value from the ideal function (v(t)), normalized to the maximum magnitude (Vm ):
I am given this prompt where Vm = 1 V. Below this line is the code which I have written.
I am trying to write a function to solve this question: Plot the error versus time for n=3,n=5,n=10, and n=50. (10points). What does it look like I am doing incorrectly?
clc;
close all;
clear all;
% define the signal parameters
Vm = 1;
T = 1;
w0 = 2*pi/T;
% define the symbolic variables
syms n t;
% define the signal
v1 = Vm*sin(4*pi*t/T);
v2 = 2*Vm*sin(4*pi*t/T);
% evaluate the fourier series integral
an1 = 2/T*int(v1*cos(n*w0*t),0,T/2) + 2/T*int(v2*cos(n*w0*t),T/2,T);
bn1 = 2/T*int(v1*sin(n*w0*t),0,T/2) + 2/T*int(v2*sin(n*w0*t),T/2,T);
a0 = 1/T*int(v1,0,T/2) + 1/T*int(v2,T/2,T);
% obtain C by substituting n in c[n]
nmax = 100;
n = 1:nmax;
a = subs(an1);
b = subs(bn1);
% define the time vector
ts = 1e-2; % ts is sampling the
t = 0:ts:3*T-ts;
% directly plot the signal x(t)
t1 = 0:ts:T-ts;
v1 = Vm*sin(4*pi*t1/T).*(t1<=T/2);
v2 = 2*Vm*sin(4*pi*t1/T).*(t1>T/2).*(t1<T);
v = v1+v2;
x = repmat(v,1,3);
% Now fourier series reconstruction
N = [3];
for p = 1:length(N)
for i = 1:length(t)
for k = N(p)
x(k,i) = a(k)*cos(k*w0*t(i)) + b(k)*sin(k*w0*t(i));
end
% y(k,i) = a0+sum(x(:,i)); % Add DC term
end
end
z = a0 + sum(x);
figure(1);
plot(t,z);
%Percent error
function [per_error] = percent_error(measured, actual)
per_error = abs(( (measured - actual) ./ 1) * 100);
end
The purpose of the forum is helping with specific technical questions, not doing your homework.

Matlab: Warning: Matrix is singular, close to singular or badly scaled. Results may be inaccurate. RCOND = NaN.

In my matlab program:
% Orto-xylene oxidation in an adiabatic PFR.
% ethylbenzene -> Anhydrated-xylene + H2
% There is water as an inert in the system
global y0 F0 deltaHR0 P0 ni n
y0(1) = 0.0769; % ethylbenzene
y0(2) = 0.; % styrene
y0(3) = 0.; % hydrogen
y0(4) = 0.923; % water
Feed = 1105.; % F01 + FH2O Feed rate [mol/s]
F0 = Feed .* y0; % Inlet feed rate of components [mol/s]
Tin = 925.;
n = 4.; % Number of reacting compound
deltaHR0 = 124850.; % heat of reaction at standard conditions[J/mol]
P0 = 240000.; % pressure [Pa]
W = 25400.; % reactor weight [kg]
ni = [-1 1 1 0]; % Stoichiometric matrix
% Initial conditions (feed and T0)
u0 = F0;
u0(n+1) = Tin;
wspan = [0 W];
[w_adiab,u] = ode15s(#dfuns,wspan,u0);
conv_adiab = 1 - u(:,1)/F0(1);
T = u(:,n+1);
subplot(2,1,1)
plot(w_adiab,conv_adiab,'-')
title('Conversion profile')
grid on
xlabel('W')
ylabel('X(A1)')
subplot(2,1,2)
plot(w_adiab,T,'-')
title('Temperature profile')
grid on
xlabel('W')
ylabel('T')
%function file dfuns
function f = dfuns (w,U)
global y0 F0 deltaHR0 P0 ni n
% U(1) = F1
% U(2) = F2
% U(3) = F3
% U(4) = F4
% y is a vector of n components
y = U(1:n)/sum(U(1:n)); % molar fractions
T = U(n+1);
k = 3.46* 10e8.* exp(-10980./T); %Needs to be in Pascal
K = 8.2.* 10e11.* exp(-15200./T); %Needs to be in Pascal
rm = k.* (y(1)* P0- (y(2).* y(3).*(P0^2))./ K);
f(1:n) = -ni(1:n).* rm;
Cp1 = 37.778 + 87.940e-3.* T + 113.436e-5.* T^2; % ethylbenzene
%Cp2 = 71.201 + 54.706e-3.* T + 64.791e-5.* T^2; % styrene
%Cp3 = 23.969 + 30.603e-3.*T - 6.418e-5.* T^2; % hydrogen
Cp4 = 36.540 - 34.827e-3.*T + 11.681e-5.*T^2; % water
deltaCp = 0.;
% deltaCp considered to be different from zero
% deltaCp = -Cp1+Cp2+Cp3;
deltaHR = deltaHR0;
% non-const deltaHR
% T0=273.5;
% deltaHR = - deltaHR0 + (37.778.* T + 87.940e-3.* (T^2)./2 +...
% 113.436e-5.* (T^3)./3) + (71.201.* T + 54.706e-3.* (T^2)./2 + ...
% 64.791e-5.* (T^3)/3) + (23.969.*T + 30.603e-3.* (T^2)./2 -...
% 6.418e-5.* (T^3)/3) - (37.778*T0 - ...
% 87.940e-3.*(T0^2)./2 + 113.436e-5.* (T0^3)./3 )+...
% (71.201 * T0 + 54.706e-3.* (T0^2)./2 + 64.791e-5.* ...
% (T0^3)./3) + (23.969 * T0 + 30.603e-3.* (T0^2)./2 -...
% 6.418e-5.* (T0^3)./3);
f(n+1) = (1./((F0(1)+F0(4)).* (y0(1).* Cp1 + y0(4).* Cp4 +y(1).* deltaCp)*...
(1 - U(1)/F0(1)))).*-deltaHR.* rm;
f = f'; % transformation to column vector
I have a problem because of the forrowing warning:
In catPFR (line 21)
Warning: Matrix is singular, close to singular or badly scaled. Results may be inaccurate. RCOND = NaN.
> In ode15s (line 589)
In catPFR (line 21)
Warning: Failure at t=0.000000e+00. Unable to meet integration tolerances without reducing the step size below the
smallest value allowed (7.905050e-323) at time t.
> In ode15s (line 668)
In catPFR (line 21)
Can please someone help me? This problem could be a error in the function but I'm really not into matlab enough to understand it. Of course, I don't get the graph I was expecting.
Thank you very much,
Serena
If you inspect return values of function dfuns (w,U) during the integration, you will see that in most cases it contains NaN's or Inf's. Of course ode15s cannot proceed in this case. Check dfuns and assure that it returns correct values.

Issue Changing Script to function in MatLab

I am trying to give a/set 'rho_real' to this code and receive P_Mpa as an/set of outputs, however the initial 'rho_real' does not seem to get changed as I run the function.
Any Help is greatly appreciated.
function P_Mpa = Density_vs_Pressure_Ethane (rho_real)
% calculating Pressure vs Density curve using
mi = [1.6069,1.6069];
sigmai = [3.5206,3.5206]; 1
% epsilon = [2.873268218e-21,2.873268218e-21];
epsilon_ki = [191.42,191.42];
xi = [0.5,0.5]; % mole fraction of component i
T = 298.15; % temperature of the system
% k_bolt = 1.3806488e-23; % Boltzmann constant = 1.3806488 × 10-23 m2 kg s-2 K-1
% Initial guess for density
rho_real = 10000;
rho = rho_real*6.022e-7;
% Initial Kij
Kij = 0;
% Temperatuure-dependent segment diameter di of component i - matrix save
di = zeros(1,2);
giihs = zeros (1,2);
rho_giihs = zeros (1,2);
m_bar = 0;
zi0=0;
zi1=0;
zi2=0;
zi3=0;
for i=1:2
m_bar=m_bar+((xi(1,i))*(mi(1,i)));
di(1,i) = (sigmai(1,i))*(1-(0.12*exp(-3*(epsilon_ki(1,i))/T)));
% Calculating Zieeeeeeh for Hard Sphere compressibility (Rechcecked)
zi0 = zi0+((pi/6)*rho)*(xi(1,i)*(mi(1,i))*((di(1,i))^0));
zi1 = zi1+((pi/6)*rho)*(xi(1,i)*(mi(1,i))*((di(1,i))^1));
zi2 = zi2+((pi/6)*rho)*(xi(1,i)*(mi(1,i))*((di(1,i))^2));
zi3 = zi3+((pi/6)*rho)*(xi(1,i)*(mi(1,i))*((di(1,i))^3));
end
for i=1:2
giihs (1,i)= (1/(1-zi3))+((((di(1,i))^2)/(2*(di(1,i))))*(3*zi2)/((1-zi3)^2))+((di(1,i)^2)/(2*(di(1,i)^2))^2)*((2*(zi2)^2)/((1-zi3)^3));
% Derevative of site to site radial distribution function of hard spheres
% with respect to density
rho_giihs (1,i) = ((zi3/((1-zi3)^2)))+(((((di(1,i))^2)/(2*(di(1,i)))))*...
((((3*zi2)/((1-zi3)^2)))+((6*zi2*zi3)/((1-zi3)^3))))+...
(((((di(1,i))^2)/(2*(di(1,i))))^2)*(((4*(zi2^2))/((1-zi3)^3))+...
(((6*zi2^2)*zi3)/((1-zi3)^4))));
end
eta = zi3;
% Calculating the hard sphere compresibility factor ( Rechecked)
zhs = (zi3/(1-zi3)+((3*zi1*zi2)/((zi0*(1-zi3)^2)))+(((3*(zi2^3))-(zi3*(zi2^3)))/(zi0*((1-(zi3)^3)))));
zhc=0;
for i = 1:2
% Calculating the hard chain compressibility factor (Rechecked)
zhc= zhc+((xi(1,i)*(mi(1,i)-1)*((giihs(1,i))^-1)*((rho_giihs(1,i)))));
end
zhc=m_bar*zhs-zhc;
% a0 constants
a0 = [0.9105631445,0.6361281449,2.6861347891,-26.547362491,97.759208784,-159.59154087,91.297774084]; % Checked and Correct Sadowski 2001
% a1 constants
a1 = [-0.3084016918,0.1860531159,-2.5030047259,21.419793629,-65.255885330,83.318680481,-33.746922930]; % Checked and Correct Sadowski 2001
% a2 constants
a2 = [-0.0906148351,0.4527842806,0.5962700728,-1.7241829131,-4.1302112531,13.776631870,-8.6728470368]; % Checked and Correct Sadowski 2001
% b0 constants
b0 = [0.7240946941,2.2382791861,-4.0025849485,-21.003576815,26.855641363,206.55133841,-355.60235612]; % Checked and Correct Sadowski 2001
% b1 constants
b1 = [-0.5755498075,0.6995095521,3.8925673390,-17.215471648,192.67226447,-161.82646165,-165.20769346]; % Checked and Correct Sadowski 2001
% b2 constants
b2 = [0.0976883116,-0.2557574982,-9.1558561530,20.642075974,-38.804430052,93.626774077,-29.666905585];
aim = zeros(1,7);
bim = zeros(1,7);
for i = 1:7
aim(1,i)=a0(1,i)+(((m_bar-1)/m_bar)*a1(1,i))+(((m_bar-1)/m_bar)*((m_bar-2)/m_bar))*a2(1,i); % Checked and Correct Sadowski 2001 (rechecked)
bim(1,i)=b0(1,i)+(((m_bar-1)/m_bar)*b1(1,i))+(((m_bar-1)/m_bar)*((m_bar-2)/m_bar))*b2(1,i);
c1 = ((1 + (m_bar*(((8*eta)-(2*eta^2))/(1-eta)^4)+((1-m_bar)*(((20*eta)-(27*eta^2)+(12*eta^3)-(2*eta^4))/(((1-eta)*(2-eta))^2)))))^-1);
c2 = ((-c1^2)*(m_bar*(((-4*eta^2)+(20*eta)+8)/((1-eta)^5))+((1-m_bar)*(((2*eta^3)+(12*eta^2)-(48*eta)+40)/(((1-eta)*(2-eta))^3)))));
% Integrals of perturbation theory without/with respect to eta (rechecked)
dI1 = 0;
dI2 = 0;
I1 = 0;
I2 = 0;
for j = 1:7
I1 = I1+ aim(1,j)*eta^(j-1);
I2 = I2+ bim(1,j)*eta^(j-1);
dI1 = dI1 + (aim(1,j)*((j-1)+1)*(eta^(j-1)));
dI2 = dI2 + (bim(1,j)*((j-1)+1)*(eta^(j-1)));
end
% Segment abriviations
m2e = 0;
m2e2 = 0;
sigma_ij = zeros(1,2);
epsilon_ij = zeros (1,2);
for i = 1:2
for j = 1:2
% Mixing rules for sigma and eta respectively.
sigma_ij(i,j)=0.5*(sigmai(1,i)+sigmai(1,j));
epsilon_ij(i,j)=sqrt((epsilon_ki(1,i)*epsilon_ki(1,j))*(1-Kij));
m2e=m2e+(xi(1,i)*xi(1,j)*mi(1,i)*mi(1,j)*((epsilon_ij(i,j)/(T)))*(sigma_ij(i,j)^3));
m2e2=m2e2+(xi(1,i)*xi(1,j)*mi(1,i)*mi(1,j)*(((epsilon_ij(i,j)/(T)))^2)*(sigma_ij(i,j)^3));
end
end
% The dispersion contribution to the comprehensibility factor
zdis = (-2*pi*rho*dI1*m2e)-(pi*rho*m_bar*((c1*dI2)+(c2*eta*I2))*m2e2);
% Compresibility Factor (rechecked)
z = 1 + zhc + zdis;
zdis;
zhc;
P = z*8.314*T*rho/6.022e-7; % (rechecked)
P_Mpa = P*1e-6;
In the line below % Initial guess for density: you set the value of rho_real to 10000. From then on, of course, rho_real will be 10000 no matter what the input argument was. If you remove this line, your function will behave as your script, with variable rho_real defined by the input argument.
MATLAB does have a way of providing default values for arguments. Your function could test how many arguments were provided. If rho_real was left out, i.e. if the number of arguments nargin is less than 1, only then you set rho_real.
if nargin < 1
rho_real = 10000
end

Matlab NaN and Inf issue

So, I'm implementing the EM algorithm in Matlab, but my matrices quickly end up contaminated by NaN and Inf values. I think it might be caused by matrix inversions, but I'm not sure that's the only reason.
Here is the code:
function [F, Q, R, x_T, P_T] = em_algo(y, G)
% y_t = G_t'*x_t + v_t 1*1 = 1*p p*1
% x_t = F*x_t-1 + w_t p*1 = p*p p*1
% G is T*p
p = size(G,2); % p = nb assets ; G = T*p
q = size(y,2); % q = nb observations ; y = T*q
T = size(y,1); % y is T*1
F = eye(p); % = Transition matrix p*p
Q = eye(p); % innovation (v) covariance matrix p*p
R = eye(q); % noise (w) covariance matrix q x q
x_T_old = zeros(p,T);
mu0 = zeros(p,1);
Sigma = eye(p); % Initial state covariance matrix p*p
converged = 0;
i = 0;
max_iter = 60; % only for testing purposes
while ~converged
if i > max_iter
break;
end
% E step = smoothing
fprintf('Iteration %d\n',i);
[x_T,P_T,P_Tm2] = smoother(G,F,Q,R,mu0,Sigma,y);
%x_T
% M step
A = zeros(p,p);
B = zeros(p,p);
C = zeros(p,p);
R = eye(q);
for t = 2:T % eq (9) in EM paper
A = A + (P_T(:,:,t-1) + (x_T(:,t-1)*x_T(:,t-1)'));
end
for t = 2:T % eq (10)
%B = B + (P_Tm2(:,:,t-1) + (x_T(:,t)*x_T(:,t-1)'));
B = B + (P_Tm2(:,:,t) + (x_T(:,t)*x_T(:,t-1)'));
end
for t = 1:T %eq (11)
C = C + (P_T(:,:,t) + (x_T(:,t)*x_T(:,t)'));
end
F = B*inv(A); %eq (12)
Q = (1/T)*(C - (B*inv(A)*B')); % eq (13) pxp
for t = 1:T
bias = y(t) - (G(t,:)*x_T(:,t));
R = R + ((bias*bias') + (G(t,:)*P_T(:,:,t)*G(t,:)'));
end
R = (1/T)*R;
if i>1
err = norm(x_T-x_T_old)/norm(x_T_old);
if err < 1e-4
converged = 1;
end
end
x_T_old = x_T;
i = i+1;
end
fprintf('EM algorithm iterated %d times\n',i);
end
This iterates until convergence (which never happens due to my issue) and calls smoother.m at each iteration:
function [x_T, P_T, P_Tm2] = smoother(G,F,Q,R,mu0,Sigma,y)
% G is T*p
p = size(mu0,1); % mu0 is p*1
T = size(y,1); % y is T*1
J = zeros(p,p,T);
K = zeros(p,T); % gain matrix
x = zeros(p,T);
x(:,1) = mu0;
x_m1 = zeros(p,T);
x_T = zeros(p,T); % x values when we know all the data
% Notation : x = xt given t ; x_m1 = xt given t-1 (m1 stands for minus
% one)
P = zeros(p,p,T);% array of cov(xt|y1...yt), eq (6) in Shumway & Stoffer 1982
P(:,:,1) = Sigma;
P_m1 = zeros(p,p,T); % Same notation ; = cov(xt, xt-1|y1...yt) , eq (7)
P_T = zeros(p,p,T);
P_Tm2 = zeros(p,p,T); % cov(xT, xT-1|y1...yT)
for t = 2:T %starts at t = 2 because at each time t we need info about t-1
x_m1(:,t) = F*x(:,t-1); % eq A3 ; pxp * px1 = px1
P_m1(:,:,t) = (F*P(:,:,t-1)*F') + Q; % A4 ; pxp * pxp = pxp
if nnz(isnan(P_m1(:,:,t)))
error('NaNs in P_m1 at time t = %d',t);
end
if nnz(isinf(P_m1(:,:,t)))
error('Infs in P_m1 at time t = %d',t);
end
K(:,t) = P_m1(:,:,t)*G(t,:)'*pinv((G(t,:)*P_m1(:,:,t)*G(t,:)') + R); %A5 ; pxp * px1 * 1*1 = p*1
%K(:,t) = P_m1(:,:,t)*G(t,:)'/((G(t,:)*P_m1(:,:,t)*G(t,:)') + R); %A5 ; pxp * px1 * 1*1 = p*1
% The matrix inversion seems to generate NaN values which quickly
% contaminate all the other matrices. There is no warning about
% (close to) singular matrices or whatever. The use of pinv()
% instead of inv() seems to solve the problem... but I don't think
% it's the appropriate way to deal with it, there must be something
% wrong elsewhere
if nnz(isnan(K(:,t)))
error('NaNs in K at time t = %d',t);
end
x(:,t) = x_m1(:,t) + (K(:,t)*(y(t)-(G(t,:)*x_m1(:,t)))); %A6
P(:,:,t) = P_m1(:,:,t) - (K(:,t)*G(t,:)*P_m1(:,:,t)); %A7
end
x_T(:,T) = x(:,T);
P_T(:,:,T) = P(:,:,T);
for t = T:-1:2 % we stop at 2 since we need to use t-1
%P_m1 seem to get really huge (x10^22...), might lead to "Inf"
%values which in turn might screw pinv()
%% inv() caused NaN value to appear, pinv seems to solve the issue
J(:,:,t-1) = P(:,:,t-1)*F'*pinv(P_m1(:,:,t)); % A8 pxp * pxp * pxp
%J(:,:,t-1) = P(:,:,t-1)*F'/(P_m1(:,:,t)); % A8 pxp * pxp * pxp
x_T(:,t-1) = x(:,t-1) + J(:,:,t-1)*(x_T(:,t)-(F*x(:,t-1))); %A9 % Becomes NaN during 8th iteration!
P_T(:,:,t-1) = P(:,:,t-1) + J(:,:,t-1)*(P_T(:,:,t)-P_m1(:,:,t))*J(:,:,t-1)'; %A10
nans = [nnz(isnan(J)) nnz(isnan(P_m1)) nnz(isnan(F)) nnz(isnan(x_T)) nnz(isnan(x_m1))];
if nnz(nans)
error('NaN invasion at time t = %d',t);
end
end
P_Tm2(:,:,T) = (eye(p) - K(:,T)*G(T,:))*F*P(:,:,T-1); % %A12
for t = T:-1:3 % stop at 3 because use of t-2
P_Tm2(:,:,t-1) = P_m1(:,:,t-1)*J(:,:,t-2)' + J(:,:,t-1)*(P_Tm2(:,:,t)-F*P(:,:,t-1))*J(:,:,t-2)'; % A11
end
end
The NaNs and Infs start popping around the ~8th iteration.
I guess in there somewhere I'm doing something unholy with my matrices, but I really have no clue about what's wrong. I trust your expertise.
Thanks in advance for the help.
Rody :
Here is how I generate the data (it's not "real world" data yet, just some test data generated to check that nothing goes wront) :
T = 500;
nbassets = 3;
G = .1 + randn(T,nbassets); % random walk trajectories
y = (1:T).';
y = 1.01.^y; % 1 * T % Exponential 1% returns curve
Dan :
You're right. I indeed lack the math background to really understand how the formulas are derived. I know it doesn't help, but I'm not sure I can remedy that for the time being. :/
Rody : Yes indeed, I arrived at the same conclusion. But I really have no clue what makes it go wrong like that.
Here is a link to the paper :
http://www.stat.pitt.edu/stoffer/em.pdf
The formulas for the smoother are all at the very end, in the appendix. Thanks for your time so far.
As the user appears to have inserted the answer into his question I will post it here:
As mentioned by #Rody the cause of the problem was that the use of inv created NaN or Inf values.
The user 'solved' this by using pinv instead.