478 lines
10 KiB
C
478 lines
10 KiB
C
// lasp_math_raw.h
|
|
//
|
|
// Author: J.A. de Jong - ASCEE
|
|
//
|
|
// Description: Raw math routines working on raw arrays of floats and
|
|
// complex numbers.
|
|
//////////////////////////////////////////////////////////////////////
|
|
#pragma once
|
|
#ifndef LASP_MATH_RAW_H
|
|
#define LASP_MATH_RAW_H
|
|
#include "lasp_assert.h"
|
|
#include "lasp_tracer.h"
|
|
#include "lasp_types.h"
|
|
#include <math.h>
|
|
|
|
#if LASP_USE_BLAS == 1
|
|
#include <cblas.h>
|
|
#elif LASP_USE_BLAS == 0
|
|
#else
|
|
#error "LASP_USE_BLAS should be set to either 0 or 1"
|
|
#endif
|
|
|
|
#ifdef LASP_DOUBLE_PRECISION
|
|
#define c_real creal
|
|
#define c_imag cimag
|
|
#define d_abs fabs
|
|
#define c_abs cabs
|
|
#define c_conj conj
|
|
#define d_atan2 atan2
|
|
#define d_acos acos
|
|
#define d_sqrt sqrt
|
|
#define c_exp cexp
|
|
#define d_sin sin
|
|
#define d_cos cos
|
|
#define d_pow pow
|
|
|
|
#else // LASP_DOUBLE_PRECISION not defined
|
|
#define c_conj conjf
|
|
#define c_real crealf
|
|
#define c_imag cimagf
|
|
#define d_abs fabsf
|
|
#define c_abs cabsf
|
|
#define d_atan2 atan2f
|
|
#define d_acos acosf
|
|
#define d_sqrt sqrtf
|
|
#define c_exp cexpf
|
|
#define d_sin sinf
|
|
#define d_cos cosf
|
|
#define d_pow powf
|
|
|
|
#endif // LASP_DOUBLE_PRECISION
|
|
|
|
#ifdef M_PI
|
|
static const d number_pi = M_PI;
|
|
#else
|
|
static const d number_pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679;
|
|
#endif
|
|
|
|
/**
|
|
* Set all elements in an array equal to val
|
|
*
|
|
* @param to
|
|
* @param val
|
|
* @param size
|
|
*/
|
|
static inline void d_set(d to[],d val,us size) {
|
|
for(us i=0;i<size;i++) {
|
|
to[i]=val;
|
|
}
|
|
}
|
|
/**
|
|
* Set all elements in an array equal to val
|
|
*
|
|
* @param to
|
|
* @param val
|
|
* @param size
|
|
*/
|
|
static inline void c_set(c to[],c val,us size) {
|
|
for(us i=0;i<size;i++) {
|
|
to[i]=val;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return the maximum of two doubles
|
|
*
|
|
* @param a value 1
|
|
* @param b value 2
|
|
*
|
|
* @returns the maximum of value 1 and 2
|
|
*/
|
|
static inline d d_max(const d a,const d b) {
|
|
return a>b?a:b;
|
|
}
|
|
|
|
|
|
/**
|
|
* Return the dot product of two arrays, one of them complex-valued,
|
|
* the other real-valued
|
|
*
|
|
* @param a the complex-valued array
|
|
* @param b the real-valued array
|
|
* @param size the size of the arrays. *Should be equal-sized!*
|
|
*
|
|
* @return the dot product
|
|
*/
|
|
static inline c cd_dot(const c a[],const d b[],us size){
|
|
c result = 0;
|
|
us i;
|
|
for(i=0;i<size;i++){
|
|
result+=a[i]*b[i];
|
|
}
|
|
return result;
|
|
}
|
|
/**
|
|
* Return the dot product of two complex-valued arrays. Wraps BLAS
|
|
* when LASP_USE_BLAS == 1.
|
|
*
|
|
* @param a complex-valued array
|
|
* @param b complex-valued array
|
|
* @param size the size of the arrays. *Should be equal-sized!*
|
|
*
|
|
* @return the dot product
|
|
*/
|
|
static inline c cc_dot(const c a[],const c b[],us size){
|
|
#if LASP_USE_BLAS == 1
|
|
WARN("CBlas zdotu not yet tested");
|
|
#if LASP_DOUBLE_PRECISION
|
|
// assert(0);
|
|
return cblas_zdotu(size,(d*) a,1,(d*) b,1);
|
|
#else
|
|
return cblas_cdotu(size,(d*) a,1,(d*) b,1);
|
|
#endif
|
|
#else
|
|
c result = 0;
|
|
us i;
|
|
for(i=0;i<size;i++){
|
|
result+=a[i]*b[i];
|
|
}
|
|
return result;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Compute the dot product of two real arrays.
|
|
*
|
|
* @param a First array.
|
|
* @param b Second array.
|
|
* @param size Size of the arrays.
|
|
* @return The result.
|
|
*/
|
|
static inline d d_dot(const d a[],const d b[],const us size){
|
|
#if LASP_USE_BLAS == 1
|
|
#if LASP_DOUBLE_PRECISION
|
|
return cblas_ddot(size,a,1,b,1);
|
|
#else // Single precision function
|
|
return cblas_sdot(size,a,1,b,1);
|
|
#endif
|
|
#else // No BLAS, do it manually
|
|
d result = 0;
|
|
us i;
|
|
for(i=0;i<size;i++){
|
|
result+=a[i]*b[i];
|
|
}
|
|
return result;
|
|
#endif
|
|
}
|
|
|
|
|
|
/**
|
|
* Copy array of floats.
|
|
*
|
|
* @param to : Array to write to
|
|
* @param from : Array to read from
|
|
* @param size : Size of arrays
|
|
*/
|
|
static inline void d_copy(d to[],const d from[],const us size){
|
|
#if LASP_USE_BLAS == 1
|
|
cblas_dcopy(size,from,1,to,1);
|
|
#else
|
|
us i;
|
|
for(i=0;i<size;i++)
|
|
to[i] = from[i];
|
|
#endif
|
|
}
|
|
|
|
|
|
/**
|
|
* Copy array of floats to array of complex floats. Imaginary part set
|
|
* to zero.
|
|
*
|
|
* @param to : Array to write to
|
|
* @param from : Array to read from
|
|
* @param size : Size of arrays
|
|
*/
|
|
static inline void cd_copy(c to[],const d from[],const us size) {
|
|
us i;
|
|
for(i=0;i<size;i++) {
|
|
to[i] = (c) (from[i]);
|
|
dbgassert(cimag(to[i]) == 0,"Imaginary part not equal to zero");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Copy float vector to complex vector. Imaginary part set
|
|
* to zero.
|
|
*
|
|
* @param to : Vector to write to
|
|
* @param from : Vector to read from
|
|
*/
|
|
static inline void c_copy(c to[],const c from[],const us size){
|
|
|
|
#if LASP_USE_BLAS == 1
|
|
#if LASP_DOUBLE_PRECISION
|
|
cblas_zcopy(size,(d*) from,1,(d*) to,1);
|
|
#else
|
|
cblas_ccopy(size,(d*) from,1,(d*) to,1);
|
|
#endif
|
|
#else
|
|
us i;
|
|
for(i=0;i<size;i++)
|
|
to[i] = from[i];
|
|
#endif
|
|
}
|
|
/**
|
|
* Multiply y with fac, and add result to x
|
|
*
|
|
* @param x[in,out] Array to add to
|
|
* @param y[in] Array to add to x
|
|
* @param[in] fac Factor with which to multiply y
|
|
* @param[in] size Size of the arrays
|
|
*/
|
|
static inline void d_add_to(d x[],const d y[],
|
|
const d fac,const us size){
|
|
#if LASP_USE_BLAS == 1
|
|
#if LASP_DOUBLE_PRECISION
|
|
cblas_daxpy(size,fac,y,1,x,1);
|
|
#else
|
|
cblas_saxpy(size,fac,y,1,x,1);
|
|
#endif
|
|
#else
|
|
us i;
|
|
for(i=0;i<size;i++)
|
|
x[i]+=fac*y[i];
|
|
#endif
|
|
}
|
|
/**
|
|
* x = x + fac*y
|
|
*
|
|
* @param[in,out] x Array to add to
|
|
* @param[in] y Array to add to x
|
|
* @param[in] fac Factor with which to multiply y
|
|
* @param[in] size Size of the arrays
|
|
*/
|
|
static inline void c_add_to(c x[],const c y[],
|
|
const c fac,const us size){
|
|
fsTRACE(15);
|
|
#if LASP_USE_BLAS == 1
|
|
#if LASP_DOUBLE_PRECISION
|
|
cblas_zaxpy(size,(d*) &fac,(d*) y,1,(d*) x,1);
|
|
#else
|
|
cblas_caxpy(size,(d*) &fac,(d*) y,1,(d*) x,1);
|
|
#endif
|
|
#else
|
|
us i;
|
|
for(i=0;i<size;i++)
|
|
x[i]+=fac*y[i];
|
|
#endif
|
|
feTRACE(15);
|
|
}
|
|
|
|
/**
|
|
* Scale an array of doubles
|
|
*
|
|
* @param a array
|
|
* @param scale_fac scale factor
|
|
* @param size size of the array
|
|
*/
|
|
static inline void d_scale(d a[],const d scale_fac,us size){
|
|
#if LASP_USE_BLAS == 1
|
|
#if LASP_DOUBLE_PRECISION
|
|
cblas_dscal(size,scale_fac,a,1);
|
|
#else
|
|
cblas_sscal(size,scale_fac,a,1);
|
|
#endif
|
|
#else
|
|
us i;
|
|
for(i=0;i<size;i++)
|
|
a[i]*=scale_fac;
|
|
#endif
|
|
}
|
|
|
|
|
|
/**
|
|
* Scale an array of complex floats
|
|
*
|
|
* @param a array
|
|
* @param scale_fac scale factor
|
|
* @param size size of the array
|
|
*/
|
|
static inline void c_scale(c a[],const c scale_fac,us size){
|
|
#if LASP_USE_BLAS == 1
|
|
// Complex argument should be given in as array of two double
|
|
// values. The first the real part, the second the imaginary
|
|
// part. Fortunately the (c) type stores the two values in this
|
|
// order. To be portable and absolutely sure anything goes well,
|
|
// we convert it explicitly here.
|
|
|
|
#if LASP_DOUBLE_PRECISION
|
|
cblas_zscal(size,(d*) &scale_fac,(d*) a,1);
|
|
#else
|
|
cblas_cscal(size,(d*) &scale_fac,(d*) a,1);
|
|
#endif
|
|
#else
|
|
us i;
|
|
for(i=0;i<size;i++)
|
|
a[i]*=scale_fac;
|
|
#endif
|
|
}
|
|
|
|
|
|
/**
|
|
* Compute the maximum value of an array
|
|
*
|
|
* @param a array
|
|
* @param size size of the array
|
|
* @return maximum
|
|
*/
|
|
static inline d darray_max(const d a[],us size){
|
|
us i;
|
|
d max = a[0];
|
|
for(i=1;i<size;i++){
|
|
if(a[i] > max) max=a[i];
|
|
}
|
|
return max;
|
|
}
|
|
/**
|
|
* Compute the minimum of an array
|
|
*
|
|
* @param a array
|
|
* @param size size of the array
|
|
* @return minimum
|
|
*/
|
|
static inline d d_min(const d a[],us size){
|
|
us i;
|
|
d min = a[0];
|
|
for(i=1;i<size;i++){
|
|
if(a[i] > min) min=a[i];
|
|
}
|
|
return min;
|
|
}
|
|
|
|
/**
|
|
* Compute the \f$ L_2 \f$ norm of an array of doubles
|
|
*
|
|
* @param a Array
|
|
* @param size Size of array
|
|
*/
|
|
static inline d d_norm(const d a[],us size){
|
|
#if LASP_USE_BLAS == 1
|
|
return cblas_dnrm2(size,a,1);
|
|
#else
|
|
d norm = 0;
|
|
us i;
|
|
for(i=0;i<size;i++){
|
|
norm+=a[i]*a[i];
|
|
}
|
|
norm = d_sqrt(norm);
|
|
return norm;
|
|
#endif
|
|
|
|
}
|
|
|
|
/**
|
|
* Compute the \f$ L_2 \f$ norm of an array of complex floats
|
|
*
|
|
* @param a Array
|
|
* @param size Size of array
|
|
*/
|
|
static inline d c_norm(const c a[],us size){
|
|
#if LASP_USE_BLAS == 1
|
|
return cblas_dznrm2(size,(d*) a,1);
|
|
#else
|
|
d norm = 0;
|
|
us i;
|
|
for(i=0;i<size;i++){
|
|
d absa = c_abs(a[i]);
|
|
norm+=absa*absa;
|
|
}
|
|
norm = d_sqrt(norm);
|
|
return norm;
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Computes the element-wise vector product, or Hadamard product of
|
|
* arr1 and arr2
|
|
*
|
|
* @param res Where the result will be stored
|
|
* @param arr1 Array 1
|
|
* @param vec2 Array 2
|
|
* @param size: Size of the arrays
|
|
*/
|
|
void d_elem_prod_d(d res[],
|
|
const d arr1[],
|
|
const d arr2[],
|
|
const us size);
|
|
|
|
/**
|
|
* Computes the element-wise vector product, or Hadamard product of
|
|
* arr1 and arr2 for complex floats
|
|
*
|
|
* @param res Where the result will be stored
|
|
* @param arr1 Array 1
|
|
* @param vec2 Array 2
|
|
* @param size: Size of the arrays
|
|
*/
|
|
void c_hadamard(c res[],
|
|
const c arr1[],
|
|
const c arr2[],
|
|
const us size);
|
|
|
|
/**
|
|
* Compute the complex conjugate of a complex vector and store the
|
|
* result.
|
|
*
|
|
* @param res Result vector
|
|
* @param in Input vector
|
|
* @param size Size of the vector
|
|
*/
|
|
static inline void carray_conj(c res[],const c in[],const us size) {
|
|
// First set the result vector to zero
|
|
fsTRACE(15);
|
|
c_set(res,0,size);
|
|
#if LASP_USE_BLAS == 1
|
|
#if LASP_DOUBLE_PRECISION
|
|
// Cast as a float, scale all odd elements with minus one to find
|
|
// the complex conjugate.
|
|
cblas_daxpy(size ,1.0,(d*) in,2,(d*) res,2);
|
|
cblas_daxpy(size,-1.0,&((d*) in)[1],2,&((d*) res)[1],2);
|
|
#else
|
|
cblas_faxpy(size ,1,(d*) in,2,(d*) res,2);
|
|
cblas_faxpy(size,-1,&((d*) in)[1],2,&((d*) res)[1],2);
|
|
#endif // LASP_DOUBLE_PRECISION
|
|
#else
|
|
for(us i=0;i<size;i++) {
|
|
res[i] = c_conj(in[i]);
|
|
}
|
|
#endif // LASP_USE_BLAS
|
|
feTRACE(15);
|
|
}
|
|
/**
|
|
* In place complex conjugation
|
|
*
|
|
* @param res Result vector
|
|
* @param size Size of the vector
|
|
*/
|
|
static inline void c_conj_inplace(c res[],us size) {
|
|
#if LASP_USE_BLAS
|
|
#if LASP_DOUBLE_PRECISION
|
|
// Cast as a float, scale all odd elements with minus one to find
|
|
// the complex conjugate.
|
|
cblas_dscal(size,-1,&((d*) res)[1],2);
|
|
#else
|
|
cblas_sscal(size,-1,&((d*) res)[1],2);
|
|
#endif // LASP_DOUBLE_PRECISION
|
|
#else
|
|
for(us i=0;i<size;i++) {
|
|
res[i] = c_conj(res[i]);
|
|
}
|
|
#endif // LASP_USE_BLAS
|
|
}
|
|
|
|
#endif // LASP_MATH_RAW_H
|
|
//////////////////////////////////////////////////////////////////////
|