Raw File

#  Generator function of class basisfd

basisfd <- function(type, rangeval, nbasis, params, dropind=NULL, 
                  quadvals=NULL, values=vector("list",0))
{
#  BASISFD  generator function of "basisfd" class.
#  Arguments:
#  BASISTYPE ... a string indicating the type of basisobj$  This may be one of
#               "Fourier", "fourier", "Fou", "fou",
#               "Bspline", "bspline", "Bsp", "bsp",
#               "pol", "poly", "polynomial",
#               "mon", "monom", "monomial",
#               "con", "const", "constant"
#               "exp", "exponen", "exponential"
#               "polyg" "polygon", "polygonal"
#  RANGEVAL ... an array of length 2 containing the lower and upper
#               boundaries for (the rangeval of argument values
#  NBASIS   ... the number of basis functions
#  PARAMS   ... If the basis is "fourier", this is a single number indicating
#                 the period.  That is, the basis functions are periodic on
#                 the interval (0,PARAMS) or any translation of it.
#               If the basis is "bspline", the values are interior points at
#                 which the piecewise polynomials join.
#                 Note that the number of basis functions NBASIS is equal
#                 to the order of the Bspline functions plus the number of
#                 interior knots, that is the length of PARAMS.
#               This means that NBASIS must be at least 1 larger than the
#                 length of PARAMS.
#  DROPIND ... A set of indices in 1:NBASIS of basis functions to drop
#                when basis objects are arguments.  Default is NULL  Note
#                that argument NBASIS is reduced by the number of indices,
#                and the derivative matrices in VALUES are also clipped.
#  QUADVALS .. A NQUAD by 2 matrix.  The firs t column contains quadrature
#                points to be used in a fixed point quadrature.  The second
#                contains quadrature weights.  For example, for (Simpson"s
#                rule for (NQUAD = 7, the points are equally spaced and the
#                weights are delta.*[1, 4, 2, 4, 2, 4, 1]/3.  DELTA is the
#                spacing between quadrature points.  The default is NULL.
#  VALUES  ... A list, with entries containing the values of
#                the basis function derivatives starting with 0 and
#                going up to the highest derivative needed.  The values
#                correspond to quadrature points in QUADVALS and it is
#                up to the user to decide whether or not to multiply
#                the derivative values by the square roots of the
#                quadrature weights so as to make numerical integration
#                a simple matrix multiplication.
#                Values are checked against QUADVALS to ensure the correct
#                number of rows, and against NBASIS to ensure the correct
#                number of columns.
#                The default is VALUES{1} = NULL
#  Returns
#  BASISOBJ  ... a basisfd object with slots
#         type
#         rangeval
#         nbasis
#         params
#         dropind
#         quadvals
#         values
#  Slot VALUES contains values of basis functions and derivatives at
#   quadrature points weighted by square root of quadrature weights.
#   These values are only generated as required, and only if slot
#   quadvals is not empty.
#
#  An alternative name for (this function is CREATE_BASIS, but PARAMS argument
#     must be supplied.
#  Specific types of bases may be set up more conveniently using functions
#  CREATE_BSPLINE_BASIS     ...  creates a b-spline basis
#  CREATE_CONSTANT_BASIS    ...  creates a constant basis
#  CREATE_EXPONENTIAL_BASIS ...  creates an exponential basis
#  CREATE_FOURIER_BASIS     ...  creates a fourier basis
#  CREATE_MONOMIAL_BASIS    ...  creates a monomial basis
#  CREATE_POLYGON_BASIS     ...  creates a polygonal basis
#  CREATE_POLYNOMIAL_BASIS  ...  creates a polynomial basis
#  CREATE_POWER_BASIS       ...  creates a monomial basis
#  last modified 2007.09.09 by Spencer Graves
#  Previously modified 8 December 2005

if (nargs()==0) {
    type      <- "bspline"
    rangeval  <- c(0,1)
    nbasis    <- 2
    params    <- NULL
    dropind   <- NULL
    quadvals  <- NULL
    values    <- vector("list",0)

    basisobj  <- list(type=type, rangeval=rangeval, nbasis=nbasis, 
                      params=params, dropind=dropind, quadvals=quadvals, 
                      values=values)
    oldClass(basisobj) <- "basisfd"
    basisobj
}

#  if first argument is a basis object, return

if (class(type)=="basisfd"){
    basisobj <- type
    return(basisobj)
}

#  check basistype

type <- use.proper.basis(type)
if (type=="unknown"){
    stop("'type' unrecognizable.")
}

#  check if QUADVALS is present, and set to default if not

if (missing(quadvals)) quadvals <- NULL
else if(!is.null(quadvals)){
     nquad <- dim(quadvals)[1]
     ncol  <- dim(quadvals)[2]
     if ((nquad == 2) && (ncol > 2)){
         quadvals <- t(quadvals)
         nquad    <- dim(quadvals)[1]
         ncol     <-dim(quadvals)[2]
     }
     if (nquad < 2) stop("Less than two quadrature points are supplied.")
     if (ncol != 2) stop("'quadvals' does not have two columns.")
}

#  check VALUES if present, and set to a single empty cell if not.
if(!missing(values) && !is.null(values)) {
 	 n <- dim(values)[1]
	 k <- dim(values)[2]
    if (n != nquad)   
        stop("Number of rows in 'values' not equal to number of quadrature points.")
    if (k != nbasis)  
        stop("Number of columns in 'values' not equal to number of basis functions.")
}
else values <- NULL

#  check if DROPIND is present, and set to default if not

if(missing(dropind)) dropind<-NULL

#  select the appropriate type and process

if (type=="fourier"){
    paramvec   <- rangeval[2] - rangeval[1]
    period     <- params[1]
    if (period <= 0)  stop("Period must be positive for (a Fourier basis")
    params <- period
    if ((2*floor(nbasis/2)) == nbasis)  nbasis <- nbasis + 1
} else if(type=="bspline"){
    if (!missing(params)){
        nparams  <- length(params)
        if(nparams>0){
          if (params[1] <= rangeval[1])       
            stop("Smallest value in BREAKS not within RANGEVAL")
          if (params[nparams] >= rangeval[2]) 
            stop("Largest value in BREAKS not within RANGEVAL")
        }
    }
} else if(type=="expon") {
    if (length(params) != nbasis) 
        stop("No. of parameters not equal to no. of basis fns for (exponential basisobj$")
} else if(type=="polyg") {
    if (length(params) != nbasis) 
        stop("No. of parameters not equal to no. of basis fns for (polygonal basisobj$")
} else if(type=="power") {
    if (length(params) != nbasis) 
        stop("No. of parameters not equal to no. of basis fns for (power basisobj$")
} else if(type=="const") {
    params <- 0
} else if(type=="monom") {
    if (length(params) != nbasis) 
        stop("No. of parameters not equal to no. of basis fns for (monomial basisobj$")
} else if(type=="polynom") {
    if (length(params) > 1) 
        stop("More than one parameter for (a polynomial basisobj$")
} else stop("Unrecognizable basis")

#  Save call

obj.call <- match.call()

#  S4 definition
# basisobj <- new("basisfd", call=obj.call, type=type, rangeval=rangeval, nbasis=nbasis, 
#                 params=params, dropind=dropind, quadvals=quadvals, values=values)

#  S3 definition

basisobj <- list(call=obj.call, type=type, rangeval=rangeval, nbasis=nbasis, 
                 params=params, dropind=dropind, quadvals=quadvals, values=values)
oldClass(basisobj) <- "basisfd"

basisobj

}

#  --------------------------------------------------------------------------
#                  print for basisfd class
#  --------------------------------------------------------------------------

print.basisfd <- function(x, ...)
{
  basisobj <- x
  cat("\nBasis object:\n")	
  if (!inherits(basisobj, "basisfd"))
    stop("Argument not a functional data object")
  cat(paste("\n  Type:  ", basisobj$type,"\n"))
  cat(paste("\n  Range: ", basisobj$rangeval[1], 
            " to ",        basisobj$rangeval[2],"\n"))
  if (basisobj$type == "const") return
  cat(paste("\n  Number of basis functions: ", 
            basisobj$nbasis,     "\n"))
  if (basisobj$type == "fourier")
    cat(paste("\n  Period: ",basisobj$params,"\n"))
  if (basisobj$type == "bspline") {
    norder <- basisobj$nbasis - length(basisobj$params)
    cat(paste("\n  Order of spline: ", norder, "\n"))
    if (length(basisobj$params) > 0) {
        print("  Interior knots")
        print(basisobj$params)
    } else {
        print("  There are no interior knots.")
    }
  }
  if (basisobj$type == "polyg") {
    print("  Argument values")
    print(basisobj$params)
  }
  if (basisobj$type == "expon") {
    print("  Rate coefficients")
    print(basisobj$params)
  }
  if (basisobj$type == "power") {
    print("  Exponents")
    print(basisobj$params)
  }
  if (length(basisobj$dropind) > 0) {
    print("  Indices of basis functions to be dropped")
    print(basisobj$dropind)
  }
}

#  --------------------------------------------------------------------------
#                  summary for basisfd class
#  --------------------------------------------------------------------------

summary.basisfd <- function(object, ...)
{
  basisobj <- object
  cat("\nBasis object:\n")	
  if (!inherits(basisobj, "basisfd"))
    stop("Argument not a functional data object")
  cat(paste("\n  Type:  ", basisobj$type,"\n"))
  cat(paste("\n  Range: ", basisobj$rangeval[1], 
            " to ",        basisobj$rangeval[2],"\n"))
  if (basisobj$type == "const") return
  cat(paste("\n  Number of basis functions: ", 
            basisobj$nbasis,     "\n"))
  if (basisobj$type == "fourier")
    cat(paste("\n  Period: ",basisobj$params,"\n"))
  if (length(basisobj$dropind) > 0) {
    print(paste(length(basisobj$dropind),
                "indices of basis functions to be dropped"))
  }
}

#  --------------------------------------------------------------------------
#  equality for basisfd class
#  --------------------------------------------------------------------------

"==.basisfd" <- function(basis1, basis2)
{

# EQ assesses whether two bases are equivalent.

#  Last modified 1 January 2007

type1   <- basis1$type
range1  <- basis1$rangeval
nbasis1 <- basis1$nbasis
pars1   <- basis1$params
drop1   <- basis1$dropind

type2   <- basis2$type
range2  <- basis2$rangeval
nbasis2 <- basis2$nbasis
pars2   <- basis2$params
drop2   <- basis2$dropind

basisequal <- TRUE

#  check types

if (!(type1 == type2)) {
    basisequal <- FALSE
    return(basisequal)
}

#  check ranges

if (range1[1] != range2[1] || range1[2] != range2[2]) {
    basisequal <- FALSE
    return(basisequal)
}

#  check numbers of basis functions

if (nbasis1 != nbasis2) {
    basisequal <- FALSE
    return(basisequal)
}

#  check parameter vectors

if (!(all(pars1 == pars2))) {
    basisequal <- FALSE
    return(basisequal)
}

#  check indices of basis function to drop

if (!(all(drop1 == drop2))) {
    basisequal <- FALSE
    return(basisequal)
}

return(basisequal)

}

#  --------------------------------------------------------------------------
#  pointwise multiplication method for basisfd class
#  --------------------------------------------------------------------------

"*.basisfd" <- function (basisobj1, basisobj2)
{
# TIMES for (two basis objects sets up a basis suitable for (
#  expanding the pointwise product of two functional data
#  objects with these respective bases.  
# In the absence of a true product basis system in this code,
#  the rules followed are inevitably a compromise:
#  (1) if both bases are B-splines, the norder is the sum of the
#      two orders - 1, and the breaks are the union of the
#      two knot sequences, each knot multiplicity being the maximum
#      of the multiplicities of the value in the two break sequences.
#      That is, no knot in the product knot sequence will have a
#      multiplicity greater than the multiplicities of this value
#      in the two knot sequences.  
#      The rationale this rule is that order of differentiability
#      of the product at eachy value will be controlled  by
#      whichever knot sequence has the greater multiplicity.  
#      In the case where one of the splines is order 1, or a step
#      function, the problem is dealt with by replacing the
#      original knot values by multiple values at that location
#      to give a discontinuous derivative.
#  (2) if both bases are Fourier bases, AND the periods are the 
#      the same, the product is a Fourier basis with number of
#      basis functions the sum of the two numbers of basis fns.
#  (3) if only one of the bases is B-spline, the product basis
#      is B-spline with the same knot sequence and order two
#      higher.
#  (4) in all other cases, the product is a B-spline basis with
#      number of basis functions equal to the sum of the two
#      numbers of bases and equally spaced knots.  
 
#  Of course the ranges must also match.
 
#  Last modified 22 March 2007
 
#  check the ranges
 
range1 <- basisobj1$rangeval
range2 <- basisobj2$rangeval
if (range1[1] != range2[1] || range1[2] != range2[2])
    stop("Ranges are not equal.")
 
#  get the types
 
type1 <- basisobj1$type
type2 <- basisobj2$type
 
#  deal with constant bases
 
if (type1 == "const" && type2 == "const") {
    prodbasisobj <- create.constant.basis(range1)
    return(prodbasisobj)
}
 
if (type1 == "const") {
    prodbasisobj <- basisobj2
    return(prodbasisobj)
}
 
if (type2 == "const") {
    prodbasisobj <- basisobj1
    return(prodbasisobj)
}
 
#  get the numbers of basis functions
 
nbasis1 <- basisobj1$nbasis
nbasis2 <- basisobj2$nbasis
 
#  work through the cases
 
if (type1 == "bspline" && type2 == "bspline") {
    #  both are bases B-splines
    #  get orders
    interiorknots1 <- basisobj1$params
    interiorknots2 <- basisobj2$params
    uniqueknots    <- union(interiorknots1, interiorknots2)
    nunique <- length(uniqueknots)
    multunique <- rep(0,nunique)
    for (i in seq(length=nunique)) {
      mult1 <- {
        if(length(interiorknots1)>0)
          length(interiorknots1[interiorknots1==uniqueknots[i]])
        else 0
      }
      mult2 <- {
        if(length(interiorknots2)>0) 
          length(interiorknots2[interiorknots2==uniqueknots[i]])
        else 0
      }
      multunique[i] <- max(mult1,mult2)
    }
#        
    allknots <- rep(0,sum(multunique))
    m2 <- 0
    for (i in seq(length=nunique)) {
        m1 <- m2 + 1
        m2 <- m2 + multunique[i]
        allknots[m1:m2] <- uniqueknots[i]
    }
    norder1 <- nbasis1 - length(interiorknots1)
    norder2 <- nbasis2 - length(interiorknots2)
    norder  <- norder1 + norder2 - 1
    allbreaks  <- c(range1[1], allknots, range1[2])
    nbasis <- length(allbreaks) + norder - 2
    prodbasisobj <- 
        create.bspline.basis(range1, nbasis, norder, allbreaks)
    return(prodbasisobj)
}
#  end if(type1 & type2 == 'bspline') 
 
if (type1 == "fourier" && type2 == "fourier") {
    #  both bases Fourier
    #  check whether periods match
    #  if they do not, default to the basis below.
    period1 <- basisobj1$params
    period2 <- basisobj2$params
    nbasis  <- nbasis1 + nbasis2
    if (period1 == period2) {
        prodbasisobj <- create.fourier.basis(range1, nbasis, period1)
        return(prodbasisobj)
    }
}
 
#  default case when all else fails: the product basis is B-spline 
#  When neither basis is a B-spline basis, the order
#  is the sum of numbers of bases, but no more than 8.
#  When one of the bases if B-spline and the other isn"t,
#  the order is the smaller of 8 or the order of the spline
#  plus 2.
 
if (type1 == "bspline" || type2 == "bspline") {
    norder <- 8
    if (type1 == "bspline") {
        interiorknots1 <- basisobj1$params
        norder1        <- nbasis1 - length(interiorknots1)
        norder         <- min(c(norder1+2, norder))
    }
    if (type2 == "bspline") {
        interiorknots2 <- basisobj2$params
        norder2        <- nbasis2 - length(interiorknots2)
        norder         <- min(c(norder2+2, norder))
    }
} else {
    #  neither basis is B-spline
    norder <- min(c(8, nbasis1+nbasis2))
}
#  set up the default B-spline product basis
nbasis <- max(c(nbasis1+nbasis2, norder+1))
prodbasisobj <- create.bspline.basis(range1, nbasis, norder)
return(prodbasisobj)
}
back to top