view armadillo-3.900.4/include/armadillo_bits/eop_aux.hpp @ 84:55a047986812 tip

Update library URI so as not to be document-local
author Chris Cannam
date Wed, 22 Apr 2020 14:21:57 +0100
parents 1ec0e2823891
children
line wrap: on
line source
// Copyright (C) 2010-2013 NICTA (www.nicta.com.au)
// Copyright (C) 2010-2013 Conrad Sanderson
// 
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.


//! \addtogroup eop_aux
//! @{



template<typename eT>
struct eop_aux_randu
  {
  arma_inline
  operator eT ()
    {
    // make sure we are internally using at least floats
    typedef typename promote_type<eT,float>::result eTp;
    
    return eT( eTp(std::rand()) * ( eTp(1) / eTp(RAND_MAX) ) );
    }
  
  
  inline
  static
  void
  fill(eT* mem, const uword N)
    {
    uword i,j;
    
    for(i=0, j=1; j < N; i+=2, j+=2)
      {
      const eT tmp_i = eT(eop_aux_randu<eT>());
      const eT tmp_j = eT(eop_aux_randu<eT>());
      
      mem[i] = tmp_i;
      mem[j] = tmp_j;
      }
    
    if(i < N)
      {
      mem[i] = eT(eop_aux_randu<eT>());
      }
    }
  };


  
template<typename T>
struct eop_aux_randu< std::complex<T> >
  {
  arma_inline
  operator std::complex<T> ()
    {
    return std::complex<T>( T(eop_aux_randu<T>()), T(eop_aux_randu<T>()) );
    }
  
  
  inline
  static
  void
  fill(std::complex<T>* mem, const uword N)
    {
    for(uword i=0; i < N; ++i)
      {
      mem[i] = std::complex<T>( eop_aux_randu< std::complex<T> >() );
      }
    }
  };



template<typename eT>
struct eop_aux_randn
  {
  // rudimentary method, based on the central limit theorem:
  // http://en.wikipedia.org/wiki/Central_limit_theorem
  
  // polar form of the Box-Muller transformation:
  // http://en.wikipedia.org/wiki/Box-Muller_transformation
  // http://en.wikipedia.org/wiki/Marsaglia_polar_method
  
  // other methods:
  // http://en.wikipedia.org/wiki/Ziggurat_algorithm
  //
  // Marsaglia and Tsang Ziggurat technique to transform from a uniform to a normal distribution.
  // G. Marsaglia, W.W. Tsang.
  // "Ziggurat method for generating random variables",
  // J. Statistical Software, vol 5, 2000.
  // http://www.jstatsoft.org/v05/i08/
  
  
  // currently using polar form of the Box-Muller transformation
  inline
  operator eT () const
    {
    // make sure we are internally using at least floats
    typedef typename promote_type<eT,float>::result eTp;
    
    eTp tmp1;
    eTp tmp2;
    eTp w;
    
    do
      {
      tmp1 = eTp(2) * eTp(std::rand()) * (eTp(1) / eTp(RAND_MAX)) - eTp(1);
      tmp2 = eTp(2) * eTp(std::rand()) * (eTp(1) / eTp(RAND_MAX)) - eTp(1);
      
      w = tmp1*tmp1 + tmp2*tmp2;
      }
    while ( w >= eTp(1) );
    
    return eT( tmp1 * std::sqrt( (eTp(-2) * std::log(w)) / w) );
    }
  
  
  
  inline
  static
  void
  generate(eT& out1, eT& out2)
    {
    // make sure we are internally using at least floats
    typedef typename promote_type<eT,float>::result eTp;
    
    eTp tmp1;
    eTp tmp2;
    eTp w;
    
    do
      {
      tmp1 = eTp(2) * eTp(std::rand()) * (eTp(1) / eTp(RAND_MAX)) - eTp(1);
      tmp2 = eTp(2) * eTp(std::rand()) * (eTp(1) / eTp(RAND_MAX)) - eTp(1);
      
      w = tmp1*tmp1 + tmp2*tmp2;
      }
    while ( w >= eTp(1) );
    
    const eTp k = std::sqrt( (eTp(-2) * std::log(w)) / w);
    
    out1 = eT(tmp1*k);
    out2 = eT(tmp2*k);
    }
  
  
  
  inline
  static
  void
  fill(eT* mem, const uword N)
    {
    uword i, j;
    
    for(i=0, j=1; j < N; i+=2, j+=2)
      {
      eop_aux_randn<eT>::generate( mem[i], mem[j] );
      }
    
    if(i < N)
      {
      mem[i] = eT(eop_aux_randn<eT>());
      }
    }
  
  };



template<typename T>
struct eop_aux_randn< std::complex<T> >
  {
  inline
  operator std::complex<T> () const
    {
    T a, b;
    
    eop_aux_randn<T>::generate(a, b);
    
    return std::complex<T>(a, b);
    }
  
  
  inline
  static
  void
  fill(std::complex<T>* mem, const uword N)
    {
    for(uword i=0; i < N; ++i)
      {
      mem[i] = std::complex<T>( eop_aux_randn< std::complex<T> >() );
      }
    }
  
  };



//! use of the SFINAE approach to work around compiler limitations
//! http://en.wikipedia.org/wiki/SFINAE

class eop_aux
  {
  public:
  
  template<typename eT> arma_inline static typename arma_integral_only<eT>::result    acos  (const eT x) { return eT( std::acos(double(x)) ); }
  template<typename eT> arma_inline static typename arma_integral_only<eT>::result    asin  (const eT x) { return eT( std::asin(double(x)) ); }
  template<typename eT> arma_inline static typename arma_integral_only<eT>::result    atan  (const eT x) { return eT( std::atan(double(x)) ); }
  
  template<typename eT> arma_inline static typename arma_real_only<eT>::result        acos  (const eT x) { return std::acos(x); }
  template<typename eT> arma_inline static typename arma_real_only<eT>::result        asin  (const eT x) { return std::asin(x); }
  template<typename eT> arma_inline static typename arma_real_only<eT>::result        atan  (const eT x) { return std::atan(x); }
  
  template<typename eT> arma_inline static typename arma_cx_only<eT>::result          acos  (const eT x) { return arma_acos(x); }
  template<typename eT> arma_inline static typename arma_cx_only<eT>::result          asin  (const eT x) { return arma_asin(x); }
  template<typename eT> arma_inline static typename arma_cx_only<eT>::result          atan  (const eT x) { return arma_atan(x); }
  
  template<typename eT> arma_inline static typename arma_integral_only<eT>::result    acosh (const eT x) { return eT( arma_acosh(double(x)) ); }
  template<typename eT> arma_inline static typename arma_integral_only<eT>::result    asinh (const eT x) { return eT( arma_asinh(double(x)) ); }
  template<typename eT> arma_inline static typename arma_integral_only<eT>::result    atanh (const eT x) { return eT( arma_atanh(double(x)) ); }
  
  template<typename eT> arma_inline static typename arma_real_or_cx_only<eT>::result acosh (const eT x) { return arma_acosh(x); }
  template<typename eT> arma_inline static typename arma_real_or_cx_only<eT>::result asinh (const eT x) { return arma_asinh(x); }
  template<typename eT> arma_inline static typename arma_real_or_cx_only<eT>::result atanh (const eT x) { return arma_atanh(x); }
  
  template<typename eT> arma_inline static typename arma_not_cx<eT>::result conj(const eT               x) { return x;            }
  template<typename  T> arma_inline static          std::complex<T>         conj(const std::complex<T>& x) { return std::conj(x); }
  
  template<typename eT> arma_inline static typename arma_integral_only<eT>::result sqrt  (const eT x) { return eT( std::sqrt (double(x)) ); }
  template<typename eT> arma_inline static typename arma_integral_only<eT>::result log10 (const eT x) { return eT( std::log10(double(x)) ); }
  template<typename eT> arma_inline static typename arma_integral_only<eT>::result log   (const eT x) { return eT( std::log  (double(x)) ); }
  template<typename eT> arma_inline static typename arma_integral_only<eT>::result exp   (const eT x) { return eT( std::exp  (double(x)) ); }
  template<typename eT> arma_inline static typename arma_integral_only<eT>::result cos   (const eT x) { return eT( std::cos  (double(x)) ); }
  template<typename eT> arma_inline static typename arma_integral_only<eT>::result sin   (const eT x) { return eT( std::sin  (double(x)) ); }
  template<typename eT> arma_inline static typename arma_integral_only<eT>::result tan   (const eT x) { return eT( std::tan  (double(x)) ); }
  template<typename eT> arma_inline static typename arma_integral_only<eT>::result cosh  (const eT x) { return eT( std::cosh (double(x)) ); }
  template<typename eT> arma_inline static typename arma_integral_only<eT>::result sinh  (const eT x) { return eT( std::sinh (double(x)) ); }
  template<typename eT> arma_inline static typename arma_integral_only<eT>::result tanh  (const eT x) { return eT( std::tanh (double(x)) ); }
  
  template<typename eT> arma_inline static typename arma_real_or_cx_only<eT>::result sqrt  (const eT x) { return std::sqrt (x); }
  template<typename eT> arma_inline static typename arma_real_or_cx_only<eT>::result log10 (const eT x) { return std::log10(x); }
  template<typename eT> arma_inline static typename arma_real_or_cx_only<eT>::result log   (const eT x) { return std::log  (x); }
  template<typename eT> arma_inline static typename arma_real_or_cx_only<eT>::result exp   (const eT x) { return std::exp  (x); }
  template<typename eT> arma_inline static typename arma_real_or_cx_only<eT>::result cos   (const eT x) { return std::cos  (x); }
  template<typename eT> arma_inline static typename arma_real_or_cx_only<eT>::result sin   (const eT x) { return std::sin  (x); }
  template<typename eT> arma_inline static typename arma_real_or_cx_only<eT>::result tan   (const eT x) { return std::tan  (x); }
  template<typename eT> arma_inline static typename arma_real_or_cx_only<eT>::result cosh  (const eT x) { return std::cosh (x); }
  template<typename eT> arma_inline static typename arma_real_or_cx_only<eT>::result sinh  (const eT x) { return std::sinh (x); }
  template<typename eT> arma_inline static typename arma_real_or_cx_only<eT>::result tanh  (const eT x) { return std::tanh (x); }
  
  template<typename eT> arma_inline static typename arma_unsigned_integral_only<eT>::result neg (const eT x) { return  x; }
  template<typename eT> arma_inline static typename arma_signed_only<eT>::result            neg (const eT x) { return -x; }
  
  template<typename eT> arma_inline static typename arma_integral_only<eT>::result floor(const eT  x) { return x;                                                }
  template<typename eT> arma_inline static typename arma_real_only<eT>::result     floor(const eT  x) { return std::floor(x);                                    }
  template<typename eT> arma_inline static typename arma_cx_only<eT>::result       floor(const eT& x) { return eT( std::floor(x.real()), std::floor(x.imag()) ); }
  
  template<typename eT> arma_inline static typename arma_integral_only<eT>::result  ceil(const eT  x) { return x;                                                }
  template<typename eT> arma_inline static typename arma_real_only<eT>::result      ceil(const eT  x) { return std::ceil(x);                                     }
  template<typename eT> arma_inline static typename arma_cx_only<eT>::result        ceil(const eT& x) { return eT( std::ceil(x.real()), std::ceil(x.imag()) );   }
  
  template<typename eT> arma_inline static typename arma_integral_only<eT>::result round(const eT  x) { return x;                                                        }
  template<typename eT> arma_inline static typename arma_real_only<eT>::result     round(const eT  x) { return (x >= eT(0)) ? std::floor(x+0.5) : std::ceil(x-0.5);      }
  template<typename eT> arma_inline static typename arma_cx_only<eT>::result       round(const eT& x) { return eT( eop_aux::round(x.real()), eop_aux::round(x.imag()) ); }
  
  template<typename eT>
  arma_inline
  static
  typename arma_integral_only<eT>::result
  log2 (const eT x)
    {
    return eT( std::log(double(x))/ double(0.69314718055994530942) );
    }
  
  
  template<typename eT>
  arma_inline
  static
  typename arma_real_or_cx_only<eT>::result
  log2 (const eT x)
    {
    typedef typename get_pod_type<eT>::result T;
    return std::log(x) / T(0.69314718055994530942);
    }
  
  
  template<typename eT>
  arma_inline
  static
  typename arma_integral_only<eT>::result
  exp10 (const eT x)
    {
    return eT( std::pow(double(10), double(x)) );
    }
  
  
  template<typename eT>
  arma_inline
  static
  typename
  arma_real_or_cx_only<eT>::result
  exp10 (const eT x)
    {
    typedef typename get_pod_type<eT>::result T;
    return std::pow( T(10), x);
    }
  
  
  template<typename eT>
  arma_inline
  static
  typename arma_integral_only<eT>::result
  exp2 (const eT x)
    {
    return eT( std::pow(double(2), double(x)) );
    }
  
  
  template<typename eT>
  arma_inline
  static
  typename arma_real_or_cx_only<eT>::result
  exp2 (const eT x)
    {
    typedef typename get_pod_type<eT>::result T;
    return std::pow( T(2), x);
    }
  
  
  template<typename T1, typename T2>
  arma_inline
  static
  typename arma_real_or_cx_only<T1>::result
  pow(const T1 base, const T2 exponent)
    {
    return std::pow(base, exponent);
    }
  
  
  
  template<typename T1, typename T2>
  arma_inline
  static
  typename arma_integral_only<T1>::result
  pow(const T1 base, const T2 exponent)
    {
    return T1( std::pow( double(base), double(exponent) ) );
    }
  
  
  
  template<typename eT>
  arma_inline
  static
  typename arma_integral_only<eT>::result
  direct_eps(const eT)
    {
    return eT(0);
    }
  
  
  
  template<typename eT>
  inline
  static
  typename arma_real_only<eT>::result
  direct_eps(const eT x)
    {
    //arma_extra_debug_sigprint();
    
    // acording to IEEE Standard for Floating-Point Arithmetic (IEEE 754)
    // the mantissa length for double is 53 bits = std::numeric_limits<double>::digits
    // the mantissa length for float  is 24 bits = std::numeric_limits<float >::digits
    
    //return std::pow( std::numeric_limits<eT>::radix, (std::floor(std::log10(std::abs(x))/std::log10(std::numeric_limits<eT>::radix))-(std::numeric_limits<eT>::digits-1)) );
    
    const eT radix_eT     = eT(std::numeric_limits<eT>::radix);
    const eT digits_m1_eT = eT(std::numeric_limits<eT>::digits - 1);
    
    // return std::pow( radix_eT, eT(std::floor(std::log10(std::abs(x))/std::log10(radix_eT)) - digits_m1_eT) );
    return eop_aux::pow( radix_eT, eT(std::floor(std::log10(std::abs(x))/std::log10(radix_eT)) - digits_m1_eT) );
    }
  
  
  
  template<typename T>
  inline
  static
  typename arma_real_only<T>::result
  direct_eps(const std::complex<T> x)
    {
    //arma_extra_debug_sigprint();
    
    //return std::pow( std::numeric_limits<T>::radix, (std::floor(std::log10(std::abs(x))/std::log10(std::numeric_limits<T>::radix))-(std::numeric_limits<T>::digits-1)) );
    
    const T radix_T     = T(std::numeric_limits<T>::radix);
    const T digits_m1_T = T(std::numeric_limits<T>::digits - 1);
    
    return std::pow( radix_T, T(std::floor(std::log10(std::abs(x))/std::log10(radix_T)) - digits_m1_T) );
    }
  
  
  
  //! work around a bug in GCC 4.4
  template<typename eT> arma_inline static
  typename arma_unsigned_integral_only<eT>::result arma_abs(const eT x)              { return x;           }
  
  template<typename eT> arma_inline static
  typename arma_signed_integral_only<eT>::result   arma_abs(const eT x)              { return std::abs(x); }
  
  template<typename eT> arma_inline static
  typename arma_real_only<eT>::result              arma_abs(const eT x)              { return std::abs(x); }
  
  template<typename T> arma_inline static
  typename arma_real_only<T>::result               arma_abs(const std::complex<T> x) { return std::abs(x); }
  
  };



//! @}