# Public-API tests that exercise internal inference/hoisting code paths. # These replace several direct `quickr:::` unit tests while keeping coverage. skip_on_cran() test_that("matrix destination inference gracefully declines non-symbol inputs", { matmul_expr_arg <- function(A, B) { declare(type(A = double(2, 3)), type(B = double(3, 2))) out <- (A + 0.0) %*% B out } crossprod_expr_arg <- function(x) { declare(type(x = double(4, 3))) out <- crossprod((x + 0.0)) out } tcrossprod_expr_arg <- function(x) { declare(type(x = double(4, 3))) out <- tcrossprod((x + 0.0)) out } outer_expr_arg <- function(x, y) { declare(type(x = double(2)), type(y = double(3))) out <- outer((x + 0.0), y) out } backsolve_expr_arg <- function(U, b) { declare(type(U = double(2, 2)), type(b = double(2))) out <- backsolve((U + 0.0), b) out } solve_expr_arg <- function(A, b) { declare(type(A = double(3, 3)), type(b = double(3))) out <- solve((A + 0.0), b) out } diag_expr_arg <- function(x) { declare(type(x = double(3))) out <- diag((x + 0.0)) out } set.seed(1) A <- matrix(rnorm(6), nrow = 2) B <- matrix(rnorm(6), nrow = 3) expect_quick_equal(matmul_expr_arg, list(A = A, B = B)) x <- matrix(rnorm(12), nrow = 4) expect_quick_equal(crossprod_expr_arg, list(x = x)) expect_quick_equal(tcrossprod_expr_arg, list(x = x)) v2 <- rnorm(2) v3 <- rnorm(3) expect_quick_equal(outer_expr_arg, list(x = v2, y = v3)) U <- matrix(c(2, 1, 0, 3), nrow = 2, byrow = TRUE) b2 <- c(1.25, -0.5) expect_quick_equal(backsolve_expr_arg, list(U = U, b = b2)) base <- matrix(rnorm(9), 3, 3) A_pd <- crossprod(base) + diag(3) b3 <- rnorm(3) expect_quick_equal(solve_expr_arg, list(A = A_pd, b = b3)) x3 <- rnorm(3) expect_quick_equal(diag_expr_arg, list(x = x3)) }) test_that("matrix destination inference works for common symbol-based shapes", { # These cases exercise the `dest_infer` helpers without reaching for any # `quickr:::` internals. The key property is that `out` is NOT declared, so # `quickr` must infer its shape from the symbol-based operands. matmul_mm <- function(A, B) { declare(type(A = double(2, 3)), type(B = double(3, 4))) out <- A %*% B out } matmul_mv <- function(A, x) { declare(type(A = double(2, 3)), type(x = double(3))) out <- A %*% x out } matmul_vm <- function(x, A) { declare(type(x = double(3)), type(A = double(3, 4))) out <- x %*% A out } matmul_t_left <- function(A, B) { declare(type(A = double(4, 3)), type(B = double(4, 2))) out <- t(A) %*% B out } matmul_t_right <- function(A, B) { declare(type(A = double(4, 3)), type(B = double(2, 3))) out <- A %*% t(B) out } matmul_t_vector <- function(v, B) { declare(type(v = double(3)), type(B = double(3, 4))) out <- t(v) %*% B out } crossprod_1 <- function(x) { declare(type(x = double(5, 3))) out <- crossprod(x) out } crossprod_2 <- function(x, y) { declare(type(x = double(5, 3)), type(y = double(5, 2))) out <- crossprod(x, y) out } tcrossprod_1 <- function(x) { declare(type(x = double(5, 3))) out <- tcrossprod(x) out } tcrossprod_2 <- function(x, y) { declare(type(x = double(5, 3)), type(y = double(2, 3))) out <- tcrossprod(x, y) out } outer_vv <- function(x, y) { declare(type(x = double(2)), type(y = double(3))) out <- outer(x, y) out } outer_sv <- function(x, y) { declare(type(x = double(1)), type(y = double(3))) out <- outer(x, y) out } triangular_vec <- function(U, b) { declare(type(U = double(2, 2)), type(b = double(2))) out <- backsolve(U, b) out } triangular_mat <- function(U, B) { declare(type(U = double(2, 2)), type(B = double(2, 3))) out <- backsolve(U, B) out } solve_inv <- function(A) { declare(type(A = double(3, 3))) out <- solve(A) out } solve_vec <- function(A, b) { declare(type(A = double(3, 3)), type(b = double(3))) out <- solve(A, b) out } solve_mat <- function(A, B) { declare(type(A = double(3, 3)), type(B = double(3, 2))) out <- solve(A, B) out } chol_out <- function(A) { declare(type(A = double(3, 3))) out <- chol(A) out } chol2inv_out <- function(A) { declare(type(A = double(3, 3))) out <- chol2inv(chol(A)) out } diag_vec <- function(x) { declare(type(x = double(3))) out <- diag(x) out } diag_mat <- function(A) { declare(type(A = double(2, 3))) out <- diag(A) out } diag_missing_x <- function(n) { declare(type(n = integer(1))) out <- diag(nrow = n) out } diag_scalar_symbol_no_nrow <- function() { # Cover the scalar-symbol branch in `infer_dest_diag()` (no nrow/ncol). n <- 3L out <- diag(n) out } diag_vec_with_nrow_ncol <- function(x, n, m) { declare(type(x = double(3)), type(n = integer(1)), type(m = integer(1))) out <- diag(x, nrow = n, ncol = m) out } set.seed(123) A <- matrix(rnorm(2 * 3), nrow = 2) B <- matrix(rnorm(3 * 4), nrow = 3) expect_quick_equal(matmul_mm, list(A = A, B = B)) x3 <- rnorm(3) expect_quick_equal(matmul_mv, list(A = A, x = x3)) expect_quick_equal(matmul_vm, list(x = x3, A = matrix(rnorm(3 * 4), 3, 4))) A43 <- matrix(rnorm(4 * 3), nrow = 4) B42 <- matrix(rnorm(4 * 2), nrow = 4) expect_quick_equal(matmul_t_left, list(A = A43, B = B42)) B23 <- matrix(rnorm(2 * 3), nrow = 2) expect_quick_equal(matmul_t_right, list(A = A43, B = B23)) expect_quick_equal( matmul_t_vector, list(v = x3, B = matrix(rnorm(3 * 4), 3, 4)) ) X <- matrix(rnorm(5 * 3), nrow = 5) Yc <- matrix(rnorm(5 * 2), nrow = 5) Yt <- matrix(rnorm(2 * 3), nrow = 2) expect_quick_equal(crossprod_1, list(x = X)) expect_quick_equal(crossprod_2, list(x = X, y = Yc)) expect_quick_equal(tcrossprod_1, list(x = X)) expect_quick_equal(tcrossprod_2, list(x = X, y = Yt)) v2 <- rnorm(2) v3 <- rnorm(3) expect_quick_equal(outer_vv, list(x = v2, y = v3)) expect_quick_equal(outer_sv, list(x = 1.25, y = v3)) U <- matrix(c(2, 1, 0, 3), nrow = 2, byrow = TRUE) b <- rnorm(2) B_rhs <- matrix(rnorm(2 * 3), nrow = 2) expect_quick_equal(triangular_vec, list(U = U, b = b)) expect_quick_equal(triangular_mat, list(U = U, B = B_rhs)) base <- matrix(rnorm(9), 3, 3) A_pd <- crossprod(base) + diag(3) b3 <- rnorm(3) B32 <- matrix(rnorm(3 * 2), nrow = 3) expect_quick_equal(solve_inv, list(A = A_pd)) expect_quick_equal(solve_vec, list(A = A_pd, b = b3)) expect_quick_equal(solve_mat, list(A = A_pd, B = B32)) expect_quick_equal(chol_out, list(A = A_pd)) expect_quick_equal(chol2inv_out, list(A = A_pd)) expect_quick_equal(diag_vec, list(x = rnorm(3))) expect_quick_equal(diag_mat, list(A = matrix(rnorm(6), nrow = 2))) expect_quick_equal(diag_missing_x, list(n = 3L)) expect_quick_equal(diag_scalar_symbol_no_nrow, list()) expect_quick_equal( diag_vec_with_nrow_ncol, list(x = rnorm(3), n = 4L, m = 2L) ) }) test_that("destination inference declines unsupported triangular/solve forms", { # These are public-facing errors, but they also exercise inference decline # paths (e.g., scalar RHS) without directly calling internal helpers. backsolve_scalar_rhs <- function(U, b) { declare(type(U = double(2, 2)), type(b = double(1))) out <- backsolve(U, b) out } solve_scalar_rhs <- function(A, b) { declare(type(A = double(2, 2)), type(b = double(1))) out <- solve(A, b) out } expect_error( quick(backsolve_scalar_rhs), regexp = "non-conformable arguments in triangular solve|expects a vector or matrix" ) expect_error( quick(solve_scalar_rhs), regexp = "non-conformable arguments in solve|expects a vector or matrix" ) })