R/sun.R

Defines functions plot.SUNdistrUv plot.SUNdistrBv plot.SUNdistr sunValues summary.SUNdistr convertCSN2SUNpar convertSN2SUNdistr joinSUNdistr conditionalSUNdistr convolutionSUNdistr affineTransSUNdistr marginalSUNdistr makeSUNdistr sunMardia array2mat vcov.SUNdistr sunVcov mean.SUNdistr sunMean rsun psun dsun tr blockDiag all.numeric

Documented in affineTransSUNdistr blockDiag conditionalSUNdistr convertCSN2SUNpar convertSN2SUNdistr convolutionSUNdistr dsun joinSUNdistr makeSUNdistr marginalSUNdistr mean.SUNdistr plot.SUNdistr psun rsun summary.SUNdistr sunMardia sunMean sunVcov tr vcov.SUNdistr

#  file sn/R/sun.R   
#  This file is a component of the R package 'sn' 
#  copyright (C) 1997-2021 Adelchi Azzalini
# 
#  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 2 or 3 of the License
#  (at your option).
#
#  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.
#
#  A copy of the GNU General Public License is available at
#  http://www.r-project.org/Licenses/
#-------------------------------------------
#
# Some support functions
#
all.numeric <- function(...)
{# check if all elements are numeric
  lst <- list(...)
  n <- length(lst)
  if(n == 0) return(NULL)
  m <- is.numeric(lst[[1]])
  if(n == 1) return(m)
  for(k in 2:n) m <- m & is.numeric(lst[[k]])
  return(m)    
} 

blockDiag <- function(...)
{# create a block-diagonal matrix from a set of matrices 
  lst <- list(...)
  n <- length(lst)
  if(n == 0) return(NULL)
  m <- as.matrix(lst[[1]])
  if(n == 1) return(m)
  for(k in 2:n) {
    mk <- as.matrix(lst[[k]])
    m <- rbind(cbind(m, matrix(0, nrow(m), ncol(mk))), 
             cbind(matrix(0, nrow(mk), ncol(m)), mk))
  }           
  return(m)    
} 

tr <- function(x) 
{# trace of a numeric square matrix
  if(mode(x) != "numeric") stop("not a numeric argument")
  if(is.matrix(x)) {
    if(ncol(x) == nrow(x)) sum(diag(x)) else stop("not a square matrix")} 
  else if(length(x)==1) x else stop("not a square matrix") 
}
#-------------------------------------------

dsun <- function(x, xi, Omega, Delta, tau, Gamma, dp=NULL, log=FALSE, silent=FALSE, ...) 
{# SUN density function  
  if (!(missing(Delta) & missing(Omega)) && !is.null(dp)) 
        stop("You cannot set both component parameters and 'dp'")
    if (!is.null(dp)) {
        if (length(dp) != 5)  stop("wrong length of non-null 'dp'")
        xi <- drop(dp[[1]])
        Omega <- dp[[2]]
        Delta <- dp[[3]]
        tau <-  dp[[4]]
        Gamma <- dp[[5]]
    }
  if(!all.numeric(x, xi, Omega, Delta, tau, Gamma)) stop("non-numeric argument(s)")  
  d <- dim(Omega)[1]
  if(length(xi)!= d | dim(Omega)[2] != d)  stop("mismatch of dimensions")
  omega <- sqrt(diag(Omega))
  Omega.bar <- cov2cor(Omega)
  O.inv <- solve(Omega.bar)  
  m <- length(tau)
  if(m==1  & !silent) 
    warning("When m=1, functions for the SN/ESN distr'n are preferable")
  if(any(dim(Gamma) != c(m,m) | dim(Delta) != c(d,m)))
    stop("mismatch of dimensions")
  x <- if(is.vector(x)) matrix(x, 1, d) else data.matrix(x) 
  n <- nrow(x)
  if(m > 20) 
    {if(silent) return(rep(NA, n)) else stop("m exceeds the admissible size")}
  if (is.vector(xi)) xi <- outer(rep(1, n), as.vector(matrix(xi, 1, d)))
  tz <- t(x-xi)/omega
  D.Oinv <- t(Delta) %*% O.inv
  p1 <- pmnorm(t(tau + D.Oinv %*% tz), rep(0,m), Gamma - D.Oinv %*% Delta, ...)
  p2 <- pmnorm(tau, rep(0,m), Gamma, ...)
  if(n == 1) {
    if(any(c(attr(p1,"status"), attr(p2,"status")) != "normal completion"))
      warning("return status from pmnorm is not 'normal completion'")
    }
  pdfN <- dmnorm(x, xi, Omega, log=log)
  if(log) pdfN + logb(p1) - logb(p2)
  else pdfN * p1/p2
}

psun <- function(x, xi, Omega, Delta, tau, Gamma, dp=NULL, log=FALSE, silent=FALSE, ...) 
{# SUN distribution function    
  if (!(missing(Delta) & missing(Omega)) && !is.null(dp)) 
        stop("You cannot set both component parameters and 'dp'")
    if (!is.null(dp)) {
        if (length(dp) != 5)  stop("wrong length of non-null 'dp'")
        xi <- drop(dp[[1]])
        Omega <- dp[[2]]
        Delta <- dp[[3]]
        tau <-  dp[[4]]
        Gamma <- dp[[5]]
    }
  if(!all.numeric(x, xi, Omega, Delta, tau, Gamma)) stop("non-numeric argument(s)")    
  d <- dim(Omega)[1]
  if(dim(Omega)[2] != d)  stop("mismatch of dimensions")
  omega <- sqrt(diag(Omega))
  Omega.bar <- cov2cor(Omega)
  O.inv <- solve(Omega.bar)  
  m <- length(tau)
  if(m==1 & !silent)
    warning("When m=1, functions for the SN/ESN distribution are preferable")
  if(any(dim(Gamma) != c(m,m) | dim(Delta) != c(d,m)))
    stop("mismatch of dimensions")
  x <- if(is.vector(x)) matrix(x, 1, d) else data.matrix(x) 
  n <- nrow(x)
  if((d+m) > 20) 
    {if(silent) return(rep(NA, n)) else stop("(d+m) exceeds the admissible size")}
  if (is.vector(xi)) xi <- outer(rep(1, n), as.vector(matrix(xi, 1, d)))
  if(ncol(x) != ncol(xi)) stop("mismatch of dimensions")
  tz <- t(x-xi)/omega  
  y <- cbind(t(tz), outer(rep(1, n), tau))
  Omega.starNeg <- rbind(cbind(Omega.bar, -Delta),  cbind(t(-Delta), Gamma))
  p1 <- pmnorm(y, mean=rep(0, m+d), varcov=Omega.starNeg, ...)
  p2 <- pmnorm(tau, rep(0,m), Gamma, ...)
  if(n==1) {
    if(any(c(attr(p1,"status"), attr(p2,"status")) != "normal completion"))
    warning("return status from pmnorm is not 'normal completion'")
    }
  as.numeric(pmin(1, pmax(0, p1/p2)))
}

rsun <- function(n=1, xi, Omega, Delta, tau, Gamma, dp=NULL, silent=FALSE) 
{# SUN random numbers, use (7.4) of SN book  
  if (!(missing(Delta) & missing(Omega)) && !is.null(dp)) 
        stop("You cannot set both component parameters and 'dp'")
    if (!is.null(dp)) {
        if (length(dp) != 5)  stop("wrong length of non-null 'dp'")
        xi <- drop(dp[[1]])
        Omega <- dp[[2]]
        Delta <- dp[[3]]
        tau <-  dp[[4]]
        Gamma <- dp[[5]]
    }
  d <- dim(Omega)[1]
  if(length(xi)!= d | dim(Omega)[2] != d)  stop("mismatch of dimensions")
  omega <- sqrt(diag(Omega))
  Omega.bar <- cov2cor(Omega)
  # O.inv <- solve(Omega.bar)  
  m <- length(tau)
  if(m==1 & !silent) 
    warning("When m=1, functions for the SN/ESN family are preferable")
  if(any(dim(Gamma) != c(m,m) | dim(Delta) != c(d,m)))
    stop("mismatch of dimensions")
  Delta_invGamma <- Delta %*% solve(Gamma)  
  Psi.bar <- Omega.bar - Delta_invGamma %*%  t(Delta)
  u0 <- mnormt::rmnorm(n, rep(0, d), Psi.bar)
  u1 <- mnormt::rmtruncnorm(n, rep(0, m), Gamma, -tau)
  tz <- t(u0) + Delta_invGamma %*% t(u1)
  t(xi + omega * tz)
}  

#-------------------------

sunMean <- function(xi, Omega, Delta, tau, Gamma, dp=NULL, silent=FALSE, ...) 
{# expected value of SUN distribution
  if (!(missing(Delta) & missing(Omega)) && !is.null(dp)) 
        stop("You cannot set both component parameters and 'dp'")
    if (!is.null(dp)) {
        if (length(dp) != 5)  stop("wrong length of non-null 'dp'")
        xi <- drop(dp[[1]])
        Omega <- dp[[2]]
        Delta <- dp[[3]]
        tau <-  dp[[4]]
        Gamma <- dp[[5]]
    }
  if(!all.numeric(xi, Omega, Delta, tau, Gamma)) stop("non-numeric argument(s)")    
  d <- dim(Omega)[1]
  if(length(xi)!= d | dim(Omega)[2] != d)  stop("mismatch of dimensions")
  omega <- sqrt(diag(Omega))
  Omega.bar <- cov2cor(Omega)
  O.inv <- solve(Omega.bar)  
  m <- length(tau)
  if(m==1 & !silent) 
    warning("When m=1, functions for the SN/ESN family are preferable")
  if(any(dim(Gamma) != c(m,m) | dim(Delta) != c(d,m)))
    stop("mismatch of dimensions") 
  if(m > 20) 
    {if(silent) return(NA) else stop("m exceeds the admissible size")}   
  prob <- mnormt::pmnorm(tau, rep(0, m), Gamma, ...)
  if(m > 3  &&  (attr(prob,"status") != "normal completion") & !silent)
    warning("return status from pmnorm is not 'normal completion'")
  deriv <- dnorm(tau)/prob
  if(m>1) for(k in 1:m) {
      Gk <- Gamma[-k,-k, drop=FALSE]
      gk <- Gamma[-k, k, drop=FALSE]
      Ec <- as.vector(gk * tau[k])
      Vc <- Gk - gk %*% t(gk)  
      deriv[k] <- deriv[k] * pmnorm(tau[-k], Ec, Vc, ...)
      }
  as.numeric(xi + omega*as.vector(Delta %*% deriv))
}
mean.SUNdistr <- function(x) sunMean(dp=slot(x, "dp"), silent=TRUE)

sunVcov <- function(xi, Omega, Delta, tau, Gamma, dp=NULL, silent=FALSE, ...) 
{# variance (matrix) of SUN  distribution, using Proposition1 of RAV&AA-2020
  if (!(missing(Delta) & missing(Omega)) && !is.null(dp)) 
        stop("You cannot set both component parameters and 'dp'")
    if (!is.null(dp)) {
        if (length(dp) != 5)  stop("wrong length of non-null 'dp'")
        xi <- drop(dp[[1]])
        Omega <- dp[[2]]
        Delta <- dp[[3]]
        tau <-  dp[[4]]
        Gamma <- dp[[5]]
    }
  if(!all.numeric(xi, Omega, Delta, tau, Gamma)) stop("non-numeric argument(s)")  
  d <- dim(Omega)[1]
  if(length(xi)!= d | dim(Omega)[2] != d)  stop("mismatch of dimensions")
  omega <- sqrt(diag(Omega))
  Omega.bar <- cov2cor(Omega)
  O.inv <- solve(Omega.bar)  
  m <- length(tau)
  if(m > 20) 
    {if(silent) return(NA) else stop("m exceeds the admissible size")}  
  if(m==1 & !silent) 
    warning("When m=1, functions for the SN/ESN family are preferable")
  if(any(dim(Gamma) != c(m,m) | dim(Delta) != c(d,m))) 
    stop("mismatch of dimensions") 
  mom.U <- mnormt::mom.mtruncnorm(2, mean=rep(0,m), Gamma, lower=-tau, ...)
  omega.Delta <- omega * Delta
  Gamma.inv <- solve(Gamma)
  A <- omega.Delta %*% Gamma.inv
  B.BT <- Omega - omega.Delta %*% Gamma.inv %*% t(omega.Delta)
  E.U <- if(m==1) mom.U$cum[1] else mom.U$cum1
  E.U2 <- if(m==1) mom.U$mom[3] else mom.U$order2$m2
  var.U <- if(m==1) mom.U$cum[2] else mom.U$order2$cum2
  return(Omega - A %*% (Gamma- var.U) %*% t(A))
}
vcov.SUNdistr <- function(object) sunVcov(dp=slot(object, "dp"), silent=TRUE)
#-------------------------------------------
# expand array to matrix (which are used by RAV&AA-2020)
array2mat <- function(x, d) 
  if(length(x)==d |  length(dim(x))==2) return(x)   else  
  {
    n <- length(dim(x))
    if(n > 4) stop("length(dim(x))>4 not allowed")
    out <- NULL
    for(k in 1:d) { 
      s1 <- if(n==3) paste("x[, , k]") else paste("x[, , k, 1]")
      m1 <- eval(str2expression(s1))
      out <- rbind(out, m1)
     }
    if(n==4)  for(j in 2:d)  out <- cbind(out, array2mat(x[,,,j], d))
    return(out) 
    }

sunMardia <- function(xi, Omega, Delta, tau, Gamma, dp=NULL, silent=FALSE, ...) 
{# Mardia measures of multivariate skewness and kurtosis for SUN distributions 
  if(!(missing(Delta) & missing(Omega)) && !is.null(dp)) 
     stop("You cannot set both component parameters and 'dp'")
  if(!is.null(dp)) {
    if (length(dp) != 5)  stop("wrong length of non-null 'dp'")
    xi <- drop(dp[[1]])
    Omega <- dp[[2]]
    Delta <- dp[[3]]
    tau <-  dp[[4]]
    Gamma <- dp[[5]]
    }
  if(!all.numeric(xi, Omega, Delta, tau, Gamma)) stop("non-numeric argument(s)")
  d <- length(xi)
  m <- length(tau)  
  compNames <- rownames(Omega)
  HcompNames <- rownames(Gamma)
  if(is.null(compNames)) compNames <- paste("V", 1:d, sep="")
  if(is.null(HcompNames)) HcompNames <- paste("H", 1:m, sep="")
  u <- sunValues(dp=dp, compNames, HcompNames, ...)
  return(u$mardia)
}

makeSUNdistr <- function(dp, name, compNames, HcompNames, drop=TRUE) 
{
  if(!is.list(dp)) stop("dp is not a list")
  if(length(dp) != 5) stop("length(dp) is not 5")
  xi <- dp[[1]] 
  Omega <- dp[[2]]
  Delta <- dp[[3]]
  tau <- dp[[4]]
  Gamma <- dp[[5]]
  if(!all.numeric(xi, Omega, Delta, tau, Gamma)) stop("non-numeric argument(s)")
  d <- length(xi)
  m <- length(tau)
  if(!all(dim(Omega) == c(d,d)))  stop("mismatch of dimensions")
  if(missing(compNames)) { compNames <-
    if(length(names(xi)) == d) names(xi) else
      as.vector(outer("V", as.character(1:d), paste,sep="")) }
  if(!is.matrix(Gamma) | m==1) {
    if(length(c(Gamma))>1) stop("Wrong dp$Gamma")
    if(c(Gamma) != 1) stop("Since m=1,  dp$Gamma must be 1, but it is not") 
    if(drop) {
    delta <- c(Delta)
    if(length(delta) != d) stop("wrong size of Delta")
    if(length(tau) != 1) stop("wrong length(tau)")
    Om.delta <- solve(cov2cor(Omega)) %*% delta
    delta.star.sq <- sum(delta %*% Om.delta)
    if(delta.star.sq >= 1 | delta.star.sq < 0) stop("unfeasible arguments")
    alpha <- as.vector(Om.delta)/sqrt(1 - delta.star.sq)
    if(missing(name)) name <- "Unknown_ESN"
    if(d==1) {
      dp.ESN <- c(xi=xi, omega=sqrt(Omega), alpha=alpha, tau=tau)
      obj <- new("SECdistrUv", dp=dp.ESN, family="ESN", name=name)
      } 
    else {
      dp.ESN <- list(xi=xi, Omega=Omega, alpha=alpha, tau=tau)
      obj <- new("SECdistrMv", dp=dp.ESN, family="ESN", name=name, compNames=compNames)
      }
    return(obj)  
    } } 
  if(any(dim(Gamma) != c(m,m)) | any(dim(Delta) != c(d,m)))
    stop("mismatch of dimensions")
  omega <- sqrt(diag(Omega))
  if(!all(diag(Gamma)==1)) stop("diag(Gamma) are not all 1's")
  big.Omega <- rbind(cbind(Omega, omega*Delta), cbind(t(omega*Delta), Gamma))
  if(max(abs(big.Omega -t(big.Omega))) > .Machine$double.eps)
    stop("(Omega, Delta, Gamma) do not make a symmetric matrix")
  big.Omega <- 0.5*(big.Omega + t(big.Omega))  
  eigenvalues <- eigen(big.Omega, symmetric=TRUE, only.values = TRUE)$values 
  if(any(eigenvalues <= 0)) 
    stop("(Omega, Delta, Gamma) do not make a positive definite matrix") 
  name <- if (!missing(name))  as.character(name)[1]
          else paste("Unnamed-SUN(d=", as.character(d), ",m=", 
                     as.character(m), ")", sep = "")
  names(dp) <- c("xi", "Omega", "Delta", "tau", "Gamma")
  if(missing(compNames)) compNames <-
    as.vector(outer("V", as.character(1:d), paste,sep="")) 
  if(missing(HcompNames)) HcompNames <-
    as.vector(outer("H", as.character(1:m), paste,sep="")) 
  names(xi) <- compNames
  dimnames(Omega) <- list(compNames, compNames)    
  dimnames(Delta) <- list(compNames, HcompNames)     
  names(tau) <- HcompNames
  dimnames(Gamma) <- list(HcompNames, HcompNames)      
  dp0 <- list(xi=xi, Omega=Omega, Delta=Delta, tau=tau, Gamma=Gamma)         
  obj <- new("SUNdistr", dp = dp0, name = name, compNames=compNames, 
             HcompNames=HcompNames)
  if(!is(obj, "SUNdistr") & drop==FALSE) 
    stop("Error. No SUNdistr object created")
  obj
}

marginalSUNdistr <- function(object, comp, name, drop=TRUE) 
{# builds from 'obj' the SUN marginal distribution identified by 'comp' 
  # class.obj <- class(object)
  if(!is(object, "SUNdistr") & !is(object, "SECdistrMv")) stop("object of wrong class")
  if(is(object, "SECdistrMv")) { 
     if(slot(object, "family") == "ESN") {
        message("This object is an ESN distribution, passed on to 'SECdistrMv'")
        return(marginalSECdistr(object, comp, name, drop)) }
        else stop("wrong 'family' type of 'SECdistrMv' object")
        } 
  dp <- slot(object, "dp")
  Omega <- dp[[2]]
  d <- dim(Omega)[1]
  if(!all(comp %in% 1L:d)) stop("some comp values not admissible")
  dp.m <- list(xi=dp[[1]][comp], Omega=Omega[comp, comp, drop=FALSE], 
               Delta=dp[[3]][comp,, drop=FALSE], tau=dp[[4]], Gamma=dp[[5]])
  if(missing(name)) {
    comp.c <- paste(as.character(comp), collapse=",")
    name <- paste(slot(object, "name"), "[", comp.c, "]", sep="")       
    }         
  compNames <- slot(object, "compNames")[comp]
  hnames <- slot(object, "HcompNames")
  obj.m <- makeSUNdistr(dp.m, name, compNames, hnames, drop=drop)         
  # if(class(obj.m) != "SUNdistr") stop("Error. No SUNdistr object created")
  obj.m
}

affineTransSUNdistr <- function(object, a, A, name, compNames, HcompNames, drop=TRUE)
{# distribution of affine transformation X=a+t(A)Y; see SN book, top of p.199 
  if(!is(object, "SUNdistr")) stop("wrong object class")
  dp <- slot(object, "dp")
  d <- length(dp$xi)
  if(!is.matrix(A) || nrow(A) != d) stop("A is not a matrix or wrong nrow(A)")
  h <- ncol(A)
  if(length(a) != h) stop("size mismatch of arguments 'a' and 'A'")
  if(missing(name)) name <- paste(deparse(substitute(a)), " + t(",  
    deparse(substitute(A)), ") %*% (", slot(object, "name"),")", sep="")
  else name <- as.character(name)[1]
  if(missing(compNames)) 
    compNames <- as.vector(outer("V",as.character(1:h), paste,sep=""))
  if(missing(HcompNames)) HcompNames <- slot(object, "HcompNames")
  Omega <- dp$Omega
  omega <- sqrt(diag(Omega))
  OmegaX <- t(A) %*% Omega %*% A
  OmegaX <- (OmegaX + t(OmegaX))/2
  eig <- eigen(OmegaX, symmetric=TRUE, only.values=TRUE)$values
  if(any(eig <= 0)) stop("singular transformation") 
  omegaX <- sqrt(diag(OmegaX))
  DeltaA <- (1/omegaX)*t(A) %*% (omega * dp$Delta)
  dpX <- list(xi=as.vector(a + t(A) %*% matrix(dp$xi, ncol=1)), Omega=OmegaX,
              Delta=DeltaA, tau=dp$tau, Gamma=dp$Gamma)
  obj <- makeSUNdistr(dp=dpX, name, compNames, HcompNames, drop=drop)
  return(obj)
}
# 
convolutionSUNdistr <- function(object1, object2,  name, compNames, HcompNames)
{# convolution of two SUN distributions; see SN book eq.(7.8) on p.199
  if(!is(object1, "SUNdistr") | !is(object2, "SUNdistr")) 
    stop("wrong object class")
  dp1 <- slot(object1, "dp")
  dp2 <- slot(object2, "dp")
  m1 <- length(dp1$tau)
  m2 <- length(dp2$tau)
  if(length(dp1$xi) != length(dp2$xi)) stop("objects with different dimensions")  
  name1 <- slot(object1, "name")
  name2 <- slot(object2, "name")
  if(missing(name)) name <- paste("(", name1, ")+(", name2, ")", sep="")
  if(missing(compNames)) compNames <- 
    as.vector(outer("V", as.character(1:length(dp1$xi)), paste, sep=""))
  Omega1 <- dp1$Omega
  omega1 <- sqrt(diag(Omega1))
  Omega2 <- dp2$Omega
  omega2 <- sqrt(diag(Omega2))
  omega <- sqrt(omega1^2+omega2^2)
  Delta <- cbind((omega1/omega)* dp1$Delta,  (omega2/omega)* dp2$Delta )
  if(missing(compNames)) compNames <-
    as.vector(outer("V", as.character(1:length(dp1$xi)), paste, sep=""))
  if(missing(HcompNames))  HcompNames <- 
    c(paste(name1, slot(object1, "HcompNames"), sep="."), 
      paste(name2, slot(object2, "HcompNames"), sep="."))            
  names(xi) <- compNames
  Omega <- Omega1 + Omega2
  dimnames(Omega) <- list(compNames, compNames)    
  dimnames(Delta) <- list(compNames, HcompNames)   
  tau <- c(dp1$tau, dp2$tau)
  Gamma <- blockDiag(dp1$Gamma, dp2$Gamma)
  names(tau) <- HcompNames
  dimnames(Gamma) <- list(HcompNames, HcompNames)    
  dp <- list(xi=dp1$xi+dp2$xi, Omega=Omega, Delta=Delta, tau=tau, Gamma=Gamma)
  obj <- makeSUNdistr(dp=dp, name, compNames, HcompNames)
  return(obj)
}
#
conditionalSUNdistr <- function(object, comp, values, eventType="=", name, drop=TRUE) 
{# Conditional distribution for the "=" case as given by eq.(7.7) of SN book, and
 # later amendment; the distribution for the ">" case is given by RAV&AA (2020).
  if(!is(object, "SUNdistr")) stop("wrong object class")
  type <- match.arg(eventType, c("=", ">"))
  if(!is.numeric(values)) stop("non-numeric 'values'")
  dp <- slot(object, "dp")
  xi <- dp$xi
  Omega <- dp$Omega
  Delta <- dp$Delta
  tau <- dp$tau
  Gamma <- dp$Gamma
  d <- length(xi)
  m <- length(tau)
  if(!all(comp %in% 1:d)) stop("some 'comp' terms outside range")
  if(length(comp) == d) stop("degenerate conditional distribution")
  if(length(comp) != length(values)) stop("mismatch of comp and values sizes") 
  omega <- sqrt(diag(Omega))
  Omega11 <- Omega[comp, comp, drop=FALSE]
  Omega22 <- Omega[-comp, -comp, drop=FALSE]
  Omega.bar <- cov2cor(Omega)
  if(type == "=") {
    O11.inv <- solve(Omega11)
    tmp1 <- Omega[-comp, comp, drop=FALSE] %*% O11.inv 
    values0 <- matrix(values - xi[comp], ncol=1)
    xi2.1 <- c(xi[-comp] + tmp1 %*% values0)
    O22.1 <- Omega22 - tmp1 %*% Omega[comp, -comp, drop=FALSE]
    tmp2 <- solve(Omega.bar[comp, comp, drop=FALSE])
    Delta1 <- Delta[comp, , drop=FALSE]
    Delta2 <- Delta[-comp, , drop=FALSE]
    tau2.1 <- c(tau + t(Delta1) %*% tmp2 %*% (values0/omega[comp]))
    Delta2.1 <- Delta2 - Omega.bar[-comp,comp] %*% tmp2 %*% Delta1
    Gamma2.1 <- Gamma - t(Delta1) %*% tmp2 %*% Delta1
    s <- sqrt(diag(Gamma2.1))
    sDelta <- Delta2.1 %*% diag(1/s, m, m) 
    stau <- tau2.1/s
    sGamma <- cov2cor(Gamma2.1)
    if(missing(name)) name <- paste(slot(object, "name"), "|comp[",
      paste(comp,collapse=","), "]=(", paste(format(values), collapse=","), 
      ")", sep="")
    names <- slot(object, "compNames")[-comp]  
    dp.c <- list(xi=xi2.1, Omega=O22.1, Delta=sDelta, tau=stau, Gamma=sGamma)
    hnames <- slot(object, "HcompNames")
    obj <- makeSUNdistr(dp=dp.c, name, names, hnames, drop=drop)
    }
  if(type == ">") {
    xi.c <- xi[-comp]
    Delta.c <- cbind(Delta[-comp,, drop=FALSE], Omega.bar[-comp,comp,drop=FALSE])
    tau.c <- c((xi[comp] + (-values))/omega[comp], tau)
    Gamma.c <- rbind(cbind(Omega.bar[comp, comp, drop=FALSE], Delta[comp,,drop=FALSE]), 
                     cbind(t(Delta[comp,, drop=FALSE]), Gamma))
    dp.c <- list(xi=xi.c, Omega=Omega22, Delta=Delta.c, tau=tau.c, Gamma=Gamma.c)
    if(missing(name)) name <- paste(slot(object, "name"), "|comp[",
      paste(comp, collapse=","), "]>(", paste(format(values), collapse=","), 
      ")", sep="")
    names <- slot(object, "compNames")[-comp] 
    hnames <- c(slot(object, "compNames")[comp], slot(object, "HcompNames"))
    obj <- makeSUNdistr(dp=dp.c, name, names, hnames, drop=drop)           
    }
  return(obj)     
}
#
joinSUNdistr <- function(object1, object2, name, compNames, HcompNames) 
{# join two SUN distributions assuming independence
  obj1 <- object1
  obj2 <- object2
  if(!is(obj1, "SUNdistr")) obj1 <- convertSN2SUNdistr(obj1, silent=TRUE)
  if(is.null(obj1)) stop("object1 is neither a SUNdistr object nor adjustable") 
  if(!is(obj2, "SUNdistr")) obj2 <- convertSN2SUNdistr(obj2, silent=TRUE)
  if(is.null(obj2)) stop("object2 is neither a SUNdistr object nor adjustable") 
  dp1 <- slot(obj1, "dp")
  dp2 <- slot(obj2, "dp")
  name1 <- slot(obj1, "name")
  name2 <- slot(obj2, "name")
  if(missing(name)) name <- paste("(",name1, ")x(", name2, ")", sep="")
  if(missing(compNames))  compNames <- 
    c(paste(name1, slot(obj1, "compNames"), sep="."), 
      paste(name2, slot(obj2, "compNames"), sep="."))
  if(missing(HcompNames))  HcompNames <- 
    c(paste(name1, slot(obj1, "HcompNames"), sep="."), 
      paste(name2, slot(obj2, "HcompNames"), sep="."))     
  dp <- list(xi=c(dp1$xi, dp2$xi), Omega=blockDiag(dp1$Omega, dp2$Omega),
            Delta=blockDiag(dp1$Delta, dp2$Delta), tau=c(dp1$tau, dp2$tau),
            Gamma=blockDiag(dp1$Gamma, dp2$Gamma))
  makeSUNdistr(dp, name, compNames, HcompNames)          
}

convertSN2SUNdistr <- function(object, HcompNames="h", silent=FALSE)
{# converts SN/ESN into a SUN distribution 
  # obj.cl <- class(object)
  if(!is(object, "SECdistrUv") & !is(object, "SECdistrMv"))
    if(silent) return(NULL) else stop("wrong class object")
  obj.fm <- slot(object, "family")    
  if(!(obj.fm %in% c("SN", "ESN"))) 
    if(silent) return(NULL) else stop("wrong family of distributions")
  dp <- slot(object, "dp")   
  if(is(object, "SECdistrUv")) {
    xi <- dp[1]
    Omega <- matrix(dp[2]^2, 1, 1)
    alpha <- dp[3]
    Delta <- matrix(alpha/sqrt(1+alpha^2), 1, 1)
    tau <- if(length(dp)>3) dp[4] else 0
    names <- slot(object, "name")
    }
  if(is(object, "SECdistrMv")) {  
    xi <- dp[[1]]
    Omega <- dp[[2]]
    alpha <- dp[[3]]
    etc <- delta.etc(alpha, Omega)
    Delta <- matrix(etc$delta, ncol=1)
    tau <- if(length(dp)>3) dp[[4]] else 0
    names <- slot(object, "compNames")
    }
  dp <- list(xi=xi, Omega=Omega, Delta=Delta, tau=tau, Gamma=matrix(1, 1, 1))
  makeSUNdistr(dp=dp, slot(object, "name"), names, HcompNames[1], drop=FALSE)        
}

convertCSN2SUNpar <- function(mu, Sigma, D, nu, Delta)
{# convert a set of CSN parameters to their SUN equivalents
  if(!all.numeric(mu, Sigma, D, nu, Delta)) stop("non-numeric argument(s)")
  if(any(eigen(Sigma, only.values=TRUE)$values <= 0)) stop("invalid Sigma")
  if(any(eigen(Delta, only.values=TRUE)$values <= 0)) stop("invalid Delta")
  p <- NCOL(Sigma)
  q <- NCOL(Delta)
  if(length(mu) != p) stop("mismatch of dimensions")
  if(length(nu) != q) stop("mismatch of dimensions")
  if(any(dim(D) != c(q, p))) stop("mismatch of dimensions")
  DS <- D %*% Sigma
  M <- rbind(cbind(Sigma, t(DS)),  cbind(DS, Delta + DS %*% t(D)))
  M0 <- cov2cor(M)
  Gamma <- M0[p + (1:q), p + (1:q), drop=FALSE]
  DeltaSUN <- M0[1:p, p+(1:q), drop=FALSE]
  list(xi=mu, Omega=matrix(Sigma, p, p), Delta=DeltaSUN, tau=-nu, Gamma=Gamma)
}

#----------------
summary.SUNdistr <- function(object, ...) 
{# 
  dp <- slot(object, "dp")
  name <- slot(object, "name")
  compNames <- slot(object, "compNames")
  HcompNames <- slot(object, "HcompNames")
  u <- sunValues(dp=dp, compNames, HcompNames, ...)
  new("summary.SUNdistr", dp=dp, name=name, compNames=compNames,
    HcompNames=HcompNames, mean=u$mean, var.cov=u$vcov, gamma1=u$gamma1, 
    cum3=u$cum3,  mardia=u$mardia)
}

sunValues <- function(dp, compNames, HcompNames, silent=FALSE, ...) 
{# Some moments and other characteristics values of a SUN distribution. 
 # Computations are based on Proposition 1 and 2 of RAV&AA-2020
 # This function is *not* exported in NAMESPACE.
  if (length(dp) != 5)  stop("wrong length of non-null 'dp'")
  xi <- drop(dp[[1]])
  Omega <- dp[[2]]
  Delta <- dp[[3]]
  tau <-  dp[[4]]
  Gamma <- dp[[5]]
  if(!all.numeric(xi, Omega, Delta, tau, Gamma)) stop("non-numeric argument(s)")   
  d <- length(xi)
  m <- length(tau)
  if(m > 20) 
    {if(silent) return(NA) else stop("m exceeds the admissible size")}  
  if(missing(compNames)) compNames <- paste("V", 1:d, sep="")
  if(missing(HcompNames)) HcompNames <- paste("H", 1:m, sep="")
  omega <- sqrt(diag(Omega))
  omega.Delta <- omega * Delta
  Gamma.inv <- solve(Gamma)
  A <- omega.Delta %*% Gamma.inv            # A=\Lambda in (17) of RAV&AA-2020
  mom.U <- mnormt::mom.mtruncnorm(4, mean=rep(0,m), Gamma, lower=-tau, ...)
  E.U <- if(m==1) mom.U$cum[1] else mom.U$cum1
  mu1.X <- A %*% E.U                        # see \mu_1(X) in Proposition 1
  Esun <- dp$xi + drop(mu1.X)           
  names(Esun) <- compNames
  # E.U2 <- if(m==1) mom.U$mom[3] else mom.U$order2$m2
  var.U <- if(m==1) mom.U$cum[2] else mom.U$order2$cum2
  Vsun <- Omega - A %*% (Gamma- var.U) %*% t(A)    # see var(X) in Prop.1
  dimnames(Vsun) <- list(compNames, compNames)    
  Sigma <- var.X <- Vsun
  sigma <- sqrt(diag(Sigma))
  Sigma.inv <- solve(Sigma)  
  mu2.X  <- var.X + mu1.X %*% t(mu1.X)
  #---
  # Calcolo cumulanti/momenti centrali del terzo ordine.
  # Partiamo da \mu_3(X) della Proposizione 1 di RAV&AA-2020.
  # Calcoliamo (I_{d^2}+K_d) utilizzando eqn.(4) e (7) a p.57
  # di Magnus & Neudecker (2007, 3^ ed) 
  D <- duplicationMatrix(d)
  Dplus <- solve(t(D) %*% D) %*% t(D)
  twiceD.Dplus_d <-  2*D %*% Dplus
  B.BT <- Omega - omega.Delta %*% Gamma.inv %*% t(omega.Delta)  # \Psi in (17)  
  mu3.U <- if(m==1) mom.U$mom[3+1] else array2mat(mom.U$order3$m3, m) 
  mu3.X <- ( (A %x% A) %*% mu3.U %*% t(A) + twiceD.Dplus_d %*% (mu1.X %x% B.BT)           
            + matrix(B.BT, ncol=1) %*% t(mu1.X) )       
  # Now apply shift \xi=-mu1.X in (A.7) of RAV&AA; first two terms cancel out
  shift <- (-mu1.X)
  cum3 <- (twiceD.Dplus_d %*% (shift %*% t(shift) %x% mu1.X + shift %x% mu2.X) 
           + matrix(mu2.X, ncol=1) %*% t(shift) + mu3.X)   
  cum3 <- array(cum3, dim=c(d,d,d))                # convert matrix into array
  gamma1 <- cum3[cbind(1:d, 1:d, 1:d)]/sigma^3  
  #---
  # Mardia measures of skewness and kurtosis; use Proposition 2 of RAV&AA-2020
  AA <- Gamma.inv %*% t(omega.Delta) %*% Sigma.inv %*% omega.Delta %*% Gamma.inv
  # AA =\tilde\Lambda^T\tilde\Lambda = \Lambda^T\Sigma\inv\Lambda in Prop.2
  vec.mu3 <- if(m==1) mom.U$centr.mom[3] else c(mom.U$order3$cum3)
  gamma1M <- beta1M <- if(m==1) drop(vec.mu3^2 *AA^3) else
                           drop(t(vec.mu3) %*% (AA %x% AA %x% AA) %*% vec.mu3)
  mu4.U <- if(m==1) mom.U$centr.mom[4] else 
   { cum4 <- array2mat(mom.U$order4$cum4, m) # conversione cum4 in matrice
    # Usiamo (2.8)-(2.9) di Kollo & Srivastava (2005, Comms.Stat-TM) per
    # passare da cumulanti a momenti centrali del quarto ordine, con correzione!
    D <- duplicationMatrix(m)
    Dplus <- solve(t(D) %*% D) %*% t(D)
    twiceD.Dplus_m <-  2*D %*% Dplus
    cmom4N <- twiceD.Dplus_m %*% (var.U %x% var.U) + c(var.U) %*% t(c(var.U))  
    cum4 + cmom4N  # matrice dei quarti momenti centrali
    }
  tmp1 <- Gamma.inv %*% t(omega.Delta) %*% Sigma.inv
  tmp2 <- B.BT %*% Sigma.inv
  beta2M <- ( tr((AA %x% AA) %*% mu4.U)  + 2* tr(var.U %*%  AA) * tr(tmp2) 
    + tr(tmp2)^2 + 4 * tr(var.U %*%  tmp1 %*% B.BT %*% t(tmp1))
    + 2 * tr(tmp2 %*% tmp2) )
  mardia <- c(gamma1M=gamma1M, gamma2M=(beta2M-d*(d+2)))
  list(mean=Esun, vcov=Vsun, gamma1=gamma1, cum3=cum3, mardia=mardia)
}  
#----------------
# plotting SUN densities
#      
plot.SUNdistr <- function(x, range, nlevels=8, levels, npt,  main, comp, 
  compLabs, gap = 0.5, ...) 
{# plot density of object of class "SUNdistr" 
  obj <- x
  if(slot(obj, "class") != "SUNdistr") stop("object of wrong class")
  dp <- slot(obj, "dp")
  d <- length(dp$xi)
  if(missing(comp)) comp <- seq(1, d) 
  if(!all(comp %in% seq(1,d))) stop("illegal 'comp' value(s)")
  pd <- length(comp) # actual plotting dimension
  if(missing(npt)) npt <- if(pd==1) 251 else rep(101, pd)
  pobj <- if(pd == d) obj else marginalSUNdistr(obj, comp=comp, drop=FALSE)  
  name.pobj <- slot(obj, "name")
  if(pd < d) name.pobj <- paste(name.pobj,"[", paste(comp, collapse=","), "]", sep="")
  if(missing(main))  { main <- if(pd == 1 | pd == 2) 
      paste("Density function of", name.pobj) else
      paste("Bivariate densities of", name.pobj) 
      }
  compNames <- slot(pobj, "compNames")
  if(missing(compLabs)) compLabs <- compNames    
  if(length(compLabs) != pd) stop("wrong length of 'compLabs' vector")
  if(missing(range)) {
    range <- matrix(NA, 2, pd)
    dp.pobj <- slot(pobj, "dp")
    m <- sunMean(dp=dp.pobj)
    v <- sunVcov(dp=dp.pobj)
    s <- sqrt(diag(v))
    range <- rbind(m -3*s, m + 3*s)
    }
  dots <- list(...)
  nmdots <- names(dots)    
  if(pd == 1)   out <- plot.SUNdistrUv(pobj, range, npt, main, ...)
  if(pd == 2) {
    p <- plot.SUNdistrBv(pobj, range, nlevels, levels, npt, compLabs, main, ...)
    out <- list(object=pobj, plot=p)
    }            
  if(pd > 2) {
    textPanel <- function(x = 0.5, y = 0.5, txt, cex, font) 
      text(x, y, txt, cex = cex, font = font)
    localAxis <- function(side, x, y, xpd, bg, main,  oma, ...) {
      if (side%%2 == 1) Axis(x, side = side, xpd = NA,  ...) else 
      Axis(y, side = side, xpd = NA, ...)
      }
    localPlot <- function(..., oma, font.main, cex.main) plot.SUNdistrBv(...)
    text.diag.panel <- compLabs
    oma <- if ("oma" %in% nmdots) dots$oma else NULL
    if (is.null(oma)) {
      oma <- c(4, 4, 4, 4)
      if (!is.null(main))  oma[3L] <- 6
      }    
    opar <- par(mfrow = c(length(comp), length(comp)), 
                mar = rep(c(gap,gap/2), each=2), oma=oma)
    on.exit(par(opar))
    out <- list(object=pobj)
    count <- 1
    for (i in comp) 
      for (j in comp) {
        count <- count + 1
        if(i == j) {
          plot(1, type="n", xlab="", ylab="", axes=FALSE)
          text(1, 1, text.diag.panel[i], cex=2)
          box()
          out[[count]] <- list()
          names(out)[count] <- paste("diagonal component", compNames[i])
        } else {
        ji <- c(j,i) 
        marg <- marginalSUNdistr(pobj, comp=ji, drop=FALSE) 
        out[[count]] <- localPlot(x=marg, range=range[,ji], nlevels, levels,
             npt=npt[ji], compNames= compNames[ji], compLabs=compLabs[ji],              
             main="", yaxt="n", xaxt="n", ...)   
        names(out)[count] <- paste("plot of components (", j, ",", i, ")")
        if(i==comp[1]) axis(3) ; if(j==length(comp)) axis(4)
        if(j==comp[1]) axis(2) ; if(i==length(comp)) axis(1)    
        box() }
      }
    par(new = FALSE)
    if (!is.null(main)) {
      font.main <- if ("font.main" %in% nmdots) 
         dots$font.main else par("font.main") 
      cex.main <- if ("cex.main" %in% nmdots) 
         dots$cex.main  else par("cex.main") 
      mtext(main, side=3, TRUE, line=5, outer = TRUE, at=NA, cex=cex.main, 
            font=font.main, adj=0.5)
      }}
  invisible(out)
}

plot.SUNdistrBv <- 
  function(x, range, nlevels=8, levels, npt, compLabs, main, ...)
{# plot BiVariate SUN distribution (hence d=2)
  obj <- x
  if(slot(obj, "class") != "SUNdistr") stop("object of wrong class")
  dp <- slot(obj, "dp")
  d <- length(dp[[1]])
  if(d != 2) stop("wrong dimensions, d=2 is required")
  if(missing(npt)) npt <- rep(51, d)
  n1 <- npt[1]
  n2 <- npt[2]
  x1 <- seq(min(range[,1]), max(range[,1]), length=n1)
  x2 <- seq(min(range[,2]), max(range[,2]), length=n2)
  x1.x2 <- cbind(rep(x1, n2), as.vector(matrix(x2, n1, n2, byrow=TRUE)))
  X <- matrix(x1.x2, n1 * n2, 2, byrow = FALSE)
  pdf <- matrix(dsun(X, dp=dp), n1, n2)
  oo <- options()
  options(warn=-1)
  compNames <- slot(obj ,"compNames")
  if(missing(levels)) levels <- pretty(range(pdf, finite=TRUE), nlevels)[-1]
  if(missing(compLabs)) compLabs <- compNames
  contour(x1, x2, pdf, levels=levels, labels=format(levels),
    main=main, xlab=compLabs[1], ylab=compLabs[2], ...)
  options(oo) 
  cL <- contourLines(x1, x2, pdf, levels=levels)
  for(j in 1:length(cL)) cL[[j]]$level <- levels[j]
  return(list(x=x1, y=x2, names=compNames, density=pdf, contourLines=cL))
}    

plot.SUNdistrUv <- function(x, range, npt=251, main, ...)
{# plot density of object "SUNdistr" when d=1
  obj <- x
  if(slot(obj, "class") != "SUNdistr") stop("object of wrong class")
  dp <- slot(obj, "dp")
  if(length(dp[[1]]) != 1) stop("SUN distribution of wrong dimension")
  dots <- list(...)
  nmdots <- names(dots)  
  topline <- if(obj@name == "") "" else	
    paste("Probability density of ", obj@name, "\n", sep="")
  if(missing(main))  main <- paste(topline, "\nunivariate SUN distribution")
  mar <- if ("mar" %in% nmdots) dots$mar else NULL
  if (is.null(mar)) {
    mar <- c(4.5, 4.5, 4, 2)
    if (is.null(main))  mar[3L] <- 2
    }     
  omar <- par()$mar
  on.exit(par(omar))
  par(mar=mar)    
  x <- seq(min(range), max(range), length=npt)
  pdf <- as.vector(dsun(matrix(x, ncol=1), dp=dp))
  xLab <- if("xlab" %in% nmdots) dots$xlab else slot(obj, "name")
  yLab <- if("ylab" %in% nmdots) dots$ylab else "probability density"
  yLim <- if("ylim" %in% nmdots) dots$ylim else c(0, max(pdf))
  plot(x, pdf, type="n", xlab=xLab, ylab=yLab, ylim=yLim)
  lines(x, pdf, ...)
  abline(h=0, lty=2, col="gray50")
  if (!is.null(main)) {
    font.m <- if("font.main" %in% nmdots) dots$font.main else par("font.main") 
    cex.m <- if("cex.main" %in% nmdots) dots$cex.main else par("cex.main") 
    title(main, line=2, cex.main=cex.m, font.main=font.m)
    }    
  invisible(list(object=obj, x=x, density=pdf))
}
#============================ classes and methods ============================

setClass("SUNdistr",
   representation(dp="list", name="character",  compNames="character", 
     HcompNames="character"),
   validity=function(object){     
     dp <- object@dp
     if(length(dp) != 5) return(FALSE)
     if(!all(names(dp) == c("xi", "Omega", "Delta", "tau", "Gamma"))) return(FALSE)
     if(mode(unlist(dp)) != "numeric") return(FALSE)
     if(!is.character(object@name)) return(FALSE)
     if(length(object@name) != 1) return(FALSE)
     if(length(object@compNames) != length(dp[[1]])) return(FALSE)
     if(length(object@HcompNames) != length(dp[[4]])) return(FALSE)
     # numeric checks are assumed to be handled by makeSUNdistr
     TRUE
     }
)

setMethod("show", "SUNdistr",
  function(object){
    if(!is(object, "SUNdistr")) stop("wrong object class")
    if(object@name != "")  
      cat("Probability distribution of variable '", object@name, "'\n", sep="")
    dp <- slot(object, "dp")
    d <- length(dp[[1]])
    m <- length(dp[[4]])
    compNames <- slot(object, "compNames")
    HcompNames <-  slot(object, "HcompNames")
    cat("This is a SUN distribution of dimension d=", d, ", involving m=",
         m, " hidden variables:", sep="")       
    cat("\n\nd-component parameters (xi, Omega):\n")
    out <- rbind(xi=dp$xi, Omega=dp$Omega)
    rownames(out) <- c("xi", paste("Omega[", compNames, ",", sep=""))
    colnames(out) <- compNames
    print(out)
    cat("\nm-component parameters (Delta, tau, Gamma):\n")
    out <- rbind(dp$Delta, dp$tau, dp$Gamma) 
    rownames(out) <- c( paste("Delta[", compNames, ",", sep=""), "tau", 
           paste("Gamma[", HcompNames, ",", sep=""))
    colnames(out) <- HcompNames       
    print(out)       
  }
)

setClass("summary.SUNdistr",
  representation(dp="list", name="character", 
    compNames="character", HcompNames="character",
    mean="vector", var.cov="matrix", gamma1="vector", cum3="array",
    mardia="vector"),
  validity=function(object) {
    dp <- slot(object, "dp")
    if(length(dp) != 5) return(FALSE)
    if(mode(unlist(dp)) != "numeric") return(FALSE)
    d <- length(dp[[1]])
    # m <- length(dp[[4]])
    if(length(slot(object, "mean")) != d) return(FALSE)
    if(any(dim(slot(object, "var.cov")) != c(d,d))) return(FALSE)
    if(length(slot(object, "gamma1")) != d) return(FALSE)
    if(any(dim(slot(object, "cum3")) != c(d,d,d))) return(FALSE)
    if(length(slot(object, "mardia")) != 2) return(FALSE)
    TRUE
  }
)     

setMethod("show", "summary.SUNdistr",
  function(object){
    obj <- object
    dp <- slot(obj, "dp")
    sun <- new("SUNdistr", dp=dp, name=slot(obj, "name"), 
      compNames=slot(obj, "compNames"), HcompNames=slot(obj, "HcompNames"))
    show(sun)
    cat("\nExpected value:\n")
    print(slot(obj, "mean"))
    cat("\nVariance matrix:\n")
    print(slot(obj, "var.cov"))
    cat("\nCoefficients of marginal skewness (gamma1):\n")
    print(slot(obj, "gamma1"))
    cat("\nMardia's measures of multivariate skewness and kurtosis:\n")
    print(slot(obj, "mardia"))
  }
)   

setMethod("plot", signature(x="SUNdistr", y="missing"), plot.SUNdistr)
setMethod("mean", signature(x="SUNdistr"), mean.SUNdistr)
setMethod("vcov", signature(object="SUNdistr"), vcov.SUNdistr)
setMethod("summary", signature(object="SUNdistr"), summary.SUNdistr)

Try the sn package in your browser

Any scripts or data that you put into this service are public.

sn documentation built on April 5, 2023, 5:15 p.m.