#include "square_mat.h" namespace bdm { using namespace itpp; using std::endl; void fsqmat::opupdt ( const vec &v, double w ) { M += outer_product ( v, v * w ); }; mat fsqmat::to_mat() const { return M; }; void fsqmat::mult_sym ( const mat &C ) { M = C * M * C.T(); }; void fsqmat::mult_sym_t ( const mat &C ) { M = C.T() * M * C; }; void fsqmat::mult_sym ( const mat &C, fsqmat &U ) const { U.M = ( C * ( M * C.T() ) ); }; void fsqmat::mult_sym_t ( const mat &C, fsqmat &U ) const { U.M = ( C.T() * ( M * C ) ); }; void fsqmat::inv ( fsqmat &Inv ) const { mat IM = itpp::inv ( M ); Inv = IM; }; void fsqmat::clear() { M.clear(); }; fsqmat::fsqmat ( const mat &M0 ) : sqmat ( M0.cols() ) { bdm_assert_debug ( ( M0.cols() == M0.rows() ), "M0 must be square" ); M = M0; }; //fsqmat::fsqmat() {}; fsqmat::fsqmat ( const int dim0 ) : sqmat ( dim0 ), M ( dim0, dim0 ) {}; std::ostream &operator<< ( std::ostream &os, const fsqmat &ld ) { os << ld.M << endl; return os; } ldmat::ldmat ( const mat &exL, const vec &exD ) : sqmat ( exD.length() ) { D = exD; L = exL; } ldmat::ldmat() : sqmat ( 0 ) {} ldmat::ldmat ( const int dim0 ) : sqmat ( dim0 ), D ( dim0 ), L ( dim0, dim0 ) {} ldmat::ldmat ( const vec D0 ) : sqmat ( D0.length() ) { D = D0; L = eye ( dim ); } ldmat::ldmat ( const mat &V ) : sqmat ( V.cols() ) { bdm_assert_debug ( dim == V.rows(), "ldmat::ldmat matrix V is not square!" ); // L and D will be allocated by ldform() //Chol is unstable this->ldform ( chol ( V ), ones ( dim ) ); } void ldmat::opupdt ( const vec &v, double w ) { int dim = D.length(); double kr; vec r = v; //beware! it is potentionally dangerous, if ITpp change _behaviour of _data()! double *Lraw = L._data(); double *Draw = D._data(); double *rraw = r._data(); bdm_assert_debug ( v.length() == dim, "LD::ldupdt vector v is not compatible with this ld." ); for ( int i = dim - 1; i >= 0; i-- ) { dydr ( rraw, Lraw + i, &w, Draw + i, rraw + i, 0, i, &kr, 1, dim ); } } std::ostream &operator<< ( std::ostream &os, const ldmat &ld ) { os << "L:" << ld.L << endl; os << "D:" << ld.D << endl; return os; } mat ldmat::to_mat() const { int dim = D.length(); mat V ( dim, dim ); double sum; int r, c, cc; for ( r = 0; r < dim; r++ ) { //row cycle for ( c = r; c < dim; c++ ) { //column cycle, using symmetricity => c=r! sum = 0.0; for ( cc = c; cc < dim; cc++ ) { //cycle over the remaining part of the vector sum += L ( cc, r ) * D ( cc ) * L ( cc, c ); //here L(cc,r) = L(r,cc)'; } V ( r, c ) = sum; // symmetricity if ( r != c ) { V ( c, r ) = sum; }; } } //mat V2 = L.transpose() * diag ( D ) * L; return V; } void ldmat::add ( const ldmat &ld2, double w ) { int dim = D.length(); bdm_assert_debug ( ld2.D.length() == dim, "LD.add() incompatible sizes of LDs" ); //Fixme can be done more efficiently either via dydr or ldform for ( int r = 0; r < dim; r++ ) { // Add columns of ld2.L' (i.e. rows of ld2.L) as dyads weighted by ld2.D this->opupdt ( ld2.L.get_row ( r ), w*ld2.D ( r ) ); } } void ldmat::clear() { L.clear(); for ( int i = 0; i < L.cols(); i++ ) { L ( i, i ) = 1; }; D.clear(); } void ldmat::inv ( ldmat &Inv ) const { Inv.clear(); //Inv = zero in LD mat U = ltuinv ( L ); Inv.ldform ( U.transpose(), 1.0 / D ); } void ldmat::mult_sym ( const mat &C ) { mat A = L * C.T(); this->ldform ( A, D ); } void ldmat::mult_sym_t ( const mat &C ) { mat A = L * C; this->ldform ( A, D ); } void ldmat::mult_sym ( const mat &C, ldmat &U ) const { mat A = L * C.T(); //could be done more efficiently using BLAS U.ldform ( A, D ); } void ldmat::mult_sym_t ( const mat &C, ldmat &U ) const { mat A = L * C; /* vec nD=zeros(U.rows()); nD.replace_mid(0, D); //I case that D < nD*/ U.ldform ( A, D ); } double ldmat::logdet() const { double ldet = 0.0; int i; // sum logarithms of diagobal elements for ( i = 0; i < D.length(); i++ ) { ldet += log ( D ( i ) ); }; return ldet; } double ldmat::qform ( const vec &v ) const { double x = 0.0, sum; int i, j; for ( i = 0; i < D.length(); i++ ) { //rows of L sum = 0.0; for ( j = 0; j <= i; j++ ) { sum += L ( i, j ) * v ( j ); } x += D ( i ) * sum * sum; }; return x; } double ldmat::invqform ( const vec &v ) const { double x = 0.0; int i; vec pom ( v.length() ); backward_substitution ( L.T(), v, pom ); for ( i = 0; i < D.length(); i++ ) { //rows of L x += pom ( i ) * pom ( i ) / D ( i ); }; return x; } ldmat& ldmat::operator *= ( double x ) { D *= x; return *this; } vec ldmat::sqrt_mult ( const vec &x ) const { int i, j; vec res ( dim ); //double sum; for ( i = 0; i < dim; i++ ) {//for each element of result res ( i ) = 0.0; for ( j = i; j < dim; j++ ) {//sum D(j)*L(:,i).*x res ( i ) += sqrt ( D ( j ) ) * L ( j, i ) * x ( j ); } } // vec res2 = L.transpose()*diag( sqrt( D ) )*x; return res; } void ldmat::ldform ( const mat &A, const vec &D0 ) { int m = A.rows(); int n = A.cols(); int mn = ( m < n ) ? m : n ; bdm_assert_debug ( D0.length() == A.rows(), "ldmat::ldform Vector D must have the length as row count of A" ); L = concat_vertical ( zeros ( n, n ), diag ( sqrt ( D0 ) ) * A ); D = zeros ( n + m ); //unnecessary big L and D will be made smaller at the end of file vec w = zeros ( n + m ); double sum, beta, pom; int cc = 0; int i = n; // indexovani o 1 niz, nez v matlabu int ii, j, jj; while ( ( i > n - mn - cc ) && ( i > 0 ) ) { i--; sum = 0.0; int last_v = m + i - n + cc + 1; vec v = zeros ( last_v + 1 ); //prepare v for ( ii = n - cc - 1; ii < m + i + 1; ii++ ) { sum += L ( ii, i ) * L ( ii, i ); v ( ii - n + cc + 1 ) = L ( ii, i ); //assign v } if ( L ( m + i, i ) == 0 ) beta = sqrt ( sum ); else beta = L ( m + i, i ) + sign ( L ( m + i, i ) ) * sqrt ( sum ); if ( std::fabs ( beta ) < eps ) { cc++; L.set_row ( n - cc, L.get_row ( m + i ) ); L.set_row ( m + i, zeros ( L.cols() ) ); D ( m + i ) = 0; L ( m + i, i ) = 1; L.set_submatrix ( n - cc, m + i - 1, i, i, 0 ); continue; } sum -= v ( last_v ) * v ( last_v ); sum /= beta * beta; sum++; v /= beta; v ( last_v ) = 1; pom = -2.0 / sum; // echo to venca for ( j = i; j >= 0; j-- ) { double w_elem = 0; for ( ii = n - cc; ii <= m + i + 1; ii++ ) w_elem += v ( ii - n + cc ) * L ( ii - 1, j ); w ( j ) = w_elem * pom; } for ( ii = n - cc - 1; ii <= m + i; ii++ ) for ( jj = 0; jj < i; jj++ ) L ( ii, jj ) += v ( ii - n + cc + 1 ) * w ( jj ); for ( ii = n - cc - 1; ii < m + i; ii++ ) L ( ii, i ) = 0; L ( m + i, i ) += w ( i ); D ( m + i ) = L ( m + i, i ) * L ( m + i, i ); for ( ii = 0; ii <= i; ii++ ) L ( m + i, ii ) /= L ( m + i, i ); } if ( i >= 0 ) for ( ii = 0; ii < i; ii++ ) { jj = D.length() - 1 - n + ii; D ( jj ) = 0; L.set_row ( jj, zeros ( L.cols() ) ); //TODO: set_row accepts Num_T L ( jj, jj ) = 1; } L.del_rows ( 0, m - 1 ); D.del ( 0, m - 1 ); dim = L.rows(); } //////// Auxiliary Functions mat ltuinv ( const mat &L ) { int dim = L.cols(); mat Il = eye ( dim ); int i, j, k, m; double s; //Fixme blind transcription of ltuinv.m for ( k = 1; k < ( dim ); k++ ) { for ( i = 0; i < ( dim - k ); i++ ) { j = i + k; //change in .m 1+1=2, here 0+0+1=1 s = L ( j, i ); for ( m = i + 1; m < ( j ); m++ ) { s += L ( m, i ) * Il ( j, m ); } Il ( j, i ) = -s; } } return Il; } void dydr ( double * r, double *f, double *Dr, double *Df, double *R, int jl, int jh, double *kr, int m, int mx ) /******************************************************************** dydr = dyadic reduction, performs transformation of sum of 2 dyads r*Dr*r'+ f*Df*f' so that the element of r pointed by R is zeroed. This version allows Dr to be NEGATIVE. Hence the name negdydr or dydr_withneg. Parameters : r ... pointer to reduced dyad f ... pointer to reducing dyad Dr .. pointer to the weight of reduced dyad Df .. pointer to the weight of reducing dyad R ... pointer to the element of r, which is to be reduced to zero; the corresponding element of f is assumed to be 1. jl .. lower index of the range within which the dyads are modified ju .. upper index of the range within which the dyads are modified kr .. pointer to the coefficient used in the transformation of r rnew = r + kr*f m .. number of rows of modified matrix (part of which is r) Remark : Constant mzero means machine zero and should be modified according to the precision of particular machine V. Peterka 17-7-89 Added: mx .. number of rows of modified matrix (part of which is f) -PN ********************************************************************/ { int j, jm; double kD, r0; double mzero = 2.2e-16; double threshold = 1e-4; if ( fabs ( *Dr ) < mzero ) *Dr = 0; r0 = *R; *R = 0.0; kD = *Df; *kr = r0 * *Dr; *Df = kD + r0 * ( *kr ); if ( *Df > mzero ) { kD /= *Df; *kr /= *Df; } else { kD = 1.0; *kr = 0.0; if ( *Df < -threshold ) { bdm_warning ( "Problem in dydr: subraction of dyad results in negative definitness. Likely mistake in calling function." ); } *Df = 0.0; } *Dr *= kD; jm = mx * jl; for ( j = m * jl; j < m*jh; j += m ) { r[j] -= r0 * f[jm]; f[jm] += *kr * r[j]; jm += mx; } } }