root/bdm/math/libDC.cpp @ 37

Revision 37, 8.8 kB (checked in by smidl, 16 years ago)

Matrix in Cholesky decomposition, Square-root Kalman and many bug fixes

Line 
1#include <itpp/itbase.h>
2#include "libDC.h"
3
4using namespace itpp;
5
6using std::endl;
7
8void fsqmat::opupdt ( const vec &v, double w ) {M+=outer_product ( v,v*w );};
9mat fsqmat::to_mat()  {return M;};
10void fsqmat::mult_sym ( const mat &C) {M=C *M*C.T();};
11void fsqmat::mult_sym_t ( const mat &C) {M=C.T() *M*C;};
12void fsqmat::mult_sym ( const mat &C, fsqmat &U) const { U.M = ( C *(M*C.T()) );};
13void fsqmat::mult_sym_t ( const mat &C, fsqmat &U) const { U.M = ( C.T() *(M*C) );};
14void fsqmat::inv ( fsqmat &Inv ) {mat IM = itpp::inv ( M ); Inv=IM;};
15void fsqmat::clear() {M.clear();};
16fsqmat::fsqmat ( const mat &M0 ) : sqmat(M0.cols())
17{
18        it_assert_debug ( ( M0.cols() ==M0.rows() ),"M0 must be square" );
19        M=M0;
20};
21
22//fsqmat::fsqmat() {};
23
24fsqmat::fsqmat(const int dim0): sqmat(dim0), M(dim0,dim0) {};
25
26std::ostream &operator<< ( std::ostream &os, const fsqmat &ld ) {
27        os << ld.M << endl;
28        return os;
29}
30
31
32ldmat::ldmat( const mat &exL, const vec &exD ) : sqmat(exD.length()) {
33        D = exD;
34        L = exL;
35}
36
37ldmat::ldmat() :sqmat(0) {}
38
39ldmat::ldmat(const int dim0): sqmat(dim0), D(dim0),L(dim0,dim0) {}
40
41ldmat::ldmat(const vec D0):sqmat(D0.length()) {
42        D = D0;
43        L = eye(dim);
44}
45
46ldmat::ldmat( const mat &V ):sqmat(V.cols()) {
47//TODO check if correct!! Based on heuristic observation of lu()
48
49        it_assert_debug( dim == V.rows(),"ldmat::ldmat matrix V is not square!" );
50               
51        // L and D will be allocated by ldform()
52       
53        //Chol is unstable
54        this->ldform(chol(V),ones(dim));
55//      this->ldform(ul(V),ones(dim));
56}
57
58void ldmat::opupdt( const vec &v,  double w ) {
59        int dim = D.length();
60        double kr;
61        vec r = v;
62        //beware! it is potentionally dangerous, if ITpp change _behaviour of _data()!
63        double *Lraw = L._data();
64        double *Draw = D._data();
65        double *rraw = r._data();
66
67        it_assert_debug( v.length() == dim, "LD::ldupdt vector v is not compatible with this ld." );
68
69        for ( int i = dim - 1; i >= 0; i-- ) {
70                dydr( rraw, Lraw + i, &w, Draw + i, rraw + i, 0, i, &kr, 1, dim );
71        }
72}
73
74std::ostream &operator<< ( std::ostream &os, const ldmat &ld ) {
75        os << "L:" << ld.L << endl;
76        os << "D:" << ld.D << endl;
77        return os;
78}
79
80mat ldmat::to_mat() {
81        int dim = D.length();
82        mat V( dim, dim );
83        double sum;
84        int r, c, cc;
85
86        for ( r = 0;r < dim;r++ ) { //row cycle
87                for ( c = r;c < dim;c++ ) {
88                        //column cycle, using symmetricity => c=r!
89                        sum = 0.0;
90                        for ( cc = c;cc < dim;cc++ ) { //cycle over the remaining part of the vector
91                                sum += L( cc, r ) * D( cc ) * L( cc, c );
92                                //here L(cc,r) = L(r,cc)';
93                        }
94                        V( r, c ) = sum;
95                        // symmetricity
96                        if ( r != c ) {V( c, r ) = sum;};
97                }
98        }
99        mat V2 = L.transpose()*diag( D )*L;
100        return V2;
101}
102
103
104void ldmat::add( const ldmat &ld2, double w ) {
105        int dim = D.length();
106
107        it_assert_debug( ld2.D.length() == dim, "LD.add() incompatible sizes of LDs;" );
108
109        //Fixme can be done more efficiently either via dydr or ldform
110        for ( int r = 0; r < dim; r++ ) {
111                // Add columns of ld2.L' (i.e. rows of ld2.L) as dyads weighted by ld2.D
112                this->opupdt( ld2.L.get_row( r ), w*ld2.D( r ) );
113        }
114}
115
116void ldmat::clear(){L.clear(); for ( int i=0;i<L.cols();i++ ){L( i,i )=1;}; D.clear();}
117
118void ldmat::inv( ldmat &Inv ) const {
119        int dim = D.length();
120        Inv.clear();   //Inv = zero in LD
121        mat U = ltuinv( L );
122
123        //Fixme can be done more efficiently either via dydr or ldform
124        for ( int r = 0; r < dim; r++ ) {
125                // Add columns of U as dyads weighted by 1/D
126                Inv.opupdt( U.get_col( r ), 1.0 / D( r ) );
127        }
128}
129
130void ldmat::mult_sym( const mat &C) {
131        mat A = L*C.T();
132        this->ldform(A,D);
133}
134
135void ldmat::mult_sym_t( const mat &C) {
136        mat A = L*C;
137        this->ldform(A,D);
138}
139
140void ldmat::mult_sym( const mat &C, ldmat &U) const {
141        mat A=L*C.T(); //could be done more efficiently using BLAS
142        U.ldform(A,D);
143}
144
145void ldmat::mult_sym_t( const mat &C, ldmat &U) const {
146        mat A=L*C;
147/*      vec nD=zeros(U.rows());
148        nD.replace_mid(0, D); //I case that D < nD*/
149        U.ldform(A,D);
150}
151
152
153double ldmat::logdet() const {
154        double ldet = 0.0;
155        int i;
156// sum logarithms of diagobal elements
157        for ( i=0; i<D.length(); i++ ){ldet+=log( D( i ) );};
158        return ldet;
159}
160
161double ldmat::qform( const vec &v ) const {
162        double x = 0.0, sum;
163        int i,j;
164
165        for ( i=0; i<D.length(); i++ ) { //rows of L
166                sum = 0.0;
167                for ( j=i; j<=i; j++ ){sum+=L( i,j )*v( i );}
168                x +=D( i )*sum*sum;
169        };
170        return x;
171}
172
173ldmat& ldmat::operator *= ( double x ) {
174        int i;
175        for ( i=0;i<D.length();i++ ){D( i )*=x;};
176        return *this;
177}
178
179vec ldmat::sqrt_mult( const vec &x ) const {
180        int i,j;
181        vec res( dim );
182        //double sum;
183        for ( i=0;i<dim;i++ ) {//for each element of result
184                res( i ) = 0.0;
185                for ( j=i;j<dim;j++ ) {//sum D(j)*L(:,i).*x
186                        res( i ) += sqrt( D( j ) )*L( j,i )*x( j );
187                }
188        }
189//      vec res2 = L.transpose()*diag( sqrt( D ) )*x;
190        return res;
191}
192
193void ldmat::ldform(const mat &A,const vec &D0 )
194{
195        int m = A.rows();
196        int n = A.cols();
197        int mn = (m<n) ? m :n ;
198
199        it_assert_debug( A.cols()==dim,"ldmat::ldform A is not compatible" );
200        it_assert_debug( D0.length()==A.rows(),"ldmat::ldform Vector D must have the length as row count of A" );
201
202        L=concat_vertical( zeros( n,n ), diag( sqrt( D0 ) )*A );
203        D=zeros( n+m );
204
205        //unnecessary big L and D will be made smaller at the end of file       
206        vec w=zeros( n+m );
207   
208        double sum, beta, pom;
209
210        int cc=0;
211        int i=n; // indexovani o 1 niz, nez v matlabu
212        int ii,j,jj;
213        while ( (i>n-mn-cc) && (i>0) ) 
214        {
215                i--;
216                sum = 0.0;
217
218                int last_v = m+i-n+cc+1;
219       
220                vec v = zeros( last_v + 1 ); //prepare v
221                for ( ii=n-cc-1;ii<m+i+1;ii++ ) 
222                {
223                        sum+= L( ii,i )*L( ii,i );
224                        v( ii-n+cc+1 )=L( ii,i ); //assign v
225                }
226
227                if ( L( m+i,i )==0 ) 
228                        beta = sqrt( sum );             
229                else
230                        beta = L( m+i,i )+sign( L( m+i,i ) )*sqrt( sum );               
231     
232                if ( std::fabs( beta )<eps )
233                {
234                        cc++;
235                        L.set_row( n-cc, L.get_row( m+i ) );
236                        L.set_row( m+i,zeros(L.cols()) );
237                        D( m+i )=0; L( m+i,i )=1;
238                        L.set_submatrix( n-cc,m+i-1,i,i,0 );
239                        continue;
240                }
241
242                sum-=v(last_v)*v(last_v);
243                sum/=beta*beta;
244                sum++;
245
246                v/=beta;
247                v(last_v)=1;
248
249                pom=-2.0/sum;
250                // echo to venca   
251
252                for ( j=i;j>=0;j-- ) 
253                {
254                        double w_elem = 0;                     
255                        for ( ii=n-     cc;ii<=m+i+1;ii++ ) 
256                                w_elem+= v( ii-n+cc )*L( ii-1,j );                     
257                        w(j)=w_elem*pom;
258                }
259
260                for ( ii=n-cc-1;ii<=m+i;ii++ ) 
261                        for ( jj=0;jj<i;jj++ ) 
262                                L( ii,jj )+= v( ii-n+cc+1)*w( jj );
263
264                for ( ii=n-cc-1;ii<m+i;ii++ )
265                        L( ii,i )= 0;
266
267                L( m+i,i )+=w( i );
268                D( m+i )=L( m+i,i )*L( m+i,i );
269
270                for ( ii=0;ii<=i;ii++ ) 
271                        L( m+i,ii )/=L( m+i,i );               
272        }
273
274        if ( i>=0 )
275                for ( ii=0;ii<i;ii++ ) 
276                {
277                        jj = D.length()-1-n+ii;
278                        D(jj) = 0;
279                        L.set_row(jj,zeros(L.cols())); //TODO: set_row accepts Num_T
280                        L(jj,jj)=1;
281                }
282
283        L.del_rows(0,m-1);
284        D.del(0,m-1);
285}
286
287//////// Auxiliary Functions
288
289mat ltuinv( const mat &L ) {
290        int dim = L.cols();
291        mat Il = eye( dim );
292        int i, j, k, m;
293        double s;
294
295//Fixme blind transcription of ltuinv.m
296        for ( k = 1; k < ( dim );k++ ) {
297                for ( i = 0; i < ( dim - k );i++ ) {
298                        j = i + k; //change in .m 1+1=2, here 0+0+1=1
299                        s = L( j, i );
300                        for ( m = i + 1; m < ( j - 1 ); m++ ) {
301                                s += L( m, i ) * Il( j, m );
302                        }
303                        Il( j, i ) = -s;
304                }
305        }
306
307        return Il;
308}
309
310void dydr( double * r, double *f, double *Dr, double *Df, double *R, int jl, int jh, double *kr, int m, int mx )
311/********************************************************************
312
313   dydr = dyadic reduction, performs transformation of sum of
314          2 dyads r*Dr*r'+ f*Df*f' so that the element of r pointed
315          by R is zeroed. This version allows Dr to be NEGATIVE. Hence the name negdydr or dydr_withneg.
316
317   Parameters :
318     r ... pointer to reduced dyad
319     f ... pointer to reducing dyad
320     Dr .. pointer to the weight of reduced dyad
321     Df .. pointer to the weight of reducing dyad
322     R ... pointer to the element of r, which is to be reduced to
323           zero; the corresponding element of f is assumed to be 1.
324     jl .. lower index of the range within which the dyads are
325           modified
326     ju .. upper index of the range within which the dyads are
327           modified
328     kr .. pointer to the coefficient used in the transformation of r
329           rnew = r + kr*f
330     m  .. number of rows of modified matrix (part of which is r)
331  Remark : Constant mzero means machine zero and should be modified
332           according to the precision of particular machine
333
334                                                 V. Peterka 17-7-89
335
336  Added:
337     mx .. number of rows of modified matrix (part of which is f)  -PN
338
339********************************************************************/
340{
341        int j, jm;
342        double kD, r0;
343        double mzero = 2.2e-16;
344        double threshold = 1e-4;
345
346        if ( fabs( *Dr ) < mzero ) *Dr = 0;
347        r0 = *R;
348        *R = 0.0;
349        kD = *Df;
350        *kr = r0 * *Dr;
351        *Df = kD + r0 * ( *kr );
352        if ( *Df > mzero ) {
353                kD /= *Df;
354                *kr /= *Df;
355        } else {
356                kD = 1.0;
357                *kr = 0.0;
358                if ( *Df < -threshold ) {
359                        it_warning( "Problem in dydr: subraction of dyad results in negative definitness. Likely mistake in calling function." );
360                }
361                *Df = 0.0;
362        }
363        *Dr *= kD;
364        jm = mx * jl;
365        for ( j = m * jl; j < m*jh; j += m ) {
366                r[j] -=  r0 * f[jm];
367                f[jm] += *kr * r[j];
368                jm += mx;
369        }
370}
Note: See TracBrowser for help on using the browser.