/* LA: linear algebra C++ interface library Copyright (C) 2008 Jiri Pittner or complex versions written by Roman Curik This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include "vec.h" #include "qsort.h" extern "C" { extern ssize_t read(int, void *, size_t); extern ssize_t write(int, const void *, size_t); } namespace LA { ////////////////////////////////////////////////////////////////////////////// //// forced instantization in the corespoding object file #define INSTANTIZE(T) \ template void NRVec::put(int fd, bool dim, bool transp) const; \ template void NRVec::get(int fd, bool dim, bool transp); \ INSTANTIZE(double) INSTANTIZE(complex) INSTANTIZE(char) INSTANTIZE(short) INSTANTIZE(int) INSTANTIZE(long) INSTANTIZE(long long) INSTANTIZE(unsigned char) INSTANTIZE(unsigned short) INSTANTIZE(unsigned int) INSTANTIZE(unsigned long) INSTANTIZE(unsigned long long) /* * Templates first, specializations for BLAS next */ // conversion ctor #ifndef MATPTR template NRVec::NRVec(const NRMat &rhs) { nn = rhs.nn*rhs.mm; v = rhs.v; count = rhs.count; (*count)++; } #endif //raw I/O template void NRVec::put(int fd, bool dim, bool transp) const { errno=0; int pad=1; //align at least 8-byte if(dim) { if(sizeof(int) != write(fd,&nn,sizeof(int))) laerror("cannot write"); if(sizeof(int) != write(fd,&pad,sizeof(int))) laerror("cannot write"); } LA_traits::multiput(nn,fd,v,dim); } template void NRVec::get(int fd, bool dim, bool transp) { int nn0[2]; //align at least 8-byte errno=0; if(dim) { if(2*sizeof(int) != read(fd,&nn0,2*sizeof(int))) laerror("cannot read"); resize(nn0[0]); } else copyonwrite(); LA_traits::multiget(nn,fd,v,dim); } // formatted print for NRVec template void NRVec::fprintf(FILE *file, const char *format, const int modulo) const { lawritemat(file, v, 1, nn, format, 1, modulo, 0); } // formatted scan for NRVec template void NRVec::fscanf(FILE *f, const char *format) { int n; if(::fscanf(f, "%d", &n) != 1) laerror("cannot read vector dimension"); resize(n); for (int i=0; i const NRVec NRVec::operator-() const { NRVec result(nn); for (int i=0; i const bool NRVec::operator>(const NRVec &rhs) const { int n=nn; if(rhs.nn::bigger(v[i],rhs.v[i])) return true; if(LA_traits::smaller(v[i],rhs.v[i])) return false; } return nn>rhs.nn; } template const bool NRVec::operator<(const NRVec &rhs) const { int n=nn; if(rhs.nn::smaller(v[i],rhs.v[i])) return true; if(LA_traits::bigger(v[i],rhs.v[i])) return false; } return nn void NRVec::randomize(const double &x) { for(int i=0; i void NRVec >::randomize(const double &x) { for(int i=0; i (x*(2.*random()/(1.+RAND_MAX) -1.),x*(2.*random()/(1.+RAND_MAX) -1.)); } //complex from real constructor template<> NRVec >::NRVec(const NRVec &rhs, bool imagpart) : nn(rhs.size()), v(new complex[rhs.size()]), count(new int(1)) { memset(v,0,nn*sizeof(complex)); cblas_dcopy(nn,&rhs[0],1,((double *)v) + (imagpart?1:0),2); } // axpy call for T = double (not strided) template<> void NRVec::axpy(const double alpha, const NRVec &x) { #ifdef DEBUG if (nn != x.nn) laerror("axpy of incompatible vectors"); #endif copyonwrite(); cblas_daxpy(nn, alpha, x.v, 1, v, 1); } // axpy call for T = complex (not strided) template<> void NRVec< complex >::axpy(const complex alpha, const NRVec< complex > &x) { #ifdef DEBUG if (nn != x.nn) laerror("axpy of incompatible vectors"); #endif copyonwrite(); cblas_zaxpy(nn, &alpha, x.v, 1, v, 1); } // axpy call for T = double (strided) template<> void NRVec::axpy(const double alpha, const double *x, const int stride) { copyonwrite(); cblas_daxpy(nn, alpha, x, stride, v, 1); } // axpy call for T = complex (strided) template<> void NRVec< complex >::axpy(const complex alpha, const complex *x, const int stride) { copyonwrite(); cblas_zaxpy(nn, &alpha, x, stride, v, 1); } // unary minus template<> const NRVec NRVec::operator-() const { NRVec result(*this); result.copyonwrite(); cblas_dscal(nn, -1.0, result.v, 1); return result; } template<> const NRVec< complex > NRVec< complex >::operator-() const { NRVec< complex > result(*this); result.copyonwrite(); cblas_zdscal(nn, -1.0, result.v, 1); return result; } // assignment of scalar to every element template NRVec & NRVec::operator=(const T &a) { copyonwrite(); if(a != (T)0) for (int i=0; i template<> NRVec & NRVec::normalize() { double tmp; tmp = cblas_dnrm2(nn, v, 1); #ifdef DEBUG if(!tmp) laerror("normalization of zero vector"); #endif copyonwrite(); tmp = 1.0/tmp; cblas_dscal(nn, tmp, v, 1); return *this; } // Normalization of NRVec< complex > template<> NRVec< complex > & NRVec< complex >::normalize() { complex tmp; tmp = cblas_dznrm2(nn, v, 1); #ifdef DEBUG if(!(tmp.real()) && !(tmp.imag())) laerror("normalization of zero vector"); #endif copyonwrite(); tmp = 1.0/tmp; cblas_zscal(nn, &tmp, v, 1); return *this; } //stubs for linkage #define INSTANTIZE_DUMMY(T) \ template<> void NRVec::gemv(const T beta, const NRMat &a, const char trans, const T alpha, const NRVec &x) { laerror("gemv on unsupported types"); } \ template<> void NRVec::gemv(const T beta, const NRSMat &a, const char trans, const T alpha, const NRVec &x) { laerror("gemv on unsupported types"); } \ template<> void NRVec::gemv(const T beta, const SparseMat &a, const char trans, const T alpha, const NRVec &x, bool s) { laerror("gemv on unsupported types"); } \ template<> void NRVec::gemv(const LA_traits_complex::Component_type beta, const LA_traits_complex::NRMat_Noncomplex_type &a, const char trans, const LA_traits_complex::Component_type alpha, const NRVec &x) { laerror("gemv on unsupported types"); } \ template<> void NRVec::gemv(const LA_traits_complex::Component_type beta, const LA_traits_complex::NRSMat_Noncomplex_type &a, const char trans, const LA_traits_complex::Component_type alpha, const NRVec &x) { laerror("gemv on unsupported types"); } \ template<> NRVec & NRVec::normalize() {laerror("normalize() impossible for integer types"); return *this;} \ template<> const NRMat NRVec::otimes(const NRVec &b,const bool conj, const T &scale) const {laerror("otimes presently implemented only for double and complex double"); return NRMat ();} // gemv calls template<> void NRVec::gemv(const double beta, const NRMat &A, const char trans, const double alpha, const NRVec &x) { #ifdef DEBUG if ((trans == 'n'?A.ncols():A.nrows()) != x.size()) laerror("incompatible sizes in gemv A*x"); #endif copyonwrite(); cblas_dgemv(CblasRowMajor, (trans=='n' ? CblasNoTrans:CblasTrans), A.nrows(), A.ncols(), alpha, A, A.ncols(), x.v, 1, beta, v, 1); } template<> void NRVec >::gemv(const double beta, const NRMat &A, const char trans, const double alpha, const NRVec > &x) { #ifdef DEBUG if ((trans == 'n'?A.ncols():A.nrows()) != x.size()) laerror("incompatible sizes in gemv A*x"); #endif copyonwrite(); cblas_dgemv(CblasRowMajor, (trans=='n' ? CblasNoTrans:CblasTrans), A.nrows(), A.ncols(), alpha, A, A.ncols(), (double *)x.v, 2, beta, (double *)v, 2); cblas_dgemv(CblasRowMajor, (trans=='n' ? CblasNoTrans:CblasTrans), A.nrows(), A.ncols(), alpha, A, A.ncols(), ((double *)x.v) + 1, 2, beta, ((double *)v)+1, 2); } template<> void NRVec< complex >::gemv(const complex beta, const NRMat< complex > &A, const char trans, const complex alpha, const NRVec &x) { #ifdef DEBUG if ((trans == 'n'?A.ncols():A.nrows()) != x.size()) laerror("incompatible sizes in gemv A*x"); #endif copyonwrite(); cblas_zgemv(CblasRowMajor, (trans=='n' ? CblasNoTrans:CblasTrans), A.nrows(), A.ncols(), &alpha, A, A.ncols(), x.v, 1, &beta, v, 1); } template<> void NRVec::gemv(const double beta, const NRSMat &A, const char trans, const double alpha, const NRVec &x) { #ifdef DEBUG if (A.ncols()!=x.size()) laerror("incompatible dimension in gemv A*x"); #endif copyonwrite(); cblas_dspmv(CblasRowMajor, CblasLower, A.ncols(), alpha, A, x.v, 1, beta, v, 1); } template<> void NRVec >::gemv(const double beta, const NRSMat &A, const char trans, const double alpha, const NRVec > &x) { #ifdef DEBUG if (A.ncols()!=x.size()) laerror("incompatible dimension in gemv A*x"); #endif copyonwrite(); cblas_dspmv(CblasRowMajor, CblasLower, A.ncols(), alpha, A, (double *)x.v, 2, beta, (double *)v, 2); cblas_dspmv(CblasRowMajor, CblasLower, A.ncols(), alpha, A, ((double *)x.v)+1, 2, beta, ((double *)v)+1, 2); } template<> void NRVec< complex >::gemv(const complex beta, const NRSMat< complex > &A, const char trans, const complex alpha, const NRVec &x) { #ifdef DEBUG if (A.ncols()!=x.size()) laerror("incompatible dimension in gemv"); #endif copyonwrite(); cblas_zhpmv(CblasRowMajor, CblasLower, A.ncols(), &alpha, A, x.v, 1, &beta, v, 1); } // Direct product Mat = Vec | Vec template<> const NRMat NRVec::otimes(const NRVec &b,const bool conj, const double &scale) const { NRMat result(0.,nn,b.nn); cblas_dger(CblasRowMajor, nn, b.nn, scale, v, 1, b.v, 1, result, b.nn); return result; } template<> const NRMat< complex > NRVec >::otimes(const NRVec< complex > &b, const bool conj, const complex &scale) const { NRMat< complex > result(0.,nn,b.nn); if(conj) cblas_zgerc(CblasRowMajor, nn, b.nn, &scale, v, 1, b.v, 1, result, b.nn); else cblas_zgeru(CblasRowMajor, nn, b.nn, &scale, v, 1, b.v, 1, result, b.nn); return result; } template int NRVec::sort(int direction, int from, int to, int *perm) { copyonwrite(); if(to == -1) to=nn-1; if(direction) return memqsort<1,NRVec,int,int>(*this,perm,from,to); else return memqsort<0,NRVec,int,int>(*this,perm,from,to); } ////////////////////////////////////////////////////////////////////////////// //// forced instantization in the corespoding object file template class NRVec; template class NRVec >; template class NRVec; template class NRVec; template class NRVec; template class NRVec; template class NRVec; template class NRVec; template class NRVec; template class NRVec; template class NRVec; template class NRVec; INSTANTIZE_DUMMY(char) INSTANTIZE_DUMMY(short) INSTANTIZE_DUMMY(int) INSTANTIZE_DUMMY(long) INSTANTIZE_DUMMY(long long) INSTANTIZE_DUMMY(unsigned char) INSTANTIZE_DUMMY(unsigned short) INSTANTIZE_DUMMY(unsigned int) INSTANTIZE_DUMMY(unsigned long) INSTANTIZE_DUMMY(unsigned long long) INSTANTIZE_DUMMY(complex) INSTANTIZE_DUMMY(complex) INSTANTIZE_DUMMY(complex) INSTANTIZE_DUMMY(complex) INSTANTIZE_DUMMY(complex) INSTANTIZE_DUMMY(complex) INSTANTIZE_DUMMY(complex) INSTANTIZE_DUMMY(complex) INSTANTIZE_DUMMY(complex) INSTANTIZE_DUMMY(complex) INSTANTIZE_DUMMY(complex >) INSTANTIZE_DUMMY(complex >) }//namespace