Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
keynmol committed Sep 7, 2024
1 parent 5b50857 commit 9ae188a
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 52 deletions.
2 changes: 0 additions & 2 deletions jvm/ParallelCollectionsEvaluator.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package genovese

//> using dep "org.scala-lang.modules::scala-parallel-collections::1.0.4"

object ParallelCollectionsEvaluator extends Evaluator:
override def evaluate(pop: Population, fitness: Vec => NormalisedFloat): Evaluated =
import scala.collection.parallel.CollectionConverters.*
Expand Down
131 changes: 99 additions & 32 deletions shared/Featureful.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,58 @@ trait Featureful[T]:

def fromFeatures(fv: IArray[NormalisedFloat]): T

def bimap[B](f: T => B, g: B => T) =
val t = this
new Featureful[B]:
override def features: IArray[Feature[?]] = t.features
def toFeatures(value: B)(using RuntimeChecks): IArray[NormalisedFloat] =
t.toFeatures(g(value))
def fromFeatures(fv: IArray[NormalisedFloat]): B = f(t.fromFeatures(fv))
end Featureful

final case class ConstFeatureful[T](const: T) extends Featureful[T]:
override lazy val features: IArray[Feature[?]] = IArray.empty
override def fromFeatures(fv: IArray[NormalisedFloat]): T = const
override def toFeatures(value: T)(using
RuntimeChecks
): IArray[NormalisedFloat] = IArray.empty

final case class TupleFeatureful[T <: Tuple](values: List[Featureful[?]])
extends Featureful[T]:
override lazy val features: IArray[Feature[?]] =
IArray.from(values.flatMap(_.features))

override def fromFeatures(fv: IArray[NormalisedFloat]): T =
val ab = Array.newBuilder[Any]

var offset = 0

values.foreach: f =>
ab += f.fromFeatures(fv.slice(offset, offset + f.features.length))
offset += f.features.length

Tuple.fromArray(ab.result()).asInstanceOf[T]
end fromFeatures

override def toFeatures(value: T)(using
RuntimeChecks
): IArray[NormalisedFloat] =
val len = features.length

val a = Array.fill(len)(NormalisedFloat.ZERO)

var offset = 0
values
.zip(value.toArray)
.foreach: (f, any) =>
val iv = f.toFeatures(any.asInstanceOf).unsafeArray
System.arraycopy(iv, 0, a, offset, f.features.length)
offset += f.features.length

IArray.unsafeFromArray(a)
end toFeatures
end TupleFeatureful

object Featureful:
def features[T](using f: Featureful[T]) = f.features

Expand All @@ -31,8 +83,27 @@ object Featureful:
derivedImpl[T]('config)
}

inline def deriveTuple[T <: Tuple] = ${ derivedTupleImpl[T] }

import scala.quoted.*

private def derivedTupleImpl[T <: Tuple](using Quotes, Type[T]) =
val inst = Expr.ofList(summonInstances[T])

'{ TupleFeatureful[T]($inst) }.asExprOf[Featureful[T]]

private def summonInstances[T: Type](using
Quotes
): List[Expr[Featureful[?]]] =
Type.of[T] match
case '[elem *: elems] =>
'{
compiletime
.summonInline[Featureful[elem]]
.asInstanceOf[Featureful[elem]]
} :: summonInstances[elems]
case '[EmptyTuple] => Nil

private given FromExpr[RuntimeChecks] with
def unapply(expr: Expr[RuntimeChecks])(using
Quotes
Expand Down Expand Up @@ -96,9 +167,9 @@ object Featureful:
case '{ Feature.IntCategory(${ Expr(alts) }) } =>
Some(Feature.IntCategory(alts).asInstanceOf[Feature[?]])

// TODO: how do I implement this?
// case '{Feature.Optional(${ Expr(alts) }) } =>
// Some(Feature.Optional(alts).asInstanceOf[Feature[?]])
// // TODO: how do I implement this?
// case '{type t; ${CategSummon[t](alts)} } =>
// Some(Feature.Categorical[t](alts).asInstanceOf[Feature[?]])

// Match the NormalisedFloatRange case
case '{ Feature.NormalisedFloatRange } =>
Expand All @@ -111,6 +182,7 @@ object Featureful:
// If none of the above patterns match, return None
case _ => None
end unapply

end given

private given FromExpr[FieldConfig] with
Expand Down Expand Up @@ -277,6 +349,8 @@ object Featureful:
extension [T](e: Expr[Featureful[T]])
def trustMeBro = e.asExprOf[Featureful[E]]

val hasOverride = summon[FieldConfig].overrides.get(name)

Type.of[E] match
case '[Option[t]] =>
val span = constructFeature[t](name)
Expand All @@ -301,41 +375,34 @@ object Featureful:
s"Incompatible field config [$other] for field [$name], which has type Float"
)

case '[Int] =>
summon[FieldConfig].overrides.get(name) match
case None =>
report.errorAndAbort(
s"Field config missing for field [$name], which has type Int"
)
case Some(Feature.IntRange(from, to)) =>
single(Expr(Feature.IntRange(from, to))).trustMeBro
case Some(other) =>
report.errorAndAbort(
s"Incompatible field config [$other] for field [$name], which has type Int"
)

case _ if hasNested.isDefined =>
hasNested.get

case '[String] =>
summon[FieldConfig].overrides.get(name) match
case '[Map[t, g]] =>
report.warning(
s"Field [$name] has type ${TypeRepr.of[Seq[t]].show}, currently genovese cannot handle it. Empty map will be used"
)

'{ ConstFeatureful(Map.empty[t, g]) }.trustMeBro
case '[Seq[t]] =>
report.warning(
s"Field [$name] has type ${TypeRepr.of[Seq[t]].show}, currently genovese cannot generated sequences of random length"
)

val f = constructFeature[t](name)

'{ OptionFeatureful[t]($f).bimap(_.toSeq, _.headOption) }.trustMeBro

case other =>
hasOverride match
case None =>
report.errorAndAbort(
s"Field config missing for field [$name], which has type String"
)
case Some(Feature.StringCategory(alts)) =>
single[String](Expr(Feature.StringCategory(alts))).trustMeBro
case Some(other) =>
report.errorAndAbort(
s"Incompatible field config [$other] for field [$name], which has type String"
s"Don't know how to turn field [$name] of type [" + TypeRepr
.of(using other)
.show + "] into a feature (or feature vector)"
)

case other =>
report.errorAndAbort(
s"Don't know how to turn field [$name] of type [" + TypeRepr
.of(using other)
.show + "] into a feature (or feature vector)"
)
case Some(feat) =>
single[E](Expr(feat.asInstanceOf)).trustMeBro
end match
end constructFeature

Expand Down
9 changes: 9 additions & 0 deletions shared/Featureful.test.scala
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,15 @@ class FeaturefulTest extends FunSuite, ScalaCheckSuite:
val value = TestEnums(oneline, wrap)
roundtrip(value) == value

property("tuples roundtrip"):
given f: Featureful[(Oneline, Wrap)] = deriveTuple[(Oneline, Wrap)]

forAll(
Gen.oneOf(Wrap.values.toSeq),
Gen.oneOf(Oneline.keep, Oneline.fold, Oneline.unfold)
): (wrap, oneline) =>
roundtrip(oneline -> wrap) == oneline -> wrap

def roundtrip[T: Featureful](value: T): T =
fromFeatures[T](toFeatures(value))

Expand Down
1 change: 1 addition & 0 deletions shared/project.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
//> using test.dep "org.scalameta::munit-scalacheck::1.0.0"
//> using test.dep "org.scalameta::munit::1.0.1"
//> using test.dep "org.scalameta:scalafmt-core_2.13:3.8.3"
//> using dep "org.scala-lang.modules::scala-parallel-collections::1.0.4"
//> using test.dep "com.github.vickumar1981:stringdistance_2.13:1.2.7"
//> using test.dep "org.scalameta::munit-diff::1.0.1"

Expand Down
69 changes: 51 additions & 18 deletions shared/scalafmt.test.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import org.scalafmt.Scalafmt
import org.scalafmt.config.*
import org.scalafmt.config.Docstrings.*
import java.util.concurrent.ConcurrentHashMap
import org.scalafmt.config.Indents.FewerBraces

given Featureful[Oneline] = Featureful.derive[Oneline](FieldConfig.None)
given Featureful[Wrap] = Featureful.derive[Wrap](FieldConfig.None)
Expand All @@ -15,20 +16,62 @@ given Featureful[Docstrings] = Featureful.derive[Docstrings](
FieldConfig(Map("wrapMaxColumn" -> Feature.IntRange(0, 1)))
)

given commentsWrap: Featureful[Comments.Wrap] =
Featureful.derived[Comments.Wrap]
given Featureful[Comments] = Featureful.derived[Comments]
given Featureful[OptIn] = Featureful.derived[OptIn]

given Featureful[BinPack.Site] = Featureful.derived[BinPack.Site]
given Featureful[BinPack.ParentCtors] = Featureful.derived[BinPack.ParentCtors]
given Featureful[BinPack] = Featureful.derive[BinPack](
FieldConfig(
Map(
"literalsMinArgCount" -> Feature.IntRange(1, 8),
"literalsInclude" -> Feature.StringCategory(List("this")),
"literalsExclude" -> Feature.StringCategory(List("a"))
)
)
)

given Featureful[FewerBraces] = Featureful.derived[FewerBraces]
given Featureful[Indents.RelativeToLhs] =
Featureful.derived[Indents.RelativeToLhs]
given Featureful[Indents] = Featureful.derive[Indents](
FieldConfig(
Map(
"main" -> Feature.IntCategory(List(0, 2, 4)),
"significant" -> Feature.IntCategory(List(0, 2, 4)),
"callSite" -> Feature.IntCategory(List(0, 2, 4)),
"ctrlSite" -> Feature.IntCategory(List(0, 2, 4)),
"binPackCallSite" -> Feature.IntCategory(List(0, 2, 4)),
"defnSite" -> Feature.IntCategory(List(0, 2, 4)),
"caseSite" -> Feature.IntCategory(List(0, 2, 4)),
"matchSite" -> Feature.IntCategory(List(0, 2, 4)),
"ctorSite" -> Feature.IntCategory(List(0, 2, 4)),
"extraBeforeOpenParenDefnSite" -> Feature.IntCategory(List(0, 2, 4)),
"binPackDefnSite" -> Feature.IntCategory(List(0, 2, 4)),
"afterInfixSite" -> Feature.IntCategory(List(0, 2, 4)),
"withSiteRelativeToExtends" -> Feature.IntCategory(List(0, 2, 4)),
"extendSite" -> Feature.IntCategory(List(0, 2, 4)),
"commaSiteRelativeToExtends" -> Feature.IntCategory(List(0, 2, 4))
)
)
)

class ScalafmtTest extends FunSuite:
test("scalafmt"):
given RuntimeChecks = RuntimeChecks.Full

// val cache = ConcurrentHashMap[Docstrings, NormalisedFloat]()
val cache = ConcurrentHashMap[Docstrings, NormalisedFloat]()

def fitness(docstrings: Docstrings = Docstrings()) =
import com.github.vickumar1981.stringdistance.*
import com.github.vickumar1981.stringdistance.StringDistance.*
import com.github.vickumar1981.stringdistance.impl.ConstantGap

// cache.computeIfAbsent(
// docstrings,
// { _ =>
cache.computeIfAbsent(
docstrings,
{ _ =>
val formatted = Scalafmt
.format(text.trim, style = ScalafmtConfig(docstrings = docstrings))
.get
Expand All @@ -40,32 +83,22 @@ class ScalafmtTest extends FunSuite:
.max(0.0f)
.min(1.0f)
)
// }
// )
}
)
end fitness

val trainingConfig = TrainingConfig(
populationSize = 100,
mutationRate = NormalisedFloat(0.8f),
steps = 100000,
steps = 5,
random = scala.util.Random(80085L),
selection = Selection.Top(0.8)
)

object Handler extends EventHandler:
import TrainingEvent.*, TrainingInstruction.*
def handle[T](t: TrainingEvent[T], data: T | Null): TrainingInstruction =
t match
case r @ ReportFitness =>
println(ReportFitness.cast(data))
Continue
case TopSpecimen =>
println(
Featureful
.fromFeatures[Docstrings](TopSpecimen.cast(data))
)
Continue
case _ => Continue
Continue
end handle

end Handler
Expand Down

0 comments on commit 9ae188a

Please sign in to comment.