skip_on_cran() test_that("matrix ops infer destination sizes for assignments", { matmul_infer <- function(A, B) { declare(type(A = double(2, 3)), type(B = double(3, 2))) out <- A %*% B out } matvec_infer <- function(A, x) { declare(type(A = double(2, 3)), type(x = double(3))) out <- A %*% x out } vecmat_infer <- function(x, A) { declare(type(x = double(2)), type(A = double(2, 3))) out <- x %*% A out } cross_infer <- function(x) { declare(type(x = double(4, 3))) out <- crossprod(x) out } cross_infer2 <- function(x, y) { declare(type(x = double(4, 3)), type(y = double(4, 2))) out <- crossprod(x, y) out } tcross_infer <- function(x) { declare(type(x = double(4, 3))) out <- tcrossprod(x) out } tcross_infer2 <- function(x, y) { declare(type(x = double(4, 3)), type(y = double(2, 3))) out <- tcrossprod(x, y) out } outer_infer <- function(x, y) { declare(type(x = double(2)), type(y = double(3))) out <- outer(x, y) out } outer_op_infer <- function(x, y) { declare(type(x = double(2)), type(y = double(3))) out <- x %o% y out } forward_infer <- function(L, b) { declare(type(L = double(2, 2)), type(b = double(2, 2))) out <- forwardsolve(L, b) out } back_infer <- function(U, b) { declare(type(U = double(2, 2)), type(b = double(2))) out <- backsolve(U, b) out } solve_vec_infer <- function(A, b) { declare(type(A = double(n, n)), type(b = double(n))) out <- solve(A, b) out } solve_mat_infer <- function(A, B) { declare(type(A = double(n, n)), type(B = double(n, k))) out <- solve(A, B) out } solve_inv_infer <- function(A) { declare(type(A = double(n, n))) out <- solve(A) out } chol_infer <- function(A) { declare(type(A = double(n, n))) out <- chol(A) out } chol2inv_infer <- function(A) { declare(type(A = double(n, n))) out <- chol2inv(chol(A)) out } set.seed(99) n <- 4 k <- 2 A <- matrix(rnorm(6), nrow = 2) B <- matrix(rnorm(6), nrow = 3) x2 <- rnorm(2) x3 <- rnorm(3) X <- matrix(rnorm(12), nrow = 4) Yc <- matrix(rnorm(8), nrow = 4) Yt <- matrix(rnorm(6), nrow = 2) v2 <- rnorm(2) v3 <- rnorm(3) L <- matrix(c(2, 0, 1, 3), nrow = 2, byrow = TRUE) U <- matrix(c(2, 1, 0, 3), nrow = 2, byrow = TRUE) b_mat <- matrix(rnorm(4), nrow = 2) b_vec <- rnorm(2) base <- matrix(rnorm(n * n), n, n) A_pd <- crossprod(base) + diag(n) b_solve <- rnorm(n) B_solve <- matrix(rnorm(n * k), n, k) expect_quick_equal(matmul_infer, list(A = A, B = B)) expect_quick_equal(matvec_infer, list(A = A, x = x3)) expect_quick_equal(vecmat_infer, list(x = x2, A = A)) expect_quick_equal(cross_infer, list(x = X)) expect_quick_equal(cross_infer2, list(x = X, y = Yc)) expect_quick_equal(tcross_infer, list(x = X)) expect_quick_equal(tcross_infer2, list(x = X, y = Yt)) expect_quick_equal(outer_infer, list(x = v2, y = v3)) expect_quick_equal(outer_op_infer, list(x = v2, y = v3)) expect_quick_equal(forward_infer, list(L = L, b = b_mat)) expect_quick_equal(back_infer, list(U = U, b = b_vec)) expect_quick_equal(solve_vec_infer, list(A = A_pd, b = b_solve)) expect_quick_equal(solve_mat_infer, list(A = A_pd, B = B_solve)) expect_quick_equal(solve_inv_infer, list(A = A_pd)) expect_quick_equal(chol_infer, list(A = A_pd)) expect_quick_equal(chol2inv_infer, list(A = A_pd)) }) test_that("crossprod requires conformability at compile time", { fn <- function(x, y, n, p, m, k) { declare( type(n = integer(1)), type(p = integer(1)), type(m = integer(1)), type(k = integer(1)), type(x = double(n, m)), type(y = double(p, k)) ) crossprod(x, y) } expect_error( quick(fn), "cannot verify conformability in crossprod", fixed = TRUE ) }) test_that("matrix helpers report unsupported inputs", { matmul_bad_rank <- function(a, b) { declare(type(a = double(2, 2, 2)), type(b = double(2, 2))) a %*% b } transpose_bad_rank <- function(x) { declare(type(x = double(2, 2, 2))) t(x) } outer_bad_rank <- function(x, y) { declare(type(x = double(2, 2)), type(y = double(2))) outer(x, y) } outer_missing <- function(x) { declare(type(x = double(2))) outer(x) } forward_k <- function(L, b) { declare(type(L = double(2, 2)), type(b = double(2))) forwardsolve(L, b, k = 1) } back_bad_upper <- function(U, b, flag) { declare( type(U = double(2, 2)), type(b = double(2)), type(flag = logical(1)) ) backsolve(U, b, upper.tri = flag) } back_bad_A <- function(A, b) { declare(type(A = double(2)), type(b = double(2))) backsolve(A, b) } back_bad_B <- function(U, b) { declare(type(U = double(2, 2)), type(b = double(2, 2, 2))) backsolve(U, b) } expect_error(quick(matmul_bad_rank), "%\\*% only supports vectors/matrices") expect_error(quick(transpose_bad_rank), "t\\(\\) only supports rank 0-2") expect_error(quick(outer_bad_rank), "outer\\(\\) only supports vectors") expect_error(quick(outer_missing), "outer\\(\\) expects X and Y") expect_error(quick(forward_k), "forwardsolve\\(\\) does not support k") expect_error(quick(back_bad_upper), "only supports literal upper\\.tri") expect_error(quick(back_bad_A), "triangular solve expects a matrix") expect_error(quick(back_bad_B), "triangular solve only supports vector") }) test_that("matrix conformability warnings are surfaced", { matmul_warn <- function(A, B, n, m, k) { declare( type(n = integer(1)), type(m = integer(1)), type(k = integer(1)), type(A = double(n, m)), type(B = double(k, n)) ) A %*% B } expect_warning( quick(matmul_warn), "cannot verify conformability in %\\*%" ) })