All Downloads are FREE. Search and download functionalities are using the official Maven repository.

apparat.graph.analysis.Dominance.scala Maven / Gradle / Ivy

/*
 * This file is part of Apparat.
 *
 * Apparat is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Apparat is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Apparat. If not, see .
 *
 * Copyright (C) 2009 Joa Ebert
 * http://www.joa-ebert.com/
 *
 */
package apparat.graph.analysis

import apparat.graph.{ControlFlow, GraphLike}
import annotation.tailrec

/**
 * @author Joa Ebert
 */
class Dominance[V](val graph: GraphLike[V]) {
	private lazy val entry: V = graph match {
		case controlFlow: ControlFlow[_] => controlFlow.entryVertex.asInstanceOf[V]
		case _ => graph.verticesIterator find (vertex => (graph indegreeOf vertex) == 0) match {
			case Some(vertex) => vertex
			case None => error("No vertex with indegree(v) == 0 found.")
		}
	}

	private lazy val postorder = graph dft entry toList

	private lazy val reversePostorder = postorder.reverse

	@tailrec private def advanceIntersection(map: Map[V, V], a: V, b: V): V = {
		if ((postorder indexOf a) < (postorder indexOf b)) advanceIntersection(map, map(a), b)
		else a
	}

	@tailrec private def intersect(map: Map[V, V], b1: V, b2: V): V = {
		if (b1 != b2) {
			val f = advanceIntersection(map, b1, b2)
			intersect(map, f, advanceIntersection(map, b2, f))
		} else {
			b1
		}
	}

	private def pickPredecessor(map: Map[V, V], predecessors: Iterable[V]): V = {
		predecessors.find(map contains _) match {
			case Some(vertex) => vertex
			case None => error("Unreachable by definition.")
		}
	}

	private lazy val doms = {
		//
		// "A Simple, Fast Dominance Algorithm"
		//
		// Keith D. Cooper et al.
		// Rice University, Houston, TX
		//
		// http://www.cs.rice.edu/~keith/EMBED/dom.pdf
		// Page 13
		//

		var result = Map(entry -> entry)
		val rp = reversePostorder filterNot (_ == entry)

		def loop(): Unit = {
			var changed = false

			for (b <- rp) {
				val predecessorsTmp = graph predecessorsOf b
				var newIDom = pickPredecessor(result, predecessorsTmp)
				val predecessors = predecessorsTmp filterNot (_ == newIDom)

				for (p <- predecessors) {
					result get p match {
						case Some(vertex) => {
							newIDom = intersect(result, vertex, newIDom)
						}
						case None =>
					}
				}

				result get b match {
					case Some(old) => if (old != newIDom) {
						result = result updated (b, newIDom)
						changed = true
					}
					case None => {
						result = result + (b -> newIDom)
						changed = true
					}
				}
			}

			if (changed) {
				loop()
			}
		}

		loop()

		result
	}

	private lazy val frontiers = {
		//
		// "A Simple, Fast Dominance Algorithm"
		//
		// Keith D. Cooper et al.
		// Rice University, Houston, TX
		//
		// http://www.cs.rice.edu/~keith/EMBED/dom.pdf
		// Page 18
		//

		var result = graph vertexMap (v => List.empty[V])

		for (b <- graph.verticesIterator) {
			val predecessors = graph predecessorsOf b

			if (predecessors.size > 1) {
				for (p <- predecessors) {
					var runner = p

					while (runner != doms(b)) {
						// result is normally a set so no duplicate into it
						val resultRunner = result(runner)
						if (!resultRunner.contains(b))
							result = result updated (runner, b :: resultRunner)
						runner = doms(runner)
					}
				}
			}
		}

		result
	}

	def apply(vertex: V) = frontiersOf(vertex)

	def frontiersOf(vertex: V) = frontiers get vertex
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy