For R Users

torch-openreml can be used in R through the reticulate package. We recommend installing torch-openreml inside a dedicated conda environment.

Installation

1. Install Conda

You can skip this step if conda is already installed on your system.

if (is.null(reticulate:::find_conda()[[1]])) {
    reticulate::install_miniconda()
}

2. Create a Conda Environment

if (reticulate::condaenv_exists("torch-openreml")) {
    reticulate::conda_remove("torch-openreml")
}

reticulate::conda_create("torch-openreml",
                         python_version = "3.12.12")

3. Install torch-openreml

reticulate::conda_install("torch-openreml",
                          pip = TRUE,
                          packages = c("git+https://github.com/anu-aagi/torch-openreml.git"))

Usage

The following example mirrors the Getting Started example. In R, it is often more convenient to construct design matrices directly using model.matrix(). As in Python, a matrix dimension may be given as the grouping factor itself, whose distinct values define the dimension.

library(reticulate)
use_condaenv("torch-openreml")

openreml <- import("torch_openreml", convert = FALSE)
torch <- import("torch", convert = FALSE)

BlockDiagonal <- openreml$covariance$BlockDiagonal
ScalarMatrix <- openreml$covariance$ScalarMatrix
IdentityMatrix <- openreml$covariance$IdentityMatrix
KroneckerProduct <- openreml$covariance$KroneckerProduct
CovariancePropagation <- openreml$covariance$CovariancePropagation
Sum <- openreml$covariance$Sum
MarginalREML <- openreml$MarginalREML

data <- agridat::john.alpha
n <- nrow(data)

y <- torch$tensor(data$yield, dtype = torch$float32)
X <- model.matrix(~ rep, data = data) |>
    torch$tensor(dtype = torch$float32)

Z <- model.matrix(~ 0 + gen + block:rep, data = data) |>
    torch$tensor(dtype = torch$float32)

V <- Sum(
    random = CovariancePropagation(
        Z = Z,
        G = BlockDiagonal(
            G_gen = ScalarMatrix(data$gen),
            G_rep_block = KroneckerProduct(
                G_rep = IdentityMatrix(data$rep),
                G_block = ScalarMatrix(data$block)
            )
        )
    ),
    residual = ScalarMatrix(n)
)

fit_openreml <- MarginalREML(V)
result <- fit_openreml$optimize(y, X, torch$zeros(3L), verbose = 1L)

print(py_to_r(fit_openreml$get_theta()$numpy()))
print(py_to_r(V$build_params(fit_openreml$get_theta())$numpy()))
print(py_to_r(fit_openreml$get_beta()$numpy()))

Random effects are predicted with the same best linear unbiased predictor (BLUP) as in the Python example. The joint design and covariance matrices are read back from the fitted covariance structure with V.tree, which evaluates the structure at the estimated parameters and returns each node under its path: "random/Z" and "random/G" hold \(\mathbf{Z}\) and \(\mathbf{G}\), and the root "/" holds \(\mathbf{V}\). Note that reticulate indexes Python objects from zero, so [[0]] selects the results from the (results, free_params_by_path) pair that tree() returns.

tree <- V$tree(fit_openreml$get_theta())[[0]]

b_hat <- openreml$blup(y, X, tree[["random/Z"]], tree[["random/G"]], tree[["/"]])
print(py_to_r(b_hat$numpy()))

The BLUPs of a single random-effect component follow the same pattern. Here the design matrix is a plain tensor built by model.matrix(), so the columns of the gen term are built on their own, while its covariance is the "random/G/G_gen" node of the tree.

Z_gen <- model.matrix(~ 0 + gen, data = data) |>
    torch$tensor(dtype = torch$float32)
gen_blup <- openreml$blup(y, X, Z_gen, tree[["random/G/G_gen"]], tree[["/"]])
print(setNames(py_to_r(gen_blup$numpy()), levels(data$gen)))
[  1] ∥∇∥:      41.8197, ∥Δ∥: 8.9438, η: 1.00, ∥Δᶜ∥: 8.9438, log 𝓛: -34.3129
[  2] ∥∇∥:  315227.5000, ∥Δ∥: 0.8838, η: 1.00, ∥Δᶜ∥: 0.8838, log 𝓛: -201185.4531 (-201151.1402)
[  3] ∥∇∥:  119231.8828, ∥Δ∥: 0.8520, η: 1.00, ∥Δᶜ∥: 0.8520, log 𝓛: -71845.0547 (+129340.3984)
[  4] ∥∇∥:   44274.7461, ∥Δ∥: 0.8143, η: 1.00, ∥Δᶜ∥: 0.8143, log 𝓛: -26065.9766 (+45779.0781)
[  5] ∥∇∥:   16330.8594, ∥Δ∥: 0.7587, η: 1.00, ∥Δᶜ∥: 0.7587, log 𝓛: -9457.3301 (+16608.6465)
[  6] ∥∇∥:    6001.5020, ∥Δ∥: 0.7142, η: 1.00, ∥Δᶜ∥: 0.7142, log 𝓛: -3392.9321 (+6064.3979)
[  7] ∥∇∥:    2194.9365, ∥Δ∥: 0.7031, η: 1.00, ∥Δᶜ∥: 0.7031, log 𝓛: -1181.3032 (+2211.6289)
[  8] ∥∇∥:     793.7987, ∥Δ∥: 0.6952, η: 1.00, ∥Δᶜ∥: 0.6952, log 𝓛: -382.4990 (+798.8043)
[  9] ∥∇∥:     278.6925, ∥Δ∥: 0.6715, η: 1.00, ∥Δᶜ∥: 0.6715, log 𝓛: -102.3015 (+280.1974)
[ 10] ∥∇∥:      90.4133, ∥Δ∥: 0.5957, η: 1.00, ∥Δᶜ∥: 0.5957, log 𝓛: -11.4285 (+90.8730)
[ 11] ∥∇∥:      23.9223, ∥Δ∥: 0.4006, η: 1.00, ∥Δᶜ∥: 0.4006, log 𝓛:  12.6798 (+24.1083)
[ 12] ∥∇∥:       3.8675, ∥Δ∥: 0.1392, η: 1.00, ∥Δᶜ∥: 0.1392, log 𝓛:  16.5909 (+3.9112)
[ 13] ∥∇∥:       0.2448, ∥Δ∥: 0.0157, η: 1.00, ∥Δᶜ∥: 0.0157, log 𝓛:  16.8083 (+0.2174)
[ 14] ∥∇∥:       0.0104, ∥Δ∥: 0.0007, η: 1.00, ∥Δᶜ∥: 0.0007, log 𝓛:  16.8100 (+0.0017)
[ 15] ∥∇∥:       0.0004, ∥Δ∥: 0.0000, η: 1.00, ∥Δᶜ∥: 0.0000, log 𝓛:  16.8095 (-0.0004)
[ 16] ∥∇∥:       0.0000, ∥Δ∥: 0.0000, η: 1.00, ∥Δᶜ∥: 0.0000, log 𝓛:  16.8101 (+0.0005)
[ 17] ∥∇∥:       0.0000, ∥Δ∥: 0.0000, η: 1.00, ∥Δᶜ∥: 0.0000, log 𝓛:  16.8102 (+0.0001)
[ 18] ∥∇∥:       0.0000, ∥Δ∥: 0.0000, η: 1.00, ∥Δᶜ∥: 0.0000, log 𝓛:  16.8099 (-0.0003)
[ 19] ∥∇∥:       0.0000, ∥Δ∥: 0.0000, η: 1.00, ∥Δᶜ∥: 0.0000, log 𝓛:  16.8102 (+0.0003)
[ 20] ∥∇∥:       0.0000, ∥Δ∥: 0.0000, η: 1.00, ∥Δᶜ∥: 0.0000, log 𝓛:  16.8100 (-0.0002)
[ 21] ∥∇∥:       0.0000, ∥Δ∥: 0.0000, η: 1.00, ∥Δᶜ∥: 0.0000, log 𝓛:  16.8104 (+0.0004)
[ 22] ∥∇∥:       0.0000, ∥Δ∥: 0.0000, η: 1.00, ∥Δᶜ∥: 0.0000, log 𝓛:  16.8103 (-0.0002)
[ 23] ∥∇∥:       0.0000, ∥Δ∥: 0.0000, η: 1.00, ∥Δᶜ∥: 0.0000, log 𝓛:  16.8097 (-0.0006)
[ 24] ∥∇∥:       0.0000, ∥Δ∥: 0.0000, η: 1.00, ∥Δᶜ∥: 0.0000, log 𝓛:  16.8097 (-0.0000)

[∇: score, Δ: 𝐉⁻¹∇, η: learning rate, Δᶜ: clip(𝛉 + ηΔ, lb, ub) - 𝛉, 𝓛: restricted likelihood]

✓ Converged at iteration 24, total time: 0.02s

[1] -0.9727983 -1.3280730 -1.2528642
[1] 0.14290193 0.07021832 0.08161612
[1]  4.5182486  0.2978466 -0.4140441
 [1]  0.501183033  0.004962160 -0.784563184  0.006125156  0.474949241
 [6]  0.044639699 -0.308948159  0.062228836 -0.809932053 -0.089373551
[11] -0.196435124  0.225757748  0.231664374  0.243399158  0.424699038
[16]  0.200964108  0.078077391 -0.110181324  0.289575398 -0.338969529
[21]  0.256131411  0.024088217 -0.176998153 -0.253058344  0.123135120
[26] -0.141226426 -0.150395423 -0.106756583  0.073703296  0.201533794
[31] -0.532640934 -0.301233232  0.243239060  0.134878263  0.275336683
[36]  0.180418730  0.050569884 -0.047783885  0.151079014  0.053760849
[41] -0.008047517 -0.199577749
         G01          G02          G03          G04          G05          G06 
 0.501183033  0.004962160 -0.784563184  0.006125156  0.474949241  0.044639699 
         G07          G08          G09          G10          G11          G12 
-0.308948159  0.062228836 -0.809932053 -0.089373551 -0.196435124  0.225757748 
         G13          G14          G15          G16          G17          G18 
 0.231664374  0.243399158  0.424699038  0.200964108  0.078077391 -0.110181324 
         G19          G20          G21          G22          G23          G24 
 0.289575398 -0.338969529  0.256131411  0.024088217 -0.176998153 -0.253058344