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 e06399d commit 5b50857
Show file tree
Hide file tree
Showing 28 changed files with 211 additions and 234 deletions.
4 changes: 4 additions & 0 deletions js/EvaluatorCompanion.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package genovese

private[genovese] trait EvaluatorCompanion:
val default = SequentialEvaluator
20 changes: 20 additions & 0 deletions jvm/ParallelCollectionsEvaluator.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
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.*
Evaluated(
IArray.unsafeFromArray(
IArray
.genericWrapArray(pop)
.toArray
.par
.map(vec => vec -> fitness(vec))
.toArray
)
)

private[genovese] trait EvaluatorCompanion:
val default = ParallelCollectionsEvaluator
28 changes: 28 additions & 0 deletions shared/EnumFeatureful.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package genovese

import scala.reflect.ClassTag

final case class EnumFeatureful[T](values: IArray[T]) extends Featureful[T]:
private val lookup = values.zipWithIndex.toMap
override lazy val features: IArray[Feature[?]] = IArray(
Feature.IntCategory(List.tabulate(values.length)(identity))
)
override def toFeatures(value: T)(using
RuntimeChecks
): IArray[NormalisedFloat] =
features.map:
case f @ Feature.IntCategory(_) =>
f.toNormalisedFloat(lookup(value))

override def fromFeatures(
fv: IArray[NormalisedFloat]
): T =
features(0): @unchecked match
case f @ Feature.IntCategory(_) =>
val idx =
f.fromNormalisedFloat(NormalisedFloat.applyUnsafe(fv(0)))
values(idx)

override def toString(): String = s"EnumFeatureful(${values.mkString(",")})"
end EnumFeatureful

10 changes: 10 additions & 0 deletions shared/Evaluator.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package genovese

trait Evaluator:
def evaluate(population: Population, fitness: Vec => NormalisedFloat): Evaluated

object Evaluator extends EvaluatorCompanion

object SequentialEvaluator extends Evaluator:
override def evaluate(population: Population, fitness: Vec => NormalisedFloat): Evaluated =
Evaluated(population.map(v => v -> fitness(v)))
File renamed without changes.
File renamed without changes.
File renamed without changes.
183 changes: 3 additions & 180 deletions Featureful.scala → shared/Featureful.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package genovese

import scala.deriving.Mirror
import scala.reflect.ClassTag
import scala.util.boundary

trait Featureful[T]:

Expand All @@ -12,69 +11,6 @@ trait Featureful[T]:

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

final case class SingleFeatureful[T](feature: Feature[T]) extends Featureful[T]:
override val features: IArray[Feature[?]] = IArray(feature)

override def toFeatures(value: T)(using
RuntimeChecks
): IArray[NormalisedFloat] =
IArray(feature.toNormalisedFloat(value))

override def fromFeatures(fv: IArray[NormalisedFloat]): T =
feature.fromNormalisedFloat(fv(0).asInstanceOf[NormalisedFloat])
end SingleFeatureful

final case class EnumFeatureful[T](values: IArray[T]) extends Featureful[T]:
private val lookup = values.zipWithIndex.toMap
override lazy val features: IArray[Feature[?]] = IArray(
Feature.IntCategory(List.tabulate(values.length)(identity))
)
override def toFeatures(value: T)(using
RuntimeChecks
): IArray[NormalisedFloat] =
features.map:
case f @ Feature.IntCategory(_) =>
f.toNormalisedFloat(lookup(value))

override def fromFeatures(
fv: IArray[NormalisedFloat]
): T =
features(0) match
case f @ Feature.IntCategory(_) =>
val idx =
f.fromNormalisedFloat(NormalisedFloat.applyUnsafe(fv(0)))
values(idx)

override def toString(): String = s"EnumFeatureful(${values.mkString(",")})"
end EnumFeatureful

final case class OptionFeatureful[T](original: Featureful[T])
extends Featureful[Option[T]]:
override lazy val features: IArray[Feature[?]] =
original.features.map(Feature.Optional(_))
override def fromFeatures(fv: IArray[NormalisedFloat]): Option[T] =
boundary:
val decompressed = fv.map: v =>
if v < 0.5f then boundary.break(None)
else NormalisedFloat.applyUnsafe(2 * (v - 0.5f))
Some(original.fromFeatures(decompressed))

override def toFeatures(value: Option[T])(using
RuntimeChecks
): IArray[NormalisedFloat] =
value match
case None =>
IArray.fill(original.features.size)(NormalisedFloat.applyUnsafe(0.25f))
case Some(value) =>
original
.toFeatures(value)
.map(v => NormalisedFloat.applyUnsafe(v / 2 + 0.5f))
end OptionFeatureful

case class FieldConfig(overrides: Map[String, Feature[?]])
object FieldConfig:
inline def None = FieldConfig(Map.empty)

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

Expand Down Expand Up @@ -160,8 +96,9 @@ object Featureful:
case '{ Feature.IntCategory(${ Expr(alts) }) } =>
Some(Feature.IntCategory(alts).asInstanceOf[Feature[?]])

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

// Match the NormalisedFloatRange case
case '{ Feature.NormalisedFloatRange } =>
Expand Down Expand Up @@ -241,27 +178,6 @@ object Featureful:

'{
EnumFeatureful[T](IArray.from($values)(using $ct))
// new Featureful[T]:
// private val ars = IArray.from[T]($values)(using $ct)
// override lazy val features: IArray[Feature[?]] = IArray(
// Feature.IntCategory(List.tabulate($values.length)(identity))
// )
// override def toFeatures(value: T)(using
// RuntimeChecks
// ): IArray[NormalisedFloat] =
// features.map:
// case f @ Feature.IntCategory(_) =>
// f.toNormalisedFloat($m.ordinal(value))

// override def fromFeatures(
// fv: IArray[NormalisedFloat]
// ): T =
// features(0) match
// case f @ Feature.IntCategory(_) =>
// val idx =
// f.fromNormalisedFloat(NormalisedFloat.applyUnsafe(fv(0)))
// ars(idx)

}

case '{
Expand Down Expand Up @@ -353,14 +269,6 @@ object Featureful:
)(using Quotes, FieldConfig): Expr[Featureful[E]] =
import quotes.reflect.*

// val isCaseClass = Implicits.search(TypeRepr.of[Mirror.ProductOf[E]]) match
// case _: ImplicitSearchSuccess => true
// case _ => false

// val isEnum = Implicits.search(TypeRepr.of[Mirror.SumOf[E]]) match
// case _: ImplicitSearchSuccess => true
// case _ => false

val hasNested = Implicits.search(TypeRepr.of[Featureful[E]]) match
case res: ImplicitSearchSuccess =>
Some(res.tree.asExprOf[Featureful[E]])
Expand Down Expand Up @@ -408,18 +316,6 @@ object Featureful:

case _ if hasNested.isDefined =>
hasNested.get
// ???

// Span.Enum('{ $e.features.head }, Type.of[E])

// case _ if hasNested.isDefined =>
// ???
// val e = hasNested.get
// Span.Splice(e.asExprOf[Featureful[E]], Type.of[E])
// '{ $e.features.toList },
// '{ any => $e.toFeatures(any.asInstanceOf[E]) },
// '{ (arr, default) => $e.fromFeatures(arr, default.asInstanceOf[E]) }
// )

case '[String] =>
summon[FieldConfig].overrides.get(name) match
Expand All @@ -443,82 +339,9 @@ object Featureful:
end match
end constructFeature

// private enum Span:
// case Primitive[T](
// feature: Expr[Feature[T]],
// tpe: Type[T]
// )

// case Enum(
// feature: Expr[Feature[?]],
// tpe: Type[?]
// )

// case Splice(
// delegate: Expr[Featureful[?]],
// tpe: Type[?]
// )

// def convert(using
// Quotes
// ): Expr[RuntimeChecks ?=> Any => IArray[NormalisedFloat]] =
// this match
// case p @ Primitive(feature, tpe) =>
// val (t, f) = cast(tpe)
// given Type[T] = p.tpe
// '{ rc ?=> any =>
// IArray(
// $f($feature).toNormalisedFloat($t(any).asInstanceOf)(using rc)
// )
// }
// case Enum(feature, tpe) =>
// '{ rc ?=> any =>
// IArray($feature.toNormalisedFloat(any.asInstanceOf)(using rc))
// }
// case Splice(delegate, tpe) =>
// '{ any => $delegate.toFeatures(any.asInstanceOf) }

// def back(using Quotes): Expr[(IArray[NormalisedFloat], Any) => Any] =
// this match
// case Primitive(feature, _) =>
// '{ (ar, _) =>
// $feature.fromNormalisedFloat(ar.apply(0).asInstanceOf)
// }
// case Enum(feature, _) =>
// '{ (ar, _) =>
// $feature.fromNormalisedFloat(ar.apply(0).asInstanceOf)
// }
// case Splice(delegate, _) =>
// '{ (arr, default) =>
// $delegate.fromFeatures(arr, default.asInstanceOf)
// }

// def features(using Quotes) = this match
// case Primitive(feature, _) => '{ List($feature) }
// case Enum(feature, _) => '{ List($feature) }
// case Splice(features, _) => '{ $features.features.toList }

// def size(using Quotes) = this match
// case Primitive(feature, _) => '{ 1 }
// case Enum(feature, _) => '{ 1 }
// case Splice(delegate, _) => '{ $delegate.features.size }

// end Span

private def single[T: Type](f: Expr[Feature[T]])(using
Quotes
): Expr[SingleFeatureful[T]] =
'{ SingleFeatureful($f) }
// Span.Primitive(
// f,
// Type.of[T]
// )

// private def cast(t: Type[?])(using Quotes) =
// t match
// case '[t] =>
// '{ (any: Any) => any.asInstanceOf[t] } -> '{ (any: Feature[?]) =>
// any.asInstanceOf[Feature[t]]
// }

end Featureful
5 changes: 3 additions & 2 deletions Featureful.test.scala → shared/Featureful.test.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package genovese

import munit.*
import org.scalacheck.Prop.*
import org.scalacheck.Gen
import org.scalacheck.Prop.*

import Featureful.*

class FeaturefulTest extends FunSuite, ScalaCheckSuite:
Expand Down Expand Up @@ -99,7 +100,7 @@ class FeaturefulTest extends FunSuite, ScalaCheckSuite:

property("enums roundtrip"):
forAll(
Gen.oneOf(Wrap.values),
Gen.oneOf(Wrap.values.toSeq),
Gen.oneOf(Oneline.keep, Oneline.fold, Oneline.unfold)
): (wrap, oneline) =>
val value = TestEnums(oneline, wrap)
Expand Down
11 changes: 11 additions & 0 deletions shared/FieldConfig.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package genovese

import scala.deriving.Mirror
import scala.reflect.ClassTag
import scala.util.boundary
import scala.annotation.nowarn

case class FieldConfig(overrides: Map[String, Feature[?]])

object FieldConfig:
inline def None = FieldConfig(Map.empty)
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
30 changes: 30 additions & 0 deletions shared/OptionFeatureful.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package genovese

import scala.deriving.Mirror
import scala.reflect.ClassTag
import scala.util.boundary
import scala.annotation.nowarn

final case class OptionFeatureful[T](original: Featureful[T])
extends Featureful[Option[T]]:
override lazy val features: IArray[Feature[?]] =
original.features.map(Feature.Optional(_))
override def fromFeatures(fv: IArray[NormalisedFloat]): Option[T] =
boundary:
val decompressed = fv.map: v =>
if v < 0.5f then boundary.break(None)
else NormalisedFloat.applyUnsafe(2 * (v - 0.5f))
Some(original.fromFeatures(decompressed))

override def toFeatures(value: Option[T])(using
RuntimeChecks
): IArray[NormalisedFloat] =
value match
case None =>
IArray.fill(original.features.size)(NormalisedFloat.applyUnsafe(0.25f))
case Some(value) =>
original
.toFeatures(value)
.map(v => NormalisedFloat.applyUnsafe(v / 2 + 0.5f))
end OptionFeatureful

File renamed without changes.
File renamed without changes.
13 changes: 13 additions & 0 deletions shared/SingleFeatureful.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package genovese

final case class SingleFeatureful[T](feature: Feature[T]) extends Featureful[T]:
override val features: IArray[Feature[?]] = IArray(feature)

override def toFeatures(value: T)(using
RuntimeChecks
): IArray[NormalisedFloat] =
IArray(feature.toNormalisedFloat(value))

override def fromFeatures(fv: IArray[NormalisedFloat]): T =
feature.fromNormalisedFloat(fv(0).asInstanceOf[NormalisedFloat])
end SingleFeatureful
5 changes: 3 additions & 2 deletions Train.test.scala → shared/Train.test.scala
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,9 @@ class TrainTest extends FunSuite:
val top = Train(
summon[Featureful[FormattingConfig]],
config = trainingConfig,
fitness = fitness
).train(Handler).maxBy(_._2)._1
fitness = fitness,
events = Handler,
).train().maxBy(_._2)._1

assertEquals(fitness(top), 0.6f)

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion project.scala → shared/project.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//> using dep "com.lihaoyi::pprint::0.9.0"
//> using dep "org.scala-lang.modules::scala-parallel-collections::1.0.4"
//> using dep "com.indoorvivants::opaque-newtypes::0.1.0"
//> using option -Wunused:all -deprecation
//> using scala 3.5.0
//> using test.dep "org.scalameta::munit-scalacheck::1.0.0"
Expand Down
Loading

0 comments on commit 5b50857

Please sign in to comment.