context("multichannels")

test_that("adding multiple edges to output channels works", {

  graph = Graph$new()$add_pipeop(po("scale"))$add_pipeop(po("pca"))$add_pipeop(po("subsample"))

  graph$add_edge("scale", "subsample")$add_edge("scale", "pca")

  expect_output(print(graph), c("scale.*subsample,pca.*\n.*subsample.*scale.*\n.*pca.*scale"))

  skip_if_not_installed("igraph")
  pdf(file = NULL)  # don't show plot. It is annoying.
  graph$plot()
  dev.off()

})

test_that("doublearrow with one output to many input works as expected", {

  g1 = po("scale") %>>% gunion(list(po("pca"), po("subsample")))
  g2 = Graph$new()$add_pipeop(po("scale"))$add_pipeop(po("pca"))$add_pipeop(po("subsample"))$
    add_edge("scale", "pca")$add_edge("scale", "subsample")

  expect_equal(g1, g2)

  expect_error(gunion(list(po("scale"), po("pca"))) %>>% gunion(list(po("nop"), po("subsample"), po("select"))),
    "mismatching number of inputs / outputs")

})

test_that("multiple edges on output channel copies, as expected", {
  graph = Graph$new()$add_pipeop(po("scale"))$add_pipeop(po("pca"))$add_pipeop(po("subsample"))

  graph$add_edge("scale", "subsample")$add_edge("scale", "pca")

  expect_list(graph$train(mlr_tasks$get("iris")), types = "Task", any.missing = FALSE, len = 2)

  nullgraph = mlr_pipeops$get("nop", id = "nop1") %>>%
    gunion(list(mlr_pipeops$get("nop", id = "nop2"), mlr_pipeops$get("nop", id = "nop3")))

  tsk0 = mlr_tasks$get("iris")
  tsk_clone = tsk0$clone(deep = TRUE)

  tmp = nullgraph$train(tsk0)

  tsk1 = tmp[[1]]
  tsk2 = tmp[[2]]

  expect_identical(tsk0, tsk1)
  expect_identical(tsk0, tsk2)

  tmp = nullgraph$predict(tsk0)

  tsk1 = tmp[[1]]
  tsk2 = tmp[[2]]

  expect_identical(tsk0, tsk1)
  expect_identical(tsk0, tsk2)

  graph = po("nop") %>>% gunion(list(
    mlr_pipeops$get("scale", id = "s1", param_vals = list(scale = TRUE, center = FALSE)),
    mlr_pipeops$get("scale", id = "s2", param_vals = list(scale = FALSE, center = TRUE))))

  tmp = graph$train(tsk0)

  stsk = tmp[[1]]
  ctsk = tmp[[2]]

  expect_equal(sapply(ctsk$data(cols = ctsk$feature_names), mean),
    c(Petal.Length = 0, Petal.Width = 0, Sepal.Length = 0, Sepal.Width = 0))

  expect_equal(sapply(stsk$data(cols = stsk$feature_names), function(x) sum(x^2) / (length(x) - 1)),
    c(Petal.Length = 1, Petal.Width = 1, Sepal.Length = 1, Sepal.Width = 1))

  tmp = graph$predict(tsk0)

  stsk = tmp[[1]]
  ctsk = tmp[[2]]

  expect_equal(sapply(ctsk$data(cols = ctsk$feature_names), mean),
    c(Petal.Length = 0, Petal.Width = 0, Sepal.Length = 0, Sepal.Width = 0))

  expect_equal(sapply(stsk$data(cols = stsk$feature_names), function(x) sum(x^2) / (length(x) - 1)),
    c(Petal.Length = 1, Petal.Width = 1, Sepal.Length = 1, Sepal.Width = 1))

  expect_identical(tsk0, tsk1)  # input task not changed

  expect_deep_clone(tsk0, tsk_clone)

})

test_that("adding multiple edges to vararg input channel works", {

  graph = Graph$new()$add_pipeop(po("scale"))$add_pipeop(po("pca"))$add_pipeop(VarargPipeop$new())

  graph$add_edge("scale", "vararg")$add_edge("pca", "vararg")

  expect_output(print(graph), c("scale.*vararg.*\n.*pca.*vararg.*\n.*vararg.*scale,pca"))

  skip_if_not_installed("igraph")
  pdf(file = NULL)  # don't show plot. It is annoying.
  graph$plot()
  dev.off()

  graph = Graph$new()$
    add_pipeop(po("scale"))$add_pipeop(po("pca"))$
    add_pipeop(po("subsample"))$add_pipeop(po("select"))$
    add_pipeop(VarargPipeop$new(innum = 2))

  expect_error(graph$add_edge("scale", "vararg"), "dst_channel must not be NULL")

  graph$add_edge("scale", "vararg", dst_channel = "...")$
    add_edge("pca", "vararg", dst_channel = "...")$
    add_edge("subsample", "vararg", dst_channel = "input1")$
    add_edge("select", "vararg", dst_channel = "input2")


  expect_output(print(graph), c("scale.*vararg.*\n.*pca.*vararg.*\n.*subsample.*vararg.*\n.*select.*vararg.*\n.*vararg.*scale,pca,subsample,select"))

  pdf(file = NULL)  # don't show plot. It is annoying.
  graph$plot()
  dev.off()

})

test_that("doublearrow with many output to vararg input works as expected", {

  g1 = gunion(list(po("scale"), po("pca"))) %>>% VarargPipeop$new()
  g2 = Graph$new()$add_pipeop(po("scale"))$add_pipeop(po("pca"))$add_pipeop(VarargPipeop$new())$
    add_edge("scale", "vararg")$add_edge("pca", "vararg")

  expect_equal(g1, g2)

  g1 = gunion(list(po("scale"), po("pca"))) %>>% VarargPipeop$new(innum = 1)
  g2 = Graph$new()$add_pipeop(po("scale"))$add_pipeop(po("pca"))$add_pipeop(VarargPipeop$new(innum = 1))$
    add_edge("scale", "vararg", dst_channel = "...")$add_edge("pca", "vararg", dst_channel = "input1")

  expect_equal(g1, g2)

  expect_error(gunion(list(po("scale"), po("pca"), po("select"), po("subsample"))) %>>% VarargPipeop$new(innum = 2),
    "mismatching number of inputs / outputs")

})

test_that("vararg passes args through as it should", {

  nullgraph = gunion(list(mlr_pipeops$get("nop", id = "nop1"), mlr_pipeops$get("nop", id = "nop2"))) %>>% VarargPipeop$new()

  expect_equal(nullgraph$train(1)[[1]], list(`...` = 1, `...` = 1))

  graph = gunion(list(
    mlr_pipeops$get("scale", id = "s1", param_vals = list(scale = TRUE, center = FALSE)),
    mlr_pipeops$get("scale", id = "s2", param_vals = list(scale = FALSE, center = TRUE)))) %>>%
    VarargPipeop$new()

  tsk0 = tsk1 = mlr_tasks$get("iris")
  tsk_clone = tsk0$clone(deep = TRUE)

  tmp = graph$train(tsk0)[[1]]

  stsk = tmp[[1]]
  ctsk = tmp[[2]]

  expect_equal(sapply(ctsk$data(cols = ctsk$feature_names), mean),
    c(Petal.Length = 0, Petal.Width = 0, Sepal.Length = 0, Sepal.Width = 0))

  expect_equal(sapply(stsk$data(cols = stsk$feature_names), function(x) sum(x^2) / (length(x) - 1)),
    c(Petal.Length = 1, Petal.Width = 1, Sepal.Length = 1, Sepal.Width = 1))

  tmp = graph$predict(tsk0)[[1]]

  stsk = tmp[[1]]
  ctsk = tmp[[2]]

  expect_equal(sapply(ctsk$data(cols = ctsk$feature_names), mean),
    c(Petal.Length = 0, Petal.Width = 0, Sepal.Length = 0, Sepal.Width = 0))

  expect_equal(sapply(stsk$data(cols = stsk$feature_names), function(x) sum(x^2) / (length(x) - 1)),
    c(Petal.Length = 1, Petal.Width = 1, Sepal.Length = 1, Sepal.Width = 1))

  expect_identical(tsk0, tsk1)  # input task not changed
  expect_deep_clone(tsk0, tsk_clone)


  nullgraph = gunion(list(
    mlr_pipeops$get("nop", id = "nop1"),
    mlr_pipeops$get("nop", id = "nop2"),
    mlr_pipeops$get("nop", id = "nop3")))$
    add_pipeop(VarargPipeop$new(innum = 1))$
    add_edge("nop1", "vararg", dst_channel = "...")$
    add_edge("nop3", "vararg", dst_channel = "...")$
    add_edge("nop2", "vararg", dst_channel = "input1")

    # FIXME: check the following warning
  expect_equal(suppressWarnings(nullgraph$train(list(1, 2, 3), single_input = FALSE))[[1]], list(`...` = 1, `...` = 3, input1 = 2))

})
