root/bdm/math/libDC.cpp @ 75

Revision 75, 9.1 kB (checked in by smidl, 16 years ago)

oprava operaci na ld

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        vec s(v.length());
165        vec S=L*v;
166
167        for ( i=0; i<D.length(); i++ ) { //rows of L
168                sum = 0.0;
169                for ( j=0; j<=i; j++ ){sum+=L( i,j )*v( j );}
170                x +=D( i )*sum*sum;
171                s(i)=sum;
172        };
173        return x;
174}
175
176double ldmat::invqform( const vec &v ) const {
177        double x = 0.0;
178        int i;
179        vec pom(v.length());
180       
181        backward_substitution(L.T(),v,pom);
182       
183        for ( i=0; i<D.length(); i++ ) { //rows of L
184                x +=pom(i)*pom(i)/D(i);
185        };
186        return x;
187}
188
189ldmat& ldmat::operator *= ( double x ) {
190        int i;
191        for ( i=0;i<D.length();i++ ){D( i )*=x;};
192        return *this;
193}
194
195vec ldmat::sqrt_mult( const vec &x ) const {
196        int i,j;
197        vec res( dim );
198        //double sum;
199        for ( i=0;i<dim;i++ ) {//for each element of result
200                res( i ) = 0.0;
201                for ( j=i;j<dim;j++ ) {//sum D(j)*L(:,i).*x
202                        res( i ) += sqrt( D( j ) )*L( j,i )*x( j );
203                }
204        }
205//      vec res2 = L.transpose()*diag( sqrt( D ) )*x;
206        return res;
207}
208
209void ldmat::ldform(const mat &A,const vec &D0 )
210{
211        int m = A.rows();
212        int n = A.cols();
213        int mn = (m<n) ? m :n ;
214
215        it_assert_debug( A.cols()==dim,"ldmat::ldform A is not compatible" );
216        it_assert_debug( D0.length()==A.rows(),"ldmat::ldform Vector D must have the length as row count of A" );
217
218        L=concat_vertical( zeros( n,n ), diag( sqrt( D0 ) )*A );
219        D=zeros( n+m );
220
221        //unnecessary big L and D will be made smaller at the end of file       
222        vec w=zeros( n+m );
223   
224        double sum, beta, pom;
225
226        int cc=0;
227        int i=n; // indexovani o 1 niz, nez v matlabu
228        int ii,j,jj;
229        while ( (i>n-mn-cc) && (i>0) ) 
230        {
231                i--;
232                sum = 0.0;
233
234                int last_v = m+i-n+cc+1;
235       
236                vec v = zeros( last_v + 1 ); //prepare v
237                for ( ii=n-cc-1;ii<m+i+1;ii++ ) 
238                {
239                        sum+= L( ii,i )*L( ii,i );
240                        v( ii-n+cc+1 )=L( ii,i ); //assign v
241                }
242
243                if ( L( m+i,i )==0 ) 
244                        beta = sqrt( sum );             
245                else
246                        beta = L( m+i,i )+sign( L( m+i,i ) )*sqrt( sum );               
247     
248                if ( std::fabs( beta )<eps )
249                {
250                        cc++;
251                        L.set_row( n-cc, L.get_row( m+i ) );
252                        L.set_row( m+i,zeros(L.cols()) );
253                        D( m+i )=0; L( m+i,i )=1;
254                        L.set_submatrix( n-cc,m+i-1,i,i,0 );
255                        continue;
256                }
257
258                sum-=v(last_v)*v(last_v);
259                sum/=beta*beta;
260                sum++;
261
262                v/=beta;
263                v(last_v)=1;
264
265                pom=-2.0/sum;
266                // echo to venca   
267
268                for ( j=i;j>=0;j-- ) 
269                {
270                        double w_elem = 0;                     
271                        for ( ii=n-     cc;ii<=m+i+1;ii++ ) 
272                                w_elem+= v( ii-n+cc )*L( ii-1,j );                     
273                        w(j)=w_elem*pom;
274                }
275
276                for ( ii=n-cc-1;ii<=m+i;ii++ ) 
277                        for ( jj=0;jj<i;jj++ ) 
278                                L( ii,jj )+= v( ii-n+cc+1)*w( jj );
279
280                for ( ii=n-cc-1;ii<m+i;ii++ )
281                        L( ii,i )= 0;
282
283                L( m+i,i )+=w( i );
284                D( m+i )=L( m+i,i )*L( m+i,i );
285
286                for ( ii=0;ii<=i;ii++ ) 
287                        L( m+i,ii )/=L( m+i,i );               
288        }
289
290        if ( i>=0 )
291                for ( ii=0;ii<i;ii++ ) 
292                {
293                        jj = D.length()-1-n+ii;
294                        D(jj) = 0;
295                        L.set_row(jj,zeros(L.cols())); //TODO: set_row accepts Num_T
296                        L(jj,jj)=1;
297                }
298
299        L.del_rows(0,m-1);
300        D.del(0,m-1);
301}
302
303//////// Auxiliary Functions
304
305mat ltuinv( const mat &L ) {
306        int dim = L.cols();
307        mat Il = eye( dim );
308        int i, j, k, m;
309        double s;
310
311//Fixme blind transcription of ltuinv.m
312        for ( k = 1; k < ( dim );k++ ) {
313                for ( i = 0; i < ( dim - k );i++ ) {
314                        j = i + k; //change in .m 1+1=2, here 0+0+1=1
315                        s = L( j, i );
316                        for ( m = i + 1; m < ( j ); m++ ) {
317                                s += L( m, i ) * Il( j, m );
318                        }
319                        Il( j, i ) = -s;
320                }
321        }
322
323        return Il;
324}
325
326void dydr( double * r, double *f, double *Dr, double *Df, double *R, int jl, int jh, double *kr, int m, int mx )
327/********************************************************************
328
329   dydr = dyadic reduction, performs transformation of sum of
330          2 dyads r*Dr*r'+ f*Df*f' so that the element of r pointed
331          by R is zeroed. This version allows Dr to be NEGATIVE. Hence the name negdydr or dydr_withneg.
332
333   Parameters :
334     r ... pointer to reduced dyad
335     f ... pointer to reducing dyad
336     Dr .. pointer to the weight of reduced dyad
337     Df .. pointer to the weight of reducing dyad
338     R ... pointer to the element of r, which is to be reduced to
339           zero; the corresponding element of f is assumed to be 1.
340     jl .. lower index of the range within which the dyads are
341           modified
342     ju .. upper index of the range within which the dyads are
343           modified
344     kr .. pointer to the coefficient used in the transformation of r
345           rnew = r + kr*f
346     m  .. number of rows of modified matrix (part of which is r)
347  Remark : Constant mzero means machine zero and should be modified
348           according to the precision of particular machine
349
350                                                 V. Peterka 17-7-89
351
352  Added:
353     mx .. number of rows of modified matrix (part of which is f)  -PN
354
355********************************************************************/
356{
357        int j, jm;
358        double kD, r0;
359        double mzero = 2.2e-16;
360        double threshold = 1e-4;
361
362        if ( fabs( *Dr ) < mzero ) *Dr = 0;
363        r0 = *R;
364        *R = 0.0;
365        kD = *Df;
366        *kr = r0 * *Dr;
367        *Df = kD + r0 * ( *kr );
368        if ( *Df > mzero ) {
369                kD /= *Df;
370                *kr /= *Df;
371        } else {
372                kD = 1.0;
373                *kr = 0.0;
374                if ( *Df < -threshold ) {
375                        it_warning( "Problem in dydr: subraction of dyad results in negative definitness. Likely mistake in calling function." );
376                }
377                *Df = 0.0;
378        }
379        *Dr *= kD;
380        jm = mx * jl;
381        for ( j = m * jl; j < m*jh; j += m ) {
382                r[j] -=  r0 * f[jm];
383                f[jm] += *kr * r[j];
384                jm += mx;
385        }
386}
Note: See TracBrowser for help on using the browser.