Skip to content

Commit 32b44c7

Browse files
committed
Add more tests to get better coverage and try to simplefy some code by remove many if() with assert functions.
1 parent db9b10d commit 32b44c7

5 files changed

Lines changed: 506 additions & 115 deletions

File tree

R/r2f-matrix-blas.R

Lines changed: 133 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,78 @@
22

33
# ---- shared matrix helpers (loaded early for implicit collation) ----
44

5+
# Assert hoist is a valid environment for BLAS/LAPACK helpers.
6+
assert_hoist_env <- function(hoist) {
7+
if (!inherits(hoist, "environment")) {
8+
stop("internal: hoist must be a hoist environment")
9+
}
10+
invisible(TRUE)
11+
}
12+
13+
# Assert a Fortran value is a rank-2 matrix.
14+
assert_rank2_matrix <- function(x, message) {
15+
stopifnot(inherits(x, Fortran), is_string(message))
16+
if (x@value@rank != 2L) {
17+
stop(message, call. = FALSE)
18+
}
19+
invisible(TRUE)
20+
}
21+
22+
# Assert a Fortran value is a scalar or vector.
23+
assert_rank_leq1 <- function(x, message) {
24+
stopifnot(inherits(x, Fortran), is_string(message))
25+
if (x@value@rank > 1L) {
26+
stop(message, call. = FALSE)
27+
}
28+
invisible(TRUE)
29+
}
30+
31+
# Assert a Fortran value is rank 0-2.
32+
assert_rank_leq2 <- function(x, message) {
33+
stopifnot(inherits(x, Fortran), is_string(message))
34+
if (x@value@rank > 2L) {
35+
stop(message, call. = FALSE)
36+
}
37+
invisible(TRUE)
38+
}
39+
40+
# Assert right-hand side rank is vector or matrix.
41+
assert_rhs_rank <- function(
42+
rank,
43+
err_scalar,
44+
err_high,
45+
call_scalar = FALSE,
46+
call_high = FALSE
47+
) {
48+
stopifnot(
49+
is_wholenumber(rank),
50+
is_string(err_scalar),
51+
is_string(err_high),
52+
is_bool(call_scalar),
53+
is_bool(call_high)
54+
)
55+
if (rank > 2L) {
56+
stop(err_high, call. = call_high)
57+
}
58+
if (rank == 0L) {
59+
stop(err_scalar, call. = call_scalar)
60+
}
61+
invisible(TRUE)
62+
}
63+
64+
# Assert conformability and warn on unknown.
65+
assert_conformable_dims <- function(left, right, context, err_msg) {
66+
stopifnot(is_string(context), is_string(err_msg))
67+
conform <- check_conformable(left, right)
68+
if (!conform$ok) {
69+
stop(err_msg, call. = FALSE)
70+
}
71+
if (conform$unknown) {
72+
warn_conformability_unknown(left, right, context)
73+
}
74+
invisible(TRUE)
75+
}
76+
577
# Return the R symbol name if operand is a bare symbol; otherwise NULL.
678
symbol_name_or_null <- function(x) {
779
stopifnot(inherits(x, Fortran))
@@ -235,9 +307,7 @@ gemm <- function(
235307
dest = NULL,
236308
context = "gemm"
237309
) {
238-
if (!inherits(hoist, "environment")) {
239-
stop("internal: hoist must be a hoist environment")
240-
}
310+
assert_hoist_env(hoist)
241311
A_name <- ensure_blas_operand_name(left, hoist)
242312
B_name <- ensure_blas_operand_name(right, hoist)
243313

@@ -281,9 +351,7 @@ gemv <- function(
281351
dest = NULL,
282352
context = "gemv"
283353
) {
284-
if (!inherits(hoist, "environment")) {
285-
stop("internal: hoist must be a hoist environment")
286-
}
354+
assert_hoist_env(hoist)
287355
A_name <- ensure_blas_operand_name(A, hoist)
288356
x_name <- ensure_blas_operand_name(x, hoist)
289357

@@ -312,7 +380,8 @@ gemv <- function(
312380
}
313381

314382
symmetrize_upper_to_lower <- function(target, n, hoist) {
315-
stopifnot(is_string(target), inherits(hoist, "environment"))
383+
stopifnot(is_string(target))
384+
assert_hoist_env(hoist)
316385

317386
idx_i <- hoist$declare_tmp(mode = "integer", dims = list(1L))
318387
idx_j <- hoist$declare_tmp(mode = "integer", dims = list(1L))
@@ -341,7 +410,8 @@ diag_length_expr <- function(nrow, ncol, context) {
341410
}
342411

343412
zero_lower_triangle <- function(target, n, hoist) {
344-
stopifnot(is_string(target), inherits(hoist, "environment"))
413+
stopifnot(is_string(target))
414+
assert_hoist_env(hoist)
345415

346416
idx_i <- hoist$declare_tmp(mode = "integer", dims = NULL)
347417
idx_j <- hoist$declare_tmp(mode = "integer", dims = NULL)
@@ -368,9 +438,7 @@ syrk <- function(
368438
dest = NULL,
369439
context = "syrk"
370440
) {
371-
if (!inherits(hoist, "environment")) {
372-
stop("internal: hoist must be a hoist environment")
373-
}
441+
assert_hoist_env(hoist)
374442
X_name <- ensure_blas_operand_name(X, hoist)
375443

376444
x_dims <- matrix_dims(X)
@@ -428,9 +496,7 @@ outer_mul <- function(
428496
dest = NULL,
429497
context = "outer"
430498
) {
431-
if (!inherits(hoist, "environment")) {
432-
stop("internal: hoist must be a hoist environment")
433-
}
499+
assert_hoist_env(hoist)
434500

435501
x <- maybe_cast_double(x)
436502
y <- maybe_cast_double(y)
@@ -482,16 +548,12 @@ triangular_solve <- function(
482548
dest = NULL,
483549
context = "triangular solve"
484550
) {
485-
if (!inherits(hoist, "environment")) {
486-
stop("internal: hoist must be a hoist environment")
487-
}
551+
assert_hoist_env(hoist)
488552

489553
A <- maybe_cast_double(A)
490554
B <- maybe_cast_double(B)
491555

492-
if (A@value@rank != 2L) {
493-
stop("triangular solve expects a matrix")
494-
}
556+
assert_rank2_matrix(A, "triangular solve expects a matrix")
495557

496558
a_dims <- matrix_dims(A)
497559
conform <- check_conformable(a_dims$rows, a_dims$cols)
@@ -504,29 +566,27 @@ triangular_solve <- function(
504566
n <- a_dims$rows
505567

506568
b_rank <- B@value@rank
507-
if (b_rank > 2L) {
508-
stop("triangular solve only supports vector or matrix right-hand sides")
509-
}
510-
if (b_rank == 0L) {
511-
stop("triangular solve expects a vector or matrix right-hand side")
512-
} else if (b_rank == 1L) {
569+
assert_rhs_rank(
570+
b_rank,
571+
err_scalar = "triangular solve expects a vector or matrix right-hand side",
572+
err_high = "triangular solve only supports vector or matrix right-hand sides"
573+
)
574+
if (b_rank == 1L) {
513575
b_len <- dim_or_one(B, 1L)
514-
conform <- check_conformable(n, b_len)
515-
if (!conform$ok) {
516-
stop("non-conformable arguments in triangular solve", call. = FALSE)
517-
}
518-
if (conform$unknown) {
519-
warn_conformability_unknown(n, b_len, "triangular solve")
520-
}
576+
assert_conformable_dims(
577+
n,
578+
b_len,
579+
context = "triangular solve",
580+
err_msg = "non-conformable arguments in triangular solve"
581+
)
521582
} else {
522583
b_rows <- dim_or_one(B, 1L)
523-
conform <- check_conformable(n, b_rows)
524-
if (!conform$ok) {
525-
stop("non-conformable arguments in triangular solve", call. = FALSE)
526-
}
527-
if (conform$unknown) {
528-
warn_conformability_unknown(n, b_rows, "triangular solve")
529-
}
584+
assert_conformable_dims(
585+
n,
586+
b_rows,
587+
context = "triangular solve",
588+
err_msg = "non-conformable arguments in triangular solve"
589+
)
530590
}
531591

532592
A_name <- ensure_blas_operand_name(A, hoist)
@@ -581,51 +641,45 @@ lapack_solve <- function(
581641
dest = NULL,
582642
context = "solve"
583643
) {
584-
if (!inherits(hoist, "environment")) {
585-
stop("internal: hoist must be a hoist environment")
586-
}
644+
assert_hoist_env(hoist)
587645

588646
A <- maybe_cast_double(A)
589647
B <- maybe_cast_double(B)
590648

591-
if (A@value@rank != 2L) {
592-
stop(context, " expects a matrix for `a`", call. = FALSE)
593-
}
649+
assert_rank2_matrix(A, paste0(context, " expects a matrix for `a`"))
594650

595651
a_dims <- matrix_dims(A)
596652
assert_square_matrix(a_dims$rows, a_dims$cols, context)
597653
n <- a_dims$rows
598654

599655
b_rank <- B@value@rank
600-
if (b_rank > 2L) {
601-
stop(
656+
assert_rhs_rank(
657+
b_rank,
658+
err_scalar = paste0(context, " expects a vector or matrix right-hand side"),
659+
err_high = paste0(
602660
context,
603-
" only supports vector or matrix right-hand sides",
604-
call. = FALSE
605-
)
606-
}
607-
if (b_rank == 0L) {
608-
stop(context, " expects a vector or matrix right-hand side", call. = FALSE)
609-
}
661+
" only supports vector or matrix right-hand sides"
662+
),
663+
call_scalar = FALSE,
664+
call_high = FALSE
665+
)
610666

611667
if (b_rank == 1L) {
612668
b_len <- dim_or_one(B, 1L)
613-
conform <- check_conformable(n, b_len)
614-
if (!conform$ok) {
615-
stop("non-conformable arguments in ", context, call. = FALSE)
616-
}
617-
if (conform$unknown) {
618-
warn_conformability_unknown(n, b_len, context)
619-
}
669+
assert_conformable_dims(
670+
n,
671+
b_len,
672+
context = context,
673+
err_msg = paste0("non-conformable arguments in ", context)
674+
)
620675
} else {
621676
b_rows <- dim_or_one(B, 1L)
622-
conform <- check_conformable(n, b_rows)
623-
if (!conform$ok) {
624-
stop("non-conformable arguments in ", context, call. = FALSE)
625-
}
626-
if (conform$unknown) {
627-
warn_conformability_unknown(n, b_rows, context)
628-
}
677+
assert_conformable_dims(
678+
n,
679+
b_rows,
680+
context = context,
681+
err_msg = paste0("non-conformable arguments in ", context)
682+
)
629683
}
630684

631685
A_name <- ensure_blas_operand_name(A, hoist)
@@ -669,14 +723,10 @@ lapack_solve <- function(
669723
}
670724

671725
lapack_inverse <- function(A, scope, hoist, dest = NULL, context = "solve") {
672-
if (!inherits(hoist, "environment")) {
673-
stop("internal: hoist must be a hoist environment")
674-
}
726+
assert_hoist_env(hoist)
675727

676728
A <- maybe_cast_double(A)
677-
if (A@value@rank != 2L) {
678-
stop(context, " expects a matrix for `a`", call. = FALSE)
679-
}
729+
assert_rank2_matrix(A, paste0(context, " expects a matrix for `a`"))
680730

681731
a_dims <- matrix_dims(A)
682732
assert_square_matrix(a_dims$rows, a_dims$cols, context)
@@ -723,14 +773,10 @@ lapack_inverse <- function(A, scope, hoist, dest = NULL, context = "solve") {
723773
}
724774

725775
lapack_chol <- function(A, scope, hoist, dest = NULL, context = "chol") {
726-
if (!inherits(hoist, "environment")) {
727-
stop("internal: hoist must be a hoist environment")
728-
}
776+
assert_hoist_env(hoist)
729777

730778
A <- maybe_cast_double(A)
731-
if (A@value@rank != 2L) {
732-
stop(context, " expects a matrix", call. = FALSE)
733-
}
779+
assert_rank2_matrix(A, paste0(context, " expects a matrix"))
734780

735781
a_dims <- matrix_dims(A)
736782
assert_square_matrix(a_dims$rows, a_dims$cols, context)
@@ -778,14 +824,10 @@ lapack_chol2inv <- function(
778824
dest = NULL,
779825
context = "chol2inv"
780826
) {
781-
if (!inherits(hoist, "environment")) {
782-
stop("internal: hoist must be a hoist environment")
783-
}
827+
assert_hoist_env(hoist)
784828

785829
R <- maybe_cast_double(R)
786-
if (R@value@rank != 2L) {
787-
stop(context, " expects a matrix", call. = FALSE)
788-
}
830+
assert_rank2_matrix(R, paste0(context, " expects a matrix"))
789831

790832
r_dims <- matrix_dims(R)
791833
assert_square_matrix(r_dims$rows, r_dims$cols, context)
@@ -827,14 +869,10 @@ lapack_chol2inv <- function(
827869
}
828870

829871
diag_extract <- function(x, scope, hoist, dest = NULL, context = "diag") {
830-
if (!inherits(hoist, "environment")) {
831-
stop("internal: hoist must be a hoist environment")
832-
}
872+
assert_hoist_env(hoist)
833873

834874
x <- maybe_cast_double(x)
835-
if (x@value@rank != 2L) {
836-
stop(context, " expects a matrix input", call. = FALSE)
837-
}
875+
assert_rank2_matrix(x, paste0(context, " expects a matrix input"))
838876

839877
x_dims <- matrix_dims(x)
840878
diag_len <- diag_length_expr(x_dims$rows, x_dims$cols, context)
@@ -882,14 +920,10 @@ diag_matrix <- function(
882920
dest = NULL,
883921
context = "diag"
884922
) {
885-
if (!inherits(hoist, "environment")) {
886-
stop("internal: hoist must be a hoist environment")
887-
}
923+
assert_hoist_env(hoist)
888924

889925
x <- maybe_cast_double(x)
890-
if (x@value@rank > 1L) {
891-
stop(context, " expects a vector or scalar input", call. = FALSE)
892-
}
926+
assert_rank_leq1(x, paste0(context, " expects a vector or scalar input"))
893927

894928
diag_len <- diag_length_expr(nrow, ncol, context)
895929
x_scalar <- passes_as_scalar(x@value)

R/r2f-matrix-infer.R

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -328,16 +328,20 @@ infer_dest_diag <- function(args, scope) {
328328
return(NULL)
329329
}
330330

331-
# Case: x is a vector or scalar, construct diagonal matrix
331+
# Case: x is a vector or scalar, construct diagonal matrix
332332
if (!is.null(x) && x@rank <= 1L) {
333333
if (has_nrow || has_ncol) {
334334
nrow <- if (has_nrow) infer_size(nrow_arg, scope) else NULL
335335
ncol <- if (has_ncol) infer_size(ncol_arg, scope) else NULL
336336
if (is.null(nrow) && is.null(ncol)) {
337337
return(NULL)
338338
}
339-
if (is.null(nrow)) nrow <- ncol
340-
if (is.null(ncol)) ncol <- nrow
339+
if (is.null(nrow)) {
340+
nrow <- ncol
341+
}
342+
if (is.null(ncol)) {
343+
ncol <- nrow
344+
}
341345
return(Variable("double", list(nrow, ncol)))
342346
}
343347
# No nrow/ncol: square matrix from vector length

0 commit comments

Comments
 (0)