Jump to content

Conc-tree list

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Zikad (talk | contribs) at 12:17, 17 May 2016. The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

A Conc Tree [1][2] is a data-structure that stores element sequences, and provides amortized O(1) time append and prepend operations, O(log n) time insert and remove operations and O(log n) time concatenation. This data structure is particularly viable for functional task-parallel and data-parallel programming, and is relatively simple to implement compared to other data-structures with similar asymptotic complexity [1]. Conc-Trees were designed to improve efficiency of data-parallel operations that do not depend on the iteration order [3], and improve constant factors in these operations by avoiding unnecessary copies of the data [2]. Orthogonally, they are used to efficiently aggregate data in functional-style task-parallel algorithms, as an implementation of the conc-list abstraction [4], which are a parallel programming counterpart to functional cons-lists, and originally introduced by the Fortress language Fortress (programming language)..

Operations

The basic Conc-Tree operation is concatenation. Conc-Trees work on the following basic data-types:

trait Conc[T] {
  def left: Conc[T]
  def right: Conc[T]
  def level: Int
  def size: Int
}

case class Empty[T] extends Conc[T] {
  def level = 0
  def size = 0
}

case class Single[T](elem: T) extends Conc[T] {
  def level = 0
  def size = 1
}

case class <>[T](left: Conc[T], right: Conc[T]) extends Conc[T] {
  val level = 1 + math.max(left.level, right.level)
  val size = left.size + right.size
}

Concatenation in O(log n) time then works by ensuring that the difference in levels (i.e. heights) between any two sibling trees is one or less, similar to invariants maintained in AVL trees. This invariant ensures that the height of the tree (length of the longest path from the root to some leaf) is always logarithmic in the number of elements in the tree. Concatenation is implemented as follows:

def concat(xs: Conc[T], ys: Conc[T]) {
  val diff = xs.level - ys.level
  if (math.abs(diff) <= 1) new <>(xs, ys)
  else if (diff < -1) {
    if (xs.left.level >= xs.right.level) {
      val nr = concat(xs.right, ys)
      new <>(xs.left, nr)
    } else {
      val nrr = concat(xs.right.right, ys)
      if (nrr.level == xs.level - 3) {
        val nr = new <>(xs.right.left, nrr)
        new <>(xs.left, nr)
      } else {
        val nl = new <>(xs.left, xs.right.left)
        new <>(nl, nrr)
      }
    }
  } else {
    // symmetric case
  }
}

Amortized O(1) time appends (or prepends) are achieved by introducing a new inner node type called Append, and using it to encode a logarithmic-length list of Conc trees, strictly decreasing in height. . The following is an implementation of an append method that is worst-case O(log n) time and amortized O(1) time:

private def append[T](xs: Append[T], ys: Conc[T]) =
  if (xs.right.level > ys.level) new Append(xs, ys)
  else {
    val zs = new <>(xs.right, ys)
    xs.left match {
      case ws @ Append(_, _) => append(ws, zs)
      case ws => if (ws.level <= xs.level) concat(ws, zs) else new Append(ws, zs)
    }
  }
}

A detailed demonstration of these operations can be found in online resources[5][6], or in the original Conc-Tree paper[1]. It was shown that these basic operations can be extended to support worst-case O(1) deque operations [2], while keeping the O(log n) concatenation time bound, at the cost of increasing the constant factors of all operations.

References

  1. ^ a b c Prokopec, A. et al. (2015) Conc-Trees for Functional and Parallel Programming. Research Paper, 2015
  2. ^ a b c Prokopec A. (2014) Data Structures and Algorithms for Data-Parallel Computing in a Managed Runtime. Doctoral Thesis, 2014
  3. ^ Steele, G. (2009) [1] Organizing Functional Code for Parallel Execution; or, foldl and foldr Considered Slightly Harmful
  4. ^ Steel, G. (2011) [2] How to Think about Parallel Programming: Not!
  5. ^ Conc-Tree presentation [3]
  6. ^ Parallel Programming lecture on Conc-Trees at EPFL [4]