
# conditional and unconditional independence tests (vectorized in x, scalar
# in y).
indep.test = function(x, y, sx, data, test, extra.args = list(), alpha = 1,
    learning = TRUE, debug = FALSE) {

  # drop empty labels from the conditioning set and, for the built-in tests, the
  # latent (fully-unobserved) variables, which cannot be conditioned on. This
  # happens before the C code decides between the conditional and unconditional
  # test, so that an all-latent conditioning set correctly becomes the latter.
  # Custom tests receive the conditioning set unchanged, so that they can handle
  # latent variables in whatever way they see fit.
  sx = sx[sx != ""]
  if (test %!in% available.omnibus.tests)
    sx = setdiff(sx, latent.nodes(data))

  .Call(call_indep_test,
        x = x,
        y = y,
        sx = sx,
        data = data,
        test = test,
        alpha = alpha,
        extra.args = extra.args,
        learning = learning,
        debug = debug)

}#INDEP.TEST

# test against all possible subsets of the conditioning set (scalar in both x
# and y).
allsubs.test = function(x, y, sx, fixed = character(0), data, test,
    extra.args = list(), alpha = 1, min = 0, max = length(sx), debug = FALSE) {

  # a latent (fully-unobserved) variable cannot be conditioned on, so drop it
  # from the conditioning candidates and from the fixed conditioning set: no
  # subset will include it, and the largest subset size shrinks accordingly.
  # Custom tests are the exception and receive the sets unchanged, as in
  # indep.test().
  if (test %!in% available.omnibus.tests) {

    latent = latent.nodes(data)
    sx = setdiff(sx, latent)
    fixed = setdiff(fixed, latent)

  }#THEN

  .Call(call_allsubs_test,
        x = x,
        y = y,
        sx = c(fixed, sx),
        fixed = fixed,
        data = data,
        test = test,
        alpha = alpha,
        extra.args = extra.args,
        min = as.integer(min),
        max = as.integer(min(max, length(sx))),
        debug = debug)

}#ALLSUBS.TEST

# test each variable in turn given the rest as a conditioning set.
roundrobin.test = function(x, z, fixed, data, test, extra.args = list(),
    alpha = 1, debug = FALSE) {

  # a latent (fully-unobserved) variable cannot be conditioned on, so drop it
  # from the round-robin set (which provides both the variables to test and
  # their conditioning sets) and from the fixed conditioning set. If a single
  # variable is left it is tested against the empty set, and if none is left
  # there is nothing to test. Custom tests are the exception and receive the set
  # unchanged, as in indep.test().
  if (test %!in% available.omnibus.tests) {

    latent = latent.nodes(data)
    z = setdiff(z, latent)
    fixed = setdiff(fixed, latent)

  }#THEN

  if (length(z) == 0)
    return(structure(numeric(0), names = character(0)))

  .Call(call_roundrobin_test,
        x = x,
        z = z,
        fixed = fixed,
        data = data,
        test = test,
        alpha = alpha,
        extra.args = extra.args,
        debug = debug)

}#ROUNDROBIN.TEST

