root/libDC.cpp @ 8

Revision 8, 6.3 kB (checked in by smidl, 16 years ago)

Kalmany funkci, PF nefunkci

Line 
1#include <itpp/itbase.h>
2#include "libDC.h"
3
4using namespace itpp;
5
6using std::endl;
7
8//! Auxiliary function dydr; dyadic reduction
9void dydr( double * r, double *f, double *Dr, double *Df, double *R, int jl, int jh, double *kr, int m, int mx );
10
11//! Auxiliary function ltuinv; inversion of a triangular matrix;
12//TODO can be done via: dtrtri.f from lapack
13mat ltuinv( const mat &L );
14
15
16
17ldmat::ldmat( const mat &exL, const vec &exD ) {
18        D = exD;
19        L = exL;
20}
21
22ldmat::ldmat() {
23        vec D ;
24        mat L;
25}
26
27ldmat::ldmat( const mat V ) {
28//TODO check if correct!! Based on heuristic observation of lu()
29
30        int dim = V.cols();
31        it_assert_debug( dim == V.rows(),"ldmat::ldmat matrix V is not square!" );
32
33        mat U( dim,dim );
34
35        L = V; //Allocate space for L
36        ivec p = ivec( dim ); //not clear why?
37
38        lu( V,L,U,p );
39
40//Now, if V is symmetric, L is what we seek and D is on diagonal of U
41        D = diag( U );
42
43//check if V was symmetric
44//TODO How? norm of L-U'?
45//it_assert_debug();
46}
47
48void ldmat::opupdt( const vec &v,  double w ) {
49        int dim = D.length();
50        double kr;
51        vec r = v;
52        //beware! it is potentionally dangerous, if ITpp change _behaviour of _data()!
53        double *Lraw = L._data();
54        double *Draw = D._data();
55        double *rraw = r._data();
56
57        it_assert_debug( v.length() == dim, "LD::ldupdt vector v is not compatible with this ld." );
58
59        for ( int i = dim - 1; i >= 0; i-- ) {
60                dydr( rraw, Lraw + i, &w, Draw + i, rraw + i, 0, i, &kr, 1, dim );
61        }
62}
63
64std::ostream &operator<< ( std::ostream &os,  sqmat &sq ) {
65        os << sq.to_mat() << endl;
66}
67
68mat ldmat::to_mat() {
69        int dim = D.length();
70        mat V( dim, dim );
71        double sum;
72        int r, c, cc;
73
74        for ( r = 0;r < dim;r++ ) { //row cycle
75                for ( c = r;c < dim;c++ ) {
76                        //column cycle, using symmetricity => c=r!
77                        sum = 0.0;
78                        for ( cc = c;cc < dim;cc++ ) { //cycle over the remaining part of the vector
79                                sum += L( cc, r ) * D( cc ) * L( cc, c );
80                                //here L(cc,r) = L(r,cc)';
81                        }
82                        V( r, c ) = sum;
83                        // symmetricity
84                        if ( r != c ) {V( c, r ) = sum;};
85                }
86        }
87        return V;
88}
89
90
91void ldmat::add( const ldmat &ld2, double w ) {
92        int dim = D.length();
93
94        it_assert_debug( ld2.D.length() == dim, "LD.add() incompatible sizes of LDs;" );
95
96        //Fixme can be done more efficiently either via dydr or ldform
97        for ( int r = 0; r < dim; r++ ) {
98                // Add columns of ld2.L' (i.e. rows of ld2.L) as dyads weighted by ld2.D
99                this->opupdt( ld2.L.get_row( r ), w*ld2.D( r ) );
100        }
101}
102
103void ldmat::clear(){L.clear(); for ( int i=0;i<L.cols();i++ ){L( i,i )=1;}; D.clear();}
104
105void ldmat::inv( ldmat &Inv ) {
106        int dim = D.length();
107        Inv.clear();   //Inv = zero in LD
108        mat U = ltuinv( L );
109
110        //Fixme can be done more efficiently either via dydr or ldform
111        for ( int r = 0; r < dim; r++ ) {
112                // Add columns of U as dyads weighted by 1/D
113                Inv.opupdt( U.get_col( r ), 1.0 / D( r ) );
114        }
115}
116
117void ldmat::mult_sym( const mat &C, bool trans ) {
118
119//TODO better
120
121        it_assert_debug( C.cols()==L.cols(), "ldmat::mult_sym wrong input argument" );
122        mat Ct=C;
123
124        if ( trans==false ) { // return C*this*C'
125                Ct *= this->to_mat();
126                Ct *= C.transpose();
127        } else {        // return C'*this*C
128                Ct = C.transpose();
129                Ct *= this->to_mat();
130                Ct *= C;
131        }
132
133        ldmat Lnew=ldmat( Ct );
134        L = Lnew.L;
135        D = Lnew.D;
136}
137
138void ldmat::mult_sym( const mat &C, ldmat &U, bool trans ) {
139
140//TODO better
141
142//TODO input test
143
144        mat Ct=C;
145
146        if ( trans==false ) { // return C*this*C'
147                Ct *= U.to_mat();
148                Ct *= C.transpose();
149        } else {        // return C'*this*C
150                Ct = C.transpose();
151                Ct *= U.to_mat();
152                Ct *= C;
153        }
154
155        ldmat Lnew=ldmat( Ct );
156        L = Lnew.L;
157        D = Lnew.D;
158}
159
160double ldmat::logdet() {
161        double ldet = 0.0;
162        int i;
163// sum logarithms of diagobal elements
164        for ( i=0; i<D.length(); i++ ){ldet+=log( D( i ) );};
165}
166
167double ldmat::qform( vec &v ) {
168        double x = 0.0, sum;
169        int i,j;
170
171        for ( i=0; i<D.length(); i++ ) { //rows of L
172                sum = 0.0;
173                for ( j=0; j<=i; j++ ){sum+=L( i,j )*v( j );}
174                x +=D( i )*sum*sum;
175        };
176        return x;
177}
178
179ldmat& ldmat::operator *= (double x){
180int i;
181for(i=0;i<D.length();i++){D(i)*=x;};
182}
183
184
185//////// Auxiliary Functions
186
187mat ltuinv( const mat &L ) {
188        int dim = L.cols();
189        mat Il = eye( dim );
190        int i, j, k, m;
191        double s;
192
193//Fixme blind transcription of ltuinv.m
194        for ( k = 1; k < ( dim );k++ ) {
195                for ( i = 0; i < ( dim - k );i++ ) {
196                        j = i + k; //change in .m 1+1=2, here 0+0+1=1
197                        s = L( j, i );
198                        for ( m = i + 1; m < ( j - 1 ); m++ ) {
199                                s += L( m, i ) * Il( j, m );
200                        }
201                        Il( j, i ) = -s;
202                }
203        }
204
205        return Il;
206}
207
208void dydr( double * r, double *f, double *Dr, double *Df, double *R, int jl, int jh, double *kr, int m, int mx )
209/********************************************************************
210
211   dydr = dyadic reduction, performs transformation of sum of
212          2 dyads r*Dr*r'+ f*Df*f' so that the element of r pointed
213          by R is zeroed. This version allows Dr to be NEGATIVE. Hence the name negdydr or dydr_withneg.
214
215   Parameters :
216     r ... pointer to reduced dyad
217     f ... pointer to reducing dyad
218     Dr .. pointer to the weight of reduced dyad
219     Df .. pointer to the weight of reducing dyad
220     R ... pointer to the element of r, which is to be reduced to
221           zero; the corresponding element of f is assumed to be 1.
222     jl .. lower index of the range within which the dyads are
223           modified
224     ju .. upper index of the range within which the dyads are
225           modified
226     kr .. pointer to the coefficient used in the transformation of r
227           rnew = r + kr*f
228     m  .. number of rows of modified matrix (part of which is r)
229  Remark : Constant mzero means machine zero and should be modified
230           according to the precision of particular machine
231
232                                                 V. Peterka 17-7-89
233
234  Added:
235     mx .. number of rows of modified matrix (part of which is f)  -PN
236
237********************************************************************/
238{
239        int j, jm;
240        double kD, r0;
241        double mzero = 2.2e-16;
242        double threshold = 1e-4;
243
244        if ( fabs( *Dr ) < mzero ) *Dr = 0;
245        r0 = *R;
246        *R = 0.0;
247        kD = *Df;
248        *kr = r0 * *Dr;
249        *Df = kD + r0 * ( *kr );
250        if ( *Df > mzero ) {
251                kD /= *Df;
252                *kr /= *Df;
253        } else {
254                kD = 1.0;
255                *kr = 0.0;
256                if ( *Df < -threshold ) {
257                it_warning( "Problem in dydr: subraction of dyad results in negative definitness. Likely mistake in calling function." );}
258                *Df = 0.0;
259        }
260        *Dr *= kD;
261        jm = mx * jl;
262        for ( j = m * jl; j < m*jh; j += m ) {
263                r[j] -=  r0 * f[jm];
264                f[jm] += *kr * r[j];
265                jm += mx;
266        }
267}
268
Note: See TracBrowser for help on using the browser.