# nint_transform: Transform Integral In docopulae: Optimal Designs for Copula Models

## Description

`nint_transform` applies monotonic transformations to an integrand and a space or list structure of spaces. Common use cases include the probability integral transform, the transformation of infinite limits to finite ones and function dimensions to interval dimensions.

## Usage

 `1` ```nint_transform(f, space, trans, funcDimToF = 0, zeroInf = 0) ```

## Arguments

 `f` `function(x, ...)`, an integrand. `space` a space or list structure of spaces. `trans` a list of named lists, each containing `dIdcs`, `g` and `giDgi` or `giDg`, where `dIdcs` is an integer vector of indices, the dimensions to transform `g=function(x[dIdcs])` mapping `x[dIdcs]` to `y` `giDgi=function(y)` returning a list of two, the inverse `gi(y) = x[dIdcs]` and the first derivatives of `gi(y)` with respect to `y` or `giDg=function(y)` returning the inverse and the first derivatives of `g(x[dIdcs])` with respect to `x[dIdcs]`. `funcDimToF` an integer vector of indices, the dimensions to look for function dimensions to transform to interval dimensions. `0` indicates all dimensions. `zeroInf` a single value, used when `f` returns `0` and the Jacobian is infinite.

## Details

Interval dimensions and function dimensions returning interval dimensions only.

If a transformation is vector valued, that is `y = c(y1, ..., yn) = g(c(x1, ..., xn))`, then each component of `y` shall exclusively depend on the corresponding component of `x`. So `y[i] = g[i](x[i])` for an implicit function `g[i]`.

The transformation of function dimensions to interval dimensions is performed after the transformations defined by `trans`. Consecutive linear transformations, `g(x[dIdx]) = (x[dIdx] - d(x)[1])/(d(x)[2] - d(x)[1])` where `d` is the function dimension at dimension `dIdx`, are used. Deciding against this transformation probably leads to considerable loss in computational performance.

## Value

`nint_transform` returns either a named list containing the transformed integrand and space, or a list of such.

`nint_integrate`, `nint_space`, `nint_tanTransform`, `fisherI`
 ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119``` ```library(mvtnorm) library(SparseGrid) dfltNCube = nint_integrateNCube ## 1D, normal pdf mu = 137 sigma = mu/6 f = function(x) dnorm(x, mean=mu, sd=sigma) space = nint_space(nint_intvDim(-Inf, Inf)) tt = nint_transform(f, space, list(nint_tanTransform(mu + 3, sigma*1.01, dIdcs=1))) tt\$space ff = Vectorize(tt\$f); curve(ff(x), tt\$space[[1]][1], tt\$space[[1]][2]) nint_integrate(tt\$f, tt\$space) # returns 1 ## 2D, normal pdf ## prepare for SparseGrid ncube = function(dimension) SparseGrid::createIntegrationGrid('GQU', dimension, 7) # rather sparse! ncube = nint_integrateNCube_SparseGrid(ncube) unlockBinding('nint_integrateNCube', environment(nint_integrate)) assign('nint_integrateNCube', ncube, envir=environment(nint_integrate)) mu = c(1, 2) sigma = matrix(c(1, 0.7, 0.7, 2), nrow=2) f = function(x) { if (all(is.infinite(x))) # dmvnorm returns NaN in this case return(0) return(dmvnorm(x, mean=mu, sigma=sigma)) } # plot f x1 = seq(-1, 3, length.out=51); x2 = seq(-1, 5, length.out=51) y = outer(x1, x2, function(x1, x2) apply(cbind(x1, x2), 1, f)) contour(x1, x2, y, xlab='x[1]', ylab='x[2]', main='f') space = nint_space(nint_intvDim(-Inf, Inf), nint_intvDim(-Inf, Inf)) tt = nint_transform(f, space, list(nint_tanTransform(mu, diag(sigma), dIdcs=1:2))) tt\$space # plot tt\$f x1 = seq(tt\$space[[1]][1], tt\$space[[1]][2], length.out=51) x2 = seq(tt\$space[[2]][1], tt\$space[[2]][2], length.out=51) y = outer(x1, x2, function(x1, x2) apply(cbind(x1, x2), 1, tt\$f)) contour(x1, x2, y, xlab='x[1]', ylab='x[2]', main='tt\$f') nint_integrate(tt\$f, tt\$space) # doesn't return 1 # tan transform is inaccurate here # probability integral transform dsigma = diag(sigma) t1 = list(g=function(x) pnorm(x, mean=mu, sd=dsigma), giDg=function(y) { x = qnorm(y, mean=mu, sd=dsigma) list(x, dnorm(x, mean=mu, sd=dsigma)) }, dIdcs=1:2) tt = nint_transform(f, space, list(t1)) # plot tt\$f x1 = seq(tt\$space[[1]][1], tt\$space[[1]][2], length.out=51) x2 = seq(tt\$space[[2]][1], tt\$space[[2]][2], length.out=51) y = outer(x1, x2, function(x1, x2) apply(cbind(x1, x2), 1, tt\$f)) contour(x1, x2, y, xlab='x[1]', ylab='x[2]', main='tt\$f') nint_integrate(tt\$f, tt\$space) # returns almost 1 ## 2D, half sphere f = function(x) sqrt(1 - x[1]^2 - x[2]^2) space = nint_space(nint_intvDim(-1, 1), nint_funcDim(function(x) nint_intvDim(c(-1, 1)*sqrt(1 - x[1]^2)))) # plot f x = seq(-1, 1, length.out=51) y = outer(x, x, function(x1, x2) apply(cbind(x1, x2), 1, f)) persp(x, x, y, theta=45, phi=45, xlab='x[1]', ylab='x[2]', zlab='f') tt = nint_transform(f, space, list()) tt\$space # plot tt\$f x1 = seq(tt\$space[[1]][1], tt\$space[[1]][2], length.out=51) x2 = seq(tt\$space[[2]][1], tt\$space[[2]][2], length.out=51) y = outer(x1, x2, function(x1, x2) apply(cbind(x1, x2), 1, tt\$f)) persp(x1, x2, y, theta=45, phi=45, xlab='x[1]', ylab='x[2]', zlab='tt\$f') nint_integrate(tt\$f, tt\$space) # returns almost 4/3*pi / 2 ## 2D, constrained normal pdf f = function(x) prod(dnorm(x, 0, 1)) space = nint_space(nint_intvDim(-Inf, Inf), nint_funcDim(function(x) nint_intvDim(-Inf, x[1]^2))) tt = nint_transform(f, space, list(nint_tanTransform(0, 1, dIdcs=1:2))) # plot tt\$f x1 = seq(tt\$space[[1]][1], tt\$space[[1]][2], length.out=51) x2 = seq(tt\$space[[2]][1], tt\$space[[2]][2], length.out=51) y = outer(x1, x2, function(x1, x2) apply(cbind(x1, x2), 1, tt\$f)) persp(x1, x2, y, theta=45, phi=45, xlab='x[1]', ylab='x[2]', zlab='tt\$f') nint_integrate(tt\$f, tt\$space) # Mathematica returns 0.716315 assign('nint_integrateNCube', dfltNCube, envir=environment(nint_integrate)) ```