Skip to content

Commit

Permalink
Merge pull request #48 from scalan/v0.5.1
Browse files Browse the repository at this point in the history
v0.5.1
  • Loading branch information
aslesarenko authored Sep 25, 2019
2 parents 5136809 + 81f7d69 commit f8b00d1
Show file tree
Hide file tree
Showing 316 changed files with 15,775 additions and 25,066 deletions.
5 changes: 3 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ env:
language: scala

jdk:
- oraclejdk9
- oraclejdk8

script:
- sbt -jvm-opts .travis.jvmopts $TEST_SUITE
- sbt -jvm-opts .travis.jvmopts coverage $TEST_SUITE

after_success:
- sbt coverageReport coverageAggregate coveralls
- sbt -jvm-opts .travis.jvmopts publish
6 changes: 3 additions & 3 deletions ast/src/main/scala/scalan/meta/AstContextBase.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ trait AstContextBase extends Symbols {
/** Mapping of external type names to their wrappers ("Array" -> WrapperDescr). */
private[scalan] val wrappers = MMap[String, WrapperDescr]()

/** Mapping of W-entities to the corresponding wrapped type name ("WArray" -> "Array") */
/** Mapping of W-entities to the corresponding wrapped type name (e.g. "WArray" -> "Array") */
private[scalan] val entityToWrapper = MMap[String, String]()

/** Mapping of <packageName>.<moduleName> to unit configuration.
Expand Down Expand Up @@ -179,11 +179,11 @@ trait AstContextBase extends Symbols {

object RepTypeOf {
def unapply(tpe: STpeExpr): Option[STpeExpr] = tpe match {
case STraitCall("Rep", Seq(t)) => // Rep[t] --> t
case STraitCall("Ref", Seq(t)) => // Ref[t] --> t
Some(t)
case STraitCall("RFunc", Seq(a, b)) => // RFunc[a,b] --> a => b
Some(STpeFunc(a, b))
case TypeDef(td, RepTypeOf(t)) => // type RepCol[args] = Rep[Col[args]] then RepCol[args] --> Col[args]
case TypeDef(td, RepTypeOf(t)) => // type RepCol[args] = Ref[Col[args]] then RepCol[args] --> Col[args]
Some(t)
case _ => None
}
Expand Down
8 changes: 5 additions & 3 deletions ast/src/main/scala/scalan/meta/Configs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import scalan.util.{FileUtil, GraphUtil}
import scalan.util.StringUtil._

import scala.collection.mutable.{Map => MMap}
import debox.{Buffer => DBuffer}
import scalan.meta.ScalanAst.WrapperConf

trait Conf {
Expand Down Expand Up @@ -59,7 +60,7 @@ abstract class ModuleConf extends Conf {
def moduleDeps: ConfMap[ModuleConf]

def dependsOnModules(): Set[ModuleConf] =
GraphUtil.depthFirstSetFrom(Set(this.dependencies.values.toSeq: _*))(m => m.dependencies.values)
GraphUtil.depthFirstSetFrom(DBuffer(this.dependencies.values.toSeq: _*))(m => DBuffer.fromIterable(m.dependencies.values)).toScalaSet()

def getSourcesRootDir = s"${baseDir.opt(_ + "/")}$name/${ModuleConf.SourcesDir }"

Expand All @@ -74,7 +75,8 @@ abstract class ModuleConf extends Conf {
baseContextTrait = "scalan.Scalan", // used like this: trait ${module.name}Defs extends ${config.baseContextTrait.opt(t => s"$t with ")}${module.name} {
extraImports = List(
"scala.reflect.runtime.universe._",
"scala.reflect._"
"scala.reflect._",
"scala.collection.mutable.WrappedArray"
),
isVirtualized = false
)
Expand Down Expand Up @@ -154,7 +156,7 @@ case class UnitConfig(
resourcePath: String, // example: <module>/<ModuleConf.ResourcesDir>
entityFile: String, // the package path and file name (example: scalan/collection/Col.scala)
baseContextTrait: String = "scalan.Scalan",
extraImports: List[String] = List("scala.reflect.runtime.universe.{WeakTypeTag, weakTypeTag}", "scalan.meta.ScalanAst._"),
extraImports: List[String] = List("scala.collection.mutable.WrappedArray"),
isVirtualized: Boolean = true,
wrappers: Map[String, WrapperConf] = Map()
) extends Conf with Updatable[UnitConfig]
Expand Down
6 changes: 3 additions & 3 deletions ast/src/main/scala/scalan/meta/SModuleBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -149,14 +149,14 @@ class SModuleBuilder(implicit val context: AstContextBase) {
}

// /** Introduces a synonym for each entity. If name of the entity is Matr, the method adds:
// * type RepMatr[T] = Rep[Matr[T]]
// * type RepMatr[T] = Ref[Matr[T]]
// * */
// def addEntityRepSynonym(module: SModuleDef) = {
// val entity = module.entityOps
// def synDef(entity: STraitDef) = STpeDef(
// name = "Rep" + entityName,
// name = "Ref" + entityName,
// tpeArgs = entity.tpeArgs,
// rhs = STraitCall("Rep", List(STraitCall(entity.name, entity.tpeArgs.map(_.toTraitCall))))
// rhs = STraitCall("Ref", List(STraitCall(entity.name, entity.tpeArgs.map(_.toTraitCall))))
// )
// module.copy(entityRepSynonym = Some(synDef))
// }
Expand Down
34 changes: 18 additions & 16 deletions ast/src/main/scala/scalan/meta/ScalanAst.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import com.trueaccord.lenses.Updatable

import scala.reflect.internal.ModifierFlags
import java.util.Objects

import scala.collection.immutable.{HashMap, HashSet}
import scalan.{ArgList, Constructor, ContainerType, FunctorType, Liftable, Reified, NeverInline, External}
import scalan.{Constructor, ContainerType, FunctorType, Liftable, Reified, NeverInline, Isospec, External, Convertible, WithMethodCallRecognizers}
import scalan.meta.Symbols._
import scalan.meta.ScalanAstTransformers.{TypeNameCollector, SubstTypeTransformer, TypeTransformerInAst}

import scala.collection.{mutable, GenIterable}
import com.typesafe.config.ConfigUtil
import scalan.util.{Covariant, Contravariant, Invariant, PrintExtensions}
import scalan.util.{Covariant, Contravariant, PrintExtensions, Invariant}
import PrintExtensions._
import ScalanAstExtensions._
import scalan.util.CollectionUtil._
Expand Down Expand Up @@ -162,7 +164,7 @@ object ScalanAst {
}

def isTupledFunc = self match {
case STraitCall("Rep", List(STpeFunc(STpeTuple(a1 :: a2 :: tail), _))) => true
case STraitCall("Ref", List(STpeFunc(STpeTuple(a1 :: a2 :: tail), _))) => true
case STpeFunc(STpeTuple(a1 :: a2 :: tail), _) => true
case _ => false
}
Expand Down Expand Up @@ -276,7 +278,7 @@ object ScalanAst {
None
}
findInTuple(t)
case STraitCall("Rep", List(tT)) =>
case STraitCall("Ref", List(tT)) =>
find(tT, argName)
case STraitCall("Thunk", List(tT)) =>
find(tT, argName).map(tail => SThunkPath(tpe, tail))
Expand Down Expand Up @@ -331,15 +333,16 @@ object ScalanAst {
tpeArgs: List[STpeExpr],
args: List[SExpr]) extends SAnnotation

final val EntityAnnotation = classOf[scalan.Entity].getSimpleName
final val LiftableAnnotation = classOf[Liftable].getSimpleName
final val IsospecAnnotation = classOf[Isospec].getSimpleName
final val ConvertibleAnnotation = classOf[Convertible].getSimpleName
final val ConstructorAnnotation = classOf[Constructor].getSimpleName
final val ExternalAnnotation = classOf[External].getSimpleName
final val ArgListAnnotation = classOf[ArgList].getSimpleName
final val ContainerTypeAnnotation = classOf[ContainerType].getSimpleName
final val FunctorTypeAnnotation = classOf[FunctorType].getSimpleName
final val ReifiedTypeArgAnnotation = classOf[Reified].getSimpleName
final val NeverInlineAnnotation = classOf[NeverInline].getSimpleName
final val WithMethodCallRecognizersAnnotation = classOf[WithMethodCallRecognizers].getSimpleName
final val SpecializedAnnotation = classOf[specialized].getSimpleName
final val InlineAnnotation = classOf[inline].getSimpleName

Expand Down Expand Up @@ -466,6 +469,7 @@ object ScalanAst {
def isMonomorphic = tpeArgs.isEmpty
override def isAbstract: Boolean = body.isEmpty
def isNeverInline: Boolean = hasAnnotation(NeverInlineAnnotation)
def withMethodCallRecognizers: Boolean = hasAnnotation(WithMethodCallRecognizersAnnotation)
override def argss: List[List[SMethodOrClassArg]] = argSections.map(_.args)
override def rhs: Option[SExpr] = body
override def exprType = ??? // TODO build STpeFunc for this method type
Expand All @@ -474,10 +478,6 @@ object ScalanAst {
def getAnnotation(annotName: String): Option[SMethodAnnotation] = annotations.find(a => a.annotationClass == annotName)
def hasAnnotation(annotName: String): Boolean = getAnnotation(annotName).isDefined

// def isExtractableArg(module: SModuleDef, tpeArg: STpeArg): Boolean = {
// allArgs.exists(a => STpePath.find(module, a.tpe, tpeArg.name).isDefined)
// }

def explicitArgs: List[SMethodArg] = argSections.flatMap(_.args.filterNot(_.impFlag))
def implicitArgs: List[SMethodArg] = argSections.flatMap(_.args.filter(_.impFlag))

Expand Down Expand Up @@ -625,7 +625,6 @@ object ScalanAst {
def tpe: STpeExpr
def default: Option[SExpr]
def annotations: List[SArgAnnotation]
def isArgList = annotations.exists(a => a.annotationClass == ArgListAnnotation)
def isTypeDesc: Boolean
}
object SMethodOrClassArg {
Expand Down Expand Up @@ -779,11 +778,13 @@ object ScalanAst {
case _ => false
}

def isLiftable(implicit ctx: AstContextBase): Boolean = {
getAnnotation(LiftableAnnotation) match {
case Some(SEntityAnnotation(_,_,_)) => true
case _ => false
}
def isLiftable(implicit ctx: AstContextBase): Boolean = hasAnnotation(LiftableAnnotation)

def isConvertible(implicit ctx: AstContextBase): Boolean = hasAnnotation(ConvertibleAnnotation)

def hasMethodCallRecognizer: Boolean = {
val hasMethodRec = body.collectFirst { case md: SMethodDef if md.withMethodCallRecognizers => md }.nonEmpty
hasMethodRec || hasAnnotation(WithMethodCallRecognizersAnnotation)
}

def asTrait: STraitDef = { assert(this.isInstanceOf[STraitDef], s"$this is not trait"); this.asInstanceOf[STraitDef] }
Expand Down Expand Up @@ -1036,6 +1037,7 @@ object ScalanAst {
isAbstract: Boolean,
annotations: List[SEntityAnnotation] = Nil) extends SEntityDef with Updatable[SClassDef] {
def isTrait = false
def hasIsospec: Boolean = hasAnnotation(IsospecAnnotation)
def signature = DefSig(DefType.Entity, name, Nil)
def clean = {
val _companion = companion.map(_.clean)
Expand Down
17 changes: 11 additions & 6 deletions ast/src/main/scala/scalan/meta/ScalanAstExtensions.scala
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package scalan.meta

import scalan.util.GraphUtil
import scalan.util.GraphUtilEx
import scalan.meta.Symbols.SNamedDefSymbol
import scala.collection.mutable.ArrayBuffer
import scalan.meta.ScalanAstTraversers.EntityUseTraverser
import scalan.meta.ScalanAst._
import scalan.util.PrintExtensions._
import scalan.meta.AstLenses._
import debox.{Buffer => DBuffer}

object ScalanAstExtensions {

Expand All @@ -28,7 +29,7 @@ object ScalanAstExtensions {
if (config.isVirtualized || arg.isTypeDesc)
s"${arg.name}: ${arg.tpe}"
else
s"${arg.name}: Rep[${arg.tpe}]"
s"${arg.name}: Ref[${arg.tpe}]"
}
}
}
Expand All @@ -37,7 +38,7 @@ object ScalanAstExtensions {
if (isVirtualized) {
as.args.map({ a =>
val res = a.tpe.unRep(module, isVirtualized)
res.getOrElse { sys.error(s"Invalid field $a. Fields of concrete classes should be of type Rep[T] for some T.") }
res.getOrElse { sys.error(s"Invalid field $a. Fields of concrete classes should be of type Ref[T] for some T.") }
})
}
else
Expand Down Expand Up @@ -108,7 +109,7 @@ object ScalanAstExtensions {

val tRes = md.tpeRes.getOrElse(error)
if (config.isVirtualized) tRes.toString
else s"Rep[$tRes]"
else s"Ref[$tRes]"
}

def declaration(config: UnitConfig, includeOverride: Boolean) = {
Expand Down Expand Up @@ -136,9 +137,13 @@ object ScalanAstExtensions {
def inherit(n: String) = {
val e = unit.getEntity(n)
val as = e.getAncestorTypeNames.filter(n => localEntityNames.contains(n))
as
DBuffer.fromIterable(as)
}
val es = GraphUtil.stronglyConnectedComponents(unit.allEntities.map(_.name))(inherit).flatten
val es = GraphUtilEx.stronglyConnectedComponents(unit.allEntities.map(_.name).toArray)(inherit)
.toIterable()
.map(_.toArray())
.flatten

es.map(unit.getEntity).toList
}

Expand Down
2 changes: 1 addition & 1 deletion ast/src/main/scala/scalan/meta/ScalanAstTransformers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ object ScalanAstTransformers {
}
}

/** Removes all Rep types including RFunc and type synonims. */
/** Removes all Ref types including RFunc and type synonims. */
class RepTypeRemover(implicit ctx: AstContextBase) extends TypeTransformer {
override def typeTransform(tpe: STpeExpr): STpeExpr = {
val t = tpe match {
Expand Down
49 changes: 49 additions & 0 deletions ast/src/main/scala/scalan/util/GraphUtilEx.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package scalan.util

import scalan.{DFunc, DFuncAdapter}
import debox.{Buffer => DBuffer}

import scala.reflect.ClassTag
import spire.syntax.all.cfor

object GraphUtilEx {
/**
* Returns the strongly connected components
* of the graph rooted at the startNodes argument,
* whose edges are given by the function argument `succ`.
*
* @see Tarjan, Robert E.. “Depth-First Search and Linear Graph Algorithms.” SIAM J. Comput. 1 (1972): 146-160.
*/
def stronglyConnectedComponents[@specialized(Int) T: ClassTag](startNodes: DBuffer[T], succ: DFunc[T, DBuffer[T]]): DBuffer[DBuffer[T]] = {
val tarjan = new Tarjan[T](succ)

// top level loop of the algorithm
cfor(0)(_ < startNodes.length, _ + 1) { i =>
val node = startNodes(i)
tarjan.visit(node)
}

tarjan.res
}

def stronglyConnectedComponents[@specialized(Int) T: ClassTag](start: Array[T])(succ: T => DBuffer[T]): DBuffer[DBuffer[T]] = {
stronglyConnectedComponents(DBuffer.fromArray(start), new DFuncAdapter(succ))
}

def buildScheduleForResult(startNodes: DBuffer[Int], neighbours: DFunc[Int, DBuffer[Int]]): DBuffer[Int] = {
val components = GraphUtilEx.stronglyConnectedComponents(startNodes, neighbours)
val nComponents = components.length
if (nComponents == 1) {
components(0)
} else {
val res = DBuffer.ofSize[Int](components(0).length)
cfor(0)(_ < nComponents, _ + 1) { i =>
res ++= components(i)
}
res
}
}

val initTarjan = new Tarjan[Int](new DFuncAdapter((i: Int) => DBuffer(i)))
}

52 changes: 52 additions & 0 deletions ast/src/main/scala/scalan/util/Tarjan.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package scalan.util

import scala.reflect.ClassTag
import spire.syntax.all.cfor
import scalan.DFunc
import debox.{Buffer => DBuffer, Map => DMap}

/** Implementation of the SCC part of Tarjan algorithm. */
final class Tarjan[@specialized(Int) T: ClassTag](private var getNeighbours: DFunc[T, DBuffer[T]]) {
private var id = 0
private var stack: DBuffer[T] = DBuffer.empty
private val mark = DMap.ofSize[T,Int](127)

val res: DBuffer[DBuffer[T]] = DBuffer.empty

/** Explore the next graph node. Returns quickly if the node is already marked.
* @return mark assigned to `node` */
def visit(node: T): Int = {
val n = mark.getOrElse(node, -1)
if (n >= 0) return n

id += 1

mark.update(node, id)
stack += node

var min: Int = id
val neighbours = getNeighbours(node)
cfor(0)(_ < neighbours.length, _ + 1) { i =>
val child = neighbours(i)
val m = visit(child)

if (m < min)
min = m
}

if (min == mark(node)) {
val scc = DBuffer.empty[T]

var loop: Boolean = true
do {
val element = stack.pop
scc += element
mark.update(element, Integer.MAX_VALUE)
loop = element != node
} while (loop)

res += scc
}
min
}
}
Loading

0 comments on commit f8b00d1

Please sign in to comment.