
maxmin.pc.forward.phase = function(target, data, nodes, alpha,
    extra.args = list(), whitelist, blacklist, test, max.sx = ncol(data),
    debug = FALSE) {

  nodes = nodes[nodes != target]
  whitelisted = nodes[sapply(nodes,
      function(y) { is.whitelisted(whitelist, c(target, y), either = TRUE) })]
  blacklisted = nodes[sapply(nodes,
      function(y) { is.blacklisted(blacklist, c(target, y), both = TRUE) })]
  cpc = c()
  association = structure(numeric(length(nodes)), names = nodes)
  to.add = ""

  # growing phase
  if (debug) {

    cat("----------------------------------------------------------------\n")
    cat("* forward phase for node ", target, ".\n", sep = "")

  }#THEN

  # whitelisted nodes are included, and blacklisted nodes are excluded.
  cpc = whitelisted
  nodes = nodes[nodes %!in% c(cpc, blacklisted)]

  # phase I (stepwise forward selection)
  repeat {

    # stop testing if the conditioning set grows too large.
    if (length(cpc) > max.sx)
      break

    # do not check nodes which have a p-value above the alpha threshold, as
    # it can only increase.
    to.be.checked = setdiff(names(which(association < alpha)), cpc)

    # get an association measure for each of the available nodes.
    association = sapply(to.be.checked, maxmin.pc.heuristic.optimized,
                    y = target, sx = cpc, data = data, test = test,
                    alpha = alpha, extra.args = extra.args,
                    association = association, debug = debug)

    # stop if there are no candidates for inclusion.
    if (all(association > alpha) || length(nodes) == 0 || is.null(nodes)) break
    # get the one which maximizes the association measure.
    to.add = names(which.min(association))

    if (debug) {

      cat("  @ ", to.add, " accepted as a parent/children candidate (p-value: ",
        association[to.add], ").\n", sep = "")
      cat("  > current candidates are '", paste(c(cpc, to.add), collapse = " "), "'.\n", sep = "")

    }#THEN

    if (association[to.add] <= alpha) {

      cpc = c(cpc, to.add)
      nodes = nodes[nodes != to.add]

    }#THEN

  }#REPEAT

  return(cpc)

}#MAXMIN.PC.FORWARD.PHASE

maxmin.pc.heuristic.optimized = function(x, y, sx, data, test, alpha,
    extra.args = list(), association, debug = FALSE) {

  min.assoc = association[x]

  if (debug) {

    cat("  * checking node ", x, " for association.\n", sep = "")
    cat("    > starting with association ", min.assoc, ".\n", sep = "")

  }#THEN

  # generate only the subsets of the current parent/children set which include
  # node added last; the rest are considered to be already tested against.
  last = sx[length(sx)]
  sx = sx[-length(sx)]

  new.min.assoc = allsubs.test(x = x, y = y, sx = sx, fixed = last, data = data,
                    test = test, extra.args = extra.args, alpha = alpha,
                    debug = debug)

  min.assoc = max(min.assoc, new.min.assoc["max.p.value"])

  if (debug)
    cat("    > node ", x, " has a minimum association of ", min.assoc, ".\n", sep = "")

  return(min.assoc)

}#MAXMIN.PC.HEURISTIC.OPTIMIZED

