https://github.com/cran/GAS
Raw File
Tip revision: e588e3a10bf22cb7dff4a49a848baac63d743c3f authored by Leopoldo Catania on 04 February 2022, 09:30:12 UTC
version 0.3.4
Tip revision: e588e3a
sstd.cpp
#include <RcppArmadillo.h>
#include "Utils.h"

using namespace arma;
using namespace Rcpp;
//// These functions are taken principally from the rugarch package of Ghalanos (2016) and have been slightly
//// modified to fit the GAS package

double xdt(const double x, const double nu)
{
  double a, b, pdf;
  a = Rf_gammafn((nu+1.0)/2.0)/sqrt(M_PI*nu);
  b = Rf_gammafn(nu/2.0)*pow((1.0+(x*x)/nu),((nu+1.0)/2.0));
  pdf = a/b;
  return pdf;
}

double dstdstd(const double x, const double nu)
{
  double pdf, s;
  if(nu<=2){
    pdf = 999;
  } else{
    s = sqrt(nu/(nu-2.0));
    pdf = s*xdt(x*s,nu);
  }
  return pdf;
}

double qstd(const double p, const double mu, const double sigma, const double nu)
{
  double s = sqrt(nu/(nu-2.0));
  double q = Rf_qt(p, nu, 1, 0) * sigma/s + mu;
  return( q );
}

double rstd(const double nu)
{
  double ans = 0;
  if(nu > 2.0)
  {
    double s = sqrt(nu/(nu-2));
    ans = Rf_rt(nu) * 1.0 / s;
  }
  return(ans);
}

double pstd(const double q, const double mu, const double sigma, const double nu)
{
  double s = sqrt(nu/(nu-2.0));
  double z = (q-mu)/sigma;
  double p = Rf_pt(z*s, nu, 1, 0);
  return( p );
}

double rsstd(const double xi, const double nu)
{
  double weight, z, rr, m1, mu, sigma, xx, ans;
  ans = 0.0;
  weight = xi / (xi + 1.0/xi);
  z = Rf_runif(-1.0 * weight, 1.0 - weight);
  xx = (z < 0)? 1.0/xi : xi;
  rr = -1.0 * fabs(rstd(nu))/xx * sign_C(z);
  m1 = 2.0 * sqrt(nu - 2.0) / (nu - 1.0) /  Rf_beta(0.5, 0.5 * nu);
  mu = m1 * (xi - 1.0/xi);
  sigma =  sqrt((1.0 - (m1 * m1)) * ((xi * xi) + 1.0/(xi * xi)) + 2 * (m1 * m1) - 1.0);
  ans =  (rr - mu ) / sigma;
  return(ans);
}

double dsstdstd(const double x, const double xi, const double nu)
{
  double mu, m1,beta, sigma, z, g,pdf,a,b, xxi;
  xxi=xi;
  a = 1.0/2.0;
  b = nu/2.0;
  beta = (Rf_gammafn(a)/Rf_gammafn(a+b))*Rf_gammafn(b);
  m1 = 2.0*sqrt(nu-2.0)/(nu-1.0)/beta;
  mu = m1*(xi-1.0/xi);
  sigma = sqrt( (1.0-pow(m1,2))*( pow(xi,2)+1.0/(pow(xi,2)) )+2.0*pow(m1,2)-1.0 );
  z = x*sigma + mu;
  if(z==0){
    xxi=1;
  }
  if(z<0){
    xxi = 1/xi;
  }
  g = 2.0/(xi+1.0/xi);
  pdf = g*dstdstd(z/xxi,nu)*sigma;
  return pdf;
}

double psstd(const double q, const double mu, const double sigma, const double xi, const double nu)
{
  double qx = (q-mu)/sigma;
  double m1 = 2.0 * sqrt(nu-2.0) / (nu-1.0) / Rf_beta(0.5, nu/2.0);
  double mux = m1*(xi-1.0/xi);
  double sig =  sqrt((1-m1*m1)*(xi*xi+1/(xi*xi)) + 2*m1*m1 - 1);
  double z = qx*sig+mux;
  double Xi = (z<0)?1.0/xi:xi;
  double g = 2.0 / (xi + 1.0/xi);
  double p = Heaviside(z, 0) - signum(z) * g * Xi * pstd(-fabs(z)/Xi, 0, 1, nu);
  return( p );
}


double qsstd(const double p, const double xi, const double nu)
{
  double m1 = 2.0 * sqrt(nu-2.0) / (nu-1.0) / Rf_beta(0.5, nu/2.0);
  double mu = m1*(xi-1.0/xi);
  double sigma =  sqrt((1-m1*m1)*(xi*xi+1/(xi*xi)) + 2*m1*m1 - 1);
  double g = 2.0 / (xi + 1.0/xi);
  double z = p-0.5;
  double Xi = (z<0)?1.0/xi:xi;
  double tmp = (Heaviside(z, 0) - signum(z)*p)/(g*Xi);
  double q = (-signum(z)*qstd(tmp, 0, 1, nu)*Xi - mu)/sigma;
  return( q );
}


double sstdskew(double dXi, double dNu){
  // Theoretical moments based on bijection betweeen Fernandez and Steel verions
  // and Hansen's Generalized Skew-T (credit due to Michael Rockinger)
  double m3 = 0.0;
  if (dNu > 2.0) {
    double eta = dNu;
    double k2  = pow(dXi, 2.0);
    double lda = (k2-1.0)/(k2+1.0);
    double ep1 = (eta+1.0)/2.0;
    double lnc = Rf_lgammafn(ep1) - Rf_lgammafn(eta/2.0) -0.5*log( M_PI*(eta-2.0));
    double c   = exp(lnc);
    double a   = 4.0*lda*c*(eta-2.0)/(eta-1.0);
    double b   = pow(1.0+3.0*pow(lda,2.0)-pow(a,2.0), 0.5);
    double my2 = 1.0+3.0*pow(lda,2.0);
    double my3 = 16.0*c*lda*(1.0+pow(lda,2.0))*(  pow(eta-2.0,2.0))/((eta-1.0)*(eta-3.0));
    // double my4 = 3.0*(eta-2.0)*(1.0+10.0*pow(lda,2.0)+5.0*pow(lda,4.0) )/(eta-4.0);
    m3  = (my3-3.0*a*my2+2.0*pow(a,3.0) )/pow(b,3.0);
  } else{
    m3 = NA_REAL;
  }
  return m3;
}


double sstdexkurt( double dXi, double dNu )
{
  // Theoretical moments based on bijection betweeen Fernandez and Steel verions
  // and Hansen's Generalized Skew-T (credit due to Michael Rockinger)
  double m4 = 0.0;
  if(dNu > 4.0){
    double eta  = dNu;
    double k2   = pow(dXi,2.0);
    double lda  = (k2-1.0)/(k2+1.0);
    double ep1 = (eta+1.0)/2.0;
    double lnc = Rf_lgammafn(ep1) - Rf_lgammafn(eta/2.0) -0.5*log( M_PI*(eta-2.0));
    double c   = exp(lnc);
    double a   = 4.0*lda*c*(eta-2.0)/(eta-1.0);
    double b   = pow(1.0+3.0*pow(lda,2.0)-pow(a,2.0),0.5 );
    double my2 = 1.0+3.0*pow(lda,2.0);
    double my3 = 16.0*c*lda*(1.0+pow(lda,2.0) )*(pow(eta-2.0,2.0))/((eta-1.0)*(eta-3.0));
    double my4 = 3.0*(eta-2.0)*(1.0+10.0*pow(lda,2.0)+5.0*pow(lda,4.0) )/(eta-4.0);
    // double m3  = (my3-3.0*a*my2+2.0*pow(a,3.0) )/pow(b,3.0);
    m4  = -3.0 + (my4-4.0*a*my3+6.0*pow(a,2.0)*my2-3.0*pow(a,4.0) )/pow(b,4.0);
  } else{
    m4 = NA_REAL;
  }
  return m4;
}

double dSSTD(double dY, double dMu, double dSigma, double dXi, double dNu, bool bLog = false ){
  double dZ = (dY - dMu)/dSigma;
  double dPDF = dsstdstd(dZ, dXi, dNu)/dSigma;

  if(bLog) dPDF = log(dPDF);

  return dPDF;
}

double pSSTD(double dY, double dMu, double dSigma, double dXi, double dNu){

  double dP = psstd(dY, dMu, dSigma, dXi, dNu);
  return dP;
}

double rSSTD(double dMu, double dSigma, double dXi, double dNu){

  double dY = dMu + rsstd(dXi, dNu)*dSigma;
  return dY;
}

double qSSTD(double dP, double dMu, double dSigma, double dXi, double dNu){

  double dQ = qsstd(dP, dXi, dNu)*dSigma + dMu;

  return dQ;
}

arma::vec mSSTD(double dMu, double dSigma, double dXi, double dNu){
  arma::vec vMoments(4);

  vMoments(0) = dMu;
  vMoments(1) = pow(dSigma, 2.0);
  vMoments(2) = sstdskew( dXi, dNu );
  vMoments(3) = sstdexkurt( dXi, dNu ) + 3.0;

  return vMoments;
}

arma::vec sstd_Score(double dY, arma::vec vTheta){

  double dMu    = vTheta(0);
  double dSigma = vTheta(1);
  double dXi    = vTheta(2);
  double dNu    = vTheta(3);

  // double dMu1 = 2.0*pow(dNu - 2.0, 0.5)/(dNu - 1.0)  * Rf_gammafn(0.5*(dNu + 1.0))/(Rf_gammafn(0.5*dNu)*Rf_gammafn(0.5));

  double dLogMu1 = log(2.0) + 0.5 * log(dNu - 2.0) - log(dNu - 1.0) + Rf_lgammafn(0.5 * (dNu + 1.0)) - Rf_lgammafn(0.5 * dNu) - Rf_lgammafn(0.5);
  double dMu1    = exp(dLogMu1);

  double dMu_tilde = dMu1*(dXi - 1.0/dXi);
  double dSigma_tilde = pow( (1.0 - pow(dMu1, 2.0))*(pow(dXi, 2.0) + pow(dXi, -2.0)) + 2.0*pow(dMu1, 2.0) -1.0, 0.5);
  double dLogSigma_tilde = 0.5 * log((1.0 - pow(dMu1, 2.0))*(pow(dXi, 2.0) + pow(dXi, -2.0)) + 2.0*pow(dMu1, 2.0) -1.0);
  double dZ = (dY - dMu)/dSigma * dSigma_tilde + dMu_tilde;

  double dXi_star  = dXi;
  double ddXi_star2 = 2.0 * dXi;

  if (dZ == 0.0){
    dXi_star = 1.0;
    ddXi_star2 = 0;
  }
  if (dZ < 0.0) {
    dXi_star = 1.0/dXi;
    ddXi_star2 = -2.0/pow(dXi, 3.0);
  }

  double dC = 1.0 + pow(dZ, 2.0)/(pow(dXi_star, 2.0) * (dNu - 2.0));

  double dA = 0.5*Rf_gammafn(0.5*(dNu + 1.0)) * ( pow(dNu - 2.0, -0.5) + pow(dNu - 2.0, 0.5)*Rf_digamma(0.5*(dNu + 1.0)));
  double dB = Rf_gammafn(0.5 * dNu) + (dNu - 1.0)*Rf_digamma(0.5*dNu)*Rf_gammafn(0.5*dNu) * 0.5;
  double ddMu1_nu = (dA*(dNu - 1.0)*Rf_gammafn(0.5*dNu) - dB*pow(dNu-2.0, 0.5)*Rf_gammafn(0.5*(dNu+1.0)))/pow( (dNu - 1.0)*Rf_gammafn(0.5*dNu), 2.0)*2.0/Rf_gammafn(0.5);


  double ddSigma_tilde_nu = (ddMu1_nu*( -(pow(dXi, 2.0) + pow(dXi, -2.0)) + 2.0 )*dMu1)/dSigma_tilde;

  double ddL_nu = ddSigma_tilde_nu*(dY - dMu)/dSigma + (dXi - 1.0/dXi)*ddMu1_nu;

  // score

  double ddMu    = (dNu + 1.0)/dC  * dSigma_tilde/dSigma * dZ/( pow(dXi_star, 2.0)*(dNu - 2.0) );

  // old one
  // double ddSigma = -1.0/dSigma + (dNu + 1.0)/dC * dSigma_tilde/pow(dSigma, 2.0) * dZ*(dY - dMu)/( pow(dXi_star, 2.0)*(dNu - 2.0) );

  double dQ = -1.0/dSigma;

  double dFoo1_W = 2.0 * log(dXi_star) + log(dNu - 2.0);
  double dFoo2_W = 2.0 * log(abs3(dZ));
  double dW = -3.0 * log(dSigma) + 2.0 * dLogSigma_tilde + 2.0 * log(abs3(dY - dMu)) + log(dNu + 1.0) - LogSum(dFoo1_W, dFoo2_W);

  double dFoo_E = dMu_tilde*(dY - dMu);

  double dSgn = 0.0;

  if (dFoo_E < 0) {

    dSgn = -1.0;

  } else {

    dSgn = +1.0;

  }

  double dE = log(dNu + 1.0) + dLogSigma_tilde + log(abs3(dMu_tilde * (dY - dMu))) - 2.0 * log(dSigma) - LogSum(dFoo1_W, dFoo2_W);

  double ddSigma = dQ + exp(dW) + dSgn * exp(dE);


  double ddNu     = ddSigma_tilde_nu/dSigma_tilde + 0.5*(1.0/dNu - 1.0/(dNu-2.0)) + Rf_digamma(0.5*(dNu+1.0))*0.5 -
                    0.5*Rf_digamma(0.5*dNu) - 1.0/(2.0 * dNu) - 0.5*(log(dC) + dZ*(dNu + 1.0)*(2.0*(dNu-2.0)*ddL_nu - dZ)/(dC*pow(dXi_star*(dNu-2.0),2.0)));


  double ddLogSigma_tilde_xi = (1.0 + pow(dMu1, 2.0))*(dXi - pow(dXi, -3.0))/((1.0 + pow(dMu1, 2.0))*(pow(dXi, 2.0) + pow(dXi, -2.0)) + 2.0*pow(dMu1, 2.0) - 1.0 );
  double ddSigma_tilde_xi = ddLogSigma_tilde_xi * dSigma_tilde;

  double ddLogG_xi = -(1.0 - 1.0/pow(dXi, 2.0))/(dXi + 1.0/dXi);

  double dL1 = pow(dZ, 2.0);
  double dL2 = (dNu - 2.0) * pow(dXi_star, 2.0);

  double ddL1 = 2.0 * dZ * ( (dY - dMu)/dSigma *ddSigma_tilde_xi + dMu1*(1.0 + 1.0/pow(dXi, 2.0)) );
  double ddL2 = (dNu - 2.0)*ddXi_star2;

  double ddXi    = ddLogG_xi + ddLogSigma_tilde_xi - 0.5 * (dNu + 1.0) *  1.0 / dC * ( ddL1*dL2 -  dL1* ddL2 )/pow(dL2, 2.0);

  arma::vec vScore(4);

  vScore(0) = ddMu;
  vScore(1) = ddSigma;
  vScore(2) = ddXi;
  vScore(3) = ddNu;

  return vScore;

}

arma::mat sstd_IM(arma::vec vTheta){

  arma::mat mIM = eye(4,4);

  return mIM;

}

back to top