LA_library/vec.cc

473 lines
13 KiB
C++
Raw Normal View History

2008-02-26 14:55:23 +01:00
/*
LA: linear algebra C++ interface library
Copyright (C) 2008 Jiri Pittner <jiri.pittner@jh-inst.cas.cz> or <jiri@pittnerovi.com>
complex versions written by Roman Curik <roman.curik@jh-inst.cas.cz>
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 <http://www.gnu.org/licenses/>.
*/
2009-11-12 22:01:19 +01:00
2004-03-17 04:07:21 +01:00
#include <iostream>
2005-02-14 01:10:07 +01:00
#include <stdlib.h>
2010-01-17 21:28:38 +01:00
#include <stdio.h>
2005-02-14 01:10:07 +01:00
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
2005-11-20 14:46:00 +01:00
#include <errno.h>
2009-11-12 22:01:19 +01:00
#include "vec.h"
2006-04-01 06:48:01 +02:00
#include "qsort.h"
2005-02-14 01:10:07 +01:00
extern "C" {
extern ssize_t read(int, void *, size_t);
extern ssize_t write(int, const void *, size_t);
}
2009-11-12 22:01:19 +01:00
namespace LA {
2004-03-17 04:07:21 +01:00
//////////////////////////////////////////////////////////////////////////////
//// forced instantization in the corespoding object file
#define INSTANTIZE(T) \
2005-09-11 22:04:24 +02:00
template void NRVec<T>::put(int fd, bool dim, bool transp) const; \
template void NRVec<T>::get(int fd, bool dim, bool transp); \
2005-02-18 23:08:15 +01:00
2004-03-17 04:07:21 +01:00
INSTANTIZE(double)
INSTANTIZE(complex<double>)
2004-03-17 06:34:59 +01:00
INSTANTIZE(char)
2009-11-12 22:01:19 +01:00
INSTANTIZE(short)
INSTANTIZE(int)
INSTANTIZE(long)
INSTANTIZE(long long)
2005-02-14 01:10:07 +01:00
INSTANTIZE(unsigned char)
2009-11-12 22:01:19 +01:00
INSTANTIZE(unsigned short)
2006-09-10 22:06:44 +02:00
INSTANTIZE(unsigned int)
2006-04-01 06:48:01 +02:00
INSTANTIZE(unsigned long)
2009-11-12 22:01:19 +01:00
INSTANTIZE(unsigned long long)
2006-04-01 06:48:01 +02:00
2005-02-18 23:08:15 +01:00
2004-03-17 04:07:21 +01:00
/*
* Templates first, specializations for BLAS next
*/
// conversion ctor
#ifndef MATPTR
template <typename T>
NRVec<T>::NRVec(const NRMat<T> &rhs)
{
nn = rhs.nn*rhs.mm;
v = rhs.v;
count = rhs.count;
(*count)++;
}
#endif
2005-02-14 01:10:07 +01:00
//raw I/O
template <typename T>
2005-09-11 22:04:24 +02:00
void NRVec<T>::put(int fd, bool dim, bool transp) const
2005-02-14 01:10:07 +01:00
{
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<T>::multiput(nn,fd,v,dim);
}
template <typename T>
2005-09-11 22:04:24 +02:00
void NRVec<T>::get(int fd, bool dim, bool transp)
2005-02-14 01:10:07 +01:00
{
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<T>::multiget(nn,fd,v,dim);
}
2004-03-17 04:07:21 +01:00
// formatted print for NRVec
template<typename T>
void NRVec<T>::fprintf(FILE *file, const char *format, const int modulo) const
{
lawritemat(file, v, 1, nn, format, 1, modulo, 0);
}
// formatted scan for NRVec
2005-02-14 01:10:07 +01:00
template <typename T>
2004-03-17 04:07:21 +01:00
void NRVec<T>::fscanf(FILE *f, const char *format)
{
int n;
2010-01-17 21:28:38 +01:00
if(::fscanf(f, "%d", &n) != 1) laerror("cannot read vector dimension");
2004-03-17 04:07:21 +01:00
resize(n);
for (int i=0; i<n; i++)
2010-01-17 21:28:38 +01:00
if (::fscanf(f, format, v+i) != 1)
2004-03-17 04:07:21 +01:00
laerror("cannot read the vector eleemnt");
}
// unary minus
template <typename T>
const NRVec<T> NRVec<T>::operator-() const
{
NRVec<T> result(nn);
for (int i=0; i<nn; i++) result.v[i]= -v[i];
return result;
}
2005-09-06 17:55:07 +02:00
//comparison operators (for lexical order)
template <typename T>
const bool NRVec<T>::operator>(const NRVec &rhs) const
{
int n=nn; if(rhs.nn<n) n=rhs.nn;
for(int i=0; i<n;++i)
{
if(LA_traits<T>::bigger(v[i],rhs.v[i])) return true;
if(LA_traits<T>::smaller(v[i],rhs.v[i])) return false;
}
return nn>rhs.nn;
}
template <typename T>
const bool NRVec<T>::operator<(const NRVec &rhs) const
{
int n=nn; if(rhs.nn<n) n=rhs.nn;
for(int i=0; i<n;++i)
{
if(LA_traits<T>::smaller(v[i],rhs.v[i])) return true;
if(LA_traits<T>::bigger(v[i],rhs.v[i])) return false;
}
return nn<rhs.nn;
}
2008-03-03 16:35:37 +01:00
template<>
void NRVec<double>::randomize(const double &x)
{
for(int i=0; i<nn; ++i) v[i] = x*(2.*random()/(1.+RAND_MAX) -1.);
}
2009-10-08 16:01:15 +02:00
template<>
void NRVec<complex<double> >::randomize(const double &x)
{
for(int i=0; i<nn; ++i) v[i] = complex<double> (x*(2.*random()/(1.+RAND_MAX) -1.),x*(2.*random()/(1.+RAND_MAX) -1.));
}
//complex from real constructor
template<>
NRVec<complex<double> >::NRVec(const NRVec<double> &rhs, bool imagpart)
: nn(rhs.size()), v(new complex<double>[rhs.size()]), count(new int(1))
{
memset(v,0,nn*sizeof(complex<double>));
cblas_dcopy(nn,&rhs[0],1,((double *)v) + (imagpart?1:0),2);
}
2005-09-06 17:55:07 +02:00
2004-03-17 04:07:21 +01:00
// axpy call for T = double (not strided)
2005-11-20 14:46:00 +01:00
template<>
2004-03-17 04:07:21 +01:00
void NRVec<double>::axpy(const double alpha, const NRVec<double> &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<double> (not strided)
2005-11-20 14:46:00 +01:00
template<>
2004-03-17 04:07:21 +01:00
void NRVec< complex<double> >::axpy(const complex<double> alpha,
const NRVec< complex<double> > &x)
{
#ifdef DEBUG
if (nn != x.nn) laerror("axpy of incompatible vectors");
#endif
copyonwrite();
2009-11-12 22:01:19 +01:00
cblas_zaxpy(nn, &alpha, x.v, 1, v, 1);
2004-03-17 04:07:21 +01:00
}
// axpy call for T = double (strided)
2005-11-20 14:46:00 +01:00
template<>
2004-03-17 04:07:21 +01:00
void NRVec<double>::axpy(const double alpha, const double *x, const int stride)
{
copyonwrite();
cblas_daxpy(nn, alpha, x, stride, v, 1);
}
// axpy call for T = complex<double> (strided)
2005-11-20 14:46:00 +01:00
template<>
2004-03-17 04:07:21 +01:00
void NRVec< complex<double> >::axpy(const complex<double> alpha,
const complex<double> *x, const int stride)
{
copyonwrite();
2009-11-12 22:01:19 +01:00
cblas_zaxpy(nn, &alpha, x, stride, v, 1);
2004-03-17 04:07:21 +01:00
}
// unary minus
2005-11-20 14:46:00 +01:00
template<>
2004-03-17 04:07:21 +01:00
const NRVec<double> NRVec<double>::operator-() const
{
NRVec<double> result(*this);
result.copyonwrite();
cblas_dscal(nn, -1.0, result.v, 1);
return result;
}
2005-11-20 14:46:00 +01:00
template<>
2004-03-17 04:07:21 +01:00
const NRVec< complex<double> >
NRVec< complex<double> >::operator-() const
{
NRVec< complex<double> > result(*this);
result.copyonwrite();
2009-11-12 22:01:19 +01:00
cblas_zdscal(nn, -1.0, result.v, 1);
2004-03-17 04:07:21 +01:00
return result;
}
// assignment of scalar to every element
template <typename T>
NRVec<T> & NRVec<T>::operator=(const T &a)
{
copyonwrite();
if(a != (T)0)
for (int i=0; i<nn; i++) v[i] = a;
else
memset(v, 0, nn*sizeof(T));
return *this;
}
// Normalization of NRVec<double>
2005-11-20 14:46:00 +01:00
template<>
2004-03-17 04:07:21 +01:00
NRVec<double> & NRVec<double>::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<double> >
2005-11-20 14:46:00 +01:00
template<>
2004-03-17 04:07:21 +01:00
NRVec< complex<double> > & NRVec< complex<double> >::normalize()
{
complex<double> tmp;
2009-11-12 22:01:19 +01:00
tmp = cblas_dznrm2(nn, v, 1);
2004-03-17 04:07:21 +01:00
#ifdef DEBUG
if(!(tmp.real()) && !(tmp.imag())) laerror("normalization of zero vector");
#endif
copyonwrite();
tmp = 1.0/tmp;
2009-11-12 22:01:19 +01:00
cblas_zscal(nn, &tmp, v, 1);
2004-03-17 04:07:21 +01:00
return *this;
}
2005-02-18 23:08:15 +01:00
//stubs for linkage
2006-04-01 06:48:01 +02:00
2009-10-08 16:01:15 +02:00
#define INSTANTIZE_DUMMY(T) \
template<> void NRVec<T>::gemv(const T beta, const NRMat<T> &a, const char trans, const T alpha, const NRVec<T> &x) { laerror("gemv on unsupported types"); } \
template<> void NRVec<T>::gemv(const T beta, const NRSMat<T> &a, const char trans, const T alpha, const NRVec<T> &x) { laerror("gemv on unsupported types"); } \
template<> void NRVec<T>::gemv(const T beta, const SparseMat<T> &a, const char trans, const T alpha, const NRVec<T> &x, bool s) { laerror("gemv on unsupported types"); } \
template<> void NRVec<T>::gemv(const LA_traits_complex<T>::Component_type beta, const LA_traits_complex<T>::NRMat_Noncomplex_type &a, const char trans, const LA_traits_complex<T>::Component_type alpha, const NRVec<T> &x) { laerror("gemv on unsupported types"); } \
2009-11-12 22:01:19 +01:00
template<> void NRVec<T>::gemv(const LA_traits_complex<T>::Component_type beta, const LA_traits_complex<T>::NRSMat_Noncomplex_type &a, const char trans, const LA_traits_complex<T>::Component_type alpha, const NRVec<T> &x) { laerror("gemv on unsupported types"); } \
template<> NRVec<T> & NRVec<T>::normalize() {laerror("normalize() impossible for integer types"); return *this;} \
template<> const NRMat<T> NRVec<T>::otimes(const NRVec<T> &b,const bool conj, const T &scale) const {laerror("otimes presently implemented only for double and complex double"); return NRMat<T> ();}
2006-04-01 06:48:01 +02:00
2004-03-17 06:34:59 +01:00
2005-02-18 23:08:15 +01:00
// gemv calls
2005-11-20 14:46:00 +01:00
template<>
2004-03-17 04:07:21 +01:00
void NRVec<double>::gemv(const double beta, const NRMat<double> &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
2006-09-12 01:07:22 +02:00
copyonwrite();
2004-03-17 04:07:21 +01:00
cblas_dgemv(CblasRowMajor, (trans=='n' ? CblasNoTrans:CblasTrans),
2005-02-18 23:08:15 +01:00
A.nrows(), A.ncols(), alpha, A, A.ncols(), x.v, 1, beta, v, 1);
2004-03-17 04:07:21 +01:00
}
2005-02-18 23:08:15 +01:00
2009-10-08 16:01:15 +02:00
template<>
void NRVec<complex<double> >::gemv(const double beta, const NRMat<double> &A,
const char trans, const double alpha, const NRVec<complex<double> > &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);
}
2005-11-20 14:46:00 +01:00
template<>
2004-03-17 04:07:21 +01:00
void NRVec< complex<double> >::gemv(const complex<double> beta,
const NRMat< complex<double> > &A, const char trans,
const complex<double> alpha, const NRVec &x)
{
#ifdef DEBUG
if ((trans == 'n'?A.ncols():A.nrows()) != x.size())
laerror("incompatible sizes in gemv A*x");
#endif
2006-09-12 01:07:22 +02:00
copyonwrite();
2004-03-17 04:07:21 +01:00
cblas_zgemv(CblasRowMajor, (trans=='n' ? CblasNoTrans:CblasTrans),
2005-02-18 23:08:15 +01:00
A.nrows(), A.ncols(), &alpha, A, A.ncols(),
x.v, 1, &beta, v, 1);
2004-03-17 04:07:21 +01:00
}
2005-02-18 23:08:15 +01:00
2005-11-20 14:46:00 +01:00
template<>
2005-02-18 23:08:15 +01:00
void NRVec<double>::gemv(const double beta, const NRSMat<double> &A,
const char trans, const double alpha, const NRVec &x)
2004-03-17 04:07:21 +01:00
{
#ifdef DEBUG
2005-02-18 23:08:15 +01:00
if (A.ncols()!=x.size()) laerror("incompatible dimension in gemv A*x");
2004-03-17 04:07:21 +01:00
#endif
2006-09-12 01:07:22 +02:00
copyonwrite();
2005-02-18 23:08:15 +01:00
cblas_dspmv(CblasRowMajor, CblasLower, A.ncols(), alpha, A, x.v, 1, beta, v, 1);
2004-03-17 04:07:21 +01:00
}
2005-02-18 23:08:15 +01:00
2009-10-08 16:01:15 +02:00
template<>
void NRVec<complex<double> >::gemv(const double beta, const NRSMat<double> &A,
const char trans, const double alpha, const NRVec<complex<double> > &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);
}
2005-02-18 23:08:15 +01:00
2005-11-20 14:46:00 +01:00
template<>
2005-02-18 23:08:15 +01:00
void NRVec< complex<double> >::gemv(const complex<double> beta,
const NRSMat< complex<double> > &A, const char trans,
const complex<double> alpha, const NRVec &x)
2004-03-17 04:07:21 +01:00
{
#ifdef DEBUG
2005-02-18 23:08:15 +01:00
if (A.ncols()!=x.size()) laerror("incompatible dimension in gemv");
2004-03-17 04:07:21 +01:00
#endif
2006-09-12 01:07:22 +02:00
copyonwrite();
2005-02-18 23:08:15 +01:00
cblas_zhpmv(CblasRowMajor, CblasLower, A.ncols(), &alpha, A,
x.v, 1, &beta, v, 1);
2004-03-17 04:07:21 +01:00
}
2005-02-18 23:08:15 +01:00
2009-11-12 22:01:19 +01:00
// Direct product Mat = Vec | Vec
2005-11-20 14:46:00 +01:00
template<>
2009-11-12 22:01:19 +01:00
const NRMat<double> NRVec<double>::otimes(const NRVec<double> &b,const bool conj, const double &scale) const
2004-03-17 04:07:21 +01:00
{
NRMat<double> result(0.,nn,b.nn);
2009-11-12 22:01:19 +01:00
cblas_dger(CblasRowMajor, nn, b.nn, scale, v, 1, b.v, 1, result, b.nn);
2004-03-17 04:07:21 +01:00
return result;
}
2009-11-12 22:01:19 +01:00
2005-11-20 14:46:00 +01:00
template<>
2004-03-17 04:07:21 +01:00
const NRMat< complex<double> >
2009-11-12 22:01:19 +01:00
NRVec<complex<double> >::otimes(const NRVec< complex<double> > &b, const bool conj, const complex<double> &scale) const
2004-03-17 04:07:21 +01:00
{
NRMat< complex<double> > result(0.,nn,b.nn);
2009-11-12 22:01:19 +01:00
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);
2004-03-17 04:07:21 +01:00
return result;
}
2006-04-01 06:48:01 +02:00
template<typename T>
2006-04-01 16:56:35 +02:00
int NRVec<T>::sort(int direction, int from, int to, int *perm)
2006-04-01 06:48:01 +02:00
{
copyonwrite();
2006-04-01 14:58:57 +02:00
if(to == -1) to=nn-1;
2006-04-01 16:56:35 +02:00
if(direction) return memqsort<1,NRVec<T>,int,int>(*this,perm,from,to);
else return memqsort<0,NRVec<T>,int,int>(*this,perm,from,to);
2006-04-01 06:48:01 +02:00
}
2006-09-10 22:06:44 +02:00
//////////////////////////////////////////////////////////////////////////////
//// forced instantization in the corespoding object file
template class NRVec<double>;
template class NRVec<complex<double> >;
template class NRVec<char>;
template class NRVec<short>;
template class NRVec<int>;
2009-11-12 22:01:19 +01:00
template class NRVec<long>;
template class NRVec<long long>;
template class NRVec<unsigned char>;
template class NRVec<unsigned short>;
2006-09-10 22:06:44 +02:00
template class NRVec<unsigned int>;
template class NRVec<unsigned long>;
2009-11-12 22:01:19 +01:00
template class NRVec<unsigned long long>;
2006-09-10 22:06:44 +02:00
2009-10-08 16:01:15 +02:00
INSTANTIZE_DUMMY(char)
INSTANTIZE_DUMMY(short)
INSTANTIZE_DUMMY(int)
2009-11-12 22:01:19 +01:00
INSTANTIZE_DUMMY(long)
INSTANTIZE_DUMMY(long long)
INSTANTIZE_DUMMY(unsigned char)
INSTANTIZE_DUMMY(unsigned short)
2009-10-08 16:01:15 +02:00
INSTANTIZE_DUMMY(unsigned int)
INSTANTIZE_DUMMY(unsigned long)
2009-11-12 22:01:19 +01:00
INSTANTIZE_DUMMY(unsigned long long)
2009-10-08 16:01:15 +02:00
INSTANTIZE_DUMMY(complex<char>)
INSTANTIZE_DUMMY(complex<short>)
INSTANTIZE_DUMMY(complex<int>)
2009-11-12 22:01:19 +01:00
INSTANTIZE_DUMMY(complex<long>)
INSTANTIZE_DUMMY(complex<long long>)
INSTANTIZE_DUMMY(complex<unsigned char>)
INSTANTIZE_DUMMY(complex<unsigned short>)
2009-10-08 16:01:15 +02:00
INSTANTIZE_DUMMY(complex<unsigned int>)
2009-11-12 22:01:19 +01:00
INSTANTIZE_DUMMY(complex<unsigned long>)
INSTANTIZE_DUMMY(complex<unsigned long long>)
2009-10-08 16:01:15 +02:00
INSTANTIZE_DUMMY(complex<complex<double> >)
INSTANTIZE_DUMMY(complex<complex<float> >)
2009-11-12 22:01:19 +01:00
}//namespace