Kernels
UML Overview
AbstractKernel
Bases: object
Source code in qmcpy/kernel/abstract_kernel.py
__call__
Evaluate the kernel with (optional) partial derivatives
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x0
|
Union[ndarray, Tensor]
|
Shape |
required |
x1
|
Union[ndarray, Tensor]
|
Shape |
required |
beta0
|
Union[ndarray, Tensor]
|
Shape |
None
|
beta1
|
Union[ndarray, Tensor]
|
Shape |
None
|
c
|
Union[ndarray, Tensor]
|
Shape |
None
|
kwargs
|
dict
|
keyword arguments to parsed call |
{}
|
Returns:
k (Union[np.ndarray, torch.Tensor]): Shape y.shape=(x0+x1).shape[:-1] kernel evaluations.
Source code in qmcpy/kernel/abstract_kernel.py
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 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 | |
single_integral_01d
Evaluate the integral of the kernel over the unit cube
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
Union[ndarray, Tensor]
|
Shape |
required |
Returns:
| Name | Type | Description |
|---|---|---|
tildek |
Union[ndarray, Tensor]
|
Shape |
Source code in qmcpy/kernel/abstract_kernel.py
double_integral_01d
Evaluate the integral of the kernel over the unit cube
Returns:
| Name | Type | Description |
|---|---|---|
tildek |
Union[ndarray, Tensor]
|
Double integral kernel evaluations. |
Source code in qmcpy/kernel/abstract_kernel.py
AbstractKernelScaleLengthscales
Bases: AbstractKernel
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
d
|
int
|
Dimension. |
required |
scale
|
Union[ndarray, Tensor]
|
Scaling factor \(S\). |
1.0
|
lengthscales
|
Union[ndarray, Tensor]
|
Lengthscales \(\boldsymbol{\gamma}\). |
1.0
|
shape_scale
|
list
|
Shape of |
[1]
|
shape_lengthscales
|
list
|
Shape of |
None
|
tfs_scale
|
Tuple[callable, callable]
|
The first argument transforms to the raw value to be optimized; the second applies the inverse transform. |
(tf_exp_eps_inv, tf_exp_eps)
|
tfs_lengthscales
|
Tuple[callable, callable]
|
The first argument transforms to the raw value to be optimized; the second applies the inverse transform. |
(tf_exp_eps_inv, tf_exp_eps)
|
torchify
|
bool
|
If |
False
|
requires_grad_scale
|
bool
|
If |
True
|
requires_grad_lengthscales
|
bool
|
If |
True
|
device
|
device
|
If |
'cpu'
|
compile_call
|
bool
|
If |
False
|
comiple_call_kwargs
|
dict
|
When |
{}
|
Source code in qmcpy/kernel/abstract_kernel.py
KernelShiftInvar
Bases: AbstractSIDSIKernel
Shift invariant kernel with smoothness \(\boldsymbol{\alpha}\), product weights (lengthscales) \(\boldsymbol{\gamma}\), and scale \(S\):
where \(B_n\) is the \(n^\text{th}\) Bernoulli polynomial.
Examples:
>>> from qmcpy import Lattice, fftbr, ifftbr
>>> n = 8
>>> d = 4
>>> lat = Lattice(d,seed=11)
>>> x = lat(n)
>>> x.shape
(8, 4)
>>> x.dtype
dtype('float64')
>>> kernel = KernelShiftInvar(
... d = d,
... alpha = list(range(1,d+1)),
... scale = 10,
... lengthscales = [1/j**2 for j in range(1,d+1)])
>>> k00 = kernel(x[0],x[0])
>>> k00.item()
91.23444453396341
>>> k0 = kernel(x,x[0])
>>> with np.printoptions(precision=2):
... print(k0)
[91.23 -2.32 5.69 5.69 12.7 -4.78 -4.78 12.7 ]
>>> assert k0[0]==k00
>>> kmat = kernel(x[:,None,:],x[None,:,:])
>>> with np.printoptions(precision=2):
... print(kmat)
[[91.23 -2.32 5.69 5.69 12.7 -4.78 -4.78 12.7 ]
[-2.32 91.23 5.69 5.69 -4.78 12.7 12.7 -4.78]
[ 5.69 5.69 91.23 -2.32 12.7 -4.78 12.7 -4.78]
[ 5.69 5.69 -2.32 91.23 -4.78 12.7 -4.78 12.7 ]
[12.7 -4.78 12.7 -4.78 91.23 -2.32 5.69 5.69]
[-4.78 12.7 -4.78 12.7 -2.32 91.23 5.69 5.69]
[-4.78 12.7 12.7 -4.78 5.69 5.69 91.23 -2.32]
[12.7 -4.78 -4.78 12.7 5.69 5.69 -2.32 91.23]]
>>> assert (kmat[:,0]==k0).all()
>>> lam = np.sqrt(n)*fftbr(k0)
>>> y = np.random.Generator(np.random.PCG64(7)).uniform(low=0,high=1,size=(n))
>>> np.allclose(ifftbr(fftbr(y)*lam),kmat@y)
True
>>> np.allclose(ifftbr(fftbr(y)/lam),np.linalg.solve(kmat,y))
True
>>> import torch
>>> xtorch = torch.from_numpy(x)
>>> kernel_torch = KernelShiftInvar(
... d = d,
... alpha = list(range(1,d+1)),
... scale = 10,
... lengthscales = [1/j**2 for j in range(1,d+1)],
... torchify = True)
>>> kmat_torch = kernel_torch(xtorch[:,None,:],xtorch[None,:,:])
>>> np.allclose(kmat_torch.detach().numpy(),kmat)
True
>>> kernel.single_integral_01d(x)
array([10., 10., 10., 10., 10., 10., 10., 10.])
>>> kernel_torch.single_integral_01d(xtorch)
tensor([10., 10., 10., 10., 10., 10., 10., 10.], dtype=torch.float64,
grad_fn=<AddBackward0>)
Batch Params
>>> rng = np.random.Generator(np.random.PCG64(7))
>>> kernel = KernelShiftInvar(
... d = 2,
... shape_scale = [4,3,1],
... shape_lengthscales = [3,2])
>>> x = rng.uniform(low=0,high=1,size=(6,5,2))
>>> kernel(x,x).shape
(4, 3, 6, 5)
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
(4, 3, 6, 5, 5)
>>> kfast = kernel(x[:,None,:,None,:],x[None,:,None,:,:])
>>> kfast.shape
(4, 3, 6, 6, 5, 5)
>>> kstable = kernel(x[:,None,:,None,:],x[None,:,None,:,:],stable=True)
>>> np.abs(kfast-kstable).max()
np.float64(4.440892098500626e-16)
Derivatives
>>> rng = np.random.Generator(np.random.PCG64(7))
>>> scale = rng.uniform(low=0,high=1,size=(1,))
>>> lengthscales = rng.uniform(low=0,high=1,size=(3,))
>>> kernel = KernelShiftInvar(
... d = 3,
... alpha = 3,
... torchify = True,
... scale = torch.from_numpy(scale),
... lengthscales = torch.from_numpy(lengthscales))
>>> x0 = torch.from_numpy(rng.uniform(low=0,high=1,size=(4,))).requires_grad_(True)
>>> x1 = torch.from_numpy(rng.uniform(low=0,high=1,size=(4,))).requires_grad_(True)
>>> x2 = torch.from_numpy(rng.uniform(low=0,high=1,size=(4,))).requires_grad_(True)
>>> x = torch.stack([x0,x1,x2],axis=-1)
>>> z0 = torch.from_numpy(rng.uniform(low=0,high=1,size=(4,))).requires_grad_(True)
>>> z1 = torch.from_numpy(rng.uniform(low=0,high=1,size=(4,))).requires_grad_(True)
>>> z2 = torch.from_numpy(rng.uniform(low=0,high=1,size=(4,))).requires_grad_(True)
>>> z = torch.stack([z0,z1,z2],axis=-1)
>>> c = torch.from_numpy(rng.uniform(low=0,high=1,size=(2,)))
>>> beta0 = torch.tensor([
... [1,0,0],
... [0,2,0]])
>>> beta1 = torch.tensor([
... [0,0,2],
... [2,1,0]])
>>> with torch.no_grad():
... y = kernel(x,z,beta0,beta1,c)
>>> with np.printoptions(formatter={"float": lambda x: "%.2f"%x}):
... y.numpy()
array([1455.14, 9475.57, 7807.08, 2785.47])
>>> y_no_deriv = kernel(x,z)
>>> y_first = y_no_deriv.clone()
>>> y_first = torch.autograd.grad(y_first,x0,grad_outputs=torch.ones_like(y_first,requires_grad=True),create_graph=True)[0]
>>> y_first = torch.autograd.grad(y_first,z2,grad_outputs=torch.ones_like(y_first,requires_grad=True),create_graph=True)[0]
>>> y_first = torch.autograd.grad(y_first,z2,grad_outputs=torch.ones_like(y_first,requires_grad=True),create_graph=True)[0]
>>> y_second = y_no_deriv.clone()
>>> y_second = torch.autograd.grad(y_second,x1,grad_outputs=torch.ones_like(y_second,requires_grad=True),create_graph=True)[0]
>>> y_second = torch.autograd.grad(y_second,x1,grad_outputs=torch.ones_like(y_second,requires_grad=True),create_graph=True)[0]
>>> y_second = torch.autograd.grad(y_second,z0,grad_outputs=torch.ones_like(y_second,requires_grad=True),create_graph=True)[0]
>>> y_second = torch.autograd.grad(y_second,z0,grad_outputs=torch.ones_like(y_second,requires_grad=True),create_graph=True)[0]
>>> y_second = torch.autograd.grad(y_second,z1,grad_outputs=torch.ones_like(y_second,requires_grad=True),create_graph=True)[0]
>>> yhat = (y_first*c[0]+y_second*c[1]).detach()
>>> with np.printoptions(formatter={"float": lambda x: "%.3f"%x}):
... yhat.numpy()
array([1455.140, 9475.570, 7807.076, 2785.473])
>>> torch.allclose(y,yhat)
True
>>> kernel = KernelShiftInvar(
... d = 3,
... alpha = 3,
... scale = scale,
... lengthscales = lengthscales)
>>> ynp = kernel(x.detach().numpy(),z.detach().numpy(),beta0.numpy(),beta1.numpy(),c.numpy())
>>> with np.printoptions(formatter={"float": lambda x: "%.2f"%x}):
... ynp
array([1455.14, 9475.59, 7807.09, 2785.48])
>>> np.allclose(ynp,y.numpy())
True
References:
- Kaarnioja, Vesa, Frances Y. Kuo, and Ian H. Sloan.
"Lattice-based kernel approximation and serendipitous weights for parametric PDEs in very high dimensions."
International Conference on Monte Carlo and Quasi-Monte Carlo Methods in Scientific Computing. Cham: Springer International Publishing, 2022.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
d
|
int
|
Dimension. |
required |
scale
|
Union[ndarray, Tensor]
|
Scaling factor \(S\). |
1.0
|
lengthscales
|
Union[ndarray, Tensor]
|
Product weights \((\gamma_1,\dots,\gamma_d)\). |
None
|
alpha
|
Union[ndarray, Tensor]
|
Smoothness parameters \((\alpha_1,\dots,\alpha_d)\) where \(\alpha_j \geq 1\) for \(j=1,\dots,d\). |
2
|
shape_scale
|
list
|
Shape of |
[1]
|
shape_lengthscales
|
list
|
Shape of |
None
|
tfs_scale
|
Tuple[callable, callable]
|
The first argument transforms to the raw value to be optimized; the second applies the inverse transform. |
(tf_exp_eps_inv, tf_exp_eps)
|
tfs_lengthscales
|
Tuple[callable, callable]
|
The first argument transforms to the raw value to be optimized; the second applies the inverse transform. |
(tf_exp_eps_inv, tf_exp_eps)
|
torchify
|
bool
|
If |
False
|
requires_grad_scale
|
bool
|
If |
True
|
requires_grad_lengthscales
|
bool
|
If |
True
|
device
|
device
|
If |
'cpu'
|
compile_call
|
bool
|
If |
False
|
comiple_call_kwargs
|
dict
|
When |
{}
|
Source code in qmcpy/kernel/si_dsi_kernels.py
KernelShiftInvarCombined
Bases: AbstractSIDSIKernel
Shift invariant kernel with combination weights \(\boldsymbol{\alpha}_1,\dots,\boldsymbol{\alpha}_d \in \mathbb{R}_{>0}^4\), product weights (lengthscales) \(\boldsymbol{\gamma}\), and scale \(S\):
where, \(\tilde{K}_p\) are defined in KernelShiftInvar for \(p \in \{1,2,3,4\}\)
Examples:
>>> from qmcpy import Lattice, fftbr, ifftbr
>>> n = 8
>>> d = 4
>>> lat = Lattice(d,seed=11)
>>> x = lat(n)
>>> x.shape
(8, 4)
>>> x.dtype
dtype('float64')
>>> kernel = KernelShiftInvarCombined(
... d = d,
... scale = 10,
... lengthscales = [1/j**2 for j in range(1,d+1)])
>>> k00 = kernel(x[0],x[0])
>>> k00.item()
117.22427096475315
>>> k0 = kernel(x,x[0])
>>> with np.printoptions(precision=2):
... print(k0)
[ 117.22 153.84 28.59 36.1 -139.83 77.1 -8.51 35.22]
>>> assert k0[0]==k00
>>> kmat = kernel(x[:,None,:],x[None,:,:])
>>> with np.printoptions(precision=2):
... print(kmat)
[[ 117.22 153.84 36.1 28.59 35.22 -8.51 77.1 -139.83]
[ 153.84 117.22 28.59 36.1 -8.51 35.22 -139.83 77.1 ]
[ 28.59 36.1 117.22 153.84 -139.83 77.1 35.22 -8.51]
[ 36.1 28.59 153.84 117.22 77.1 -139.83 -8.51 35.22]
[-139.83 77.1 35.22 -8.51 117.22 153.84 36.1 28.59]
[ 77.1 -139.83 -8.51 35.22 153.84 117.22 28.59 36.1 ]
[ -8.51 35.22 -139.83 77.1 28.59 36.1 117.22 153.84]
[ 35.22 -8.51 77.1 -139.83 36.1 28.59 153.84 117.22]]
>>> assert (kmat[:,0]==k0).all()
>>> lam = np.sqrt(n)*fftbr(k0)
>>> y = np.random.Generator(np.random.PCG64(7)).uniform(low=0,high=1,size=(n))
>>> np.allclose(ifftbr(fftbr(y)*lam),kmat@y)
True
>>> np.allclose(ifftbr(fftbr(y)/lam),np.linalg.solve(kmat,y))
True
>>> import torch
>>> xtorch = torch.from_numpy(x)
>>> kernel_torch = KernelShiftInvarCombined(
... d = d,
... scale = 10,
... lengthscales = [1/j**2 for j in range(1,d+1)],
... torchify = True)
>>> kmat_torch = kernel_torch(xtorch[:,None,:],xtorch[None,:,:])
>>> np.allclose(kmat_torch.detach().numpy(),kmat)
True
>>> kernel.single_integral_01d(x)
array([10., 10., 10., 10., 10., 10., 10., 10.])
>>> kernel_torch.single_integral_01d(xtorch)
tensor([10., 10., 10., 10., 10., 10., 10., 10.], dtype=torch.float64,
grad_fn=<AddBackward0>)
Batch Params
>>> rng = np.random.Generator(np.random.PCG64(7))
>>> kernel = KernelShiftInvarCombined(
... d = 2,
... shape_scale = [4,3,1],
... shape_lengthscales = [3,2])
>>> x = rng.uniform(low=0,high=1,size=(6,5,2))
>>> kernel(x,x).shape
(4, 3, 6, 5)
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
(4, 3, 6, 5, 5)
>>> kfast = kernel(x[:,None,:,None,:],x[None,:,None,:,:])
>>> kfast.shape
(4, 3, 6, 6, 5, 5)
>>> kstable = kernel(x[:,None,:,None,:],x[None,:,None,:,:],stable=True)
>>> np.abs(kfast-kstable).max()
np.float64(3.552713678800501e-15)
References:
- Kaarnioja, Vesa, Frances Y. Kuo, and Ian H. Sloan. "Lattice-based kernel approximation and serendipitous weights for parametric PDEs in very high dimensions." International Conference on Monte Carlo and Quasi-Monte Carlo Methods in Scientific Computing. Cham: Springer International Publishing, 2022.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
d
|
int
|
Dimension. |
required |
scale
|
Union[ndarray, Tensor]
|
Scaling factor \(S\). |
1.0
|
lengthscales
|
Union[ndarray, Tensor]
|
Product weights \((\gamma_1,\dots,\gamma_d)\). |
None
|
alpha
|
Union[ndarray, Tensor]
|
Weights \(\boldsymbol{\alpha}_1,\dots,\boldsymbol{\alpha}_d \in \mathbb{R}_{>0}^4\). |
1
|
shape_scale
|
list
|
Shape of |
[1]
|
shape_lengthscales
|
list
|
Shape of |
None
|
shape_alpha
|
list
|
Shape of |
None
|
tfs_scale
|
Tuple[callable, callable]
|
The first argument transforms to the raw value to be optimized; the second applies the inverse transform. |
(tf_exp_eps_inv, tf_exp_eps)
|
tfs_lengthscales
|
Tuple[callable, callable]
|
The first argument transforms to the raw value to be optimized; the second applies the inverse transform. |
(tf_exp_eps_inv, tf_exp_eps)
|
tfs_alpha
|
Tuple[callable, callable]
|
The first argument transforms to the raw value to be optimized; the second applies the inverse transform. |
(tf_exp_eps_inv, tf_exp_eps)
|
torchify
|
bool
|
If |
False
|
requires_grad_scale
|
bool
|
If |
True
|
requires_grad_lengthscales
|
bool
|
If |
True
|
requires_grad_alpha
|
bool
|
If |
True
|
device
|
device
|
If |
'cpu'
|
compile_call
|
bool
|
If |
False
|
comiple_call_kwargs
|
dict
|
When |
{}
|
Source code in qmcpy/kernel/si_dsi_kernels.py
KernelDigShiftInvar
Bases: AbstractSIDSIKernel
Digitally shift invariant kernel in base \(b=2\) with smoothness \(\boldsymbol{\alpha}\), product weights \(\boldsymbol{\gamma}\), and scale \(S\):
where
- \(x \oplus z\) is XOR between bits,
- \(\mathrm{wal}_k\) is the \(k^\text{th}\) Walsh function,
- \(\beta(x) = - \lfloor \log_2(x) \rfloor\) and \(t_\nu(x) = 2^{-\nu \beta(x)}\) where \(\beta(0)=t_\nu(0) = 0\), and
- and \(\mu_\alpha\) is the Dick weight function which sums the first \(\alpha\) largest indices of \(1\) bits in the binary expansion of \(k\) e.g. \(k=13=1101_2\) has 1-bit indexes \((4,3,1)\) so
Examples:
>>> from qmcpy import DigitalNetB2, fwht
>>> n = 8
>>> d = 4
>>> dnb2 = DigitalNetB2(d,seed=11)
>>> x = dnb2(n,return_binary=True)
>>> x.shape
(8, 4)
>>> x.dtype
dtype('uint64')
>>> kernel = KernelDigShiftInvar(
... d = d,
... t = dnb2.t,
... alpha = list(range(1,d+1)),
... scale = 10,
... lengthscales = [1/j**2 for j in range(1,d+1)])
>>> k00 = kernel(x[0],x[0])
>>> k00.item()
34.490370029184525
>>> k0 = kernel(x,x[0])
>>> with np.printoptions(precision=2):
... print(k0)
[34.49 4.15 9.59 4.98 15.42 5.45 11.99 4.51]
>>> assert k0[0]==k00
>>> kmat = kernel(x[:,None,:],x[None,:,:])
>>> with np.printoptions(precision=2):
... print(kmat)
[[34.49 4.15 9.59 4.98 15.42 5.45 11.99 4.51]
[ 4.15 34.49 4.98 9.59 5.45 15.42 4.51 11.99]
[ 9.59 4.98 34.49 4.15 11.99 4.51 15.42 5.45]
[ 4.98 9.59 4.15 34.49 4.51 11.99 5.45 15.42]
[15.42 5.45 11.99 4.51 34.49 4.15 9.59 4.98]
[ 5.45 15.42 4.51 11.99 4.15 34.49 4.98 9.59]
[11.99 4.51 15.42 5.45 9.59 4.98 34.49 4.15]
[ 4.51 11.99 5.45 15.42 4.98 9.59 4.15 34.49]]
>>> assert (kmat[:,0]==k0).all()
>>> lam = np.sqrt(n)*fwht(k0)
>>> y = np.random.Generator(np.random.PCG64(7)).uniform(low=0,high=1,size=(n))
>>> np.allclose(fwht(fwht(y)*lam),kmat@y)
True
>>> np.allclose(fwht(fwht(y)/lam),np.linalg.solve(kmat,y))
True
>>> import torch
>>> xtorch = bin_from_numpy_to_torch(x)
>>> kernel_torch = KernelDigShiftInvar(
... d = d,
... t = dnb2.t,
... alpha = list(range(1,d+1)),
... scale = 10,
... lengthscales = [1/j**2 for j in range(1,d+1)],
... torchify = True)
>>> kmat_torch = kernel_torch(xtorch[:,None,:],xtorch[None,:,:])
>>> np.allclose(kmat_torch.detach().numpy(),kmat)
True
>>> xf = to_float(x,dnb2.t)
>>> kmat_from_floats = kernel(xf[:,None,:],xf[None,:,:])
>>> np.allclose(kmat,kmat_from_floats)
True
>>> xftorch = to_float(xtorch,dnb2.t)
>>> xftorch.dtype
torch.float32
>>> kmat_torch_from_floats = kernel_torch(xftorch[:,None,:],xftorch[None,:,:])
>>> torch.allclose(kmat_torch_from_floats,kmat_torch)
True
>>> kernel.single_integral_01d(x)
array([10., 10., 10., 10., 10., 10., 10., 10.])
>>> kernel_torch.single_integral_01d(xtorch)
tensor([10., 10., 10., 10., 10., 10., 10., 10.], grad_fn=<AddBackward0>)
Batch Params
>>> rng = np.random.Generator(np.random.PCG64(7))
>>> kernel = KernelDigShiftInvar(
... d = 2,
... t = 10,
... shape_scale = [4,3,1],
... shape_lengthscales = [3,2])
>>> x = rng.uniform(low=0,high=1,size=(6,5,2))
>>> kernel(x,x).shape
(4, 3, 6, 5)
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
(4, 3, 6, 5, 5)
>>> kfast = kernel(x[:,None,:,None,:],x[None,:,None,:,:])
>>> kfast.shape
(4, 3, 6, 6, 5, 5)
>>> kstable = kernel(x[:,None,:,None,:],x[None,:,None,:,:],stable=True)
>>> np.abs(kfast-kstable).max()
np.float64(4.440892098500626e-16)
References:
-
Dick, Josef.
"Walsh spaces containing smooth functions and quasi-Monte Carlo rules of arbitrary high order."
SIAM Journal on Numerical Analysis 46.3 (2008): 1519-1553. -
Dick, Josef.
"The decay of the Walsh coefficients of smooth functions."
Bulletin of the Australian Mathematical Society 80.3 (2009): 430-453. -
Jagadeeswaran, Rathinavel, and Fred J. Hickernell.
"Fast automatic Bayesian cubature using Sobol' sampling."
Advances in Modeling and Simulation: Festschrift for Pierre L'Ecuyer. Cham: Springer International Publishing, 2022. 301-318. -
Rathinavel, Jagadeeswaran.
Fast automatic Bayesian cubature using matching kernels and designs.
Illinois Institute of Technology, 2019. -
Sorokin, Aleksei.
"A Unified Implementation of Quasi-Monte Carlo Generators, Randomization Routines, and Fast Kernel Methods."
arXiv preprint arXiv:2502.14256 (2025).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
d
|
int
|
Dimension. |
required |
t
|
int
|
number of bits in binary represtnations. Typically |
None
|
scale
|
Union[ndarray, Tensor]
|
Scaling factor \(S\). |
1.0
|
lengthscales
|
Union[ndarray, Tensor]
|
Product weights \((\gamma_1,\dots,\gamma_d)\). |
None
|
alpha
|
Union[ndarray, Tensor]
|
Smoothness parameters \((\alpha_1,\dots,\alpha_d)\) where \(\alpha_j \geq 1\) for \(j=1,\dots,d\). |
2
|
shape_scale
|
list
|
Shape of |
[1]
|
shape_lengthscales
|
list
|
Shape of |
None
|
tfs_scale
|
Tuple[callable, callable]
|
The first argument transforms to the raw value to be optimized; the second applies the inverse transform. |
(tf_exp_eps_inv, tf_exp_eps)
|
tfs_lengthscales
|
Tuple[callable, callable]
|
The first argument transforms to the raw value to be optimized; the second applies the inverse transform. |
(tf_exp_eps_inv, tf_exp_eps)
|
torchify
|
bool
|
If |
False
|
requires_grad_scale
|
bool
|
If |
True
|
requires_grad_lengthscales
|
bool
|
If |
True
|
device
|
device
|
If |
'cpu'
|
compile_call
|
bool
|
If |
False
|
comiple_call_kwargs
|
dict
|
When |
{}
|
Source code in qmcpy/kernel/si_dsi_kernels.py
KernelDigShiftInvarAdaptiveAlpha
Bases: AbstractSIDSIKernel
Digitally shift invariant kernel in base \(b=2\) with smoothness \(\boldsymbol{\alpha} \geq \boldsymbol{0}\), product weights \(\boldsymbol{\gamma}\), and scale \(S\):
where
- \(x \oplus z\) is XOR between bits,
- \(\mathrm{wal}_k\) is the \(k^\text{th}\) Walsh function,
- \(\beta(x) = - \lfloor \log_2(x) \rfloor\) and \(t_\nu(x) = 2^{-\nu \beta(x)}\) where \(\beta(0)=t_\nu(0) = 0\), and
- and \(\mu_\alpha\) is the Dick weight function which sums the first \(\alpha\) largest indices of \(1\) bits in the binary expansion of \(k\) e.g. \(k=13=1101_2\) has 1-bit indexes \((4,3,1)\) so
Examples:
>>> from qmcpy import DigitalNetB2, fwht
>>> n = 8
>>> d = 4
>>> dnb2 = DigitalNetB2(d,seed=11)
>>> x = dnb2(n,return_binary=True)
>>> x.shape
(8, 4)
>>> x.dtype
dtype('uint64')
>>> kernel = KernelDigShiftInvarAdaptiveAlpha(
... d = d,
... t = dnb2.t,
... alpha = list(range(1,d+1)),
... scale = 10,
... lengthscales = [1/j**2 for j in range(1,d+1)])
>>> k00 = kernel(x[0],x[0])
>>> k00.item()
48.084656084656096
>>> k0 = kernel(x,x[0])
>>> with np.printoptions(precision=2):
... print(k0)
[48.08 0. 9.38 0. 19.74 0. 14.84 0. ]
>>> assert k0[0]==k00
>>> kmat = kernel(x[:,None,:],x[None,:,:])
>>> with np.printoptions(precision=2):
... print(kmat)
[[48.08 0. 9.38 0. 19.74 0. 14.84 0. ]
[ 0. 48.08 0. 9.38 0. 19.74 0. 14.84]
[ 9.38 0. 48.08 0. 14.84 0. 19.74 0. ]
[ 0. 9.38 0. 48.08 0. 14.84 0. 19.74]
[19.74 0. 14.84 0. 48.08 0. 9.38 0. ]
[ 0. 19.74 0. 14.84 0. 48.08 0. 9.38]
[14.84 0. 19.74 0. 9.38 0. 48.08 0. ]
[ 0. 14.84 0. 19.74 0. 9.38 0. 48.08]]
>>> assert (kmat[:,0]==k0).all()
>>> lam = np.sqrt(n)*fwht(k0)
>>> y = np.random.Generator(np.random.PCG64(7)).uniform(low=0,high=1,size=(n))
>>> np.allclose(fwht(fwht(y)*lam),kmat@y)
True
>>> np.allclose(fwht(fwht(y)/lam),np.linalg.solve(kmat,y))
True
>>> import torch
>>> xtorch = bin_from_numpy_to_torch(x)
>>> kernel_torch = KernelDigShiftInvarAdaptiveAlpha(
... d = d,
... t = dnb2.t,
... alpha = list(range(1,d+1)),
... scale = 10,
... lengthscales = [1/j**2 for j in range(1,d+1)],
... torchify = True)
>>> kmat_torch = kernel_torch(xtorch[:,None,:],xtorch[None,:,:])
>>> np.allclose(kmat_torch.detach().numpy(),kmat,atol=1e-5)
True
>>> xf = to_float(x,dnb2.t)
>>> kmat_from_floats = kernel(xf[:,None,:],xf[None,:,:])
>>> np.allclose(kmat,kmat_from_floats)
True
>>> xftorch = to_float(xtorch,dnb2.t)
>>> xftorch.dtype
torch.float32
>>> kmat_torch_from_floats = kernel_torch(xftorch[:,None,:],xftorch[None,:,:])
>>> torch.allclose(kmat_torch_from_floats,kmat_torch)
True
>>> kernel.single_integral_01d(x)
array([10., 10., 10., 10., 10., 10., 10., 10.])
>>> kernel_torch.single_integral_01d(xtorch)
tensor([10., 10., 10., 10., 10., 10., 10., 10.], grad_fn=<AddBackward0>)
Batch Params
>>> rng = np.random.Generator(np.random.PCG64(7))
>>> kernel = KernelDigShiftInvarAdaptiveAlpha(
... d = 2,
... t = 10,
... shape_scale = [4,3,1],
... shape_lengthscales = [3,2])
>>> x = rng.uniform(low=0,high=1,size=(6,5,2))
>>> kernel(x,x).shape
(4, 3, 6, 5)
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
(4, 3, 6, 5, 5)
>>> kfast = kernel(x[:,None,:,None,:],x[None,:,None,:,:])
>>> kfast.shape
(4, 3, 6, 6, 5, 5)
>>> kstable = kernel(x[:,None,:,None,:],x[None,:,None,:,:],stable=True)
>>> np.abs(kfast-kstable).max()
np.float64(4.440892098500626e-16)
References:
- Dick, Josef, and Friedrich Pillichshammer.
"Multivariate integration in weighted Hilbert spaces based on Walsh functions and weighted Sobolev spaces."
Journal of Complexity 21.2 (2005): 149-195.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
d
|
int
|
Dimension. |
required |
t
|
int
|
number of bits in binary represtnations. Typically |
None
|
scale
|
Union[ndarray, Tensor]
|
Scaling factor \(S\). |
1.0
|
lengthscales
|
Union[ndarray, Tensor]
|
Product weights \((\gamma_1,\dots,\gamma_d)\). |
None
|
alpha
|
Union[ndarray, Tensor]
|
Smoothness parameters \((\alpha_1,\dots,\alpha_d)\) where \(\alpha_j \geq 1\) for \(j=1,\dots,d\). |
1
|
shape_alpha
|
list
|
Shape of |
None
|
shape_scale
|
list
|
Shape of |
[1]
|
shape_lengthscales
|
list
|
Shape of |
None
|
tfs_scale
|
Tuple[callable, callable]
|
The first argument transforms to the raw value to be optimized; the second applies the inverse transform. |
(tf_exp_eps_inv, tf_exp_eps)
|
tfs_lengthscales
|
Tuple[callable, callable]
|
The first argument transforms to the raw value to be optimized; the second applies the inverse transform. |
(tf_exp_eps_inv, tf_exp_eps)
|
tfs_alpha
|
Tuple[callable, callable]
|
The first argument transforms to the raw value to be optimized; the second applies the inverse transform. |
(tf_exp_eps_inv, tf_exp_eps)
|
torchify
|
bool
|
If |
False
|
requires_grad_scale
|
bool
|
If |
True
|
requires_grad_lengthscales
|
bool
|
If |
True
|
requires_grad_alpha
|
bool
|
If |
True
|
device
|
device
|
If |
'cpu'
|
compile_call
|
bool
|
If |
False
|
comiple_call_kwargs
|
dict
|
When |
{}
|
Source code in qmcpy/kernel/si_dsi_kernels.py
KernelDigShiftInvarCombined
Bases: AbstractSIDSIKernel
Digitally shift invariant kernel in base \(b=2\) with combination weights \(\boldsymbol{\alpha}_1,\dots,\boldsymbol{\alpha}_d \in \mathbb{R}_{>0}^4\), smoothness \(\boldsymbol{\alpha}\), product weights \(\boldsymbol{\gamma}\), and scale \(S\):
where, \(\oplus\) is defined in the docs for KernelDigShiftInvar and so are \(\tilde{K}_p\) for \(p \in \{1,2,3,4\}\)
Examples:
>>> from qmcpy import DigitalNetB2, fwht
>>> n = 8
>>> d = 4
>>> dnb2 = DigitalNetB2(d,seed=11)
>>> x = dnb2(n,return_binary=True)
>>> x.shape
(8, 4)
>>> x.dtype
dtype('uint64')
>>> kernel = KernelDigShiftInvarCombined(
... d = d,
... t = dnb2.t,
... scale = 10,
... lengthscales = [1/j**2 for j in range(1,d+1)])
>>> k00 = kernel(x[0],x[0])
>>> k00.item()
306.66030731930863
>>> k0 = kernel(x,x[0])
>>> with np.printoptions(precision=2):
... print(k0)
[306.66 -1.65 6.88 -13.5 22.57 -9.34 7.99 -7.54]
>>> assert k0[0]==k00
>>> kmat = kernel(x[:,None,:],x[None,:,:])
>>> with np.printoptions(precision=2):
... print(kmat)
[[306.66 -1.65 6.88 -13.5 22.57 -9.34 7.99 -7.54]
[ -1.65 306.66 -13.5 6.88 -9.34 22.57 -7.54 7.99]
[ 6.88 -13.5 306.66 -1.65 7.99 -7.54 22.57 -9.34]
[-13.5 6.88 -1.65 306.66 -7.54 7.99 -9.34 22.57]
[ 22.57 -9.34 7.99 -7.54 306.66 -1.65 6.88 -13.5 ]
[ -9.34 22.57 -7.54 7.99 -1.65 306.66 -13.5 6.88]
[ 7.99 -7.54 22.57 -9.34 6.88 -13.5 306.66 -1.65]
[ -7.54 7.99 -9.34 22.57 -13.5 6.88 -1.65 306.66]]
>>> assert (kmat[:,0]==k0).all()
>>> lam = np.sqrt(n)*fwht(k0)
>>> y = np.random.Generator(np.random.PCG64(7)).uniform(low=0,high=1,size=(n))
>>> np.allclose(fwht(fwht(y)*lam),kmat@y)
True
>>> np.allclose(fwht(fwht(y)/lam),np.linalg.solve(kmat,y))
True
>>> import torch
>>> xtorch = bin_from_numpy_to_torch(x)
>>> kernel_torch = KernelDigShiftInvarCombined(
... d = d,
... t = dnb2.t,
... scale = 10,
... lengthscales = [1/j**2 for j in range(1,d+1)],
... torchify = True)
>>> kmat_torch = kernel_torch(xtorch[:,None,:],xtorch[None,:,:])
>>> np.allclose(kmat_torch.detach().numpy(),kmat)
True
>>> xf = to_float(x,dnb2.t)
>>> kmat_from_floats = kernel(xf[:,None,:],xf[None,:,:])
>>> np.allclose(kmat,kmat_from_floats)
True
>>> xftorch = to_float(xtorch,dnb2.t)
>>> xftorch.dtype
torch.float32
>>> kmat_torch_from_floats = kernel_torch(xftorch[:,None,:],xftorch[None,:,:])
>>> torch.allclose(kmat_torch_from_floats,kmat_torch)
True
>>> kernel.single_integral_01d(x)
array([10., 10., 10., 10., 10., 10., 10., 10.])
>>> kernel_torch.single_integral_01d(xtorch)
tensor([10., 10., 10., 10., 10., 10., 10., 10.], grad_fn=<AddBackward0>)
Batch Params
>>> rng = np.random.Generator(np.random.PCG64(7))
>>> kernel = KernelDigShiftInvarCombined(
... d = 2,
... t = 10,
... shape_scale = [4,3,1],
... shape_lengthscales = [3,2])
>>> x = rng.uniform(low=0,high=1,size=(6,5,2))
>>> kernel(x,x).shape
(4, 3, 6, 5)
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
(4, 3, 6, 5, 5)
>>> kfast = kernel(x[:,None,:,None,:],x[None,:,None,:,:])
>>> kfast.shape
(4, 3, 6, 6, 5, 5)
>>> kstable = kernel(x[:,None,:,None,:],x[None,:,None,:,:],stable=True)
>>> np.abs(kfast-kstable).max()
np.float64(8.881784197001252e-16)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
d
|
int
|
Dimension. |
required |
t
|
int
|
number of bits in binary represtnations. Typically |
None
|
scale
|
Union[ndarray, Tensor]
|
Scaling factor \(S\). |
1.0
|
lengthscales
|
Union[ndarray, Tensor]
|
Product weights \((\gamma_1,\dots,\gamma_d)\). |
None
|
alpha
|
Union[ndarray, Tensor]
|
Weights \(\boldsymbol{\alpha}_1,\dots,\boldsymbol{\alpha}_d \in \mathbb{R}_{>0}^4\). |
1.0
|
shape_scale
|
list
|
Shape of |
[1]
|
shape_lengthscales
|
list
|
Shape of |
None
|
shape_alpha
|
list
|
Shape of |
None
|
tfs_scale
|
Tuple[callable, callable]
|
The first argument transforms to the raw value to be optimized; the second applies the inverse transform. |
(tf_exp_eps_inv, tf_exp_eps)
|
tfs_lengthscales
|
Tuple[callable, callable]
|
The first argument transforms to the raw value to be optimized; the second applies the inverse transform. |
(tf_exp_eps_inv, tf_exp_eps)
|
torchify
|
bool
|
If |
False
|
requires_grad_scale
|
bool
|
If |
True
|
requires_grad_lengthscales
|
bool
|
If |
True
|
requires_grad_alpha
|
bool
|
If |
True
|
device
|
device
|
If |
'cpu'
|
compile_call
|
bool
|
If |
False
|
comiple_call_kwargs
|
dict
|
When |
{}
|
Source code in qmcpy/kernel/si_dsi_kernels.py
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 | |
KernelGaussian
Bases: AbstractKernelGaussianSE
Gaussian / Squared Exponential kernel implemented using the product of exponentials.
Examples:
>>> rng = np.random.Generator(np.random.PCG64(7))
>>> kernel = KernelGaussian(d=2)
>>> x = rng.uniform(low=0,high=1,size=(4,2))
>>> kernel(x[0],x[0]).item()
1.0
>>> kernel(x,x)
array([1., 1., 1., 1.])
>>> kernel(x[:,None,:],x[None,:,:])
array([[1. , 0.78888466, 0.9483142 , 0.8228498 ],
[0.78888466, 1. , 0.72380317, 0.62226176],
[0.9483142 , 0.72380317, 1. , 0.95613874],
[0.8228498 , 0.62226176, 0.95613874, 1. ]])
Multiple randomizations
>>> x = rng.uniform(low=0,high=1,size=(6,5,2))
>>> kernel(x,x).shape
(6, 5)
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
(6, 5, 5)
>>> kernel(x[:,None,:,None,:],x[None,:,None,:,:]).shape
(6, 6, 5, 5)
Batch hyperparameters
>>> kernel = KernelGaussian(
... d = 2,
... shape_scale = [4,3,1],
... shape_lengthscales = [3,1])
>>> kernel(x,x).shape
(4, 3, 6, 5)
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
(4, 3, 6, 5, 5)
>>> kernel(x[:,None,:,None,:],x[None,:,None,:,:]).shape
(4, 3, 6, 6, 5, 5)
Integrals
>>> kernel = KernelGaussian(
... d = 2,
... scale = rng.uniform(low=0,high=1,size=(3,1,)),
... lengthscales = rng.uniform(low=0,high=1,size=(1,2)))
>>> kintint = kernel.double_integral_01d()
>>> kintint
array([0.50079567, 0.11125229, 0.34760005])
>>> x_qmc_4d = DigitalNetB2(4,seed=7)(2**16)
>>> kintint_qmc = kernel(x_qmc_4d[:,:2],x_qmc_4d[:,2:]).mean(1)
>>> kintint_qmc
array([0.5007959 , 0.11125234, 0.34760021])
>>> with np.printoptions(formatter={"float":lambda x: "%.1e"%x}):
... np.abs(kintint-kintint_qmc)
array([2.3e-07, 5.1e-08, 1.6e-07])
>>> x = rng.uniform(low=0,high=1,size=(4,2))
>>> kint = kernel.single_integral_01d(x)
>>> kint
array([[0.54610372, 0.4272801 , 0.43001936, 0.44688778],
[0.12131753, 0.09492073, 0.09552926, 0.0992766 ],
[0.37904817, 0.29657323, 0.29847453, 0.31018283]])
>>> x_qmc_2d = DigitalNetB2(2,seed=7)(2**16)
>>> kint_qmc = kernel(x[:,None,:],x_qmc_2d).mean(-1)
>>> kint_qmc
array([[0.54610372, 0.4272801 , 0.43001936, 0.44688778],
[0.12131753, 0.09492073, 0.09552926, 0.0992766 ],
[0.37904817, 0.29657323, 0.29847453, 0.31018283]])
>>> with np.printoptions(formatter={"float":lambda x: "%.1e"%x}):
... np.abs(kint-kint_qmc)
array([[2.2e-13, 4.0e-13, 4.2e-12, 3.9e-12],
[4.8e-14, 8.9e-14, 9.4e-13, 8.8e-13],
[1.5e-13, 2.8e-13, 2.9e-12, 2.7e-12]])
>>> k_1l = KernelGaussian(d=2,lengthscales=[.5])
>>> k_2l = KernelGaussian(d=2,lengthscales=[.5,.5])
>>> print("%.5f"%k_2l.double_integral_01d())
0.58363
>>> print("%.5f"%k_1l.double_integral_01d())
0.58363
>>> k_1l.single_integral_01d(x)
array([0.58119655, 0.46559577, 0.57603494, 0.53494393])
>>> k_2l.single_integral_01d(x)
array([0.58119655, 0.46559577, 0.57603494, 0.53494393])
PyTorch
>>> import torch
>>> rng = np.random.Generator(np.random.PCG64(7))
>>> kernel = KernelGaussian(d=2,torchify=True)
>>> x = torch.from_numpy(rng.uniform(low=0,high=1,size=(4,2)))
>>> kernel(x[0],x[0]).item()
1.0
>>> kernel(x,x)
tensor([1., 1., 1., 1.], dtype=torch.float64, grad_fn=<MulBackward0>)
>>> kernel(x[:,None,:],x[None,:,:])
tensor([[1.0000, 0.7889, 0.9483, 0.8228],
[0.7889, 1.0000, 0.7238, 0.6223],
[0.9483, 0.7238, 1.0000, 0.9561],
[0.8228, 0.6223, 0.9561, 1.0000]], dtype=torch.float64,
grad_fn=<MulBackward0>)
Multiple randomizations
>>> x = torch.from_numpy(rng.uniform(low=0,high=1,size=(6,5,2)))
>>> kernel(x,x).shape
torch.Size([6, 5])
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
torch.Size([6, 5, 5])
>>> kernel(x[:,None,:,None,:],x[None,:,None,:,:]).shape
torch.Size([6, 6, 5, 5])
Batch hyperparameters
>>> kernel = KernelGaussian(
... d = 2,
... shape_scale = [4,3,1],
... shape_lengthscales = [3,1],
... torchify = True)
>>> kernel(x,x).shape
torch.Size([4, 3, 6, 5])
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
torch.Size([4, 3, 6, 5, 5])
>>> kernel(x[:,None,:,None,:],x[None,:,None,:,:]).shape
torch.Size([4, 3, 6, 6, 5, 5])
Integrals
>>> kernel = KernelGaussian(
... d = 2,
... torchify = True,
... scale = torch.from_numpy(rng.uniform(low=0,high=1,size=(3,1,))),
... lengthscales = torch.from_numpy(rng.uniform(low=0,high=1,size=(1,2))),
... requires_grad_scale = False,
... requires_grad_lengthscales = False)
>>> kintint = kernel.double_integral_01d()
>>> kintint
tensor([0.5008, 0.1113, 0.3476], dtype=torch.float64)
>>> x_qmc_4d = torch.from_numpy(DigitalNetB2(4,seed=7)(2**16))
>>> kintint_qmc = kernel(x_qmc_4d[:,:2],x_qmc_4d[:,2:]).mean(1)
>>> kintint_qmc
tensor([0.5008, 0.1113, 0.3476], dtype=torch.float64)
>>> with np.printoptions(formatter={"float":lambda x: "%.1e"%x}):
... torch.abs(kintint-kintint_qmc).numpy()
array([2.3e-07, 5.1e-08, 1.6e-07])
>>> x = torch.from_numpy(rng.uniform(low=0,high=1,size=(4,2)))
>>> kint = kernel.single_integral_01d(x)
>>> kint
tensor([[0.5461, 0.4273, 0.4300, 0.4469],
[0.1213, 0.0949, 0.0955, 0.0993],
[0.3790, 0.2966, 0.2985, 0.3102]], dtype=torch.float64)
>>> x_qmc_2d = torch.from_numpy(DigitalNetB2(2,seed=7)(2**16))
>>> kint_qmc = kernel(x[:,None,:],x_qmc_2d).mean(-1)
>>> kint_qmc
tensor([[0.5461, 0.4273, 0.4300, 0.4469],
[0.1213, 0.0949, 0.0955, 0.0993],
[0.3790, 0.2966, 0.2985, 0.3102]], dtype=torch.float64)
>>> with np.printoptions(formatter={"float":lambda x: "%.1e"%x}):
... torch.abs(kint-kint_qmc).numpy()
array([[2.2e-13, 4.0e-13, 4.2e-12, 3.9e-12],
[4.8e-14, 8.9e-14, 9.4e-13, 8.8e-13],
[1.5e-13, 2.8e-13, 2.9e-12, 2.7e-12]])
>>> k_1l = KernelGaussian(d=2,lengthscales=[.5],torchify=True)
>>> k_2l = KernelGaussian(d=2,lengthscales=[.5,.5],torchify=True)
>>> k_2l.double_integral_01d()
tensor(0.5836, grad_fn=<MulBackward0>)
>>> k_1l.double_integral_01d()
tensor(0.5836, grad_fn=<MulBackward0>)
>>> k_1l.single_integral_01d(x)
tensor([0.5812, 0.4656, 0.5760, 0.5349], dtype=torch.float64,
grad_fn=<MulBackward0>)
>>> k_2l.single_integral_01d(x)
tensor([0.5812, 0.4656, 0.5760, 0.5349], dtype=torch.float64,
grad_fn=<MulBackward0>)
Derivatives
>>> kernel = KernelGaussian(
... d = 3,
... torchify = True,
... scale = torch.from_numpy(rng.uniform(low=0,high=1,size=(1,))),
... lengthscales = torch.from_numpy(rng.uniform(low=0,high=1,size=(3,))))
>>> x0 = torch.from_numpy(rng.uniform(low=0,high=1,size=(4,))).requires_grad_(True)
>>> x1 = torch.from_numpy(rng.uniform(low=0,high=1,size=(4,))).requires_grad_(True)
>>> x2 = torch.from_numpy(rng.uniform(low=0,high=1,size=(4,))).requires_grad_(True)
>>> x = torch.stack([x0,x1,x2],axis=-1)
>>> z0 = torch.from_numpy(rng.uniform(low=0,high=1,size=(4,))).requires_grad_(True)
>>> z1 = torch.from_numpy(rng.uniform(low=0,high=1,size=(4,))).requires_grad_(True)
>>> z2 = torch.from_numpy(rng.uniform(low=0,high=1,size=(4,))).requires_grad_(True)
>>> z = torch.stack([z0,z1,z2],axis=-1)
>>> c = torch.from_numpy(rng.uniform(low=0,high=1,size=(2,)))
>>> beta0 = torch.tensor([
... [1,0,0],
... [0,2,0]])
>>> beta1 = torch.tensor([
... [0,0,2],
... [2,1,0]])
>>> with torch.no_grad():
... y = kernel(x,z,beta0,beta1,c)
>>> y
tensor([ 97.6657, 3.8621, -65.9329, -1.1932], dtype=torch.float64)
>>> y_no_deriv = kernel(x,z)
>>> y_first = y_no_deriv.clone()
>>> y_first = torch.autograd.grad(y_first,x0,grad_outputs=torch.ones_like(y_first,requires_grad=True),create_graph=True)[0]
>>> y_first = torch.autograd.grad(y_first,z2,grad_outputs=torch.ones_like(y_first,requires_grad=True),create_graph=True)[0]
>>> y_first = torch.autograd.grad(y_first,z2,grad_outputs=torch.ones_like(y_first,requires_grad=True),create_graph=True)[0]
>>> y_second = y_no_deriv.clone()
>>> y_second = torch.autograd.grad(y_second,x1,grad_outputs=torch.ones_like(y_second,requires_grad=True),create_graph=True)[0]
>>> y_second = torch.autograd.grad(y_second,x1,grad_outputs=torch.ones_like(y_second,requires_grad=True),create_graph=True)[0]
>>> y_second = torch.autograd.grad(y_second,z0,grad_outputs=torch.ones_like(y_second,requires_grad=True),create_graph=True)[0]
>>> y_second = torch.autograd.grad(y_second,z0,grad_outputs=torch.ones_like(y_second,requires_grad=True),create_graph=True)[0]
>>> y_second = torch.autograd.grad(y_second,z1,grad_outputs=torch.ones_like(y_second,requires_grad=True),create_graph=True)[0]
>>> yhat = (y_first*c[0]+y_second*c[1]).detach()
>>> yhat
tensor([ 97.6657, 3.8621, -65.9329, -1.1932], dtype=torch.float64)
>>> torch.allclose(y,yhat)
True
Source code in qmcpy/kernel/abstract_kernel.py
KernelSquaredExponential
Bases: AbstractKernelGaussianSE
Gaussian / Squared Exponential kernel implemented using the pairwise distance function.
Please use KernelGaussian when using derivative information.
Examples:
>>> rng = np.random.Generator(np.random.PCG64(7))
>>> kernel = KernelSquaredExponential(d=2)
>>> x = rng.uniform(low=0,high=1,size=(4,2))
>>> kernel(x[0],x[0]).item()
1.0
>>> kernel(x,x)
array([1., 1., 1., 1.])
>>> kernel(x[:,None,:],x[None,:,:])
array([[1. , 0.78888466, 0.9483142 , 0.8228498 ],
[0.78888466, 1. , 0.72380317, 0.62226176],
[0.9483142 , 0.72380317, 1. , 0.95613874],
[0.8228498 , 0.62226176, 0.95613874, 1. ]])
Multiple randomizations
>>> x = rng.uniform(low=0,high=1,size=(6,5,2))
>>> kernel(x,x).shape
(6, 5)
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
(6, 5, 5)
>>> kernel(x[:,None,:,None,:],x[None,:,None,:,:]).shape
(6, 6, 5, 5)
Batch hyperparameters
>>> kernel = KernelSquaredExponential(
... d = 2,
... shape_scale = [4,3,1],
... shape_lengthscales = [3,1])
>>> kernel(x,x).shape
(4, 3, 6, 5)
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
(4, 3, 6, 5, 5)
>>> kernel(x[:,None,:,None,:],x[None,:,None,:,:]).shape
(4, 3, 6, 6, 5, 5)
PyTorch
>>> import torch
>>> rng = np.random.Generator(np.random.PCG64(7))
>>> kernel = KernelSquaredExponential(d=2,torchify=True)
>>> x = torch.from_numpy(rng.uniform(low=0,high=1,size=(4,2)))
>>> kernel(x[0],x[0]).item()
1.0
>>> kernel(x,x)
tensor([1., 1., 1., 1.], dtype=torch.float64, grad_fn=<MulBackward0>)
>>> kernel(x[:,None,:],x[None,:,:])
tensor([[1.0000, 0.7889, 0.9483, 0.8228],
[0.7889, 1.0000, 0.7238, 0.6223],
[0.9483, 0.7238, 1.0000, 0.9561],
[0.8228, 0.6223, 0.9561, 1.0000]], dtype=torch.float64,
grad_fn=<MulBackward0>)
Multiple randomizations
>>> x = torch.from_numpy(rng.uniform(low=0,high=1,size=(6,5,2)))
>>> kernel(x,x).shape
torch.Size([6, 5])
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
torch.Size([6, 5, 5])
>>> kernel(x[:,None,:,None,:],x[None,:,None,:,:]).shape
torch.Size([6, 6, 5, 5])
Batch hyperparameters
>>> kernel = KernelSquaredExponential(
... d = 2,
... shape_scale = [4,3,1],
... shape_lengthscales = [3,1],
... torchify = True)
>>> kernel(x,x).shape
torch.Size([4, 3, 6, 5])
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
torch.Size([4, 3, 6, 5, 5])
>>> kernel(x[:,None,:,None,:],x[None,:,None,:,:]).shape
torch.Size([4, 3, 6, 6, 5, 5])
Source code in qmcpy/kernel/abstract_kernel.py
KernelRationalQuadratic
Bases: AbstractKernelScaleLengthscales
Rational Quadratic kernel
Examples:
>>> rng = np.random.Generator(np.random.PCG64(7))
>>> kernel = KernelRationalQuadratic(d=2)
>>> x = rng.uniform(low=0,high=1,size=(4,2))
>>> kernel(x[0],x[0]).item()
1.0
>>> kernel(x,x)
array([1., 1., 1., 1.])
>>> kernel(x[:,None,:],x[None,:,:])
array([[1. , 0.80831912, 0.94960504, 0.83683297],
[0.80831912, 1. , 0.75572321, 0.67824456],
[0.94960504, 0.75572321, 1. , 0.95707312],
[0.83683297, 0.67824456, 0.95707312, 1. ]])
Multiple randomizations
>>> x = rng.uniform(low=0,high=1,size=(6,5,2))
>>> kernel(x,x).shape
(6, 5)
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
(6, 5, 5)
>>> kernel(x[:,None,:,None,:],x[None,:,None,:,:]).shape
(6, 6, 5, 5)
Batch hyperparameters
>>> kernel = KernelRationalQuadratic(
... d = 2,
... shape_scale = [4,3,1],
... shape_lengthscales = [3,1])
>>> kernel(x,x).shape
(4, 3, 6, 5)
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
(4, 3, 6, 5, 5)
>>> kernel(x[:,None,:,None,:],x[None,:,None,:,:]).shape
(4, 3, 6, 6, 5, 5)
PyTorch
>>> import torch
>>> rng = np.random.Generator(np.random.PCG64(7))
>>> kernel = KernelRationalQuadratic(d=2,torchify=True)
>>> x = torch.from_numpy(rng.uniform(low=0,high=1,size=(4,2)))
>>> kernel(x[0],x[0]).item()
1.0
>>> kernel(x,x)
tensor([1., 1., 1., 1.], dtype=torch.float64, grad_fn=<MulBackward0>)
>>> kernel(x[:,None,:],x[None,:,:])
tensor([[1.0000, 0.8083, 0.9496, 0.8368],
[0.8083, 1.0000, 0.7557, 0.6782],
[0.9496, 0.7557, 1.0000, 0.9571],
[0.8368, 0.6782, 0.9571, 1.0000]], dtype=torch.float64,
grad_fn=<MulBackward0>)
Multiple randomizations
>>> x = torch.from_numpy(rng.uniform(low=0,high=1,size=(6,5,2)))
>>> kernel(x,x).shape
torch.Size([6, 5])
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
torch.Size([6, 5, 5])
>>> kernel(x[:,None,:,None,:],x[None,:,None,:,:]).shape
torch.Size([6, 6, 5, 5])
Batch hyperparameters
>>> kernel = KernelRationalQuadratic(
... d = 2,
... shape_alpha = [4,3,1],
... shape_lengthscales = [3,1],
... torchify = True)
>>> kernel(x,x).shape
torch.Size([4, 3, 6, 5])
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
torch.Size([4, 3, 6, 5, 5])
>>> kernel(x[:,None,:,None,:],x[None,:,None,:,:]).shape
torch.Size([4, 3, 6, 6, 5, 5])
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
d
|
int
|
Dimension. |
required |
scale
|
Union[ndarray, Tensor]
|
Scaling factor \(S\). |
1.0
|
lengthscales
|
Union[ndarray, Tensor]
|
Lengthscales \(\boldsymbol{\gamma}\). |
1.0
|
alpha
|
Union[ndarray, Tensor]
|
Scale mixture parameter \(\alpha\). |
1.0
|
shape_scale
|
list
|
Shape of |
[1]
|
shape_lengthscales
|
list
|
Shape of |
None
|
shape_alpha
|
list
|
Shape of |
[1]
|
tfs_scale
|
Tuple[callable, callable]
|
The first argument transforms to the raw value to be optimized; the second applies the inverse transform. |
(tf_exp_eps_inv, tf_exp_eps)
|
tfs_lengthscales
|
Tuple[callable, callable]
|
The first argument transforms to the raw value to be optimized; the second applies the inverse transform. |
(tf_exp_eps_inv, tf_exp_eps)
|
tfs_alpha
|
Tuple[callable, callable]
|
The first argument transforms to the raw value to be optimized; the second applies the inverse transform. |
(tf_exp_eps_inv, tf_exp_eps)
|
torchify
|
bool
|
If |
False
|
requires_grad_scale
|
bool
|
If |
True
|
requires_grad_lengthscales
|
bool
|
If |
True
|
requires_grad_alpha
|
bool
|
If |
True
|
device
|
device
|
If |
'cpu'
|
compile_call
|
bool
|
If |
False
|
comiple_call_kwargs
|
dict
|
When |
{}
|
Source code in qmcpy/kernel/common_kernels.py
KernelMatern12
Bases: AbstractKernelScaleLengthscales
Matern kernel with \(\alpha=1/2\).
Examples:
>>> rng = np.random.Generator(np.random.PCG64(7))
>>> kernel = KernelMatern12(d=2)
>>> x = rng.uniform(low=0,high=1,size=(4,2))
>>> kernel(x[0],x[0]).item()
1.0
>>> kernel(x,x)
array([1., 1., 1., 1.])
>>> kernel(x[:,None,:],x[None,:,:])
array([[1. , 0.61448839, 0.79424131, 0.64302787],
[0.61448839, 1. , 0.56635268, 0.50219691],
[0.79424131, 0.56635268, 1. , 0.80913986],
[0.64302787, 0.50219691, 0.80913986, 1. ]])
Multiple randomizations
>>> x = rng.uniform(low=0,high=1,size=(6,5,2))
>>> kernel(x,x).shape
(6, 5)
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
(6, 5, 5)
>>> kernel(x[:,None,:,None,:],x[None,:,None,:,:]).shape
(6, 6, 5, 5)
Batch hyperparameters
>>> kernel = KernelMatern12(
... d = 2,
... shape_scale = [4,3,1],
... shape_lengthscales = [3,1])
>>> kernel(x,x).shape
(4, 3, 6, 5)
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
(4, 3, 6, 5, 5)
>>> kernel(x[:,None,:,None,:],x[None,:,None,:,:]).shape
(4, 3, 6, 6, 5, 5)
PyTorch
>>> import torch
>>> rng = np.random.Generator(np.random.PCG64(7))
>>> kernel = KernelMatern12(d=2,torchify=True)
>>> x = torch.from_numpy(rng.uniform(low=0,high=1,size=(4,2)))
>>> kernel(x[0],x[0]).item()
1.0
>>> kernel(x,x)
tensor([1., 1., 1., 1.], dtype=torch.float64, grad_fn=<MulBackward0>)
>>> kernel(x[:,None,:],x[None,:,:])
tensor([[1.0000, 0.6145, 0.7942, 0.6430],
[0.6145, 1.0000, 0.5664, 0.5022],
[0.7942, 0.5664, 1.0000, 0.8091],
[0.6430, 0.5022, 0.8091, 1.0000]], dtype=torch.float64,
grad_fn=<MulBackward0>)
Multiple randomizations
>>> x = torch.from_numpy(rng.uniform(low=0,high=1,size=(6,5,2)))
>>> kernel(x,x).shape
torch.Size([6, 5])
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
torch.Size([6, 5, 5])
>>> kernel(x[:,None,:,None,:],x[None,:,None,:,:]).shape
torch.Size([6, 6, 5, 5])
Batch hyperparameters
>>> kernel = KernelMatern12(
... d = 2,
... shape_scale = [4,3,1],
... shape_lengthscales = [3,1],
... torchify = True)
>>> kernel(x,x).shape
torch.Size([4, 3, 6, 5])
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
torch.Size([4, 3, 6, 5, 5])
>>> kernel(x[:,None,:,None,:],x[None,:,None,:,:]).shape
torch.Size([4, 3, 6, 6, 5, 5])
Source code in qmcpy/kernel/abstract_kernel.py
KernelMatern32
Bases: AbstractKernelScaleLengthscales
Matern kernel with \(\alpha=3/2\).
Examples:
>>> rng = np.random.Generator(np.random.PCG64(7))
>>> kernel = KernelMatern32(d=2)
>>> x = rng.uniform(low=0,high=1,size=(4,2))
>>> kernel(x[0],x[0]).item()
1.0
>>> kernel(x,x)
array([1., 1., 1., 1.])
>>> kernel(x[:,None,:],x[None,:,:])
array([[1. , 0.79309639, 0.93871358, 0.82137958],
[0.79309639, 1. , 0.74137353, 0.66516872],
[0.93871358, 0.74137353, 1. , 0.9471166 ],
[0.82137958, 0.66516872, 0.9471166 , 1. ]])
Multiple randomizations
>>> x = rng.uniform(low=0,high=1,size=(6,5,2))
>>> kernel(x,x).shape
(6, 5)
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
(6, 5, 5)
>>> kernel(x[:,None,:,None,:],x[None,:,None,:,:]).shape
(6, 6, 5, 5)
Batch hyperparameters
>>> kernel = KernelMatern32(
... d = 2,
... shape_scale = [4,3,1],
... shape_lengthscales = [3,1])
>>> kernel(x,x).shape
(4, 3, 6, 5)
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
(4, 3, 6, 5, 5)
>>> kernel(x[:,None,:,None,:],x[None,:,None,:,:]).shape
(4, 3, 6, 6, 5, 5)
PyTorch
>>> import torch
>>> rng = np.random.Generator(np.random.PCG64(7))
>>> kernel = KernelMatern32(d=2,torchify=True)
>>> x = torch.from_numpy(rng.uniform(low=0,high=1,size=(4,2)))
>>> kernel(x[0],x[0]).item()
1.0
>>> kernel(x,x)
tensor([1., 1., 1., 1.], dtype=torch.float64, grad_fn=<MulBackward0>)
>>> kernel(x[:,None,:],x[None,:,:])
tensor([[1.0000, 0.7931, 0.9387, 0.8214],
[0.7931, 1.0000, 0.7414, 0.6652],
[0.9387, 0.7414, 1.0000, 0.9471],
[0.8214, 0.6652, 0.9471, 1.0000]], dtype=torch.float64,
grad_fn=<MulBackward0>)
Multiple randomizations
>>> x = torch.from_numpy(rng.uniform(low=0,high=1,size=(6,5,2)))
>>> kernel(x,x).shape
torch.Size([6, 5])
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
torch.Size([6, 5, 5])
>>> kernel(x[:,None,:,None,:],x[None,:,None,:,:]).shape
torch.Size([6, 6, 5, 5])
Batch hyperparameters
>>> kernel = KernelMatern32(
... d = 2,
... shape_scale = [4,3,1],
... shape_lengthscales = [3,1],
... torchify = True)
>>> kernel(x,x).shape
torch.Size([4, 3, 6, 5])
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
torch.Size([4, 3, 6, 5, 5])
>>> kernel(x[:,None,:,None,:],x[None,:,None,:,:]).shape
torch.Size([4, 3, 6, 6, 5, 5])
Source code in qmcpy/kernel/abstract_kernel.py
KernelMatern52
Bases: AbstractKernelScaleLengthscales
Matern kernel with \(\alpha=5/2\).
Examples:
>>> rng = np.random.Generator(np.random.PCG64(7))
>>> kernel = KernelMatern52(d=2)
>>> x = rng.uniform(low=0,high=1,size=(4,2))
>>> kernel(x[0],x[0]).item()
1.0
>>> kernel(x,x)
array([1., 1., 1., 1.])
>>> kernel(x[:,None,:],x[None,:,:])
array([[1. , 0.83612941, 0.95801903, 0.861472 ],
[0.83612941, 1. , 0.78812397, 0.71396963],
[0.95801903, 0.78812397, 1. , 0.96425994],
[0.861472 , 0.71396963, 0.96425994, 1. ]])
Multiple randomizations
>>> x = rng.uniform(low=0,high=1,size=(6,5,2))
>>> kernel(x,x).shape
(6, 5)
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
(6, 5, 5)
>>> kernel(x[:,None,:,None,:],x[None,:,None,:,:]).shape
(6, 6, 5, 5)
Batch hyperparameters
>>> kernel = KernelMatern52(
... d = 2,
... shape_scale = [4,3,1],
... shape_lengthscales = [3,1])
>>> kernel(x,x).shape
(4, 3, 6, 5)
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
(4, 3, 6, 5, 5)
>>> kernel(x[:,None,:,None,:],x[None,:,None,:,:]).shape
(4, 3, 6, 6, 5, 5)
PyTorch
>>> import torch
>>> rng = np.random.Generator(np.random.PCG64(7))
>>> kernel = KernelMatern52(d=2,torchify=True)
>>> x = torch.from_numpy(rng.uniform(low=0,high=1,size=(4,2)))
>>> kernel(x[0],x[0]).item()
1.0
>>> kernel(x,x)
tensor([1., 1., 1., 1.], dtype=torch.float64, grad_fn=<MulBackward0>)
>>> kernel(x[:,None,:],x[None,:,:])
tensor([[1.0000, 0.8361, 0.9580, 0.8615],
[0.8361, 1.0000, 0.7881, 0.7140],
[0.9580, 0.7881, 1.0000, 0.9643],
[0.8615, 0.7140, 0.9643, 1.0000]], dtype=torch.float64,
grad_fn=<MulBackward0>)
Multiple randomizations
>>> x = torch.from_numpy(rng.uniform(low=0,high=1,size=(6,5,2)))
>>> kernel(x,x).shape
torch.Size([6, 5])
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
torch.Size([6, 5, 5])
>>> kernel(x[:,None,:,None,:],x[None,:,None,:,:]).shape
torch.Size([6, 6, 5, 5])
Batch hyperparameters
>>> kernel = KernelMatern52(
... d = 2,
... shape_scale = [4,3,1],
... shape_lengthscales = [3,1],
... torchify = True)
>>> kernel(x,x).shape
torch.Size([4, 3, 6, 5])
>>> kernel(x[:,:,None,:],x[:,None,:,:]).shape
torch.Size([4, 3, 6, 5, 5])
>>> kernel(x[:,None,:,None,:],x[None,:,None,:,:]).shape
torch.Size([4, 3, 6, 6, 5, 5])
Source code in qmcpy/kernel/abstract_kernel.py
KernelMultiTask
Bases: AbstractKernel
Multi-task kernel
parameterized for \(T\) tasks by a factor \(\mathsf{F} \in \mathbb{R}^{T \times r}\) and a diagonal \(\boldsymbol{v} \in \mathbb{R}^T\) so that
Examples:
>>> kmt = KernelMultiTask(KernelGaussian(d=2),num_tasks=3,diag=[1,2,3])
>>> x = np.random.rand(4,2)
>>> task = np.arange(3)
>>> kmt(task[1],task[1],x[0],x[0]).item()
3.0
>>> kmt(task,task,x[0],x[0])
array([2., 3., 4.])
>>> kmt(task[:,None],task[None,:],x[0],x[0]).shape
(3, 3)
>>> kmt(task[1],task[1],x,x,)
array([3., 3., 3., 3.])
>>> kmt(task,task,x[:3],x[:3])
array([2., 3., 4.])
>>> kmt(task[:,None],task[:,None],x,x).shape
(3, 4)
>>> v = kmt(task,task,x[:3,None,:],x[None,:3,:])
>>> v.shape
(3, 3)
>>> np.allclose(v,kmt.base_kernel(x[:3,None,:],x[None,:3,:])*kmt.taskmat[task,task])
True
>>> kmt(task[:,None,None],task[:,None,None],x[:,None,:],x[None,:,:]).shape
(3, 4, 4)
>>> kmt(task[:,None,None,None],task[None,:,None,None],x[:,None,:],x[None,:,:]).shape
(3, 3, 4, 4)
Batched inference
>>> kernel_base = KernelGaussian(d=10,shape_lengthscales=(5,1),shape_scale=(3,5,1))
>>> rng = np.random.Generator(np.random.PCG64(7))
>>> kmt = KernelMultiTask(kernel_base,
... num_tasks=4,
... shape_factor=(6,3,5,4,2),
... diag = rng.uniform(low=0,high=1,size=(3,5,4)))
>>> x = np.random.rand(8,10)
>>> task = np.arange(4)
>>> kmt(task[0],task[0],x[0],x[0]).shape
(6, 3, 5)
>>> kmt(task,task,x[0],x[0]).shape
(6, 3, 5, 4)
>>> kmt(task[0],task[0],x,x).shape
(6, 3, 5, 8)
>>> v = kmt(task,task,x[:4,None,:],x[None,:4,:])
>>> v.shape
(6, 3, 5, 4, 4)
>>> kmat_x = kmt.base_kernel(x[:4,None,:],x[None,:4,:])
>>> kmat_x.shape
(3, 5, 4, 4)
>>> kmat_tasks = kmt.taskmat[...,task,task]
>>> kmat_tasks.shape
(6, 3, 5, 4)
>>> np.allclose(v,kmat_tasks[...,None,:]*kmat_x)
True
>>> np.allclose(v,kmat_tasks[...,:,None]*kmat_x)
False
>>> kmt(task[:,None,None,None],task[None,:,None,None],x[:,None,:],x[None,:,:]).shape
(6, 3, 5, 4, 4, 8, 8)
>>> kmt(task[:,None],task[None,:],x[:,None,None,None,:],x[None,:,None,None,:]).shape
(6, 3, 5, 8, 8, 4, 4)
Integrals
>>> kernel = KernelGaussian(
... d = 2,
... scale = rng.uniform(low=0,high=1,size=(3,1)),
... lengthscales = rng.uniform(low=0,high=1,size=(1,2)))
>>> kmt = KernelMultiTask(
... base_kernel=kernel,
... num_tasks=5,
... diag = rng.uniform(low=0,high=1,size=(6,3,5)),
... factor = rng.uniform(low=0,high=1,size=(3,5,2)))
>>> task = np.arange(5)
>>> kmt.double_integral_01d(task0=task[0],task1=task[1]).shape
(6, 3)
>>> kmt.double_integral_01d(task0=task,task1=task).shape
(6, 3, 5)
>>> kmt.double_integral_01d(task0=task[:,None],task1=task[None,:]).shape
(6, 3, 5, 5)
>>> x = rng.uniform(low=0,high=1,size=(7,4,2))
>>> kmt.single_integral_01d(task0=task[0],task1=task[1],x=x).shape
(6, 3, 7, 4)
>>> kmt.single_integral_01d(task0=task[:,None,None],task1=task[:,None,None],x=x).shape
(6, 3, 5, 7, 4)
>>> kmt.single_integral_01d(task0=task[:,None,None,None],task1=task[None,:,None,None],x=x).shape
(6, 3, 5, 5, 7, 4)
Cholesky Construction
>>> kmt = KernelMultiTask(
... KernelGaussian(5),
... num_tasks = 3,
... method = "CHOLESKY",
... factor = 2,
... diag = 1.5,
... )
>>> kmt.taskmat
array([[ 2.25, 3. , 3. ],
[ 3. , 6.25, 7. ],
[ 3. , 7. , 10.25]])
>>> kmt = KernelMultiTask(
... KernelGaussian(5),
... num_tasks = 3,
... method = "CHOLESKY",
... factor = 2,
... diag = 1.5,
... shape_factor = [2,3*(1+3)//2-3],
... shape_diag = [3],
... )
>>> kmt.taskmat
array([[[ 2.25, 3. , 3. ],
[ 3. , 6.25, 7. ],
[ 3. , 7. , 10.25]],
[[ 2.25, 3. , 3. ],
[ 3. , 6.25, 7. ],
[ 3. , 7. , 10.25]]])
>>> kmt = KernelMultiTask(
... KernelGaussian(5),
... num_tasks = 3,
... method = "CHOLESKY",
... factor = 2,
... diag = 1.5,
... shape_factor = [3*(1+3)//2-3],
... shape_diag = [2,3],
... )
>>> kmt.taskmat
array([[[ 2.25, 3. , 3. ],
[ 3. , 6.25, 7. ],
[ 3. , 7. , 10.25]],
[[ 2.25, 3. , 3. ],
[ 3. , 6.25, 7. ],
[ 3. , 7. , 10.25]]])
>>> kmt = KernelMultiTask(
... KernelGaussian(5),
... num_tasks = 3,
... method = "CHOLESKY",
... factor = 2,
... diag = 1.5,
... shape_factor = [2,3*(1+3)//2-3],
... shape_diag = [2,3],
... )
>>> kmt.taskmat
array([[[ 2.25, 3. , 3. ],
[ 3. , 6.25, 7. ],
[ 3. , 7. , 10.25]],
[[ 2.25, 3. , 3. ],
[ 3. , 6.25, 7. ],
[ 3. , 7. , 10.25]]])
PyTorch
>>> import torch
>>> kmt = KernelMultiTask(KernelGaussian(d=2,torchify=True),num_tasks=3,diag=[1,2,3])
>>> x = torch.from_numpy(np.random.rand(4,2))
>>> task = np.arange(3)
>>> kmt(task[1],task[1],x[0],x[0]).item()
3.0
>>> kmt(task,task,x[0],x[0])
tensor([2., 3., 4.], dtype=torch.float64, grad_fn=<SelectBackward0>)
>>> kmt(task[:,None],task[None,:],x[0],x[0]).shape
torch.Size([3, 3])
>>> kmt(task[1],task[1],x,x)
tensor([3., 3., 3., 3.], dtype=torch.float64, grad_fn=<SelectBackward0>)
>>> kmt(task,task,x[:3],x[:3])
tensor([2., 3., 4.], dtype=torch.float64, grad_fn=<SelectBackward0>)
>>> kmt(task[:,None],task[:,None],x,x).shape
torch.Size([3, 4])
>>> v = kmt(task,task,x[:3,None,:],x[None,:3,:])
>>> v.shape
torch.Size([3, 3])
>>> torch.allclose(v,kmt.base_kernel(x[:3,None,:],x[None,:3,:])*kmt.taskmat[task,task])
True
>>> kmt(task[:,None,None],task[:,None,None],x[:,None,:],x[None,:,:]).shape
torch.Size([3, 4, 4])
>>> kmt(task[:,None,None,None],task[None,:,None,None],x[:,None,:],x[None,:,:]).shape
torch.Size([3, 3, 4, 4])
Batched inference
>>> kernel_base = KernelGaussian(d=10,shape_lengthscales=(5,1),shape_scale=(3,5,1),torchify=True)
>>> rng = np.random.Generator(np.random.PCG64(7))
>>> kmt = KernelMultiTask(kernel_base,
... num_tasks=4,
... shape_factor=(6,3,5,4,2),
... diag = rng.uniform(low=0,high=1,size=(3,5,4)))
>>> x = torch.from_numpy(np.random.rand(8,10))
>>> task = torch.arange(4)
>>> kmt(task[0],task[0],x[0],x[0]).shape
torch.Size([6, 3, 5])
>>> kmt(task,task,x[0],x[0]).shape
torch.Size([6, 3, 5, 4])
>>> kmt(task[0],task[0],x,x).shape
torch.Size([6, 3, 5, 8])
>>> v = kmt(task,task,x[:4,None,:],x[None,:4,:])
>>> v.shape
torch.Size([6, 3, 5, 4, 4])
>>> kmat_x = kmt.base_kernel(x[:4,None,:],x[None,:4,:])
>>> kmat_x.shape
torch.Size([3, 5, 4, 4])
>>> kmat_tasks = kmt.taskmat[...,task,task]
>>> kmat_tasks.shape
torch.Size([6, 3, 5, 4])
>>> torch.allclose(v,kmat_tasks[...,None,:]*kmat_x)
True
>>> torch.allclose(v,kmat_tasks[...,:,None]*kmat_x)
False
>>> kmt(task[:,None,None,None],task[None,:,None,None],x[:,None,:],x[None,:,:]).shape
torch.Size([6, 3, 5, 4, 4, 8, 8])
>>> kmt(task[:,None],task[None,:],x[:,None,None,None,:],x[None,:,None,None,:]).shape
torch.Size([6, 3, 5, 8, 8, 4, 4])
>>> kmt.factor.dtype
torch.float32
>>> kmt.diag.dtype
torch.float64
Integrals
>>> kernel = KernelGaussian(
... d = 2,
... torchify = True,
... scale = rng.uniform(low=0,high=1,size=(3,1)),
... lengthscales = rng.uniform(low=0,high=1,size=(1,2)))
>>> kmt = KernelMultiTask(
... base_kernel=kernel,
... num_tasks=5,
... diag = rng.uniform(low=0,high=1,size=(6,3,5)),
... factor = rng.uniform(low=0,high=1,size=(3,5,2)))
>>> task = torch.arange(5)
>>> kmt.double_integral_01d(task0=task[0],task1=task[1]).shape
torch.Size([6, 3])
>>> kmt.double_integral_01d(task0=task,task1=task).shape
torch.Size([6, 3, 5])
>>> kmt.double_integral_01d(task0=task[:,None],task1=task[None,:]).shape
torch.Size([6, 3, 5, 5])
>>> x = torch.from_numpy(rng.uniform(low=0,high=1,size=(7,4,2)))
>>> kmt.single_integral_01d(task0=task[0],task1=task[1],x=x).shape
torch.Size([6, 3, 7, 4])
>>> kmt.single_integral_01d(task0=task[:,None,None],task1=task[:,None,None],x=x).shape
torch.Size([6, 3, 5, 7, 4])
>>> kmt.single_integral_01d(task0=task[:,None,None,None],task1=task[None,:,None,None],x=x).shape
torch.Size([6, 3, 5, 5, 7, 4])
Cholesky Construction
>>> kmt = KernelMultiTask(
... KernelGaussian(5,torchify=True),
... num_tasks = 3,
... method = "CHOLESKY",
... factor = 2,
... diag = 1.5,
... )
>>> kmt.taskmat
tensor([[ 2.2500, 3.0000, 3.0000],
[ 3.0000, 6.2500, 7.0000],
[ 3.0000, 7.0000, 10.2500]], grad_fn=<ViewBackward0>)
>>> kmt = KernelMultiTask(
... KernelGaussian(5,torchify=True),
... num_tasks = 3,
... method = "CHOLESKY",
... factor = 2,
... diag = 1.5,
... shape_factor = [2,3*(1+3)//2-3],
... shape_diag = [3],
... )
>>> kmt.taskmat
tensor([[[ 2.2500, 3.0000, 3.0000],
[ 3.0000, 6.2500, 7.0000],
[ 3.0000, 7.0000, 10.2500]],
[[ 2.2500, 3.0000, 3.0000],
[ 3.0000, 6.2500, 7.0000],
[ 3.0000, 7.0000, 10.2500]]], grad_fn=<ViewBackward0>)
>>> kmt = KernelMultiTask(
... KernelGaussian(5,torchify=True),
... num_tasks = 3,
... method = "CHOLESKY",
... factor = 2,
... diag = 1.5,
... shape_factor = [3*(1+3)//2-3],
... shape_diag = [2,3],
... )
>>> kmt.taskmat
tensor([[[ 2.2500, 3.0000, 3.0000],
[ 3.0000, 6.2500, 7.0000],
[ 3.0000, 7.0000, 10.2500]],
[[ 2.2500, 3.0000, 3.0000],
[ 3.0000, 6.2500, 7.0000],
[ 3.0000, 7.0000, 10.2500]]], grad_fn=<ViewBackward0>)
>>> kmt = KernelMultiTask(
... KernelGaussian(5,torchify=True),
... num_tasks = 3,
... method = "CHOLESKY",
... factor = 2,
... diag = 1.5,
... shape_factor = [2,3*(1+3)//2-3],
... shape_diag = [2,3],
... )
>>> kmt.taskmat
tensor([[[ 2.2500, 3.0000, 3.0000],
[ 3.0000, 6.2500, 7.0000],
[ 3.0000, 7.0000, 10.2500]],
[[ 2.2500, 3.0000, 3.0000],
[ 3.0000, 6.2500, 7.0000],
[ 3.0000, 7.0000, 10.2500]]], grad_fn=<ViewBackward0>)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
base_kernel
|
AbstractKernel
|
\(K_{\mathrm{base}}\). |
required |
num_tasks
|
int
|
Number of tasks \(T>1\). |
required |
factor
|
Union[ndarray, Tensor]
|
Factor \(\mathsf{F}\). |
1.0
|
diag
|
Union[ndarray, Tensor]
|
Diagonal parameter \(\boldsymbol{v}\). |
1.0
|
shape_factor
|
list
|
Shape of |
None
|
shape_diag
|
list
|
Shape of |
None
|
tfs_factor
|
Tuple[callable, callable]
|
The first argument transforms to the raw value to be optimized; the second applies the inverse transform. |
(tf_identity, tf_identity)
|
tfs_diag
|
Tuple[callable, callable]
|
The first argument transforms to the raw value to be optimized; the second applies the inverse transform. |
(tf_exp_eps_inv, tf_exp_eps)
|
requires_grad_factor
|
bool
|
If |
True
|
requires_grad_diag
|
bool
|
If |
True
|
method
|
str
|
|
'LOW RANK'
|
Source code in qmcpy/kernel/multitask_kernel.py
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 | |
__call__
Evaluate the kernel with (optional) partial derivatives
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
task0
|
Union[int, ndarray, Tensor]
|
First task indices \(i_0\). |
required |
task1
|
Union[int, ndarray, Tensor]
|
Second task indices \(i_1\). |
required |
x0
|
Union[ndarray, Tensor]
|
Shape |
required |
x1
|
Union[ndarray, Tensor]
|
Shape |
required |
beta0
|
Union[ndarray, Tensor]
|
Shape |
None
|
beta1
|
Union[ndarray, Tensor]
|
Shape |
None
|
c
|
Union[ndarray, Tensor]
|
Shape |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
k |
Union[ndarray, Tensor]
|
Kernel evaluations with batched shape, see the doctests for examples. |
Source code in qmcpy/kernel/multitask_kernel.py
single_integral_01d
Evaluate the integral of the kernel over the unit cube
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
task0
|
Union[int, ndarray, Tensor]
|
First task indices \(i_0\). |
required |
task1
|
Union[int, ndarray, Tensor]
|
Second task indices \(i_1\). |
required |
x
|
Union[ndarray, Tensor]
|
Shape |
required |
Returns:
| Name | Type | Description |
|---|---|---|
tildek |
Union[ndarray, Tensor]
|
Shape |
Source code in qmcpy/kernel/multitask_kernel.py
double_integral_01d
Evaluate the integral of the kernel over the unit cube
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
task0
|
Union[int, ndarray, Tensor]
|
First task indices \(i_0\). |
required |
task1
|
Union[int, ndarray, Tensor]
|
Second task indices \(i_1\). |
required |
Returns:
| Name | Type | Description |
|---|---|---|
tildek |
Union[ndarray, Tensor]
|
Double integral kernel evaluations. |