library(cvms)
context("softmax()")

test_that("softmax_vector() works", {

  logits <- c(2, 57, 76, 23, 65, 0.3, 65.3)
  exp_logits <- exp(logits)
  sum_exp_logits <- sum(exp_logits)
  softmaxed <- exp_logits/sum_exp_logits

  expect_equal(softmax_vector(logits), softmaxed)
  expect_equal(softmax_vector(2, 57, 76, 23, 65, 0.3, 65.3), softmaxed)
  expect_equal(sum(softmax_vector(logits)), 1)
  expect_equal(sum(softmax_vector(-logits)), 1)

  ## Testing 'softmax_vector(logits)'                                       ####
  ## Initially generated by xpectr
  # Assigning output
  output_12505 <- softmax_vector(logits)
  # Testing class
  expect_equal(
    class(output_12505),
    "numeric",
    fixed = TRUE)
  # Testing type
  expect_type(
    output_12505,
    type = "double")
  # Testing values
  expect_equal(
    output_12505,
    c(7.28100438257926e-33, 5.60257652385053e-09, 0.999960749299178,
      9.60230314258677e-24, 1.67010452367847e-05, 1.33011953925298e-33,
      2.25440530085991e-05),
    tolerance = 1e-4)
  # Testing names
  expect_equal(
    names(output_12505),
    NULL,
    fixed = TRUE)
  # Testing length
  expect_equal(
    length(output_12505),
    7L)
  # Testing sum of element lengths
  expect_equal(
    sum(xpectr::element_lengths(output_12505)),
    7L)
  ## Finished testing 'softmax_vector(logits)'                              ####

})

test_that("softmax() works", {

  df <- data.frame(
    "l1" = c(2, 57, 76, 23, 65, 0.3, 65.3),
    "l2" = c(5, 2, 45,-10,-42, 23, 56.2),
    "l3" = c(42, 12.6, 21, 43.2, 1, 0, 98),
    "c1" = factor(c("a", "b", "c", "d", "e", "f", "g"),
                  levels = c("a", "b", "c", "d", "e", "f", "g"))
  )

  vector_softmax <- function(...){
    exp_logits <- exp(c(...))
    sum_exp_logits <- sum(exp_logits)
    exp_logits/sum_exp_logits
  }

  df_colwise_softmaxed <- df %>%
    dplyr::mutate(l1 = vector_softmax(l1),
                  l2 = vector_softmax(l2),
                  l3 = vector_softmax(l3))
  expect_equal(as.data.frame(softmax(df, cols = c("l1", "l2", "l3"), axis = "c"), stringsAsFactors=TRUE),
               as.data.frame(df_colwise_softmaxed), stringsAsFactors=TRUE)

  df_rowwise_softmaxed <- plyr::ldply(seq_len(nrow(df)), function(r){
    vector_softmax(unlist(df[r,c("l1","l2","l3")], recursive = TRUE, use.names = TRUE))
  }) %>% dplyr::as_tibble() %>%
    dplyr::mutate(c1 = df$c1)
  expect_equal(as.data.frame(softmax(df, cols = c("l1", "l2", "l3"), axis = "r"), stringsAsFactors=TRUE),
               as.data.frame(df_rowwise_softmaxed), stringsAsFactors=TRUE)

  ## Test with gxs_function

  # xpectr::gxs_function(fn = softmax,
  #                      args_values = list(
  #                        "data" = list(df, NA, 1),
  #                        "cols" = list(c("l1", "l2", "l3"),
  #                                      c(1, 2, 3),
  #                                      4, NA, "l4"),
  #                        "axis" = list("r", "c", "x", NA)
  #                      ), indentation = 2,
  #                      tolerance = "1e-10",
  #                      round_to_tolerance = FALSE)
  #

  ## Testing 'softmax'                                                        ####
  ## Initially generated by xpectr
  # Testing different combinations of argument values

  # Testing softmax(data = NA, cols = c("l1", "l2", "l3"),...
  # Testing side effects
  expect_error(
    xpectr::strip_msg(softmax(data = NA, cols = c("l1", "l2", "l3"), axis = "r")),
    xpectr::strip(paste0("1 assertions failed:\n * Variable 'data': Must be of type 'd",
           "ata.frame', not 'logical'.")),
    fixed = TRUE)

  # Testing softmax(data = 1, cols = c("l1", "l2", "l3"), ...
  # Testing side effects
  expect_error(
    xpectr::strip_msg(softmax(data = 1, cols = c("l1", "l2", "l3"), axis = "r")),
    xpectr::strip(paste0("1 assertions failed:\n * Variable 'data': Must be of type 'd",
           "ata.frame', not 'double'.")),
    fixed = TRUE)

  # Testing softmax(data = df, cols = c(1, 2, 3), axis = "r")
  # Assigning output
  output_12030 <- softmax(data = df, cols = c(1, 2, 3), axis = "r")
  # Testing class
  expect_equal(
    class(output_12030),
    c("tbl_df", "tbl", "data.frame"),
    fixed = TRUE)
  # Testing column values
  expect_equal(
    output_12030[["l1"]],
    c(4.24835425529159e-18, 1, 0.999999999999972, 1.68752985466077e-09,
      1, 1.38520885997973e-10, 6.28883849646162e-15),
    tolerance = 1e-10)
  expect_equal(
    output_12030[["l2"]],
    c(8.53304762574407e-17, 1.2995814250075e-24, 3.44247710846988e-14,
      7.86200945932739e-24, 3.39227019302602e-47, 0.99999999975886,
      7.02248235171148e-19),
    tolerance = 1e-10)
  expect_equal(
    output_12030[["l3"]],
    c(1, 5.21584892208621e-20, 1.29958142500747e-24, 0.999999998312468,
      1.60381089054864e-28, 1.02618796292273e-10, 1),
    tolerance = 1e-10)
  expect_equal(
    output_12030[["c1"]],
    structure(1:7, .Label = c("a", "b", "c", "d", "e", "f", "g"),
      class = "factor"))
  # Testing column names
  expect_equal(
    names(output_12030),
    c("l1", "l2", "l3", "c1"),
    fixed = TRUE)
  # Testing column classes
  expect_equal(
    xpectr::element_classes(output_12030),
    c("numeric", "numeric", "numeric", "factor"),
    fixed = TRUE)
  # Testing column types
  expect_equal(
    xpectr::element_types(output_12030),
    c("double", "double", "double", "integer"),
    fixed = TRUE)
  # Testing dimensions
  expect_equal(
    dim(output_12030),
    c(7L, 4L))
  # Testing group keys
  expect_equal(
    colnames(dplyr::group_keys(output_12030)),
    character(0),
    fixed = TRUE)

  # Testing softmax(data = df, cols = 4, axis = "r")
  # Testing side effects
  expect_error(
    xpectr::strip_msg(softmax(data = df, cols = 4, axis = "r")),
    xpectr::strip("softmax() only works on numeric columns."),
    fixed = TRUE)

  # Testing softmax(data = df, cols = NA, axis = "r")
  # Testing side effects
  expect_error(
    xpectr::strip_msg(softmax(data = df, cols = NA, axis = "r")),
    xpectr::strip(paste0("Assertion on 'must.include' failed. Must be of class 'string",
           "', not 'logical'.")),
    fixed = TRUE)

  # Testing softmax(data = df, cols = "l4", axis = "r")
  # Testing side effects
  expect_error(
    xpectr::strip_msg(softmax(data = df, cols = "l4", axis = "r"), lowercase = TRUE),
    xpectr::strip("Must include the elements {l4}.", lowercase = TRUE), # colnames(data)
    fixed = TRUE)

  # Testing softmax(data = df, cols = c("l1", "l2", "l3"),...
  # Assigning output
  output_16124 <- softmax(data = df, cols = c("l1", "l2", "l3"), axis = "c")
  # Testing class
  expect_equal(
    class(output_16124),
    c("tbl_df", "tbl", "data.frame"),
    fixed = TRUE)
  # Testing column values
  expect_equal(
    output_16124[["l1"]],
    c(7.28100438257926e-33, 5.60257652385053e-09, 0.999960749299178,
      9.60230314258677e-24, 1.67010452367847e-05, 1.33011953925298e-33,
      2.25440530085991e-05),
    tolerance = 1e-10)
  expect_equal(
    output_16124[["l2"]],
    c(5.80920346814549e-23, 2.89223210231392e-24, 1.36740090845997e-05,
      1.77704882117296e-29, 2.2504840460157e-43, 3.81432120430906e-15,
      0.999986325990915),
    tolerance = 1e-10)
  expect_equal(
    output_16124[["l3"]],
    c(4.78089288388547e-25, 8.15175738259058e-38, 3.62514091914356e-34,
      1.58731233695789e-24, 7.47197233734299e-43, 2.74878500791021e-43,
      1),
    tolerance = 1e-10)
  expect_equal(
    output_16124[["c1"]],
    structure(1:7, .Label = c("a", "b", "c", "d", "e", "f", "g"),
      class = "factor"))
  # Testing column names
  expect_equal(
    names(output_16124),
    c("l1", "l2", "l3", "c1"),
    fixed = TRUE)
  # Testing column classes
  expect_equal(
    xpectr::element_classes(output_16124),
    c("numeric", "numeric", "numeric", "factor"),
    fixed = TRUE)
  # Testing column types
  expect_equal(
    xpectr::element_types(output_16124),
    c("double", "double", "double", "integer"),
    fixed = TRUE)
  # Testing dimensions
  expect_equal(
    dim(output_16124),
    c(7L, 4L))
  # Testing group keys
  expect_equal(
    colnames(dplyr::group_keys(output_16124)),
    character(0),
    fixed = TRUE)

  # Testing softmax(data = df, cols = c("l1", "l2", "l3"),...
  # Testing side effects
  expect_error(
    xpectr::strip_msg(softmax(data = df, cols = c("l1", "l2", "l3"), axis = "x")),
    xpectr::strip(paste0("1 assertions failed:\n * Variable 'axis': Must be element of",
           " set {'r','c'}, but is 'x'.")),
    fixed = TRUE)

  # Testing softmax(data = df, cols = c("l1", "l2", "l3"),...
  # Testing side effects
  expect_error(
    xpectr::strip_msg(softmax(data = df, cols = c("l1", "l2", "l3"), axis = NA)),
    xpectr::strip(paste0("1 assertions failed:\n * Variable 'axis': Must be element of",
           " set {'r','c'}, but is 'NA'.")),
    fixed = TRUE)

  # Testing softmax(data = df, cols = c("l1", "l2", "l3"),...
  # Testing side effects
  expect_error(
    xpectr::strip_msg(softmax(data = df, cols = c("l1", "l2", "l3"), axis = NULL)),
    xpectr::strip(paste0("1 assertions failed:\n * Variable 'axis': Must be a subset o",
           "f {'r','c'}, not 'NULL'.")),
    fixed = TRUE)

  # Testing softmax(data = df, cols = NULL, axis = "r")
  # Testing side effects
  expect_error(
    xpectr::strip_msg(softmax(data = df, cols = NULL, axis = "r")),
    xpectr::strip("softmax() only works on numeric columns."),
    fixed = TRUE)

  # Testing softmax(data = NULL, cols = c("l1", "l2", "l3"...
  # Testing side effects
  expect_error(
    xpectr::strip_msg(softmax(data = NULL, cols = c("l1", "l2", "l3"), axis = "r")),
    xpectr::strip(paste0("1 assertions failed:\n * Variable 'data': Must be of type 'd",
           "ata.frame', not 'NULL'.")),
    fixed = TRUE)

  # Testing softmax(data = df, cols = c("l1", "l2", "l3"),...
  # Assigning output
  output_19032 <- softmax(data = df, cols = c("l1", "l2", "l3"), axis = "r")
  # Testing class
  expect_equal(
    class(output_19032),
    c("tbl_df", "tbl", "data.frame"),
    fixed = TRUE)
  # Testing column values
  expect_equal(
    output_19032[["l1"]],
    c(4.24835425529159e-18, 1, 0.999999999999972, 1.68752985466077e-09,
      1, 1.38520885997973e-10, 6.28883849646162e-15),
    tolerance = 1e-10)
  expect_equal(
    output_19032[["l2"]],
    c(8.53304762574407e-17, 1.2995814250075e-24, 3.44247710846988e-14,
      7.86200945932739e-24, 3.39227019302602e-47, 0.99999999975886,
      7.02248235171148e-19),
    tolerance = 1e-10)
  expect_equal(
    output_19032[["l3"]],
    c(1, 5.21584892208621e-20, 1.29958142500747e-24, 0.999999998312468,
      1.60381089054864e-28, 1.02618796292273e-10, 1),
    tolerance = 1e-10)
  expect_equal(
    output_19032[["c1"]],
    structure(1:7, .Label = c("a", "b", "c", "d", "e", "f", "g"),
      class = "factor"))
  # Testing column names
  expect_equal(
    names(output_19032),
    c("l1", "l2", "l3", "c1"),
    fixed = TRUE)
  # Testing column classes
  expect_equal(
    xpectr::element_classes(output_19032),
    c("numeric", "numeric", "numeric", "factor"),
    fixed = TRUE)
  # Testing column types
  expect_equal(
    xpectr::element_types(output_19032),
    c("double", "double", "double", "integer"),
    fixed = TRUE)
  # Testing dimensions
  expect_equal(
    dim(output_19032),
    c(7L, 4L))
  # Testing group keys
  expect_equal(
    colnames(dplyr::group_keys(output_19032)),
    character(0),
    fixed = TRUE)

  ## Finished testing 'softmax'                                               ####


})
