This repository has been archived by the owner on Apr 27, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
First version of the API, incl/ demo.
- Loading branch information
1 parent
df29b95
commit 2455d44
Showing
8 changed files
with
458 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
# Created by .ignore support plugin (hsz.mobi) | ||
### SBT template | ||
# Simple Build Tool | ||
# http://www.scala-sbt.org/release/docs/Getting-Started/Directories.html#configuring-version-control | ||
|
||
dist/* | ||
target/ | ||
lib_managed/ | ||
src_managed/ | ||
project/boot/ | ||
project/plugins/project/ | ||
.history | ||
.cache | ||
### Java template | ||
# Compiled class file | ||
*.class | ||
|
||
# Log file | ||
*.log | ||
|
||
# BlueJ files | ||
*.ctxt | ||
|
||
# Mobile Tools for Java (J2ME) | ||
.mtj.tmp/ | ||
|
||
# Package Files # | ||
*.war | ||
*.ear | ||
*.zip | ||
*.tar.gz | ||
*.rar | ||
|
||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml | ||
hs_err_pid* | ||
### JetBrains template | ||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm | ||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 | ||
|
||
# User-specific stuff: | ||
.idea | ||
|
||
## File-based project format: | ||
*.iws | ||
|
||
## Plugin-specific files: | ||
|
||
# IntelliJ | ||
out/ | ||
|
||
# mpeltonen/sbt-idea plugin | ||
.idea_modules/ | ||
|
||
# JIRA plugin | ||
atlassian-ide-plugin.xml | ||
|
||
# Cursive Clojure plugin | ||
.idea/replstate.xml | ||
|
||
# Crashlytics plugin (for Android Studio and IntelliJ) | ||
com_crashlytics_export_strings.xml | ||
crashlytics.properties | ||
crashlytics-build.properties | ||
fabric.properties | ||
### Scala template |
30 changes: 30 additions & 0 deletions
30
src/main/scala/com/softwaremill/helisa/EvolutionResult.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package com.softwaremill.helisa | ||
|
||
import com.softwaremill.helisa.api.convert.Decoder | ||
import io.{jenetics => j} | ||
|
||
class EvolutionResult[A: Decoder[?, G], G <: Gene[_, G], FRC <: Comparable[FRC]](val jResult: j.engine.EvolutionResult[G, FRC]) { | ||
|
||
def optimize = jResult.getOptimize | ||
|
||
def population = jResult.getPopulation.asScala.flatMap(_.decode[A].toSeq) | ||
|
||
def bestPhenotype: Option[A] = jResult.getBestPhenotype.decode | ||
|
||
def worstPhenotype: Option[A] = jResult.getWorstPhenotype.decode | ||
|
||
def generation: Long = jResult.getGeneration | ||
|
||
def totalGenerations: Long = jResult.getTotalGenerations | ||
|
||
def killCount = jResult.getKillCount | ||
|
||
def altererCount = jResult.getAlterCount | ||
|
||
def invalidCount = jResult.getInvalidCount | ||
|
||
def bestFitness = jResult.getBestFitness | ||
|
||
def worstFitness = jResult.getWorstFitness | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package com.softwaremill.helisa | ||
|
||
import com.softwaremill.helisa.api.convert.{CodecBuilder, Decoder} | ||
import io.{jenetics => j} | ||
|
||
import scala.collection.JavaConverters._ | ||
import scala.concurrent.ExecutionContext | ||
|
||
object Evolver { | ||
|
||
def apply[A, G <: Gene[_, G], @specialized(Int, Double, Float, Long) FitnessResult](fitnessFunction: A => FitnessResult, | ||
genotype: () => Genotype[G])( | ||
implicit decoder: Decoder[A, G], | ||
evComp: FitnessResultComparable[FitnessResult]): EvolverBuilder[A, G, evComp.FitnessResultC] = { | ||
|
||
import java.util.function._ | ||
import scala.compat.java8.FunctionConverters._ | ||
|
||
val codec: j.engine.Codec[A, G] = CodecBuilder.codecFor[A](genotype) | ||
new EvolverBuilder(j.engine.Engine.builder(fitnessFunction.andThen(evComp(_)).asJava, codec)) | ||
} | ||
|
||
} | ||
|
||
class Evolver[A: Decoder[?, G], G <: Gene[_, G], FRC <: Comparable[FRC]](val jEngine: j.engine.Engine[G, FRC]) { | ||
|
||
def stream(): Stream[EvolutionResult[A, G, FRC]] = jEngine.stream().iterator().asScala.map(new EvolutionResult(_)).toStream | ||
|
||
} | ||
|
||
class EvolverBuilder[A: Decoder[?, G], G <: Gene[_, G], FRC <: Comparable[FRC]] private[helisa] ( | ||
private val jBuilder: j.engine.Engine.Builder[G, FRC]) { | ||
import scala.compat.java8.FunctionConverters._ | ||
|
||
private def modifyBuilder(mod: j.engine.Engine.Builder[G, FRC] => Unit): EvolverBuilder[A, G, FRC] = { | ||
mod(jBuilder) | ||
this | ||
} | ||
|
||
def fitnessScaler(scaler: FRC => FRC) = modifyBuilder(_.fitnessScaler(scaler.asJava)) | ||
|
||
def offspringSelector(selector: Selector[G, FRC]) = modifyBuilder(_.offspringSelector(selector.asJava)) | ||
|
||
def offspringSelector(selector: j.Selector[G, FRC]) = modifyBuilder(_.offspringSelector(selector)) | ||
|
||
def survivorsSelector(selector: Selector[G, FRC]) = modifyBuilder(_.survivorsSelector(selector.asJava)) | ||
|
||
def survivorsSelector(selector: j.Selector[G, FRC]) = modifyBuilder(_.survivorsSelector(selector)) | ||
|
||
def sSelector(selector: Selector[G, FRC]) = modifyBuilder(_.selector(selector.asJava)) | ||
|
||
def selector(selector: j.Selector[G, FRC]) = modifyBuilder(_.selector(selector)) | ||
|
||
def alterers(alterer1: Alterer[G, FRC], rest: Alterer[G, FRC]*) = | ||
modifyBuilder(_.alterers(alterer1.asJava, rest.map(_.asJava): _*)) | ||
|
||
def alterers(alterer1: j.Alterer[G, FRC], rest: j.Alterer[G, FRC]*) = modifyBuilder(_.alterers(alterer1, rest: _*)) | ||
|
||
def phenotypeValidator(validator: A => Boolean) = | ||
modifyBuilder(_.phenotypeValidator(_.getGenotype.decode[A].exists(validator))) | ||
|
||
def genotypeValidator(validator: Genotype[G] => Boolean) = modifyBuilder(_.genotypeValidator(validator.asJava)) | ||
|
||
def optimize(optimize: Optimize) = modifyBuilder(_.optimize(optimize)) | ||
|
||
def maximizing() = modifyBuilder(_.maximizing()) | ||
|
||
def minimizing() = modifyBuilder(_.minimizing()) | ||
|
||
def offspringFraction(fraction: Double) = modifyBuilder(_.offspringFraction(fraction)) | ||
|
||
def survivorsFraction(fraction: Double) = modifyBuilder(_.survivorsFraction(fraction)) | ||
|
||
def survivorsSize(size: Int) = modifyBuilder(_.survivorsSize(size)) | ||
|
||
def offspringSize(size: Int) = modifyBuilder(_.offspringSize(size)) | ||
|
||
def populationSize(size: Int) = modifyBuilder(_.populationSize(size)) | ||
|
||
def maximalPhenotypeAge(age: Long) = modifyBuilder(_.maximalPhenotypeAge(age)) | ||
|
||
def executor(ec: ExecutionContext) = modifyBuilder(_.executor(ec.execute(_))) | ||
|
||
def clock(clock: java.time.Clock) = modifyBuilder(_.clock(clock)) | ||
|
||
def individualCreationRetries(retries: Int) = modifyBuilder(_.individualCreationRetries(retries)) | ||
|
||
def build(): Evolver[A, G, FRC] = new Evolver(jBuilder.build()) | ||
|
||
} |
41 changes: 41 additions & 0 deletions
41
src/main/scala/com/softwaremill/helisa/FitnessResultComparable.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package com.softwaremill.helisa | ||
|
||
import scala.annotation.implicitNotFound | ||
|
||
@implicitNotFound("""Comparable to {FitnessResult} not found. The result of your fitness function should either: | ||
1. Be a primitive (Int/Long/Double/Float). | ||
2. Implement java.lang.Comparable.""") | ||
trait FitnessResultComparable[FitnessResult] { | ||
type FitnessResultC <: Comparable[FitnessResultC] | ||
def apply(c: FitnessResult): FitnessResultC | ||
} | ||
|
||
object FitnessResultComparable { | ||
implicit def fitnessResultComparable[_FitnessResultC <: Comparable[_FitnessResultC]]: FitnessResultComparable[_FitnessResultC] = | ||
new FitnessResultComparable[_FitnessResultC] { | ||
type FitnessResultC = _FitnessResultC | ||
def apply(c: _FitnessResultC): _FitnessResultC = c | ||
} | ||
|
||
implicit object DoubleFitnessResultComparable extends FitnessResultComparable[Double] { | ||
type FitnessResultC = java.lang.Double | ||
def apply(c: Double): java.lang.Double = c | ||
} | ||
|
||
implicit object FloatFitnessResultComparable extends FitnessResultComparable[Float] { | ||
type FitnessResultC = java.lang.Float | ||
def apply(c: Float): java.lang.Float = c | ||
} | ||
|
||
implicit object IntegerFitnessResultComparable extends FitnessResultComparable[Int] { | ||
type FitnessResultC = java.lang.Integer | ||
def apply(c: Int): java.lang.Integer = c | ||
} | ||
|
||
implicit object LongFitnessResultComparable extends FitnessResultComparable[Long] { | ||
type FitnessResultC = java.lang.Long | ||
|
||
def apply(c: Long): java.lang.Long = c | ||
} | ||
|
||
} |
21 changes: 21 additions & 0 deletions
21
src/main/scala/com/softwaremill/helisa/api/convert/CodecBuilder.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.softwaremill.helisa.api.convert | ||
|
||
import java.util.function | ||
import io.{jenetics => j} | ||
import com.softwaremill.helisa.Gene | ||
|
||
abstract class CodecBuilder[A] { | ||
def apply[G <: Gene[_, G]](genotype: () => j.Genotype[G])(implicit d: Decoder[A, G]): j.engine.Codec[A, G] | ||
} | ||
|
||
object CodecBuilder { | ||
def codecFor[A] = new CodecBuilder[A] { | ||
def apply[G <: Gene[_, G]](genotype: () => j.Genotype[G])(implicit d: Decoder[A, G]) = new j.engine.Codec[A, G] { | ||
def encoding(): j.util.Factory[j.Genotype[G]] = () => genotype() | ||
|
||
def decoder(): function.Function[j.Genotype[G], A] = | ||
(jGenotype: j.Genotype[G]) => | ||
d.decode(jGenotype).getOrElse(throw new IllegalStateException(s"Can't convert this genotype: $jGenotype")) | ||
} | ||
} | ||
} |
35 changes: 35 additions & 0 deletions
35
src/main/scala/com/softwaremill/helisa/api/convert/Decoder.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package com.softwaremill.helisa.api.convert | ||
|
||
import com.softwaremill.helisa.Gene | ||
import io.{jenetics => j} | ||
import shapeless.ops.hlist.ToTraversable | ||
import shapeless.ops.traversable.FromTraversable | ||
import shapeless.{Generic, HList} | ||
|
||
import scala.annotation.implicitNotFound | ||
import scala.collection.JavaConverters._ | ||
|
||
@implicitNotFound(msg = """Decoder for ${A} , ${G} not found. | ||
For automatic generation, you need these things: | ||
1. *All* fields of the case class you use *must* be compatible with possible Gene values. | ||
2. import com.softwaremill.helisa._ | ||
""") | ||
trait Decoder[A, G <: Gene[_, G]] { | ||
|
||
def decode(genotype: j.Genotype[G]): Option[A] | ||
|
||
} | ||
|
||
object Decoder { | ||
|
||
implicit def caseClassDecoder[A, G <: Gene[_, G], Repr <: HList](implicit g: Generic.Aux[A, Repr], | ||
tT: ToTraversable.Aux[Repr, Vector, _], | ||
fT: FromTraversable[Repr]): Decoder[A, G] = | ||
(genotype: j.Genotype[G]) => { | ||
import shapeless.syntax.std.traversable._ | ||
val repr = genotype.iterator().asScala.map(_.getGene.getAllele).toTraversable.toHList[Repr] | ||
repr.map(g.from) | ||
} | ||
|
||
} |
Oops, something went wrong.