0

I have the following simplied definition of an addition operation over a field:

import inox._
import inox.trees.{forall => _, _}
import inox.trees.dsl._

object Field { 

  val element = FreshIdentifier("element")
  val zero = FreshIdentifier("zero")
  val one = FreshIdentifier("one")

  val elementADT = mkSort(element)()(Seq(zero, one))
  val zeroADT = mkConstructor(zero)()(Some(element)) {_ => Seq()}
  val oneADT = mkConstructor(one)()(Some(element)) {_ => Seq()}

  val addID = FreshIdentifier("add")

  val addFunction = mkFunDef(addID)("element") { case Seq(eT) => 
    val args: Seq[ValDef] = Seq("f1" :: eT, "f2" :: eT)  
    val retType: Type = eT
    val body: Seq[Variable] => Expr = { case Seq(f1,f2) =>
      //do the addition for this field
      f1 //do something better...
    } 
    (args, retType, body)
  }

  //-------Helper functions for arithmetic operations and zero element of field----------------
  implicit class ExprOperands(private val lhs: Expr) extends AnyVal{
    def +(rhs: Expr): Expr = E(addID)(T(element)())(lhs, rhs)
  }

}

I'd like this operation to be used with infix notation and the current solution that I find to do so in Scala is given here. So that's why I'm including the implicit class at the bottom.

Say now I want to use this definition of addition:

import inox._
import inox.trees.{forall => _, _}
import inox.trees.dsl._

import welder._

object Curve{

  val affinePoint = FreshIdentifier("affinePoint")
  val infinitePoint = FreshIdentifier("infinitePoint")
  val finitePoint = FreshIdentifier("finitePoint")
  val first = FreshIdentifier("first")
  val second = FreshIdentifier("second")
  val affinePointADT = mkSort(affinePoint)("F")(Seq(infinitePoint,finitePoint))
  val infiniteADT = mkConstructor(infinitePoint)("F")(Some(affinePoint))(_ => Seq())
  val finiteADT = mkConstructor(finitePoint)("F")(Some(affinePoint)){ case Seq(fT) =>
    Seq(ValDef(first, fT), ValDef(second, fT))
  }

  val F = T(Field.element)()
  val affine = T(affinePoint)(F)
  val infinite = T(infinitePoint)(F)
  val finite = T(finitePoint)(F)

  val onCurveID = FreshIdentifier("onCurve")

  val onCurveFunction = mkFunDef(onCurveID)() { case Seq() => 
    val args: Seq[ValDef] = Seq("p" :: affine, "a" :: F, "b" :: F)
    val retType: Type = BooleanType
    val body: Seq[Variable] => Expr = { case Seq(p,a,b) =>
      if_(p.isInstOf(finite)){
        val x: Expr = p.asInstOf(finite).getField(first)
        val y: Expr = p.asInstOf(finite).getField(second)
        x === y+y
      } else_ {
        BooleanLiteral(true)
      }
    }
    (args, retType, body)
  }

  //---------------------------Registering elements-----------------------------------

  val symbols = NoSymbols
    .withADTs(Seq(affinePointADT, 
                  infiniteADT, 
                  finiteADT,
                  Field.zeroADT,
                  Field.oneADT,
                  Field.elementADT))
    .withFunctions(Seq(Field.addFunction, 

                        onCurveFunction))

  val program = InoxProgram(Context.empty, symbols)
  val theory = theoryOf(program)
  import theory._

  val expr = (E(BigInt(1)) + E(BigInt(1))) === E(BigInt(2))

  val theorem: Theorem = prove(expr)

}

This won't compile giving the following error:

java.lang.ExceptionInInitializerError
    at Main$.main(Main.scala:4)
    at Main.main(Main.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
Caused by: inox.ast.TypeOps$TypeErrorException: Type error: if (p.isInstanceOf[finitePoint[element]]) {
  p.asInstanceOf[finitePoint[element]].first == p.asInstanceOf[finitePoint[element]].second + p.asInstanceOf[finitePoint[element]].second
} else {
  true
}, expected Boolean, found <untyped>
    at inox.ast.TypeOps$TypeErrorException$.apply(TypeOps.scala:24)
    at inox.ast.TypeOps$class.typeCheck(TypeOps.scala:264)
    at inox.ast.SimpleSymbols$SimpleSymbols.typeCheck(SimpleSymbols.scala:12)
    at inox.ast.Definitions$AbstractSymbols$$anonfun$ensureWellFormed$2.apply(Definitions.scala:166)
    at inox.ast.Definitions$AbstractSymbols$$anonfun$ensureWellFormed$2.apply(Definitions.scala:165)
    at scala.collection.TraversableLike$WithFilter$$anonfun$foreach$1.apply(TraversableLike.scala:733)
    at scala.collection.immutable.Map$Map2.foreach(Map.scala:137)
    at scala.collection.TraversableLike$WithFilter.foreach(TraversableLike.scala:732)
    at inox.ast.Definitions$AbstractSymbols$class.ensureWellFormed(Definitions.scala:165)
    at inox.ast.SimpleSymbols$SimpleSymbols.ensureWellFormed$lzycompute(SimpleSymbols.scala:12)
    at inox.ast.SimpleSymbols$SimpleSymbols.ensureWellFormed(SimpleSymbols.scala:12)
    at inox.solvers.unrolling.AbstractUnrollingSolver$class.assertCnstr(UnrollingSolver.scala:129)
    at inox.solvers.SolverFactory$$anonfun$getFromName$1$$anon$1.inox$tip$TipDebugger$$super$assertCnstr(SolverFactory.scala:115)
    at inox.tip.TipDebugger$class.assertCnstr(TipDebugger.scala:52)
    at inox.solvers.SolverFactory$$anonfun$getFromName$1$$anon$1.assertCnstr(SolverFactory.scala:115)
    at inox.solvers.SolverFactory$$anonfun$getFromName$1$$anon$1.assertCnstr(SolverFactory.scala:115)
    at welder.Solvers$class.prove(Solvers.scala:51)
    at welder.package$$anon$1.prove(package.scala:10)
    at welder.Solvers$class.prove(Solvers.scala:23)
    at welder.package$$anon$1.prove(package.scala:10)
    at Curve$.<init>(curve.scala:61)
    at Curve$.<clinit>(curve.scala)
    at Main$.main(Main.scala:4)
    at Main.main(Main.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)

In fact, what is happening is that in the expression x === y+y the + is not being applied correctly so that it is untyped. I recall that inside the objects of Welder proofs one cannot define nested objects or classes I don't know if this has to do with it.

Anyways, do I have to forget about using infix notation in my code for Welder or there is a solution to this?

Community
  • 1
  • 1
user1868607
  • 2,558
  • 1
  • 17
  • 38

1 Answers1

1

The issue here is that the implicit class you defined is not visible when you create y+y (you would need to import Field._ for it to be visible).

I don't remember exactly how implicit resolution takes place in Scala, so maybe adding import Field._ inside the Curve object will override the + that comes from the inox DSL (that's the one being applied when you write y+y, giving you an arithmetic plus expression that expects integer arguments, hence the type error). Otherwise, you'll unfortunately have ambiguity in the implicit resolution, and I'm not sure it's possible to use the infix + operator in that case without giving up the whole dsl.