Commit aaac72f4 authored by Romain Reuillon's avatar Romain Reuillon
Browse files

[Core] enh: refactor domain

parent 57fa5ba8
package org.openmole.core.dsl
import org.openmole.core.workflow.domain.{ DomainInput, DomainValidation }
import org.openmole.tool.logger.LoggerService
package object extension {
type FromContext[+T] = org.openmole.core.expansion.FromContext[T]
......@@ -39,14 +36,15 @@ package object extension {
type BoundedFromContextDomain[-D, +T] = org.openmole.core.workflow.domain.BoundedFromContextDomain[D, T]
type BoundedDomain[-D, +T] = org.openmole.core.workflow.domain.BoundedDomain[D, T]
type FixDomain[-D, +T] = org.openmole.core.workflow.domain.FixDomain[D, T]
type SizedDomain[-D] = org.openmole.core.workflow.domain.SizedDomain[D]
type DiscreteDomain[-D, +T] = org.openmole.core.workflow.domain.DiscreteDomain[D, T]
type DiscreteFromContextDomain[-D, +T] = org.openmole.core.workflow.domain.DiscreteFromContextDomain[D, T]
type CenterDomain[-D, +T] = org.openmole.core.workflow.domain.CenterDomain[D, T]
type CenterFromContextDomain[-D, +T] = org.openmole.core.workflow.domain.CenterFromContextDomain[D, T]
type DomainInput[-D] = org.openmole.core.workflow.domain.DomainInput[D]
type DomainValidation[-D] = org.openmole.core.workflow.domain.DomainValidation[D]
type DomainCenter[-D, +T] = org.openmole.core.workflow.domain.DomainCenter[D, T]
type DomainCenterFromContext[-D, +T] = org.openmole.core.workflow.domain.DomainCenterFromContext[D, T]
type DomainSize[-D] = org.openmole.core.workflow.domain.DomainSize[D]
type Domain[+D] = org.openmole.core.workflow.domain.Domain[D]
def Domain = org.openmole.core.workflow.domain.Domain
type Factor[D, T] = org.openmole.core.workflow.sampling.Factor[D, T]
def Factor[D, T](p: Val[T], d: D) = org.openmole.core.workflow.sampling.Factor(p, d)
......@@ -108,5 +106,5 @@ package object extension {
type Information = squants.information.Information
type JavaLogger = org.openmole.tool.logger.JavaLogger
def Logger = LoggerService
def Logger = org.openmole.tool.logger.LoggerService
}
......@@ -28,22 +28,21 @@ import scala.annotation.implicitNotFound
*/
@implicitNotFound("${D} is not a bounded variation domain of type ${T}")
trait BoundedDomain[-D, +T] {
def min(domain: D): T
def max(domain: D): T
def apply(domain: D): Domain[(T, T)]
}
object BoundedFromContextDomain {
implicit def boundsIsContextBounds[D, T](implicit bounds: BoundedDomain[D, T]): BoundedFromContextDomain[D, T] =
new BoundedFromContextDomain[D, T] {
def min(d: D) = FromContext.value(bounds.min(d))
def max(d: D) = FromContext.value(bounds.max(d))
d {
val domain = bounds(d)
val (min, max) = domain.domain
domain.copy(domain = (FromContext.value(min), FromContext.value(max)))
}
}
@implicitNotFound("${D} is not a bounded variation domain of type T | FromContext[${T}]")
trait BoundedFromContextDomain[-D, +T] {
def min(domain: D): FromContext[T]
def max(domain: D): FromContext[T]
def apply(domain: D): Domain[(FromContext[T], FromContext[T])]
}
\ No newline at end of file
......@@ -27,15 +27,18 @@ import scala.annotation.implicitNotFound
*/
@implicitNotFound("${D} is not a discrete variation domain of type ${T}")
trait DiscreteDomain[-D, +T] {
def iterator(domain: D): Iterator[T]
def apply(domain: D): Domain[Iterator[T]]
}
object DiscreteFromContextDomain {
implicit def discreteIsContextDiscrete[D, T](implicit d: DiscreteDomain[D, T]): DiscreteFromContextDomain[D, T] =
domain FromContext.value(d.iterator(domain))
domain {
val dv = d(domain)
dv.copy(domain = FromContext.value(dv.domain))
}
}
@implicitNotFound("${D} is not a discrete variation domain of type T | FromContext[${T}]")
trait DiscreteFromContextDomain[-D, +T] {
def iterator(domain: D): FromContext[Iterator[T]]
def apply(domain: D): Domain[FromContext[Iterator[T]]]
}
\ No newline at end of file
package org.openmole.core.workflow.domain
/*
* Copyright (C) 2021 Romain Reuillon
*
......@@ -15,15 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.openmole.core.workflow.domain
import org.openmole.core.context._
import org.openmole.core.expansion.Validate
object DomainValidation {
implicit def empty[T]: DomainValidation[T] = _ Validate.success
}
trait DomainValidation[-T] {
def apply(t: T): Validate
}
case class Domain[+D](domain: D, inputs: PrototypeSet = PrototypeSet.empty, validation: Validate = Validate.success)
......@@ -26,20 +26,15 @@ import scala.annotation.implicitNotFound
* @tparam T
*/
@implicitNotFound("${D} is not a variation domain with a center of type ${T}")
trait CenterDomain[-D, +T] {
def center(domain: D): T
trait DomainCenter[-D, +T] {
def apply(domain: D): T
}
object CenterFromContextDomain {
implicit def centerIsContextCenter[D, T](implicit c: CenterDomain[D, T]): CenterFromContextDomain[D, T] =
new CenterFromContextDomain[D, T] {
def center(domain: D) = FromContext.value(c.center(domain))
}
object DomainCenterFromContext {
implicit def centerIsContextCenter[D, T](implicit c: DomainCenter[D, T]): DomainCenterFromContext[D, T] = d FromContext.value(c(d))
}
@implicitNotFound("${D} is not a variation domain with a center of type T | FromContext[${T}]")
trait CenterFromContextDomain[-D, +T] {
def center(domain: D): FromContext[T]
trait DomainCenterFromContext[-D, +T] {
def apply(domain: D): FromContext[T]
}
/*
* Copyright (C) 2010 Romain Reuillon
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.openmole.core.workflow.domain
import org.openmole.core.context._
object DomainInput {
/**
* By default implicitly no inputs
* @tparam T
* @return
*/
implicit def empty[T]: DomainInput[T] = _ PrototypeSet.empty
}
/**
* Property of having inputs
* @tparam D
*/
trait DomainInput[-T] {
def apply(t: T): PrototypeSet
}
......@@ -7,6 +7,6 @@ import scala.annotation.implicitNotFound
* @tparam D
*/
@implicitNotFound("${D} is not a sized variation domain")
trait SizedDomain[-D] {
trait DomainSize[-D] {
def apply(domain: D): Int
}
......@@ -9,5 +9,5 @@ import scala.annotation.implicitNotFound
*/
@implicitNotFound("${D} is not a fix variation domain of type ${T}")
trait FixDomain[-D, +T] {
def apply(domain: D): Iterable[T]
def apply(domain: D): Domain[Iterable[T]]
}
......@@ -22,13 +22,16 @@ import cats.implicits._
object UnrolledDomain {
implicit def isDiscrete[D, T: Manifest]: DiscreteDomain[UnrolledDomain[D, T], Array[T]] = domain Seq(domain.discrete.iterator(domain.d).toArray).iterator
implicit def inputs[D, T: Manifest]: DomainInput[UnrolledDomain[D, T]] = domain domain.inputs(domain.d)
implicit def validate[D, T: Manifest]: DomainValidation[UnrolledDomain[D, T]] = domain domain.validate(domain.d)
implicit def isDiscrete[D, T: Manifest]: DiscreteDomain[UnrolledDomain[D, T], Array[T]] = domain
Domain(
domain = Seq(domain.discrete(domain.d).domain.toArray).iterator,
inputs = domain.discrete(domain.d).inputs,
validation = domain.discrete(domain.d).validation
)
def apply[D[_], T: Manifest](domain: D[T])(implicit discrete: DiscreteDomain[D[T], T], inputs: DomainInput[D[T]], validate: DomainValidation[D[T]]) =
def apply[D[_], T: Manifest](domain: D[T])(implicit discrete: DiscreteDomain[D[T], T]) =
new UnrolledDomain[D[T], T](domain)
}
class UnrolledDomain[D, T: Manifest](val d: D)(implicit val discrete: DiscreteDomain[D, T], val inputs: DomainInput[D], val validate: DomainValidation[D])
class UnrolledDomain[D, T: Manifest](val d: D)(implicit val discrete: DiscreteDomain[D, T])
......@@ -37,25 +37,31 @@ package sampling {
def is(d: FromContext[T]) = Factor(p, d)
}
implicit def fromContextIsDiscrete[T] = new DiscreteFromContextDomain[FromContext[T], T] {
override def iterator(domain: FromContext[T]): FromContext[Iterator[T]] = domain.map(v Vector(v).iterator)
}
implicit def fromContextIsDiscrete[T]: DiscreteFromContextDomain[FromContext[T], T] = domain Domain(domain.map(v Vector(v).iterator))
implicit def fromIsSampling[T](t: T)(implicit isSampling: IsSampling[T], samplingInputs: DomainInput[T], samplingValidate: DomainValidation[T]) =
implicit def fromIsSampling[T](t: T)(implicit isSampling: IsSampling[T]) =
new Sampling {
override def validate = isSampling.validate(t) ++ samplingValidate(t)
override def inputs = isSampling.inputs(t) ++ samplingInputs(t)
override def validate = isSampling.validate(t)
override def inputs = isSampling.inputs(t)
override def outputs: Iterable[Val[_]] = isSampling.outputs(t)
override def apply(): FromContext[Iterator[Iterable[Variable[_]]]] = isSampling.apply(t)
}
implicit def factorIsSampling[D, T](implicit domain: DiscreteFromContextDomain[D, T], domainInputs: DomainInput[D], domainValidate: DomainValidation[D]) = new IsSampling[Factor[D, T]] {
def validate(f: Factor[D, T]): Validate = domain.iterator(f.domain).validate ++ domainValidate(f.domain)
def inputs(f: Factor[D, T]) = domain.iterator(f.domain).inputs ++ domainInputs.apply(f.domain)
implicit def factorIsSampling[D, T](implicit domain: DiscreteFromContextDomain[D, T]) = new IsSampling[Factor[D, T]] {
def validate(f: Factor[D, T]): Validate = {
val domainValue = domain(f.domain)
domainValue.domain.validate ++ domainValue.validation
}
def inputs(f: Factor[D, T]) = {
val domainValue = domain(f.domain)
domain(f.domain).inputs ++ domainValue.inputs
}
def outputs(f: Factor[D, T]) = List(f.value)
override def apply(f: Factor[D, T]): FromContext[Iterator[collection.Iterable[Variable[T]]]] =
domain.iterator(f.domain).map { values values.map { v List(Variable(f.value, v)) } }
domain(f.domain).domain.map { values values.map { v List(Variable(f.value, v)) } }
}
type Sampling = sampling.Sampling
......
......@@ -75,40 +75,44 @@ object Scalable {
implicit def factorOfDoubleIsScalable[D, T: ScalableType](implicit bounded: BoundedFromContextDomain[D, T]) = new Scalable[Factor[D, T]] {
def isScalar(t: Factor[D, T]) = true
override def inputs(t: Factor[D, T]) = Seq()
override def inputs(t: Factor[D, T]) = bounded(t.domain).inputs
override def prototype(t: Factor[D, T]): Val[_] = t.value
override def size(t: Factor[D, T]): FromContext[Int] = 1
override def unflatten(s: Factor[D, T])(values: Seq[Double], scale: Boolean): FromContext[Scaled] = {
override def unflatten(s: Factor[D, T])(values: Seq[Double], scale: Boolean): FromContext[Scaled] = FromContext { p
import p._
val g = values.head
assert(!g.isNaN)
(bounded.min(s.domain) map2 bounded.max(s.domain)) { (min, max)
val sc = if (scale) implicitly[ScalableType[T]].scale(g, min, max) else implicitly[ScalableType[T]].convert(g)
ScaledScalar(s.value, sc)
}
val (min, max) = bounded(s.domain).domain
val sc = if (scale) implicitly[ScalableType[T]].scale(g, min.from(context), max.from(context)) else implicitly[ScalableType[T]].convert(g)
ScaledScalar(s.value, sc)
}
}
implicit def factorOfSequenceIsScalable[D, T: ScalableType: ClassTag](implicit bounded: BoundedFromContextDomain[D, Array[T]]) = new Scalable[Factor[D, Array[T]]] {
def isScalar(t: Factor[D, Array[T]]) = false
override def inputs(t: Factor[D, Array[T]]) = Seq()
override def inputs(t: Factor[D, Array[T]]) = bounded(t.domain).inputs
override def prototype(t: Factor[D, Array[T]]): Val[_] = t.value
override def size(t: Factor[D, Array[T]]): FromContext[Int] =
(bounded.min(t.domain) map2 bounded.max(t.domain)) { case (min, max) math.min(min.size, max.size) }
override def size(t: Factor[D, Array[T]]): FromContext[Int] = FromContext { p
import p._
val (min, max) = bounded(t.domain).domain
math.min(min.from(context).size, max.from(context).size)
}
override def unflatten(t: Factor[D, Array[T]])(values: Seq[Double], scale: Boolean): FromContext[Scaled] = {
override def unflatten(t: Factor[D, Array[T]])(values: Seq[Double], scale: Boolean): FromContext[Scaled] = FromContext { p
import p._
val (min, max) = bounded(t.domain).domain
def scaled =
(bounded.min(t.domain) map2 bounded.max(t.domain)) {
case (min, max)
if (scale) (values zip (min zip max)).map { case (g, (min, max)) implicitly[ScalableType[T]].scale(g, min, max) }
else values.map(implicitly[ScalableType[T]].convert)
}
if (scale) (values zip (min.from(context) zip max.from(context))).map { case (g, (min, max)) implicitly[ScalableType[T]].scale(g, min, max) }
else values.map(implicitly[ScalableType[T]].convert)
scaled.map { sc ScaledSequence(t.value, sc.toArray) }
ScaledSequence(t.value, scaled.toArray)
}
}
......
......@@ -7,9 +7,7 @@ class ContextDomainSpec extends FlatSpec with Matchers {
"A value domain" should "be accepted as a context domain" in {
def f[D](d: D)(implicit f: DiscreteFromContextDomain[D, Int]) = ""
implicit def intIsFinite = new DiscreteDomain[Int, Int] {
override def iterator(domain: Int) = Iterator(domain)
}
implicit def intIsFinite: DiscreteDomain[Int, Int] = domain Domain(Iterator(domain))
f(8)
}
......
......@@ -83,7 +83,7 @@ class HookSpec extends FlatSpec with Matchers {
"Display hook" should "be accepted" in {
val t1 = EmptyTask()
val ex = t1 hook display
ex.run
(ex: DSL)
}
}
......@@ -21,7 +21,7 @@ import java.io.{ ByteArrayInputStream, ByteArrayOutputStream }
import org.openmole.core.context.Val
import org.openmole.core.serializer.SerializerService
import org.openmole.core.workflow.builder._
import org.openmole.core.workflow.domain.DiscreteFromContextDomain
import org.openmole.core.workflow.domain._
import org.scalatest._
import org.openmole.core.workflow.dsl._
import org.openmole.core.workflow.sampling.ExplicitSampling
......@@ -63,7 +63,7 @@ class SerializationSpec extends FlatSpec with Matchers {
val data = List("A", "B", "C")
val i = Val[String]("i")
implicit def listFactor: DiscreteFromContextDomain[List[String], String] = domain domain.iterator
implicit def listFactor: DiscreteFromContextDomain[List[String], String] = domain Domain(domain.iterator)
val exp = ExplorationTask(i in data)
val t = EmptyTask() set (inputs += i)
......
......@@ -7,34 +7,26 @@ import cats.implicits._
package object bounds {
implicit def tupleOfStringToBounds[T: FromString: Manifest] = new BoundedFromContextDomain[(String, String), T] {
override def min(domain: (String, String)): FromContext[T] = FromContext.codeToFromContext[T](domain._1)
override def max(domain: (String, String)): FromContext[T] = FromContext.codeToFromContext[T](domain._2)
implicit def tupleOfStringToBounds[T: FromString: Manifest]: BoundedFromContextDomain[(String, String), T] = domain {
val minCode = FromContext.codeToFromContext[T](domain._1)
val maxCode = FromContext.codeToFromContext[T](domain._2)
Domain((minCode, maxCode))
}
implicit def tupleIsBounds[T] = new BoundedDomain[(T, T), T] {
override def min(domain: (T, T)) = domain._1
override def max(domain: (T, T)) = domain._2
}
implicit def iterableOfTuplesIsBounds[T: Manifest] = new BoundedDomain[Iterable[(T, T)], Array[T]] {
override def min(domain: Iterable[(T, T)]) = domain.unzip._1.toArray
override def max(domain: Iterable[(T, T)]) = domain.unzip._2.toArray
}
implicit def arrayOfTuplesIsBounds[T: Manifest] = new BoundedDomain[Array[(T, T)], Array[T]] {
override def min(domain: Array[(T, T)]) = domain.unzip._1
override def max(domain: Array[(T, T)]) = domain.unzip._2
}
implicit def tupleIsBounds[T]: BoundedDomain[(T, T), T] = domain Domain(domain)
implicit def iterableOfTuplesIsBounds[T: Manifest]: BoundedDomain[Iterable[(T, T)], Array[T]] = domain Domain((domain.unzip._1.toArray, domain.unzip._2.toArray))
implicit def arrayOfTuplesIsBounds[T: Manifest]: BoundedDomain[Array[(T, T)], Array[T]] = domain Domain((domain.unzip._1, domain.unzip._2))
implicit def iterableOfStringTuplesIsBounds[T: FromString: Manifest] = new BoundedFromContextDomain[Iterable[(String, String)], Array[T]] {
override def min(domain: Iterable[(String, String)]) = domain.unzip._1.toVector.traverse(v FromContext.codeToFromContext[T](v): FromContext[T]).map(_.toArray)
override def max(domain: Iterable[(String, String)]) = domain.unzip._2.toVector.traverse(v FromContext.codeToFromContext[T](v): FromContext[T]).map(_.toArray)
implicit def iterableOfStringTuplesIsBounds[T: FromString: Manifest]: BoundedFromContextDomain[Iterable[(String, String)], Array[T]] = domain {
def min = domain.unzip._1.toVector.traverse(v FromContext.codeToFromContext[T](v): FromContext[T]).map(_.toArray)
def max = domain.unzip._2.toVector.traverse(v FromContext.codeToFromContext[T](v): FromContext[T]).map(_.toArray)
Domain((min, max))
}
implicit def arrayOfStringTuplesIsBounds[T: FromString: Manifest] = new BoundedFromContextDomain[Array[(String, String)], Array[T]] {
override def min(domain: Array[(String, String)]) = domain.unzip._1.toVector.traverse(v FromContext.codeToFromContext[T](v): FromContext[T]).map(_.toArray)
override def max(domain: Array[(String, String)]) = domain.unzip._2.toVector.traverse(v FromContext.codeToFromContext[T](v): FromContext[T]).map(_.toArray)
implicit def arrayOfStringTuplesIsBounds[T: FromString: Manifest]: BoundedFromContextDomain[Array[(String, String)], Array[T]] = domain {
def min = domain.unzip._1.toVector.traverse(v FromContext.codeToFromContext[T](v): FromContext[T]).map(_.toArray)
def max = domain.unzip._2.toVector.traverse(v FromContext.codeToFromContext[T](v): FromContext[T]).map(_.toArray)
Domain((min, max))
}
}
......@@ -21,13 +21,15 @@ import org.openmole.core.dsl._
import org.openmole.core.dsl.extension._
object SeqDomain {
implicit def isFinite[T]: DiscreteFromContextDomain[SeqDomain[T], T] = domain FromContext { p
import p._
domain.values.iterator.map(_.from(context))
}
implicit def inputs[T]: DomainInput[SeqDomain[T]] = domain domain.values.flatMap(_.inputs)
implicit def validate[T]: DomainValidation[SeqDomain[T]] = domain domain.values.map(_.validate)
implicit def isFinite[T]: DiscreteFromContextDomain[SeqDomain[T], T] = domain
Domain(
FromContext { p
import p._
domain.values.iterator.map(_.from(context))
},
domain.values.flatMap(_.inputs),
domain.values.map(_.validate)
)
def apply[T](values: FromContext[T]*) = new SeqDomain[T](values: _*)
}
......
......@@ -17,10 +17,8 @@
package org.openmole.plugin.domain
import org.openmole.core.context.{ PrototypeSet, Val }
import org.openmole.core.expansion.FromContext
import org.openmole.core.workflow.domain.{ DomainInput, _ }
import org.openmole.core.workflow.sampling._
import org.openmole.core.dsl._
import org.openmole.core.dsl.extension._
import org.openmole.tool.types._
import scala.reflect.ClassTag
......@@ -29,57 +27,30 @@ package collection {
// Avoid clash with iterableOfToArrayIsFix when T is of type Array[T]
trait LowPriorityImplicits {
implicit def iterableIsDiscrete[T] = new DiscreteFromContextDomain[Iterable[T], T] {
override def iterator(domain: Iterable[T]) = domain.iterator
}
implicit def iterableIsFix[T] = new FixDomain[Iterable[T], T] {
override def apply(domain: Iterable[T]): Iterable[T] = domain
}
implicit def iterableIsSized[T] = new SizedDomain[Iterable[T]] {
override def apply(domain: Iterable[T]) = domain.size
}
implicit def iterableIsDiscrete[T]: DiscreteFromContextDomain[Iterable[T], T] = domain Domain(domain.iterator)
implicit def iterableIsFix[T]: FixDomain[Iterable[T], T] = domain Domain(domain)
implicit def iterableIsSized[T]: DomainSize[Iterable[T]] = domain domain.size
}
}
package object collection extends LowPriorityImplicits {
implicit def iterableOfToArrayIsFinite[T: ClassTag, A1[_]: ToArray] = new DiscreteFromContextDomain[Iterable[A1[T]], Array[T]] {
override def iterator(domain: Iterable[A1[T]]) = domain.map(implicitly[ToArray[A1]].apply[T]).iterator
}
implicit def iterableOfToArrayIsFix[T: ClassTag, A1[_]: ToArray] = new FixDomain[Iterable[A1[T]], Array[T]] {
override def apply(domain: Iterable[A1[T]]) = domain.map(implicitly[ToArray[A1]].apply[T])
}
implicit def arrayIsDiscrete[T] = new DiscreteFromContextDomain[Array[T], T] {
override def iterator(domain: Array[T]) = domain.iterator
}
implicit def arrayIsFix[T] = new FixDomain[Array[T], T] {
override def apply(domain: Array[T]): Iterable[T] = domain.toIterable
}
implicit def arrayIsSized[T] = new SizedDomain[Array[T]] {
override def apply(domain: Array[T]) = domain.size
}
implicit def iteratorIsDiscrete[T] = new DiscreteFromContextDomain[Iterator[T], T] {
override def iterator(domain: Iterator[T]) = domain
}
implicit def fromContextIteratorIsDiscrete[T] = new DiscreteFromContextDomain[FromContext[Iterator[T]], T] {
override def iterator(domain: FromContext[Iterator[T]]) = domain
}
implicit def iterableOfToArrayIsFinite[T: ClassTag, A1[_]: ToArray]: DiscreteFromContextDomain[Iterable[A1[T]], Array[T]] = domain Domain(domain.map(implicitly[ToArray[A1]].apply[T]).iterator)
implicit def iterableOfToArrayIsFix[T: ClassTag, A1[_]: ToArray]: FixDomain[Iterable[A1[T]], Array[T]] = domain Domain(domain.map(implicitly[ToArray[A1]].apply[T]))