diff options
| author | chick | 2020-08-14 19:47:53 -0700 |
|---|---|---|
| committer | Jack Koenig | 2020-08-14 19:47:53 -0700 |
| commit | 6fc742bfaf5ee508a34189400a1a7dbffe3f1cac (patch) | |
| tree | 2ed103ee80b0fba613c88a66af854ae9952610ce /src/main/scala/firrtl/graph | |
| parent | b516293f703c4de86397862fee1897aded2ae140 (diff) | |
All of src/ formatted with scalafmt
Diffstat (limited to 'src/main/scala/firrtl/graph')
| -rw-r--r-- | src/main/scala/firrtl/graph/DiGraph.scala | 46 | ||||
| -rw-r--r-- | src/main/scala/firrtl/graph/EdgeData.scala | 5 | ||||
| -rw-r--r-- | src/main/scala/firrtl/graph/EulerTour.scala | 61 | ||||
| -rw-r--r-- | src/main/scala/firrtl/graph/RenderDiGraph.scala | 78 |
4 files changed, 105 insertions, 85 deletions
diff --git a/src/main/scala/firrtl/graph/DiGraph.scala b/src/main/scala/firrtl/graph/DiGraph.scala index 32bcac5f..7720028c 100644 --- a/src/main/scala/firrtl/graph/DiGraph.scala +++ b/src/main/scala/firrtl/graph/DiGraph.scala @@ -2,7 +2,7 @@ package firrtl.graph -import scala.collection.{Map, Set, mutable} +import scala.collection.{mutable, Map, Set} import scala.collection.mutable.{LinkedHashMap, LinkedHashSet} /** An exception that is raised when an assumed DAG has a cycle */ @@ -13,6 +13,7 @@ class PathNotFoundException extends Exception("Unreachable node") /** A companion to create DiGraphs from mutable data */ object DiGraph { + /** Create a DiGraph from a MutableDigraph, representing the same graph */ def apply[T](mdg: MutableDiGraph[T]): DiGraph[T] = mdg @@ -33,7 +34,8 @@ object DiGraph { } /** Represents common behavior of all directed graphs */ -class DiGraph[T] (private[graph] val edges: LinkedHashMap[T, LinkedHashSet[T]]) { +class DiGraph[T](private[graph] val edges: LinkedHashMap[T, LinkedHashSet[T]]) { + /** Check whether the graph contains vertex v */ def contains(v: T): Boolean = edges.contains(v) @@ -74,8 +76,7 @@ class DiGraph[T] (private[graph] val edges: LinkedHashMap[T, LinkedHashSet[T]]) try { foundPath = path(vertex, node, blacklist = Set.empty) true - } - catch { + } catch { case _: PathNotFoundException => foundPath = Seq.empty[T] false @@ -138,7 +139,7 @@ class DiGraph[T] (private[graph] val edges: LinkedHashMap[T, LinkedHashSet[T]]) * @return a Map[T,T] from each visited node to its predecessor in the * traversal */ - def BFS(root: T): Map[T,T] = BFS(root, Set.empty[T]) + def BFS(root: T): Map[T, T] = BFS(root, Set.empty[T]) /** Performs breadth-first search on the directed graph, with a blacklist of nodes * @@ -147,8 +148,8 @@ class DiGraph[T] (private[graph] val edges: LinkedHashMap[T, LinkedHashSet[T]]) * @return a Map[T,T] from each visited node to its predecessor in the * traversal */ - def BFS(root: T, blacklist: Set[T]): Map[T,T] = { - val prev = new mutable.LinkedHashMap[T,T] + def BFS(root: T, blacklist: Set[T]): Map[T, T] = { + val prev = new mutable.LinkedHashMap[T, T] val queue = new mutable.Queue[T] queue.enqueue(root) while (queue.nonEmpty) { @@ -181,7 +182,9 @@ class DiGraph[T] (private[graph] val edges: LinkedHashMap[T, LinkedHashSet[T]]) * @param blacklist list of nodes to stop searching, if encountered * @return a Set[T] of nodes reachable from `root` */ - def reachableFrom(root: T, blacklist: Set[T]): LinkedHashSet[T] = new LinkedHashSet[T] ++ BFS(root, blacklist).map({ case (k, v) => k }) + def reachableFrom(root: T, blacklist: Set[T]): LinkedHashSet[T] = new LinkedHashSet[T] ++ BFS(root, blacklist).map({ + case (k, v) => k + }) /** Finds a path (if one exists) from one node to another * @@ -238,7 +241,7 @@ class DiGraph[T] (private[graph] val edges: LinkedHashMap[T, LinkedHashSet[T]]) val callStack = new mutable.Stack[StrongConnectFrame[T]] for (node <- getVertices) { - callStack.push(new StrongConnectFrame(node,getEdges(node).iterator)) + callStack.push(new StrongConnectFrame(node, getEdges(node).iterator)) while (!callStack.isEmpty) { val frame = callStack.top val v = frame.v @@ -257,7 +260,7 @@ class DiGraph[T] (private[graph] val edges: LinkedHashMap[T, LinkedHashSet[T]]) val w = frame.edgeIter.next if (!indices.contains(w)) { frame.childCall = Some(w) - callStack.push(new StrongConnectFrame(w,getEdges(w).iterator)) + callStack.push(new StrongConnectFrame(w, getEdges(w).iterator)) } else if (onstack.contains(w)) { lowlinks(v) = lowlinks(v).min(indices(w)) } @@ -269,8 +272,7 @@ class DiGraph[T] (private[graph] val edges: LinkedHashMap[T, LinkedHashSet[T]]) val w = stack.pop onstack -= w scc += w - } - while (scc.last != v); + } while (scc.last != v); sccs.append(scc.toSeq) } callStack.pop @@ -291,7 +293,7 @@ class DiGraph[T] (private[graph] val edges: LinkedHashMap[T, LinkedHashSet[T]]) * @param start the node to start at * @return a Map[T,Seq[Seq[T]]] where the value associated with v is the Seq of all paths from start to v */ - def pathsInDAG(start: T): LinkedHashMap[T,Seq[Seq[T]]] = { + def pathsInDAG(start: T): LinkedHashMap[T, Seq[Seq[T]]] = { // paths(v) holds the set of paths from start to v val paths = new LinkedHashMap[T, mutable.Set[Seq[T]]] val queue = new mutable.Queue[T] @@ -299,7 +301,7 @@ class DiGraph[T] (private[graph] val edges: LinkedHashMap[T, LinkedHashSet[T]]) def addBinding(n: T, p: Seq[T]): Unit = { paths.getOrElseUpdate(n, new LinkedHashSet[Seq[T]]) += p } - addBinding(start,Seq(start)) + addBinding(start, Seq(start)) queue += start queue ++= linearize.filter(reachable.contains(_)) while (!queue.isEmpty) { @@ -310,22 +312,25 @@ class DiGraph[T] (private[graph] val edges: LinkedHashMap[T, LinkedHashSet[T]]) } } } - paths.map({ case (k,v) => (k,v.toSeq) }) + paths.map({ case (k, v) => (k, v.toSeq) }) } /** Returns a graph with all edges reversed */ def reverse: DiGraph[T] = { val mdg = new MutableDiGraph[T] edges.foreach({ case (u, edges) => mdg.addVertex(u) }) - edges.foreach({ case (u, edges) => - edges.foreach(v => mdg.addEdge(v,u)) + edges.foreach({ + case (u, edges) => + edges.foreach(v => mdg.addEdge(v, u)) }) DiGraph(mdg) } private def filterEdges(vprime: Set[T]): LinkedHashMap[T, LinkedHashSet[T]] = { - def filterNodeSet(s: LinkedHashSet[T]): LinkedHashSet[T] = s.filter({ case (k) => vprime.contains(k) }) - def filterAdjacencyLists(m: LinkedHashMap[T, LinkedHashSet[T]]): LinkedHashMap[T, LinkedHashSet[T]] = m.map({ case (k, v) => (k, filterNodeSet(v)) }) + def filterNodeSet(s: LinkedHashSet[T]): LinkedHashSet[T] = s.filter({ case (k) => vprime.contains(k) }) + def filterAdjacencyLists(m: LinkedHashMap[T, LinkedHashSet[T]]): LinkedHashMap[T, LinkedHashSet[T]] = m.map({ + case (k, v) => (k, filterNodeSet(v)) + }) val eprime: LinkedHashMap[T, LinkedHashSet[T]] = edges.filter({ case (k, v) => vprime.contains(k) }) filterAdjacencyLists(eprime) } @@ -354,7 +359,7 @@ class DiGraph[T] (private[graph] val edges: LinkedHashMap[T, LinkedHashSet[T]]) */ def simplify(vprime: Set[T]): DiGraph[T] = { require(vprime.subsetOf(edges.keySet)) - val pathEdges = vprime.map(v => (v, reachableFrom(v) & (vprime-v)) ) + val pathEdges = vprime.map(v => (v, reachableFrom(v) & (vprime - v))) new DiGraph(new LinkedHashMap[T, LinkedHashSet[T]] ++ pathEdges) } @@ -384,6 +389,7 @@ class DiGraph[T] (private[graph] val edges: LinkedHashMap[T, LinkedHashSet[T]]) } class MutableDiGraph[T] extends DiGraph[T](new LinkedHashMap[T, LinkedHashSet[T]]) { + /** Add vertex v to the graph * @return v, the added vertex */ diff --git a/src/main/scala/firrtl/graph/EdgeData.scala b/src/main/scala/firrtl/graph/EdgeData.scala index 16990de0..6a63c3b9 100644 --- a/src/main/scala/firrtl/graph/EdgeData.scala +++ b/src/main/scala/firrtl/graph/EdgeData.scala @@ -6,11 +6,10 @@ import scala.collection.mutable /** * An exception that indicates that an edge cannot be found in a graph with edge data. - * + * * @note the vertex type is not captured as a type parameter, as it would be erased. */ -class EdgeNotFoundException(u: Any, v: Any) - extends IllegalArgumentException(s"Edge (${u}, ${v}) does not exist!") +class EdgeNotFoundException(u: Any, v: Any) extends IllegalArgumentException(s"Edge (${u}, ${v}) does not exist!") /** * Mixing this trait into a DiGraph indicates that each edge may be associated with an optional diff --git a/src/main/scala/firrtl/graph/EulerTour.scala b/src/main/scala/firrtl/graph/EulerTour.scala index 2d8a17e2..5e075ae2 100644 --- a/src/main/scala/firrtl/graph/EulerTour.scala +++ b/src/main/scala/firrtl/graph/EulerTour.scala @@ -6,6 +6,7 @@ import scala.collection.mutable /** Euler Tour companion object */ object EulerTour { + /** Create an Euler Tour of a `DiGraph[T]` */ def apply[T](diGraph: DiGraph[T], start: T): EulerTour[Seq[T]] = { val r = mutable.Map[Seq[T], Int]() @@ -66,8 +67,8 @@ class EulerTour[T](r: Map[T, Int], e: Seq[T], h: Seq[Int]) { * the index of that minimum in each block, b. */ private lazy val blocks = (h ++ (1 to (m - n % m))).grouped(m).toArray - private lazy val a = blocks map (_.min) - private lazy val b = blocks map (b => b.indexOf(b.min)) + private lazy val a = blocks.map(_.min) + private lazy val b = blocks.map(b => b.indexOf(b.min)) /** Construct a Sparse Table (ST) representation for the minimum index * of a sequence of integers. Data in the returned array is indexed @@ -75,7 +76,10 @@ class EulerTour[T](r: Map[T, Int], e: Seq[T], h: Seq[Int]) { */ private def constructSparseTable(x: Seq[Int]): Array[Array[Int]] = { val tmp = Array.ofDim[Int](x.size + 1, math.ceil(lg(x.size)).toInt) - for (i <- 0 to x.size - 1; j <- 0 to math.ceil(lg(x.size)).toInt - 1) { + for { + i <- 0 to x.size - 1 + j <- 0 to math.ceil(lg(x.size)).toInt - 1 + } { tmp(i)(j) = -1 } @@ -86,11 +90,11 @@ class EulerTour[T](r: Map[T, Int], e: Seq[T], h: Seq[Int]) { } else { val (a, b, c) = (base, base + (1 << (size - 1)), size - 1) - val l = if (tmp(a)(c) != -1) { tmp(a)(c) } - else { tableRecursive(a, c) } + val l = if (tmp(a)(c) != -1) { tmp(a)(c) } + else { tableRecursive(a, c) } - val r = if (tmp(b)(c) != -1) { tmp(b)(c) } - else { tableRecursive(b, c) } + val r = if (tmp(b)(c) != -1) { tmp(b)(c) } + else { tableRecursive(b, c) } val min = if (x(l) < x(r)) l else r tmp(base)(size) = min @@ -99,9 +103,11 @@ class EulerTour[T](r: Map[T, Int], e: Seq[T], h: Seq[Int]) { } } - for (i <- (0 to x.size - 1); - j <- (0 to math.ceil(lg(x.size)).toInt - 1); - if i + (1 << j) - 1 < x.size) { + for { + i <- (0 to x.size - 1) + j <- (0 to math.ceil(lg(x.size)).toInt - 1) + if i + (1 << j) - 1 < x.size + } { tableRecursive(i, j) } tmp @@ -117,16 +123,26 @@ class EulerTour[T](r: Map[T, Int], e: Seq[T], h: Seq[Int]) { } val size = m - 1 - val out = Seq.fill(size)(Seq(-1, 1)) - .flatten.combinations(m - 1).flatMap(_.permutations).toList + val out = Seq + .fill(size)(Seq(-1, 1)) + .flatten + .combinations(m - 1) + .flatMap(_.permutations) + .toList .sortWith(sortSeqSeq) .map(_.foldLeft(Seq(0))((h, pm) => (h.head + pm) +: h).reverse) - .map{ a => + .map { a => val tmp = Array.ofDim[Int](m, m) - for (i <- 0 to size; j <- i to size) yield { + for { + i <- 0 to size + j <- i to size + } yield { val window = a.slice(i, j + 1) - tmp(i)(j) = window.indexOf(window.min) + i } - tmp }.toArray + tmp(i)(j) = window.indexOf(window.min) + i + } + tmp + } + .toArray out } private lazy val tables = constructTableLookups(m) @@ -167,7 +183,7 @@ class EulerTour[T](r: Map[T, Int], e: Seq[T], h: Seq[Int]) { // Compute block and word indices val (block_i, block_j) = (i / m, j / m) - val (word_i, word_j) = (i % m, j % m) + val (word_i, word_j) = (i % m, j % m) /** Up to four possible minimum indices are then computed based on the * following conditions: @@ -187,12 +203,12 @@ class EulerTour[T](r: Map[T, Int], e: Seq[T], h: Seq[Int]) { val min_i = block_i * m + tables(tableIdx(block_i))(word_i)(word_j) Seq(min_i) case (bi, bj) if (block_i == block_j - 1) => - val min_i = block_i * m + tables(tableIdx(block_i))(word_i)( m - 1) - val min_j = block_j * m + tables(tableIdx(block_j))( 0)(word_j) + val min_i = block_i * m + tables(tableIdx(block_i))(word_i)(m - 1) + val min_j = block_j * m + tables(tableIdx(block_j))(0)(word_j) Seq(min_i, min_j) case _ => - val min_i = block_i * m + tables(tableIdx(block_i))(word_i)( m - 1) - val min_j = block_j * m + tables(tableIdx(block_j))( 0)(word_j) + val min_i = block_i * m + tables(tableIdx(block_i))(word_i)(m - 1) + val min_j = block_j * m + tables(tableIdx(block_j))(0)(word_j) val (min_between_l, min_between_r) = { val range = math.floor(lg(block_j - block_i - 1)).toInt val base_0 = block_i + 1 @@ -200,7 +216,8 @@ class EulerTour[T](r: Map[T, Int], e: Seq[T], h: Seq[Int]) { val (idx_0, idx_1) = (st(base_0)(range), st(base_1)(range)) val (min_0, min_1) = (b(idx_0) + idx_0 * m, b(idx_1) + idx_1 * m) - (min_0, min_1) } + (min_0, min_1) + } Seq(min_i, min_between_l, min_between_r, min_j) } diff --git a/src/main/scala/firrtl/graph/RenderDiGraph.scala b/src/main/scala/firrtl/graph/RenderDiGraph.scala index b3c1373c..45be3a8f 100644 --- a/src/main/scala/firrtl/graph/RenderDiGraph.scala +++ b/src/main/scala/firrtl/graph/RenderDiGraph.scala @@ -16,7 +16,6 @@ import scala.collection.mutable */ class RenderDiGraph[T <: Any](diGraph: DiGraph[T], graphName: String = "", rankDir: String = "LR") { - /** * override this to change the default way a node is displayed. Default is toString surrounded by double quotes * This example changes the double quotes to brackets @@ -38,8 +37,7 @@ class RenderDiGraph[T <: Any](diGraph: DiGraph[T], graphName: String = "", rankD try { diGraph.linearize - } - catch { + } catch { case cyclicException: CyclicException => val node = cyclicException.node.asInstanceOf[T] path = diGraph.findLoopAtNode(node) @@ -61,31 +59,29 @@ class RenderDiGraph[T <: Any](diGraph: DiGraph[T], graphName: String = "", rankD val loop = findOneLoop - if(loop.nonEmpty) { + if (loop.nonEmpty) { // Find all the children of the nodes in the loop val childrenFound = diGraph.getEdgeMap.flatMap { case (node, children) if loop.contains(node) => children - case _ => Seq.empty + case _ => Seq.empty }.toSet // Create a new DiGraph containing only loop and direct children or parents val edgeData = diGraph.getEdgeMap - val newEdgeData = edgeData.flatMap { case (node, children) => - if(loop.contains(node)) { - Some(node -> children) - } - else if(childrenFound.contains(node)) { - Some(node -> children.intersect(loop)) - } - else { - val newChildren = children.intersect(loop) - if(newChildren.nonEmpty) { - Some(node -> newChildren) - } - else { - None - } + val newEdgeData = edgeData.flatMap { + case (node, children) => + if (loop.contains(node)) { + Some(node -> children) + } else if (childrenFound.contains(node)) { + Some(node -> children.intersect(loop)) + } else { + val newChildren = children.intersect(loop) + if (newChildren.nonEmpty) { + Some(node -> newChildren) + } else { + None + } } } @@ -96,8 +92,7 @@ class RenderDiGraph[T <: Any](diGraph: DiGraph[T], graphName: String = "", rankD } } newRenderer.toDotWithLoops(loop, getRankedNodes) - } - else { + } else { "" } } @@ -114,10 +109,11 @@ class RenderDiGraph[T <: Any](diGraph: DiGraph[T], graphName: String = "", rankD val edges = diGraph.getEdgeMap - edges.foreach { case (parent, children) => - children.foreach { child => - s.append(s""" ${renderNode(parent)} -> ${renderNode(child)};""" + "\n") - } + edges.foreach { + case (parent, children) => + children.foreach { child => + s.append(s""" ${renderNode(parent)} -> ${renderNode(child)};""" + "\n") + } } s.append("}\n") s.toString @@ -137,24 +133,25 @@ class RenderDiGraph[T <: Any](diGraph: DiGraph[T], graphName: String = "", rankD val edges = diGraph.getEdgeMap - edges.foreach { case (parent, children) => - allNodes += parent - allNodes ++= children + edges.foreach { + case (parent, children) => + allNodes += parent + allNodes ++= children - children.foreach { child => - val highlight = if(loopedNodes.contains(parent) && loopedNodes.contains(child)) { - "[color=red,penwidth=3.0]" - } - else { - "" + children.foreach { child => + val highlight = if (loopedNodes.contains(parent) && loopedNodes.contains(child)) { + "[color=red,penwidth=3.0]" + } else { + "" + } + s.append(s""" ${renderNode(parent)} -> ${renderNode(child)}$highlight;""" + "\n") } - s.append(s""" ${renderNode(parent)} -> ${renderNode(child)}$highlight;""" + "\n") - } } val paredRankedNodes = rankedNodes.flatMap { nodes => val newNodes = nodes.filter(allNodes.contains) - if(newNodes.nonEmpty) { Some(newNodes) } else { None } + if (newNodes.nonEmpty) { Some(newNodes) } + else { None } } paredRankedNodes.foreach { nodesAtRank => @@ -183,7 +180,7 @@ class RenderDiGraph[T <: Any](diGraph: DiGraph[T], graphName: String = "", rankD diGraph.getEdges(node) }.filterNot(alreadyVisited.contains).distinct - if(nextNodes.nonEmpty) { + if (nextNodes.nonEmpty) { walkByRank(nextNodes, rankNumber + 1) } } @@ -191,6 +188,7 @@ class RenderDiGraph[T <: Any](diGraph: DiGraph[T], graphName: String = "", rankD walkByRank(diGraph.findSources.toSeq) rankNodes } + /** * Convert this graph into input for the graphviz dot program. * It tries to align nodes in columns based @@ -216,7 +214,7 @@ class RenderDiGraph[T <: Any](diGraph: DiGraph[T], graphName: String = "", rankD children }.filterNot(alreadyVisited.contains).distinct - if(nextNodes.nonEmpty) { + if (nextNodes.nonEmpty) { walkByRank(nextNodes, rankNumber + 1) } } |
