tests/testthat/test-sum_byname.R

test_that("sum_byname() of constants works as expected", {
  # Simple sum of constants
  expect_equal(sum_byname(2, 3), 5)
  expect_equal(sum_byname(2, 3, 4), 9)
  
  # If summed against NULL, return the item.
  expect_equal(sum_byname(NULL, 1), 1)
  expect_equal(sum_byname(2, NULL), 2)
  expect_equal(sum_byname(2, NULL, NULL), 2)
  expect_equal(sum_byname(NULL, NULL, 2, NULL, NULL), 2)
  expect_equal(sum_byname(list(NULL, 1), list(2, 3)), list(2, 4))
  expect_equal(sum_byname(list(NULL, 1, 2), list(2, 3, NULL), list(4, NULL, 5)), list(6, 4, 7))
  # If summed against NA, return NA
  expect_equal(sum_byname(2, NA), NA_integer_)
  expect_equal(sum_byname(3, 2, NA), NA_integer_)
})


test_that("sum_byname() of matrices works as expected", {
  productnames <- c("p1", "p2")
  industrynames <- c("i1", "i2")
  U <- matrix(1:4, ncol = 2, dimnames = list(productnames, industrynames)) %>%
    setrowtype("Products") %>% setcoltype("Industries")

    # If only one argument, return it.
  expect_equal(sum_byname(U), U)
  
  Y <- matrix(1:4, ncol = 2, dimnames = list(rev(productnames), rev(industrynames))) %>%
    setrowtype("Products") %>% setcoltype("Industries")
  Z <- matrix(rev(1:4), ncol = 2, dimnames = list(rev(productnames), rev(industrynames))) %>%
    setrowtype("Products") %>% setcoltype("Industries")
  
  # This is a non-sensical test.  Row and column names are not respected. 
  # Row names, column names, and row and column types come from the first operand (U).
  expect_equal(U + Y, 
               matrix(c(2, 4, 6, 8), ncol = 2, dimnames = dimnames(U)) %>% 
                 setrowtype(rowtype(U)) %>% setcoltype(coltype(U)))
  # Now, row and column names are respected.
  UplusY <- matrix(5, nrow = 2, ncol = 2, dimnames = dimnames(U)) %>%
    setrowtype(rowtype(U)) %>% setcoltype(coltype(U))
  expect_equal(sum_byname(U, Y), UplusY)
  expect_equal(sum_byname(U, Y, Z), sum_byname(U, Z) %>% sum_byname(Y))
  
  expect_equal(sum_byname(U, 100), U + 100)
  expect_equal(sum_byname(200, Y), 200 + Y %>% sort_rows_cols() %>% 
                 setrowtype(rowtype(Y)) %>% 
                 setcoltype(coltype(Y)))
  
  # This is a non-sensical test.  Row and column names are not respected.
  # Row names, column names, and row and column types come from the first operand (U).
  V <- matrix(1:4, ncol = 2, dimnames = list(industrynames, productnames)) %>%
    setrowtype("Industries") %>% setcoltype("Products")
  expect_equal(U + V,
               matrix(c(2, 4, 6, 8), ncol = 2, dimnames = dimnames(U)) %>% 
                 setrowtype(rowtype(U)) %>% setcoltype(coltype(U)))
  
  # We should not be able to add U and V, because their row and column types differ.
  # Would like to test for entire error message which is 
  # "rowtype(a) == rowtype(b) is not TRUE"
  # However, it seems that the testthat package has trouble dealing with "(" in error messages.
  # So, we'll just test for the first word.
  expect_error(sum_byname(U, V), "rowtype")
})


test_that("sum_byname() gives error when they are vectors without row names", {
  a <- matrix(c(1, 2, 3), nrow = 1, dimnames = list(NULL, c("c1", "c2", "c3"))) %>% 
    setcoltype("coltype")
  b <- 2 * a
  
  expect_error(sum_byname(a, b), "NULL dimnames for margin = 1 on a")
})


test_that("sum_byname() of matrices in lists and data frames works as expected", {
  productnames <- c("p1", "p2")
  industrynames <- c("i1", "i2")
  U <- matrix(1:4, ncol = 2, dimnames = list(productnames, industrynames)) %>%
    setrowtype("Products") %>% setcoltype("Industries")
  Y <- matrix(1:4, ncol = 2, dimnames = list(rev(productnames), rev(industrynames))) %>%
    setrowtype("Products") %>% setcoltype("Industries")
  Z <- matrix(rev(1:4), ncol = 2, dimnames = list(rev(productnames), rev(industrynames))) %>%
    setrowtype("Products") %>% setcoltype("Industries")

  UplusY <- matrix(5, nrow = 2, ncol = 2, dimnames = dimnames(U)) %>%
    setrowtype(rowtype(U)) %>% setcoltype(coltype(U))
  UYZ <- sum_byname(U, Y) %>% sum_byname(Z)
  Uplus100 <- U + 100

  # Define a data frame to be used with testing below.
  DF <- data.frame(U = I(list()), Y = I(list()), Z = I(list()))
  DF[[1,"U"]] <- U
  DF[[2,"U"]] <- U
  DF[[1,"Y"]] <- Y
  DF[[2,"Y"]] <- Y
  DF[[1,"Z"]] <- Z
  DF[[2,"Z"]] <- Z
  
  # sum_byname should also work with lists.
  expect_equal(sum_byname(list(U,U), list(Y, Y)), list(UplusY, UplusY))
  expect_equal(sum_byname(list(U,U), list(100,100)), list(Uplus100, Uplus100))
  expect_equal(sum_byname(list(U,U), as.list(rep_len(100, 2))), list(Uplus100, Uplus100))
  
  # sum_byname also should work with data frames, as they are lists.
  expect_equal(sum_byname(DF$U, DF$Y), list(UplusY, UplusY))
  expect_equal(DF %>% dplyr::mutate(sums = sum_byname(U, Y)), 
               DF %>% dplyr::mutate(sums = list(UplusY, UplusY)))
  
  # And sum_byname should work with more than 2 operands.
  expect_equal(sum_byname(DF$U, DF$Y, DF$Z), list(UYZ, UYZ))
})


test_that("sum_byname() of Matrix objects in lists and data frames works as expected", {
  productnames <- c("p1", "p2")
  industrynames <- c("i1", "i2")
  U <- Matrix::Matrix(1:4, ncol = 2, dimnames = list(productnames, industrynames)) %>%
    setrowtype("Products") %>% setcoltype("Industries")
  Y <- Matrix::Matrix(1:4, ncol = 2, dimnames = list(rev(productnames), rev(industrynames))) %>%
    setrowtype("Products") %>% setcoltype("Industries")
  Z <- Matrix::Matrix(rev(1:4), ncol = 2, dimnames = list(rev(productnames), rev(industrynames))) %>%
    setrowtype("Products") %>% setcoltype("Industries")
  
  UplusY <- Matrix::Matrix(5, nrow = 2, ncol = 2, dimnames = dimnames(U)) %>%
    setrowtype(rowtype(U)) %>% setcoltype(coltype(U))
  UYZ <- sum_byname(U, Y) %>% sum_byname(Z)
  Uplus100 <- U + 100
  
  # Define a data frame to be used with testing below.
  DF <- data.frame(U = I(list()), Y = I(list()), Z = I(list()))
  DF[[1,"U"]] <- U
  DF[[2,"U"]] <- U
  DF[[1,"Y"]] <- Y
  DF[[2,"Y"]] <- Y
  DF[[1,"Z"]] <- Z
  DF[[2,"Z"]] <- Z
  
  # sum_byname should also work with lists.
  expect_equal(sum_byname(list(U,U), list(Y, Y)), list(UplusY, UplusY))
  expect_equal(sum_byname(list(U,U), list(100,100)), list(Uplus100, Uplus100))
  expect_equal(sum_byname(list(U,U), as.list(rep_len(100, 2))), list(Uplus100, Uplus100))
  
  # sum_byname also should work with data frames, as they are lists.
  expect_equal(sum_byname(DF$U, DF$Y), list(UplusY, UplusY))
  expect_equal(DF %>% dplyr::mutate(sums = sum_byname(U, Y)), 
               DF %>% dplyr::mutate(sums = list(UplusY, UplusY)))
  
  # And sum_byname should work with more than 2 operands.
  expect_equal(sum_byname(DF$U, DF$Y, DF$Z), list(UYZ, UYZ))
})


test_that("sum_byname() of matrices that are in lists in a cell of a data frame works as expected", {
  test_func <- function(this_U, this_Y, this_Z) {
    UplusY <- matrix(5, nrow = 2, ncol = 2, dimnames = dimnames(this_U)) %>%
      setrowtype(rowtype(this_U)) %>% setcoltype(coltype(this_U))
    UYZ <- sum_byname(this_U, this_Y, this_Z)
    
    ulist <- list(this_U, this_U)
    ylist <- list(this_Y, this_Y)
    zlist <- list(this_Z, this_Z)
    DF <- data.frame(Ulist = I(list()), Ylist = I(list()), Zlist = I(list()))
    # Put lists in each cell of the data frame.
    DF[[1,"Ulist"]] <- ulist
    DF[[2,"Ulist"]] <- ulist
    DF[[1,"Ylist"]] <- ylist
    DF[[2,"Ylist"]] <- ylist
    DF[[1,"Zlist"]] <- zlist
    DF[[2,"Zlist"]] <- zlist
    
    # Operate on the lists in each cell of the data frame.
    res <- DF %>% 
      dplyr::mutate(
        sum = sum_byname(Ulist, Ylist),
        bigsum = sum_byname(Ulist, Ylist, Zlist)
      )
    matsbyname:::expect_equal_matrix_or_Matrix(res$sum[[1]][[1]], UplusY)
    matsbyname:::expect_equal_matrix_or_Matrix(res$sum[[1]][[2]], UplusY)
    matsbyname:::expect_equal_matrix_or_Matrix(res$sum[[2]][[1]], UplusY)
    matsbyname:::expect_equal_matrix_or_Matrix(res$sum[[2]][[2]], UplusY)
    
    matsbyname:::expect_equal_matrix_or_Matrix(res$bigsum[[1]][[1]], UYZ)
    matsbyname:::expect_equal_matrix_or_Matrix(res$bigsum[[1]][[2]], UYZ)
    matsbyname:::expect_equal_matrix_or_Matrix(res$bigsum[[2]][[1]], UYZ)
    matsbyname:::expect_equal_matrix_or_Matrix(res$bigsum[[2]][[2]], UYZ)
  }
  
  # Test with matrix objects
  productnames <- c("p1", "p2")
  industrynames <- c("i1", "i2")
  Um <- matrix(1:4, ncol = 2, dimnames = list(productnames, industrynames)) %>%
    setrowtype("Products") %>% setcoltype("Industries")
  Ym <- matrix(1:4, ncol = 2, dimnames = list(rev(productnames), rev(industrynames))) %>%
    setrowtype("Products") %>% setcoltype("Industries")
  Zm <- matrix(rev(1:4), ncol = 2, dimnames = list(rev(productnames), rev(industrynames))) %>%
    setrowtype("Products") %>% setcoltype("Industries")
  
  test_func(Um, Ym, Zm)

  # Test with Matrix objects
  UM <- Matrix::Matrix(1:4, ncol = 2, dimnames = list(productnames, industrynames)) %>%
    setrowtype("Products") %>% setcoltype("Industries")
  YM <- Matrix::Matrix(1:4, ncol = 2, dimnames = list(rev(productnames), rev(industrynames))) %>%
    setrowtype("Products") %>% setcoltype("Industries")
  ZM <- Matrix::Matrix(rev(1:4), ncol = 2, dimnames = list(rev(productnames), rev(industrynames))) %>%
    setrowtype("Products") %>% setcoltype("Industries")
  
  test_func(UM, YM, ZM)
})


test_that("sum_byname() of matrices that are in lists in a cell of a data frame works as expected", {
  productnames <- c("p1", "p2")
  industrynames <- c("i1", "i2")
  U <- matrix(1:4, ncol = 2, dimnames = list(productnames, industrynames)) %>%
    setrowtype("Products") %>% setcoltype("Industries")
  Y <- matrix(1:4, ncol = 2, dimnames = list(rev(productnames), rev(industrynames))) %>%
    setrowtype("Products") %>% setcoltype("Industries")

  UplusY <- matrix(5, nrow = 2, ncol = 2, dimnames = dimnames(U)) %>%
    setrowtype(rowtype(U)) %>% setcoltype(coltype(U))

  # Now check to see what happens when one of the operands
  # is a list and the other is not.
  DF2 <- data.frame(ulist2_col = I(list()), Y = I(list()))
  # Put lists in each cell of the data frame.
  ulist2 <- list(U, U)
  DF2[[1,"ulist2_col"]] <- ulist2
  DF2[[2,"ulist2_col"]] <- ulist2
  DF2[[1,"Y"]] <- Y
  DF2[[2,"Y"]] <- Y
  res2 <- DF2 %>% 
    dplyr::mutate(
      sum = sum_byname(ulist2_col, Y)
    )
  expect_equal(res2$sum[[1]][[1]], UplusY)
  expect_equal(res2$sum[[1]][[2]], UplusY)
  expect_equal(res2$sum[[2]][[1]], UplusY)
  expect_equal(res2$sum[[2]][[2]], UplusY)
  
  # Try when the matrix length will not be a multiple of the list length.
  U3 <- matrix(1:5, nrow = 5, ncol = 1, dimnames = list(c("p1", "p2", "p3", "p4", "p5"), "i1")) %>% 
    setrowtype("Products") %>% setcoltype("Industries")
  U3plusY <- sum_byname(U3, Y)
  ulist3 <- list(U3, U3, U3)
  DF3 <- data.frame(ulist3_col = I(list()), Y = I(list()))
  DF3[[1,"ulist3_col"]] <- ulist3
  DF3[[2,"ulist3_col"]] <- ulist3
  DF3[[3,"ulist3_col"]] <- ulist3
  DF3[[1,"Y"]] <- Y
  DF3[[2,"Y"]] <- Y
  DF3[[3,"Y"]] <- Y
  res3 <- DF3 %>% 
    dplyr::mutate(
      sum = sum_byname(ulist3_col, Y)
    )
  expect_equal(res3$sum[[1]][[1]], U3plusY)
  expect_equal(res3$sum[[1]][[2]], U3plusY)
  expect_equal(res3$sum[[1]][[3]], U3plusY)
  expect_equal(res3$sum[[2]][[1]], U3plusY)
  expect_equal(res3$sum[[2]][[2]], U3plusY)
  expect_equal(res3$sum[[2]][[3]], U3plusY)
  expect_equal(res3$sum[[3]][[1]], U3plusY)
  expect_equal(res3$sum[[3]][[2]], U3plusY)
  expect_equal(res3$sum[[3]][[3]], U3plusY)
})


test_that("sum_byname() of matrices that are in lists in a cell of a data frame works with Matrix objects", {
  productnames <- c("p1", "p2")
  industrynames <- c("i1", "i2")
  U <- matsbyname::Matrix(1:4, nrow = 2, ncol = 2, dimnames = list(productnames, industrynames)) %>%
    setrowtype("Products") %>% setcoltype("Industries")
  Y <- matsbyname::Matrix(1:4, nrow = 2, ncol = 2, dimnames = list(rev(productnames), rev(industrynames))) %>%
    setrowtype("Products") %>% setcoltype("Industries")
  
  UplusY <- matsbyname::Matrix(5, nrow = 2, ncol = 2, dimnames = dimnames(U)) %>%
    setrowtype(rowtype(U)) %>% setcoltype(coltype(U))
  
  # Now check to see what happens when one of the operands
  # is a list and the other is not.
  DF2 <- data.frame(ulist2_col = I(list()), Y = I(list()))
  # Put lists in each cell of the data frame.
  ulist2 <- list(U, U)
  DF2[[1,"ulist2_col"]] <- ulist2
  DF2[[2,"ulist2_col"]] <- ulist2
  DF2[[1,"Y"]] <- Y
  DF2[[2,"Y"]] <- Y
  res2 <- DF2 %>% 
    dplyr::mutate(
      sum = sum_byname(ulist2_col, Y)
    )
  expect_equal(res2$sum[[1]][[1]], UplusY)
  expect_equal(res2$sum[[1]][[2]], UplusY)
  expect_equal(res2$sum[[2]][[1]], UplusY)
  expect_equal(res2$sum[[2]][[2]], UplusY)
  
  # Try when the matrix length will not be a multiple of the list length.
  U3 <- matsbyname::Matrix(1:5, nrow = 5, ncol = 1, dimnames = list(c("p1", "p2", "p3", "p4", "p5"), "i1")) %>% 
    setrowtype("Products") %>% setcoltype("Industries")
  U3plusY <- sum_byname(U3, Y)
  ulist3 <- list(U3, U3, U3)
  DF3 <- data.frame(ulist3_col = I(list()), Y = I(list()))
  DF3[[1,"ulist3_col"]] <- ulist3
  DF3[[2,"ulist3_col"]] <- ulist3
  DF3[[3,"ulist3_col"]] <- ulist3
  DF3[[1,"Y"]] <- Y
  DF3[[2,"Y"]] <- Y
  DF3[[3,"Y"]] <- Y
  res3 <- DF3 %>% 
    dplyr::mutate(
      sum = sum_byname(ulist3_col, Y)
    )
  expect_equal(res3$sum[[1]][[1]], U3plusY)
  expect_equal(res3$sum[[1]][[2]], U3plusY)
  expect_equal(res3$sum[[1]][[3]], U3plusY)
  expect_equal(res3$sum[[2]][[1]], U3plusY)
  expect_equal(res3$sum[[2]][[2]], U3plusY)
  expect_equal(res3$sum[[2]][[3]], U3plusY)
  expect_equal(res3$sum[[3]][[1]], U3plusY)
  expect_equal(res3$sum[[3]][[2]], U3plusY)
  expect_equal(res3$sum[[3]][[3]], U3plusY)
})


test_that("sum_byname() works as expected via grouping and summarise", {
  df_simple <- tibble::tribble(~key, ~val, 
                               "A", 1, 
                               "A", 2, 
                               "B", 10)
  res_simple <- df_simple %>% 
    dplyr::group_by(key) %>% 
    dplyr::summarise(val = sum(val))
  expected_simple <- tibble::tribble(~key, ~val, 
                                     "A", 3, 
                                     "B", 10)
  expect_equal(res_simple, expected_simple)
  
  # This works differently, and unexpectedly.
  res_simple2 <- df_simple %>% 
    dplyr::group_by(key) %>% 
    # We don't use the .summarise = TRUE condition, so
    # the resuult is just the original data frame (with groups)
    dplyr::reframe(val = sum_byname(val))
  # Here is what we expect.
  expect_equal(res_simple2, df_simple)
  
  res_simple3 <- df_simple %>% 
    dplyr::group_by(key) %>% 
    # Here, we use the .summarise = TRUE argument.
    dplyr::summarise(val = sum_byname(val, .summarise = TRUE))
  # So sum_byname() should produce the column sum along the data frame.
  # The result is a list column, because a list column
  # will also accommodate a list of matrices.
  expected_simple3 <- expected_simple
  expected_simple3$val <- list(3, 10)
  expect_equal(res_simple3, expected_simple3)
  
  m <- matrix(c(11, 12, 13,
                21, 22, 23), nrow = 2, ncol = 3, byrow = TRUE, 
              dimnames = list(c("r1", "r2"), c("c1", "c2", "c3")))
  df <- tibble::tibble(key = c("A", "A", "B"), m = list(m, m, m))
  res <- df %>% 
    dplyr::group_by(key) %>% 
    dplyr::summarise(m = sum_byname(m, .summarise = TRUE))
  expected <- tibble::tibble(key = c("A", "B"), 
                             m = list(2 * m, m))
  expect_equal(res, expected)
  
  # Try summarise with 2 columns
  df2 <- df
  df2$m2 <- list(3*m, 4*m, 5*m)
  res2 <- df2 %>% 
    dplyr::group_by(key) %>% 
    dplyr::summarise(m = sum_byname(m, .summarise = TRUE), m2 = sum_byname(m2, .summarise = TRUE))
  expect_equal(res2$m[[1]], 2 * m)
  expect_equal(res2$m[[2]], m)
  expect_equal(res2$m2[[1]], 7 * m)
  expect_equal(res2$m2[[2]], 5 * m)
})


test_that("sum_byname() works as expected via grouping and summarise for Matrix objects", {
  m <- matsbyname::Matrix(c(11, 12, 13,
                            21, 22, 23), nrow = 2, ncol = 3, byrow = TRUE, 
                          dimnames = list(c("r1", "r2"), c("c1", "c2", "c3")))
  df <- tibble::tibble(key = c("A", "A", "B"), m = list(m, m, m))
  res <- df %>% 
    dplyr::group_by(key) %>% 
    dplyr::summarise(m = sum_byname(m, .summarise = TRUE))
  expected <- tibble::tibble(key = c("A", "B"), 
                             m = list(2 * m, m))
  expect_equal(res, expected)
  
  # Try summarise with 2 columns
  df2 <- df
  df2$m2 <- list(3*m, 4*m, 5*m)
  res2 <- df2 %>% 
    dplyr::group_by(key) %>% 
    dplyr::summarise(m = sum_byname(m, .summarise = TRUE), m2 = sum_byname(m2, .summarise = TRUE))
  expect_equal(res2$m[[1]], 2 * m)
  expect_equal(res2$m[[2]], m)
  expect_equal(res2$m2[[1]], 7 * m)
  expect_equal(res2$m2[[2]], 5 * m)
})


test_that("sum_byname() works with sparse Matrix objects", {
  # Try with regular matrix objects
  a <- matrix(0, nrow = 2, ncol = 2, dimnames = list(c("r1", "r2"), c("c1", "c2")))
  b <- matrix(0, nrow = 2, ncol = 2, dimnames = list(c("r3", "r4"), c("c3", "c4")))
  res1 <- sum_byname(a, b)
  expected1 <- matrix(0, nrow = 4, ncol = 4, dimnames = list(paste0("r", 1:4), paste0("c", 1:4)))
  expect_equal(res1, expected1)
  
  # Try with Matrix objects
  A <- Matrix::Matrix(0, nrow = 2, ncol = 2, dimnames = list(c("r1", "r2"), c("c1", "c2")))
  B <- Matrix::Matrix(0, nrow = 2, ncol = 2, dimnames = list(c("r3", "r4"), c("c3", "c4")))

  res2 <- sum_byname(A, B)
  expected2 <- Matrix::Matrix(0, nrow = 4, ncol = 4, dimnames = list(paste0("r", 1:4), paste0("c", 1:4)))
  matsbyname:::expect_equal_matrix_or_Matrix(res2, expected2)
  
  D <- Matrix::Matrix(1, nrow = 2, ncol = 2, dimnames = list(c("r1", "r2"), c("c1", "c2")))
  E <- Matrix::Matrix(2, nrow = 2, ncol = 2, dimnames = list(c("r3", "r4"), c("c3", "c4")))
  res3 <- sum_byname(D, E)
  expected3 <- Matrix::Matrix(c(1, 1, 0, 0, 
                                1, 1, 0, 0,
                                0, 0, 2, 2, 
                                0, 0, 2, 2), nrow = 4, ncol = 4, byrow = TRUE,
                              dimnames = list(paste0("r", 1:4), paste0("c", 1:4)))
  matsbyname:::expect_equal_matrix_or_Matrix(res3, expected3)
  
  # Check with a matrix and a Matrix
  f <- matrix(2, nrow = 2, ncol = 2, dimnames = list(c("r3", "r4"), c("c3", "c4")))
  res4 <- sum_byname(f, D)
  expected4 <- expected3
  matsbyname:::expect_equal_matrix_or_Matrix(res4, expected4)
  
  res5 <- sum_byname(D, f)
  expected5 <- expected3
  matsbyname:::expect_equal_matrix_or_Matrix(res5, expected5)
})


test_that("sum_byname() fails with mismatch row or col types on Matrix objects", {
  A <- matsbyname::Matrix(0, nrow = 2, ncol = 2, dimnames = list(c("r1", "r2"), c("c1", "c2"))) %>% 
    setrowtype("rows") %>% setcoltype("cols")
  B <- matsbyname::Matrix(1, nrow = 2, ncol = 2, dimnames = list(c("r1", "r2"), c("c1", "c2"))) %>% 
    setrowtype("Product") %>% setcoltype("Industry")
  
  expect_error(sum_byname(A, B), "rowtype\\(a\\) \\(rows\\) != rowtype\\(b\\) \\(Product\\)")
})
  

Try the matsbyname package in your browser

Any scripts or data that you put into this service are public.

matsbyname documentation built on May 29, 2024, 8:10 a.m.