Commit 6fce88d5 authored by Arthur Bit-Monnot's avatar Arthur Bit-Monnot

Gather algebra and syntax providers in a new core module.

parent 9b41a59f
......@@ -19,10 +19,10 @@ object GraphColoring extends Family("graph-coloring") {
implicit val tag: TagIsoInt[Color] = TagIsoInt.fromEnum(Array(Red, Green, Blue))
def color(name: String): Input[Color] = Input(name)
def color(name: String): Tentative[Color] = Input(name)
import Color._
implicit def color2Cst(color: Color): Cst[Color] = Cst(color)
implicit def color2Cst(color: Color): Tentative[Color] = Cst(color)
instances("simple-graph") {
val A = color("A")
......@@ -8,7 +8,7 @@ object Jobshop extends Family("jobshop") {
val START = Cst(1)
val END = Input[Int]("makespan").subjectTo(START <= _)
def input(): Input[Int] = Input()
def input(): Tentative[Int] = Input()
def tp()= input().subjectTo(x => START <= x && x <= END)
case class Job(jobNumber: Int,
......@@ -64,9 +64,19 @@ lazy val root = project
publishLocal := {}
lazy val algebra = project
.settings(name := "dahu-core-algebra")
.settings(commonSettings: _*)
.settings(libraryDependencies ++= Seq(
"org.typelevel" %% "cats-core" % "1.1.0",
"org.typelevel" %% "spire" % "0.14.1"
lazy val planningModel = project
.settings(name := "dahu-planning-model")
.settings(commonSettings: _*)
.settings(libraryDependencies ++= Seq(
"com.chuusai" %% "shapeless" % "2.3.3",
......@@ -117,7 +127,7 @@ lazy val recursion = project
lazy val model = project
.dependsOn(utils, recursion)
.dependsOn(utils, recursion, algebra)
.settings(name := "dahu-model")
.settings(commonSettings ++ utestSettings: _*)
package dahu.core.algebra
trait BoolLike[A] {
def and(a: A, b: A): A
def or(a: A, b: A): A
def not(a: A): A
object BoolLike {
def apply[A](implicit instance: BoolLike[A]): BoolLike[A] = instance
class BoolLikeOps[A](private val a: A) extends AnyVal {
def &&(b: A)(implicit B: BoolLike[A]): A = B.and(a, b)
def ||(b: A)(implicit B: BoolLike[A]): A = B.or(a, b)
def unary_!(implicit B: BoolLike[A]): A = B.not(a)
def implies(b: A)(implicit B: BoolLike[A]): A = B.or(B.not(a), b)
def ==>(b: A)(implicit B: BoolLike[A]): A = B.or(B.not(a), b)
package dahu.core.algebra
trait Comparable[-A, -B] {
type Bool
def BL: BoolLike[Bool]
def leq(a: A, b: B): Bool
def lt(a: A, b: B): Bool
def geq(a: A, b: B): Bool
def gt(a: A, b: B): Bool
def eqv(a: A, b: B): Bool = BL.and(leq(a, b), geq(a, b))
def neq(a: A, b: B): Bool = BL.not(eqv(a, b))
object Comparable {
type Aux[A, B, C0] = Comparable[A, B] { type Bool = C0 }
package dahu.core.algebra
trait NumberLike[-A] extends Orderable[A] {
type Num
def times(a: A, b: A): Num
def add(a: A, b: A): Num
def sub(a: A, b: A): Num
def negate(a: A): Num
object NumberLike {
type Aux[A, C0, Num0] = NumberLike[A] { type Bool = C0; type Num = Num0 }
def apply[A](implicit ev: NumberLike[A]): Aux[A, ev.Bool, ev.Num] = ev
class NumberLikeOps[A](private val a: A) extends AnyVal {
def *(b: A)(implicit N: NumberLike[A]): N.Num = N.times(a, b)
def +(b: A)(implicit N: NumberLike[A]): N.Num = N.add(a, b)
def -(b: A)(implicit N: NumberLike[A]): N.Num = N.sub(a, b)
package dahu.core.algebra
trait Orderable[-A] extends Comparable[A, A] {
override def geq(a: A, b: A): Bool = leq(b, a)
override def gt(a: A, b: A): Bool = lt(b, a)
object Orderable {
type Aux[A, C0] = Orderable[A] { type Bool = C0 }
implicit class OrderableOps[A](private val a: A) extends AnyVal {
def <=(b: A)(implicit O: Orderable[A]): O.Bool = O.leq(a, b)
def <(b: A)(implicit O: Orderable[A]): O.Bool =, b)
def >=(b: A)(implicit O: Orderable[A]): O.Bool = O.geq(a, b)
def >(b: A)(implicit O: Orderable[A]): O.Bool =, b)
def ===(b: A)(implicit O: Orderable[A]): O.Bool = O.eqv(a, b)
def =!=(b: A)(implicit O: Orderable[A]): O.Bool = O.neq(a, b)
......@@ -48,14 +48,17 @@ final case class Input[T: Tag](id: Ident) extends Term[T] {
override def typ: Tag[T] = Tag[T]
object Input {
def apply[T: Tag](name: String): Input[T] = new Input[T](Provided(name))
def apply[T: Tag](): Input[T] = new Input[T](Anonymous())
def apply[T: Tag](name: String): Tentative[T] = new Input[T](Provided(name))
def apply[T: Tag](): Tentative[T] = new Input[T](Anonymous())
/** Evaluation returns a Right[T](value) */
final case class Cst[T: Tag](value: T) extends Term[T] {
override def typ: Tag[T] = Tag[T]
object Cst {
def apply[T: Tag](v: T): Tentative[T] = new Cst(v)
final case class ITE[T](cond: Tentative[Boolean], onTrue: Tentative[T], onFalse: Tentative[T])
extends Tentative[T] {
package dahu.model.input
import dahu.model.functions.{Fun, Fun1, Fun2}
import dahu.model.math.BooleanLike.BooleanOps
import dahu.model.math.Numeric.{NumericBase, NumericOps}
import dahu.core
import dahu.core.algebra
import dahu.core.algebra.{BoolLike, NumberLike, Orderable}
import dahu.model.functions.{Fun1, Fun2}
import dahu.model.math._
import dahu.model.types.{BoxedInt, Tag, TagIsoInt}
import shapeless.=:!=
import dahu.model.types.{Tag, TagIsoInt}
import scala.language.implicitConversions
......@@ -23,34 +23,42 @@ object dsl {
def ITE[T](cond: Tentative[Boolean], t: Tentative[T], f: Tentative[T]) =
new ITE[T](cond, t, f)
implicit def double2Cst(value: Double): Cst[Double] = Cst(value)
implicit def int2Cst(value: Int): Cst[Int] = Cst(value)
implicit def double2Cst(value: Double): Tentative[Double] = Cst(value)
implicit def int2Cst(value: Int): Tentative[Int] = Cst(value)
implicit class InputHelper(val sc: StringContext) extends AnyVal {
def d(args: Any*): Input[Double] = Input[Double](sc.s(args: _*))
def d(args: Any*): Tentative[Double] = Input[Double](sc.s(args: _*))
// todo: check is this is actually needed
implicit def input2Expr[T](input: Input[T]): Tentative[T] = input
implicit def cst2Expr[T](cst: Cst[T]): Tentative[T] = cst
implicit def value2Expr[T: NumericBase: Tag](value: T): Tentative[T] = Cst(value)
implicit def tentative2numOps[T](lhs: Tentative[T])(implicit num: Numeric[T, Tentative],
bool: BooleanLike[Boolean, Tentative],
tag: Tag[T]) =
new NumericOps[T, Tentative](lhs)
implicit class TentativeOrderOps[T: TagIsoInt](lhs: Tentative[T])(implicit ev: T =:!= Int,
ev2: T =:!= Double) {
def ===(rhs: Tentative[T]): Tentative[Boolean] =
int.EQ(TagIsoInt[T].unbox(lhs), TagIsoInt[T].unbox(rhs))
def =!=(rhs: Tentative[T]): Tentative[Boolean] =
bool.Not(new TentativeOrderOps(lhs) === rhs)
implicit val boolLike: BoolLike[Tentative[Boolean]] = new BoolLike[Tentative[Boolean]] {
override def and(a: Tentative[Boolean], b: Tentative[Boolean]): Tentative[Boolean] =
Computation(bool.And, Seq(a, b))
override def or(a: Tentative[Boolean], b: Tentative[Boolean]): Tentative[Boolean] =
Computation(bool.Or, Seq(a, b))
override def not(a: Tentative[Boolean]): Tentative[Boolean] =
Computation(bool.Not, a)
implicit def tentative2boolOps(lhs: Tentative[Boolean])(
implicit bool: BooleanLike[Boolean, Tentative]) =
new BooleanOps[Boolean, Tentative](lhs)(bool)
implicit val intsNumber: NumberLike.Aux[Tentative[Int], Tentative[Boolean], Tentative[Int]] =
Numeric.toNumberLike[Int, Tentative]
implicit val numbersDouble
: NumberLike.Aux[Tentative[Double], Tentative[Boolean], Tentative[Double]] =
Numeric.toNumberLike[Double, Tentative]
implicit def orderableIsoInt[T: TagIsoInt]: Orderable.Aux[Tentative[T], Tentative[Boolean]] =
new Orderable[Tentative[T]] {
override type Bool = Tentative[Boolean]
override def BL: BoolLike[Tentative[Boolean]] = boolLike
override def leq(a: Tentative[T], b: Tentative[T]): Bool =
intsNumber.leq(TagIsoInt[T].unbox(a), TagIsoInt[T].unbox(b))
override def lt(a: Tentative[T], b: Tentative[T]): Bool =[T].unbox(a), TagIsoInt[T].unbox(b))
implicit def toNumberLikeOps[A: NumberLike](a: A) = new algebra.NumberLike.NumberLikeOps(a)
implicit def toOrderableLikeOps[A: Orderable](a: A) = new core.algebra.Orderable.OrderableOps(a)
implicit def toBoolLikeOps[A: BoolLike](a: A) = new core.algebra.BoolLike.BoolLikeOps(a)
implicit final class ToSubjectToOps[F[_], T](private val lhs: F[T])(
implicit ev: F[T] <:< Tentative[T]) {
package dahu.model.math
import dahu.model.functions._
trait BooleanLike[T, F[_]] {
def and(conjuncts: F[T]*): F[T]
def or(disjuncts: F[T]*): F[T]
def not(term: F[T]): F[T]
object BooleanLike {
def apply[T, F[_]](implicit ev: BooleanLike[T, F]): BooleanLike[T, F] = ev
trait BooleanBase[T] {
def and: FunN[T, T]
def or: FunN[T, T]
def not: Fun1[T, T]
implicit object BoolAlgebra extends BooleanBase[Boolean] {
override def and: FunN[Boolean, Boolean] = bool.And
override def or: FunN[Boolean, Boolean] = bool.Or
override def not: Fun1[Boolean, Boolean] = bool.Not
implicit def instanceOfReifApp[T, F[_]](implicit ev: BooleanBase[T],
F: ReifiedApplicative[F]): BooleanLike[T, F] =
new BooleanLike[T, F] {
override def and(conjuncts: F[T]*): F[T] =
F.mapN(conjuncts: _*)(ev.and)
override def or(disjuncts: F[T]*): F[T] =
F.mapN(disjuncts: _*)(ev.or)
override def not(term: F[T]): F[T] =
implicit class BooleanOps[T, F[_]](val lhs: F[T])(implicit bool: BooleanLike[T, F]) {
def &&(rhs: F[T]): F[T] = bool.and(lhs, rhs)
def ||(rhs: F[T]): F[T] = bool.or(lhs, rhs)
def unary_~(): F[T] = bool.not(lhs)
def implies(rhs: F[T]): F[T] = (~lhs) || rhs
def ==>(rhs: F[T]): F[T] = lhs implies rhs
package dahu.model.math
import dahu.core.algebra.{BoolLike, NumberLike, Orderable}
import dahu.model.functions._
import dahu.model.types.{Tag, TagIsoInt}
......@@ -80,18 +81,19 @@ object Numeric {
F.mapN(lhs, rhs)(ev.times)
implicit class NumericOps[T, F[_]](val lhs: F[T])(implicit num: Numeric[T, F],
bool: BooleanLike[Boolean, F]) {
def <=(rhs: F[T]): F[Boolean] = num.leq(lhs, rhs)
def <(rhs: F[T]): F[Boolean] =, rhs)
def >=(rhs: F[T]): F[Boolean] = num.geq(lhs, rhs)
def >(rhs: F[T]): F[Boolean] =, rhs)
def ===(rhs: F[T]): F[Boolean] = num.eqv(lhs, rhs)
def =!=(rhs: F[T]): F[Boolean] = bool.not(lhs === rhs)
def *(rhs: F[T]): F[T] = num.times(lhs, rhs)
def +(rhs: F[T]): F[T] = num.add(lhs, rhs)
def unary_-(): F[T] = num.negate(lhs)
def -(rhs: F[T]): F[T] = num.add(lhs, -rhs)
def toNumberLike[T, F[_]](implicit num: Numeric[T, F],
bool: BoolLike[F[Boolean]]): NumberLike.Aux[F[T], F[Boolean], F[T]] =
new NumberLike[F[T]] {
override type Bool = F[Boolean]
override type Num = F[T]
override def BL: BoolLike[Bool] = bool
override def leq(a: F[T], b: F[T]): Bool = num.leq(a, b)
override def lt(a: F[T], b: F[T]): Bool =, b)
override def eqv(a: F[T], b: F[T]): Bool = num.eqv(a, b)
override def times(a: F[T], b: F[T]): F[T] = num.times(a, b)
override def add(a: F[T], b: F[T]): F[T] = num.add(a, b)
override def sub(a: F[T], b: F[T]): F[T] = num.substract(a, b)
override def negate(a: F[T]): F[T] = num.negate(a)
package dahu.model.math
import dahu.model.functions._
import dahu.model.input.Cst
import dahu.model.input.{Cst, Tentative}
import dahu.model.types.{BoxedInt, Tag}
import dahu.model.types.Tag
object double {
......@@ -109,9 +109,9 @@ object bool {
override def reverse: Reversible[Boolean, Boolean] = this
val True: Cst[Boolean] = Cst(true)
val True: Tentative[Boolean] = Cst(true)
val TrueF: CstF[Any] = CstF(dahu.model.types.Value(true), Tag[Boolean])
val False: Cst[Boolean] = Cst(false)
val False: Tentative[Boolean] = Cst(false)
val FalseF: CstF[Any] = CstF(dahu.model.types.Value(false), Tag[Boolean])
......@@ -3,7 +3,6 @@ package dahu.model.input
import dahu.model.compiler.Algebras
import dahu.model.interpreter.Interpreter
import dahu.model.interpreter.Interpreter.Res
import dahu.model.problem.SatisfactionProblem
import dahu.model.types._
import utest._
......@@ -34,11 +33,11 @@ object BagPacking extends TestSuite {
val ast = Algebras.parse(valid)
"all-true" - {
val satisfied = Interpreter.eval(ast)(_ => Value(true))
assert(satisfied == Some(false))
satisfied ==> Some(false)
"all-false" - {
val satisfied = Interpreter.eval(ast)(_ => Value(false))
assert(satisfied == Some(true))
satisfied ==> Some(true)
"predefined-results" - {
......@@ -5,7 +5,6 @@ import
import dahu.planning.model.core.CoreModel
import dahu.planning.model.transforms.FullToCore
import dahu.planning.model.{core, full}
import dahu.planning.parsing.anml
package object parser {
package dahu.planning.model.common
import dahu.core.algebra.{BoolLike, Orderable}
sealed abstract class Interval[A] {
val start: A
val end: A
......@@ -23,6 +25,20 @@ sealed abstract class Interval[A] {
object Interval {
def point[A](pt: A): Interval[A] = ClosedInterval(pt, pt)
implicit def orderedInstance[A](implicit O: Orderable[A]): Orderable.Aux[Interval[A], O.Bool] =
new Orderable[Interval[A]] {
type Bool = O.Bool
override def BL: BoolLike[Bool] = O.BL
override def leq(a: Interval[A], b: Interval[A]): Bool =
O.leq(a.end, b.start)
override def lt(a: Interval[A], b: Interval[A]): Bool =
if(a.isRightOpen || b.isLeftOpen)
O.leq(a.end, b.start)
else, b.start)
case class ClosedInterval[A](start: A, end: A) extends Interval[A] {
......@@ -10,8 +10,6 @@ import dahu.planning.model.common.{Cst => _, _}
import dahu.planning.model.core._
import dahu.planning.model.{common, core}
import dahu.utils.errors._
import dahu.planning.planner.syntax._
import dahu.planning.planner.syntax.Ordered._
import scala.collection.mutable
......@@ -26,7 +24,7 @@ case class EffectToken(changeItv: Interval[Tentative[Int]],
value: Tentative[Literal])
sealed trait Literal {
def asConstant(tag: TagIsoInt[Literal]): Cst[Literal] = Cst(this)(tag)
def asConstant(tag: TagIsoInt[Literal]): Tentative[Literal] = Cst(this)(tag)
case class IntLit(value: Int) extends Literal {
override def toString: String = value.toString
......@@ -450,7 +448,7 @@ case class Chronicle(ctx: ProblemContext,
case (Opt(EffectToken(changeItv1, end1, fluent1, _), p1),
Opt(EffectToken(changeItv2, end2, fluent2, _), p2)) =>
implies(and(p1, p2, sameFluent(fluent1, fluent2)),
Interval.point(end1) :< changeItv2 || Interval.point(end2) :< changeItv1)
Interval.point(end1) < changeItv2 || Interval.point(end2) < changeItv1)
package dahu.planning.planner
import dahu.model.input.{Computation, Cst, Tentative}
import dahu.model.math._
import dahu.planning.model.common.Interval
package object syntax {
trait Comparable[A, B] {
type C
def leq(a: A, b: B): C
def lt(a: A, b: B): C
def geq(a: A, b: B): C
def gt(a: A, b: B): C
trait Ordered[A] extends Comparable[A, A] {
override def geq(a: A, b: A): C = leq(b, a)
override def gt(a: A, b: A): C = lt(b, a)
object Ordered {
type Aux[A, C0] = Ordered[A] { type C = C0 }
implicit val ofTentativeInt: Aux[Tentative[Int], Tentative[Boolean]] =
new Ordered[Tentative[Int]] {
type C = Tentative[Boolean]
override def leq(a: Tentative[Int], b: Tentative[Int]): Tentative[Boolean] =
Computation(int.LEQ, a, b)
override def lt(a: Tentative[Int], b: Tentative[Int]): Tentative[Boolean] =
leq(Computation(int.Add, Seq(a, Cst(1))), b)
implicit def intervalComparable[A, C](implicit C: Ordered[A]) =
new Ordered[Interval[A]] {
type C = C.C
override def leq(a: Interval[A], b: Interval[A]): C =
C.leq(a.end, b.start)
override def lt(a: Interval[A], b: Interval[A]): C =
if(a.isRightOpen || b.isLeftOpen)
C.leq(a.end, b.start)
else, b.start)
implicit class OrderedOps[A](private val a: A) extends AnyVal {
def <=(b: A)(implicit C: Ordered[A]): C.C = C.leq(a, b)
def :<(b: A)(implicit C: Ordered[A]): C.C =, b)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment